feat(plugins): add Wise plugin with multi-currency account grouping - #8
feat(plugins): add Wise plugin with multi-currency account grouping#8CWZMorro wants to merge 6 commits into
Conversation
- Parses full "16 May 2026" / "11 March 2025" dates directly, no year
inference that caused March 2025 transactions to land in 2026
- Skips cancelled transactions via status element check
- "To CAD"-style conversions emit two transactions: a deposit for the
received currency and a withdrawal for the source currency
- Supports both /home and /all-transactions pages
…rate accounts Wise now returns TransactionGroup[] keyed by currency (e.g. "Wise CAD", "Wise MYR"). App.tsx renders one table per group, each with its own export button. Other plugins return Transaction[] and are auto-wrapped into a single group with no UI change. CSV download flattens all groups.
… only When Wise auto-converts a purchase (e.g. paying 18 CNY from an MYR balance), only the MYR deduction is recorded. The CNY merchant amount is kept in the notes field for reference but no longer creates a phantom CNY withdrawal.
There was a problem hiding this comment.
Pull request overview
Adds a new Wise scraper plugin and extends the transaction model to support multiple named account groups (e.g., per-currency Wise balances), enabling per-group export to ActualBudget while keeping CSV export as a flattened list.
Changes:
- Added
Wiseplugin that scrapes/all-transactionswith a/homefallback and groups transactions by currency. - Introduced
TransactionGroupand migrated the frontend storage/UI to usetransactionStore.groups(auto-wrapping single-group plugins). - Updated export flow to stage only a selected group’s transactions via
exportGroupin Chrome storage, and updated CSV export to flatten groups.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/plugins/src/Wise.ts | New Wise scraper that returns multiple currency-based transaction groups. |
| packages/plugins/src/index.ts | Exports the new Wise plugin from the plugins package. |
| packages/frontend/src/config.ts | Registers Wise plugin and broadens scrape return type to allow grouped results. |
| packages/frontend/src/components/EmptyState/EmptyState.tsx | Adds Wise to the supported plugin list shown in the empty state. |
| packages/frontend/src/components/ActionButtons/SyncAccountsButton.tsx | Makes export per-group by writing exportGroup before opening ActualBudget. |
| packages/frontend/src/components/ActionButtons/DownloadCsvButton.tsx | Flattens grouped transactions before CSV export. |
| packages/frontend/src/components/ActionButtons/ActionButtons.tsx | Removes global export button (now per-group in App.tsx), leaving only CSV. |
| packages/frontend/src/App.tsx | Adapts UI/storage to grouped transactions and renders per-group tables + export buttons. |
| packages/core/src/types/openbanker.ts | Adds TransactionGroup, changes TransactionList to groups, adds exportGroup in storage type. |
| packages/chrome/src/background.ts | Exports CSV from either exportGroup (preferred) or flattened transactionStore.groups, then clears exportGroup. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…up type, storage error guard, dead ButtonGroup
james-yap
left a comment
There was a problem hiding this comment.
Code Review
Overall this is a clean, well-structured feature. The TransactionGroup abstraction is solid and the Wise plugin handles a lot of date format edge cases nicely. Two issues need addressing before merge — see inline comments.
🔴 Warnings (should fix)
- Wise.ts — Negative amount regex may silently drop withdrawal transactions
- background.ts —
exportGroupcleanup is fire-and-forget with no error handling
💡 Suggestions (non-blocking)
- App.tsx — Duck-typing for group detection is fragile long-term
- Wise.ts — Transactions with unparseable dates are still added (empty date string)
- Wise.ts — Silent
catch (_) {}on base64 decode swallows errors
✅ Looks Good
- NGPF
/gflag removal is a correct bugfix (stateful regex reuse bug) - Write-then-open sequencing in
SyncAccountsButtonis properly async - Per-group CSV fallback logic in
background.tsis clean - Date parsing covers a solid range of Wise format variants
Reviewed by Hermes Agent
Inline notes
const cleaned = rawText.replace(/^[+\-]\s*/, '').trim();Then derive
chrome.storage[CHROME_STORAGE_STRATEGY].remove("exportGroup");No callback / await. If the service worker is terminated before it completes, stale await chrome.storage[CHROME_STORAGE_STRATEGY].remove("exportGroup");
if (Array.isArray(raw) && raw.length > 0 && 'account' in raw[0])Works today, but breaks silently if
Reviewed by Hermes Agent |
…Amount, await exportGroup cleanup
|
|
||
| }, []); | ||
|
|
||
| const hasData = transactionStore.pluginName !== ""; |

Summary
Test plan