The myRole select added for issue #286 wasn't included in the GROUP BY
clause, causing a 500 ("column album_user.role must appear in the
GROUP BY clause") whenever includeShared=true was requested.
Closes#286. The album picker for add_to_album/remove_from_album only
showed albums owned by the current user. Add an opt-in ?includeShared
param to /api/albums/list that also includes albums where the user
has 'editor' role (upload access), and group the picker into 'My
Albums' / 'Shared Albums' sections. Other callers of listAlbums()
don't pass includeShared, so they keep the existing owner-only
behavior unchanged.
Merges potential-trips + potential-trip-assets into
potential-albums-dates + potential-albums-assets respectively, keyed
by a new ?groupBy=day|trip query param. The actual grouping logic is
extracted into two new helper files (potentialAlbumsGrouping.helper.ts,
potentialAlbumsAssets.helper.ts), each holding a day-mode and
trip-mode function the unified handlers call into.
Client-facing functions (listPotentialTrips, listPotentialTripAssets)
keep their existing names/signatures — only their internal path and a
groupBy param changed — so no frontend component call sites need
updating. Also drops the two now-unused LIST_POTENTIAL_TRIP*_PATH
route constants.
Addresses the maintainer's open caching-strategy question by removing
the need for a second endpoint/cache entirely: one endpoint per
concern, two grouping strategies.
Immich v3 dropped asset.deviceId/deviceAssetId (af4cfce on main).
This branch predates that migration, so its own SELECT_ORPHAN_RANGE
query still referenced the column, which would 500 on any current
Immich v3 instance. Match the field list already used by the sibling
potential-albums-assets.ts endpoint, which was updated for v3.
clusterTrips's gap check compared array-index adjacency between
DaySignal entries. Since `days` only contains dates with >=1 photo
(GROUP BY DATE(...) with no zero-photo rows), two trips separated by
months with no photos in between were array-adjacent (gapLen=0) and
got merged into one bogus trip. Compare actual elapsed calendar days
between the last and next away day instead.
The local tag table can lag behind Immich's own tag state (e.g. tags
created directly in Immich, or before this app's sync ran), causing
remove_tag to silently no-op on a tag that actually exists. Mirror the
sibling "tag" action's approach and resolve against the Immich API,
matching on the tag's full-path "value" field. Drops the now-unused
db/sql local lookup.
makeDeviceAssetId(item.assetId) was passed as an extra 5th argument
before tagId, which doesn't match uploadAssetBuffer's signature
(asset, payload, uploadHeaders, jsonHeaders, tagId?) and broke the
TS build. Match the call pattern used by the sibling nextcloud/immich
processors.
The id list was built via raw string interpolation into sql.raw().
Switch to sql.join with proper parameter binding, matching the
pattern used by the other match branches in this function.
- Show full condition details on IF/Switch nodes with person thumbnails
- Show album name and tag on action nodes
- Add dark mode support for React Flow controls via colorMode
- Center images in lightbox preview
- Fix leaflet marker icons for both Webpack and Turbopack bundlers
- Add import_api_key setting with auto-generate endpoint and settings UI
- Import job runner uses import API key when available, falls back to session
- Show ApiKeyGate empty state in both workflow and import pages when key missing
- Replace workflow API key warning popover with full gate overlay
- Redesign person cards: square avatar, hover action toolbar, cleaner layout
- Birthday field now uses popover with calendar + natural language input
- Fix autocomplete dropdown clipping inside overflow-hidden cards via portal
- People grid column slider persisted to localStorage (min 3, max 20)
Add delete with confirm dialog to asset lightbox (always visible, handles
deletion internally with local state update). Force dark theme on asset
info panel and fix text color inheritance. Add edge-to-edge image display
in lightbox by removing slide padding. Show open-in-immich link on hover
only. Add workflow page title breadcrumb. Add one-click workflow API key
generation that creates the key in Immich and saves it automatically.
Add beta badge to Workflows in the sidebar. Include settings page
improvements, workflow detail updates, profile info and sidebar
nav refinements, and validate-api-key endpoint.
Redesign import-shared with sticky import bar, dense gallery grid,
progress bar, and cleaner landing state. Add password-protected
shared link support - detects 401 "Password required" from Immich
and shows a password input. Also reduce asset grid spacing and
replace "Open in Immich" text with a link icon.
Reorganize the exif analytics page into labeled sections (Camera & Gear,
Location, Technical, Storage) with icon headers. Replace donut charts
with horizontal bar charts for multi-category EXIF distributions.
Improve heatmap with emerald color scale, day labels, and legend.
Add polished stat cards with icons and skeleton loading states.
- API returns node counts, total runs, and last run status per workflow
- List view with status icon, trigger badges, stats, and last run info
- Human-readable schedule labels (Every 6h, Every 30m)
- Last run shows status icon, asset count, and relative time
- Actions appear on hover for cleaner default state
- Improved empty state
- Add ownerId to settings table for per-user key-value storage
- Add settings KV API endpoint scoped by user
- Add workflow API key config in settings page
- Action executor uses per-user workflow API key, falls back to session auth
- Bootstrap cron scheduler on server start via instrumentation hook
- Re-register/unregister cron on workflow enable/disable/delete
- Downgrade node-cron to v3 for Turbopack compatibility
- Add structured console logs to workflow engine for all steps
- Enabled toggle saves immediately to server
- Schedule popover saves immediately to server
- Use react-hot-toast instead of shadcn toast in workflow editor
- Visual node-based workflow editor using React Flow
- Asset triggers: new asset, asset updated, all assets (with lookback buffer)
- Logic nodes: if/switch with combinable conditions (person, location, date, camera, EXIF, favorites, album membership)
- Action nodes: create album, add/remove from album, favorite, unfavorite, archive, tag
- Workflow-level triggers: manual run, cron schedule, webhook
- Debug mode: dry run with step-by-step logs and asset previews
- Run history with per-node asset tracking
- Run detail page with annotated read-only graph
- Processed asset tracking to prevent duplicate processing
- Multi-person picker with face thumbnails
- Album picker dropdown for actions
- JSON import/export for workflow sharing
- Workflow list page with create, delete, enable/disable
- Move instrumentation.ts to src/ so Next.js picks it up (required when using src/ layout)
- Enable experimental.instrumentationHook in next.config.mjs (required in Next.js 14)
- Switch Dockerfile deps stage from npm to bun to match lockfile
- Explicitly copy @libsql and libsql into standalone runner — Next.js file tracing
misses dynamically required native modules (require(`@libsql/${target}`))
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace raw fetch() in settings, share-key, and import-shared with
centralized API handlers via src/lib/api.ts. Also auto-create the data/
directory on startup so the SQLite db path is always valid.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Removed the additional tags for assets in the MissingLocationAssets component, returning only the sorted assets.
- Updated AssetGrid to include Immich link tags for each asset, utilizing the exImmichUrl from the configuration context.
- Enhanced the dependency array for the asset mapping effect to include exImmichUrl for proper updates.
- Updated the deleteAssets function to accept an options parameter for forced deletion.
- Introduced a new handleTrash function to move selected assets to trash instead of permanent deletion.
- Added a confirmation dialog for moving assets to trash, improving user experience and providing recovery options.
- Updated the UI to reflect the new trash functionality with appropriate button and alert dialog integration.
- Introduced new API routes for people names, geo photos, and album photos statistics.
- Updated analytics handler to include functions for fetching new statistics.
- Added new chart components for visualizing people names, geo photos, and album photos data in the Exif data analytics page.
- Modified asset deletion function to accept an options parameter for forced deletion.
- Added functionality to auto-select assets based on criteria: lowest quality and smallest size.
- Implemented keyboard shortcut (Escape) to unselect all assets.
- Updated UI to include an auto-select dropdown in the floating bar for better user experience.
- Enhanced toast notifications to inform users about the auto-selection results.
- Added a floating bar to display selected assets information in discard mode.
- Implemented logic to calculate and display the count and total size of selected assets.
- Introduced a delete confirmation dialog for removing selected assets, including success and error feedback via toast notifications.
- Updated the state management to handle asset deletion and clean up empty duplicate records.
- Added a `selectionMode` prop to `DuplicateAssetRecord`, `DuplicateAssetItem`, and `VirtualizedDuplicateList` components to toggle between "keep" and "discard" modes.
- Updated UI elements to reflect the current selection mode, including button states and labels.
- Enhanced the logic for keeping or deleting selected assets based on the selected mode in the `BulkDuplicatePage` component.
- Improved user experience by providing clear visual feedback for asset selection actions.
- Updated the `listSimilarFaces` API to accept a name parameter for filtering results.
- Modified the `PersonMergeDropdown` component to include a new select input for choosing between "nameless", "tagged", and "all" options.
- Adjusted the API handler to filter similar faces based on the selected name criteria.
- Improved the UI layout for the threshold and name selection inputs.
- Changed the `onSelect` prop in `AlbumThumbnail` to accept the entire album object instead of just the album ID.
- Introduced new API routes for merging albums and added the corresponding handler.
- Removed the `useAlbumSelection` hook and integrated selection logic directly in the `AlbumList` component.
- Added a `MergeAlbumDialog` component for merging albums.
- Updated the album list page to handle album merging and selection state more effectively.
- Introduced useMemo to separate known and unknown people based on their names.
- Enhanced rendering logic to display known and unknown people distinctly.
- Updated UI elements for better layout and usability, including search input and person rendering.
- Adjusted padding and spacing for a more consistent design across the component.
- Integrated PhotoSelectionContext into AlbumImages for better state management of selected assets.
- Replaced local asset state with context-driven updates, allowing for seamless asset fetching and selection.
- Added image gallery functionality using react-grid-gallery and yet-another-react-lightbox for enhanced user experience.
- Updated AssetOffsetDialog to include timezone options for date adjustments, improving flexibility in asset date management.
- Refactored UI elements for better layout and usability across both components.