feat: Stream the transactions spreadsheet and speed up reports#92
Conversation
Code Review SummaryThe PR introduces significant performance improvements for both the transactions spreadsheet and reports. It transitions from sequential to concurrent fetching and optimizes data processing for charts. It also adds a robust CSV export feature and sortable columns. 🚀 Key Improvements
💡 Minor Suggestions
|
| const searchInput = ref(''); | ||
| const search = ref(''); | ||
|
|
||
| let searchTimer: ReturnType<typeof setTimeout> | null = null; |
There was a problem hiding this comment.
The debouncing logic uses a local variable searchTimer. This could lead to memory leaks or multiple timers if the component re-renders frequently or if the watch is triggered rapidly. It is safer to use a ref for the timer or a utility like useDebounce from VueUse.
| let searchTimer: ReturnType<typeof setTimeout> | null = null; | |
| const searchTimer = ref<ReturnType<typeof setTimeout> | null>(null); | |
| watch(searchInput, (value) => { | |
| if (searchTimer.value) clearTimeout(searchTimer.value); | |
| searchTimer.value = setTimeout(() => { | |
| search.value = value; | |
| }, 200); | |
| }); |
| const queue: number[] = []; | ||
| for (let p = 2; p <= targetPages; p++) queue.push(p); | ||
|
|
||
| let cursor = 0; |
There was a problem hiding this comment.
Concurrency control: The worker pattern here is good, but cursor++ is not atomic in a multi-threaded environment. While JS is single-threaded, if fetchPage contained an await before the increment, it could cause issues. It's fine here because of JS event loop, but a cleaner pattern is queue.shift().
| let cursor = 0; | |
| const worker = async () => { | |
| while (queue.length > 0) { | |
| const p = queue.shift()!; | |
| const resp = await fetchPage(p); | |
| pages[p - 1] = resp.data || []; | |
| } | |
| }; |
Reports now load noticeably faster and no longer hide charts while data is still arriving. - Report transaction pages are fetched concurrently instead of one at a time, so wide date ranges render much sooner. - Per-category spending trends are built in a single pass rather than rescanning every transaction once per category. - The charts and other report tabs stay visible whenever chart data exists, with a loading state instead of a flash of the empty screen. - A notice appears when a period has more transactions than can be charted at once, so partial figures are not mistaken for complete ones. - Amounts that could not be converted to the default currency are now flagged, so cross-currency totals are no longer silently understated. The transactions spreadsheet streams rows in chunks: the first rows and running totals appear immediately and grow as the rest load. Columns can be sorted, the current view can be exported to a CSV file, and search is debounced so typing stays smooth on large sets.
b37e2e6 to
0238442
Compare
Deploying webui with
|
| Latest commit: |
0238442
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://5b6e29ad.webui-9fh.pages.dev |
| Branch Preview URL: | https://feat-issue-88-followups.webui-9fh.pages.dev |
Performance and UX follow-ups from issue #88, focused on making reports and the transactions spreadsheet fast and reliable.
Reports performance
Reports correctness
Transactions spreadsheet
Backend test coverage for the currency behavior is in a companion PR on trakli/webservice.
Refs #88