feat(prometheus-direct-charting): slice 3 — remove grafana + config rewrite + changelog

Remove the entire Grafana surface: integrations/grafana.py, GrafanaWidgetSource
(+ _fetch_chart, now redundant since prometheus chart exists), GrafanaLinkWidget,
LinksTab, get_grafana_status endpoint, useGrafanaStatus hook, GrafanaStatus type,
fetchGrafanaStatus client fn, registry/nav/tab entries (FE+BE). Rewrite
config.yaml thin-dashboard rule to match reality (recharts is sanctioned for
Prometheus-backed series). CHANGELOG migration note added.

Backend: 293 pytest pass, ruff clean. Frontend: build+lint green (0 errors).
SC-115/116 grep-clean (only prometheus_range.py migration comments + Dashboard.test
shortcut fixture remain — both spec-allowed).
This commit is contained in:
Developer
2026-07-08 22:33:44 +00:00
parent 65bae95e3c
commit 67ca0fc3bc
27 changed files with 134 additions and 937 deletions
@@ -21,13 +21,9 @@ describe("navEntries", () => {
it("returns all observability entries", () => {
const entries = configuredNavEntries(
new Set(["alertmanager", "grafana", "prometheus"]),
new Set(["alertmanager", "prometheus"]),
);
expect(entries.map((e) => e.label)).toEqual([
"Alertmanager",
"Grafana",
"Prometheus",
]);
expect(entries.map((e) => e.label)).toEqual(["Alertmanager", "Prometheus"]);
});
it("returns Backups + Authentik when configured", () => {
-7
View File
@@ -10,7 +10,6 @@ import {
Activity,
DatabaseBackup,
GanttChartSquare,
Link2,
Monitor,
Server,
Users,
@@ -49,12 +48,6 @@ export const SERVICE_TYPE_NAV_ENTRIES: NavEntry[] = [
icon: Activity,
path: "/services/alertmanager",
},
{
serviceType: "grafana",
label: "Grafana",
icon: Link2,
path: "/services/grafana",
},
{
serviceType: "prometheus",
label: "Prometheus",
+7 -11
View File
@@ -12,7 +12,6 @@ describe("service registry", () => {
it("registers the backend service types", () => {
expect(Object.keys(SERVICE_REGISTRY).sort()).toEqual([
"alertmanager",
"grafana",
"jellyfin",
"nextcloud",
"prometheus",
@@ -21,9 +20,6 @@ describe("service registry", () => {
});
it("binds widget kinds per service", () => {
expect(SERVICE_REGISTRY.grafana.widgets.map((w) => w.kind)).toEqual([
"link",
]);
expect(SERVICE_REGISTRY.prometheus.widgets.map((w) => w.kind)).toEqual([
"metric",
"chart",
@@ -43,12 +39,12 @@ describe("service registry", () => {
expect(Object.keys(BUILTIN_WIDGETS).sort()).toEqual(["backups", "static"]);
});
it("resolves a service-bound widget via the services list", () => {
it("resolves a prometheus metric widget via the services list", () => {
const widget: WidgetInstance = {
id: "w1",
service_id: "s1",
widget_kind: "link",
title: "Dashboard",
widget_kind: "metric",
title: "Metric",
config: {},
enabled: true,
sort_order: 0,
@@ -58,9 +54,9 @@ describe("service registry", () => {
const services: ServiceInstance[] = [
{
id: "s1",
service_type: "grafana",
name: "Grafana",
config: { base_url: "https://grafana.example.com" },
service_type: "prometheus",
name: "Prometheus",
config: { base_url: "https://prometheus.example.com" },
secrets_set: { api_key: true },
enabled: true,
created_at: 0,
@@ -69,7 +65,7 @@ describe("service registry", () => {
];
const resolved = resolveWidget(widget, services);
expect(resolved).toBeDefined();
expect(resolved?.refreshIntervalMs).toBe(0);
expect(resolved?.refreshIntervalMs).toBe(30_000);
});
it("resolves an alertmanager active_alerts widget", () => {
-24
View File
@@ -1,7 +1,6 @@
import type { ComponentType } from "react";
import { AlertmanagerAlertsWidget } from "../widgets/AlertmanagerAlertsWidget";
import { BackupsWidget } from "../widgets/BackupsWidget";
import { GrafanaLinkWidget } from "../widgets/GrafanaLinkWidget";
import { PrometheusChartWidget } from "../widgets/PrometheusChartWidget";
import { PrometheusGaugeWidget } from "../widgets/PrometheusGaugeWidget";
import { PrometheusMeanWidget } from "../widgets/PrometheusMeanWidget";
@@ -69,29 +68,6 @@ export const SERVICE_REGISTRY: Record<string, ServiceBinding> = {
},
],
},
grafana: {
serviceType: "grafana",
name: "Grafana",
description: "Dashboards, metrics, and logs.",
widgets: [
{
kind: "link",
name: "Dashboard link",
description: "Deep-link to a Grafana dashboard or panel.",
refreshIntervalMs: 0,
defaultConfig: { dashboard_uid: "" },
configSchema: {
type: "object",
properties: {
dashboard_uid: { type: "string" },
panel_id: { type: "integer" },
},
required: ["dashboard_uid"],
},
component: GrafanaLinkWidget,
},
],
},
prometheus: {
serviceType: "prometheus",
name: "Prometheus",