feat(onboarding): getting-started banner on top of every page #403
No reviewers
Labels
No labels
autopilot:pending-human
source:analyste
source:defenseur
source:human
source:medic
status:approved
status:blocked
status:in-progress
status:needs-clarification
status:needs-fix
status:ready
status:review
status:triage
type:bug
type:feature
type:infra
type:refactor
type:schema
type:security
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: maximus/Simpl-Resultat#403
Loading…
Reference in a new issue
No description provided.
Delete branch "issue-397-onboarding-banner"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Resolves #397
Generated autonomously by /autopilot run of 2026-10-08
Ce qui change pour l'utilisateur
CARD_PAGESest encore vide, il reste aussi sur /import, /transactions et /budget.Technique
src/components/onboarding/OnboardingBanner.tsx(nouveau), piloté par props :mode,checklist,nextStep,budgetReady,listOpen,onToggleList,onHide,onResume. Il ne rend rien hors des modesbanneretcomplete. Le bouton de la liste portearia-expandedet unaria-controlsvers un conteneur toujours rendu.AppShell:OnboardingBannerSlotlituseOnboarding()et tient l'état déplié. AppShell le monte avant<Outlet/>, dans le fournisseur, aveckey={pathname}: chaque page commence repliée.onboardingPath.ts:stepNavState(key)rend{ onboarding: { focus: true } }, avecguided: trueen plus pourmanualCategory. Il sert à tout lien vers une étape : le bandeau, les lignes de la liste et « Reprendre ».OnboardingChecklist:compactet la propmodesont retirés ;skipped, avec cette priorité : en attente, verrouillée, faite, passée, à faire ;sr-onlyaprès le libellé ;<Link onClick={() => onResume(key)}>(react-router appelleonClickavant de naviguer) ;onResumeest requise.DashboardEmptyStatetransmetonResumeà sa liste (la propmodedisparaît). Son rendu ne change pas, et un test l'épingle.DashboardPage: la barre compacte est retirée.UsersSettingsPage:hiddenetshowdansuseOnboarding(), sansgetPreferencenishowChecklistdirects ;restoredsert à la confirmation.onboarding.banner.*,onboarding.state.*,onboarding.checklist.skippedBadgeet.resume, ainsi quesettings.users.onboarding.labelet.confirmation.docs/architecture.md: les lignes que ce changement rend fausses (compte de composants, dossieronboarding/, mode compact, réaffichage), comme #396.Preuves
npm run buildvert.npx vitest run: 1680 → 1727 tests (89 → 94 fichiers), tous verts.OnboardingBanner.render.test.tsx(13) ;AppShell.render.test.tsx(12) : vrai rendu d'AppShell, avec le mode dérivé parderiveOnboardingViewet le vraiCARD_PAGES;AppShell.slot.test.tsx(5) ;UsersSettingsPage.test.tsx(6) :useStatesimulé, donc le même état d'un rendu à l'autre, sans remontage ;DashboardEmptyState.render.test.tsx(3) ;OnboardingChecklist.test.tsx: 3 tests du mode compact retirés, 8 ajoutés ;DashboardPage.render.test.tsxadapté (+1) ;onboardingPath.test.ts(+2).git checkout: 8/8 rouges.cardmode="banner"en dur (parcours masqué, tableau de bord vide, carte)budgetReadyaria-expandedfigé àfalseresumehiddenkey={pathname}sur l'emplacement du bandeauAvant : 1727 verts. Après restauration : 1727 verts, arbre propre.
Décisions
Seize décisions, toutes consignées dans le journal du run. Les principales :
stepNavState). L'entrée guidée de l'étape 5 s'applique donc aussi depuis la liste. Écarté : le focus seul dans la liste.onClick, sans attendre l'écriture : le reducer règle les deux ordres de RESUME et de la relecture. Écarté :useNavigateaprèsawait, qui ajouterait un hook de routeur à un composant pur.aria-hidden: le texte masqué l'annonce déjà.DashboardEmptyStateinchangé » est lu comme « la carte garde sa liste détaillée » : la carte ne fait que passer des props, et son rendu est épinglé par un test.key={pathname}). Écartés : un état qui suit l'utilisateur de page en page, et une liste qui se rouvre en revenant sur sa page.settings.users.onboarding.showreste tel quel : il est absent de la table de textes de l'issue.docs/guide-utilisateur.mdl. 86 et 581, et les clésdocs.*) décrit encore la barre compacte : laissé à #401, comme le prévoit le plan.Pour relire
OnboardingBanner.tsx, puisAppShell.tsx(emplacement et clé de route), puisOnboardingChecklist.tsx.DashboardEmptyStateinchangé » (proponResumetransmise) ;🤖 Generated with Claude Code
Auto-revue /autopilot — verdict : APPROVE
Revue du diff de ce seul maillon (20 fichiers, base
issue-396-onboarding-shared-state), critère par critère de #397.Critères d'acceptation
OnboardingBanner, tests de rendu (OnboardingBanner.render.test.tsx, 13 tests) :nextStep.toavec son état,guidedcompris pour l'étape 5 ;aria-expandedselon la liste ;/settings/users#gettingStarted) et « Fermer » ;none, ni en modecard.AppShell.render.test.tsx). Le test fait un vrai rendu d'AppShell, et le mode y est dérivé parderiveOnboardingViewavec le vraiCARD_PAGES:compact:modeest retirée, ainsi que les 3 tests du mode compact ;DashboardEmptyStategarde le même rendu, épinglé par un test ; seule la proponResumey passe désormais (décision MEDIUM).OnboardingChecklist:sr-only) ;aria-hidden) et « Reprendre », qui appelleresume(key)puis navigue avec l'état de focus.UsersSettingsPage:hiddenetshowviennent du contexte. Le bouton de réaffichage apparaît sans remontage : l'état est conservé d'un rendu à l'autre, et seule la valeur deuseOnboarding()change.npm run buildetnpx vitest runverts (1680 → 1727).Mises en garde de l'issue et décisions de planification
CARD_PAGESn'est pas touché, donc le bandeau reste sur toute page sans carte.getPreferencenishowChecklist.Conventions
stepNavStatevit dansutils/.OnboardingChecklistModeet le marqueurdata-modedes tests sont retirés.Constats non bloquants
key={pathname}). En contrepartie, le focus d'un lien du bandeau retombe sur la page à la navigation.useStatesimulé est dupliqué entreAppShell.slot.test.tsxetUsersSettingsPage.test.tsx.docs/guide-utilisateur.md, lignes 86 et 581, et les clésdocs.*) décrit encore la barre compacte : à reprendre dans #401.CI
check-frontend, run 501 sur46e7142: vert. Le journal du job montre le build (tscpuisvite build) etvitest runà 94 fichiers et 1727 tests, tous verts.check-rustne se déclenche pas : aucun changement Rust.Revue adversariale — verdict : APPROVE
Revue indépendante du seul maillon #403 (base
issue-396-onboarding-shared-state, tête46e7142), après l'auto-revue du worker.Résumé : le bandeau, son montage dans
AppShell, le retrait de la barre compacte, les états annoncés de la liste et la lecture de l'état partagé par Paramètres → Utilisateurs font ce que demande #397, critère par critère. Aucun défaut bloquant ; les douze mutations du relecteur rougissent toutes.Exécuté
/tmp,npm ci), tête46e7142:npm run buildvert (tsc + vite) ;npx vitest run: 94 fichiers, 1727 tests verts.check-frontend) vert sur46e7142, log lu : build, 94 fichiers, 1727 tests.git checkout, arbre propre après chacune : 12/12 rouges.rowState: « passée » l'emporte sur « faite »stepNavStateposeguidedsur toutes les étapesrestoredau lieu dehidden<Outlet/>aria-controlsn'existe que dépliéechecklist === nulldu bandeau retiréeAprès restauration : 1727 verts, arbre propre.
Vérifié
CARD_PAGESest vide, donc le bandeau reste sur /import, /transactions et /budget, épinglé avec le vraiCARD_PAGES. La page Paramètres ne lit ni n'écrit plus la préférence elle-même.onboarding.checklist.hide,common.close) existent.sr-only(première utilisation dans le projet) est bien généré par Tailwind dans le CSS du build.onClickavant de naviguer (handleClick, lu dansnode_modules). Entre l'écriture deresumeet la relecture que lance la navigation, les deux ordres finissent sur la ligne reprise, grâce àskippedSetAt(#396).docs.dashboard.steps.1,docs.settings.features.8et.steps.7,guide-utilisateur.mdl. 86) n'existent plus surissue-401-onboarding-guide-qa(#407). Le report à #401 tient donc sur la pile complète ; seule une pile mergée jusqu'à #403 sans la suite livrerait un guide faux.pull_refclosesdepuis #403, et46e7142contientResolves #397. L'issue se fermera aussi par un merge en avance rapide. Les trois commits suivent le format conventionnel.Suggestions (non bloquantes)
<body>. Il en va de même après un lien du bandeau vers une page sans carte (« Ouvrir le guide », ligne Budget verrouillée), puisquekey={pathname}remonte le bandeau. L'ancienne barre compacte se comportait pareil, ce n'est donc pas une régression. À ajouter à la liste NVDA/Orca de #401, ou à une issue de suivi (focus sur<main>ou sur le titre de la page).OnboardingChecklist»). À juger en QA, avec au besoin une prop qui retire l'en-tête de la liste dans le bandeau.UsersSettingsPage.test.tsx) : son assertion ne peut pas rougir pour la régression réaliste, une lecture dans unuseEffect, puisqu'un effet ne tourne pas quand le composant est appelé comme une fonction. Mutation faite (unuseEffectqui appellegetPreference, remis dans la page) : 6/6 rouges, mais par « Invalid hook call », pas par cette assertion. La mise en garde de l'issue est donc gardée par accident. Une vérification sur la source (aucun import deuserPreferenceServiceni deONBOARDING_CHECKLIST_HIDDEN_KEYdans la page), ou un nom de test qui dit ce qu'il prouve, serait plus juste.guided: truedepuis la liste et « Reprendre » : pour les lignes, l'issue ne demande que « l'état de focus ». La PR étend l'entrée guidée de l'étape 5 à tout lien vers elle (décision MEDIUM consignée). C'est cohérent ; à confirmer par Max.Points à trancher du corps de la PR
DashboardEmptyStateinchangé » : d'accord. SansonResume, une ligne passée de la carte d'accueil naviguerait sans être reprise. Ce cas deviendra possible quand #398 ajoutera « Passer ».Actions faites
status:reviewàstatus:approved./tmp/pr403-*supprimés en fin de revue ; dépôt local intact.