65bae95e3c
Add gauge widget (recharts RadialBarChart with configurable threshold bands, scalar-only per SC-111) and mean widget (client-side average over range-query window, scalar-only per SC-114). Extract shared _instant_query helper from the metric path; _fetch_gauge and _fetch_mean dispatch in PrometheusWidgetSource.fetch(). Both new widget kinds declared in integrations/prometheus.py and frontend registry. Backend: 305 pytest pass, ruff clean. Frontend: 136 vitest pass, build+lint green.
60 lines
1.6 KiB
TypeScript
60 lines
1.6 KiB
TypeScript
import { Alert, AlertDescription } from "@/components/ui/alert";
|
|
import { Skeleton } from "@/components/ui/skeleton";
|
|
import { SectionCard } from "../components/SectionCard";
|
|
import { useWidgetData } from "../hooks/useWidgets";
|
|
import type { WidgetInstance } from "../types";
|
|
|
|
interface Props {
|
|
widget: WidgetInstance;
|
|
refreshIntervalMs: number;
|
|
description?: string;
|
|
}
|
|
|
|
interface MeanData {
|
|
value: number;
|
|
unit?: string | null;
|
|
}
|
|
|
|
function formatMean(value: number, unit?: string | null): string {
|
|
let formatted: string;
|
|
if (Math.abs(value) >= 1000) {
|
|
formatted = value.toFixed(0);
|
|
} else if (Math.abs(value) >= 1) {
|
|
formatted = value.toFixed(2).replace(/\.?0+$/, "");
|
|
} else {
|
|
formatted = value.toFixed(4).replace(/\.?0+$/, "");
|
|
}
|
|
return unit ? `${formatted} ${unit}` : formatted;
|
|
}
|
|
|
|
export function PrometheusMeanWidget({
|
|
widget,
|
|
refreshIntervalMs,
|
|
description,
|
|
}: Props) {
|
|
const { data, isLoading } = useWidgetData(widget.id, refreshIntervalMs);
|
|
const mean = data?.data as MeanData | undefined;
|
|
|
|
return (
|
|
<SectionCard title={widget.title} description={description}>
|
|
{isLoading && !data ? (
|
|
<Skeleton className="h-16 w-32" />
|
|
) : data?.error ? (
|
|
<Alert variant="destructive">
|
|
<AlertDescription>{data.error}</AlertDescription>
|
|
</Alert>
|
|
) : mean ? (
|
|
<div className="flex flex-col items-center justify-center py-4">
|
|
<span className="text-3xl font-bold">
|
|
{formatMean(mean.value, mean.unit)}
|
|
</span>
|
|
</div>
|
|
) : (
|
|
<Alert>
|
|
<AlertDescription>No data. Check your PromQL query.</AlertDescription>
|
|
</Alert>
|
|
)}
|
|
</SectionCard>
|
|
);
|
|
}
|