Merge pull request #26326 from overleaf/td-clean-up-scope-store

Create separate window.overleaf.unstable.store based on React context values

GitOrigin-RevId: 68f070a6fc5e2965a82720024d91b16fa622b28b
This commit is contained in:
Tim Down
2025-07-02 08:05:53 +00:00
committed by Copybot
parent dc97da1276
commit 904fac958d
34 changed files with 621 additions and 251 deletions
@@ -37,6 +37,7 @@ import { Update } from '@/features/history/services/types/update'
import { useDebugDiffTracker } from '../hooks/use-debug-diff-tracker'
import { useEditorContext } from '@/shared/context/editor-context'
import { convertFileRefToBinaryFile } from '@/features/ide-react/util/file-view'
import { useEditorOpenDocContext } from '@/features/ide-react/context/editor-open-doc-context'
export interface GotoOffsetOptions {
gotoOffset: number
@@ -53,8 +54,6 @@ interface OpenDocOptions
export type EditorManager = {
getEditorType: () => EditorType | null
showSymbolPalette: boolean
currentDocument: DocumentContainer | null
currentDocumentId: DocId | null
getCurrentDocValue: () => string | null
getCurrentDocumentId: () => DocId | null
setIgnoringExternalUpdates: (value: boolean) => void
@@ -63,8 +62,6 @@ export type EditorManager = {
openDocs: OpenDocuments
openFileWithId: (fileId: string) => void
openInitialDoc: (docId: string) => void
openDocName: string | null
setOpenDocName: (openDocName: string) => void
isLoading: boolean
trackChanges: boolean
jumpToLine: (options: GotoLineOptions) => void
@@ -104,14 +101,13 @@ export const EditorManagerProvider: FC<React.PropsWithChildren> = ({
'editor.showSymbolPalette'
)
const [showVisual] = useScopeValue<boolean>('editor.showVisual')
const [currentDocument, setCurrentDocument] =
useScopeValue<DocumentContainer | null>('editor.sharejs_doc')
const [currentDocumentId, setCurrentDocumentId] = useScopeValue<DocId | null>(
'editor.open_doc_id'
)
const [openDocName, setOpenDocName] = useScopeValue<string | null>(
'editor.open_doc_name'
)
const {
currentDocumentId,
setCurrentDocumentId,
setOpenDocName,
currentDocument,
setCurrentDocument,
} = useEditorOpenDocContext()
const [opening, setOpening] = useScopeValue<boolean>('editor.opening')
const [errorState, setIsInErrorState] =
useScopeValue<boolean>('editor.error_state')
@@ -667,16 +663,12 @@ export const EditorManagerProvider: FC<React.PropsWithChildren> = ({
() => ({
getEditorType,
showSymbolPalette,
currentDocument,
currentDocumentId,
getCurrentDocValue,
getCurrentDocumentId,
setIgnoringExternalUpdates,
openDocWithId,
openDoc,
openDocs,
openDocName,
setOpenDocName,
trackChanges,
isLoading,
openFileWithId,
@@ -689,8 +681,6 @@ export const EditorManagerProvider: FC<React.PropsWithChildren> = ({
[
getEditorType,
showSymbolPalette,
currentDocument,
currentDocumentId,
getCurrentDocValue,
getCurrentDocumentId,
setIgnoringExternalUpdates,
@@ -699,8 +689,6 @@ export const EditorManagerProvider: FC<React.PropsWithChildren> = ({
openDocs,
openFileWithId,
openInitialDoc,
openDocName,
setOpenDocName,
trackChanges,
isLoading,
jumpToLine,
@@ -0,0 +1,63 @@
import {
createContext,
Dispatch,
FC,
PropsWithChildren,
SetStateAction,
useContext,
useState,
} from 'react'
import { DocId } from '../../../../../types/project-settings'
import useExposedState from '@/shared/hooks/use-exposed-state'
import { DocumentContainer } from '@/features/ide-react/editor/document-container'
type EditorOpenDocContextValue = {
currentDocumentId: DocId | null
setCurrentDocumentId: Dispatch<SetStateAction<DocId | null>>
openDocName: string | null
setOpenDocName: Dispatch<SetStateAction<string | null>>
currentDocument: DocumentContainer | null
setCurrentDocument: Dispatch<SetStateAction<DocumentContainer | null>>
}
export const EditorOpenDocContext = createContext<
EditorOpenDocContextValue | undefined
>(undefined)
export const EditorOpenDocProvider: FC<PropsWithChildren> = ({ children }) => {
const [currentDocumentId, setCurrentDocumentId] =
useExposedState<DocId | null>(null, 'editor.open_doc_id')
const [openDocName, setOpenDocName] = useExposedState<string | null>(
null,
'editor.open_doc_name'
)
const [currentDocument, setCurrentDocument] =
useState<DocumentContainer | null>(null)
const value = {
currentDocumentId,
setCurrentDocumentId,
openDocName,
setOpenDocName,
currentDocument,
setCurrentDocument,
}
return (
<EditorOpenDocContext.Provider value={value}>
{children}
</EditorOpenDocContext.Provider>
)
}
export const useEditorOpenDocContext = (): EditorOpenDocContextValue => {
const context = useContext(EditorOpenDocContext)
if (!context) {
throw new Error(
'useEditorOpenDocContext is only available inside EditorOpenDocContext.Provider'
)
}
return context
}
@@ -0,0 +1,49 @@
import {
createContext,
Dispatch,
FC,
PropsWithChildren,
SetStateAction,
useContext,
} from 'react'
import { EditorView } from '@codemirror/view'
import useExposedState from '@/shared/hooks/use-exposed-state'
export type EditorContextValue = {
view: EditorView | null
setView: Dispatch<SetStateAction<EditorView | null>>
}
// This provides access to the CodeMirror EditorView instance outside the editor
// component itself, including external extensions (in particular, Writefull)
export const EditorViewContext = createContext<EditorContextValue | undefined>(
undefined
)
export const EditorViewProvider: FC<PropsWithChildren> = ({ children }) => {
const [view, setView] = useExposedState<EditorView | null>(
null,
'editor.view'
)
const value = {
view,
setView,
}
return (
<EditorViewContext.Provider value={value}>
{children}
</EditorViewContext.Provider>
)
}
export const useEditorViewContext = (): EditorContextValue => {
const context = useContext(EditorViewContext)
if (!context) {
throw new Error(
'useEditorViewContext is only available inside EditorViewProvider'
)
}
return context
}
@@ -11,6 +11,7 @@ import {
import { useProjectContext } from '@/shared/context/project-context'
import { useIdeReactContext } from '@/features/ide-react/context/ide-react-context'
import { useEditorManagerContext } from '@/features/ide-react/context/editor-manager-context'
import { useEditorOpenDocContext } from '@/features/ide-react/context/editor-open-doc-context'
import {
FileTreeDocumentFindResult,
FileTreeFileRefFindResult,
@@ -40,8 +41,8 @@ export const FileTreeOpenProvider: FC<React.PropsWithChildren> = ({
}) => {
const { rootDocId, owner } = useProjectContext()
const { eventEmitter, projectJoined } = useIdeReactContext()
const { openDocWithId, currentDocumentId, openInitialDoc } =
useEditorManagerContext()
const { openDocWithId, openInitialDoc } = useEditorManagerContext()
const { currentDocumentId } = useEditorOpenDocContext()
const { setOpenFile } = useLayoutContext()
const [openEntity, setOpenEntity] = useState<
FileTreeDocumentFindResult | FileTreeFileRefFindResult | null
@@ -81,6 +81,13 @@ export const IdeReactProvider: FC<React.PropsWithChildren> = ({ children }) => {
const [scopeEventEmitter] = useState(
() => new ReactScopeEventEmitter(eventEmitter)
)
const [unstableStore] = useState(() => {
const store = new ReactScopeValueStore()
// Add dummy editor.ready key for Writefull, that relies on this calling
// back once after watching it
store.set('editor.ready', undefined)
return store
})
const [startedFreeTrial, setStartedFreeTrial] = useState(false)
const release = getMeta('ol-ExposedSettings')?.sentryRelease ?? null
@@ -179,6 +186,7 @@ export const IdeReactProvider: FC<React.PropsWithChildren> = ({ children }) => {
ide={ide}
scopeStore={scopeStore}
scopeEventEmitter={scopeEventEmitter}
unstableStore={unstableStore}
>
{children}
</IdeProvider>
@@ -10,7 +10,7 @@ import {
} from 'react'
import { useIdeReactContext } from '@/features/ide-react/context/ide-react-context'
import { useConnectionContext } from '@/features/ide-react/context/connection-context'
import { useEditorManagerContext } from '@/features/ide-react/context/editor-manager-context'
import { useEditorOpenDocContext } from '@/features/ide-react/context/editor-open-doc-context'
import { getJSON, postJSON } from '@/infrastructure/fetch-json'
import { useOnlineUsersContext } from '@/features/ide-react/context/online-users-context'
import { useEditorContext } from '@/shared/context/editor-context'
@@ -54,7 +54,7 @@ export const MetadataProvider: FC<React.PropsWithChildren> = ({ children }) => {
const { onlineUsersCount } = useOnlineUsersContext()
const { permissionsLevel } = useEditorContext()
const permissions = usePermissionsContext()
const { currentDocument } = useEditorManagerContext()
const { currentDocument } = useEditorOpenDocContext()
const { showGenericMessageModal } = useModalsContext()
const [documents, setDocuments] = useState<DocumentsMetadata>({})
@@ -18,7 +18,7 @@ import useSocketListener from '@/features/ide-react/hooks/use-socket-listener'
import { debugConsole } from '@/utils/debugging'
import { IdeEvents } from '@/features/ide-react/create-ide-event-emitter'
import { getHueForUserId } from '@/shared/utils/colors'
import { useEditorManagerContext } from '@/features/ide-react/context/editor-manager-context'
import { useEditorOpenDocContext } from '@/features/ide-react/context/editor-open-doc-context'
export type OnlineUser = {
id: string
@@ -70,7 +70,7 @@ export const OnlineUsersProvider: FC<React.PropsWithChildren> = ({
}) => {
const { eventEmitter } = useIdeReactContext()
const { socket } = useConnectionContext()
const { currentDocumentId } = useEditorManagerContext()
const { currentDocumentId } = useEditorOpenDocContext()
const { fileTreeData } = useFileTreeData()
const [onlineUsers, setOnlineUsers] = useState<Record<string, OnlineUser>>({})
@@ -14,7 +14,7 @@ import * as eventTracking from '@/infrastructure/event-tracking'
import { isValidTeXFile } from '@/main/is-valid-tex-file'
import localStorage from '@/infrastructure/local-storage'
import { useProjectContext } from '@/shared/context/project-context'
import { useEditorManagerContext } from '@/features/ide-react/context/editor-manager-context'
import { useEditorOpenDocContext } from '@/features/ide-react/context/editor-open-doc-context'
export type PartialFlatOutline = {
level: number
@@ -118,7 +118,7 @@ export const OutlineProvider: FC<React.PropsWithChildren> = ({ children }) => {
[flatOutline, currentlyHighlightedLine]
)
const { openDocName } = useEditorManagerContext()
const { openDocName } = useEditorOpenDocContext()
const isTexFile = useMemo(
() => (openDocName ? isValidTeXFile(openDocName) : false),
[openDocName]
@@ -4,7 +4,9 @@ import { ConnectionProvider } from './connection-context'
import { DetachCompileProvider } from '@/shared/context/detach-compile-context'
import { DetachProvider } from '@/shared/context/detach-context'
import { EditorManagerProvider } from '@/features/ide-react/context/editor-manager-context'
import { EditorOpenDocProvider } from '@/features/ide-react/context/editor-open-doc-context'
import { EditorProvider } from '@/shared/context/editor-context'
import { EditorViewProvider } from '@/features/ide-react/context/editor-view-context'
import { FileTreeDataProvider } from '@/shared/context/file-tree-data-context'
import { FileTreeOpenProvider } from '@/features/ide-react/context/file-tree-open-context'
import { FileTreePathProvider } from '@/features/file-tree/contexts/file-tree-path'
@@ -39,7 +41,9 @@ export const ReactContextRoot: FC<
DetachCompileProvider,
DetachProvider,
EditorManagerProvider,
EditorOpenDocProvider,
EditorProvider,
EditorViewProvider,
FileTreeDataProvider,
FileTreeOpenProvider,
FileTreePathProvider,
@@ -74,47 +78,51 @@ export const ReactContextRoot: FC<
<Providers.UserSettingsProvider>
<Providers.ProjectProvider>
<Providers.SnapshotProvider>
<Providers.FileTreeDataProvider>
<Providers.FileTreePathProvider>
<Providers.ReferencesProvider>
<Providers.DetachProvider>
<Providers.EditorProvider>
<Providers.UserFeaturesProvider>
<Providers.PermissionsProvider>
<Providers.RailProvider>
<Providers.LayoutProvider>
<Providers.ProjectSettingsProvider>
<Providers.EditorManagerProvider>
<Providers.LocalCompileProvider>
<Providers.DetachCompileProvider>
<Providers.ChatProvider>
<Providers.FileTreeOpenProvider>
<Providers.OnlineUsersProvider>
<Providers.MetadataProvider>
<Providers.OutlineProvider>
<Providers.IdeRedesignSwitcherProvider>
<Providers.CommandRegistryProvider>
{children}
</Providers.CommandRegistryProvider>
</Providers.IdeRedesignSwitcherProvider>
</Providers.OutlineProvider>
</Providers.MetadataProvider>
</Providers.OnlineUsersProvider>
</Providers.FileTreeOpenProvider>
</Providers.ChatProvider>
</Providers.DetachCompileProvider>
</Providers.LocalCompileProvider>
</Providers.EditorManagerProvider>
</Providers.ProjectSettingsProvider>
</Providers.LayoutProvider>
</Providers.RailProvider>
</Providers.PermissionsProvider>
</Providers.UserFeaturesProvider>
</Providers.EditorProvider>
</Providers.DetachProvider>
</Providers.ReferencesProvider>
</Providers.FileTreePathProvider>
</Providers.FileTreeDataProvider>
<Providers.DetachProvider>
<Providers.EditorViewProvider>
<Providers.EditorOpenDocProvider>
<Providers.EditorProvider>
<Providers.FileTreeDataProvider>
<Providers.FileTreePathProvider>
<Providers.ReferencesProvider>
<Providers.UserFeaturesProvider>
<Providers.PermissionsProvider>
<Providers.RailProvider>
<Providers.LayoutProvider>
<Providers.ProjectSettingsProvider>
<Providers.EditorManagerProvider>
<Providers.LocalCompileProvider>
<Providers.DetachCompileProvider>
<Providers.ChatProvider>
<Providers.FileTreeOpenProvider>
<Providers.OnlineUsersProvider>
<Providers.MetadataProvider>
<Providers.OutlineProvider>
<Providers.IdeRedesignSwitcherProvider>
<Providers.CommandRegistryProvider>
{children}
</Providers.CommandRegistryProvider>
</Providers.IdeRedesignSwitcherProvider>
</Providers.OutlineProvider>
</Providers.MetadataProvider>
</Providers.OnlineUsersProvider>
</Providers.FileTreeOpenProvider>
</Providers.ChatProvider>
</Providers.DetachCompileProvider>
</Providers.LocalCompileProvider>
</Providers.EditorManagerProvider>
</Providers.ProjectSettingsProvider>
</Providers.LayoutProvider>
</Providers.RailProvider>
</Providers.PermissionsProvider>
</Providers.UserFeaturesProvider>
</Providers.ReferencesProvider>
</Providers.FileTreePathProvider>
</Providers.FileTreeDataProvider>
</Providers.EditorProvider>
</Providers.EditorOpenDocProvider>
</Providers.EditorViewProvider>
</Providers.DetachProvider>
</Providers.SnapshotProvider>
</Providers.ProjectProvider>
</Providers.UserSettingsProvider>