import React, { useEffect, useState } from "react";
import { Link } from "react-router-dom";
import { apiFetch } from "../api";
import { useAuth } from "../state";
function getTargetGroupMeta(target) {
const tags = target?.tags || {};
if (tags.monitor_mode !== "all_databases" || !tags.monitor_group_id) return null;
return {
id: tags.monitor_group_id,
name: tags.monitor_group_name || target.name || "All databases",
};
}
export function DashboardPage() {
const { tokens, refresh, alertStatus } = useAuth();
const [targets, setTargets] = useState([]);
const [search, setSearch] = useState("");
const [openGroups, setOpenGroups] = useState({});
const [loading, setLoading] = useState(true);
const [error, setError] = useState("");
useEffect(() => {
let active = true;
(async () => {
try {
const targetRows = await apiFetch("/targets", {}, tokens, refresh);
if (active) {
setTargets(targetRows);
}
} catch (e) {
if (active) setError(String(e.message || e));
} finally {
if (active) setLoading(false);
}
})();
return () => {
active = false;
};
}, [tokens, refresh]);
if (loading) return
Loading dashboard...
;
if (error) return {error}
;
const targetSeverities = new Map();
for (const item of alertStatus.warnings || []) {
if (!targetSeverities.has(item.target_id)) targetSeverities.set(item.target_id, "warning");
}
for (const item of alertStatus.alerts || []) {
targetSeverities.set(item.target_id, "alert");
}
const affectedTargetCount = targetSeverities.size;
const okCount = Math.max(0, targets.length - affectedTargetCount);
const filteredTargets = targets.filter((t) => {
const q = search.trim().toLowerCase();
if (!q) return true;
return (
(t.name || "").toLowerCase().includes(q) ||
(t.host || "").toLowerCase().includes(q) ||
(t.dbname || "").toLowerCase().includes(q)
);
});
const groupedRows = [];
const groupedMap = new Map();
for (const t of filteredTargets) {
const meta = getTargetGroupMeta(t);
if (!meta) {
groupedRows.push({ type: "single", target: t });
continue;
}
if (!groupedMap.has(meta.id)) {
const groupRow = { type: "group", groupId: meta.id, groupName: meta.name, targets: [] };
groupedMap.set(meta.id, groupRow);
groupedRows.push(groupRow);
}
groupedMap.get(meta.id).targets.push(t);
}
return (
Dashboard Overview
Real-time snapshot of monitored PostgreSQL targets.
{targets.length}
Total Targets
{alertStatus.warning_count || 0}
Warnings
{alertStatus.alert_count || 0}
Alerts
{groupedRows.map((row) => {
if (row.type === "single") {
const t = row.target;
const severity = targetSeverities.get(t.id) || "ok";
return (
{t.name}
{severity === "alert" ? "Alert" : severity === "warning" ? "Warning" : "OK"}
Host: {t.host}:{t.port}
DB: {t.dbname}
);
}
const highestSeverity = row.targets.some((t) => targetSeverities.get(t.id) === "alert")
? "alert"
: row.targets.some((t) => targetSeverities.get(t.id) === "warning")
? "warning"
: "ok";
const first = row.targets[0];
const isOpen = !!openGroups[row.groupId];
return (
{row.groupName}
{highestSeverity === "alert" ? "Alert" : highestSeverity === "warning" ? "Warning" : "OK"}
Host: {first.host}:{first.port}
DB: All databases ({row.targets.length})
{isOpen && (
{row.targets.map((t) => {
const severity = targetSeverities.get(t.id) || "ok";
return (
{t.dbname}
{severity === "alert" ? "Alert" : severity === "warning" ? "Warning" : "OK"}
Details
);
})}
)}
);
})}
{filteredTargets.length === 0 && (
No targets match your search.
)}
);
}