import React, { useEffect, useMemo, useState } from "react";
import { useParams } from "react-router-dom";
import { Line, LineChart, ResponsiveContainer, Tooltip, XAxis, YAxis } from "recharts";
import { apiFetch } from "../api";
import { useAuth } from "../state";
const ranges = {
"15m": 15 * 60 * 1000,
"1h": 60 * 60 * 1000,
"24h": 24 * 60 * 60 * 1000,
"7d": 7 * 24 * 60 * 60 * 1000,
};
function toQueryRange(range) {
const to = new Date();
const from = new Date(to.getTime() - ranges[range]);
return { from: from.toISOString(), to: to.toISOString() };
}
async function loadMetric(targetId, metric, range, tokens, refresh) {
const { from, to } = toQueryRange(range);
return apiFetch(
`/targets/${targetId}/metrics?metric=${encodeURIComponent(metric)}&from=${encodeURIComponent(from)}&to=${encodeURIComponent(to)}`,
{},
tokens,
refresh
);
}
export function TargetDetailPage() {
const { id } = useParams();
const { tokens, refresh } = useAuth();
const [range, setRange] = useState("1h");
const [series, setSeries] = useState({});
const [locks, setLocks] = useState([]);
const [activity, setActivity] = useState([]);
const [error, setError] = useState("");
const [loading, setLoading] = useState(true);
useEffect(() => {
let active = true;
(async () => {
setLoading(true);
try {
const [connections, xacts, cache, locksTable, activityTable] = await Promise.all([
loadMetric(id, "connections_total", range, tokens, refresh),
loadMetric(id, "xacts_total", range, tokens, refresh),
loadMetric(id, "cache_hit_ratio", range, tokens, refresh),
apiFetch(`/targets/${id}/locks`, {}, tokens, refresh),
apiFetch(`/targets/${id}/activity`, {}, tokens, refresh),
]);
if (!active) return;
setSeries({ connections, xacts, cache });
setLocks(locksTable);
setActivity(activityTable);
setError("");
} catch (e) {
if (active) setError(String(e.message || e));
} finally {
if (active) setLoading(false);
}
})();
return () => {
active = false;
};
}, [id, range, tokens, refresh]);
const chartData = useMemo(
() =>
(series.connections || []).map((point, idx) => ({
ts: new Date(point.ts).toLocaleTimeString(),
connections: point.value,
xacts: series.xacts?.[idx]?.value || 0,
cache: series.cache?.[idx]?.value || 0,
})),
[series]
);
if (loading) return
Lade Target Detail...
;
if (error) return {error}
;
return (
Target Detail #{id}
{Object.keys(ranges).map((r) => (
))}
Connections / TPS approx / Cache hit ratio
Locks
| Type |
Mode |
Granted |
Relation |
PID |
{locks.map((l, i) => (
| {l.locktype} |
{l.mode} |
{String(l.granted)} |
{l.relation || "-"} |
{l.pid} |
))}
Activity
| PID |
User |
State |
Wait |
{activity.map((a) => (
| {a.pid} |
{a.usename} |
{a.state} |
{a.wait_event_type || "-"} |
))}
);
}