Draft
Conversation
The Runs page now polls for status updates on the rows currently on
screen, and surfaces a "< new (n) >" button when newer runs have
arrived. Polls every 2s, on focus, and on visibility change. Uses
straight polling via `useAutoRevalidate`; no SSE.
To keep visible rows stable across polls, page 1 now pins an anchor:
an upper-bound `run_id` stored in `?anchor=…` in the URL. Pagination
and filters compose with the anchor naturally -- the cursor is the
page boundary, the anchor is "as of when I started looking." First
load resolves the anchor server-side from the newest row in the
response, then the client replaces the URL to add it (no history
entry, no scroll reset). Filter changes drop both anchor and cursor
so a stale anchor never silently excludes matching rows.
The "< new (n) >" button counts runs newer than the anchor under the
exact same filter set, capped at 99 ("99+" past the cap). Three
states distinguished by `newCount`:
- positive integer -> known count, badge shown.
- 0 -> confirmed empty, button hidden.
- null -> unknown (deep-linked URL with cursor but no anchor).
Button still shown without a badge so the user has the escape hatch
back to a fresh page 1.
If the user paginates forward and then clicks Previous all the way
back to the most-recent page within the anchor window, the anchor
resets automatically (presenter reports `atFreshestEdge`, the route
strips cursor/direction/anchor on next render). They land on the
truly newest data instead of being pinned to the original snapshot.
Architecture:
- `anchor: z.string().optional()` added to `RunListInputOptionsSchema`
and threaded through `clickhouseRunsRepository.listRunIds` as a
`run_id <= {anchor}` predicate that composes with the existing
cursor predicates. No change to the existing pagination semantics.
- `countRunsNewerThan` on the runs repository (ClickHouse-only, same
filter pipeline as the list query, LIMIT cap+1 to bound cost).
- `NextRunListPresenter` resolves a default anchor from `runs[0].id`
when none is supplied on a fresh page 1, runs the count when an
anchor exists, and returns `anchor`, `newCount`, `atFreshestEdge`
alongside the existing payload.
- `ListPagination` extended with a third button that mirrors
Prev/Next exactly -- LinkButton with a `to=` href, not a
Button-with-onClick -- so middle-click, prefetching, and
shortcut-key handling work identically. Shortcut: `n`.
- New consts in `apps/webapp/app/consts.ts`:
`RUNS_LIST_POLL_INTERVAL_MS = 2000`, `NEW_RUNS_BADGE_CAP = 99`.
What didn't change:
- Loader stays non-deferred (no `<Suspense>` for the runs table).
Initial-load UX is the Remix default: previous page during nav,
browser loading on hard refresh.
- The list query itself -- count is a separate query, run
sequentially after the list. If it shows up in p95 we can
Promise.all it.
- No new endpoints; the loader returns everything in one round trip.
--- prior commit ---
Runs page now updates visible rows.
Every ~1.5s, refresh the status of the rows currently on screen on the Runs
page (`/orgs/:org/projects/:project/env/:env/runs`) without changing which
rows are shown.
1.5s is perhaps a bit aggressive.
This adds an anchor so we know the most recent run_id, which will help
us implement a < new (n) > button later (we count things more recent
than this).
This changes the RunListInputOptionsSchema, and
TaskRunListSearchFilters, and downstream stuff.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The Runs page now polls for status updates on the rows currently on screen, and surfaces a "< new (n) >" button when newer runs have arrived. Polls every 2s, on focus, and on visibility change. Uses straight polling via
useAutoRevalidate; no SSE.To keep visible rows stable across polls, page 1 now pins an anchor: an upper-bound
run_idstored in?anchor=…in the URL. Pagination and filters compose with the anchor naturally -- the cursor is the page boundary, the anchor is "as of when I started looking." First load resolves the anchor server-side from the newest row in the response, then the client replaces the URL to add it (no history entry, no scroll reset). Filter changes drop both anchor and cursor so a stale anchor never silently excludes matching rows.The "< new (n) >" button counts runs newer than the anchor under the exact same filter set, capped at 99 ("99+" past the cap). Three states distinguished by
newCount:If the user paginates forward and then clicks Previous all the way back to the most-recent page within the anchor window, the anchor resets automatically (presenter reports
atFreshestEdge, the route strips cursor/direction/anchor on next render). They land on the truly newest data instead of being pinned to the original snapshot.Architecture:
anchor: z.string().optional()added toRunListInputOptionsSchemaand threaded throughclickhouseRunsRepository.listRunIdsas arun_id <= {anchor}predicate that composes with the existing cursor predicates. No change to the existing pagination semantics.countRunsNewerThanon the runs repository (ClickHouse-only, same filter pipeline as the list query, LIMIT cap+1 to bound cost).NextRunListPresenterresolves a default anchor fromruns[0].idwhen none is supplied on a fresh page 1, runs the count when an anchor exists, and returnsanchor,newCount,atFreshestEdgealongside the existing payload.ListPaginationextended with a third button that mirrors Prev/Next exactly -- LinkButton with ato=href, not a Button-with-onClick -- so middle-click, prefetching, and shortcut-key handling work identically. Shortcut:n.apps/webapp/app/consts.ts:RUNS_LIST_POLL_INTERVAL_MS = 2000,NEW_RUNS_BADGE_CAP = 99.What didn't change:
<Suspense>for the runs table). Initial-load UX is the Remix default: previous page during nav, browser loading on hard refresh.--- prior commit ---
Runs page now updates visible rows.
Every ~1.5s, refresh the status of the rows currently on screen on the Runs page (
/orgs/:org/projects/:project/env/:env/runs) without changing which rows are shown.1.5s is perhaps a bit aggressive.
This adds an anchor so we know the most recent run_id, which will help us implement a < new (n) > button later (we count things more recent than this).
This changes the RunListInputOptionsSchema, and
TaskRunListSearchFilters, and downstream stuff.
Closes #
✅ Checklist
Testing
[Describe the steps you took to test this change]
Changelog
[Short description of what has changed]
Screenshots
[Screenshots]
💯