-
Notifications
You must be signed in to change notification settings - Fork 8
feat(ash): UX overhaul — zoom keys, history pan/scrub, cursor crosshair, context-sensitive timeline #773
Description
Overview
Three related UX improvements to /ash that work together to make the TUI feel like a real monitoring tool rather than a read-only display.
1. Reassign zoom keys: [/] instead of ←/→
Current: ←/→ cycle zoom levels. This is the wrong mental model — left/right arrows should mean "move in time", not "change scale".
Change:
[= zoom out (wider time window)]= zoom in (narrower time window)←/→= pan/scrub through history (see below)
Footer hint updates accordingly: [/]:zoom ←→:pan
In Live mode, pressing ← auto-switches to History mode anchored at "now" and starts panning backward.
2. History pan/scrub with ←/→ + vertical cursor line
When in History mode (or after pressing ← from Live):
←/→shifts the time window backward/forward by one bucket width- A vertical cursor line
│is drawn at the "selected" column in the timeline - A floating infobox appears (bottom-right of timeline or replacing the drill-down hint area) showing the exact breakdown for that moment:
- Timestamp of the bucket
- AAS value
- Top wait types with counts and % share
- Color-coded to match bar colors
This is the keyboard equivalent of a Grafana hover tooltip — instant drill-in to any historical moment without leaving the timeline view.
State additions:
cursor_col: Option<usize>inAshState—None= no cursor,Some(col)= column index from rightpan_offset: i64— how many buckets we've shifted from "now"
3. Context-sensitive upper timeline on drill-down
Current: Drill into Lock in the bottom pane → top timeline still shows all wait types stacked. The two halves are disconnected.
Proposed: The timeline adapts to the current drill level:
| Drill level | Timeline shows |
|---|---|
| Top (WaitType) | All wait types stacked as today (unchanged) |
| WaitEvent { type } | Only that wait type's bars, broken down by individual wait events (Lock/relation, Lock/tuple, Lock/transactionid as separate colors) |
| QueryId { type, event } | Only that specific wait event's contribution; bars colored by query_id |
This makes the top and bottom halves a coherent unit — as you drill in, both panes zoom into the same slice of data.
Color handling: At WaitEvent level, use a deterministic hash of the event name to pick from the existing color palette. At QueryId level, same approach with query_id.
Implementation order
- Zoom key reassignment — purely a
state.rskeybinding change, no renderer touch. 1-2 hours. - History pan + cursor line — adds
cursor_col/pan_offsettoAshState, one renderer pass to draw│and infobox. ~half day. - Context-sensitive timeline — touches
renderer.rsbar-building logic to filter/recolor by drill level. ~1 day.
All three are independent of any other open PR.
Acceptance criteria
[/]change zoom level;←/→pan the time window- Pressing
←in Live mode transitions to History mode automatically - Vertical cursor line visible when panning; infobox shows bucket stats
- At WaitEvent drill level, timeline bars show individual events within that type
- At QueryId drill level, timeline bars show individual queries
- Footer hints stay accurate at each level
- All existing drill-down, zoom, legend, and exit behavior unchanged