mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
History migration: Add error handling for all history requests (#12872)
* Add error handling for all history requests * Remove comment GitOrigin-RevId: 528dc98a0fc4ab523f8536274996c4166be45064
This commit is contained in:
parent
70bae34bd8
commit
1fb921de99
9 changed files with 86 additions and 49 deletions
|
@ -4,7 +4,7 @@ import { Alert } from 'react-bootstrap'
|
|||
// Using this workaround due to inconsistent and improper error responses from the server
|
||||
type ModalErrorProps = {
|
||||
error: {
|
||||
response: Response
|
||||
response?: Response
|
||||
data?: {
|
||||
message?: string
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ type ModalErrorProps = {
|
|||
function ModalError({ error }: ModalErrorProps) {
|
||||
const { t } = useTranslation()
|
||||
|
||||
if (error.response.status === 400 && error?.data?.message) {
|
||||
if (error.response?.status === 400 && error.data?.message) {
|
||||
return <Alert bsStyle="danger">{error.data.message}</Alert>
|
||||
}
|
||||
|
||||
|
|
|
@ -7,12 +7,13 @@ import { useHistoryContext } from '../../context/history-context'
|
|||
import { diffDoc } from '../../services/api'
|
||||
import { highlightsFromDiffResponse } from '../../utils/highlights-from-diff-response'
|
||||
import useAsync from '../../../../shared/hooks/use-async'
|
||||
import ErrorMessage from '../error-message'
|
||||
|
||||
function DiffView() {
|
||||
const [diff, setDiff] = useState<Nullable<Diff>>(null)
|
||||
const { selection, projectId } = useHistoryContext()
|
||||
|
||||
const { isLoading, runAsync } = useAsync<DocDiffResponse>()
|
||||
const { isLoading, runAsync, error } = useAsync<DocDiffResponse>()
|
||||
|
||||
const { updateRange, selectedFile } = selection
|
||||
|
||||
|
@ -23,9 +24,8 @@ function DiffView() {
|
|||
|
||||
const { fromV, toV } = updateRange
|
||||
|
||||
// TODO: Error handling
|
||||
runAsync(diffDoc(projectId, fromV, toV, selectedFile.pathname)).then(
|
||||
data => {
|
||||
runAsync(diffDoc(projectId, fromV, toV, selectedFile.pathname))
|
||||
.then(data => {
|
||||
let diff: Diff | undefined
|
||||
|
||||
if (!data?.diff) {
|
||||
|
@ -42,18 +42,24 @@ function DiffView() {
|
|||
}
|
||||
|
||||
setDiff(diff)
|
||||
}
|
||||
)
|
||||
})
|
||||
.catch(console.error)
|
||||
}, [projectId, runAsync, updateRange, selectedFile])
|
||||
|
||||
return (
|
||||
<div className="doc-panel">
|
||||
<div className="history-header toolbar-container">
|
||||
<Toolbar diff={diff} selection={selection} />
|
||||
</div>
|
||||
<div className="doc-container">
|
||||
<Main diff={diff} isLoading={isLoading} />
|
||||
</div>
|
||||
{error ? (
|
||||
<ErrorMessage />
|
||||
) : (
|
||||
<>
|
||||
<div className="history-header toolbar-container">
|
||||
<Toolbar diff={diff} selection={selection} />
|
||||
</div>
|
||||
<div className="doc-container">
|
||||
<Main diff={diff} isLoading={isLoading} />
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
export default function ErrorMessage() {
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<div className="history-error">
|
||||
<div className="text-danger error">
|
||||
{t('generic_something_went_wrong')}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -7,13 +7,13 @@ import {
|
|||
import HistoryFileTreeFolderList from './file-tree/history-file-tree-folder-list'
|
||||
|
||||
export default function HistoryFileTree() {
|
||||
const { files } = useHistoryContext().selection
|
||||
const { selection, error } = useHistoryContext()
|
||||
|
||||
const fileTree = _.reduce(files, reducePathsToTree, [])
|
||||
const fileTree = _.reduce(selection.files, reducePathsToTree, [])
|
||||
|
||||
const mappedFileTree = fileTreeDiffToFileTreeData(fileTree)
|
||||
|
||||
return (
|
||||
return error ? null : (
|
||||
<HistoryFileTreeFolderList
|
||||
folders={mappedFileTree.folders}
|
||||
docs={mappedFileTree.docs ?? []}
|
||||
|
|
|
@ -4,27 +4,33 @@ import { HistoryProvider, useHistoryContext } from '../context/history-context'
|
|||
import { createPortal } from 'react-dom'
|
||||
import HistoryFileTree from './history-file-tree'
|
||||
import LoadingSpinner from '../../../shared/components/loading-spinner'
|
||||
import ErrorMessage from './error-message'
|
||||
|
||||
const fileTreeContainer = document.getElementById('history-file-tree')
|
||||
|
||||
function Main() {
|
||||
const { loadingState } = useHistoryContext()
|
||||
const { loadingState, error } = useHistoryContext()
|
||||
|
||||
let content = null
|
||||
if (loadingState === 'loadingInitial') {
|
||||
content = <LoadingSpinner />
|
||||
} else if (error) {
|
||||
content = <ErrorMessage />
|
||||
} else {
|
||||
content = (
|
||||
<>
|
||||
<DiffView />
|
||||
<ChangeList />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{fileTreeContainer
|
||||
? createPortal(<HistoryFileTree />, fileTreeContainer)
|
||||
: null}
|
||||
<div className="history-react">
|
||||
{loadingState === 'loadingInitial' ? (
|
||||
<LoadingSpinner />
|
||||
) : (
|
||||
<>
|
||||
<DiffView />
|
||||
<ChangeList />
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<div className="history-react">{content}</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -88,7 +88,7 @@ function useHistory() {
|
|||
const [labels, setLabels] = useState<HistoryContextValue['labels']>(null)
|
||||
const [loadingState, setLoadingState] =
|
||||
useState<HistoryContextValue['loadingState']>('loadingInitial')
|
||||
const [error, setError] = useState(null)
|
||||
const [error, setError] = useState<HistoryContextValue['error']>(null)
|
||||
|
||||
const fetchNextBatchOfUpdates = useCallback(() => {
|
||||
const loadUpdates = (updatesData: Update[]) => {
|
||||
|
@ -197,28 +197,32 @@ function useHistory() {
|
|||
}
|
||||
const { fromV, toV } = updateRange
|
||||
|
||||
diffFiles(projectId, fromV, toV).then(({ diff: files }) => {
|
||||
const selectedFile = autoSelectFile(
|
||||
files,
|
||||
updateRange.toV,
|
||||
comparing,
|
||||
updates
|
||||
)
|
||||
const newFiles = files.map(file => {
|
||||
if (isFileRenamed(file) && file.newPathname) {
|
||||
return renamePathnameKey(file)
|
||||
}
|
||||
diffFiles(projectId, fromV, toV)
|
||||
.then(({ diff: files }) => {
|
||||
const selectedFile = autoSelectFile(
|
||||
files,
|
||||
updateRange.toV,
|
||||
comparing,
|
||||
updates
|
||||
)
|
||||
const newFiles = files.map(file => {
|
||||
if (isFileRenamed(file) && file.newPathname) {
|
||||
return renamePathnameKey(file)
|
||||
}
|
||||
|
||||
return file
|
||||
return file
|
||||
})
|
||||
setSelection({
|
||||
updateRange,
|
||||
comparing,
|
||||
files: newFiles,
|
||||
selectedFile,
|
||||
})
|
||||
})
|
||||
setSelection({
|
||||
updateRange,
|
||||
comparing,
|
||||
files: newFiles,
|
||||
selectedFile,
|
||||
.catch(error => {
|
||||
setError(error)
|
||||
})
|
||||
})
|
||||
}, [updateRange, projectId, updates, comparing])
|
||||
}, [updateRange, projectId, updates, comparing, setError])
|
||||
|
||||
useEffect(() => {
|
||||
// Set update range if there isn't one and updates have loaded
|
||||
|
@ -239,6 +243,7 @@ function useHistory() {
|
|||
const value = useMemo<HistoryContextValue>(
|
||||
() => ({
|
||||
error,
|
||||
setError,
|
||||
loadingState,
|
||||
setLoadingState,
|
||||
updatesInfo,
|
||||
|
@ -255,6 +260,7 @@ function useHistory() {
|
|||
}),
|
||||
[
|
||||
error,
|
||||
setError,
|
||||
loadingState,
|
||||
setLoadingState,
|
||||
updatesInfo,
|
||||
|
|
|
@ -9,7 +9,7 @@ import type { HistoryContextValue } from '../types/history-context-value'
|
|||
|
||||
export function useRestoreDeletedFile() {
|
||||
const { runAsync } = useAsync()
|
||||
const { setLoadingState, projectId } = useHistoryContext()
|
||||
const { setLoadingState, projectId, setError } = useHistoryContext()
|
||||
const ide = useIdeContext()
|
||||
const { setView } = useLayoutContext()
|
||||
|
||||
|
@ -35,6 +35,7 @@ export function useRestoreDeletedFile() {
|
|||
|
||||
setView('editor')
|
||||
})
|
||||
.catch(error => setError(error))
|
||||
.finally(() => {
|
||||
setLoadingState('ready')
|
||||
})
|
||||
|
|
|
@ -27,6 +27,7 @@ export type HistoryContextValue = {
|
|||
React.SetStateAction<HistoryContextValue['loadingState']>
|
||||
>
|
||||
error: Nullable<unknown>
|
||||
setError: React.Dispatch<React.SetStateAction<HistoryContextValue['error']>>
|
||||
labels: Nullable<LoadedLabel[]>
|
||||
setLabels: React.Dispatch<React.SetStateAction<HistoryContextValue['labels']>>
|
||||
projectId: string
|
||||
|
|
|
@ -485,3 +485,7 @@ history-root {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.history-error {
|
||||
padding: 16px;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue