Skip to content

feat(search): sectioned top-bar results — artists, albums, titles#326

Merged
InstaZDLL merged 4 commits into
mainfrom
feat/search-albums-artists
Jun 28, 2026
Merged

feat(search): sectioned top-bar results — artists, albums, titles#326
InstaZDLL merged 4 commits into
mainfrom
feat/search-albums-artists

Conversation

@InstaZDLL

@InstaZDLL InstaZDLL commented Jun 28, 2026

Copy link
Copy Markdown
Owner

Closes #321.

Problème

La barre de recherche annonce « titre, artiste, album » mais le dropdown ne listait que des titres — aucun moyen d'atteindre une page album ou artiste, alors que la donnée existe déjà.

Backend

  • Nouvelles commands search_albums / search_artists (browse.rs). FTS étant track-scoped, elles font un substring-match de la forme canonical_name de la requête contre album.canonical_title / artist.canonical_name (via instr(), préfixes en tête), avec LIMIT clampé. Même shape slim { artwork_base, items } que list_albums / list_artists → le front réutilise expandAlbumRow / expandArtistRow.
  • L'expansion des thumbnails par-ligne (offload spawn_blocking) est factorisée en helpers partagés expand_album_rows / expand_artist_rows, réutilisés par les chemins list et search (pas de duplication).

Frontend

  • Wrappers searchAlbums / searchArtists (browse.ts).
  • TopBar : fan-out des 3 entités en un Promise.all, dropdown en sections Artistes / Albums / Titres (composant SearchSection). Les rows artiste/album naviguent vers ArtistDetailView / AlbumDetailView via les nouvelles props onNavigateToArtist / onNavigateToAlbum ; les titres jouent comme avant.
  • Les filtres avancés restent track-only : dès qu'un filtre est posé, les sections album/artiste sont supprimées et seul search_tracks_advanced tourne.

i18n

topbar.search.{artists,albums,titles} ajoutés aux 17 locales.

Docs

docs/features/library.md (section Search) + catalogue CLAUDE.md.

Validation

bun run typecheck + bun run lint + cargo clippy verts. Pas de migration (FTS + colonnes canonical existent déjà).

Summary by CodeRabbit

  • Nouvelles fonctionnalités
    • La recherche de la barre supérieure affiche désormais des résultats séparés pour titres, albums et artistes (FTS5), avec regroupement en sections.
    • Navigation directe : ouvrir un album ou un artiste depuis le dropdown de recherche.
  • Correctifs
    • Avec les filtres avancés, la recherche reste track-only (albums/artistes masqués).
    • Mise à jour plus fiable de la recherche : debounce à 250 ms et annulation des résultats obsolètes.
  • Documentation
    • Mise à jour de la documentation “Search” (logique debounce, sections et filtres) et ajustement de la mise en forme dans le guide.

The global search advertised titles/artists/albums but the dropdown only
listed tracks, with no way to reach an album or artist page.

Backend: add `search_albums` / `search_artists` commands in browse.rs.
FTS is track-scoped, so they substring-match the query's `canonical_name`
form against `album.canonical_title` / `artist.canonical_name` (prefix
matches rank first) and return the same slim `{ artwork_base, items }`
shape as `list_albums` / `list_artists`. The per-row thumbnail expansion
is factored into shared `expand_album_rows` / `expand_artist_rows`
helpers reused by both the list and search paths.

Frontend: `searchAlbums` / `searchArtists` wrappers; TopBar fans the
three entities out in one `Promise.all` and renders sectioned results
(Artists / Albums / Titles). Artist + album rows navigate to the detail
views via new `onNavigateToArtist` / `onNavigateToAlbum` props; title
rows still play. Advanced filters stay track-only — when any is set the
album/artist sections are suppressed.

i18n: `topbar.search.{artists,albums,titles}` across all 17 locales.
Docs: library.md Search section + CLAUDE.md catalogue.
@InstaZDLL InstaZDLL added scope: frontend React/Vite frontend (src/) scope: backend Rust/Tauri backend (src-tauri/) scope: i18n Translations (src/i18n/) scope: docs Docs, README, assets type: feat New feature size: xl > 500 lines labels Jun 28, 2026
@coderabbitai

coderabbitai Bot commented Jun 28, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 175f241d-8436-42e6-809e-f54ac2861ae4

📥 Commits

Reviewing files that changed from the base of the PR and between c222c50 and 00fda39.

📒 Files selected for processing (1)
  • src/components/layout/TopBar.tsx

📝 Walkthrough

Walkthrough

La recherche de la TopBar renvoie désormais des albums et des artistes en plus des titres. Le backend, les commandes Tauri, les wrappers TypeScript et l’UI ont été mis à jour, avec des libellés localisés et une documentation alignée.

Changes

Recherche sectionnée dans la TopBar

