From dc890d1fcc47323375c59c1f0b7f3b152b6351b7 Mon Sep 17 00:00:00 2001 From: Caleb Allen Date: Fri, 14 Aug 2026 13:12:01 -0400 Subject: [PATCH] feat(library): remove a track from the library without deleting the file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RemoveFromLibrary deletes the audio_files rows the way the scan's own orphan cleanup does and records each path in excluded_paths. The exclusion is not an enhancement: without it the next scan finds the file, sees no row and imports it again, so the button undoes itself. The soft scan compares files on disk against rows in the database, so surveyAudioFiles and countAudioFiles both take the exclusion set — otherwise an excluded path makes the two disagree forever and queues a full scan on every launch. Deleting a row cascades to queue_tracks, so the removal calls the same CompactQueue hook RemoveLibrary does. Also lands the requested badge: library-status-indicator is a button again where it can act, utils/library-status.ts states once what owning and wanting mean, and the long-declared queued state finally has a producer. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01UDCbcCZQepnpSQYJ6SxxZm --- .pi/skills/yellowjacket-dev/SKILL.md | 22 +- .../references/schema-change.md | 16 +- .planning/NOTES.md | 298 +++++++++++++++ .../008-the-last-audit.md | 197 +++++++++- .../009-the-badge-that-cannot-act.md | 300 +++++++++++++++ CLAUDE.md | 181 ++++++++- backend/database/sql/queries/audio_files.sql | 4 + .../database/sql/queries/excluded_paths.sql | 15 + .../database/sql/schemas/excluded_paths.sql | 25 ++ .../database/sql/sqlcgen/audio_files.sql.go | 50 +++ .../sql/sqlcgen/excluded_paths.sql.go | 75 ++++ backend/database/sql/sqlcgen/models.go | 7 + backend/datamap/datamap.go | 8 + backend/datamap/datamap_test.go | 8 + backend/events/events.go | 13 + backend/library/exclusions.go | 92 +++++ backend/library/library.go | 55 ++- backend/library/remove_tracks.go | 199 ++++++++++ backend/library/remove_tracks_test.go | 296 ++++++++++++++ backend/library/rescan.go | 9 + backend/library/scan_queue.go | 7 +- backend/library/staleness_test.go | 6 +- backend/shortcuts/config.go | 19 +- e2e/specs/remove-from-library.spec.ts | 149 ++++++++ e2e/specs/requested-badge.spec.ts | 339 ++++++++++++++++ .../src/assets/icons/fa/regular/bookmark.svg | 1 + .../explore-album-details.ts | 68 +++- .../explore-artist-details.ts | 15 +- .../components/explore-view/explore-view.ts | 26 +- .../library-status-indicator.ts | 189 ++++++++- .../top-results-row/top-results-row.ts | 31 +- .../src/components/track-list/track-list.ts | 105 +++++ frontend/src/events.ts | 11 + frontend/src/icons/names.txt | 1 + .../src/services/keyboard-shortcut-service.ts | 11 +- frontend/src/services/shortcut-meta.ts | 6 + frontend/src/store/library-store.ts | 68 ++++ frontend/src/utils/library-status.ts | 106 +++++ .../test/components/album-actions.test.ts | 20 +- .../test/components/library-status.test.ts | 361 ++++++++++++++++++ .../test/components/settings-names.test.ts | 28 +- .../test/stores/keyboard-shortcuts.test.ts | 29 ++ frontend/test/stores/library-store.test.ts | 49 +++ frontend/wailsjs/go/explore/Service.d.ts | 6 +- frontend/wailsjs/go/explore/Service.js | 12 +- frontend/wailsjs/go/library/Library.d.ts | 2 + frontend/wailsjs/go/library/Library.js | 4 + frontend/wailsjs/go/models.ts | 14 + 48 files changed, 3450 insertions(+), 103 deletions(-) rename .planning/plans/{active => completed}/008-the-last-audit.md (67%) create mode 100644 .planning/plans/completed/009-the-badge-that-cannot-act.md create mode 100644 backend/database/sql/queries/excluded_paths.sql create mode 100644 backend/database/sql/schemas/excluded_paths.sql create mode 100644 backend/database/sql/sqlcgen/excluded_paths.sql.go create mode 100644 backend/library/exclusions.go create mode 100644 backend/library/remove_tracks.go create mode 100644 backend/library/remove_tracks_test.go create mode 100644 e2e/specs/remove-from-library.spec.ts create mode 100644 e2e/specs/requested-badge.spec.ts create mode 100644 frontend/src/assets/icons/fa/regular/bookmark.svg create mode 100644 frontend/src/utils/library-status.ts create mode 100644 frontend/test/components/library-status.test.ts diff --git a/.pi/skills/yellowjacket-dev/SKILL.md b/.pi/skills/yellowjacket-dev/SKILL.md index ed30b03..b0ad847 100644 --- a/.pi/skills/yellowjacket-dev/SKILL.md +++ b/.pi/skills/yellowjacket-dev/SKILL.md @@ -18,7 +18,7 @@ here has disappeared. ## Read this part before you fail -Fourteen things cost a cycle each the first time. They are here, not in a +Fifteen things cost a cycle each the first time. They are here, not in a reference, because you need them *before* the failure, not after. - **Time out every binding call.** A bound Go method called with wrong @@ -54,6 +54,16 @@ reference, because you need them *before* the failure, not after. `label` to `aria-labelledby` — so a new dialog that forgets to call the helper from `updated()` is invisible to `getByRole('dialog', {name})`. +- **A name is computed on the element carrying the *role*, and Web + Awesome puts the role in its own shadow root.** `aria-label` on a + `` or a `` host never reaches the tree. Use the + component's own `label` (plus `styles/wa-slider-label.css.ts`, since + a slider's is visible) or `utils/name-dialog.ts`. And in the light + DOM, a `