feat(sidebar+assistant): filtre Recents/Sauvegardes (#99), pastille Deep Research (#100) et icone du bouton + (BUG-049)
CI / lint (push) Failing after 1m20s
CI / test (push) Skipped
CI / build (push) Skipped
CI / e2e (push) Skipped
CI / security (push) Successful in 59s

This commit is contained in:
2026-09-16 20:16:41 -04:00
parent 8f26a418a9
commit 4231f2e929
22 changed files with 491 additions and 80 deletions
+34 -1
View File
@@ -141,4 +141,37 @@ bien l'icône Lucide `plus` (vérifié par test JSDOM).
- `MAX_SESSIONS = 200` : le comportement de purge est testé (`TestAIGatewayHistoryStore`)
; la rétention configurable (item #95 du backlog) pourra s'appuyer sur ce plafond.
- Les modules web/Canva du panneau « + » sont volontairement désactivés tant que
l'écosystème d'outils phase 2 (#92) n'est pas livré.
l'écosystème d'outils phase 2 (#92) n'est pas livré.
## I. Complément — icône « + » et pastille Deep Research (BUG-049, #100) — ✅ livré
*(1) **BUG-049 — l'icône du bouton « + » n'était pas visible.*** Le SVG Lucide était
bien rendu, mais la règle générique `.bookslm-input-area button { padding: 8px 16px;
background: var(--accent); color:#fff }` l'emportait en **spécificité** sur
`.bookslm-btn-plus` (une classe seule). Le bouton conservait `width:32px` avec
`padding: 8px 16px` → **largeur de contenu = 0 px**, donc SVG à `width: 0px`
(invisible). Correctif CSS : sélecteur porté à
`.bookslm-input-area button.bookslm-btn-plus` (et `:hover`), qui reprend la main
(`padding:0`, fond transparent, couleur `--text-secondary`). Vérifié en navigateur
(Playwright) : `svgWidth` passe de `0px` à `18px`.
*(2) **#100 — Deep Research devient une pastille (comme les skills).*** Auparavant,
cliquer sur « Deep Research » injectait la directive de recherche dans la zone de
saisie. Désormais :
- `_startDeepResearch()` active le **mode Agent** (si nécessaire), positionne le drapeau
`_activeDeepResearch` et rend une **pastille** `.bookslm-chip-deep-research`
(`_renderAttachments()`), sans rien écrire dans le composeur.
- La pastille se retire via son « × » (comme les chips skills/fichiers) et remet le
drapeau à `false`.
- La directive (`bookslm.deep_research_prompt`) est injectée **au moment de l'envoi**
dans le `message` du payload (`_sendMessage()`), sans polluer le message affiché à
l'utilisateur.
- Message d'information mis à jour (`bookslm.deep_research_started`) : « Deep Research
activé — ajoutez votre question puis envoyez. »
### Tests du complément
- `tests/frontend/ai.test.mjs` (+1) : le clic sur « Deep Research » ajoute une pastille,
laisse le composeur vide, positionne le drapeau, et le retrait de la pastille remet
le drapeau à `false`.
- Vérification navigateur du bouton « + » (Playwright, instance de test).
+72
View File
@@ -0,0 +1,72 @@
# #99 — Barre de filtrage de la sidebar sur « Récents » et « Sauvegardes »
> **Statut :** ✅ livré · **Version :** 2.6.0 · **ID :** #99
> **Lié :** BUG-049 (icône du bouton « + » de l'assistant), #100 (pastille Deep Research).
## Contexte
La barre de recherche/filtrage de la sidebar (`#sidebar-filter-input`) agissait
historiquement sur les onglets **Fichiers** (arborescence) et **Tags**. L'onglet
**Historique IA** a reçu son propre filtrage en #98. Les onglets **Récents** et
**Sauvegardes** (« saved searches ») n'étaient pas couverts : taper dans la barre
n'avait aucun effet dans ces deux vues.
## A. Onglet « Récents » — ✅ livré
- Nouveau cache module `_recentQuery` et fonction exportée `filterRecentFiles(query)`
(`frontend/js/config.js`).
- `_applyRecentFilter(files)` filtre le cache `_recentFilesCache` sur **titre, chemin,
vault, aperçu et tags**, via `_sidebarNorm()` (normalisation `NFD` + suppression des
diacritiques + minuscules) — donc insensible à la casse **et** aux accents.
- `loadRecentFiles()` applique désormais le filtre courant après chaque chargement.
- Aucun résultat → un message `sidebar.no_results` est inséré dans `#recent-list`
(classe `.sidebar-filter-empty`, style existant).
- `switchSidebarTab("recent")` applique la requête courante et pose le placeholder
`sidebar.filter_recent`.
## B. Onglet « Sauvegardes » — ✅ livré
- Nouveau `_savedQuery` et fonction exportée `filterSavedSearches(query)`
(`frontend/js/viewer.js`).
- `_applySavedFilter()` combine désormais **le filtre de type** (pills Tous / Recherches
/ Répertoires) **et la requête texte** : un élément est visible si son `data-type`
correspond au pill **et** si son texte (requête, vault, chemins inclus/exclus) contient
la requête normalisée (`_savedNorm`).
- Aucun résultat avec une requête active → message `sidebar.no_results` ajouté à
`#saved-searches-list` (nettoyé à chaque ré-application pour ne pas s'accumuler).
- `switchSidebarTab("saved")` ré-applique la requête et pose le placeholder
`sidebar.filter_saved`.
## C. Routage unifié de la barre de filtrage — ✅ livré
`initSidebarFilter()` (`frontend/js/sidebar.js`) est refactorisé autour de deux
fonctions `routeFilter(q)` / `routeClear()` qui dirigent la saisie, la bascule
casse (`Aa`) et le bouton « × » vers le filtre de l'onglet actif :
| Onglet | Filtre |
|---|---|
| `vaults` | `performTreeSearch` / `restoreSidebarTree` |
| `recent` | `filterRecentFiles` |
| `saved` | `filterSavedSearches` |
| `ai` | `filterAIHistory` |
| `tags` | `filterTagCloud` |
## D. i18n — ✅ livré
- `sidebar.filter_recent` : « Filtrer les fichiers récents... » / "Filter recent files..."
- `sidebar.filter_saved` : « Filtrer les recherches sauvegardées... » / "Filter saved searches..."
- Le message d'absence de résultat réutilise `sidebar.no_results`.
## E. Tests — ✅ livré
- `tests/frontend/sidebar-filters.test.mjs` (nouveau, 8 tests) : rendu des listes,
filtrage par titre/casse, accents/tags, vault/chemin, restauration, message
d'absence de résultat, et combinaison pill + requête sur les sauvegardes.
- Ajouté à la liste explicite du job `lint` de `.gitea/workflows/ci.yml`.
## F. Points d'attention
- Le filtrage est **client-side** (les listes sont déjà chargées) : aucune requête
réseau supplémentaire n'est déclenchée par la frappe.
- Sur « Sauvegardes », le filtre de type et la requête sont **cumulatifs** ; vider la
barre (ou « × ») ne réinitialise pas le pill actif.