Skip to content

OP#10281: Add the browser progressbar for long operations - #838

Merged
randy-seng merged 9 commits into
mainfrom
task/10281-show-progress-of-long-operations-in-the-web-ui
Sep 21, 2026
Merged

randy-seng merged 9 commits into
mainfrom
task/10281-show-progress-of-long-operations-in-the-web-ui

Conversation

@randy-seng

@randy-seng randy-seng commented Sep 7, 2026 •

Copy link
Copy Markdown
Member

What this does

Correction (scope). This PR delivers the progress model and the widget, not the wiring. No production caller builds a progressbar on this branch: LoadTrackFiles and Datastore take a ProgressbarBuilder and never call it, and the only self._progressbar(...) call site reachable from the web UI (PandasTrackProvider._convert_tracks) is skipped because the default dataset is Polars. Loading tracks in the browser still shows nothing until #840 (OP#10282) adds ProgressbarBuilder.start() and calls it from LoadTrackFiles. Struck-through text below overclaims and is kept for the record.

Long operations in the web UI showed nothing. OtAnalyticsNiceGuiApplicationStarter still wired TqdmBuilder, so progress for loading tracks or running analysis went what progress reporting exists goes to the console the browser user never sees. This branch adds NiceguiProgressbar, a persistent dialog showing item counts, a determinate bar, the last completed item, and a cancel button, and points progressbar_builder at NiceguiProgressbarBuilder. The CLI keeps tqdm.

Why

Progress belongs to the application layer, the widget to the UI, so the state is split: ProgressState in OTAnalytics/application/progress.py owns description, fraction, message, and finished, driven by the existing Counter abstraction; NiceguiProgressbar only renders it. Driving the bar by Counter rather than by iteration position matters because completions from concurrent work do not arrive in sequence order — hence complete(item) alongside the iterator path in __call__.

Cancellation is deliberately a plain flag, not asyncio.Task.cancel(). The work being cancelled is a synchronous loop over a sequence — parsing tracks, calculating events — which never yields control while it runs. There is no moment at which something from outside could interrupt it, so the only way to stop it is for the loop itself to check a flag between items. Making that work asynchronous purely to gain an interruption point would mean reshaping the operations themselves, which is far more than showing a progressbar is worth. The asyncio.Event inside is for the other side: it lets the UI await cancellation instead of polling for it.

Notes for the reviewer

Start with NiceguiProgressbar.open() in plugin_ui/nicegui_gui/nicegui/progressbar.py:74. Two early returns carry real behaviour rather than defensiveness:

  • context.client.is_auto_index_client — during --config preload at startup there is no browser client, and building a dialog then raises. Progress is still tracked; only the rendering is skipped.
  • self._state.finished — an empty operation would otherwise open a dialog nothing can ever close, because only a progress update reaches _refresh and closes it.

_refresh closing the dialog on finished is the only close path besides cancel; if a caller reports fewer completions than total, the dialog stays open. That is the persistent prop's cost and the reason the cancel button exists.

NiceguiProgressbarBuilder.progressbar exposing the most recent bar is a seam for the concurrent-loading work, not used yet.

Risk and rollout

Nothing outside the NiceGUI starter changes; plugin_progress.tqdm_progressbar.TqdmBuilder is untouched and still used by the CLI (guarded by a new test). Worst case in the browser is a dialog that stays open after work finishes — visible immediately, and revertible by restoring the single line in nicegui_application.py:241. Since nothing builds a progressbar yet, browser behaviour is unchanged by this PR; the dialog-stays-open risk becomes real with #840 and is revertible by restoring the single line in nicegui_application.py:241.

Cancellation has no consumer in this branch beyond the cancel button setting it; pressing cancel closes the dialog but does not yet stop the running operation.

Testing

uv run pytest on the four new/changed test modules: 27 passed. Covers counts and current item, cancel setting the signal, auto-close at completion, the builder's iterator path, empty sequences, replacing a previous bar, and both no-browser cases.

Still to verify by hand: an actual track load in the browser — a track load shows nothing on this branch, so that check belongs on #840. Worth verifying here: that --config preload startup is unaffected.

Follow-ups

#840 (OP#10282) wires the progressbar into LoadTrackFiles and moves parsing off the event loop.

Wire Cancellation into the operations themselves so cancel aborts the work, not just the dialog.

OP#10281

@randy-seng
randy-seng force-pushed the task/10281-show-progress-of-long-operations-in-the-web-ui branch from 43dd659 to aca9ce5 Compare September 7, 2026 20:46
@randy-seng
randy-seng force-pushed the task/10281-show-progress-of-long-operations-in-the-web-ui branch from aca9ce5 to 1fe3737 Compare September 9, 2026 21:50
@randy-seng
randy-seng force-pushed the task/10281-show-progress-of-long-operations-in-the-web-ui branch from 1fe3737 to bf995c9 Compare September 9, 2026 22:22
@randy-seng
randy-seng force-pushed the task/10281-show-progress-of-long-operations-in-the-web-ui branch from bf995c9 to 268e006 Compare September 14, 2026 13:50
@randy-seng
randy-seng requested a review from schubsen September 14, 2026 18:14
@randy-seng
randy-seng force-pushed the task/10281-show-progress-of-long-operations-in-the-web-ui branch from 9da1afa to 0af04d3 Compare September 16, 2026 11:42
@randy-seng
randy-seng force-pushed the task/10281-show-progress-of-long-operations-in-the-web-ui branch from 0af04d3 to f6374c3 Compare September 16, 2026 14:06
@randy-seng randy-seng self-assigned this Sep 16, 2026
Base automatically changed from task/10280-make-the-source-of-tracks-and-videos-interchangeable to main September 16, 2026 16:34
@randy-seng
randy-seng force-pushed the task/10281-show-progress-of-long-operations-in-the-web-ui branch from f6374c3 to 1939274 Compare September 16, 2026 16:34
@randy-seng randy-seng changed the title Task/10281 show progress of long operations in the web UI OP#10281: Add the browser progressbar for long operations Sep 17, 2026
Comment thread OTAnalytics/application/progress.py Outdated
Comment thread OTAnalytics/application/progress.py Outdated
@randy-seng
randy-seng requested a review from schubsen September 21, 2026 11:39
@randy-seng
randy-seng merged commit 3d54c4e into main Sep 21, 2026
15 checks passed
@randy-seng
randy-seng deleted the task/10281-show-progress-of-long-operations-in-the-web-ui branch September 21, 2026 12:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants