Ver Fonte

[web] Tear down `sidebar-navigation-ui-update`, Update project-list look in SP/CE (#24920)

* Remove hacks that conditionally hid `ds-nav` survey

* Remove `getAssignment` of `sidebar-navigation-ui-update`

* Remove `hasDsNav`: make it true everywhere

* Remove dead code

* Update Footer so thin footer is shown in SP/CE

* Run `web$ make cleanup_unused_locales` & `bin/run web npm run extract-translations`

* [server-pro] fix learn wiki tests following DS navigation changes

* [server-pro] tests: remove logout action before switching session

* [server-pro] tests: fix logout test

* [server-pro] tests: use new css class for sidebar on project dashboard

* Revert "should add a documentation entry to the nav bar" test change

---------

Co-authored-by: Jakob Ackermann <jakob.ackermann@overleaf.com>
GitOrigin-RevId: 93eb7a1b03bb4e54ad1770150d83778b8f7f6727
Antoine Clausse há 1 ano atrás
pai
commit
13270dee2d

+ 1 - 1
server-ce/test/accounts.spec.ts

@@ -9,7 +9,7 @@ describe('Accounts', function () {
   it('can log in and out', function () {
     login('user@example.com')
     cy.visit('/project')
-    cy.findByText('Account').click()
+    cy.findByRole('menuitem', { name: 'Account' }).click()
     cy.findByText('Log Out').click()
     cy.url().should('include', '/login')
     cy.visit('/project')

+ 2 - 2
server-ce/test/admin.spec.ts

@@ -293,7 +293,7 @@ describe('admin panel', function () {
       cy.findByText(deletedProjectName).should('not.exist')
 
       cy.log('navigate to thrashed projects and delete the project')
-      cy.get('.project-list-sidebar-react').within(() => {
+      cy.get('.project-list-sidebar-scroll').within(() => {
         cy.findByText('Trashed Projects').click()
       })
       findProjectRow(deletedProjectName).within(() =>
@@ -318,7 +318,7 @@ describe('admin panel', function () {
       cy.log('login as the user and verify the project is restored')
       login(user1)
       cy.visit('/project')
-      cy.get('.project-list-sidebar-react').within(() => {
+      cy.get('.project-list-sidebar-scroll').within(() => {
         cy.findByText('Trashed Projects').click()
       })
       cy.findByText(`${deletedProjectName} (Restored)`)

+ 0 - 4
server-ce/test/create-and-compile-project.spec.ts

@@ -102,10 +102,6 @@ describe('Project creation and compilation', function () {
       cy.findByText('Invite not yet accepted.')
     })
 
-    cy.visit('/project')
-    cy.findByText('Account').click()
-    cy.findByText('Log Out').click()
-
     login('collaborator@example.com')
     openProjectViaInviteNotification(targetProjectName)
     cy.get('@targetProjectId').then(targetProjectId => {

+ 2 - 2
server-ce/test/templates.spec.ts

@@ -96,12 +96,12 @@ describe('Templates', () => {
         .parent()
         .parent()
         .within(() => cy.get('input[type="checkbox"]').first().check())
-      cy.get('.project-list-sidebar-react').within(() => {
+      cy.get('.project-list-sidebar-scroll').within(() => {
         cy.findAllByText('New Tag').first().click()
       })
       cy.focused().type(tagName)
       cy.findByText('Create').click()
-      cy.get('.project-list-sidebar-react').within(() => {
+      cy.get('.project-list-sidebar-scroll').within(() => {
         cy.findByText(tagName)
           .parent()
           .within(() => cy.get('.name').should('have.text', `${tagName} (1)`))

+ 0 - 9
services/web/app/src/Features/Project/ProjectListController.mjs

@@ -411,15 +411,6 @@ async function projectListPage(req, res, next) {
     logger.error({ err: error }, 'Failed to get individual subscription')
   }
 
-  // Get the user's assignment for the DS unified nav split test, which
-  // populates splitTestVariants with a value for the split test name and allows
-  // Pug to send it to the browser
-  await SplitTestHandler.promises.getAssignment(
-    req,
-    res,
-    'sidebar-navigation-ui-update'
-  )
-
   // Get the user's assignment for the papers notification banner split test,
   // which populates splitTestVariants with a value for the split test name and
   // allows Pug to send it to the browser

+ 0 - 1
services/web/frontend/extracted-translations.json

@@ -1127,7 +1127,6 @@
   "optional": "",
   "or": "",
   "organization_name": "",
-  "organize_projects": "",
   "organize_tags": "",
   "other": "",
   "other_causes_of_compile_timeouts": "",

+ 0 - 119
services/web/frontend/js/features/project-list/components/project-list-default.tsx

@@ -1,119 +0,0 @@
-import { useProjectListContext } from '../context/project-list-context'
-import { useTranslation } from 'react-i18next'
-import CurrentPlanWidget from './current-plan-widget/current-plan-widget'
-import NewProjectButton from './new-project-button'
-import ProjectListTable from './table/project-list-table'
-import SurveyWidget from './survey-widget'
-import UserNotifications from './notifications/user-notifications'
-import SearchForm from './search-form'
-import ProjectsDropdown from './dropdown/projects-dropdown'
-import SortByDropdown from './dropdown/sort-by-dropdown'
-import ProjectTools from './table/project-tools/project-tools'
-import ProjectListTitle from './title/project-list-title'
-import Sidebar from './sidebar/sidebar'
-import LoadMore from './load-more'
-import OLCol from '@/features/ui/components/ol/ol-col'
-import OLRow from '@/features/ui/components/ol/ol-row'
-import { TableContainer } from '@/features/ui/components/bootstrap-5/table'
-import DashApiError from '@/features/project-list/components/dash-api-error'
-
-export default function ProjectListDefault() {
-  const { t } = useTranslation()
-  const {
-    error,
-    searchText,
-    setSearchText,
-    selectedProjects,
-    filter,
-    tags,
-    selectedTagId,
-  } = useProjectListContext()
-
-  const selectedTag = tags.find(tag => tag._id === selectedTagId)
-
-  const tableTopArea = (
-    <div className="pt-2 pb-3 d-md-none d-flex gap-2">
-      <NewProjectButton
-        id="new-project-button-projects-table"
-        showAddAffiliationWidget
-      />
-      <SearchForm
-        inputValue={searchText}
-        setInputValue={setSearchText}
-        filter={filter}
-        selectedTag={selectedTag}
-        className="overflow-hidden flex-grow-1"
-      />
-    </div>
-  )
-
-  return (
-    <>
-      <Sidebar />
-      <div className="project-list-main-react">
-        {error ? <DashApiError /> : ''}
-        <OLRow>
-          <OLCol>
-            <UserNotifications />
-          </OLCol>
-        </OLRow>
-        <div className="project-list-header-row">
-          <ProjectListTitle
-            filter={filter}
-            selectedTag={selectedTag}
-            selectedTagId={selectedTagId}
-            className="text-truncate d-none d-md-block"
-          />
-          <div className="project-tools">
-            <div className="d-none d-md-block">
-              {selectedProjects.length === 0 ? (
-                <CurrentPlanWidget />
-              ) : (
-                <ProjectTools />
-              )}
-            </div>
-            <div className="d-md-none">
-              <CurrentPlanWidget />
-            </div>
-          </div>
-        </div>
-        <OLRow className="d-none d-md-block">
-          <OLCol lg={7}>
-            <SearchForm
-              inputValue={searchText}
-              setInputValue={setSearchText}
-              filter={filter}
-              selectedTag={selectedTag}
-            />
-          </OLCol>
-        </OLRow>
-        <div className="project-list-sidebar-survey-wrapper d-md-none">
-          <SurveyWidget />
-        </div>
-        <div className="mt-1 d-md-none">
-          <div
-            role="toolbar"
-            className="projects-toolbar"
-            aria-label={t('projects')}
-          >
-            <ProjectsDropdown />
-            <SortByDropdown />
-          </div>
-        </div>
-        <OLRow className="row-spaced">
-          <OLCol>
-            <TableContainer bordered>
-              {tableTopArea}
-              <ProjectListTable />
-            </TableContainer>
-          </OLCol>
-        </OLRow>
-        <OLRow className="row-spaced">
-          <OLCol>
-            <LoadMore />
-          </OLCol>
-        </OLRow>
-      </div>
-    </>
-  )
-}

+ 3 - 2
services/web/frontend/js/features/project-list/components/project-list-ds-nav.tsx

@@ -16,13 +16,14 @@ import { TableContainer } from '@/features/ui/components/bootstrap-5/table'
 import DashApiError from '@/features/project-list/components/dash-api-error'
 import getMeta from '@/utils/meta'
 import DefaultNavbar from '@/features/ui/components/bootstrap-5/navbar/default-navbar'
-import FatFooter from '@/features/ui/components/bootstrap-5/footer/fat-footer'
+import Footer from '@/features/ui/components/bootstrap-5/footer/footer'
 import SidebarDsNav from '@/features/project-list/components/sidebar/sidebar-ds-nav'
 import SystemMessages from '@/shared/components/system-messages'
 import overleafLogo from '@/shared/svgs/overleaf-a-ds-solution-mallard.svg'
 
 export function ProjectListDsNav() {
   const navbarProps = getMeta('ol-navbar')
+  const footerProps = getMeta('ol-footer')
   const { t } = useTranslation()
   const {
     error,
@@ -117,7 +118,7 @@ export function ProjectListDsNav() {
                 </div>
               </div>
             </div>
-            <FatFooter />
+            <Footer {...footerProps} />
           </div>
           <div>
             <SystemMessages />

+ 7 - 26
services/web/frontend/js/features/project-list/components/project-list-root.tsx

@@ -16,12 +16,8 @@ import getMeta from '@/utils/meta'
 import DefaultNavbar from '@/features/ui/components/bootstrap-5/navbar/default-navbar'
 import Footer from '@/features/ui/components/bootstrap-5/footer/footer'
 import WelcomePageContent from '@/features/project-list/components/welcome-page-content'
-import ProjectListDefault from '@/features/project-list/components/project-list-default'
 import { ProjectListDsNav } from '@/features/project-list/components/project-list-ds-nav'
-import {
-  DsNavStyleProvider,
-  hasDsNav,
-} from '@/features/project-list/components/use-is-ds-nav'
+import { DsNavStyleProvider } from '@/features/project-list/components/use-is-ds-nav'
 
 function ProjectListRoot() {
   const { isReady } = useWaitForI18n()
@@ -87,15 +83,7 @@ function ProjectListPageContent() {
       <LoadingBranded loadProgress={loadProgress} label={t('loading')} />
     )
 
-    if (hasDsNav()) {
-      return loadingComponent
-    } else {
-      return (
-        <DefaultNavbarAndFooter>
-          <div className="loading-container">{loadingComponent}</div>
-        </DefaultNavbarAndFooter>
-      )
-    }
+    return loadingComponent
   }
 
   if (totalProjectsCount === 0) {
@@ -104,19 +92,12 @@ function ProjectListPageContent() {
         <WelcomePageContent />
       </DefaultPageContentWrapper>
     )
-  } else if (hasDsNav()) {
-    return (
-      <DsNavStyleProvider>
-        <ProjectListDsNav />
-      </DsNavStyleProvider>
-    )
-  } else {
-    return (
-      <DefaultPageContentWrapper>
-        <ProjectListDefault />
-      </DefaultPageContentWrapper>
-    )
   }
+  return (
+    <DsNavStyleProvider>
+      <ProjectListDsNav />
+    </DsNavStyleProvider>
+  )
 }
 
 export default withErrorBoundary(ProjectListRoot, GenericErrorBoundaryFallback)

+ 3 - 6
services/web/frontend/js/features/project-list/components/sidebar/sidebar-filters.tsx

@@ -5,7 +5,6 @@ import {
 } from '../../context/project-list-context'
 import TagsList from './tags-list'
 import ProjectsFilterMenu from '../projects-filter-menu'
-import { hasDsNav } from '@/features/project-list/components/use-is-ds-nav'
 
 type SidebarFilterProps = {
   filter: Filter
@@ -38,11 +37,9 @@ export default function SidebarFilters() {
       <SidebarFilter filter="shared" text={t('shared_with_you')} />
       <SidebarFilter filter="archived" text={t('archived_projects')} />
       <SidebarFilter filter="trashed" text={t('trashed_projects')} />
-      {hasDsNav() && (
-        <li role="none">
-          <hr />
-        </li>
-      )}
+      <li role="none">
+        <hr />
+      </li>
       <TagsList />
     </ul>
   )

+ 4 - 15
services/web/frontend/js/features/project-list/components/sidebar/tags-list.tsx

@@ -1,7 +1,6 @@
 import { sortBy } from 'lodash'
 import { useTranslation } from 'react-i18next'
 import { DotsThreeVertical, Plus, TagSimple } from '@phosphor-icons/react'
-import MaterialIcon from '../../../../shared/components/material-icon'
 import {
   UNCATEGORIZED_KEY,
   useProjectListContext,
@@ -14,7 +13,6 @@ import {
   DropdownMenu,
   DropdownToggle,
 } from '@/features/ui/components/bootstrap-5/dropdown-menu'
-import { hasDsNav } from '@/features/project-list/components/use-is-ds-nav'
 
 export default function TagsList() {
   const { t } = useTranslation()
@@ -42,16 +40,11 @@ export default function TagsList() {
         aria-hidden="true"
         data-testid="organize-projects"
       >
-        {hasDsNav() ? t('organize_tags') : t('organize_projects')}
+        {t('organize_tags')}
       </li>
       <li className="tag">
         <button type="button" className="tag-name" onClick={openCreateTagModal}>
-          {hasDsNav() ? (
-            <Plus weight="bold" />
-          ) : (
-            <MaterialIcon type="add" className="tag-list-icon" />
-          )}
-
+          <Plus weight="bold" />
           <span className="name">{t('new_tag')}</span>
         </button>
       </li>
@@ -73,11 +66,7 @@ export default function TagsList() {
                   color: getTagColor(tag),
                 }}
               >
-                {hasDsNav() ? (
-                  <TagSimple weight="fill" className="tag-list-icon" />
-                ) : (
-                  <MaterialIcon type="label" className="tag-list-icon" />
-                )}
+                <TagSimple weight="fill" className="tag-list-icon" />
               </span>
               <span className="name">
                 {tag.name}{' '}
@@ -93,7 +82,7 @@ export default function TagsList() {
                 id={`${tag._id}-dropdown-toggle`}
                 data-testid="tag-dropdown-toggle"
               >
-                {hasDsNav() && <DotsThreeVertical weight="bold" />}
+                <DotsThreeVertical weight="bold" />
               </DropdownToggle>
               <DropdownMenu className="dropdown-menu-sm-width">
                 <DropdownItem

+ 1 - 10
services/web/frontend/js/features/project-list/components/survey-widget-ds-nav.tsx

@@ -1,11 +1,9 @@
 import usePersistedState from '../../../shared/hooks/use-persisted-state'
 import getMeta from '../../../utils/meta'
 import { useCallback } from 'react'
-import classnames from 'classnames'
 import OLButton from '@/features/ui/components/ol/ol-button'
 import { useTranslation } from 'react-i18next'
 import { X } from '@phosphor-icons/react'
-import { useHideDsSurvey } from '@/features/project-list/components/use-is-ds-nav'
 
 export function SurveyWidgetDsNav() {
   const { t } = useTranslation()
@@ -14,7 +12,6 @@ export function SurveyWidgetDsNav() {
     `dismissed-${survey?.name}`,
     false
   )
-  const hideDsSurvey = useHideDsSurvey()
 
   const dismissSurvey = useCallback(() => {
     setDismissedSurvey(true)
@@ -24,14 +21,8 @@ export function SurveyWidgetDsNav() {
     return null
   }
 
-  // Hide the survey for users who have sidebar-navigation-ui-update:
-  // They've had it for months. We don't need their feedback anymore
-  if (hideDsSurvey && survey?.name === 'ds-nav') {
-    return null
-  }
-
   return (
-    <div className={classnames('user-notifications', `survey-${survey.name}`)}>
+    <div className="user-notifications">
       <div className="notification-entry">
         <div role="alert" className="survey-notification">
           <div className="notification-body">

+ 0 - 6
services/web/frontend/js/features/project-list/components/survey-widget.tsx

@@ -18,12 +18,6 @@ export default function SurveyWidget() {
     return null
   }
 
-  // Short-term hard-coded special case: hide the "DS nav" survey for users on
-  // the default variant
-  if (survey?.name === 'ds-nav') {
-    return null
-  }
-
   return (
     <div className="user-notifications">
       <div className="notification-entry">

+ 0 - 12
services/web/frontend/js/features/project-list/components/use-is-ds-nav.tsx

@@ -1,16 +1,4 @@
 import { createContext, type FC, type ReactNode, useContext } from 'react'
-import { useSplitTestContext } from '@/shared/context/split-test-context'
-import getMeta from '@/utils/meta'
-
-export const hasDsNav = () => getMeta('ol-ExposedSettings').isOverleaf
-
-/**
- * This hook returns whether the user has the split-test assignment 'sidebar-navigation-ui-update'
- */
-export const useHideDsSurvey = () => {
-  const { splitTestVariants } = useSplitTestContext()
-  return splitTestVariants['sidebar-navigation-ui-update'] === 'active'
-}
 
 /**
  * This context wraps elements that should be styled according to the sidebar-navigation-ui-update redesign

+ 0 - 1
services/web/locales/en.json

@@ -1490,7 +1490,6 @@
   "organization_name": "Organization name",
   "organization_or_company_name": "Organization or company name",
   "organization_or_company_type": "Organization or company type",
-  "organize_projects": "Organize Projects",
   "organize_tags": "Organize Tags",
   "original_price": "Original price",
   "other": "Other",