Fix regex help icon click-toggle and add PromQL by()/sum(rate()) grouping

RegexHelpIcon previously used a single `open` boolean driven by both hover
and click, so clicking to pin the popover open was undone by the next
mouseleave. Split into separate `pinned` (click) and `hovering` (mouse-over)
states so a click-toggle actually persists until clicked again.

The seeded `log_category` dashboard's line panel plotted the bare metric
name, since `sum()`/`rate()` always collapsed all label combinations into
one series and PromQL syntax had no way to preserve a label dimension
through an aggregation. Added `by (label, ...)` grouping and nested
`sum(rate(metric[range]))`/`avg(rate(...))` parsing, and made `rate()`
compute a real windowed time series instead of a single trailing point, so
a query like `sum(rate(log_category[1m])) by (category)` now renders one
line per category.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o
This commit is contained in:
Hugh Kaznowski
2026-09-05 20:17:50 +01:00
co-authored by Claude Sonnet 5
parent d6b7f7dfb6
commit 5aa7c1bae9
4 changed files with 330 additions and 34 deletions
+6 -4
View File
@@ -236,7 +236,7 @@ fn seeded_default_dashboard() -> Dashboard {
Panel {
id: generate_id("error-volume-line"),
title: "Error vs. non-error volume".to_string(),
promql: SEEDED_METRIC_NAME.to_string(),
promql: format!("sum(rate({SEEDED_METRIC_NAME}[1m])) by ({SEEDED_METRIC_LABEL})"),
chart_type: ChartType::Line,
},
Panel {
@@ -793,9 +793,11 @@ mod tests {
assert_eq!(default_profile.dashboards.len(), 1);
let dashboard = &default_profile.dashboards[0];
assert_eq!(dashboard.panels.len(), 2);
assert!(dashboard.panels.iter().all(|p| p.promql == SEEDED_METRIC_NAME));
assert!(dashboard.panels.iter().any(|p| p.chart_type == ChartType::Line));
assert!(dashboard.panels.iter().any(|p| p.chart_type == ChartType::Pie));
assert!(dashboard
.panels
.iter()
.any(|p| p.chart_type == ChartType::Line && p.promql.contains(SEEDED_METRIC_NAME)));
assert!(dashboard.panels.iter().any(|p| p.chart_type == ChartType::Pie && p.promql == SEEDED_METRIC_NAME));
// Reload (simulating a restart) and ensure_default again: must not re-seed or duplicate.
let mut store = ProfileStore::load(&store_path);