Skip to content
1 change: 0 additions & 1 deletion config/renderer-layout-writer-baseline.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@
2 src/renderer/src/runtime/web-session-tabs-sync/apply-preparation-groups.ts
5 src/renderer/src/runtime/web-session-tabs-sync/apply-terminal-records.ts
4 src/renderer/src/runtime/web-session-tabs-sync/apply-worktree-records.ts
1 src/renderer/src/runtime/web-session-tabs-sync/mirrored-editor-file-identity.ts
2 src/renderer/src/runtime/web-session-tabs-sync/session-tabs-inventory-absence.ts
1 src/renderer/src/runtime/web-session-terminal-orphan-recovery-surface.ts
2 src/renderer/src/runtime/web-session-terminal-orphan-topology.ts
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React from 'react'
import { conflictOverviewFileId } from '@/store/slices/editor/file-ids/editor-file-ids'
import { detectLanguage } from '@/lib/language-detect'
import { joinPath } from '@/lib/path'
import { useAppStore } from '@/store'
Expand Down Expand Up @@ -82,7 +83,7 @@ export function EditorConflictReviewSurface({
: undefined

return {
id: absolutePath,
id: conflictOverviewFileId(openFiles, activeFile.worktreeId, absolutePath),
filePath: absolutePath,
relativePath: entry.path,
worktreeId: activeFile.worktreeId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -324,15 +324,15 @@ describe('attachEditorAutosaveController', () => {
} as never
]
})
store.getState().openFile({
const fileId = store.getState().openFile({
filePath: '/runtime/folder/src/file.ts',
relativePath: 'src/file.ts',
worktreeId: workspaceKey,
language: 'typescript',
mode: 'edit'
})
store.getState().setEditorDraft('/runtime/folder/src/file.ts', 'edited')
store.getState().markFileDirty('/runtime/folder/src/file.ts', true)
store.getState().setEditorDraft(fileId, 'edited')
store.getState().markFileDirty(fileId, true)

const cleanup = attachEditorAutosaveController(withLoadedBaselines(store))
try {
Expand Down Expand Up @@ -397,16 +397,16 @@ describe('attachEditorAutosaveController', () => {
'repo-1': [{ id: 'wt-1', repoId: 'repo-1', path: '/remote/repo' }] as never
}
})
store.getState().openFile({
const fileId = store.getState().openFile({
filePath: '/remote/repo/file.ts',
relativePath: 'file.ts',
worktreeId: 'wt-1',
runtimeEnvironmentId: 'env-1',
language: 'typescript',
mode: 'edit'
})
store.getState().setEditorDraft('/remote/repo/file.ts', 'edited')
store.getState().markFileDirty('/remote/repo/file.ts', true)
store.getState().setEditorDraft(fileId, 'edited')
store.getState().markFileDirty(fileId, true)

const cleanup = attachEditorAutosaveController(withLoadedBaselines(store))
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ describe('createEditorPanelDraftSelector', () => {
let scopedInvalidations = 0
let unrelatedPanelInvalidations = 0
const selectors = files.map(createEditorPanelDraftSelector)
const previousSelections = selectors.map((selector) => selector({ editorDrafts }))
const previousSelections = selectors.map((selector) =>
selector({ editorDrafts, openFiles: [] })
)

for (let edit = 0; edit < 200; edit += 1) {
const previousDrafts = editorDrafts
Expand All @@ -32,7 +34,7 @@ describe('createEditorPanelDraftSelector', () => {
if (previousDrafts !== editorDrafts) {
wholeMapInvalidations += 1
}
const nextSelection = selectors[panelIndex]({ editorDrafts })
const nextSelection = selectors[panelIndex]({ editorDrafts, openFiles: [] })
if (previousSelections[panelIndex] !== nextSelection) {
scopedInvalidations += 1
if (panelIndex !== 0) {
Expand Down Expand Up @@ -65,15 +67,15 @@ describe('createEditorPanelDraftSelector', () => {
const selectConflictDrafts = createEditorPanelDraftSelector(conflictReview)
const selectNoDrafts = createEditorPanelDraftSelector(null)

expect(selectPreviewDrafts({ editorDrafts })).toEqual({
expect(selectPreviewDrafts({ editorDrafts, openFiles: [] })).toEqual({
preview: 'preview draft',
source: ''
})
expect(selectConflictDrafts({ editorDrafts })).toEqual({
expect(selectConflictDrafts({ editorDrafts, openFiles: [] })).toEqual({
review: 'review draft',
selected: 'selected draft'
})
expect(selectNoDrafts({ editorDrafts })).toEqual({})
expect(selectNoDrafts({ editorDrafts, openFiles: [] })).toEqual({})
})

it('includes overview conflict drafts and ignores unrelated draft replacements', () => {
Expand All @@ -96,14 +98,39 @@ describe('createEditorPanelDraftSelector', () => {
unrelated: 'other draft'
}

const selection = selectDrafts({ editorDrafts })
const selection = selectDrafts({ editorDrafts, openFiles: [] })
expect(selection).toEqual({
'C:\\repo\\src\\a.ts': 'draft a',
'C:\\repo\\src\\b.ts': ''
})

expect(
selectDrafts({ editorDrafts: { ...editorDrafts, unrelated: 'changed elsewhere' } })
selectDrafts({
editorDrafts: { ...editorDrafts, unrelated: 'changed elsewhere' },
openFiles: []
})
).toBe(selection)
})

it("shows an overview file open in a server tab under that tab's id, with its unsaved edits", () => {
const conflictReview = makeFile('review', {
filePath: '/repo',
mode: 'conflict-review',
conflictReview: {
source: 'live-summary',
snapshotTimestamp: 1,
entries: [{ path: 'src/a.ts', conflictKind: 'both_modified' }]
}
})
const serverFile = makeFile('editor:worktree-1:env-1:%2Frepo%2Fsrc%2Fa.ts', {
filePath: '/repo/src/a.ts',
relativePath: 'src/a.ts',
runtimeEnvironmentId: 'env-1'
})
const selectDrafts = createEditorPanelDraftSelector(conflictReview)

expect(
selectDrafts({ editorDrafts: { [serverFile.id]: 'unsaved' }, openFiles: [serverFile] })
).toEqual({ [serverFile.id]: 'unsaved' })
})
})
45 changes: 28 additions & 17 deletions src/renderer/src/components/editor/editor-panel-draft-selector.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import type { AppState } from '@/store'
import { joinPath } from '@/lib/path'
import type { OpenFile } from '@/store/slices/editor'
import { conflictOverviewFileId } from '@/store/slices/editor/file-ids/editor-file-ids'

type EditorDraftState = Pick<AppState, 'editorDrafts'>
type EditorDraftState = Pick<AppState, 'editorDrafts' | 'openFiles'>
type EditorPanelDraftSelector = (state: EditorDraftState) => Record<string, string>

const EMPTY_EDITOR_PANEL_DRAFTS = Object.freeze({}) as Record<string, string>
Expand All @@ -13,21 +14,30 @@ export function createEditorPanelDraftSelector(
// Why: previews and conflict review can render a related file, but drafts
// from every other panel must not wake this editor on each keystroke.
const fileIds = activeFile
? Array.from(
new Set(
[
activeFile.id,
activeFile.markdownPreviewSourceFileId,
activeFile.conflictReview?.selectedFileId,
...(activeFile.mode === 'conflict-review' && !activeFile.conflictReview?.selectedFileId
? (activeFile.conflictReview?.entries ?? []).map((entry) =>
joinPath(activeFile.filePath, entry.path)
)
: [])
].filter((fileId): fileId is string => Boolean(fileId))
)
)
? [
activeFile.id,
activeFile.markdownPreviewSourceFileId,
activeFile.conflictReview?.selectedFileId
].filter((fileId): fileId is string => Boolean(fileId))
: []
const overviewPaths =
activeFile?.mode === 'conflict-review' && !activeFile.conflictReview?.selectedFileId
? (activeFile.conflictReview?.entries ?? []).map((entry) =>
joinPath(activeFile.filePath, entry.path)
)
: []
// Why: an overview file open in a tab shows under that tab's id (a server file's is not its path).
const selectedFileIds = (state: EditorDraftState): string[] =>
overviewPaths.length === 0 || !activeFile
? fileIds
: Array.from(
new Set([
...fileIds,
...overviewPaths.map((path) =>
conflictOverviewFileId(state.openFiles, activeFile.worktreeId, path)
)
])
)
let previousDrafts: AppState['editorDrafts'] | null = null
let previousSelection = EMPTY_EDITOR_PANEL_DRAFTS

Expand All @@ -39,7 +49,8 @@ export function createEditorPanelDraftSelector(
}
previousDrafts = state.editorDrafts

const changed = fileIds.some((fileId) => {
const ids = selectedFileIds(state)
const changed = ids.some((fileId) => {
const draft = state.editorDrafts[fileId]
return (
draft !== previousSelection[fileId] ||
Expand All @@ -51,7 +62,7 @@ export function createEditorPanelDraftSelector(
}

const nextSelection: Record<string, string> = {}
for (const fileId of fileIds) {
for (const fileId of ids) {
const draft = state.editorDrafts[fileId]
if (draft !== undefined) {
nextSelection[fileId] = draft
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,23 +33,25 @@ const FILE = '/repo/a.ts'
let store: ReturnType<typeof createTestStore>
let detach: () => void

const tab = () => store.getState().openFiles.find((file) => file.id === FILE)!
// A server's file is named by its owned id, not its path.
let fileId: string
const tab = () => store.getState().openFiles.find((file) => file.id === fileId)!

beforeEach(() => {
vi.useFakeTimers()
vi.clearAllMocks()
store = createTestStore()
store.getState().openFile({
fileId = store.getState().openFile({
filePath: FILE,
relativePath: 'a.ts',
worktreeId: 'wt-1',
runtimeEnvironmentId: 'env-1',
language: 'typescript',
mode: 'edit'
})
store.getState().setEditorDraft(FILE, 'unsaved')
store.getState().markFileDirty(FILE, true)
store.getState().setLastKnownDiskSignature(FILE, getDiskBaselineSignature('v1'))
store.getState().setEditorDraft(fileId, 'unsaved')
store.getState().markFileDirty(fileId, true)
store.getState().setLastKnownDiskSignature(fileId, getDiskBaselineSignature('v1'))
})

afterEach(() => {
Expand All @@ -62,14 +64,14 @@ it('reads once more when a new check is requested while a read is in flight', as
mocks.readRuntimeFileContent.mockImplementation(
() => new Promise((resolve) => replies.push((content) => resolve({ content, isBinary: false })))
)
store.getState().setPendingDiskBaselineVerification(FILE, true)
store.getState().setPendingDiskBaselineVerification(fileId, true)
detach = attachRestoredTabConflictScan(store)
await vi.advanceTimersByTimeAsync(0)
expect(replies).toHaveLength(1)

// A second catch-up lands mid-read, after an external write.
requestRestoredTabReverification(FILE)
requestRestoredTabReverification(FILE)
requestRestoredTabReverification(fileId)
requestRestoredTabReverification(fileId)
replies[0]('v1')
await vi.advanceTimersByTimeAsync(0)
expect(tab().pendingDiskBaselineVerification).toBe(true)
Expand All @@ -85,7 +87,7 @@ it('reads once more when a new check is requested while a read is in flight', as
it('marks a dirty runtime-owned tab deleted when its host says the file is gone', async () => {
mocks.readRuntimeFileContent.mockRejectedValue(new Error('read failed'))
mocks.runtimePathsExist.mockResolvedValue([{ exists: false }])
store.getState().setPendingDiskBaselineVerification(FILE, true)
store.getState().setPendingDiskBaselineVerification(fileId, true)
detach = attachRestoredTabConflictScan(store)
await vi.advanceTimersByTimeAsync(0)

Expand All @@ -102,7 +104,7 @@ it('marks a dirty runtime-owned tab deleted when its host says the file is gone'
it('stops retrying and shows the conflict banner when the disk can never be checked', async () => {
mocks.readRuntimeFileContent.mockRejectedValue(new Error('host unreachable'))
mocks.runtimePathsExist.mockResolvedValue([{ error: 'unverifiable' }])
store.getState().setPendingDiskBaselineVerification(FILE, true)
store.getState().setPendingDiskBaselineVerification(fileId, true)
detach = attachRestoredTabConflictScan(store)
await vi.advanceTimersByTimeAsync(10 * 60_000)

Expand All @@ -117,12 +119,12 @@ it('does not let an absence answer from before a newer check resolve that check'
mocks.runtimePathsExist.mockImplementationOnce(
() => new Promise((resolve) => (answerProbe = resolve))
)
store.getState().setPendingDiskBaselineVerification(FILE, true)
store.getState().setPendingDiskBaselineVerification(fileId, true)
detach = attachRestoredTabConflictScan(store)
await vi.advanceTimersByTimeAsync(0)

// The file comes back and a new catch-up asks again while the old probe is pending.
requestRestoredTabReverification(FILE)
requestRestoredTabReverification(fileId)
mocks.readRuntimeFileContent.mockResolvedValueOnce({ content: 'v2 recreated', isBinary: false })
answerProbe([{ exists: false }])
await vi.advanceTimersByTimeAsync(0)
Expand All @@ -134,9 +136,9 @@ it('does not let an absence answer from before a newer check resolve that check'
it("forgets a tab's check requests once the tab closes", async () => {
mocks.readRuntimeFileContent.mockResolvedValue({ content: 'v1', isBinary: false })
detach = attachRestoredTabConflictScan(store)
requestRestoredTabReverification(FILE)
requestRestoredTabReverification(fileId)
expect(getRestoredTabReverificationRequestCountForTest()).toBeGreaterThan(0)

store.getState().closeFile(FILE)
store.getState().closeFile(fileId)
expect(getRestoredTabReverificationRequestCountForTest()).toBe(0)
})
Original file line number Diff line number Diff line change
Expand Up @@ -519,23 +519,21 @@ describe('editor saves through a remote host without the guarded write (client c
'repo-1': [makeWorktree({ id: 'wt-1', repoId: 'repo-1', path: '/remote/repo' })]
}
})
store.getState().openFile({
const fileId = store.getState().openFile({
filePath: '/remote/repo/file.ts',
relativePath: 'file.ts',
worktreeId: 'wt-1',
runtimeEnvironmentId: 'env-1',
language: 'typescript',
mode: 'edit'
})
store
.getState()
.setLastKnownDiskSignature('/remote/repo/file.ts', getDiskBaselineSignature('original'))
store.getState().setEditorDraft('/remote/repo/file.ts', 'edited')
store.getState().markFileDirty('/remote/repo/file.ts', true)
store.getState().setLastKnownDiskSignature(fileId, getDiskBaselineSignature('original'))
store.getState().setEditorDraft(fileId, 'edited')
store.getState().markFileDirty(fileId, true)

const cleanup = attachEditorAutosaveController(store)
try {
const save = requestEditorFileSave({ fileId: '/remote/repo/file.ts' })
const save = requestEditorFileSave({ fileId })
await (written ? save : expect(save).rejects.toThrow(/changed on disk/))
const methods = runtimeCall.mock.calls.map(([args]) => args.method)
expect(mocks.readRuntimeFileContent).toHaveBeenCalled()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useEffect, type MutableRefObject } from 'react'
import { conflictOverviewFileId } from '@/store/slices/editor/file-ids/editor-file-ids'
import type { OpenFile } from '@/store/slices/editor'
import { joinPath } from '@/lib/path'
import type { useAppStore } from '@/store'
Expand All @@ -13,6 +14,7 @@ type GitStatusByWorktree = ReturnType<typeof useAppStore.getState>['gitStatusByW
type UseEditorPanelActiveTabContentLoadParams = {
activeFile: OpenFile | null
selectedConflictReviewFile: OpenFile | null
openFiles: readonly OpenFile[]
isVisible: boolean
isChangesMode: boolean
gitStatusEntries: GitStatusByWorktree[string] | undefined
Expand Down Expand Up @@ -41,6 +43,7 @@ function hasLiveRead(
export function useEditorPanelActiveTabContentLoad({
activeFile,
selectedConflictReviewFile,
openFiles,
isVisible,
isChangesMode,
gitStatusEntries,
Expand Down Expand Up @@ -96,8 +99,9 @@ export function useEditorPanelActiveTabContentLoad({
}

const absolutePath = joinPath(activeFile.filePath, entry.path)
if (needsFileRead(absolutePath)) {
void loadFileContent(absolutePath, absolutePath, activeFile.worktreeId, entry.path)
const fileId = conflictOverviewFileId(openFiles, activeFile.worktreeId, absolutePath)
if (needsFileRead(fileId)) {
void loadFileContent(absolutePath, fileId, activeFile.worktreeId, entry.path)
}
}
return
Comment on lines 99 to 107

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🔎 Supported by static analysis

🏁 Script executed:

sed -n '1,200p' src/renderer/src/components/editor/useEditorPanelActiveTabContentLoad.ts
sed -n '125,205p' src/renderer/src/components/editor/useEditorPanelContentState.ts

Repository: stablyai/orca

Length of output: 7368


🏁 Script executed:

set -o pipefail
printf '%s\n' '--- conflictOverviewFileId definitions/usages ---'
rg -n -F --glob '*.ts' --glob '*.tsx' -e 'conflictOverviewFileId' -e 'resolveEditorFileIdForOwner' src/ || test "$?" -eq 1
printf '%s\n' '--- openFiles and conflict-review state references ---'
rg -n -F --glob '*.ts' --glob '*.tsx' -e 'setOpenFiles' -e 'openFiles:' -e 'selectedConflictReviewFile' -e "mode: 'conflict-review'" src/renderer/src/components/editor src/renderer/src/store src/renderer/src | head -n 240
printf '%s\n' '--- helper source ---'
helper=$(rg -l -F --glob '*.ts' --glob '*.tsx' 'export function conflictOverviewFileId' src/ | head -n 1)
if [ -n "$helper" ]; then
  sed -n '1,240p' "$helper"
fi
printf '%s\n' '--- owner hook context ---'
sed -n '1,180p' src/renderer/src/components/editor/useEditorPanelContentState.ts
printf '%s\n' '--- relevant tests ---'
rg -n -F --glob '*.{test,spec}.ts' --glob '*.{test,spec}.tsx' -e 'conflictOverviewFileId' -e 'conflict-review' -e 'openFiles' src/renderer/src | head -n 240

Repository: stablyai/orca

Length of output: 42134


🏁 Script executed:

set -o pipefail
printf '%s\n' '--- editor-file-ids ---'
nl -ba src/renderer/src/store/slices/editor/file-ids/editor-file-ids.ts | sed -n '100,215p'
printf '%s\n' '--- open conflict review action ---'
nl -ba src/renderer/src/store/slices/editor/actions/open-conflict-review.ts | sed -n '1,180p'
printf '%s\n' '--- open conflict file action ---'
file=$(rg -l -F --glob '*.ts' 'resolveEditorFileIdForOwner(' src/renderer/src/store/slices/editor/actions | head -n 1)
printf 'candidate=%s\n' "$file"
if [ -n "$file" ]; then nl -ba "$file" | sed -n '1,150p'; fi
printf '%s\n' '--- content state derivation ---'
nl -ba src/renderer/src/components/editor/useEditorPanelContentState.ts | sed -n '1,210p'
printf '%s\n' '--- conflict surface lookup and callbacks ---'
nl -ba src/renderer/src/components/editor/EditorConflictReviewSurface.tsx | sed -n '1,125p'
nl -ba src/renderer/src/components/editor/EditorConflictReviewSurface.tsx | sed -n '230,280p'

Repository: stablyai/orca

Length of output: 35999


🏁 Script executed:

set -o pipefail
printf '%s\n' '--- open-file-apply ---'
nl -ba src/renderer/src/store/slices/editor/actions/open-file-apply.ts | sed -n '1,180p'
printf '%s\n' '--- workspace editor item ---'
nl -ba src/renderer/src/store/slices/editor/tabs/workspace-editor-item.ts | sed -n '1,240p'
printf '%s\n' '--- callers of openWorkspaceEditorItem and openFile actions ---'
rg -n -F --glob '*.ts' --glob '*.tsx' -e 'openWorkspaceEditorItem(' -e 'openFile(' -e 'openFileApply' src/renderer/src | head -n 260
printf '%s\n' '--- file content loader ---'
nl -ba src/renderer/src/components/editor/useEditorPanelFileContentLoader.ts | sed -n '1,260p'

Repository: stablyai/orca

Length of output: 43057


🏁 Script executed:

set -o pipefail
printf '%s\n' '--- non-activating production open calls ---'
rg -n -F --glob '*.ts' --glob '*.tsx' -g '!*.test.*' -g '!*.spec.*' -e "selection: 'none'" -e "selection: 'background'" -e 'openFile({' -e 'openFile(' src/renderer/src | head -n 320
printf '%s\n' '--- openFile action declaration and wrapper ---'
rg -n -F --glob '*.ts' -e 'openFile:' -e 'createOpenFile' -e 'applyOpenFileToState' src/renderer/src/store/slices/editor
printf '%s\n' '--- editor synchronization mutations ---'
rg -n -F --glob '*.ts' --glob '*.tsx' -g '!*.test.*' -g '!*.spec.*' -e 'openFiles:' -e 'set((s)' -e 'setState({' src/renderer/src/runtime src/renderer/src/store | grep -E 'openFiles|migrat|mirror|sync|batch' | head -n 320
printf '%s\n' '--- migration implementation ---'
nl -ba src/renderer/src/components/editor/migrate-restored-editor-file-owner.ts | sed -n '1,240p'

Repository: stablyai/orca

Length of output: 18046


🏁 Script executed:

set -o pipefail
printf '%s\n' '--- open-file action ---'
nl -ba src/renderer/src/store/slices/editor/actions/open-file-action.ts | sed -n '1,125p'
printf '%s\n' '--- OpenFileOptions and selection call sites ---'
nl -ba src/renderer/src/store/slices/editor/types/editor-files-slice.ts | sed -n '1,90p'
rg -n -C 4 --glob '*.ts' --glob '*.tsx' -g '!*.test.*' -g '!*.spec.*' -e 'selection:' -e 'openFile\(' src/renderer/src/components src/renderer/src/hooks src/renderer/src/runtime src/renderer/src/lib | head -n 360
printf '%s\n' '--- sync final patch ---'
nl -ba src/renderer/src/runtime/web-session-tabs-sync/apply-final-patch.ts | sed -n '1,180p'
printf '%s\n' '--- reparent implementation ---'
rg -n -F --glob '*.ts' -e 'reparentRestoredEditorFileOwner' src/renderer/src

Repository: stablyai/orca

Length of output: 41948


🏁 Script executed:

set -o pipefail
printf '%s\n' '--- restored owner reparent ---'
nl -ba src/renderer/src/store/slices/editor/actions/restored-editor-owner.ts | sed -n '1,240p'
printf '%s\n' '--- nextOpenFiles producers ---'
rg -n -C 5 --glob '*.ts' -g '!*.test.*' -e 'nextOpenFiles' src/renderer/src/runtime src/renderer/src/store | head -n 360
printf '%s\n' '--- sync tab builders ---'
nl -ba src/renderer/src/runtime/web-session-tabs-sync/tab-builders.ts | sed -n '1,180p'

Repository: stablyai/orca

Length of output: 30132


🏁 Script executed:

set -o pipefail
printf '%s\n' '--- mirrored editor identity ---'
nl -ba src/renderer/src/runtime/web-session-tabs-sync/mirrored-editor-file-identity.ts | sed -n '1,260p'
printf '%s\n' '--- active-state reconciliation ---'
rg -n -C 6 --glob '*.ts' -g '!*.test.*' -e 'function applyActiveStateUpdates' -e 'nextActiveFileId' -e 'activeFileIdByWorktree' src/renderer/src/runtime/web-session-tabs-sync | head -n 320

Repository: stablyai/orca

Length of output: 19590


Rerun the conflict overview load when openFiles changes.

The overview effect uses openFiles to select the content ID, but openFiles is not a dependency. If synchronization adds the matching server-owned edit tab while the review tab remains active, the overview switches from the path ID to the owned ID without loading content for that ID. The overview can remain stuck in its loading state.

Suggested fix
     isVisible,
-    gitStatusEntries
+    gitStatusEntries,
+    openFiles
   ])

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ export function useEditorPanelContentState({
useEditorPanelActiveTabContentLoad({
activeFile,
selectedConflictReviewFile,
openFiles,
isVisible,
isChangesMode,
gitStatusEntries,
Expand Down
Loading
Loading