From 92a2debc9a6c1b30175d8daab88d1ffa464a6065 Mon Sep 17 00:00:00 2001 From: Rebeka Dekany <50901361+rebekadekany@users.noreply.github.com> Date: Mon, 12 Aug 2024 16:45:27 +0200 Subject: [PATCH] Merge pull request #19557 from overleaf/rd-left-menu-dropdown [web] Migrate the left menu on the project dashboard part #2 GitOrigin-RevId: 55b213352dd850650668bb4e507e11607aee0107 --- .../web/frontend/extracted-translations.json | 1 + .../components/new-project-button.tsx | 339 ++++++++++++------ .../modal-content-new-project-form.tsx | 6 +- .../components/sidebar/tags-list.tsx | 8 +- ...me-message-create-new-project-dropdown.tsx | 4 +- .../components/types/dropdown-menu-props.ts | 1 + .../stylesheets/app/project-list-react.less | 34 +- .../bootstrap-5/pages/project-list.scss | 13 + .../stylesheets/components/dropdowns.less | 6 +- .../components/sidebar/tags-list.test.tsx | 6 +- 10 files changed, 284 insertions(+), 134 deletions(-) diff --git a/services/web/frontend/extracted-translations.json b/services/web/frontend/extracted-translations.json index 6797120695..f8e7902bed 100644 --- a/services/web/frontend/extracted-translations.json +++ b/services/web/frontend/extracted-translations.json @@ -1383,6 +1383,7 @@ "tc_switch_guests_tip": "", "tc_switch_user_tip": "", "tell_the_project_owner_and_ask_them_to_upgrade": "", + "template": "", "template_approved_by_publisher": "", "template_description": "", "template_title_taken_from_project_title": "", diff --git a/services/web/frontend/js/features/project-list/components/new-project-button.tsx b/services/web/frontend/js/features/project-list/components/new-project-button.tsx index ba4b39615d..ef519a563c 100644 --- a/services/web/frontend/js/features/project-list/components/new-project-button.tsx +++ b/services/web/frontend/js/features/project-list/components/new-project-button.tsx @@ -1,5 +1,8 @@ import { type JSXElementConstructor, useCallback, useState } from 'react' -import { Dropdown, MenuItem } from 'react-bootstrap' +import { + Dropdown as BS3Dropdown, + MenuItem as BS3MenuItem, +} from 'react-bootstrap' import { useTranslation } from 'react-i18next' import ControlledDropdown from '../../../shared/components/controlled-dropdown' import getMeta from '../../../utils/meta' @@ -10,6 +13,15 @@ import AddAffiliation, { useAddAffiliation } from './add-affiliation' import { Nullable } from '../../../../../types/utils' import { sendMB } from '../../../infrastructure/event-tracking' import importOverleafModules from '../../../../macros/import-overleaf-module.macro' +import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher' +import { + Dropdown, + DropdownDivider, + DropdownHeader, + DropdownItem, + DropdownMenu, + DropdownToggle, +} from '@/features/ui/components/bootstrap-5/dropdown-menu' type SendTrackingEvent = { dropdownMenu: string @@ -30,7 +42,6 @@ type NewProjectButtonProps = { id: string buttonText?: string className?: string - menuClassName?: string trackingKey?: string showAddAffiliationWidget?: boolean } @@ -39,7 +50,6 @@ function NewProjectButton({ id, buttonText, className, - menuClassName, trackingKey, showAddAffiliationWidget, }: NewProjectButtonProps) { @@ -88,7 +98,7 @@ function NewProjectButton({ const handleModalMenuClick = useCallback( ( - e: React.MouseEvent>, + e: React.MouseEvent, { modalVariant, dropdownMenuEvent }: ModalMenuClickOptions ) => { // avoid invoking the "onClick" callback on the main dropdown button @@ -105,10 +115,7 @@ function NewProjectButton({ ) const handlePortalTemplateClick = useCallback( - ( - e: React.MouseEvent>, - institutionTemplateName: string - ) => { + (e: React.MouseEvent, institutionTemplateName: string) => { // avoid invoking the "onClick" callback on the main dropdown button e.stopPropagation() @@ -122,10 +129,7 @@ function NewProjectButton({ ) const handleStaticTemplateClick = useCallback( - ( - e: React.MouseEvent>, - templateTrackingKey: string - ) => { + (e: React.MouseEvent, templateTrackingKey: string) => { // avoid invoking the "onClick" callback on the main dropdown button e.stopPropagation() @@ -142,113 +146,230 @@ function NewProjectButton({ ) const ImportProjectFromGithubMenu: JSXElementConstructor<{ - onClick: (e: React.MouseEvent>) => void + onClick: (e: React.MouseEvent) => void }> = importProjectFromGithubMenu?.import.default return ( <> - - - {buttonText || t('new_project')} - - - - handleModalMenuClick(e, { - modalVariant: 'blank_project', - dropdownMenuEvent: 'blank-project', - }) - } - > - {t('blank_project')} - - - handleModalMenuClick(e, { - modalVariant: 'example_project', - dropdownMenuEvent: 'example-project', - }) - } - > - {t('example_project')} - - - handleModalMenuClick(e, { - modalVariant: 'upload_project', - dropdownMenuEvent: 'upload-project', - }) - } - > - {t('upload_project')} - - {ImportProjectFromGithubMenu && ( - - handleModalMenuClick(e, { - modalVariant: 'import_from_github', - dropdownMenuEvent: 'import-from-github', - }) - } - /> - )} - {portalTemplates.length > 0 ? ( - <> - - - {`${t('institution')} ${t('templates')}`} - - {portalTemplates.map((portalTemplate, index) => ( - + + {buttonText || t('new_project')} + + + + handleModalMenuClick(e, { + modalVariant: 'blank_project', + dropdownMenuEvent: 'blank-project', + }) + } + > + {t('blank_project')} + + + handleModalMenuClick(e, { + modalVariant: 'example_project', + dropdownMenuEvent: 'example-project', + }) + } + > + {t('example_project')} + + + handleModalMenuClick(e, { + modalVariant: 'upload_project', + dropdownMenuEvent: 'upload-project', + }) + } + > + {t('upload_project')} + + {ImportProjectFromGithubMenu && ( + - handlePortalTemplateClick(e, portalTemplate.name) + handleModalMenuClick(e, { + modalVariant: 'import_from_github', + dropdownMenuEvent: 'import-from-github', + }) + } + /> + )} + {portalTemplates.length > 0 ? ( + <> + + + {portalTemplates.map((portalTemplate, index) => ( + + handlePortalTemplateClick(e, portalTemplate.name) + } + > + {portalTemplate.name} + + ))} + + ) : null} + + {templateLinks && templateLinks.length > 0 && ( + <> + + + + )} + {templateLinks?.map((templateLink, index) => ( + + handleStaticTemplateClick(e, templateLink.trackingKey) } > - {portalTemplate.name} - + {templateLink.name === 'view_all' + ? t('view_all') + : templateLink.name} + ))} - - ) : null} - - {templateLinks && templateLinks.length > 0 && ( - <> - - {t('templates')} - - )} - {templateLinks?.map((templateLink, index) => ( - - handleStaticTemplateClick(e, templateLink.trackingKey) - } + {showAddAffiliationWidget && enableAddAffiliationWidget ? ( + <> + +
  • + +
  • + + ) : null} + +
    + } + bs5={ + + - {templateLink.name === 'view_all' - ? t('view_all') - : templateLink.name} - - ))} - {showAddAffiliationWidget && enableAddAffiliationWidget ? ( - <> - -
  • - + {buttonText || t('new_project')} + + +
  • + + handleModalMenuClick(e, { + modalVariant: 'blank_project', + dropdownMenuEvent: 'blank-project', + }) + } + > + {t('blank_project')} +
  • - - ) : null} - - +
  • + + handleModalMenuClick(e, { + modalVariant: 'example_project', + dropdownMenuEvent: 'example-project', + }) + } + > + {t('example_project')} + +
  • +
  • + + handleModalMenuClick(e, { + modalVariant: 'upload_project', + dropdownMenuEvent: 'upload-project', + }) + } + > + {t('upload_project')} + +
  • +
  • + {ImportProjectFromGithubMenu && ( + + handleModalMenuClick(e, { + modalVariant: 'import_from_github', + dropdownMenuEvent: 'import-from-github', + }) + } + /> + )} +
  • + {portalTemplates.length > 0 ? ( + <> + + + {portalTemplates.map((portalTemplate, index) => ( +
  • + + handlePortalTemplateClick(e, portalTemplate.name) + } + aria-label={`${portalTemplate.name} ${t('template')}`} + > + {portalTemplate.name} + +
  • + ))} + + ) : null} + + {templateLinks && templateLinks.length > 0 && ( + <> + + + + )} + {templateLinks?.map((templateLink, index) => ( +
  • + + handleStaticTemplateClick(e, templateLink.trackingKey) + } + aria-label={`${templateLink.name} ${t('template')}`} + > + {templateLink.name === 'view_all' + ? t('view_all') + : templateLink.name} + +
  • + ))} + {showAddAffiliationWidget && enableAddAffiliationWidget ? ( + <> + +
  • + +
  • + + ) : null} + +
    + } + /> setModal(null)} /> ) diff --git a/services/web/frontend/js/features/project-list/components/new-project-button/modal-content-new-project-form.tsx b/services/web/frontend/js/features/project-list/components/new-project-button/modal-content-new-project-form.tsx index 562334847a..169258de40 100644 --- a/services/web/frontend/js/features/project-list/components/new-project-button/modal-content-new-project-form.tsx +++ b/services/web/frontend/js/features/project-list/components/new-project-button/modal-content-new-project-form.tsx @@ -101,8 +101,12 @@ function ModalContentNewProjectForm({ onCancel, template = 'none' }: Props) { variant="primary" onClick={createNewProject} disabled={projectName === '' || isLoading} + isLoading={isLoading} + bs3Props={{ + loading: isLoading ? `${t('creating')}…` : t('create'), + }} > - {isLoading ? `${t('creating')}…` : t('create')} + {t('create')} diff --git a/services/web/frontend/js/features/project-list/components/sidebar/tags-list.tsx b/services/web/frontend/js/features/project-list/components/sidebar/tags-list.tsx index 6e868a9204..bce043a7e5 100644 --- a/services/web/frontend/js/features/project-list/components/sidebar/tags-list.tsx +++ b/services/web/frontend/js/features/project-list/components/sidebar/tags-list.tsx @@ -36,8 +36,12 @@ export default function TagsList() { return ( <> -
  • -

    {t('organize_projects')}

    +