fix: address 4 P2 review issues from PR #8 round 6

db/commands: paginate tag search — add offset + COUNT query to
search_images_by_tag returning (images, total); TagSearchParams gains
offset field and command returns TagSearchPage; store handles both the
initial load and load-more path so results beyond PAGE_SIZE are reachable

commands: semantic search over-fetches by 4× when any post-query filter
(folder, media kind, favorites, rating) is active, then truncates to the
requested limit; previously well-rated matches ranked just beyond the bare
vector limit were silently omitted

db: wrap update_folder_path in a transaction so a path-rewrite failure
(e.g. uniqueness collision) rolls back the already-updated folder row
instead of leaving the DB in an inconsistent half-migrated state

store: invalidate exploreTagsFolderId when a tagging run completes so
Explore reflects the updated tag distribution without requiring a manual
folder switch; previously the cache was never busted by background tagging
This commit is contained in:
2026-06-07 22:15:48 +01:00
parent 04ade3d5d6
commit 7efb187971
3 changed files with 83 additions and 25 deletions
+27 -13
View File
@@ -725,7 +725,8 @@ export const useGalleryStore = create<GalleryState>((set, get) => ({
}
if (parsedSearch.mode === "tag" && parsedSearch.query) {
const images = await invoke<ImageRecord[]>("search_images_by_tag", {
const offset = reset ? 0 : loadedCount;
const result = await invoke<{ images: ImageRecord[]; total: number; offset: number; limit: number }>("search_images_by_tag", {
params: {
query: parsedSearch.query,
folder_id: selectedFolderId,
@@ -733,22 +734,32 @@ export const useGalleryStore = create<GalleryState>((set, get) => ({
favorites_only: favoritesOnly,
rating_min: minimumRating > 0 ? minimumRating : null,
limit: PAGE_SIZE,
offset,
},
});
if (requestToken !== galleryRequestToken) return;
set({
images,
totalImages: images.length,
loadedCount: images.length,
loadingImages: false,
collectionTitle: `Tag search: ${parsedSearch.query}`,
selectedFolderId,
similarSourceImageId: null,
similarSourceFolderId: null,
similarHasMore: false,
similarFolderId: null,
});
if (reset) {
set({
images: result.images,
totalImages: result.total,
loadedCount: result.images.length,
loadingImages: false,
collectionTitle: `Tag search: ${parsedSearch.query}`,
selectedFolderId,
similarSourceImageId: null,
similarSourceFolderId: null,
similarHasMore: false,
similarFolderId: null,
});
} else {
set((state) => ({
images: [...state.images, ...result.images],
loadedCount: state.loadedCount + result.images.length,
totalImages: result.total,
loadingImages: false,
}));
}
return;
}
@@ -1608,6 +1619,9 @@ export const useGalleryStore = create<GalleryState>((set, get) => ({
"AI tagging complete",
`${folderName} finished generating tags.${failureDetail}`,
);
// New tags are now in the DB — invalidate the Explore tag cache so
// reopening Explore reflects the updated tag distribution.
set({ exploreTagsFolderId: undefined });
}
}