/**
* Prometheus Metrics tab (spec R2.4, R8.2).
*
* Instance-scoped tab showing Prometheus service health.
* usePrometheusStatus is scoped by instance.id; usePrometheusTargets
* stays global (returns Node Exporter scrape targets for external Prom).
*/
import { Radio } from "lucide-react";
import {
usePrometheusStatus,
usePrometheusTargets,
} from "../../hooks/useObservability";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { Skeleton } from "@/components/ui/skeleton";
import type { PrometheusTarget, ServiceInstance } from "../../types";
function TargetsTable({ targets }: { targets: PrometheusTarget[] }) {
return (
{targets.map((target, idx) => (
{target.targets.join(", ")}
{target.labels && Object.keys(target.labels).length > 0 && (
{Object.entries(target.labels).map(([key, value]) => (
{key}: {value}
))}
)}
))}
);
}
export function MetricsTab({ instance }: { instance: ServiceInstance }) {
const {
data: status,
isLoading: statusLoading,
error: statusError,
} = usePrometheusStatus(instance.id);
const {
data: targets,
isLoading: targetsLoading,
error: targetsError,
} = usePrometheusTargets();
const statusDetail = status?.up
? status.version
? `version ${status.version}`
: "reachable"
: statusLoading
? "checking…"
: "unreachable";
return (
Prometheus {statusDetail}
{statusError && (
Failed to reach Prometheus
{statusError.message}
)}
Node Exporter Targets ({targets?.length ?? 0})
{targetsLoading ? (
) : !targets || targets.length === 0 ? (
No Node Exporter targets
Enable Node Exporter on an SSH machine in Settings to populate
Prometheus scrape targets.
) : (
)}
{targetsError && (
Failed to load targets
{targetsError.message}
)}
);
}