mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-12 13:13:45 +01:00
Merge pull request #36074 from overleaf/mj-reload-after-failed-catch-up
[web] Reload after failed intermittent-connection catchup GitOrigin-RevId: c9a6315ecb6ebe957ad85c05ebc84bb8165881ab
This commit is contained in:
committed by
Copybot
parent
35ba44f22b
commit
d1691345c5
+12
-1
@@ -14,6 +14,7 @@ import { uploadBatch } from '@/infrastructure/batch-file-uploader'
|
||||
import { debugConsole } from '@/utils/debugging'
|
||||
import Notification from '@/shared/components/notification'
|
||||
import { downloadFileContent } from '@/utils/download-file'
|
||||
import { useLocation } from '@/shared/hooks/use-location'
|
||||
|
||||
export type UnableToSyncModalProps = {
|
||||
baseContent: string
|
||||
@@ -22,6 +23,7 @@ export type UnableToSyncModalProps = {
|
||||
rootFolderId: string | undefined
|
||||
show: boolean
|
||||
onHide: () => void
|
||||
reloadAfterClose?: boolean
|
||||
}
|
||||
|
||||
// Generates the offline copy filename with a timestamp to avoid duplicates.
|
||||
@@ -52,11 +54,20 @@ function UnableToSyncModal({
|
||||
docName,
|
||||
rootFolderId,
|
||||
show,
|
||||
onHide,
|
||||
onHide: onHideProp,
|
||||
reloadAfterClose = false,
|
||||
}: UnableToSyncModalProps) {
|
||||
const { t } = useTranslation()
|
||||
const [saving, setSaving] = useState(false)
|
||||
const [saveError, setSaveError] = useState(false)
|
||||
const location = useLocation()
|
||||
|
||||
const onHide = useCallback(() => {
|
||||
onHideProp()
|
||||
if (reloadAfterClose) {
|
||||
location.reload()
|
||||
}
|
||||
}, [onHideProp, reloadAfterClose, location])
|
||||
|
||||
const handleDownload = useCallback(() => {
|
||||
downloadFileContent(targetContent, docName ?? 'document.txt')
|
||||
|
||||
@@ -606,6 +606,7 @@ export const EditorManagerProvider: FC<React.PropsWithChildren> = ({
|
||||
editorContent: editorContent || '',
|
||||
baseContent: backupRecord.snapshot,
|
||||
docName: document.docName,
|
||||
reloadAfterClose: true,
|
||||
})
|
||||
OfflineDocBackup.remove(projectId, document.doc_id)
|
||||
} else {
|
||||
@@ -644,13 +645,14 @@ export const EditorManagerProvider: FC<React.PropsWithChildren> = ({
|
||||
|
||||
useEffect(() => {
|
||||
const handleUnableToSync = ({
|
||||
detail: [{ editorContent, baseContent, docName }],
|
||||
detail: [{ editorContent, baseContent, docName, reloadAfterClose }],
|
||||
}: CustomEvent<IdeEvents['ide:unableToSyncOfflineChanges']>) => {
|
||||
showUnableToSyncModal({
|
||||
baseContent,
|
||||
targetContent: editorContent,
|
||||
docName,
|
||||
rootFolderId: fileTreeDataRef.current?._id,
|
||||
reloadAfterClose,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,11 @@ type ModalsContextValue = {
|
||||
showUnableToSyncModal: (
|
||||
data: Pick<
|
||||
UnableToSyncModalProps,
|
||||
'baseContent' | 'targetContent' | 'docName' | 'rootFolderId'
|
||||
| 'baseContent'
|
||||
| 'targetContent'
|
||||
| 'docName'
|
||||
| 'rootFolderId'
|
||||
| 'reloadAfterClose'
|
||||
>
|
||||
) => void
|
||||
}
|
||||
@@ -64,13 +68,18 @@ export const ModalsContextProvider: FC<React.PropsWithChildren> = ({
|
||||
const [unableToSyncModalData, setUnableToSyncModalData] = useState<
|
||||
Pick<
|
||||
UnableToSyncModalProps,
|
||||
'baseContent' | 'targetContent' | 'docName' | 'rootFolderId'
|
||||
| 'baseContent'
|
||||
| 'targetContent'
|
||||
| 'docName'
|
||||
| 'rootFolderId'
|
||||
| 'reloadAfterClose'
|
||||
>
|
||||
>({
|
||||
baseContent: '',
|
||||
targetContent: '',
|
||||
docName: null,
|
||||
rootFolderId: undefined,
|
||||
reloadAfterClose: undefined,
|
||||
})
|
||||
|
||||
const handleHideGenericModal = useCallback(() => {
|
||||
@@ -122,7 +131,11 @@ export const ModalsContextProvider: FC<React.PropsWithChildren> = ({
|
||||
(
|
||||
data: Pick<
|
||||
UnableToSyncModalProps,
|
||||
'baseContent' | 'targetContent' | 'docName' | 'rootFolderId'
|
||||
| 'baseContent'
|
||||
| 'targetContent'
|
||||
| 'docName'
|
||||
| 'rootFolderId'
|
||||
| 'reloadAfterClose'
|
||||
>
|
||||
) => {
|
||||
setUnableToSyncModalData(data)
|
||||
|
||||
@@ -28,6 +28,7 @@ export type IdeEvents = {
|
||||
editorContent: string
|
||||
baseContent: string
|
||||
docName: string
|
||||
reloadAfterClose?: boolean
|
||||
},
|
||||
]
|
||||
'ide:offlineChangesSynced': [{ docId: string }]
|
||||
|
||||
+111
@@ -9,6 +9,7 @@ import type { SocketDebuggingInfo } from '@/features/ide-react/connection/types/
|
||||
import { IdeEventEmitter } from '@/features/ide-react/create-ide-event-emitter'
|
||||
import { OfflineDocBackup } from '@/features/ide-react/editor/offline-doc-backup'
|
||||
import { GlobalToasts } from '@/features/ide-react/components/global-toasts'
|
||||
import { location } from '@/shared/components/location'
|
||||
import {
|
||||
EditorProviders,
|
||||
makeEditorOpenDocProvider,
|
||||
@@ -177,6 +178,31 @@ describe('EditorManagerProvider docError sync modals', function () {
|
||||
})
|
||||
})
|
||||
|
||||
it('reloads the page when the backup-path modal is closed', function () {
|
||||
cy.then(() => {
|
||||
setSplitTest(true)
|
||||
plantBackup(CURRENT_DOC_ID)
|
||||
cy.stub(location, 'reload').as('reload')
|
||||
})
|
||||
|
||||
mount()
|
||||
|
||||
cy.then(() => {
|
||||
currentDoc.trigger(
|
||||
'error',
|
||||
new Error('forced'),
|
||||
{},
|
||||
'offline edits content'
|
||||
)
|
||||
})
|
||||
|
||||
cy.findByRole('dialog').within(() => {
|
||||
cy.findByRole('button', { name: 'Discard changes' }).click()
|
||||
})
|
||||
|
||||
cy.get('@reload').should('have.been.calledOnce')
|
||||
})
|
||||
|
||||
it('shows nothing and keeps the backup when the failure happens while offline', function () {
|
||||
let key: string
|
||||
cy.then(() => {
|
||||
@@ -279,6 +305,91 @@ describe('EditorManagerProvider docError sync modals', function () {
|
||||
})
|
||||
})
|
||||
|
||||
it('does not reload when the recovery event omits reloadAfterClose', function () {
|
||||
let capturedEmitter: IdeEventEmitter | null = null
|
||||
|
||||
cy.then(() => {
|
||||
cy.stub(location, 'reload').as('reload')
|
||||
})
|
||||
|
||||
cy.mount(
|
||||
<EditorProviders
|
||||
projectId={PROJECT_ID}
|
||||
providers={{
|
||||
EditorOpenDocProvider: makeEditorOpenDocProvider({
|
||||
currentDocumentId: CURRENT_DOC_ID as any,
|
||||
openDocName: currentDoc.docName,
|
||||
currentDocument: currentDoc as any,
|
||||
}),
|
||||
}}
|
||||
>
|
||||
<CaptureEventEmitter
|
||||
onReady={emitter => {
|
||||
capturedEmitter = emitter
|
||||
}}
|
||||
/>
|
||||
</EditorProviders>
|
||||
)
|
||||
|
||||
cy.then(() => {
|
||||
capturedEmitter!.emit('ide:unableToSyncOfflineChanges', {
|
||||
docId: CURRENT_DOC_ID,
|
||||
editorContent: 'recovered content',
|
||||
baseContent: 'original content',
|
||||
docName: 'recovered.tex',
|
||||
})
|
||||
})
|
||||
|
||||
cy.findByRole('dialog').within(() => {
|
||||
cy.findByRole('button', { name: 'Discard changes' }).click()
|
||||
})
|
||||
|
||||
cy.get('@reload').should('not.have.been.called')
|
||||
})
|
||||
|
||||
it('reloads when the recovery event sets reloadAfterClose', function () {
|
||||
let capturedEmitter: IdeEventEmitter | null = null
|
||||
|
||||
cy.then(() => {
|
||||
cy.stub(location, 'reload').as('reload')
|
||||
})
|
||||
|
||||
cy.mount(
|
||||
<EditorProviders
|
||||
projectId={PROJECT_ID}
|
||||
providers={{
|
||||
EditorOpenDocProvider: makeEditorOpenDocProvider({
|
||||
currentDocumentId: CURRENT_DOC_ID as any,
|
||||
openDocName: currentDoc.docName,
|
||||
currentDocument: currentDoc as any,
|
||||
}),
|
||||
}}
|
||||
>
|
||||
<CaptureEventEmitter
|
||||
onReady={emitter => {
|
||||
capturedEmitter = emitter
|
||||
}}
|
||||
/>
|
||||
</EditorProviders>
|
||||
)
|
||||
|
||||
cy.then(() => {
|
||||
capturedEmitter!.emit('ide:unableToSyncOfflineChanges', {
|
||||
docId: CURRENT_DOC_ID,
|
||||
editorContent: 'recovered content',
|
||||
baseContent: 'original content',
|
||||
docName: 'recovered.tex',
|
||||
reloadAfterClose: true,
|
||||
})
|
||||
})
|
||||
|
||||
cy.findByRole('dialog').within(() => {
|
||||
cy.findByRole('button', { name: 'Discard changes' }).click()
|
||||
})
|
||||
|
||||
cy.get('@reload').should('have.been.calledOnce')
|
||||
})
|
||||
|
||||
it('shows the success toast on the ide:offlineChangesSynced event', function () {
|
||||
let capturedEmitter: IdeEventEmitter | null = null
|
||||
|
||||
|
||||
Reference in New Issue
Block a user