Move `showEditFaces` state to `assetViewerManager` so the edit faces
panel open/close state is globally accessible. Add Escape key handling
to `PersonSidePanel` that closes the assign-face sub-panel first, then
the edit faces panel. Guard the asset viewer's global Escape-to-close
action so it doesn't fire while either face panel is open.
Change-Id: I0c947fe0758aef0eac473f4cc72f6a3b6a6a6964
AdaptiveImage stacks quality layers (thumbnail → preview → original) as they load. Without compositor layer promotion on the container, the browser could render a stale frame when the original-quality layer was overlaid on top of the preview-quality layer.
Add `will-change: transform` as a class on AdaptiveImage's root element so it gets a dedicated compositor layer from first paint. This also subsumes the imperative `style.willChange = 'transform'` that zoomImageAction was applying to the same element (the zoom target from photo-viewer is the AdaptiveImage root), so drop that now-redundant code.
Change-Id: Icd866a2bb5a5fce299c36404547fa0546a6a6964
fix(web): cancel video preview fetch when bind:this is cleared early
In Svelte 5.53.9, `bind:this` is now cleared earlier in the unmount
sequence ("better bind:this cleanup timing"). The video thumbnail's
$effect was relying on the old order to read the bound `player` element
and clear its `src` to abort the in-flight `/api/assets/{id}/video/playback`
range request — but the bind is now `undefined` by the time the effect
runs, so the cleanup is silently skipped. The detached <video> keeps
its src, and Firefox does not abort an in-flight media fetch when the
element is detached/GC'd. Long-lived 206 range requests then saturate
Firefox's 6-connection HTTP/1.1 per-host limit and freeze the timeline
(see #27585).
Capture the player reference inside the effect and tear down via the
effect cleanup return — Svelte runs the prior cleanup (with the captured
ref) before `bind:this` is cleared. Use the canonical
`pause() / removeAttribute('src') / load()` sequence which actually aborts
the fetch in Firefox, even on a detached element.
Fixes#27585
Change-Id: I4d9fba859955f5c54f603c345e61d4206a6a6964
When a concurrent caller awaits `this.complete` inside `execute()` and
`cancel()` is called, the promise rejects with `undefined` outside of any
try/catch, causing "Uncaught (in promise) undefined" console spam during
rapid timeline scrolling.
- Wrap the `await this.complete` path in try/catch, returning 'CANCELED'
- Guard the `finally` block to only null `cancelToken` if it still belongs
to this call, preventing a race condition with `cancel()` to `init()`
Change-Id: I65764dd664eb408433fc6e5fc2be4df56a6a6964
* Fix#26502: Fix timestamp handling for database backup in Web UI
Frontend parsed backup timestamps as UTC, but they were in the
server's local timezone, causing wrong relative times.
Add `timezone` field to DatabaseBackupDto to expose server timezone.
Update frontend to parse timestamps using this timezone.
Convert timestamps to user's local timezone before rendering.
Fallback to browser timezone if server timezone is missing.
Ensures correct relative time display in Web UI.
* fix: regenerate open-api types and remove custom backup type
- Ran `make open-api` to update types based on backend changes
- Removed custom BackupWithTimezone type in MaintenanceBackupsList
- Updated timezone props to use the newly generated native type
* fix: simplify timezone handling for database backups
- Updated DatabaseBackupDto to make timezone a required property
- Removed manual DateTime.local().zoneName fallbacks
- Cleaned up type casts after regenerating OpenAPI types
* fix: Add missing newline at end of spec file
Rename MonthGroup class to TimelineMonth to better convey that it represents a single month within the timeline. Updates the file, class, and all references across 16 files.
Change-Id: Id50fd6d4b7d0e431571b67c0f81c0e316a6a6964