feat(results): progressive loading — fix Running…null, add Cancel (Esc + KILL QUERY)#15
Merged
Merged
Conversation
…Esc + KILL QUERY) Three fixes to how a slow/long query (repro: `select sleep(3)`) is shown, aligned to the design handoff §6b-running. 1. "Running…null" bug: setRunBtn passed `null` as a replaceChildren arg while running, and replaceChildren coerces null → a "null" text node (unlike the h() helper which skips it). Filter the array before replaceChildren. 2. Cancel a long query: a Cancel button in the results toolbar (replaces Copy/Export while running, red on hover) plus a global Esc handler. Cancel aborts the stream AND issues `KILL QUERY WHERE query_id=…` so the server stops too (best-effort; swallows errors). The Run button is just a disabled "Running…". On cancel the partial rows are kept and the result is flagged cancelled (not an error) → a red "Cancelled · partial" badge, Copy/Export re-enabled. 3. Progressive loading visuals: while running the results toolbar shows live accent counters — elapsed ms (ticking off a 100ms interval, so it advances even for row-less queries like sleep), rows-read, bytes-scanned — and the body shows a 2px streaming strip (determinate fill at read/total, else an indeterminate sweep) with a "Starting query…" spinner before the first batch. Partial rows stream into the table as they arrive. - core/stream.js: newResult adds `cancelled`. - net/ch-client.js: query_id on the run URL; killQuery(). - ui/app.js: setRunBtn null fix, run() (query_id + ms tick + cancelled), cancel(). - ui/shortcuts.js: Esc → cancel while running. - ui/results.js: running toolbar (live counters + Cancel), streaming strip, "Starting query…", cancelled badge. - ui/icons.js, styles.css: spinner icon + spin/runsweep animations and states. Tests cover all of it (gate green); verified live on otel with select sleep(3): button reads "Running…" with no null, live counters + Cancel + sweep strip appear, and Esc cancels → "Cancelled · partial". Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QennTvGKAtJZrv9EpQagef
…ws ~16s → ~0.5s) The streaming Table query was sent with wait_end_of_query=1, which buffers the entire response server-side and sends it only after the query finishes — so "progressive" loading wasn't progressive: on SELECT * FROM a 1.3M-row table the first rows appeared at ~16s. Measured against the same query with the flag off, the first block arrives at ~0.5s (~600 rows). Keep wait_end_of_query=1 only for the raw (TSV/JSON) modes — those read the whole body anyway, so they lose nothing and keep a clean HTTP error status. The streaming path drops it and already surfaces mid-stream errors via the in-band `exception` line (applyStreamLine), so error handling is unchanged. Verified live on otel: SELECT * FROM claude_otel.otel_logs now paints its first ~630 rows at ~473ms (was ~13–16s). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QennTvGKAtJZrv9EpQagef
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.
Better visualization of slow/long-query loading, aligned to the design handoff §6b-running. Repro for all three:
select sleep(3).1. "Running…null" bug
The Run button rendered
Running…null.setRunBtncalledreplaceChildren(Icon.play(), span, running ? null : kbd)— while running the third arg isnull, andreplaceChildren(unlike theh()helper, which skips null children) coercesnullinto a"null"text node. Fixed by filtering the array beforereplaceChildren.2. Cancel a long query
KILL QUERY WHERE query_id=…(aquery_idis now tagged on the run request) so ClickHouse stops server-side work too. Best-effort — swallows errors (e.g. missing privilege) so cancel never throws.cancelled(not an error) → a red "Cancelled · partial" badge, with Copy/Export re-enabled.3. Progressive loading visuals
sleep), rows read, bytes scanned.read/total, else an indeterminate sweep) and a "Starting query…" spinner before the first batch. Partial rows stream into the table as they arrive (no blocking spinner).Files
core/stream.js(cancelled flag) ·net/ch-client.js(query_id +killQuery) ·ui/app.js(null fix,run()query_id/ms-tick/cancelled,cancel()) ·ui/shortcuts.js(Esc→cancel) ·ui/results.js(running toolbar, strip, badge) ·ui/icons.js+styles.css(spinner + animations).Tests & verification
npm testgreen, per-file gate held (stream/ch-client/icons/shortcuts at 100; results branches ≥90; app.js ≥95/≥90). New tests:setRunBtnno-null,cancel()abort+KILL,tickElapsed,killQuerySQL, Esc→cancel, streaming/"Starting query…"/cancelled-badge render.Verified live on otel (
select sleep(3)): button reads "Running…" (nonull); toolbar shows ticking ms + spinner + rows/bytes + Cancel · Esc; sweep strip; Esc cancels mid-run → "Cancelled · partial", Copy/Export back. Deployed to otel + antalya.🤖 Generated with Claude Code
https://claude.ai/code/session_01QennTvGKAtJZrv9EpQagef