feat(rapports) : repli/depliage a chaque niveau de la hierarchie (socle + 3 rapports) #288
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#288
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
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?
Refs:
spec-decisions-collapse-multi-niveaux.md+spec-plan-collapse-multi-niveaux.md(plan v2, revu par /review-spec)Contexte
Le repli des categories (#254, #265) ne permet de replier que le premier niveau. La taxonomie standard a trois niveaux : 11 racines, 41 categories intermediaires, 98 feuilles. Ces 41 intermediaires portent deja sous-total, style et indentation — mais aucun chevron.
Comportement cible
Algorithme : visibilite par remontee d'ancetres (PAS par adjacence)
Ce choix resout d'un coup : (1) l'ordre par niveau de la grille Budget, (2) le tri par type qui peut placer un enfant dans une autre section que son parent, (3) la feuille « (direct) » (masquee par construction), (4) la contrainte visible()-avant-reorderRows (disparait).
Travail a faire
src/utils/collapsibleRows.ts— reecrirevisibleRowsen remontee d'ancetres ; ajouterparentKeyOfaCollapseAccessors;collapsibleKeysretourne tous les parents ;keyOfprefixep:<id>(le rend injectif — aujourd'hui un sous-total parent et sa feuille « (direct) » partagentString(categoryId)).src/utils/collapsibleRows.test.ts— reecrire (les tests actuels verrouillent le mono-niveau : l.53-63, l.70-73, l.82-84).src/hooks/useCollapsibleGroups.ts— persister dansuser_preferences(viagetPreference/setPreference, async) au lieu delocalStorage;storageKey: string | null(null = pas de persistance) ;options.defaultExpanded(defaut false) ; semantique « Set = ecarts au defaut » ;collapseAll(rows). Ne PAS appeleruseProfile()(throw hors provider ; la cle user_preferences est deja scopee par profil).const collapsed = isTopParent && groups.isCollapsed(row)->isParent && …(ComparePeriodTable.tsx:157, BudgetVsActualTable.tsx:119, CategoryOverTimeTable.tsx:96). Sans ca, tout parent intermediaire aurait un chevron perpetuellement ouvert +aria-expanded={true}mensonger.isTopParent ? <button> : <span>->isParent ? …(ComparePeriodTable.tsx:184, BudgetVsActualTable.tsx:140, CategoryOverTimeTable.tsx:123).parentKeyOfdans les 3 jeux d'accesseurs (COMPARE_:64, BVA_:35, OVERTIME_* dans overTimeTableModel.ts:18).aria-level={depth + 1}sur les lignes parentes.src/components/reports/overTimeTableModel.test.ts— ETENDRE la fixture a 3 niveaux (racine > parent intermediaire > feuilles) + assertions de cascade. (La fixture actuelle l.57-68 n'a que 2 niveaux : ses tests passent identiquement sous le nouvel algo — « mettre a jour » n'avait pas de cible.)src/components/reports/CategoryTable.tsx(74 lignes, 0 import).Fichiers concernes
src/utils/collapsibleRows.ts(+.test.ts)src/hooks/useCollapsibleGroups.tssrc/services/userPreferenceService.ts(lu —getPreference/setPreferenceinchanges)src/components/reports/{ComparePeriodTable,BudgetVsActualTable,CategoryOverTimeTable}.tsxsrc/components/reports/overTimeTableModel.ts(+.test.ts)src/components/reports/CategoryTable.tsx(supprime)src/i18n/locales/{fr,en}.json,CHANGELOG.md,CHANGELOG.fr.mdTests (repo SANS jsdom/testing-library — logique en modules purs)
collapsibleRows.test.ts, reecrit :parent_idcyclique : garde MAX_TREE_DEPTH, pas de bouclecollapsibleKeysliste tous les parentsExtraire la polarite en helper pur
isCollapsedFor(flipped, key, defaultExpanded)(le hook n'est pas testable).Review caveats
depthoptionnel avec fallbacks derives (row.depth ?? (…?1:0)) : neutralise (depth ne pilote plus la visibilite, seulement indentation + aria-level). Une valeur fausse degrade l'affichage, ne masque plus.keyOfnon injectif : corrige par le prefixep:— le gardeisParentredevient cosmetique.Decisions prises en planification
user_preferences(base du profil) et nonlocalStorage: zero residu apres suppression de profil (deleteProfile ne purge aucun localStorage) — exigence privacy-first.Criteres d'acceptation
aria-expanded={false}user_preferences(isole par profil, detruit avec lui)aria-levelSpec source
spec-plan-collapse-multi-niveaux.md (v2)