From c732a02b3818d97d861bf8798a1f37c6c09e3bb0 Mon Sep 17 00:00:00 2001 From: Alf Eaton Date: Fri, 25 Apr 2025 11:23:05 +0100 Subject: [PATCH] Use toast notifications for SyncTeX errors and handle missing file errors (#24579) GitOrigin-RevId: 88c6658ff0d11fdb43cef19c48b542a3b2206666 --- .../ide-react/components/alerts/alerts.tsx | 22 --------- .../ide-react/context/ide-react-context.tsx | 1 - .../components/pdf-synctex-controls.tsx | 25 +++------- .../pdf-preview/components/synctex-toasts.tsx | 47 +++++++++++++++++++ .../stories/editor/synctex-toasts.stories.tsx | 26 ++++++++++ .../web/frontend/stylesheets/app/editor.less | 4 -- .../bootstrap-5/pages/editor/pdf.scss | 5 ++ 7 files changed, 85 insertions(+), 45 deletions(-) create mode 100644 services/web/frontend/js/features/pdf-preview/components/synctex-toasts.tsx create mode 100644 services/web/frontend/stories/editor/synctex-toasts.stories.tsx diff --git a/services/web/frontend/js/features/ide-react/components/alerts/alerts.tsx b/services/web/frontend/js/features/ide-react/components/alerts/alerts.tsx index 98f23d8f2a..4829913ade 100644 --- a/services/web/frontend/js/features/ide-react/components/alerts/alerts.tsx +++ b/services/web/frontend/js/features/ide-react/components/alerts/alerts.tsx @@ -2,11 +2,9 @@ import { useTranslation } from 'react-i18next' import { LostConnectionAlert } from './lost-connection-alert' import { useConnectionContext } from '@/features/ide-react/context/connection-context' import { debugging } from '@/utils/debugging' -import useScopeValue from '@/shared/hooks/use-scope-value' import { createPortal } from 'react-dom' import { useGlobalAlertsContainer } from '@/features/ide-react/context/global-alerts-context' import OLNotification from '@/features/ui/components/ol/ol-notification' -import OLButton from '@/features/ui/components/ol/ol-button' export function Alerts() { const { t } = useTranslation() @@ -19,8 +17,6 @@ export function Alerts() { } = useConnectionContext() const globalAlertsContainer = useGlobalAlertsContainer() - const [synctexError] = useScopeValue('sync_tex_error') - if (!globalAlertsContainer) { return null } @@ -50,24 +46,6 @@ export function Alerts() { /> ) : null} - {synctexError ? ( - {t('synctex_failed')}} - action={ - - {t('more_info')} - - } - /> - ) : null} - {connectionState.inactiveDisconnect || (connectionState.readyState === WebSocket.CLOSED && (connectionState.error === 'rate-limited' || diff --git a/services/web/frontend/js/features/ide-react/context/ide-react-context.tsx b/services/web/frontend/js/features/ide-react/context/ide-react-context.tsx index 313989903a..da3aad097e 100644 --- a/services/web/frontend/js/features/ide-react/context/ide-react-context.tsx +++ b/services/web/frontend/js/features/ide-react/context/ide-react-context.tsx @@ -41,7 +41,6 @@ export const IdeReactContext = createContext( function populateIdeReactScope(store: ReactScopeValueStore) { store.set('settings', {}) - store.set('sync_tex_error', false) } function populateProjectScope(store: ReactScopeValueStore) { diff --git a/services/web/frontend/js/features/pdf-preview/components/pdf-synctex-controls.tsx b/services/web/frontend/js/features/pdf-preview/components/pdf-synctex-controls.tsx index 12013f48eb..7d91f3251f 100644 --- a/services/web/frontend/js/features/pdf-preview/components/pdf-synctex-controls.tsx +++ b/services/web/frontend/js/features/pdf-preview/components/pdf-synctex-controls.tsx @@ -4,7 +4,6 @@ import { useProjectContext } from '../../../shared/context/project-context' import { getJSON } from '../../../infrastructure/fetch-json' import { useDetachCompileContext as useCompileContext } from '../../../shared/context/detach-compile-context' import { useLayoutContext } from '../../../shared/context/layout-context' -import useScopeValue from '../../../shared/hooks/use-scope-value' import { useTranslation } from 'react-i18next' import useIsMounted from '../../../shared/hooks/use-is-mounted' import useAbortController from '../../../shared/hooks/use-abort-controller' @@ -26,6 +25,7 @@ import { CursorPosition } from '@/features/ide-react/types/cursor-position' import { isValidTeXFile } from '@/main/is-valid-tex-file' import { PdfScrollPosition } from '@/shared/hooks/use-pdf-scroll-position' import { Placement } from 'react-bootstrap-5/types' +import { showFileErrorToast } from '@/features/pdf-preview/components/synctex-toasts' const GoToCodeButton = memo(function GoToCodeButton({ syncToCode, @@ -183,8 +183,6 @@ function PdfSynctexControls() { 'detached' ) - const [, setSynctexError] = useScopeValue('sync_tex_error') - const getCurrentFilePath = useCallback(() => { const docId = getCurrentDocumentId() @@ -212,25 +210,16 @@ function PdfSynctexControls() { (file, line) => { if (file) { const doc = findEntityByPath(file)?.entity - if (!doc) { - debugConsole.warn(`Document with path ${file} not found`) + if (doc) { + openDocWithId(doc._id, { + gotoLine: line, + }) return } - - openDocWithId(doc._id, { - gotoLine: line, - }) - } else { - setSynctexError(true) - - window.setTimeout(() => { - if (isMounted.current) { - setSynctexError(false) - } - }, 4000) } + showFileErrorToast() }, - [findEntityByPath, openDocWithId, isMounted, setSynctexError] + [findEntityByPath, openDocWithId] ) const goToPdfLocation = useCallback( diff --git a/services/web/frontend/js/features/pdf-preview/components/synctex-toasts.tsx b/services/web/frontend/js/features/pdf-preview/components/synctex-toasts.tsx new file mode 100644 index 0000000000..62806b85e9 --- /dev/null +++ b/services/web/frontend/js/features/pdf-preview/components/synctex-toasts.tsx @@ -0,0 +1,47 @@ +import { GlobalToastGeneratorEntry } from '@/features/ide-react/components/global-toasts' +import { useTranslation } from 'react-i18next' +import OLButton from '@/features/ui/components/ol/ol-button' + +export const SynctexFileErrorToast = () => { + const { t } = useTranslation() + + return ( +
+ {t('synctex_failed')} + + + {t('more_info')} + +
+ ) +} + +const generators: GlobalToastGeneratorEntry[] = [ + { + key: 'synctex:file-error', + generator: () => ({ + content: , + type: 'warning', + autoHide: true, + delay: 4000, + isDismissible: true, + }), + }, +] + +export default generators + +export const showFileErrorToast = () => { + window.dispatchEvent( + new CustomEvent('ide:show-toast', { + detail: { + key: 'synctex:file-error', + }, + }) + ) +} diff --git a/services/web/frontend/stories/editor/synctex-toasts.stories.tsx b/services/web/frontend/stories/editor/synctex-toasts.stories.tsx new file mode 100644 index 0000000000..0e4a55c5f6 --- /dev/null +++ b/services/web/frontend/stories/editor/synctex-toasts.stories.tsx @@ -0,0 +1,26 @@ +import { Meta, StoryObj } from '@storybook/react' +import { OLToast } from '@/features/ui/components/ol/ol-toast' +import { SynctexFileErrorToast } from '@/features/pdf-preview/components/synctex-toasts' + +const meta = { + title: 'Editor/ Synctex File Error Toast', + component: SynctexFileErrorToast, + decorators: [ + Story => ( +
+ } /> +
+ ), + ], +} satisfies Meta + +export default meta +type Story = StoryObj + +export const WithoutFile = { + args: { data: {} }, +} satisfies Story + +export const WithFile = { + args: { data: { filePath: 'references.bbl' } }, +} satisfies Story diff --git a/services/web/frontend/stylesheets/app/editor.less b/services/web/frontend/stylesheets/app/editor.less index 544fbb7b38..3139c98678 100644 --- a/services/web/frontend/stylesheets/app/editor.less +++ b/services/web/frontend/stylesheets/app/editor.less @@ -83,10 +83,6 @@ margin-left: 20px; } -#synctex-more-info-button { - margin-left: 20px; -} - #ide-body { background-color: @pdf-bg; .full-size; diff --git a/services/web/frontend/stylesheets/bootstrap-5/pages/editor/pdf.scss b/services/web/frontend/stylesheets/bootstrap-5/pages/editor/pdf.scss index 78c7072ca7..7293db2c95 100644 --- a/services/web/frontend/stylesheets/bootstrap-5/pages/editor/pdf.scss +++ b/services/web/frontend/stylesheets/bootstrap-5/pages/editor/pdf.scss @@ -442,3 +442,8 @@ top: var(--spacing-10); z-index: 1; } + +.synctex-error-toast-content { + display: flex; + gap: 20px; +}