fix(ui): avoid file search cache key collisions (#1343)

Co-authored-by: Isaac Sanchez <isanchez-hawkins@arize.com>
This commit is contained in:
Isaac Sanchez-Hawkins
2026-05-21 15:51:09 +03:00
committed by GitHub
co-authored by Isaac Sanchez
parent 51c8d52ab5
commit 6fbdb22c7e
2 changed files with 24 additions and 4 deletions
@@ -89,4 +89,16 @@ describe('useFileSearchStore', () => {
expect(cacheEntries).toHaveLength(1);
expect(cacheEntries[0]?.files).toEqual([{ path: 'fresh.ts' }]);
});
test('keeps directory and query separators from colliding in cache keys', async () => {
const firstPromise = useFileSearchStore.getState().searchFiles('/project::nested', 'foo');
searchRequests[0].resolve([{ path: 'first.ts' }]);
await firstPromise;
const secondPromise = useFileSearchStore.getState().searchFiles('/project', 'nested::foo');
expect(searchRequests).toHaveLength(2);
searchRequests[1].resolve([{ path: 'second.ts' }]);
expect(await secondPromise).toEqual([{ path: 'second.ts' }]);
});
});
+12 -4
View File
@@ -34,7 +34,16 @@ const buildCacheKey = (
) => {
const normalizedDirectory = directory.trim();
const normalizedQuery = query.trim().toLowerCase();
return `${normalizedDirectory}::${normalizedQuery}::${limit}::${includeHidden ? '1' : '0'}::${respectGitignore ? '1' : '0'}::${type}`;
return JSON.stringify([normalizedDirectory, normalizedQuery, limit, includeHidden, respectGitignore, type]);
};
const cacheKeyMatchesDirectory = (cacheKey: string, directory: string) => {
try {
const value: unknown = JSON.parse(cacheKey);
return Array.isArray(value) && value[0] === directory;
} catch {
return false;
}
};
export const useFileSearchStore = create<FileSearchStoreState>()(
@@ -127,12 +136,11 @@ export const useFileSearchStore = create<FileSearchStoreState>()(
}
const normalizedDirectory = directory.trim();
const prefix = `${normalizedDirectory}::`;
set((state) => {
const nextCache = { ...state.cache };
const nextKeys = state.cacheKeys.filter((cacheKey) => {
if (cacheKey.startsWith(prefix)) {
if (cacheKeyMatchesDirectory(cacheKey, normalizedDirectory)) {
delete nextCache[cacheKey];
return false;
}
@@ -140,7 +148,7 @@ export const useFileSearchStore = create<FileSearchStoreState>()(
});
const nextInFlightEntries = Object.entries(state.inFlight).filter(
([key]) => !key.startsWith(prefix)
([key]) => !cacheKeyMatchesDirectory(key, normalizedDirectory)
);
const nextInFlight = Object.fromEntries(nextInFlightEntries);