feat(shortcuts): bind tracklist.delete to the confirmation
CI / check (push) Canceled after 0s
CI / e2e (push) Canceled after 0s
Search index maintenance / maintain-index (push) Canceled after 0s
Build & publish Arch package / arch-package (push) Successful in 2m5s

The binding has been in the defaults and in Settings since it was
written, with nothing on the other end of it, because "remove from
library" did not exist. It does now — and Delete only *opens* the
dialog, never performs the removal, which is the only version
defensible one keystroke from a focused row.

The e2e case asserts the two things that matter and neither is the row
count: the file is still on disk, and a real scan of the real directory
does not bring the row back. It watches a control path survive the same
scan, because a guard that excluded everything would pass the negative
assertion for free — and it restores the database it spends.
This commit is contained in:
2026-08-13 13:28:38 -04:00
parent 6d97e3c872
commit 41a4dd7148
6 changed files with 223 additions and 12 deletions
@@ -1191,8 +1191,29 @@ export class TrackList
'shortcut:tracklist-play',
this.handleShortcutPlay,
);
this.listenWhileActive(
document,
'shortcut:tracklist-delete',
this.handleShortcutDelete,
);
}
/**
* Delete opens the confirmation and does nothing else.
*
* That is the whole design of the binding: one keystroke from a
* focused row, a key that *asks* is defensible and a key that
* *acts* is not — so this is the same dialog the menu command
* opens, reached by a different route.
*/
private handleShortcutDelete = (): void => {
const filePaths = this.selection.getSelectedKeysOrdered();
if (filePaths.length === 0) return;
void this.removeFromLibrary(filePaths);
};
/** Enter plays the selection — the `tracklist.play` binding, which
* has existed in the defaults and in Settings since it was written
* and has never had anything on the other end of it. */
@@ -438,9 +438,14 @@ async function dispatch(action: string): Promise<void> {
);
break;
// No `tracklist.delete`: it dispatched an event nothing
// listened for, from a binding Settings advertised as
// configurable. See backend/shortcuts/config.go.
// `tracklist.delete` opens the confirmation and nothing else:
// the key is a request, not an action. See
// backend/shortcuts/config.go.
case 'tracklist.delete':
document.dispatchEvent(
new CustomEvent('shortcut:tracklist-delete'),
);
break;
// Panel-specific: autotag review. The view listens for these
// while it is the view on screen, and for nothing while it is
+6
View File
@@ -121,6 +121,12 @@ export const SHORTCUT_META: Record<string, ShortcutMeta> = {
scope: 'panel:track-list',
defaultKey: 'Enter',
},
'tracklist.delete': {
label: 'Remove from Library',
category: 'Navigation',
scope: 'panel:track-list',
defaultKey: 'Delete',
},
'autotag.apply': {
label: 'Apply Match',
category: 'Autotag',