mirror of
https://github.com/stablyai/orca.git
synced 2026-11-03 18:47:40 +00:00
fix(editor): scope default-pane reading positions by file owner (#34816)
Same-path files with different owners (runtime hosts or worktrees) shared Monaco, rich-markdown, notebook, and PDF/media reading positions when the tab id equals the file id. Key them by file id, matching the diff and markdown preview keys. Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
This commit is contained in:
@@ -2,10 +2,12 @@
|
||||
import { cleanup, render } from '@testing-library/react'
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
import type { OpenFile } from '@/store/slices/editor'
|
||||
import { buildOwnedEditorFileId } from '@/store/slices/editor/file-ids/editor-file-ids'
|
||||
|
||||
const lifecycle = vi.hoisted(() => ({
|
||||
events: [] as string[],
|
||||
diffModelKeys: [] as string[],
|
||||
viewStateKeys: new Array<string>(),
|
||||
models: new Map<string, { content: string; undo: string[] }>(),
|
||||
notebookProps: [] as {
|
||||
fileId: string
|
||||
@@ -70,7 +72,9 @@ vi.mock('@/lib/lazy-with-retry', async () => {
|
||||
readOnly?: boolean
|
||||
liveTail?: boolean
|
||||
viewStateId?: string
|
||||
viewStateKey: string
|
||||
}) {
|
||||
lifecycle.viewStateKeys.push(props.viewStateKey)
|
||||
/* oxlint-disable react-hooks/exhaustive-deps -- Mount-only by design: a prop-effect would hide a missing outer React remount. */
|
||||
React.useEffect(() => {
|
||||
lifecycle.events.push(`mount:${props.filePath}`)
|
||||
@@ -215,6 +219,7 @@ afterEach(() => {
|
||||
cleanup()
|
||||
lifecycle.events.length = 0
|
||||
lifecycle.diffModelKeys.length = 0
|
||||
lifecycle.viewStateKeys.length = 0
|
||||
lifecycle.models.clear()
|
||||
lifecycle.mountedProps.length = 0
|
||||
lifecycle.notebookProps.length = 0
|
||||
@@ -222,6 +227,28 @@ afterEach(() => {
|
||||
})
|
||||
|
||||
describe('EditorContent Monaco lifecycle boundary', () => {
|
||||
it('keeps default-pane view state separate for the same path on different runtime hosts', () => {
|
||||
const filePath = '/repo/main.ts'
|
||||
const worktreeId = 'repo::/repo'
|
||||
const first = file(filePath, {
|
||||
id: buildOwnedEditorFileId(filePath, worktreeId, 'host-a'),
|
||||
runtimeEnvironmentId: 'host-a'
|
||||
})
|
||||
const second = file(filePath, {
|
||||
id: buildOwnedEditorFileId(filePath, worktreeId, 'host-b'),
|
||||
runtimeEnvironmentId: 'host-b'
|
||||
})
|
||||
const view = render(
|
||||
<EditorContent {...props(first, 'first host')} viewStateScopeId={first.id} />
|
||||
)
|
||||
const firstKey = lifecycle.viewStateKeys.at(-1)
|
||||
expect(firstKey).toBeTypeOf('string')
|
||||
|
||||
view.rerender(<EditorContent {...props(second, 'second host')} viewStateScopeId={second.id} />)
|
||||
|
||||
expect(lifecycle.viewStateKeys.at(-1)).not.toBe(firstKey)
|
||||
})
|
||||
|
||||
it('unmounts the prior path before reconciling a stale retained target model', () => {
|
||||
const first = file('/repo/first.ts')
|
||||
const second = file('/repo/second.ts')
|
||||
|
||||
@@ -98,7 +98,7 @@ export function EditorContent({
|
||||
}): React.JSX.Element {
|
||||
const editorViewStateKey =
|
||||
viewStateScopeId === activeFile.id
|
||||
? activeFile.filePath
|
||||
? activeFile.id
|
||||
: `${activeFile.filePath}::${viewStateScopeId}`
|
||||
const diffViewStateKey =
|
||||
viewStateScopeId === activeFile.id ? activeFile.id : `${activeFile.id}::${viewStateScopeId}`
|
||||
@@ -109,7 +109,7 @@ export function EditorContent({
|
||||
// Why: only the single-pane edit path gets PDF scroll memory — diff and conflict review mount several viewers on one path.
|
||||
const pdfViewStateKey =
|
||||
viewStateScopeId === activeFile.id
|
||||
? `${activeFile.filePath}:pdf`
|
||||
? `${activeFile.id}:pdf`
|
||||
: `${activeFile.filePath}::${viewStateScopeId}:pdf`
|
||||
// Scope durable PDF zoom by owner: identical paths can belong to different worktrees or remote hosts.
|
||||
const pdfPreferenceKey = buildPdfScalePreferenceKey(activeFile)
|
||||
|
||||
Reference in New Issue
Block a user