diff --git a/src/renderer/src/components/right-sidebar/FileExplorer.tsx b/src/renderer/src/components/right-sidebar/FileExplorer.tsx index 303ffef21..6809f3cc6 100644 --- a/src/renderer/src/components/right-sidebar/FileExplorer.tsx +++ b/src/renderer/src/components/right-sidebar/FileExplorer.tsx @@ -8,6 +8,7 @@ import { folderRelativePathToIncludeGlob } from './file-search-include-pattern' import { ScrollArea } from '@/components/ui/scroll-area' import { cn } from '@/lib/utils' import { isGitRepoKind } from '../../../../shared/repo-kind' +import { shouldResetFileExplorerForVisibleWorktree } from './file-explorer-reset' import { FileExplorerBackgroundMenu } from './FileExplorerBackgroundMenu' import { FileExplorerToolbar } from './FileExplorerToolbar' import { FileExplorerTreeStatus } from './FileExplorerTreeStatus' @@ -157,12 +158,22 @@ function FileExplorerInner(): React.JSX.Element { scrollRef }) + const lastResetWorktreePathRef = useRef(null) useEffect(() => { if (!visibleWorktreePath) { return } // Why: the sidebar remains mounted while closed to preserve caches, but // loading the hidden tree would probe every clicked workspace on macOS. + if ( + !shouldResetFileExplorerForVisibleWorktree( + lastResetWorktreePathRef.current, + visibleWorktreePath + ) + ) { + return + } + lastResetWorktreePathRef.current = visibleWorktreePath resetSelection() resetAndLoad() clearFileExplorerUndoHistory() diff --git a/src/renderer/src/components/right-sidebar/file-explorer-reset.test.ts b/src/renderer/src/components/right-sidebar/file-explorer-reset.test.ts new file mode 100644 index 000000000..66a341c4c --- /dev/null +++ b/src/renderer/src/components/right-sidebar/file-explorer-reset.test.ts @@ -0,0 +1,24 @@ +import { describe, expect, it } from 'vitest' +import { shouldResetFileExplorerForVisibleWorktree } from './file-explorer-reset' + +describe('shouldResetFileExplorerForVisibleWorktree', () => { + it('preserves explorer state across hide and reopen of the same worktree', () => { + let lastResetWorktreePath: string | null = null + const shouldReset = (visibleWorktreePath: string | null): boolean => { + if (shouldResetFileExplorerForVisibleWorktree(lastResetWorktreePath, visibleWorktreePath)) { + lastResetWorktreePath = visibleWorktreePath + return true + } + return false + } + + expect(shouldReset(null)).toBe(false) + expect(shouldReset('/repo')).toBe(true) + expect(shouldReset(null)).toBe(false) + expect(shouldReset('/repo')).toBe(false) + }) + + it('resets when the visible worktree path changes', () => { + expect(shouldResetFileExplorerForVisibleWorktree('/repo', '/repo-next')).toBe(true) + }) +}) diff --git a/src/renderer/src/components/right-sidebar/file-explorer-reset.ts b/src/renderer/src/components/right-sidebar/file-explorer-reset.ts new file mode 100644 index 000000000..2473fe9a8 --- /dev/null +++ b/src/renderer/src/components/right-sidebar/file-explorer-reset.ts @@ -0,0 +1,6 @@ +export function shouldResetFileExplorerForVisibleWorktree( + lastResetWorktreePath: string | null, + visibleWorktreePath: string | null +): visibleWorktreePath is string { + return visibleWorktreePath !== null && lastResetWorktreePath !== visibleWorktreePath +}