mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-12 21:23:45 +01:00
[web] hide all toasts when offline (#35400)
GitOrigin-RevId: cf179bf7a761ddaae56f3e5bab6327b0f3625fb5
This commit is contained in:
@@ -7,6 +7,7 @@ import { createPortal } from 'react-dom'
|
||||
import { useGlobalAlertsContainer } from '@/features/ide-react/context/global-alerts-context'
|
||||
import Notification from '@/shared/components/notification'
|
||||
import importOverleafModules from '../../../../../macros/import-overleaf-module.macro'
|
||||
import { useFeatureFlag } from '@/shared/context/split-test-context'
|
||||
|
||||
const rollingBuildsUpdatedAlert: Array<{
|
||||
import: { default: ElementType }
|
||||
@@ -23,6 +24,9 @@ export function Alerts() {
|
||||
secondsUntilReconnect,
|
||||
} = useConnectionContext()
|
||||
const globalAlertsContainer = useGlobalAlertsContainer()
|
||||
const improvedFlakyConnections = useFeatureFlag(
|
||||
'intermittent-connection-improvements'
|
||||
)
|
||||
|
||||
if (!globalAlertsContainer) {
|
||||
return null
|
||||
@@ -36,56 +40,60 @@ export function Alerts() {
|
||||
)
|
||||
)}
|
||||
|
||||
{connectionState.forceDisconnected &&
|
||||
// hide "disconnected" banner when displaying out of sync modal
|
||||
connectionState.error !== 'out-of-sync' ? (
|
||||
<div className="notification-list">
|
||||
<Notification
|
||||
type="error"
|
||||
content={<strong>{t('disconnected')}</strong>}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
{!improvedFlakyConnections && (
|
||||
<>
|
||||
{connectionState.forceDisconnected &&
|
||||
// hide "disconnected" banner when displaying out of sync modal
|
||||
connectionState.error !== 'out-of-sync' ? (
|
||||
<div className="notification-list">
|
||||
<Notification
|
||||
type="error"
|
||||
content={<strong>{t('disconnected')}</strong>}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{connectionState.reconnectAt ? (
|
||||
<LostConnectionAlert
|
||||
reconnectAt={connectionState.reconnectAt}
|
||||
tryReconnectNow={tryReconnectNow}
|
||||
/>
|
||||
) : null}
|
||||
{connectionState.reconnectAt ? (
|
||||
<LostConnectionAlert
|
||||
reconnectAt={connectionState.reconnectAt}
|
||||
tryReconnectNow={tryReconnectNow}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{isStillReconnecting ? (
|
||||
<div className="notification-list">
|
||||
<Notification
|
||||
type="warning"
|
||||
content={<strong>{t('reconnecting')}…</strong>}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
{isStillReconnecting ? (
|
||||
<div className="notification-list">
|
||||
<Notification
|
||||
type="warning"
|
||||
content={<strong>{t('reconnecting')}…</strong>}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{connectionState.inactiveDisconnect ||
|
||||
(connectionState.readyState === WebSocket.CLOSED &&
|
||||
(connectionState.error === 'rate-limited' ||
|
||||
connectionState.error === 'unable-to-connect') &&
|
||||
!secondsUntilReconnect()) ? (
|
||||
<div className="notification-list">
|
||||
<Notification
|
||||
type="warning"
|
||||
content={
|
||||
<strong>{t('editor_disconected_click_to_reconnect')}</strong>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
{connectionState.inactiveDisconnect ||
|
||||
(connectionState.readyState === WebSocket.CLOSED &&
|
||||
(connectionState.error === 'rate-limited' ||
|
||||
connectionState.error === 'unable-to-connect') &&
|
||||
!secondsUntilReconnect()) ? (
|
||||
<div className="notification-list">
|
||||
<Notification
|
||||
type="warning"
|
||||
content={
|
||||
<strong>{t('editor_disconected_click_to_reconnect')}</strong>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{debugging ? (
|
||||
<div className="notification-list">
|
||||
<Notification
|
||||
type="warning"
|
||||
content={<strong>Connected: {isConnected.toString()}</strong>}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
{debugging ? (
|
||||
<div className="notification-list">
|
||||
<Notification
|
||||
type="warning"
|
||||
content={<strong>Connected: {isConnected.toString()}</strong>}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
</>
|
||||
)}
|
||||
</>,
|
||||
globalAlertsContainer
|
||||
)
|
||||
|
||||
+8
@@ -3,11 +3,15 @@ import { useTranslation } from 'react-i18next'
|
||||
import Notification from '@/shared/components/notification'
|
||||
import { useEditorManagerContext } from '@/features/ide-react/context/editor-manager-context'
|
||||
import { useIdeReactContext } from '@/features/ide-react/context/ide-react-context'
|
||||
import { useFeatureFlag } from '@/shared/context/split-test-context'
|
||||
|
||||
export const UnsavedDocsLockedAlert: FC = () => {
|
||||
const { t } = useTranslation()
|
||||
const { openDocs } = useEditorManagerContext()
|
||||
const { reportError } = useIdeReactContext()
|
||||
const improvedFlakyConnections = useFeatureFlag(
|
||||
'intermittent-connection-improvements'
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
const { pendingOpsLength, inflightOpsLength } = openDocs.getUnsavedOpsSize()
|
||||
@@ -17,6 +21,10 @@ export const UnsavedDocsLockedAlert: FC = () => {
|
||||
})
|
||||
}, [reportError, openDocs])
|
||||
|
||||
if (improvedFlakyConnections) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="notification-list">
|
||||
<Notification
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
import { Alerts } from '@/features/ide-react/components/alerts/alerts'
|
||||
import { ConnectionContext } from '@/features/ide-react/context/connection-context'
|
||||
import { GlobalAlertsProvider } from '@/features/ide-react/context/global-alerts-context'
|
||||
import { ProjectContext } from '@/shared/context/project-context'
|
||||
import { SplitTestProvider } from '@/shared/context/split-test-context'
|
||||
import { makeTutorialProvider } from '../../../../helpers/make-tutorial-provider'
|
||||
|
||||
const TutorialProvider = makeTutorialProvider()
|
||||
|
||||
const disconnectedConnectionContextValue = {
|
||||
socket: { socket: {} },
|
||||
connectionState: {
|
||||
forceDisconnected: true,
|
||||
readyState: WebSocket.CLOSED,
|
||||
error: '',
|
||||
},
|
||||
isConnected: false,
|
||||
isStillReconnecting: false,
|
||||
secondsUntilReconnect: () => 0,
|
||||
tryReconnectNow: () => {},
|
||||
registerUserActivity: () => {},
|
||||
closeConnection: () => {},
|
||||
getSocketDebuggingInfo: () => ({ id: '' }),
|
||||
} as any
|
||||
|
||||
const projectContextValue = {
|
||||
project: { imageName: 'texlive-full:2023.1' },
|
||||
} as any
|
||||
|
||||
const mount = () => {
|
||||
cy.mount(
|
||||
<SplitTestProvider>
|
||||
<TutorialProvider>
|
||||
<ProjectContext.Provider value={projectContextValue}>
|
||||
<GlobalAlertsProvider>
|
||||
<ConnectionContext.Provider
|
||||
value={disconnectedConnectionContextValue}
|
||||
>
|
||||
<Alerts />
|
||||
</ConnectionContext.Provider>
|
||||
</GlobalAlertsProvider>
|
||||
</ProjectContext.Provider>
|
||||
</TutorialProvider>
|
||||
</SplitTestProvider>
|
||||
)
|
||||
}
|
||||
|
||||
const enableFlag = () => {
|
||||
cy.window().then(win => {
|
||||
win.metaAttributesCache.set('ol-splitTestVariants', {
|
||||
'intermittent-connection-improvements': 'enabled',
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
describe('<Alerts />', function () {
|
||||
it('shows the connection alert when flag is disabled', function () {
|
||||
mount()
|
||||
cy.findByRole('alert').should('exist')
|
||||
})
|
||||
|
||||
it('suppresses the connection alert when flag is enabled', function () {
|
||||
enableFlag()
|
||||
mount()
|
||||
cy.findByRole('alert').should('not.exist')
|
||||
})
|
||||
})
|
||||
+59
-6
@@ -4,6 +4,8 @@ import { GlobalAlertsProvider } from '@/features/ide-react/context/global-alerts
|
||||
import { FileTreePathContext } from '@/features/file-tree/contexts/file-tree-path'
|
||||
import { ConnectionContext } from '@/features/ide-react/context/connection-context'
|
||||
import { SplitTestProvider } from '@/shared/context/split-test-context'
|
||||
import { EditorManagerContext } from '@/features/ide-react/context/editor-manager-context'
|
||||
import { IdeReactContext } from '@/features/ide-react/context/ide-react-context'
|
||||
|
||||
const defaultUnsavedDocsContextValue = {
|
||||
unsavedDocs: new Map<string, number>([['doc1', 16]]),
|
||||
@@ -37,16 +39,37 @@ const mockFileTreePathContextValue = {
|
||||
previewByPath: () => null,
|
||||
}
|
||||
|
||||
const mount = () => {
|
||||
const mockEditorManagerContextValue = {
|
||||
openDocs: {
|
||||
getUnsavedOpsSize: () => ({ pendingOpsLength: 2, inflightOpsLength: 1 }),
|
||||
},
|
||||
} as any
|
||||
|
||||
const mount = ({
|
||||
unsavedDocsContextValue = defaultUnsavedDocsContextValue,
|
||||
reportError = cy.stub(),
|
||||
}: {
|
||||
unsavedDocsContextValue?: typeof defaultUnsavedDocsContextValue
|
||||
reportError?: any
|
||||
} = {}) => {
|
||||
const ideReactContextValue = { reportError } as any
|
||||
cy.mount(
|
||||
<SplitTestProvider>
|
||||
<GlobalAlertsProvider>
|
||||
<ConnectionContext.Provider value={mockConnectionContextValue}>
|
||||
<FileTreePathContext.Provider value={mockFileTreePathContextValue}>
|
||||
<UnsavedDocsContext.Provider value={defaultUnsavedDocsContextValue}>
|
||||
<UnsavedDocs />
|
||||
</UnsavedDocsContext.Provider>
|
||||
</FileTreePathContext.Provider>
|
||||
<IdeReactContext.Provider value={ideReactContextValue}>
|
||||
<EditorManagerContext.Provider
|
||||
value={mockEditorManagerContextValue}
|
||||
>
|
||||
<FileTreePathContext.Provider
|
||||
value={mockFileTreePathContextValue}
|
||||
>
|
||||
<UnsavedDocsContext.Provider value={unsavedDocsContextValue}>
|
||||
<UnsavedDocs />
|
||||
</UnsavedDocsContext.Provider>
|
||||
</FileTreePathContext.Provider>
|
||||
</EditorManagerContext.Provider>
|
||||
</IdeReactContext.Provider>
|
||||
</ConnectionContext.Provider>
|
||||
</GlobalAlertsProvider>
|
||||
</SplitTestProvider>
|
||||
@@ -72,4 +95,34 @@ describe('<UnsavedDocs />', function () {
|
||||
mount()
|
||||
cy.findByRole('alert').should('not.exist')
|
||||
})
|
||||
|
||||
describe('when locked', function () {
|
||||
const lockedContextValue = {
|
||||
unsavedDocs: new Map<string, number>(),
|
||||
isLocked: true,
|
||||
}
|
||||
|
||||
it('shows the locked alert and reports the error when flag is disabled', function () {
|
||||
const reportError = cy.stub().as('reportError')
|
||||
mount({ unsavedDocsContextValue: lockedContextValue, reportError })
|
||||
cy.findByRole('alert').should('exist')
|
||||
cy.get('@reportError').should(
|
||||
'have.been.calledOnceWith',
|
||||
'connection-lost-with-unsaved-changes',
|
||||
{ pendingOpsLength: 2, inflightOpsLength: 1 }
|
||||
)
|
||||
})
|
||||
|
||||
it('hides the locked alert but still reports the error when flag is enabled', function () {
|
||||
const reportError = cy.stub().as('reportError')
|
||||
enableFlag()
|
||||
mount({ unsavedDocsContextValue: lockedContextValue, reportError })
|
||||
cy.findByRole('alert').should('not.exist')
|
||||
cy.get('@reportError').should(
|
||||
'have.been.calledOnceWith',
|
||||
'connection-lost-with-unsaved-changes',
|
||||
{ pendingOpsLength: 2, inflightOpsLength: 1 }
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user