From cfafed09bc76c5bcb6427998091b2c120a2a2185 Mon Sep 17 00:00:00 2001 From: CREDO23 Date: Fri, 19 Jun 2026 19:12:14 +0200 Subject: [PATCH] fix: forward citation line anchor to editor panel and harden reveal --- .../components/editor/source-code-editor.tsx | 33 ++++++++++++------- .../layout/ui/right-panel/RightPanel.tsx | 2 ++ 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/surfsense_web/components/editor/source-code-editor.tsx b/surfsense_web/components/editor/source-code-editor.tsx index 0277cde85..4af4f2125 100644 --- a/surfsense_web/components/editor/source-code-editor.tsx +++ b/surfsense_web/components/editor/source-code-editor.tsx @@ -49,15 +49,20 @@ export function SourceCodeEditor({ } const range = highlightLinesRef.current; if (!range) return; - const start = Math.max(1, Math.floor(range.start)); - const end = Math.max(start, Math.floor(range.end)); - decorationsRef.current = editor.createDecorationsCollection([ - { - range: new monaco.Range(start, 1, end, 1), - options: { isWholeLine: true, className: "citation-line-highlight" }, - }, - ]); - editor.revealLinesInCenter(start, end); + const lineCount = editor.getModel()?.getLineCount() ?? range.end; + const start = Math.min(Math.max(1, Math.floor(range.start)), lineCount); + const end = Math.min(Math.max(start, Math.floor(range.end)), lineCount); + try { + decorationsRef.current = editor.createDecorationsCollection([ + { + range: new monaco.Range(start, 1, end, 1), + options: { isWholeLine: true, className: "citation-line-highlight" }, + }, + ]); + } catch { + // Decoration failure must not block the reveal below. + } + editor.revealLinesInCenter(start, end, monaco.editor.ScrollType.Immediate); }, []); useEffect(() => { @@ -138,8 +143,14 @@ export function SourceCodeEditor({ monacoRef.current = monaco; editorRef.current = editor; applySidebarTheme(monaco); - // Defer one frame so the model is laid out before revealing. - requestAnimationFrame(() => applyHighlight()); + // Reveal now, then once more after the first layout settles: + // the panel slide-in animation means the editor often has no + // usable viewport height on the initial frame. + applyHighlight(); + const layoutSub = editor.onDidLayoutChange(() => { + applyHighlight(); + layoutSub.dispose(); + }); if (!isManualSaveEnabled) return; editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS, () => { void onSaveRef.current?.(); diff --git a/surfsense_web/components/layout/ui/right-panel/RightPanel.tsx b/surfsense_web/components/layout/ui/right-panel/RightPanel.tsx index 5a7588979..bfad44dd8 100644 --- a/surfsense_web/components/layout/ui/right-panel/RightPanel.tsx +++ b/surfsense_web/components/layout/ui/right-panel/RightPanel.tsx @@ -308,6 +308,8 @@ export function RightPanel({ searchSpaceId={editorState.searchSpaceId ?? undefined} title={editorState.title} onClose={closeEditor} + highlightLines={editorState.highlightLines} + forceSourceView={editorState.forceSourceView} /> )}