From 73cc1b571b2040ddf3e7d2183962638551acd93c Mon Sep 17 00:00:00 2001 From: Tom Wells Date: Mon, 27 Apr 2026 10:42:54 +0100 Subject: [PATCH] Add DS nav page switcher behind overleaf-library flag (#33112) * Add DS nav page switcher behind overleaf-library flag - Add shared DsNavPageSwitcher component (Library/Projects nav links + logo) - Show page switcher in projects sidebar when overleaf-library flag enabled - Hide 'All projects' filter and sidebar New Project button behind flag - Move New Project button to content area header when flag enabled - Prevent full page reload when clicking active nav item - Change Upgrade button to premium variant when flag enabled - Add overleaf-library split test to ProjectListController - Add library-page class to remove rounded corner on /library - Add Cypress component tests for DsNavPageSwitcher Closes #33092 GitOrigin-RevId: 2e348da8307bf944d481b54b3a2bcc2eb319e18e --- .../Project/ProjectListController.mjs | 1 + .../current-plan-widget/free-plan.tsx | 5 +- .../components/project-list-ds-nav.tsx | 58 ++++++--- .../components/sidebar/sidebar-ds-nav.tsx | 25 +++- .../components/sidebar/sidebar-filters.tsx | 6 +- .../sidebar/ds-nav-page-switcher.tsx | 79 ++++++++++++ .../pages/project-list-ds-nav.scss | 74 ++++++++++++ .../sidebar/ds-nav-page-switcher.spec.tsx | 114 ++++++++++++++++++ 8 files changed, 342 insertions(+), 20 deletions(-) create mode 100644 services/web/frontend/js/shared/components/sidebar/ds-nav-page-switcher.tsx create mode 100644 services/web/test/frontend/shared/components/sidebar/ds-nav-page-switcher.spec.tsx diff --git a/services/web/app/src/Features/Project/ProjectListController.mjs b/services/web/app/src/Features/Project/ProjectListController.mjs index 70a8fcdecd..1119e14cc1 100644 --- a/services/web/app/src/Features/Project/ProjectListController.mjs +++ b/services/web/app/src/Features/Project/ProjectListController.mjs @@ -530,6 +530,7 @@ async function projectListPage(req, res, next) { const splitTests = [ // Split tests that will be made available to the frontend 'import-docx', + 'overleaf-library', ].filter(Boolean) await Promise.all( diff --git a/services/web/frontend/js/features/project-list/components/current-plan-widget/free-plan.tsx b/services/web/frontend/js/features/project-list/components/current-plan-widget/free-plan.tsx index 351f16520b..b27ecc8b28 100644 --- a/services/web/frontend/js/features/project-list/components/current-plan-widget/free-plan.tsx +++ b/services/web/frontend/js/features/project-list/components/current-plan-widget/free-plan.tsx @@ -4,10 +4,12 @@ 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 function FreePlan({ featuresPageURL }: FreePlanProps) { + const isLibraryEnabled = isSplitTestEnabled('overleaf-library') const { t } = useTranslation() const currentPlanLabel = ( {' '} diff --git a/services/web/frontend/js/features/project-list/components/project-list-ds-nav.tsx b/services/web/frontend/js/features/project-list/components/project-list-ds-nav.tsx index bab7c25c47..b0d7e02f06 100644 --- a/services/web/frontend/js/features/project-list/components/project-list-ds-nav.tsx +++ b/services/web/frontend/js/features/project-list/components/project-list-ds-nav.tsx @@ -23,6 +23,7 @@ import overleafLogo from '@/shared/svgs/overleaf-a-ds-solution-mallard.svg' import overleafLogoDark from '@/shared/svgs/overleaf-a-ds-solution-mallard-dark.svg' import CookieBanner from '@/shared/components/cookie-banner' import { useActiveOverallTheme } from '@/shared/hooks/use-active-overall-theme' +import { isSplitTestEnabled } from '@/utils/splitTestUtils' export function ProjectListDsNav() { const navbarProps = getMeta('ol-navbar') @@ -38,27 +39,48 @@ export function ProjectListDsNav() { selectedTagId, } = useProjectListContext() const activeOverallTheme = useActiveOverallTheme() + const isLibraryEnabled = isSplitTestEnabled('overleaf-library') const selectedTag = tags.find(tag => tag._id === selectedTagId) const tableTopArea = (
- - + {isLibraryEnabled ? ( + <> + + + + ) : ( + <> + + + + )}
) return ( -
+
- - + + + {isLibraryEnabled && ( + + + + )}
{/* Omit the survey card in mobile view for now */} diff --git a/services/web/frontend/js/features/project-list/components/sidebar/sidebar-ds-nav.tsx b/services/web/frontend/js/features/project-list/components/sidebar/sidebar-ds-nav.tsx index 10491e2861..185d1fbb96 100644 --- a/services/web/frontend/js/features/project-list/components/sidebar/sidebar-ds-nav.tsx +++ b/services/web/frontend/js/features/project-list/components/sidebar/sidebar-ds-nav.tsx @@ -7,10 +7,15 @@ 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 { DsNavPageSwitcher } from '@/shared/components/sidebar/ds-nav-page-switcher' +import { useProjectListContext } from '@/features/project-list/context/project-list-context' function SidebarDsNav() { const { t } = useTranslation() const { show: showAddAffiliationWidget } = useAddAffiliation() + const isLibraryEnabled = isSplitTestEnabled('overleaf-library') + const { selectFilter } = useProjectListContext() const { mousePos, getHandleProps, getTargetProps } = usePersistedResize({ name: 'project-sidebar', }) @@ -25,14 +30,26 @@ function SidebarDsNav() { }, })} > + {isLibraryEnabled && ( + <> + selectFilter('all')} + /> +
+ + )}