From 247f04557c83b2a146975348925aeee5e8ab991b Mon Sep 17 00:00:00 2001 From: Tim Down <158919+timdown@users.noreply.github.com> Date: Thu, 24 Apr 2025 14:33:59 +0100 Subject: [PATCH] Merge pull request #25073 from overleaf/td-upgrade-react-error-boundary Upgrade react-error-boundary to version 5 GitOrigin-RevId: ebccd35e10084aa221c437c09ddfdb86f6272cf3 --- package-lock.json | 15 ++++++--------- .../components/diff-view/diff-view.tsx | 19 ++++--------------- .../history/context/history-context.tsx | 8 ++------ .../context/hooks/use-restore-deleted-file.ts | 10 ++++------ .../context/hooks/use-restore-project.ts | 6 ++---- .../hooks/use-restore-selected-file.ts | 10 ++++------ .../hooks/use-codemirror-scope.ts | 6 +----- services/web/package.json | 2 +- 8 files changed, 24 insertions(+), 52 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5b460b88ba..dc82fa1342 100644 --- a/package-lock.json +++ b/package-lock.json @@ -35064,16 +35064,13 @@ } }, "node_modules/react-error-boundary": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-2.3.2.tgz", - "integrity": "sha512-ZMzi7s4pj/6A/6i9RS4tG7g1PdF2Rgr4/7FTQ8sbKHex19uNji0j+xq0OS//c6TUgQRKoL6P51BNNNFmYpRMhw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-5.0.0.tgz", + "integrity": "sha512-tnjAxG+IkpLephNcePNA7v6F/QpWLH8He65+DmedchDwg162JZqx4NmbXj0mlAYVVEd81OW7aFhmbsScYfiAFQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.11.2" - }, - "engines": { - "node": ">=10", - "npm": ">=6" + "@babel/runtime": "^7.12.5" }, "peerDependencies": { "react": ">=16.13.1" @@ -45422,7 +45419,7 @@ "react-dnd": "^16.0.1", "react-dnd-html5-backend": "^16.0.1", "react-dom": "^17.0.2", - "react-error-boundary": "^2.3.1", + "react-error-boundary": "^5.0.0", "react-google-recaptcha": "^3.1.0", "react-i18next": "^13.3.1", "react-linkify": "^1.0.0-alpha", diff --git a/services/web/frontend/js/features/history/components/diff-view/diff-view.tsx b/services/web/frontend/js/features/history/components/diff-view/diff-view.tsx index 82695a8189..47b9b84eb5 100644 --- a/services/web/frontend/js/features/history/components/diff-view/diff-view.tsx +++ b/services/web/frontend/js/features/history/components/diff-view/diff-view.tsx @@ -5,7 +5,6 @@ import { Diff, DocDiffResponse } from '../../services/types/doc' import { useHistoryContext } from '../../context/history-context' import { diffDoc } from '../../services/api' import { highlightsFromDiffResponse } from '../../utils/highlights-from-diff-response' -import { useErrorHandler } from 'react-error-boundary' import useAsync from '../../../../shared/hooks/use-async' import { useTranslation } from 'react-i18next' @@ -14,7 +13,6 @@ function DiffView() { const { isLoading, data, runAsync } = useAsync() const { t } = useTranslation() const { updateRange, selectedFile } = selection - const handleError = useErrorHandler() useEffect(() => { if (!updateRange || !selectedFile?.pathname || loadingFileDiffs) { @@ -32,11 +30,9 @@ function DiffView() { selectedFile.pathname, abortController.signal ) - ) - .catch(handleError) - .finally(() => { - abortController = null - }) + ).finally(() => { + abortController = null + }) // Abort an existing request before starting a new one or on unmount return () => { @@ -44,14 +40,7 @@ function DiffView() { abortController.abort() } } - }, [ - projectId, - runAsync, - updateRange, - selectedFile, - loadingFileDiffs, - handleError, - ]) + }, [projectId, runAsync, updateRange, selectedFile, loadingFileDiffs]) const diff = useMemo(() => { let diff: Diff | null diff --git a/services/web/frontend/js/features/history/context/history-context.tsx b/services/web/frontend/js/features/history/context/history-context.tsx index 7dc2c996c5..3740990941 100644 --- a/services/web/frontend/js/features/history/context/history-context.tsx +++ b/services/web/frontend/js/features/history/context/history-context.tsx @@ -25,7 +25,6 @@ import { Update, } from '../services/types/update' import { Selection } from '../services/types/selection' -import { useErrorHandler } from 'react-error-boundary' import { getUpdateForVersion } from '../utils/history-details' import { getHueForUserId } from '@/shared/utils/colors' @@ -99,7 +98,6 @@ function useHistory() { ) const updatesAbortControllerRef = useRef(null) - const handleError = useErrorHandler() const fetchNextBatchOfUpdates = useCallback(() => { // If there is an in-flight request for updates, just let it complete, by @@ -199,11 +197,10 @@ function useHistory() { loadingState: 'ready', }) }) - .catch(handleError) .finally(() => { updatesAbortControllerRef.current = null }) - }, [updatesInfo, projectId, labels, handleError, userHasFullFeature]) + }, [updatesInfo, projectId, labels, userHasFullFeature]) // Abort in-flight updates request on unmount useEffect(() => { @@ -284,7 +281,6 @@ function useHistory() { } }) }) - .catch(handleError) .finally(() => { setLoadingFileDiffs(false) abortController = null @@ -295,7 +291,7 @@ function useHistory() { abortController.abort() } } - }, [projectId, fromV, toV, updateForToV, handleError]) + }, [projectId, fromV, toV, updateForToV]) useEffect(() => { // Set update range if there isn't one and updates have loaded diff --git a/services/web/frontend/js/features/history/context/hooks/use-restore-deleted-file.ts b/services/web/frontend/js/features/history/context/hooks/use-restore-deleted-file.ts index 226991e3b1..2b8b740b51 100644 --- a/services/web/frontend/js/features/history/context/hooks/use-restore-deleted-file.ts +++ b/services/web/frontend/js/features/history/context/hooks/use-restore-deleted-file.ts @@ -4,7 +4,6 @@ import { restoreFile } from '../../services/api' import { isFileRemoved } from '../../utils/file-diff' import { useHistoryContext } from '../history-context' import type { HistoryContextValue } from '../types/history-context-value' -import { useErrorHandler } from 'react-error-boundary' import { useFileTreeData } from '@/shared/context/file-tree-data-context' import { findInTree } from '@/features/file-tree/util/find-in-tree' import { useCallback, useEffect, useState } from 'react' @@ -23,7 +22,6 @@ export function useRestoreDeletedFile() { const { projectId } = useHistoryContext() const { setView } = useLayoutContext() const { openDocWithId, openFileWithId } = useEditorManagerContext() - const handleError = useErrorHandler() const { fileTreeData } = useFileTreeData() const [state, setState] = useState('idle') const [restoredFileMetadata, setRestoredFileMetadata] = @@ -59,14 +57,14 @@ export function useRestoreDeletedFile() { if (state === 'waitingForFileTree') { const timer = window.setTimeout(() => { setState('timedOut') - handleError(new Error('timed out')) + throw new Error('timed out') }, 3000) return () => { window.clearTimeout(timer) } } - }, [handleError, state]) + }, [state]) const restoreDeletedFile = useCallback( (selection: HistoryContextValue['selection']) => { @@ -93,13 +91,13 @@ export function useRestoreDeletedFile() { }, error => { setState('error') - handleError(error) + throw error } ) } } }, - [handleError, projectId] + [projectId] ) return { restoreDeletedFile, isLoading } diff --git a/services/web/frontend/js/features/history/context/hooks/use-restore-project.ts b/services/web/frontend/js/features/history/context/hooks/use-restore-project.ts index ec4e4a4ef8..8675c1701d 100644 --- a/services/web/frontend/js/features/history/context/hooks/use-restore-project.ts +++ b/services/web/frontend/js/features/history/context/hooks/use-restore-project.ts @@ -1,12 +1,10 @@ import { useCallback, useState } from 'react' -import { useErrorHandler } from 'react-error-boundary' import { restoreProjectToVersion } from '../../services/api' import { useLayoutContext } from '@/shared/context/layout-context' type RestorationState = 'initial' | 'restoring' | 'restored' | 'error' export const useRestoreProject = () => { - const handleError = useErrorHandler() const { setView } = useLayoutContext() const [restorationState, setRestorationState] = @@ -22,10 +20,10 @@ export const useRestoreProject = () => { }) .catch(err => { setRestorationState('error') - handleError(err) + throw err }) }, - [handleError, setView] + [setView] ) return { diff --git a/services/web/frontend/js/features/history/context/hooks/use-restore-selected-file.ts b/services/web/frontend/js/features/history/context/hooks/use-restore-selected-file.ts index 12b72faafd..f4d5b1b9ab 100644 --- a/services/web/frontend/js/features/history/context/hooks/use-restore-selected-file.ts +++ b/services/web/frontend/js/features/history/context/hooks/use-restore-selected-file.ts @@ -3,7 +3,6 @@ import { restoreFileToVersion } from '../../services/api' import { isFileRemoved } from '../../utils/file-diff' import { useHistoryContext } from '../history-context' import type { HistoryContextValue } from '../types/history-context-value' -import { useErrorHandler } from 'react-error-boundary' import { useFileTreeData } from '@/shared/context/file-tree-data-context' import { findInTree } from '@/features/file-tree/util/find-in-tree' import { useCallback, useEffect, useState } from 'react' @@ -24,7 +23,6 @@ export function useRestoreSelectedFile() { const { projectId } = useHistoryContext() const { setView } = useLayoutContext() const { openDocWithId, openFileWithId } = useEditorManagerContext() - const handleError = useErrorHandler() const { fileTreeData } = useFileTreeData() const [state, setState] = useState('idle') const [restoredFileMetadata, setRestoredFileMetadata] = @@ -60,14 +58,14 @@ export function useRestoreSelectedFile() { if (state === 'waitingForFileTree') { const timer = window.setTimeout(() => { setState('timedOut') - handleError(new Error('timed out')) + throw new Error('timed out') }, RESTORE_FILE_TIMEOUT) return () => { window.clearTimeout(timer) } } - }, [handleError, state]) + }, [state]) const restoreSelectedFile = useCallback( (selection: HistoryContextValue['selection']) => { @@ -91,13 +89,13 @@ export function useRestoreSelectedFile() { }, error => { setState('error') - handleError(error) + throw error } ) } } }, - [handleError, projectId] + [projectId] ) return { restoreSelectedFile, isLoading } diff --git a/services/web/frontend/js/features/source-editor/hooks/use-codemirror-scope.ts b/services/web/frontend/js/features/source-editor/hooks/use-codemirror-scope.ts index 598cd60f15..86f47ec2d9 100644 --- a/services/web/frontend/js/features/source-editor/hooks/use-codemirror-scope.ts +++ b/services/web/frontend/js/features/source-editor/hooks/use-codemirror-scope.ts @@ -33,7 +33,6 @@ import { setSpellCheckLanguage } from '../extensions/spelling' import { setKeybindings } from '../extensions/keybindings' import { Highlight } from '../../../../../types/highlight' import { EditorView } from '@codemirror/view' -import { useErrorHandler } from 'react-error-boundary' import { setVisual } from '../extensions/visual/visual' import { useFileTreePathContext } from '@/features/file-tree/contexts/file-tree-path' import { useUserSettingsContext } from '@/shared/context/user-settings-context' @@ -265,8 +264,6 @@ function useCodeMirrorScope(view: EditorView) { visual: showVisual, }) - const handleError = useErrorHandler() - const handleException = useCallback((exception: any) => { captureException(exception, { tags: { @@ -304,7 +301,6 @@ function useCodeMirrorScope(view: EditorView) { spelling: spellingRef.current, visual: visualRef.current, projectFeatures: projectFeaturesRef.current, - handleError, handleException, }), }) @@ -335,7 +331,7 @@ function useCodeMirrorScope(view: EditorView) { } // IMPORTANT: This effect must not depend on anything variable apart from currentDocument, // as the editor state is recreated when the effect runs. - }, [view, currentDocument, handleError, handleException]) + }, [view, currentDocument, handleException]) useEffect(() => { if (openDocName) { diff --git a/services/web/package.json b/services/web/package.json index a80b86dd0f..806bbe2f5d 100644 --- a/services/web/package.json +++ b/services/web/package.json @@ -333,7 +333,7 @@ "react-dnd": "^16.0.1", "react-dnd-html5-backend": "^16.0.1", "react-dom": "^17.0.2", - "react-error-boundary": "^2.3.1", + "react-error-boundary": "^5.0.0", "react-google-recaptcha": "^3.1.0", "react-i18next": "^13.3.1", "react-linkify": "^1.0.0-alpha",