Skip to content

feat(ash): UX overhaul — zoom keys, history pan/scrub, cursor crosshair, context-sensitive timeline #773

@NikolayS

Description

@NikolayS

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> in AshStateNone = no cursor, Some(col) = column index from right
  • pan_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

  1. Zoom key reassignment — purely a state.rs keybinding change, no renderer touch. 1-2 hours.
  2. History pan + cursor line — adds cursor_col/pan_offset to AshState, one renderer pass to draw and infobox. ~half day.
  3. Context-sensitive timeline — touches renderer.rs bar-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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions