whisper-money/resources/js/lib
Víctor Falcón 1cc10566a3
feat: parent/child category tree (#474)
## Summary

Adds nested categories (parent → child, up to **3 levels**) across the
app. Children inherit their parent's type and cashflow direction, and
every category selector now renders the hierarchy as an indented tree.
Gated behind the `CategoryTree` Pennant flag (off by default).

## Backend

- **Migration**: nullable self-referencing `parent_id`; uniqueness
scoped per-parent via a `parent_unique_marker` virtual column (root
names stay unique). New composite unique created before dropping the old
one so the `user_id` FK keeps a supporting index.
- **`CategoryTree` service**: descendant/ancestor resolution, depth &
cycle checks, type cascade, subtree deletion.
- **Validation**: depth limit, cycle prevention, inherited + locked
child type.
- **Delete strategies**: reparent (default), promote to root, or cascade
(uncategorizes affected transactions).
- **Transaction filter** expands a selected parent to its descendants.
- **Cashflow Sankey & breakdown** roll up to top-level parents with
click-to-drill (children + a parent "direct" node).
- **Budgets** tracking a parent also count their children's
transactions.
- **Unified** the frontend category query behind
`Category::forDisplay()` / `FRONTEND_COLUMNS` (8 call sites) so every
selector receives the full Category shape, including `parent_id`.

## Frontend

- New `category-tree.ts` helpers (build/flatten/descendants/path,
tree-aware selection toggle + tri-state).
- **Settings page**: indented tree, sortable by name/color/type
(siblings sorted, hierarchy preserved), parent picker, delete-strategy
dialog.
- **Combobox** (transaction table cell + edit/create modal + parent
picker): indented tree, search keeps matches with their ancestors.
- **Transaction filter**: indented tree, tri-state cascading selection
(parent ↔ children), themed checkboxes, selected branches float to top
on open, ancestor-aware search.
- **Categorizer palette** and **budget multi-select**: same indented
tree + ancestor-aware search.
- **Sankey**: click a parent node to drill into its children, with
breadcrumb.
- Pennant `CategoryTree` flag gates the parent UI.

## Tests

- Pest: model/validation, delete strategies, filter expansion, cashflow
rollup/drill, budget child inclusion.
- Vitest: tree-aware selection logic.
- All green; Pint / ESLint / Prettier clean.

## Rollout

Flag is off by default — enable per user with:
\`\`\`
php artisan feature:enable "App\\Features\\CategoryTree" you@example.com
\`\`\`
2026-06-03 19:30:12 +02:00
..
balance-import-config-storage.ts fix: add SSR guards to localStorage/sessionStorage access 2025-12-08 18:19:20 +01:00
category-tree.test.ts feat: parent/child category tree (#474) 2026-06-03 19:30:12 +02:00
category-tree.ts feat: parent/child category tree (#474) 2026-06-03 19:30:12 +02:00
chart-calculations.test.ts fix(dashboard): treat loans as debt in net worth (#238) 2026-03-20 09:55:53 +00:00
chart-calculations.ts feat(accounts): add real estate asset tracking (#241) 2026-03-24 10:21:32 +00:00
chunk-load-recovery.test.ts Fix Vite asset preload recovery (#399) 2026-05-14 15:59:08 +02:00
chunk-load-recovery.ts Fix Vite asset preload recovery (#399) 2026-05-14 15:59:08 +02:00
crypto.ts Add some toast notifications 2025-11-11 11:39:28 +00:00
csrf.test.ts refactor(js): extract shared getCsrfToken util (#475) 2026-06-03 17:26:09 +02:00
csrf.ts refactor(js): extract shared getCsrfToken util (#475) 2026-06-03 17:26:09 +02:00
cursor-pagination.test.ts Fix Sentry transaction and dashboard crashes (#372) 2026-05-10 11:10:31 +01:00
cursor-pagination.ts Fix Sentry transaction and dashboard crashes (#372) 2026-05-10 11:10:31 +01:00
debug.ts fix: make useIsMobile hook and utility functions SSR-safe 2025-12-08 17:33:54 +01:00
dexie-db.ts feat(budgets): track multiple categories and labels per budget (#466) 2026-06-01 12:32:23 +02:00
file-parser.test.ts feat(importer): support YYYYMMDD date format (#470) 2026-06-01 16:44:46 +02:00
file-parser.ts feat(importer): support YYYYMMDD date format (#470) 2026-06-01 16:44:46 +02:00
import-config-storage.ts Fix transaction importer account preselect (#396) 2026-05-14 12:38:44 +02:00
key-storage.ts fix: make encryption key storage SSR-safe to prevent 502 errors 2025-12-08 17:13:45 +01:00
orphan-components.test.ts chore(frontend): add orphan component detection and remove dead components (#181) 2026-03-02 12:43:27 +01:00
posthog.test.ts Harden browser storage and PostHog recording (#402) 2026-05-14 15:57:48 +02:00
posthog.ts feat(posthog): route analytics through reverse proxy (#463) 2026-06-01 09:29:30 +02:00
rule-builder-utils.test.ts feat(transactions): add counterparty fields (#440) 2026-05-27 16:20:55 +02:00
rule-builder-utils.ts feat: parent/child category tree (#474) 2026-06-03 19:30:12 +02:00
rule-engine.ts feat(transactions): add counterparty fields (#440) 2026-05-27 16:20:55 +02:00
sankey-utils.ts feat: Group small expending categories on the Sankey chart 2026-01-11 19:04:20 +01:00
sentry.test.ts fix: filter Safari cashback extension errors (#447) 2026-05-28 15:10:49 +02:00
sentry.ts fix: filter Safari cashback extension errors (#447) 2026-05-28 15:10:49 +02:00
subscription-payment-issue-toast.test.ts feat: keep past due subscriptions active (#416) 2026-05-22 10:19:11 +01:00
subscription-payment-issue-toast.ts feat: keep past due subscriptions active (#416) 2026-05-22 10:19:11 +01:00
sync-manager.ts fix(accounts): translate update button in edit account modal (#455) 2026-05-30 16:09:30 +02:00
transaction-delete-confirmation.test.ts Fix Spanish translations in category and delete flows (#397) 2026-05-14 11:36:53 +01:00
transaction-delete-confirmation.ts Fix Spanish translations in category and delete flows (#397) 2026-05-14 11:36:53 +01:00
transaction-re-evaluation.test.ts Add labels to automation rules (#379) 2026-05-11 14:56:25 +02:00
transaction-re-evaluation.ts Add labels to automation rules (#379) 2026-05-11 14:56:25 +02:00
utils.ts Prevent duplicate notes when re-evaluating automation rules 2025-12-04 16:42:54 +01:00