feat(prometheus-direct-charting): slice 1 — prom range query + chart rebrand

Add PrometheusWidgetSource._fetch_chart hitting /api/v1/query_range directly
(SC-101..104). New shared helpers in widgets/prometheus_range.py:
step_for_window (window preset -> step, ~200pts) and normalize_prometheus_matrix
(extracted label/dedup rule, retargeted at Prom matrix, robust to malformed
data). Chart widget kind moved grafana->prometheus in both registries;
GrafanaChartWidget renamed -> PrometheusChartWidget (git mv, recharts body
preserved). Grafana binding/service untouched (removed in slice 3).

Backend: 298 pytest pass, ruff clean. Frontend: 128 vitest pass, build+lint green.
This commit is contained in:
Developer
2026-07-08 21:51:49 +00:00
parent d906b0392b
commit 5dad98231f
12 changed files with 383 additions and 56 deletions
+23 -34
View File
@@ -2,7 +2,7 @@ import type { ComponentType } from "react";
import { AlertmanagerAlertsWidget } from "../widgets/AlertmanagerAlertsWidget";
import { BackupsWidget } from "../widgets/BackupsWidget";
import { GrafanaLinkWidget } from "../widgets/GrafanaLinkWidget";
import { GrafanaChartWidget } from "../widgets/GrafanaChartWidget";
import { PrometheusChartWidget } from "../widgets/PrometheusChartWidget";
import { JellyfinWidget } from "../widgets/JellyfinWidget";
import { JellyfinNowPlayingWidget } from "../widgets/JellyfinNowPlayingWidget";
import { PrometheusMetricWidget } from "../widgets/PrometheusMetricWidget";
@@ -88,39 +88,6 @@ export const SERVICE_REGISTRY: Record<string, ServiceBinding> = {
},
component: GrafanaLinkWidget,
},
{
kind: "chart",
name: "Chart",
description: "Live time-series chart from a Grafana datasource query.",
refreshIntervalMs: 60_000,
defaultConfig: {
datasource_uid: "prometheus",
query: "",
from_ts: "now-1h",
to_ts: "now",
interval_ms: 30_000,
max_data_points: 100,
},
configSchema: {
type: "object",
properties: {
datasource_uid: {
type: "string",
description: "Grafana datasource UID (e.g. 'prometheus')",
},
query: {
type: "string",
description: "Query expression (e.g. PromQL)",
},
from_ts: { type: "string" },
to_ts: { type: "string" },
interval_ms: { type: "integer" },
max_data_points: { type: "integer" },
},
required: ["query"],
},
component: GrafanaChartWidget,
},
],
},
prometheus: {
@@ -141,6 +108,28 @@ export const SERVICE_REGISTRY: Record<string, ServiceBinding> = {
},
component: PrometheusMetricWidget,
},
{
kind: "chart",
name: "Chart",
description: "Multi-series line chart from a PromQL range query.",
refreshIntervalMs: 60_000,
defaultConfig: { promql: "", window: "1h" },
configSchema: {
type: "object",
properties: {
promql: {
type: "string",
description: "PromQL range query expression",
},
window: {
type: "string",
description: "Time window preset (1h, 6h, 24h, 7d)",
},
},
required: ["promql"],
},
component: PrometheusChartWidget,
},
],
},
jellyfin: {