feat: add tag filter for assets - #52
Merged
Merged
Conversation
Filter photos by Immich tag across the grid and map, mirroring the existing album-filter pattern (closes #51). Backend: - New tags and assetTags tables (migration 016), synced from Immich via getTags + getTagAssetIDs and a syncTags routine mirroring syncAlbums - Thread tagID through asset, map-marker, day-count and page-info queries; add GET /tags for the dropdown - Honor startDate/endDate in map-marker queries - getTags count joins through to real assets, excluding orphaned rows and stack-secondary / hidden-library assets - Tag and album sync now advance updatedAt only after assets are replaced, so a transient fetch failure is retried instead of leaving membership stale; per-item failures are isolated - deleteUserSyncData clears tags and assetTags on API-key change Frontend: - TagFilterGroup searchable dropdown, disabled on the album list - Persist tagID in the URL and thread it through view/catalog/map state - Re-fit the map viewport when the tag or date filter changes the markers - URL sync reads a live ref so chained filter changes no longer clobber one another
There was a problem hiding this comment.
Pull request overview
Adds an Immich tag-based filter that propagates end-to-end (URL/state → frontend grid/map → backend queries), enabling workflows like finding already-tagged photos and mass geolocating them.
Changes:
- Introduces tag persistence and selection in frontend state/URL, plus a searchable
TagFilterGroupUI control. - Adds backend tag storage + sync from Immich and exposes tags via a new
GET /tagsendpoint. - Threads
tagID(and for map markers, date range) through asset, day-count, page-info, and map-marker queries.
Reviewed changes
Copilot reviewed 42 out of 42 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/utils/view.ts | Adds URL param constant for tag selection. |
| src/shared/types/tag.ts | Introduces shared tag row type for frontend consumption. |
| src/shared/types/context.ts | Extends view/map context types to include tag selection and dates. |
| src/shared/services/backendApi.ts | Threads tagID into asset/day-count/page-info/map-marker requests; adds fetchTags(). |
| src/shared/services/backendApi.guards.ts | Adds runtime guard for tag payloads. |
| src/shared/context/useViewDomain.ts | Wires tag selection into view domain + URL sync; clears tag in album list mode. |
| src/shared/context/useUIMapController.ts | Passes tag selection through map controller inputs. |
| src/shared/context/useProviderValues.ts | Propagates tag selection + dates through provider memoization. |
| src/shared/context/useCatalogDomain.ts | Threads tag selection into asset loading hook. |
| src/shared/context/useAppProviderState.ts | Integrates tag state into app provider wiring. |
| src/shared/components/PhotoListContainer.tsx | Clears tag when switching into album mode; passes tag props to filter bar. |
| src/shared/components/PhotoList.tsx | Adds tag props to filter bar composition and disables tag filter on album list. |
| src/features/tags/useTags.ts | New hook to fetch tags lazily (on-demand) with abort handling. |
| src/features/photoGrid/useAssets.ts | Adds tag dependency to asset loading and refresh logic. |
| src/features/map/hooks/useMapViewModel.ts | Threads tag/date into map marker loading and view model output. |
| src/features/map/hooks/useMapViewController.ts | Includes tag/date in controller dependencies for fit/reload behavior. |
| src/features/map/hooks/useMapViewAutoFit.ts | Resets auto-fit when tag/date filters change (defer fit until markers update). |
| src/features/map/hooks/useMapMarkers.ts | Threads tag/date into map marker fetch and reload triggers. |
| src/features/map/hooks/useFocusMapAsset.ts | Passes selected tag into focus resolution flow. |
| src/features/map/hooks/useFocusMapAsset.flow.ts | Threads tag into page-info queries when resolving focus target. |
| src/features/filterBar/useURLState.ts | Persists tag in URL state and switches URL sync to a live ref model. |
| src/features/filterBar/useDayCounts.ts | Threads tag filter into day-count fetching. |
| src/features/filterBar/TagFilterGroup.tsx | New searchable tag dropdown UI component. |
| src/features/filterBar/FilterBar.tsx | Renders tag filter group and wires props. |
| src/features/albums/useAlbums.ts | Adjusts album reload behavior when date/gps filters change. |
| backend/types.go | Adds backend tag row + Immich tag response types. |
| backend/syncTags.go | Implements tag metadata upsert + asset membership sync. |
| backend/syncService.go | Integrates tag sync; changes album sync stamping behavior; adds tag fetch limit. |
| backend/syncService_test.go | Adds regression tests for deferred updatedAt stamping and recovery behavior. |
| backend/migrations/016_add_tags.sql | Adds tags and assetTags tables and index. |
| backend/migrations_test.go | Updates expected migration version to 16. |
| backend/main.go | Registers protected GET /tags route. |
| backend/interfaces.go | Extends store interfaces to support tags and tag-aware queries. |
| backend/immichClient.go | Adds Immich tag list + tag asset search calls. |
| backend/handlersAuth.go | Updates map marker count calls for new signature. |
| backend/handlers.go | Threads tag/date into handlers; adds handleGetTags; validates map marker date params. |
| backend/handlers_test.go | Updates existing tests for new filtered-assets signature. |
| backend/databaseTags.go | Adds tag persistence, tag membership replacement, and tag list query w/ counts. |
| backend/databaseLibraries_test.go | Updates map marker/asset query calls for new signatures. |
| backend/databaseAlbums.go | Adds setAlbumSynced() helper to stamp updatedAt post-success. |
| backend/database.go | Adds tag-aware asset filters, tag/date-aware marker filters, and tag-aware page-info logic. |
| backend/database_test.go | Updates tests and adds coverage for tag-filtered queries and tag counts. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…tags - Record both album and tag failures via errors.Join instead of only the first (full + incremental sync) - Clear map markers on date-range change too, matching album/tag, so stale out-of-range pins are not briefly shown or interactable - Add handler test for GET /tags (authenticated success + unauthenticated)
|
Thank you, very useful, I was able to geolocalize hundreds of images in a few minutes |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #51 — lets you filter photos by an Immich tag across the grid and map, so already-tagged images can be found and mass-geolocated.
Backend
tags/assetTagstables (migration 016), synced from Immich viagetTags+getTagAssetIDswith asyncTagsroutine mirroringsyncAlbums.tagIDthreaded through asset, map-marker, day-count and page-info queries; newGET /tagsendpoint for the dropdown.startDate/endDate.getTagscount joins through to real assets, excluding orphaned rows and stack-secondary / hidden-library assets, so the badge matches the filtered list.updatedAtonly after assets are replaced — a transient fetch failure is retried next sync instead of leaving membership stale; per-item failures are isolated.deleteUserSyncDataclearstags/assetTagson API-key change.Frontend
TagFilterGroupsearchable dropdown, disabled on the album list and cleared when leaving an album.tagIDpersisted in the URL and threaded through view/catalog/map state.Tests
updatedAtsync (tag and album), and the failed-fetch-recovers behavior.go vetpass; frontendtsc+ eslint clean.