Files
actual/packages/desktop-client/package.json
tabedzkiGitHubClaude Sonnet 4.6coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
6519bbecb6 [AI] feat(budget analysis report): export csv feature (#8163)
* [AI] feat(budget-report): add CSV export for budget analysis report

Add an 'Export CSV' button that downloads a CSV file containing Month,
Budgeted, Spent, Overspending Adjustment, and Balance columns for the
currently displayed date range.

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

* [AI] feat(budget-report): replace CSV export button with download icon

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

* [AI] refactor(csv-export): centralize CSV utility to loot-core with formula injection protection

Extracts CSV field escaping and row building into a shared
loot-core/shared/csv.ts module so desktop-client and cli packages can
reuse it without duplication. Adds single-quote prefix guard against
spreadsheet formula injection for values starting with =, +, -, @, tab,
or carriage-return.

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

* [AI] fix(csv-export): fix loot-core import path and remove over-broad formula injection protection for negative numbers

* fix: added in release note

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

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

* Update BudgetAnalysis.tsx

removed extra </Tooltip> introduced by coderabbitai

* fix: applied coderabbitai's suggestions for this PR

* [autofix.ci] apply automated fixes

* [AI] fix: resolve typecheck errors and test failures in csv export

- Make labels param optional with English defaults in buildBudgetAnalysisCsv
- Pass translated labels from BudgetAnalysis component call site
- Fix escapeCsvField: remove tab from quote-wrapping check (formula prefix handles it)

Assisted-by: ClaudeCode:claude-sonnet-4-6

* [AI] refactor(budget-analysis-export): use csv-stringify, move labels inside buildBudgetAnalysisCsv

- Replace custom buildCsv with csv-stringify/sync (already used in loot-core)
- Move translated column labels inside buildBudgetAnalysisCsv; callers no longer pass labels
- Pass numbers directly to csv-stringify instead of converting with toFixed(2)
- Add csv-stringify to desktop-client package.json deps
- Fix release notes title to user-facing prose

Assisted-by: ClaudeCode:claude-sonnet-4-6

* [AI] fix: remove orphaned csv.ts, fix release note wording

- Delete loot-core/src/shared/csv.ts and csv.test.ts (orphaned after switch to csv-stringify)
- Remove [AI] prefix from release note body (commit-style prefix inappropriate in release note content)

Assisted-by: ClaudeCode:claude-sonnet-4-6

* [AI] fix: add csv-stringify to yarn.lock to fix immutable install

The rebase onto main reset yarn.lock without the csv-stringify entry under the @actual-app/web workspace, while package.json still declared it. CI runs yarn install --immutable, which refused to reconcile the mismatch and failed the build.

Assisted-by: ClaudeCode:claude-opus-4.8

* attempt to resolve the hanging error

* [AI] fix: restore Tooltip import dropped during rebase

Resolving the import-collision conflict against master accidentally dropped
the Tooltip import used by the CSV export button. Restore it.

Assisted-by: ClaudeCode:claude-opus-4.8

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-07-06 20:19:20 +00:00

212 lines
10 KiB
JSON

{
"name": "@actual-app/web",
"version": "26.7.0",
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/actualbudget/actual.git",
"directory": "packages/desktop-client"
},
"files": [
"build"
],
"imports": {
"#browser-preload": {
"electron-renderer": "./src/browser-preload.electron.ts",
"default": "./src/browser-preload.js"
},
"#accounts": "./src/accounts/index.ts",
"#budget": "./src/budget/index.ts",
"#payees": "./src/payees/index.ts",
"#queries": "./src/queries/index.ts",
"#redux": "./src/redux/index.ts",
"#reports": "./src/reports/index.ts",
"#spreadsheet": "./src/spreadsheet/index.ts",
"#style": "./src/style/index.ts",
"#tags": "./src/tags/index.ts",
"#transactions": "./src/transactions/index.ts",
"#undo": "./src/undo/index.ts",
"#global-events": "./src/global-events.ts",
"#enablebanking": "./src/enablebanking.ts",
"#gocardless": "./src/gocardless.ts",
"#i18n": "./src/i18n.ts",
"#mocks": "./src/mocks.tsx",
"#mocks/*": "./src/mocks/*.ts",
"#components/forms": "./src/components/forms/index.tsx",
"#components/banksync": "./src/components/banksync/index.tsx",
"#components/banksync/bankSyncUtils": "./src/components/banksync/bankSyncUtils.ts",
"#components/banksync/BuiltInProviders": "./src/components/banksync/BuiltInProviders.tsx",
"#components/banksync/useBuiltInBankSyncProviders": "./src/components/banksync/useBuiltInBankSyncProviders.ts",
"#components/banksync/useBankSyncAccountSettings": "./src/components/banksync/useBankSyncAccountSettings.ts",
"#components/budget": "./src/components/budget/index.tsx",
"#components/budget/goals/actions": "./src/components/budget/goals/actions.ts",
"#components/budget/goals/automationExamples": "./src/components/budget/goals/automationExamples.ts",
"#components/budget/goals/cleanupModel": "./src/components/budget/goals/cleanupModel.ts",
"#components/budget/goals/constants": "./src/components/budget/goals/constants.ts",
"#components/budget/goals/displayTemplateMeta": "./src/components/budget/goals/displayTemplateMeta.ts",
"#components/budget/goals/editor/fieldLayout": "./src/components/budget/goals/editor/fieldLayout.ts",
"#components/budget/goals/formatMonthLabel": "./src/components/budget/goals/formatMonthLabel.ts",
"#components/budget/goals/reducer": "./src/components/budget/goals/reducer.ts",
"#components/budget/goals/useBudgetAutomationCategories": "./src/components/budget/goals/useBudgetAutomationCategories.ts",
"#components/budget/goals/validateAutomation": "./src/components/budget/goals/validateAutomation.ts",
"#components/budget/util": "./src/components/budget/util.ts",
"#components/codemirror/autocompleteTabAccept": "./src/components/codemirror/autocompleteTabAccept.ts",
"#components/formula/queryTimeFrame": "./src/components/formula/queryTimeFrame.ts",
"#components/mobile/utils": "./src/components/mobile/utils.ts",
"#components/modals/BudgetAutomationsModal/migrateTemplatesToAutomations": "./src/components/modals/BudgetAutomationsModal/migrateTemplatesToAutomations.ts",
"#components/reports/chart-theme": "./src/components/reports/chart-theme.ts",
"#components/reports/constants": "./src/components/reports/constants.ts",
"#components/reports/disabledList": "./src/components/reports/disabledList.ts",
"#components/reports/getCustomTick": "./src/components/reports/getCustomTick.ts",
"#components/reports/getLiveRange": "./src/components/reports/getLiveRange.ts",
"#components/reports/graphs/showActivity": "./src/components/reports/graphs/showActivity.ts",
"#components/reports/graphs/util/computePadding": "./src/components/reports/graphs/util/computePadding.ts",
"#components/reports/numberFormatter": "./src/components/reports/numberFormatter.ts",
"#components/reports/ReportOptions": "./src/components/reports/ReportOptions.ts",
"#components/reports/reportRanges": "./src/components/reports/reportRanges.ts",
"#components/reports/setSessionReport": "./src/components/reports/setSessionReport.ts",
"#components/reports/spendingAverageRange": "./src/components/reports/spendingAverageRange.ts",
"#components/reports/spreadsheets/cash-flow-spreadsheet": "./src/components/reports/spreadsheets/cash-flow-spreadsheet.tsx",
"#components/reports/spreadsheets/*": "./src/components/reports/spreadsheets/*.ts",
"#components/reports/useDashboardWidgetCopyMenu": "./src/components/reports/useDashboardWidgetCopyMenu.ts",
"#components/reports/useReport": "./src/components/reports/useReport.ts",
"#components/reports/util": "./src/components/reports/util.ts",
"#components/schedules": "./src/components/schedules/index.tsx",
"#components/schedules/schedule-edit-utils": "./src/components/schedules/schedule-edit-utils.ts",
"#components/transactions/table/utils": "./src/components/transactions/table/utils.ts",
"#components/util/accountValidation": "./src/components/util/accountValidation.ts",
"#components/util/countries": "./src/components/util/countries.ts",
"#components/util/localeToCountry": "./src/components/util/localeToCountry.ts",
"#components/*": "./src/components/*.tsx",
"#hooks/useCachedSchedules": "./src/hooks/useCachedSchedules.tsx",
"#hooks/useDisplayPayee": "./src/hooks/useDisplayPayee.tsx",
"#hooks/useDragDrop": "./src/hooks/useDragDrop.tsx",
"#hooks/useProperFocus": "./src/hooks/useProperFocus.tsx",
"#hooks/useScrollListener": "./src/hooks/useScrollListener.tsx",
"#hooks/useSelected": "./src/hooks/useSelected.tsx",
"#hooks/useSheetName": "./src/hooks/useSheetName.tsx",
"#hooks/useSingleActiveEditForm": "./src/hooks/useSingleActiveEditForm.tsx",
"#hooks/useSplitsExpanded": "./src/hooks/useSplitsExpanded.tsx",
"#hooks/useSpreadsheet": "./src/hooks/useSpreadsheet.tsx",
"#hooks/*": "./src/hooks/*.ts",
"#auth/AuthProvider": "./src/auth/AuthProvider.tsx",
"#auth/ProtectedRoute": "./src/auth/ProtectedRoute.tsx",
"#auth/*": "./src/auth/*.ts",
"#contextmenu/*": "./src/contextmenu/*.ts",
"#style/theme": "./src/style/theme.tsx",
"#style/*": "./src/style/*.ts",
"#notes/*": "./src/notes/*.tsx",
"#accounts/*": "./src/accounts/*.ts",
"#app/*": "./src/app/*.ts",
"#budget/*": "./src/budget/*.ts",
"#budgetfiles/*": "./src/budgetfiles/*.ts",
"#modals/*": "./src/modals/*.ts",
"#notifications/*": "./src/notifications/*.ts",
"#payees/*": "./src/payees/*.ts",
"#prefs/*": "./src/prefs/*.ts",
"#queries/*": "./src/queries/*.ts",
"#redux/*": "./src/redux/*.ts",
"#reports/*": "./src/reports/*.ts",
"#spreadsheet/*": "./src/spreadsheet/*.ts",
"#tags/*": "./src/tags/*.ts",
"#transactions/*": "./src/transactions/*.ts",
"#undo/*": "./src/undo/*.ts",
"#users/*": "./src/users/*.ts",
"#util/*": "./src/util/*.ts"
},
"scripts": {
"start": "cross-env PORT=3001 vite",
"start:browser": "cross-env ./bin/watch-browser",
"watch": "cross-env BROWSER=none yarn start",
"build": "vite build",
"build:browser": "vite build --mode=browser",
"generate:i18n": "i18next",
"test": "vitest --run",
"validate:theme-catalog": "node --experimental-strip-types bin/validate-theme-catalog.mts",
"e2e": "npx playwright test --browser=chromium",
"vrt": "cross-env VRT=true npx playwright test --browser=chromium",
"playwright": "playwright",
"typecheck": "tsgo -b && tsc-strict"
},
"devDependencies": {
"@actual-app/components": "workspace:*",
"@actual-app/core": "workspace:*",
"@babel/core": "^7.29.7",
"@codemirror/autocomplete": "^6.20.3",
"@codemirror/language": "^6.12.3",
"@codemirror/state": "^6.6.0",
"@codemirror/view": "^6.43.1",
"@emotion/css": "^11.13.5",
"@fontsource-variable/inter": "^5.2.8",
"@fontsource/redacted-script": "^5.2.8",
"@lezer/highlight": "^1.2.3",
"@playwright/test": "1.59.1",
"@react-aria/interactions": "^3.28.1",
"@reduxjs/toolkit": "^2.12.0",
"@rolldown/plugin-babel": "~0.2.3",
"@rollup/plugin-inject": "^5.0.5",
"@tanstack/react-query": "^5.101.0",
"@testing-library/dom": "10.4.1",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "16.3.2",
"@testing-library/user-event": "14.6.1",
"@types/pikaday": "^1.7.10",
"@types/react": "^19.2.17",
"@types/react-dom": "^19.2.3",
"@typescript/native-preview": "beta",
"@uiw/react-codemirror": "^4.25.10",
"@use-gesture/react": "^10.3.1",
"@vitejs/plugin-basic-ssl": "^2.3.0",
"@vitejs/plugin-react": "^6.0.2",
"auto-text-size": "^0.2.3",
"babel-plugin-react-compiler": "^1.0.0",
"cmdk": "^1.1.1",
"cross-env": "^10.1.0",
"csv-stringify": "^6.7.0",
"date-fns": "^4.4.0",
"downshift": "9.3.6",
"es-toolkit": "^1.47.1",
"fzf": "^0.5.2",
"html-to-image": "^1.11.13",
"hyperformula": "^3.3.0",
"i18next": "^26.3.1",
"i18next-parser": "^9.4.0",
"i18next-resources-to-backend": "^1.2.1",
"jsdom": "^29.1.1",
"lru-cache": "^11.5.1",
"mdast-util-newline-to-break": "^2.0.0",
"pikaday": "1.8.2",
"plugins-service": "workspace:*",
"re-resizable": "^6.11.2",
"react": "19.2.7",
"react-aria": "^3.49.0",
"react-aria-components": "^1.18.0",
"react-dnd": "^16.0.1",
"react-dnd-html5-backend": "^16.0.1",
"react-dom": "19.2.7",
"react-error-boundary": "^6.1.2",
"react-grid-layout": "^2.2.3",
"react-hotkeys-hook": "^5.3.2",
"react-i18next": "^17.0.8",
"react-markdown": "^10.1.0",
"react-redux": "^9.3.0",
"react-router": "7.17.0",
"react-simple-pull-to-refresh": "^1.3.4",
"react-spring": "^10.0.4",
"react-swipeable": "^7.0.2",
"react-virtualized-auto-sizer": "^2.0.3",
"recharts": "^3.8.1",
"rehype-external-links": "^3.0.0",
"remark-gfm": "^4.0.1",
"rolldown": "^1.1.1",
"rollup-plugin-visualizer": "^7.0.1",
"sass": "^1.101.0",
"typescript-strict-plugin": "^2.4.4",
"usehooks-ts": "^3.1.1",
"uuid": "^14.0.1",
"vite": "^8.0.16",
"vite-plugin-pwa": "^1.3.0",
"vitest": "^4.1.8"
}
}