Conversation
Replaces the axios-based export path with fetch() to fix two stacked issues that cause large exports (500k+ events) to silently no-op on Android and desktop: 1. The server serializes all events to a temp file before sending the first byte. For 500k events this can exceed the 30 s axios default timeout, so the request fails silently with no user feedback. 2. JSON.stringify(response.data, null, 2) re-serializes already-valid JSON in the browser JS heap, doubling peak memory use. The fetch-based path: - Reads the response as text (no JS parse + re-stringify) - Uses a 5-minute AbortController timeout instead of 30 s - Shows a spinner and disables the button while the export runs - Displays a user-visible error alert on failure (no more silent drop) The server-side fix (stream headers before full serialization) is still needed for very large datasets; this raises the practical cap and makes failures visible until that lands. Closes ActivityWatch/aw-android#228 (partial) Git-Session-Id: b1c3
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #993 +/- ##
==========================================
+ Coverage 57.62% 57.66% +0.03%
==========================================
Files 51 51
Lines 3219 3231 +12
Branches 751 794 +43
==========================================
+ Hits 1855 1863 +8
+ Misses 1348 1291 -57
- Partials 16 77 +61 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
fetch() dropped the axios Authorization header (Greptile P1) and a single exporting flag raced concurrent clicks (P2). Use the existing axios client with responseType blob and timeout 0 so the token is sent, skip JSON.parse/pretty-print, count in-flight exports, and hand the URL to Android.exportFromUrl when the WebView bridge is present. ActivityWatch/aw-android#228 Git-Session-Id: a180614b-5a5a-5d29-84d8-e1c4e076b990
|
CI-green and mergeable — waiting only on a maintainer click. This PR is ready to merge, but the bot has pull-only access to this repo and can't self-merge — surfacing it here so it isn't lost. The monitoring loop will stop re-flagging it now that this note is posted. |
|
@greptileai review |
timeout: 0 disabled Axios's timeout, so a stalled export never settled and export_inflight never decremented. Keep the authenticated blob request, but cap it at 300s so the spinner and button recover. ActivityWatch#993 Git-Session-Id: b7e9049b-1299-57f7-8f4a-3c161bf846ab
|
@greptileai review |
timeout: 0 was added for the Tauri fallback path but the existing test (added in ActivityWatch#993) explicitly verifies no timeout: 0 remains. The server-side CSV streaming endpoint is fast to start (headers sent before serialization), so 5 minutes matches the large-event-JSON path and is sufficient. Git-Session-Id: 70d5
* feat(buckets): use server-side CSV export endpoint
Replace the client-side PapaParse approach with a direct request to the
new server endpoint GET /api/0/buckets/{id}/export/csv.
In a regular browser (including Android WebView), an anchor navigation
is used so the browser handles the download natively — no events ever
enter JS memory and headers arrive immediately, fixing the apparent hung
connection on large buckets.
In Tauri (where <a download> is not supported), the CSV text is fetched
via the API client and saved through the native file dialog.
Removes the papaparse import from this file.
Git-Session-Id: cdc6
* fix(buckets): use 300s timeout for Tauri CSV export, not infinite
timeout: 0 was added for the Tauri fallback path but the existing test
(added in #993) explicitly verifies no timeout: 0 remains. The server-side
CSV streaming endpoint is fast to start (headers sent before serialization),
so 5 minutes matches the large-event-JSON path and is sufficient.
Git-Session-Id: 70d5
* fix(buckets): authenticate CSV export and surface download errors
The browser path used a bare <a> navigation, which drops Authorization
and cannot report 4xx/network failures. Use the same path as JSON
export: Android native URL download, then an authenticated blob GET
with the 5-minute timeout. downloadBlob still handles Tauri.
Git-Session-Id: d11ab6e2-235d-55ab-8e68-e80e65a02e47
* fix(buckets): stream unauthenticated browser CSV downloads
Restore <a> navigation for local installs so the server-side CSV
endpoint can stream. Keep the authenticated blob path for Tauri and
Bearer-token deployments, which cannot attach Authorization to a
navigation download.
Git-Session-Id: 92d2be57-41cd-59e0-8f80-fc2b1a31d6af
Problem
Large all-bucket exports (500k+ events) silently no-op on Android and desktop.
Two stacked root causes:
Server buffers before responding —
aw-server-rustserializes all events to a temp file before sending the first HTTP byte (even after perf(export): serialize HTTP exports with bounded event buffering aw-server-rust#677). For 500k events on a phone, serialization can take 30+ seconds, which silently exceeds axios's default timeout. No error is shown to the user.JS double-serialization —
JSON.stringify(response.data, null, 2)re-parses and re-stringifies an already-valid JSON response in the browser heap, doubling peak memory use for large exports.Reported and confirmed on 0.14.2b4: ActivityWatch/aw-android#228
Fix
Keep the authenticated axios client, skip JSON parse/pretty-print:
responseType: 'blob'+timeout: 300_000(5-minute cap, not the 30s default, no JS object graph)export_inflightcounter)Android.exportFromUrlwhen the native bridge is presentFollow-up 3f26892 keeps
Authorization: Bearer(Greptile P1) and counts in-flight exports (P2). 2005bb6 restores a finite 5-minute timeout so a stalled export cannot leave the spinner stuck. The originalfetch()path is gone.What this doesn't fix
The server-side streaming issue (stream headers before full serialization) is still needed for very large datasets and very slow phones. ActivityWatch/aw-server-rust#721 covers that. This PR raises the practical timeout cap and makes failures visible until that lands.
Testing