mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-12 13:13:45 +01:00
[web] do not show the cannot sync modal if still offline (#35939)
GitOrigin-RevId: 20c6f138e05fb8459b27f8ea9b376c21c7820799
This commit is contained in:
@@ -86,7 +86,8 @@ export const EditorManagerProvider: FC<React.PropsWithChildren> = ({
|
||||
const { t } = useTranslation()
|
||||
const { reportError, eventEmitter, projectId, setOutOfSync } =
|
||||
useIdeReactContext()
|
||||
const { socket, closeConnection, connectionState } = useConnectionContext()
|
||||
const { socket, closeConnection, connectionState, isConnected } =
|
||||
useConnectionContext()
|
||||
const { view, setView, setOpenFile } = useLayoutContext()
|
||||
const {
|
||||
showGenericMessageModal,
|
||||
@@ -587,6 +588,13 @@ export const EditorManagerProvider: FC<React.PropsWithChildren> = ({
|
||||
document.doc_id
|
||||
)
|
||||
if (hasOfflineBackup) {
|
||||
if (!isConnected) {
|
||||
// Still offline, so nothing has been rejected yet: this is the
|
||||
// fatal op timeout running out while the outage is ongoing. Keep
|
||||
// the backup and let recovery on the next load report the outcome,
|
||||
// rather than declaring a failed sync mid-outage.
|
||||
return
|
||||
}
|
||||
eventEmitter.emit('ide:unableToSyncOfflineChanges', {
|
||||
docId: document.doc_id,
|
||||
editorContent: editorContent || '',
|
||||
@@ -624,6 +632,7 @@ export const EditorManagerProvider: FC<React.PropsWithChildren> = ({
|
||||
setOutOfSync,
|
||||
t,
|
||||
projectId,
|
||||
isConnected,
|
||||
])
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
+67
-2
@@ -1,7 +1,11 @@
|
||||
import { FC, useEffect } from 'react'
|
||||
import { FC, PropsWithChildren, useEffect, useState } from 'react'
|
||||
import EventEmitter from '@/utils/EventEmitter'
|
||||
import { useEditorManagerContext } from '@/features/ide-react/context/editor-manager-context'
|
||||
import { ConnectionContext } from '@/features/ide-react/context/connection-context'
|
||||
import { useIdeReactContext } from '@/features/ide-react/context/ide-react-context'
|
||||
import { SocketIOMock } from '@/ide/connection/SocketIoShim'
|
||||
import type { Socket } from '@/features/ide-react/connection/types/socket'
|
||||
import type { SocketDebuggingInfo } from '@/features/ide-react/connection/types/connection-state'
|
||||
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'
|
||||
@@ -71,6 +75,38 @@ function plantBackup(docId: string, { trackChanges = false } = {}) {
|
||||
return key
|
||||
}
|
||||
|
||||
// The default harness reports a healthy connection, which stands in for the
|
||||
// post-reconnect sync failure. This one stands in for the fatal op timeout
|
||||
// firing while the outage is still ongoing.
|
||||
const OfflineConnectionProvider: FC<PropsWithChildren> = ({ children }) => {
|
||||
const [value] = useState(() => ({
|
||||
socket: new SocketIOMock() as any as Socket,
|
||||
connectionState: {
|
||||
readyState: WebSocket.CLOSED,
|
||||
forceDisconnected: false,
|
||||
inactiveDisconnect: false,
|
||||
reconnectAt: null,
|
||||
forcedDisconnectDelay: 0,
|
||||
lastConnectionAttempt: 0,
|
||||
error: '' as const,
|
||||
},
|
||||
isConnected: false,
|
||||
isStillReconnecting: false,
|
||||
secondsUntilReconnect: () => 0,
|
||||
tryReconnectNow: () => {},
|
||||
registerUserActivity: () => {},
|
||||
disconnect: () => {},
|
||||
closeConnection: () => {},
|
||||
getSocketDebuggingInfo: () => ({}) as SocketDebuggingInfo,
|
||||
}))
|
||||
|
||||
return (
|
||||
<ConnectionContext.Provider value={value}>
|
||||
{children}
|
||||
</ConnectionContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
function setSplitTest(enabled: boolean) {
|
||||
window.metaAttributesCache.set('ol-splitTestVariants', {
|
||||
'intermittent-connection-improvements': enabled ? 'enabled' : 'default',
|
||||
@@ -92,7 +128,9 @@ describe('EditorManagerProvider docError sync modals', function () {
|
||||
window.sessionStorage.clear()
|
||||
})
|
||||
|
||||
const mount = () => {
|
||||
const mount = (
|
||||
extraProviders: Record<string, FC<PropsWithChildren>> = {}
|
||||
) => {
|
||||
cy.mount(
|
||||
<EditorProviders
|
||||
projectId={PROJECT_ID}
|
||||
@@ -102,6 +140,7 @@ describe('EditorManagerProvider docError sync modals', function () {
|
||||
openDocName: currentDoc.docName,
|
||||
currentDocument: currentDoc as any,
|
||||
}),
|
||||
...extraProviders,
|
||||
}}
|
||||
>
|
||||
<OpenNewDocOnMount />
|
||||
@@ -139,6 +178,32 @@ describe('EditorManagerProvider docError sync modals', function () {
|
||||
})
|
||||
})
|
||||
|
||||
it('shows nothing and keeps the backup when the failure happens while offline', function () {
|
||||
let key: string
|
||||
cy.then(() => {
|
||||
setSplitTest(true)
|
||||
key = plantBackup(CURRENT_DOC_ID)
|
||||
})
|
||||
|
||||
mount({ ConnectionProvider: OfflineConnectionProvider })
|
||||
|
||||
cy.then(() => {
|
||||
currentDoc.trigger(
|
||||
'error',
|
||||
new Error('forced'),
|
||||
{},
|
||||
'offline edits content'
|
||||
)
|
||||
})
|
||||
|
||||
cy.findByRole('dialog').should('not.exist')
|
||||
|
||||
// The outcome is still undetermined, so recovery on the next load decides.
|
||||
cy.then(() => {
|
||||
expect(window.sessionStorage.getItem(key!)).to.not.equal(null)
|
||||
})
|
||||
})
|
||||
|
||||
it('passes editorContent and docName through to the download button', function () {
|
||||
cy.then(() => {
|
||||
setSplitTest(true)
|
||||
|
||||
Reference in New Issue
Block a user