Compare commits

...

130 Commits

Author SHA1 Message Date
autofix-ci[bot]
25c5a59ca1 [autofix.ci] apply automated fixes 2026-01-09 13:53:10 -08:00
Joel Jeremy Marquez
de6f7cb59b Rename to ComboBox 2026-01-09 13:53:10 -08:00
Joel Jeremy Marquez
db8e994bd0 yarn install 2026-01-09 13:52:37 -08:00
Joel Jeremy Marquez
4567235f3e Fix typecheck error 2026-01-09 13:51:18 -08:00
Joel Jeremy Marquez
4406c2515f Fix lint and typecheck errors 2026-01-09 13:51:18 -08:00
Joel Jeremy Marquez
e8508310e2 Cleanup 2026-01-09 13:51:18 -08:00
Joel Jeremy Marquez
28db29ac5e Implement PayeeAutocomplete2 based on react-aria-component's ComboBox 2026-01-09 13:51:18 -08:00
lelemm
fed1cd7d30 Added Global Synced Prefs (#6234)
* Added Global Synced Prefs

* [autofix.ci] apply automated fixes

* Add release notes for PR #6234

* typecheck

* lint fix

* Refactor global synced preferences to server preferences

- Removed global synced preferences implementation and related files.
- Introduced server preferences with a new slice and hooks for managing user settings.
- Updated components and hooks to utilize server preferences instead of global synced preferences.
- Adjusted Redux store and mock configurations to reflect the changes.
- Enhanced user settings consistency across devices with the new server preferences structure.

* Implement server preferences for feature flags and enhance admin permissions

- Updated the Experimental component to conditionally display based on user permissions and login method.
- Refactored feature flag handling to use 'flags.plugins' instead of 'plugins'.
- Introduced server-side checks to restrict access to server preferences for admin users only.
- Added comprehensive tests for server preferences management, ensuring proper handling of user roles and preferences.

* Enhance error handling in saveServerPrefs thunk

- Updated the saveServerPrefs async thunk to handle potential errors from the server response.
- Added a check for the presence of an error in the result and return it accordingly.
- Ensured that preferences are still dispatched to the store upon successful save.

* Feedback: strict "flags.plugins" typing

* Feedback: move state slice

* Feedback: localstorage pref

* Feedback: move serverPrefsSlide into prefsSlice

* Refactor: Remove duplicate import of PostError in app.ts

* Rename serverPrefs state slice property to server (#6596)

---------

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: Matiss Janis Aboltins <matiss@mja.lv>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
2026-01-09 08:17:36 +00:00
Juulz
da1a2457ba Tags: add light colors to tag color picker, update tag hover depending on tag background brightness (#6448)
* Add matching light tints to color picker

* Update ColorPicker light colors

* Update light colors to color wheel

* Update P.10

* Update light theme tag colors

* Create 6396.md Add light tints to tag color picker.

* Update development.ts to match light.ts

Because the Code bunny wanted them to match.

* Update palette.ts

* Update development.ts

* Update light.ts

* Update ColorPicker.tsx

Moved light colors under original dark colors.

* [autofix.ci] apply automated fixes

* Update ColorPicker.tsx

Remove comment.

* Update colors.ts

* Update useTagCSS.ts

* [autofix.ci] apply automated fixes

* Update useTagCSS.ts

* Adjust color mix percentages and add !important to text

* [autofix.ci] apply automated fixes

* Refactor color mix logic in useTagCSS hook

* Change noteTagBackgroundHover color back to purple150

* Remove purple75 from palette

Remove unused purple75 color definition. No longer needed.

* Change noteTagBackgroundHover back to color to purple150

* [autofix.ci] apply automated fixes

* Modify color mixing logic in useTagCSS hook

updated the percentage for the color-mix function - light theme. Added text comment for later reference.

* [autofix.ci] apply automated fixes

* Add release notes for tag color picker enhancements

* [autofix.ci] apply automated fixes

* Add purple125 color to palette

* Update color value for purple tint in ColorPicker

* Change noteTagDefault color to purple125

* Change noteTagDefault color to purple125

* Fix syntax for purple125 color definition

* Update noteTagBackground color to purple125

* Update noteTagBackground color to purple125

* Delete upcoming-release-notes/6396.md

#6396 was closed in favor of #6448

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: youngcw <calebyoung94@gmail.com>
2026-01-08 16:31:41 +00:00
FictionFics
5673ca5049 Fix/stacked bar graph crash 6406 (#6554)
* fix: remove responsive prop from StackedBarGraph to prevent infinite loop

Fixes #6406

The 'responsive' prop on BarChart was conflicting with explicit width/height
props provided by AutoSizer, causing recharts' useElementOffset hook to
trigger an infinite re-render loop. This manifested as React Error #185
(Maximum update depth exceeded) when displaying stacked bar graphs with
many months of data.

Removing the redundant 'responsive' prop resolves the issue since explicit
dimensions are already provided by the Container component.

* docs: add release notes for #6406

* [autofix.ci] apply automated fixes

---------

Co-authored-by: Salva <spenamedina@Salvas-MacBook-Pro.local>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-01-08 16:30:18 +00:00
Michael Clark
4b8feb1dfc :electron: Improve metainfo validation for flathub (#6593)
* manifest validation for flathub

* install builder separately

* confirmed working, now removing validation errors

* updates to metainfo with new validation fixes

* release notes
2026-01-08 09:15:02 +00:00
Matiss Janis Aboltins
771e5072cb Add custom checks to CodeRabbit configuration (#6592)
* Add custom checks to CodeRabbit configuration

- Add settings check to evaluate new setting toggles against core design principles
- Add linting check to prevent oxlint-disable lines
- Add typecheck check to prevent @ts-strict-ignore in new components/utilities

* Add release notes for custom checks in CodeRabbit configuration

* Refactor custom checks in CodeRabbit configuration for clarity and consistency

- Consolidate custom checks under a single list format for better readability
- Maintain existing checks for settings, linting, and typecheck with unchanged instructions
2026-01-07 21:39:45 +00:00
FictionFics
fd42705c75 Fix/saved filters position (#6552)
* fix: move saved filters to end of dropdown with separator

- Reorganized filter menu items to place 'saved filters' at the end
- Added separator before 'saved filters' to distinguish from regular filters
- Maintained alphabetical sorting for regular filter options

Fixes #6535

* docs: add release notes

* [autofix.ci] apply automated fixes

* fixing typos

* fix: use Menu.line for proper separator rendering

* refactor: remove duplication by extracting saved filter from array

* [autofix.ci] apply automated fixes

---------

Co-authored-by: Salva <spenamedina@Salvas-MacBook-Pro.local>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-01-07 18:50:24 +00:00
Joelson Carvalho
8a1e1923dd Fix iOS keyboard suddenly hiding while editing budget amounts (#6583)
* Fix iOS keyboard suddenly hiding while editing budget amounts

The react-aria-components Buttons calls the onHoverStart even if there
is no fine pointing device attached to the client (iOS 26+), causing the
amount input to loose its focus.
This commits checks if there is any input with focus before auto focus
the menu Container.

* [autofix.ci] apply automated fixes

* Fix menu aria pattern by making excluding menu buttons from tab order

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-01-07 18:50:14 +00:00
Matiss Janis Aboltins
d30f3aa36d ci: require e2e tests to pass in merge queue (#6581)
* Add merge_group trigger to e2e-test workflow

* Add release notes for PR #6581

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-07 18:45:02 +00:00
Daniel Kerwin
36a3586648 [fix] improves UX of notifications for mobile devices (#6551)
* fix: implements z-axis stacked notifications and style improvements, resolves #6539

* [autofix.ci] apply automated fixes

* chore: add release notes

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6551

* chore: remove opacity

* [autofix.ci] apply automated fixes

* fix: get first notification text (behind the latest notification)

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6551

* chore: add implicit interactive prop

---------

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-07 18:07:19 +00:00
Juulz
ea551608df fix: Keyboard shortcuts modal: Rearrange and add date shortcut "E" (#6573)
* Refactor keyboard shortcuts in KeyboardShortcutModal

Updated keyboard shortcuts for various actions in the KeyboardShortcutModal component. Changed shortcut names and IDs for better clarity and organization.

* Update keyboard shortcuts modal text from 'General' to 'Global'

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6573

* Add release notes for bugfix in KeybordShortcutModal

Update KeybordShortcutModal.tsx to set date for selected transactions and reorganize the list to match documentation.

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-07 16:21:42 +00:00
Stephen Brown II
30953d3d9f Add Wallos schedule importer to community repos (#6585)
* Add Wallos schedule importer to community repos

Added a new entry for Wallos schedule importer with a brief description.

* Add Wallos to expected words
2026-01-07 08:43:43 +00:00
Matiss Janis Aboltins
9e7a4cde36 Remove ESLint and complete migration to oxlint (#6584)
* Remove ESLint and migrate fully to oxlint

* Add release notes for PR #6584

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-06 23:19:03 +00:00
Matiss Janis Aboltins
3966778de3 Update CodeRabbit configuration with review workflow and labeling (#6582)
* Update CodeRabbit configuration with review workflow and labeling

* Add release notes for PR #6582

* Update CodeRabbit configuration to change label descriptions to instructions and modify release notes category from Enhancements to Maintenance.

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-06 22:37:20 +00:00
Lenno Nagel
a9509f477f Fix LHV bank adapter not being loaded due to filename mismatch (#6533)
* Fix LHV bank adapter not being loaded due to filename mismatch

The bank-factory.js loads bank adapters by filtering for files containing
underscores, but lhv-lhvbee22.js used a hyphen. This caused the LHV adapter
to never be loaded, falling back to the generic IntegrationBank handler
which doesn't extract payee names from card transaction remittance info.

Rename lhv-lhvbee22.js to lhv_lhvbee22.js to match the naming convention
used by all other bank adapters.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Add release notes for PR #6533

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* [autofix.ci] apply automated fixes

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-01-06 18:43:54 +00:00
Ilia Skliaruk
a2a82e90d6 fix: Update autoDecimals behavior based on hideFraction preference (#6572) 2026-01-06 17:55:25 +00:00
youngcw
acc21f1762 fix up to only templates and negative carryover (#6566) 2026-01-06 17:45:12 +00:00
Ilia Skliaruk
4055725106 fix(web): Close popover on Escape press (#6570)
* fix(web): Close popover on second Escape press when autocomplete options are closed

* [autofix.ci] apply automated fixes

* fix(web): use more accurate approach with isOpen

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-01-06 17:44:50 +00:00
Jonathon Jongsma
31349b7bc8 Add target income adjustment factor to crossover report (#6373)
* Add target income adjustment factor to crossover report

Allow the user to specify an adjustment factor to apply to their target
retirement income. This allows them to be a little more conservative
or aggressive on their retirement goals rather than relying only on the
calculated expense projection.

For example, if you want to spend more in retirement (or are simply more
risk-averse), you could set the target income adjustment to 120%. Or if
you expect some retirement income from a defined-benefit pension and
don't need to rely only on the income sources in your budget, you could
set this to 80% to account for that external income.

Originally discussed at https://github.com/actualbudget/actual/issues/6134#issuecomment-3608247467

Co-authored-by: Claude <noreply@anthropic.com>

* [autofix.ci] apply automated fixes

* Add null check in crossover report

Review finding from PR

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

---------

Signed-off-by: Jonathon Jongsma <jonathon@quotidian.org>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-01-06 16:36:49 +00:00
Faizan Qureshi
5f1c13e25c Fix date format interfering with month filter edit (#6497)
The month filter edit popup was always displaying dates in mm/yyyy format
regardless of user's date format preference. Now respects the configured
date format setting.

Fixes #6341
2026-01-06 16:33:05 +00:00
Ilia Skliaruk
fa45342d8d fix: prevent renaming category groups to existing names (#6499)
* fix: prevent renaming category groups to existing names

* fix: prevent category group duplication by ignoring current group in checks

* fix: rename 6498.md to 6499.md to reflect updated content
2026-01-06 16:31:40 +00:00
Ilia Skliaruk
d52f920e98 fix: Unsplit transaction without losing the parent’s data. (#6501)
* fix: Unsplit transaction without losing parent's transaction information (amount, notes, etc.)

* [autofix.ci] apply automated fixes

* fix: Refine conditional logic and update makeTransactionWithChildCategory to use Partial<TransactionEntity>

* fix: Correct child transaction reference in unsplit logic

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-01-06 16:31:17 +00:00
Juulz
97c2854825 [Docs] Update goal templates doc & images (#6558)
* Update goal templates documentation for clarity

Add updated images for category and group dropdown. Update docs to reflect actual behavior.

* Add files via upload

* Delete packages/docs/static/img/goal-template/apply-template-group.webp

Remove replaced images

* Refine goal templates documentation

Removed unnecessary note and clarified template behavior.

* Fix formatting and warning notes.

* Fix typos and improve clarity in goal templates

Resolving (some of) the AI bunny's suggestions.

* Delete packages/docs/static/img/goal-template/apply-template-category.webp

* Update note on 'up to' template limits

Clarified the note about category limits for templates using 'up to'.
2026-01-06 16:30:39 +00:00
Juulz
6a9e173a1a Update transaction shortcuts in tips and tricks (#6555)
Update shortcut descriptions for "T" and "E"
2026-01-06 14:53:39 +00:00
Matiss Janis Aboltins
bf505c2bd5 Upgrade oxlint and oxfmt dependencies (#6560)
* Update oxlint and oxfmt versions, add suppressions for warnings

* Add release notes for PR #6560

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-05 22:59:08 +00:00
Copilot
64db9a59f4 Fix null context crash in tracking budget mode (#6538)
* Initial plan

* Fix fatal error by adding default values to TrackingBudgetContext

The TrackingBudgetContext was initialized with null, causing a fatal error when components tried to destructure properties like currentMonth. This fix adds proper default values and type definitions, matching the pattern used in EnvelopeBudgetContext.

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

* Add release notes for issue #6538

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: MatissJanis <886567+MatissJanis@users.noreply.github.com>
2026-01-05 22:58:54 +00:00
Matthias Benaets
7f3aa3a2b5 fix: Proper formatting of the Formula Card (#6493)
* fix: Proper formatting of the Formula Card

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-01-05 18:44:40 +00:00
Michael Clark
929131b776 :electron: Fix sha256 workflow (#6545)
* fix sha256

* release notes

* metainfo warning on flathub

* remove vcs browser - will deal with that later
2026-01-05 17:35:10 +00:00
Matthew Mao
d9c759ff1b Add find and replace (with RegEx support) mode when editing transaction notes (#6282)
* prevent hidden toggle input from taking space

* add find and replace to edit notes modal

* make mode buttons same height

* add release note

* fix PR number

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6282

* use checkbox instead of mobile toggle

* typo

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6282

* fix import

* review

* update

* update

* update

* update

* fix mistaken deletion

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6282

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6282

* Reorder note amendment strings in EditFieldModal

* require find value

* update mode order

* retrigger checks

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: youngcw <calebyoung94@gmail.com>
2026-01-05 17:25:43 +00:00
Diego Palacios
52559eb221 Avoid budget amount truncation by collapsing the dropdown arrow (#6459)
* Avoid budget amount truncation by collapsing the dropdown arrow

* [autofix.ci] apply automated fixes

* fix transitions

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-01-05 17:25:12 +00:00
Julian Dominguez-Schatz
3e565fa513 Disable workflows in forks (#6531)
* Add condition to run workflows only for non-forks

* Add condition to skip deployment for forks

* Add release notes for CI workflow changes
2026-01-05 14:37:38 +00:00
Matiss Janis Aboltins
f1faf45659 lint: move last remaining native eslint rules to oxlint (create new alternatives) (#6468)
* lint: clean up unnecessary config and disables

* fix: update package import path in browser preload script

* lint: create custom ESLint rules for rules not in oxlint

- Add object-shorthand-properties rule (replaces object-shorthand)
- Add prefer-const rule (replaces prefer-const)
- Add no-anchor-tag rule (replaces no-restricted-syntax for <a> tags)
- Add no-react-default-import rule (replaces no-restricted-syntax for React.*)

These custom rules are needed because oxlint doesn't support these rules yet.
All rules are properly tested and integrated into the ESLint config.

* refactor: enhance prefer-const rule to track variable reassignments by scope

- Introduced a mapping of scopes to reassigned variable names, improving the accuracy of the prefer-const rule.
- Added helper functions to determine variable scopes and reassignment status.
- Updated logic to check variable reassignments during declaration analysis.
- Adjusted test cases to reflect changes in variable handling.
2026-01-05 09:00:44 +00:00
Herbert Kipkoech
88fbfe7078 docs: add guidance on avoiding Nginx header collisions for COOP/COEP (#6477)
* fix-nginx-header-collision

Added a note on Cross-Origin Isolation and header collisions for Nginx configuration, including a sample Nginx configuration to prevent header duplication.

* Fix formatting of headers in NGINX documentation

* Add new terms to spelling expectations

* Fix placement of 'COOP' in expect.txt

* Update reverse-proxies.md doc display
2026-01-05 09:00:41 +00:00
Matiss Janis Aboltins
235d771d58 Add tests for MobilePayeesPage component (#6506) 2026-01-05 09:00:29 +00:00
Matiss Janis Aboltins
384128ec50 Disable CodeRabbit high-level summary feature (#6536) 2026-01-05 09:00:23 +00:00
Michael Clark
2ed32c4bc4 :electron: Fix electron publish workflow matrix ordering (#6544)
* fix issue with matrix ordering oelectron master publish workflow

* simplify

* image type source

* rabbit
2026-01-04 16:45:33 +00:00
github-actions[bot]
47ffa61f75 🔖 (26.1.0) (#6520)
* 🔖 (26.1.0)

* Trigger CI

* Remove used release notes

* Add release notes for version 26.1.0

This commit introduces the release notes for version 26.1.0, highlighting notable improvements such as currency display in the budget, mobile schedules functionality, link detection in transaction notes, and an extension of historical data. The release also includes various enhancements, bug fixes, and maintenance updates, acknowledging contributions from multiple developers.

* Update spelling expectations and release notes for version 26.1.0

This commit adds new terms to the spelling expectations file and updates the release notes to reflect changes in the documentation, including formatting improvements for clarity. Notable contributions from various developers are acknowledged.

* Add new terms to spelling expectations file

This commit updates the spelling expectations by adding new terms, enhancing the accuracy of the documentation spell-checking process. The changes include the addition of 'jws' and 'oxc' to the list of expected terms.

* Update release notes for version 26.1.0 to include Flathub availability for Linux users

* Update release notes to reflect Docker tag for version 26.1.0 in documentation

---------

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] <41898282+github-actions[bot]@users.noreply.github.com>
2026-01-04 14:00:21 +00:00
Michael Clark
0a73ba06b1 add flathub link on downloads page (#6521) 2026-01-03 13:08:05 +00:00
Copilot
e121e525ce Fix crash when switching filter operators between single and multi-value modes (#6491)
* Initial plan

* Fix crash when switching filter from 'is' to 'one of'

- Add logic to convert single values to arrays when switching to oneOf/notOneOf operators
- Add comprehensive tests for the fix

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

* Add type assertions to fix TypeScript errors

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

* Keep first element when switching from 'one of' to 'is', use strict comparison

- When switching from array operators (oneOf/notOneOf) to single-value operators (is/isNot), keep the first element instead of clearing
- Use strict equality operators (=== instead of ==)
- Add comprehensive tests for array-to-single conversion

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

* Add release notes for PR #6491

* Fix crash due to filter value conversion issue

* Address PR feedback: remove notes test, preserve single values between operators

- Remove test for notes field exclusion (issue #6325 handles notes separately)
- Only clear values when converting FROM arrays, not between single-value operators
- Add test to verify single values are preserved when switching between single-value operators (e.g., 'is' to 'contains')

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

* Update value handling in updateFilterReducer

Handle value conversion for single-value operators and clear value for certain type switches.

* Refactor value assignment for single-value operators

* Refactor value assignment logic in updateFilterReducer

Simplify the handling of value assignment for single-value operators by consolidating conditions. Ensure proper conversion between arrays and single values while maintaining type integrity.

* Remove redundant array checks in updateFilterReducer tests

---------

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>
2025-12-30 23:53:43 +00:00
Copilot
fc89c74445 Fix authorization bypass allowing non-owners to delete shared budgets (#6338)
* Initial plan

* Add permission checks for budget deletion

- Server-side: Check if user is file owner or admin before allowing deletion
- Client-side: Hide "Delete from all devices" button for non-owners
- Add comprehensive tests for permission checking
- Non-owners see message that only owner can delete from server

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

* Add release notes for PR #6338

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6338

* Fix: Change unauthorized to forbidden in delete-user-file

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

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6338

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6338

* Fix: Update error reason from 'unauthorized' to 'forbidden' in delete-user-file response

* Update VRT screenshot for date filter test case

* [autofix.ci] apply automated fixes

---------

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: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: matiss <matiss@mja.lv>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Matt Fiddaman <github@m.fiddaman.uk>
2025-12-30 23:25:46 +00:00
Matt Fiddaman
47aef8ca51 expand logger to cover more of loot-core (#6503)
* expand lint rule

* note

* fix tests

* feedback
2025-12-30 22:58:28 +00:00
Michael Clark
a2267c4806 fix author images (#6512) 2025-12-30 16:53:22 +00:00
Julian Dominguez-Schatz
65da89efeb Add configuration to use built-in test explorer in VS Code (#6505)
* Add configuration files to make tests runnable in VS Code

* Add default configs/fix tests when run from VS Code

* Fix typo

* Add release notes
2025-12-29 22:40:20 +00:00
Michael Clark
cc60d8e716 optimize docs images to save bbandwidth (#6508) 2025-12-29 22:02:53 +00:00
Faizan Qureshi
dfc56b879f fix(mobile): fix stale amounts in cover overspending modal (#6488)
* fix(mobile): close modals after cover overspending action

When covering overspending on mobile, the category selection modal would
remain open with stale data after the cover action completed. This fix
dispatches closeModal() after the cover action to return the user to the
budget view with the updated overspending banner.

Fixes #6487

* fix: rename release notes file to match PR number

* fix(mobile): fix stale overspending amounts in cover modal

Fixes #6487
2025-12-27 21:02:51 +00:00
Matiss Janis Aboltins
45fa1aaf02 test: improve help-menu e2e test stability (#6489) 2025-12-27 13:31:47 +00:00
Matiss Janis Aboltins
a7ab3f375e Release notes newline fix (#6492)
* Refactor: Remove trailing newline from release notes file

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

* Fix template string for release notes summary

* Add release notes for PR #6492

* [autofix.ci] apply automated fixes

* Add finishing_touches section to config

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
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>
2025-12-27 13:31:41 +00:00
Tunde Jaiyesmi
f6bdc713d6 fix(bug): #6291 (#6416)
* fix(bug): #6291

* generated release note

* [autofix.ci] apply automated fixes

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6416

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6416

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6416

* merge

* Update upcoming-release-notes/6416.md

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

---------

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: youngcw <calebyoung94@gmail.com>
Co-authored-by: Matt Fiddaman <github@m.fiddaman.uk>
2025-12-23 02:12:53 +00:00
lelemm
cfea779fc8 AI Generated documentation for excel formula (#6430)
* ai generated documentation

* added words to expect

* removed placeholder images

* Add release notes for PR #6430

* [autofix.ci] apply automated fixes

* Remove release notes for experimental formulas

Co-authored-by: lelemm <lelemm@gmail.com>

* Checkpoint before follow-up message

Co-authored-by: lelemm <lelemm@gmail.com>

* Checkpoint before follow-up message

Co-authored-by: lelemm <lelemm@gmail.com>

* Remove experimental formula card from reports

Co-authored-by: lelemm <lelemm@gmail.com>

* Docs: Update experimental feature warning with feedback issue

Co-authored-by: lelemm <lelemm@gmail.com>

---------

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>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2025-12-22 18:35:37 +00:00
Matiss Janis Aboltins
c2c57e6618 lint: clean up unnecessary config and disables (#6465)
* lint: clean up unnecessary config and disables

* fix: update package import path in browser preload script
2025-12-22 18:30:53 +00:00
scojo
badc97a38a Fix date handling for CrossoverCard report. (#6469)
* Fix date handling for CrossoverCard report. Make consistent with Crossover main report.

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-12-22 14:21:32 +00:00
Michael Clark
f5bbf74051 📜 Docs meta tags for social media (#6466)
* docs socials meta

* description

* nits
2025-12-21 18:18:28 +00:00
Roberto Carlos Gomez Araque
5629e238d6 Fix for issue #1253 (Budget can't be balanced when "Hide decimal places" in the setting is on) (#6274)
* Fix number formatting of intlFormatter with a wrapper to handle -0 edge case (#1253)

* Fix Normalize integer currency values in makeBalanceAmountStyle function based on formatting user prefs (#1253)

* [autofix.ci] apply automated fixes

* Add release notes for budget balancing issue when "Hide decimal places" is enabled

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Matiss Janis Aboltins <matiss@mja.lv>
2025-12-21 17:39:01 +00:00
Matiss Janis Aboltins
cee994cf97 lint: add react/jsx-boolean-value lint rule (#6464) 2025-12-21 13:25:00 +00:00
Connor Shea
3004b6fa6e chore: Add a meta.name to the eslint plugin. (#6463)
* Add a name to the eslint plugin.

* Add release note.

* Also update the no-restricted-imports patterns in .oxlintrc.json.

The glob library is different from what ESLint uses, so the globs need
a bit of adjustment.
2025-12-21 08:33:22 +00:00
Matiss Janis Aboltins
1fe1bad2f8 lint: move actual eslint rules to oxlint and some eslint (#6462)
* lint: move actual eslint rules to oxlint and some eslint

* Update ESLint configuration to remove test file patterns from linting

* Add review status configuration to .coderabbit.yaml

* Remove oxlint plugin from ESLint configuration and package dependencies
2025-12-20 23:00:35 +00:00
Julian Dominguez-Schatz
1a6b53aa28 Disable issue enrichment (#6461)
* Disable issue enrichment

* Add release notes for PR #6461

* [autofix.ci] apply automated fixes

* Change category to Maintenance and update feature description

Updated the release notes to reflect a change in the issue enrichment feature description.

---------

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>
2025-12-20 21:59:02 +00:00
Matiss Janis Aboltins
146aeb1f5a lint: fix most eslint/no-empty-function violations (#6457)
* lint: fix most eslint/no-empty-function violations

* Remove unnecessary closing brace in .oxlintrc.json
2025-12-20 21:38:05 +00:00
Matiss Janis Aboltins
3d7f0827ad Bring back i18n extraction ci job (#6460) 2025-12-20 21:26:26 +00:00
Matiss Janis Aboltins
1f114765d2 Update API test script to include clean step (#6455)
* Update API test script to include clean step

* Update 6455.md

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

---------

Co-authored-by: Matt Fiddaman <github@m.fiddaman.uk>
2025-12-20 20:35:33 +00:00
Matiss Janis Aboltins
d9a1260c91 lint: actual/typography disallow using curly quotes (#6454)
* Update typography rule to disallow curly quotes with auto-fix

- Reverse typography rule to detect and flag curly quotes instead of straight quotes
- Add auto-fixer that converts curly quotes to straight quotes
- Fix auto-fixer to properly escape quotes when they match string delimiters

* Fix quotation marks in error messages and formatting strings across multiple files

- Standardize quotation marks from curly to straight in error messages and string formatting for consistency.
- Update various components and utility files to ensure proper string handling and improve readability.

* Standardize quotation marks across multiple files

- Replace curly quotes with straight quotes in various documentation and code files for consistency and improved readability.
- Update error messages, comments, and documentation to ensure uniformity in string formatting.

* Standardize month formatting across multiple components

- Update month formatting strings from "MMMM 'yy" to "MMMM ''yy" in various components and utility files for consistency.
- Ensure uniformity in how months are displayed throughout the application.

* Refactor typography rule to enhance curly quote handling

- Simplify the error reporting mechanism for curly quotes by creating a shared fix function.
- Update test cases to include various curly quote scenarios for improved coverage.
- Ensure consistent handling of curly quotes in formatting functions across multiple files.

* Refactor typography handling and update tests for curly quotes

- Replace curly quotes with their Unicode equivalents in typography rule and related test cases for consistency.
- Remove unnecessary eslint-disable comments to improve code clarity.
- Ensure proper handling of quotes in arithmetic and utility tests to align with updated typography standards.

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6454

* Fix: Correct typo in budget cell notification message

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

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6454

* Temporarily disable i18n string extraction workflow

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2025-12-20 19:51:16 +00:00
Matiss Janis Aboltins
ddb95359c3 lint: fix eslint/default-case rule violations (#6456) 2025-12-20 19:45:22 +00:00
youngcw
3fd1577a59 📮 2026 roadmap (#6347)
* init

* reword

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6347

* cleanup vrt

* add cli feature

* Apply suggestions from code review

Co-authored-by: Julian Dominguez-Schatz <julian.dominguezschatz@gmail.com>
Co-authored-by: Kelly Arwine <2262535+kellyarwine@users.noreply.github.com>

* a bit of extra

* fix

* Apply suggestions from code review

Co-authored-by: Julian Dominguez-Schatz <julian.dominguezschatz@gmail.com>

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Julian Dominguez-Schatz <julian.dominguezschatz@gmail.com>
Co-authored-by: Kelly Arwine <2262535+kellyarwine@users.noreply.github.com>
2025-12-20 13:43:40 +00:00
Copilot
ffc32517f8 Fix crash when setting recurring date in rule conditions (#6427)
* Initial plan

* Fix crash when setting date in a rule with null value

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

* Update RuleEditor and input components to handle RecurConfig values correctly

---------

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>
2025-12-19 23:40:50 +00:00
Matiss Janis Aboltins
4fc00ae7f1 lint: patch typescript ignored issues (#6450)
* Updates across multiple packages

* Release notes

* Enhance error handling in budget goals reducer by throwing an error when the template is null
2025-12-19 23:40:28 +00:00
Matiss Janis Aboltins
b092681468 Update linting configuration (#6451) 2025-12-19 22:11:25 +00:00
Matiss Janis Aboltins
07fbcebb6a lint: move eslint-native rules to oxlint (#6449)
* Update linting configuration and fix related issues

* Fix type coercion for comment ID in check-first-comment.js to ensure proper comparison with summary comment IDs
2025-12-19 19:57:30 +00:00
Matiss Janis Aboltins
80bb888bae Change minimum transaction date from 2000 to 1995 (#6440)
This change updates the minimum allowed date for transactions from
2000-01-01 to 1995-01-01, allowing users to enter older transaction
dates without crashes. This addresses the date validation bug that
was causing issues with old dates.

- Updated date validation in schema-helpers.ts
- Updated corresponding tests in schema-helpers.test.ts
2025-12-19 18:06:04 +00:00
Matiss Janis Aboltins
d437d6e4f3 ci: improve vrt-update UX (#6439)
- Use sticky-pull-request-comment action for better comment management
- Add 👀 reaction to /update-vrt comments for immediate feedback
- Add note about 50-minute duration in VRT comment
2025-12-19 18:04:55 +00:00
Matt Fiddaman
0b80e5491e fix dynamic font size calculation in formula reports (#6445)
* fix dynamic font size calculation

* note

* typecheck
2025-12-19 10:09:03 +00:00
Matiss Janis Aboltins
05735eb55d Lint: simplify ESLint config and add oxlint configuration (#6443)
* Simplify ESLint config and add oxlint configuration

- Switch from typescript-eslint recommended to base config
- Remove redundant TypeScript-specific rules that are handled by base config
- Add oxlint configuration with appropriate rules
- Simplify globals configuration using globals package
- Add coverage directory to ESLint ignores
- Clean up various TypeScript rule configurations

* Add release notes for PR #6443

* [autofix.ci] apply automated fixes

* Refactor release note generator and update CLI argument parsing

- Adjusted the release note generator to fix string formatting.
- Refactored CLI argument parsing in migrate/cli.ts to use parseSync for improved clarity and consistency.

---------

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>
2025-12-18 23:53:46 +00:00
Matiss Janis Aboltins
a0850eab17 lint: remove deprecated eslint formatting rules (#6444)
* lint: remove deprecated eslint rules

* Rename -Infinity.md to 6444.md
2025-12-18 23:51:44 +00:00
lelemm
b54fdd6888 Excel formula feedbacks (#6432)
* More feedbacks

* cleanup

* [autofix.ci] apply automated fixes

* Add release notes for PR #6432

* [autofix.ci] apply automated fixes

---------

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>
2025-12-18 13:54:35 +00:00
Ani07-05
329d884b9b Fix schedule upcoming length years off-by-1 calculation (#6437)
* Fix schedule upcoming length years off-by-1 calculation

- Replace addYears with addMonths(value * 12) to preserve day precision
- Fixes issue where year-based upcoming schedules always calculated from Jan 1st
- Add test cases for mid-year dates to prevent regression

Fixes #6435

* Fix syntax error in schedules.test.ts and add release notes
2025-12-17 20:39:15 +00:00
Madeleine Ethridge
e8a4ebaaa3 Fix merging split transactions (#6240)
* fix(transactions): preserve split categories when merging with imported uncategorized tx; avoid orphaned subtransactions

When merging a split-categorized manual transaction with an uncategorized
imported one, keep the split lines (including categoryId) and avoid leaving
orphaned subtransactions by properly transferring parent_id references.

Fixes #5801.

* docs: add release note for PR #5856

* fix: resolve lint and typecheck errors

- Rename unused variables sub1, sub2 to _sub1, _sub2 to fix lint warnings
- Fix typecheck error by using double type assertion (unknown) in merge.ts

* refactor: optimize subtransaction queries and test db access

Address code review feedback:
- Merge two SQL queries into one using IN clause for better performance
- Use db.first in test to avoid conversion path and match db.all semantics

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* [autofix.ci] apply automated fixes

* refactor: apply code review feedback with stable branch logic

- Revert test to use db.getTransaction (not db.first) to preserve type conversion
- Refactor SQL query to use explicit branches (IN for 2 parents, = for 1, skip for 0)
- This approach is more stable across different SQL drivers

Addresses: #5856 (review feedback from @joel-jeremy)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* chore(release-notes): set category to Enhancements and shorten text; fix(merge): use shared deleteTransaction with grouped fetch + batchUpdateTransactions

* resolving lint warnings and recommendation on the test query

* switching to use the getTransaction helper

* corrected is_parent assertion to be true

* updated the PR number

---------

Co-authored-by: Golenspade <2023004079@mails.cust.edu.cn>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: fankex <2112325885@qq.com>
Co-authored-by: youngcw <calebyoung94@gmail.com>
2025-12-17 17:53:19 +00:00
TildenWinston
b5465dc506 exclude transfers from calendar summary card (#6367)
* Add conditions for transfer field in dashboard for Calendar card

Adding default filter for calendar dashboard card to remove transfers

* Add release notes for calendar summary card bugfix
2025-12-17 15:40:35 +00:00
Juulz
596a30fa00 Update tips-tricks.md and add context menus - fixes #6185 (#6417)
* Update tips-tricks.md

* Update tips-tricks.md

* Update tips-tricks.md

* Update tips-tricks.md

* Update tips-tricks.md

* Update tips-tricks.md

* Update tips-tricks.md

* Update tips-tricks.md

* Update tips-tricks.md

* Update tips-tricks.md

* Update tips-tricks.md

* Update tips-tricks.md

* Update tips-tricks.md

* Update tips-tricks.md

* Update tips-tricks.md

* Update tips-tricks.md

* Update tips-tricks.md

* Update tips-tricks.md

* Update tips-tricks.md

* Update tips-tricks.md

* Update tips-tricks.md

* Update tips-tricks.md

* Update expect.txt

Add REGEXREPLACE

* Update tips-tricks.md

* Update tips-tricks.md

* Update expect.txt

Add deselection

* Update tips-tricks.md

* Update tips-tricks.md

* Update tips-tricks.md

Typo

* Update tips-tricks.md

* Update tips-tricks.md

* Update tips-tricks.md
2025-12-17 15:20:18 +00:00
Jonathon Jongsma
91271de144 Rename "Nest egg" to "Life Savings" in crossover report graph (#6425)
I'm not sure how widely-understood the term "nest egg" is,
so use a more general term like "life savings". Also, for
projected future amounts, the tooltip already contains the word
"(projected)" to indicate that this is a future value, so we don't
need the word 'target' here, which I find a bit confusing. See
https://github.com/actualbudget/actual/pull/6384#issuecomment-3649921717
for more discussion.

Signed-off-by: Jonathon Jongsma <jonathon@quotidian.org>
2025-12-17 15:13:19 +00:00
Michael Clark
3fafb898d0 🧪 Fix flaky VRT test and prevent downloading translations where not needed (#6429)
* this is a test

* [autofix.ci] apply automated fixes

* dot reporter for line by line

* [autofix.ci] apply automated fixes

* ok...

* list reporter

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6429

* fix couple of issues

* Revert "Update VRT screenshots"

This reverts commit 0124b13475.

* putting text change back

* release notes

* skipping translations on the desktop app

---------

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>
2025-12-16 23:03:09 +00:00
Matiss Janis Aboltins
3b41455ae3 refactor: replace eslint-plugin-import with eslint-plugin-perfectionist for import sorting (#6428) 2025-12-16 21:25:20 +00:00
Tunde Jaiyesmi
c73b1afb74 fix(running-balance): resolve mobile toggle issue #6368 (#6379)
* fix(running-balance): #6368

* release note

* [autofix.ci] apply automated fixes

---------

Co-authored-by: dt_emmy <emmydave414@gmail.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: youngcw <calebyoung94@gmail.com>
2025-12-16 15:31:21 +00:00
Matiss Janis Aboltins
51ba596301 ci: fix vrt-generate and apply workflows (#6421) 2025-12-16 15:31:05 +00:00
scojo
081a3b0ca9 Refactor how crossover report dates are handled (#6383)
* Refactor how report dates are handled to more closely match pattern oin CashFlow report. Fixes issues with black screen when selecting certain Live date modes

* Add null handling for allMonths and make date clamping more consistent.

* Remove arbitray limit for at least two montsh to calculate expenses.  This allows the chart to work (someone) with one previous month of expenses.
2025-12-16 15:30:30 +00:00
Juulz
10b1fd7dcd Bugfix: Update merging.md (shortcut from M to G) (#6423)
* Update merging.md

Change shortcut key from M to G

* Create merging

* Create readme.md

* Add files via upload

* Delete packages/docs/static/img/merge-transactions/readme.md

* Delete packages/docs/static/img/merging

* Delete packages/docs/static/img/merging_transactions.png

* Update merging.md

Add new screenshot

* Update merging.md

* Update merging.md
2025-12-16 15:14:55 +00:00
Matiss Janis Aboltins
9d0d21fdef Fix VRT comment posting for fork PRs (#6420)
* Fix VRT comment posting for fork PRs

Use workflow_run trigger to post VRT failure comments with elevated permissions, enabling comments on PRs from fork repositories where GITHUB_TOKEN is read-only.

* Update permissions in e2e-vrt-comment workflow to allow read access for actions

* Enhance VRT comment posting in workflow by using environment variables for PR number and artifact URL
2025-12-15 22:22:43 +00:00
Matiss Janis Aboltins
3d19873e4f fix: add missing error handling to transaction creation page (#6336)
* feat: Show add account prompt when no accounts exist

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

* Fix: Show category creation prompt when no categories exist

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

* Refactor: Navigate to budget instead of opening modal

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

* Add release notes for PR #6336

* [autofix.ci] apply automated fixes

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
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>
2025-12-15 21:08:03 +00:00
Lee Kyeong Joon
71fe875462 fix(reports-table): ensure group row background spans full width (#6418)
* fix(reports-table): ensure custom report group row background spans full table width

* docs(release-notes): add entry for custom report group row coloring (#6418)
2025-12-15 19:02:03 +00:00
Parker Chen
cfa1156fe0 fix: Update methods to match TypeScript type (#6331) 2025-12-15 17:52:10 +00:00
lelemm
7fa1ff230e Enhance: Formula feedbacks (#6413)
* more feedbacks

* [autofix.ci] apply automated fixes

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

* fixed some tests and dashboard import

* md + theme fixes

* [autofix.ci] apply automated fixes

* Trigger actions

* sticky

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-12-15 17:21:35 +00:00
Michael Clark
d0dc1efda3 📜 Cache image folder (#6409)
* cache image folder as well

* remove immutable
2025-12-14 20:18:39 +00:00
Michael Clark
72be36d399 allow browser to cache on docs (#6405) 2025-12-14 16:53:27 +00:00
Matiss Janis Aboltins
fca4522a65 lint: enable linter in docs and fix issues (#6400)
- Removed temporary ignores for the docs package.
- Updated linting rules for the docs package to improve code quality.
- Refactored variable declarations from `let` to `const` for better consistency.
- Added a new configuration file for oxlint in the docs directory.
- Made minor formatting adjustments across various components.
2025-12-13 23:52:42 +00:00
Matiss Janis Aboltins
1989424099 lint: format docs package (#6399)
* lint: move some more rules to oxlint/oxfmt and upgrade linter versions

* lint: format docs package
2025-12-13 23:18:13 +00:00
Matiss Janis Aboltins
094da46fb0 lint: move some more rules to oxlint/oxfmt and upgrade linter versions (#6398) 2025-12-13 22:41:21 +00:00
scojo
7648446bbf Add projected net worth to crossover point report (#6384) 2025-12-13 19:26:15 +00:00
Aaron
2d4b834fe8 typescript: update validate-user.js to validate-user.ts (#6142)
* typescript: update validate-user.js to validate-user.ts

* fix capitalization in release notes.
2025-12-13 18:54:01 +00:00
plsdev89
8fe06c68f3 fix: hide merge-and-edit-rule when not creating rule (#6393)
* fix: hide merge-and-edit-rule when not creating rule

When 'Automatically rename these payees in the future' is unchecked, no rule is created, so 'Merge and edit rule' should not be offered.

Fixes #6377

* docs: add release note for #6393
2025-12-13 18:29:12 +00:00
Matiss Janis Aboltins
af7bf534ba test: use local dev server for e2e tests (#6388)
* fix: use start:browser for playwright webServer to load correct browser-preload

The playwright webServer was running 'yarn start' which doesn't set
IS_GENERIC_BROWSER, causing Vite to not resolve .browser.js files.
This resulted in browser-preload.js (empty electron stub) being loaded
instead of browser-preload.browser.js, making window.Actual undefined.

Changed to 'yarn start:browser' which properly sets IS_GENERIC_BROWSER=1
via the watch-browser script.

* chore: update Playwright configuration and add blob-report to .gitignore

- Modified Playwright config to use 'yarn start' with the correct working directory for local builds.
- Added 'blob-report' to .gitignore to exclude it from version control.
- Created release notes for running e2e tests against a local build instead of Netlify.

* chore: update transaction test snapshots for split and transfer transactions

- Updated binary snapshots for split and transfer test transactions in the e2e tests.
- Ensured that the latest visual changes are reflected in the test suite for accurate regression testing.

* chore: update transaction test snapshots for split and transfer transactions

- Updated binary snapshots for split and transfer test transactions in the e2e tests to reflect recent changes.
- Ensured visual consistency for accurate regression testing.

* refactor: change test lifecycle hooks from beforeAll/afterAll to beforeEach/afterEach

- Updated test files to use beforeEach and afterEach hooks for better isolation of tests.
- This change ensures that each test starts with a fresh state, improving reliability and reducing side effects across tests.

* chore: update e2e test workflow to disable translation downloads

- Modified the e2e test workflow to include a new input parameter `download-translations` set to 'false' for the setup action.
- This change aims to streamline the testing process by preventing unnecessary translation downloads during the test runs.

* chore: update e2e test snapshots for settings page visuals

- Updated binary snapshots for the settings page in e2e tests to reflect recent visual changes.
- Ensured that the latest visual updates are accurately represented for regression testing.

* fix: safely close page in e2e tests

- Updated all e2e test files to use optional chaining when closing the page, ensuring that the close method is only called if the page is defined.
- This change improves the robustness of the tests by preventing potential errors when the page object is not available.
2025-12-13 18:27:40 +00:00
Michael Clark
6fafc6371b 📜 Redirect www traffic to .org as well (#6395)
* redirect www traffic to .org as well

* conflict
2025-12-13 16:53:48 +00:00
Michael Clark
7214e263d7 add cname in static so it doesnt remove it when deploying (#6394) 2025-12-13 15:28:22 +00:00
Michael Clark
87cfcd35f7 📜 Docusaurus config for gh-pages (#6386)
* docusaurus config for gh-pages

* [autofix.ci] apply automated fixes

* workflow

* deploy:docs

* using github actions bot as name

* release notes

* adding jekyll to excludes

* nojeklyll

* setup first then deploy

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-12-13 15:05:45 +00:00
Michael Clark
fb5a86dec1 📜 Redirect the .com domain to .org (#6391)
* redirect the .com domain to .org

* ok wabbit
2025-12-13 14:57:55 +00:00
Matiss Janis Aboltins
4ae85096cd feat: trigger VRT updates via /update-vrt comment (#6380)
* feat: trigger VRT updates via /update-vrt comment

- Change vrt-update-generate.yml to trigger on issue_comment with /update-vrt
- Update VRT failure comment to inform users about the /update-vrt command
- Add step to fetch PR details since issue_comment events don't provide them

* fix: update VRT trigger condition to use startsWith for command detection

- Modify the condition in vrt-update-generate.yml to use startsWith instead of contains for the /update-vrt command in PR comments, ensuring more accurate command detection.
2025-12-13 10:28:28 +00:00
Juulz
2e42903ba7 Update custom tag CSS so all themes use the dark color scheme (#6245)
* Update useTagCSS.ts light = dark

* Update useTagCSS.ts so all themes use the same color scheme

* [autofix.ci] apply automated fixes

* Improve tag readability in light theme.

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-12-13 00:18:06 +00:00
凯旋 - kǎixuán
a66ec78a50 Make category group rows clickable in mobile budget view (#6272)
* fix(mobile): Ensure background color fills entire viewport

- Added minHeight: '100vh' to ensure background covers full viewport
- Kept paddingBottom for mobile navigation
- Maintained existing theme color usage

* feat(mobile): Make entire income group row clickable to toggle collapse

- Added onClick handler to the main View container
- Added cursor: pointer for better UX
- Kept existing arrow button functionality
- Ensured consistent behavior with expense groups

* feat(mobile): Make entire expense group row clickable to toggle collapse

- Added onClick handler to the main View container
- Added cursor: pointer for better UX
- Maintained existing arrow button functionality
- Improved touch target size for better mobile usability

* chore(release): add release note

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-12-13 00:17:51 +00:00
Stephen Brown II
c6fcdb06e4 Right-align report table numeric columns (#6355)
* Right-align report table numeric columns

* Set textAlign=right on unexposedContent

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6355

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-12-13 00:17:35 +00:00
Matiss Janis Aboltins
8734f7db22 Fix API init() silently ignoring authentication failures (#6337)
When using the @actual-app/api package, if authentication failed during
init() (e.g., wrong password, network issue), the error was silently
ignored. This led to confusing 'Could not get remote files' errors later
when calling downloadBudget().

This fix ensures init() properly throws an error when authentication
fails, providing clear feedback like 'Authentication failed: invalid-password'.

Fixes #6320
2025-12-12 23:16:47 +00:00
Matiss Janis Aboltins
32bc254040 Lint: port react and import rules from eslint to oxc (#6312)
* Enforce JSX file extensions for React components

- Update eslint config to enforce .jsx/.tsx extensions for files containing JSX
- Convert docs package JS files to JSX where they contain React code
- Fix unstable nested components in CrossoverGraph and NetWorthGraph
- Update oxlint configuration
- Update e2e fixtures

* Fix: Rename react-hooks/exhaustive-deps to react/exhaustive-deps

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

* Enhance ESLint configuration and update import rules

* Refactor ESLint configuration to enhance import order rules and add eslint-plugin-import

* Fix ESLint directive comments in API files to use correct syntax

* Fix

* Fix ESLint directive comments and update import/extensions rule in configuration

* Refactor ESLint configuration to enforce JSX extension rules and improve code clarity

* Update ESLint configuration: disable 'import/no-unresolved' rule and remove obsolete .oxlintrc.json file

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2025-12-12 22:40:38 +00:00
Matiss Janis Aboltins
ecb8a1a548 Shard e2e ci jobs (#6359)
* Refactor e2e-test workflow to improve Playwright test sharding and report handling

- Restore full shard count (5 shards) for Playwright tests to enhance test coverage and performance
- Re-enable functional desktop app tests with proper xvfb setup
- Simplify Playwright test command structure for better readability
- Refactor VRT blob report merging process with improved artifact handling
- Update Playwright reporter configuration to use blob reporter in CI
- Streamline artifact paths and download/merge operations for better organization

* Remove VRT environment variable from e2e-test workflow to streamline test execution

* Update e2e-test workflow to always upload VRT blob report artifacts, ensuring consistent artifact handling regardless of job cancellation.
2025-12-12 21:39:20 +00:00
Joshua Granick
77f9403afb Apply ESLint ignore rules to Oxfmt to prevent false positives when running 'npm lint' (#6348)
* Apply ESLint excluded paths to Oxfmt

* Add release notes

* Revert "Apply ESLint excluded paths to Oxfmt"

This reverts commit 2fec839182.

* Filter additional dist directories in top-level .gitignore to exclude from oxfmt linting
2025-12-12 20:32:05 +00:00
Michael Clark
cb4d616761 Add Flathub badge to release (#6376)
* add link to flathub to release

* style a bit better

* release notes
2025-12-11 22:04:21 +00:00
Matiss Janis Aboltins
b99d3ab802 Use PAT to trigger CI workflows in VRT update workflow (#6363) 2025-12-11 21:02:10 +00:00
Jonathon Jongsma
9c9a98844f Fix detection of crossover point for low expense months (#6371)
* Fix detection of crossover point for low expense months

Always compute the expense projection and calculate the crossover point
based on the projection instead of individual historical expense data
because otherwise a low expense month can incorrectly trigger a false
crossover point detection.

See comment at
https://github.com/actualbudget/actual/issues/6134#issuecomment-3608140098
for more information.

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

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6371

---------

Signed-off-by: Jonathon Jongsma <jonathon@quotidian.org>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-12-11 20:00:16 +00:00
Michael Clark
64bc7dbf6e 🤖 Adding path filters so workflows only run when required (#6364)
* adding path filters to workflows so they only run when required

* trigger them also when the workflow changes

* adding yarn lock in case packages affect e2e

* release notes

* add the package.json in case we modify the scripts

* Remove API changes from size comparison workflow

* Clarify size impact of package changes in workflow

Updated comments to clarify that certain package changes don't affect the size of the web/api.

* Fix comments for VRT update exclusions

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6364

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6364

* Fix comment formatting in VRT update workflow

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-12-11 19:20:36 +00:00
Jonathon Jongsma
1775520dd3 Change default crossover point project type to 'hampel' (#6372)
As mentioned at
https://github.com/actualbudget/actual/issues/6134#issuecomment-35495936
52, a linear projection type doesn't seem to make much sense for expense
projection. It should definitely not be the default projection type.
Arguably it should not even be an option.

Signed-off-by: Jonathon Jongsma <jonathon@quotidian.org>
Co-authored-by: youngcw <calebyoung94@gmail.com>
2025-12-11 19:06:22 +00:00
Michael Clark
ef222f395b :electron: Add reviewers to Flathub release pr & documentation (#6361)
* add reviewers to flathub pr

* release notes

* some docs for flathub release

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6361

* documentation

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-12-11 15:54:17 +00:00
Juulz
39170fa007 Docs - Update carrying-debt.md to fix the empty ::: warning ::: admonition (#6354)
* Update carrying-debt.md

Updated the empty ::: warning ::: that wasn't showing.

* Update carrying-debt.md screenshots

Update screenshot size.

---------

Co-authored-by: youngcw <calebyoung94@gmail.com>
2025-12-11 15:32:21 +00:00
Matiss Janis Aboltins
6f76b67da7 Use personal access token securely for VRT update workflow push (#6356)
* Use personal access token securely for VRT update workflow push

* Update button label from 'Apply budget template' to 'Overwrite budget template' in mobile budget menu modal for consistency with recent changes.

* Update button label from 'Overwrite budget template' to 'Overwrite with template' in mobile budget menu modal for clarity and consistency.
2025-12-10 19:25:07 +00:00
youngcw
962fe44772 [Goals] fix not budgeting enough when schedule amount from previous month was less than this month (#6268)
* fix not budgeting enough when schedule hasn't been paid yet

* remove comments

* make logic better

* fix bad rebase

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6268

* cleanup vrt

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-12-09 23:09:10 +00:00
Matiss Janis Aboltins
91f444d788 Use ACTIONS_UPDATE_TOKEN for workflows that push to forks (#6349)
GITHUB_TOKEN doesn't have permission to push to fork branches. Use a PAT stored as ACTIONS_UPDATE_TOKEN instead for:
- VRT update workflow (checkout and push to contributor forks)
- AI-generated release notes (commit files to PR branches)
2025-12-09 22:47:33 +00:00
Matiss Janis Aboltins
0aa96ecaee Fix lint violations (vol.3) (#6301)
* Fix lint violations

* Refactor code for clarity and consistency

- Updated various components to improve readability and maintainability, including:
  - Changed `while (1)` to `while (true)` for better clarity.
  - Simplified conditional checks by removing unnecessary boolean casts.
  - Added missing `key` props in mapped elements to ensure proper rendering in lists.
  - Adjusted the handling of hidden states in budget components for clearer logic.
  - Cleaned up linting rules in `.oxlintrc.json` to streamline configuration.

* Enhance accessibility and linting compliance

- Updated `.oxlintrc.json` to add a warning for `jsx-a11y/no-autofocus` and removed several disabled rules.
- Added `aria-level` attributes to improve semantic structure in `Page.tsx`, `Modal.tsx`, and `ReportCardName.tsx`.
- Replaced `<label>` elements with `<Text>` components in various modals to ensure proper accessibility.
- Added `htmlFor` attributes to labels in `ImportTransactionsModal.tsx` for better form accessibility.
- Disabled specific linting rules inline to address accessibility concerns in `Image.jsx` and `Toggle.tsx`.

* Add new keywords to spelling allowlist

- Updated `.github/actions/docs-spelling/allow/keywords.txt` to include `oxfmt` and `oxlint` for improved spell-checking in documentation and code comments.

* Disable no-autofocus rule in .oxlintrc.json

* Update Trans component usage in MergeUnusedPayeesModal

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-12-09 21:39:50 +00:00
Juulz
5a4fc5823c Change 'Apply' to 'Overwrite' for budget templates on Category and Group menus - fixes #6181 (#6235)
* Change 'Apply' to 'Overwrite'

* Change 'Apply' to 'Overwrite'

* Change 'Apply' to 'Overwrite'

* Change 'Apply' to 'Overwrite'

* Change 'Apply' to 'Overwrite'

* Create 6235.md

Add release notes

* Update to Overwrite with budget template

* Update to Overwrite with budget template

* Update to Overwrite with budget template

* Update to Overwrite with budget template

* Update to Overwrite with budget template

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6235

* Update to Overwrite with template

* Update to Overwrite with templates

* Update to Overwrite with template

* Update to Overwrite with template

* Update to Overwrite with templates

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6235

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6235

* cleanup vrt

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #6235

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: youngcw <calebyoung94@gmail.com>
2025-12-09 21:37:01 +00:00
Juulz
14a1e8bb45 Update importing.md - fixes #6136 (#6232)
* Update importing.md

Update to include links to connecting your bank, community projects and added that AB supports CAMT imports.

* Update importing.md

* Update importing.md

* Update importing.md

Added pluggy.ai

* Apply suggestions from code review

Co-authored-by: youngcw <calebyoung94@gmail.com>

---------

Co-authored-by: youngcw <calebyoung94@gmail.com>
2025-12-09 16:29:10 +00:00
Michael Clark
8279271119 :electron: Update desktop file on linux to have keywords and categories (#6335)
* update desktop file on linux to have keywords and categories

* release notes
2025-12-09 09:30:02 +00:00
1607 changed files with 9777 additions and 5859 deletions

35
.coderabbit.yaml Normal file
View File

@@ -0,0 +1,35 @@
issue_enrichment:
auto_enrich:
enabled: false
reviews:
request_changes_workflow: true
review_status: true
high_level_summary: false
finishing_touches:
docstrings:
enabled: false
pre_merge_checks:
docstrings:
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.'
- label: 'API'
instructions: 'This issue or PR updates the API in `packages/api`.'
- label: 'documentation'
instructions: 'This issue updates the documentation in `packages/docs`.'
- label: 'contains DB migrations'
instructions: 'This issue or PR contains DB migrations in `packages/loot-core/migrations`.'
- label: 'size small'
instructions: 'This issue or PR is a small change (less than 50 lines of code) that is expected to have a small impact on the codebase.'
auto_apply_labels: true

View File

@@ -26,7 +26,7 @@ body:
id: what-happened
attributes:
label: What happened?
description: Also tell us, what did you expect to happen? If youre reporting an issue with imports, please attach a (redacted) version of the file youre having trouble importing. You may need to zip it before uploading.
description: Also tell us, what did you expect to happen? If you're reporting an issue with imports, please attach a (redacted) version of the file you're having trouble importing. You may need to zip it before uploading.
placeholder: Tell us what you see!
value: 'A bug happened!'
validations:

View File

@@ -7,19 +7,19 @@ body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this feature request! Please ensure you provide as much information as possible so we can better understand what youre proposing so we can come up with the best solution for everyone.
Thanks for taking the time to fill out this feature request! Please ensure you provide as much information as possible so we can better understand what you're proposing so we can come up with the best solution for everyone.
- type: checkboxes
id: existing-issue
attributes:
label: 'Verified feature request does not already exist?'
description: 'Please search to see if an issue or PR already exists for the feature youre requesting.'
description: "Please search to see if an issue or PR already exists for the feature you're requesting."
options:
- label: 'I have searched and found no existing issue'
required: true
- type: checkboxes
attributes:
label: '💻'
description: (Optional) Please check this box if youre willing to open a PR to implement this feature. Well help you get started and answer any questions you have along the way :)
description: (Optional) Please check this box if you're willing to open a PR to implement this feature. We'll help you get started and answer any questions you have along the way :)
options:
- label: Would you like to implement this feature?
- type: textarea
@@ -33,7 +33,7 @@ body:
id: solution
attributes:
label: Describe your ideal solution to this problem
description: Feel free to give multiple different ideas for how the problem could be solved — wed love to have a discussion to find the best way to solve your problem and related problems others may face! (Or leave this blank if you dont have a solution in mind yet.)
description: Feel free to give multiple different ideas for how the problem could be solved — we'd love to have a discussion to find the best way to solve your problem and related problems others may face! (Or leave this blank if you don't have a solution in mind yet.)
validations:
required: false
- type: textarea

View File

@@ -1,12 +1,13 @@
#!/usr/bin/env node
import { Octokit } from '@octokit/rest';
import fs from 'fs';
import { Octokit } from '@octokit/rest';
const token = process.env.GITHUB_TOKEN;
const repo = process.env.GITHUB_REPOSITORY;
const issueNumber = process.env.GITHUB_EVENT_ISSUE_NUMBER;
const commentId = process.env.GITHUB_EVENT_COMMENT_ID;
const commentId = String(process.env.GITHUB_EVENT_COMMENT_ID);
if (!token || !repo || !issueNumber || !commentId) {
console.log('Missing required environment variables');
@@ -51,7 +52,7 @@ async function checkFirstComment() {
const isFirstSummaryComment =
coderabbitSummaryComments.length === 1 &&
coderabbitSummaryComments[0].id == commentId;
String(coderabbitSummaryComments[0].id) === commentId;
console.log(
`CodeRabbit summary comments found: ${coderabbitSummaryComments.length}`,

View File

@@ -1,8 +1,9 @@
#!/usr/bin/env node
import { Octokit } from '@octokit/rest';
import fs from 'fs';
import { Octokit } from '@octokit/rest';
const token = process.env.GITHUB_TOKEN;
const repo = process.env.GITHUB_REPOSITORY;
const issueNumber = process.env.GITHUB_EVENT_ISSUE_NUMBER;

View File

@@ -46,7 +46,8 @@ category: ${cleanCategory}
authors: [${summaryData.author}]
---
${summaryData.summary}`;
${summaryData.summary}
`;
const fileName = `upcoming-release-notes/${summaryData.prNumber}.md`;
@@ -75,7 +76,7 @@ ${summaryData.summary}`;
repo: headRepo,
path: fileName,
message: `Add release notes for PR #${summaryData.prNumber}`,
content: Buffer.from(`${fileContent}\n\n`).toString('base64'),
content: Buffer.from(fileContent).toString('base64'),
branch: prBranch,
committer: {
name: 'github-actions[bot]',

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env node
const https = require('https');
const fs = require('fs');
const https = require('https');
const commentBody = process.env.GITHUB_EVENT_COMMENT_BODY;
const prDetailsJson = process.env.PR_DETAILS;

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env node
const https = require('https');
const fs = require('fs');
const https = require('https');
const commentBody = process.env.GITHUB_EVENT_COMMENT_BODY;
const prDetailsJson = process.env.PR_DETAILS;
@@ -71,7 +71,7 @@ try {
console.log('Generated summary:', summary);
const result = {
summary: summary,
summary,
prNumber: prDetails.number,
author: prDetails.author,
};

View File

@@ -1,8 +1,9 @@
#!/usr/bin/env node
import { Octokit } from '@octokit/rest';
import fs from 'fs';
import { Octokit } from '@octokit/rest';
const token = process.env.GITHUB_TOKEN;
const repo = process.env.GITHUB_REPOSITORY;
const issueNumber = process.env.GITHUB_EVENT_ISSUE_NUMBER;

View File

@@ -4,8 +4,8 @@
// 1. Identify the migrations in packages/loot-core/migrations/* on `master` and HEAD
// 2. Make sure that any new migrations on HEAD are dated after the latest migration on `master`.
const path = require('path');
const { spawnSync } = require('child_process');
const path = require('path');
const migrationsDir = path.join(
__dirname,
@@ -35,14 +35,15 @@ function readMigrations(ref) {
}
spawnSync('git', ['fetch', 'origin', 'master']);
let masterMigrations = readMigrations('origin/master');
let headMigrations = readMigrations('HEAD');
const masterMigrations = readMigrations('origin/master');
const headMigrations = readMigrations('HEAD');
let latestMasterMigration = masterMigrations[masterMigrations.length - 1].date;
let newMigrations = headMigrations.filter(
const latestMasterMigration =
masterMigrations[masterMigrations.length - 1].date;
const newMigrations = headMigrations.filter(
migration => !masterMigrations.find(m => m.name === migration.name),
);
let badMigrations = newMigrations.filter(
const badMigrations = newMigrations.filter(
migration => migration.date <= latestMasterMigration,
);

View File

@@ -101,6 +101,8 @@ offbudget
ofx
OFX
oneof
oxfmt
oxlint
payeerule
pikaday
pikapods

View File

@@ -72,5 +72,6 @@ ignore$
(?:^|/)yarn\.lock$
(?:^|/)(?i)docusaurus.config.js
(?:^|/)(?i)README.md
(?:^|/)(?i).nojekyll
^\static/
\.tsx$

View File

@@ -8,6 +8,7 @@ Anglais
aql
AUR
Authentik
AVERAGEA
BANKA
BANKINTER
BAWAATWW
@@ -37,20 +38,29 @@ Cloudflare
CMCIFRPAXXX
COBADEFF
CODEOWNERS
COEP
commerzbank
COOP
Copiar
COUNTA
COUNTBLANK
countif
CREGBEBB
crt
Danske
datadir
DATEDIF
Depositos
deselection
DIREKT
Dockerfiles
Dominguez
DUSSDEDDXXX
DUSSELDORF
EDATE
ENTERCARD
Entra
EOMONTH
EUA
Eurocard
fidd
@@ -58,6 +68,7 @@ Fineco
Finicity
Fintro
Finverse
flathub
Flathub
FORTUNEO
FTNOFRP
@@ -71,16 +82,28 @@ Grafana
HABAL
Hampel
HELADEF
HLOOKUP
IFERROR
IFNA
INDUSTRIEL
INGBPLPW
Ingo
INR
Intesa
INVSTMTMSGSRS
IRR
ISERROR
ISEVEN
ISLOGICAL
ISNA
ISODD
ISOWEEKNUM
ISTEXT
ISYBANK
ITBBITMM
jfdoming
JMD
jws
KBCBE
Keycloak
Khurozov
@@ -90,15 +113,18 @@ lage
LHV
LHVBEE
LKR
MAXA
mbank
mdc
modals
Moldovan
murmurhash
NETWORKDAYS
nginx
OIDC
overbudgeted
overbudgeting
oxc
Paribas
passwordless
pluggyai
@@ -113,6 +139,7 @@ Qatari
QNTOFRP
QONTO
Raiffeisen
REGEXREPLACE
revolut
RIED
RSchedule
@@ -126,7 +153,11 @@ sseldorf
SSK
Stadtsparkasse
statestore
STDEVP
SUBASKBX
sumif
SUMPRODUCT
SUMSQ
SVGR
swc
SWEDBANK
@@ -144,9 +175,12 @@ ubuntu
userinfo
Userscripts
UZS
VLOOKUP
vrt
VUB
Wallos
websecure
WEEKNUM
Widiba
WOR
youngcw

View File

@@ -1,40 +0,0 @@
#!/bin/bash
current_commit=$(git rev-parse HEAD)
echo "Running on commit $COMMIT_SHA"
function get_status() {
echo "::group::API Response"
curl --header "Authorization: Bearer $GITHUB_TOKEN" "https://api.github.com/repos/actualbudget/actual/commits/$COMMIT_SHA/statuses" > /tmp/status.json
cat /tmp/status.json
echo "::endgroup::"
netlify=$(yarn jq '[.[] | select(.context == "netlify/actualbudget/deploy-preview")][0]' /tmp/status.json)
state=$(yarn jq -r '.state' <<< "$netlify")
echo "::group::Netlify Status"
echo "$netlify"
echo "::endgroup::"
}
get_status
while [ "$netlify" == "null" ]; do
echo "Waiting for Netlify to start building..."
sleep 10
get_status
done
while [ "$state" == "pending" ]; do
echo "Waiting for Netlify to finish building..."
sleep 10
get_status
done
if [ "$state" == "success" ]; then
echo -e "\033[0;32mNetlify build succeeded!\033[0m"
yarn jq -r '"url=" + .target_url' <<< "$netlify" > $GITHUB_OUTPUT
exit 0
else
echo -e "\033[0;31mNetlify build failed. Cancelling end-to-end tests.\033[0m"
exit 1
fi

View File

@@ -20,6 +20,8 @@ jobs:
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up environment
uses: ./.github/actions/setup
with:
download-translations: 'false'
- name: Check if this is CodeRabbit's first comment
id: check-first-comment
@@ -72,7 +74,7 @@ jobs:
if: steps.check-first-comment.outputs.result == 'true' && steps.check-release-notes-exists.outputs.result == 'false' && steps.generate-summary.outputs.result != 'null' && steps.determine-category.outputs.result != 'null' && steps.determine-category.outputs.result != ''
run: node .github/actions/ai-generated-release-notes/create-release-notes-file.js
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_TOKEN: ${{ secrets.ACTIONS_UPDATE_TOKEN }}
GITHUB_REPOSITORY: ${{ github.repository }}
GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }}
SUMMARY_DATA: ${{ steps.generate-summary.outputs.result }}

View File

@@ -18,6 +18,8 @@ jobs:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up environment
uses: ./.github/actions/setup
with:
download-translations: 'false'
- name: Format code
run: yarn lint:fix
- uses: autofix-ci/action@635ffb0c9798bd160680f18fd73371e355b85f27

View File

@@ -19,6 +19,8 @@ jobs:
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up environment
uses: ./.github/actions/setup
with:
download-translations: 'false'
- name: Count points
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

33
.github/workflows/docs-release.yml vendored Normal file
View File

@@ -0,0 +1,33 @@
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

@@ -2,6 +2,17 @@ name: E2E Tests
on:
pull_request:
paths:
- 'packages/**'
- 'package.json'
- 'yarn.lock'
- '.github/workflows/e2e-test.yml'
- '!packages/sync-server/**' # Sync server changes don't affect E2E tests
- '!packages/api/**' # API changes don't affect E2E tests
- '!packages/ci-actions/**' # CI actions changes don't affect E2E tests
- '!packages/docs/**' # Docs changes don't affect E2E tests
- '!packages/eslint-plugin-actual/**' # Eslint plugin changes don't affect E2E tests
merge_group:
env:
GITHUB_PR_NUMBER: ${{github.event.pull_request.number}}
@@ -11,42 +22,29 @@ concurrency:
cancel-in-progress: true
jobs:
netlify:
name: Wait for Netlify build to finish
runs-on: ubuntu-latest
outputs:
netlify_url: ${{ steps.netlify.outputs.url }}
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up environment
uses: ./.github/actions/setup
- name: Wait for Netlify build to finish
id: netlify
env:
COMMIT_SHA: ${{ github.event.pull_request.head.sha }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: ./.github/actions/netlify-wait-for-build
functional:
name: Functional
needs: netlify
name: Functional (shard ${{ matrix.shard }}/5)
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
shard: [1, 2, 3, 4, 5]
container:
image: mcr.microsoft.com/playwright:v1.56.0-jammy
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up environment
uses: ./.github/actions/setup
with:
download-translations: 'false'
- name: Trust the repository directory
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
- name: Run E2E Tests on Netlify URL
run: yarn e2e
env:
E2E_START_URL: ${{ needs.netlify.outputs.netlify_url }}
- name: Run E2E Tests
run: yarn e2e --shard=${{ matrix.shard }}/5
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
if: always()
with:
name: desktop-client-test-results
name: desktop-client-test-results-shard-${{ matrix.shard }}
path: packages/desktop-client/test-results/
retention-days: 30
overwrite: true
@@ -60,6 +58,8 @@ jobs:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up environment
uses: ./.github/actions/setup
with:
download-translations: 'false'
- name: Trust the repository directory
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
- name: Run Desktop app E2E Tests
@@ -74,23 +74,68 @@ jobs:
overwrite: true
vrt:
name: Visual regression
needs: netlify
name: Visual regression (shard ${{ matrix.shard }}/5)
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
shard: [1, 2, 3, 4, 5]
container:
image: mcr.microsoft.com/playwright:v1.56.0-jammy
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up environment
uses: ./.github/actions/setup
- name: Run VRT Tests on Netlify URL
run: yarn vrt
env:
E2E_START_URL: ${{ needs.netlify.outputs.netlify_url }}
with:
download-translations: 'false'
- name: Run VRT Tests
run: yarn vrt --shard=${{ matrix.shard }}/5
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
if: always()
with:
name: desktop-client-test-results
path: packages/desktop-client/test-results/
name: vrt-blob-report-${{ matrix.shard }}
path: packages/desktop-client/blob-report/
retention-days: 1
overwrite: true
merge-vrt:
name: Merge VRT Reports
needs: vrt
runs-on: ubuntu-latest
if: ${{ !cancelled() }}
container:
image: mcr.microsoft.com/playwright:v1.56.0-jammy
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Set up environment
uses: ./.github/actions/setup
- name: Download all blob reports
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
with:
path: packages/desktop-client/all-blob-reports
pattern: vrt-blob-report-*
merge-multiple: true
- name: Merge reports
id: merge-reports
run: yarn workspace @actual-app/web run playwright merge-reports --reporter html ./all-blob-reports
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
id: playwright-report-vrt
with:
name: html-report--attempt-${{ github.run_attempt }}
path: packages/desktop-client/playwright-report
retention-days: 30
overwrite: true
- name: Save VRT metadata for comment workflow
if: github.event_name == 'pull_request'
run: |
mkdir -p vrt-metadata
echo "${{ github.event.pull_request.number }}" > vrt-metadata/pr-number.txt
echo "${{ needs.vrt.result }}" > vrt-metadata/vrt-result.txt
echo "${{ steps.playwright-report-vrt.outputs.artifact-url }}" > vrt-metadata/artifact-url.txt
- name: Upload VRT metadata
if: github.event_name == 'pull_request'
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: vrt-comment-metadata
path: vrt-metadata/
retention-days: 1

66
.github/workflows/e2e-vrt-comment.yml vendored Normal file
View File

@@ -0,0 +1,66 @@
name: VRT Comment
# This workflow posts VRT failure comments on PRs, including fork PRs.
# It runs with elevated permissions via workflow_run trigger.
on:
workflow_run:
workflows: ['E2E Tests']
types:
- completed
permissions:
actions: read
pull-requests: write
jobs:
comment:
name: Post VRT Comment
runs-on: ubuntu-latest
if: github.event.workflow_run.event == 'pull_request'
steps:
- name: Download VRT metadata
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
run-id: ${{ github.event.workflow_run.id }}
name: vrt-comment-metadata
path: /tmp/vrt-metadata
continue-on-error: true
- name: Extract metadata
id: metadata
run: |
if [ ! -f "/tmp/vrt-metadata/pr-number.txt" ]; then
echo "No metadata found, skipping..."
echo "should_comment=false" >> "$GITHUB_OUTPUT"
exit 0
fi
PR_NUMBER=$(cat "/tmp/vrt-metadata/pr-number.txt")
VRT_RESULT=$(cat "/tmp/vrt-metadata/vrt-result.txt")
ARTIFACT_URL=$(cat "/tmp/vrt-metadata/artifact-url.txt")
echo "pr_number=$PR_NUMBER" >> "$GITHUB_OUTPUT"
echo "vrt_result=$VRT_RESULT" >> "$GITHUB_OUTPUT"
echo "artifact_url=$ARTIFACT_URL" >> "$GITHUB_OUTPUT"
if [ "$VRT_RESULT" = "failure" ]; then
echo "should_comment=true" >> "$GITHUB_OUTPUT"
echo "VRT tests failed for PR #$PR_NUMBER"
else
echo "should_comment=false" >> "$GITHUB_OUTPUT"
echo "VRT tests passed or skipped for PR #$PR_NUMBER"
fi
- name: Comment on PR with VRT report link
if: steps.metadata.outputs.should_comment == 'true'
uses: marocchino/sticky-pull-request-comment@773744901bac0e8cbb5a0dc842800d45e9b2b405 # v2.9.4
with:
number: ${{ steps.metadata.outputs.pr_number }}
header: vrt-comment
hide_and_recreate: true
hide_classify: OUTDATED
message: |
<!-- vrt-comment -->
VRT tests ❌ failed. [View the test report](${{ steps.metadata.outputs.artifact_url }}).
To update the VRT screenshots, comment `/update-vrt` on this PR. The VRT update operation takes about 50 minutes.

View File

@@ -52,14 +52,13 @@ jobs:
sudo flatpak install org.freedesktop.Sdk//24.08 -y
sudo flatpak install org.freedesktop.Platform//24.08 -y
sudo flatpak install org.electronjs.Electron2.BaseApp//24.08 -y
sudo flatpak install org.flatpak.Builder -y
METAINFO_FILE="packages/desktop-electron/extra-resources/linux/com.actualbudget.actual.metainfo.xml"
TODAY=$(date +%Y-%m-%d)
VERSION=${{ steps.process_version.outputs.version }}
sed -i "s/%RELEASE_VERSION%/$VERSION/g; s/%RELEASE_DATE%/$TODAY/g" "$METAINFO_FILE"
sudo apt-get install appstream
appstreamcli --version
appstreamcli validate "$METAINFO_FILE"
flatpak run --command=flatpak-builder-lint org.flatpak.Builder appstream "$METAINFO_FILE"
- name: Set up environment
uses: ./.github/actions/setup
- name: Build Electron for Mac
@@ -101,27 +100,20 @@ jobs:
## Desktop releases
Please note: Microsoft store updates can sometimes lag behind the main release by a couple of days while they verify the new version.
<a href="https://apps.microsoft.com/detail/9p2hmlhsdbrm?cid=Github+Releases&mode=direct">
<img src="https://get.microsoft.com/images/en-us%20dark.svg" width="200"/>
</a>
<p>
<a href="https://apps.microsoft.com/detail/9p2hmlhsdbrm?cid=Github+Releases&mode=direct"><img src="https://get.microsoft.com/images/en-us%20dark.svg" width="200" /></a>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACw=" width="12" height="1" alt="" />
<a href="https://flathub.org/apps/com.actualbudget.actual"><img width="165" style="margin-left:12px;" alt="Get it on Flathub" src="https://flathub.org/api/badge?locale=en" /></a>
</p>
files: |
packages/desktop-electron/dist/*.dmg
packages/desktop-electron/dist/*.exe
!packages/desktop-electron/dist/Actual-windows.exe
packages/desktop-electron/dist/*.AppImage
packages/desktop-electron/dist/*.flatpak
- name: Retrieve AppImage SHA256 for Flathub
id: appimage_sha256
run: |
APPIMAGE_X64_SHA256=$(sha256sum packages/desktop-electron/dist/Actual-linux-x86_64.AppImage | awk '{ print $1 }')
APPIMAGE_ARM64_SHA256=$(sha256sum packages/desktop-electron/dist/Actual-linux-arm64.AppImage | awk '{ print $1 }')
echo "appimage_x64_sha256=$APPIMAGE_X64_SHA256" >> "$GITHUB_OUTPUT"
echo "appimage_arm64_sha256=$APPIMAGE_ARM64_SHA256" >> "$GITHUB_OUTPUT"
outputs:
version: ${{ steps.process_version.outputs.version }}
appimage_x64_sha256: ${{ steps.appimage_sha256.outputs.appimage_x64_sha256 }}
appimage_arm64_sha256: ${{ steps.appimage_sha256.outputs.appimage_arm64_sha256 }}
publish-microsoft-store:
needs: build
@@ -170,6 +162,19 @@ jobs:
runs-on: ubuntu-22.04
if: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') }}
steps:
- name: Download Linux artifacts
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
with:
name: actual-electron-ubuntu-22.04
- name: Calculate AppImage SHA256
id: appimage_sha256
run: |
APPIMAGE_X64_SHA256=$(sha256sum Actual-linux-x86_64.AppImage | awk '{ print $1 }')
APPIMAGE_ARM64_SHA256=$(sha256sum Actual-linux-arm64.AppImage | awk '{ print $1 }')
echo "APPIMAGE_X64_SHA256=$APPIMAGE_X64_SHA256" >> "$GITHUB_ENV"
echo "APPIMAGE_ARM64_SHA256=$APPIMAGE_ARM64_SHA256" >> "$GITHUB_ENV"
- name: Checkout Flathub repo
uses: actions/checkout@v6
with:
@@ -179,11 +184,11 @@ jobs:
- name: Update manifest with new SHA256
run: |
# Replace x86_64 entry
sed -i "/x86_64.AppImage/{n;s|sha256:.*|sha256: ${{ needs.build.outputs.appimage_x64_sha256 }}|}" com.actualbudget.actual.yml
sed -i "/x86_64.AppImage/{n;s|sha256:.*|sha256: ${{ env.APPIMAGE_X64_SHA256 }}|}" com.actualbudget.actual.yml
sed -i "/x86_64.AppImage/s|url:.*|url: https://github.com/actualbudget/actual/releases/download/v${{ needs.build.outputs.version }}/Actual-linux-x86_64.AppImage|" com.actualbudget.actual.yml
# Replace arm64 entry
sed -i "/arm64.AppImage/{n;s|sha256:.*|sha256: ${{ needs.build.outputs.appimage_arm64_sha256 }}|}" com.actualbudget.actual.yml
sed -i "/arm64.AppImage/{n;s|sha256:.*|sha256: ${{ env.APPIMAGE_ARM64_SHA256 }}|}" com.actualbudget.actual.yml
sed -i "/arm64.AppImage/s|url:.*|url: https://github.com/actualbudget/actual/releases/download/v${{ needs.build.outputs.version }}/Actual-linux-arm64.AppImage|" com.actualbudget.actual.yml
cat com.actualbudget.actual.yml
@@ -192,10 +197,11 @@ jobs:
uses: peter-evans/create-pull-request@v7
with:
token: ${{ secrets.FLATHUB_GITHUB_TOKEN }}
commit-message: "Update Actual flatpak to version ${{ needs.build.outputs.version }}"
branch: "release/${{ needs.build.outputs.version }}"
title: "Update Actual flatpak to version ${{ needs.build.outputs.version }}"
commit-message: 'Update Actual flatpak to version ${{ needs.build.outputs.version }}'
branch: 'release/${{ needs.build.outputs.version }}'
title: 'Update Actual flatpak to version ${{ needs.build.outputs.version }}'
body: |
This PR updates the Actual desktop flatpak to version ${{ needs.build.outputs.version }}.
:link: [View release notes](https://actualbudget.org/blog/release-${{ needs.build.outputs.version }})
reviewers: 'jfdoming,MatissJanis,youngcw' # The core team that have accepted the collaborator access to the Flathub repo

View File

@@ -9,6 +9,15 @@ env:
on:
pull_request:
paths:
- 'packages/**'
- 'package.json'
- 'yarn.lock'
- '.github/workflows/electron-pr.yml'
- '!packages/api/**' # API changes don't affect Electron
- '!packages/ci-actions/**' # CI actions changes don't affect Electron
- '!packages/docs/**' # Docs changes don't affect Electron
- '!packages/eslint-plugin-actual/**' # Eslint plugin changes don't affect Electron
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
@@ -43,14 +52,13 @@ jobs:
sudo flatpak install org.freedesktop.Sdk//24.08 -y
sudo flatpak install org.freedesktop.Platform//24.08 -y
sudo flatpak install org.electronjs.Electron2.BaseApp//24.08 -y
sudo flatpak install org.flatpak.Builder -y
METAINFO_FILE="packages/desktop-electron/extra-resources/linux/com.actualbudget.actual.metainfo.xml"
TODAY=$(date +%Y-%m-%d)
VERSION=$(node ./packages/ci-actions/bin/get-next-package-version.js --package-json ./packages/desktop-electron/package.json --type nightly)
sed -i "s/%RELEASE_VERSION%/$VERSION/g; s/%RELEASE_DATE%/$TODAY/g" "$METAINFO_FILE"
sudo apt-get install appstream
appstreamcli --version
appstreamcli validate "$METAINFO_FILE"
flatpak run --command=flatpak-builder-lint org.flatpak.Builder appstream "$METAINFO_FILE"
- name: Set up environment
uses: ./.github/actions/setup
- name: Build Electron

View File

@@ -29,7 +29,7 @@ jobs:
The enhancement backlog can be found here: https://github.com/actualbudget/actual/issues?q=label%3A%22needs+votes%22+sort%3Areactions-%2B1-desc+
Dont forget to upvote the top comment with 👍!
Don't forget to upvote the top comment with 👍!
<!-- feature-auto-close-comment -->
- name: Close Issue

View File

@@ -3,7 +3,7 @@ name: Publish nightly desktop app
# Publish nightly version of desktop app - Runs every day at midnight
on:
schedule:
- cron: "0 0 * * *"
- cron: '0 0 * * *'
workflow_dispatch:
defaults:
@@ -26,6 +26,7 @@ jobs:
- windows-latest
- macos-latest
runs-on: ${{ matrix.os }}
if: github.event.repository.fork == false
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- if: ${{ startsWith(matrix.os, 'windows') }}
@@ -48,14 +49,13 @@ jobs:
sudo flatpak install org.freedesktop.Sdk//24.08 -y
sudo flatpak install org.freedesktop.Platform//24.08 -y
sudo flatpak install org.electronjs.Electron2.BaseApp//24.08 -y
sudo flatpak install org.flatpak.Builder -y
METAINFO_FILE="packages/desktop-electron/extra-resources/linux/com.actualbudget.actual.metainfo.xml"
TODAY=$(date +%Y-%m-%d)
VERSION=$(node ./packages/ci-actions/bin/get-next-package-version.js --package-json ./packages/desktop-electron/package.json --type nightly)
sed -i "s/%RELEASE_VERSION%/$VERSION/g; s/%RELEASE_DATE%/$TODAY/g" "$METAINFO_FILE"
sudo apt-get install appstream
appstreamcli --version
appstreamcli validate "$METAINFO_FILE"
flatpak run --command=flatpak-builder-lint org.flatpak.Builder appstream "$METAINFO_FILE"
- name: Set up environment
uses: ./.github/actions/setup

View File

@@ -15,7 +15,13 @@ on:
pull_request_target:
paths:
- 'packages/**'
- '!packages/sync-server/**'
- 'package.json'
- 'yarn.lock'
- '.github/workflows/size-compare.yml'
- '!packages/sync-server/**' # Sync server changes don't affect the size of the web/api
- '!packages/ci-actions/**' # CI actions changes don't affect the size of the web/api
- '!packages/docs/**' # Docs changes don't affect the size of the web/api
- '!packages/eslint-plugin-actual/**' # Eslint plugin changes don't affect the size of the web/api
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}

View File

@@ -58,7 +58,8 @@ jobs:
with:
repository: ${{ steps.metadata.outputs.head_repo }}
ref: ${{ steps.metadata.outputs.head_ref }}
token: ${{ secrets.GITHUB_TOKEN }}
token: ${{ secrets.ACTIONS_UPDATE_TOKEN }}
persist-credentials: false
fetch-depth: 0
- name: Validate and apply patch
@@ -121,22 +122,15 @@ jobs:
env:
HEAD_REF: ${{ steps.metadata.outputs.head_ref }}
HEAD_REPO: ${{ steps.metadata.outputs.head_repo }}
GITHUB_TOKEN: ${{ secrets.ACTIONS_UPDATE_TOKEN }}
run: |
# Use PAT in URL to ensure push triggers CI workflows
# Note: GitHub Actions automatically masks secrets in logs
git remote set-url origin "https://x-access-token:${GITHUB_TOKEN}@github.com/${HEAD_REPO}.git"
git push origin "HEAD:refs/heads/$HEAD_REF"
echo "Successfully pushed VRT updates to $HEAD_REPO@$HEAD_REF"
- name: Comment on PR - Success
if: steps.apply.outputs.applied == 'true'
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
script: |
await github.rest.issues.createComment({
issue_number: ${{ steps.metadata.outputs.pr_number }},
owner: context.repo.owner,
repo: context.repo.repo,
body: '✅ VRT screenshots have been automatically updated.'
});
- name: Comment on PR - Failure
if: failure() && steps.metadata.outputs.pr_number != ''
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0

View File

@@ -1,51 +1,82 @@
name: VRT Update - Generate
# SECURITY: This workflow runs in untrusted fork context with no write permissions.
# It only generates VRT patch artifacts that are later applied by vrt-update-apply.yml
# Triggered by commenting "/update-vrt" on a pull request.
on:
pull_request:
types: [opened, synchronize, reopened]
paths:
- 'packages/**'
- '.github/workflows/vrt-update-generate.yml'
issue_comment:
types: [created]
permissions:
contents: read
pull-requests: read
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
cancel-in-progress: true
group: ${{ github.workflow }}-${{ github.event.issue.number }}
cancel-in-progress: false
jobs:
add-reaction:
name: Add 👀 Reaction
runs-on: ubuntu-latest
# Only run on PR comments containing /update-vrt
if: >
github.event.issue.pull_request &&
startsWith(github.event.comment.body, '/update-vrt')
permissions:
pull-requests: write
steps:
- name: Add 👀 reaction to comment
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
script: |
await github.rest.reactions.createForIssueComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: context.payload.comment.id,
content: 'eyes'
});
generate-vrt-updates:
name: Generate VRT Updates
runs-on: ubuntu-latest
# Only run on PR comments containing /update-vrt
if: >
github.event.issue.pull_request &&
startsWith(github.event.comment.body, '/update-vrt')
container:
image: mcr.microsoft.com/playwright:v1.56.0-jammy
steps:
- name: Get PR details
id: pr
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
script: |
const { data: pr } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.issue.number
});
core.setOutput('head_sha', pr.head.sha);
core.setOutput('head_ref', pr.head.ref);
core.setOutput('head_repo', pr.head.repo.full_name);
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
ref: ${{ github.event.pull_request.head.sha }}
ref: ${{ steps.pr.outputs.head_sha }}
- name: Set up environment
uses: ./.github/actions/setup
with:
download-translations: 'false'
- name: Run VRT Tests on Desktop app
continue-on-error: true
run: |
xvfb-run --auto-servernum --server-args="-screen 0 1920x1080x24" -- yarn e2e:desktop --update-snapshots
- name: Wait for Netlify build to finish
id: netlify
env:
COMMIT_SHA: ${{ github.event.pull_request.head.sha }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: ./.github/actions/netlify-wait-for-build
- name: Run VRT Tests on Netlify URL
- name: Run VRT Tests
continue-on-error: true
run: yarn vrt --update-snapshots
env:
E2E_START_URL: ${{ steps.netlify.outputs.url }}
- name: Create patch with PNG changes only
id: create-patch
@@ -84,7 +115,7 @@ jobs:
if: steps.create-patch.outputs.has_changes == 'true'
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: vrt-patch-${{ github.event.pull_request.number }}
name: vrt-patch-${{ github.event.issue.number }}
path: vrt-update.patch
retention-days: 5
@@ -92,14 +123,14 @@ jobs:
if: steps.create-patch.outputs.has_changes == 'true'
run: |
mkdir -p pr-metadata
echo "${{ github.event.pull_request.number }}" > pr-metadata/pr-number.txt
echo "${{ github.event.pull_request.head.ref }}" > pr-metadata/head-ref.txt
echo "${{ github.event.pull_request.head.repo.full_name }}" > pr-metadata/head-repo.txt
echo "${{ github.event.issue.number }}" > pr-metadata/pr-number.txt
echo "${{ steps.pr.outputs.head_ref }}" > pr-metadata/head-ref.txt
echo "${{ steps.pr.outputs.head_repo }}" > pr-metadata/head-repo.txt
- name: Upload PR metadata
if: steps.create-patch.outputs.has_changes == 'true'
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: vrt-metadata-${{ github.event.pull_request.number }}
name: vrt-metadata-${{ github.event.issue.number }}
path: pr-metadata/
retention-days: 5

13
.gitignore vendored
View File

@@ -15,9 +15,17 @@ export-2020-01-10.csv
# JavaScript
node_modules
packages/api/app/bundle.api.js
packages/api/app/stats.json
packages/api/dist
packages/api/@types
packages/crdt/dist
packages/desktop-client/build-stats
packages/desktop-client/dev-dist
packages/desktop-client/public/kcab
packages/desktop-client/locale
packages/desktop-client/playwright-report
packages/desktop-client/test-results
packages/desktop-electron/client-build
packages/desktop-electron/build
packages/desktop-electron/.electron-symbols
@@ -25,6 +33,8 @@ packages/desktop-electron/dist
packages/desktop-electron/loot-core
packages/desktop-client/service-worker
packages/plugins-service/dist
packages/loot-core/lib-dist
packages/sync-server/coverage
bundle.desktop.js
bundle.desktop.js.map
bundle.mobile.js
@@ -40,7 +50,8 @@ bundle.mobile.js.map
!.yarn/versions
# VSCode
.vscode
.vscode/*
!.vscode/settings.default.json
# IntelliJ IDEA
.idea

View File

@@ -3,6 +3,8 @@
"singleQuote": true,
"trailingComma": "all",
"arrowParens": "avoid",
"printWidth": 80
"printWidth": 80,
"ignorePatterns": [
"packages/docs/*" // TOOD: fixme; temporary
]
}

View File

@@ -1,16 +1,384 @@
{
"$schema": "./node_modules/oxlint/configuration_schema.json",
"plugins": ["react", "typescript", "import", "jsx-a11y"],
"jsPlugins": [
"./packages/eslint-plugin-actual/lib/index.js",
"eslint-plugin-typescript-paths",
"eslint-plugin-perfectionist"
],
"env": {
"browser": true,
"node": true,
"vitest": true
},
"globals": {
"vi": "readonly",
"backend": "readonly",
"importScripts": "readonly",
"FS": "readonly" // TODO: remove this
},
"rules": {
// TODO fix all these and re-enable
"jsx-a11y/alt-text": "off",
"jsx-a11y/aria-role": "off",
"jsx-a11y/click-events-have-key-events": "off",
"jsx-a11y/label-has-associated-control": "off",
"jsx-a11y/prefer-tag-over-role": "off",
"jsx-a11y/role-has-required-aria-props": "off",
"jsx-a11y/tabindex-no-positive": "off",
"no-autofocus": "off",
// Import sorting
// TODO replace once oxfmt supports this: https://github.com/oxc-project/oxc/issues/17076
"perfectionist/sort-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"
}
],
// Actual rules
"actual/typography": "warn",
"actual/no-untranslated-strings": "error",
"actual/prefer-trans-over-t": "error",
"actual/prefer-if-statement": "warn",
"actual/prefer-logger-over-console": "error",
"actual/object-shorthand-properties": "warn",
"actual/prefer-const": "warn",
"actual/no-anchor-tag": "warn",
"actual/no-react-default-import": "warn",
// JSX A11y rules
"jsx-a11y/no-autofocus": [
"warn",
{
"ignoreNonDOM": true
}
],
"jsx-a11y/alt-text": "warn",
"jsx-a11y/anchor-has-content": "warn",
"jsx-a11y/anchor-is-valid": [
"warn",
{
"aspects": ["noHref", "invalidHref"]
}
],
"jsx-a11y/aria-activedescendant-has-tabindex": "warn",
"jsx-a11y/aria-props": "warn",
"jsx-a11y/aria-proptypes": "warn",
"jsx-a11y/aria-role": [
"warn",
{
"ignoreNonDOM": true
}
],
"jsx-a11y/aria-unsupported-elements": "warn",
"jsx-a11y/heading-has-content": "warn",
"jsx-a11y/iframe-has-title": "warn",
"jsx-a11y/img-redundant-alt": "warn",
"jsx-a11y/no-access-key": "warn",
"jsx-a11y/no-distracting-elements": "warn",
"jsx-a11y/no-redundant-roles": "warn",
"jsx-a11y/role-has-required-aria-props": "warn",
"jsx-a11y/role-supports-aria-props": "warn",
"jsx-a11y/scope": "warn",
// Typescript rules
"typescript/ban-ts-comment": [
"warn",
{
// TODO: remove this
"ts-ignore": "allow-with-description"
}
],
"typescript/consistent-type-definitions": ["warn", "type"],
"typescript/consistent-type-imports": [
"warn",
{
"prefer": "type-imports",
"fixStyle": "inline-type-imports"
}
],
"typescript/no-implied-eval": "warn",
"typescript/no-explicit-any": "warn",
"typescript/no-restricted-types": [
"warn",
{
"types": {
// forbid FC as superfluous
"FunctionComponent": {
"message": "Type the props argument and let TS infer or use ComponentType for a component prop"
},
"FC": {
"message": "Type the props argument and let TS infer or use ComponentType for a component prop"
}
}
}
],
"typescript/no-var-requires": "warn",
// Import rules
"import/first": "error",
"import/no-amd": "error",
"import/no-default-export": "warn",
"import/no-webpack-loader-syntax": "error",
"import/no-useless-path-segments": "warn",
"import/no-unresolved": "warn",
"import/no-unused-modules": "warn",
"import/no-duplicates": [
"warn",
{
"prefer-inline": true
}
],
// React rules
"react/exhaustive-deps": [
"warn",
{
"additionalHooks": "(useQuery|useEffectAfterMount)"
}
],
"react/jsx-curly-brace-presence": "warn",
"react/jsx-filename-extension": [
"warn",
{
"extensions": [".jsx", ".tsx"],
"allow": "as-needed"
}
],
"react/jsx-no-comment-textnodes": "warn",
"react/jsx-no-duplicate-props": "warn",
"react/jsx-no-target-blank": "warn",
"react/jsx-no-undef": "error",
"react/jsx-no-useless-fragment": "warn",
"react/jsx-pascal-case": [
"warn",
{
"allowAllCaps": true,
"ignore": []
}
],
"react/no-danger-with-children": "warn",
"react/no-direct-mutation-state": "warn",
"react/no-is-mounted": "warn",
"react/no-unstable-nested-components": "warn",
"react/require-render-return": "error",
"react/rules-of-hooks": "error",
"react/self-closing-comp": "warn",
"react/style-prop-object": "warn",
"react/jsx-boolean-value": "warn",
// ESLint rules
"eslint/array-callback-return": "warn",
// "eslint/curly": ["warn", "multi-line", "consistent"], // TODO: re-enable? this rule is really slow
"eslint/default-case": [
"warn",
{
"commentPattern": "^no default$"
}
],
"eslint/eqeqeq": ["warn", "smart"],
"eslint/no-array-constructor": "warn",
"eslint/no-caller": "warn",
"eslint/no-cond-assign": ["warn", "except-parens"],
"eslint/no-const-assign": "warn",
"eslint/no-control-regex": "warn",
"eslint/no-delete-var": "warn",
"eslint/no-dupe-class-members": "warn",
"eslint/no-dupe-keys": "warn",
"eslint/no-duplicate-case": "warn",
"eslint/no-empty-character-class": "warn",
"eslint/no-empty-function": "warn",
"eslint/no-empty-pattern": "warn",
"eslint/no-eval": "warn",
"eslint/no-ex-assign": "warn",
"eslint/no-extend-native": "warn",
"eslint/no-extra-bind": "warn",
"eslint/no-extra-label": "warn",
"eslint/no-fallthrough": "warn",
"eslint/no-func-assign": "warn",
"eslint/no-invalid-regexp": "warn",
"eslint/no-iterator": "warn",
"eslint/no-label-var": "warn",
"eslint/no-var": "warn",
"eslint/no-labels": [
"warn",
{
"allowLoop": true,
"allowSwitch": false
}
],
"eslint/no-new-func": "warn",
"eslint/no-script-url": "warn",
"eslint/no-self-assign": "warn",
"eslint/no-self-compare": "warn",
"eslint/no-sequences": "warn",
"eslint/no-shadow-restricted-names": "warn",
"eslint/no-sparse-arrays": "warn",
"eslint/no-template-curly-in-string": "warn",
"eslint/no-this-before-super": "warn",
"eslint/no-throw-literal": "warn",
"eslint/no-unreachable": "warn",
"eslint/no-obj-calls": "warn",
"eslint/no-new-wrappers": "warn",
"eslint/no-unsafe-negation": "warn",
"eslint/no-multi-str": "warn",
"eslint/no-global-assign": "warn",
"eslint/no-lone-blocks": "warn",
"eslint/no-unused-labels": "warn",
"eslint/no-object-constructor": "warn",
"eslint/no-new-native-nonconstructor": "warn",
"eslint/no-redeclare": "warn",
"eslint/no-useless-computed-key": "warn",
"eslint/no-useless-concat": "warn",
"eslint/no-useless-escape": "warn",
"eslint/require-yield": "warn",
"eslint/getter-return": "warn",
"eslint/unicode-bom": ["warn", "never"],
"eslint/no-use-isnan": "warn",
"eslint/valid-typeof": "warn",
"eslint/no-useless-rename": [
"warn",
{
"ignoreDestructuring": false,
"ignoreImport": false,
"ignoreExport": false
}
],
"eslint/no-with": "warn",
"eslint/no-regex-spaces": "warn",
"eslint/no-restricted-globals": [
"warn",
// https://github.com/facebook/create-react-app/tree/main/packages/confusing-browser-globals
"addEventListener",
"blur",
"close",
"closed",
"confirm",
"defaultStatus",
"defaultstatus",
"event",
"external",
"find",
"focus",
"frameElement",
"frames",
"history",
"innerHeight",
"innerWidth",
"length",
"location",
"locationbar",
"menubar",
"moveBy",
"moveTo",
"name",
"onblur",
"onerror",
"onfocus",
"onload",
"onresize",
"onunload",
"open",
"opener",
"opera",
"outerHeight",
"outerWidth",
"pageXOffset",
"pageYOffset",
"parent",
"print",
"removeEventListener",
"resizeBy",
"resizeTo",
"screen",
"screenLeft",
"screenTop",
"screenX",
"screenY",
"scroll",
"scrollbars",
"scrollBy",
"scrollTo",
"scrollX",
"scrollY",
"status",
"statusbar",
"stop",
"toolbar",
"top"
],
"eslint/no-restricted-imports": [
"warn",
{
"paths": [
{
"name": "react-router",
"importNames": ["useNavigate"],
"message": "Please import Actual's useNavigate() hook from `src/hooks` instead."
},
{
"name": "react-redux",
"importNames": ["useDispatch"],
"message": "Please import Actual's useDispatch() hook from `src/redux` instead."
},
{
"name": "react-redux",
"importNames": ["useSelector"],
"message": "Please import Actual's useSelector() hook from `src/redux` instead."
},
{
"name": "react-redux",
"importNames": ["useStore"],
"message": "Please import Actual's useStore() hook from `src/redux` instead."
}
],
"patterns": [
{
"group": ["**/*.api", "**/*.web", "**/*.electron"],
"message": "Don't directly reference imports from other platforms"
},
{
"group": ["uuid"],
"importNames": ["*"],
"message": "Use `import { v4 as uuidv4 } from 'uuid'` instead"
},
{
"group": ["**/style", "**/colors"],
"importNames": ["colors"],
"message": "Please use themes instead of colors"
},
{
"group": ["@actual-app/web/**/*"],
"message": "Please do not import `@actual-app/web` in `loot-core`"
}
]
}
],
"eslint/no-useless-constructor": "warn",
"eslint/no-undef": "warn",
"eslint/no-unused-expressions": "warn"
},
"overrides": [
{
@@ -59,11 +427,64 @@
"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",
"packages/desktop-client/src/hooks/useQuery.ts"
],
"rules": {
"react-hooks/exhaustive-deps": "off",
},
"react/exhaustive-deps": "off"
}
},
{
"files": ["**/*.test.{js,ts,jsx,tsx}", "packages/docs/**/*"],
"rules": {
"actual/no-untranslated-strings": "off",
"actual/prefer-logger-over-console": "off"
}
},
{
"files": [
"packages/api/migrations/*",
"packages/loot-core/migrations/*",
"packages/sync-server/src/app-gocardless/banks/*.js",
"*.config.{ts,mts,mjs}"
],
"rules": {
"import/no-default-export": "off"
}
},
{
"files": ["packages/docs/**/*"],
"rules": {
"actual/no-anchor-tag": "off"
}
},
{
"files": ["packages/desktop-client/**/*.{js,ts,jsx,tsx}"],
"rules": {
"typescript-paths/absolute-parent-import": [
"error",
{ "preferPathOverBaseUrl": true }
],
"typescript-paths/absolute-import": ["error", { "enableAlias": false }]
}
},
// 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": {
"eslint/no-empty-function": "off"
}
}
]
}

7
.vscode/settings.default.json vendored Normal file
View File

@@ -0,0 +1,7 @@
{
"typescript.tsdk": "node_modules/typescript/lib",
"editor.defaultFormatter": "oxc.oxc-vscode",
"vitest.nodeEnv": {
"NODE_OPTIONS": "--experimental-vm-modules --import ./packages/sync-server/register-loader.mjs --trace-warnings"
}
}

View File

@@ -8,6 +8,7 @@ CI=${CI:-false}
cd "$ROOT/.."
POSITIONAL=()
SKIP_EXE_BUILD=false
SKIP_TRANSLATIONS=false
while [[ $# -gt 0 ]]; do
key="$1"
@@ -20,6 +21,10 @@ while [[ $# -gt 0 ]]; do
SKIP_EXE_BUILD=true
shift
;;
--skip-translations)
SKIP_TRANSLATIONS=true
shift
;;
*)
POSITIONAL+=("$1")
shift
@@ -29,15 +34,19 @@ done
set -- "${POSITIONAL[@]}"
# Get translations
echo "Updating translations..."
if ! [ -d packages/desktop-client/locale ]; then
git clone https://github.com/actualbudget/translations packages/desktop-client/locale
if [ $SKIP_TRANSLATIONS == false ]; then
# Get translations
echo "Updating translations..."
if ! [ -d packages/desktop-client/locale ]; then
git clone https://github.com/actualbudget/translations packages/desktop-client/locale
fi
pushd packages/desktop-client/locale > /dev/null
git pull
popd > /dev/null
packages/desktop-client/bin/remove-untranslated-languages
fi
pushd packages/desktop-client/locale > /dev/null
git pull
popd > /dev/null
packages/desktop-client/bin/remove-untranslated-languages
export NODE_OPTIONS="--max-old-space-size=4096"

View File

@@ -6,7 +6,6 @@ import prompts from 'prompts';
async function run() {
const username = await execAsync(
// eslint-disable-next-line actual/typography
"gh api user --jq '.login'",
'To avoid having to enter your username, consider installing the official GitHub CLI (https://github.com/cli/cli) and logging in with `gh auth login`.',
);
@@ -161,8 +160,7 @@ category: ${type}
authors: [${username}]
---
${summary}
`;
${summary}`;
}
// simple exec that fails silently and returns an empty string on failure

View File

@@ -1,769 +0,0 @@
import tsParser from '@typescript-eslint/parser';
import { defineConfig } from 'eslint/config';
import pluginImport from 'eslint-plugin-import';
import pluginJSXA11y from 'eslint-plugin-jsx-a11y';
import oxlint from 'eslint-plugin-oxlint';
import pluginReact from 'eslint-plugin-react';
import pluginReactHooks from 'eslint-plugin-react-hooks';
import pluginTypescriptPaths from 'eslint-plugin-typescript-paths';
import globals from 'globals';
import pluginTypescript from 'typescript-eslint';
// eslint-disable-next-line import/extensions
import pluginActual from './packages/eslint-plugin-actual/lib/index.js';
const confusingBrowserGlobals = [
// https://github.com/facebook/create-react-app/tree/main/packages/confusing-browser-globals
'addEventListener',
'blur',
'close',
'closed',
'confirm',
'defaultStatus',
'defaultstatus',
'event',
'external',
'find',
'focus',
'frameElement',
'frames',
'history',
'innerHeight',
'innerWidth',
'length',
'location',
'locationbar',
'menubar',
'moveBy',
'moveTo',
'name',
'onblur',
'onerror',
'onfocus',
'onload',
'onresize',
'onunload',
'open',
'opener',
'opera',
'outerHeight',
'outerWidth',
'pageXOffset',
'pageYOffset',
'parent',
'print',
'removeEventListener',
'resizeBy',
'resizeTo',
'screen',
'screenLeft',
'screenTop',
'screenX',
'screenY',
'scroll',
'scrollbars',
'scrollBy',
'scrollTo',
'scrollX',
'scrollY',
'status',
'statusbar',
'stop',
'toolbar',
'top',
];
export default defineConfig(
{
ignores: [
//temporary
'packages/docs',
'packages/api/app/bundle.api.js',
'packages/api/app/stats.json',
'packages/api/@types',
'packages/api/migrations',
'packages/component-library/src/icons/**/*',
'packages/desktop-client/bundle.browser.js',
'packages/desktop-client/dev-dist/',
'packages/desktop-client/service-worker/*',
'packages/desktop-client/build-electron/',
'packages/desktop-client/build-stats/',
'packages/desktop-client/public/kcab/',
'packages/desktop-client/public/data/',
'packages/desktop-client/test-results/',
'packages/desktop-client/playwright-report/',
'packages/desktop-electron/client-build/',
'packages/loot-core/**/lib-dist/*',
'packages/loot-core/**/proto/*',
'packages/sync-server/user-files/',
'packages/sync-server/server-files/',
'.yarn/*',
'.github/*',
'**/build/',
'**/dist/',
'**/node_modules/',
],
},
{
// Temporary until the sync-server is migrated to TypeScript
files: [
'packages/sync-server/**/*.spec.{js,jsx}',
'packages/sync-server/**/*.test.{js,jsx}',
],
languageOptions: {
globals: {
vi: true,
describe: true,
expect: true,
it: true,
beforeAll: true,
beforeEach: true,
afterAll: true,
afterEach: true,
test: true,
},
},
},
{
linterOptions: {
reportUnusedDisableDirectives: true,
},
languageOptions: {
globals: {
...globals.browser,
...globals.commonjs,
...globals.node,
globalThis: false,
vi: true,
},
},
settings: {
react: {
version: 'detect',
},
'import/resolver': {
typescript: {
alwaysTryTypes: true,
},
},
},
},
pluginReact.configs.flat.recommended,
pluginReact.configs.flat['jsx-runtime'],
pluginTypescript.configs.recommended,
pluginImport.flatConfigs.recommended,
{
plugins: {
actual: pluginActual,
},
rules: {
'actual/no-untranslated-strings': 'error',
'actual/prefer-trans-over-t': 'error',
},
},
{
files: ['**/*.{js,ts,jsx,tsx,mjs,mts}'],
plugins: {
'jsx-a11y': pluginJSXA11y,
'react-hooks': pluginReactHooks,
},
rules: {
// http://eslint.org/docs/rules/
'array-callback-return': 'warn',
'default-case': [
'warn',
{
commentPattern: '^no default$',
},
],
curly: ['warn', 'multi-line', 'consistent'],
'dot-location': ['warn', 'property'],
eqeqeq: ['warn', 'smart'],
'new-parens': 'warn',
'no-array-constructor': 'warn',
'no-caller': 'warn',
'no-cond-assign': ['warn', 'except-parens'],
'no-const-assign': 'warn',
'no-control-regex': 'warn',
'no-delete-var': 'warn',
'no-dupe-args': 'warn',
'no-dupe-class-members': 'warn',
'no-dupe-keys': 'warn',
'no-duplicate-case': 'warn',
'no-empty-character-class': 'warn',
'no-empty-pattern': 'warn',
'no-eval': 'warn',
'no-ex-assign': 'warn',
'no-extend-native': 'warn',
'no-extra-bind': 'warn',
'no-extra-label': 'warn',
'no-fallthrough': 'warn',
'no-func-assign': 'warn',
'no-implied-eval': 'warn',
'no-invalid-regexp': 'warn',
'no-iterator': 'warn',
'no-label-var': 'warn',
'no-labels': [
'warn',
{
allowLoop: true,
allowSwitch: false,
},
],
'no-lone-blocks': 'warn',
'no-mixed-operators': [
'warn',
{
groups: [
['&', '|', '^', '~', '<<', '>>', '>>>'],
['==', '!=', '===', '!==', '>', '>=', '<', '<='],
['&&', '||'],
['in', 'instanceof'],
],
allowSamePrecedence: false,
},
],
'no-multi-str': 'warn',
'no-global-assign': 'warn',
'no-unsafe-negation': 'warn',
'no-new-func': 'warn',
'no-new-object': 'warn',
'no-new-symbol': 'warn',
'no-new-wrappers': 'warn',
'no-obj-calls': 'warn',
'no-octal': 'warn',
'no-octal-escape': 'warn',
'no-redeclare': 'warn',
'no-regex-spaces': 'warn',
'no-script-url': 'warn',
'no-self-assign': 'warn',
'no-self-compare': 'warn',
'no-sequences': 'warn',
'no-shadow-restricted-names': 'warn',
'no-sparse-arrays': 'warn',
'no-template-curly-in-string': 'warn',
'no-this-before-super': 'warn',
'no-throw-literal': 'warn',
'no-undef': 'error',
'no-unreachable': 'warn',
'no-unused-expressions': [
'error',
{
allowShortCircuit: true,
allowTernary: true,
allowTaggedTemplates: true,
},
],
'no-unused-labels': 'warn',
'no-use-before-define': [
'warn',
{
functions: false,
classes: false,
variables: false,
},
],
'no-useless-computed-key': 'warn',
'no-useless-concat': 'warn',
'no-useless-constructor': 'warn',
'no-useless-escape': 'warn',
'no-useless-rename': [
'warn',
{
ignoreDestructuring: false,
ignoreImport: false,
ignoreExport: false,
},
],
'no-with': 'warn',
'no-whitespace-before-property': 'warn',
'require-yield': 'warn',
'rest-spread-spacing': ['warn', 'never'],
strict: ['warn', 'never'],
'unicode-bom': ['warn', 'never'],
'use-isnan': 'warn',
'valid-typeof': 'warn',
'no-restricted-properties': [
'error',
{
object: 'require',
property: 'ensure',
message:
'Please use import() instead. More info: https://facebook.github.io/create-react-app/docs/code-splitting',
},
{
object: 'System',
property: 'import',
message:
'Please use import() instead. More info: https://facebook.github.io/create-react-app/docs/code-splitting',
},
],
'getter-return': 'warn',
// https://github.com/benmosher/eslint-plugin-import/tree/master/docs/rules
'import/first': 'error',
'import/no-amd': 'error',
'import/no-anonymous-default-export': 'warn',
'import/no-webpack-loader-syntax': 'error',
'import/extensions': [
'warn',
'never',
{
json: 'always',
},
],
'import/no-useless-path-segments': 'warn',
'import/no-duplicates': [
'warn',
{
'prefer-inline': true,
},
],
'import/order': [
'warn',
{
alphabetize: {
caseInsensitive: true,
order: 'asc',
},
groups: ['builtin', 'external', 'parent', 'sibling', 'index'],
'newlines-between': 'always',
pathGroups: [
{
// Enforce that React (and react-related packages) is the first import
group: 'builtin',
pattern: 'react?(-*)',
position: 'before',
},
{
// Separate imports from Actual from "real" external imports
group: 'external',
pattern: 'loot-{core,design}/**/*',
position: 'after',
},
],
pathGroupsExcludedImportTypes: ['react'],
},
],
// https://github.com/yannickcr/eslint-plugin-react/tree/master/docs/rules
'react/forbid-foreign-prop-types': [
'warn',
{
allowInPropTypes: true,
},
],
'react/jsx-no-comment-textnodes': 'warn',
'react/jsx-no-duplicate-props': 'warn',
'react/jsx-no-target-blank': 'warn',
'react/jsx-no-undef': 'error',
'react/jsx-pascal-case': [
'warn',
{
allowAllCaps: true,
ignore: [],
},
],
'react/no-danger-with-children': 'warn',
// Disabled because of undesirable warnings
// See https://github.com/facebook/create-react-app/issues/5204 for
// blockers until its re-enabled
// 'react/no-deprecated': 'warn',
'react/no-direct-mutation-state': 'warn',
'react/no-is-mounted': 'warn',
'react/no-typos': 'error',
'react/require-render-return': 'error',
'react/style-prop-object': 'warn',
'react/jsx-no-useless-fragment': 'warn',
'react/self-closing-comp': 'warn',
'react/jsx-filename-extension': [
'warn',
{
extensions: ['.jsx', '.tsx'],
allow: 'as-needed',
},
],
'react/no-unstable-nested-components': [
'warn',
{
allowAsProps: true,
customValidators: ['formatter'],
},
],
// Don't need this as we're using TypeScript
'react/prop-types': 'off',
// https://github.com/evcohen/eslint-plugin-jsx-a11y/tree/master/docs/rules
'jsx-a11y/alt-text': 'warn',
'jsx-a11y/anchor-has-content': 'warn',
'jsx-a11y/anchor-is-valid': [
'warn',
{
aspects: ['noHref', 'invalidHref'],
},
],
'jsx-a11y/aria-activedescendant-has-tabindex': 'warn',
'jsx-a11y/aria-props': 'warn',
'jsx-a11y/aria-proptypes': 'warn',
'jsx-a11y/aria-role': [
'warn',
{
ignoreNonDOM: true,
},
],
'jsx-a11y/aria-unsupported-elements': 'warn',
'jsx-a11y/heading-has-content': 'warn',
'jsx-a11y/iframe-has-title': 'warn',
'jsx-a11y/img-redundant-alt': 'warn',
'jsx-a11y/no-access-key': 'warn',
'jsx-a11y/no-distracting-elements': 'warn',
'jsx-a11y/no-redundant-roles': 'warn',
'jsx-a11y/role-has-required-aria-props': 'warn',
'jsx-a11y/role-supports-aria-props': 'warn',
'jsx-a11y/scope': 'warn',
// https://github.com/facebook/react/tree/main/packages/eslint-plugin-react-hooks
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': [
'warn',
{
additionalHooks: '(useQuery|useEffectAfterMount)',
},
],
'actual/typography': 'warn',
'actual/prefer-if-statement': 'warn',
'actual/prefer-logger-over-console': 'error',
// Note: base rule explicitly disabled in favor of the TS one
'no-unused-vars': 'off',
'@typescript-eslint/no-unused-vars': [
'warn',
{
varsIgnorePattern: '^(_|React)',
argsIgnorePattern: '^(_|React)',
ignoreRestSiblings: true,
caughtErrors: 'none',
},
],
'no-restricted-globals': ['warn', ...confusingBrowserGlobals],
// https://github.com/eslint/eslint/issues/16954
// https://github.com/eslint/eslint/issues/16953
'no-loop-func': 'off',
// TODO: re-enable these rules
'react/react-in-jsx-scope': 'off',
'no-var': 'warn',
'react/jsx-curly-brace-presence': 'warn',
'object-shorthand': ['warn', 'properties'],
'no-restricted-syntax': [
'warn',
{
// forbid React.* as they are legacy https://twitter.com/dan_abramov/status/1308739731551858689
selector:
":matches(MemberExpression[object.name='React'], TSQualifiedName[left.name='React'])",
message:
'Using default React import is discouraged, please use named exports directly instead.',
},
{
// forbid <a> in favor of <Link>
selector: 'JSXOpeningElement[name.name="a"]',
message: 'Using <a> is discouraged, please use <Link> instead.',
},
],
'no-restricted-imports': [
'warn',
{
paths: [
{
name: 'react-router',
importNames: ['useNavigate'],
message:
"Please import Actual's useNavigate() hook from `src/hooks` instead.",
},
{
name: 'react-redux',
importNames: ['useDispatch'],
message:
"Please import Actual's useDispatch() hook from `src/redux` instead.",
},
{
name: 'react-redux',
importNames: ['useSelector'],
message:
"Please import Actual's useSelector() hook from `src/redux` instead.",
},
{
name: 'react-redux',
importNames: ['useStore'],
message:
"Please import Actual's useStore() hook from `src/redux` instead.",
},
],
patterns: [
{
group: ['*.api', '*.web', '*.electron'],
message: "Don't directly reference imports from other platforms",
},
{
group: ['uuid'],
importNames: ['*'],
message: "Use `import { v4 as uuidv4 } from 'uuid'` instead",
},
{
group: ['**/style', '**/colors'],
importNames: ['colors'],
message: 'Please use themes instead of colors',
},
{
group: ['@actual-app/web/*'],
message: 'Please do not import `@actual-app/web` in `loot-core`',
},
],
},
],
'@typescript-eslint/ban-ts-comment': [
'error',
{
'ts-ignore': 'allow-with-description',
},
],
// Rules disabled during TS migration
'@typescript-eslint/no-var-requires': 'off',
'prefer-const': 'warn',
'prefer-spread': 'off',
'@typescript-eslint/no-empty-function': 'off',
'@typescript-eslint/no-require-imports': 'off',
'import/no-default-export': 'warn',
},
},
{
files: ['**/*.{ts,tsx}'],
languageOptions: {
parser: tsParser,
ecmaVersion: 2018,
sourceType: 'module',
parserOptions: {
projectService: true,
ecmaFeatures: {
jsx: true,
},
// typescript-eslint specific options
warnOnUnsupportedTypeScriptVersion: true,
},
},
// If adding a typescript-eslint version of an existing ESLint rule,
// make sure to disable the ESLint rule here.
rules: {
// TypeScript's `noFallthroughCasesInSwitch` option is more robust (#6906)
'default-case': 'off',
// 'tsc' already handles this (https://github.com/typescript-eslint/typescript-eslint/issues/291)
'no-dupe-class-members': 'off',
// 'tsc' already handles this (https://github.com/typescript-eslint/typescript-eslint/issues/477)
'no-undef': 'off',
// TypeScript already handles these (https://typescript-eslint.io/troubleshooting/typed-linting/performance/#eslint-plugin-import)
'import/named': 'off',
'import/namespace': 'off',
'import/default': 'off',
'import/no-named-as-default-member': 'off',
'import/no-unresolved': 'off',
// Add TypeScript specific rules (and turn off ESLint equivalents)
'@typescript-eslint/consistent-type-assertions': 'warn',
'no-array-constructor': 'off',
'@typescript-eslint/no-array-constructor': 'warn',
'no-redeclare': 'off',
'@typescript-eslint/no-redeclare': 'warn',
'no-use-before-define': 'off',
'@typescript-eslint/no-use-before-define': [
'warn',
{
functions: false,
classes: false,
variables: false,
typedefs: false,
},
],
'no-unused-expressions': 'off',
'@typescript-eslint/no-unused-expressions': [
'error',
{
allowShortCircuit: true,
allowTernary: true,
allowTaggedTemplates: true,
},
],
'no-useless-constructor': 'off',
'@typescript-eslint/no-useless-constructor': 'warn',
},
},
{
files: ['packages/desktop-client/**/*.{js,ts,jsx,tsx}'],
plugins: {
'typescript-paths': pluginTypescriptPaths,
},
rules: {
'typescript-paths/absolute-parent-import': [
'error',
{ preferPathOverBaseUrl: true },
],
'typescript-paths/absolute-import': ['error', { enableAlias: false }],
},
},
{
files: [
'packages/desktop-client/**/*.{ts,tsx}',
'packages/loot-core/src/client/**/*.{ts,tsx}',
],
rules: {
// enforce import type
'@typescript-eslint/consistent-type-imports': [
'warn',
{
prefer: 'type-imports',
fixStyle: 'inline-type-imports',
},
],
'@typescript-eslint/no-restricted-types': [
'warn',
{
types: {
// forbid FC as superfluous
FunctionComponent: {
message:
'Type the props argument and let TS infer or use ComponentType for a component prop',
},
FC: {
message:
'Type the props argument and let TS infer or use ComponentType for a component prop',
},
},
},
],
},
},
{
files: [
'packages/loot-core/src/types/**/*',
'packages/loot-core/src/client/state-types/**/*',
'**/icons/**/*',
'**/{mocks,__mocks__}/**/*',
// can't correctly resolve usages
'**/*.{testing,electron,browser,web,api}.ts',
],
rules: {
'import/no-unused-modules': 'off',
},
},
{
files: ['packages/api/migrations/*', 'packages/loot-core/migrations/*'],
rules: {
'import/no-default-export': 'off',
},
},
{
files: ['packages/api/index.ts'],
rules: {
'import/no-unresolved': 'off',
},
},
// Allow configuring vitest with default exports (recommended as per vitest docs)
{
files: [
'**/vitest.config.{ts,mts}',
'**/vitest.web.config.ts',
'**/vite.config.{ts,mts}',
'eslint.config.mjs',
],
rules: {
'import/no-anonymous-default-export': 'off',
'import/no-default-export': 'off',
},
},
{
files: [
'eslint.config.mjs',
'**/*.test.js',
'**/*.test.ts',
'**/*.test.jsx',
'**/*.test.tsx',
'**/*.spec.js',
],
rules: {
'actual/typography': 'off',
'actual/no-untranslated-strings': 'off',
'actual/prefer-logger-over-console': 'off',
},
},
{
files: [
'packages/desktop-client/**/*.{ts,tsx}',
'packages/loot-core/src/client/**/*.{ts,tsx}',
],
ignores: ['**/**/globals.d.ts'],
rules: {
// enforce type over interface
'@typescript-eslint/consistent-type-definitions': ['warn', 'type'],
},
},
{
files: ['packages/sync-server/**/*'],
// TODO: fix the issues in these files
rules: {
'actual/typography': 'off',
},
},
{
files: ['packages/sync-server/src/app-gocardless/banks/*.js'],
rules: {
'import/no-anonymous-default-export': 'off',
'import/no-default-export': 'off',
},
},
// Disable ESLint rules that are already covered by oxlint
// This must be at the end to override previous rule configurations
...oxlint.configs['flat/recommended'],
);

View File

@@ -7,11 +7,11 @@
"bugs": {
"url": "https://github.com/actualbudget/actual/issues/"
},
"license": "MIT",
"repository": {
"type": "git",
"url": "git@github.com:actualbudget/actual.git"
},
"license": "MIT",
"workspaces": {
"packages": [
"packages/*"
@@ -40,19 +40,20 @@
"build:plugins-service": "yarn workspace plugins-service build",
"build:api": "yarn workspace @actual-app/api build",
"build:docs": "yarn workspace docs build",
"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",
"test": "lage test --continue",
"test:debug": "lage test --no-cache --continue",
"e2e": "yarn workspace @actual-app/web run e2e",
"e2e:desktop": "yarn build:desktop --skip-exe-build && yarn workspace desktop-electron e2e",
"e2e:desktop": "yarn build:desktop --skip-exe-build --skip-translations && yarn workspace desktop-electron e2e",
"playwright": "yarn workspace @actual-app/web run playwright",
"vrt": "yarn workspace @actual-app/web run vrt",
"vrt:docker": "./bin/run-vrt",
"rebuild-electron": "./node_modules/.bin/electron-rebuild -m ./packages/loot-core",
"rebuild-node": "yarn workspace loot-core rebuild",
"lint": "oxfmt --check . && oxlint --deny-warnings && eslint . --max-warnings 0",
"lint:fix": "oxfmt . && oxlint --deny-warnings --fix && eslint . --max-warnings 0 --fix",
"lint": "oxfmt --check . && oxlint --deny-warnings",
"lint:fix": "oxfmt . && oxlint --deny-warnings --fix",
"install:server": "yarn workspaces focus @actual-app/sync-server --production",
"typecheck": "yarn tsc --incremental && tsc-strict",
"jq": "./node_modules/node-jq/bin/jq",
@@ -62,54 +63,45 @@
"@octokit/rest": "^22.0.1",
"@types/node": "^22.19.1",
"@types/prompts": "^2.4.9",
"@typescript-eslint/parser": "^8.46.4",
"cross-env": "^10.1.0",
"eslint": "^9.39.1",
"eslint-import-resolver-typescript": "^4.4.4",
"eslint-plugin-import": "^2.32.0",
"eslint-plugin-jsx-a11y": "^6.10.2",
"eslint-plugin-oxlint": "^1.30.0",
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-hooks": "^7.0.1",
"eslint": "^9.39.2",
"eslint-plugin-perfectionist": "^4.15.1",
"eslint-plugin-typescript-paths": "^0.0.33",
"globals": "^16.5.0",
"html-to-image": "^1.11.13",
"husky": "^9.1.7",
"lage": "^2.14.15",
"lint-staged": "^16.2.6",
"lint-staged": "^16.2.7",
"minimatch": "^10.1.1",
"node-jq": "^6.3.1",
"npm-run-all": "^4.1.5",
"oxfmt": "^0.15.0",
"oxlint": "^1.30.0",
"oxfmt": "^0.22.0",
"oxlint": "^1.37.0",
"p-limit": "^7.2.0",
"prompts": "^2.4.2",
"source-map-support": "^0.5.21",
"ts-node": "^10.9.2",
"typescript": "^5.9.3",
"typescript-eslint": "^8.46.4",
"typescript-strict-plugin": "^2.4.4"
},
"resolutions": {
"rollup": "4.40.1",
"socks": ">=2.8.3"
},
"engines": {
"node": ">=22",
"yarn": "^4.9.1"
},
"lint-staged": {
"*.{js,mjs,jsx,ts,tsx,md,json,yml,yaml}": [
"oxfmt --no-error-on-unmatched-pattern"
],
"*.{js,mjs,jsx,ts,tsx}": [
"oxlint --deny-warnings --fix",
"eslint --max-warnings 0 --fix --no-warn-ignored"
"oxlint --deny-warnings --fix"
]
},
"packageManager": "yarn@4.10.3",
"browserslist": [
"electron >= 35.0",
"defaults"
]
],
"engines": {
"node": ">=22",
"yarn": "^4.9.1"
},
"packageManager": "yarn@4.10.3"
}

View File

@@ -97,6 +97,14 @@ class Query {
serialize() {
return this.state;
}
reset() {
return q(this.state.table);
}
serializeAsString() {
return JSON.stringify(this.serialize());
}
}
export function q(table) {

View File

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

View File

@@ -125,10 +125,10 @@ export function addTransactions(
});
}
export interface ImportTransactionsOpts {
export type ImportTransactionsOpts = {
defaultCleared?: boolean;
dryRun?: boolean;
}
};
export function importTransactions(
accountId: APIAccountEntity['id'],

View File

@@ -1,17 +1,14 @@
{
"name": "@actual-app/api",
"version": "25.12.0",
"license": "MIT",
"version": "26.1.0",
"description": "An API for Actual",
"engines": {
"node": ">=20"
},
"license": "MIT",
"files": [
"@types",
"dist"
],
"main": "dist/index.js",
"types": "@types/index.d.ts",
"files": [
"dist",
"@types"
],
"scripts": {
"build:app": "yarn workspace loot-core build:api",
"build:crdt": "yarn workspace @actual-app/crdt build",
@@ -19,7 +16,7 @@
"build:migrations": "cp migrations/*.sql dist/migrations",
"build:default-db": "cp default-db.sqlite dist/",
"build": "yarn run clean && yarn run build:app && yarn run build:node && yarn run build:migrations && yarn run build:default-db",
"test": "yarn run build:app && yarn run build:crdt && vitest --run",
"test": "yarn run clean && yarn run build:app && yarn run build:crdt && vitest --run",
"clean": "rm -rf dist @types"
},
"dependencies": {
@@ -33,5 +30,8 @@
"tsc-alias": "^1.8.16",
"typescript": "^5.9.3",
"vitest": "^4.0.9"
},
"engines": {
"node": ">=20"
}
}

View File

@@ -1,7 +1,7 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
// Using ES2021 because thats the newest version where
// Using ES2021 because that's the newest version where
// the latest Node 16.x release supports all of the features
"target": "ES2021",
"module": "CommonJS",

View File

@@ -1,5 +1,4 @@
// @ts-ignore: bundle not available until we build it
// eslint-disable-next-line import/extensions
import * as bundle from './app/bundle.api.js';
export const amountToInteger = bundle.lib.amountToInteger;

View File

@@ -22,7 +22,7 @@ function parseRawArgs(argv) {
if (!key?.startsWith('--')) {
throw new Error(
`Unexpected argument ${key ?? ''}. Use --key value pairs.`,
`Unexpected argument "${key ?? ''}". Use --key value pairs.`,
);
}
@@ -34,7 +34,7 @@ function parseRawArgs(argv) {
}
if (values.length === 0) {
throw new Error(`Missing value for argument ${key}.`);
throw new Error(`Missing value for argument "${key}".`);
}
const keyName = key.slice(2);
@@ -55,14 +55,14 @@ function getSingleValue(args, key) {
return undefined;
}
if (values.length !== 1) {
throw new Error(`Argument --${key} must have exactly one value.`);
throw new Error(`Argument "--${key}" must have exactly one value.`);
}
return values[0];
}
function parseMapping(values, key, description) {
if (!values || values.length === 0) {
throw new Error(`Missing required argument --${key} (${description}).`);
throw new Error(`Missing required argument "--${key}" (${description}).`);
}
if (values.length === 1) {
@@ -81,7 +81,7 @@ function parseMapping(values, key, description) {
Object.entries(parsed).map(([name, pathValue]) => {
if (typeof pathValue !== 'string') {
throw new Error(
`Value for ${name} in --${key} must be a string path.`,
`Value for "${name}" in "--${key}" must be a string path.`,
);
}
return [name, pathValue];
@@ -91,7 +91,7 @@ function parseMapping(values, key, description) {
const message =
error instanceof Error ? error.message : 'Unknown parsing error';
throw new Error(
`Failed to parse --${key} value as JSON object: ${message}`,
`Failed to parse "--${key}" value as JSON object: ${message}`,
);
}
}
@@ -104,7 +104,7 @@ function parseMapping(values, key, description) {
if (!rawName || rawPathParts.length === 0) {
throw new Error(
`Argument --${key} must be provided as name=path pairs or a JSON object.`,
`Argument "--${key}" must be provided as name=path pairs or a JSON object.`,
);
}
@@ -112,12 +112,12 @@ function parseMapping(values, key, description) {
const pathValue = rawPathParts.join('=').trim();
if (!name) {
throw new Error(`Argument --${key} contains an empty bundle name.`);
throw new Error(`Argument "--${key}" contains an empty bundle name.`);
}
if (!pathValue) {
throw new Error(
`Argument --${key} for bundle ${name} must include a non-empty path.`,
`Argument "--${key}" for bundle "${name}" must include a non-empty path.`,
);
}
@@ -125,7 +125,7 @@ function parseMapping(values, key, description) {
}
if (entries.size === 0) {
throw new Error(`Argument --${key} must define at least one bundle.`);
throw new Error(`Argument "--${key}" must define at least one bundle.`);
}
return entries;
@@ -152,7 +152,7 @@ function parseArgs(argv) {
if (!headPath) {
throw new Error(
`Bundle ${name} is missing a corresponding --head entry.`,
`Bundle "${name}" is missing a corresponding "--head" entry.`,
);
}
@@ -166,7 +166,7 @@ function parseArgs(argv) {
for (const name of headMap.keys()) {
if (!baseMap.has(name)) {
throw new Error(
`Bundle ${name} is missing a corresponding --base entry.`,
`Bundle "${name}" is missing a corresponding "--base" entry.`,
);
}
}
@@ -194,8 +194,8 @@ async function loadStats(filePath) {
error instanceof Error
? error.message
: 'Unknown error while parsing stats file';
console.error(`[bundle-stats] Failed to parse ${filePath}: ${message}`);
throw new Error(`Failed to load stats file ${filePath}: ${message}`);
console.error(`[bundle-stats] Failed to parse "${filePath}": ${message}`);
throw new Error(`Failed to load stats file "${filePath}": ${message}`);
}
}

View File

@@ -6,7 +6,6 @@
import fs from 'node:fs';
import { parseArgs } from 'node:util';
// eslint-disable-next-line import/extensions
import { getNextVersion } from '../src/versions/get-next-package-version.js';
const args = process.argv;

View File

@@ -26,12 +26,12 @@ function parseArgs(argv) {
if (!key?.startsWith('--')) {
throw new Error(
`Unexpected argument ${key ?? ''}. Use --key value pairs.`,
`Unexpected argument "${key ?? ''}". Use --key value pairs.`,
);
}
if (typeof value === 'undefined') {
throw new Error(`Missing value for argument ${key}.`);
throw new Error(`Missing value for argument "${key}".`);
}
switch (key) {
@@ -42,16 +42,16 @@ function parseArgs(argv) {
args.identifier = value;
break;
default:
throw new Error(`Unknown argument ${key}.`);
throw new Error(`Unknown argument "${key}".`);
}
}
if (!args.commentFile) {
throw new Error('Missing required argument --comment-file.');
throw new Error('Missing required argument "--comment-file".');
}
if (!args.identifier) {
throw new Error('Missing required argument --identifier.');
throw new Error('Missing required argument "--identifier".');
}
return args;
@@ -70,7 +70,7 @@ function getRepoInfo() {
const [owner, repo] = repository.split('/');
if (!owner || !repo) {
throw new Error(`Invalid GITHUB_REPOSITORY value ${repository}.`);
throw new Error(`Invalid GITHUB_REPOSITORY value "${repository}".`);
}
return { owner, repo };

View File

@@ -2,10 +2,10 @@
"name": "@actual-app/ci-actions",
"private": true,
"type": "module",
"devDependencies": {
"vitest": "^4.0.9"
},
"scripts": {
"test": "vitest --run"
},
"devDependencies": {
"vitest": "^4.0.9"
}
}

View File

@@ -66,7 +66,7 @@ export function getNextVersion({
return `${nextVersionYear}.${nextVersionMonth}.0`;
default:
throw new Error(
'Invalid type specified. Use auto, nightly, hotfix, or monthly.',
'Invalid type specified. Use "auto", "nightly", "hotfix", or "monthly".',
);
}
}

View File

@@ -2,22 +2,6 @@
"name": "@actual-app/components",
"version": "0.0.1",
"license": "MIT",
"peerDependencies": {
"react": ">=18.2",
"react-dom": ">=18.2"
},
"dependencies": {
"@emotion/css": "^11.13.5",
"react-aria-components": "^1.13.0",
"usehooks-ts": "^3.1.1"
},
"devDependencies": {
"@svgr/cli": "^8.1.0",
"@types/react": "^19.2.5",
"react": "19.2.0",
"react-dom": "19.2.0",
"vitest": "^4.0.9"
},
"exports": {
"./hooks/*": "./src/hooks/*.ts",
"./icons/logo": "./src/icons/logo/index.ts",
@@ -30,6 +14,7 @@
"./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",
@@ -54,5 +39,21 @@
"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"
},
"dependencies": {
"@emotion/css": "^11.13.5",
"react-aria-components": "^1.13.0",
"usehooks-ts": "^3.1.1"
},
"devDependencies": {
"@svgr/cli": "^8.1.0",
"@types/react": "^19.2.5",
"react": "19.2.0",
"react-dom": "19.2.0",
"vitest": "^4.0.9"
},
"peerDependencies": {
"react": ">=18.2",
"react-dom": ">=18.2"
}
}

View File

@@ -1,11 +1,11 @@
import { ChangeEvent, ReactNode } from 'react';
import { type ChangeEvent, type ReactNode } from 'react';
import {
ColorPicker as AriaColorPicker,
ColorPickerProps as AriaColorPickerProps,
type ColorPickerProps as AriaColorPickerProps,
Dialog,
DialogTrigger,
ColorSwatch as AriaColorSwatch,
ColorSwatchProps,
type ColorSwatchProps,
ColorSwatchPicker as AriaColorSwatchPicker,
ColorSwatchPickerItem,
ColorField,
@@ -32,7 +32,6 @@ function ColorSwatch(props: ColorSwatchProps) {
);
}
// colors from https://materialui.co/colors
const DEFAULT_COLOR_SET = [
'#690CB0',
'#D32F2F',
@@ -54,12 +53,32 @@ const DEFAULT_COLOR_SET = [
'#5D4037',
'#616161',
'#455A64',
'#FF6666', //red
'#FF99FF', //magenta
'#C39DDF', //purple
'#6666FF', //blue
'#B2FFFF', //cyan
'#99cb99', //green
'#FFFF7F', //yellow
'#FFAB66', //orange
'#D4B89C', //brown
'#BFBFBF', //gray
'#FFAEAE', //colors repeat from above with a lighter tint
'#FFCCFF',
'#E4D4FF', //this is now purple125
'#B0B0FF',
'#D8FFFF',
'#CFE5CF',
'#FFFFB2',
'#FFD5B3',
'#E4D3C3',
'#DADADA',
];
interface ColorSwatchPickerProps {
type ColorSwatchPickerProps = {
columns?: number;
colorset?: string[];
}
};
function ColorSwatchPicker({
columns = 5,
@@ -89,7 +108,6 @@ function ColorSwatchPicker({
cursor: 'pointer',
'&[data-selected]::after': {
// eslint-disable-next-line actual/typography
content: '""',
position: 'absolute',
inset: 0,
@@ -123,11 +141,11 @@ function ColorSwatchPicker({
}
const isColor = (value: string) => /^#[0-9a-fA-F]{6}$/.test(value);
interface ColorPickerProps extends AriaColorPickerProps {
type ColorPickerProps = {
children?: ReactNode;
columns?: number;
colorset?: string[];
}
} & AriaColorPickerProps;
export function ColorPicker({
children,

View File

@@ -0,0 +1,198 @@
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

@@ -3,8 +3,8 @@ import {
cloneElement,
isValidElement,
type ReactElement,
Ref,
RefObject,
type Ref,
type RefObject,
useEffect,
useRef,
} from 'react';

View File

@@ -1,5 +1,5 @@
import * as React from 'react';
import { forwardRef, Ref } from 'react';
import { forwardRef, type Ref } from 'react';
import { render } from '@testing-library/react';

View File

@@ -1,6 +1,6 @@
import React, {
ChangeEvent,
ComponentPropsWithRef,
type ChangeEvent,
type ComponentPropsWithRef,
type KeyboardEvent,
type FocusEvent,
} from 'react';

View File

@@ -1,12 +1,13 @@
import {
type ReactNode,
useEffect,
useRef,
useState,
type ComponentProps,
type ComponentType,
type SVGProps,
type CSSProperties,
type KeyboardEvent,
useEffect,
useRef,
} from 'react';
import { Button } from './Button';
@@ -78,62 +79,81 @@ export function Menu<const NameType = string>({
}: MenuProps<NameType>) {
const elRef = useRef<HTMLDivElement>(null);
const items = allItems.filter(x => x);
const filteredItems = items.filter(
item => item && item !== Menu.line && item.type !== Menu.label,
);
const [hoveredIndex, setHoveredIndex] = useState<number | null>(null);
const currentIndex = filteredItems.indexOf(items[hoveredIndex || 0]);
const transformIndex = (idx: number) => items.indexOf(filteredItems[idx]);
function hoverPrevious() {
setHoveredIndex(
hoveredIndex === null ? 0 : transformIndex(Math.max(currentIndex - 1, 0)),
);
}
function hoverNext() {
setHoveredIndex(
hoveredIndex === null
? 0
: transformIndex(Math.min(currentIndex + 1, filteredItems.length - 1)),
);
}
function selectItem() {
const item = items[hoveredIndex || 0];
if (
hoveredIndex !== null &&
item !== Menu.line &&
!isLabel(item) &&
!item.disabled
) {
onMenuSelect?.(item.name);
}
}
function onKeyDown(e: KeyboardEvent) {
switch (e.key) {
case 'ArrowUp':
e.preventDefault();
hoverPrevious();
break;
case 'ArrowDown':
e.preventDefault();
hoverNext();
break;
case 'Enter':
e.preventDefault();
selectItem();
break;
default:
}
}
useEffect(() => {
const activeElement = document.activeElement;
if (
activeElement &&
(['input', 'select', 'textarea'].includes(
activeElement.tagName.toLowerCase(),
) ||
activeElement.hasAttribute('contenteditable') ||
activeElement.getAttribute('role') === 'textbox')
) {
return;
}
const el = elRef.current;
el?.focus();
const onKeyDown = (e: KeyboardEvent) => {
const filteredItems = items.filter(
item => item && item !== Menu.line && item.type !== Menu.label,
);
const currentIndex = filteredItems.indexOf(items[hoveredIndex || 0]);
const transformIndex = (idx: number) => items.indexOf(filteredItems[idx]);
switch (e.key) {
case 'ArrowUp':
e.preventDefault();
setHoveredIndex(
hoveredIndex === null
? 0
: transformIndex(Math.max(currentIndex - 1, 0)),
);
break;
case 'ArrowDown':
e.preventDefault();
setHoveredIndex(
hoveredIndex === null
? 0
: transformIndex(
Math.min(currentIndex + 1, filteredItems.length - 1),
),
);
break;
case 'Enter':
e.preventDefault();
const item = items[hoveredIndex || 0];
if (hoveredIndex !== null && item !== Menu.line && !isLabel(item)) {
onMenuSelect?.(item.name);
}
break;
default:
}
};
el?.addEventListener('keydown', onKeyDown);
return () => {
el?.removeEventListener('keydown', onKeyDown);
};
}, [hoveredIndex]);
}, []);
return (
<View
className={className}
style={{ outline: 'none', borderRadius: 4, overflow: 'hidden', ...style }}
tabIndex={1}
onKeyDown={onKeyDown}
innerRef={elRef}
>
{header}
@@ -166,6 +186,7 @@ export function Menu<const NameType = string>({
return (
<Button
excludeFromTabOrder
key={String(item.name)}
variant="bare"
slot={slot}

View File

@@ -34,7 +34,7 @@ export const Popover = ({
return (
<ReactAriaPopover
data-popover={true}
data-popover
ref={ref}
placement="bottom end"
offset={1}

View File

@@ -36,6 +36,7 @@ export const Toggle = ({
})}
type="checkbox"
/>
{/* oxlint-disable-next-line eslint-plugin-jsx-a11y(label-has-associated-control) */}
<label
data-toggle-container
data-on={isOn}
@@ -62,7 +63,6 @@ export const Toggle = ({
data-on={isOn}
className={css(
{
// eslint-disable-next-line actual/typography
content: '" "',
position: 'absolute',
top: '2px',

View File

@@ -3,7 +3,7 @@ import { keyframes } from '@emotion/css';
import { theme } from './theme';
import { tokens } from './tokens';
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// oxlint-disable-next-line typescript/no-explicit-any
export type CSSProperties = Record<string, any>;
const MOBILE_MIN_HEIGHT = 40;
@@ -12,7 +12,7 @@ const shadowLarge = {
boxShadow: '0 15px 30px 0 rgba(0,0,0,0.11), 0 5px 15px 0 rgba(0,0,0,0.08)',
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// oxlint-disable-next-line typescript/no-explicit-any
export const styles: Record<string, any> = {
incomeHeaderHeight: 70,
cardShadow: '0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24)',
@@ -91,7 +91,6 @@ export const styles: Record<string, any> = {
},
shadowLarge,
tnum: {
// eslint-disable-next-line actual/typography
fontFeatureSettings: '"tnum"',
},
notFixed: { fontFeatureSettings: '' },

View File

@@ -1,6 +1,6 @@
# `@actual-app/crdt`
This package contains the core CRDT logic that enables Actuals syncing. It is shared between the client and server. We may or may not follow semver when updating this package; any usage of it outside Actual is undocumented and at your own risk.
This package contains the core CRDT logic that enables Actual's syncing. It is shared between the client and server. We may or may not follow semver when updating this package; any usage of it outside Actual is undocumented and at your own risk.
## protobuf
@@ -10,7 +10,7 @@ We use [protobuf](https://developers.google.com/protocol-buffers/) to encode mes
The protobuf is generated by using the [protoc](https://github.com/protocolbuffers/protobuf) compiler.
This can be installed by downloading one of the [pre-built binaries](https://github.com/protocolbuffers/protobuf/releases/) and placing it in your `$PATH`. The version used to build the current protobuf is [v3.20.1](https://github.com/protocolbuffers/protobuf/releases/tag/v3.20.1). Youll also need to [download the latest version of `protoc-gen-js`](https://github.com/protocolbuffers/protobuf-javascript/releases/latest). For convenience, you can put both of these binaries in `./bin`.
This can be installed by downloading one of the [pre-built binaries](https://github.com/protocolbuffers/protobuf/releases/) and placing it in your `$PATH`. The version used to build the current protobuf is [v3.20.1](https://github.com/protocolbuffers/protobuf/releases/tag/v3.20.1). You'll also need to [download the latest version of `protoc-gen-js`](https://github.com/protocolbuffers/protobuf-javascript/releases/latest). For convenience, you can put both of these binaries in `./bin`.
Once installed, the protobuf can be generated by running `./bin/generate-proto`.

View File

@@ -1,18 +1,18 @@
{
"name": "@actual-app/crdt",
"version": "2.1.0",
"license": "MIT",
"description": "CRDT layer of Actual",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"license": "MIT",
"files": [
"dist"
],
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build:node": "tsc --p tsconfig.dist.json",
"proto:generate": "./bin/generate-proto",
"build": "rm -rf dist && yarn run build:node",
"test": "vitest --run --globals"
"test": "vitest --run"
},
"dependencies": {
"google-protobuf": "^3.21.4",

View File

@@ -7,7 +7,7 @@
// * Need to check to make sure if account exists when handling
// * transaction changes in syncing
import { Timestamp } from './timestamp';
import { type Timestamp } from './timestamp';
/**
* Represents a node within a trinary radix trie.
@@ -134,7 +134,7 @@ export function diff(trie1: TrieNode, trie2: TrieNode): number | null {
node2 = node2[diffkey] || emptyTrie();
}
// eslint-disable-next-line no-unreachable
// oxlint-disable-next-line no-unreachable
return null;
}

View File

@@ -1,7 +1,7 @@
import murmurhash from 'murmurhash';
import { v4 as uuidv4 } from 'uuid';
import { TrieNode } from './merkle';
import { type TrieNode } from './merkle';
/**
* Hybrid Unique Logical Clock (HULC) timestamp generator

View File

@@ -1,4 +1,4 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
/* oxlint-disable typescript/no-explicit-any */
import './proto/sync_pb.js'; // Import for side effects
export {

View File

@@ -1,4 +1,4 @@
/* eslint-disable @typescript-eslint/no-namespace */
/* oxlint-disable typescript/no-namespace */
// package:
// file: sync.proto

View File

@@ -1,7 +1,7 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
// Using ES2021 because thats the newest version where
// Using ES2021 because that's the newest version where
// the latest Node 16.x release supports all of the features
"target": "ES2021",
"module": "CommonJS",

View File

@@ -0,0 +1,11 @@
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
globals: true,
include: ['src/**/*.test.(js|ts)'],
environment: 'node',
maxWorkers: 1,
isolate: false,
},
});

View File

@@ -7,6 +7,7 @@ node_modules
coverage
test-results
playwright-report
blob-report
# production
build

View File

@@ -23,7 +23,7 @@ test.describe('Mobile Accounts', () => {
});
test.afterEach(async () => {
await page.close();
await page?.close();
});
test('opens the accounts page and asserts on balances', async () => {

View File

@@ -23,7 +23,7 @@ test.describe('Accounts', () => {
});
test.afterEach(async () => {
await page.close();
await page?.close();
});
test('creates a new account and views the initial balance transaction', async () => {

View File

@@ -28,7 +28,7 @@ test.describe('Mobile Bank Sync', () => {
});
test.afterEach(async () => {
await page.close();
await page?.close();
});
test('checks the page visuals', async () => {

View File

@@ -11,23 +11,21 @@ test.describe('Bank Sync', () => {
let bankSyncPage: BankSyncPage;
let configurationPage: ConfigurationPage;
test.beforeAll(async ({ browser }) => {
test.beforeEach(async ({ browser }) => {
page = await browser.newPage();
navigation = new Navigation(page);
configurationPage = new ConfigurationPage(page);
await page.goto('/');
await configurationPage.createTestFile();
});
test.afterAll(async () => {
await page.close();
});
test.beforeEach(async () => {
bankSyncPage = await navigation.goToBankSyncPage();
});
test.afterEach(async () => {
await page?.close();
});
test('checks the page visuals', async () => {
await bankSyncPage.waitToLoad();
await expect(page).toMatchThemeScreenshots();

View File

@@ -350,8 +350,8 @@ budgetTypes.forEach(budgetType => {
await expect(budgetedButton).toHaveText(
amountToCurrency(amountToTemplate),
);
const notification = page.getByRole('alert').first();
await expect(notification).toContainText(templateNotes);
const templateNotification = page.getByRole('alert').nth(1);
await expect(templateNotification).toContainText(templateNotes);
await expect(page).toMatchThemeScreenshots();
});

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 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: 32 KiB

After

Width:  |  Height:  |  Size: 34 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: 31 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 34 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: 32 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 35 KiB

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