Merge pull request #36649 from overleaf/dp-cleanup-library-feature-flag

Remove the overleaf-library feature flag

GitOrigin-RevId: ebeabd43c9e44dbc2344b4e8e7e5b9095fcc86e0
This commit is contained in:
David
2026-09-17 12:04:13 +00:00
committed by Copybot
parent 6c802c03a6
commit 90be47c5e1
18 changed files with 148 additions and 237 deletions
@@ -4,12 +4,10 @@ import OLTooltip from '@/shared/components/ol/ol-tooltip'
import MaterialIcon from '@/shared/components/material-icon'
import { FreePlanSubscription } from '../../../../../../types/project/dashboard/subscription'
import * as eventTracking from '../../../../infrastructure/event-tracking'
import { isSplitTestEnabled } from '@/utils/splitTestUtils'
type FreePlanProps = Pick<FreePlanSubscription, 'featuresPageURL'>
function FreePlan({ featuresPageURL }: FreePlanProps) {
const isLibraryEnabled = isSplitTestEnabled('overleaf-library')
const { t } = useTranslation()
const currentPlanLabel = (
<Trans
@@ -45,8 +43,8 @@ function FreePlan({ featuresPageURL }: FreePlanProps) {
</OLTooltip>{' '}
<span className="d-none d-md-inline-block">
<OLButton
variant={isLibraryEnabled ? 'premium' : 'primary'}
size={isLibraryEnabled ? 'sm' : undefined}
variant="premium"
size="sm"
href="/user/subscription/plans"
onClick={handleClick}
>
@@ -9,13 +9,11 @@ import {
import {
OLDropdown,
OLDropdownDivider,
OLDropdownHeader,
OLDropdownItem,
OLDropdownMenu,
OLDropdownToggle,
} from '@/shared/components/ol/ol-dropdown-menu'
import MaterialIcon from '@/shared/components/material-icon'
import { isSplitTestEnabled } from '@/utils/splitTestUtils'
import ProjectsFilterMenu from '../projects-filter-menu'
import TagsList from '../tags-list'
import { ActivePage } from '../../util/navigation-state'
@@ -78,7 +76,6 @@ function NavigationDropdown({
)
const [view, setView] = useState<'top' | 'tags' | 'trash'>('top')
const { filter, selectedTagId, tags } = useProjectListContext()
const isLibraryEnabled = isSplitTestEnabled('overleaf-library')
const projectsTrashActive =
activePage === 'projects' &&
selectedTagId === undefined &&
@@ -126,7 +123,7 @@ function NavigationDropdown({
filter="all"
text={t('all_projects')}
activePage={activePage}
leadingIcon={isLibraryEnabled && <Folder size={20} />}
leadingIcon={<Folder size={20} />}
/>
</li>
<li role="none">
@@ -134,7 +131,7 @@ function NavigationDropdown({
filter="owned"
text={t('your_projects')}
activePage={activePage}
leadingIcon={isLibraryEnabled && <OLDropdownItem.EmptyLeadingIcon />}
leadingIcon={<OLDropdownItem.EmptyLeadingIcon />}
/>
</li>
<li role="none">
@@ -142,7 +139,7 @@ function NavigationDropdown({
filter="shared"
text={t('shared_with_you')}
activePage={activePage}
leadingIcon={isLibraryEnabled && <OLDropdownItem.EmptyLeadingIcon />}
leadingIcon={<OLDropdownItem.EmptyLeadingIcon />}
/>
</li>
<li role="none">
@@ -150,71 +147,40 @@ function NavigationDropdown({
filter="archived"
text={t('archived_projects')}
activePage={activePage}
leadingIcon={isLibraryEnabled && <OLDropdownItem.EmptyLeadingIcon />}
leadingIcon={<OLDropdownItem.EmptyLeadingIcon />}
/>
</li>
{!isLibraryEnabled && (
<li role="none">
<Item
filter="trashed"
text={t('trashed_projects')}
activePage={activePage}
/>
</li>
)}
</>
)
const submenuItems = (
<>
{filterItems}
<OLDropdownHeader className="text-uppercase">
{t('tags')}:
</OLDropdownHeader>
<TagsList />
</>
)
return (
<OLDropdown
onToggle={
isLibraryEnabled
? show => {
if (show) {
if (selectedTagId !== undefined) {
setView('tags')
} else if (isTrashActive) {
setView('trash')
} else {
setView('top')
}
} else {
setView('top')
}
}
: undefined
}
onToggle={show => {
if (show) {
if (selectedTagId !== undefined) {
setView('tags')
} else if (isTrashActive) {
setView('trash')
} else {
setView('top')
}
} else {
setView('top')
}
}}
>
<OLDropdownToggle
id="projects-types-dropdown-toggle-btn"
className="ps-0 mb-0 btn-transparent h3"
size="lg"
aria-label={
isLibraryEnabled ? t('navigation_menu') : t('filter_projects')
}
aria-label={t('navigation_menu')}
>
<span className="text-truncate" aria-hidden>
{title}
</span>
</OLDropdownToggle>
<OLDropdownMenu
flip={false}
className={
isLibraryEnabled ? 'projects-dropdown-menu-library' : undefined
}
>
{!isLibraryEnabled && submenuItems}
{isLibraryEnabled && view === 'top' && (
<OLDropdownMenu flip={false} className="projects-dropdown-menu-library">
{view === 'top' && (
<>
{filterItems}
<li role="none">
@@ -257,7 +223,7 @@ function NavigationDropdown({
</li>
</>
)}
{isLibraryEnabled && view === 'tags' && (
{view === 'tags' && (
<>
<li role="none">
<OLDropdownItem
@@ -276,7 +242,7 @@ function NavigationDropdown({
<TagsList />
</>
)}
{isLibraryEnabled && view === 'trash' && (
{view === 'trash' && (
<>
<li role="none">
<OLDropdownItem
@@ -22,7 +22,6 @@ import { useSendProjectListMB } from '@/features/project-list/components/project
import type { PortalTemplate } from '../../../../../types/portal-template'
import { useFeatureFlag } from '@/shared/context/split-test-context'
import { useProjectListContext } from '@/features/project-list/context/project-list-context'
import { isSplitTestEnabled } from '@/utils/splitTestUtils'
import { NestableDropdownContextProvider } from '@/shared/context/nestable-dropdown-context'
import { NestedMenuBarDropdown } from '@/shared/components/menu-bar/menu-bar-dropdown'
@@ -72,11 +71,9 @@ function NewProjectButton({
useFeatureFlag('import-markdown') &&
getMeta('ol-ExposedSettings').enablePandocConversions
const { selectedTagId, tags } = useProjectListContext()
const isLibraryEnabled = isSplitTestEnabled('overleaf-library')
const initialTags =
isLibraryEnabled && selectedTagId
? tags.filter(tag => tag._id === selectedTagId)
: []
const initialTags = selectedTagId
? tags.filter(tag => tag._id === selectedTagId)
: []
const sendTrackingEvent = useCallback(
({
dropdownMenu,
@@ -26,7 +26,6 @@ import overleafLogoDark from '@/shared/svgs/overleaf-a-ds-solution-mallard-dark.
import CookieBanner from '@/shared/components/cookie-banner'
import NoProjects from '@/features/project-list/components/no-projects'
import { useActiveOverallTheme } from '@/shared/hooks/use-active-overall-theme'
import { isSplitTestEnabled } from '@/utils/splitTestUtils'
import { useFeatureFlag } from '@/shared/context/split-test-context'
export function ProjectListDsNav() {
@@ -44,48 +43,28 @@ export function ProjectListDsNav() {
currentFilterProjectsCount,
} = useProjectListContext()
const activeOverallTheme = useActiveOverallTheme()
const isLibraryEnabled = isSplitTestEnabled('overleaf-library')
const isSharedWorkspaceEnabled = useFeatureFlag('shared-workspace')
const selectedTag = tags.find(tag => tag._id === selectedTagId)
const showTrashHeader = isLibraryEnabled && filter === 'trashed'
const showTrashHeader = filter === 'trashed'
const showNewProjectButton =
!isLibraryEnabled ||
(filter !== 'shared' && filter !== 'archived' && filter !== 'trashed')
filter !== 'shared' && filter !== 'archived' && filter !== 'trashed'
const tableTopArea = (
<div className="pt-2 pb-3 d-md-none d-flex gap-2">
{isLibraryEnabled ? (
<>
<SearchForm
inputValue={searchText}
setInputValue={setSearchText}
filter={filter}
selectedTag={selectedTag}
className="overflow-hidden flex-grow-1"
/>
{showNewProjectButton && (
<NewProjectButton
id="new-project-button-projects-table"
showAddAffiliationWidget
align="end"
/>
)}
</>
) : (
<>
<NewProjectButton
id="new-project-button-projects-table"
showAddAffiliationWidget
/>
<SearchForm
inputValue={searchText}
setInputValue={setSearchText}
filter={filter}
selectedTag={selectedTag}
className="overflow-hidden flex-grow-1"
/>
</>
<SearchForm
inputValue={searchText}
setInputValue={setSearchText}
filter={filter}
selectedTag={selectedTag}
className="overflow-hidden flex-grow-1"
/>
{showNewProjectButton && (
<NewProjectButton
id="new-project-button-projects-table"
showAddAffiliationWidget
align="end"
/>
)}
</div>
)
@@ -93,7 +72,6 @@ export function ProjectListDsNav() {
return (
<div
className={classNames('project-ds-nav-page', 'website-redesign', {
'library-enabled': isLibraryEnabled,
'ds-nav-hides-top-navbar': showTrashHeader,
})}
>
@@ -159,7 +137,7 @@ export function ProjectListDsNav() {
) : (
<div className="project-ds-nav-project-list">
<OLRow className="d-none d-md-flex align-items-center">
<OLCol md={isLibraryEnabled ? 8 : undefined} lg={7}>
<OLCol md={8} lg={7}>
<SearchForm
inputValue={searchText}
setInputValue={setSearchText}
@@ -167,7 +145,7 @@ export function ProjectListDsNav() {
selectedTag={selectedTag}
/>
</OLCol>
{isLibraryEnabled && showNewProjectButton && (
{showNewProjectButton && (
<OLCol className="ms-auto" xs="auto">
<NewProjectButton
id="new-project-button-projects-table"
@@ -2,14 +2,12 @@ import { JSXElementConstructor } from 'react'
import { useTranslation } from 'react-i18next'
import classnames from 'classnames'
import { Trash } from '@phosphor-icons/react'
import NewProjectButton from '../new-project-button'
import SidebarFilters from './sidebar-filters'
import AddAffiliation, { useAddAffiliation } from '../add-affiliation'
import { usePersistedResize } from '@/shared/hooks/use-resize'
import { useScrolled } from '@/features/project-list/components/sidebar/use-scroll'
import { SurveyWidgetDsNav } from '@/features/project-list/components/survey-widget-ds-nav'
import { SidebarLowerSection } from '@/shared/components/sidebar/sidebar-lower-section'
import { isSplitTestEnabled } from '@/utils/splitTestUtils'
import { DsNavOverleafLogo } from '@/shared/components/sidebar/ds-nav-overleaf-logo'
import { useProjectListContext } from '@/features/project-list/context/project-list-context'
import importOverleafModules from '../../../../../macros/import-overleaf-module.macro'
@@ -29,7 +27,6 @@ function SidebarDsNav({
}) {
const { t } = useTranslation()
const { show: showAddAffiliationWidget } = useAddAffiliation()
const isLibraryEnabled = isSplitTestEnabled('overleaf-library')
const { filter, selectedTagId, selectFilter } = useProjectListContext()
const isTrashActive =
activePage === 'library'
@@ -43,7 +40,7 @@ function SidebarDsNav({
const { mousePos, getHandleProps, getTargetProps } = usePersistedResize({
name: 'project-sidebar',
})
const { containerRef, scrolledUp, scrolledDown } = useScrolled()
const { containerRef, scrolledUp } = useScrolled()
return (
<div
@@ -54,19 +51,11 @@ function SidebarDsNav({
},
})}
>
{isLibraryEnabled && (activePage === 'library' || isTrashActive) && (
<DsNavOverleafLogo />
)}
{(activePage === 'library' || isTrashActive) && <DsNavOverleafLogo />}
<nav
className="flex-grow flex-shrink"
aria-label={t('project_categories_tags')}
>
{!isLibraryEnabled && (
<NewProjectButton
id="new-project-button-sidebar"
className={scrolledDown ? 'show-shadow' : undefined}
/>
)}
<div
className="project-list-sidebar-scroll"
ref={containerRef}
@@ -84,29 +73,25 @@ function SidebarDsNav({
)}
>
<SidebarLowerSection showThemeToggle>
{isLibraryEnabled && (
<>
{DsNavLibraryLink && (
<DsNavLibraryLink
active={activePage === 'library' && !trashActive}
inLibrary={activePage === 'library'}
/>
)}
<button
type="button"
className={classnames('ds-nav-page-switcher-item', {
active: isTrashActive,
})}
aria-current={isTrashActive ? 'page' : undefined}
onClick={() => selectFilter('trashed')}
>
<Trash size={20} />
<span className="ds-nav-page-switcher-item-label">
{t('trash')}
</span>
</button>
</>
{DsNavLibraryLink && (
<DsNavLibraryLink
active={activePage === 'library' && !trashActive}
inLibrary={activePage === 'library'}
/>
)}
<button
type="button"
className={classnames('ds-nav-page-switcher-item', {
active: isTrashActive,
})}
aria-current={isTrashActive ? 'page' : undefined}
onClick={() => selectFilter('trashed')}
>
<Trash size={20} />
<span className="ds-nav-page-switcher-item-label">
{t('trash')}
</span>
</button>
<div className="project-list-sidebar-survey-wrapper">
<SurveyWidgetDsNav />
</div>
@@ -6,7 +6,6 @@ import {
} from '../../context/project-list-context'
import TagsList from './tags-list'
import ProjectsFilterMenu from '../projects-filter-menu'
import { isSplitTestEnabled } from '@/utils/splitTestUtils'
import { Folder } from '@phosphor-icons/react'
import { ActivePage } from '../../util/navigation-state'
@@ -51,14 +50,13 @@ export default function SidebarFilters({
activePage: ActivePage
}) {
const { t } = useTranslation()
const isLibraryEnabled = isSplitTestEnabled('overleaf-library')
return (
<ul className="list-unstyled project-list-filters">
<SidebarFilter
activePage={activePage}
filter="all"
text={isLibraryEnabled ? t('projects') : t('all_projects')}
icon={isLibraryEnabled && <Folder size={20} />}
text={t('projects')}
icon={<Folder size={20} />}
/>
<SidebarFilter
activePage={activePage}
@@ -75,13 +73,6 @@ export default function SidebarFilters({
filter="archived"
text={t('archived_projects')}
/>
{!isLibraryEnabled && (
<SidebarFilter
activePage={activePage}
filter="trashed"
text={t('trashed_projects')}
/>
)}
<li aria-hidden="true">
<hr />
</li>
@@ -1,16 +1,32 @@
import { TFunction } from 'i18next'
import { useTranslation } from 'react-i18next'
import classnames from 'classnames'
import importOverleafModules from '../../../../../macros/import-overleaf-module.macro'
export type TrashTab = 'projects' | 'references'
export type TrashPageTab = { key: TrashTab; label: string; href: string }
type TrashPageTabModule = {
import: { default: (t: TFunction) => TrashPageTab }
path: string
}
const trashPageTabModules: TrashPageTabModule[] =
importOverleafModules('trashPageTabs')
function TrashPageTabs({ activeTab }: { activeTab: TrashTab }) {
const { t } = useTranslation()
const tabs: { key: TrashTab; label: string; href: string }[] = [
const tabs: TrashPageTab[] = [
{ key: 'projects', label: t('projects'), href: '/project/trashed' },
{ key: 'references', label: t('references'), href: '/library/trashed' },
...trashPageTabModules.map(({ import: getTab }) => getTab.default(t)),
]
if (tabs.length < 2) {
return null
}
return (
<nav className="trash-page-tabs" aria-label={t('trash')}>
{tabs.map(tab => {