From 524fe162ea584b802cc000dc734ddc2429b75008 Mon Sep 17 00:00:00 2001 From: le king fu Date: Mon, 13 Jul 2026 20:32:58 -0400 Subject: [PATCH 1/2] chore: harden release skill (pre-flight and post-CI checks) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Lessons from the v0.13.0 release (session fdda84cb): - Step 0: revalidate the tip locally before tagging — check.yml never runs on main, and ensure .claude/worktrees/ is empty (vitest recurses) - Step 9: verify the published release — 7 expected artifacts and latest.json content (drives auto-update); status=success is not enough - Rule: tagging publishes externally via the updater JSON — confirm with Max before tagging Co-Authored-By: Claude Fable 5 --- .claude/skills/release/SKILL.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.claude/skills/release/SKILL.md b/.claude/skills/release/SKILL.md index e052ec2..2b1dddc 100644 --- a/.claude/skills/release/SKILL.md +++ b/.claude/skills/release/SKILL.md @@ -2,7 +2,7 @@ name: release description: Release a new version of Simpl-Resultat (bump, changelog, tag, push) user-invocable: true -updated: 2026-07-01 +updated: 2026-07-13 --- # /release — Release Simpl-Resultat @@ -15,6 +15,7 @@ updated: 2026-07-01 ## Workflow +0. **Pré-vol — revalider le tip localement.** `check.yml` ne tourne pas sur `main` : le tip mergé n'a jamais été vu par le CI (le dernier run vert portait sur la branche d'issue avant merge), et le tag grave ce tip exact dans des binaires distribués. Lancer `npm run build && npm test` (vitest) + `cd src-tauri && cargo check && cargo test`. Vérifier aussi que `.claude/worktrees/` est vide (worktrees leftover → vitest récurse et gonfle le compteur). Ne tagger que sur un tip vert. 1. Determiner la nouvelle version (argument utilisateur ou demander) 2. Bump version dans les 5 fichiers : - `src-tauri/Cargo.toml` (ligne `version = "..."`) @@ -37,6 +38,9 @@ updated: 2026-07-01 ``` 7. Push : `git push origin main && git push origin vX.Y.Z` 8. Forgejo CI build automatique (Windows + Linux) via `release.yml` sur `on: push: tags: v*` +9. **Post-CI — vérifier la release publiée.** Surveiller `release.yml` (outil `Monitor` sur le run), puis vérifier la release réellement attachée — `status=success` du workflow ne suffit pas : + - Les **7 artefacts** attendus : `.exe` NSIS, `.deb`, `.rpm`, leurs 3 signatures `.sig`, et `latest.json`. + - Le contenu de `latest.json` (il pilote l'auto-update des installations existantes) : champ `version` correct, signatures non vides pour les deux plateformes, URLs pointant vers les bons binaires, notes extraites du CHANGELOG. ## Regles @@ -45,7 +49,9 @@ updated: 2026-07-01 - Format Keep a Changelog : `## [X.Y.Z] - YYYY-MM-DD` - Les changelogs sont bundles dans `public/` pour l'affichage in-app - Tag **annote** (`-a`), pas lightweight : les artefacts CI reference le tag pour les release notes +- **Tagger publie vers l'extérieur** : `release.yml` pousse le JSON d'updater, donc les utilisateurs installés reçoivent la mise à jour automatiquement. Confirmer avec Max avant de tagger. ## Changelog - 2026-04-19 — Added Cargo.lock + package-lock.json to bump list, `npm install --package-lock-only` fallback when lockfile stale, explicit `[Unreleased]` migration pattern, annotated tags (#102/#112 release cycle) - 2026-07-01 — Documenter que le header FR est `## [Non publié]` (≠ `[Unreleased]`), pour éviter le faux diagnostic « changelog FR vide » lors de la migration. Source : session 5466da98. +- 2026-07-13 — Étape 0 (pré-vol) : revalider le tip localement avant de tagger — `check.yml` ne tourne pas sur `main`, le tip mergé n'a jamais été vu par le CI ; vérifier `.claude/worktrees/` vide (vitest récurse sinon). Étape 9 (post-CI) : vérifier la release publiée — 7 artefacts attendus + contenu de `latest.json` (pilote l'auto-update) ; `status=success` ne suffit pas. Règle : tagger publie vers l'extérieur (updater automatique) → confirmer avec Max avant de tagger. Source : session fdda84cb (release v0.13.0). -- 2.45.2 From 48adb3db772a7f31ffbf573c2ccc8cad5ffe7dc2 Mon Sep 17 00:00:00 2001 From: le king fu Date: Wed, 15 Jul 2026 20:58:18 -0400 Subject: [PATCH 2/2] feat(reports): collapse category hierarchy at every level (socle + 3 reports) Generalize the report category collapse from level-1-only to every hierarchy level, on the three hierarchical report tables (real-vs-real Compare, real-vs-budget Compare, Trends by category). Visibility is now decided by an ancestor walk, not by row adjacency, so it is independent of row order (the level-ordered budget grid emits a non-DFS order). - collapsibleRows: rewrite visibleRows as an ancestor walk (a row is hidden iff any ancestor is collapsed); add parentKeyOf + injective `p:` keys; collapsibleKeys returns all parents (any depth); extract the pure, tested isCollapsedFor polarity helper; MAX_TREE_DEPTH cycle guard. - useCollapsibleGroups: persist in user_preferences (per-profile, destroyed with the profile) instead of localStorage; storageKey nullable (no persistence); options.defaultExpanded; async hydration (no flash); collapseAll(rows). - 3 tables: fix BOTH gates (collapsed flag + button) isTopParent -> isParent, add parentKeyOf accessors, aria-level on parent rows. - Delete dead CategoryTable.tsx (0 imports). - Tests: rewrite collapsibleRows.test.ts (BFS==DFS masking, cycle guard, cross-section ancestor, "(direct)" leaf, polarity); extend overTimeTableModel fixture to 3 levels with cascade assertions. Collapse stays purely visual: subtotals and result lines are computed from raw rows, never from visible rows. Resolves #288 Generated autonomously by /autopilot run of 2026-07-15 Co-Authored-By: Claude Opus 4.8 (1M context) --- CHANGELOG.fr.md | 4 + CHANGELOG.md | 4 + .../reports/BudgetVsActualTable.tsx | 15 +- .../reports/CategoryOverTimeTable.tsx | 7 +- src/components/reports/CategoryTable.tsx | 74 ------ src/components/reports/ComparePeriodTable.tsx | 14 +- .../reports/overTimeTableModel.test.ts | 96 +++++-- src/components/reports/overTimeTableModel.ts | 7 +- src/hooks/useCollapsibleGroups.ts | 106 +++++--- src/utils/collapsibleRows.test.ts | 246 ++++++++++++++---- src/utils/collapsibleRows.ts | 111 +++++--- 11 files changed, 434 insertions(+), 250 deletions(-) delete mode 100644 src/components/reports/CategoryTable.tsx diff --git a/CHANGELOG.fr.md b/CHANGELOG.fr.md index 1a34346..7c0ae1c 100644 --- a/CHANGELOG.fr.md +++ b/CHANGELOG.fr.md @@ -2,6 +2,10 @@ ## [Non publié] +### Modifié + +- Rapports : les trois tableaux de rapport hiérarchiques (Comparaison réel-vs-réel, réel-vs-budget, et Tendances par catégorie) permettent désormais de **replier ou déplier chaque niveau de la hiérarchie de catégories**, plus seulement le premier. Chaque catégorie parente — y compris les intermédiaires — porte son propre chevron ; en déplier une révèle ses enfants directs (eux-mêmes repliés), pour descendre un niveau à la fois. Les tableaux s'ouvrent entièrement repliés (seules les catégories de premier niveau visibles), « Tout déplier » ouvre tous les niveaux d'un coup, et vos choix de repli sont désormais enregistrés **par profil** — dans la base de données du profil, donc détruits avec lui — au lieu du navigateur. Les sous-totaux et les lignes de résultat restent rigoureusement inchangés quel que soit ce que vous repliez (#288). + ## [0.13.0] - 2026-07-12 ### Ajouté diff --git a/CHANGELOG.md b/CHANGELOG.md index baa699f..9131ae0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Changed + +- Reports: the three hierarchical report tables (real-vs-real Compare, real-vs-budget Compare, and Trends by category) now let you **collapse or expand every level of the category hierarchy**, not just the top level. Every parent category — including the intermediate ones — carries its own chevron; expanding one reveals its direct children (themselves collapsed), so you drill down one level at a time. The tables open fully collapsed (only the top-level categories visible), "Expand all" opens every level at once, and your collapse choices are now saved **per profile** — in the profile's own database, so they are destroyed with the profile — instead of in the browser. Subtotals and result lines stay exactly the same whatever you fold away (#288). + ## [0.13.0] - 2026-07-12 ### Added diff --git a/src/components/reports/BudgetVsActualTable.tsx b/src/components/reports/BudgetVsActualTable.tsx index bd8f1b0..2257db5 100644 --- a/src/components/reports/BudgetVsActualTable.tsx +++ b/src/components/reports/BudgetVsActualTable.tsx @@ -29,11 +29,11 @@ interface BudgetVsActualTableProps { const STORAGE_KEY = "subtotals-position"; -// Collapse groups keyed by category id; depth mirrors the render logic below -// (a missing depth is derived from parent_id) so hidden rows are exactly a -// group's indented descendants. +// Collapse groups keyed by category id; a row is hidden when any ancestor +// (walking parent_id) is collapsed, so every parent level is collapsible. const BVA_COLLAPSE_ACCESSORS: CollapseAccessors = { - keyOf: (row) => String(row.category_id), + keyOf: (row) => `p:${row.category_id}`, + parentKeyOf: (row) => (row.parent_id != null ? `p:${row.parent_id}` : null), depthOf: (row) => row.depth ?? (row.parent_id !== null && !row.is_parent ? 1 : 0), isParent: (row) => row.is_parent, }; @@ -116,11 +116,12 @@ export default function BudgetVsActualTable({ data }: BudgetVsActualTableProps) const depth = row.depth ?? (row.parent_id !== null && !row.is_parent ? 1 : 0); const isTopParent = isParent && depth === 0; const isIntermediateParent = isParent && depth >= 1; - const collapsed = isTopParent && groups.isCollapsed(row); + const collapsed = isParent && groups.isCollapsed(row); const paddingClass = depth >= 3 ? "pl-20" : depth === 2 ? "pl-14" : depth === 1 ? "pl-8" : "px-3"; return ( - {isTopParent ? ( + {isParent ? (