Merge pull request #26951 from overleaf/mj-layout-broken

[web] Add restoreView to LayoutContext

GitOrigin-RevId: 3a50c1e215c99236f503285fee1c924df57e07e4
This commit is contained in:
Mathias Jakobsen
2025-07-10 09:42:23 +01:00
committed by Copybot
parent 9a89466674
commit 96955fe2a0
9 changed files with 48 additions and 27 deletions
@@ -21,7 +21,7 @@ type RestorationState =
export function useRestoreDeletedFile() {
const { projectId } = useHistoryContext()
const { setView } = useLayoutContext()
const { restoreView } = useLayoutContext()
const { openDocWithId, openFileWithId } = useEditorManagerContext()
const { showBoundary } = useErrorBoundary()
const { fileTreeData } = useFileTreeData()
@@ -37,7 +37,7 @@ export function useRestoreDeletedFile() {
if (result) {
setState('complete')
const { _id: id } = result.entity
setView('editor')
restoreView()
if (restoredFileMetadata.type === 'doc') {
openDocWithId(id)
@@ -52,7 +52,7 @@ export function useRestoreDeletedFile() {
restoredFileMetadata,
openDocWithId,
openFileWithId,
setView,
restoreView,
])
useEffect(() => {
@@ -7,7 +7,7 @@ type RestorationState = 'initial' | 'restoring' | 'restored' | 'error'
export const useRestoreProject = () => {
const { showBoundary } = useErrorBoundary()
const { setView } = useLayoutContext()
const { restoreView } = useLayoutContext()
const [restorationState, setRestorationState] =
useState<RestorationState>('initial')
@@ -18,14 +18,14 @@ export const useRestoreProject = () => {
restoreProjectToVersion(projectId, version)
.then(() => {
setRestorationState('restored')
setView('editor')
restoreView()
})
.catch(err => {
setRestorationState('error')
showBoundary(err)
})
},
[showBoundary, setView]
[showBoundary, restoreView]
)
return {
@@ -22,7 +22,7 @@ type RestoreState =
export function useRestoreSelectedFile() {
const { projectId } = useHistoryContext()
const { setView } = useLayoutContext()
const { restoreView } = useLayoutContext()
const { openDocWithId, openFileWithId } = useEditorManagerContext()
const { showBoundary } = useErrorBoundary()
const { fileTreeData } = useFileTreeData()
@@ -38,7 +38,7 @@ export function useRestoreSelectedFile() {
if (result) {
setState('complete')
const { _id: id } = result.entity
setView('editor')
restoreView()
if (restoredFileMetadata.type === 'doc') {
openDocWithId(id)
@@ -53,7 +53,7 @@ export function useRestoreSelectedFile() {
restoredFileMetadata,
openDocWithId,
openFileWithId,
setView,
restoreView,
])
useEffect(() => {
@@ -7,15 +7,18 @@ import { useEditorAnalytics } from '@/shared/hooks/use-editor-analytics'
export default function ShowHistoryButton() {
const { t } = useTranslation()
const { view, setView } = useLayoutContext()
const { view, setView, restoreView } = useLayoutContext()
const { sendEvent } = useEditorAnalytics()
const toggleHistoryOpen = useCallback(() => {
const action = view === 'history' ? 'close' : 'open'
sendEvent('navigation-clicked-history', { action })
setView(view === 'history' ? 'editor' : 'history')
}, [view, setView, sendEvent])
if (view === 'history') {
restoreView()
} else {
setView('history')
}
}, [view, setView, sendEvent, restoreView])
return (
<div className="ide-redesign-toolbar-button-container">
@@ -20,7 +20,7 @@ const [publishModalModules] = importOverleafModules('publishModal')
const SubmitProjectButton = publishModalModules?.import.NewPublishToolbarButton
export const Toolbar = () => {
const { view, setView } = useLayoutContext()
const { view, restoreView } = useLayoutContext()
const { cobranding } = useEditorContext()
const { permissionsLevel } = useIdeReactContext()
const shouldDisplaySubmitButton =
@@ -29,8 +29,8 @@ export const Toolbar = () => {
const handleBackToEditorClick = useCallback(() => {
eventTracking.sendMB('navigation-clicked-history', { action: 'close' })
setView('editor')
}, [setView])
restoreView()
}, [restoreView])
if (view === 'history') {
return (
@@ -4,7 +4,7 @@ import OLButton from '@/features/ui/components/ol/ol-button'
import { useLayoutContext } from '../../../shared/context/layout-context'
function SwitchToEditorButton() {
const { pdfLayout, setView, detachRole } = useLayoutContext()
const { pdfLayout, restoreView, detachRole } = useLayoutContext()
const { t } = useTranslation()
@@ -17,7 +17,7 @@ function SwitchToEditorButton() {
}
function handleClick() {
setView('editor')
restoreView()
window.setTimeout(() => {
window.dispatchEvent(new Event('editor:focus'))
})
@@ -8,6 +8,7 @@ import {
SetStateAction,
FC,
useState,
useRef,
} from 'react'
import useDetachLayout from '../hooks/use-detach-layout'
import localStorage from '../../infrastructure/local-storage'
@@ -61,6 +62,7 @@ export type LayoutContextValue = LayoutContextOwnStates & {
pdfPreviewOpen: boolean
setProjectSearchIsOpen: Dispatch<SetStateAction<boolean>>
setOpenFile: Dispatch<SetStateAction<BinaryFile | null>>
restoreView: () => void
}
const debugPdfDetach = getMeta('ol-debugPdfDetach')
@@ -85,6 +87,8 @@ export const LayoutProvider: FC<React.PropsWithChildren> = ({ children }) => {
const historyToggleEmitter = useScopeEventEmitter('history:toggle', true)
const { isOpen: railIsOpen, setIsOpen: setRailIsOpen } = useRailContext()
const [prevRailIsOpen, setPrevRailIsOpen] = useState(railIsOpen)
// Whether we came from a file or a document when we left the ide
const lastIdeView = useRef<IdeView>('editor')
const setView = useCallback(
(value: IdeView | null) => {
@@ -103,12 +107,8 @@ export const LayoutProvider: FC<React.PropsWithChildren> = ({ children }) => {
setRailIsOpen(prevRailIsOpen)
}
if (value === 'editor' && openFile) {
// if a file is currently opened, ensure the view is 'file' instead of
// 'editor' when the 'editor' view is requested. This is to ensure
// that the entity selected in the file tree is the one visible and
// that docs don't take precedence over files.
return 'file'
if (value === 'editor' || value === 'file') {
lastIdeView.current = value
}
return value
@@ -117,7 +117,6 @@ export const LayoutProvider: FC<React.PropsWithChildren> = ({ children }) => {
[
_setView,
setRailIsOpen,
openFile,
historyToggleEmitter,
prevRailIsOpen,
setPrevRailIsOpen,
@@ -125,6 +124,10 @@ export const LayoutProvider: FC<React.PropsWithChildren> = ({ children }) => {
]
)
const restoreView = useCallback(() => {
setView(lastIdeView.current ?? 'editor')
}, [setView])
// whether the chat pane is open
const [chatIsOpen, setChatIsOpen] = usePersistedState<boolean>(
'ui.chatOpen',
@@ -192,11 +195,16 @@ export const LayoutProvider: FC<React.PropsWithChildren> = ({ children }) => {
const changeLayout = useCallback(
(newLayout: IdeLayout, newView: IdeView = 'editor') => {
const targetView = newLayout === 'sideBySide' ? 'editor' : newView
setPdfLayout(newLayout)
setView(newLayout === 'sideBySide' ? 'editor' : newView)
if (targetView === 'editor') {
restoreView()
} else {
setView(targetView)
}
setLayoutInLocalStorage(newLayout)
},
[setPdfLayout, setView]
[setPdfLayout, setView, restoreView]
)
// Force codemirror to reposition all tooltips to prevent an issue
@@ -276,6 +284,7 @@ export const LayoutProvider: FC<React.PropsWithChildren> = ({ children }) => {
setLoadingStyleSheet,
setView,
view,
restoreView,
}),
[
reattach,
@@ -302,6 +311,7 @@ export const LayoutProvider: FC<React.PropsWithChildren> = ({ children }) => {
setLoadingStyleSheet,
setView,
view,
restoreView,
]
)
@@ -95,6 +95,7 @@ const createInitialValue = () =>
setProjectSearchIsOpen: cy.stub(),
openFile: null,
setOpenFile: cy.stub(),
restoreView: cy.stub(),
}) satisfies LayoutContextValue
const LayoutProvider: FC<React.PropsWithChildren> = ({ children }) => {
@@ -409,6 +409,11 @@ const makeLayoutProvider = (
},
[setPdfLayout, setView]
)
const restoreView = useCallback(() => {
setView('editor')
}, [])
const {
reattach,
detach,
@@ -443,6 +448,7 @@ const makeLayoutProvider = (
setLoadingStyleSheet,
setView,
view,
restoreView,
}),
[
reattach,
@@ -469,6 +475,7 @@ const makeLayoutProvider = (
setLoadingStyleSheet,
setView,
view,
restoreView,
]
)