diff --git a/services/web/frontend/js/features/editor-left-menu/hooks/use-set-overall-theme.tsx b/services/web/frontend/js/features/editor-left-menu/hooks/use-set-overall-theme.tsx index 6b696f4474..83920e74ba 100644 --- a/services/web/frontend/js/features/editor-left-menu/hooks/use-set-overall-theme.tsx +++ b/services/web/frontend/js/features/editor-left-menu/hooks/use-set-overall-theme.tsx @@ -1,6 +1,5 @@ import { useCallback, useEffect, useState } from 'react' import _ from 'lodash' -import useScopeValue from '../../../shared/hooks/use-scope-value' import type { OverallThemeMeta } from '../../../../../types/project-settings' import { saveUserSettings } from '../utils/api' import { UserSettings } from '../../../../../types/user-settings' @@ -8,12 +7,12 @@ import { useUserSettingsContext } from '@/shared/context/user-settings-context' import getMeta from '@/utils/meta' import { isBootstrap5 } from '@/features/utils/bootstrap-5' import { isIEEEBranded } from '@/utils/is-ieee-branded' +import { useLayoutContext } from '@/shared/context/layout-context' export default function useSetOverallTheme() { const [chosenTheme, setChosenTheme] = useState(null) - const [loadingStyleSheet, setLoadingStyleSheet] = useScopeValue( - 'ui.loadingStyleSheet' - ) + + const { loadingStyleSheet, setLoadingStyleSheet } = useLayoutContext() const { userSettings, setUserSettings } = useUserSettingsContext() const { overallTheme } = userSettings diff --git a/services/web/frontend/js/features/history/extensions/highlights.ts b/services/web/frontend/js/features/history/extensions/highlights.ts index 9fbc82888f..ce274cf724 100644 --- a/services/web/frontend/js/features/history/extensions/highlights.ts +++ b/services/web/frontend/js/features/history/extensions/highlights.ts @@ -126,7 +126,7 @@ function createHighlightTooltip(pos: number, highlight: Highlight) { create: () => { const dom = document.createElement('div') dom.classList.add('ol-cm-highlight-tooltip') - dom.style.setProperty('--hue', highlight.hue.toString()) + dom.style.setProperty('--hue', String(highlight.hue)) dom.textContent = highlight.label return { dom } diff --git a/services/web/frontend/js/features/ide-react/components/editor/editor-pane.tsx b/services/web/frontend/js/features/ide-react/components/editor/editor-pane.tsx index cae4d1368a..77ffcd6cd4 100644 --- a/services/web/frontend/js/features/ide-react/components/editor/editor-pane.tsx +++ b/services/web/frontend/js/features/ide-react/components/editor/editor-pane.tsx @@ -2,10 +2,8 @@ import { Panel, PanelGroup } from 'react-resizable-panels' 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 { - EditorScopeValue, - useEditorManagerContext, -} from '@/features/ide-react/context/editor-manager-context' +import { useEditorManagerContext } from '@/features/ide-react/context/editor-manager-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' import { FullSizeLoadingSpinner } from '@/shared/components/loading-spinner' diff --git a/services/web/frontend/js/features/ide-react/context/editor-manager-context.tsx b/services/web/frontend/js/features/ide-react/context/editor-manager-context.tsx index d996f91ce3..75cc329a48 100644 --- a/services/web/frontend/js/features/ide-react/context/editor-manager-context.tsx +++ b/services/web/frontend/js/features/ide-react/context/editor-manager-context.tsx @@ -85,20 +85,6 @@ function hasGotoOffset(options: OpenDocOptions): options is GotoOffsetOptions { return typeof options.gotoOffset === 'number' } -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 - showVisual: boolean - newSourceEditor: boolean - error_state: boolean -} - export const EditorManagerContext = createContext( undefined ) diff --git a/services/web/frontend/js/features/ide-react/context/ide-react-context.tsx b/services/web/frontend/js/features/ide-react/context/ide-react-context.tsx index 6bd12b5146..4fe590d9df 100644 --- a/services/web/frontend/js/features/ide-react/context/ide-react-context.tsx +++ b/services/web/frontend/js/features/ide-react/context/ide-react-context.tsx @@ -20,7 +20,6 @@ import { useConnectionContext } from '@/features/ide-react/context/connection-co import { getMockIde } from '@/shared/context/mock/mock-ide' import { populateEditorScope } from '@/features/ide-react/scope-adapters/editor-manager-context-adapter' import { postJSON } from '@/infrastructure/fetch-json' -import { populateOnlineUsersScope } from '@/features/ide-react/context/online-users-context' import { ReactScopeEventEmitter } from '@/features/ide-react/scope-event-emitter/react-scope-event-emitter' import getMeta from '@/utils/meta' @@ -74,7 +73,6 @@ export function createReactScopeValueStore(projectId: string) { populateLayoutScope(scopeStore) populateProjectScope(scopeStore) populatePdfScope(scopeStore) - populateOnlineUsersScope(scopeStore) populateReviewPanelScope(scopeStore) scopeStore.allowNonExistentPath('hasLintingError') diff --git a/services/web/frontend/js/features/ide-react/context/online-users-context.tsx b/services/web/frontend/js/features/ide-react/context/online-users-context.tsx index 15a1a15a60..baae763633 100644 --- a/services/web/frontend/js/features/ide-react/context/online-users-context.tsx +++ b/services/web/frontend/js/features/ide-react/context/online-users-context.tsx @@ -7,10 +7,8 @@ import { useMemo, useState, } from 'react' -import { ReactScopeValueStore } from '@/features/ide-react/scope-value-store/react-scope-value-store' import { useIdeReactContext } from '@/features/ide-react/context/ide-react-context' import { useConnectionContext } from '@/features/ide-react/context/connection-context' -import useScopeValue from '@/shared/hooks/use-scope-value' import { CursorPosition } from '@/features/ide-react/types/cursor-position' import { omit } from 'lodash' import { Doc } from '../../../../../types/doc' @@ -63,16 +61,9 @@ type OnlineUsersContextValue = { onlineUsersCount: number } -export function populateOnlineUsersScope(store: ReactScopeValueStore) { - store.set('onlineUsers', {}) - store.set('onlineUserCursorHighlights', {}) - store.set('onlineUsersArray', []) - store.set('onlineUsersCount', 0) -} - -const OnlineUsersContext = createContext( - undefined -) +export const OnlineUsersContext = createContext< + OnlineUsersContextValue | undefined +>(undefined) export const OnlineUsersProvider: FC = ({ children }) => { const { eventEmitter } = useIdeReactContext() @@ -80,20 +71,12 @@ export const OnlineUsersProvider: FC = ({ children }) => { const { currentDocumentId } = useEditorManagerContext() const { fileTreeData } = useFileTreeData() - const [onlineUsers, setOnlineUsers] = - useScopeValue('onlineUsers') - const [onlineUserCursorHighlights, setOnlineUserCursorHighlights] = - useScopeValue( - 'onlineUserCursorHighlights' - ) - const [onlineUsersArray, setOnlineUsersArray] = - useScopeValue( - 'onlineUsersArray' - ) - const [onlineUsersCount, setOnlineUsersCount] = - useScopeValue( - 'onlineUsersCount' - ) + const [onlineUsers, setOnlineUsers] = useState>({}) + const [onlineUserCursorHighlights, setOnlineUserCursorHighlights] = useState< + Record + >({}) + const [onlineUsersArray, setOnlineUsersArray] = useState([]) + const [onlineUsersCount, setOnlineUsersCount] = useState(0) const [currentPosition, setCurrentPosition] = useState( null diff --git a/services/web/frontend/js/features/ide-react/context/react-context-root.tsx b/services/web/frontend/js/features/ide-react/context/react-context-root.tsx index 9f199373cb..9ec848dbf6 100644 --- a/services/web/frontend/js/features/ide-react/context/react-context-root.tsx +++ b/services/web/frontend/js/features/ide-react/context/react-context-root.tsx @@ -73,8 +73,8 @@ export const ReactContextRoot: FC<{ providers?: Record }> = ({ - - + + @@ -94,8 +94,8 @@ export const ReactContextRoot: FC<{ providers?: Record }> = ({ - - + + diff --git a/services/web/frontend/js/features/ide-react/scope-adapters/editor-manager-context-adapter.ts b/services/web/frontend/js/features/ide-react/scope-adapters/editor-manager-context-adapter.ts index 5083066986..537c501c72 100644 --- a/services/web/frontend/js/features/ide-react/scope-adapters/editor-manager-context-adapter.ts +++ b/services/web/frontend/js/features/ide-react/scope-adapters/editor-manager-context-adapter.ts @@ -1,6 +1,20 @@ import { ReactScopeValueStore } from '@/features/ide-react/scope-value-store/react-scope-value-store' import customLocalStorage from '@/infrastructure/local-storage' import getMeta from '@/utils/meta' +import { DocumentContainer } from '@/features/ide-react/editor/document-container' + +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 + showVisual: boolean + error_state: boolean +} export function populateEditorScope( store: ReactScopeValueStore, @@ -8,7 +22,7 @@ export function populateEditorScope( ) { store.set('project.name', null) - store.set('editor', { + const editor: Omit = { showSymbolPalette: false, toggleSymbolPalette: () => {}, sharejs_doc: null, @@ -17,10 +31,10 @@ export function populateEditorScope( opening: true, trackChanges: false, wantTrackChanges: false, - // No Ace here - newSourceEditor: true, error_state: false, - }) + } + store.set('editor', editor) + store.persisted( 'editor.showVisual', getMeta('ol-usedLatex') === 'never' || showVisualFallbackValue(projectId), diff --git a/services/web/frontend/js/features/ide-react/scope-adapters/layout-context-adapter.ts b/services/web/frontend/js/features/ide-react/scope-adapters/layout-context-adapter.ts index fa722db38f..88f252f70b 100644 --- a/services/web/frontend/js/features/ide-react/scope-adapters/layout-context-adapter.ts +++ b/services/web/frontend/js/features/ide-react/scope-adapters/layout-context-adapter.ts @@ -11,5 +11,4 @@ export default function populateLayoutScope(store: ReactScopeValueStore) { store.set('ui.leftMenuShown', false) store.set('ui.miniReviewPanelVisible', false) store.set('ui.pdfLayout', 'sideBySide') - store.set('ui.loadingStyleSheet', false) } diff --git a/services/web/frontend/js/features/ide-react/scope-adapters/review-panel-context-adapter.ts b/services/web/frontend/js/features/ide-react/scope-adapters/review-panel-context-adapter.ts index 7a5e2aeafe..2bf212f2c6 100644 --- a/services/web/frontend/js/features/ide-react/scope-adapters/review-panel-context-adapter.ts +++ b/services/web/frontend/js/features/ide-react/scope-adapters/review-panel-context-adapter.ts @@ -4,6 +4,5 @@ import { isSplitTestEnabled } from '@/utils/splitTestUtils' export default function populateReviewPanelScope(store: ReactScopeValueStore) { store.set('loadingThreads', true) store.set('users', {}) - store.set('addNewComment', () => {}) store.set('usingNewReviewPanel', isSplitTestEnabled('review-panel-redesign')) } diff --git a/services/web/frontend/js/features/ide-redesign/components/editor.tsx b/services/web/frontend/js/features/ide-redesign/components/editor.tsx index d8f5fa4df4..505e14e072 100644 --- a/services/web/frontend/js/features/ide-redesign/components/editor.tsx +++ b/services/web/frontend/js/features/ide-redesign/components/editor.tsx @@ -1,8 +1,6 @@ import { LoadingPane } from '@/features/ide-react/components/editor/loading-pane' -import { - EditorScopeValue, - useEditorManagerContext, -} from '@/features/ide-react/context/editor-manager-context' +import { useEditorManagerContext } from '@/features/ide-react/context/editor-manager-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' import classNames from 'classnames' diff --git a/services/web/frontend/js/features/source-editor/extensions/cursor-highlights.ts b/services/web/frontend/js/features/source-editor/extensions/cursor-highlights.ts index 724a23fe6a..78d2903825 100644 --- a/services/web/frontend/js/features/source-editor/extensions/cursor-highlights.ts +++ b/services/web/frontend/js/features/source-editor/extensions/cursor-highlights.ts @@ -144,7 +144,7 @@ const cursorTooltip = (view: EditorView, pos: number): Tooltip | null => { for (const highlight of highlights) { const label = document.createElement('div') label.classList.add('ol-cm-cursorHighlightLabel') - label.style.setProperty('--hue', highlight.hue) + label.style.setProperty('--hue', String(highlight.hue)) label.textContent = highlight.label dom.appendChild(label) } @@ -178,7 +178,7 @@ class CursorMarker extends RectangleMarker { draw(): HTMLDivElement { const element = super.draw() - element.style.setProperty('--hue', this.highlight.hue) + element.style.setProperty('--hue', String(this.highlight.hue)) return element } } diff --git a/services/web/frontend/js/features/source-editor/hooks/use-codemirror-scope.ts b/services/web/frontend/js/features/source-editor/hooks/use-codemirror-scope.ts index 9e593196a5..bc2bd7d56b 100644 --- a/services/web/frontend/js/features/source-editor/hooks/use-codemirror-scope.ts +++ b/services/web/frontend/js/features/source-editor/hooks/use-codemirror-scope.ts @@ -60,6 +60,7 @@ import { isBootstrap5 } from '@/features/utils/bootstrap-5' import { Permissions } from '@/features/ide-react/types/permissions' import { lineHeights } from '@/shared/utils/styles' import { useEditorManagerContext } from '@/features/ide-react/context/editor-manager-context' +import { useOnlineUsersContext } from '@/features/ide-react/context/online-users-context' function useCodeMirrorScope(view: EditorView) { const { fileTreeData } = useFileTreeData() @@ -94,9 +95,7 @@ function useCodeMirrorScope(view: EditorView) { referencesSearchMode, } = userSettings - const [cursorHighlights] = useScopeValue>( - 'onlineUserCursorHighlights' - ) + const { onlineUserCursorHighlights } = useOnlineUsersContext() let [spellCheckLanguage] = useScopeValue('project.spellCheckLanguage') // spell check is off when read-only @@ -558,14 +557,14 @@ function useCodeMirrorScope(view: EditorView) { }) useEffect(() => { - if (cursorHighlights && currentDocument) { - const items = cursorHighlights[currentDocument.doc_id] + if (onlineUserCursorHighlights && currentDocument) { + const items = onlineUserCursorHighlights[currentDocument.doc_id] highlightsRef.current.cursorHighlights = items window.setTimeout(() => { view.dispatch(setCursorHighlights(items)) }) } - }, [view, cursorHighlights, currentDocument]) + }, [view, onlineUserCursorHighlights, currentDocument]) useEventListener( 'editor:focus', diff --git a/services/web/frontend/js/shared/context/layout-context.tsx b/services/web/frontend/js/shared/context/layout-context.tsx index 1c2ad44002..145d840540 100644 --- a/services/web/frontend/js/shared/context/layout-context.tsx +++ b/services/web/frontend/js/shared/context/layout-context.tsx @@ -157,9 +157,7 @@ export const LayoutProvider: FC = ({ children }) => { const [pdfLayout, setPdfLayout] = useScopeValue('ui.pdfLayout') // whether stylesheet on theme is loading - const [loadingStyleSheet, setLoadingStyleSheet] = useScopeValue( - 'ui.loadingStyleSheet' - ) + const [loadingStyleSheet, setLoadingStyleSheet] = useState(false) const changeLayout = useCallback( (newLayout: IdeLayout, newView: IdeView = 'editor') => { diff --git a/services/web/test/frontend/features/source-editor/components/codemirror-editor.spec.tsx b/services/web/test/frontend/features/source-editor/components/codemirror-editor.spec.tsx index a753734c8c..027ff67109 100644 --- a/services/web/test/frontend/features/source-editor/components/codemirror-editor.spec.tsx +++ b/services/web/test/frontend/features/source-editor/components/codemirror-editor.spec.tsx @@ -7,6 +7,8 @@ import { docId } from '../helpers/mock-doc' import { activeEditorLine } from '../helpers/active-editor-line' import { TestContainer } from '../helpers/test-container' import customLocalStorage from '@/infrastructure/local-storage' +import { OnlineUsersContext } from '@/features/ide-react/context/online-users-context' +import { FC } from 'react' describe('', { scrollBehavior: false }, function () { beforeEach(function () { @@ -190,29 +192,42 @@ describe('', { scrollBehavior: false }, function () { it('renders cursor highlights', function () { const scope = mockScope() - scope.onlineUserCursorHighlights = { - [docId]: [ - { - label: 'Test User', - cursor: { row: 10, column: 5 }, - hue: 150, - }, - { - label: 'Another User', - cursor: { row: 7, column: 2 }, - hue: 50, - }, - { - label: 'Starter User', - cursor: { row: 0, column: 0 }, - hue: 0, - }, - ], + const value = { + onlineUsers: {}, + onlineUserCursorHighlights: { + [docId]: [ + { + label: 'Test User', + cursor: { row: 10, column: 5 }, + hue: 150, + }, + { + label: 'Another User', + cursor: { row: 7, column: 2 }, + hue: 50, + }, + { + label: 'Starter User', + cursor: { row: 0, column: 0 }, + hue: 0, + }, + ], + }, + onlineUsersArray: [], + onlineUsersCount: 3, + } + + const OnlineUsersProvider: FC = ({ children }) => { + return ( + + {children} + + ) } cy.mount( - + diff --git a/services/web/types/highlight.ts b/services/web/types/highlight.ts index 4017158ca7..5dc47ba6bd 100644 --- a/services/web/types/highlight.ts +++ b/services/web/types/highlight.ts @@ -1,5 +1,5 @@ export type Highlight = { cursor: { row: number; column: number } - hue: string + hue: number label: string } diff --git a/services/web/types/window.ts b/services/web/types/window.ts index 64f2d9ed47..1150bf1e50 100644 --- a/services/web/types/window.ts +++ b/services/web/types/window.ts @@ -16,9 +16,6 @@ declare global { socket: Socket } MathJax: Record - crypto: { - randomUUID: () => string - } // For react-google-recaptcha recaptchaOptions?: { enterprise?: boolean