Compare commits

..

103 Commits

Author SHA1 Message Date
Matiss Janis Aboltins
0f77d333ca Bump version 2026-02-22 15:19:27 +00:00
Matiss Janis Aboltins
9966c024cb [AI] Enforce file access authorization on sync API endpoints (#7040)
* [AI] Enforce file access authorization on sync API endpoints

Co-authored-by: Cursor <cursoragent@cursor.com>

* Refactor file deletion authorization to return error message as text

* Refactor file upload validation to improve error handling

* Add tests to allow admin users to retrieve encryption keys and sync files for other users

- Implemented a test for admin access to retrieve encryption keys for another user's file in the /user-get-key endpoint.
- Added a test for admin users to sync another user's file in the /sync endpoint, ensuring proper response and headers.

These changes enhance the authorization checks for admin actions on user files.

* Refactor file cleanup in tests to use onTestFinished for better error handling

* Enhance admin capabilities in file management tests

* Add migration to backfill file owners with admin ID

* Enhance file access authorization in sync API

* Update migration to backfill file owners with admin ID to ensure consistent ordering in the query

* Refactor access control tests for file downloads in sync API

* Add test for non-owner file download access via user_access in sync API

This test verifies that users with appropriate access can download files owned by others, utilizing the requireFileAccess logic and UserService.countUserAccess. It ensures correct response headers and content delivery for shared files.

* Refactor file cleanup in upload and download tests to utilize onTestFinished for improved error handling

This update consolidates file cleanup logic in the test suite, ensuring that temporary files are removed after each test execution. The changes enhance the reliability of tests by consistently managing file state across various scenarios.

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-21 16:30:58 +00:00
Matiss Janis Aboltins
ea937d1009 Require authentication for SimpleFIN and Pluggy.ai endpoints (#7034)
* Add authentication middleware to SimpleFIN and Pluggy.ai endpoints

Protect /simplefin/* and /pluggyai/* routes with validateSessionMiddleware
so only authenticated users can access bank account and transaction data.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Release notes

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-21 16:30:57 +00:00
Matiss Janis Aboltins
0d6742664b 🔖 (26.2.0) (#6837)
* 🔖 (26.2.0)

* Remove used release notes

* docs pages

* s/flathub/Flathub

* s/coderabbit/CodeRabbit

* allowlist

---------

Co-authored-by: matt-fidd <81489167+matt-fidd@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Matt Fiddaman <github@m.fiddaman.uk>
2026-02-02 12:12:46 +00:00
Alexis Vielma
37e807f161 fix: resolve issue with banksync table border (#6825) 2026-01-31 18:23:11 +00:00
Matt Fiddaman
c9abc62b3a fix reconciliation when experimental currency support is enabled (#6824)
* fix reconcilation when using currency symbols

* note

* fix tests
2026-01-31 00:34:38 +00:00
Matt Fiddaman
234f257260 fix spacing and borders on bank sync page (#6823)
* fix bank sync tables

* note
2026-01-31 00:26:02 +00:00
Spydi
49d583e4ad docs: add ANZ Plus Bank to community repos (#6785)
* docs: add ANZ Plus Bank to community repos

Added ANZ Plus Bank to the Community Repos page.
Link(s): https://github.com/spydisec/PDFtoOFX/
Short summary: Convert ANZ Plus bank statement PDFs to OFX format for seamless import into Actual Budget and other personal finance applications.
Placement: https://actualbudget.org/docs/community-repos/

* Update packages/docs/docs/community-repos.md

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Fix typo in ANZ Plus bank converter description

* chore: update docs spelling allowlist

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-01-30 23:11:17 +00:00
Stephen Brown II
460cb7b6cd Add workflow to remove 'suspect ai generated' label when 'AI Generated' is added (#6810) 2026-01-30 23:00:15 +00:00
Matt Fiddaman
1eb68c8e19 fix crossover report resizing bug (#6821)
* fix crossover report

* note
2026-01-30 21:27:20 +00:00
Michael Clark
2ec592c2d6 Remove gh pages deploy & reinstate netlify autodeploy (#6822)
* remove gh pages deploys now that netlify have removed prod deploys

* release notes

* thanks wabbit
2026-01-30 19:36:13 +00:00
Copilot
19edbeb5c2 Surface clock drift errors with actionable messages (#6789)
* Initial plan

* Add clock-drift error handling to sync flow

Co-authored-by: MatissJanis <886567+MatissJanis@users.noreply.github.com>

* Add release notes for PR #6789

* Refactor error handling in sync flow

- Extracted error handling logic into a separate function for better readability and maintainability.
- Updated the receiveMessages and _sendMessages functions to utilize the new errorHandler.
- Removed redundant error handling code from the _sendMessages function.
- Enhanced error handling for SyncError and ClockDriftError to emit specific events.

* Enhance error handling in receiveMessages function

- Added try-catch block to handle Timestamp.ClockDriftError specifically.
- Emitted a sync error event for clock-drift errors to improve synchronization feedback.
- Maintained existing functionality while improving error reporting.

* Update authorship in release notes and refine clock-drift error messaging for clarity

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: MatissJanis <886567+MatissJanis@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Matiss Janis Aboltins <matiss@mja.lv>
2026-01-29 14:24:25 +00:00
Matiss Janis Aboltins
d8b7e45aaa Fix date picker keyboard navigation regression (#6808) 2026-01-28 21:44:33 +00:00
Michael Clark
f71249f510 🎨 Storybook docs (#6770)
* start to a storybook

* release notes

* commit the release notes

* add test:web back

* adding some scripts to the main package for storybook

* styled it up a bit

* remove unneeded icon

* lint

* remove needless comment

* moving clarifying comment

* fast failing

* feedback

* removing unneeded config
2026-01-28 18:38:02 +00:00
Matiss Janis Aboltins
ebf8e985ad Fix missing bottom navigation bar on mobile reports page (#6803)
* Fix missing bottom navigation bar on mobile reports page

Update route pattern from /reports to /reports/* to match nested routes

* Release notes

* Add release notes for version 6803

* Refactor reports route to include dashboardId parameter
2026-01-28 17:17:22 +00:00
Copilot
690e2d0871 Fix: Accept keyboard apostrophe (U+0027) in arithmetic parser for apostrophe-dot format (#6795)
* Initial plan

* Add test case for apostrophe-dot format bug

Co-authored-by: MatissJanis <886567+MatissJanis@users.noreply.github.com>

* Fix: Support keyboard apostrophe (U+0027) in arithmetic parser for apostrophe-dot format

The arithmetic parser was only recognizing the typographic apostrophe (U+2019)
that Intl.NumberFormat outputs, but not the regular apostrophe (U+0027) that
users type on their keyboards. This caused amounts like "12'345.67" to be
truncated to "12" when users typed them.

The fix adds U+0027 to the regex character class in arithmetic.ts so both
apostrophe characters are accepted.

Co-authored-by: MatissJanis <886567+MatissJanis@users.noreply.github.com>

* Add explicit character code verification to apostrophe-dot test

Use escape sequences (\u0027 and \u2019) to ensure the test explicitly
uses the correct apostrophe characters, and add assertions to verify
the character codes are as expected.

Co-authored-by: MatissJanis <886567+MatissJanis@users.noreply.github.com>

* Fix lint

* Add comprehensive tests for apostrophe-dot format in arithmetic.test.ts

Added three new test cases to verify both apostrophe types work correctly:
1. Tests keyboard apostrophe (U+0027) with explicit character code verification
2. Tests typographic apostrophe (U+2019) with explicit character code verification
3. Tests arithmetic operations with both apostrophe types

This addresses the feedback to add tests for the new logic in arithmetic.ts.

Co-authored-by: MatissJanis <886567+MatissJanis@users.noreply.github.com>

* [autofix.ci] apply automated fixes

* Add release notes for PR #6795

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: MatissJanis <886567+MatissJanis@users.noreply.github.com>
Co-authored-by: Matiss Janis Aboltins <matiss@mja.lv>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-28 16:58:33 +00:00
Juulz
91faa2f7f1 [fix] Update BudgetAnalysisGraph to use a darker gray for balance to increase legibility (#6791)
* Update BudgetAnalysisGraph.tsx

Use reportsGray for Balance.

* Fix Budget Analysis Graph balance color variable

Use reportsGray instead of numberNeutral for balance points and line.
2026-01-28 15:18:02 +00:00
Matiss Janis Aboltins
4888d3faed Fix schedule transaction amount color on mobile (#6792)
* Fix schedule transaction amount color on mobile

Change schedule amount color from pageText to pageTextSubdued to match the label color, consistent with desktop version.

Fixes #6781

* Enhance Budget Analysis report UI and functionality

- Improve chart colors to align with Cash Flow report style
- Streamline report view by removing legend items
- Introduce a quick select option for 1 month in the header
- Implement dynamic interval switching based on date range

This update aims to provide a more cohesive and user-friendly experience in the Budget Analysis report.

* Update snapshot images for account page tests and fix color styling in transaction and schedule list items

- Updated snapshot images for account page tests to reflect recent UI changes.
- Adjusted color styling for transaction amounts to ensure consistency with the overall theme.
- Changed schedule amount color back to match the primary text color for better visibility.
2026-01-28 09:10:44 +00:00
Andrii Hrushetskyi
3091320719 Fix: Added Czech CZK and Hungarian HUF currencies (#6500)
* Fix: Added Czech CZK and Hungarian HUF currencies

* Fix: Added translations for prev commit

* Update upcoming-release-notes/6500.md

Co-authored-by: Matiss Janis Aboltins <matiss@mja.lv>

---------

Co-authored-by: Matiss Janis Aboltins <matiss@mja.lv>
2026-01-27 18:49:03 +00:00
Michael Clark
72304c6182 Fix nightly edge not scheduling (#6775)
* fix nightly edge not scheduling

* changing to 11PM UTC

* clarifying comment

* better diff
2026-01-25 10:44:26 +00:00
tabedzki
e4903ca6e3 Feat/add-budget-analysis-report (#6137)
* Add Budget Analysis report with full implementation

Co-authored-by: tabedzki <35670232+tabedzki@users.noreply.github.com>

* Add preset time ranges, intervals, bar chart, hide balance, and display controls

Co-authored-by: tabedzki <35670232+tabedzki@users.noreply.github.com>

* Fix duplicate function declaration syntax error in budget-analysis-spreadsheet.ts

Co-authored-by: tabedzki <35670232+tabedzki@users.noreply.github.com>

* Fix floating point precision error in daily/weekly intervals and replace interval button with dropdown

Co-authored-by: tabedzki <35670232+tabedzki@users.noreply.github.com>

* Make card always display monthly data and match report's chart type

Co-authored-by: tabedzki <35670232+tabedzki@users.noreply.github.com>

* fix: adjust widget placement and presentation

* fix: adjusted the dot presentation

* feat: added svg for line chart/barchart

* fix: added one month to the report

* added the upcoming release notes

* amended the upcoming release notes

* fix: removed unused variables

* formatted using prettier --write

* [autofix.ci] apply automated fixes

* feat: added new feature to the Reports Page in the test budget

* fix: amended the reports.test.ts file to expect Budget Analysis

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6137

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6137

* revert: removed the inclusion of the Budget Analysis tool from the test file

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6137

* fix: changed the display to always be monthly since budgets are monthly; removed the 1month view

* [autofix.ci] apply automated fixes

* [autofix.ci] apply automated fixes (attempt 2/3)

* fix: removed comment

* feat: added experimental feature flag for Budget Analysis tool

* feat: Switched option to use SVG Icons instead of words to shorten horizontal layout

* Removed interval possibilities and removed unnecessary compact variable as indicated by CodeRabbit

* Update packages/desktop-client/src/components/reports/reports/BudgetAnalysisCard.tsx

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Added basic documentation for Budget Analysis Report

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6137

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6137

* fix: added budget-analysis doc to sidebar

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6137

* feat(reports): improve Budget Analysis report UI and behavior

- Update chart colors to match Cash Flow report style
  (Budgeted: blue, Balance: pageTextLight)
- Remove legend items from report view for cleaner UI
- Add 1 month quick select option to header
- Pass isConcise prop to BudgetAnalysisGraph for proper date formatting
- Add dynamic daily/monthly interval switching based on date range

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6137

* feat(reports): refactor BudgetAnalysisGraph and improve isConcise calculation according to Rabbit AI

* feat(reports): add translation support for Budget Analysis graph labels

* feat(reports): centralize translation for Budget Analysis graph labels

* feat: use the budget values directly from the budget spreadsheet/server

* feat: enhance budget analysis with overspending adjustments and detailed reporting

* style: format code for better readability in BudgetAnalysis and budget-analysis-spreadsheet components

* refactor: remove unused variables

* docs: added in the image to the docs

* fix: reimplement support for conditionsOp

* [autofix.ci] apply automated fixes

* style: simplify budget analysis labels for clarity

* fix: add the on copy function

* feat: tooltip improvements

* feat: enhance budget analysis to track overspending adjustments across months

* fix: removed the absolute value for spent

* feat: update the charts to look closer to the CashFlow report

* fix: correct financial formatting for totalSpent in BudgetAnalysis

* feat: add filterExclude prop to Header and BudgetAnalysis for improved filtering options

* feat: implement privacy mode for Y-axis values in BudgetAnalysisGraph

* feat: change default graph type to Bar in BudgetAnalysis

* feat: remove commented-out filter button code in Header component

* feat: remove commented-out code for filter exclusion in Header component

* fix: update the feedback link to the dedicated issue

* refactor: financial display components to use FinancialText for consistency in Budget Analysis reports

* fix: update the card to also start as bar graph

* docs: update Budget Analysis report to include category filtering information

* style: refactor imports and whitespace

* refactor: simplify inline content structure in BudgetAnalysis component

* [autofix.ci] apply automated fixes

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6137

* fix: removed color descriptors from the chart

* fix: update color themes for Budget Analysis to use custom theme definitions

* [autofix.ci] apply automated fixes

* feat: update Budget Analysis merge md file

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6137

* fix: update budget analysis report image

* fix: white space adjustment in descriptor

* [autofix.ci] apply automated fixes

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: youngcw <calebyoung94@gmail.com>
2026-01-24 20:00:10 +00:00
Matt Fiddaman
d768cfa508 update package versions with release action when explicit version passed (#6767)
* update package versions when explicit version passed

* note
2026-01-24 15:30:17 +00:00
Matt Fiddaman
e0ed53c4af make colors on budget page more legibile (#6764)
* use old budget page colours

* running balance

* schedule indicator

* mobile to budget

* note

* template indicator due should match underfunded

* coderabbit

* mobile to budget neutral zero

* matiss feedback

* mobile account balance

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6764

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-24 15:26:02 +00:00
Matiss Janis Aboltins
c3e3a258e0 Mobile: improve performance for transaction list usage (#6755)
* Mobile: add usePullToRefreshOnScrollContainer hook, bypass PTR library, refactor transaction list

* Remove usePullToRefreshOnScrollContainer hook from desktop client

* Enhance PullToRefresh component with optional style prop and refactor TransactionList layout

* Refactor TransactionListItem component: remove unused imports and hooks, update props type to use ListBoxItemRenderProps
2026-01-24 08:39:46 +00:00
Matt Fiddaman
f55a42d817 fix report drag and drop reordering (#6763)
* fix report drag and drop

* note
2026-01-23 19:37:17 +00:00
Mats Nilsson
331aafda30 Create an option for stacked net worth graph (#6603)
This commit adds an option to the net worth graph that makes it into a
stacked line graph.
2026-01-23 16:29:30 +00:00
Matt Fiddaman
be95b9a3d5 fix mobile uncategorised banner (#6758)
* fix mobile uncategorised banner

* cleanup unnecessary nesting

* note
2026-01-23 14:25:59 +00:00
Matt Fiddaman
8eadd09bfc fix monthly spending number colouring (#6756)
* fix monthly spending summary colouring

* note

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6756

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-23 11:11:37 +00:00
Juulz
414aa95fd8 add "To budget" color variables (#6754)
* Add budget color variables to theme

* Add isPositive check for budget amount styling

* Add budget number constants for positive, zero, and negative

* Add budget status constants for positive, zero, and negative

* Add budget number constants for positive, zero, and negative

* Update midnight.ts

* Create 6754.md
2026-01-22 23:10:14 +00:00
Michael Clark
19ed2423d4 Fix edge nightly deploy (#6753)
* fix edge nightly deploy

* fix name

* rename file

* clarifying comment

* bit more clear

* adding release notes to satisfy pipeline

* spelling
2026-01-22 21:47:24 +00:00
Alexis Vielma
4986e433a5 feat: consistent table styling (#6697)
* feat: consistent table styling

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6697

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6697

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6697

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-22 20:43:39 +00:00
Michael Clark
9a3415adab 🚀 Deploy edge every night (#6751)
* deploy edge at midnight

* release ntoes
2026-01-22 19:39:03 +00:00
Jonathon Jongsma
bcfefde4ad Add contributions to crossover report (#6639)
Add the ability to specify expected monthly contributions to the
crossover report. This will allow users to estimate the growth of their
investments more accurately instead of treating all account growth as
exponential investment returns. When the checkbox is unclicked, the
automatically calculated historical return value will be used. When the
checkbox is clicked, it will display two input fields. One for expected
investment growth, and one for expected monthly contributions to your
retirement accounts.

Signed-off-by: Jonathon Jongsma <jonathon@quotidian.org>
2026-01-22 16:52:34 +00:00
dependabot[bot]
c4514b1fe6 Bump lodash from 4.17.21 to 4.17.23 (#6749)
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.21 to 4.17.23.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.21...4.17.23)

---
updated-dependencies:
- dependency-name: lodash
  dependency-version: 4.17.23
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-22 12:19:01 +00:00
Matt Fiddaman
7a5bfe7c20 use consistent colours on the budget page (#6747)
* fix colouring of non-numerical summary cards

* define new colours

* use new colours on budget page

* use colours on account pages

* note

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6747

* fix mobile colouring

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6747

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-22 11:58:15 +00:00
Juulz
323403b5f7 🎨 Shades of gray custom light theme (#6739)
* Add 'Shades of Gray (light)' theme to catalog

* Update color format in customThemeCatalog.json

* [autofix.ci] apply automated fixes

* Add release notes for light custom theme enhancement

🎨 Light custom theme featuring shades of gray and a few colors.

* Reorder color values in customThemeCatalog.json

* Change color value 

Updated a color value in the custom theme catalog.

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-01-21 20:55:19 +00:00
Matt Fiddaman
a35fdf4d18 make colours on reports page consistent (#6672)
* add colour definitions

* chart theme definitions

* replace with new colour variables

* clean up chart-theme

* merge fixes

* note

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6672

* coderabbit

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-21 18:06:00 +00:00
Matiss Janis Aboltins
d0a72f10b6 Fix reports to correctly render categories with identical names (#6733)
* Fix reports to correctly render categories with identical names

Use category id instead of name as the data key for chart lookups to prevent
collisions when multiple categories share the same display name.

* Enhance CustomTooltip in LineGraph and StackedBarGraph to utilize legend data for improved display names. This change introduces a new LegendEntity type and updates the tooltip rendering logic to map data keys to their corresponding names, ensuring clarity when displaying chart data.
2026-01-21 18:01:23 +00:00
J B
b651238ad2 Enhance Average Goal Template to allow adjusting the budgetted amount… (#6711)
* Enhance Average Goal Template to allow adjusting the budgetted amount from the average by a percent or fixed amount

* fix typos

* ensure check is for undefined, so zero doesn't cause edge cases

* typo in enhancement message

* scale by cents for fixed amount, fixup tests for this as well

* Add support for fixed values in Schedule template

* [autofix.ci] apply automated fixes

* Changed to 'fixed' from 'amount'. Added unparse logic for Average, also fixed Schedule unparse

* move to generic for syntax from specific number

* consider currency preferences when calculating fixed modifications

* lint

* [autofix.ci] apply automated fixes

* timeframe -> period

* percentage -> value

* pass currency for calculation

* lint

* import from proper local dir

* [autofix.ci] apply automated fixes

* script block around {number} to prevent mdx conflict

* match order of ops between schedule and average for percent adjustment

* diversify example

* Link to schedule>adjustments from average

* Removed example column in favor of extra context
Slight rewording to avoid 'average' overload

* rabbit nitpicks

* number

* period

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: youngcw <calebyoung94@gmail.com>
2026-01-21 17:31:46 +00:00
Michael Clark
8d1f0cf1de :electron: Update flathub screenshots to meet quality guidelines (#6611)
* update desktop app screenshots to meet quality guidelines

* better comply with flathub quality guidelines

* screenshot updates
2026-01-21 09:12:53 +00:00
Copilot
b50c45c9c9 Remove broken bank identifier spreadsheet link from GoCardless README (#6731)
* Initial plan

* Remove broken Google Doc link from GoCardless README

Co-authored-by: MatissJanis <886567+MatissJanis@users.noreply.github.com>

* Add release notes for PR #6731

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: MatissJanis <886567+MatissJanis@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-20 21:16:44 +00:00
Matiss Janis Aboltins
8f2369d5b8 Fix desktop notifications positioning (#6729)
* Fix desktop notifications container width

Add explicit width (400px) to the notifications container on desktop
to fix the positioning issue introduced in #6551.

Fixes #6718

* Add release notes for PR #6729

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-20 21:14:39 +00:00
Matiss Janis Aboltins
713ac88fee Mobile: navigate to config page when switching budget file (#6728)
Change the "Switch budget file" menu option on mobile to navigate back
to the config/budget selection page instead of opening a modal. This
makes the behavior consistent with the "Switch file" button in settings.

Remove the now-unused BudgetFileSelectionModal component.
2026-01-20 21:14:24 +00:00
Juulz
bcbcd6ad9f 🎨 Add new theme 'Theme from 1970' to customThemeCatalog (#6730)
* Add new theme 'Theme from 1970' to customThemeCatalog

* Add release notes for 1970-inspired light theme

Added release notes for a new custom light theme inspired by 1970 colors.
2026-01-20 20:57:06 +00:00
Matiss Janis Aboltins
c9a0ffa91c Replace theme screenshots with color palette preview (#6722)
* Replace theme screenshots with color palette preview

- Replace screenshot images in theme installer with 3x2 color palette grid
- Add colors array to catalog themes in customThemeCatalog.json
- Update CatalogTheme type to include optional colors property
- Remove getThemeScreenshotUrl function
- Extract ColorPalette component to separate file
- Update documentation to reflect color palette instead of screenshots
- Update tests to verify color palettes instead of images
- Extract actual theme colors from GitHub repositories

* Update ColorPalette component to use data-swatch attribute for color swatches in ThemeInstaller tests

* Update packages/desktop-client/src/data/customThemeCatalog.json

Co-authored-by: Michael Clark <5285928+MikesGlitch@users.noreply.github.com>

* Update color palettes for Simple Dark and Okabe Ito themes

Co-authored-by: matiss <matiss@mja.lv>

---------

Co-authored-by: Michael Clark <5285928+MikesGlitch@users.noreply.github.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-01-20 18:00:34 +00:00
Matiss Janis Aboltins
6a9df6562c Fix AuthSettings - hide when no server configured and show warning when offline (#6723)
* Fix AuthSettings - hide if no server configured and show warning if offline

* Add release notes for auth settings fix

* Refactor AuthSettings component to always display OpenID label hint and remove offline condition check in tests
2026-01-20 18:00:07 +00:00
Matiss Janis Aboltins
d4144f4b9c lint: enable oxfmt on docs package (#6720) 2026-01-19 22:37:56 +00:00
Matiss Janis Aboltins
176336e7f3 Upgrade oxfmt/oxlint and migrate import sorting to oxfmt (#6719)
* Upgrade oxfmt/oxlint and migrate import sorting to oxfmt

Upgrade oxfmt from 0.22.0 to 0.26.0 and oxlint from 1.38.0 to 1.41.0.

Move import sorting configuration from oxlint (perfectionist/sort-imports)
to oxfmt's new experimentalSortImports feature, which provides native
import sorting support in the formatter.

* Add release notes for maintenance updates including oxlint and oxfmt upgrades
2026-01-19 21:46:24 +00:00
Matt Fiddaman
de0f4e9440 ⬆️ upgrade react deps (#6717)
* react & react-dom

* react-virtualized-auto-sizer v2

* react-grid-layout v2

* note

* Update table.tsx

Co-authored-by: Joel Jeremy Marquez <joeljeremy.marquez@gmail.com>

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6717

---------

Co-authored-by: Joel Jeremy Marquez <joeljeremy.marquez@gmail.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-19 18:53:15 +00:00
Matiss Janis Aboltins
65dee4c627 lint: a11y issue fixes (#6679)
* Fix accessibility issues: use semantic HTML and correct tab indices

- Replace View with semantic h1 in ModalHeader
- Fix tabIndex from 1 to 0 in Menu component
- Remove disabled oxlint accessibility rules
- Update components to use proper semantic HTML elements

* Refactor button elements to semantic HTML in Autocomplete and CategoryAutocomplete components

- Replace button elements with div/View while maintaining role="button" for accessibility.
- Update styles and props accordingly to ensure consistent behavior.
- Adjust onClick types in Item and SecondaryItem components for better type safety.

* Add release notes for upcoming maintenance updates addressing various accessibility issues

* Refactor autocomplete components to improve text alignment and button semantics

- Added textAlign: 'left' style to AccountItem and PayeeItem for consistent text alignment.
- Removed type="button" from CategoryItem to streamline button semantics.
- Updated ItemContent to use the Button component instead of a button element, enhancing accessibility and consistency.

* Refactor budget and report components to improve text alignment

- Removed font: 'inherit' style from EnvelopeBudgetComponents and TrackingBudgetComponents for cleaner styling.
- Updated ActionableGridListItem and ReportCard components to replace font: 'inherit' with textAlign: 'left' for consistent text alignment.

* Update ActionableGridListItem to include font inheritance for improved styling consistency

* Refactor button elements to use the Button component for consistency and improved semantics

- Updated various components (EnvelopeBudgetComponents, IncomeCategoryMonth, CategoryMonth, ActionableGridListItem, ReportCard, DesktopLinkedNotes) to replace native button elements with the custom Button component.
- Adjusted styles and event handlers to align with the new Button implementation, ensuring consistent behavior and accessibility across the application.

* Update Button and ActionableGridListItem styles for consistency

- Set a fixed borderRadius of 4 for the Button component, ensuring uniformity across variants.
- Adjusted ActionableGridListItem to have a borderRadius of 0 for a cleaner design.

* Update CategoryAutocomplete to include button type attribute for improved semantics

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6679

* Update VRT screenshot for Payees search functionality

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-19 18:19:13 +00:00
Copilot
9376217c5e Fix mobile Calendar crash from missing DisplayPayeeProvider (#6698)
* Initial plan

* Fix mobile Calendar fatal error by correcting height constraint

The Virtualizer component in TransactionList requires its parent to have a defined height. Changed the View wrapper from height: '100%' to flex: 1 to properly distribute space within the flex container, accounting for the chevron button.

Co-authored-by: MatissJanis <886567+MatissJanis@users.noreply.github.com>

* Add DisplayPayeeProvider to fix mobile Calendar error

The TransactionListItem component uses useDisplayPayee hook which requires DisplayPayeeProvider context. Wrapped TransactionListMobile with DisplayPayeeProvider to fix "useDisplayPayee must be used within a DisplayPayeeContextProvider" error on mobile.

Co-authored-by: MatissJanis <886567+MatissJanis@users.noreply.github.com>

* Change flex to height for View component

* Add release notes for PR #6698

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: MatissJanis <886567+MatissJanis@users.noreply.github.com>
Co-authored-by: Matiss Janis Aboltins <matiss@mja.lv>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-19 18:05:02 +00:00
Matiss Janis Aboltins
e6e108ffbd Add error styling to ThemeInstaller component (#6689)
* Add error styling to ThemeInstaller component

* Add upcoming release notes for theme enhancements, including improved error handling and expanded theme catalog.

* Update upcoming-release-notes/6689.md

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Update ThemeInstaller to set selected catalog theme on click

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-01-19 18:04:45 +00:00
Matt Fiddaman
517b1b4a81 fix "show completed schedules" toggle being persisted (#6716)
* make mobile consistent with desktop

* remove old option and modal

* note

* remove some useMemos

* coderabbit
2026-01-19 17:37:42 +00:00
Matt Fiddaman
cdae09e554 fix HyperFormula custom functions and add FIXED formula (#6645)
* fix custom HyperFormula functions

* add FIXED formula

* note

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-01-19 17:00:40 +00:00
Juulz
59233c4786 🎨 Add Simple Dark and Okabe Ito custom themes to catalog (#6696)
* Update customThemeCatalog.json

Add Simple Dark and Okabe Ito themes

* Add Simple Dark and Okabe Ito themes to theme catalog

* Update customThemeCatalog.json
2026-01-19 16:54:45 +00:00
Matt Fiddaman
502babd310 add separator between PR body and bundle stats (#6715)
* add seperator line before bundle stats post

* note

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-01-19 16:39:36 +00:00
Matt Fiddaman
3c302b3af9 apply tabular number styles more consistently (#6661)
* reports/reports

* reports/graphs

* account balance

* budgets

* goals

* reports stragglers

* rules

* schedules

* table

* bank sync modal

* spreadsheet

* inputs

* cover menu

* note

* agent configs, and coderabbit review rule

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6661

* fix test

* rename to FinancialText

* lint

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6661

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-19 16:39:16 +00:00
Matt Fiddaman
4c2d3e6998 ⬆️ bump Electron versions (#6703)
* bump electron

* note
2026-01-19 11:19:47 +00:00
Julian Dominguez-Schatz
e79d91b000 Change 'Bugfix' -> 'Bugfixes' in release notes (#6707)
* Change 'Bugfix' -> 'Bugfixes'

* Add release notes for PR #6707

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-18 22:03:39 +00:00
Matiss Janis Aboltins
2457a0b454 Add blog post: Next Steps for Funding Contributors (#6673)
* Add blog post: Next Steps for Funding Contributors

* Add release notes for PR #6673

* Delete upcoming-release-notes/6673.md

* Update packages/docs/blog/2026-01-17-next-steps-for-funding-contributors.md

Co-authored-by: Matt Fiddaman <github@m.fiddaman.uk>

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Matt Fiddaman <github@m.fiddaman.uk>
2026-01-18 21:37:22 +00:00
Julian Dominguez-Schatz
84a1d12dae Remove duplicate spelling check (#6691)
* Remove duplicate spelling check

* Correct Flathub store capitalization in release notes

* Fix typo in Flathub store automation entry

* Add release notes for PR #6691

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-18 19:27:49 +00:00
Copilot
b50d48a31a Fix sidebar link highlighting for nested routes (#6669)
* Initial plan

* Add release notes for PR #6669

* Fix Reports link highlighting in sidebar for nested routes

Co-authored-by: MatissJanis <886567+MatissJanis@users.noreply.github.com>

* Simplify by hardcoding end={false} in InternalLink

Co-authored-by: MatissJanis <886567+MatissJanis@users.noreply.github.com>

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6669

* Fix All accounts link to use exact matching

Co-authored-by: MatissJanis <886567+MatissJanis@users.noreply.github.com>

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6669

* Merge master and accept incoming screenshot changes

Co-authored-by: MatissJanis <886567+MatissJanis@users.noreply.github.com>

* Remove screenshot changes from current branch

Co-authored-by: MatissJanis <886567+MatissJanis@users.noreply.github.com>

* Revert all remaining screenshots to master versions

Co-authored-by: MatissJanis <886567+MatissJanis@users.noreply.github.com>

* Rename 'end' prop to 'isExactPathMatch' for clarity

Co-authored-by: MatissJanis <886567+MatissJanis@users.noreply.github.com>

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6669

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: MatissJanis <886567+MatissJanis@users.noreply.github.com>
Co-authored-by: Matiss Janis Aboltins <matiss@mja.lv>
2026-01-18 18:11:07 +00:00
Matiss Janis Aboltins
9289932af9 Fix flaky mobile payees VRT test by waiting for navbar animation (#6699)
* Fix flaky mobile payees VRT test by waiting for navbar animation to complete

Add wait timeout after dragNavbarDown() to ensure react-spring animation finishes before screenshots are taken.

* Add release notes for reducing payees e2e test flakiness

* Fix release note formatting: use sentence case and add period

Co-authored-by: matiss <matiss@mja.lv>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-01-18 18:10:35 +00:00
Matt Fiddaman
fe624f0158 post bundle size comparison comment in the PR body instead (#6677)
* post size-compare comment in pr body instead of comment

* note
2026-01-18 18:07:48 +00:00
Julian Dominguez-Schatz
7443886856 Run yarn dedupe on the repository (#6694)
* Run yarn dedupe

* Add release notes
2026-01-18 16:42:07 +00:00
Matthias Benaets
58b1420c60 fix: limit custom css textarea to resize vertically (#6695) 2026-01-18 13:54:57 +00:00
Michael Clark
7035b32f26 🎨 Custom theme: Black Gold (#6688)
* black gold theme

* release notes

* release note typo

* release note
2026-01-18 09:42:00 +00:00
Matiss Janis Aboltins
ee0e7ed3e0 Refactor theme catalog fetching to use custom hook (#6681)
* Refactor theme catalog fetching to use custom hook

- Move catalog fetching logic from ThemeInstaller to useThemeCatalog hook
- Fetch catalog asynchronously from GitHub instead of direct import
- Update tests to mock useThemeCatalog hook for faster test execution
- Remove catalog validation and translation dependencies from hook

* Remove redundant visibility checks for 'Demo Theme' button in ThemeInstaller tests and add assertion to verify presence of images.

* Refactor ThemeInstaller component to improve error handling and loading state display

- Change conditional rendering for catalog error to use ternary operator for clarity
- Simplify loading state display logic within the theme catalog view
- Ensure consistent styling and structure for theme items in the catalog

* Initialize loading state in useThemeCatalog hook to true

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-01-17 10:06:16 +00:00
Matiss Janis Aboltins
b6452f930b lint: add perfectionist/sort-named-imports rule (#6680)
* Apply import sorting with perfectionist/sort-named-imports rule

- Add perfectionist/sort-named-imports oxlint rule
- Sort named imports: value imports before type imports
- Update component-library and desktop-client files to match new rule

* Add release notes for linting updates on named imports
2026-01-16 23:41:45 +00:00
Joel Jeremy Marquez
bf814a6873 Update category schedule indicator to honor the upcoming days length setting (#6559)
* Update category schedule indicator to honor the upcoming days length setting

* [autofix.ci] apply automated fixes

* Update filter

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-01-16 17:40:05 +00:00
Matt Fiddaman
81c5dd347f fix inaccurate net payment/deposit calculations (#6675)
* fix net calculations

* note
2026-01-16 17:22:16 +00:00
Matt Fiddaman
cd87d5a899 give contributor points for marking issues as duplicates (#6659)
* reward closing issues as duplicates

* note

* remove debugging
2026-01-16 15:19:57 +00:00
Asherah Connor
f5e1d5eab4 Only reverse import preview transactions if they appear to be sorted by date ascending (#6543)
* Sort import preview transactions by (parsed) date, descending

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6543

---------

Co-authored-by: Matt Fiddaman <github@m.fiddaman.uk>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-16 14:50:54 +00:00
Matiss Janis Aboltins
6bf119786c lint: re-enable some react rules (#6667)
* Remove hooks disable in electron fixtures

Co-authored-by: matiss <matiss@mja.lv>

* Add release notes for PR #6667

* Re-enable exhaustive-deps for low-risk hooks

Co-authored-by: matiss <matiss@mja.lv>

* Reduce exhaustive-deps overrides

Co-authored-by: matiss <matiss@mja.lv>

* Format useQuery hook

Co-authored-by: matiss <matiss@mja.lv>

* Fix exhaustive-deps warnings in hooks

Co-authored-by: matiss <matiss@mja.lv>

* Format useQuery dependencies

Co-authored-by: matiss <matiss@mja.lv>

* Document dynamic hook dependencies

Co-authored-by: matiss <matiss@mja.lv>

* Use react exhaustive-deps disables

Co-authored-by: matiss <matiss@mja.lv>

* Adjust exhaustive-deps disables

Co-authored-by: matiss <matiss@mja.lv>

* Refactor React hooks to address exhaustive-deps linting issues

- Updated multiple components to use `useEffectEvent` for better handling of dependencies.
- Adjusted dependencies in various hooks to improve code quality and maintainability.
- Removed unnecessary `useCallback` and `useRef` usages where applicable.
- Consolidated linting rules for React hooks to enhance consistency across the codebase.

* Refactor useEffect hooks to improve dependency management

- Updated ManageRules component to correctly return the init function in useEffect.
- Adjusted Modals component to disable exhaustive-deps linting for specific dependencies, enhancing clarity and maintainability.

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-16 08:45:29 +00:00
Juulz
14d4c7748d add missing theme variable for custom theming (#6665)
* Update BudgetName color to use sidebarBudgetName 

New theme variable sidebarBudgetName

* Update dark.ts to add sidebarBudgetName variable

* Update development.ts to add sidebarBudgetName variable

* Update light.ts to add sidebarBudgetName variable

* Update midnight.ts to add sidebarBudgetName variable

* Update dark.ts

* Update development.ts

* Update light.ts

* Update midnight.ts

* Update theme.ts

* Create 6665.md

Add `sidebarBudgetName` color variable
2026-01-16 00:19:30 +00:00
Matiss Janis Aboltins
edf61a477a Add code review guidelines for LLM agents (#6670)
* Add code review guidelines and update documentation

* Add release notes for PR #6670

* LLM: add code review guidelines to upcoming release notes

* Update review_status in .coderabbit.yaml to false

* Update CODE_REVIEW_GUIDELINES.md

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-01-15 21:13:42 +00:00
Matiss Janis Aboltins
0724f7eaef Add GitHub workflow to welcome fork PR contributors (#6657)
* lint: patch some no-empty-function violations

* docs: update ESLint rules and remove unused loadOwner function in UserAccess component

* Add GitHub workflow to welcome fork PR contributors

* Add release notes for PR #6657

* Update category for upcoming release notes

Changed category from Features to Maintenance.

* Update fork-pr-welcome.yml

Co-authored-by: Matt Fiddaman <github@m.fiddaman.uk>

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Matt Fiddaman <github@m.fiddaman.uk>
2026-01-15 20:34:31 +00:00
Matiss Janis Aboltins
d01d0eacb8 Add custom themes installation feature (#6612)
* Add custom themes feature with GitHub installation support

- Add ThemeInstaller component for installing themes from GitHub
- Implement custom theme validation and CSS parsing
- Add support for installed custom themes in preferences
- Add CustomThemeStyle component with CSS validation
- Update theme system to support custom overlay backgrounds
- Add comprehensive tests for theme installation and validation
- Add documentation and release notes for custom themes feature

* Update custom theme catalog: remove several themes and add 'Miami Beach' from a new repository.

* Enhance CSS validation in custom themes

- Refactor `validatePropertyValue` to implement an allowlist approach for CSS property values, rejecting complex constructs and functions except for rgb/rgba/hsl/hsla.
- Add comprehensive tests for various invalid CSS scenarios, including function calls and at-rules.
- Improve error messages for better clarity on validation failures.
- Ensure property name validation checks for format and allowed characters.

* Update custom theme catalog: rename theme from 'Miami Beach' to 'Shades of Coffee'.

* Remove 'forceReload' feature flag and related code from the application settings and feature flag definitions.

* Enhance ThemeInstaller component to support installed themes

- Add `installedTheme` prop to `ThemeInstaller` for managing custom themes.
- Implement logic to populate the text box with installed custom theme CSS when reopening.
- Update tests to verify behavior for installed themes with and without repositories.
- Improve CSS validation to allow additional CSS keywords and ensure proper structure.
2026-01-15 18:04:35 +00:00
lif
bb70074f35 fix: disable oneOf and notOneOf operations for Notes filter (#6567)
* fix: disable oneOf and notOneOf operations for Notes filter

The Notes field is a free-text field and should not support "one of" /
"not one of" filter operations, as these require predefined values.
Attempting to use these operations with the Notes filter caused the app
to crash with a TypeError.

This change:
- Adds 'oneOf' and 'notOneOf' to disallowedOps for the notes field
- Updates the TypeScript type definitions to reflect this constraint
- Updates existing tests to use imported_payee field for oneOf tests
- Adds unit tests for the isValidOp and getValidOps functions

Fixes #6325

Signed-off-by: majiayu000 <1835304752@qq.com>

* move note

---------

Signed-off-by: majiayu000 <1835304752@qq.com>
Co-authored-by: Matt Fiddaman <github@m.fiddaman.uk>
2026-01-15 00:56:22 +00:00
dependabot[bot]
5860b95c9c [WIP] chore(deps): bump undici from 7.16.0 to 7.18.2 (#6658)
* chore(deps): bump undici from 7.16.0 to 7.18.2

Bumps [undici](https://github.com/nodejs/undici) from 7.16.0 to 7.18.2.
- [Release notes](https://github.com/nodejs/undici/releases)
- [Commits](https://github.com/nodejs/undici/compare/v7.16.0...v7.18.2)

---
updated-dependencies:
- dependency-name: undici
  dependency-version: 7.18.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

* Add release notes for PR #6658

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-14 21:53:46 +00:00
Bradley Nelson
a58bac6de6 Add session token authentication to API init() (#6540)
* add session token authentication to API init()

Allow users to authenticate using a session token directly instead of
username/password when initializing the API. This is useful for
scenarios where a token has already been obtained through other means.

Changes:
- Refactor InitConfig to use union types for type-safe auth method selection
- Add sessionToken option that validates token on init
- Use TypeScript `never` types to make auth methods mutually exclusive

* add release notes for session token authentication
2026-01-14 21:24:33 +00:00
Juulz
d01f38d480 Copy all old colors from colors.ts to palette.ts (#6627)
* Update color palette with old color values

* Update color palette with new values

* Replace old color imports with old color definitions

* Update color exports to use consistent casing

Done in bulk in MS-Word

* Fix export statements for color constants

* Clean up palette.ts by removing old import comment

Removed commented-out import statement for old colors.

* Add oldColor hex color definitions to palette.ts

Copy hex color definitions from colors.ts into palette.ts.

* Delete packages/desktop-client/src/style/colors.ts

no longer needed

* Disable colors export due to file deletion

* [autofix.ci] apply automated fixes

* Remove restricted import comment from index.ts

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-01-14 20:48:04 +00:00
Matt Fiddaman
4b1f127910 update baseline-browser-mapping (#6647)
* update baseline-browser-mapping

* note
2026-01-14 20:40:56 +00:00
Stephen Brown II
f5377ac7b7 chore: migrate from inter-ui to @fontsource-variable/inter (#6436)
* Update inter-ui to latest npm package: ^4.1.1

* chore: migrate from inter-ui to @fontsource-variable/inter

- Replace inter-ui v3.19.3 with @fontsource-variable/inter v5.2.8
- Import variable font CSS directly via @import statements
- Update font-family declarations to use 'Inter Variable' to match Fontsource naming
- Simplifies path resolution and removes custom SCSS overrides

* Add release notes

* Enable Inter font features

Add ss04 to styles.tnum

Remove font feature settings and always apply in tnum style

Always enable alternate digits (ss01) and slashed zero (zero) font features
instead of making them user-configurable preferences.

* Add font feature settings to mobile financial amounts

Apply styles.tnum to mobile components displaying financial amounts
to enable OpenType features (tnum, ss01, ss04) for proper number styling:
- TransactionListItem: transaction amounts and running balance
- BudgetTable: header totals, ToBudget, and Saved amounts
- ExpenseGroupListItem: expense group totals
- BudgetCell, SpentCell, BalanceCell: category amounts
- IncomeGroup: income group amounts
- SchedulesListItem: schedule amounts

This ensures consistent digit rendering with serifs on "1" and open
digit forms across all mobile transaction, budget, and schedule views.

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6436

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6436

* revert VRT changes

* remove lint line

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6436

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6436

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Matt Fiddaman <github@m.fiddaman.uk>
2026-01-14 20:36:43 +00:00
Matt Fiddaman
826ad86ada ⬆️ mid month dependency bump (#6656)
* @types/node (^22.19.1 → ^22.19.3)

* oxlint (^1.37.0 → ^1.38.0)

* better-sqlite3 (^12.4.1 → ^12.5.0)

* vitest (^4.0.9 → ^4.0.16)

* react-aria-components (^1.13.0 → ^1.14.0)

* @codemirror/autocomplete (^6.19.1 → ^6.20.0)

* @codemirror/language (^6.11.3 → ^6.12.1)

* @codemirror/state (^6.5.2 → ^6.5.3)

* @swc/core (^1.15.2 → ^1.15.8)

* @uiw/react-codemirror (^4.25.3 → ^4.25.4)

* @vitejs/plugin-basic-ssl (^2.1.0 → ^2.1.3)

* @vitejs/plugin-react (^5.1.1 → ^5.1.2)

* hyperformula (^3.1.0 → ^3.1.1)

* i18next (^25.6.2 → ^25.7.4)

* jsdom (^27.2.0 → ^27.4.0)

* react-aria (^3.44.0 → ^3.45.0)

* @swc/helpers (^0.5.17 → ^0.5.18)

* react-error-boundary (^6.0.0 → ^6.0.3)

* react-grid-layout (^1.5.2 → ^1.5.3)

* react-i18next (^16.3.3 → ^16.5.1)

* react-simple-pull-to-refresh (^1.3.3 → ^1.3.4)

* sass (^1.94.0 → ^1.97.2)

* vite (^7.2.2 → ^7.3.1)

* vite-plugin-pwa (^1.1.0 → ^1.2.0)

* fs-extra (^11.3.2 → ^11.3.3)

* @easyops-cn/docusaurus-search-local (^0.52.1 → ^0.52.2)

* react (^19.2.0 → ^19.2.3)

* react-dom (^19.2.0 → ^19.2.3)

* @reduxjs/toolkit (^2.10.1 → ^2.11.2)

* lru-cache (^11.2.2 → ^11.2.4)

* ua-parser-js (^2.0.6 → ^2.0.7)

* workbox-precaching (^7.3.0 → ^7.4.0)

* winston (^3.18.3 → ^3.19.0)

* supertest (^7.1.4 → ^7.2.2)

* playwright (^1.56.0 → ^1.57.0)

* stragglers

* note

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-01-14 20:17:55 +00:00
Will Thomas
c1720f35fd Add Report pages (#6411)
* Adding multiple report pages

* Adding release notes

* Updating release note number

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6411

* Fixing deletion id, allowing empty dashboard name, adding custom report dashboard saving, new dashboard default to empty

* Update VRT snapshots for command bar, payees, and schedules tests

* Update VRT snapshots for payees page visuals and search functionality tests

* Towards move/copy logic (need widget meta copy still!)

* refactor move widget to use add and remove

* Move/Copy modal

* fixes for rename duplicate calls, rename focus issue, and deletion undefined issue

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6411

* some bug/clarity fixes

* better type discipline, dashboard_pages schema, PR review fixes

* re-org of dashboard pages into dropdown, better mobile support, rename moved to title icon

* dashboard spacing fix (even for ridiculously long names), widget type-checking function

* Fix translation interpolation

* Fixing copy vs. move filename, removing old rename modal, minor review tweaks

* overview change simplification, routing error handling, move -> copy migration

* renaming for dashboard pages and error handling

* abstracting out `isWidgetType` function

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6411

* Reorganizing dashboard selector and vertical separator, fix widget tombstoning and undoability

* [autofix.ci] apply automated fixes

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6411

* fix dashboard not found spinner, fix dashboard deletion redirect, add SaveReportWrapper

* fix some deletion navigation issues and idioms

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6411

* Translate 'modified' status in SaveReport component

* [autofix.ci] apply automated fixes

---------

Co-authored-by: Matiss Janis Aboltins <matiss@mja.lv>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-01-13 22:41:47 +00:00
Stephen Brown II
93cce07542 fix(privacy): hide currency symbols in redacted overlay (#6438)
* fix(privacy): hide currency symbols in redacted overlay

Add RedactedContent component that uses useLayoutEffect to walk the DOM
and replace non-alphanumeric characters (like currency symbols) with spaces.
This ensures characters not rendered by Redacted Script font are hidden,
regardless of how deeply nested they are in the component tree.

* refactor: simplify RedactedContent text node processing loop
2026-01-13 22:19:19 +00:00
Matiss Janis Aboltins
b88feb9336 lint: patch some no-empty-function violations & delete unused code (#6642)
* lint: patch some no-empty-function violations

* docs: update ESLint rules and remove unused loadOwner function in UserAccess component

* refactor: remove getRemoteFile function and associated method from budget file handlers

* chore: disable docstring checks in coderabbit configuration
2026-01-13 22:05:24 +00:00
Matiss Janis Aboltins
0c3a515e29 Update linting rules and replace @ts-ignore with @ts-expect-error (#6636)
* Update linting rules and replace @ts-ignore with @ts-expect-error

* Add release notes for PR #6636

* Fix TypeScript linting issue by adding @ts-ignore for electron types in server start message

* Change category to Maintenance and update linting rules

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-13 21:53:14 +00:00
Copilot
5d82435700 Restrict AI-generated release notes workflow to PRs targeting master branch (#6622)
* Initial plan

* Add release notes for PR #6622

* Update release-notes workflow to only trigger for PRs against master

Co-authored-by: MatissJanis <886567+MatissJanis@users.noreply.github.com>

* Fix: Apply branch filter to AI release notes workflow instead of check workflow

Co-authored-by: MatissJanis <886567+MatissJanis@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: MatissJanis <886567+MatissJanis@users.noreply.github.com>
2026-01-13 21:27:42 +00:00
Copilot
bcf53007ca Fix missing final newline in generated release notes (#6641)
* Initial plan

* Add release notes for PR #6641

* Fix release-note-generator to add final newline to generated files

Co-authored-by: MatissJanis <886567+MatissJanis@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: MatissJanis <886567+MatissJanis@users.noreply.github.com>
2026-01-13 21:13:50 +00:00
Matiss Janis Aboltins
64aa88aa22 Add ACTIONS_UPDATE_TOKEN to GitHub Actions workflows (#6530)
* Add ACTIONS_UPDATE_TOKEN to GitHub Actions workflows

* Add release notes for PR #6530

* Update category for release notes

Changed category from Enhancements to Maintenance.

* Remove ACTIONS_UPDATE_TOKEN from GitHub Actions workflows for release notes generation

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-13 20:58:54 +00:00
Jonathon Jongsma
6d8cba1564 Crossover report: Remove leftover help text referring to linear trend. (#6638)
Accidentally forgotten in https://github.com/actualbudget/actual/pull/6589

Signed-off-by: Jonathon Jongsma <jonathon@quotidian.org>
2026-01-13 20:24:00 +00:00
Joel Jeremy Marquez
914074d4b6 Fix transactions table payee schedule icon not showing if linked schedule has a different account configured (#6561)
* Fix transactions table payee schedule icon not showing if linked schedule has a different account configured

* [autofix.ci] apply automated fixes

* Move SchedulesProvider higher in component tree

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-01-13 20:21:48 +00:00
lif
2b8a15f51c fix: skip schedule prompt for transactions already linked to schedule (#6569)
* fix: skip schedule prompt for transactions already linked to schedule

When editing a future-dated transaction on mobile that is already linked
to a schedule, the app was incorrectly showing the "convert to schedule"
prompt. This was confusing since the transaction was already associated
with a schedule.

This change adds a check for `unserializedTransaction.schedule` to skip
showing the schedule prompt if the transaction is already linked to a
schedule.

Fixes #6357

Signed-off-by: majiayu000 <1835304752@qq.com>

* fix: resolve build and lint issues in TransactionEdit.tsx

* docs: add release notes for PR #6569

* chore: remove duplicate release note file

Signed-off-by: majiayu000 <1835304752@qq.com>

* chore: rename release note file to match PR number

Signed-off-by: majiayu000 <1835304752@qq.com>

* fix: apply schedule prompt fix to desktop version

Signed-off-by: majiayu000 <1835304752@qq.com>

---------

Signed-off-by: majiayu000 <1835304752@qq.com>
2026-01-13 20:20:29 +00:00
Jonathon Jongsma
0467b13848 Update the projection types in crossover report (#6589)
* Add unfiltered median projection type to crossover report

Signed-off-by: Jonathon Jongsma <jonathon@quotidian.org>

* Add a new 'mean' projection type to crossover report

Some people may want to use the average monthly expenses rather than
median expenses.

Signed-off-by: Jonathon Jongsma <jonathon@quotidian.org>

* Remove 'linear trend' from crossover report

The linear projection type almost never provides any useful information
for projecting future expenses. For example, if my expenses have been
declining for the past several months, that doesn't mean that they will
continue to decline until they reach 0 in retirement. It's way too easy
to receive a nonsense projection with the linear projection type. Just
remove it.

Signed-off-by: Jonathon Jongsma <jonathon@quotidian.org>

* Add release notes for crossover point projections

Signed-off-by: Jonathon Jongsma <jonathon@quotidian.org>

* [autofix.ci] apply automated fixes

---------

Signed-off-by: Jonathon Jongsma <jonathon@quotidian.org>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-01-13 16:34:19 +00:00
Matiss Janis Aboltins
843e957757 Remove force reload feature (#6626)
* Remove force reload feature flag and related code

Co-authored-by: matiss <matiss@mja.lv>

* Add release notes for PR #6626

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-12 08:39:04 +00:00
RMcGhee
073725e270 Bug/1617 rules modal error (#6625)
* Remove error thrown and nonprod check

* Formatting

* Added release notes

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-01-11 22:11:08 +00:00
Çağdaş Şenel
0e20e17fa4 enable include current month option for last month (#6577) 2026-01-11 20:32:19 +00:00
Matiss Janis Aboltins
f1fd99eeac docs: blog post for Actual Budget Wrapped 2025 (#6580)
* Add blog post for Actual Budget Wrapped 2025

* Add release notes for PR #6580

* Delete upcoming-release-notes/6580.md

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-10 12:00:36 +00:00
RMcGhee
cf3a42792f Bug/5679 payee filter (#6594)
* Fix filters, added tests

* Added release notes

* [autofix.ci] apply automated fixes

* Fix missing awaits in test, use placeholder locator

* Added release notes file

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6594

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-10 10:16:08 +00:00
dependabot[bot]
d41af58daf chore(deps-dev): bump react-router from 7.9.6 to 7.12.0 in /packages/desktop-client (#6608)
* chore(deps-dev): bump react-router in /packages/desktop-client

Bumps [react-router](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router) from 7.9.6 to 7.12.0.
- [Release notes](https://github.com/remix-run/react-router/releases)
- [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router/CHANGELOG.md)
- [Commits](https://github.com/remix-run/react-router/commits/react-router@7.12.0/packages/react-router)

---
updated-dependencies:
- dependency-name: react-router
  dependency-version: 7.12.0
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>

* Add release notes for PR #6608

* fix release notes

Updated authors field to remove bot notation.

* yarn lock

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Michael Clark <5285928+MikesGlitch@users.noreply.github.com>
2026-01-10 09:50:36 +00:00
youngcw
25ee19c1e1 [Goals] Fix some schedule template regressions (#6610)
* Small fix

* Add release notes for PR #6610

* Apply suggestions from code review

Co-authored-by: Joel Jeremy Marquez <joeljeremy.marquez@gmail.com>

* review

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Joel Jeremy Marquez <joeljeremy.marquez@gmail.com>
2026-01-10 00:29:38 +00:00
1008 changed files with 14062 additions and 5978 deletions

View File

@@ -3,24 +3,15 @@ issue_enrichment:
enabled: false
reviews:
request_changes_workflow: true
review_status: true
review_status: false
high_level_summary: false
finishing_touches:
docstrings:
enabled: false
pre_merge_checks:
docstrings:
mode: off
enabled: false
custom_checks:
- mode: error
name: 'settings'
instructions: 'Every addition of a new setting toggle must be thoroughly evaluated against the core design principles of Actual. The settings screen is reserved for essential and foundational options only — do not introduce settings for minor UI adjustments such as sizes, paddings, colors, or margins. Prioritize preserving a simple and uncluttered user experience. Users proposing new settings must confirm in a reply to the Coderabbit comment that they have reviewed and ensured alignment with these principles. Excessive or granular UI options increase code complexity and risk confusing users, and are generally not permitted.'
- mode: error
name: 'linting'
instructions: 'Do not allow any oxlint-disable lines.'
- mode: error
name: 'typecheck'
instructions: 'Do not allow creating new components or utilities with the @ts-strict-ignore comment.'
labeling_instructions:
- label: 'suspect ai generated'
instructions: 'This issue or PR is suspected to be generated by AI.'

View File

@@ -33,11 +33,11 @@ try {
{
role: 'system',
content:
'You are categorizing pull requests for release notes. You must respond with exactly one of these categories: "Features", "Enhancements", "Bugfix", or "Maintenance". No other text or explanation.',
'You are categorizing pull requests for release notes. You must respond with exactly one of these categories: "Features", "Enhancements", "Bugfixes", or "Maintenance". No other text or explanation.',
},
{
role: 'user',
content: `PR Title: ${prDetails.title}\n\nGenerated Summary: ${summaryData.summary}\n\nCodeRabbit Analysis:\n${commentBody}\n\nCategories:\n- Features: New functionality or capabilities\n- Bugfix: Fixes for broken or incorrect behavior\n- Enhancements: Improvements to existing functionality\n- Maintenance: Code cleanup, refactoring, dependencies, etc.\n\nWhat category does this PR belong to?`,
content: `PR Title: ${prDetails.title}\n\nGenerated Summary: ${summaryData.summary}\n\nCodeRabbit Analysis:\n${commentBody}\n\nCategories:\n- Features: New functionality or capabilities\n- Bugfixes: Fixes for broken or incorrect behavior\n- Enhancements: Improvements to existing functionality\n- Maintenance: Code cleanup, refactoring, dependencies, etc.\n\nWhat category does this PR belong to?`,
},
],
max_tokens: 10,
@@ -86,7 +86,7 @@ try {
// Validate the category response
const validCategories = [
'Features',
'Bugfix',
'Bugfixes',
'Enhancements',
'Maintenance',
];

View File

@@ -36,11 +36,13 @@ async function getPRDetails() {
console.log('- PR Number:', pr.number);
console.log('- PR Author:', pr.user.login);
console.log('- PR Title:', pr.title);
console.log('- Base Branch:', pr.base.ref);
const result = {
number: pr.number,
author: pr.user.login,
title: pr.title,
baseBranch: pr.base.ref,
};
setOutput('result', JSON.stringify(result));

View File

@@ -5,6 +5,7 @@ Activo
AESUDEF
ALZEY
Anglais
ANZ
aql
AUR
Authentik
@@ -40,13 +41,13 @@ COBADEFF
CODEOWNERS
COEP
commerzbank
COOP
Copiar
COUNTA
COUNTBLANK
countif
CREGBEBB
crt
CZK
Danske
datadir
DATEDIF
@@ -68,7 +69,6 @@ Fineco
Finicity
Fintro
Finverse
flathub
Flathub
FORTUNEO
FTNOFRP
@@ -83,6 +83,7 @@ HABAL
Hampel
HELADEF
HLOOKUP
HUF
IFERROR
IFNA
INDUSTRIEL
@@ -116,12 +117,14 @@ LKR
MAXA
mbank
mdc
metainfo
modals
Moldovan
murmurhash
NETWORKDAYS
nginx
OIDC
Okabe
overbudgeted
overbudgeting
oxc
@@ -134,7 +137,6 @@ prefs
Primoco
Priotecs
proactively
pwa
Qatari
QNTOFRP
QONTO
@@ -172,6 +174,7 @@ touchscreen
triaging
UAH
ubuntu
undici
userinfo
Userscripts
UZS

View File

@@ -278,7 +278,7 @@ async function countContributorPoints() {
if (
event.event === 'closed' &&
event.state_reason === 'not_planned'
['not_planned', 'duplicate'].includes(event.state_reason)
) {
const closer = event.actor.login;
const userStats = stats.get(closer);

View File

@@ -41,8 +41,21 @@ jobs:
GITHUB_REPOSITORY: ${{ github.repository }}
GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }}
- name: Check if release notes file already exists
- name: Check if PR targets master branch
if: steps.check-first-comment.outputs.result == 'true' && steps.pr-details.outputs.result != 'null'
id: check-base-branch
run: |
BASE_BRANCH=$(echo '${{ steps.pr-details.outputs.result }}' | jq -r '.baseBranch')
echo "Base branch: $BASE_BRANCH"
if [ "$BASE_BRANCH" = "master" ]; then
echo "targets_master=true" >> $GITHUB_OUTPUT
else
echo "targets_master=false" >> $GITHUB_OUTPUT
echo "PR does not target master branch, skipping release notes generation"
fi
- name: Check if release notes file already exists
if: steps.check-first-comment.outputs.result == 'true' && steps.pr-details.outputs.result != 'null' && steps.check-base-branch.outputs.targets_master == 'true'
id: check-release-notes-exists
run: node .github/actions/ai-generated-release-notes/check-release-notes-exists.js
env:

View File

@@ -1,33 +0,0 @@
name: Release Docs to Github Pages
# Release docs on every push to master
on:
push:
branches:
- master
paths:
- 'packages/docs/**'
- '.github/workflows/docs-spelling.yml'
- '.github/actions/docs-spelling/**'
workflow_dispatch:
jobs:
deploy:
runs-on: ubuntu-latest
name: Deploy Docs
if: github.event.repository.fork == false
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up environment
uses: ./.github/actions/setup
with:
download-translations: 'false'
- name: Docusaurus Deploy
run: |
GIT_USER=MikesGlitch \
GIT_PASS=${{ secrets.DOCS_GITHUB_PAGES_DEPLOY }} \
GIT_USER_NAME=github-actions[bot] \
GIT_USER_EMAIL=github-actions[bot]@users.noreply.github.com \
yarn deploy:docs

View File

@@ -30,7 +30,7 @@ jobs:
matrix:
shard: [1, 2, 3, 4, 5]
container:
image: mcr.microsoft.com/playwright:v1.56.0-jammy
image: mcr.microsoft.com/playwright:v1.57.0-jammy
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up environment
@@ -53,7 +53,7 @@ jobs:
name: Functional Desktop App
runs-on: ubuntu-latest
container:
image: mcr.microsoft.com/playwright:v1.56.0-jammy
image: mcr.microsoft.com/playwright:v1.57.0-jammy
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up environment
@@ -81,7 +81,7 @@ jobs:
matrix:
shard: [1, 2, 3, 4, 5]
container:
image: mcr.microsoft.com/playwright:v1.56.0-jammy
image: mcr.microsoft.com/playwright:v1.57.0-jammy
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up environment
@@ -104,7 +104,7 @@ jobs:
runs-on: ubuntu-latest
if: ${{ !cancelled() }}
container:
image: mcr.microsoft.com/playwright:v1.56.0-jammy
image: mcr.microsoft.com/playwright:v1.57.0-jammy
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up environment

48
.github/workflows/fork-pr-welcome.yml vendored Normal file
View File

@@ -0,0 +1,48 @@
name: Fork PR Welcome
##########################################################################################
# WARNING! This workflow uses the 'pull_request_target' event. That means that it will #
# always run in the context of the main actualbudget/actual repo, even if the PR is from #
# a fork. This is necessary to get access to a GitHub token that can post a comment on #
# the PR. Be VERY CAREFUL about adding things to this workflow, since forks can inject #
# arbitrary code into their branch, and can pollute the artifacts we download. Arbitrary #
# code execution in this workflow could lead to a compromise of the main repo. #
##########################################################################################
# See: https://securitylab.github.com/research/github-actions-preventing-pwn-requests #
##########################################################################################
on:
pull_request_target:
types: [opened, reopened]
permissions:
pull-requests: write
jobs:
welcome:
name: Post Welcome Message
runs-on: ubuntu-latest
if: github.event.pull_request.head.repo.full_name != github.repository
steps:
- name: Post welcome comment
uses: marocchino/sticky-pull-request-comment@773744901bac0e8cbb5a0dc842800d45e9b2b405 # v2.9.4
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
number: ${{ github.event.pull_request.number }}
header: fork-pr-welcome
hide_and_recreate: true
hide_classify: OUTDATED
message: |
<!-- fork-pr-welcome -->
👋 Hello contributor!
We would love to review your PR! Before we can do that, please make sure:
- ✅ All CI checks pass
- ✅ The PR is moved from draft to open (if applicable)
- ✅ The "[WIP]" prefix is removed from the PR title
- ✅ All CodeRabbit code review comments are resolved (if you disagree with anything - reply to the bot with your reasoning so we can read through it). The bot will eventually approve the PR.
We do this to reduce the TOIL the core contributor team has to go through for each PR and to allow for speedy reviews and merges.
For more information, please see our [Contributing Guide](https://actualbudget.org/docs/contributing/).

View File

@@ -35,7 +35,10 @@ jobs:
pkg="${packages[$key]}"
if [[ -n "${{ github.event.inputs.version }}" ]]; then
version="${{ github.event.inputs.version }}"
version=$(node ./packages/ci-actions/bin/get-next-package-version.js \
--package-json "./packages/$pkg/package.json" \
--version "${{ github.event.inputs.version }}" \
--update)
else
version=$(node ./packages/ci-actions/bin/get-next-package-version.js \
--package-json "./packages/$pkg/package.json" \
@@ -50,6 +53,7 @@ jobs:
- name: Create PR
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8
with:
token: ${{ secrets.ACTIONS_UPDATE_TOKEN }}
commit-message: '🔖 (${{ steps.bump_package_versions.outputs.version }})'
title: '🔖 (${{ steps.bump_package_versions.outputs.version }})'
body: 'Generated by [generate-release-pr.yml](../tree/master/.github/workflows/generate-release-pr.yml)'

View File

@@ -0,0 +1,25 @@
name: Remove 'suspect ai generated' label when 'AI generated' is present
on:
pull_request_target:
types: [labeled]
permissions:
pull-requests: write
jobs:
remove-suspect-label:
if: >-
${{ contains(github.event.pull_request.labels.*.name, 'AI generated') &&
contains(github.event.pull_request.labels.*.name, 'suspect ai generated') }}
runs-on: ubuntu-slim
steps:
- uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
script: |
await github.rest.issues.removeLabel({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
name: 'suspect ai generated'
});

View File

@@ -1,6 +1,6 @@
name: Publish nightly npm packages
# Nightly npm packages are built daily
# Nightly npm packages are built daily at midnight UTC
on:
schedule:
- cron: '0 0 * * *'

View File

@@ -139,7 +139,8 @@ jobs:
--head desktop-client=./head/web-stats.json \
--head loot-core=./head/loot-core-stats.json \
--head api=./head/api-stats.json \
--identifier combined > bundle-stats-comment.md
--identifier combined \
--format pr-body > bundle-stats-comment.md
- name: Post combined bundle stats comment
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -148,4 +149,5 @@ jobs:
run: |
node packages/ci-actions/bin/update-bundle-stats-comment.mjs \
--comment-file bundle-stats-comment.md \
--identifier '<!--- bundlestats-action-comment key:combined --->'
--identifier combined \
--target pr-body

View File

@@ -44,7 +44,7 @@ jobs:
github.event.issue.pull_request &&
startsWith(github.event.comment.body, '/update-vrt')
container:
image: mcr.microsoft.com/playwright:v1.56.0-jammy
image: mcr.microsoft.com/playwright:v1.57.0-jammy
steps:
- name: Get PR details
id: pr

3
.gitignore vendored
View File

@@ -76,3 +76,6 @@ build/
# Lage cache
.lage/
*storybook.log
storybook-static

View File

@@ -4,7 +4,31 @@
"trailingComma": "all",
"arrowParens": "avoid",
"printWidth": 80,
"ignorePatterns": [
"packages/docs/*" // TOOD: fixme; temporary
]
"experimentalSortImports": {
"groups": [
"react",
"builtin",
"external",
"loot-core",
"parent",
"sibling",
"index",
"desktop-client"
],
"customGroups": [
{
"groupName": "react",
"elementNamePattern": ["react"]
},
{
"groupName": "loot-core",
"elementNamePattern": ["loot-core"]
},
{
"groupName": "desktop-client",
"elementNamePattern": ["@desktop-client"]
}
],
"newlinesBetween": true
}
}

View File

@@ -15,44 +15,14 @@
"vi": "readonly",
"backend": "readonly",
"importScripts": "readonly",
"FS": "readonly" // TODO: remove this
"FS": "readonly"
},
"rules": {
// TODO fix all these and re-enable
"jsx-a11y/click-events-have-key-events": "off",
"jsx-a11y/prefer-tag-over-role": "off",
"jsx-a11y/tabindex-no-positive": "off",
// Import sorting
// TODO replace once oxfmt supports this: https://github.com/oxc-project/oxc/issues/17076
"perfectionist/sort-imports": [
"perfectionist/sort-named-imports": [
"warn",
{
"groups": [
"react",
"builtin",
"external",
"loot-core",
"parent",
"sibling",
"index",
"desktop-client"
],
"customGroups": [
{
"groupName": "react",
"elementNamePattern": "^react(-.*)?$"
},
{
"groupName": "loot-core",
"elementNamePattern": "^loot-core"
},
{
"groupName": "desktop-client",
"elementNamePattern": "^@desktop-client"
}
],
"newlinesBetween": "always"
"groups": ["value-import", "type-import"]
}
],
@@ -103,13 +73,7 @@
"jsx-a11y/scope": "warn",
// Typescript rules
"typescript/ban-ts-comment": [
"warn",
{
// TODO: remove this
"ts-ignore": "allow-with-description"
}
],
"typescript/ban-ts-comment": ["warn"],
"typescript/consistent-type-definitions": ["warn", "type"],
"typescript/consistent-type-imports": [
"warn",
@@ -190,7 +154,7 @@
// ESLint rules
"eslint/array-callback-return": "warn",
// "eslint/curly": ["warn", "multi-line", "consistent"], // TODO: re-enable? this rule is really slow
"eslint/curly": ["warn", "multi-line", "consistent"],
"eslint/default-case": [
"warn",
{
@@ -382,55 +346,9 @@
},
"overrides": [
{
// TODO: fix the issues in these files
"files": [
"packages/component-library/src/Menu.tsx",
"packages/desktop-client/src/components/accounts/Account.jsx",
"packages/desktop-client/src/components/accounts/MobileAccount.jsx",
"packages/desktop-client/src/components/accounts/MobileAccounts.jsx",
"packages/desktop-client/src/components/budget/BudgetCategories.jsx",
"packages/desktop-client/src/components/budget/BudgetSummaries.tsx",
"packages/desktop-client/src/components/budget/DynamicBudgetTable.tsx",
"packages/desktop-client/src/components/budget/envelope/HoldMenu.tsx",
"packages/desktop-client/src/components/budget/envelope/TransferMenu.tsx",
"packages/desktop-client/src/components/budget/index.tsx",
"packages/desktop-client/src/components/budget/MobileBudget.tsx",
"packages/desktop-client/src/components/FinancesApp.tsx",
"packages/desktop-client/src/components/GlobalKeys.ts",
"packages/desktop-client/src/components/LoggedInUser.tsx",
"packages/desktop-client/src/components/manager/ManagementApp.jsx",
"packages/desktop-client/src/components/manager/subscribe/common.tsx",
"packages/desktop-client/src/components/ManageRules.tsx",
"packages/desktop-client/src/components/mobile/MobileAmountInput.jsx",
"packages/desktop-client/src/components/mobile/MobileNavTabs.tsx",
"packages/desktop-client/src/components/Modals.tsx",
"packages/desktop-client/src/components/modals/EditRule.jsx",
"packages/desktop-client/src/components/modals/ImportTransactions.jsx",
"packages/desktop-client/src/components/modals/ImportTransactionsModal/ImportTransactionsModal.tsx",
"packages/desktop-client/src/components/modals/MergeUnusedPayees.jsx",
"packages/desktop-client/src/components/Notifications.tsx",
"packages/desktop-client/src/components/payees/ManagePayees.jsx",
"packages/desktop-client/src/components/payees/ManagePayeesWithData.jsx",
"packages/desktop-client/src/components/payees/PayeeTable.tsx",
"packages/desktop-client/src/components/reports/graphs/tableGraph/ReportTable.tsx",
"packages/desktop-client/src/components/reports/graphs/tableGraph/ReportTableTotals.tsx",
"packages/desktop-client/src/components/reports/reports/CashFlowCard.jsx",
"packages/desktop-client/src/components/reports/reports/CustomReport.jsx",
"packages/desktop-client/src/components/reports/reports/CustomReport.tsx",
"packages/desktop-client/src/components/reports/reports/NetWorthCard.jsx",
"packages/desktop-client/src/components/reports/SaveReportName.tsx",
"packages/desktop-client/src/components/reports/useReport.ts",
"packages/desktop-client/src/components/schedules/ScheduleDetails.jsx",
"packages/desktop-client/src/components/schedules/ScheduleEditModal.tsx",
"packages/desktop-client/src/components/schedules/SchedulesTable.tsx",
"packages/desktop-client/src/components/select/DateSelect.tsx",
"packages/desktop-client/src/components/sidebar/Tools.tsx",
"packages/desktop-client/src/components/sort.tsx",
"packages/desktop-client/src/hooks/useEffectAfterMount.ts",
"packages/desktop-client/src/hooks/useQuery.ts"
],
"files": ["packages/desktop-electron/**/*"],
"rules": {
"react/exhaustive-deps": "off"
"react/rules-of-hooks": "off"
}
},
{
@@ -470,16 +388,9 @@
// TODO: enable these
{
"files": [
"packages/desktop-client/src/components/admin/UserAccess/UserAccess.tsx",
"packages/desktop-client/src/components/admin/UserDirectory/UserDirectory.tsx",
"packages/desktop-client/src/components/budget/BudgetCategories.tsx",
"packages/desktop-client/src/components/budget/envelope/BalanceMovementMenu.tsx",
"packages/desktop-client/src/components/ManageRules.tsx",
"packages/desktop-client/src/components/mobile/budget/ExpenseGroupList.tsx",
"packages/desktop-client/src/components/modals/EditFieldModal.tsx",
"packages/desktop-client/src/components/reports/reports/Calendar.tsx",
"packages/desktop-client/src/components/schedules/ScheduleLink.tsx",
"packages/desktop-client/src/components/ServerContext.tsx",
"packages/desktop-client/src/components/table.tsx"
],
"rules": {

View File

@@ -169,7 +169,7 @@ Custom ESLint rules specific to Actual.
- `no-untranslated-strings`: Enforces i18n usage
- `prefer-trans-over-t`: Prefers Trans component over t() function
- `prefer-logger-over-console`: Enforces using logger instead of console
- `prefer-logger-over-console`: Enforces using logger instead of console in `packages/loot-core/`
- `typography`: Typography rules
- `prefer-if-statement`: Prefers explicit if statements
@@ -259,6 +259,10 @@ Always run `yarn typecheck` before committing.
- Generate i18n files: `yarn generate:i18n`
- Custom ESLint rules enforce translation usage
### 5. Financial Number Typography
- Wrap standalone financial numbers with `FinancialText` or apply `styles.tnum` directly if wrapping is not possible
## Code Style & Conventions
### TypeScript Guidelines
@@ -328,7 +332,6 @@ Always maintain newlines between import groups.
**Never:**
- Use `console.*` (use logger instead - enforced by ESLint)
- Import from `uuid` without destructuring: use `import { v4 as uuidv4 } from 'uuid'`
- Import colors directly - use theme instead
- Import `@actual-app/web/*` in `loot-core`
@@ -541,7 +544,6 @@ Before committing changes, ensure:
- [ ] `yarn typecheck` passes
- [ ] `yarn lint:fix` has been run
- [ ] Relevant tests pass
- [ ] No new console.\* usage (use logger)
- [ ] User-facing strings are translated
- [ ] Prefer `type` over `interface`
- [ ] Named exports used (not default exports)
@@ -555,6 +557,10 @@ When creating pull requests:
- **AI-Generated PRs**: If you create a PR using AI assistance, add the **"AI generated"** label to the pull request. This helps maintainers understand the nature of the contribution.
## Code Review Guidelines
When performing code reviews (especially for LLM agents): **see [CODE_REVIEW_GUIDELINES.md](./CODE_REVIEW_GUIDELINES.md)** for specific guidelines.
## Performance Considerations
- **Bundle Size**: Check with rollup-plugin-visualizer

94
CODE_REVIEW_GUIDELINES.md Normal file
View File

@@ -0,0 +1,94 @@
# CODE_REVIEW_GUIDELINES.md - Guidelines for LLM Agents Performing Code Reviews
This document provides specific guidelines for LLM agents performing code reviews on the Actual Budget codebase. These guidelines help maintain code quality, consistency, and follow the project's design principles.
## Settings Proliferation
**Do NOT add new settings for every little UI tweak.**
Actual Budget follows a design philosophy that prioritizes simplicity and avoids settings bloat. Before introducing code that adds new settings:
- Consider if the UI tweak can be achieved through existing theme/design tokens
- Evaluate whether the setting provides meaningful value to users
- Check if the change aligns with Actual's design guidelines
- Prefer hardcoded values or theme-based solutions over adding user-facing settings
## TypeScript Strict Mode Suppressions
**Do NOT approve code that adds new `@ts-strict-ignore` comments.**
The project uses strict TypeScript checking via `typescript-strict-plugin`. Adding `@ts-strict-ignore` comments undermines type safety. Instead, review should encourage:
- Fixing the underlying type issue
- Using proper type definitions
- Refactoring code to satisfy strict type checking
- Only in exceptional cases, document why strict checking cannot be applied and seek alternative solutions
## Linter Suppressions
**Do NOT approve code that adds new `eslint-disable` or `oxlint-disable` comments.**
Linter rules are in place for good reasons. Instead of suppressing them:
- Fix the underlying issue
- If the rule is incorrectly flagging valid code, consider if the code can be refactored
- Only approve suppressions if there's a documented, exceptional reason
## Type Assertions
**Prefer `x satisfies SomeType` over `x as SomeType` for type coercions.**
The `satisfies` operator provides better type safety by:
- Ensuring the value actually satisfies the type (narrowing)
- Preserving the actual type information for better inference
- Catching type mismatches at compile time
**Exception:** If you truly need to assert a type that TypeScript cannot verify (e.g., runtime type guards), use `as` but require a comment explaining why it's safe.
## Avoiding `any` and `unknown`
**Flag code that uses `any` or `unknown` unless absolutely necessary.**
The use of `any` or `unknown` should be rare and well-justified. Before approving:
- Require explicit justification for why the type cannot be determined
- Suggest using proper type definitions or generics
- Consider if the type can be narrowed or properly inferred
- Look for existing type definitions in `packages/loot-core/src/types/`
Only approve `any` or `unknown` if there's a documented, exceptional reason (e.g., interop with untyped external libraries, gradual migration).
## Internationalization (i18n)
**All user-facing strings must be translated.**
The project has custom ESLint rules (`actual/no-untranslated-strings`) that enforce i18n usage, but reviewers should actively flag untranslated strings:
- Use `Trans` component instead of `t()` function when possible
- All text visible to users must use i18n functions
- Flag hardcoded strings that should be translated
## Test Mocking
**Minimize mocked dependencies; prefer real implementations.**
When reviewing tests, encourage the use of real implementations over mocks:
- Prefer real dependencies, utilities, and data structures
- Only mock when the real implementation is impractical (e.g., external APIs, file system in unit tests)
- Ensure mocks accurately represent real behavior
Over-mocking makes tests brittle and less reliable. Real implementations provide better confidence that code works correctly.
## Financial Number Typography
Standalone financial numbers should have tabular number styles applied.
- Standalone financial numbers should be wrapped with `FinancialText` or `styles.tnum` should be applied directly if wrapping is not possible
## Related Documentation
- See [AGENTS.md](./AGENTS.md) for general development guidelines
- See [CONTRIBUTING.md](./CONTRIBUTING.md) for contribution guidelines
- Community documentation: [https://actualbudget.org/docs/contributing/](https://actualbudget.org/docs/contributing/)

View File

@@ -37,7 +37,7 @@ async function run() {
choices: [
{ title: '✨ Features', value: 'Features' },
{ title: '👍 Enhancements', value: 'Enhancements' },
{ title: '🐛 Bugfix', value: 'Bugfix' },
{ title: '🐛 Bugfixes', value: 'Bugfixes' },
{ title: '⚙️ Maintenance', value: 'Maintenance' },
],
},
@@ -160,7 +160,8 @@ category: ${type}
authors: [${username}]
---
${summary}`;
${summary}
`;
}
// simple exec that fails silently and returns an empty string on failure

View File

@@ -28,5 +28,5 @@ echo "Running VRT tests with the following parameters:"
echo "E2E_START_URL: $E2E_START_URL"
echo "VRT_ARGS: $VRT_ARGS"
MSYS_NO_PATHCONV=1 docker run --rm --network host -v "$(pwd)":/work/ -w /work/ -it mcr.microsoft.com/playwright:v1.56.0-jammy /bin/bash \
MSYS_NO_PATHCONV=1 docker run --rm --network host -v "$(pwd)":/work/ -w /work/ -it mcr.microsoft.com/playwright:v1.57.0-jammy /bin/bash \
-c "E2E_START_URL=$E2E_START_URL yarn vrt $VRT_ARGS"

View File

@@ -33,6 +33,7 @@
"start:service-plugins": "yarn workspace plugins-service watch",
"start:browser-backend": "yarn workspace loot-core watch:browser",
"start:browser-frontend": "yarn workspace @actual-app/web start:browser",
"start:storybook": "yarn workspace @actual-app/components start:storybook",
"build:browser-backend": "yarn workspace loot-core build:browser",
"build:server": "yarn build:browser && yarn workspace @actual-app/sync-server build",
"build:browser": "./bin/package-browser",
@@ -40,6 +41,7 @@
"build:plugins-service": "yarn workspace plugins-service build",
"build:api": "yarn workspace @actual-app/api build",
"build:docs": "yarn workspace docs build",
"build:storybook": "yarn workspace @actual-app/components build:storybook",
"deploy:docs": "yarn workspace docs deploy",
"generate:i18n": "yarn workspace @actual-app/web generate:i18n",
"generate:release-notes": "ts-node ./bin/release-note-generator.ts",
@@ -61,8 +63,9 @@
},
"devDependencies": {
"@octokit/rest": "^22.0.1",
"@types/node": "^22.19.1",
"@types/node": "^22.19.3",
"@types/prompts": "^2.4.9",
"baseline-browser-mapping": "^2.9.14",
"cross-env": "^10.1.0",
"eslint": "^9.39.2",
"eslint-plugin-perfectionist": "^4.15.1",
@@ -74,8 +77,8 @@
"minimatch": "^10.1.1",
"node-jq": "^6.3.1",
"npm-run-all": "^4.1.5",
"oxfmt": "^0.22.0",
"oxlint": "^1.37.0",
"oxfmt": "^0.26.0",
"oxlint": "^1.41.0",
"p-limit": "^7.2.0",
"prompts": "^2.4.2",
"source-map-support": "^0.5.21",

View File

@@ -6,6 +6,7 @@ import type {
// loot-core types
import type { InitConfig } from 'loot-core/server/main';
// oxlint-disable-next-line typescript/ban-ts-comment
// @ts-ignore: bundle not available until we build it
import * as bundle from './app/bundle.api.js';
import * as injected from './injected';

View File

@@ -1,6 +1,6 @@
{
"name": "@actual-app/api",
"version": "26.1.0",
"version": "26.2.1",
"description": "An API for Actual",
"license": "MIT",
"files": [
@@ -21,7 +21,7 @@
},
"dependencies": {
"@actual-app/crdt": "workspace:^",
"better-sqlite3": "^12.4.1",
"better-sqlite3": "^12.5.0",
"compare-versions": "^6.1.1",
"node-fetch": "^3.3.2",
"uuid": "^13.0.0"
@@ -29,7 +29,7 @@
"devDependencies": {
"tsc-alias": "^1.8.16",
"typescript": "^5.9.3",
"vitest": "^4.0.9"
"vitest": "^4.0.16"
},
"engines": {
"node": ">=20"

View File

@@ -1,3 +1,4 @@
// oxlint-disable-next-line typescript/ban-ts-comment
// @ts-ignore: bundle not available until we build it
import * as bundle from './app/bundle.api.js';

View File

@@ -174,6 +174,7 @@ function parseArgs(argv) {
return {
sections,
identifier: getSingleValue(args, 'identifier') ?? 'bundle-stats',
format: getSingleValue(args, 'format') ?? 'pr-body',
};
}
@@ -463,6 +464,12 @@ const TOTAL_HEADERS = makeHeader([
'Total bundle size',
'% Changed',
]);
const SUMMARY_HEADERS = makeHeader([
'Bundle',
'Files count',
'Total bundle size',
'% Changed',
]);
const TABLE_HEADERS = makeHeader(['Asset', 'File Size', '% Changed']);
const CHUNK_TABLE_HEADERS = makeHeader(['File', 'Δ', 'Size']);
@@ -596,6 +603,24 @@ function printTotalAssetTable(statsDiff) {
return `**Total**\n${TOTAL_HEADERS}\n${printAssetTableRow(statsDiff.total)}`;
}
function printSummaryTable(sections) {
if (sections.length === 0) {
return `${SUMMARY_HEADERS}\nNo bundle stats were generated.`;
}
const rows = sections.map(section => {
const total = section.statsDiff.total;
return [
section.name,
total.name,
toFileSizeDiffCell(total),
conditionalPercentage(total.diffPercentage),
].join(' | ');
});
return `${SUMMARY_HEADERS}\n${rows.join('\n')}`;
}
function renderSection(title, statsDiff, chunkModuleDiff) {
const { total, ...groups } = statsDiff;
const parts = [`#### ${title}`, '', printTotalAssetTable({ total })];
@@ -615,8 +640,30 @@ function renderSection(title, statsDiff, chunkModuleDiff) {
return parts.join('\n');
}
function renderSections(sections) {
return sections
.map(section =>
renderSection(section.name, section.statsDiff, section.chunkDiff),
)
.join('\n\n---\n\n');
}
function getIdentifierMarkers(key) {
const label = 'bundlestats-action-comment';
return {
start: `<!--- ${label} key:${key} start --->`,
end: `<!--- ${label} key:${key} end --->`,
};
}
async function main() {
const args = parseArgs(process.argv);
const allowedFormats = new Set(['comment', 'pr-body']);
if (!allowedFormats.has(args.format)) {
throw new Error(
`Invalid format "${args.format}". Use "comment" or "pr-body".`,
);
}
console.error(
`[bundle-stats] Found ${args.sections.length} sections to process`,
@@ -654,22 +701,29 @@ async function main() {
});
}
const identifier = `<!--- bundlestats-action-comment key:${args.identifier} --->`;
const markers = getIdentifierMarkers(args.identifier);
const sectionsContent = renderSections(sections);
const summaryTable = printSummaryTable(sections);
const comment = [
const detailedBody = ['### Bundle Stats', '', sectionsContent].join('\n');
const commentBody = [markers.start, detailedBody, '', markers.end, ''].join(
'\n',
);
const prBody = [
markers.start,
'### Bundle Stats',
'',
sections
.map(section =>
renderSection(section.name, section.statsDiff, section.chunkDiff),
)
.join('\n\n---\n\n'),
summaryTable,
'',
identifier,
`<details>\n<summary>View detailed bundle stats</summary>\n\n${sectionsContent}\n</details>`,
'',
markers.end,
'',
].join('\n');
process.stdout.write(comment);
process.stdout.write(args.format === 'comment' ? commentBody : prBody);
}
main().catch(error => {

View File

@@ -19,6 +19,10 @@ const options = {
type: 'string', // nightly, hotfix, monthly, auto
short: 't',
},
version: {
type: 'string',
short: 'v',
},
update: {
type: 'boolean',
short: 'u',
@@ -44,16 +48,21 @@ try {
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
const currentVersion = packageJson.version;
const explicitVersion = values.version;
let newVersion;
try {
newVersion = getNextVersion({
currentVersion,
type: values.type,
currentDate: new Date(),
});
} catch (e) {
console.error(e.message);
process.exit(1);
if (explicitVersion) {
newVersion = explicitVersion;
} else {
try {
newVersion = getNextVersion({
currentVersion,
type: values.type,
currentDate: new Date(),
});
} catch (e) {
console.error(e.message);
process.exit(1);
}
}
process.stdout.write(newVersion);

View File

@@ -14,10 +14,14 @@ import process from 'node:process';
import { Octokit } from '@octokit/rest';
const BOT_BOUNDARY_MARKER = '<!--- actual-bot-sections --->';
const BOT_BOUNDARY_TEXT = `${BOT_BOUNDARY_MARKER}\n<hr />`;
function parseArgs(argv) {
const args = {
commentFile: null,
identifier: null,
target: 'comment',
};
for (let i = 2; i < argv.length; i += 2) {
@@ -41,6 +45,9 @@ function parseArgs(argv) {
case '--identifier':
args.identifier = value;
break;
case '--target':
args.target = value;
break;
default:
throw new Error(`Unknown argument "${key}".`);
}
@@ -54,6 +61,12 @@ function parseArgs(argv) {
throw new Error('Missing required argument "--identifier".');
}
if (!['comment', 'pr-body'].includes(args.target)) {
throw new Error(
`Invalid value "${args.target}" for "--target". Use "comment" or "pr-body".`,
);
}
return args;
}
@@ -110,20 +123,123 @@ function isGitHubActionsBot(comment) {
return comment.user?.login === 'github-actions[bot]';
}
function escapeRegExp(value) {
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
function getIdentifierMarkers(identifier) {
if (identifier.includes('<!---')) {
return {
start: identifier,
end: null,
};
}
const label = 'bundlestats-action-comment';
return {
start: `<!--- ${label} key:${identifier} start --->`,
end: `<!--- ${label} key:${identifier} end --->`,
};
}
function upsertBlock(existingBody, block, markers) {
const body = existingBody ?? '';
if (markers.end) {
const pattern = new RegExp(
`${escapeRegExp(markers.start)}[\\s\\S]*?${escapeRegExp(markers.end)}`,
'm',
);
if (pattern.test(body)) {
return body.replace(pattern, block.trim());
}
}
if (body.trim().length === 0) {
return block.trim();
}
const separator = body.endsWith('\n') ? '\n' : '\n\n';
const boundary = body.includes(BOT_BOUNDARY_MARKER)
? ''
: `${BOT_BOUNDARY_TEXT}\n\n`;
return `${body}${separator}${boundary}${block.trim()}`;
}
async function updatePullRequestBody(
octokit,
owner,
repo,
pullNumber,
block,
markers,
) {
const { data } = await octokit.rest.pulls.get({
owner,
repo,
pull_number: pullNumber,
});
const nextBody = upsertBlock(data.body ?? '', block, markers);
await octokit.rest.pulls.update({
owner,
repo,
pull_number: pullNumber,
body: nextBody,
});
}
async function deleteExistingComment(
octokit,
owner,
repo,
issueNumber,
markers,
) {
const comments = await listComments(octokit, owner, repo, issueNumber);
const existingComment = comments.find(
comment =>
isGitHubActionsBot(comment) && comment.body?.includes(markers.start),
);
if (existingComment) {
await octokit.rest.issues.deleteComment({
owner,
repo,
comment_id: existingComment.id,
});
}
}
async function main() {
const { commentFile, identifier } = parseArgs(process.argv);
const { commentFile, identifier, target } = parseArgs(process.argv);
const commentBody = await loadCommentBody(commentFile);
const token = assertGitHubToken();
const { owner, repo } = getRepoInfo();
const issueNumber = getPullRequestNumber();
const markers = getIdentifierMarkers(identifier);
const octokit = new Octokit({ auth: token });
const comments = await listComments(octokit, owner, repo, issueNumber);
if (target === 'pr-body') {
await updatePullRequestBody(
octokit,
owner,
repo,
issueNumber,
commentBody,
markers,
);
await deleteExistingComment(octokit, owner, repo, issueNumber, markers);
console.log('Updated pull request body with bundle stats.');
return;
}
const comments = await listComments(octokit, owner, repo, issueNumber);
const existingComment = comments.find(
comment =>
isGitHubActionsBot(comment) && comment.body?.includes(identifier),
isGitHubActionsBot(comment) && comment.body?.includes(markers.start),
);
if (existingComment) {
@@ -134,15 +250,16 @@ async function main() {
body: commentBody,
});
console.log('Updated existing bundle stats comment.');
} else {
await octokit.rest.issues.createComment({
owner,
repo,
issue_number: issueNumber,
body: commentBody,
});
console.log('Created new bundle stats comment.');
return;
}
await octokit.rest.issues.createComment({
owner,
repo,
issue_number: issueNumber,
body: commentBody,
});
console.log('Created new bundle stats comment.');
}
main().catch(error => {

View File

@@ -6,6 +6,6 @@
"test": "vitest --run"
},
"devDependencies": {
"vitest": "^4.0.9"
"vitest": "^4.0.16"
}
}

View File

@@ -1,4 +1,4 @@
import { describe, it, expect } from 'vitest';
import { describe, expect, it } from 'vitest';
import { getNextVersion } from './get-next-package-version';

View File

@@ -0,0 +1,3 @@
{
"jsPlugins": ["eslint-plugin-storybook"]
}

View File

@@ -0,0 +1,43 @@
import { dirname } from 'path';
import { fileURLToPath } from 'url';
import type { StorybookConfig } from '@storybook/react-vite';
import viteTsconfigPaths from 'vite-tsconfig-paths';
/**
* This function is used to resolve the absolute path of a package.
* It is needed in projects that use Yarn PnP or are set up within a monorepo.
*/
function getAbsolutePath(value: string) {
return dirname(fileURLToPath(import.meta.resolve(`${value}/package.json`)));
}
const config: StorybookConfig = {
stories: [
'../src/Introduction.mdx',
'../src/**/*.mdx',
'../src/**/*.stories.@(js|jsx|mjs|ts|tsx)',
],
addons: [
getAbsolutePath('@chromatic-com/storybook'),
getAbsolutePath('@storybook/addon-a11y'),
getAbsolutePath('@storybook/addon-docs'),
],
framework: getAbsolutePath('@storybook/react-vite'),
core: {
disableTelemetry: true,
},
async viteFinal(config) {
const { mergeConfig } = await import('vite');
return mergeConfig(config, {
// Telling Vite how to resolve path aliases
plugins: [viteTsconfigPaths({ root: '../..' })],
esbuild: {
// Needed to handle JSX in .ts/.tsx files
jsx: 'automatic',
},
});
},
};
export default config;

View File

@@ -0,0 +1,74 @@
import { addons } from 'storybook/manager-api';
import { create } from 'storybook/theming/create';
// Colors from the Actual Budget light theme palette
const purple500 = '#8719e0';
const purple400 = '#9a3de8';
const navy900 = '#102a43';
const navy700 = '#334e68';
const navy600 = '#486581';
const navy150 = '#d9e2ec';
const navy100 = '#e8ecf0';
const white = '#ffffff';
// Create a custom Storybook theme matching Actual Budget's light theme
const theme = create({
base: 'light',
brandTitle: 'Actual Budget',
brandUrl: 'https://actualbudget.org',
brandImage: 'https://actualbudget.org/img/actual.webp',
brandTarget: '_blank',
// UI colors
colorPrimary: purple500,
colorSecondary: purple400,
// App chrome
appBg: navy100,
appContentBg: white,
appPreviewBg: white,
appBorderColor: navy150,
appBorderRadius: 4,
// Fonts
fontBase:
'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif',
fontCode: 'ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace',
// Text colors
textColor: navy900,
textInverseColor: white,
textMutedColor: navy600,
// Toolbar
barTextColor: navy700,
barHoverColor: purple500,
barSelectedColor: purple500,
barBg: white,
// Form colors
buttonBg: white,
buttonBorder: navy900,
booleanBg: navy150,
booleanSelectedBg: purple500,
inputBg: white,
inputBorder: navy900,
inputTextColor: navy900,
inputBorderRadius: 4,
});
addons.setConfig({
theme,
enableShortcuts: true,
isFullscreen: false,
isToolshown: true,
sidebar: {
collapsedRoots: [],
filters: {
patterns: item => {
// Hide stories that are marked as internal
return !item.tags?.includes('internal');
},
},
},
});

View File

@@ -0,0 +1,88 @@
import { type ReactNode } from 'react';
import type { Preview } from '@storybook/react-vite';
// Not ideal to import from desktop-client, but we need a source of truth for theme variables
import * as darkTheme from '../../desktop-client/src/style/themes/dark';
import * as developmentTheme from '../../desktop-client/src/style/themes/development';
import * as lightTheme from '../../desktop-client/src/style/themes/light';
import * as midnightTheme from '../../desktop-client/src/style/themes/midnight';
const THEMES = {
light: lightTheme,
dark: darkTheme,
midnight: midnightTheme,
development: developmentTheme,
} as const;
type ThemeName = keyof typeof THEMES;
const ThemedStory = ({
themeName,
children,
}: {
themeName?: ThemeName;
children?: ReactNode;
}) => {
if (!themeName || !THEMES[themeName]) {
throw new Error(`No theme specified`);
}
const css = Object.entries(THEMES[themeName])
.map(([key, value]) => `--color-${key}: ${value};`)
.join('\n');
return (
<div>
<style>{`:root {\n${css}}`}</style>
{children}
</div>
);
};
const preview: Preview = {
decorators: [
(Story, { globals }) => {
const themeName = globals.theme;
return (
<ThemedStory themeName={themeName}>
<Story />
</ThemedStory>
);
},
],
globalTypes: {
theme: {
name: 'Theme',
description: 'Global theme for components',
defaultValue: 'light',
toolbar: {
icon: 'circlehollow',
items: [
{ value: 'light', title: 'Light' },
{ value: 'dark', title: 'Dark' },
{ value: 'midnight', title: 'Midnight' },
{ value: 'development', title: 'Development' },
],
},
},
},
parameters: {
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/i,
},
},
a11y: {
// 'todo' - show a11y violations in the test UI only
// 'error' - fail CI on a11y violations
// 'off' - skip a11y checks entirely
test: 'todo',
},
},
};
export default preview;

View File

@@ -14,7 +14,6 @@
"./block": "./src/Block.tsx",
"./button": "./src/Button.tsx",
"./card": "./src/Card.tsx",
"./combo-box": "./src/ComboBox.tsx",
"./form-error": "./src/FormError.tsx",
"./initial-focus": "./src/InitialFocus.ts",
"./inline-field": "./src/InlineField.tsx",
@@ -38,19 +37,27 @@
"scripts": {
"generate:icons": "rm src/icons/*/*.tsx; cd src/icons && svgr --template template.ts --index-template index-template.ts --typescript --expand-props start -d . .",
"test": "npm-run-all -cp 'test:*'",
"test:web": "ENV=web vitest --run -c vitest.web.config.ts"
"test:web": "ENV=web vitest --run -c vitest.web.config.ts",
"start:storybook": "storybook dev -p 6006",
"build:storybook": "storybook build"
},
"dependencies": {
"@emotion/css": "^11.13.5",
"react-aria-components": "^1.13.0",
"react-aria-components": "^1.14.0",
"usehooks-ts": "^3.1.1"
},
"devDependencies": {
"@chromatic-com/storybook": "^5.0.0",
"@storybook/addon-a11y": "^10.2.0",
"@storybook/addon-docs": "^10.2.0",
"@storybook/react-vite": "^10.2.0",
"@svgr/cli": "^8.1.0",
"@types/react": "^19.2.5",
"react": "19.2.0",
"react-dom": "19.2.0",
"vitest": "^4.0.9"
"eslint-plugin-storybook": "^10.2.0",
"react": "19.2.3",
"react-dom": "19.2.3",
"storybook": "^10.2.0",
"vitest": "^4.0.16"
},
"peerDependencies": {
"react": ">=18.2",

View File

@@ -1,4 +1,4 @@
import { type ComponentProps, type ReactNode, type CSSProperties } from 'react';
import { type ComponentProps, type CSSProperties, type ReactNode } from 'react';
import { Block } from './Block';
import { View } from './View';

View File

@@ -0,0 +1,100 @@
import type { Meta, StoryObj } from '@storybook/react-vite';
import { fn } from 'storybook/test';
import { Button } from './Button';
const meta = {
title: 'Button',
component: Button,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
argTypes: {
onClick: { action: 'clicked' },
},
args: { onClick: fn() },
} satisfies Meta<typeof Button>;
export default meta;
type Story = StoryObj<typeof meta>;
// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args
export const Primary: Story = {
args: {
variant: 'primary',
bounce: false,
children: 'Button Text',
},
parameters: {
docs: {
description: {
story: `
Primary button variant uses the following theme CSS variables:
- \`--color-buttonPrimaryText\`
- \`--color-buttonPrimaryTextHover\`
- \`--color-buttonPrimaryBackground\`
- \`--color-buttonPrimaryBackgroundHover\`
- \`--color-buttonPrimaryBorder\`
- \`--color-buttonPrimaryShadow\`
- \`--color-buttonPrimaryDisabledText\`
- \`--color-buttonPrimaryDisabledBackground\`
- \`--color-buttonPrimaryDisabledBorder\`
`,
},
},
},
};
export const Normal: Story = {
args: {
variant: 'normal',
bounce: false,
children: 'Button Text',
},
parameters: {
docs: {
description: {
story: `
Normal button variant uses the following theme CSS variables:
- \`--color-buttonNormalText\`
- \`--color-buttonNormalTextHover\`
- \`--color-buttonNormalBackground\`
- \`--color-buttonNormalBackgroundHover\`
- \`--color-buttonNormalBorder\`
- \`--color-buttonNormalShadow\`
- \`--color-buttonNormalSelectedText\`
- \`--color-buttonNormalSelectedBackground\`
- \`--color-buttonNormalDisabledText\`
- \`--color-buttonNormalDisabledBackground\`
- \`--color-buttonNormalDisabledBorder\`
`,
},
},
},
};
export const Bare: Story = {
args: {
variant: 'bare',
bounce: false,
children: 'Button Text',
},
parameters: {
docs: {
description: {
story: `
Bare button variant uses the following theme CSS variables:
- \`--color-buttonBareText\`
- \`--color-buttonBareTextHover\`
- \`--color-buttonBareBackground\`
- \`--color-buttonBareBackgroundHover\`
- \`--color-buttonBareBackgroundActive\`
- \`--color-buttonBareDisabledText\`
- \`--color-buttonBareDisabledBackground\`
`,
},
},
},
};

View File

@@ -2,8 +2,8 @@ import React, {
forwardRef,
useMemo,
type ComponentPropsWithoutRef,
type ReactNode,
type CSSProperties,
type ReactNode,
} from 'react';
import { Button as ReactAriaButton } from 'react-aria-components';

View File

@@ -1,4 +1,4 @@
import { type ComponentProps, forwardRef } from 'react';
import { forwardRef, type ComponentProps } from 'react';
import { theme } from './theme';
import { View } from './View';

View File

@@ -1,15 +1,15 @@
import { type ChangeEvent, type ReactNode } from 'react';
import {
ColorPicker as AriaColorPicker,
type ColorPickerProps as AriaColorPickerProps,
ColorSwatch as AriaColorSwatch,
ColorSwatchPicker as AriaColorSwatchPicker,
ColorField,
ColorSwatchPickerItem,
Dialog,
DialogTrigger,
ColorSwatch as AriaColorSwatch,
type ColorSwatchProps,
ColorSwatchPicker as AriaColorSwatchPicker,
ColorSwatchPickerItem,
ColorField,
parseColor,
type ColorPickerProps as AriaColorPickerProps,
type ColorSwatchProps,
} from 'react-aria-components';
import { css } from '@emotion/css';

View File

@@ -1,198 +0,0 @@
import {
type ComponentProps,
useRef,
useContext,
type KeyboardEvent,
useEffect,
createContext,
type ReactNode,
} from 'react';
import {
ComboBox as AriaComboBox,
ListBox,
ListBoxItem,
ListBoxSection,
type ListBoxSectionProps,
type ComboBoxProps as AriaComboBoxProps,
type ListBoxItemProps,
ComboBoxStateContext as AriaComboBoxStateContext,
type Key,
} from 'react-aria-components';
import { type ComboBoxState as AriaComboBoxState } from 'react-stately';
import { css, cx } from '@emotion/css';
import { Input } from './Input';
import { Popover } from './Popover';
import { styles } from './styles';
import { theme } from './theme';
import { View } from './View';
const popoverClassName = () =>
css({
...styles.darkScrollbar,
...styles.popover,
backgroundColor: theme.menuAutoCompleteBackground,
color: theme.menuAutoCompleteText,
padding: '5px 0',
borderRadius: 4,
});
const listBoxClassName = ({ width }: { width?: number }) =>
css({
width,
minWidth: 200,
maxHeight: 200,
overflow: 'auto',
'& [data-focused]': {
backgroundColor: theme.menuAutoCompleteBackgroundHover,
},
});
type ComboBoxProps<T extends object> = Omit<
AriaComboBoxProps<T>,
'children'
> & {
inputPlaceholder?: string;
children: ComponentProps<typeof ListBox<T>>['children'];
};
export function ComboBox<T extends object>({
children,
...props
}: ComboBoxProps<T>) {
const viewRef = useRef<HTMLDivElement | null>(null);
return (
<AriaComboBox<T>
allowsEmptyCollection
allowsCustomValue
menuTrigger="focus"
{...props}
>
<View ref={viewRef}>
<ComboBoxInput placeholder={props.inputPlaceholder} />
</View>
<Popover isNonModal className={popoverClassName()}>
<ListBox<T>
className={listBoxClassName({ width: viewRef.current?.clientWidth })}
>
{children}
</ListBox>
</Popover>
</AriaComboBox>
);
}
type ComboBoxInputContextValue = {
getFocusedKey?: (state: AriaComboBoxState<unknown>) => Key | null;
};
const ComboBoxInputContext = createContext<ComboBoxInputContextValue | null>(
null,
);
type ComboBoxInputProviderProps = {
children: ReactNode;
getFocusedKey?: (state: AriaComboBoxState<unknown>) => Key | null;
};
export function ComboBoxInputProvider({
children,
getFocusedKey,
}: ComboBoxInputProviderProps) {
return (
<ComboBoxInputContext.Provider value={{ getFocusedKey }}>
{children}
</ComboBoxInputContext.Provider>
);
}
type ComboBoxInputProps = ComponentProps<typeof Input>;
function ComboBoxInput({ onKeyUp, ...props }: ComboBoxInputProps) {
const state = useContext(AriaComboBoxStateContext);
const _onKeyUp = (e: KeyboardEvent<HTMLInputElement>) => {
if (e.key === 'Escape') {
state?.revert();
}
onKeyUp?.(e);
};
const comboBoxInputContext = useContext(ComboBoxInputContext);
useEffect(() => {
if (state && state.inputValue && !state.selectionManager.focusedKey) {
const focusedKey: Key | null =
(comboBoxInputContext?.getFocusedKey
? comboBoxInputContext.getFocusedKey(state)
: defaultGetFocusedKey(state)) ?? null;
state.selectionManager.setFocusedKey(focusedKey);
}
}, [comboBoxInputContext, state, state?.inputValue]);
return <Input onKeyUp={_onKeyUp} {...props} />;
}
function defaultGetFocusedKey<T>(state: AriaComboBoxState<T>) {
// Focus on the first suggestion item when typing.
const keys = Array.from(state.collection.getKeys());
return (
keys
.map(key => state.collection.getItem(key))
.find(i => i && i.type === 'item')?.key ?? null
);
}
const defaultComboBoxSectionClassName = () =>
css({
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
'& header': {
paddingTop: 5,
paddingBottom: 5,
paddingLeft: 10,
color: theme.menuAutoCompleteTextHeader,
},
});
type ComboBoxSectionProps<T extends object> = ListBoxSectionProps<T>;
export function ComboBoxSection<T extends object>({
className,
...props
}: ComboBoxSectionProps<T>) {
return (
<ListBoxSection
className={cx(defaultComboBoxSectionClassName(), className)}
{...props}
/>
);
}
const defaultComboBoxItemClassName = () =>
css({
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
paddingTop: 5,
paddingBottom: 5,
paddingLeft: 20,
});
type ComboBoxItemProps = ListBoxItemProps;
export function ComboBoxItem({ className, ...props }: ComboBoxItemProps) {
return (
<ListBoxItem
className={
typeof className === 'function'
? renderProps =>
cx(defaultComboBoxItemClassName(), className(renderProps))
: cx(defaultComboBoxItemClassName(), className)
}
{...props}
/>
);
}

View File

@@ -1,4 +1,4 @@
import { type ReactNode, type CSSProperties } from 'react';
import { type CSSProperties, type ReactNode } from 'react';
import { View } from './View';

View File

@@ -2,11 +2,11 @@ import {
Children,
cloneElement,
isValidElement,
useEffect,
useRef,
type ReactElement,
type Ref,
type RefObject,
useEffect,
useRef,
} from 'react';
type InitialFocusProps<T extends HTMLElement> = {

View File

@@ -1,8 +1,8 @@
import React, {
type ChangeEvent,
type ComponentPropsWithRef,
type KeyboardEvent,
type FocusEvent,
type KeyboardEvent,
} from 'react';
import { Input as ReactAriaInput } from 'react-aria-components';

View File

@@ -0,0 +1,27 @@
import { Meta } from '@storybook/addon-docs/blocks';
<Meta title="Introduction" />
# Actual Budget Component Library
Welcome to the **Actual Budget Component Library**. Explore our UI components, see how they look across different themes, and learn how to use them in your code.
### What you can do here
- ✨ **Browse components** in the sidebar
- 🎨 **Switch themes** using the toolbar above
- 📚 **Read documentation** and see code examples
- 🔍 **Test variations** and component states
- ♿ **Check accessibility** compliance
### Getting Started
Select a component from the sidebar to explore its documentation, variants, and interactive controls.
---
### Useful Links
- [Actual Budget Website](https://actualbudget.org)
- [Documentation](https://actualbudget.org/docs)
- [GitHub Repository](https://github.com/actualbudget/actual)

View File

@@ -1,4 +1,4 @@
import { forwardRef, type ReactNode, type CSSProperties } from 'react';
import { forwardRef, type CSSProperties, type ReactNode } from 'react';
import { styles } from './styles';
import { Text } from './Text';

View File

@@ -1,13 +1,13 @@
import {
type ReactNode,
useEffect,
useRef,
useState,
type ComponentProps,
type ComponentType,
type SVGProps,
type CSSProperties,
type KeyboardEvent,
useEffect,
useRef,
type ReactNode,
type SVGProps,
} from 'react';
import { Button } from './Button';
@@ -152,7 +152,7 @@ export function Menu<const NameType = string>({
<View
className={className}
style={{ outline: 'none', borderRadius: 4, overflow: 'hidden', ...style }}
tabIndex={1}
tabIndex={0}
onKeyDown={onKeyDown}
innerRef={elRef}
>

View File

@@ -1,4 +1,4 @@
import { type ComponentProps, useCallback, useEffect, useRef } from 'react';
import { useCallback, useEffect, useRef, type ComponentProps } from 'react';
import { Popover as ReactAriaPopover } from 'react-aria-components';
import { css } from '@emotion/css';

View File

@@ -1,8 +1,8 @@
import React, {
type HTMLProps,
type Ref,
type ReactNode,
forwardRef,
type HTMLProps,
type ReactNode,
type Ref,
} from 'react';
import { css, cx } from '@emotion/css';

View File

@@ -1,4 +1,4 @@
import React, { type SVGProps, useState } from 'react';
import React, { useState, type SVGProps } from 'react';
export const SvgLoading = (props: SVGProps<SVGSVGElement>) => {
const { color = 'currentColor' } = props;

View File

@@ -91,7 +91,10 @@ export const styles: Record<string, any> = {
},
shadowLarge,
tnum: {
fontFeatureSettings: '"tnum"',
// tnum: Tabular numbers
// ss01: Open digits
// ss04: Disambiguation w/o zero
fontFeatureSettings: '"tnum", "ss01", "ss04"',
},
notFixed: { fontFeatureSettings: '' },
text: {
@@ -159,4 +162,11 @@ export const styles: Record<string, any> = {
padding: 16,
cursor: 'pointer',
},
tableContainer: {
flex: 1,
border: '1px solid ' + theme.tableBorder,
borderTopLeftRadius: 6,
borderTopRightRadius: 6,
overflow: 'hidden',
},
};

View File

@@ -13,6 +13,9 @@ export const theme = {
pageTextPositive: 'var(--color-pageTextPositive)',
pageTextLink: 'var(--color-pageTextLink)',
pageTextLinkLight: 'var(--color-pageTextLinkLight)',
numberPositive: 'var(--color-numberPositive)',
numberNegative: 'var(--color-numberNegative)',
numberNeutral: 'var(--color-numberNeutral)',
cardBackground: 'var(--color-cardBackground)',
cardBorder: 'var(--color-cardBorder)',
cardShadow: 'var(--color-cardShadow)',
@@ -43,6 +46,7 @@ export const theme = {
sidebarItemBackgroundHover: 'var(--color-sidebarItemBackgroundHover)',
sidebarItemText: 'var(--color-sidebarItemText)',
sidebarItemTextSelected: 'var(--color-sidebarItemTextSelected)',
sidebarBudgetName: 'var(--color-sidebarBudgetName)',
menuBackground: 'var(--color-menuBackground)',
menuItemBackground: 'var(--color-menuItemBackground)',
menuItemBackgroundHover: 'var(--color-menuItemBackgroundHover)',
@@ -186,6 +190,19 @@ export const theme = {
reportsGray: 'var(--color-reportsGray)',
reportsLabel: 'var(--color-reportsLabel)',
reportsInnerLabel: 'var(--color-reportsInnerLabel)',
reportsChartFill: 'var(--color-reportsChartFill)',
reportsNumberPositive: 'var(--color-reportsNumberPositive)',
reportsNumberNegative: 'var(--color-reportsNumberNegative)',
reportsNumberNeutral: 'var(--color-reportsNumberNeutral)',
budgetNumberPositive: 'var(--color-budgetNumberPositive)',
budgetNumberNegative: 'var(--color-budgetNumberNegative)',
budgetNumberNeutral: 'var(--color-budgetNumberNeutral)',
budgetNumberZero: 'var(--color-budgetNumberZero)',
toBudgetPositive: 'var(--color-toBudgetPositive)',
toBudgetZero: 'var(--color-toBudgetZero)',
toBudgetNegative: 'var(--color-toBudgetNegative)',
templateNumberFunded: 'var(--color-templateNumberFunded)',
templateNumberUnderFunded: 'var(--color-templateNumberUnderFunded)',
noteTagBackground: 'var(--color-noteTagBackground)',
noteTagBackgroundHover: 'var(--color-noteTagBackgroundHover)',
noteTagDefault: 'var(--color-noteTagDefault)',
@@ -201,4 +218,5 @@ export const theme = {
tooltipBackground: 'var(--color-tooltipBackground)',
tooltipBorder: 'var(--color-tooltipBorder)',
calendarCellBackground: 'var(--color-calendarCellBackground)',
overlayBackground: 'var(--color-overlayBackground)',
};

View File

@@ -24,6 +24,6 @@
"protoc-gen-js": "3.21.4-4",
"ts-protoc-gen": "0.15.0",
"typescript": "^5.9.3",
"vitest": "^4.0.9"
"vitest": "^4.0.16"
}
}

View File

@@ -65,10 +65,10 @@ Run manually:
```sh
# Run docker container
docker run --rm --network host -v $(pwd):/work/ -w /work/ -it mcr.microsoft.com/playwright:v1.56.0-jammy /bin/bash
docker run --rm --network host -v $(pwd):/work/ -w /work/ -it mcr.microsoft.com/playwright:v1.57.0-jammy /bin/bash
# If you receive an error such as "docker: invalid reference format", please instead use the following command:
docker run --rm --network host -v ${pwd}:/work/ -w /work/ -it mcr.microsoft.com/playwright:v1.56.0-jammy /bin/bash
docker run --rm --network host -v ${pwd}:/work/ -w /work/ -it mcr.microsoft.com/playwright:v1.57.0-jammy /bin/bash
# Once inside the docker container, run the VRT tests: important - they MUST be ran against a HTTPS server.
# Use the ip and port noted earlier

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 151 KiB

After

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 KiB

After

Width:  |  Height:  |  Size: 161 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 148 KiB

After

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 133 KiB

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 133 KiB

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 132 KiB

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 178 KiB

After

Width:  |  Height:  |  Size: 192 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 172 KiB

After

Width:  |  Height:  |  Size: 187 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 173 KiB

After

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Some files were not shown because too many files have changed in this diff Show More