Files
Developer 7efc06a629 chore(prometheus-direct-charting): archive verified+synced change
Move to openspec/changes/archive/2026-07-08-prometheus-direct-charting/
(git mv, history preserved). 9 artifacts: proposal/spec/design/tasks/
apply-progress/verify-report/sync-report/archive-report + delta spec.
Canonical openspec/specs/prometheus-charting/ remains.
2026-07-08 23:01:35 +00:00

4.9 KiB
Raw Permalink Blame History

Apply Progress: Prometheus Direct Charting

Change: prometheus-direct-charting Phase: apply-progress Date: 2026-07-08 Status: complete — all 39 tasks done, all gates green, verified (see verify-report.md)

Slices delivered

Three slices, each its own commit, each leaving pytest / npm run build / npm run lint / ruff green.

Slice 1 — Prometheus range query + chart rebrand (commit 5dad982, amended)

  • Created backend/src/media_library_viewer_api/widgets/prometheus_range.py with step_for_window(s) (max(15, round(s/200)) → ~200 pts/window) and normalize_prometheus_matrix(result) (shared label rule extracted from the to-be-removed Grafana path; drops __name__/__*, joins sorted k=v, falls back to "value", dedups with (n)).
  • Extended PrometheusWidgetSource.fetch to dispatch widget_kind == "chart"_fetch_chart hitting /api/v1/query_range directly, returning {series:[...]} (SC-101..104). Grafana path left intact at this slice.
  • Declared chart widget kind in integrations/prometheus.py (config: promql, window{1h,6h,24h,7d}).
  • git mv GrafanaChartWidget.tsx → PrometheusChartWidget.tsx (recharts body preserved verbatim; empty-state copy updated); git mv of its test. Rebound chart grafana→prometheus in both registries (SC-105..108).
  • Backend tests: new test_prometheus_range.py (step + normalization); chart-adapter test in test_widgets.py. Frontend registry test updated.

Slice 2 — Gauge + mean widgets (commit 58be6e0, amended)

  • Extracted shared _instant_query helper; added _fetch_gauge (instant → scalar, multi-series → {error}) and _fetch_mean (range query over preset → client-side arithmetic mean of non-null values, scalar-only).
  • Declared gauge (promql, warn_at/crit_at/min/max/unit) and mean (promql, window, unit) kinds in integrations/prometheus.py.
  • Created PrometheusGaugeWidget.tsx (recharts RadialBarChart; green/amber/red threshold bands when warn_at+crit_at set; neutral single track otherwise) and PrometheusMeanWidget.tsx (MetricCard-style single value). Wired both into the frontend prometheus binding + barrel.
  • Tests: backend adapter tests (scalar-only enforcement, mean aggregation incl. NaN-skip, error cases); frontend component tests (error + rendered, gauge with/without bands, mean with/without unit).

Slice 3 — Grafana removal + config + changelog (commit ba94317, amended)

  • Deleted integrations/grafana.py, GrafanaLinkWidget.tsx, service-tabs/LinksTab.tsx (+ test). Removed GrafanaWidgetSource + adapter registration; grafana from SERVICE_DEFINITIONS/SERVICE_ADAPTERS (BE) and SERVICE_REGISTRY/BUILTIN_WIDGETS (FE); get_grafana_status endpoint; useGrafanaStatus/fetchGrafanaStatus/GrafanaStatus; nav entry; service-tabs/index.ts grafana case; Dashboard.tsx OBSERVABILITY_TYPES grafana member; ServicesPage.tsx empty-state copy; grafana tests.
  • Rewrote openspec/config.yaml: removed stale "Do NOT re-implement charting in-app" + "No recharts/d3" claims; states Manage renders Prometheus-backed metrics directly via recharts and that Grafana is no longer integrated.
  • Added CHANGELOG.md [Unreleased] entry: BREAKING — Grafana service type removed; migrate by deleting grafana instances and recreating as Prometheus; grafana/chart widgets → prometheus/chart.
  • Net: 920 lines across 27 files.

Coverage close — SC-125 loading-state tests

  • Added one it("renders skeleton while loading") case to each of the three Prometheus widget test files, asserting the Skeleton (data-slot="skeleton") renders under { data: undefined, isLoading: true }. Closes the PARTIAL finding on SC-125.

Deviations from tasks.md

  • None functional. The only textual drift is SC-118: ObservabilityPage.tsx had already been refactored into service-tabs/ (the project map was stale). Removal targets adjusted to the real files (LinksTab.tsx, service-tabs/index.ts, navEntries.ts, Dashboard.tsx, ServicesPage.tsx); the spec was patched (SC-116/SC-118) to reflect this before apply. SC-118's intent (no Grafana UI surface) is fully satisfied.

Final gate results (re-run after coverage close)

Gate Result
backend && PYTHONPATH=src python3 -m pytest -q 293 passed, 2 warnings (pre-existing pythonjsonlogger DeprecationWarning)
backend && PYTHONPATH=src python3 -m ruff check src tests All checks passed
frontend && npm run build (tsc -b + vite build) exit 0 (pre-existing chunk-size warning)
frontend && npm run lint 0 errors, 1 pre-existing warning (WidgetConfigDialog.tsx:370, untouched)
frontend && npx vitest run (3 Prom widget tests) 14 passed (11 original + 3 new loading)

Verification

See verify-report.md — adversarial fresh-context review: 26/27 fully PASS, 1 PARTIAL→PASS (SC-125 closed here). No blocking findings remain.