Recherche partout — chantier 2+3 : mise en page + UX + onglets (fusion #68, suite de validation)
Branche recherche-onglets-ux-68 → main. Ne pas merger sans le go du coordinateur ; aucune version bumpée, aucune issue ouverte/fermée par cette PR. Référence de validation : issue Projets/fusion-trois-apps #68 (son état n'est pas changé par cette PR).
Ce qui est corrigé, point par point
Mise en page TikTak : cause trouvée — recherche.html étend base.html sans layout_class, donc .rp-page (enfant direct de .layout) tombait en auto-placement dans la 2e colonne de la grille (largeur sidebar), d'où l'étroite colonne à gauche. Correctif dans recherche.css seul, gardé par l'ancêtre .layout (TikTak seul) : .layout > .rp-page { grid-column: 2 / -1; max-width: none; } — la page occupe toute la largeur disponible juste à droite du rail d'icônes, sans toucher aux autres pages (elles ne portent pas .rp-page) ; en mobile (≤760 px) elle prend la colonne unique.
Mise en page ObsiGate : voir le paragraphe propre à ObsiGate ci-dessous.
Focus automatique : l'attribut autofocus seul ne survivait pas au chargement des surcouches (barre, palette, app). La page appelle désormais focus() explicitement en fin d'init, plus un rappel requestAnimationFrame/setTimeout et un rappel pageshow ; cliquer la barre « Rechercher partout » (data-act="palette") alors qu'on est déjà sur la page replace le curseur dans la boîte (et sélectionne le texte) au lieu de recharger ; / et Ctrl+K / ⌘K inchangés.
« Tout voir » : ne quitte plus la page. Le clic bascule vers l'onglet de l'application (son href reste une URL partageable ?q=&tab= au cas où le JS ne tournerait pas) ; dans l'onglet propre à l'app, le lien est masqué (redondant).
Onglets : Tout, ObsiGate, Flowdeck, TikTak, Kanbante, Console Spark — mêmes onglets, mêmes compteurs sur les 4 hôtes. « Tout » = les 4 sections groupées, chaque liste tronquée à 8 ; un onglet app = tous les résultats de cette app (requête ObsiGate en limit=100, les autres API renvoient leur jeu complet, aucune troncature côté client). L'onglet actif vit dans l'URL (?tab=, absent = Tout) : partageable, et le retour arrière navigateur le restaure (popstate). Clavier : ←/→, Début/Fin entre onglets ; ↑/↓ puis Entrée sur les résultats visibles conservés (les liens des sections masquées sont exclus de la navigation).
Compteurs et états : chaque onglet affiche le TOTAL de son application (pas le nombre tronqué de « Tout »), « … » pendant le chargement, « 0 » pour un vide honnête, rien pour une section en erreur (pas de faux 0). « Tout » affiche « … » tant qu'une section charge, sinon la somme des totaux connus. Une section injoignable ne casse pas les autres (état par section, comme en #68) ; le correctif CORS lui-même est chez un autre travailleur et n'est pas touché ici (aucun fichier CORS/middleware, aucune ligne d'onglets de la barre modifiée).
Console Spark : AUCUN endpoint de recherche console n'est mergé à ce jour (agent-commun : seule la PR #12 est ouverte, autre programme — ce dépôt n'est pas touché ici, et l'endpoint n'est pas réimplémenté ici). Le code tente l'appel conventionnel GET {base-console}/api/search?q= (même convention que les autres hôtes ; chemin À CONFIRMER avec le travailleur console dès que son endpoint atterrit) et, en cas d'échec, de HTTP non-OK ou de format non reconnu, affiche honnêtement « Console Spark : recherche indisponible pour l'instant » — jamais de faux résultats, jamais de faux 0. La base console vient de data-base-console rendu par l'hôte, sinon de window.DRACO_URLS.agent / window.DRACO_AGENT_URL, sinon de la dérivation -dev, sinon du href d'un onglet de barre console/spark, sinon du défaut prod agent.dracodev.net. L'onglet console n'est interrogé que lorsqu'il est affiché ; « Tout » ne le contient pas, pour ne pas polluer la vue groupée d'un message d'indisponibilité.
Fichiers
Page de recherche de l'hôte (gabarit + onglets + section console), recherche.js et recherche.css vendangés à l'identique sur les 4 hôtes, tests de logique pure étendus. Aucun autre fichier touché.
Tests (chiffres réels, pas de déployé, pas de capture)
Tests de logique pure : TikTak/Kanbante/Flowdeck node tests/recherche.test.js → 59 assertions OK chacun ; ObsiGate node tests/frontend/recherche.test.mjs → 42 assertions OK. Nouveautés couvertes : parseTab, visibleKeys (Tout = 4 sections, sans console), troncature 8 vs complet, compteurs (…/total/0/vide), buildSearchUrl, searchPath/normalize complets, normalizeConsole (URL absolue/relative conservée, sans URL = pas de faux lien, format inconnu = non reconnu), resolveConsoleBase (explicite > injecté > -dev > href barre > prod). Suites existantes sans régression (les assertions #68 d'origine passent toutes).
Harnais DOM local (hors PR, fait tourner le vrai recherche.js avec un fetch factice : ObsiGate 12 résultats, Flowdeck 3, TikTak vide, Kanbante en erreur, console en erreur) → 23 assertions OK : focus au chargement, « Tout » = 8 liens affichés pour ObsiGate avec compteur 12, compteurs 12/3/0/vide, « Tout » = 15, section Kanbante en erreur sans casser la page, « Tout voir » ObsiGate → onglet avec les 12 résultats + URL ?q=test&tab=obsigate + focus onglet, flèche droite → Flowdeck, console = message indisponible et compteur vide, popstate restaure requête + onglet, clic palette → focus + sélection, Entrée → premier résultat visible.
Écarts préexistants nommés : aucun écart nouveau constaté dans les fichiers touchés ; les validations déployées ci-dessous restent à faire par Bruno après merge/publication (aucun test déployé, aucune capture dans cette PR).
À valider en direct par Bruno après merge/publication
Mise en page TikTak (pleine largeur à droite du rail, mobile compris) ; mise en page ObsiGate (voir paragraphe ObsiGate) ; focus (clic barre, ⌘K, /, rechargement) ; « Tout voir » (reste sur la page, bascule d'onglet) ; onglets + URL (partage ?tab=, retour arrière) ; compteurs (totaux, …, 0, section en erreur) ; onglet Console Spark (indisponible honnête tant que l'endpoint console n'est pas mergé, puis résultats réels après confirmation du chemin avec l'autre travailleur).
Paragraphe propre à ObsiGate
Mise en page (point 2) : la page n'est plus nue. La route /recherche reste servie hors SPA (avant le catch-all, comme /admin.html — backend/main.py n'est PAS touché ici), mais recherche.html reprend désormais le gabarit de l'app : feuilles /static/style.css + /static/draco-barre.css, en-tête de fusion copié statiquement depuis index.html (snippet figé commons v0.1.6, onglets = liens réels via jetons {{URL_*}}, bouton central = focus dans la boîte), en-tête ObsiGate simplifié, sidebar statique (Tableau de bord, Rechercher partout) dans les classes de l'app (.app-container, .header, .main-body, .sidebar, .content-wrapper, .content-area), et navigation .rp-og-nav dans recherche.css. Base console : window.DRACO_URLS.agent, déjà injecté par la route (aucun jeton ajouté, aucun fichier serveur touché).
Deltas explicites à valider en direct : (a) la sidebar est statique — les vaults, tags et récents dynamiques restent dans la SPA (une intégration dans le routeur SPA aurait exigé de toucher index.html/app.js, hors périmètre de ce correctif) ; (b) les menus, le panneau Spark, les alertes et le domaine de la barre copiée ne sont pas rejoués sur cette page autonome — l'autre travailleur (onglet Console Spark de la barre) devra reporter son ajout dans cette copie au re-vendoring, comme pour tout hôte ; (c) style.css importe les polices Google Fonts, que la CSP stricte de /recherche (style-src 'self') bloque : la page retombe sur les polices système (repli typographique, pas de page cassée) — élargir la CSP serait une décision séparée, non prise ici. Fichiers : frontend/recherche.html, frontend/js/recherche.js, frontend/recherche.css, tests/frontend/recherche.test.mjs.
## Recherche partout — chantier 2+3 : mise en page + UX + onglets (fusion #68, suite de validation)
Branche `recherche-onglets-ux-68` → `main`. Ne pas merger sans le go du coordinateur ; aucune version bumpée, aucune issue ouverte/fermée par cette PR. Référence de validation : issue Projets/fusion-trois-apps #68 (son état n'est pas changé par cette PR).
### Ce qui est corrigé, point par point
1. Mise en page TikTak : cause trouvée — `recherche.html` étend `base.html` sans `layout_class`, donc `.rp-page` (enfant direct de `.layout`) tombait en auto-placement dans la 2e colonne de la grille (largeur sidebar), d'où l'étroite colonne à gauche. Correctif dans `recherche.css` seul, gardé par l'ancêtre `.layout` (TikTak seul) : `.layout > .rp-page { grid-column: 2 / -1; max-width: none; }` — la page occupe toute la largeur disponible juste à droite du rail d'icônes, sans toucher aux autres pages (elles ne portent pas `.rp-page`) ; en mobile (≤760 px) elle prend la colonne unique.
2. Mise en page ObsiGate : voir le paragraphe propre à ObsiGate ci-dessous.
3. Focus automatique : l'attribut `autofocus` seul ne survivait pas au chargement des surcouches (barre, palette, app). La page appelle désormais `focus()` explicitement en fin d'init, plus un rappel `requestAnimationFrame`/`setTimeout` et un rappel `pageshow` ; cliquer la barre « Rechercher partout » (`data-act="palette"`) alors qu'on est déjà sur la page replace le curseur dans la boîte (et sélectionne le texte) au lieu de recharger ; `/` et Ctrl+K / ⌘K inchangés.
4. « Tout voir » : ne quitte plus la page. Le clic bascule vers l'onglet de l'application (son `href` reste une URL partageable `?q=&tab=` au cas où le JS ne tournerait pas) ; dans l'onglet propre à l'app, le lien est masqué (redondant).
5. Onglets : Tout, ObsiGate, Flowdeck, TikTak, Kanbante, Console Spark — mêmes onglets, mêmes compteurs sur les 4 hôtes. « Tout » = les 4 sections groupées, chaque liste tronquée à 8 ; un onglet app = tous les résultats de cette app (requête ObsiGate en `limit=100`, les autres API renvoient leur jeu complet, aucune troncature côté client). L'onglet actif vit dans l'URL (`?tab=`, absent = Tout) : partageable, et le retour arrière navigateur le restaure (`popstate`). Clavier : ←/→, Début/Fin entre onglets ; ↑/↓ puis Entrée sur les résultats visibles conservés (les liens des sections masquées sont exclus de la navigation).
6. Compteurs et états : chaque onglet affiche le TOTAL de son application (pas le nombre tronqué de « Tout »), « … » pendant le chargement, « 0 » pour un vide honnête, rien pour une section en erreur (pas de faux 0). « Tout » affiche « … » tant qu'une section charge, sinon la somme des totaux connus. Une section injoignable ne casse pas les autres (état par section, comme en #68) ; le correctif CORS lui-même est chez un autre travailleur et n'est pas touché ici (aucun fichier CORS/middleware, aucune ligne d'onglets de la barre modifiée).
7. Console Spark : AUCUN endpoint de recherche console n'est mergé à ce jour (agent-commun : seule la PR #12 est ouverte, autre programme — ce dépôt n'est pas touché ici, et l'endpoint n'est pas réimplémenté ici). Le code tente l'appel conventionnel `GET {base-console}/api/search?q=` (même convention que les autres hôtes ; chemin À CONFIRMER avec le travailleur console dès que son endpoint atterrit) et, en cas d'échec, de HTTP non-OK ou de format non reconnu, affiche honnêtement « Console Spark : recherche indisponible pour l'instant » — jamais de faux résultats, jamais de faux 0. La base console vient de `data-base-console` rendu par l'hôte, sinon de `window.DRACO_URLS.agent` / `window.DRACO_AGENT_URL`, sinon de la dérivation -dev, sinon du href d'un onglet de barre console/spark, sinon du défaut prod `agent.dracodev.net`. L'onglet console n'est interrogé que lorsqu'il est affiché ; « Tout » ne le contient pas, pour ne pas polluer la vue groupée d'un message d'indisponibilité.
### Fichiers
- Page de recherche de l'hôte (gabarit + onglets + section console), `recherche.js` et `recherche.css` vendangés à l'identique sur les 4 hôtes, tests de logique pure étendus. Aucun autre fichier touché.
### Tests (chiffres réels, pas de déployé, pas de capture)
- Tests de logique pure : TikTak/Kanbante/Flowdeck `node tests/recherche.test.js` → 59 assertions OK chacun ; ObsiGate `node tests/frontend/recherche.test.mjs` → 42 assertions OK. Nouveautés couvertes : `parseTab`, `visibleKeys` (Tout = 4 sections, sans console), troncature 8 vs complet, compteurs (`…`/total/`0`/vide), `buildSearchUrl`, `searchPath`/`normalize` complets, `normalizeConsole` (URL absolue/relative conservée, sans URL = pas de faux lien, format inconnu = non reconnu), `resolveConsoleBase` (explicite > injecté > -dev > href barre > prod). Suites existantes sans régression (les assertions #68 d'origine passent toutes).
- Harnais DOM local (hors PR, fait tourner le vrai `recherche.js` avec un `fetch` factice : ObsiGate 12 résultats, Flowdeck 3, TikTak vide, Kanbante en erreur, console en erreur) → 23 assertions OK : focus au chargement, « Tout » = 8 liens affichés pour ObsiGate avec compteur 12, compteurs 12/3/0/vide, « Tout » = 15, section Kanbante en erreur sans casser la page, « Tout voir » ObsiGate → onglet avec les 12 résultats + URL `?q=test&tab=obsigate` + focus onglet, flèche droite → Flowdeck, console = message indisponible et compteur vide, `popstate` restaure requête + onglet, clic palette → focus + sélection, Entrée → premier résultat visible.
- Écarts préexistants nommés : aucun écart nouveau constaté dans les fichiers touchés ; les validations déployées ci-dessous restent à faire par Bruno après merge/publication (aucun test déployé, aucune capture dans cette PR).
### À valider en direct par Bruno après merge/publication
Mise en page TikTak (pleine largeur à droite du rail, mobile compris) ; mise en page ObsiGate (voir paragraphe ObsiGate) ; focus (clic barre, ⌘K, `/`, rechargement) ; « Tout voir » (reste sur la page, bascule d'onglet) ; onglets + URL (partage `?tab=`, retour arrière) ; compteurs (totaux, `…`, `0`, section en erreur) ; onglet Console Spark (indisponible honnête tant que l'endpoint console n'est pas mergé, puis résultats réels après confirmation du chemin avec l'autre travailleur).
### Paragraphe propre à ObsiGate
Mise en page (point 2) : la page n'est plus nue. La route `/recherche` reste servie hors SPA (avant le catch-all, comme `/admin.html` — `backend/main.py` n'est PAS touché ici), mais `recherche.html` reprend désormais le gabarit de l'app : feuilles `/static/style.css` + `/static/draco-barre.css`, en-tête de fusion copié statiquement depuis `index.html` (snippet figé commons v0.1.6, onglets = liens réels via jetons `{{URL_*}}`, bouton central = focus dans la boîte), en-tête ObsiGate simplifié, sidebar statique (Tableau de bord, Rechercher partout) dans les classes de l'app (`.app-container`, `.header`, `.main-body`, `.sidebar`, `.content-wrapper`, `.content-area`), et navigation `.rp-og-nav` dans `recherche.css`. Base console : `window.DRACO_URLS.agent`, déjà injecté par la route (aucun jeton ajouté, aucun fichier serveur touché).
Deltas explicites à valider en direct : (a) la sidebar est statique — les vaults, tags et récents dynamiques restent dans la SPA (une intégration dans le routeur SPA aurait exigé de toucher `index.html`/`app.js`, hors périmètre de ce correctif) ; (b) les menus, le panneau Spark, les alertes et le domaine de la barre copiée ne sont pas rejoués sur cette page autonome — l'autre travailleur (onglet Console Spark de la barre) devra reporter son ajout dans cette copie au re-vendoring, comme pour tout hôte ; (c) `style.css` importe les polices Google Fonts, que la CSP stricte de `/recherche` (`style-src 'self'`) bloque : la page retombe sur les polices système (repli typographique, pas de page cassée) — élargir la CSP serait une décision séparée, non prise ici. Fichiers : `frontend/recherche.html`, `frontend/js/recherche.js`, `frontend/recherche.css`, `tests/frontend/recherche.test.mjs`.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Recherche partout — chantier 2+3 : mise en page + UX + onglets (fusion #68, suite de validation)
Branche
recherche-onglets-ux-68→main. Ne pas merger sans le go du coordinateur ; aucune version bumpée, aucune issue ouverte/fermée par cette PR. Référence de validation : issue Projets/fusion-trois-apps #68 (son état n'est pas changé par cette PR).Ce qui est corrigé, point par point
recherche.htmlétendbase.htmlsanslayout_class, donc.rp-page(enfant direct de.layout) tombait en auto-placement dans la 2e colonne de la grille (largeur sidebar), d'où l'étroite colonne à gauche. Correctif dansrecherche.cssseul, gardé par l'ancêtre.layout(TikTak seul) :.layout > .rp-page { grid-column: 2 / -1; max-width: none; }— la page occupe toute la largeur disponible juste à droite du rail d'icônes, sans toucher aux autres pages (elles ne portent pas.rp-page) ; en mobile (≤760 px) elle prend la colonne unique.autofocusseul ne survivait pas au chargement des surcouches (barre, palette, app). La page appelle désormaisfocus()explicitement en fin d'init, plus un rappelrequestAnimationFrame/setTimeoutet un rappelpageshow; cliquer la barre « Rechercher partout » (data-act="palette") alors qu'on est déjà sur la page replace le curseur dans la boîte (et sélectionne le texte) au lieu de recharger ;/et Ctrl+K / ⌘K inchangés.hrefreste une URL partageable?q=&tab=au cas où le JS ne tournerait pas) ; dans l'onglet propre à l'app, le lien est masqué (redondant).limit=100, les autres API renvoient leur jeu complet, aucune troncature côté client). L'onglet actif vit dans l'URL (?tab=, absent = Tout) : partageable, et le retour arrière navigateur le restaure (popstate). Clavier : ←/→, Début/Fin entre onglets ; ↑/↓ puis Entrée sur les résultats visibles conservés (les liens des sections masquées sont exclus de la navigation).GET {base-console}/api/search?q=(même convention que les autres hôtes ; chemin À CONFIRMER avec le travailleur console dès que son endpoint atterrit) et, en cas d'échec, de HTTP non-OK ou de format non reconnu, affiche honnêtement « Console Spark : recherche indisponible pour l'instant » — jamais de faux résultats, jamais de faux 0. La base console vient dedata-base-consolerendu par l'hôte, sinon dewindow.DRACO_URLS.agent/window.DRACO_AGENT_URL, sinon de la dérivation -dev, sinon du href d'un onglet de barre console/spark, sinon du défaut prodagent.dracodev.net. L'onglet console n'est interrogé que lorsqu'il est affiché ; « Tout » ne le contient pas, pour ne pas polluer la vue groupée d'un message d'indisponibilité.Fichiers
recherche.jsetrecherche.cssvendangés à l'identique sur les 4 hôtes, tests de logique pure étendus. Aucun autre fichier touché.Tests (chiffres réels, pas de déployé, pas de capture)
node tests/recherche.test.js→ 59 assertions OK chacun ; ObsiGatenode tests/frontend/recherche.test.mjs→ 42 assertions OK. Nouveautés couvertes :parseTab,visibleKeys(Tout = 4 sections, sans console), troncature 8 vs complet, compteurs (…/total/0/vide),buildSearchUrl,searchPath/normalizecomplets,normalizeConsole(URL absolue/relative conservée, sans URL = pas de faux lien, format inconnu = non reconnu),resolveConsoleBase(explicite > injecté > -dev > href barre > prod). Suites existantes sans régression (les assertions #68 d'origine passent toutes).recherche.jsavec unfetchfactice : ObsiGate 12 résultats, Flowdeck 3, TikTak vide, Kanbante en erreur, console en erreur) → 23 assertions OK : focus au chargement, « Tout » = 8 liens affichés pour ObsiGate avec compteur 12, compteurs 12/3/0/vide, « Tout » = 15, section Kanbante en erreur sans casser la page, « Tout voir » ObsiGate → onglet avec les 12 résultats + URL?q=test&tab=obsigate+ focus onglet, flèche droite → Flowdeck, console = message indisponible et compteur vide,popstaterestaure requête + onglet, clic palette → focus + sélection, Entrée → premier résultat visible.À valider en direct par Bruno après merge/publication
Mise en page TikTak (pleine largeur à droite du rail, mobile compris) ; mise en page ObsiGate (voir paragraphe ObsiGate) ; focus (clic barre, ⌘K,
/, rechargement) ; « Tout voir » (reste sur la page, bascule d'onglet) ; onglets + URL (partage?tab=, retour arrière) ; compteurs (totaux,…,0, section en erreur) ; onglet Console Spark (indisponible honnête tant que l'endpoint console n'est pas mergé, puis résultats réels après confirmation du chemin avec l'autre travailleur).Paragraphe propre à ObsiGate
Mise en page (point 2) : la page n'est plus nue. La route
/recherchereste servie hors SPA (avant le catch-all, comme/admin.html—backend/main.pyn'est PAS touché ici), maisrecherche.htmlreprend désormais le gabarit de l'app : feuilles/static/style.css+/static/draco-barre.css, en-tête de fusion copié statiquement depuisindex.html(snippet figé commons v0.1.6, onglets = liens réels via jetons{{URL_*}}, bouton central = focus dans la boîte), en-tête ObsiGate simplifié, sidebar statique (Tableau de bord, Rechercher partout) dans les classes de l'app (.app-container,.header,.main-body,.sidebar,.content-wrapper,.content-area), et navigation.rp-og-navdansrecherche.css. Base console :window.DRACO_URLS.agent, déjà injecté par la route (aucun jeton ajouté, aucun fichier serveur touché).Deltas explicites à valider en direct : (a) la sidebar est statique — les vaults, tags et récents dynamiques restent dans la SPA (une intégration dans le routeur SPA aurait exigé de toucher
index.html/app.js, hors périmètre de ce correctif) ; (b) les menus, le panneau Spark, les alertes et le domaine de la barre copiée ne sont pas rejoués sur cette page autonome — l'autre travailleur (onglet Console Spark de la barre) devra reporter son ajout dans cette copie au re-vendoring, comme pour tout hôte ; (c)style.cssimporte les polices Google Fonts, que la CSP stricte de/recherche(style-src 'self') bloque : la page retombe sur les polices système (repli typographique, pas de page cassée) — élargir la CSP serait une décision séparée, non prise ici. Fichiers :frontend/recherche.html,frontend/js/recherche.js,frontend/recherche.css,tests/frontend/recherche.test.mjs.