Layer / File(s) Summary
Commandes Rust de recherche
src-tauri/crates/app/src/commands/browse.rs
Les commandes album et artiste factorisent l’expansion des lignes, valident les pochettes/métadonnées, puis ajoutent search_albums et search_artists avec normalisation, limite bornée et classement par préfixe.
Branchement Tauri et wrappers
src-tauri/crates/app/src/lib.rs, src/lib/tauri/browse.ts, src/components/layout/AppLayout.tsx
Les nouvelles commandes sont enregistrées côté Tauri, les wrappers searchAlbums et searchArtists appellent les handlers et convertissent les réponses, et AppLayout transmet les callbacks de navigation au TopBar.
TopBar sectionnée et navigation
src/components/layout/TopBar.tsx
TopBar sépare les résultats tracks/albums/artistes, invalide les recherches concurrentes, exécute le fan-out selon les filtres, et affiche le dropdown en sections avec navigation dédiée.
Libellés et documentation
src/i18n/locales/*.json, docs/features/library.md, CLAUDE.md
Les locales ajoutent les libellés artists, albums et titles, la documentation de recherche met à jour le debounce et le mode track-only des filtres avancés, et CLAUDE.md ajuste la mise en forme de scan:progress.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

Trois sections s’allument dans la barre,
Titre, album, artiste au même endroit.
Le clic trouve enfin sa bonne route,
Et la recherche parle trois langues à la fois.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning La plupart des exigences de #321 sont couvertes, mais la section « Top result » demandée par l’issue n’apparaît pas dans le changement. Ajoutez un vrai « Top result » au dropdown (meilleur match global) ou documentez son exclusion, puis vérifiez l’acceptation de #321.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed Le titre suit le format Conventional Commits et résume bien la recherche sectionnée par artistes, albums et titres.
Description check ✅ Passed La description couvre le problème, les changements, i18n et validation; elle est seulement moins fidèle au template sur « How I tested » et les captures.
Out of Scope Changes check ✅ Passed Les changements restent centrés sur la recherche sectionnée, la navigation, l’i18n et la doc, sans ajout manifestement hors sujet.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/search-albums-artists

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/features/library.md`:
- Line 40: The advanced filter description in the library feature docs is
partially enumerating track-only filters and is missing other conditions handled
by TopBar.tsx. Update the wording to avoid listing an incomplete set of filters;
instead describe the behavior generically as “when any advanced filter is set”
or “when track-only filters are active,” so it stays aligned with the track-only
branching in TopBar and the related search flow.

In `@src/components/layout/TopBar.tsx`:
- Around line 151-177: The search flow in TopBar should ignore stale responses,
since Promise.all(...).then(...) can apply results from an older request after a
newer query has already been issued. Update the search handler around
tracksPromise, albumsPromise, artistsPromise, and the Promise.all callback to
track the latest request with a ref-based requestId or snapshot, and only call
setSearchResults, setAlbumResults, setArtistResults, and setIsSearchOpen when
the response matches the current request.
- Around line 82-88: The focus-reopen logic in TopBar still only checks track
matches, so searches with only albums or artists can look empty on refocus.
Update the menu reopen condition used by the input/focus handling in TopBar to
consider albumResults and artistResults alongside searchResults, and make sure
the state/effect that controls the dropdown uses all three result sets
consistently.
- Around line 581-663: The search result rows in TopBar are clickable but not
keyboard-accessible because the artist, album, and track entries are rendered as
non-interactive li elements with onClick only. Update the result items inside
the artistResults, albumResults, and searchResults sections to use a semantic
interactive control such as a full-width button type="button" or link, and wire
it to handleArtistResultClick, handleAlbumResultClick, and
handleSearchResultClick so they can be activated by keyboard and announced
correctly by assistive tech.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 7c41c4db-c5c3-4c28-a296-63822bab7502

📥 Commits

Reviewing files that changed from the base of the PR and between aa35067 and 53f5d6b.

📒 Files selected for processing (24)
  • CLAUDE.md
  • docs/features/library.md
  • src-tauri/crates/app/src/commands/browse.rs
  • src-tauri/crates/app/src/lib.rs
  • src/components/layout/AppLayout.tsx
  • src/components/layout/TopBar.tsx
  • src/i18n/locales/ar.json
  • src/i18n/locales/de.json
  • src/i18n/locales/en.json
  • src/i18n/locales/es.json
  • src/i18n/locales/fr.json
  • src/i18n/locales/hi.json
  • src/i18n/locales/id.json
  • src/i18n/locales/it.json
  • src/i18n/locales/ja.json
  • src/i18n/locales/ko.json
  • src/i18n/locales/nl.json
  • src/i18n/locales/pt-BR.json
  • src/i18n/locales/pt.json
  • src/i18n/locales/ru.json
  • src/i18n/locales/tr.json
  • src/i18n/locales/zh-CN.json
  • src/i18n/locales/zh-TW.json
  • src/lib/tauri/browse.ts

Comment thread docs/features/library.md Outdated
Comment thread src/components/layout/TopBar.tsx
Comment thread src/components/layout/TopBar.tsx
Comment thread src/components/layout/TopBar.tsx
@InstaZDLL InstaZDLL self-assigned this Jun 28, 2026
- Guard against stale responses: each `runSearch` bumps a `searchSeqRef`
  and the `Promise.all` callback only applies results when its id is
  still current, so a slow older request can't clobber a newer query.
- Focus-reopen now considers album + artist results, not just tracks —
  an album-only / artist-only result set no longer looks empty on
  refocus.
- Result rows are now keyboard-accessible: each artist / album / title
  entry is a full-width `<button type="button">` inside its `<li>`
  (Tab + Enter/Space, announced by assistive tech) instead of an
  `onClick`-only `<li>`.
- Docs: describe the advanced-filter suppression generically ("when any
  advanced filter is active") instead of an incomplete filter list.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/components/layout/TopBar.tsx (1)

246-252: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Invalide la recherche en cours à la fermeture.

closeSearch() vide l’état sans incrémenter searchSeqRef. Si une recherche déjà lancée se résout après un clic sur artiste/album/titre, son seq reste courant et peut rouvrir le dropdown après la navigation ou la lecture.

Correctif proposé
 const closeSearch = () => {
+  searchSeqRef.current += 1;
   setIsSearchOpen(false);
   setSearchQuery("");
   setSearchResults([]);
   setAlbumResults([]);
   setArtistResults([]);
 };

As per path instructions, src/**: "Vérifie les erreurs de state/effects, les handlers qui lancent des commandes Tauri, les problèmes d'accessibilité visibles, et les régressions de navigation/player."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/layout/TopBar.tsx` around lines 246 - 252, La fermeture de la
recherche ne invalide pas les requêtes encore en vol, ce qui peut laisser une
réponse ancienne réouvrir l’UI après navigation. Dans closeSearch(), incrémentez
searchSeqRef en plus de vider les états, afin que les résultats déjà lancés
deviennent obsolètes; gardez la logique de recherche/filtrage dans les handlers
associés à searchSeqRef pour rejeter toute réponse avec un seq périmé.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/components/layout/TopBar.tsx`:
- Around line 246-252: La fermeture de la recherche ne invalide pas les requêtes
encore en vol, ce qui peut laisser une réponse ancienne réouvrir l’UI après
navigation. Dans closeSearch(), incrémentez searchSeqRef en plus de vider les
états, afin que les résultats déjà lancés deviennent obsolètes; gardez la
logique de recherche/filtrage dans les handlers associés à searchSeqRef pour
rejeter toute réponse avec un seq périmé.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: b70cb93b-bf36-42fa-a67a-944a9339d688

📥 Commits

Reviewing files that changed from the base of the PR and between 53f5d6b and f6f79bf.

📒 Files selected for processing (2)
  • docs/features/library.md
  • src/components/layout/TopBar.tsx

closeSearch() cleared the result state but didn't bump searchSeqRef, so
a fan-out still in flight when the user clicked a result could resolve
afterward and reopen the dropdown with stale results over the page just
navigated to. Bump the seq in closeSearch so those responses are
rejected by the existing `seq === searchSeqRef.current` guard.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/layout/TopBar.tsx`:
- Around line 246-250: La fermeture de la recherche invalide les requêtes en
cours, mais pas le debounce planifié par handleSearchInput, ce qui peut encore
déclencher runSearch après navigation. Dans TopBar.tsx, ajoute un moyen
d’annuler le setTimeout en attente lors de closeSearch (par exemple via une ref
de timer partagée avec handleSearchInput), et assure-toi que closeSearch nettoie
aussi ce timer en plus d’incrémenter searchSeqRef.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: fecda811-51a4-473e-9bf7-8ad45553c699

📥 Commits

Reviewing files that changed from the base of the PR and between f6f79bf and c222c50.

📒 Files selected for processing (1)
  • src/components/layout/TopBar.tsx

Comment thread src/components/layout/TopBar.tsx
closeSearch() invalidated in-flight requests but not the debounce timer
scheduled by handleSearchInput, so a keystroke from just before a
result click could still fire runSearch (with the captured old query)
after navigation and reopen the dropdown. Clear searchTimerRef in
closeSearch alongside the seq bump.
@InstaZDLL InstaZDLL merged commit 276054e into main Jun 28, 2026
14 checks passed
@InstaZDLL InstaZDLL deleted the feat/search-albums-artists branch June 28, 2026 14:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

scope: backend Rust/Tauri backend (src-tauri/) scope: docs Docs, README, assets scope: frontend React/Vite frontend (src/) scope: i18n Translations (src/i18n/) size: xl > 500 lines type: feat New feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

topbar search only surfaces tracks — albums and artists are unreachable

1 participant