fix: clean up stale file tree paths on startup
Removes missing expanded folders from persisted Files state Prevents repeated 404 noise for stale file tree paths Avoids startup SDK race when restoring sessions
This commit is contained in:
@@ -28,4 +28,23 @@ describe('useFilesViewTabsStore', () => {
|
||||
|
||||
expect(useFilesViewTabsStore.getState().byRoot[root]?.expandedPaths).toEqual(['/repo/src']);
|
||||
});
|
||||
|
||||
test('removes stale expanded paths by prefix without closing files', () => {
|
||||
const root = '/repo';
|
||||
const store = useFilesViewTabsStore.getState();
|
||||
|
||||
store.addOpenPath(root, '/repo/src/index.ts');
|
||||
store.expandPaths(root, [
|
||||
'/repo/src',
|
||||
'/repo/bun test packages',
|
||||
'/repo/bun test packages/web',
|
||||
'/repo/other',
|
||||
]);
|
||||
|
||||
store.removeExpandedPathsByPrefix(root, '/repo/bun test packages');
|
||||
|
||||
const state = useFilesViewTabsStore.getState().byRoot[root];
|
||||
expect(state?.openPaths).toEqual(['/repo/src/index.ts']);
|
||||
expect(state?.expandedPaths).toEqual(['/repo/src', '/repo/other']);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -18,6 +18,7 @@ type FilesViewTabsActions = {
|
||||
addOpenPath: (root: string, path: string, options?: { allowOutsideRoot?: boolean }) => void;
|
||||
removeOpenPath: (root: string, path: string) => void;
|
||||
removeOpenPathsByPrefix: (root: string, prefixPath: string) => void;
|
||||
removeExpandedPathsByPrefix: (root: string, prefixPath: string) => void;
|
||||
setSelectedPath: (root: string, path: string | null, options?: { allowOutsideRoot?: boolean }) => void;
|
||||
ensureSelectedPath: (root: string) => void;
|
||||
toggleExpandedPath: (root: string, path: string) => void;
|
||||
@@ -270,6 +271,43 @@ export const useFilesViewTabsStore = create<FilesViewTabsStore>()(
|
||||
});
|
||||
},
|
||||
|
||||
removeExpandedPathsByPrefix: (root, prefixPath) => {
|
||||
const normalizedRoot = normalizePath((root || '').trim());
|
||||
const normalizedPrefix = normalizePath((prefixPath || '').trim());
|
||||
if (!normalizedRoot || !normalizedPrefix) {
|
||||
return;
|
||||
}
|
||||
|
||||
set((state) => {
|
||||
const current = state.byRoot[normalizedRoot];
|
||||
if (!current) {
|
||||
return state;
|
||||
}
|
||||
|
||||
const comparablePrefix = toComparablePath(normalizedPrefix);
|
||||
const comparablePrefixWithSlash = comparablePrefix.endsWith('/') ? comparablePrefix : `${comparablePrefix}/`;
|
||||
const expandedPaths = current.expandedPaths.filter((candidate) => {
|
||||
const comparablePath = toComparablePath(candidate);
|
||||
return comparablePath !== comparablePrefix && !comparablePath.startsWith(comparablePrefixWithSlash);
|
||||
});
|
||||
|
||||
if (expandedPaths.length === current.expandedPaths.length) {
|
||||
return state;
|
||||
}
|
||||
|
||||
const byRoot = {
|
||||
...state.byRoot,
|
||||
[normalizedRoot]: {
|
||||
...current,
|
||||
expandedPaths,
|
||||
touchedAt: Date.now(),
|
||||
},
|
||||
};
|
||||
|
||||
return { byRoot: clampRoots(byRoot, 20) };
|
||||
});
|
||||
},
|
||||
|
||||
setSelectedPath: (root, path, options) => {
|
||||
const normalizedRoot = normalizePath((root || '').trim());
|
||||
const normalizedPath = path ? normalizePath(path.trim()) : null;
|
||||
|
||||
Reference in New Issue
Block a user