Commit graph

85 commits

Author SHA1 Message Date
le king fu
3b70abdb9e feat: propagate right-click "add as keyword" to transactions page and highlights list (#75)
Some checks failed
PR Check / rust (push) Has been cancelled
PR Check / frontend (push) Has been cancelled
PR Check / rust (pull_request) Has been cancelled
PR Check / frontend (pull_request) Has been cancelled
Wire the ContextMenu + AddKeywordDialog pair onto the remaining per-transaction
surfaces. No new business logic — pure composition of #69 / #74 pieces.

- HighlightsTopTransactionsList: optional onContextMenuRow prop, ReportsHighlightsPage
  renders ContextMenu + AddKeywordDialog on right-click
- TransactionTable: optional onRowContextMenu prop on each <tr>; TransactionsPage
  handles it and opens the dialog pre-filled with the row description + current
  category
- Aggregate tables (HighlightsTopMoversTable, ComparePeriodTable, MonthlyTrendsTable,
  CategoryOverTimeTable) are intentionally NOT wired: they show category / month
  aggregates, not individual transactions, so there is no keyword to extract from
  a row — the dialog would be nonsensical there

Fixes #75

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 15:15:33 -04:00
le king fu
62430c63dc feat: category zoom + secure AddKeywordDialog with context menu (#74)
Some checks failed
PR Check / rust (push) Has been cancelled
PR Check / frontend (push) Has been cancelled
PR Check / rust (pull_request) Has been cancelled
PR Check / frontend (pull_request) Has been cancelled
Service layer
- New reportService.getCategoryZoom(categoryId, from, to, includeChildren) —
  bounded recursive CTE (WHERE ct.depth < 5) protects against parent_id cycles;
  direct-only path skips the CTE; every binding is parameterised
- Export categorizationService helpers normalizeDescription / buildKeywordRegex /
  compileKeywords so the dialog can reuse them
- New validateKeyword() enforces 2–64 char length (anti-ReDoS), whitespace-only
  rejection, returns discriminated result
- New previewKeywordMatches(keyword, limit=50) uses parameterised LIKE + regex
  filter in memory; caps candidate scan at 1000 rows to protect against
  catastrophic backtracking
- New applyKeywordWithReassignment wraps INSERT (or UPDATE-reassign) +
  per-transaction UPDATEs in an explicit BEGIN/COMMIT/ROLLBACK; rejects
  existing keyword reassignment unless allowReplaceExisting is set; never
  recategorises historical transactions beyond the ids the caller supplied

Hook
- Flesh out useCategoryZoom with reducer + fetch + refetch hook

Components (flat under src/components/reports/)
- CategoryZoomHeader — category combobox + include/direct toggle
- CategoryDonutChart — template'd from dashboard/CategoryPieChart with
  innerRadius=55 and ChartPatternDefs for SVG patterns
- CategoryEvolutionChart — AreaChart with Intl-formatted axes
- CategoryTransactionsTable — sortable table with per-row onContextMenu
  → ContextMenu → "Add as keyword" action

AddKeywordDialog — src/components/categories/AddKeywordDialog.tsx
- Lives in categories/ (not reports/) because it is a keyword-editing widget
  consumed from multiple sections
- Renders transaction descriptions as React children only (no
  dangerouslySetInnerHTML); CSS truncation (CWE-79 safe)
- Per-row checkboxes for applying recategorisation; cap visible rows at 50;
  explicit opt-in checkbox to extend to N-50 non-displayed matches
- Surfaces apply errors + "keyword already exists" replace prompt
- Re-runs category zoom fetch on success so the zoomed view updates

Page
- ReportsCategoryPage composes header + donut + evolution + transactions
  + AddKeywordDialog, fetches from useCategoryZoom, preserves query string
  for back navigation

i18n
- New keys reports.category.* and reports.keyword.* in FR + EN
- Plural forms use i18next v25 _one / _other suffixes (nMatches)

Tests
- 3 reportService tests cover bounded CTE, cycle-guard depth check, direct-only fallthrough
- New categorizationService.test.ts: 13 tests covering validation boundaries,
  parameterised LIKE preview, regex word-boundary filter, explicit BEGIN/COMMIT
  wrapping, rollback on failure, existing keyword reassignment policy
- 62 total tests passing

Fixes #74

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 15:09:17 -04:00
le king fu
ff350d75e7 feat: compare report — MoM / YoY / budget with view toggle (#73)
Some checks failed
PR Check / rust (push) Successful in 23m24s
PR Check / frontend (push) Successful in 2m17s
PR Check / frontend (pull_request) Has been cancelled
PR Check / rust (pull_request) Has been cancelled
- Services: getCompareMonthOverMonth(year, month) and getCompareYearOverYear(year)
  return CategoryDelta[] (expense-side, ABS aggregates, parameterised SQL only)
- Shared CategoryDelta type with HighlightMover now aliased to it
- Flesh out useCompare hook: reducer + fetch + automatic year/month inference
  from the shared useReportsPeriod `to` date; budget mode skips fetch and
  delegates to CompareBudgetView which wraps the existing BudgetVsActualTable
- Components: CompareModeTabs (MoM/YoY/Budget tabs), ComparePeriodTable (sortable
  table with signed delta coloring), ComparePeriodChart (diverging horizontal
  bar chart with ChartPatternDefs for SVG patterns), CompareBudgetView
  (fetches budget rows for the current target year/month)
- ReportsComparePage wires everything with PeriodSelector + ViewModeToggle
  (storage key reports-viewmode-compare); chart/table toggle is hidden in budget
  mode since the budget table has its own presentation
- i18n keys: reports.compare.modeMoM / modeYoY / modeBudget in FR + EN
- 4 new vitest cases for the compare services: parameterised boundaries,
  January wrap-around to December previous year, delta conversion with
  previous=0 fallback to null pct, year-over-year spans

Fixes #73

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 14:57:13 -04:00
le king fu
ac9c8afc4a feat: reports hub with highlights panel and detailed highlights page (#71)
All checks were successful
PR Check / rust (pull_request) Successful in 24m54s
PR Check / frontend (pull_request) Successful in 2m32s
PR Check / rust (push) Successful in 24m14s
PR Check / frontend (push) Successful in 2m26s
- Transform /reports into a hub: highlights panel + 4 nav cards
- New service: reportService.getHighlights (parameterised SQL, deterministic
  via referenceDate argument for tests, computes current-month balance, YTD,
  12-month sparkline series, top expense movers vs previous month, top recent
  transactions within configurable 30/60/90 day window)
- Extended types: HighlightsData, HighlightMover, MonthBalance
- Wired useHighlights hook with reducer + window-days state
- Hub tiles (flat naming under src/components/reports):
  HubNetBalanceTile, HubTopMoversTile, HubTopTransactionsTile,
  HubHighlightsPanel, HubReportNavCard
- Detailed ReportsHighlightsPage: balance tiles, sortable top movers table,
  diverging bar chart (Recharts + patterns SVG), top transactions list with
  30/60/90 window toggle; ViewModeToggle persistence keyed as
  reports-viewmode-highlights
- New i18n keys: reports.hub.*, reports.highlights.*
- 5 new vitest cases: empty profile, parameterised queries, window sizing,
  delta computation, zero-previous divisor handling

Fixes #71

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 14:47:55 -04:00
le king fu
91430e994a refactor: remove pivot report, add sub-route skeletons and shared components (#69)
All checks were successful
PR Check / rust (push) Successful in 24m21s
PR Check / frontend (push) Successful in 2m12s
PR Check / rust (pull_request) Successful in 23m5s
PR Check / frontend (pull_request) Successful in 2m16s
- Delete DynamicReport* components and pivot types (PivotConfig, PivotResult, PivotFieldId, etc.)
- Remove getDynamicReportData/getDynamicFilterValues from reportService
- Strip pivotConfig/pivotResult from useReports hook and ReportsPage
- Drop "dynamic" from ReportTab union
- Remove reports.pivot.* and reports.dynamic i18n keys in FR and EN
- Add skeletons for /reports/highlights, /trends, /compare, /category pages
- Register the 4 new sub-routes in App.tsx
- Add reports.hub, reports.viewMode, reports.empty, common.underConstruction keys
- New shared ContextMenu component with click-outside + Escape handling
- Refactor ChartContextMenu to compose generic ContextMenu
- New ViewModeToggle with localStorage persistence via storageKey
- New Sparkline (Recharts LineChart) for compact trends
- Unit tests for readViewMode helper

Fixes #69

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 14:25:38 -04:00
ba5257791f Merge pull request 'fix: migrate PIN hashing from SHA-256 to Argon2id (#54)' (#55) from fix/simpl-resultat-54-argon2id-pin into main 2026-04-14 12:49:05 +00:00
le king fu
9a9d3c89b9 feat: dismissable banner with session-storage memory (#81)
All checks were successful
PR Check / rust (push) Successful in 22m28s
PR Check / frontend (push) Successful in 2m17s
PR Check / rust (pull_request) Successful in 22m30s
PR Check / frontend (pull_request) Successful in 2m18s
Adds a close button and session-scoped dismissal flag so the banner
can be acknowledged for the current run but reappears on the next
app launch if the fallback is still active — matches the #81
acceptance criterion.

- sessionStorage key survives page navigation within the run, is
  cleared on app restart.
- Graceful on storage quota errors.
- New `common.close` i18n key (FR: "Fermer", EN: "Close") used as
  the aria-label of the close button.
2026-04-14 08:20:20 -04:00
le king fu
3b1c41c48e feat: settings banner when OAuth tokens fall back to file store (#81)
Some checks are pending
PR Check / rust (push) Waiting to run
PR Check / frontend (push) Waiting to run
PR Check / rust (pull_request) Successful in 22m28s
PR Check / frontend (pull_request) Successful in 2m19s
Adds a visible warning in the Settings page when `token_store` has
landed in the file fallback instead of the OS keychain. Without this,
a user on a keychain-less system would silently lose the security
benefit introduced in #78 and never know.

- New `get_token_store_mode` service wrapper in authService.ts.
- New `TokenStoreFallbackBanner` component: fetches the mode on mount,
  renders nothing when mode is `keychain` or null, renders an
  amber warning card when mode is `file`.
- Mounted in SettingsPage right after AccountCard so it sits next to
  the account state the user can fix (log out + log back in once the
  keychain is available).
- i18n keys under `account.tokenStore.fallback.*` in fr/en.

Refs #66

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 08:18:41 -04:00
le king fu
60b995394e fix: tighten CSP img-src, show initials instead of external avatar
Some checks are pending
PR Check / rust (push) Waiting to run
PR Check / frontend (push) Waiting to run
PR Check / rust (pull_request) Successful in 17m9s
PR Check / frontend (pull_request) Successful in 2m15s
Privacy-first: remove 'https:' from img-src CSP directive to prevent
IP leaks via external avatar URLs (Google/Gravatar). AccountCard now
shows user initials instead of loading a remote image.

Also remove .keys-temp/ from .gitignore (not relevant to this PR).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 15:24:52 -04:00
le king fu
b53a902f11 feat: Maximus Account OAuth2 PKCE + machine activation + subscription check (#51, #53)
All checks were successful
PR Check / rust (push) Successful in 16m34s
PR Check / frontend (push) Successful in 2m14s
PR Check / rust (pull_request) Successful in 16m31s
PR Check / frontend (pull_request) Successful in 2m13s
- Add auth_commands.rs: OAuth2 PKCE flow (start_oauth, handle_auth_callback,
  refresh_auth_token, get_account_info, check_subscription_status, logout)
- Add deep-link handler in lib.rs for simpl-resultat://auth/callback
- Add AccountCard.tsx + useAuth hook + authService.ts
- Add machine activation commands (activate, deactivate, list, get_activation_status)
- Extend LicenseCard with machine management UI
- get_edition() now checks account subscription for Premium detection
- Daily subscription status check (refresh token if last check > 24h)
- Configure CSP for API/auth endpoints
- Configure tauri-plugin-deep-link for desktop
- Update i18n (FR/EN), changelogs, and architecture docs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 14:18:51 -04:00
dd106a1df6 Merge pull request 'feat: gate auto-updates behind license entitlement (#48)' (#58) from issue-48-gate-auto-updates into issue-46-license-commands-entitlements
All checks were successful
PR Check / rust (push) Successful in 16m9s
PR Check / frontend (push) Successful in 2m11s
PR Check / rust (pull_request) Successful in 16m10s
PR Check / frontend (pull_request) Successful in 2m14s
2026-04-10 13:55:39 +00:00
le king fu
6d67ab8935 feat: gate auto-updates behind license entitlement (#48)
All checks were successful
PR Check / rust (push) Successful in 16m6s
PR Check / frontend (push) Successful in 2m15s
Both code paths that touch the updater now consult `check_entitlement`
from the Rust entitlements module before calling `check()`:

- `useUpdater.ts` adds a `notEntitled` status; on Free, the check
  short-circuits and the Settings page displays an upgrade hint instead
  of fetching update metadata.
- `ErrorPage.tsx` (recovery screen) does the same so the error path
  matches the main path; users on Free no longer see network errors when
  the updater would have run.

The gate name (`auto-update`) is the same string consumed by
`commands/entitlements.rs::FEATURE_TIERS`, so changing which tier
unlocks updates is a one-line edit in that file.

Bilingual i18n keys for the new messages are added to both `fr.json`
and `en.json`. CHANGELOG entries in both languages.
2026-04-09 15:52:59 -04:00
le king fu
2da2de183a feat: license card in settings (#47)
All checks were successful
PR Check / rust (push) Successful in 16m19s
PR Check / frontend (push) Successful in 2m14s
Adds the user-facing layer on top of the Rust license commands shipped
in #46.

- `licenseService.ts` thin wrapper around the new Tauri commands
- `useLicense` hook follows the project's useReducer pattern (idle,
  loading, ready, validating, error) and exposes `submitKey`,
  `refresh`, and `checkEntitlement` for cross-component use
- `LicenseCard` shows the current edition, the expiry date when set,
  accepts a license key with inline validation feedback, and links to
  the purchase page via `openUrl` from `@tauri-apps/plugin-opener`
- Card is inserted at the top of `SettingsPage` so the edition is the
  first thing users see when looking for license-related actions
- i18n: new `license.*` keys in both `fr.json` and `en.json`
- Bilingual CHANGELOG entries
2026-04-09 15:47:04 -04:00
escouade-bot
e5be6f5a56 fix: wrap rehash updateProfile in try/catch for best-effort (#54)
All checks were successful
PR Check / rust (push) Successful in 16m33s
PR Check / frontend (push) Successful in 2m14s
PR Check / rust (pull_request) Successful in 16m33s
PR Check / frontend (pull_request) Successful in 2m15s
Both handlePinSuccess handlers (ProfileSwitcher and ProfileSelectionPage)
now catch updateProfile errors so that a failed rehash persistence does
not block switchProfile.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 15:46:27 -04:00
escouade-bot
34626711eb fix: address reviewer feedback (#54)
- Add automatic re-hashing of legacy SHA-256 PINs to Argon2id on
  successful verification, returning new hash to frontend for persistence
- Use constant-time comparison (subtle::ConstantTimeEq) for both
  Argon2id and legacy SHA-256 hash verification
- Add unit tests for hash_pin, verify_pin (Argon2id and legacy paths),
  re-hashing flow, error cases, and hex encoding roundtrip
- Update frontend to handle VerifyPinResult struct and save rehashed
  PIN hash via profile update

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 15:46:27 -04:00
escouade-bot
97da6f9f71 fix: address reviewer feedback (#41)
- Correct CHANGELOG to reflect default type is expense, not all types
- Validate select onChange value against allowed CategoryTypeFilter values

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 04:01:43 -04:00
escouade-bot
56b46f1dfa Remove hard-coded expense filter from Category Over Time report
The Category Over Time report previously only showed expenses (t.amount < 0).
This removes that filter so all transaction types are shown by default,
and adds a type filter (expense/income/transfer) in the right filter panel.

Ref: simpl-resultat#41

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 00:05:27 -04:00
21bf1173ea fix: remove double sign negation for previous year actuals (#34)
Transaction amounts are already signed in the DB (expenses negative,
income positive). Remove Math.abs() normalization and stop multiplying
by sign at display time to avoid double negation.

Extract buildPrevYearTotalMap as a testable exported function and
rewrite tests to import the real function instead of reimplementing it.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 12:02:58 -04:00
64b7d8d11b fix: remove duplicated px-3 class and improve readability (#29)
Clean up the sticky category cell className: remove the duplicated
px-3 for top-level parents and break the long ternary into readable
multi-line format.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 21:28:46 -04:00
0d324b89c4 fix: address reviewer feedback (#29)
- Replace semi-transparent backgrounds on sticky columns with opaque
  color-mix equivalents so scrolled content is fully hidden
- Add opaque background to section header sticky td
- Extract IIFE month options in ReportsPage into a useMemo
2026-03-09 21:28:30 -04:00
c5a3e0f696 feat: sticky category column, month dropdown selector, default to last completed month (#29)
- Add sticky left-0 positioning to all category cells in BudgetVsActualTable
- Replace MonthNavigator arrows with inline title + dropdown month selector
- Default budget month to previous completed month instead of current
- Add i18n keys for new title prefix (FR/EN)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 21:28:09 -04:00
18c7ef3ee9 fix: make pie chart legend always visible with hover percentages (#23)
Show category names permanently in compact form (text-xs) so they
are always discoverable. Percentages appear only on chart hover to
save space, matching the original request while keeping the legend
accessible without interaction.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 21:17:59 -04:00
66d0cd85ff fix: address reviewer feedback (#23)
- Extract reorderRows into shared utility (src/utils/reorderRows.ts) to
  deduplicate identical function in BudgetTable and BudgetVsActualTable
- Restore alphabetical sorting of children in budgetService.ts
- Fix styling for intermediate parent rows at depth 2+ (was only handling
  depth 0-1)
- Reduce pie chart size (height 220->180, radii reduced) and padding to
  give more space to the table

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 21:02:24 -04:00
4a5b5fb5fe fix: address reviewer feedback (#23)
- Make reorderRows() recursive to support subtotals toggle at all depth
  levels (not just depth 0-1)
- Restore pie chart legend (show on hover only to save space)
- Give more horizontal space to budget table (3/4 grid vs 2/3)
2026-03-09 20:46:00 -04:00
dbe249783e fix: display level 4+ categories under their parent in dashboard budget table (#23)
- Replace flat alphabetical sort with tree-order traversal so child
  categories appear directly under their parent subtotal row
- Make category hierarchy recursive (supports arbitrary depth)
- Reduce pie chart width from 1/2 to 1/3 of the dashboard
- Show pie chart labels only on hover via tooltip

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 01:10:46 -04:00
8742c25945 Merge pull request 'feat: add previous year total column to budget table (#16)' (#18) from fix/simpl-resultat-16-budget-previous-year into main 2026-03-08 16:39:43 +00:00
e32a14557f Merge pull request 'fix: improve chart tooltip visibility over legend labels (#19)' (#21) from fix/simpl-resultat-19-tooltip-transparency into main 2026-03-08 16:39:22 +00:00
4923880a6e Add box-shadow and z-index to chart tooltips for better visibility (#19)
Tooltip was blending with the legend labels at the bottom of the chart,
especially when showing all categories at once. Added shadow and z-index
to ensure the tooltip stands out from the background.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 12:06:16 -04:00
d5790a08e9 Remove internal title from CategoryPieChart for dashboard consistency (#17)
Move the pie chart title to DashboardPage as an external h2,
matching the pattern used by BudgetVsActual and ExpensesOverTime sections.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 12:04:35 -04:00
097c16dc14 feat: add previous year total column to budget table (#16)
Add a read-only column showing the annual budget total from the
previous year for each category. This serves as a baseline reference
when planning the current year's budget.

- Add previousYearTotal field to BudgetYearRow type
- Fetch previous year budget entries in useBudget hook
- Display column between Category and Annual in BudgetTable
- Propagate totals through parent/subtotal/section/grand total rows
- Add i18n keys for FR ("Année préc.") and EN ("Prev. Year")

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 11:04:10 -04:00
le king fu
861d78eca2 Improve visual hierarchy of subtotals and totals in all tables
Section subtotals: text-sm font-semibold with more padding.
Grand totals: text-sm font-bold with border-t-2 and extra padding.
Applied consistently across BudgetTable, BudgetVsActualTable,
MonthlyTrendsTable, CategoryOverTimeTable, CategoryTable,
and DynamicReportTable.

Closes #14

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 09:10:27 -05:00
le king fu
e1192beca3 Fix missing categories and gray text in category reports
Increase category over time limit from 8 to 50 so all categories appear.
Fix category name visibility: use foreground color for bar chart Y-axis
labels and chart legend text instead of muted/inherited colors.

Closes #13

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 09:06:40 -05:00
le king fu
420506b074 Bump version to 0.6.2 — Section subtotals and category detail fix
All checks were successful
Release / build-and-release (push) Successful in 30m13s
Add per-section subtotals (expenses, income, transfers) to budget table
and budget vs actual report. Fix category detail panel visibility when
scrolling through long category lists.

Closes #11, closes #12

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 16:22:36 -05:00
le king fu
820360df5b Fix chart label visibility and improve budget cell edit UX
- Change chart amount labels from white to black with white stroke outline
  for better contrast on all bar colors (fixes #8)
- Improve budget table editable cells: add hover background, pointer cursor,
  tooltip hint, and larger click target for clearer affordance (fixes #9)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 14:42:44 -05:00
le king fu
0a5b7bce10 Bump version to 0.6.0 — Reports enhancements and comment visibility fix
All checks were successful
Release / build-and-release (push) Successful in 26m12s
- Add table/chart toggle for Trends, By Category, and Over Time reports
- Add "Show amounts" toggle to display values on chart elements
- Add filter panel with category checkboxes and source dropdown
- Add source filter at SQL level for all chart report queries
- Add sticky headers on Dynamic Report and Budget vs Actual tables
- Add interactive hover: dimmed non-hovered bars, filtered tooltip, legend hover
- Fix comment icon color to match split indicator (orange) (#7)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 21:01:13 -05:00
le king fu
3e0f826256 Add sort and amount toggle to report details, sticky budget headers
- #1: Sortable columns (date, description, amount) in the transaction
  detail modal with click-to-toggle direction
- #2: Budget table headers stay fixed when scrolling vertically
- #3: Eye/EyeOff toggle to show/hide the amounts column in the
  transaction detail modal

Closes #1, closes #2, closes #3

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 09:31:47 -05:00
le king fu
d604d5ae63 Fix updater latest.json and add log viewer in settings
Some checks failed
Release / build-and-release (push) Has been cancelled
Fix updater: strip v-prefix from version in latest.json, and delete
old package before re-uploading to avoid 409 conflicts.
Add frontend log capture (console intercept) with a log viewer card
in the settings page (filterable, copyable, clearable).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 21:09:10 -05:00
le king fu
849945f339 Add error boundary, error page, and startup timeout
Prevent infinite spinner when DB connection fails at startup by adding
a 10s timeout on connectActiveProfile(). Add ErrorBoundary to catch
React crashes and ErrorPage with refresh, update check, and contact links.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 19:01:39 -05:00
le king fu
a04813ced2 feat: add 3rd level of category hierarchy
Support up to 3 levels of categories (e.g., Dépenses récurrentes →
Assurances → Assurance-auto) while keeping SQL JOINs bounded and
existing 2-level branches fully compatible.

Changes across 14 files:
- Types: add "level3" pivot field, depth property on budget row types
- Reports: grandparent JOIN for 3-level resolution in dynamic reports
- Categories: depth validation (max 3), auto is_inputable management,
  recursive tree operations, 3-level drag-drop with subtree validation
- Budget: 3-level grouping with intermediate subtotals, leaf-only
  aggregation, depth-based indentation (pl-8/pl-14)
- Seed data: Assurances split into Assurance-auto/habitation/vie
- i18n: level3 translations for FR and EN

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 19:54:05 -05:00
le king fu
2ae7fb301c fix: decouple dynamic report from global page date filters
The dynamic report now relies exclusively on its own panel filters
instead of inheriting the global period selector date range.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 10:09:14 -05:00
le king fu
04ec221808 feat: support multiple column dimensions in dynamic reports
Combine column dimensions into composite keys instead of using only the
first column dimension, enabling richer pivot tables and charts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 10:00:42 -05:00
le king fu
b46cad5888 feat: add "This year" period option to reports and dashboard
Adds a "year" period (Jan 1 to today) between "6 months" and "12 months"
in the period selector across all reports and dashboard views.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 09:18:27 -05:00
le king fu
d06153f472 feat: allow reusable pivot fields across zones and right-click filter exclusion
Fields can now be assigned to multiple zones simultaneously (e.g. rows + filters).
Right-clicking a filter value excludes it (NOT IN), shown with strikethrough in red.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 09:10:15 -05:00
le king fu
bcf7f0a2d0 feat: add fullscreen toggle to dynamic report
Overlay covers the full viewport while keeping the config panel
accessible. Press Escape or click the button to exit.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 09:00:42 -05:00
le king fu
438b72cba2 fix: pivot rows before rendering to prevent duplicate categories in dynamic report table
The table was rendering one <tr> per SQL result row instead of pivoting
the column-dimension values into a single row per unique row-key combo.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 08:52:22 -05:00
le king fu
20b3a54ec7 feat: add Dynamic Report (pivot table) tab to Reports page
Implement a pivot table feature allowing users to compose custom reports
by assigning dimensions (Year, Month, Type, Level 1/2) to rows, columns,
and filters, with periodic and YTD measures as values. Includes a side
panel for configuration, a dynamic table with subtotals, and a stacked
bar chart visualization.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 08:26:50 -05:00
le king fu
2436f78023 feat: allow deleting keywords from the All Keywords view
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 07:29:29 -05:00
le king fu
b353165f61 feat: add toggle to position subtotals above or below detail rows
Add a toggle button to BudgetVsActualTable and BudgetTable that lets
users choose whether parent subtotal rows appear before or after their
children. The preference is persisted in localStorage and shared across
both tables.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 09:46:53 -05:00
le king fu
446f6effab feat: add custom date range picker to reports and dashboard
Allow users to select an arbitrary date interval (e.g. Jan 1–15) in
addition to the existing preset periods. The "Custom" button opens a
dropdown with two date inputs and an Apply button. Works on both the
Reports and Dashboard pages.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 09:46:32 -05:00
Le-King-Fu
731610cf3c fix: improve split indicator visibility and adjustments layout
Some checks failed
Release / build (ubuntu-22.04) (push) Has been cancelled
Release / build (windows-latest) (push) Has been cancelled
- Change split icon color to orange-500 in transactions table for
  better contrast in both dark and light modes
- Show split transactions at the top of the adjustments left panel
  when there are no manual adjustments (instead of below empty state)
- Add a divider between manual adjustments and splits when both exist

Bumps version to 0.3.5.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 02:01:15 +00:00