feat(balance): chart vehicle/class toggle + collapsible returns #208

Merged
maximus merged 1 commit from issue-204-chart-vehicle-toggle-collapsible-returns into main 2026-06-02 01:08:42 +00:00
Owner

Fixes #204

Issue 3 of overnight-2026-06-01-bilan-axe-vehicule. Tracking/reporting UI on top of the merged data layer (#202) + input UI (#203).

What

  • Service getSnapshotTotalsByVehicleAndDate(range) mirrors the by-category aggregation with GROUP BY COALESCE(a.vehicle_type, none) — null-envelope accounts collapse into a single none bucket, never a SQL NULL key. vehicle_type added to getAccountsLatestSnapshot SELECT + AccountLatestSnapshot type.
  • useBalanceOverview new groupAxis (class|vehicle) state ORTHOGONAL to chartMode; loads byVehicle alongside byCategory. Default groupAxis = class.
  • Chart toggle (BalanceEvolutionChart + BalancePage): stacked-mode sub-toggle « Par classe dactif » (default) / « Par enveloppe ». Vehicle legend REUSES the #203 vehicleType.* labels; the none bucket uses the new balance.vehicle.none.
  • Collapsible returns (BalanceAccountsTable): the 4 Modified-Dietz columns are collapsed by default, toggle persisted across sessions via userPreferenceService key balance_show_returns (load on mount, write on toggle). Returns computation is gated so a collapsed table never runs Modified Dietz.
  • i18n FR/EN: balance.chart.axis.{byAssetClass,byVehicle}, balance.vehicle.none, balance.accountsTable.toggleReturns.{show,hide} (+ balance.chart.axisLegend aria-label). Parity verified.

Tests

  • npm run build (tsc + vite): green, 0 type errors.
  • npm test (vitest): 3314 passed / 201 files.
  • 5 new service tests: empty DB, COALESCE-none SQL shape, mixed envelopes + none bucket, all-none snapshot, date-range params. Extended #202 test asserting vehicle_type threaded.

Reviewer focus

  • The none-bucket COALESCE in getSnapshotTotalsByVehicleAndDate (HIGH caveat).
  • groupAxis kept independent of chartMode (MEDIUM caveat) — sub-toggle only renders in stacked mode.
  • BalanceAccountsTable diff is large mostly from re-indentation under the new toggle wrapper div.

🤖 Generated with Claude Code

Fixes #204 Issue 3 of `overnight-2026-06-01-bilan-axe-vehicule`. Tracking/reporting UI on top of the merged data layer (#202) + input UI (#203). ## What - **Service** `getSnapshotTotalsByVehicleAndDate(range)` mirrors the by-category aggregation with `GROUP BY COALESCE(a.vehicle_type, none)` — null-envelope accounts collapse into a single `none` bucket, never a SQL NULL key. `vehicle_type` added to `getAccountsLatestSnapshot` SELECT + `AccountLatestSnapshot` type. - **`useBalanceOverview`** new `groupAxis` (`class`|`vehicle`) state ORTHOGONAL to `chartMode`; loads `byVehicle` alongside `byCategory`. Default `groupAxis = class`. - **Chart toggle** (`BalanceEvolutionChart` + `BalancePage`): stacked-mode sub-toggle « Par classe dactif » (default) / « Par enveloppe ». Vehicle legend REUSES the #203 `vehicleType.*` labels; the `none` bucket uses the new `balance.vehicle.none`. - **Collapsible returns** (`BalanceAccountsTable`): the 4 Modified-Dietz columns are collapsed by default, toggle persisted across sessions via `userPreferenceService` key `balance_show_returns` (load on mount, write on toggle). Returns computation is gated so a collapsed table never runs Modified Dietz. - **i18n FR/EN**: `balance.chart.axis.{byAssetClass,byVehicle}`, `balance.vehicle.none`, `balance.accountsTable.toggleReturns.{show,hide}` (+ `balance.chart.axisLegend` aria-label). Parity verified. ## Tests - `npm run build` (tsc + vite): green, 0 type errors. - `npm test` (vitest): 3314 passed / 201 files. - 5 new service tests: empty DB, COALESCE-none SQL shape, mixed envelopes + none bucket, all-none snapshot, date-range params. Extended #202 test asserting `vehicle_type` threaded. ## Reviewer focus - The `none`-bucket COALESCE in `getSnapshotTotalsByVehicleAndDate` (HIGH caveat). - `groupAxis` kept independent of `chartMode` (MEDIUM caveat) — sub-toggle only renders in stacked mode. - `BalanceAccountsTable` diff is large mostly from re-indentation under the new toggle wrapper div. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
maximus added 1 commit 2026-06-02 01:05:19 +00:00
feat(balance): chart vehicle/class toggle + collapsible returns (#204)
All checks were successful
PR Check / rust (pull_request) Successful in 22m13s
PR Check / frontend (pull_request) Successful in 2m21s
0104e9223a
Issue 3 of overnight-2026-06-01-bilan-axe-vehicule. Builds the tracking UI
on top of the merged data layer (#202) and input UI (#203).

- Service: getSnapshotTotalsByVehicleAndDate(range) mirrors the by-category
  aggregation with GROUP BY COALESCE(a.vehicle_type, 'none') so null-envelope
  accounts land in a single 'none' bucket (never a SQL NULL key). Add
  vehicle_type to getAccountsLatestSnapshot SELECT + type.
- useBalanceOverview: new groupAxis ('class'|'vehicle') state ORTHOGONAL to
  chartMode; loads byVehicle alongside byCategory. Default groupAxis='class'.
- BalanceEvolutionChart + BalancePage: stacked-mode sub-toggle 'Par classe
  d'actif' (default) / 'Par enveloppe'. Vehicle legend reuses the #203
  vehicleType.* labels; the 'none' bucket uses balance.vehicle.none.
- BalanceAccountsTable: 4 return columns collapsed by default with a toggle,
  persisted across sessions via userPreferenceService key balance_show_returns.
- i18n FR/EN: balance.chart.axis.{byAssetClass,byVehicle}, balance.vehicle.none,
  balance.accountsTable.toggleReturns.{show,hide} (+ axisLegend aria label).

Tests: npm run build green (0 type errors); vitest 3314 passed. Added 5
service tests for the 'none' bucket + mixed envelopes + date range.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Author
Owner

Review — APPROVE

Revue indépendante (orchestrateur /sprint), diff vérifié sur la branche.

Vérifications

  • [HIGH] getSnapshotTotalsByVehicleAndDate : COALESCE(a.vehicle_type,'none') présent dans le SELECT et le GROUP BY → bucket 'none' unique pour les comptes sans enveloppe, jamais une clé SQL NULL. Mirror fidèle de getSnapshotTotalsByCategoryAndDate. Tests service (shape SQL + mixed-envelope + all-none).
  • [MEDIUM] groupAxis orthogonal à chartMode : état indépendant dans useBalanceOverview, n'affecte que le mode empilé, défaut 'class'. Charge byCategory ET byVehicle en parallèle.
  • getAccountsLatestSnapshot : vehicle_type ajouté au SELECT + au type.
  • Toggle graphique (BalancePage) : rendu uniquement en mode stacked, boutons classe(défaut)/enveloppe avec aria-pressed ; le chart sélectionne byVehicle vs byCategory + activeLabels selon l'axe.
  • Rendements repliables (BalanceAccountsTable) : showReturns défaut false, persisté via userPreferenceService (balance_show_returns), toggle aria-expanded ; le calcul Modified-Dietz est gated derrière showReturns (perf, neutre — ces valeurs ne servent qu'aux 4 colonnes masquées).
  • Légende réutilise les labels #203 : balance.vehicle.* ne contient que none ; les 6 enveloppes réutilisent balance.account.form.vehicleType.*. i18n parité 6/6 (FR/EN). npm run build + vitest verts.

Déviation acceptée : balance.chart.axisLegend ajouté (aria-label du groupe de toggle, miroir de modeLegend).

Verdict : APPROVE.

## Review — APPROVE ✅ Revue indépendante (orchestrateur `/sprint`), diff vérifié sur la branche. **Vérifications** - ✅ **[HIGH] `getSnapshotTotalsByVehicleAndDate`** : `COALESCE(a.vehicle_type,'none')` présent dans le SELECT **et** le GROUP BY → bucket `'none'` unique pour les comptes sans enveloppe, jamais une clé SQL NULL. Mirror fidèle de `getSnapshotTotalsByCategoryAndDate`. Tests service (shape SQL + mixed-envelope + all-none). - ✅ **[MEDIUM] `groupAxis` orthogonal à `chartMode`** : état indépendant dans `useBalanceOverview`, n'affecte que le mode empilé, défaut `'class'`. Charge byCategory ET byVehicle en parallèle. - ✅ **`getAccountsLatestSnapshot`** : `vehicle_type` ajouté au SELECT + au type. - ✅ **Toggle graphique** (BalancePage) : rendu uniquement en mode `stacked`, boutons classe(défaut)/enveloppe avec `aria-pressed` ; le chart sélectionne byVehicle vs byCategory + activeLabels selon l'axe. - ✅ **Rendements repliables** (BalanceAccountsTable) : `showReturns` défaut `false`, persisté via `userPreferenceService` (`balance_show_returns`), toggle `aria-expanded` ; le calcul Modified-Dietz est gated derrière `showReturns` (perf, neutre — ces valeurs ne servent qu'aux 4 colonnes masquées). - ✅ **Légende réutilise les labels #203** : `balance.vehicle.*` ne contient que `none` ; les 6 enveloppes réutilisent `balance.account.form.vehicleType.*`. i18n parité 6/6 (FR/EN). `npm run build` + `vitest` verts. **Déviation acceptée** : `balance.chart.axisLegend` ajouté (aria-label du groupe de toggle, miroir de `modeLegend`). Verdict : **APPROVE**.
maximus merged commit d3b8ad6266 into main 2026-06-02 01:08:42 +00:00
maximus deleted branch issue-204-chart-vehicle-toggle-collapsible-returns 2026-06-02 01:08:42 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: maximus/Simpl-Resultat#208
No description provided.