fix(timeline): clear selection after keyboard archive/delete/approve
X (archive/restore), Delete, and S (approve) keyboard handlers in gridKeyNav advanced focus and invalidated the photos query but never cleared the selection — so the archived/deleted/approved UIDs stayed in the SvelteSet and kept their rings on tiles that hadn't unmounted yet. A subsequent Ctrl-click would then pile new UIDs on top of the stale set, leaving the user uncertain which photos a follow-up action would actually target. The BulkActionBar button path already cleared selection for the same reason; mirror that here. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -225,6 +225,13 @@ export function gridKeyNav(node: HTMLElement, params: GridKeyNavParams = {}) {
|
|||||||
// archived/restored — relevant when the cull targets came from a
|
// archived/restored — relevant when the cull targets came from a
|
||||||
// multi-selection rather than the single focused tile.
|
// multi-selection rather than the single focused tile.
|
||||||
focusAfter(ids);
|
focusAfter(ids);
|
||||||
|
// Drop the now-stale selection set. The archived UIDs are about
|
||||||
|
// to leave the timeline on refetch, but the SvelteSet membership
|
||||||
|
// keeps the selection ring on them until then — confusing for
|
||||||
|
// the user and a footgun if they Ctrl-click to add more and end
|
||||||
|
// up re-archiving the same photos. The BulkActionBar button path
|
||||||
|
// clears for the same reason; mirror it here.
|
||||||
|
clearSelection();
|
||||||
invalidatePhotos(ids);
|
invalidatePhotos(ids);
|
||||||
const label = target ? `Archived ${ids.length}` : `Restored ${ids.length}`;
|
const label = target ? `Archived ${ids.length}` : `Restored ${ids.length}`;
|
||||||
toast.success(label);
|
toast.success(label);
|
||||||
@@ -259,6 +266,8 @@ export function gridKeyNav(node: HTMLElement, params: GridKeyNavParams = {}) {
|
|||||||
toast.error(err instanceof Error ? err.message : 'Delete failed');
|
toast.error(err instanceof Error ? err.message : 'Delete failed');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
focusAfter(ids);
|
||||||
|
clearSelection();
|
||||||
invalidatePhotos(ids);
|
invalidatePhotos(ids);
|
||||||
toast.success(`Deleted ${ids.length}`);
|
toast.success(`Deleted ${ids.length}`);
|
||||||
}
|
}
|
||||||
@@ -277,6 +286,12 @@ export function gridKeyNav(node: HTMLElement, params: GridKeyNavParams = {}) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const { updated, errors } = await batchEdit(ids, (id) => approvePhoto(id));
|
const { updated, errors } = await batchEdit(ids, (id) => approvePhoto(id));
|
||||||
|
// Approve moves photos out of the review pile, so the same
|
||||||
|
// stale-selection trap as archive/delete applies — advance focus
|
||||||
|
// past the approved set and drop the now-irrelevant selection
|
||||||
|
// before invalidate refetches the (smaller) view.
|
||||||
|
focusAfter(ids);
|
||||||
|
clearSelection();
|
||||||
invalidatePhotos(ids);
|
invalidatePhotos(ids);
|
||||||
if (errors.length) {
|
if (errors.length) {
|
||||||
toast.error(`Kept ${updated.length}; ${errors.length} failed`, {
|
toast.error(`Kept ${updated.length}; ${errors.length} failed`, {
|
||||||
|
|||||||
Reference in New Issue
Block a user