Add real-time polling to dashboard#272
Conversation
The dashboard previously required a manual page reload to see updated run statuses and new step attempts. This adds a `usePolling` hook that calls `router.invalidate()` on a 2s interval to re-run active route loaders, giving the UI live updates with zero new dependencies. Polling pauses when the browser tab is hidden and resumes (with an immediate refresh) when it becomes visible again. On the run detail page, polling is disabled once the run reaches a terminal state.
There was a problem hiding this comment.
Pull request overview
Adds automatic, real-time data refresh to the dashboard by introducing a reusable polling hook that periodically re-invalidates TanStack Router loaders, with run-detail polling disabled once a run finishes.
Changes:
- Introduces a
usePollinghook that callsrouter.invalidate()on an interval and reacts to tab visibility changes. - Enables polling on the home dashboard route and conditionally on the run detail route (disabled for terminal run statuses).
- Adds a shared
TERMINAL_RUN_STATUSESset typed againstWorkflowRunStatus, plus unit tests for the polling hook.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/dashboard/src/routes/runs/$runId.tsx | Uses polling on run details until the run reaches a terminal status. |
| packages/dashboard/src/routes/index.tsx | Enables polling on the dashboard home route. |
| packages/dashboard/src/lib/use-polling.ts | New hook implementing interval-based router invalidation + visibility handling. |
| packages/dashboard/src/lib/use-polling.test.ts | Adds unit tests for polling interval/enablement/visibility/unmount behavior. |
| packages/dashboard/src/lib/status.ts | Adds TERMINAL_RUN_STATUSES constant for terminal workflow run states. |
| } | ||
| } | ||
|
|
||
| start(); |
There was a problem hiding this comment.
Polling is started unconditionally on mount (start()), so if the page is initially loaded while the tab is hidden (document.hidden === true), it will continue polling until the tab becomes visible (and may never stop if it stays hidden). To match the intended behavior (“polling pauses when the browser tab is hidden”), initialize based on the current visibility state (e.g., call handleVisibilityChange() on mount, or guard start() with if (!document.hidden)). Add a test covering the initially-hidden mount case.
| start(); | |
| if (!document.hidden) { | |
| start(); | |
| } |
|
|
||
| it("calls router.invalidate on the default interval", () => { | ||
| renderHook(() => { | ||
| usePolling() |
There was a problem hiding this comment.
This new test file doesn’t appear to be formatted according to the repo’s Prettier settings (e.g., missing semicolons and long single-line statements). Since CI runs prettier --check ., please run the formatter (e.g., npm run format:fix) and ensure the file matches Prettier output.
| usePolling() | |
| usePolling(); |
Guard start() with a document.hidden check so polling does not begin when the page loads in a background tab. Add a test covering the initially-hidden mount case. Co-authored-by: Cursor <cursoragent@cursor.com>
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
The dashboard currently fetches data once during route loading and never refreshes. Users must manually reload the page to see updated run statuses and new step attempts.
This adds a
usePollinghook that callsrouter.invalidate()on a configurable interval (default 2s) to re-run active TanStack Router loaders. No new dependencies — just the existing router API.TERMINAL_RUN_STATUSESconstant typed againstWorkflowRunStatus