mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-14 14:13:43 +01:00
[web] Re-introduce orphan detection in detached PDF (#32994)
GitOrigin-RevId: 07a58d6f7e3c6db8465c62b390e34270c2b4fd67
This commit is contained in:
committed by
Copybot
parent
5e675664c6
commit
c46fba951e
@@ -1503,6 +1503,7 @@
|
||||
"recovering": "",
|
||||
"recurly_email_update_needed": "",
|
||||
"recurly_email_updated": "",
|
||||
"redirect_to_editor": "",
|
||||
"redirect_url": "",
|
||||
"redo": "",
|
||||
"reduce_costs_group_licenses": "",
|
||||
@@ -1902,6 +1903,7 @@
|
||||
"synctex_failed": "",
|
||||
"syntax_checks": "",
|
||||
"syntax_validation": "",
|
||||
"tab_connecting": "",
|
||||
"table": "",
|
||||
"tabs_open_in_preview_mode_until_you_interact_with_them": "",
|
||||
"tag_color": "",
|
||||
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
import LoadingSpinner from '@/shared/components/loading-spinner'
|
||||
import { memo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
function PdfPreviewHybridToolbarConnectingInner() {
|
||||
const { t } = useTranslation()
|
||||
return (
|
||||
<div className="toolbar-pdf-left">
|
||||
<div className="toolbar-pdf-orphan">
|
||||
<LoadingSpinner size="sm" loadingText={`${t('tab_connecting')}…`} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default memo(PdfPreviewHybridToolbarConnectingInner)
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { memo, useCallback } from 'react'
|
||||
import { buildUrlWithDetachRole } from '@/shared/utils/url-helper'
|
||||
import { useLocation } from '@/shared/hooks/use-location'
|
||||
import OLButton from '@/shared/components/ol/ol-button'
|
||||
|
||||
function PdfPreviewHybridToolbarOrphanRefreshInner() {
|
||||
const { t } = useTranslation()
|
||||
const location = useLocation()
|
||||
|
||||
const redirect = useCallback(() => {
|
||||
location.assign(buildUrlWithDetachRole(null).toString())
|
||||
}, [location])
|
||||
|
||||
return (
|
||||
<div className="toolbar-pdf-left">
|
||||
<OLButton
|
||||
variant="primary"
|
||||
size="sm"
|
||||
onClick={redirect}
|
||||
className="toolbar-pdf-orphan-btn"
|
||||
>
|
||||
{t('redirect_to_editor')}
|
||||
</OLButton>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default memo(PdfPreviewHybridToolbarOrphanRefreshInner)
|
||||
+23
-2
@@ -6,15 +6,36 @@ import PdfHybridDownloadButton from '@/features/pdf-preview/components/pdf-hybri
|
||||
import { DetachedSynctexControl } from '@/features/pdf-preview/components/detach-synctex-control'
|
||||
import SwitchToEditorButton from '@/features/pdf-preview/components/switch-to-editor-button'
|
||||
import PdfHybridLogsButton from '@/features/pdf-preview/components/pdf-hybrid-logs-button'
|
||||
import PdfPreviewHybridToolbarOrphanRefreshInner from './pdf-preview-hybrid-toolbar-orphan-refresh-inner'
|
||||
import PdfPreviewHybridToolbarConnectingInner from './pdf-preview-hybrid-toolbar-connecting-inner'
|
||||
import useDetachedOrphanDetection from '../hooks/use-detached-orphan-detection'
|
||||
|
||||
function PdfPreviewHybridToolbar() {
|
||||
const { t } = useTranslation()
|
||||
// TODO: add detached pdf logic
|
||||
const orphanState = useDetachedOrphanDetection()
|
||||
|
||||
let ToolbarContent = null
|
||||
if (orphanState === 'orphan') {
|
||||
ToolbarContent = PdfPreviewHybridToolbarOrphanRefreshInner
|
||||
} else if (orphanState === 'connecting') {
|
||||
ToolbarContent = PdfPreviewHybridToolbarConnectingInner
|
||||
} else {
|
||||
ToolbarContent = PdfPreviewHybridToolbarInner
|
||||
}
|
||||
|
||||
return (
|
||||
<OLButtonToolbar
|
||||
className="toolbar toolbar-pdf toolbar-pdf-hybrid"
|
||||
aria-label={t('pdf')}
|
||||
>
|
||||
<ToolbarContent />
|
||||
</OLButtonToolbar>
|
||||
)
|
||||
}
|
||||
|
||||
function PdfPreviewHybridToolbarInner() {
|
||||
return (
|
||||
<>
|
||||
<div className="toolbar-pdf-left">
|
||||
<PdfCompileButton />
|
||||
<PdfHybridLogsButton />
|
||||
@@ -26,7 +47,7 @@ function PdfPreviewHybridToolbar() {
|
||||
<DetachedSynctexControl />
|
||||
{/* TODO: should we have code check? */}
|
||||
</div>
|
||||
</OLButtonToolbar>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
import { useLayoutContext } from '@/shared/context/layout-context'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
|
||||
type OrphanState = 'connecting' | 'orphan' | 'not-orphan'
|
||||
|
||||
const ORPHAN_UI_TIMEOUT_MS = 5000
|
||||
|
||||
export default function useDetachedOrphanDetection(): OrphanState {
|
||||
const { detachRole, detachIsLinked } = useLayoutContext()
|
||||
const uiTimeoutRef = useRef<number>()
|
||||
const [longTimeOrphan, setLongTimeOrphan] = useState(false)
|
||||
|
||||
const orphaned = !detachIsLinked && detachRole === 'detached'
|
||||
|
||||
useEffect(() => {
|
||||
if (uiTimeoutRef.current) {
|
||||
window.clearTimeout(uiTimeoutRef.current)
|
||||
}
|
||||
|
||||
if (orphaned) {
|
||||
uiTimeoutRef.current = window.setTimeout(() => {
|
||||
setLongTimeOrphan(true)
|
||||
}, ORPHAN_UI_TIMEOUT_MS)
|
||||
} else {
|
||||
setLongTimeOrphan(false)
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (uiTimeoutRef.current) {
|
||||
window.clearTimeout(uiTimeoutRef.current)
|
||||
}
|
||||
}
|
||||
}, [orphaned])
|
||||
|
||||
if (!orphaned) {
|
||||
// not detached, or detached but linked
|
||||
return 'not-orphan'
|
||||
}
|
||||
|
||||
if (longTimeOrphan) {
|
||||
return 'orphan'
|
||||
} else if (orphaned) {
|
||||
return 'connecting'
|
||||
} else {
|
||||
return 'not-orphan'
|
||||
}
|
||||
}
|
||||
@@ -107,6 +107,15 @@
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.toolbar-pdf-orphan {
|
||||
color: var(--toolbar-btn-color);
|
||||
}
|
||||
|
||||
.toolbar-pdf-orphan-btn,
|
||||
.toolbar-pdf-orphan {
|
||||
margin-left: var(--spacing-02);
|
||||
}
|
||||
|
||||
.btn.pdf-toolbar-btn {
|
||||
display: inline-block;
|
||||
color: var(--toolbar-btn-color);
|
||||
|
||||
@@ -1999,6 +1999,7 @@
|
||||
"reconnecting_in_x_secs": "Reconnecting in __seconds__ secs",
|
||||
"recurly_email_update_needed": "Your billing email address is currently <0>__recurlyEmail__</0>. If needed you can update your billing address to <1>__userEmail__</1>.",
|
||||
"recurly_email_updated": "Your billing email address was successfully updated",
|
||||
"redirect_to_editor": "Redirect to editor",
|
||||
"redirect_url": "Redirect URL",
|
||||
"redirecting": "Redirecting",
|
||||
"redo": "Redo",
|
||||
@@ -2490,6 +2491,7 @@
|
||||
"synctex_failed": "Couldn’t find the corresponding source file",
|
||||
"syntax_checks": "Syntax checks",
|
||||
"syntax_validation": "Code check",
|
||||
"tab_connecting": "Connecting with the editor",
|
||||
"table": "Table",
|
||||
"table_generator": "Table Generator",
|
||||
"tabs_open_in_preview_mode_until_you_interact_with_them": "Tabs open in preview mode until you interact with them",
|
||||
|
||||
+69
-20
@@ -15,16 +15,17 @@ describe('<PdfPreviewHybridToolbar/>', function () {
|
||||
</EditorProviders>
|
||||
)
|
||||
|
||||
cy.findByRole('button', { name: 'Recompile' })
|
||||
cy.findByRole('button', { name: 'Recompile' }).should('exist')
|
||||
})
|
||||
|
||||
describe('orphan mode', function () {
|
||||
// eslint-disable-next-line mocha/no-skipped-tests
|
||||
it.skip('shows connecting message on load', function () {
|
||||
beforeEach(function () {
|
||||
cy.window().then(win => {
|
||||
win.metaAttributesCache.set('ol-detachRole', 'detached')
|
||||
})
|
||||
})
|
||||
|
||||
it('shows connecting message on load', function () {
|
||||
cy.mount(
|
||||
<EditorProviders>
|
||||
<PdfPreviewHybridToolbar />
|
||||
@@ -32,13 +33,13 @@ describe('<PdfPreviewHybridToolbar/>', function () {
|
||||
)
|
||||
|
||||
cy.contains('Connecting with the editor')
|
||||
cy.findByRole('button', { name: 'Recompile' }).should('not.exist')
|
||||
cy.findByRole('button', { name: 'Redirect to editor' }).should(
|
||||
'not.exist'
|
||||
)
|
||||
})
|
||||
|
||||
it('shows compile UI when connected', function () {
|
||||
cy.window().then(win => {
|
||||
win.metaAttributesCache.set('ol-detachRole', 'detached')
|
||||
})
|
||||
|
||||
cy.mount(
|
||||
<EditorProviders>
|
||||
<PdfPreviewHybridToolbar />
|
||||
@@ -52,15 +53,11 @@ describe('<PdfPreviewHybridToolbar/>', function () {
|
||||
})
|
||||
})
|
||||
|
||||
cy.findByRole('button', { name: 'Recompile' })
|
||||
cy.findByRole('button', { name: 'Recompile' }).should('exist')
|
||||
cy.contains('Connecting with the editor').should('not.exist')
|
||||
})
|
||||
|
||||
// eslint-disable-next-line mocha/no-skipped-tests
|
||||
it.skip('shows connecting message when disconnected', function () {
|
||||
cy.window().then(win => {
|
||||
win.metaAttributesCache.set('ol-detachRole', 'detached')
|
||||
})
|
||||
|
||||
it('shows connecting message when disconnected', function () {
|
||||
cy.mount(
|
||||
<EditorProviders>
|
||||
<PdfPreviewHybridToolbar />
|
||||
@@ -72,6 +69,11 @@ describe('<PdfPreviewHybridToolbar/>', function () {
|
||||
role: 'detacher',
|
||||
event: 'connected',
|
||||
})
|
||||
})
|
||||
|
||||
cy.findByRole('button', { name: 'Recompile' }).should('exist')
|
||||
|
||||
cy.wrap(null).then(() => {
|
||||
testDetachChannel.postMessage({
|
||||
role: 'detacher',
|
||||
event: 'closed',
|
||||
@@ -79,14 +81,27 @@ describe('<PdfPreviewHybridToolbar/>', function () {
|
||||
})
|
||||
|
||||
cy.contains('Connecting with the editor')
|
||||
cy.findByRole('button', { name: 'Recompile' }).should('not.exist')
|
||||
})
|
||||
|
||||
// eslint-disable-next-line mocha/no-skipped-tests
|
||||
it.skip('shows redirect button after timeout', function () {
|
||||
cy.window().then(win => {
|
||||
win.metaAttributesCache.set('ol-detachRole', 'detached')
|
||||
})
|
||||
it('shows redirect button after timeout', function () {
|
||||
cy.clock()
|
||||
|
||||
cy.mount(
|
||||
<EditorProviders>
|
||||
<PdfPreviewHybridToolbar />
|
||||
</EditorProviders>
|
||||
)
|
||||
|
||||
cy.contains('Connecting with the editor')
|
||||
|
||||
cy.tick(6000)
|
||||
|
||||
cy.findByRole('button', { name: 'Redirect to editor' }).should('exist')
|
||||
cy.contains('Connecting with the editor').should('not.exist')
|
||||
})
|
||||
|
||||
it('recovers to compile UI when link is restored after timeout', function () {
|
||||
cy.clock()
|
||||
|
||||
cy.mount(
|
||||
@@ -96,8 +111,42 @@ describe('<PdfPreviewHybridToolbar/>', function () {
|
||||
)
|
||||
|
||||
cy.tick(6000)
|
||||
cy.findByRole('button', { name: 'Redirect to editor' }).should('exist')
|
||||
|
||||
cy.findByRole('button', { name: 'Redirect to editor' })
|
||||
cy.wrap(null).then(() => {
|
||||
testDetachChannel.postMessage({
|
||||
role: 'detacher',
|
||||
event: 'connected',
|
||||
})
|
||||
})
|
||||
|
||||
cy.findByRole('button', { name: 'Recompile' }).should('exist')
|
||||
cy.findByRole('button', { name: 'Redirect to editor' }).should(
|
||||
'not.exist'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('detacher role', function () {
|
||||
it('never shows orphan UI', function () {
|
||||
cy.clock()
|
||||
cy.window().then(win => {
|
||||
win.metaAttributesCache.set('ol-detachRole', 'detacher')
|
||||
})
|
||||
|
||||
cy.mount(
|
||||
<EditorProviders>
|
||||
<PdfPreviewHybridToolbar />
|
||||
</EditorProviders>
|
||||
)
|
||||
|
||||
cy.tick(6000)
|
||||
|
||||
cy.findByRole('button', { name: 'Recompile' }).should('exist')
|
||||
cy.contains('Connecting with the editor').should('not.exist')
|
||||
cy.findByRole('button', { name: 'Redirect to editor' }).should(
|
||||
'not.exist'
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user