Skip to content

feat: drag to select time histogram for the date filter (#356) - #357

Merged
timdegroot1996 merged 2 commits into
mainfrom
feat/356-date-histogram
Sep 25, 2026
Merged

timdegroot1996 merged 2 commits into
mainfrom
feat/356-date-histogram

Conversation

@timdegroot1996

Copy link
Copy Markdown
Collaborator

Fixes #356

What

The date range was four static inputs, which nobody uses to zoom in with: you cannot see where the runs are, so there is nothing to aim at. The filter modal now opens with a bar chart of the runs per time bucket above the range, the way Grafana and Kibana let you pick a period. The four date/time inputs moved below it into one horizontal row.

  • Drag across the bars → the inputs are filled and the chart zooms into the selection, re-bucketing finer, so dragging again drills further down (a month at a bar per day → a week at a bar per 6 hours → a day at a bar per hour).
  • Click one bar → that bucket. Reset Range → the full span, same as widening the inputs by hand.
  • Bars are runs per bucket, stacked by run status, with a separator at every bucket edge and a label every nth bar.
  • Hover → a block per run with the three status rows the run graphs show: how many tests passed, failed and were skipped.

The window is not state of its own: it is derived from the four inputs on every render, so filter profiles and the merge dialogue carry the zoom without knowing a chart exists, and the filter pipeline is untouched.

The bars follow every other filter (runs, tags, versions, metadata, custom filters, suite path) but not the date range itself, through a new "dates" facet of the existing apply_filters_except(). That is what makes widening possible: the runs outside the window come straight back. The amount filter is left out for the same reason it is left out of the option counts.

How

No new dependency. chartjs-plugin-zoom would have meant a CDN entry plus a local copy for --offlinedependencies, so instead:

  • the brush is pointer handling over the category scale (getValueForPixel gives the bucket index, so a selection always covers whole bars);
  • the bucket separators are drawn by a small inline plugin, because Chart.js only puts a gridline under a tick that carries a label, which turns a row of empty buckets into one wide gap;
  • the tooltip is an element rather than the Chart.js one, because a tooltip on the canvas is clipped by the chart and paints every line in a single colour — a block per run needs neither. It is styled after the Chart.js tooltip and lets the chart stay 160px tall.
  • day, week and month buckets advance by calendar field, so a DST switch does not shift every bucket after it by an hour.

Bug fixed along the way

Information popups flip above their icon when they would run off the bottom of the window, which still leaves the window when the icon is itself below the fold. The extra filter row made that reachable on the Suite Path row at 800px; they are now clamped to the window.

Notes

Two traps this codebase makes easy to hit, both cost a debugging round:

  • an element id is a property of window, so a chart may not be kept under the id of its canvas — window.dateHistogramGraph was the canvas, and .destroy() silently did not exist;
  • every module ends up in one script, so the new date parser could not be called parse_run_start: the one in common.js parses differently and the overview page broke on it. It is get_run_start_date() now.

No new CLI flag, setting, endpoint or stored state. Every existing element id is unchanged.

Tests

  • Robot 124/124 in Docker, 5 new tests in 06_filters (bars, drag-zoom, bar click, reset, following the other filters) plus 6 keywords.
  • JavaScript 352/352, 18 new: bucket unit picking, boundary alignment and DST, status split, and the tooltip content.
  • Python 406/406.

Checked against a generated 500-run dashboard (70 days, 5-10 runs a day, 41k tests): first render 4.6s, filter modal with histogram 0.85s, drag-zoom and re-bucket 0.55s.

Docs

docs/filtering.md sections 4 and 5, plus a line in README.md and setup.py.

🤖 Generated with Claude Code

timdegroot1996 and others added 2 commits September 26, 2026 01:18
The date range was four static inputs, which nobody uses to zoom in with:
you cannot see where the runs are, so there is nothing to aim at. The
filter modal now opens with a bar chart of the runs per time bucket above
the range, the way Grafana and Kibana let you pick a period, and the four
inputs sit below it as one horizontal row.

Dragging across the bars fills the inputs and zooms the chart into the
selection, re-bucketing finer, so dragging again drills further down.
Clicking one bar selects that bucket, Reset Range goes back to the full
span. The window is not state of its own: it is derived from the inputs on
every render, so filter profiles and the merge dialogue carry the zoom
without knowing that a chart exists.

The bars follow every other filter but not the date range itself, through
a new "dates" facet of apply_filters_except(), so widening the range
brings the runs outside the window straight back. Hovering a bar gives a
block per run with the three status rows the run graphs show.

No new dependency: Chart.js and the date-fns adapter are already bundled.
The brush is pointer handling over the category scale, the bucket
separators are drawn by a small inline plugin because Chart.js only puts a
gridline under a tick that carries a label, and the tooltip is an element
because the one on the canvas is clipped by the chart and paints every
line in a single colour.

Two things that bundling makes easy to get wrong and that cost a debug
round each: an element id is a property of window, so the chart may not be
kept under the id of its canvas, and every module ends up in one script,
so the new date parser could not be called parse_run_start - the one in
common.js parses differently and the overview page broke on it.

Also fixes the information popups. They flip above their icon when they
would run off the bottom of the window, which still leaves the window when
the icon is itself below the fold; the extra filter row made that
reachable. They are now clamped to the window.

Tests: 5 robot tests in 06_filters, 18 JavaScript tests.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@timdegroot1996
timdegroot1996 merged commit 0b41826 into main Sep 25, 2026
3 checks passed
@timdegroot1996 timdegroot1996 mentioned this pull request Sep 26, 2026
@timdegroot1996
timdegroot1996 deleted the feat/356-date-histogram branch September 26, 2026 15:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Improvement] Drag-to-select time histogram for the date filter, like Grafana and Kibana

1 participant