Improve loading display and stages #114

Closed
opened 2026-05-11 00:42:33 +00:00 by maxtkc · 0 comments
Owner

Summary

Right now the feedProgressIndicator top-bar only appears inside parseFile(), meaning there is a silent gap before it shows up:

  • URL path: fetch() + response.blob() can take several seconds on a large feed — the user sees nothing during this time.
  • File path: file.arrayBuffer() (can be slow on large files) runs before the indicator appears.

The fix is to call feedProgressIndicator.startLoading() earlier — at the start of parseFromURL for URL loads and at the start of parseFile for file loads — and to add clearly-labelled "Downloading feed..." and "Reading file..." stages before the existing "Clearing existing data..." stage. No streaming or real download-percentage is needed; indeterminate is fine for the download stage.

Relevant Context

File Relevant symbols
src/modules/gtfs-parser.ts parseFile() (line 556), parseFromURL() (line 660)
src/modules/feed-progress-indicator.ts FeedProgressIndicator, singleton feedProgressIndicator
src/modules/ui.ts loadGTFSFile() (line 254), loadGTFSFromURL() (line 392) — orchestrators that call into gtfs-parser

Current progress stages in parseFile:

% Message
(on startLoading) "Loading GTFS file..."
10 "Clearing existing data..."
20 "Extracting ZIP file..." (from worker)
20–80 "Processing {filename}..." (from worker, per file)
90 "Finalizing..." (from worker)
100 "Complete!"

Key invariant: feedProgressIndicator.startLoading(operation, ...) must be called before any updateProgress(operation, ...) — the indicator ignores updates for unknown operations. parseFile must not call startLoading again once the caller has already started it (that would reset the progress bar to 0).


Phase 1 — Add "Downloading feed..." stage to URL path

Goal: Make the indicator appear the moment loadGTFSFromURL is called, before the network request starts, so there is never a blank wait.

  • In parseFromURL (src/modules/gtfs-parser.ts), call feedProgressIndicator.startLoading(operation, 'Downloading feed...') at the very top (use the same operation = 'parseFile' key so it shares state with the subsequent parseFile call).
  • After response.blob() resolves, call feedProgressIndicator.updateProgress(operation, 5, 'Preparing...') to signal the download is done.
  • Because parseFromURL now starts the indicator, guard the startLoading call inside parseFile so it only fires when the indicator is not already active for that operation. Check feedProgressIndicator.isLoading() or pass an optional flag — simplest approach: add an optional alreadyStarted = false parameter to parseFile and have parseFromURL pass true.
  • Adjust the initial progress number in parseFile to start at 5 (instead of calling startLoading with 0 then immediately going to 10) when called from URL path, or just leave the "Clearing existing data..." call at 10 since the bar will jump from wherever the caller left it.

Gotcha: The operation string in parseFromURL must match the one used in parseFile ('parseFile') so finishLoading in parseFile's catch/finally correctly cleans up regardless of which path started the indicator.


Phase 2 — Add "Reading file..." stage to file-upload path

Goal: For direct file uploads, show the indicator before file.arrayBuffer() is called, so large files don't produce a blank wait either.

  • Move the feedProgressIndicator.startLoading(operation, 'Loading GTFS file...') call in parseFile to before the file.arrayBuffer() call — it already is before it, so this is just a status/label change.
  • After startLoading, update status to 'Reading file...' at progress 0 to clearly communicate the file-read stage.
  • After await file.arrayBuffer() resolves, update to 'Clearing existing data...' at progress 5 (or keep 10, adjust to taste).
  • Remove the redundant initial startLoading message "Loading GTFS file..." by merging it into the first updateProgress call, so the sequence is clean:
    • startLoading(operation, 'Reading file...') → progress 0
    • updateProgress(operation, 10, 'Clearing existing data...') → after arrayBuffer resolves
    • then worker stages as before (20–90)

Gotcha: When called from parseFromURL, startLoading is already active. The alreadyStarted flag from Phase 1 prevents parseFile from resetting the bar to 0 or calling startLoading again. In that path, skip directly to updateProgress(operation, 5, 'Clearing existing data...') after the arrayBuffer call.


Original Issue

The loading display right now is fine, but we should analyze the loading process and make sure that when we load a feed, we immediately show something. I think the issue is that we don't have a stage for actually downloading or uploading the feed. Lets analyze this process and see how we can improve it.

## Summary Right now the `feedProgressIndicator` top-bar only appears *inside* `parseFile()`, meaning there is a silent gap before it shows up: - **URL path**: `fetch()` + `response.blob()` can take several seconds on a large feed — the user sees nothing during this time. - **File path**: `file.arrayBuffer()` (can be slow on large files) runs before the indicator appears. The fix is to call `feedProgressIndicator.startLoading()` earlier — at the start of `parseFromURL` for URL loads and at the start of `parseFile` for file loads — and to add clearly-labelled "Downloading feed..." and "Reading file..." stages before the existing "Clearing existing data..." stage. No streaming or real download-percentage is needed; indeterminate is fine for the download stage. ## Relevant Context | File | Relevant symbols | |------|-----------------| | `src/modules/gtfs-parser.ts` | `parseFile()` (line 556), `parseFromURL()` (line 660) | | `src/modules/feed-progress-indicator.ts` | `FeedProgressIndicator`, singleton `feedProgressIndicator` | | `src/modules/ui.ts` | `loadGTFSFile()` (line 254), `loadGTFSFromURL()` (line 392) — orchestrators that call into gtfs-parser | **Current progress stages in `parseFile`:** | % | Message | |---|---------| | (on `startLoading`) | "Loading GTFS file..." | | 10 | "Clearing existing data..." | | 20 | "Extracting ZIP file..." (from worker) | | 20–80 | "Processing {filename}..." (from worker, per file) | | 90 | "Finalizing..." (from worker) | | 100 | "Complete!" | **Key invariant**: `feedProgressIndicator.startLoading(operation, ...)` must be called before any `updateProgress(operation, ...)` — the indicator ignores updates for unknown operations. `parseFile` must not call `startLoading` again once the caller has already started it (that would reset the progress bar to 0). --- ## Phase 1 — Add "Downloading feed..." stage to URL path **Goal**: Make the indicator appear the moment `loadGTFSFromURL` is called, before the network request starts, so there is never a blank wait. - [x] In `parseFromURL` (`src/modules/gtfs-parser.ts`), call `feedProgressIndicator.startLoading(operation, 'Downloading feed...')` at the very top (use the same `operation = 'parseFile'` key so it shares state with the subsequent `parseFile` call). - [x] After `response.blob()` resolves, call `feedProgressIndicator.updateProgress(operation, 5, 'Preparing...')` to signal the download is done. - [x] Because `parseFromURL` now starts the indicator, guard the `startLoading` call inside `parseFile` so it only fires when the indicator is not already active for that operation. Check `feedProgressIndicator.isLoading()` or pass an optional flag — simplest approach: add an optional `alreadyStarted = false` parameter to `parseFile` and have `parseFromURL` pass `true`. - [x] Adjust the initial progress number in `parseFile` to start at 5 (instead of calling `startLoading` with 0 then immediately going to 10) when called from URL path, or just leave the "Clearing existing data..." call at 10 since the bar will jump from wherever the caller left it. **Gotcha**: The `operation` string in `parseFromURL` must match the one used in `parseFile` (`'parseFile'`) so `finishLoading` in `parseFile`'s catch/finally correctly cleans up regardless of which path started the indicator. --- ## Phase 2 — Add "Reading file..." stage to file-upload path **Goal**: For direct file uploads, show the indicator before `file.arrayBuffer()` is called, so large files don't produce a blank wait either. - [x] Move the `feedProgressIndicator.startLoading(operation, 'Loading GTFS file...')` call in `parseFile` to *before* the `file.arrayBuffer()` call — it already is before it, so this is just a status/label change. - [x] After `startLoading`, update status to `'Reading file...'` at progress 0 to clearly communicate the file-read stage. - [x] After `await file.arrayBuffer()` resolves, update to `'Clearing existing data...'` at progress 5 (or keep 10, adjust to taste). - [x] Remove the redundant initial `startLoading` message "Loading GTFS file..." by merging it into the first `updateProgress` call, so the sequence is clean: - `startLoading(operation, 'Reading file...')` → progress 0 - `updateProgress(operation, 10, 'Clearing existing data...')` → after arrayBuffer resolves - then worker stages as before (20–90) **Gotcha**: When called from `parseFromURL`, `startLoading` is already active. The `alreadyStarted` flag from Phase 1 prevents `parseFile` from resetting the bar to 0 or calling `startLoading` again. In that path, skip directly to `updateProgress(operation, 5, 'Clearing existing data...')` after the arrayBuffer call. --- ## Original Issue The loading display right now is fine, but we should analyze the loading process and make sure that when we load a feed, we immediately show something. I think the issue is that we don't have a stage for actually downloading or uploading the feed. Lets analyze this process and see how we can improve it.
maxtkc self-assigned this 2026-05-11 00:42:33 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
gtfs.zone/coloring-book#114
No description provided.