Timeline: scales, graduations, tooltip, colors, live updates and zoom

The histogram above the list becomes a configurable timeline:

- Scale linear / sqrt (default) / log, height S/M/L, bars or area.
- Colors: stacked by severity (error+, warning, the rest), intensity
  against the median of the window (calm, burst >3x, anomaly >10x), or
  none; colors are CSS variables with light and dark values.
- Vertical graduations on round local times (hh:mm:ss, hh:mm, dd/mm).
- Tooltip: interval bounds, total and detail per severity.
- Division automatic (~100 intervals) or fixed (1 s to 1 day), capped at
  300 intervals by the server; intervals aligned on the local time zone.
- Refresh off / 5 s / 15 s / 30 s / 1 min / at each new interval. In
  live mode the last interval is incremented from the SSE stream and the
  timeline reloads at each new interval; paused while the tab is hidden.
- Click a bar to zoom on its interval, drag to zoom on a selection: the
  list, export and counters follow through new from/to parameters.

The timeline now runs on the server clock (bounds and "now" come from
/api/histogram): the axis was drawn from the browser clock and refreshed
every 30 s only, so a clock difference with the server or a hidden tab
left it behind the logs.

/api/histogram returns interval indexes with the count per severity; the
division logic lives in histogram.go with table-driven tests.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
cedricandClaude Opus 5.5 committed 2026-10-01 20:23:18 +02:00
1 parent 32593b9515
commit ebf6340ff0
8 files changed
+1119 -86

No files matched your search

+34 -1
View File
@@ -90,7 +90,7 @@
</div>
</section>
<section id="histo" class="histo" data-i18n-aria="histoAria"></section>
<section id="histo" class="histo" data-i18n-aria="histoAria" hidden></section>
<div id="error" class="error-banner" hidden></div>
<button id="newPill" class="pill" type="button" hidden></button>
@@ -249,6 +249,39 @@
<div id="fontPreview" class="list preview-list" aria-hidden="true"></div>
<p class="muted small" data-i18n="fontHelp"></p>
</section>
<section class="set-section">
<h3 data-i18n="histoTitle">Timeline</h3>
<div class="field-grid">
<span class="lbl" data-i18n="hScale">Scale</span>
<div class="seg" role="radiogroup" data-histo="scale" data-i18n-aria="hScale">
<button type="button" role="radio" data-v="linear" data-i18n="hLinear">Linear</button>
<button type="button" role="radio" data-v="sqrt">√</button>
<button type="button" role="radio" data-v="log">Log</button>
</div>
<span class="lbl" data-i18n="hHeight">Height</span>
<div class="seg" role="radiogroup" data-histo="height" data-i18n-aria="hHeight">
<button type="button" role="radio" data-v="s">S</button>
<button type="button" role="radio" data-v="m">M</button>
<button type="button" role="radio" data-v="l">L</button>
</div>
<span class="lbl" data-i18n="hColor">Color</span>
<div class="seg" role="radiogroup" data-histo="color" data-i18n-aria="hColor">
<button type="button" role="radio" data-v="severity" data-i18n="hColSeverity">Severity</button>
<button type="button" role="radio" data-v="intensity" data-i18n="hColIntensity">Intensity</button>
<button type="button" role="radio" data-v="none" data-i18n="hColNone">None</button>
</div>
<span class="lbl" data-i18n="hRender">Display</span>
<div class="seg" role="radiogroup" data-histo="render" data-i18n-aria="hRender">
<button type="button" role="radio" data-v="bars" data-i18n="hBars">Bars</button>
<button type="button" role="radio" data-v="area" data-i18n="hArea">Area</button>
</div>
<label for="histoStep" data-i18n="hStep">Division</label>
<select id="histoStep" class="field" data-histo="step"></select>
<label for="histoRefresh" data-i18n="hRefresh">Refresh</label>
<select id="histoRefresh" class="field" data-histo="refresh"></select>
</div>
<p class="muted small" data-i18n="histoHelp"></p>
</section>
</div>
<!-- Data -->