[PR #7451] [AI] Formula Feature Improvements: FORMATNUMBER, FORMATCURRENCY, and Tooltip Fixes #37370

Open
opened 2026-04-21 00:22:23 -05:00 by GiteaMirror · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/actualbudget/actual/pull/7451
Author: @lelemm
Created: 4/9/2026
Status: 🔄 Open

Base: masterHead: cursor/formula-feedback-improvements-4223


📝 Commits (7)

  • 6d2171c [AI] Add FORMATNUMBER and FORMATCURRENCY functions to address TEXT() formatting limitations
  • 3bb11c1 [AI] Add support for line breaks in formula card results
  • 506f939 [AI] Remove unusable formula functions that require cell ranges
  • 2e051ee [AI] Add comprehensive integration tests for formula rules and formula cards
  • 2fed7e2 Potential fix for pull request finding 'Unused variable, import, function or class'
  • c241c0b [AI] Make formatting functions respect app settings with locale-based fallbacks
  • 82fc4b8 Update VRT screenshots

📊 Changes

10 files changed (+2433 additions, -249 deletions)

View changed files

📝 packages/desktop-client/src/components/formula/codeMirror-excelLanguage.tsx (+21 -40)
📝 packages/desktop-client/src/components/formula/queryModeFunctions.ts (+63 -198)
📝 packages/desktop-client/src/components/formula/transactionModeFunctions.ts (+47 -5)
📝 packages/desktop-client/src/components/reports/FormulaResult.tsx (+16 -5)
📝 packages/desktop-electron/e2e/__screenshots__/onboarding.test.ts/Onboarding-checks-the-page-visuals-1-linux.png (+0 -0)
packages/loot-core/src/server/reports/formula-card-integration.test.ts (+723 -0)
📝 packages/loot-core/src/server/rules/action.ts (+5 -0)
📝 packages/loot-core/src/server/rules/customFunctions.ts (+309 -1)
packages/loot-core/src/server/rules/formula-action-integration.test.ts (+1168 -0)
📝 packages/loot-core/src/server/rules/formula-action.test.ts (+81 -0)

📄 Description

Summary

This PR addresses several user feedback items from issue #5949 regarding the formula card and formula rules feature.

Changes Made

1. FORMATNUMBER() Function (Addresses TEXT() formatting limitations)

Feedback: Users reported that TEXT(QUERY("NetWorth"), "$#,##0.00") doesn't properly format numbers with thousands separators. The TEXT function in HyperFormula has limited format code support compared to Excel.

Solution: Added a new FORMATNUMBER() function that properly formats numbers with thousands separators and respects app settings.

Usage:

=FORMATNUMBER(1234567.89)  // Uses app number format settings
=FORMATNUMBER(1234567.89, 2)  // Specify decimal places
=FORMATNUMBER(1234567.89, 2, ".", ",")  // Override with custom separators

Settings Integration:

  • Uses app's number format preference (comma-dot, dot-comma, space-comma, etc.)
  • Falls back to locale-based defaults if no preference set
  • All parameters optional - respects user's configuration

2. FORMATCURRENCY() Function (Proper currency formatting)

Feedback: Users need proper currency formatting for formula cards with symbol, thousands separators, and decimal places.

Solution: Added a new FORMATCURRENCY() function that formats numbers as currency and respects app currency settings.

Usage:

=FORMATCURRENCY(1234567.89)  // Uses app currency symbol and format
=FORMATCURRENCY(1234567.89, "€")  // Override with Euro symbol
=FORMATCURRENCY(-1234567.89)  // Handles negatives: "-$1,234,567.89"

Settings Integration:

  • Uses app's default currency code preference
  • Uses app's number format preference for separators
  • Falls back to locale-based currency (en-GB→GBP, de/fr/es→EUR, ja→JPY, etc.)
  • All parameters optional - respects user's configuration

Locale-based Defaults:

  • en-GB → GBP (£)
  • de/fr/es/it/nl → EUR (€)
  • ja → JPY (¥)
  • en-IN/hi → INR (₹)
  • en-CA → CAD ($)
  • en-AU → AUD ($)
  • Default → USD ($)

Number Format Patterns:

  • comma-dot: 1,000.00 (US/UK/Canada)
  • dot-comma: 1.000,00 (Europe)
  • space-comma: 1 000,00 (France)
  • apostrophe-dot: 1'000.00 (Switzerland)
  • comma-dot-in: 1,00,000.00 (India)

3. Line Break Support in Formula Cards

Feedback: User @Juulz reported that line breaks don't work in formula cards, making multi-line displays ugly. Requested ability to use CHAR(10) or CHAR(13) in CONCATENATE.

Solution: Updated FormulaResult component to support multi-line text with proper rendering and font size calculation.

Usage:

=CONCATENATE("Total 1: ", value1, CHAR(10), "Total 2: ", value2, CHAR(10), "Total 3: ", value3)

Result:

Total 1: 100
Total 2: 200
Total 3: 300

Implementation:

  • Added whiteSpace: 'pre-wrap' to preserve line breaks
  • Added textAlign: 'center' to keep multi-line text centered
  • Updated font size calculation to account for multiple lines (divides height by line count)
  • Calculates based on longest line length for proper sizing

4. Formula Function Cleanup 🧹

Feedback: User requested review of all formula functions to remove ones that don't make sense in Actual's context.

Problem: Many Excel functions require cell ranges (like A1:A10) which don't exist in Actual. Actual uses named expressions like QUERY("myQuery") and transaction field variables like amount or date.

Solution: Removed 27 unusable functions from autocomplete suggestions:

Removed Functions:

  • Range-based counting: AVERAGEA, COUNT, COUNTA, COUNTBLANK, COUNTIF, COUNTIFS
    • Use QUERY_COUNT() instead
  • Range-based aggregation: MAXA, MINA, SUMIF, SUMIFS, SUMPRODUCT, SUMSQ
    • Use QUERY() with filters instead
  • Statistical functions: MEDIAN, MODE, STDEV, STDEVP, VAR, VARP, PERCENTILE, QUARTILE, RANK
    • These require arrays of data which don't exist in our context
  • Lookup functions: VLOOKUP, HLOOKUP, INDEX, MATCH, LOOKUP
    • These require table arrays and cell references
  • Reference checking: ISREF
    • Checks for cell references which don't exist

Kept Useful Functions:

  • Math functions that work with individual values: SUM, AVERAGE, MAX, MIN, ROUND, etc.
  • Text functions: CONCATENATE, UPPER, LEFT, RIGHT, etc.
  • Date functions: TODAY, YEAR, MONTH, EOMONTH, etc.
  • Logical functions: IF, AND, OR, IFERROR, etc.
  • Query-specific functions: QUERY, QUERY_COUNT, BUDGET_QUERY, etc.
  • CHOOSE (works with index and individual values)

Impact: Autocomplete suggestions are now more relevant and less confusing. Users won't see functions they can't actually use.

5. Tooltip Quote Consistency Fix

Feedback: Tooltips used backticks around formula examples while actual usage used double quotes, causing confusion.

Solution: Removed backticks from all formula examples in tooltips for consistency. Examples now show formulas as plain text without wrapping backticks.

Before: `=UPPER(notes)`
After: =UPPER(notes)

6. Updated Documentation

  • Added function definitions to queryModeFunctions.ts (for formula cards)
  • Added function definitions to transactionModeFunctions.ts (for formula rules)
  • Updated syntax highlighting to recognize new functions and removed obsolete ones
  • Updated descriptions to clarify that formatting functions use app settings by default

7. Comprehensive Integration Tests 🧪

Added 50 integration tests that validate formulas with real database operations:

Formula Rule Integration Tests (36 tests)

Tests validate formula execution with actual transaction data:

  • Basic operations: FORMATCURRENCY, nested IFs, date formatting
  • Text manipulation: CONCATENATE, UPPER, LEFT, RIGHT, TRIM, PROPER
  • Math functions: ROUND, ABS, MAX, MIN, CEILING, SQRT, SUM, PRODUCT
  • Date functions: YEAR, MONTH, DAY, DAYS, EOMONTH, WEEKDAY
  • Logical functions: AND, OR, NOT, IFERROR, SWITCH
  • New formatting functions with various options
  • Multi-line output with CHAR(10)
  • Information functions: ISNUMBER, ISTEXT, ISEVEN, ISODD, ISBLANK
  • Error handling and type validation
  • Complex nested formulas (3-4 levels deep)

Formula Card Integration Tests (14 tests)

Tests validate formulas with real query results from database:

  • Single and multiple query integration
  • Query results with formatting functions
  • Percentage calculations across queries
  • Date-based query filtering
  • Complex nested calculations with multiple queries
  • Multi-line output with query results
  • Error handling with empty queries
  • Running totals across accounts
  • MAX/MIN operations with query results

Test Quality:

  • Real database operations (not mocked)
  • Complex nested formulas demonstrating actual use cases
  • Every formula function type covered in at least one test
  • Edge cases tested (empty results, division by zero, type mismatches)
  • All 662 tests passing

Technical Implementation

Settings Architecture

Problem: HyperFormula custom functions are synchronous, but preferences are stored in async database.

Solution:

  • Created loadUserPreferencesForFormulas() async function that loads preferences once
  • Caches preferences globally for synchronous access by custom functions
  • Called on module initialization (avoids repeated DB queries)
  • No reactors needed - clean and efficient

Settings Priority:

  1. Explicit function parameters (if provided)
  2. User's app settings (from preferences DB)
  3. Locale-based defaults (inferred from language setting)

This approach avoids unnecessary reactors while properly respecting user preferences!

Feedbacks Not Addressed (with reasoning)

BALANCEONDAY() Function

Feedback: Request for a function to get account balance on a specific date for credit card statement calculations.

Reason not implemented: This would require database access to query transaction history, which is not available in the formula execution context (both for formula cards and formula rules). The formula execution is designed to be stateless and work with the data provided in the context. Implementing this would require architectural changes to allow async database queries during formula execution.

Alternative approach: Users can currently achieve this by creating a query with appropriate date filters and using QUERY() to get the sum of transactions up to that date.

LASTSYNCEDBALANCE Variable

Feedback: Request for access to lastSyncedBalance in custom pills/formulas.

Reason not implemented: Similar to BALANCEONDAY, this would require access to account metadata that isn't available in the current formula execution context. The balance_current field is stored in the accounts table and would need to be passed as a variable to the formula execution context.

Alternative approach: This could be added in a future enhancement by extending the variable context passed to formula execution to include account metadata when the formula is executed in an account-specific context.

Dynamic "Last Month" Dropdown

Feedback: Request for dynamic time selection like "last month" in the hamburger menu for time selections.

Reason not in this PR: This is a UI/UX enhancement for the query time frame selector, not related to formula functions. This would be better addressed in a separate PR focused on the query configuration UI.

Testing

  • All existing tests pass (604 tests)
  • New unit tests for FORMATNUMBER and FORMATCURRENCY (8 tests)
  • New integration tests for formula rules (36 tests)
  • New integration tests for formula cards (14 tests)
  • Total: 662 tests passing
  • Type checking passes
  • Linting passes

Code Comments

Throughout the code, I've added comments explaining which feedback triggered each change:

// Feedback: Users reported that TEXT() function doesn't properly format numbers with
// thousands separators (e.g., TEXT(value, "$#,##0.00") doesn't work as expected).
// This custom function provides proper number formatting with thousands separators.
// User feedback: Should respect app's number format settings, with locale-based fallbacks

This makes it easy to trace each change back to the original user feedback.

Addresses feedback items from #5949

Open in Web Open in Cursor 

Bundle Stats

Bundle Files count Total bundle size % Changed
desktop-client 27 12.86 MB → 12.8 MB (-56.74 kB) -0.43%
loot-core 1 4.84 MB → 4.85 MB (+5.67 kB) +0.11%
api 1 3.84 MB → 3.84 MB (+5.52 kB) +0.14%
cli 1 7.89 MB 0%
View detailed bundle stats

desktop-client

Total

Files count Total bundle size % Changed
27 12.86 MB → 12.8 MB (-56.74 kB) -0.43%
Changeset (largest 100 files by percent change)
File Δ Size
node_modules/@jlongster/sql.js/dist/sql-wasm.js 🆕 +89.77 kB 0 B → 89.77 kB
node_modules/google-protobuf/google-protobuf.js 🆕 +84.08 kB 0 B → 84.08 kB
home/runner/work/actual/actual/packages/loot-core/src/server/aql/compiler.ts 🆕 +24.02 kB 0 B → 24.02 kB
home/runner/work/actual/actual/packages/loot-core/src/server/db/index.ts 🆕 +18.96 kB 0 B → 18.96 kB
node_modules/adm-zip/adm-zip.js 🆕 +17.31 kB 0 B → 17.31 kB
home/runner/work/actual/actual/packages/crdt/src/proto/sync_pb.js 🆕 +16.73 kB 0 B → 16.73 kB
home/runner/work/actual/actual/packages/loot-core/src/server/sync/index.ts 🆕 +12.48 kB 0 B → 12.48 kB
node_modules/adm-zip/zipEntry.js 🆕 +10.41 kB 0 B → 10.41 kB
home/runner/work/actual/actual/packages/loot-core/src/server/aql/schema/index.ts 🆕 +9.33 kB 0 B → 9.33 kB
home/runner/work/actual/actual/packages/loot-core/src/server/budget/envelope.ts 🆕 +8.9 kB 0 B → 8.9 kB
node_modules/adm-zip/zipFile.js 🆕 +8.81 kB 0 B → 8.81 kB
node_modules/adm-zip/headers/entryHeader.js 🆕 +7.53 kB 0 B → 7.53 kB
node_modules/adm-zip/util/utils.js 🆕 +7.13 kB 0 B → 7.13 kB
home/runner/work/actual/actual/packages/loot-core/src/server/budget/report.ts 🆕 +6.72 kB 0 B → 6.72 kB
home/runner/work/actual/actual/packages/loot-core/src/server/budget/base.ts 🆕 +6.48 kB 0 B → 6.48 kB
home/runner/work/actual/actual/packages/loot-core/src/server/aql/schema/executors.ts 🆕 +6.14 kB 0 B → 6.14 kB
home/runner/work/actual/actual/packages/crdt/src/crdt/timestamp.ts 🆕 +5.01 kB 0 B → 5.01 kB
home/runner/work/actual/actual/packages/loot-core/src/server/aql/schema-helpers.ts 🆕 +3.87 kB 0 B → 3.87 kB
node_modules/adm-zip/methods/zipcrypto.js 🆕 +3.14 kB 0 B → 3.14 kB
home/runner/work/actual/actual/packages/loot-core/src/server/db/sort.ts 🆕 +2.89 kB 0 B → 2.89 kB
node_modules/murmurhash/murmurhash.js 🆕 +2.86 kB 0 B → 2.86 kB
home/runner/work/actual/actual/packages/loot-core/src/platform/server/sqlite/index.ts 🆕 +2.75 kB 0 B → 2.75 kB
node_modules/adm-zip/headers/mainHeader.js 🆕 +2.75 kB 0 B → 2.75 kB
home/runner/work/actual/actual/packages/loot-core/src/server/sync/encoder.ts 🆕 +2.7 kB 0 B → 2.7 kB
home/runner/work/actual/actual/packages/loot-core/src/server/models.ts 🆕 +2.69 kB 0 B → 2.69 kB
node_modules/adm-zip/util/errors.js 🆕 +2.47 kB 0 B → 2.47 kB
home/runner/work/actual/actual/packages/loot-core/src/platform/server/fs/path-join.ts 🆕 +2.23 kB 0 B → 2.23 kB
node_modules/adm-zip/util/constants.js 🆕 +1.91 kB 0 B → 1.91 kB
home/runner/work/actual/actual/packages/crdt/src/crdt/merkle.ts 🆕 +1.91 kB 0 B → 1.91 kB
home/runner/work/actual/actual/packages/loot-core/src/server/aql/exec.ts 🆕 +1.61 kB 0 B → 1.61 kB
home/runner/work/actual/actual/packages/loot-core/src/server/sheet.ts 🆕 +1.56 kB 0 B → 1.56 kB
home/runner/work/actual/actual/packages/loot-core/src/platform/server/fs/index.ts 🆕 +1.54 kB 0 B → 1.54 kB
node_modules/adm-zip/util/fattr.js 🆕 +1.49 kB 0 B → 1.49 kB
home/runner/work/actual/actual/packages/loot-core/src/server/app.ts 🆕 +1.22 kB 0 B → 1.22 kB
home/runner/work/actual/actual/packages/loot-core/src/server/encryption/encryption-internals.ts 🆕 +1.2 kB 0 B → 1.2 kB
node_modules/adm-zip/methods/inflater.js 🆕 +1019 B 0 B → 1019 B
home/runner/work/actual/actual/packages/loot-core/src/platform/server/sqlite/unicodeLike.ts 🆕 +993 B 0 B → 993 B
home/runner/work/actual/actual/packages/loot-core/src/server/post.ts 🆕 +991 B 0 B → 991 B
node_modules/adm-zip/methods/deflater.js 🆕 +906 B 0 B → 906 B
home/runner/work/actual/actual/packages/loot-core/src/server/undo.ts 🆕 +815 B 0 B → 815 B
home/runner/work/actual/actual/packages/loot-core/src/server/prefs.ts 🆕 +682 B 0 B → 682 B
home/runner/work/actual/actual/packages/loot-core/src/server/server-config.ts 🆕 +676 B 0 B → 676 B
home/runner/work/actual/actual/packages/loot-core/src/server/mutators.ts 🆕 +524 B 0 B → 524 B
node_modules/mitt/dist/mitt.mjs 🆕 +513 B 0 B → 513 B
home/runner/work/actual/actual/packages/loot-core/src/platform/server/connection/index.ts 🆕 +512 B 0 B → 512 B
home/runner/work/actual/actual/packages/loot-core/src/platform/server/fs/shared.ts 🆕 +498 B 0 B → 498 B
home/runner/work/actual/actual/packages/loot-core/src/server/budget/util.ts 🆕 +403 B 0 B → 403 B
home/runner/work/actual/actual/packages/loot-core/src/server/encryption/index.ts 🆕 +393 B 0 B → 393 B
home/runner/work/actual/actual/packages/loot-core/src/platform/server/fetch/index.ts 🆕 +373 B 0 B → 373 B
home/runner/work/actual/actual/packages/crdt/src/index.ts 🆕 +367 B 0 B → 367 B
node_modules/adm-zip/util/index.js 🆕 +358 B 0 B → 358 B
home/runner/work/actual/actual/packages/loot-core/src/server/sync/repair.ts 🆕 +340 B 0 B → 340 B
node_modules/adm-zip/util/decoder.js 🆕 +273 B 0 B → 273 B
node_modules/adm-zip/methods/index.js 🆕 +262 B 0 B → 262 B
home/runner/work/actual/actual/packages/loot-core/src/server/spreadsheet/globals.ts 🆕 +262 B 0 B → 262 B
home/runner/work/actual/actual/packages/loot-core/src/server/aql/index.ts 🆕 +258 B 0 B → 258 B
node_modules/adm-zip/headers/index.js 🆕 +230 B 0 B → 230 B
home/runner/work/actual/actual/packages/loot-core/src/server/db/util.ts 🆕 +195 B 0 B → 195 B
home/runner/work/actual/actual/packages/loot-core/src/platform/server/sqlite/normalise.ts 🆕 +168 B 0 B → 168 B
__vite-browser-external 🆕 +166 B 0 B → 166 B
home/runner/work/actual/actual/packages/loot-core/src/server/main-app.ts 🆕 +149 B 0 B → 149 B
home/runner/work/actual/actual/packages/loot-core/src/server/spreadsheet/util.ts 🆕 +133 B 0 B → 133 B
home/runner/work/actual/actual/packages/loot-core/src/server/cloud-storage.ts 🆕 +129 B 0 B → 129 B
node_modules/absurd-sql/dist/indexeddb-backend.js 🆕 +99 B 0 B → 99 B
home/runner/work/actual/actual/packages/loot-core/src/server/rules/customFunctions.ts 📈 +5.48 kB (+522.63%) 1.05 kB → 6.53 kB
home/runner/work/actual/actual/packages/loot-core/src/shared/async.ts 📈 +708 B (+270.23%) 262 B → 970 B
home/runner/work/actual/actual/packages/loot-core/src/server/errors.ts 📈 +412 B (+214.58%) 192 B → 604 B
home/runner/work/actual/actual/packages/loot-core/src/platform/server/asyncStorage/index.ts 📈 +706 B (+155.16%) 455 B → 1.13 kB
home/runner/work/actual/actual/packages/loot-core/src/platform/server/indexeddb/index.ts 📈 +348 B (+25.87%) 1.31 kB → 1.65 kB
home/runner/work/actual/actual/packages/loot-core/src/server/rules/action.ts 📈 +34 B (+12.41%) 274 B → 308 B
src/components/formula/transactionModeFunctions.ts 📈 +1.05 kB (+7.71%) 13.64 kB → 14.7 kB
src/components/reports/FormulaResult.tsx 📈 +231 B (+5.99%) 3.76 kB → 3.99 kB
home/runner/work/actual/actual/packages/loot-core/src/shared/util.ts 📈 +417 B (+4.62%) 8.82 kB → 9.23 kB
src/queries/aqlQuery.ts 📈 +4 B (+3.23%) 124 B → 128 B
src/undo/index.ts 📈 +4 B (+0.73%) 551 B → 555 B
src/tags/queries.ts 📈 +2 B (+0.64%) 311 B → 313 B
node_modules/chevrotain/lib_esm/src/parse/grammar/first.js 📈 +8 B (+0.60%) 1.29 kB → 1.3 kB
src/hooks/useMetadataPref.ts 📈 +2 B (+0.57%) 352 B → 354 B
src/budget/mutations.ts 📈 +70 B (+0.55%) 12.36 kB → 12.42 kB
src/reports/queries.ts 📈 +6 B (+0.54%) 1.09 kB → 1.09 kB
home/runner/work/actual/actual/packages/loot-core/src/server/rules/handlebars-helpers.ts 📈 +12 B (+0.36%) 3.25 kB → 3.26 kB
src/hooks/useTransactionBatchActions.ts 📈 +28 B (+0.31%) 8.72 kB → 8.74 kB
src/transactions/queries.ts 📈 +2 B (+0.31%) 647 B → 649 B
node_modules/handlebars/dist/cjs/handlebars/decorators/inline.js 📈 +2 B (+0.25%) 789 B → 791 B
node_modules/moment/dist/moment.js 📈 +256 B (+0.22%) 111.44 kB → 111.69 kB
src/components/ServerContext.tsx 📈 +12 B (+0.21%) 5.67 kB → 5.68 kB
src/budget/queries.ts 📈 +2 B (+0.20%) 1020 B → 1022 B
node_modules/handlebars/dist/cjs/handlebars/helpers/block-helper-missing.js 📈 +2 B (+0.19%) 1.02 kB → 1.02 kB
src/hooks/useSpreadsheet.tsx 📈 +6 B (+0.19%) 3.16 kB → 3.17 kB
node_modules/handlebars/dist/cjs/handlebars/logger.js 📈 +2 B (+0.18%) 1.07 kB → 1.07 kB
home/runner/work/actual/actual/packages/loot-core/src/shared/schedules.ts 📈 +20 B (+0.18%) 10.72 kB → 10.74 kB
node_modules/handlebars/dist/cjs/handlebars/helpers/with.js 📈 +2 B (+0.17%) 1.14 kB → 1.14 kB
node_modules/handlebars/dist/cjs/handlebars/helpers/if.js 📈 +2 B (+0.17%) 1.18 kB → 1.18 kB
node_modules/source-map/lib/mapping-list.js 📈 +2 B (+0.15%) 1.27 kB → 1.27 kB
node_modules/handlebars/dist/cjs/handlebars.runtime.js 📈 +2 B (+0.13%) 1.56 kB → 1.56 kB
src/components/transactions/TransactionList.tsx 📈 +18 B (+0.10%) 17.13 kB → 17.15 kB
node_modules/source-map/lib/array-set.js 📈 +2 B (+0.10%) 1.93 kB → 1.93 kB
node_modules/chevrotain/lib_esm/src/parse/grammar/follow.js 📈 +2 B (+0.10%) 1.95 kB → 1.95 kB
node_modules/handlebars/dist/cjs/handlebars/helpers/each.js 📈 +2 B (+0.09%) 2.22 kB → 2.22 kB
node_modules/handlebars/dist/cjs/handlebars/utils.js 📈 +2 B (+0.08%) 2.33 kB → 2.33 kB
View detailed bundle breakdown

Added
No assets were added

Removed
No assets were removed

Bigger

Asset File Size % Changed
static/js/useTransactionBatchActions.js 4.33 MB → 4.72 MB (+403.18 kB) +9.09%
static/js/ReportRouter.js 1.17 MB → 1.17 MB (+231 B) +0.02%

Smaller

Asset File Size % Changed
static/js/theme.js 485.18 kB → 30.79 kB (-454.39 kB) -93.65%
static/js/FormulaEditor.js 852.77 kB → 849.03 kB (-3.74 kB) -0.44%
static/js/index.js 3.31 MB → 3.31 MB (-2.01 kB) -0.06%

Unchanged

Asset File Size % Changed
static/js/BackgroundImage.js 121.09 kB 0%
static/js/TransactionList.js 82.49 kB 0%
static/js/ca.js 191.98 kB 0%
static/js/da.js 104.66 kB 0%
static/js/de.js 174.38 kB 0%
static/js/en-GB.js 8.2 kB 0%
static/js/en.js 175.72 kB 0%
static/js/es.js 181.8 kB 0%
static/js/fr.js 177.08 kB 0%
static/js/indexeddb-main-thread-worker-e59fee74.js 13.46 kB 0%
static/js/it.js 165.87 kB 0%
static/js/narrow.js 363.02 kB 0%
static/js/nb-NO.js 151.85 kB 0%
static/js/nl.js 108.93 kB 0%
static/js/pl.js 88.34 kB 0%
static/js/pt-BR.js 177.44 kB 0%
static/js/resize-observer.js 18.06 kB 0%
static/js/th.js 179.3 kB 0%
static/js/uk.js 212.6 kB 0%
static/js/wide.js 295 B 0%
static/js/workbox-window.prod.es5.js 7.33 kB 0%
static/js/zh-Hans.js 99.27 kB 0%

loot-core

Total

Files count Total bundle size % Changed
1 4.84 MB → 4.85 MB (+5.67 kB) +0.11%
Changeset
File Δ Size
home/runner/work/actual/actual/packages/loot-core/src/server/rules/customFunctions.ts 📈 +5.63 kB (+525.32%) 1.07 kB → 6.71 kB
home/runner/work/actual/actual/packages/loot-core/src/server/rules/action.ts 📈 +35 B (+0.44%) 7.84 kB → 7.87 kB
View detailed bundle breakdown

Added

Asset File Size % Changed
kcab.worker.-abDimv-.js 0 B → 4.85 MB (+4.85 MB) -

Removed

Asset File Size % Changed
kcab.worker.2cr-I6dh.js 4.84 MB → 0 B (-4.84 MB) -100%

Bigger
No assets were bigger

Smaller
No assets were smaller

Unchanged
No assets were unchanged


api

Total

Files count Total bundle size % Changed
1 3.84 MB → 3.84 MB (+5.52 kB) +0.14%
Changeset
File Δ Size
home/runner/work/actual/actual/packages/loot-core/src/server/rules/customFunctions.ts 📈 +5.49 kB (+522.21%) 1.05 kB → 6.54 kB
home/runner/work/actual/actual/packages/loot-core/src/server/rules/action.ts 📈 +34 B (+0.45%) 7.39 kB → 7.42 kB
View detailed bundle breakdown

Added
No assets were added

Removed
No assets were removed

Bigger

Asset File Size % Changed
index.js 3.84 MB → 3.84 MB (+5.52 kB) +0.14%

Smaller
No assets were smaller

Unchanged
No assets were unchanged


cli

Total

Files count Total bundle size % Changed
1 7.89 MB 0%
View detailed bundle breakdown

Added
No assets were added

Removed
No assets were removed

Bigger
No assets were bigger

Smaller
No assets were smaller

Unchanged

Asset File Size % Changed
cli.js 7.89 MB 0%

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/actualbudget/actual/pull/7451 **Author:** [@lelemm](https://github.com/lelemm) **Created:** 4/9/2026 **Status:** 🔄 Open **Base:** `master` ← **Head:** `cursor/formula-feedback-improvements-4223` --- ### 📝 Commits (7) - [`6d2171c`](https://github.com/actualbudget/actual/commit/6d2171c183282a8104dee6ddce828b9eaffbf242) [AI] Add FORMATNUMBER and FORMATCURRENCY functions to address TEXT() formatting limitations - [`3bb11c1`](https://github.com/actualbudget/actual/commit/3bb11c15d30ded9a438987ebff29469a287a075e) [AI] Add support for line breaks in formula card results - [`506f939`](https://github.com/actualbudget/actual/commit/506f9393dda8cad9008ff8c23199376ba754e52e) [AI] Remove unusable formula functions that require cell ranges - [`2e051ee`](https://github.com/actualbudget/actual/commit/2e051ee496546f3f8cc0e44d1fe418da507c49eb) [AI] Add comprehensive integration tests for formula rules and formula cards - [`2fed7e2`](https://github.com/actualbudget/actual/commit/2fed7e29660aac4524b4889b2ec97d871ebdd3b8) Potential fix for pull request finding 'Unused variable, import, function or class' - [`c241c0b`](https://github.com/actualbudget/actual/commit/c241c0b117af5762417cc9255f61dd8cc19052d9) [AI] Make formatting functions respect app settings with locale-based fallbacks - [`82fc4b8`](https://github.com/actualbudget/actual/commit/82fc4b871cc2cb2f6e5913df191362e8d939504f) Update VRT screenshots ### 📊 Changes **10 files changed** (+2433 additions, -249 deletions) <details> <summary>View changed files</summary> 📝 `packages/desktop-client/src/components/formula/codeMirror-excelLanguage.tsx` (+21 -40) 📝 `packages/desktop-client/src/components/formula/queryModeFunctions.ts` (+63 -198) 📝 `packages/desktop-client/src/components/formula/transactionModeFunctions.ts` (+47 -5) 📝 `packages/desktop-client/src/components/reports/FormulaResult.tsx` (+16 -5) 📝 `packages/desktop-electron/e2e/__screenshots__/onboarding.test.ts/Onboarding-checks-the-page-visuals-1-linux.png` (+0 -0) ➕ `packages/loot-core/src/server/reports/formula-card-integration.test.ts` (+723 -0) 📝 `packages/loot-core/src/server/rules/action.ts` (+5 -0) 📝 `packages/loot-core/src/server/rules/customFunctions.ts` (+309 -1) ➕ `packages/loot-core/src/server/rules/formula-action-integration.test.ts` (+1168 -0) 📝 `packages/loot-core/src/server/rules/formula-action.test.ts` (+81 -0) </details> ### 📄 Description <!-- CURSOR_AGENT_PR_BODY_BEGIN --> ## Summary This PR addresses several user feedback items from issue #5949 regarding the formula card and formula rules feature. ## Changes Made ### 1. **FORMATNUMBER() Function** (Addresses TEXT() formatting limitations) **Feedback:** Users reported that `TEXT(QUERY("NetWorth"), "$#,##0.00")` doesn't properly format numbers with thousands separators. The TEXT function in HyperFormula has limited format code support compared to Excel. **Solution:** Added a new `FORMATNUMBER()` function that properly formats numbers with thousands separators and **respects app settings**. **Usage:** ```excel =FORMATNUMBER(1234567.89) // Uses app number format settings =FORMATNUMBER(1234567.89, 2) // Specify decimal places =FORMATNUMBER(1234567.89, 2, ".", ",") // Override with custom separators ``` **Settings Integration:** - ✅ Uses app's number format preference (comma-dot, dot-comma, space-comma, etc.) - ✅ Falls back to locale-based defaults if no preference set - ✅ All parameters optional - respects user's configuration ### 2. **FORMATCURRENCY() Function** (Proper currency formatting) **Feedback:** Users need proper currency formatting for formula cards with symbol, thousands separators, and decimal places. **Solution:** Added a new `FORMATCURRENCY()` function that formats numbers as currency and **respects app currency settings**. **Usage:** ```excel =FORMATCURRENCY(1234567.89) // Uses app currency symbol and format =FORMATCURRENCY(1234567.89, "€") // Override with Euro symbol =FORMATCURRENCY(-1234567.89) // Handles negatives: "-$1,234,567.89" ``` **Settings Integration:** - ✅ Uses app's default currency code preference - ✅ Uses app's number format preference for separators - ✅ Falls back to locale-based currency (en-GB→GBP, de/fr/es→EUR, ja→JPY, etc.) - ✅ All parameters optional - respects user's configuration **Locale-based Defaults:** - `en-GB` → GBP (£) - `de/fr/es/it/nl` → EUR (€) - `ja` → JPY (¥) - `en-IN/hi` → INR (₹) - `en-CA` → CAD ($) - `en-AU` → AUD ($) - Default → USD ($) **Number Format Patterns:** - `comma-dot`: 1,000.00 (US/UK/Canada) - `dot-comma`: 1.000,00 (Europe) - `space-comma`: 1 000,00 (France) - `apostrophe-dot`: 1'000.00 (Switzerland) - `comma-dot-in`: 1,00,000.00 (India) ### 3. **Line Break Support in Formula Cards** ✨ **Feedback:** User @Juulz reported that line breaks don't work in formula cards, making multi-line displays ugly. Requested ability to use CHAR(10) or CHAR(13) in CONCATENATE. **Solution:** Updated FormulaResult component to support multi-line text with proper rendering and font size calculation. **Usage:** ```excel =CONCATENATE("Total 1: ", value1, CHAR(10), "Total 2: ", value2, CHAR(10), "Total 3: ", value3) ``` **Result:** ``` Total 1: 100 Total 2: 200 Total 3: 300 ``` **Implementation:** - Added `whiteSpace: 'pre-wrap'` to preserve line breaks - Added `textAlign: 'center'` to keep multi-line text centered - Updated font size calculation to account for multiple lines (divides height by line count) - Calculates based on longest line length for proper sizing ### 4. **Formula Function Cleanup** 🧹 **Feedback:** User requested review of all formula functions to remove ones that don't make sense in Actual's context. **Problem:** Many Excel functions require cell ranges (like `A1:A10`) which don't exist in Actual. Actual uses named expressions like `QUERY("myQuery")` and transaction field variables like `amount` or `date`. **Solution:** Removed 27 unusable functions from autocomplete suggestions: **Removed Functions:** - **Range-based counting:** `AVERAGEA`, `COUNT`, `COUNTA`, `COUNTBLANK`, `COUNTIF`, `COUNTIFS` - *Use `QUERY_COUNT()` instead* - **Range-based aggregation:** `MAXA`, `MINA`, `SUMIF`, `SUMIFS`, `SUMPRODUCT`, `SUMSQ` - *Use `QUERY()` with filters instead* - **Statistical functions:** `MEDIAN`, `MODE`, `STDEV`, `STDEVP`, `VAR`, `VARP`, `PERCENTILE`, `QUARTILE`, `RANK` - *These require arrays of data which don't exist in our context* - **Lookup functions:** `VLOOKUP`, `HLOOKUP`, `INDEX`, `MATCH`, `LOOKUP` - *These require table arrays and cell references* - **Reference checking:** `ISREF` - *Checks for cell references which don't exist* **Kept Useful Functions:** - ✅ Math functions that work with individual values: `SUM`, `AVERAGE`, `MAX`, `MIN`, `ROUND`, etc. - ✅ Text functions: `CONCATENATE`, `UPPER`, `LEFT`, `RIGHT`, etc. - ✅ Date functions: `TODAY`, `YEAR`, `MONTH`, `EOMONTH`, etc. - ✅ Logical functions: `IF`, `AND`, `OR`, `IFERROR`, etc. - ✅ Query-specific functions: `QUERY`, `QUERY_COUNT`, `BUDGET_QUERY`, etc. - ✅ `CHOOSE` (works with index and individual values) **Impact:** Autocomplete suggestions are now more relevant and less confusing. Users won't see functions they can't actually use. ### 5. **Tooltip Quote Consistency Fix** **Feedback:** Tooltips used backticks around formula examples while actual usage used double quotes, causing confusion. **Solution:** Removed backticks from all formula examples in tooltips for consistency. Examples now show formulas as plain text without wrapping backticks. **Before:** `` `=UPPER(notes)` `` **After:** `=UPPER(notes)` ### 6. **Updated Documentation** - Added function definitions to `queryModeFunctions.ts` (for formula cards) - Added function definitions to `transactionModeFunctions.ts` (for formula rules) - Updated syntax highlighting to recognize new functions and removed obsolete ones - Updated descriptions to clarify that formatting functions use app settings by default ### 7. **Comprehensive Integration Tests** 🧪 Added **50 integration tests** that validate formulas with real database operations: #### Formula Rule Integration Tests (36 tests) Tests validate formula execution with actual transaction data: - ✅ Basic operations: FORMATCURRENCY, nested IFs, date formatting - ✅ Text manipulation: CONCATENATE, UPPER, LEFT, RIGHT, TRIM, PROPER - ✅ Math functions: ROUND, ABS, MAX, MIN, CEILING, SQRT, SUM, PRODUCT - ✅ Date functions: YEAR, MONTH, DAY, DAYS, EOMONTH, WEEKDAY - ✅ Logical functions: AND, OR, NOT, IFERROR, SWITCH - ✅ New formatting functions with various options - ✅ Multi-line output with CHAR(10) - ✅ Information functions: ISNUMBER, ISTEXT, ISEVEN, ISODD, ISBLANK - ✅ Error handling and type validation - ✅ Complex nested formulas (3-4 levels deep) #### Formula Card Integration Tests (14 tests) Tests validate formulas with real query results from database: - ✅ Single and multiple query integration - ✅ Query results with formatting functions - ✅ Percentage calculations across queries - ✅ Date-based query filtering - ✅ Complex nested calculations with multiple queries - ✅ Multi-line output with query results - ✅ Error handling with empty queries - ✅ Running totals across accounts - ✅ MAX/MIN operations with query results **Test Quality:** - Real database operations (not mocked) - Complex nested formulas demonstrating actual use cases - Every formula function type covered in at least one test - Edge cases tested (empty results, division by zero, type mismatches) - **All 662 tests passing** ✅ ## Technical Implementation ### Settings Architecture **Problem:** HyperFormula custom functions are synchronous, but preferences are stored in async database. **Solution:** - Created `loadUserPreferencesForFormulas()` async function that loads preferences once - Caches preferences globally for synchronous access by custom functions - Called on module initialization (avoids repeated DB queries) - No reactors needed - clean and efficient **Settings Priority:** 1. Explicit function parameters (if provided) 2. User's app settings (from preferences DB) 3. Locale-based defaults (inferred from language setting) This approach avoids unnecessary reactors while properly respecting user preferences! ## Feedbacks Not Addressed (with reasoning) ### BALANCEONDAY() Function **Feedback:** Request for a function to get account balance on a specific date for credit card statement calculations. **Reason not implemented:** This would require database access to query transaction history, which is not available in the formula execution context (both for formula cards and formula rules). The formula execution is designed to be stateless and work with the data provided in the context. Implementing this would require architectural changes to allow async database queries during formula execution. **Alternative approach:** Users can currently achieve this by creating a query with appropriate date filters and using `QUERY()` to get the sum of transactions up to that date. ### LASTSYNCEDBALANCE Variable **Feedback:** Request for access to `lastSyncedBalance` in custom pills/formulas. **Reason not implemented:** Similar to BALANCEONDAY, this would require access to account metadata that isn't available in the current formula execution context. The `balance_current` field is stored in the accounts table and would need to be passed as a variable to the formula execution context. **Alternative approach:** This could be added in a future enhancement by extending the variable context passed to formula execution to include account metadata when the formula is executed in an account-specific context. ### Dynamic "Last Month" Dropdown **Feedback:** Request for dynamic time selection like "last month" in the hamburger menu for time selections. **Reason not in this PR:** This is a UI/UX enhancement for the query time frame selector, not related to formula functions. This would be better addressed in a separate PR focused on the query configuration UI. ## Testing - ✅ All existing tests pass (604 tests) - ✅ New unit tests for FORMATNUMBER and FORMATCURRENCY (8 tests) - ✅ **New integration tests for formula rules (36 tests)** - ✅ **New integration tests for formula cards (14 tests)** - ✅ **Total: 662 tests passing** - ✅ Type checking passes - ✅ Linting passes ## Code Comments Throughout the code, I've added comments explaining which feedback triggered each change: ```typescript // Feedback: Users reported that TEXT() function doesn't properly format numbers with // thousands separators (e.g., TEXT(value, "$#,##0.00") doesn't work as expected). // This custom function provides proper number formatting with thousands separators. // User feedback: Should respect app's number format settings, with locale-based fallbacks ``` This makes it easy to trace each change back to the original user feedback. ## Related Issue Addresses feedback items from #5949 <!-- CURSOR_AGENT_PR_BODY_END --> <div><a href="https://cursor.com/agents/bc-bdd61858-e301-4195-b11e-7ba65d744223"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-web-light.png"><img alt="Open in Web" width="114" height="28" src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a>&nbsp;<a href="https://cursor.com/background-agent?bcId=bc-bdd61858-e301-4195-b11e-7ba65d744223"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img alt="Open in Cursor" width="131" height="28" src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a>&nbsp;</div> <!--- actual-bot-sections ---> <hr /> <!--- bundlestats-action-comment key:combined start ---> ### Bundle Stats Bundle | Files count | Total bundle size | % Changed ------ | ----------- | ----------------- | --------- desktop-client | 27 | 12.86 MB → 12.8 MB (-56.74 kB) | -0.43% loot-core | 1 | 4.84 MB → 4.85 MB (+5.67 kB) | +0.11% api | 1 | 3.84 MB → 3.84 MB (+5.52 kB) | +0.14% cli | 1 | 7.89 MB | 0% <details> <summary>View detailed bundle stats</summary> #### desktop-client **Total** Files count | Total bundle size | % Changed ----------- | ----------------- | --------- 27 | 12.86 MB → 12.8 MB (-56.74 kB) | -0.43% <details> <summary>Changeset (largest 100 files by percent change)</summary> File | Δ | Size ---- | - | ---- `node_modules/@jlongster/sql.js/dist/sql-wasm.js` | 🆕 +89.77 kB | 0 B → 89.77 kB `node_modules/google-protobuf/google-protobuf.js` | 🆕 +84.08 kB | 0 B → 84.08 kB `home/runner/work/actual/actual/packages/loot-core/src/server/aql/compiler.ts` | 🆕 +24.02 kB | 0 B → 24.02 kB `home/runner/work/actual/actual/packages/loot-core/src/server/db/index.ts` | 🆕 +18.96 kB | 0 B → 18.96 kB `node_modules/adm-zip/adm-zip.js` | 🆕 +17.31 kB | 0 B → 17.31 kB `home/runner/work/actual/actual/packages/crdt/src/proto/sync_pb.js` | 🆕 +16.73 kB | 0 B → 16.73 kB `home/runner/work/actual/actual/packages/loot-core/src/server/sync/index.ts` | 🆕 +12.48 kB | 0 B → 12.48 kB `node_modules/adm-zip/zipEntry.js` | 🆕 +10.41 kB | 0 B → 10.41 kB `home/runner/work/actual/actual/packages/loot-core/src/server/aql/schema/index.ts` | 🆕 +9.33 kB | 0 B → 9.33 kB `home/runner/work/actual/actual/packages/loot-core/src/server/budget/envelope.ts` | 🆕 +8.9 kB | 0 B → 8.9 kB `node_modules/adm-zip/zipFile.js` | 🆕 +8.81 kB | 0 B → 8.81 kB `node_modules/adm-zip/headers/entryHeader.js` | 🆕 +7.53 kB | 0 B → 7.53 kB `node_modules/adm-zip/util/utils.js` | 🆕 +7.13 kB | 0 B → 7.13 kB `home/runner/work/actual/actual/packages/loot-core/src/server/budget/report.ts` | 🆕 +6.72 kB | 0 B → 6.72 kB `home/runner/work/actual/actual/packages/loot-core/src/server/budget/base.ts` | 🆕 +6.48 kB | 0 B → 6.48 kB `home/runner/work/actual/actual/packages/loot-core/src/server/aql/schema/executors.ts` | 🆕 +6.14 kB | 0 B → 6.14 kB `home/runner/work/actual/actual/packages/crdt/src/crdt/timestamp.ts` | 🆕 +5.01 kB | 0 B → 5.01 kB `home/runner/work/actual/actual/packages/loot-core/src/server/aql/schema-helpers.ts` | 🆕 +3.87 kB | 0 B → 3.87 kB `node_modules/adm-zip/methods/zipcrypto.js` | 🆕 +3.14 kB | 0 B → 3.14 kB `home/runner/work/actual/actual/packages/loot-core/src/server/db/sort.ts` | 🆕 +2.89 kB | 0 B → 2.89 kB `node_modules/murmurhash/murmurhash.js` | 🆕 +2.86 kB | 0 B → 2.86 kB `home/runner/work/actual/actual/packages/loot-core/src/platform/server/sqlite/index.ts` | 🆕 +2.75 kB | 0 B → 2.75 kB `node_modules/adm-zip/headers/mainHeader.js` | 🆕 +2.75 kB | 0 B → 2.75 kB `home/runner/work/actual/actual/packages/loot-core/src/server/sync/encoder.ts` | 🆕 +2.7 kB | 0 B → 2.7 kB `home/runner/work/actual/actual/packages/loot-core/src/server/models.ts` | 🆕 +2.69 kB | 0 B → 2.69 kB `node_modules/adm-zip/util/errors.js` | 🆕 +2.47 kB | 0 B → 2.47 kB `home/runner/work/actual/actual/packages/loot-core/src/platform/server/fs/path-join.ts` | 🆕 +2.23 kB | 0 B → 2.23 kB `node_modules/adm-zip/util/constants.js` | 🆕 +1.91 kB | 0 B → 1.91 kB `home/runner/work/actual/actual/packages/crdt/src/crdt/merkle.ts` | 🆕 +1.91 kB | 0 B → 1.91 kB `home/runner/work/actual/actual/packages/loot-core/src/server/aql/exec.ts` | 🆕 +1.61 kB | 0 B → 1.61 kB `home/runner/work/actual/actual/packages/loot-core/src/server/sheet.ts` | 🆕 +1.56 kB | 0 B → 1.56 kB `home/runner/work/actual/actual/packages/loot-core/src/platform/server/fs/index.ts` | 🆕 +1.54 kB | 0 B → 1.54 kB `node_modules/adm-zip/util/fattr.js` | 🆕 +1.49 kB | 0 B → 1.49 kB `home/runner/work/actual/actual/packages/loot-core/src/server/app.ts` | 🆕 +1.22 kB | 0 B → 1.22 kB `home/runner/work/actual/actual/packages/loot-core/src/server/encryption/encryption-internals.ts` | 🆕 +1.2 kB | 0 B → 1.2 kB `node_modules/adm-zip/methods/inflater.js` | 🆕 +1019 B | 0 B → 1019 B `home/runner/work/actual/actual/packages/loot-core/src/platform/server/sqlite/unicodeLike.ts` | 🆕 +993 B | 0 B → 993 B `home/runner/work/actual/actual/packages/loot-core/src/server/post.ts` | 🆕 +991 B | 0 B → 991 B `node_modules/adm-zip/methods/deflater.js` | 🆕 +906 B | 0 B → 906 B `home/runner/work/actual/actual/packages/loot-core/src/server/undo.ts` | 🆕 +815 B | 0 B → 815 B `home/runner/work/actual/actual/packages/loot-core/src/server/prefs.ts` | 🆕 +682 B | 0 B → 682 B `home/runner/work/actual/actual/packages/loot-core/src/server/server-config.ts` | 🆕 +676 B | 0 B → 676 B `home/runner/work/actual/actual/packages/loot-core/src/server/mutators.ts` | 🆕 +524 B | 0 B → 524 B `node_modules/mitt/dist/mitt.mjs` | 🆕 +513 B | 0 B → 513 B `home/runner/work/actual/actual/packages/loot-core/src/platform/server/connection/index.ts` | 🆕 +512 B | 0 B → 512 B `home/runner/work/actual/actual/packages/loot-core/src/platform/server/fs/shared.ts` | 🆕 +498 B | 0 B → 498 B `home/runner/work/actual/actual/packages/loot-core/src/server/budget/util.ts` | 🆕 +403 B | 0 B → 403 B `home/runner/work/actual/actual/packages/loot-core/src/server/encryption/index.ts` | 🆕 +393 B | 0 B → 393 B `home/runner/work/actual/actual/packages/loot-core/src/platform/server/fetch/index.ts` | 🆕 +373 B | 0 B → 373 B `home/runner/work/actual/actual/packages/crdt/src/index.ts` | 🆕 +367 B | 0 B → 367 B `node_modules/adm-zip/util/index.js` | 🆕 +358 B | 0 B → 358 B `home/runner/work/actual/actual/packages/loot-core/src/server/sync/repair.ts` | 🆕 +340 B | 0 B → 340 B `node_modules/adm-zip/util/decoder.js` | 🆕 +273 B | 0 B → 273 B `node_modules/adm-zip/methods/index.js` | 🆕 +262 B | 0 B → 262 B `home/runner/work/actual/actual/packages/loot-core/src/server/spreadsheet/globals.ts` | 🆕 +262 B | 0 B → 262 B `home/runner/work/actual/actual/packages/loot-core/src/server/aql/index.ts` | 🆕 +258 B | 0 B → 258 B `node_modules/adm-zip/headers/index.js` | 🆕 +230 B | 0 B → 230 B `home/runner/work/actual/actual/packages/loot-core/src/server/db/util.ts` | 🆕 +195 B | 0 B → 195 B `home/runner/work/actual/actual/packages/loot-core/src/platform/server/sqlite/normalise.ts` | 🆕 +168 B | 0 B → 168 B `__vite-browser-external` | 🆕 +166 B | 0 B → 166 B `home/runner/work/actual/actual/packages/loot-core/src/server/main-app.ts` | 🆕 +149 B | 0 B → 149 B `home/runner/work/actual/actual/packages/loot-core/src/server/spreadsheet/util.ts` | 🆕 +133 B | 0 B → 133 B `home/runner/work/actual/actual/packages/loot-core/src/server/cloud-storage.ts` | 🆕 +129 B | 0 B → 129 B `node_modules/absurd-sql/dist/indexeddb-backend.js` | 🆕 +99 B | 0 B → 99 B `home/runner/work/actual/actual/packages/loot-core/src/server/rules/customFunctions.ts` | 📈 +5.48 kB (+522.63%) | 1.05 kB → 6.53 kB `home/runner/work/actual/actual/packages/loot-core/src/shared/async.ts` | 📈 +708 B (+270.23%) | 262 B → 970 B `home/runner/work/actual/actual/packages/loot-core/src/server/errors.ts` | 📈 +412 B (+214.58%) | 192 B → 604 B `home/runner/work/actual/actual/packages/loot-core/src/platform/server/asyncStorage/index.ts` | 📈 +706 B (+155.16%) | 455 B → 1.13 kB `home/runner/work/actual/actual/packages/loot-core/src/platform/server/indexeddb/index.ts` | 📈 +348 B (+25.87%) | 1.31 kB → 1.65 kB `home/runner/work/actual/actual/packages/loot-core/src/server/rules/action.ts` | 📈 +34 B (+12.41%) | 274 B → 308 B `src/components/formula/transactionModeFunctions.ts` | 📈 +1.05 kB (+7.71%) | 13.64 kB → 14.7 kB `src/components/reports/FormulaResult.tsx` | 📈 +231 B (+5.99%) | 3.76 kB → 3.99 kB `home/runner/work/actual/actual/packages/loot-core/src/shared/util.ts` | 📈 +417 B (+4.62%) | 8.82 kB → 9.23 kB `src/queries/aqlQuery.ts` | 📈 +4 B (+3.23%) | 124 B → 128 B `src/undo/index.ts` | 📈 +4 B (+0.73%) | 551 B → 555 B `src/tags/queries.ts` | 📈 +2 B (+0.64%) | 311 B → 313 B `node_modules/chevrotain/lib_esm/src/parse/grammar/first.js` | 📈 +8 B (+0.60%) | 1.29 kB → 1.3 kB `src/hooks/useMetadataPref.ts` | 📈 +2 B (+0.57%) | 352 B → 354 B `src/budget/mutations.ts` | 📈 +70 B (+0.55%) | 12.36 kB → 12.42 kB `src/reports/queries.ts` | 📈 +6 B (+0.54%) | 1.09 kB → 1.09 kB `home/runner/work/actual/actual/packages/loot-core/src/server/rules/handlebars-helpers.ts` | 📈 +12 B (+0.36%) | 3.25 kB → 3.26 kB `src/hooks/useTransactionBatchActions.ts` | 📈 +28 B (+0.31%) | 8.72 kB → 8.74 kB `src/transactions/queries.ts` | 📈 +2 B (+0.31%) | 647 B → 649 B `node_modules/handlebars/dist/cjs/handlebars/decorators/inline.js` | 📈 +2 B (+0.25%) | 789 B → 791 B `node_modules/moment/dist/moment.js` | 📈 +256 B (+0.22%) | 111.44 kB → 111.69 kB `src/components/ServerContext.tsx` | 📈 +12 B (+0.21%) | 5.67 kB → 5.68 kB `src/budget/queries.ts` | 📈 +2 B (+0.20%) | 1020 B → 1022 B `node_modules/handlebars/dist/cjs/handlebars/helpers/block-helper-missing.js` | 📈 +2 B (+0.19%) | 1.02 kB → 1.02 kB `src/hooks/useSpreadsheet.tsx` | 📈 +6 B (+0.19%) | 3.16 kB → 3.17 kB `node_modules/handlebars/dist/cjs/handlebars/logger.js` | 📈 +2 B (+0.18%) | 1.07 kB → 1.07 kB `home/runner/work/actual/actual/packages/loot-core/src/shared/schedules.ts` | 📈 +20 B (+0.18%) | 10.72 kB → 10.74 kB `node_modules/handlebars/dist/cjs/handlebars/helpers/with.js` | 📈 +2 B (+0.17%) | 1.14 kB → 1.14 kB `node_modules/handlebars/dist/cjs/handlebars/helpers/if.js` | 📈 +2 B (+0.17%) | 1.18 kB → 1.18 kB `node_modules/source-map/lib/mapping-list.js` | 📈 +2 B (+0.15%) | 1.27 kB → 1.27 kB `node_modules/handlebars/dist/cjs/handlebars.runtime.js` | 📈 +2 B (+0.13%) | 1.56 kB → 1.56 kB `src/components/transactions/TransactionList.tsx` | 📈 +18 B (+0.10%) | 17.13 kB → 17.15 kB `node_modules/source-map/lib/array-set.js` | 📈 +2 B (+0.10%) | 1.93 kB → 1.93 kB `node_modules/chevrotain/lib_esm/src/parse/grammar/follow.js` | 📈 +2 B (+0.10%) | 1.95 kB → 1.95 kB `node_modules/handlebars/dist/cjs/handlebars/helpers/each.js` | 📈 +2 B (+0.09%) | 2.22 kB → 2.22 kB `node_modules/handlebars/dist/cjs/handlebars/utils.js` | 📈 +2 B (+0.08%) | 2.33 kB → 2.33 kB </details> <details> <summary>View detailed bundle breakdown</summary> <div> **Added** No assets were added **Removed** No assets were removed **Bigger** Asset | File Size | % Changed ----- | --------- | --------- static/js/useTransactionBatchActions.js | 4.33 MB → 4.72 MB (+403.18 kB) | +9.09% static/js/ReportRouter.js | 1.17 MB → 1.17 MB (+231 B) | +0.02% **Smaller** Asset | File Size | % Changed ----- | --------- | --------- static/js/theme.js | 485.18 kB → 30.79 kB (-454.39 kB) | -93.65% static/js/FormulaEditor.js | 852.77 kB → 849.03 kB (-3.74 kB) | -0.44% static/js/index.js | 3.31 MB → 3.31 MB (-2.01 kB) | -0.06% **Unchanged** Asset | File Size | % Changed ----- | --------- | --------- static/js/BackgroundImage.js | 121.09 kB | 0% static/js/TransactionList.js | 82.49 kB | 0% static/js/ca.js | 191.98 kB | 0% static/js/da.js | 104.66 kB | 0% static/js/de.js | 174.38 kB | 0% static/js/en-GB.js | 8.2 kB | 0% static/js/en.js | 175.72 kB | 0% static/js/es.js | 181.8 kB | 0% static/js/fr.js | 177.08 kB | 0% static/js/indexeddb-main-thread-worker-e59fee74.js | 13.46 kB | 0% static/js/it.js | 165.87 kB | 0% static/js/narrow.js | 363.02 kB | 0% static/js/nb-NO.js | 151.85 kB | 0% static/js/nl.js | 108.93 kB | 0% static/js/pl.js | 88.34 kB | 0% static/js/pt-BR.js | 177.44 kB | 0% static/js/resize-observer.js | 18.06 kB | 0% static/js/th.js | 179.3 kB | 0% static/js/uk.js | 212.6 kB | 0% static/js/wide.js | 295 B | 0% static/js/workbox-window.prod.es5.js | 7.33 kB | 0% static/js/zh-Hans.js | 99.27 kB | 0% </div> </details> --- #### loot-core **Total** Files count | Total bundle size | % Changed ----------- | ----------------- | --------- 1 | 4.84 MB → 4.85 MB (+5.67 kB) | +0.11% <details> <summary>Changeset</summary> File | Δ | Size ---- | - | ---- `home/runner/work/actual/actual/packages/loot-core/src/server/rules/customFunctions.ts` | 📈 +5.63 kB (+525.32%) | 1.07 kB → 6.71 kB `home/runner/work/actual/actual/packages/loot-core/src/server/rules/action.ts` | 📈 +35 B (+0.44%) | 7.84 kB → 7.87 kB </details> <details> <summary>View detailed bundle breakdown</summary> <div> **Added** Asset | File Size | % Changed ----- | --------- | --------- kcab.worker.-abDimv-.js | 0 B → 4.85 MB (+4.85 MB) | - **Removed** Asset | File Size | % Changed ----- | --------- | --------- kcab.worker.2cr-I6dh.js | 4.84 MB → 0 B (-4.84 MB) | -100% **Bigger** No assets were bigger **Smaller** No assets were smaller **Unchanged** No assets were unchanged </div> </details> --- #### api **Total** Files count | Total bundle size | % Changed ----------- | ----------------- | --------- 1 | 3.84 MB → 3.84 MB (+5.52 kB) | +0.14% <details> <summary>Changeset</summary> File | Δ | Size ---- | - | ---- `home/runner/work/actual/actual/packages/loot-core/src/server/rules/customFunctions.ts` | 📈 +5.49 kB (+522.21%) | 1.05 kB → 6.54 kB `home/runner/work/actual/actual/packages/loot-core/src/server/rules/action.ts` | 📈 +34 B (+0.45%) | 7.39 kB → 7.42 kB </details> <details> <summary>View detailed bundle breakdown</summary> <div> **Added** No assets were added **Removed** No assets were removed **Bigger** Asset | File Size | % Changed ----- | --------- | --------- index.js | 3.84 MB → 3.84 MB (+5.52 kB) | +0.14% **Smaller** No assets were smaller **Unchanged** No assets were unchanged </div> </details> --- #### cli **Total** Files count | Total bundle size | % Changed ----------- | ----------------- | --------- 1 | 7.89 MB | 0% <details> <summary>View detailed bundle breakdown</summary> <div> **Added** No assets were added **Removed** No assets were removed **Bigger** No assets were bigger **Smaller** No assets were smaller **Unchanged** Asset | File Size | % Changed ----- | --------- | --------- cli.js | 7.89 MB | 0% </div> </details> </details> <!--- bundlestats-action-comment key:combined end ---> --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
GiteaMirror added the pull-request label 2026-04-21 00:22:23 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/actual#37370