Просмотр исходного кода

Tearing down of old Editor (Left settings menu) (#31357)

* removing one class

* removing the ide redesign class

* moving error logs files from ide-redesign to orignal directory

* moving the final file of error logs

* removing the left settings menu files

* deleting left-menu-mask.tsx and related css styling

* deleting editor-left-menu-body.tsx

* deleting download-menu.tsx and related css and test and story files

* deleting actions-menu.tsx and  test and story files

* deleting help-menu.tsx and test and story files

* deleting sync-menu.tsx  and test and story files

* deleting settings-menu.tsx file

* deleting download-pdf.tsx

* deleting download-source.tsx

* deleting actions-copy-project.tsx

* deleting actions-word-count.tsx ans tests

* deleting help-contact-us.tsx

* deleting help-documentation.tsx and related files

* deleting help-show-hotkeys.tsx and related files

* deleting settings-auto-close-brackets.tsx

* deleting settings-auto-complete

* settings-compiler

* settings-dictionary

* deleting setting-menu files and test files

* styles:fix

* make cleanup_unused_locales

* removing some extra css and adding some comments

* npm run extract-translations

* adding settings-menu-select.tsx back

* adding back settings-overall-theme.tsx

* format:fix

* removing the settings-overall-theme.tsx and related test file

* deleting settings-menu-select and adding option type in use-editor-theme-option-group

* removing css

* deleting files and styling related to LeftMenuButton

* removing the related left editor menu files

* removing the paths

* Revert "removing the related left editor menu files"

This reverts commit 78ffbfff88cfd3ceb19946ac45a1ed6a790388f4.

* adding back the overall-theme-settings.tsx and removing the tests related to removed file

* adding back the tests with new component

* make cleanup_unused_locales

* extract-translations

* deleting the actions-manage-template.tsx file

GitOrigin-RevId: 75bcbef81740cea0452eca62f2ce52b7f10acd08
Davinder Singh 8 месяцев назад
Родитель
Сommit
51b5f9a862
70 измененных файлов с 12 добавлено и 3761 удалено
  1. 0 9
      services/web/frontend/extracted-translations.json
  2. 0 30
      services/web/frontend/js/features/editor-left-menu/components/actions-copy-project.tsx
  3. 0 39
      services/web/frontend/js/features/editor-left-menu/components/actions-menu.tsx
  4. 0 20
      services/web/frontend/js/features/editor-left-menu/components/actions-word-count.tsx
  5. 0 21
      services/web/frontend/js/features/editor-left-menu/components/download-menu.tsx
  6. 0 51
      services/web/frontend/js/features/editor-left-menu/components/download-pdf.tsx
  7. 0 31
      services/web/frontend/js/features/editor-left-menu/components/download-source.tsx
  8. 0 17
      services/web/frontend/js/features/editor-left-menu/components/editor-left-menu-body.tsx
  9. 0 56
      services/web/frontend/js/features/editor-left-menu/components/editor-left-menu.tsx
  10. 0 24
      services/web/frontend/js/features/editor-left-menu/components/help-contact-us.tsx
  11. 0 14
      services/web/frontend/js/features/editor-left-menu/components/help-documentation.tsx
  12. 0 31
      services/web/frontend/js/features/editor-left-menu/components/help-menu.tsx
  13. 0 32
      services/web/frontend/js/features/editor-left-menu/components/help-show-hotkeys.tsx
  14. 0 72
      services/web/frontend/js/features/editor-left-menu/components/left-menu-button.tsx
  15. 0 39
      services/web/frontend/js/features/editor-left-menu/components/left-menu-mask.tsx
  16. 0 64
      services/web/frontend/js/features/editor-left-menu/components/settings-menu.tsx
  17. 0 28
      services/web/frontend/js/features/editor-left-menu/components/settings/settings-auto-close-brackets.tsx
  18. 0 27
      services/web/frontend/js/features/editor-left-menu/components/settings/settings-auto-complete.tsx
  19. 0 45
      services/web/frontend/js/features/editor-left-menu/components/settings/settings-compiler.tsx
  20. 0 30
      services/web/frontend/js/features/editor-left-menu/components/settings/settings-dictionary.tsx
  21. 0 55
      services/web/frontend/js/features/editor-left-menu/components/settings/settings-document.tsx
  22. 0 53
      services/web/frontend/js/features/editor-left-menu/components/settings/settings-editor-theme.tsx
  23. 0 33
      services/web/frontend/js/features/editor-left-menu/components/settings/settings-font-family.tsx
  24. 0 25
      services/web/frontend/js/features/editor-left-menu/components/settings/settings-font-size.tsx
  25. 0 48
      services/web/frontend/js/features/editor-left-menu/components/settings/settings-image-name.tsx
  26. 0 32
      services/web/frontend/js/features/editor-left-menu/components/settings/settings-keybindings.tsx
  27. 0 32
      services/web/frontend/js/features/editor-left-menu/components/settings/settings-line-height.tsx
  28. 0 27
      services/web/frontend/js/features/editor-left-menu/components/settings/settings-math-preview.tsx
  29. 0 121
      services/web/frontend/js/features/editor-left-menu/components/settings/settings-menu-select.tsx
  30. 0 52
      services/web/frontend/js/features/editor-left-menu/components/settings/settings-new-editor.tsx
  31. 0 42
      services/web/frontend/js/features/editor-left-menu/components/settings/settings-overall-theme.tsx
  32. 0 29
      services/web/frontend/js/features/editor-left-menu/components/settings/settings-pdf-viewer.tsx
  33. 0 42
      services/web/frontend/js/features/editor-left-menu/components/settings/settings-spell-check-language.tsx
  34. 0 27
      services/web/frontend/js/features/editor-left-menu/components/settings/settings-syntax-validation.tsx
  35. 0 42
      services/web/frontend/js/features/editor-left-menu/components/sync-menu.tsx
  36. 9 1
      services/web/frontend/js/features/editor-left-menu/hooks/use-editor-theme-option-groups.tsx
  37. 0 44
      services/web/frontend/js/features/word-count-modal/components/word-count-button.tsx
  38. 0 57
      services/web/frontend/stories/editor-left-menu/actions-menu.stories.tsx
  39. 0 44
      services/web/frontend/stories/editor-left-menu/download-menu.stories.tsx
  40. 0 33
      services/web/frontend/stories/editor-left-menu/help-menu.stories.tsx
  41. 0 37
      services/web/frontend/stories/editor-left-menu/sync-menu.stories.tsx
  42. 0 169
      services/web/frontend/stylesheets/pages/editor/left-menu.scss
  43. 0 7
      services/web/locales/en.json
  44. 0 900
      services/web/test/frontend/components/editor-left-menu/editor-left-menu.spec.tsx
  45. 0 49
      services/web/test/frontend/components/editor-left-menu/scope.tsx
  46. 0 56
      services/web/test/frontend/features/editor-left-menu/components/actions-copy-project.test.tsx
  47. 0 86
      services/web/test/frontend/features/editor-left-menu/components/actions-menu.test.tsx
  48. 0 66
      services/web/test/frontend/features/editor-left-menu/components/actions-word-count.test.tsx
  49. 0 59
      services/web/test/frontend/features/editor-left-menu/components/download-menu.test.tsx
  50. 0 29
      services/web/test/frontend/features/editor-left-menu/components/help-contact-us.test.tsx
  51. 0 12
      services/web/test/frontend/features/editor-left-menu/components/help-documentation.test.tsx
  52. 0 39
      services/web/test/frontend/features/editor-left-menu/components/help-menu.test.tsx
  53. 0 20
      services/web/test/frontend/features/editor-left-menu/components/help-show-hotkeys.test.tsx
  54. 0 30
      services/web/test/frontend/features/editor-left-menu/components/settings/settings-auto-close-brackets.test.tsx
  55. 0 30
      services/web/test/frontend/features/editor-left-menu/components/settings/settings-auto-complete.test.tsx
  56. 0 36
      services/web/test/frontend/features/editor-left-menu/components/settings/settings-compiler.test.tsx
  57. 0 33
      services/web/test/frontend/features/editor-left-menu/components/settings/settings-dictionary.test.tsx
  58. 0 51
      services/web/test/frontend/features/editor-left-menu/components/settings/settings-document.test.tsx
  59. 0 112
      services/web/test/frontend/features/editor-left-menu/components/settings/settings-editor-theme.test.tsx
  60. 0 35
      services/web/test/frontend/features/editor-left-menu/components/settings/settings-font-family.test.tsx
  61. 0 31
      services/web/test/frontend/features/editor-left-menu/components/settings/settings-font-size.test.tsx
  62. 0 47
      services/web/test/frontend/features/editor-left-menu/components/settings/settings-image-name.test.tsx
  63. 0 33
      services/web/test/frontend/features/editor-left-menu/components/settings/settings-keybindings.test.tsx
  64. 0 33
      services/web/test/frontend/features/editor-left-menu/components/settings/settings-line-height.test.tsx
  65. 0 30
      services/web/test/frontend/features/editor-left-menu/components/settings/settings-math-preview.test.tsx
  66. 0 98
      services/web/test/frontend/features/editor-left-menu/components/settings/settings-overall-theme.test.tsx
  67. 0 30
      services/web/test/frontend/features/editor-left-menu/components/settings/settings-pdf-viewer.test.tsx
  68. 0 50
      services/web/test/frontend/features/editor-left-menu/components/settings/settings-spell-check-language.test.tsx
  69. 0 30
      services/web/test/frontend/features/editor-left-menu/components/settings/settings-syntax-validation.test.tsx
  70. 3 4
      services/web/test/frontend/features/settings-modal/settings/overall-theme-setting.test.tsx

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

@@ -648,8 +648,6 @@
   "folder_location": "",
   "folder_name": "",
   "following_paths_conflict": "",
-  "font_family": "",
-  "font_size": "",
   "footer_about_us": "",
   "footer_contact_us": "",
   "footnotes": "",
@@ -1011,7 +1009,6 @@
   "limited_to_n_collaborators_per_project": "",
   "limited_to_n_collaborators_per_project_plural": "",
   "line": "",
-  "line_height": "",
   "line_width_is_the_width_of_the_line_in_the_current_environment": "",
   "link": "",
   "link_account": "",
@@ -1152,7 +1149,6 @@
   "new_compile_domain_notice": "",
   "new_compiles_in_this_project_will_automatically_use_the_newest_version": "",
   "new_create_tables_and_equations": "",
-  "new_editor_look": "",
   "new_error_logs_make_it_easier_to_find_whats_wrong": "",
   "new_file": "",
   "new_folder": "",
@@ -1326,7 +1322,6 @@
   "please_ask_the_project_owner_to_upgrade_to_track_changes": "",
   "please_change_primary_to_remove": "",
   "please_compile_pdf_before_download": "",
-  "please_compile_pdf_before_word_count": "",
   "please_confirm_primary_email_or_edit": "",
   "please_confirm_secondary_email_or_edit": "",
   "please_confirm_your_email_before_making_it_default": "",
@@ -1678,7 +1673,6 @@
   "show_document_preamble": "",
   "show_equation_preview": "",
   "show_file_tree": "",
-  "show_hotkeys": "",
   "show_in_code": "",
   "show_in_pdf": "",
   "show_less": "",
@@ -1723,10 +1717,8 @@
   "sort_by": "",
   "sort_by_x": "",
   "sort_projects": "",
-  "source": "",
   "speak": "",
   "speech_input_not_available": "",
-  "spell_check": "",
   "spellcheck": "",
   "spellcheck_language": "",
   "split_view": "",
@@ -2243,7 +2235,6 @@
   "wide": "",
   "will_lose_edit_access_on_date": "",
   "with_premium_subscription_you_also_get": "",
-  "word_count": "",
   "word_count_lower": "",
   "words": "",
   "work_in_vim_or_emacs_emulation_mode": "",

+ 0 - 30
services/web/frontend/js/features/editor-left-menu/components/actions-copy-project.tsx

@@ -1,30 +0,0 @@
-import { useCallback, useState } from 'react'
-import { useTranslation } from 'react-i18next'
-import EditorCloneProjectModalWrapper from '../../clone-project-modal/components/editor-clone-project-modal-wrapper'
-import LeftMenuButton from './left-menu-button'
-import * as eventTracking from '../../../infrastructure/event-tracking'
-import useOpenProject from '@/shared/hooks/use-open-project'
-
-export default function ActionsCopyProject() {
-  const [showModal, setShowModal] = useState(false)
-  const { t } = useTranslation()
-  const openProject = useOpenProject()
-
-  const handleShowModal = useCallback(() => {
-    eventTracking.sendMB('left-menu-copy')
-    setShowModal(true)
-  }, [])
-
-  return (
-    <>
-      <LeftMenuButton onClick={handleShowModal} icon="file_copy">
-        {t('copy_project')}
-      </LeftMenuButton>
-      <EditorCloneProjectModalWrapper
-        show={showModal}
-        handleHide={() => setShowModal(false)}
-        openProject={openProject}
-      />
-    </>
-  )
-}

+ 0 - 39
services/web/frontend/js/features/editor-left-menu/components/actions-menu.tsx

@@ -1,39 +0,0 @@
-import { ElementType } from 'react'
-import { useTranslation } from 'react-i18next'
-import getMeta from '../../../utils/meta'
-import importOverleafModules from '../../../../macros/import-overleaf-module.macro'
-import ActionsCopyProject from './actions-copy-project'
-import ActionsWordCount from './actions-word-count'
-
-const components = importOverleafModules('editorLeftMenuManageTemplate') as {
-  import: { default: ElementType }
-  path: string
-}[]
-
-export default function ActionsMenu() {
-  const { t } = useTranslation()
-  const anonymous = getMeta('ol-anonymous')
-
-  if (anonymous) {
-    return null
-  }
-
-  return (
-    <>
-      <h4>{t('actions')}</h4>
-      <ul className="list-unstyled nav">
-        <li>
-          <ActionsCopyProject />
-        </li>
-        {components.map(({ import: { default: Component }, path }) => (
-          <li key={path}>
-            <Component />
-          </li>
-        ))}
-        <li>
-          <ActionsWordCount />
-        </li>
-      </ul>
-    </>
-  )
-}

+ 0 - 20
services/web/frontend/js/features/editor-left-menu/components/actions-word-count.tsx

@@ -1,20 +0,0 @@
-import { useState, useCallback } from 'react'
-import WordCountModal from '../../word-count-modal/components/word-count-modal'
-import * as eventTracking from '../../../infrastructure/event-tracking'
-import { WordCountButton } from '@/features/word-count-modal/components/word-count-button'
-
-export default function ActionsWordCount() {
-  const [showModal, setShowModal] = useState(false)
-
-  const handleShowModal = useCallback(() => {
-    eventTracking.sendMB('left-menu-count')
-    setShowModal(true)
-  }, [])
-
-  return (
-    <>
-      <WordCountButton handleShowModal={handleShowModal} />
-      <WordCountModal show={showModal} handleHide={() => setShowModal(false)} />
-    </>
-  )
-}

+ 0 - 21
services/web/frontend/js/features/editor-left-menu/components/download-menu.tsx

@@ -1,21 +0,0 @@
-import { useTranslation } from 'react-i18next'
-import DownloadPDF from './download-pdf'
-import DownloadSource from './download-source'
-
-export default function DownloadMenu() {
-  const { t } = useTranslation()
-
-  return (
-    <>
-      <h4 className="mt-0">{t('download')}</h4>
-      <ul className="list-unstyled nav nav-downloads text-center">
-        <li>
-          <DownloadSource />
-        </li>
-        <li>
-          <DownloadPDF />
-        </li>
-      </ul>
-    </>
-  )
-}

+ 0 - 51
services/web/frontend/js/features/editor-left-menu/components/download-pdf.tsx

@@ -1,51 +0,0 @@
-import { useTranslation } from 'react-i18next'
-import { useDetachCompileContext as useCompileContext } from '../../../shared/context/detach-compile-context'
-import { useProjectContext } from '../../../shared/context/project-context'
-import { isSmallDevice } from '../../../infrastructure/event-tracking'
-import MaterialIcon from '@/shared/components/material-icon'
-import OLTooltip from '@/shared/components/ol/ol-tooltip'
-import { useEditorAnalytics } from '@/shared/hooks/use-editor-analytics'
-
-export default function DownloadPDF() {
-  const { t } = useTranslation()
-  const { pdfDownloadUrl, pdfUrl } = useCompileContext()
-  const { projectId } = useProjectContext()
-  const { sendEvent } = useEditorAnalytics()
-
-  function sendDownloadEvent() {
-    sendEvent('download-pdf-button-click', {
-      projectId,
-      location: 'left-menu',
-      isSmallDevice,
-    })
-  }
-
-  if (pdfUrl) {
-    return (
-      <a
-        href={pdfDownloadUrl || pdfUrl}
-        target="_blank"
-        rel="noreferrer"
-        onClick={sendDownloadEvent}
-      >
-        <MaterialIcon type="picture_as_pdf" size="2x" />
-        <br />
-        PDF
-      </a>
-    )
-  } else {
-    return (
-      <OLTooltip
-        id="disabled-pdf-download"
-        description={t('please_compile_pdf_before_download')}
-        overlayProps={{ placement: 'bottom' }}
-      >
-        <div className="link-disabled">
-          <MaterialIcon type="picture_as_pdf" size="2x" />
-          <br />
-          PDF
-        </div>
-      </OLTooltip>
-    )
-  }
-}

+ 0 - 31
services/web/frontend/js/features/editor-left-menu/components/download-source.tsx

@@ -1,31 +0,0 @@
-import { useTranslation } from 'react-i18next'
-import { useProjectContext } from '../../../shared/context/project-context'
-import * as eventTracking from '../../../infrastructure/event-tracking'
-import { isSmallDevice } from '../../../infrastructure/event-tracking'
-import MaterialIcon from '@/shared/components/material-icon'
-
-export default function DownloadSource() {
-  const { t } = useTranslation()
-  const { projectId } = useProjectContext()
-
-  function sendDownloadEvent() {
-    eventTracking.sendMB('download-zip-button-click', {
-      projectId,
-      location: 'left-menu',
-      isSmallDevice,
-    })
-  }
-
-  return (
-    <a
-      href={`/project/${projectId}/download/zip`}
-      target="_blank"
-      rel="noreferrer"
-      onClick={sendDownloadEvent}
-    >
-      <MaterialIcon type="folder_zip" size="2x" />
-      <br />
-      {t('source')}
-    </a>
-  )
-}

+ 0 - 17
services/web/frontend/js/features/editor-left-menu/components/editor-left-menu-body.tsx

@@ -1,17 +0,0 @@
-import DownloadMenu from './download-menu'
-import ActionsMenu from './actions-menu'
-import HelpMenu from './help-menu'
-import SyncMenu from './sync-menu'
-import SettingsMenu from './settings-menu'
-
-export default function EditorLeftMenuBody() {
-  return (
-    <>
-      <DownloadMenu />
-      <ActionsMenu />
-      <SyncMenu />
-      <SettingsMenu />
-      <HelpMenu />
-    </>
-  )
-}

+ 0 - 56
services/web/frontend/js/features/editor-left-menu/components/editor-left-menu.tsx

@@ -1,56 +0,0 @@
-import { useLayoutContext } from '../../../shared/context/layout-context'
-import LeftMenuMask from './left-menu-mask'
-import classNames from 'classnames'
-import { lazy, memo, Suspense } from 'react'
-import { FullSizeLoadingSpinner } from '@/shared/components/loading-spinner'
-import { Offcanvas } from 'react-bootstrap'
-import { EditorLeftMenuProvider } from './editor-left-menu-context'
-import withErrorBoundary from '@/infrastructure/error-boundary'
-import OLNotification from '@/shared/components/ol/ol-notification'
-import { useTranslation } from 'react-i18next'
-
-const EditorLeftMenuBody = lazy(() => import('./editor-left-menu-body'))
-
-const LazyEditorLeftMenuWithErrorBoundary = withErrorBoundary(
-  () => (
-    <Suspense fallback={<FullSizeLoadingSpinner delay={500} />}>
-      <EditorLeftMenuBody />
-    </Suspense>
-  ),
-  () => {
-    const { t } = useTranslation()
-    return <OLNotification type="error" content={t('something_went_wrong')} />
-  }
-)
-
-function EditorLeftMenu() {
-  const { leftMenuShown, setLeftMenuShown } = useLayoutContext()
-
-  const closeLeftMenu = () => {
-    setLeftMenuShown(false)
-  }
-
-  return (
-    <EditorLeftMenuProvider>
-      <Offcanvas
-        show={leftMenuShown}
-        onHide={closeLeftMenu}
-        backdropClassName="left-menu-modal-backdrop"
-        id="left-menu-offcanvas"
-      >
-        <Offcanvas.Body
-          className={classNames('full-size', 'left-menu', {
-            shown: leftMenuShown,
-          })}
-          id="left-menu"
-          data-testid="left-menu"
-        >
-          <LazyEditorLeftMenuWithErrorBoundary />
-        </Offcanvas.Body>
-      </Offcanvas>
-      {leftMenuShown && <LeftMenuMask />}
-    </EditorLeftMenuProvider>
-  )
-}
-
-export default memo(EditorLeftMenu)

+ 0 - 24
services/web/frontend/js/features/editor-left-menu/components/help-contact-us.tsx

@@ -1,24 +0,0 @@
-import { useTranslation } from 'react-i18next'
-import { useCallback } from 'react'
-import * as eventTracking from '../../../infrastructure/event-tracking'
-import { useContactUsModal } from '../../../shared/hooks/use-contact-us-modal'
-import LeftMenuButton from './left-menu-button'
-
-export default function HelpContactUs() {
-  const { modal, showModal } = useContactUsModal()
-  const { t } = useTranslation()
-
-  const showModalWithAnalytics = useCallback(() => {
-    eventTracking.sendMB('left-menu-contact')
-    showModal()
-  }, [showModal])
-
-  return (
-    <>
-      <LeftMenuButton onClick={showModalWithAnalytics} icon="contact_support">
-        {t('contact_us')}
-      </LeftMenuButton>
-      {modal}
-    </>
-  )
-}

+ 0 - 14
services/web/frontend/js/features/editor-left-menu/components/help-documentation.tsx

@@ -1,14 +0,0 @@
-import { useTranslation } from 'react-i18next'
-import LeftMenuButton from './left-menu-button'
-
-export default function HelpDocumentation() {
-  const { t } = useTranslation()
-
-  return (
-    <>
-      <LeftMenuButton type="link" href="/learn" icon="book_4">
-        {t('documentation')}
-      </LeftMenuButton>
-    </>
-  )
-}

+ 0 - 31
services/web/frontend/js/features/editor-left-menu/components/help-menu.tsx

@@ -1,31 +0,0 @@
-import { useTranslation } from 'react-i18next'
-import getMeta from '../../../utils/meta'
-import HelpContactUs from './help-contact-us'
-import HelpDocumentation from './help-documentation'
-import HelpShowHotkeys from './help-show-hotkeys'
-
-export default function HelpMenu() {
-  const { t } = useTranslation()
-  const showSupport = getMeta('ol-showSupport')
-
-  return (
-    <>
-      <h4>{t('help')}</h4>
-      <ul className="list-unstyled nav">
-        <li>
-          <HelpShowHotkeys />
-        </li>
-        {showSupport ? (
-          <>
-            <li>
-              <HelpDocumentation />
-            </li>
-            <li>
-              <HelpContactUs />
-            </li>
-          </>
-        ) : null}
-      </ul>
-    </>
-  )
-}

+ 0 - 32
services/web/frontend/js/features/editor-left-menu/components/help-show-hotkeys.tsx

@@ -1,32 +0,0 @@
-import { useState, useCallback } from 'react'
-import { useTranslation } from 'react-i18next'
-import * as eventTracking from '../../../infrastructure/event-tracking'
-import { useProjectContext } from '../../../shared/context/project-context'
-import HotkeysModal from '../../hotkeys-modal/components/hotkeys-modal'
-import LeftMenuButton from './left-menu-button'
-import { isMac } from '@/shared/utils/os'
-
-export default function HelpShowHotkeys() {
-  const [showModal, setShowModal] = useState(false)
-  const { t } = useTranslation()
-  const { features } = useProjectContext()
-
-  const showModalWithAnalytics = useCallback(() => {
-    eventTracking.sendMB('left-menu-hotkeys')
-    setShowModal(true)
-  }, [])
-
-  return (
-    <>
-      <LeftMenuButton onClick={showModalWithAnalytics} icon="keyboard">
-        {t('show_hotkeys')}
-      </LeftMenuButton>
-      <HotkeysModal
-        show={showModal}
-        handleHide={() => setShowModal(false)}
-        isMac={isMac}
-        trackChangesVisible={features?.trackChangesVisible}
-      />
-    </>
-  )
-}

+ 0 - 72
services/web/frontend/js/features/editor-left-menu/components/left-menu-button.tsx

@@ -1,72 +0,0 @@
-import { PropsWithChildren } from 'react'
-import MaterialIcon from '@/shared/components/material-icon'
-
-type Props = {
-  onClick?: () => void
-  icon?: string
-  svgIcon?: React.ReactElement | null
-  disabled?: boolean
-  disabledAccesibilityText?: string
-  type?: 'button' | 'link'
-  href?: string
-  translate?: React.HTMLAttributes<HTMLElement>['translate']
-}
-
-function LeftMenuButtonIcon({
-  svgIcon,
-  icon,
-}: {
-  svgIcon?: React.ReactElement | null
-  icon?: string
-}) {
-  if (svgIcon) {
-    return <div className="material-symbols">{svgIcon}</div>
-  } else if (icon) {
-    return <MaterialIcon type={icon} />
-  } else return null
-}
-
-export default function LeftMenuButton({
-  children,
-  svgIcon,
-  onClick,
-  icon,
-  disabled = false,
-  disabledAccesibilityText,
-  type = 'button',
-  href,
-  translate,
-}: PropsWithChildren<Props>) {
-  if (disabled) {
-    return (
-      <div className="left-menu-button link-disabled">
-        <LeftMenuButtonIcon svgIcon={svgIcon} icon={icon} />
-        <span translate={translate}>{children}</span>
-        {disabledAccesibilityText ? (
-          <span className="visually-hidden">{disabledAccesibilityText}</span>
-        ) : null}
-      </div>
-    )
-  }
-
-  if (type === 'button') {
-    return (
-      <button onClick={onClick} className="left-menu-button">
-        <LeftMenuButtonIcon svgIcon={svgIcon} icon={icon} />
-        <span translate={translate}>{children}</span>
-      </button>
-    )
-  } else {
-    return (
-      <a
-        href={href}
-        target="_blank"
-        rel="noreferrer"
-        className="left-menu-button"
-      >
-        <LeftMenuButtonIcon svgIcon={svgIcon} icon={icon} />
-        <span translate={translate}>{children}</span>
-      </a>
-    )
-  }
-}

+ 0 - 39
services/web/frontend/js/features/editor-left-menu/components/left-menu-mask.tsx

@@ -1,39 +0,0 @@
-import { memo, useEffect, useRef, useState } from 'react'
-import { useLayoutContext } from '../../../shared/context/layout-context'
-import { useUserSettingsContext } from '@/shared/context/user-settings-context'
-
-export default memo(function LeftMenuMask() {
-  const { setLeftMenuShown } = useLayoutContext()
-  const { userSettings } = useUserSettingsContext()
-  const { editorTheme, editorLightTheme, editorDarkTheme, overallTheme } =
-    userSettings
-  const [original] = useState({
-    editorTheme,
-    overallTheme,
-    editorLightTheme,
-    editorDarkTheme,
-  })
-  const maskRef = useRef<HTMLDivElement | null>(null)
-
-  useEffect(() => {
-    if (maskRef.current) {
-      if (
-        editorTheme !== original.editorTheme ||
-        editorLightTheme !== original.editorLightTheme ||
-        editorDarkTheme !== original.editorDarkTheme ||
-        overallTheme !== original.overallTheme
-      ) {
-        maskRef.current.style.opacity = '0'
-      }
-    }
-  }, [editorTheme, editorLightTheme, editorDarkTheme, overallTheme, original])
-
-  return (
-    // eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions
-    <div
-      id="left-menu-mask"
-      ref={maskRef}
-      onClick={() => setLeftMenuShown(false)}
-    />
-  )
-})

+ 0 - 64
services/web/frontend/js/features/editor-left-menu/components/settings-menu.tsx

@@ -1,64 +0,0 @@
-import { useTranslation } from 'react-i18next'
-import getMeta from '../../../utils/meta'
-import SettingsAutoCloseBrackets from './settings/settings-auto-close-brackets'
-import SettingsAutoComplete from './settings/settings-auto-complete'
-import SettingsCompiler from './settings/settings-compiler'
-import SettingsDictionary from './settings/settings-dictionary'
-import SettingsDocument from './settings/settings-document'
-import SettingsEditorTheme from './settings/settings-editor-theme'
-import SettingsFontFamily from './settings/settings-font-family'
-import SettingsFontSize from './settings/settings-font-size'
-import SettingsImageName from './settings/settings-image-name'
-import SettingsKeybindings from './settings/settings-keybindings'
-import SettingsLineHeight from './settings/settings-line-height'
-import SettingsOverallTheme from './settings/settings-overall-theme'
-import SettingsPdfViewer from './settings/settings-pdf-viewer'
-import SettingsSpellCheckLanguage from './settings/settings-spell-check-language'
-import SettingsSyntaxValidation from './settings/settings-syntax-validation'
-import SettingsMathPreview from './settings/settings-math-preview'
-import importOverleafModules from '../../../../macros/import-overleaf-module.macro'
-import { ElementType } from 'react'
-import OLForm from '@/shared/components/ol/ol-form'
-import SettingsNewEditor from './settings/settings-new-editor'
-
-const moduleSettings: Array<{
-  import: { default: ElementType }
-  path: string
-}> = importOverleafModules('settingsEntries')
-
-export default function SettingsMenu() {
-  const { t } = useTranslation()
-  const anonymous = getMeta('ol-anonymous')
-
-  if (anonymous) {
-    return null
-  }
-
-  return (
-    <>
-      <h4>{t('settings')}</h4>
-      <OLForm id="left-menu-setting" className="settings">
-        <SettingsCompiler />
-        <SettingsImageName />
-        <SettingsDocument />
-        <SettingsSpellCheckLanguage />
-        <SettingsDictionary />
-        {moduleSettings.map(({ import: { default: Component }, path }) => (
-          <Component key={path} />
-        ))}
-        <SettingsAutoComplete />
-        <SettingsAutoCloseBrackets />
-        <SettingsSyntaxValidation />
-        <SettingsMathPreview />
-        <SettingsOverallTheme />
-        <SettingsEditorTheme />
-        <SettingsKeybindings />
-        <SettingsFontSize />
-        <SettingsFontFamily />
-        <SettingsLineHeight />
-        <SettingsPdfViewer />
-        <SettingsNewEditor />
-      </OLForm>
-    </>
-  )
-}

+ 0 - 28
services/web/frontend/js/features/editor-left-menu/components/settings/settings-auto-close-brackets.tsx

@@ -1,28 +0,0 @@
-import { useTranslation } from 'react-i18next'
-import { useProjectSettingsContext } from '../../context/project-settings-context'
-import SettingsMenuSelect from './settings-menu-select'
-
-export default function SettingsAutoCloseBrackets() {
-  const { t } = useTranslation()
-  const { autoPairDelimiters, setAutoPairDelimiters } =
-    useProjectSettingsContext()
-
-  return (
-    <SettingsMenuSelect
-      onChange={setAutoPairDelimiters}
-      value={autoPairDelimiters}
-      options={[
-        {
-          value: true,
-          label: t('on'),
-        },
-        {
-          value: false,
-          label: t('off'),
-        },
-      ]}
-      label={t('auto_close_brackets')}
-      name="autoPairDelimiters"
-    />
-  )
-}

+ 0 - 27
services/web/frontend/js/features/editor-left-menu/components/settings/settings-auto-complete.tsx

@@ -1,27 +0,0 @@
-import { useTranslation } from 'react-i18next'
-import { useProjectSettingsContext } from '../../context/project-settings-context'
-import SettingsMenuSelect from './settings-menu-select'
-
-export default function SettingsAutoComplete() {
-  const { t } = useTranslation()
-  const { autoComplete, setAutoComplete } = useProjectSettingsContext()
-
-  return (
-    <SettingsMenuSelect
-      onChange={setAutoComplete}
-      value={autoComplete}
-      options={[
-        {
-          value: true,
-          label: t('on'),
-        },
-        {
-          value: false,
-          label: t('off'),
-        },
-      ]}
-      label={t('auto_complete')}
-      name="autoComplete"
-    />
-  )
-}

+ 0 - 45
services/web/frontend/js/features/editor-left-menu/components/settings/settings-compiler.tsx

@@ -1,45 +0,0 @@
-import { useTranslation } from 'react-i18next'
-import type { ProjectCompiler } from '../../../../../../types/project-settings'
-import { usePermissionsContext } from '@/features/ide-react/context/permissions-context'
-import { useProjectSettingsContext } from '../../context/project-settings-context'
-import SettingsMenuSelect from './settings-menu-select'
-import { useSetCompilationSettingWithEvent } from '../../hooks/use-set-compilation-setting'
-
-export default function SettingsCompiler() {
-  const { t } = useTranslation()
-  const { write } = usePermissionsContext()
-  const { compiler, setCompiler } = useProjectSettingsContext()
-  const changeCompiler = useSetCompilationSettingWithEvent(
-    'compiler',
-    setCompiler
-  )
-
-  return (
-    <SettingsMenuSelect<ProjectCompiler>
-      onChange={changeCompiler}
-      value={compiler}
-      disabled={!write}
-      options={[
-        {
-          value: 'pdflatex',
-          label: 'pdfLaTeX',
-        },
-        {
-          value: 'latex',
-          label: 'LaTeX',
-        },
-        {
-          value: 'xelatex',
-          label: 'XeLaTeX',
-        },
-        {
-          value: 'lualatex',
-          label: 'LuaLaTeX',
-        },
-      ]}
-      label={t('compiler')}
-      name="compiler"
-      translateOptions="no"
-    />
-  )
-}

+ 0 - 30
services/web/frontend/js/features/editor-left-menu/components/settings/settings-dictionary.tsx

@@ -1,30 +0,0 @@
-import { useState } from 'react'
-import { useTranslation } from 'react-i18next'
-import DictionaryModal from '../../../dictionary/components/dictionary-modal'
-import OLButton from '@/shared/components/ol/ol-button'
-import OLFormGroup from '@/shared/components/ol/ol-form-group'
-import OLFormLabel from '@/shared/components/ol/ol-form-label'
-
-export default function SettingsDictionary() {
-  const { t } = useTranslation()
-  const [showModal, setShowModal] = useState(false)
-
-  return (
-    <OLFormGroup className="left-menu-setting">
-      <OLFormLabel htmlFor="dictionary-settings">{t('dictionary')}</OLFormLabel>
-      <OLButton
-        id="dictionary-settings"
-        variant="secondary"
-        size="sm"
-        onClick={() => setShowModal(true)}
-      >
-        {t('edit')}
-      </OLButton>
-
-      <DictionaryModal
-        show={showModal}
-        handleHide={() => setShowModal(false)}
-      />
-    </OLFormGroup>
-  )
-}

+ 0 - 55
services/web/frontend/js/features/editor-left-menu/components/settings/settings-document.tsx

@@ -1,55 +0,0 @@
-import { useMemo } from 'react'
-import { useTranslation } from 'react-i18next'
-import { isValidTeXFile } from '../../../../main/is-valid-tex-file'
-import { usePermissionsContext } from '@/features/ide-react/context/permissions-context'
-import { useProjectSettingsContext } from '../../context/project-settings-context'
-import SettingsMenuSelect from './settings-menu-select'
-import type { Option } from './settings-menu-select'
-import { useFileTreeData } from '@/shared/context/file-tree-data-context'
-import { useSetCompilationSettingWithEvent } from '../../hooks/use-set-compilation-setting'
-
-export default function SettingsDocument() {
-  const { t } = useTranslation()
-  const { write } = usePermissionsContext()
-  const { docs } = useFileTreeData()
-  const { rootDocId, setRootDocId } = useProjectSettingsContext()
-  const changeRootDoc = useSetCompilationSettingWithEvent(
-    'root-doc-id',
-    setRootDocId,
-    { omitValueInEvent: true }
-  )
-
-  const validDocsOptions = useMemo(() => {
-    const filteredDocs =
-      docs?.filter(
-        doc => isValidTeXFile(doc.doc.name) || rootDocId === doc.doc.id
-      ) ?? []
-
-    const mappedDocs: Array<Option> = filteredDocs.map(doc => ({
-      value: doc.doc.id,
-      label: doc.path,
-    }))
-
-    if (!rootDocId) {
-      mappedDocs.unshift({
-        value: '',
-        label: 'None',
-        disabled: true,
-      })
-    }
-
-    return mappedDocs
-  }, [docs, rootDocId])
-
-  return (
-    <SettingsMenuSelect
-      onChange={changeRootDoc}
-      value={rootDocId ?? ''}
-      disabled={!write}
-      options={validDocsOptions}
-      label={t('main_document')}
-      name="rootDocId"
-      translateOptions="no"
-    />
-  )
-}

+ 0 - 53
services/web/frontend/js/features/editor-left-menu/components/settings/settings-editor-theme.tsx

@@ -1,53 +0,0 @@
-import { useTranslation } from 'react-i18next'
-import { useProjectSettingsContext } from '../../context/project-settings-context'
-import SettingsMenuSelect from './settings-menu-select'
-import { useEditorThemesOptionGroups } from '../../hooks/use-editor-theme-option-groups'
-import { isIEEEBranded } from '@/utils/is-ieee-branded'
-
-export default function SettingsEditorTheme() {
-  const { t } = useTranslation()
-  const optGroups = useEditorThemesOptionGroups()
-  const {
-    editorTheme,
-    setEditorTheme,
-    editorLightTheme,
-    editorDarkTheme,
-    setEditorLightTheme,
-    setEditorDarkTheme,
-    overallTheme,
-  } = useProjectSettingsContext()
-
-  if (overallTheme === 'system' && !isIEEEBranded()) {
-    return (
-      <>
-        <SettingsMenuSelect
-          onChange={setEditorLightTheme}
-          value={editorLightTheme}
-          optgroups={optGroups}
-          label={t('editor_theme_light')}
-          name="editorLightTheme"
-          translateOptions="no"
-        />
-        <SettingsMenuSelect
-          onChange={setEditorDarkTheme}
-          value={editorDarkTheme}
-          optgroups={optGroups}
-          label={t('editor_theme_dark')}
-          name="editorDarkTheme"
-          translateOptions="no"
-        />
-      </>
-    )
-  }
-
-  return (
-    <SettingsMenuSelect
-      onChange={setEditorTheme}
-      value={editorTheme}
-      optgroups={optGroups}
-      label={t('editor_theme')}
-      name="editorTheme"
-      translateOptions="no"
-    />
-  )
-}

+ 0 - 33
services/web/frontend/js/features/editor-left-menu/components/settings/settings-font-family.tsx

@@ -1,33 +0,0 @@
-import { useTranslation } from 'react-i18next'
-import { useProjectSettingsContext } from '../../context/project-settings-context'
-import SettingsMenuSelect from './settings-menu-select'
-import { FontFamily } from '@/shared/utils/styles'
-
-export default function SettingsFontFamily() {
-  const { t } = useTranslation()
-  const { fontFamily, setFontFamily } = useProjectSettingsContext()
-
-  return (
-    <SettingsMenuSelect<FontFamily>
-      onChange={setFontFamily}
-      value={fontFamily}
-      options={[
-        {
-          value: 'monaco',
-          label: 'Monaco / Menlo / Consolas',
-        },
-        {
-          value: 'lucida',
-          label: 'Lucida / Source Code Pro',
-        },
-        {
-          value: 'opendyslexicmono',
-          label: 'OpenDyslexic Mono',
-        },
-      ]}
-      label={t('font_family')}
-      name="fontFamily"
-      translateOptions="no"
-    />
-  )
-}

+ 0 - 25
services/web/frontend/js/features/editor-left-menu/components/settings/settings-font-size.tsx

@@ -1,25 +0,0 @@
-import { useTranslation } from 'react-i18next'
-import { useProjectSettingsContext } from '../../context/project-settings-context'
-import SettingsMenuSelect from './settings-menu-select'
-import type { Option } from './settings-menu-select'
-
-const sizes = [10, 11, 12, 13, 14, 16, 18, 20, 22, 24]
-const options: Option<number>[] = sizes.map(size => ({
-  value: size,
-  label: `${size}px`,
-}))
-
-export default function SettingsFontSize() {
-  const { t } = useTranslation()
-  const { fontSize, setFontSize } = useProjectSettingsContext()
-
-  return (
-    <SettingsMenuSelect
-      onChange={setFontSize}
-      value={fontSize}
-      options={options}
-      label={t('font_size')}
-      name="fontSize"
-    />
-  )
-}

+ 0 - 48
services/web/frontend/js/features/editor-left-menu/components/settings/settings-image-name.tsx

@@ -1,48 +0,0 @@
-import { useMemo } from 'react'
-import { useTranslation } from 'react-i18next'
-import getMeta from '../../../../utils/meta'
-import SettingsMenuSelect from './settings-menu-select'
-import type { Option } from './settings-menu-select'
-import { useProjectSettingsContext } from '../../context/project-settings-context'
-import { usePermissionsContext } from '@/features/ide-react/context/permissions-context'
-import { useSetCompilationSettingWithEvent } from '../../hooks/use-set-compilation-setting'
-
-export default function SettingsImageName() {
-  const { t } = useTranslation()
-  const { imageName, setImageName } = useProjectSettingsContext()
-  const { write } = usePermissionsContext()
-  const changeImageName = useSetCompilationSettingWithEvent(
-    'image-name',
-    setImageName
-  )
-
-  const allowedImageNames = useMemo(() => getMeta('ol-imageNames') || [], [])
-
-  const options: Array<Option> = useMemo(
-    () =>
-      allowedImageNames
-        // filter out images that aren't allowed, unless thats the current image the project is on
-        .filter(image => image.allowed || image.imageName === imageName)
-        .map(({ imageName, imageDesc }) => ({
-          value: imageName,
-          label: imageDesc,
-        })),
-    [allowedImageNames, imageName]
-  )
-
-  if (allowedImageNames.length === 0) {
-    return null
-  }
-
-  return (
-    <SettingsMenuSelect
-      onChange={changeImageName}
-      value={imageName}
-      disabled={!write}
-      options={options}
-      label={t('tex_live_version')}
-      name="imageName"
-      translateOptions="no"
-    />
-  )
-}

+ 0 - 32
services/web/frontend/js/features/editor-left-menu/components/settings/settings-keybindings.tsx

@@ -1,32 +0,0 @@
-import { useTranslation } from 'react-i18next'
-import type { Keybindings } from '../../../../../../types/user-settings'
-import { useProjectSettingsContext } from '../../context/project-settings-context'
-import SettingsMenuSelect from './settings-menu-select'
-
-export default function SettingsKeybindings() {
-  const { t } = useTranslation()
-  const { mode, setMode } = useProjectSettingsContext()
-
-  return (
-    <SettingsMenuSelect<Keybindings>
-      onChange={setMode}
-      value={mode}
-      options={[
-        {
-          value: 'default',
-          label: 'None',
-        },
-        {
-          value: 'vim',
-          label: 'Vim',
-        },
-        {
-          value: 'emacs',
-          label: 'Emacs',
-        },
-      ]}
-      label={t('keybindings')}
-      name="mode"
-    />
-  )
-}

+ 0 - 32
services/web/frontend/js/features/editor-left-menu/components/settings/settings-line-height.tsx

@@ -1,32 +0,0 @@
-import { useTranslation } from 'react-i18next'
-import { useProjectSettingsContext } from '../../context/project-settings-context'
-import SettingsMenuSelect from './settings-menu-select'
-import { LineHeight } from '@/shared/utils/styles'
-
-export default function SettingsLineHeight() {
-  const { t } = useTranslation()
-  const { lineHeight, setLineHeight } = useProjectSettingsContext()
-
-  return (
-    <SettingsMenuSelect<LineHeight>
-      onChange={setLineHeight}
-      value={lineHeight}
-      options={[
-        {
-          value: 'compact',
-          label: t('compact'),
-        },
-        {
-          value: 'normal',
-          label: t('normal'),
-        },
-        {
-          value: 'wide',
-          label: t('wide'),
-        },
-      ]}
-      label={t('line_height')}
-      name="lineHeight"
-    />
-  )
-}

+ 0 - 27
services/web/frontend/js/features/editor-left-menu/components/settings/settings-math-preview.tsx

@@ -1,27 +0,0 @@
-import { useTranslation } from 'react-i18next'
-import { useProjectSettingsContext } from '../../context/project-settings-context'
-import SettingsMenuSelect from './settings-menu-select'
-
-export default function SettingsMathPreview() {
-  const { t } = useTranslation()
-  const { mathPreview, setMathPreview } = useProjectSettingsContext()
-
-  return (
-    <SettingsMenuSelect
-      onChange={setMathPreview}
-      value={mathPreview}
-      options={[
-        {
-          value: true,
-          label: t('on'),
-        },
-        {
-          value: false,
-          label: t('off'),
-        },
-      ]}
-      label={t('equation_preview')}
-      name="mathPreview"
-    />
-  )
-}

+ 0 - 121
services/web/frontend/js/features/editor-left-menu/components/settings/settings-menu-select.tsx

@@ -1,121 +0,0 @@
-import OLFormGroup from '@/shared/components/ol/ol-form-group'
-import OLFormLabel from '@/shared/components/ol/ol-form-label'
-import OLFormSelect from '@/shared/components/ol/ol-form-select'
-import { ChangeEventHandler, useCallback, useEffect, useRef } from 'react'
-import { useEditorLeftMenuContext } from '@/features/editor-left-menu/components/editor-left-menu-context'
-import OLSpinner from '@/shared/components/ol/ol-spinner'
-
-type PossibleValue = string | number | boolean
-
-export type Option<T extends PossibleValue = string> = {
-  value: T
-  label: string
-  ariaHidden?: 'true' | 'false'
-  disabled?: boolean
-}
-
-export type Optgroup<T extends PossibleValue = string> = {
-  label: string
-  options: Array<Option<T>>
-}
-
-type SettingsMenuSelectProps<T extends PossibleValue = string> = {
-  label: string
-  name: string
-  options?: Array<Option<T>>
-  optgroups?: Array<Optgroup<T>>
-  loading?: boolean
-  onChange: (val: T) => void
-  value?: T
-  disabled?: boolean
-  translateOptions?: 'yes' | 'no'
-}
-
-export default function SettingsMenuSelect<T extends PossibleValue = string>({
-  label,
-  name,
-  options,
-  optgroups,
-  loading,
-  onChange,
-  value,
-  disabled = false,
-  translateOptions,
-}: SettingsMenuSelectProps<T>) {
-  const handleChange: ChangeEventHandler<HTMLSelectElement> = useCallback(
-    event => {
-      const selectedValue = event.target.value
-      let onChangeValue: PossibleValue = selectedValue
-      if (typeof value === 'boolean') {
-        onChangeValue = selectedValue === 'true'
-      } else if (typeof value === 'number') {
-        onChangeValue = parseInt(selectedValue, 10)
-      }
-      onChange(onChangeValue as T)
-    },
-    [onChange, value]
-  )
-
-  const { settingToFocus } = useEditorLeftMenuContext()
-
-  const selectRef = useRef<HTMLSelectElement | null>(null)
-
-  useEffect(() => {
-    if (settingToFocus === name && selectRef.current) {
-      selectRef.current.scrollIntoView({
-        block: 'center',
-        behavior: 'smooth',
-      })
-      selectRef.current.focus()
-    }
-
-    // clear the focus setting
-    window.dispatchEvent(
-      new CustomEvent('ui.focus-setting', { detail: undefined })
-    )
-  }, [name, settingToFocus])
-
-  return (
-    <OLFormGroup
-      controlId={`settings-menu-${name}`}
-      className="left-menu-setting"
-    >
-      <OLFormLabel>{label}</OLFormLabel>
-      {loading ? (
-        <OLSpinner size="sm" />
-      ) : (
-        <OLFormSelect
-          size="sm"
-          onChange={handleChange}
-          value={value?.toString()}
-          disabled={disabled}
-          ref={selectRef}
-          translate={translateOptions}
-        >
-          {options?.map(option => (
-            <option
-              key={`${name}-${option.value}`}
-              value={option.value.toString()}
-              aria-hidden={option.ariaHidden}
-              disabled={option.disabled}
-            >
-              {option.label}
-            </option>
-          ))}
-          {optgroups?.map(optgroup => (
-            <optgroup label={optgroup.label} key={optgroup.label}>
-              {optgroup.options.map(option => (
-                <option
-                  value={option.value.toString()}
-                  key={option.value.toString()}
-                >
-                  {option.label}
-                </option>
-              ))}
-            </optgroup>
-          ))}
-        </OLFormSelect>
-      )}
-    </OLFormGroup>
-  )
-}

+ 0 - 52
services/web/frontend/js/features/editor-left-menu/components/settings/settings-new-editor.tsx

@@ -1,52 +0,0 @@
-import { useTranslation } from 'react-i18next'
-import SettingsMenuSelect from './settings-menu-select'
-import { useSwitchEnableNewEditorState } from '@/features/ide-redesign/hooks/use-switch-enable-new-editor-state'
-import { useLayoutContext } from '@/shared/context/layout-context'
-import { useCallback } from 'react'
-import {
-  canUseNewEditor,
-  useIsNewEditorEnabled,
-} from '@/features/ide-redesign/utils/new-editor-utils'
-import { useEditorAnalytics } from '@/shared/hooks/use-editor-analytics'
-
-export default function SettingsNewEditor() {
-  const { t } = useTranslation()
-  const { setEditorRedesignStatus } = useSwitchEnableNewEditorState()
-  const { setLeftMenuShown } = useLayoutContext()
-  const enabled = useIsNewEditorEnabled()
-  const show = canUseNewEditor()
-  const { sendEvent } = useEditorAnalytics()
-
-  const onChange = useCallback(
-    (newValue: boolean) => {
-      sendEvent('switch-to-new-editor', {
-        location: 'left-menu',
-      })
-      setEditorRedesignStatus(newValue).then(() => setLeftMenuShown(false))
-    },
-    [setEditorRedesignStatus, setLeftMenuShown, sendEvent]
-  )
-
-  if (!show) {
-    return null
-  }
-
-  return (
-    <SettingsMenuSelect
-      onChange={onChange}
-      value={enabled}
-      options={[
-        {
-          value: true,
-          label: t('on'),
-        },
-        {
-          value: false,
-          label: t('off'),
-        },
-      ]}
-      label={t('new_editor_look')}
-      name="new-editor-setting"
-    />
-  )
-}

+ 0 - 42
services/web/frontend/js/features/editor-left-menu/components/settings/settings-overall-theme.tsx

@@ -1,42 +0,0 @@
-import { useMemo } from 'react'
-import { useTranslation } from 'react-i18next'
-import { useLayoutContext } from '../../../../shared/context/layout-context'
-import getMeta from '../../../../utils/meta'
-import SettingsMenuSelect, { Option } from './settings-menu-select'
-import { useProjectSettingsContext } from '../../context/project-settings-context'
-import type { OverallThemeMeta } from '../../../../../../types/project-settings'
-import { isIEEEBranded } from '@/utils/is-ieee-branded'
-import { OverallTheme } from '@/shared/utils/styles'
-
-export default function SettingsOverallTheme() {
-  const { t } = useTranslation()
-  const overallThemes = getMeta('ol-overallThemes') as
-    | OverallThemeMeta[]
-    | undefined
-  const { loadingStyleSheet } = useLayoutContext()
-  const { overallTheme, setOverallTheme } = useProjectSettingsContext()
-
-  const options: Array<Option<OverallTheme>> = useMemo(
-    () =>
-      overallThemes?.map(({ name, val }) => ({
-        value: val,
-        label: name,
-      })) ?? [],
-    [overallThemes]
-  )
-
-  if (!overallThemes || isIEEEBranded()) {
-    return null
-  }
-
-  return (
-    <SettingsMenuSelect<OverallTheme>
-      onChange={setOverallTheme}
-      value={overallTheme}
-      options={options}
-      loading={loadingStyleSheet}
-      label={t('overall_theme')}
-      name="overallTheme"
-    />
-  )
-}

+ 0 - 29
services/web/frontend/js/features/editor-left-menu/components/settings/settings-pdf-viewer.tsx

@@ -1,29 +0,0 @@
-import { useTranslation } from 'react-i18next'
-import type { PdfViewer } from '../../../../../../types/user-settings'
-import { useProjectSettingsContext } from '../../context/project-settings-context'
-import SettingsMenuSelect from './settings-menu-select'
-
-export default function SettingsPdfViewer() {
-  const { t } = useTranslation()
-  const { pdfViewer, setPdfViewer } = useProjectSettingsContext()
-
-  return (
-    <SettingsMenuSelect<PdfViewer>
-      onChange={setPdfViewer}
-      value={pdfViewer}
-      options={[
-        {
-          value: 'pdfjs',
-          label: t('overleaf'),
-        },
-        {
-          value: 'native',
-          label: t('browser'),
-        },
-      ]}
-      label={t('pdf_viewer')}
-      name="pdfViewer"
-      translateOptions="no"
-    />
-  )
-}

+ 0 - 42
services/web/frontend/js/features/editor-left-menu/components/settings/settings-spell-check-language.tsx

@@ -1,42 +0,0 @@
-import { useMemo } from 'react'
-import { useTranslation } from 'react-i18next'
-import getMeta from '../../../../utils/meta'
-import { useProjectSettingsContext } from '../../context/project-settings-context'
-import SettingsMenuSelect from './settings-menu-select'
-import type { Optgroup } from './settings-menu-select'
-import { useIdeReactContext } from '@/features/ide-react/context/ide-react-context'
-import { supportsWebAssembly } from '@/utils/wasm'
-
-export default function SettingsSpellCheckLanguage() {
-  const { t } = useTranslation()
-
-  const { spellCheckLanguage, setSpellCheckLanguage } =
-    useProjectSettingsContext()
-  const { permissionsLevel } = useIdeReactContext()
-
-  const optgroup: Optgroup = useMemo(() => {
-    const options = (getMeta('ol-languages') ?? [])
-      // only include spell-check languages that are available in the client
-      .filter(language => language.dic !== undefined)
-
-    return {
-      label: 'Language',
-      options: options.map(language => ({
-        value: language.code,
-        label: language.name,
-      })),
-    }
-  }, [])
-
-  return (
-    <SettingsMenuSelect
-      onChange={setSpellCheckLanguage}
-      value={supportsWebAssembly() ? spellCheckLanguage : ''}
-      options={[{ value: '', label: t('off') }]}
-      optgroups={[optgroup]}
-      label={t('spell_check')}
-      name="spellCheckLanguage"
-      disabled={permissionsLevel === 'readOnly' || !supportsWebAssembly()}
-    />
-  )
-}

+ 0 - 27
services/web/frontend/js/features/editor-left-menu/components/settings/settings-syntax-validation.tsx

@@ -1,27 +0,0 @@
-import { useTranslation } from 'react-i18next'
-import { useProjectSettingsContext } from '../../context/project-settings-context'
-import SettingsMenuSelect from './settings-menu-select'
-
-export default function SettingsSyntaxValidation() {
-  const { t } = useTranslation()
-  const { syntaxValidation, setSyntaxValidation } = useProjectSettingsContext()
-
-  return (
-    <SettingsMenuSelect<boolean>
-      onChange={setSyntaxValidation}
-      value={syntaxValidation}
-      options={[
-        {
-          value: true,
-          label: t('on'),
-        },
-        {
-          value: false,
-          label: t('off'),
-        },
-      ]}
-      label={t('syntax_validation')}
-      name="syntaxValidation"
-    />
-  )
-}

+ 0 - 42
services/web/frontend/js/features/editor-left-menu/components/sync-menu.tsx

@@ -1,42 +0,0 @@
-import { ElementType } from 'react'
-import { useTranslation } from 'react-i18next'
-import importOverleafModules from '../../../../macros/import-overleaf-module.macro'
-import getMeta from '../../../utils/meta'
-
-const components = importOverleafModules('editorLeftMenuSync') as {
-  import: { default: ElementType }
-  path: string
-}[]
-
-export default function SyncMenu() {
-  const { t } = useTranslation()
-  const anonymous = getMeta('ol-anonymous')
-  const gitBridgeEnabled = getMeta('ol-gitBridgeEnabled')
-
-  if (anonymous) {
-    return null
-  }
-
-  if (components.length === 0) {
-    return null
-  }
-
-  // This flag can only be false in CE and Server Pro. In this case we skip rendering the
-  // entire sync section, since Dropbox and GitHub are never available in SP
-  if (!gitBridgeEnabled) {
-    return null
-  }
-
-  return (
-    <>
-      <h4>{t('sync')}</h4>
-      <ul className="list-unstyled nav">
-        {components.map(({ import: { default: Component }, path }) => (
-          <li key={path}>
-            <Component />
-          </li>
-        ))}
-      </ul>
-    </>
-  )
-}

+ 9 - 1
services/web/frontend/js/features/editor-left-menu/hooks/use-editor-theme-option-groups.tsx

@@ -1,6 +1,5 @@
 import getMeta from '@/utils/meta'
 import { useMemo } from 'react'
-import { Option } from '../components/settings/settings-menu-select'
 import { useTranslation } from 'react-i18next'
 
 const overrides = new Map([['overleaf', 'overleaf light']])
@@ -8,6 +7,15 @@ function getThemeName(theme: string): string {
   return (overrides.get(theme) ?? theme).replace(/_/g, ' ')
 }
 
+type PossibleValue = string | number | boolean
+
+type Option<T extends PossibleValue = string> = {
+  value: T
+  label: string
+  ariaHidden?: 'true' | 'false'
+  disabled?: boolean
+}
+
 export function useEditorThemesOptionGroups() {
   const editorThemes = getMeta('ol-editorThemes')
   const legacyEditorThemes = getMeta('ol-legacyEditorThemes')

+ 0 - 44
services/web/frontend/js/features/word-count-modal/components/word-count-button.tsx

@@ -1,44 +0,0 @@
-import { useDetachCompileContext as useCompileContext } from '@/shared/context/detach-compile-context'
-import { useTranslation } from 'react-i18next'
-import { isSplitTestEnabled } from '@/utils/splitTestUtils'
-import LeftMenuButton from '@/features/editor-left-menu/components/left-menu-button'
-import OLTooltip from '@/shared/components/ol/ol-tooltip'
-import { memo } from 'react'
-
-export const WordCountButton = memo<{
-  handleShowModal: () => void
-}>(function WordCountButton({ handleShowModal }) {
-  const { pdfUrl } = useCompileContext()
-  const { t } = useTranslation()
-
-  const enabled = pdfUrl || isSplitTestEnabled('word-count-client')
-
-  if (!enabled) {
-    return (
-      <OLTooltip
-        id="disabled-word-count"
-        description={t('please_compile_pdf_before_word_count')}
-        overlayProps={{
-          placement: 'top',
-        }}
-      >
-        {/* OverlayTrigger won't fire unless the child is a non-react html element (e.g div, span) */}
-        <div>
-          <LeftMenuButton
-            icon="match_case"
-            disabled
-            disabledAccesibilityText={t('please_compile_pdf_before_word_count')}
-          >
-            {t('word_count')}
-          </LeftMenuButton>
-        </div>
-      </OLTooltip>
-    )
-  }
-
-  return (
-    <LeftMenuButton onClick={handleShowModal} icon="match_case">
-      {t('word_count')}
-    </LeftMenuButton>
-  )
-})

+ 0 - 57
services/web/frontend/stories/editor-left-menu/actions-menu.stories.tsx

@@ -1,57 +0,0 @@
-import ActionsMenu from '../../js/features/editor-left-menu/components/actions-menu'
-import { ScopeDecorator } from '../decorators/scope'
-import { mockCompile, mockCompileError } from '../fixtures/compile'
-import { document, mockDocument } from '../fixtures/document'
-import useFetchMock from '../hooks/use-fetch-mock'
-import { useScope } from '../hooks/use-scope'
-
-export default {
-  title: 'Editor / Left Menu / Actions Menu',
-  component: ActionsMenu,
-  decorators: [
-    (Story: any) => ScopeDecorator(Story, { mockCompileOnLoad: false }),
-  ],
-}
-
-export const NotCompiled = () => {
-  window.metaAttributesCache.set('ol-anonymous', false)
-
-  useFetchMock(fetchMock => {
-    mockCompileError(fetchMock, 'failure')
-  })
-
-  return (
-    <div id="left-menu" className="shown">
-      <ActionsMenu />
-    </div>
-  )
-}
-
-export const CompileSuccess = () => {
-  window.metaAttributesCache.set('ol-anonymous', false)
-
-  useScope({
-    editor: {
-      sharejs_doc: mockDocument(document.tex),
-    },
-  })
-
-  useFetchMock(fetchMock => {
-    mockCompile(fetchMock)
-    fetchMock.get('express:/project/:projectId/wordcount', {
-      texcount: {
-        encode: 'ascii',
-        textWords: 10,
-        headers: 11,
-        mathInline: 12,
-        mathDisplay: 13,
-      },
-    })
-  })
-
-  return (
-    <div id="left-menu" className="shown">
-      <ActionsMenu />
-    </div>
-  )
-}

+ 0 - 44
services/web/frontend/stories/editor-left-menu/download-menu.stories.tsx

@@ -1,44 +0,0 @@
-import DownloadMenu from '../../js/features/editor-left-menu/components/download-menu'
-import { ScopeDecorator } from '../decorators/scope'
-import { mockCompile, mockCompileError } from '../fixtures/compile'
-import { document, mockDocument } from '../fixtures/document'
-import useFetchMock from '../hooks/use-fetch-mock'
-import { useScope } from '../hooks/use-scope'
-
-export default {
-  title: 'Editor / Left Menu / Download Menu',
-  component: DownloadMenu,
-  decorators: [
-    (Story: any) => ScopeDecorator(Story, { mockCompileOnLoad: false }),
-  ],
-}
-
-export const NotCompiled = () => {
-  useFetchMock(fetchMock => {
-    mockCompileError(fetchMock, 'failure')
-  })
-
-  return (
-    <div id="left-menu" className="shown">
-      <DownloadMenu />
-    </div>
-  )
-}
-
-export const CompileSuccess = () => {
-  useScope({
-    editor: {
-      sharejs_doc: mockDocument(document.tex),
-    },
-  })
-
-  useFetchMock(fetchMock => {
-    mockCompile(fetchMock)
-  })
-
-  return (
-    <div id="left-menu" className="shown">
-      <DownloadMenu />
-    </div>
-  )
-}

+ 0 - 33
services/web/frontend/stories/editor-left-menu/help-menu.stories.tsx

@@ -1,33 +0,0 @@
-import HelpMenu from '../../js/features/editor-left-menu/components/help-menu'
-import { ScopeDecorator } from '../decorators/scope'
-
-export default {
-  title: 'Editor / Left Menu / Help Menu',
-  component: HelpMenu,
-  decorators: [ScopeDecorator],
-}
-
-export const ShowSupport = () => {
-  window.metaAttributesCache.set('ol-showSupport', true)
-  window.metaAttributesCache.set('ol-user', {
-    email: 'sherlock@holmes.co.uk',
-    first_name: 'Sherlock',
-    last_name: 'Holmes',
-  })
-
-  return (
-    <div id="left-menu" className="shown">
-      <HelpMenu />
-    </div>
-  )
-}
-
-export const HideSupport = () => {
-  window.metaAttributesCache.set('ol-showSupport', false)
-
-  return (
-    <div id="left-menu" className="shown">
-      <HelpMenu />
-    </div>
-  )
-}

+ 0 - 37
services/web/frontend/stories/editor-left-menu/sync-menu.stories.tsx

@@ -1,37 +0,0 @@
-import SyncMenu from '../../js/features/editor-left-menu/components/sync-menu'
-import { ScopeDecorator } from '../decorators/scope'
-import { useScope } from '../hooks/use-scope'
-
-export default {
-  title: 'Editor / Left Menu / Sync Menu',
-  component: SyncMenu,
-  decorators: [ScopeDecorator],
-}
-
-export const WriteAccess = () => {
-  window.metaAttributesCache.set('ol-anonymous', false)
-  window.metaAttributesCache.set('ol-gitBridgeEnabled', true)
-  useScope({
-    permissionsLevel: 'owner',
-  })
-
-  return (
-    <div id="left-menu" className="shown">
-      <SyncMenu />
-    </div>
-  )
-}
-
-export const ReadOnlyAccess = () => {
-  window.metaAttributesCache.set('ol-anonymous', false)
-  window.metaAttributesCache.set('ol-gitBridgeEnabled', true)
-  useScope({
-    permissionsLevel: 'readOnly',
-  })
-
-  return (
-    <div id="left-menu" className="shown">
-      <SyncMenu />
-    </div>
-  )
-}

+ 0 - 169
services/web/frontend/stylesheets/pages/editor/left-menu.scss

@@ -6,175 +6,6 @@
   --left-menu-form-select-border: var(--border-disabled);
 }
 
-.left-menu {
-  position: absolute;
-  top: 0;
-  bottom: 0;
-  background-color: var(--bg-light-secondary);
-  z-index: 100;
-  overflow: hidden auto;
-  transition: left ease-in-out 0.5s;
-  font-size: var(--font-size-02);
-  width: 340px;
-
-  &.shown {
-    left: 0;
-  }
-
-  h4 {
-    font-family: $font-family-sans-serif;
-    font-weight: 400;
-    font-size: var(--font-size-03);
-    margin: var(--spacing-05) 0;
-    padding-bottom: var(--spacing-03);
-    color: var(--content-secondary);
-    border-bottom: 1px solid var(--border-primary-dark);
-
-    &:first-child {
-      margin-top: 0;
-    }
-  }
-
-  ul.nav {
-    .left-menu-button {
-      cursor: pointer;
-      padding: var(--spacing-03);
-      font-weight: 700;
-      color: var(--link-ui);
-      display: flex;
-      align-items: center;
-      width: 100%;
-      background-color: inherit;
-      border: none;
-      text-decoration: none;
-
-      .material-symbols {
-        margin-right: var(--spacing-04);
-        color: var(--neutral-70);
-      }
-
-      &:hover,
-      &:active {
-        background-color: var(--bg-info-01);
-        color: var(--white);
-
-        .material-symbols {
-          color: var(--white);
-        }
-      }
-    }
-
-    a {
-      cursor: pointer;
-
-      &:hover,
-      &:active,
-      &:focus {
-        background-color: var(--bg-info-01);
-        color: var(--white);
-
-        .material-symbols {
-          color: var(--white);
-        }
-      }
-
-      .material-symbols {
-        color: var(--neutral-70);
-      }
-
-      padding: var(--spacing-03);
-      font-weight: 700;
-    }
-
-    .link-disabled {
-      color: var(--content-disabled);
-    }
-  }
-
-  > ul.nav:last-child {
-    margin-bottom: var(--spacing-05);
-  }
-
-  ul.nav-downloads {
-    li {
-      display: inline-block;
-      text-align: center;
-      width: 100px;
-
-      a {
-        color: var(--content-secondary);
-        text-decoration: none;
-      }
-
-      .material-symbols {
-        margin: var(--spacing-03) 0;
-      }
-    }
-  }
-
-  form.settings {
-    label {
-      font-weight: normal;
-      color: var(--content-secondary);
-      flex: 1 0 50%;
-      margin-bottom: 0;
-      padding-right: var(--spacing-03);
-      white-space: nowrap;
-    }
-
-    button,
-    select {
-      width: 50%;
-      margin: var(--spacing-04) 0;
-    }
-  }
-
-  .left-menu-setting {
-    padding: 0 var(--spacing-02);
-    display: flex;
-    flex-wrap: wrap;
-    align-items: center;
-    justify-content: center;
-    border-bottom: 1px solid rgb(0 0 0 / 7%);
-    margin-bottom: 0;
-    height: 43px;
-
-    &:first-child {
-      margin-top: calc(var(--spacing-04) * -1);
-    }
-
-    &:last-child {
-      border-bottom: 0;
-    }
-
-    &:hover,
-    &:focus-within {
-      background-color: var(--bg-info-01);
-
-      label {
-        color: var(--white);
-      }
-    }
-
-    .form-select {
-      border: 1px solid var(--left-menu-form-select-border);
-    }
-  }
-}
-
-#left-menu-mask {
-  opacity: 0.4;
-  background-color: #999;
-  z-index: 99;
-  transition: opacity 0.5s;
-  position: absolute;
-  inset: 0;
-}
-
-.left-menu-modal-backdrop {
-  background-color: transparent;
-}
-
 .loading-spinner-container {
   display: flex;
   align-items: center;

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

@@ -830,8 +830,6 @@
   "folder_name": "Folder name",
   "folders": "Folders",
   "following_paths_conflict": "The following files and folders conflict with the same path",
-  "font_family": "Font Family",
-  "font_size": "Font Size",
   "footer_about_us": "About us",
   "footer_contact_us": "Contact us",
   "footnotes": "Footnotes",
@@ -1298,7 +1296,6 @@
   "limited_document_history": "Limited document history",
   "limited_to_n_collaborators_per_project": "Limited to __count__ collaborator per project",
   "limited_to_n_collaborators_per_project_plural": "Limited to __count__ collaborators per project",
-  "line_height": "Line Height",
   "line_width_is_the_width_of_the_line_in_the_current_environment": "Line width is the width of the line in the current environment. e.g. a full page width in single-column layout or half a page width in a two-column layout.",
   "link": "Link",
   "link_account": "Link Account",
@@ -1487,7 +1484,6 @@
   "new_compile_domain_notice": "Something might be blocking your browser from accessing Overleaf’s PDF download location, <0>__compilesUserContentDomain__</0>. This could be caused by network blocking or a strict browser plugin rule. Please follow our <1>troubleshooting guide</1>.",
   "new_compiles_in_this_project_will_automatically_use_the_newest_version": "New compiles in this project will automatically use the newest version. <0>Learn how to change compiler settings</0>",
   "new_create_tables_and_equations": "NEW! <sparkle/> Create tables and equations in seconds",
-  "new_editor_look": "New editor look",
   "new_error_logs_make_it_easier_to_find_whats_wrong": "New error logs make it easier to find what’s wrong and fix your document, so you can get compiling again.",
   "new_file": "New file",
   "new_folder": "New folder",
@@ -1727,7 +1723,6 @@
   "please_ask_the_project_owner_to_upgrade_to_track_changes": "Please ask the project owner to upgrade to use track changes",
   "please_change_primary_to_remove": "Please change your primary email in order to remove",
   "please_compile_pdf_before_download": "Please compile your project before downloading the PDF",
-  "please_compile_pdf_before_word_count": "Please compile your project before performing a word count",
   "please_confirm_email": "Please confirm your email __emailAddress__ by clicking on the link in the confirmation email ",
   "please_confirm_primary_email_or_edit": "Please confirm your primary email address __emailAddress__. To edit it, go to <0>Account settings</0>.",
   "please_confirm_secondary_email_or_edit": "Please confirm your secondary email address __emailAddress__. To edit it, go to <0>Account settings</0>.",
@@ -2152,7 +2147,6 @@
   "show_document_preamble": "Show document preamble",
   "show_equation_preview": "Show equation preview",
   "show_file_tree": "Show file tree",
-  "show_hotkeys": "Show Hotkeys",
   "show_in_code": "Show in code",
   "show_in_pdf": "Show in PDF",
   "show_less": "show less",
@@ -2212,7 +2206,6 @@
   "source": "Source",
   "speak": "Speak",
   "speech_input_not_available": "Speech input is not yet available in this browser",
-  "spell_check": "Spell check",
   "spellcheck": "Spellcheck",
   "spellcheck_language": "Spellcheck language",
   "split_view": "Split view",

+ 0 - 900
services/web/test/frontend/components/editor-left-menu/editor-left-menu.spec.tsx

@@ -1,900 +0,0 @@
-import EditorLeftMenu from '../../../../frontend/js/features/editor-left-menu/components/editor-left-menu'
-import {
-  ImageName,
-  OverallThemeMeta,
-  SpellCheckLanguage,
-} from '../../../../types/project-settings'
-import {
-  EditorProviders,
-  makeProjectProvider,
-} from '../../helpers/editor-providers'
-import { mockScope } from './scope'
-import { Folder } from '../../../../types/folder'
-import { docsInFolder } from '@/features/file-tree/util/docs-in-folder'
-import getMeta from '@/utils/meta'
-import { mockProject } from '../../features/source-editor/helpers/mock-project'
-import { UserId } from '../../../../types/user'
-
-describe('<EditorLeftMenu />', function () {
-  beforeEach(function () {
-    cy.viewport(800, 800)
-    cy.interceptCompile()
-  })
-
-  describe('for non-anonymous users', function () {
-    const overallThemes: OverallThemeMeta[] = [
-      {
-        name: 'Overall Theme 1',
-        val: '',
-        path: 'https://overleaf.com/overalltheme-1.css',
-      },
-      {
-        name: 'Overall Theme 2',
-        val: 'light-',
-        path: 'https://overleaf.com/overalltheme-2.css',
-      },
-    ]
-
-    const ImageNames: ImageName[] = [
-      {
-        imageDesc: 'Image 1',
-        imageName: 'img-1',
-        allowed: true,
-      },
-      {
-        imageDesc: 'Image 2',
-        imageName: 'img-2',
-        allowed: true,
-      },
-    ]
-
-    beforeEach(function () {
-      window.metaAttributesCache.set('ol-overallThemes', overallThemes)
-      window.metaAttributesCache.set('ol-imageNames', ImageNames)
-      window.metaAttributesCache.set('ol-anonymous', false)
-      window.metaAttributesCache.set('ol-gitBridgeEnabled', true)
-      window.metaAttributesCache.set('ol-showSupport', true)
-      Object.assign(getMeta('ol-ExposedSettings'), { ieeeBrandId: 123 })
-      window.metaAttributesCache.set('ol-user', {
-        email: 'sherlock@holmes.co.uk',
-        first_name: 'Sherlock',
-        last_name: 'Holmes',
-      })
-    })
-
-    it('render full menu', function () {
-      const scope = mockScope()
-      const project = mockProject()
-
-      cy.mount(
-        <EditorProviders
-          scope={scope}
-          layoutContext={{ leftMenuShown: true }}
-          providers={{ ProjectProvider: makeProjectProvider(project) }}
-        >
-          <EditorLeftMenu />
-        </EditorProviders>
-      )
-
-      // Download Menu
-      cy.findByRole('heading', { name: 'Download' })
-      cy.findByRole('link', { name: 'Source' })
-      cy.findByRole('link', { name: 'PDF' })
-
-      // Actions Menu
-      cy.findByRole('heading', { name: 'Actions' })
-      cy.findByRole('button', { name: 'Copy project' })
-      cy.findByRole('button', { name: 'Word Count' })
-
-      // Sync Menu
-      cy.findByRole('heading', { name: 'Sync' })
-      cy.findByRole('button', { name: 'Dropbox' })
-      cy.findByRole('button', { name: 'Git' })
-      cy.findByRole('button', { name: 'GitHub' })
-
-      // Settings Menu
-      cy.findByRole('heading', { name: 'Settings' })
-      cy.findByLabelText('Compiler')
-      cy.findByLabelText('TeX Live version')
-      cy.findByLabelText('Main document')
-      cy.findByLabelText('Spell check')
-      cy.findByLabelText('Auto-complete')
-      cy.findByLabelText('Auto-close brackets')
-      cy.findByLabelText('Code check')
-      cy.findByLabelText('Editor theme')
-      cy.findByLabelText('Overall theme')
-      cy.findByLabelText('Keybindings')
-      cy.findByLabelText('Font Size')
-      cy.findByLabelText('Font Family')
-      cy.findByLabelText('Line Height')
-      cy.findByLabelText('PDF Viewer')
-
-      // Help Menu
-      cy.findByRole('heading', { name: 'Help' })
-      cy.findByRole('button', { name: 'Show Hotkeys' })
-      cy.findByRole('link', { name: 'Documentation' })
-      cy.findByRole('button', { name: 'Contact us' })
-    })
-
-    describe('download menu', function () {
-      it('have a correct source & pdf download url', function () {
-        const scope = mockScope()
-        cy.mount(
-          <EditorProviders
-            scope={scope}
-            layoutContext={{ leftMenuShown: true }}
-          >
-            <EditorLeftMenu />
-          </EditorProviders>
-        )
-
-        cy.findByRole('link', { name: 'Source' }).should(
-          'have.attr',
-          'href',
-          '/project/project123/download/zip'
-        )
-
-        cy.findByRole('link', { name: 'PDF' })
-          .should('have.attr', 'href')
-          .and('match', /\/download\/project\/project123\/build/)
-      })
-    })
-
-    describe('actions menu', function () {
-      it('shows copy project modal correctly', function () {
-        cy.intercept('POST', '/project/*/clone', {
-          body: {
-            project_id: 'new_project_id',
-          },
-        })
-
-        const scope = mockScope()
-
-        cy.mount(
-          <EditorProviders
-            scope={scope}
-            layoutContext={{ leftMenuShown: true }}
-          >
-            <EditorLeftMenu />
-          </EditorProviders>
-        )
-
-        cy.findByRole('button', { name: 'Copy project' }).click()
-        cy.findByRole('heading', { name: 'Copy project' })
-
-        // try closing & re-opening the modal with different methods
-        cy.findByRole('button', { name: 'Close dialog' }).click()
-        cy.findByRole('button', { name: 'Copy project' }).click()
-        cy.findByRole('button', { name: 'Cancel' }).click()
-        cy.findByRole('button', { name: 'Copy project' }).click()
-
-        cy.findByLabelText(/New name/i).focus()
-        cy.findByLabelText(/New name/i).clear()
-        cy.findByLabelText(/New name/i).type('Project Renamed')
-        cy.get('#clone-project-form-name[value="Project Renamed"')
-      })
-
-      it('shows word count modal correctly', function () {
-        cy.intercept('GET', '/project/*/wordcount*', {
-          texcount: {
-            encode: 'ascii',
-            textWords: 781,
-            headWords: 66,
-            outside: 11,
-            headers: 41,
-            elements: 2,
-            mathInline: 6,
-            mathDisplay: 1,
-            errors: 0,
-          },
-        }).as('wordCount')
-
-        const scope = mockScope()
-
-        cy.mount(
-          <EditorProviders
-            scope={scope}
-            layoutContext={{ leftMenuShown: true }}
-          >
-            <EditorLeftMenu />
-          </EditorProviders>
-        )
-
-        cy.findByRole('button', { name: 'Word Count' }).click()
-
-        cy.wait('@wordCount')
-        cy.findByText('Total Words:')
-        cy.findByText('781')
-        cy.findByText('Headers:')
-        cy.findByText('41')
-        cy.findByText('Math Inline:')
-        cy.findByText('6')
-        cy.findByText('Math Display:')
-        cy.findByText('1')
-      })
-    })
-
-    describe('sync menu', function () {
-      it('shows dropbox modal correctly', function () {
-        cy.intercept('GET', '/dropbox/status', {
-          registered: true,
-        })
-
-        const scope = mockScope({
-          user: {
-            features: {
-              dropbox: false,
-            },
-          },
-        })
-
-        cy.mount(
-          <EditorProviders
-            scope={scope}
-            layoutContext={{ leftMenuShown: true }}
-            projectOwner={{
-              _id: '123' as UserId,
-              email: 'owner@example.com',
-              first_name: 'Test',
-              last_name: 'Owner',
-              privileges: 'owner',
-              signUpDate: new Date('2025-07-07').toISOString(),
-            }}
-          >
-            <EditorLeftMenu />
-          </EditorProviders>
-        )
-
-        cy.findByRole('button', { name: 'Dropbox' }).click()
-        cy.findByText('Dropbox Sync')
-      })
-
-      it('shows git modal correctly', function () {
-        const scope = mockScope()
-
-        cy.mount(
-          <EditorProviders
-            scope={scope}
-            layoutContext={{ leftMenuShown: true }}
-            projectOwner={{
-              _id: '123' as UserId,
-              email: 'owner@example.com',
-              first_name: 'Test',
-              last_name: 'Owner',
-              privileges: 'owner',
-              signUpDate: new Date('2025-07-07').toISOString(),
-            }}
-            projectFeatures={
-              {
-                gitBridge: true,
-              } as any
-            }
-          >
-            <EditorLeftMenu />
-          </EditorProviders>
-        )
-
-        cy.findByRole('button', { name: 'Git' }).click()
-        cy.findByText('Clone with Git')
-        cy.findByText(/clone your project by using the link below/)
-      })
-
-      it('shows git modal paywall correctly', function () {
-        const scope = mockScope()
-
-        cy.mount(
-          <EditorProviders
-            scope={scope}
-            layoutContext={{ leftMenuShown: true }}
-            projectOwner={{
-              _id: '123' as UserId,
-              email: 'owner@example.com',
-              first_name: 'Test',
-              last_name: 'Owner',
-              privileges: 'owner',
-              signUpDate: new Date('2025-07-07').toISOString(),
-            }}
-            projectFeatures={
-              {
-                gitBridge: false,
-              } as any
-            }
-          >
-            <EditorLeftMenu />
-          </EditorProviders>
-        )
-
-        cy.findByRole('button', { name: 'Git' }).click()
-        cy.findByText('Collaborate online and offline, using your own workflow')
-      })
-
-      it('shows github modal correctly', function () {
-        cy.intercept('GET', '/user/github-sync/status', {
-          available: false,
-          enabled: false,
-        }).as('user-status')
-
-        cy.intercept('GET', '/project/*/github-sync/status', {
-          enabled: false,
-        }).as('project-status')
-
-        const scope = mockScope()
-
-        cy.mount(
-          <EditorProviders
-            scope={scope}
-            layoutContext={{ leftMenuShown: true }}
-          >
-            <EditorLeftMenu />
-          </EditorProviders>
-        )
-
-        cy.wait('@compile')
-        cy.findByRole('button', { name: 'GitHub' }).click()
-        cy.findByText('GitHub Sync')
-
-        cy.wait(['@user-status', '@project-status'])
-        cy.findByText('Push to GitHub, pull to Overleaf')
-      })
-
-      it('hides the entire sync section when git bridge is disabled', function () {
-        window.metaAttributesCache.set('ol-gitBridgeEnabled', false)
-
-        cy.findByRole('button', { name: 'Dropbox' }).should('not.exist')
-        cy.findByRole('button', { name: 'Git' }).should('not.exist')
-        cy.findByRole('button', { name: 'GitHub' }).should('not.exist')
-      })
-    })
-
-    describe('settings menu', function () {
-      it('shows compiler menu correctly', function () {
-        const scope = mockScope()
-
-        cy.mount(
-          <EditorProviders
-            scope={scope}
-            layoutContext={{ leftMenuShown: true }}
-          >
-            <EditorLeftMenu />
-          </EditorProviders>
-        )
-
-        cy.get<HTMLOptionElement>('#settings-menu-compiler option').then(
-          options => {
-            const values = [...options].map(o => o.value)
-            expect(values).to.deep.eq([
-              'pdflatex',
-              'latex',
-              'xelatex',
-              'lualatex',
-            ])
-
-            const texts = [...options].map(o => o.text)
-            expect(texts).to.deep.eq([
-              'pdfLaTeX',
-              'LaTeX',
-              'XeLaTeX',
-              'LuaLaTeX',
-            ])
-          }
-        )
-      })
-
-      it('shows texlive version menu correctly', function () {
-        const scope = mockScope()
-
-        cy.mount(
-          <EditorProviders
-            scope={scope}
-            layoutContext={{ leftMenuShown: true }}
-          >
-            <EditorLeftMenu />
-          </EditorProviders>
-        )
-
-        cy.get<HTMLOptionElement>('#settings-menu-imageName option').then(
-          options => {
-            const values = [...options].map(o => o.value)
-            expect(values).to.deep.eq(['img-1', 'img-2'])
-
-            const texts = [...options].map(o => o.text)
-            expect(texts).to.deep.eq(['Image 1', 'Image 2'])
-          }
-        )
-      })
-
-      it('shows document menu correctly', function () {
-        const rootFolder: Folder = {
-          _id: 'root-folder-id',
-          name: 'rootFolder',
-          docs: [
-            {
-              _id: 'id1',
-              name: 'main.tex',
-            },
-            {
-              _id: 'id2',
-              name: 'main2.tex',
-            },
-          ],
-          fileRefs: [],
-          folders: [],
-        }
-
-        const scope = mockScope()
-
-        cy.mount(
-          <EditorProviders
-            layoutContext={{ leftMenuShown: true }}
-            scope={scope}
-            rootFolder={[rootFolder as any]}
-          >
-            <EditorLeftMenu />
-          </EditorProviders>
-        )
-
-        const docs = docsInFolder(rootFolder)
-
-        cy.get<HTMLOptionElement>('#settings-menu-rootDocId option').then(
-          options => {
-            const values = [...options].map(o => o.value)
-            expect(values).to.deep.eq(docs.map(doc => doc.doc.id))
-
-            const texts = [...options].map(o => o.text)
-            expect(texts).to.deep.eq(docs.map(doc => doc.path))
-          }
-        )
-      })
-
-      it('shows spellcheck menu correctly', function () {
-        const languages: SpellCheckLanguage[] = [
-          {
-            name: 'Lang 1',
-            code: 'lang-1',
-            dic: 'lang_1',
-          },
-          {
-            name: 'Lang 2',
-            code: 'lang-2',
-            dic: 'lang_2',
-          },
-        ]
-
-        window.metaAttributesCache.set('ol-languages', languages)
-
-        const scope = mockScope()
-
-        cy.mount(
-          <EditorProviders
-            scope={scope}
-            layoutContext={{ leftMenuShown: true }}
-          >
-            <EditorLeftMenu />
-          </EditorProviders>
-        )
-
-        cy.get<HTMLOptionElement>(
-          '#settings-menu-spellCheckLanguage option'
-        ).then(options => {
-          const values = [...options].map(o => o.value)
-          expect(values).to.deep.eq(['', 'lang-1', 'lang-2'])
-
-          const texts = [...options].map(o => o.text)
-          expect(texts).to.deep.eq(['Off', 'Lang 1', 'Lang 2'])
-        })
-      })
-
-      it('shows dictionary modal correctly', function () {
-        const scope = mockScope()
-
-        cy.mount(
-          <EditorProviders
-            scope={scope}
-            layoutContext={{ leftMenuShown: true }}
-          >
-            <EditorLeftMenu />
-          </EditorProviders>
-        )
-
-        cy.get('label[for="dictionary-settings"] ~ button').click()
-        cy.findByText('Edit Dictionary')
-        cy.findByText('Your custom dictionary is empty.')
-      })
-
-      it('shows auto-complete menu correctly', function () {
-        const scope = mockScope()
-
-        cy.mount(
-          <EditorProviders
-            scope={scope}
-            layoutContext={{ leftMenuShown: true }}
-          >
-            <EditorLeftMenu />
-          </EditorProviders>
-        )
-
-        cy.get<HTMLOptionElement>('#settings-menu-autoComplete option').then(
-          options => {
-            const values = [...options].map(o => o.value)
-            expect(values).to.deep.eq(['true', 'false'])
-
-            const texts = [...options].map(o => o.text)
-            expect(texts).to.deep.eq(['On', 'Off'])
-          }
-        )
-      })
-
-      it('shows auto-close brackets menu correctly', function () {
-        const scope = mockScope()
-
-        cy.mount(
-          <EditorProviders
-            scope={scope}
-            layoutContext={{ leftMenuShown: true }}
-          >
-            <EditorLeftMenu />
-          </EditorProviders>
-        )
-
-        cy.get<HTMLOptionElement>(
-          '#settings-menu-autoPairDelimiters option'
-        ).then(options => {
-          const values = [...options].map(o => o.value)
-          expect(values).to.deep.eq(['true', 'false'])
-
-          const texts = [...options].map(o => o.text)
-          expect(texts).to.deep.eq(['On', 'Off'])
-        })
-      })
-
-      it('shows code check menu correctly', function () {
-        const scope = mockScope()
-
-        cy.mount(
-          <EditorProviders
-            scope={scope}
-            layoutContext={{ leftMenuShown: true }}
-          >
-            <EditorLeftMenu />
-          </EditorProviders>
-        )
-
-        cy.get<HTMLOptionElement>(
-          '#settings-menu-syntaxValidation option'
-        ).then(options => {
-          const values = [...options].map(o => o.value)
-          expect(values).to.deep.eq(['true', 'false'])
-
-          const texts = [...options].map(o => o.text)
-          expect(texts).to.deep.eq(['On', 'Off'])
-        })
-      })
-
-      it('shows editor theme menu correctly', function () {
-        const editorThemes = [
-          { name: 'editortheme-1', dark: false },
-          { name: 'editortheme-2', dark: false },
-          { name: 'editortheme-3', dark: false },
-        ]
-
-        const legacyEditorThemes = [
-          { name: 'legacytheme-1', dark: false },
-          { name: 'legacytheme-2', dark: false },
-          { name: 'legacytheme-3', dark: false },
-        ]
-
-        window.metaAttributesCache.set('ol-editorThemes', editorThemes)
-        window.metaAttributesCache.set(
-          'ol-legacyEditorThemes',
-          legacyEditorThemes
-        )
-
-        const scope = mockScope()
-
-        cy.mount(
-          <EditorProviders
-            scope={scope}
-            layoutContext={{ leftMenuShown: true }}
-          >
-            <EditorLeftMenu />
-          </EditorProviders>
-        )
-
-        cy.get<HTMLOptionElement>('#settings-menu-editorTheme option').then(
-          options => {
-            const values = [...options].map(o => o.value)
-            expect(values).to.deep.eq([
-              'editortheme-1',
-              'editortheme-2',
-              'editortheme-3',
-              'legacytheme-1',
-              'legacytheme-2',
-              'legacytheme-3',
-            ])
-
-            const texts = [...options].map(o => o.text)
-            expect(texts).to.deep.eq([
-              'editortheme-1',
-              'editortheme-2',
-              'editortheme-3',
-              'legacytheme-1 (Legacy)',
-              'legacytheme-2 (Legacy)',
-              'legacytheme-3 (Legacy)',
-            ])
-          }
-        )
-      })
-
-      it('shows overall theme menu correctly', function () {
-        const scope = mockScope()
-
-        cy.mount(
-          <EditorProviders
-            scope={scope}
-            layoutContext={{ leftMenuShown: true }}
-          >
-            <EditorLeftMenu />
-          </EditorProviders>
-        )
-
-        cy.get<HTMLOptionElement>('#settings-menu-overallTheme option').then(
-          options => {
-            const values = [...options].map(o => o.value)
-            expect(values).to.deep.eq(['', 'light-'])
-
-            const texts = [...options].map(o => o.text)
-            expect(texts).to.deep.eq(['Overall Theme 1', 'Overall Theme 2'])
-          }
-        )
-      })
-
-      it('shows keybindings menu correctly', function () {
-        const scope = mockScope()
-
-        cy.mount(
-          <EditorProviders
-            scope={scope}
-            layoutContext={{ leftMenuShown: true }}
-          >
-            <EditorLeftMenu />
-          </EditorProviders>
-        )
-
-        cy.get<HTMLOptionElement>('#settings-menu-mode option').then(
-          options => {
-            const values = [...options].map(o => o.value)
-            expect(values).to.deep.eq(['default', 'vim', 'emacs'])
-
-            const texts = [...options].map(o => o.text)
-            expect(texts).to.deep.eq(['None', 'Vim', 'Emacs'])
-          }
-        )
-      })
-
-      it('shows font size menu correctly', function () {
-        const scope = mockScope()
-
-        cy.mount(
-          <EditorProviders
-            scope={scope}
-            layoutContext={{ leftMenuShown: true }}
-          >
-            <EditorLeftMenu />
-          </EditorProviders>
-        )
-
-        cy.get<HTMLOptionElement>('#settings-menu-fontSize option').then(
-          options => {
-            const values = [...options].map(o => o.value)
-            expect(values).to.deep.eq([
-              '10',
-              '11',
-              '12',
-              '13',
-              '14',
-              '16',
-              '18',
-              '20',
-              '22',
-              '24',
-            ])
-
-            const texts = [...options].map(o => o.text)
-            expect(texts).to.deep.eq([
-              '10px',
-              '11px',
-              '12px',
-              '13px',
-              '14px',
-              '16px',
-              '18px',
-              '20px',
-              '22px',
-              '24px',
-            ])
-          }
-        )
-      })
-
-      it('shows font family menu correctly', function () {
-        const scope = mockScope()
-
-        cy.mount(
-          <EditorProviders
-            scope={scope}
-            layoutContext={{ leftMenuShown: true }}
-          >
-            <EditorLeftMenu />
-          </EditorProviders>
-        )
-
-        cy.get<HTMLOptionElement>('#settings-menu-fontFamily option').then(
-          options => {
-            const values = [...options].map(o => o.value)
-            expect(values).to.deep.eq(['monaco', 'lucida', 'opendyslexicmono'])
-
-            const texts = [...options].map(o => o.text)
-            expect(texts).to.deep.eq([
-              'Monaco / Menlo / Consolas',
-              'Lucida / Source Code Pro',
-              'OpenDyslexic Mono',
-            ])
-          }
-        )
-      })
-
-      it('shows line height menu correctly', function () {
-        const scope = mockScope()
-
-        cy.mount(
-          <EditorProviders
-            scope={scope}
-            layoutContext={{ leftMenuShown: true }}
-          >
-            <EditorLeftMenu />
-          </EditorProviders>
-        )
-
-        cy.get<HTMLOptionElement>('#settings-menu-lineHeight option').then(
-          options => {
-            const values = [...options].map(o => o.value)
-            expect(values).to.deep.eq(['compact', 'normal', 'wide'])
-
-            const texts = [...options].map(o => o.text)
-            expect(texts).to.deep.eq(['Compact', 'Normal', 'Wide'])
-          }
-        )
-      })
-
-      it('shows pdf viewer menu correctly', function () {
-        const scope = mockScope()
-
-        cy.mount(
-          <EditorProviders
-            scope={scope}
-            layoutContext={{ leftMenuShown: true }}
-          >
-            <EditorLeftMenu />
-          </EditorProviders>
-        )
-
-        cy.get<HTMLOptionElement>('#settings-menu-pdfViewer option').then(
-          options => {
-            const values = [...options].map(o => o.value)
-            expect(values).to.deep.eq(['pdfjs', 'native'])
-
-            const texts = [...options].map(o => o.text)
-            expect(texts).to.deep.eq(['Overleaf', 'Browser'])
-          }
-        )
-      })
-    })
-
-    describe('help menu', function () {
-      it('shows hotkeys modal correctly', function () {
-        const scope = mockScope()
-
-        cy.mount(
-          <EditorProviders
-            scope={scope}
-            layoutContext={{ leftMenuShown: true }}
-          >
-            <EditorLeftMenu />
-          </EditorProviders>
-        )
-
-        cy.findByRole('button', { name: 'Show Hotkeys' }).click()
-        cy.findByText('Hotkeys')
-      })
-
-      it('shows correct url for documentation', function () {
-        const scope = mockScope()
-
-        cy.mount(
-          <EditorProviders
-            scope={scope}
-            layoutContext={{ leftMenuShown: true }}
-          >
-            <EditorLeftMenu />
-          </EditorProviders>
-        )
-
-        cy.findByRole('link', { name: 'Documentation' }).should(
-          'have.attr',
-          'href',
-          '/learn'
-        )
-      })
-
-      it('shows correct contact us modal', function () {
-        const scope = mockScope()
-
-        cy.mount(
-          <EditorProviders
-            scope={scope}
-            layoutContext={{ leftMenuShown: true }}
-          >
-            <EditorLeftMenu />
-          </EditorProviders>
-        )
-
-        cy.findByRole('button', { name: 'Contact us' }).click()
-        cy.findByText('Affected project URL (Optional)')
-      })
-    })
-  })
-
-  describe('for anonymous users', function () {
-    it('render minimal menu', function () {
-      const scope = mockScope()
-
-      window.metaAttributesCache.set('ol-anonymous', true)
-      Object.assign(getMeta('ol-ExposedSettings'), { ieeeBrandId: 123 })
-
-      cy.mount(
-        <EditorProviders scope={scope} layoutContext={{ leftMenuShown: true }}>
-          <EditorLeftMenu />
-        </EditorProviders>
-      )
-
-      // Download Menu
-      cy.findByRole('heading', { name: 'Download' })
-      cy.findByRole('link', { name: 'Source' })
-      cy.findByRole('link', { name: 'PDF' })
-
-      // Actions Menu
-      cy.findByRole('heading', { name: 'Actions' }).should('not.exist')
-      cy.findByRole('button', { name: 'Copy project' }).should('not.exist')
-      cy.findByRole('button', { name: 'Word Count' }).should('not.exist')
-
-      // Sync Menu
-      cy.findByRole('heading', { name: 'Sync' }).should('not.exist')
-      cy.findByRole('button', { name: 'Dropbox' }).should('not.exist')
-      cy.findByRole('button', { name: 'Git' }).should('not.exist')
-      cy.findByRole('button', { name: 'GitHub' }).should('not.exist')
-
-      // Settings Menu
-      cy.findByRole('heading', { name: 'Settings' }).should('not.exist')
-      cy.findByLabelText('Compiler').should('not.exist')
-      cy.findByLabelText('TeX Live version').should('not.exist')
-      cy.findByLabelText('Main document').should('not.exist')
-      cy.findByLabelText('Spell check').should('not.exist')
-      cy.findByLabelText('Auto-complete').should('not.exist')
-      cy.findByLabelText('Auto-close brackets').should('not.exist')
-      cy.findByLabelText('Code check').should('not.exist')
-      cy.findByLabelText('Editor theme').should('not.exist')
-      cy.findByLabelText('Overall theme').should('not.exist')
-      cy.findByLabelText('Keybindings').should('not.exist')
-      cy.findByLabelText('Font Size').should('not.exist')
-      cy.findByLabelText('Font Family').should('not.exist')
-      cy.findByLabelText('Line Height').should('not.exist')
-      cy.findByLabelText('PDF Viewer').should('not.exist')
-
-      // Help Menu
-      cy.findByRole('heading', { name: 'Help' })
-      cy.findByRole('button', { name: 'Show Hotkeys' })
-      cy.findByRole('button', { name: 'Documentation' }).should('not.exist')
-      cy.findByRole('link', { name: 'Contact us' }).should('not.exist')
-    })
-  })
-})

+ 0 - 49
services/web/test/frontend/components/editor-left-menu/scope.tsx

@@ -1,49 +0,0 @@
-import { MainDocument } from '../../../../types/project-settings'
-import { PdfViewer } from '../../../../types/user-settings'
-
-type Scope = {
-  settings?: {
-    syntaxValidation?: boolean
-    pdfViewer?: PdfViewer
-  }
-  editor?: {
-    sharejs_doc?: {
-      doc_id?: string
-      getSnapshot?: () => string
-    }
-  }
-  ui?: {
-    view?: 'editor' | 'history' | 'file' | 'pdf'
-    pdfLayout?: 'flat' | 'sideBySide' | 'split'
-    leftMenuShown?: boolean
-  }
-  project?: {
-    members?: any[]
-    owner: {
-      _id: string
-    }
-    features?: {
-      gitBridge?: boolean
-    }
-  }
-  user?: {
-    features?: {
-      dropbox: boolean
-    }
-  }
-  docs?: MainDocument[]
-}
-
-export const mockScope = (scope?: Scope) => ({
-  settings: {
-    syntaxValidation: false,
-    pdfViewer: 'pdfjs',
-  },
-  editor: {
-    sharejs_doc: {
-      doc_id: 'test-doc',
-      getSnapshot: () => 'some doc content',
-    },
-  },
-  ...scope,
-})

+ 0 - 56
services/web/test/frontend/features/editor-left-menu/components/actions-copy-project.test.tsx

@@ -1,56 +0,0 @@
-import { fireEvent, screen, waitFor } from '@testing-library/react'
-import fetchMock from 'fetch-mock'
-import sinon from 'sinon'
-import { expect } from 'chai'
-import ActionsCopyProject from '../../../../../frontend/js/features/editor-left-menu/components/actions-copy-project'
-import { renderWithEditorContext } from '../../../helpers/render-with-context'
-import { location } from '@/shared/components/location'
-
-describe('<ActionsCopyProject />', function () {
-  beforeEach(function () {
-    this.locationWrapperSandbox = sinon.createSandbox()
-    this.locationWrapperStub = this.locationWrapperSandbox.stub(location)
-    window.metaAttributesCache.set('ol-preventCompileOnLoad', true)
-  })
-
-  afterEach(function () {
-    this.locationWrapperSandbox.restore()
-    fetchMock.removeRoutes().clearHistory()
-  })
-
-  it('shows correct modal when clicked', async function () {
-    renderWithEditorContext(<ActionsCopyProject />)
-
-    fireEvent.click(screen.getByRole('button', { name: 'Copy project' }))
-
-    screen.getByLabelText(/New name/i)
-  })
-
-  it('loads the project page when submitted', async function () {
-    fetchMock.post('express:/project/:id/clone', {
-      status: 200,
-      body: {
-        project_id: 'new-project',
-      },
-    })
-
-    renderWithEditorContext(<ActionsCopyProject />)
-
-    fireEvent.click(screen.getByRole('button', { name: 'Copy project' }))
-
-    const input = screen.getByLabelText(/New name/i)
-    fireEvent.change(input, { target: { value: 'New project' } })
-
-    const button = screen.getByRole('button', { name: 'Copy' })
-    button.click()
-
-    await waitFor(() => {
-      expect(button.textContent).to.equal('Copying…')
-    })
-
-    const assignStub = this.locationWrapperStub.assign
-    await waitFor(() => {
-      expect(assignStub).to.have.been.calledOnceWith('/project/new-project')
-    })
-  })
-})

+ 0 - 86
services/web/test/frontend/features/editor-left-menu/components/actions-menu.test.tsx

@@ -1,86 +0,0 @@
-import { screen, waitFor } from '@testing-library/react'
-import { expect } from 'chai'
-import fetchMock from 'fetch-mock'
-import ActionsMenu from '../../../../../frontend/js/features/editor-left-menu/components/actions-menu'
-import { renderWithEditorContext } from '../../../helpers/render-with-context'
-
-describe('<ActionsMenu />', function () {
-  beforeEach(function () {
-    fetchMock.post('express:/project/:projectId/compile', {
-      status: 'success',
-      pdfDownloadDomain: 'https://clsi.test-overleaf.com',
-      outputFiles: [
-        {
-          path: 'output.pdf',
-          build: 'build-123',
-          url: '/build/build-123/output.pdf',
-          type: 'pdf',
-        },
-      ],
-    })
-  })
-
-  afterEach(function () {
-    fetchMock.removeRoutes().clearHistory()
-  })
-
-  it('shows correct menu for non-anonymous users', async function () {
-    window.metaAttributesCache.set('ol-anonymous', false)
-
-    renderWithEditorContext(<ActionsMenu />, {
-      projectId: '123abc',
-      mockCompileOnLoad: true,
-      scope: {
-        editor: {
-          sharejs_doc: {
-            doc_id: 'test-doc',
-            getSnapshot: () => 'some doc content',
-          },
-        },
-      },
-    })
-
-    screen.getByText('Actions')
-    screen.getByRole('button', {
-      name: 'Copy project',
-    })
-
-    await waitFor(() => {
-      screen.getByRole('button', {
-        name: 'Word Count',
-      })
-    })
-  })
-
-  it('does not show anything for anonymous users', async function () {
-    window.metaAttributesCache.set('ol-anonymous', true)
-
-    renderWithEditorContext(<ActionsMenu />, {
-      projectId: '123abc',
-      mockCompileOnLoad: true,
-      scope: {
-        editor: {
-          sharejs_doc: {
-            doc_id: 'test-doc',
-            getSnapshot: () => 'some doc content',
-          },
-        },
-      },
-    })
-
-    expect(screen.queryByText('Actions')).to.equal(null)
-    expect(
-      screen.queryByRole('button', {
-        name: 'Copy project',
-      })
-    ).to.equal(null)
-
-    await waitFor(() => {
-      expect(
-        screen.queryByRole('button', {
-          name: 'Word Count',
-        })
-      ).to.equal(null)
-    })
-  })
-})

+ 0 - 66
services/web/test/frontend/features/editor-left-menu/components/actions-word-count.test.tsx

@@ -1,66 +0,0 @@
-import { screen, waitFor } from '@testing-library/react'
-import { expect } from 'chai'
-import fetchMock from 'fetch-mock'
-import ActionsWordCount from '../../../../../frontend/js/features/editor-left-menu/components/actions-word-count'
-import { renderWithEditorContext } from '../../../helpers/render-with-context'
-
-describe('<ActionsWordCount />', function () {
-  afterEach(function () {
-    fetchMock.removeRoutes().clearHistory()
-  })
-
-  it('shows correct modal when clicked after document is compiled', async function () {
-    const compileEndpoint = 'express:/project/:projectId/compile'
-    const wordcountEndpoint = 'express:/project/:projectId/wordcount'
-
-    fetchMock.post(compileEndpoint, {
-      status: 'success',
-      pdfDownloadDomain: 'https://clsi.test-overleaf.com',
-      outputFiles: [
-        {
-          path: 'output.pdf',
-          build: 'build-123',
-          url: '/build/build-123/output.pdf',
-          type: 'pdf',
-        },
-      ],
-    })
-
-    fetchMock.get(wordcountEndpoint, {
-      texcount: {
-        encode: 'ascii',
-        textWords: 0,
-        headers: 0,
-        mathInline: 0,
-        mathDisplay: 0,
-      },
-    })
-
-    renderWithEditorContext(<ActionsWordCount />, {
-      projectId: '123abc',
-      mockCompileOnLoad: true,
-      scope: {
-        editor: {
-          sharejs_doc: {
-            doc_id: 'test-doc',
-            getSnapshot: () => 'some doc content',
-          },
-        },
-      },
-    })
-
-    // when loading, we don't render the "Word Count" as button yet
-    expect(screen.queryByRole('button', { name: 'Word Count' })).to.equal(null)
-
-    await waitFor(
-      () => expect(fetchMock.callHistory.called(compileEndpoint)).to.be.true
-    )
-
-    const button = await screen.findByRole('button', { name: 'Word Count' })
-    button.click()
-
-    await waitFor(
-      () => expect(fetchMock.callHistory.called(wordcountEndpoint)).to.be.true
-    )
-  })
-})

+ 0 - 59
services/web/test/frontend/features/editor-left-menu/components/download-menu.test.tsx

@@ -1,59 +0,0 @@
-import { screen, waitFor } from '@testing-library/react'
-import { expect } from 'chai'
-import fetchMock from 'fetch-mock'
-import DownloadMenu from '../../../../../frontend/js/features/editor-left-menu/components/download-menu'
-import { renderWithEditorContext } from '../../../helpers/render-with-context'
-
-describe('<DownloadMenu />', function () {
-  afterEach(function () {
-    fetchMock.removeRoutes().clearHistory()
-  })
-
-  it('shows download links with correct url', async function () {
-    fetchMock.post('express:/project/:projectId/compile', {
-      clsiServerId: 'foo',
-      compileGroup: 'priority',
-      status: 'success',
-      pdfDownloadDomain: 'https://clsi.test-overleaf.com',
-      outputFiles: [
-        {
-          path: 'output.pdf',
-          build: 'build-123',
-          url: '/build/build-123/output.pdf',
-          type: 'pdf',
-        },
-      ],
-    })
-
-    renderWithEditorContext(<DownloadMenu />, {
-      projectId: '123abc',
-      mockCompileOnLoad: true,
-      scope: {
-        editor: {
-          sharejs_doc: {
-            doc_id: 'test-doc',
-            getSnapshot: () => 'some doc content',
-          },
-        },
-      },
-    })
-
-    const sourceLink = screen.getByRole('link', {
-      name: 'Source',
-    })
-
-    expect(sourceLink.getAttribute('href')).to.equal(
-      '/project/123abc/download/zip'
-    )
-
-    await waitFor(() => {
-      const pdfLink = screen.getByRole('link', {
-        name: 'PDF',
-      })
-
-      expect(pdfLink.getAttribute('href')).to.equal(
-        '/download/project/123abc/build/build-123/output/output.pdf?compileGroup=priority&clsiserverid=foo&popupDownload=true'
-      )
-    })
-  })
-})

+ 0 - 29
services/web/test/frontend/features/editor-left-menu/components/help-contact-us.test.tsx

@@ -1,29 +0,0 @@
-import { expect } from 'chai'
-import { screen, fireEvent, within } from '@testing-library/react'
-import HelpContactUs from '../../../../../frontend/js/features/editor-left-menu/components/help-contact-us'
-import { renderWithEditorContext } from '../../../helpers/render-with-context'
-import fetchMock from 'fetch-mock'
-
-describe('<HelpContactUs />', function () {
-  beforeEach(function () {
-    window.metaAttributesCache.set('ol-user', {
-      email: 'sherlock@holmes.co.uk',
-      first_name: 'Sherlock',
-      last_name: 'Holmes',
-    })
-  })
-
-  afterEach(function () {
-    fetchMock.removeRoutes().clearHistory()
-  })
-
-  it('open contact us modal when clicked', function () {
-    renderWithEditorContext(<HelpContactUs />)
-
-    expect(screen.queryByRole('dialog')).to.equal(null)
-    fireEvent.click(screen.getByRole('button', { name: 'Contact us' }))
-    const modal = screen.getAllByRole('dialog')[0]
-    within(modal).getAllByText('Get in touch')
-    within(modal).getByText('Subject')
-  })
-})

+ 0 - 12
services/web/test/frontend/features/editor-left-menu/components/help-documentation.test.tsx

@@ -1,12 +0,0 @@
-import { expect } from 'chai'
-import { screen, render } from '@testing-library/react'
-import HelpDocumentation from '../../../../../frontend/js/features/editor-left-menu/components/help-documentation'
-
-describe('<HelpDocumentation />', function () {
-  it('has correct href attribute', function () {
-    render(<HelpDocumentation />)
-
-    const link = screen.getByRole('link', { name: 'Documentation' })
-    expect(link.getAttribute('href')).to.equal('/learn')
-  })
-})

+ 0 - 39
services/web/test/frontend/features/editor-left-menu/components/help-menu.test.tsx

@@ -1,39 +0,0 @@
-import { screen } from '@testing-library/react'
-import { expect } from 'chai'
-import fetchMock from 'fetch-mock'
-import HelpMenu from '../../../../../frontend/js/features/editor-left-menu/components/help-menu'
-import { renderWithEditorContext } from '../../../helpers/render-with-context'
-
-describe('<HelpMenu />', function () {
-  beforeEach(function () {
-    window.metaAttributesCache.set('ol-user', {
-      email: 'sherlock@holmes.co.uk',
-      first_name: 'Sherlock',
-      last_name: 'Holmes',
-    })
-  })
-
-  afterEach(function () {
-    fetchMock.removeRoutes().clearHistory()
-  })
-
-  it('shows correct menu if `showSupport` is `true`', function () {
-    window.metaAttributesCache.set('ol-showSupport', true)
-
-    renderWithEditorContext(<HelpMenu />)
-
-    screen.getByRole('button', { name: 'Show Hotkeys' })
-    screen.getByRole('button', { name: 'Contact us' })
-    screen.getByRole('link', { name: 'Documentation' })
-  })
-
-  it('shows correct menu if `showSupport` is `false`', function () {
-    window.metaAttributesCache.set('ol-showSupport', false)
-
-    renderWithEditorContext(<HelpMenu />)
-
-    screen.getByRole('button', { name: 'Show Hotkeys' })
-    expect(screen.queryByRole('button', { name: 'Contact us' })).to.equal(null)
-    expect(screen.queryByRole('link', { name: 'Documentation' })).to.equal(null)
-  })
-})

+ 0 - 20
services/web/test/frontend/features/editor-left-menu/components/help-show-hotkeys.test.tsx

@@ -1,20 +0,0 @@
-import { expect } from 'chai'
-import { screen, fireEvent, within } from '@testing-library/react'
-import HelpShowHotkeys from '../../../../../frontend/js/features/editor-left-menu/components/help-show-hotkeys'
-import { renderWithEditorContext } from '../../../helpers/render-with-context'
-import fetchMock from 'fetch-mock'
-
-describe('<HelpShowHotkeys />', function () {
-  afterEach(function () {
-    fetchMock.removeRoutes().clearHistory()
-  })
-
-  it('open hotkeys modal when clicked', function () {
-    renderWithEditorContext(<HelpShowHotkeys />)
-
-    expect(screen.queryByRole('dialog')).to.equal(null)
-    fireEvent.click(screen.getByRole('button', { name: 'Show Hotkeys' }))
-    const modal = screen.getAllByRole('dialog')[0]
-    within(modal).getByText('Common')
-  })
-})

+ 0 - 30
services/web/test/frontend/features/editor-left-menu/components/settings/settings-auto-close-brackets.test.tsx

@@ -1,30 +0,0 @@
-import { screen, within, render } from '@testing-library/react'
-import { expect } from 'chai'
-import fetchMock from 'fetch-mock'
-import SettingsAutoCloseBrackets from '../../../../../../frontend/js/features/editor-left-menu/components/settings/settings-auto-close-brackets'
-import { EditorLeftMenuProvider } from '@/features/editor-left-menu/components/editor-left-menu-context'
-import { EditorProviders } from '../../../../helpers/editor-providers'
-
-describe('<SettingsAutoCloseBrackets />', function () {
-  afterEach(function () {
-    fetchMock.removeRoutes().clearHistory()
-  })
-
-  it('shows correct menu', async function () {
-    render(
-      <EditorProviders>
-        <EditorLeftMenuProvider>
-          <SettingsAutoCloseBrackets />
-        </EditorLeftMenuProvider>
-      </EditorProviders>
-    )
-
-    const select = screen.getByLabelText('Auto-close brackets')
-
-    const optionOn = within(select).getByText('On')
-    expect(optionOn.getAttribute('value')).to.equal('true')
-
-    const optionOff = within(select).getByText('Off')
-    expect(optionOff.getAttribute('value')).to.equal('false')
-  })
-})

+ 0 - 30
services/web/test/frontend/features/editor-left-menu/components/settings/settings-auto-complete.test.tsx

@@ -1,30 +0,0 @@
-import { screen, within, render } from '@testing-library/react'
-import { expect } from 'chai'
-import fetchMock from 'fetch-mock'
-import SettingsAutoComplete from '../../../../../../frontend/js/features/editor-left-menu/components/settings/settings-auto-complete'
-import { EditorLeftMenuProvider } from '@/features/editor-left-menu/components/editor-left-menu-context'
-import { EditorProviders } from '../../../../helpers/editor-providers'
-
-describe('<SettingsAutoComplete />', function () {
-  afterEach(function () {
-    fetchMock.removeRoutes().clearHistory()
-  })
-
-  it('shows correct menu', async function () {
-    render(
-      <EditorProviders>
-        <EditorLeftMenuProvider>
-          <SettingsAutoComplete />
-        </EditorLeftMenuProvider>
-      </EditorProviders>
-    )
-
-    const select = screen.getByLabelText('Auto-complete')
-
-    const optionOn = within(select).getByText('On')
-    expect(optionOn.getAttribute('value')).to.equal('true')
-
-    const optionOff = within(select).getByText('Off')
-    expect(optionOff.getAttribute('value')).to.equal('false')
-  })
-})

+ 0 - 36
services/web/test/frontend/features/editor-left-menu/components/settings/settings-compiler.test.tsx

@@ -1,36 +0,0 @@
-import { screen, within, render } from '@testing-library/react'
-import { expect } from 'chai'
-import fetchMock from 'fetch-mock'
-import SettingsCompiler from '../../../../../../frontend/js/features/editor-left-menu/components/settings/settings-compiler'
-import { EditorLeftMenuProvider } from '@/features/editor-left-menu/components/editor-left-menu-context'
-import { EditorProviders } from '../../../../helpers/editor-providers'
-
-describe('<SettingsCompiler />', function () {
-  afterEach(function () {
-    fetchMock.removeRoutes().clearHistory()
-  })
-
-  it('shows correct menu', async function () {
-    render(
-      <EditorProviders>
-        <EditorLeftMenuProvider>
-          <SettingsCompiler />
-        </EditorLeftMenuProvider>
-      </EditorProviders>
-    )
-
-    const select = screen.getByLabelText('Compiler')
-
-    const optionPdfLaTeX = within(select).getByText('pdfLaTeX')
-    expect(optionPdfLaTeX.getAttribute('value')).to.equal('pdflatex')
-
-    const optionLaTeX = within(select).getByText('LaTeX')
-    expect(optionLaTeX.getAttribute('value')).to.equal('latex')
-
-    const optionXeLaTeX = within(select).getByText('XeLaTeX')
-    expect(optionXeLaTeX.getAttribute('value')).to.equal('xelatex')
-
-    const optionLuaLaTeX = within(select).getByText('LuaLaTeX')
-    expect(optionLuaLaTeX.getAttribute('value')).to.equal('lualatex')
-  })
-})

+ 0 - 33
services/web/test/frontend/features/editor-left-menu/components/settings/settings-dictionary.test.tsx

@@ -1,33 +0,0 @@
-import { fireEvent, screen, within, render } from '@testing-library/react'
-import { expect } from 'chai'
-import SettingsDictionary from '../../../../../../frontend/js/features/editor-left-menu/components/settings/settings-dictionary'
-import { EditorLeftMenuProvider } from '@/features/editor-left-menu/components/editor-left-menu-context'
-import { EditorProviders } from '../../../../helpers/editor-providers'
-
-describe('<SettingsDictionary />', function () {
-  it('open dictionary modal', function () {
-    render(
-      <EditorProviders>
-        <EditorLeftMenuProvider>
-          <SettingsDictionary />
-        </EditorLeftMenuProvider>
-      </EditorProviders>
-    )
-
-    screen.getByText('Dictionary')
-
-    const button = screen.getByText('Edit')
-    fireEvent.click(button)
-
-    const modal = screen.getByTestId('dictionary-modal')
-
-    within(modal).getByRole('heading', { name: 'Edit Dictionary' })
-    within(modal).getByText('Your custom dictionary is empty.')
-
-    const closeButton = within(modal).getByRole('button', {
-      name: 'Close dialog',
-    })
-    fireEvent.click(closeButton)
-    expect(screen.getByTestId('dictionary-modal')).to.not.be.null
-  })
-})

+ 0 - 51
services/web/test/frontend/features/editor-left-menu/components/settings/settings-document.test.tsx

@@ -1,51 +0,0 @@
-import { screen, within, render } from '@testing-library/react'
-import { expect } from 'chai'
-import fetchMock from 'fetch-mock'
-import SettingsDocument from '../../../../../../frontend/js/features/editor-left-menu/components/settings/settings-document'
-import { Folder } from '../../../../../../types/folder'
-import { EditorLeftMenuProvider } from '@/features/editor-left-menu/components/editor-left-menu-context'
-import { EditorProviders } from '../../../../helpers/editor-providers'
-
-describe('<SettingsDocument />', function () {
-  const rootFolder: Folder = {
-    _id: 'root-folder-id',
-    name: 'rootFolder',
-    docs: [
-      {
-        _id: '123abc',
-        name: 'main.tex',
-      },
-    ],
-    fileRefs: [],
-    folders: [],
-  }
-
-  let originalSettings: typeof window.metaAttributesCache
-
-  beforeEach(function () {
-    originalSettings = window.metaAttributesCache.get('ol-ExposedSettings')
-    window.metaAttributesCache.set('ol-ExposedSettings', {
-      validRootDocExtensions: ['tex'],
-    })
-  })
-
-  afterEach(function () {
-    fetchMock.removeRoutes().clearHistory()
-    window.metaAttributesCache.set('ol-ExposedSettings', originalSettings)
-  })
-
-  it('shows correct menu', async function () {
-    render(
-      <EditorProviders rootFolder={[rootFolder as any]}>
-        <EditorLeftMenuProvider>
-          <SettingsDocument />
-        </EditorLeftMenuProvider>
-      </EditorProviders>
-    )
-
-    const select = screen.getByLabelText('Main document')
-
-    const optionOn = within(select).getByText('main.tex')
-    expect(optionOn.getAttribute('value')).to.equal('123abc')
-  })
-})

+ 0 - 112
services/web/test/frontend/features/editor-left-menu/components/settings/settings-editor-theme.test.tsx

@@ -1,112 +0,0 @@
-import { screen, within, render } from '@testing-library/react'
-import { expect } from 'chai'
-import fetchMock from 'fetch-mock'
-import SettingsEditorTheme from '../../../../../../frontend/js/features/editor-left-menu/components/settings/settings-editor-theme'
-import { EditorLeftMenuProvider } from '@/features/editor-left-menu/components/editor-left-menu-context'
-import { EditorProviders } from '../../../../helpers/editor-providers'
-
-const MOCK_IEEE_BRAND_ID = 123
-
-describe('<SettingsEditorTheme />', function () {
-  const editorThemes = [
-    { name: 'editortheme-1', dark: false },
-    { name: 'editortheme-2', dark: false },
-    { name: 'editortheme-3', dark: false },
-  ]
-
-  const legacyEditorThemes = [
-    { name: 'legacytheme-1', dark: false },
-    { name: 'legacytheme-2', dark: false },
-    { name: 'legacytheme-3', dark: false },
-  ]
-
-  beforeEach(function () {
-    window.metaAttributesCache.set('ol-editorThemes', editorThemes)
-    window.metaAttributesCache.set('ol-legacyEditorThemes', legacyEditorThemes)
-    window.metaAttributesCache.set('ol-brandVariation', {
-      brand_id: undefined,
-    })
-    window.metaAttributesCache.get('ol-ExposedSettings').ieeeBrandId =
-      MOCK_IEEE_BRAND_ID
-  })
-
-  afterEach(function () {
-    fetchMock.removeRoutes().clearHistory()
-  })
-
-  function checkSelect(select: HTMLElement) {
-    for (const theme of editorThemes) {
-      const option = within(select).getByText(theme.name.replace(/_/g, ' '))
-      expect(option.getAttribute('value')).to.equal(theme.name)
-    }
-
-    for (const theme of legacyEditorThemes) {
-      const option = within(select).getByText(
-        theme.name.replace(/_/g, ' ') + ' (Legacy)'
-      )
-      expect(option.getAttribute('value')).to.equal(theme.name)
-    }
-  }
-
-  describe('with default theme', function () {
-    beforeEach(function () {
-      render(
-        <EditorProviders userSettings={{ overallTheme: '' }}>
-          <EditorLeftMenuProvider>
-            <SettingsEditorTheme />
-          </EditorLeftMenuProvider>
-        </EditorProviders>
-      )
-    })
-
-    it('shows correct menu', async function () {
-      const select = screen.getByLabelText('Editor theme')
-      expect(select).to.exist
-      checkSelect(select)
-    })
-  })
-
-  describe('with system theme', function () {
-    beforeEach(function () {
-      render(
-        <EditorProviders userSettings={{ overallTheme: 'system' }}>
-          <EditorLeftMenuProvider>
-            <SettingsEditorTheme />
-          </EditorLeftMenuProvider>
-        </EditorProviders>
-      )
-    })
-
-    it('shows correct menu', async function () {
-      const select = screen.queryByLabelText('Editor theme')
-      expect(select).to.not.exist
-      const lightSelect = screen.getByLabelText('Light editor theme')
-      expect(lightSelect).to.exist
-      checkSelect(lightSelect)
-      const darkSelect = screen.getByLabelText('Dark editor theme')
-      expect(darkSelect).to.exist
-      checkSelect(darkSelect)
-    })
-  })
-
-  describe('with IEEE branding', function () {
-    beforeEach(function () {
-      window.metaAttributesCache.set('ol-brandVariation', {
-        brand_id: MOCK_IEEE_BRAND_ID,
-      })
-      render(
-        <EditorProviders userSettings={{ overallTheme: 'system' }}>
-          <EditorLeftMenuProvider>
-            <SettingsEditorTheme />
-          </EditorLeftMenuProvider>
-        </EditorProviders>
-      )
-    })
-
-    it('ignores the system theme and shows single selection', async function () {
-      const select = screen.getByLabelText('Editor theme')
-      expect(select).to.exist
-      checkSelect(select)
-    })
-  })
-})

+ 0 - 35
services/web/test/frontend/features/editor-left-menu/components/settings/settings-font-family.test.tsx

@@ -1,35 +0,0 @@
-import { screen, within, render } from '@testing-library/react'
-import { expect } from 'chai'
-import fetchMock from 'fetch-mock'
-import SettingsFontFamily from '../../../../../../frontend/js/features/editor-left-menu/components/settings/settings-font-family'
-import { EditorLeftMenuProvider } from '@/features/editor-left-menu/components/editor-left-menu-context'
-import { EditorProviders } from '../../../../helpers/editor-providers'
-
-describe('<SettingsFontFamily />', function () {
-  afterEach(function () {
-    fetchMock.removeRoutes().clearHistory()
-  })
-
-  it('shows correct menu', async function () {
-    render(
-      <EditorProviders>
-        <EditorLeftMenuProvider>
-          <SettingsFontFamily />
-        </EditorLeftMenuProvider>
-      </EditorProviders>
-    )
-
-    const select = screen.getByLabelText('Font Family')
-
-    const optionMonaco = within(select).getByText('Monaco / Menlo / Consolas')
-    expect(optionMonaco.getAttribute('value')).to.equal('monaco')
-
-    const optionLucida = within(select).getByText('Lucida / Source Code Pro')
-    expect(optionLucida.getAttribute('value')).to.equal('lucida')
-
-    const optionOpenDyslexicMono = within(select).getByText('OpenDyslexic Mono')
-    expect(optionOpenDyslexicMono.getAttribute('value')).to.equal(
-      'opendyslexicmono'
-    )
-  })
-})

+ 0 - 31
services/web/test/frontend/features/editor-left-menu/components/settings/settings-font-size.test.tsx

@@ -1,31 +0,0 @@
-import { screen, within, render } from '@testing-library/react'
-import { expect } from 'chai'
-import fetchMock from 'fetch-mock'
-import SettingsFontSize from '../../../../../../frontend/js/features/editor-left-menu/components/settings/settings-font-size'
-import { EditorLeftMenuProvider } from '@/features/editor-left-menu/components/editor-left-menu-context'
-import { EditorProviders } from '../../../../helpers/editor-providers'
-
-describe('<SettingsFontSize />', function () {
-  const sizes = ['10', '11', '12', '13', '14', '16', '18', '20', '22', '24']
-
-  afterEach(function () {
-    fetchMock.removeRoutes().clearHistory()
-  })
-
-  it('shows correct menu', async function () {
-    render(
-      <EditorProviders>
-        <EditorLeftMenuProvider>
-          <SettingsFontSize />
-        </EditorLeftMenuProvider>
-      </EditorProviders>
-    )
-
-    const select = screen.getByLabelText('Font Size')
-
-    for (const size of sizes) {
-      const option = within(select).getByText(`${size}px`)
-      expect(option.getAttribute('value')).to.equal(size)
-    }
-  })
-})

+ 0 - 47
services/web/test/frontend/features/editor-left-menu/components/settings/settings-image-name.test.tsx

@@ -1,47 +0,0 @@
-import { screen, within, render } from '@testing-library/react'
-import { expect } from 'chai'
-import fetchMock from 'fetch-mock'
-import SettingsImageName from '../../../../../../frontend/js/features/editor-left-menu/components/settings/settings-image-name'
-import type { ImageName } from '../../../../../../types/project-settings'
-import { EditorLeftMenuProvider } from '@/features/editor-left-menu/components/editor-left-menu-context'
-import { EditorProviders } from '../../../../helpers/editor-providers'
-
-describe('<SettingsImageName />', function () {
-  const imageNames: ImageName[] = [
-    {
-      imageDesc: 'Image 1',
-      imageName: 'img-1',
-      allowed: true,
-    },
-    {
-      imageDesc: 'Image 2',
-      imageName: 'img-2',
-      allowed: true,
-    },
-  ]
-
-  beforeEach(function () {
-    window.metaAttributesCache.set('ol-imageNames', imageNames)
-  })
-
-  afterEach(function () {
-    fetchMock.removeRoutes().clearHistory()
-  })
-
-  it('shows correct menu', async function () {
-    render(
-      <EditorProviders>
-        <EditorLeftMenuProvider>
-          <SettingsImageName />
-        </EditorLeftMenuProvider>
-      </EditorProviders>
-    )
-
-    const select = screen.getByLabelText('TeX Live version')
-
-    for (const { imageName, imageDesc } of imageNames) {
-      const option = within(select).getByText(imageDesc)
-      expect(option.getAttribute('value')).to.equal(imageName)
-    }
-  })
-})

+ 0 - 33
services/web/test/frontend/features/editor-left-menu/components/settings/settings-keybindings.test.tsx

@@ -1,33 +0,0 @@
-import { screen, within, render } from '@testing-library/react'
-import { expect } from 'chai'
-import fetchMock from 'fetch-mock'
-import SettingsKeybindings from '../../../../../../frontend/js/features/editor-left-menu/components/settings/settings-keybindings'
-import { EditorProviders } from '../../../../helpers/editor-providers'
-import { EditorLeftMenuProvider } from '@/features/editor-left-menu/components/editor-left-menu-context'
-
-describe('<SettingsKeybindings />', function () {
-  afterEach(function () {
-    fetchMock.removeRoutes().clearHistory()
-  })
-
-  it('shows correct menu', async function () {
-    render(
-      <EditorProviders>
-        <EditorLeftMenuProvider>
-          <SettingsKeybindings />
-        </EditorLeftMenuProvider>
-      </EditorProviders>
-    )
-
-    const select = screen.getByLabelText('Keybindings')
-
-    const optionNone = within(select).getByText('None')
-    expect(optionNone.getAttribute('value')).to.equal('default')
-
-    const optionVim = within(select).getByText('Vim')
-    expect(optionVim.getAttribute('value')).to.equal('vim')
-
-    const optionEmacs = within(select).getByText('Emacs')
-    expect(optionEmacs.getAttribute('value')).to.equal('emacs')
-  })
-})

+ 0 - 33
services/web/test/frontend/features/editor-left-menu/components/settings/settings-line-height.test.tsx

@@ -1,33 +0,0 @@
-import { screen, within, render } from '@testing-library/react'
-import { expect } from 'chai'
-import fetchMock from 'fetch-mock'
-import SettingsLineHeight from '../../../../../../frontend/js/features/editor-left-menu/components/settings/settings-line-height'
-import { EditorProviders } from '../../../../helpers/editor-providers'
-import { EditorLeftMenuProvider } from '@/features/editor-left-menu/components/editor-left-menu-context'
-
-describe('<SettingsLineHeight />', function () {
-  afterEach(function () {
-    fetchMock.removeRoutes().clearHistory()
-  })
-
-  it('shows correct menu', async function () {
-    render(
-      <EditorProviders>
-        <EditorLeftMenuProvider>
-          <SettingsLineHeight />
-        </EditorLeftMenuProvider>
-      </EditorProviders>
-    )
-
-    const select = screen.getByLabelText('Line Height')
-
-    const optionCompact = within(select).getByText('Compact')
-    expect(optionCompact.getAttribute('value')).to.equal('compact')
-
-    const optionNormal = within(select).getByText('Normal')
-    expect(optionNormal.getAttribute('value')).to.equal('normal')
-
-    const optionWide = within(select).getByText('Wide')
-    expect(optionWide.getAttribute('value')).to.equal('wide')
-  })
-})

+ 0 - 30
services/web/test/frontend/features/editor-left-menu/components/settings/settings-math-preview.test.tsx

@@ -1,30 +0,0 @@
-import { screen, within, render } from '@testing-library/react'
-import { expect } from 'chai'
-import fetchMock from 'fetch-mock'
-import SettingsMathPreview from '@/features/editor-left-menu/components/settings/settings-math-preview'
-import { EditorProviders } from '../../../../helpers/editor-providers'
-import { EditorLeftMenuProvider } from '@/features/editor-left-menu/components/editor-left-menu-context'
-
-describe('<SettingsMathPreview />', function () {
-  afterEach(function () {
-    fetchMock.removeRoutes().clearHistory()
-  })
-
-  it('shows correct menu', async function () {
-    render(
-      <EditorProviders>
-        <EditorLeftMenuProvider>
-          <SettingsMathPreview />
-        </EditorLeftMenuProvider>
-      </EditorProviders>
-    )
-
-    const select = screen.getByLabelText('Equation preview')
-
-    const optionOn = within(select).getByText('On')
-    expect(optionOn.getAttribute('value')).to.equal('true')
-
-    const optionOff = within(select).getByText('Off')
-    expect(optionOff.getAttribute('value')).to.equal('false')
-  })
-})

+ 0 - 98
services/web/test/frontend/features/editor-left-menu/components/settings/settings-overall-theme.test.tsx

@@ -1,98 +0,0 @@
-import { screen, within, render } from '@testing-library/react'
-import { expect } from 'chai'
-import fetchMock from 'fetch-mock'
-import SettingsOverallTheme from '../../../../../../frontend/js/features/editor-left-menu/components/settings/settings-overall-theme'
-import type { OverallThemeMeta } from '../../../../../../types/project-settings'
-import getMeta from '@/utils/meta'
-import { EditorProviders } from '../../../../helpers/editor-providers'
-import { EditorLeftMenuProvider } from '@/features/editor-left-menu/components/editor-left-menu-context'
-
-const IEEE_BRAND_ID = 1234
-const OTHER_BRAND_ID = 2234
-
-describe('<SettingsOverallTheme />', function () {
-  const overallThemes: OverallThemeMeta[] = [
-    {
-      name: 'Overall Theme 1',
-      val: '',
-      path: 'https://overleaf.com/overalltheme-1.css',
-    },
-    {
-      name: 'Overall Theme 2',
-      val: 'light-',
-      path: 'https://overleaf.com/overalltheme-2.css',
-    },
-  ]
-
-  beforeEach(function () {
-    window.metaAttributesCache.set('ol-overallThemes', overallThemes)
-    Object.assign(getMeta('ol-ExposedSettings'), {
-      ieeeBrandId: IEEE_BRAND_ID,
-    })
-  })
-
-  afterEach(function () {
-    fetchMock.removeRoutes().clearHistory()
-  })
-
-  it('shows correct menu', async function () {
-    render(
-      <EditorProviders>
-        <EditorLeftMenuProvider>
-          <SettingsOverallTheme />
-        </EditorLeftMenuProvider>
-      </EditorProviders>
-    )
-
-    const select = screen.getByLabelText('Overall theme')
-
-    for (const theme of overallThemes) {
-      const option = within(select).getByText(theme.name)
-      expect(option.getAttribute('value')).to.equal(theme.val)
-    }
-  })
-  describe('Branded Project', function () {
-    it('should hide overall theme picker for IEEE branded projects', function () {
-      window.metaAttributesCache.set('ol-brandVariation', {
-        brand_id: IEEE_BRAND_ID,
-      })
-      render(
-        <EditorProviders>
-          <EditorLeftMenuProvider>
-            <SettingsOverallTheme />
-          </EditorLeftMenuProvider>
-        </EditorProviders>
-      )
-      const select = screen.queryByText('Overall theme')
-      expect(select).to.not.exist
-    })
-
-    it('should show overall theme picker for branded projects that are not IEEE', function () {
-      window.metaAttributesCache.set('ol-brandVariation', {
-        brand_id: OTHER_BRAND_ID,
-      })
-      render(
-        <EditorProviders>
-          <EditorLeftMenuProvider>
-            <SettingsOverallTheme />
-          </EditorLeftMenuProvider>
-        </EditorProviders>
-      )
-      const select = screen.getByLabelText('Overall theme')
-      expect(select).to.exist
-    })
-
-    it('should show overall theme picker for non branded projects', function () {
-      window.metaAttributesCache.set('ol-brandVariation', undefined)
-      render(
-        <EditorProviders>
-          <EditorLeftMenuProvider>
-            <SettingsOverallTheme />
-          </EditorLeftMenuProvider>
-        </EditorProviders>
-      )
-      const select = screen.getByLabelText('Overall theme')
-      expect(select).to.exist
-    })
-  })
-})

+ 0 - 30
services/web/test/frontend/features/editor-left-menu/components/settings/settings-pdf-viewer.test.tsx

@@ -1,30 +0,0 @@
-import { screen, within, render } from '@testing-library/react'
-import { expect } from 'chai'
-import fetchMock from 'fetch-mock'
-import SettingsPdfViewer from '../../../../../../frontend/js/features/editor-left-menu/components/settings/settings-pdf-viewer'
-import { EditorProviders } from '../../../../helpers/editor-providers'
-import { EditorLeftMenuProvider } from '@/features/editor-left-menu/components/editor-left-menu-context'
-
-describe('<SettingsPdfViewer />', function () {
-  afterEach(function () {
-    fetchMock.removeRoutes().clearHistory()
-  })
-
-  it('shows correct menu', async function () {
-    render(
-      <EditorProviders>
-        <EditorLeftMenuProvider>
-          <SettingsPdfViewer />
-        </EditorLeftMenuProvider>
-      </EditorProviders>
-    )
-
-    const select = screen.getByLabelText('PDF Viewer')
-
-    const optionOverleaf = within(select).getByText('Overleaf')
-    expect(optionOverleaf.getAttribute('value')).to.equal('pdfjs')
-
-    const optionBrowser = within(select).getByText('Browser')
-    expect(optionBrowser.getAttribute('value')).to.equal('native')
-  })
-})

+ 0 - 50
services/web/test/frontend/features/editor-left-menu/components/settings/settings-spell-check-language.test.tsx

@@ -1,50 +0,0 @@
-import { screen, within, render } from '@testing-library/react'
-import { expect } from 'chai'
-import fetchMock from 'fetch-mock'
-import SettingsSpellCheckLanguage from '../../../../../../frontend/js/features/editor-left-menu/components/settings/settings-spell-check-language'
-import type { SpellCheckLanguage } from '../../../../../../types/project-settings'
-import { EditorProviders } from '../../../../helpers/editor-providers'
-import { EditorLeftMenuProvider } from '@/features/editor-left-menu/components/editor-left-menu-context'
-
-describe('<SettingsSpellCheckLanguage />', function () {
-  const languages: SpellCheckLanguage[] = [
-    {
-      name: 'Lang 1',
-      code: 'lang-1',
-      dic: 'lang_1',
-    },
-    {
-      name: 'Lang 2',
-      code: 'lang-2',
-      dic: 'lang_2',
-    },
-  ]
-
-  beforeEach(function () {
-    window.metaAttributesCache.set('ol-languages', languages)
-  })
-
-  afterEach(function () {
-    fetchMock.removeRoutes().clearHistory()
-  })
-
-  it('shows correct menu', async function () {
-    render(
-      <EditorProviders>
-        <EditorLeftMenuProvider>
-          <SettingsSpellCheckLanguage />
-        </EditorLeftMenuProvider>
-      </EditorProviders>
-    )
-
-    const select = screen.getByLabelText('Spell check')
-
-    const optionEmpty = within(select).getByText('Off')
-    expect(optionEmpty.getAttribute('value')).to.equal('')
-
-    for (const language of languages) {
-      const option = within(select).getByText(language.name)
-      expect(option.getAttribute('value')).to.equal(language.code)
-    }
-  })
-})

+ 0 - 30
services/web/test/frontend/features/editor-left-menu/components/settings/settings-syntax-validation.test.tsx

@@ -1,30 +0,0 @@
-import { screen, within, render } from '@testing-library/react'
-import { expect } from 'chai'
-import fetchMock from 'fetch-mock'
-import SettingsSyntaxValidation from '../../../../../../frontend/js/features/editor-left-menu/components/settings/settings-syntax-validation'
-import { EditorProviders } from '../../../../helpers/editor-providers'
-import { EditorLeftMenuProvider } from '@/features/editor-left-menu/components/editor-left-menu-context'
-
-describe('<SettingsSyntaxValidation />', function () {
-  afterEach(function () {
-    fetchMock.removeRoutes().clearHistory()
-  })
-
-  it('shows correct menu', async function () {
-    render(
-      <EditorProviders>
-        <EditorLeftMenuProvider>
-          <SettingsSyntaxValidation />
-        </EditorLeftMenuProvider>
-      </EditorProviders>
-    )
-
-    const select = screen.getByLabelText('Code check')
-
-    const optionOn = within(select).getByText('On')
-    expect(optionOn.getAttribute('value')).to.equal('true')
-
-    const optionOff = within(select).getByText('Off')
-    expect(optionOff.getAttribute('value')).to.equal('false')
-  })
-})

+ 3 - 4
services/web/test/frontend/features/settings-modal/settings/overall-theme-setting.test.tsx

@@ -1,7 +1,6 @@
 import { screen, within, render } from '@testing-library/react'
 import { expect } from 'chai'
 import fetchMock from 'fetch-mock'
-import SettingsOverallTheme from '../../../../../frontend/js/features/editor-left-menu/components/settings/settings-overall-theme'
 import type { OverallThemeMeta } from '../../../../../types/project-settings'
 import getMeta from '@/utils/meta'
 import { EditorProviders } from '../../../helpers/editor-providers'
@@ -76,7 +75,7 @@ describe('<OverallThemeSetting />', function () {
       render(
         <EditorProviders>
           <SettingsModalProvider>
-            <SettingsOverallTheme />
+            <OverallThemeSetting />
           </SettingsModalProvider>
         </EditorProviders>
       )
@@ -91,7 +90,7 @@ describe('<OverallThemeSetting />', function () {
       render(
         <EditorProviders>
           <SettingsModalProvider>
-            <SettingsOverallTheme />
+            <OverallThemeSetting />
           </SettingsModalProvider>
         </EditorProviders>
       )
@@ -104,7 +103,7 @@ describe('<OverallThemeSetting />', function () {
       render(
         <EditorProviders>
           <SettingsModalProvider>
-            <SettingsOverallTheme />
+            <OverallThemeSetting />
           </SettingsModalProvider>
         </EditorProviders>
       )