* [AI] Only show stacked bar tooltip truncation indicator when categories are hidden
* [AI] Cover the non-compact tooltip case and sharpen the release note
* Add Syncloud to the additional installation options
Syncloud is a server operating system for a Raspberry Pi, a spare PC or a VPS,
which packages actual-server as one of the apps it installs and updates. Listed
under the community options alongside the other platform guides, with one link
for what it is and one for setting a device up.
* Drop the Syncloud description and setup link
Keep only the link that is about running Actual, as requested in review.
* docs: add Rauthy to the list of tested OpenID providers
Closes#8838
Co-Authored-By: Claude Opus 5 <[email protected]>
* docs: note Rauthy needs RS256 for token and ID token algorithms
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---------
Co-authored-by: Fionn Jones <[email protected]>
Co-authored-by: Claude Opus 5 <[email protected]>
Co-authored-by: youngcw <[email protected]>
* let account-move reassign the account group
* provide a react-aria router to the app
* add account tree keys and pure move helpers
* rebuild the sidebar account list on the react-aria tree with drag and drop
* add a keyboard drag handle to sidebar tree rows
* fix typecheck
* coderabbit
* fix chevron spacing and indentation
* coderabbit
* [AI] Keep custom report charts stable with long legends (#5394)
Fixes#5394
* [AI] Use forEach for parameterized report tests
---------
Co-authored-by: Felipe Medici <[email protected]>
* [AI] Detect CSV file encoding and add a per-account encoding selector
Read CSV/TSV files as raw bytes and decode them based on the detected
encoding instead of always assuming UTF-8: the byte order mark, BOM-less
UTF-16 (NUL byte analysis), strict UTF-8 validation, and a windows-1252
fallback that also decodes ISO-8859-1 content. A mostly-valid UTF-8 file
with a few corrupted bytes still decodes as UTF-8 with replacement
characters instead of falling back to windows-1252.
Add an encoding selector to the CSV import options, persisted per
account like the delimiter, for files in encodings that cannot be
detected automatically (e.g. windows-1250, ISO-8859-2).
Adds fixtures and tests for UTF-16 (with and without BOM), UTF-8 with
BOM, corrupted UTF-8, NUL-padded UTF-8, and windows-1252 content.
Fixes#6327
* Update VRT screenshots
Auto-generated by VRT workflow
PR: #8924
* Update VRT screenshots
Auto-generated by VRT workflow
PR: #8924
* [AI] Address review: require dominant NUL parity and translate encoding labels
Require one parity to clearly dominate (>= 90% of NUL bytes) before
detecting BOM-less UTF-16, so a UTF-8 file with dense contiguous NUL
padding (even split across parities) is no longer misdetected as
UTF-16. Adds a fixture with padding above the 10% density threshold.
Wrap the encoding selector labels in t() per the repository's
translated user-facing text requirement.
* [AI] Drop iso-8859-1 from the CSV encoding selector
TextDecoder resolves the iso-8859-1 label to the windows-1252 decoder
per the WHATWG encoding spec, so the option was redundant and could
mislead users into expecting true ISO-8859-1 decoding. windows-1252
already covers ISO-8859-1 content; keep the alias accepted in
decodeCsvBytes with a clarifying comment and an alias test.
* [AI] Make the iso-8859-1 alias test distinguish Windows-1252
The alias test now uses a fixture containing the 0x80 byte, which
windows-1252 decodes as the euro sign while a true ISO-8859-1 decoder
would produce a C1 control character, so the assertion actually
verifies the windows-1252 alias semantics.
* [AI] Simplify CSV encoding detection to BOM and explicit selection
Follow the review suggestion: the byte order mark selects UTF-16
LE/BE and everything else decodes as UTF-8; other encodings are
handled by the manual per-account selector this PR adds. Drop the
speculative BOM-less UTF-16, windows-1252 fallback, and corrupted
UTF-8 heuristics along with their fixtures and tests.
---------
Co-authored-by: François Lafleur <[email protected]>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
* fix YNAB4 import dropping the parent payee on split children
YNAB4 stores the payee on the parent transaction only, but the importer
spread a `payee: undefined` key onto every non-transfer sub transaction.
`makeChild` treats a present key as explicit, so the children never fell
back to the parent's payee and showed up with no payee at all. Only emit
the key when a payee was actually resolved; transfer children are unchanged.
Fixes#3561
* Update packages/loot-core/src/server/importers/ynab4.ts
---------
Co-authored-by: Tim <[email protected]>
The month rewrite in parseDate matched "Sep", "Sep." and "September"
but not the four-letter "Sept" that some bank exports use. The word
boundary after "sep" failed on the trailing "t", so the month was never
converted to a number and every September row was rejected as an
invalid date.
Extend the regex to also accept "Sept" and "Sept." and cover the
DD MMM YY, DD MMM YYYY and MMM DD, YYYY forms in the parseDate table.
Closes#8888
* optimise transactions edits/deletes by making the running balance query find applicable rules first, and only run if required
* balance now fetched at most once and only for a rule whos conditions matched
* monte carlo income streams
* simplify release note
* enhancement
* fix withdrawal rule floor when income is specified
* update screenshots
* suplus pot and images
* way better description in the run details
* covering case where income is all thats setup and spending is the same as the income
* feedback
* screenshots and rename of minimum withdrawal to min spending
* additional docs
* [AI] Show a progress bar while importing a YNAB budget
* [AI] Name the account in transaction import progress
* [AI] Defer scheduled import progress until rule updates finish
Change-Id: rnuttktwqnkslztsvklpqxvnwnvqvopy
* [AI] Prevent dismissing an import while it is running
Change-Id: tnwzlovsmtsqwtkxorqnymtxvwuyrsvk
* [AI] Subscribe to import progress before importing
Change-Id: kwnmmmslpoxpxrmpzltnwsrqvuryzous
* [AI] Rank exact payee matches above tied substring matches
fzf's tiebreakers default to none, so when two suggestions tie on match
score (e.g. querying 'Amazon' against both 'Amazon' and 'Amazon Prime'),
the ranking falls back to original array order instead of favoring the
exact match. useTags.ts already fixes this for tag filtering via
tiebreakers: [byLengthAsc, byStartAsc]; this applies the same fix to
payee autocomplete matching.
Split out from the combined payee/category fix on
fix/exact-match-tiebreak-scoring — the category half is intentionally
not carried over, since category suggestions are meant to stay ordered
the way they appear within the budget arrangement.
* [AI] Use alphabetically-ordered payee names in exact-match tiebreak test
'Amazon Prime'/'Amazon' needed to be listed out of alpha order to
demonstrate the bug, which doesn't match how the payee list is
naturally sorted. 'AAA Google'/'Google' demonstrates the same fix
while staying in alpha order like the rest of the suite.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
---------
Co-authored-by: Claude Sonnet 5 <[email protected]>
* [AI] fix(sync): receive only the latest timestamp to stop counter overflow
Timestamp.recv was called once per incoming message. Each call burns one
tick of the 16-bit HLC counter whenever the logical clock does not advance,
and the counter only resets when Date.now() moves forward. Browsers that
coarsen Date.now() (LibreWolf, or Firefox with resistFingerprinting, which
rounds it to 100ms) give the loop enough time to pass 65535 messages in a
single tick, so a large sync throws OverflowError and the budget never
opens.
Receive only the highest incoming timestamp instead. The clock lands in the
same place, the drift check still sees the furthest-ahead message, and the
counter advances once per batch.
* [AI] fix(sync): address timestamp review feedback
Change-Id: oowtnqoxrmltvupuxowqqnnynnqwkxqx
* [AI] Fix missing vite-plugin-peggy workspace in sync-server.Dockerfile
The deps stage copies each workspace's package.json individually for Docker layer caching, but packages/vite-plugin-peggy/package.json was never added to that list even though loot-core and api both depend on it via workspace:*, so yarn install fails resolution with Workspace not found. Add the missing COPY line.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
* release note
---------
Co-authored-by: Amy Hawkins <[email protected]>
Co-authored-by: Claude Sonnet 5 <[email protected]>
* [AI] Add Karma to the custom theme catalog
Karma is a dark theme for Actual Budget. The CSS is hosted at
sreetamdas/karma/actual.css and every --color-* token is mapped from the
canonical Karma palette, so the theme stays in step with the Karma ports for
VS Code, Zed and iTerm.
Colors are the six representative hues for the catalog swatch: the near-black
background, the purple primary accent, and the green/pink/orange/cyan accents.
* [AI] Add release note for the Karma theme
* Bump @vitest/mocker in the npm_and_yarn group across 0 directory
Updates `@vitest/mocker` from 4.1.10 to 5.0.0
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Changelog](https://github.com/vitest-dev/vitest/blob/main/docs/releases.md)
- [Commits](https://github.com/vitest-dev/vitest/commits/v5.0.0/packages/mocker)
---
updated-dependencies:
- dependency-name: "@vitest/mocker"
dependency-version: 5.0.0
dependency-type: indirect
dependency-group: npm_and_yarn
...
Signed-off-by: dependabot[bot] <[email protected]>
* [AI] Fix typecheck failures under vitest 5
Vitest 5 changed two things that broke the typecheck/build jobs:
- `vi.fn()`'s inferred type now references `Procedure` from an internal
vitest chunk that cannot be named from outside, so the hoisted mocks in
`cloud-storage.test.ts` tripped TS2883. Annotate them as `Mock`.
- The `expect` package was inlined and the global `jest.Matchers`
declaration dropped, so `@testing-library/jest-dom`'s default entry no
longer augments vitest's `Assertion`. Use the `/vitest` entry point
instead.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Bvwt76cXUoLwfHiy1jhToc
* [AI] Bump @actual-app/crdt to 3.1.3
The dependency bump touches packages/crdt/package.json, so the CRDT
version bump check requires a new version. Matches how the previous
dependabot group bump (#8921) was handled.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Bvwt76cXUoLwfHiy1jhToc
* [AI] Add release note for the vitest bump
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Bvwt76cXUoLwfHiy1jhToc
---------
Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: MatissJanis <[email protected]>
Co-authored-by: Claude Opus 5 <[email protected]>
* [AI] Keep older app versions syncing and loading budgets touched by newer versions
Cross-version compatibility for sync and budget files:
- Sync messages referencing tables/columns this client doesn't have yet
(sent by a newer app version) are deferred into a messages_pending
table (coalesced per cell) instead of failing the sync, and replayed
after migrations run on budget load. Deferral applies only to inbound
messages; local writes still surface apply-failure.
- Budgets already migrated by a newer app version now load, as long as
every known migration is present (checkDatabaseValidity tolerance).
- A CI guard (schema introspection over the real migration chain)
enforces that migrations stay additive-only: no dropped/renamed
tables or columns, no constraint changes on existing tables
(NOT NULL, DEFAULT, UNIQUE, CHECK, primary keys), and new synced
tables use a single id primary key with optional columns.
- An "Update available" notification tells the user when deferred
changes are waiting for an app update, re-shown on budget load while
messages remain pending.
Co-Authored-By: Claude Fable 5 <[email protected]>
* [AI] Address review findings for cross-version sync
- Clear messages_pending during sync reset so replaying deferred
messages can't resurrect hard-deleted rows as empty stubs
- Treat an explicit DEFAULT NULL as no usable default in the
additive-migration validator
- Make the CHECK-clause scanner quote/comment-aware so changes behind
a quoted paren can't slip through
- Flag type and DEFAULT changes on existing columns
- Make the deferred-messages notification sticky so it isn't dismissed
during budget load
* [AI] Harden and simplify the additive-migration schema validator
- Ignore CHECK( tokens inside quoted literals and comments by scanning
a masked copy of the stored CREATE TABLE text
- Skip schema snapshots for pre-cutoff migrations in the chain test
- Collapse per-column attribute comparisons into a single changed-keys
check and drop the redundant required-flip branch
* [AI] Harden the cross-version sync deferral and replay flow
Findings from several review rounds of the deferral feature:
- Carry inbound values with unknown serialization formats opaquely
(deferring them like missing columns) instead of wedging sync
- Replay honors last-write-wins against the crdt log, takes a real
UPDATE path so row constraints see the merged row, retries
dependency chains to a fixpoint, drops only deterministic failures,
and aborts safely on possibly-transient errors
- Notify the user when deferred changes are dropped or discarded
(new dropped-messages event), delivered reliably during budget load
- Reset sync counts only real losses toward the discard warning
- Guard replay behind a configured server so serverless-session edits
can't be reverted; ignore legacy spreadsheet_cells messages
- Restore corruption detection for empty migration directories and
narrow the UI's schema-mismatch classification
- Move serialization and notification helpers into their own modules
* [AI] Simplify the cross-version sync branch and shrink its diff
- Hoist the applyMessages callback to a named function, undoing ~280
lines of reindentation churn
- Fold the sync notification helpers into sync/utils.ts
- Drop an unreachable pending-message cleanup clause, a consumer-less
re-export, and a committed empty-fixture directory (mkdtemp instead)
- Tighten review-era comments to their load-bearing constraints
- Skip pointless work: unfiltered return when nothing deferred,
snapshot reuse in the additive chain test
* [AI] Bump pending-messages migration timestamp past latest master migration
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01BYNhGvhoHHKeAwiCJxfHsN
* [AI] Make messages_pending migration idempotent
Use CREATE TABLE IF NOT EXISTS so budgets that already have the table
from the previous migration id still open after the timestamp bump.
* [AI] Document additive-only migration rules for contributors
Add a README in the migrations folder explaining cross-version sync
constraints, allowed schema changes, and what the additive test misses.
* [AI] Preserve CHECK literal case in migration schema diff
Lowercase SQL tokens outside quoted strings when comparing CHECK
constraints so 'ARCHIVED' and 'archived' are treated as different.
* [AI] Create messages_pending on demand instead of relying on the migration
The browser serves migration files through caches that can lag behind
the app code (stale service-worker precache, unrebuilt dev
environment), producing 'no such table: messages_pending' on every
budget load — and a failed sync batch if a message needed deferring.
The code that uses the table now creates it on first touch, sharing
one copy of the DDL with the (idempotent) migration.
---------
Co-authored-by: Claude Fable 5 <[email protected]>
* Make sure datepicker cannot go before earliest transaction
* [AI] use sendCatch for Sankey budget-month queries
Avoids triggering global server-error notifications when selected months have no budget data.
* Release note
* Revert "[AI] use sendCatch for Sankey budget-month queries"
This reverts commit 89db5a9d8c.
* Add function to calculate bounded month range
* Ensure only valid months can be selected
* Update release note
* Revert "Ensure only valid months can be selected"
This reverts commit 12b3850ec6.
* Use bounded start and end in createBaseGraphSpreadsheet
* Linting fix
* [AI] Adapt SankeyCard initialization per rabbit comments
* Update release note
* [AI] Respect OFX ENCODING/CHARSET headers when importing files
Read OFX/QFX files as raw bytes and decode using the encoding declared in the file header instead of always assuming UTF-8. Files declaring CHARSET:8859-1 or 1252 are decoded as windows-1252, and ENCODING:UTF-8 files as UTF-8.
Also converts the 8859-1.qfx fixture to actual Latin-1 bytes (it was saved as UTF-8 despite declaring CHARSET:8859-1, so the test did not exercise the charset path) and adds fixtures and tests for windows-1252 and UTF-8 with non-ASCII content.
Fixes#8872
* [AI] Add release note for OFX charset decoding fix
* Apply suggestion from @coderabbitai[bot]
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
---------
Co-authored-by: François Lafleur <[email protected]>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>