CollapsibleSection.tsx and LogTimeline.tsx imported from each other
(TimeRange/TimeRangePresetId one way, sectionHeaderClassName the
other). Move the range types/helpers into a dependency-free
webapp/src/lib/timeRange.ts and repoint all importers there.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TeyhRfMYjMditek6geDRoQ
A rate() series over a metric whose occurrences are confined to a short
burst within a much wider queried range (e.g. sum by (code)
(rate(KeyPressed[5m])) against a ~10h log where all key presses happen
in the first 10s) rendered as broken: the line simply stopped at the
last real occurrence, and the chart's x-axis auto-scaled to the tiny
span of actual data points rather than the queried range, silently
narrowing a 10-hour view down to ~10 seconds with no indication anything
was off.
Backend (src/engine.rs): windowed_rate_series now appends a synthetic
boundary point at start_ms/end_ms (computed via the existing
rate::rate_at against the original occurrence points, so a boundary
inside a still-warm window gets its true partial value rather than a
hardcoded 0) whenever the real series doesn't already reach that edge.
Wired into both the bare rate() and sum()/avg(rate()) evaluate_promql
branches, which already had start_ms/end_ms in scope.
Frontend (PanelChart.tsx/Dashboards.tsx): the line chart's XAxis now
uses an explicit numeric domain pinned to the panel's queried range
(passed down from Dashboards.tsx's PanelPreview) instead of recharts'
default auto-scale-to-data-extent, so sparse data can no longer make
the axis look narrower than what was actually queried.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o
Every built-in theme now exposes three accents (--c-accent/-2/-3) instead
of one, so PanelChart's series palette draws distinct colours per theme
via color-mix() rather than a fixed, theme-independent hex list. Existing
presets keep their current base surface/border/text/accent look — the two
new accent vars are purely additive. Adds a new "Light Green" scheme
(light-surfaced, same green/magenta hue family as "Green") selectable
alongside the existing built-ins, both in ColorScheme (frontend + backend)
and the settings picker.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o
PanelChart's BarChart and PieChart rendered one bar/slice and legend
row per PromqlSeries with no bound, so panels with many series wrapped
the 8-color palette (repeating colors) and produced unreadable,
unbounded legends. Add squashRows(), which sorts by value descending
and collapses series beyond COLORS.length - 1 into a single "Other"
bucket (sum of the rest), applied to both bar and pie chart data before
render. Panels at or below the threshold are unaffected.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o
Pass over src/*.rs, webapp/src/**, and the in-app "?" docs prose:
condensed multi-paragraph doc comments to single lines that state the
non-obvious why, deleted comments that only restated adjacent code, and
tightened the Docs.tsx help-panel wording. No logic, structure, or code
formatting changed — verified via cargo test (143 passed) and
tsc -b && vite build.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o
Backend: replace Profile.dashboards' opaque JSON stub with typed
Dashboard/Panel structs, add ProfileStore CRUD (create/save/list/delete
dashboard) and matching /api/settings/profiles/:name/dashboards[/:id] routes,
with tests covering the HTTP round trip and persistence across a simulated
restart.
Frontend: add recharts (lightweight, React 19-compatible) and a Dashboards
component with a dashboard builder (create dashboards, add/remove/edit panels
with a PromQL query + chart type), live per-panel previews that respect the
active time range and show malformed-query errors inline instead of crashing,
and load/save wired to the new profile-backed persistence.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o