mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-06-01 21:31:36 +02:00
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:
@@ -3,6 +3,7 @@ import React, { FC, lazy, Suspense } from 'react'
|
||||
import useScopeValue from '@/shared/hooks/use-scope-value'
|
||||
import SourceEditor from '@/features/source-editor/components/source-editor'
|
||||
import { useEditorManagerContext } from '@/features/ide-react/context/editor-manager-context'
|
||||
import { useEditorOpenDocContext } from '@/features/ide-react/context/editor-open-doc-context'
|
||||
import { EditorScopeValue } from '@/features/ide-react/scope-adapters/editor-manager-context-adapter'
|
||||
import classNames from 'classnames'
|
||||
import { LoadingPane } from '@/features/ide-react/components/editor/loading-pane'
|
||||
@@ -17,7 +18,8 @@ const SymbolPalettePane = lazy(
|
||||
export const EditorPane: FC = () => {
|
||||
const [editor] = useScopeValue<EditorScopeValue>('editor')
|
||||
const { selectedEntityCount, openEntity } = useFileTreeOpenContext()
|
||||
const { currentDocumentId, isLoading } = useEditorManagerContext()
|
||||
const { isLoading } = useEditorManagerContext()
|
||||
const { currentDocumentId } = useEditorOpenDocContext()
|
||||
|
||||
if (!currentDocumentId) {
|
||||
return null
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -6,8 +6,6 @@ export type EditorScopeValue = {
|
||||
showSymbolPalette: false
|
||||
toggleSymbolPalette: () => void
|
||||
sharejs_doc: DocumentContainer | null
|
||||
open_doc_id: string | null
|
||||
open_doc_name: string | null
|
||||
opening: boolean
|
||||
trackChanges: boolean
|
||||
wantTrackChanges: boolean
|
||||
@@ -25,8 +23,6 @@ export function populateEditorScope(
|
||||
showSymbolPalette: false,
|
||||
toggleSymbolPalette: () => {},
|
||||
sharejs_doc: null,
|
||||
open_doc_id: null,
|
||||
open_doc_name: null,
|
||||
opening: true,
|
||||
trackChanges: false,
|
||||
wantTrackChanges: false,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { LoadingPane } from '@/features/ide-react/components/editor/loading-pane'
|
||||
import { useEditorManagerContext } from '@/features/ide-react/context/editor-manager-context'
|
||||
import { useEditorOpenDocContext } from '@/features/ide-react/context/editor-open-doc-context'
|
||||
import { EditorScopeValue } from '@/features/ide-react/scope-adapters/editor-manager-context-adapter'
|
||||
import { useFileTreeOpenContext } from '@/features/ide-react/context/file-tree-open-context'
|
||||
import useScopeValue from '@/shared/hooks/use-scope-value'
|
||||
@@ -14,16 +14,16 @@ import SymbolPalettePane from '@/features/ide-react/components/editor/symbol-pal
|
||||
export const Editor = () => {
|
||||
const [editor] = useScopeValue<EditorScopeValue>('editor')
|
||||
const { selectedEntityCount, openEntity } = useFileTreeOpenContext()
|
||||
const { currentDocumentId } = useEditorManagerContext()
|
||||
const { currentDocumentId, currentDocument } = useEditorOpenDocContext()
|
||||
|
||||
if (!currentDocumentId) {
|
||||
return null
|
||||
}
|
||||
|
||||
const isLoading = Boolean(
|
||||
(!editor.sharejs_doc || editor.opening) &&
|
||||
(!currentDocument || editor.opening) &&
|
||||
!editor.error_state &&
|
||||
editor.open_doc_id
|
||||
currentDocumentId
|
||||
)
|
||||
|
||||
return (
|
||||
|
||||
@@ -12,7 +12,7 @@ export const usePdfPreviewContext = () => {
|
||||
const context = useContext(PdfPreviewContext)
|
||||
if (!context) {
|
||||
throw new Error(
|
||||
'usePdfPreviewContext is only avalable inside PdfPreviewProvider'
|
||||
'usePdfPreviewContext is only available inside PdfPreviewProvider'
|
||||
)
|
||||
}
|
||||
return context
|
||||
|
||||
@@ -13,6 +13,7 @@ import * as eventTracking from '../../../infrastructure/event-tracking'
|
||||
import { debugConsole } from '@/utils/debugging'
|
||||
import { useFileTreePathContext } from '@/features/file-tree/contexts/file-tree-path'
|
||||
import { useEditorManagerContext } from '@/features/ide-react/context/editor-manager-context'
|
||||
import { useEditorOpenDocContext } from '@/features/ide-react/context/editor-open-doc-context'
|
||||
import useEventListener from '@/shared/hooks/use-event-listener'
|
||||
import { CursorPosition } from '@/features/ide-react/types/cursor-position'
|
||||
import { isValidTeXFile } from '@/main/is-valid-tex-file'
|
||||
@@ -34,8 +35,8 @@ export default function useSynctex(): {
|
||||
|
||||
const { selectedEntities } = useFileTreeData()
|
||||
const { findEntityByPath, dirname, pathInFolder } = useFileTreePathContext()
|
||||
const { getCurrentDocumentId, openDocWithId, openDocName } =
|
||||
useEditorManagerContext()
|
||||
const { openDocName } = useEditorOpenDocContext()
|
||||
const { getCurrentDocumentId, openDocWithId } = useEditorManagerContext()
|
||||
|
||||
const [cursorPosition, setCursorPosition] = useState<CursorPosition | null>(
|
||||
() => {
|
||||
|
||||
@@ -21,7 +21,7 @@ import { useIdeReactContext } from '@/features/ide-react/context/ide-react-conte
|
||||
import { useConnectionContext } from '@/features/ide-react/context/connection-context'
|
||||
import useSocketListener from '@/features/ide-react/hooks/use-socket-listener'
|
||||
import { throttle } from 'lodash'
|
||||
import { useEditorManagerContext } from '@/features/ide-react/context/editor-manager-context'
|
||||
import { useEditorOpenDocContext } from '@/features/ide-react/context/editor-open-doc-context'
|
||||
|
||||
export type Ranges = {
|
||||
docId: string
|
||||
@@ -81,7 +81,7 @@ const RangesActionsContext = createContext<RangesActions | undefined>(undefined)
|
||||
export const RangesProvider: FC<React.PropsWithChildren> = ({ children }) => {
|
||||
const view = useCodeMirrorViewContext()
|
||||
const { projectId } = useIdeReactContext()
|
||||
const { currentDocument } = useEditorManagerContext()
|
||||
const { currentDocument } = useEditorOpenDocContext()
|
||||
const { socket } = useConnectionContext()
|
||||
const [ranges, setRanges] = useState<Ranges | undefined>(() =>
|
||||
buildRanges(currentDocument)
|
||||
|
||||
@@ -20,7 +20,7 @@ import { UserId } from '../../../../../types/user'
|
||||
import { deleteJSON, getJSON, postJSON } from '@/infrastructure/fetch-json'
|
||||
import RangesTracker from '@overleaf/ranges-tracker'
|
||||
import { CommentOperation } from '../../../../../types/change'
|
||||
import { useEditorManagerContext } from '@/features/ide-react/context/editor-manager-context'
|
||||
import { useEditorOpenDocContext } from '@/features/ide-react/context/editor-open-doc-context'
|
||||
import { useEditorContext } from '@/shared/context/editor-context'
|
||||
import { debugConsole } from '@/utils/debugging'
|
||||
import { captureException } from '@/infrastructure/error-reporter'
|
||||
@@ -50,7 +50,7 @@ const ThreadsActionsContext = createContext<ThreadsActions | undefined>(
|
||||
|
||||
export const ThreadsProvider: FC<React.PropsWithChildren> = ({ children }) => {
|
||||
const { _id: projectId } = useProjectContext()
|
||||
const { currentDocument } = useEditorManagerContext()
|
||||
const { currentDocument } = useEditorOpenDocContext()
|
||||
const { isRestrictedTokenMember } = useEditorContext()
|
||||
|
||||
// const [error, setError] = useState<Error>()
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { memo, useCallback, useEffect } from 'react'
|
||||
import { useCodeMirrorViewContext } from './codemirror-context'
|
||||
import useCodeMirrorScope from '../hooks/use-codemirror-scope'
|
||||
import useScopeValueSetterOnly from '@/shared/hooks/use-scope-value-setter-only'
|
||||
import { useEditorViewContext } from '@/features/ide-react/context/editor-view-context'
|
||||
|
||||
function CodeMirrorView() {
|
||||
const view = useCodeMirrorViewContext()
|
||||
|
||||
const [, setView] = useScopeValueSetterOnly('editor.view')
|
||||
const { setView } = useEditorViewContext()
|
||||
|
||||
// append the editor view dom to the container node when mounted
|
||||
const containerRef = useCallback(
|
||||
@@ -25,7 +25,8 @@ function CodeMirrorView() {
|
||||
}
|
||||
}, [view])
|
||||
|
||||
// add the editor view to the scope value store, so it can be accessed by external extensions
|
||||
// Add the CodeMirror view to the editor view context so that it can be
|
||||
// accessed outside the editor component
|
||||
useEffect(() => {
|
||||
setView(view)
|
||||
}, [setView, view])
|
||||
|
||||
@@ -4,12 +4,12 @@ import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
|
||||
import { sendMB } from '../../../infrastructure/event-tracking'
|
||||
import { isValidTeXFile } from '../../../main/is-valid-tex-file'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useEditorManagerContext } from '@/features/ide-react/context/editor-manager-context'
|
||||
import { useEditorOpenDocContext } from '@/features/ide-react/context/editor-open-doc-context'
|
||||
|
||||
function EditorSwitch() {
|
||||
const { t } = useTranslation()
|
||||
const [visual, setVisual] = useScopeValue('editor.showVisual')
|
||||
const { openDocName } = useEditorManagerContext()
|
||||
const { openDocName } = useEditorOpenDocContext()
|
||||
|
||||
const richTextAvailable = openDocName ? isValidTeXFile(openDocName) : false
|
||||
|
||||
|
||||
@@ -57,6 +57,7 @@ import {
|
||||
} from '@/features/ide-react/context/editor-manager-context'
|
||||
import { GotoLineOptions } from '@/features/ide-react/types/goto-line-options'
|
||||
import { useOnlineUsersContext } from '@/features/ide-react/context/online-users-context'
|
||||
import { useEditorOpenDocContext } from '@/features/ide-react/context/editor-open-doc-context'
|
||||
|
||||
function useCodeMirrorScope(view: EditorView) {
|
||||
const { fileTreeData } = useFileTreeData()
|
||||
@@ -68,8 +69,8 @@ function useCodeMirrorScope(view: EditorView) {
|
||||
const { logEntryAnnotations, editedSinceCompileStarted, compiling } =
|
||||
useCompileContext()
|
||||
|
||||
const { currentDocument, openDocName, trackChanges } =
|
||||
useEditorManagerContext()
|
||||
const { openDocName, currentDocument } = useEditorOpenDocContext()
|
||||
const { trackChanges } = useEditorManagerContext()
|
||||
const metadata = useMetadataContext()
|
||||
|
||||
const { id: userId } = useUserContext()
|
||||
|
||||
@@ -6,6 +6,7 @@ import { useProjectContext } from '@/shared/context/project-context'
|
||||
import useAbortController from '@/shared/hooks/use-abort-controller'
|
||||
import { useProjectSettingsContext } from '@/features/editor-left-menu/context/project-settings-context'
|
||||
import { useEditorManagerContext } from '@/features/ide-react/context/editor-manager-context'
|
||||
import { useEditorOpenDocContext } from '@/features/ide-react/context/editor-open-doc-context'
|
||||
import { useFileTreePathContext } from '@/features/file-tree/contexts/file-tree-path'
|
||||
import { debugConsole } from '@/utils/debugging'
|
||||
import { signalWithTimeout } from '@/utils/abort-signal'
|
||||
@@ -20,7 +21,8 @@ export const WordCountClient: FC = () => {
|
||||
const [data, setData] = useState<WordCountData | null>(null)
|
||||
const { projectSnapshot, rootDocId } = useProjectContext()
|
||||
const { spellCheckLanguage } = useProjectSettingsContext()
|
||||
const { openDocs, currentDocument } = useEditorManagerContext()
|
||||
const { openDocs } = useEditorManagerContext()
|
||||
const { currentDocument } = useEditorOpenDocContext()
|
||||
const { pathInFolder } = useFileTreePathContext()
|
||||
|
||||
const { signal } = useAbortController()
|
||||
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
import { countFiles } from '../../features/file-tree/util/count-in-tree'
|
||||
import useDeepCompareEffect from '../../shared/hooks/use-deep-compare-effect'
|
||||
import { docsInFolder } from '@/features/file-tree/util/docs-in-folder'
|
||||
import useScopeValueSetterOnly from '@/shared/hooks/use-scope-value-setter-only'
|
||||
import { useEditorOpenDocContext } from '@/features/ide-react/context/editor-open-doc-context'
|
||||
import { Folder } from '../../../../types/folder'
|
||||
import { Project } from '../../../../types/project'
|
||||
import { MainDocument } from '../../../../types/project-settings'
|
||||
@@ -180,8 +180,7 @@ export const FileTreeDataProvider: FC<React.PropsWithChildren> = ({
|
||||
children,
|
||||
}) => {
|
||||
const [project] = useScopeValue<Project>('project')
|
||||
const [currentDocumentId] = useScopeValue('editor.open_doc_id')
|
||||
const [, setOpenDocName] = useScopeValueSetterOnly('editor.open_doc_name')
|
||||
const { currentDocumentId, setOpenDocName } = useEditorOpenDocContext()
|
||||
const [permissionsLevel] = useScopeValue('permissionsLevel')
|
||||
const { fileTreeFromHistory, snapshot, snapshotVersion } =
|
||||
useSnapshotContext()
|
||||
|
||||
@@ -10,6 +10,7 @@ export type Ide = {
|
||||
type IdeContextValue = Ide & {
|
||||
scopeStore: ScopeValueStore
|
||||
scopeEventEmitter: ScopeEventEmitter
|
||||
unstableStore: ScopeValueStore
|
||||
}
|
||||
|
||||
export const IdeContext = createContext<IdeContextValue | undefined>(undefined)
|
||||
@@ -19,14 +20,14 @@ export const IdeProvider: FC<
|
||||
ide: Ide
|
||||
scopeStore: ScopeValueStore
|
||||
scopeEventEmitter: ScopeEventEmitter
|
||||
unstableStore: ScopeValueStore
|
||||
}>
|
||||
> = ({ ide, scopeStore, scopeEventEmitter, children }) => {
|
||||
> = ({ ide, scopeStore, scopeEventEmitter, unstableStore, children }) => {
|
||||
/**
|
||||
* Expose scopeStore via `window.overleaf.unstable.store`, so it can be accessed by external extensions.
|
||||
* Expose unstableStore via `window.overleaf.unstable.store`, so it can be accessed by external extensions.
|
||||
*
|
||||
* These properties are expected to be available:
|
||||
* - `editor.view`
|
||||
* - `project.spellcheckLanguage`
|
||||
* - `editor.open_doc_name`,
|
||||
* - `editor.open_doc_id`,
|
||||
* - `settings.theme`
|
||||
@@ -40,18 +41,19 @@ export const IdeProvider: FC<
|
||||
...window.overleaf,
|
||||
unstable: {
|
||||
...window.overleaf?.unstable,
|
||||
store: scopeStore,
|
||||
store: unstableStore,
|
||||
},
|
||||
}
|
||||
}, [scopeStore])
|
||||
}, [unstableStore])
|
||||
|
||||
const value = useMemo<IdeContextValue>(() => {
|
||||
return {
|
||||
...ide,
|
||||
scopeStore,
|
||||
scopeEventEmitter,
|
||||
unstableStore,
|
||||
}
|
||||
}, [ide, scopeStore, scopeEventEmitter])
|
||||
}, [ide, scopeStore, scopeEventEmitter, unstableStore])
|
||||
|
||||
return <IdeContext.Provider value={value}>{children}</IdeContext.Provider>
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ import { useFileTreePathContext } from '@/features/file-tree/contexts/file-tree-
|
||||
import { useUserSettingsContext } from '@/shared/context/user-settings-context'
|
||||
import { useFeatureFlag } from '@/shared/context/split-test-context'
|
||||
import { useEditorManagerContext } from '@/features/ide-react/context/editor-manager-context'
|
||||
import { useEditorOpenDocContext } from '@/features/ide-react/context/editor-open-doc-context'
|
||||
import { getJSON } from '@/infrastructure/fetch-json'
|
||||
import { CompileResponseData } from '../../../../types/compile'
|
||||
import {
|
||||
@@ -127,7 +128,8 @@ export const LocalCompileProvider: FC<React.PropsWithChildren> = ({
|
||||
children,
|
||||
}) => {
|
||||
const { hasPremiumCompile, isProjectOwner } = useEditorContext()
|
||||
const { openDocWithId, openDocs, currentDocument } = useEditorManagerContext()
|
||||
const { openDocWithId, openDocs } = useEditorManagerContext()
|
||||
const { currentDocument } = useEditorOpenDocContext()
|
||||
const { role } = useDetachContext()
|
||||
|
||||
const {
|
||||
|
||||
@@ -9,11 +9,11 @@ import {
|
||||
useEffect,
|
||||
} from 'react'
|
||||
|
||||
import { UserSettings, Keybindings } from '../../../../types/user-settings'
|
||||
import { UserSettings } from '../../../../types/user-settings'
|
||||
import getMeta from '@/utils/meta'
|
||||
import useScopeValue from '@/shared/hooks/use-scope-value'
|
||||
import { userStyles } from '../utils/styles'
|
||||
import { canUseNewEditor } from '@/features/ide-redesign/utils/new-editor-utils'
|
||||
import { useIdeContext } from '@/shared/context/ide-context'
|
||||
|
||||
const defaultSettings: UserSettings = {
|
||||
pdfViewer: 'pdfjs',
|
||||
@@ -39,15 +39,6 @@ type UserSettingsContextValue = {
|
||||
>
|
||||
}
|
||||
|
||||
type ScopeSettings = {
|
||||
overallTheme: 'light' | 'dark'
|
||||
keybindings: Keybindings
|
||||
fontSize: number
|
||||
fontFamily: string
|
||||
lineHeight: number
|
||||
isNewEditor: boolean
|
||||
}
|
||||
|
||||
export const UserSettingsContext = createContext<
|
||||
UserSettingsContextValue | undefined
|
||||
>(undefined)
|
||||
@@ -60,10 +51,10 @@ export const UserSettingsProvider: FC<React.PropsWithChildren> = ({
|
||||
)
|
||||
|
||||
// update the global scope 'settings' value, for extensions
|
||||
const [, setScopeSettings] = useScopeValue<ScopeSettings>('settings')
|
||||
const { unstableStore } = useIdeContext()
|
||||
useEffect(() => {
|
||||
const { fontFamily, lineHeight } = userStyles(userSettings)
|
||||
setScopeSettings({
|
||||
unstableStore.set('settings', {
|
||||
overallTheme: userSettings.overallTheme === 'light-' ? 'light' : 'dark',
|
||||
keybindings: userSettings.mode === 'none' ? 'default' : userSettings.mode,
|
||||
fontFamily,
|
||||
@@ -71,7 +62,7 @@ export const UserSettingsProvider: FC<React.PropsWithChildren> = ({
|
||||
fontSize: userSettings.fontSize,
|
||||
isNewEditor: canUseNewEditor() && userSettings.enableNewEditor,
|
||||
})
|
||||
}, [setScopeSettings, userSettings])
|
||||
}, [unstableStore, userSettings])
|
||||
|
||||
const value = useMemo<UserSettingsContextValue>(
|
||||
() => ({
|
||||
|
||||
25
services/web/frontend/js/shared/hooks/use-exposed-state.ts
Normal file
25
services/web/frontend/js/shared/hooks/use-exposed-state.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { type Dispatch, type SetStateAction, useEffect, useState } from 'react'
|
||||
import { useIdeContext } from '../context/ide-context'
|
||||
|
||||
/**
|
||||
* Creates a state variable that is exposed via window.overleaf.unstable.store,
|
||||
* which is used by Writefull (and only Writefull). Once Writefull is integrated
|
||||
* into our codebase, it should be able to hook directly into our React
|
||||
* contexts and we would then be able to remove this hook, replacing it with
|
||||
* useState.
|
||||
*/
|
||||
export default function useExposedState<T = any>(
|
||||
initialState: T | (() => T),
|
||||
path: string
|
||||
): [T, Dispatch<SetStateAction<T>>] {
|
||||
const [value, setValue] = useState<T>(initialState)
|
||||
|
||||
const { unstableStore } = useIdeContext()
|
||||
|
||||
// Update the unstable store whenever the value changes
|
||||
useEffect(() => {
|
||||
unstableStore.set(path, value)
|
||||
}, [unstableStore, path, value])
|
||||
|
||||
return [value, setValue]
|
||||
}
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
createReactScopeValueStore,
|
||||
} from '@/features/ide-react/context/ide-react-context'
|
||||
import { IdeEventEmitter } from '@/features/ide-react/create-ide-event-emitter'
|
||||
import { ReactScopeValueStore } from '@/features/ide-react/scope-value-store/react-scope-value-store'
|
||||
import { ReactScopeEventEmitter } from '@/features/ide-react/scope-event-emitter/react-scope-event-emitter'
|
||||
import { ConnectionContext } from '@/features/ide-react/context/connection-context'
|
||||
import { Socket } from '@/features/ide-react/connection/types/socket'
|
||||
@@ -65,6 +66,8 @@ const initialScope = {
|
||||
},
|
||||
editor: {
|
||||
richText: false,
|
||||
|
||||
// FIXME: This is pretty useless because the editor relies on a much more fleshed-out document, so we rely on overriding it in individual stories
|
||||
sharejs_doc: {
|
||||
doc_id: 'test-doc',
|
||||
getSnapshot: () => 'some doc content',
|
||||
@@ -195,12 +198,13 @@ const IdeReactProvider: FC<React.PropsWithChildren> = ({ children }) => {
|
||||
scopeStore.set(key, value)
|
||||
}
|
||||
const scopeEventEmitter = new ReactScopeEventEmitter(new IdeEventEmitter())
|
||||
const unstableStore = new ReactScopeValueStore()
|
||||
|
||||
window.overleaf = {
|
||||
...window.overleaf,
|
||||
unstable: {
|
||||
...window.overleaf?.unstable,
|
||||
store: scopeStore,
|
||||
store: unstableStore,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -208,6 +212,7 @@ const IdeReactProvider: FC<React.PropsWithChildren> = ({ children }) => {
|
||||
socket,
|
||||
scopeStore,
|
||||
scopeEventEmitter,
|
||||
unstableStore,
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import { ruleIds } from '@/ide/human-readable-logs/HumanReadableLogsHints'
|
||||
import { ScopeDecorator } from './decorators/scope'
|
||||
import { useMeta } from './hooks/use-meta'
|
||||
import { FC, ReactNode } from 'react'
|
||||
import { useScope } from './hooks/use-scope'
|
||||
import { EditorViewContext } from '@/features/ide-react/context/editor-view-context'
|
||||
import { EditorView } from '@codemirror/view'
|
||||
import { LogEntry } from '@/features/pdf-preview/util/types'
|
||||
|
||||
@@ -58,12 +58,30 @@ export default meta
|
||||
|
||||
type Story = StoryObj<typeof PdfLogEntry>
|
||||
|
||||
const MockEditorViewProvider: FC<React.PropsWithChildren> = ({ children }) => {
|
||||
const value = {
|
||||
view: new EditorView({
|
||||
doc: '\\begin{document',
|
||||
}),
|
||||
setView: () => {},
|
||||
}
|
||||
|
||||
return (
|
||||
<EditorViewContext.Provider value={value}>
|
||||
{children}
|
||||
</EditorViewContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
const Provider: FC<React.PropsWithChildren<{ children: ReactNode }>> = ({
|
||||
children,
|
||||
}) => {
|
||||
useMeta({ 'ol-showAiErrorAssistant': true })
|
||||
useScope({ 'editor.view': new EditorView({ doc: '\\begin{document' }) })
|
||||
return <div className="logs-pane p-2">{children}</div>
|
||||
return (
|
||||
<MockEditorViewProvider>
|
||||
<div className="logs-pane p-2">{children}</div>
|
||||
</MockEditorViewProvider>
|
||||
)
|
||||
}
|
||||
|
||||
export const PdfLogEntryWithControls: Story = {
|
||||
|
||||
@@ -2,9 +2,86 @@ import SourceEditor from '../../js/features/source-editor/components/source-edit
|
||||
import { ScopeDecorator } from '../decorators/scope'
|
||||
import { useScope } from '../hooks/use-scope'
|
||||
import { useMeta } from '../hooks/use-meta'
|
||||
import { FC } from 'react'
|
||||
import React, { FC, useState } from 'react'
|
||||
import { FileTreePathContext } from '@/features/file-tree/contexts/file-tree-path'
|
||||
import RangesTracker from '@overleaf/ranges-tracker'
|
||||
import useExposedState from '@/shared/hooks/use-exposed-state'
|
||||
import { EditorOpenDocContext } from '@/features/ide-react/context/editor-open-doc-context'
|
||||
import { DocId } from '../../../types/project-settings'
|
||||
import { StoryObj } from '@storybook/react'
|
||||
import { DocumentContainer } from '@/features/ide-react/editor/document-container'
|
||||
|
||||
type Story = StoryObj<typeof SourceEditor>
|
||||
|
||||
const EditorOpenDocProvider: FC<
|
||||
React.PropsWithChildren<{
|
||||
initialOpenDocName: string | null
|
||||
initialDocument: DocumentContainer
|
||||
}>
|
||||
> = ({ children, initialOpenDocName, initialDocument }) => {
|
||||
const [currentDocumentId, setCurrentDocumentId] =
|
||||
useExposedState<DocId | null>(null, 'editor.open_doc_id')
|
||||
const [openDocName, setOpenDocName] = useExposedState<string | null>(
|
||||
initialOpenDocName,
|
||||
'editor.open_doc_name'
|
||||
)
|
||||
const [currentDocument, setCurrentDocument] =
|
||||
useState<DocumentContainer | null>(initialDocument)
|
||||
|
||||
const value = {
|
||||
currentDocumentId,
|
||||
setCurrentDocumentId,
|
||||
openDocName,
|
||||
setOpenDocName,
|
||||
currentDocument,
|
||||
setCurrentDocument,
|
||||
}
|
||||
|
||||
return (
|
||||
<EditorOpenDocContext.Provider value={value}>
|
||||
{children}
|
||||
</EditorOpenDocContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
const LatexEditorOpenDocProvider: FC<React.PropsWithChildren> = ({
|
||||
children,
|
||||
}) => (
|
||||
<EditorOpenDocProvider
|
||||
initialOpenDocName="example.tex"
|
||||
initialDocument={
|
||||
mockDoc(content.tex, changes.tex) as unknown as DocumentContainer
|
||||
}
|
||||
>
|
||||
{children}
|
||||
</EditorOpenDocProvider>
|
||||
)
|
||||
|
||||
const MarkdownEditorOpenDocProvider: FC<React.PropsWithChildren> = ({
|
||||
children,
|
||||
}) => (
|
||||
<EditorOpenDocProvider
|
||||
initialOpenDocName="example.md"
|
||||
initialDocument={
|
||||
mockDoc(content.md, changes.md) as unknown as DocumentContainer
|
||||
}
|
||||
>
|
||||
{children}
|
||||
</EditorOpenDocProvider>
|
||||
)
|
||||
|
||||
const BibtexEditorOpenDocProvider: FC<React.PropsWithChildren> = ({
|
||||
children,
|
||||
}) => (
|
||||
<EditorOpenDocProvider
|
||||
initialOpenDocName="example.bib"
|
||||
initialDocument={
|
||||
mockDoc(content.bib, changes.bib) as unknown as DocumentContainer
|
||||
}
|
||||
>
|
||||
{children}
|
||||
</EditorOpenDocProvider>
|
||||
)
|
||||
|
||||
const FileTreePathProvider: FC<React.PropsWithChildren> = ({ children }) => (
|
||||
<FileTreePathContext.Provider
|
||||
@@ -29,11 +106,6 @@ export default {
|
||||
title: 'Editor / Source Editor',
|
||||
component: SourceEditor,
|
||||
decorators: [
|
||||
(Story: any) =>
|
||||
ScopeDecorator(Story, {
|
||||
mockCompileOnLoad: true,
|
||||
providers: { FileTreePathProvider },
|
||||
}),
|
||||
(Story: any) => (
|
||||
<div style={{ height: '90vh' }}>
|
||||
<Story />
|
||||
@@ -59,102 +131,144 @@ const permissions = {
|
||||
write: true,
|
||||
}
|
||||
|
||||
export const Latex = (args: any, { globals: { theme } }: any) => {
|
||||
// FIXME: useScope has no effect
|
||||
useScope({
|
||||
editor: {
|
||||
sharejs_doc: mockDoc(content.tex, changes.tex),
|
||||
open_doc_name: 'example.tex',
|
||||
},
|
||||
rootFolder: {
|
||||
name: 'rootFolder',
|
||||
id: 'root-folder-id',
|
||||
type: 'folder',
|
||||
children: [
|
||||
{
|
||||
name: 'example.tex.tex',
|
||||
id: 'example-doc-id',
|
||||
type: 'doc',
|
||||
export const Latex: Story = {
|
||||
decorators: [
|
||||
Story =>
|
||||
ScopeDecorator(Story, {
|
||||
mockCompileOnLoad: true,
|
||||
providers: {
|
||||
FileTreePathProvider,
|
||||
EditorOpenDocProvider: LatexEditorOpenDocProvider,
|
||||
},
|
||||
}),
|
||||
|
||||
(Story, { globals }) => {
|
||||
// FIXME: useScope has no effect
|
||||
useScope({
|
||||
rootFolder: {
|
||||
name: 'rootFolder',
|
||||
id: 'root-folder-id',
|
||||
type: 'folder',
|
||||
children: [
|
||||
{
|
||||
name: 'example.tex.tex',
|
||||
id: 'example-doc-id',
|
||||
type: 'doc',
|
||||
selected: false,
|
||||
$$hashKey: 'object:89',
|
||||
},
|
||||
{
|
||||
name: 'frog.jpg',
|
||||
id: 'frog-image-id',
|
||||
type: 'file',
|
||||
linkedFileData: null,
|
||||
created: '2023-05-04T16:11:04.352Z',
|
||||
$$hashKey: 'object:108',
|
||||
},
|
||||
],
|
||||
selected: false,
|
||||
$$hashKey: 'object:89',
|
||||
},
|
||||
{
|
||||
name: 'frog.jpg',
|
||||
id: 'frog-image-id',
|
||||
type: 'file',
|
||||
linkedFileData: null,
|
||||
created: '2023-05-04T16:11:04.352Z',
|
||||
$$hashKey: 'object:108',
|
||||
settings: {
|
||||
...settings,
|
||||
overallTheme: globals.theme === 'default-' ? '' : globals.theme,
|
||||
},
|
||||
],
|
||||
selected: false,
|
||||
},
|
||||
settings: {
|
||||
...settings,
|
||||
overallTheme: theme === 'default-' ? '' : theme,
|
||||
},
|
||||
permissions,
|
||||
})
|
||||
permissions,
|
||||
})
|
||||
|
||||
useMeta({
|
||||
'ol-showSymbolPalette': true,
|
||||
})
|
||||
useMeta({
|
||||
'ol-showSymbolPalette': true,
|
||||
})
|
||||
|
||||
return <SourceEditor />
|
||||
return <Story />
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
export const Markdown = (args: any, { globals: { theme } }: any) => {
|
||||
useScope({
|
||||
editor: {
|
||||
sharejs_doc: mockDoc(content.md, changes.md),
|
||||
open_doc_name: 'example.md',
|
||||
},
|
||||
settings: {
|
||||
...settings,
|
||||
overallTheme: theme === 'default-' ? '' : theme,
|
||||
},
|
||||
permissions,
|
||||
})
|
||||
export const Markdown: Story = {
|
||||
decorators: [
|
||||
Story =>
|
||||
ScopeDecorator(Story, {
|
||||
mockCompileOnLoad: true,
|
||||
providers: {
|
||||
FileTreePathProvider,
|
||||
EditorOpenDocProvider: MarkdownEditorOpenDocProvider,
|
||||
},
|
||||
}),
|
||||
|
||||
return <SourceEditor />
|
||||
(Story, { globals }) => {
|
||||
// FIXME: useScope has no effect
|
||||
useScope({
|
||||
settings: {
|
||||
...settings,
|
||||
overallTheme: globals.theme === 'default-' ? '' : globals.theme,
|
||||
},
|
||||
permissions,
|
||||
})
|
||||
|
||||
return <Story />
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
export const Visual = (args: any, { globals: { theme } }: any) => {
|
||||
useScope({
|
||||
editor: {
|
||||
sharejs_doc: mockDoc(content.tex, changes.tex),
|
||||
open_doc_name: 'example.tex',
|
||||
showVisual: true,
|
||||
},
|
||||
settings: {
|
||||
...settings,
|
||||
overallTheme: theme === 'default-' ? '' : theme,
|
||||
},
|
||||
permissions,
|
||||
})
|
||||
useMeta({
|
||||
'ol-showSymbolPalette': true,
|
||||
'ol-mathJaxPath': 'https://unpkg.com/mathjax@3.2.2/es5/tex-svg-full.js',
|
||||
'ol-project_id': '63e21c07946dd8c76505f85a',
|
||||
})
|
||||
export const Visual: Story = {
|
||||
decorators: [
|
||||
Story =>
|
||||
ScopeDecorator(Story, {
|
||||
mockCompileOnLoad: true,
|
||||
providers: {
|
||||
FileTreePathProvider,
|
||||
EditorOpenDocProvider: LatexEditorOpenDocProvider,
|
||||
},
|
||||
}),
|
||||
|
||||
return <SourceEditor />
|
||||
(Story, { globals }) => {
|
||||
// FIXME: useScope has no effect, so this does not default to the visual editor
|
||||
useScope({
|
||||
editor: {
|
||||
showVisual: true,
|
||||
},
|
||||
settings: {
|
||||
...settings,
|
||||
overallTheme: globals.theme === 'default-' ? '' : globals.theme,
|
||||
},
|
||||
permissions,
|
||||
})
|
||||
|
||||
useMeta({
|
||||
'ol-showSymbolPalette': true,
|
||||
'ol-mathJaxPath': 'https://unpkg.com/mathjax@3.2.2/es5/tex-svg-full.js',
|
||||
'ol-project_id': '63e21c07946dd8c76505f85a',
|
||||
})
|
||||
|
||||
return <Story />
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
export const Bibtex = (args: any, { globals: { theme } }: any) => {
|
||||
useScope({
|
||||
editor: {
|
||||
sharejs_doc: mockDoc(content.bib, changes.bib),
|
||||
open_doc_name: 'example.bib',
|
||||
},
|
||||
settings: {
|
||||
...settings,
|
||||
overallTheme: theme === 'default-' ? '' : theme,
|
||||
},
|
||||
permissions,
|
||||
})
|
||||
export const Bibtex: Story = {
|
||||
decorators: [
|
||||
Story =>
|
||||
ScopeDecorator(Story, {
|
||||
mockCompileOnLoad: true,
|
||||
providers: {
|
||||
FileTreePathProvider,
|
||||
EditorOpenDocProvider: BibtexEditorOpenDocProvider,
|
||||
},
|
||||
}),
|
||||
|
||||
return <SourceEditor />
|
||||
(Story, { globals }) => {
|
||||
// FIXME: useScope has no effect
|
||||
useScope({
|
||||
settings: {
|
||||
...settings,
|
||||
overallTheme: globals.theme === 'default-' ? '' : globals.theme,
|
||||
},
|
||||
permissions,
|
||||
})
|
||||
|
||||
return <Story />
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const MAX_DOC_LENGTH = 2 * 1024 * 1024 // ol-maxDocLength
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
import { EditorView } from '@codemirror/view'
|
||||
import { OpenDocuments } from '@/features/ide-react/editor/open-documents'
|
||||
import { LogEntry } from '@/features/pdf-preview/util/types'
|
||||
import { EditorViewContext } from '@/features/ide-react/context/editor-view-context'
|
||||
|
||||
describe('<PdfLogsEntries/>', function () {
|
||||
const fakeFindEntityResult: FindResult = {
|
||||
@@ -48,6 +49,19 @@ describe('<PdfLogsEntries/>', function () {
|
||||
)
|
||||
}
|
||||
|
||||
const EditorViewProvider: FC<React.PropsWithChildren> = ({ children }) => {
|
||||
const value = {
|
||||
view: new EditorView({ doc: '\\documentclass{article}' }),
|
||||
setView: cy.stub(),
|
||||
}
|
||||
|
||||
return (
|
||||
<EditorViewContext.Provider value={value}>
|
||||
{children}
|
||||
</EditorViewContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
const logEntries: LogEntry[] = [
|
||||
{
|
||||
file: 'main.tex',
|
||||
@@ -62,10 +76,6 @@ describe('<PdfLogsEntries/>', function () {
|
||||
},
|
||||
]
|
||||
|
||||
const scope = {
|
||||
'editor.view': new EditorView({ doc: '\\documentclass{article}' }),
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
cy.interceptCompile()
|
||||
cy.interceptEvents()
|
||||
@@ -73,7 +83,7 @@ describe('<PdfLogsEntries/>', function () {
|
||||
|
||||
it('displays human readable hint', function () {
|
||||
cy.mount(
|
||||
<EditorProviders scope={scope}>
|
||||
<EditorProviders providers={{ EditorViewProvider }}>
|
||||
<PdfLogsEntries entries={logEntries} />
|
||||
</EditorProviders>
|
||||
)
|
||||
@@ -84,8 +94,11 @@ describe('<PdfLogsEntries/>', function () {
|
||||
it('opens doc on click', function () {
|
||||
cy.mount(
|
||||
<EditorProviders
|
||||
scope={scope}
|
||||
providers={{ EditorManagerProvider, FileTreePathProvider }}
|
||||
providers={{
|
||||
EditorManagerProvider,
|
||||
FileTreePathProvider,
|
||||
EditorViewProvider,
|
||||
}}
|
||||
>
|
||||
<PdfLogsEntries entries={logEntries} />
|
||||
</EditorProviders>
|
||||
@@ -114,8 +127,11 @@ describe('<PdfLogsEntries/>', function () {
|
||||
|
||||
cy.mount(
|
||||
<EditorProviders
|
||||
scope={scope}
|
||||
providers={{ EditorManagerProvider, FileTreePathProvider }}
|
||||
providers={{
|
||||
EditorManagerProvider,
|
||||
FileTreePathProvider,
|
||||
EditorViewProvider,
|
||||
}}
|
||||
>
|
||||
<PdfLogsEntries entries={logEntries} />
|
||||
</EditorProviders>
|
||||
@@ -154,8 +170,11 @@ describe('<PdfLogsEntries/>', function () {
|
||||
|
||||
cy.mount(
|
||||
<EditorProviders
|
||||
scope={scope}
|
||||
providers={{ EditorManagerProvider, FileTreePathProvider }}
|
||||
providers={{
|
||||
EditorManagerProvider,
|
||||
FileTreePathProvider,
|
||||
EditorViewProvider,
|
||||
}}
|
||||
>
|
||||
<PdfLogsEntries entries={logEntries} />
|
||||
</EditorProviders>
|
||||
|
||||
@@ -3,7 +3,10 @@ import { cloneDeep } from 'lodash'
|
||||
import { useDetachCompileContext as useCompileContext } from '../../../../frontend/js/shared/context/detach-compile-context'
|
||||
import { useFileTreeData } from '../../../../frontend/js/shared/context/file-tree-data-context'
|
||||
import { useEffect } from 'react'
|
||||
import { EditorProviders } from '../../helpers/editor-providers'
|
||||
import {
|
||||
EditorProviders,
|
||||
makeEditorOpenDocProvider,
|
||||
} from '../../helpers/editor-providers'
|
||||
import { mockScope } from './scope'
|
||||
import { detachChannel, testDetachChannel } from '../../helpers/detach-channel'
|
||||
import { FindResult } from '@/features/file-tree/util/path'
|
||||
@@ -73,6 +76,22 @@ const WithSelectedEntities = ({
|
||||
return null
|
||||
}
|
||||
|
||||
function mockProviders() {
|
||||
return {
|
||||
EditorOpenDocProvider: makeEditorOpenDocProvider({
|
||||
openDocName: 'main.tex',
|
||||
currentDocument: {
|
||||
doc_id: 'test-doc',
|
||||
getSnapshot: () => 'some doc content',
|
||||
hasBufferedOps: () => false,
|
||||
on: () => {},
|
||||
off: () => {},
|
||||
leaveAndCleanUpPromise: () => Promise.resolve(),
|
||||
},
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
describe('<PdfSynctexControls/>', function () {
|
||||
beforeEach(function () {
|
||||
window.metaAttributesCache.set('ol-project_id', 'test-project')
|
||||
@@ -84,9 +103,10 @@ describe('<PdfSynctexControls/>', function () {
|
||||
cy.interceptCompile()
|
||||
|
||||
const scope = mockScope()
|
||||
const providers = mockProviders()
|
||||
|
||||
cy.mount(
|
||||
<EditorProviders scope={scope}>
|
||||
<EditorProviders scope={scope} providers={providers}>
|
||||
<WithPosition mockPosition={mockPosition} />
|
||||
<WithSelectedEntities mockSelectedEntities={mockSelectedEntities} />
|
||||
<PdfSynctexControls />
|
||||
@@ -145,9 +165,10 @@ describe('<PdfSynctexControls/>', function () {
|
||||
cy.interceptCompile()
|
||||
|
||||
const scope = mockScope()
|
||||
const providers = mockProviders()
|
||||
|
||||
cy.mount(
|
||||
<EditorProviders scope={scope}>
|
||||
<EditorProviders scope={scope} providers={providers}>
|
||||
<WithPosition mockPosition={mockPosition} />
|
||||
<WithSelectedEntities
|
||||
mockSelectedEntities={
|
||||
@@ -169,9 +190,10 @@ describe('<PdfSynctexControls/>', function () {
|
||||
cy.interceptCompile()
|
||||
|
||||
const scope = mockScope()
|
||||
const providers = mockProviders()
|
||||
|
||||
cy.mount(
|
||||
<EditorProviders scope={scope}>
|
||||
<EditorProviders scope={scope} providers={providers}>
|
||||
<WithPosition mockPosition={mockPosition} />
|
||||
<WithSelectedEntities
|
||||
mockSelectedEntities={[{ type: 'fileRef' }] as FindResult[]}
|
||||
@@ -196,9 +218,10 @@ describe('<PdfSynctexControls/>', function () {
|
||||
cy.interceptCompile()
|
||||
|
||||
const scope = mockScope()
|
||||
const providers = mockProviders()
|
||||
|
||||
cy.mount(
|
||||
<EditorProviders scope={scope}>
|
||||
<EditorProviders scope={scope} providers={providers}>
|
||||
<WithPosition mockPosition={mockPosition} />
|
||||
<WithSelectedEntities mockSelectedEntities={mockSelectedEntities} />
|
||||
<PdfSynctexControls />
|
||||
@@ -218,9 +241,10 @@ describe('<PdfSynctexControls/>', function () {
|
||||
cy.interceptCompile()
|
||||
|
||||
const scope = mockScope()
|
||||
const providers = mockProviders()
|
||||
|
||||
cy.mount(
|
||||
<EditorProviders scope={scope}>
|
||||
<EditorProviders scope={scope} providers={providers}>
|
||||
<WithPosition mockPosition={mockPosition} />
|
||||
<WithSelectedEntities mockSelectedEntities={mockSelectedEntities} />
|
||||
<PdfSynctexControls />
|
||||
@@ -279,9 +303,10 @@ describe('<PdfSynctexControls/>', function () {
|
||||
cy.interceptCompile()
|
||||
|
||||
const scope = mockScope()
|
||||
const providers = mockProviders()
|
||||
|
||||
cy.mount(
|
||||
<EditorProviders scope={scope}>
|
||||
<EditorProviders scope={scope} providers={providers}>
|
||||
<WithPosition mockPosition={mockPosition} />
|
||||
<WithSelectedEntities mockSelectedEntities={mockSelectedEntities} />
|
||||
<PdfSynctexControls />
|
||||
@@ -317,9 +342,10 @@ describe('<PdfSynctexControls/>', function () {
|
||||
cy.interceptCompile()
|
||||
|
||||
const scope = mockScope()
|
||||
const providers = mockProviders()
|
||||
|
||||
cy.mount(
|
||||
<EditorProviders scope={scope}>
|
||||
<EditorProviders scope={scope} providers={providers}>
|
||||
<WithPosition mockPosition={mockPosition} />
|
||||
<PdfSynctexControls />
|
||||
</EditorProviders>
|
||||
@@ -338,9 +364,10 @@ describe('<PdfSynctexControls/>', function () {
|
||||
cy.interceptCompile()
|
||||
|
||||
const scope = mockScope()
|
||||
const providers = mockProviders()
|
||||
|
||||
cy.mount(
|
||||
<EditorProviders scope={scope}>
|
||||
<EditorProviders scope={scope} providers={providers}>
|
||||
<PdfSynctexControls />
|
||||
</EditorProviders>
|
||||
)
|
||||
@@ -385,9 +412,10 @@ describe('<PdfSynctexControls/>', function () {
|
||||
cy.interceptCompile()
|
||||
|
||||
const scope = mockScope()
|
||||
const providers = mockProviders()
|
||||
|
||||
cy.mount(
|
||||
<EditorProviders scope={scope}>
|
||||
<EditorProviders scope={scope} providers={providers}>
|
||||
<WithPosition mockPosition={mockPosition} />
|
||||
<PdfSynctexControls />
|
||||
</EditorProviders>
|
||||
|
||||
@@ -6,7 +6,6 @@ export const mockScope = () => ({
|
||||
pdfViewer: 'pdfjs',
|
||||
},
|
||||
editor: {
|
||||
open_doc_name: 'main.tex',
|
||||
sharejs_doc: {
|
||||
doc_id: 'test-doc',
|
||||
getSnapshot: () => 'some doc content',
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
USER_ID,
|
||||
} from '../../../helpers/editor-providers'
|
||||
import { location } from '@/shared/components/location'
|
||||
import useScopeValue from '@/shared/hooks/use-scope-value'
|
||||
|
||||
async function changePrivilegeLevel(screen, { current, next }) {
|
||||
const select = screen.getByDisplayValue(current)
|
||||
@@ -820,7 +821,14 @@ describe('<ShareProjectModal/>', function () {
|
||||
fetchMock.get(`/project/${project._id}/tokens`, {})
|
||||
fetchMock.post('express:/project/:projectId/settings/admin', 204)
|
||||
|
||||
renderWithEditorContext(<ShareProjectModal {...modalProps} />, {
|
||||
let setPublicAccessLevel = function () {}
|
||||
|
||||
function WrappedModal() {
|
||||
setPublicAccessLevel = useScopeValue('project.publicAccesLevel')[1]
|
||||
return <ShareProjectModal {...modalProps} />
|
||||
}
|
||||
|
||||
renderWithEditorContext(<WrappedModal />, {
|
||||
scope: {
|
||||
project: { ...project, publicAccesLevel: 'private' },
|
||||
},
|
||||
@@ -839,13 +847,10 @@ describe('<ShareProjectModal/>', function () {
|
||||
publicAccessLevel: 'tokenBased',
|
||||
})
|
||||
|
||||
// NOTE: updating the scoped project data manually,
|
||||
// as the project data is usually updated via the websocket connection
|
||||
window.overleaf.unstable.store.set('project', {
|
||||
...project,
|
||||
publicAccesLevel: 'tokenBased',
|
||||
})
|
||||
// watchCallbacks.project({ ...project, publicAccesLevel: 'tokenBased' })
|
||||
// NOTE: the project data is usually updated via the websocket connection
|
||||
// but we can't do that so we're doing it via the scope value store (this
|
||||
// will be via the project context when this value has been migrated)
|
||||
setPublicAccessLevel('tokenBased')
|
||||
|
||||
await screen.findByText('Link sharing is on')
|
||||
const disableButton = await screen.findByRole('button', {
|
||||
@@ -859,13 +864,7 @@ describe('<ShareProjectModal/>', function () {
|
||||
publicAccessLevel: 'private',
|
||||
})
|
||||
|
||||
// NOTE: updating the scoped project data manually,
|
||||
// as the project data is usually updated via the websocket connection
|
||||
window.overleaf.unstable.store.set('project', {
|
||||
...project,
|
||||
publicAccesLevel: 'private',
|
||||
})
|
||||
// watchCallbacks.project({ ...project, publicAccesLevel: 'private' })
|
||||
setPublicAccessLevel('private')
|
||||
|
||||
await screen.findByText('Link sharing is off')
|
||||
})
|
||||
|
||||
@@ -17,8 +17,8 @@ export const mockScope = (
|
||||
return {
|
||||
editor: {
|
||||
sharejs_doc: mockDoc(content, docOptions),
|
||||
open_doc_name: 'test.tex',
|
||||
open_doc_id: docId,
|
||||
openDocName: 'test.tex',
|
||||
currentDocumentId: docId,
|
||||
showVisual: false,
|
||||
wantTrackChanges: false,
|
||||
},
|
||||
|
||||
@@ -9,12 +9,15 @@ import {
|
||||
IdeReactContext,
|
||||
} from '@/features/ide-react/context/ide-react-context'
|
||||
import { IdeEventEmitter } from '@/features/ide-react/create-ide-event-emitter'
|
||||
import { ReactScopeValueStore } from '@/features/ide-react/scope-value-store/react-scope-value-store'
|
||||
import { ReactScopeEventEmitter } from '@/features/ide-react/scope-event-emitter/react-scope-event-emitter'
|
||||
import { ConnectionContext } from '@/features/ide-react/context/connection-context'
|
||||
import { EditorOpenDocContext } from '@/features/ide-react/context/editor-open-doc-context'
|
||||
import { ReactContextRoot } from '@/features/ide-react/context/react-context-root'
|
||||
import useEventListener from '@/shared/hooks/use-event-listener'
|
||||
import useDetachLayout from '@/shared/hooks/use-detach-layout'
|
||||
import { LayoutContext } from '@/shared/context/layout-context'
|
||||
import useExposedState from '@/shared/hooks/use-exposed-state'
|
||||
|
||||
// these constants can be imported in tests instead of
|
||||
// using magic strings
|
||||
@@ -119,6 +122,8 @@ export function EditorProviders({
|
||||
off: () => {},
|
||||
leaveAndCleanUpPromise: async () => {},
|
||||
},
|
||||
openDocName: null,
|
||||
currentDocumentId: null,
|
||||
},
|
||||
project: {
|
||||
_id: projectId,
|
||||
@@ -144,6 +149,11 @@ export function EditorProviders({
|
||||
providers={{
|
||||
ConnectionProvider: makeConnectionProvider(socket),
|
||||
IdeReactProvider: makeIdeReactProvider(scope, socket),
|
||||
EditorOpenDocProvider: makeEditorOpenDocProvider({
|
||||
openDocId: scope.editor.currentDocumentId,
|
||||
openDocName: scope.editor.openDocName,
|
||||
currentDocument: scope.editor.sharejs_doc,
|
||||
}),
|
||||
LayoutProvider: makeLayoutProvider(layoutContext),
|
||||
...providers,
|
||||
}}
|
||||
@@ -202,15 +212,16 @@ const makeIdeReactProvider = (scope, socket) => {
|
||||
// TODO: path for nested entries
|
||||
scopeStore.set(key, value)
|
||||
}
|
||||
scopeStore.set('editor.sharejs_doc', scope.editor.sharejs_doc)
|
||||
const scopeEventEmitter = new ReactScopeEventEmitter(
|
||||
new IdeEventEmitter()
|
||||
)
|
||||
const unstableStore = new ReactScopeValueStore()
|
||||
|
||||
return {
|
||||
socket,
|
||||
scopeStore,
|
||||
scopeEventEmitter,
|
||||
unstableStore,
|
||||
}
|
||||
})
|
||||
|
||||
@@ -219,10 +230,10 @@ const makeIdeReactProvider = (scope, socket) => {
|
||||
...window.overleaf,
|
||||
unstable: {
|
||||
...window.overleaf?.unstable,
|
||||
store: ideContextValue.scopeStore,
|
||||
store: ideContextValue.unstableStore,
|
||||
},
|
||||
}
|
||||
}, [ideContextValue.scopeStore])
|
||||
}, [ideContextValue.unstableStore])
|
||||
|
||||
return (
|
||||
<IdeReactContext.Provider value={ideReactContextValue}>
|
||||
@@ -235,6 +246,44 @@ const makeIdeReactProvider = (scope, socket) => {
|
||||
return IdeReactProvider
|
||||
}
|
||||
|
||||
export function makeEditorOpenDocProvider(initialValues) {
|
||||
const {
|
||||
currentDocumentId: initialCurrentDocumentId,
|
||||
openDocName: initialOpenDocName,
|
||||
currentDocument: initialCurrentDocument,
|
||||
} = initialValues
|
||||
const EditorOpenDocProvider = ({ children }) => {
|
||||
const [currentDocumentId, setCurrentDocumentId] = useExposedState(
|
||||
initialCurrentDocumentId,
|
||||
'editor.open_doc_id'
|
||||
)
|
||||
const [openDocName, setOpenDocName] = useExposedState(
|
||||
initialOpenDocName,
|
||||
'editor.open_doc_name'
|
||||
)
|
||||
const [currentDocument, setCurrentDocument] = useState(
|
||||
initialCurrentDocument
|
||||
)
|
||||
|
||||
const value = {
|
||||
currentDocumentId,
|
||||
setCurrentDocumentId,
|
||||
openDocName,
|
||||
setOpenDocName,
|
||||
currentDocument,
|
||||
setCurrentDocument,
|
||||
}
|
||||
|
||||
return (
|
||||
<EditorOpenDocContext.Provider value={value}>
|
||||
{children}
|
||||
</EditorOpenDocContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
return EditorOpenDocProvider
|
||||
}
|
||||
|
||||
const makeLayoutProvider = layoutContextOverrides => {
|
||||
const layout = {
|
||||
...layoutContextDefault,
|
||||
|
||||
Reference in New Issue
Block a user