Init first files

This commit is contained in:
2026-02-12 09:09:13 +01:00
parent 6535699b0e
commit d1d8ae43a4
61 changed files with 2424 additions and 0 deletions

View File

@@ -0,0 +1,79 @@
import React, { useEffect, useState } from "react";
import { apiFetch } from "../api";
import { useAuth } from "../state";
export function QueryInsightsPage() {
const { tokens, refresh } = useAuth();
const [targets, setTargets] = useState([]);
const [targetId, setTargetId] = useState("");
const [rows, setRows] = useState([]);
const [error, setError] = useState("");
useEffect(() => {
(async () => {
try {
const t = await apiFetch("/targets", {}, tokens, refresh);
setTargets(t);
if (t.length > 0) setTargetId(String(t[0].id));
} catch (e) {
setError(String(e.message || e));
}
})();
}, []);
useEffect(() => {
if (!targetId) return;
(async () => {
try {
const data = await apiFetch(`/targets/${targetId}/top-queries`, {}, tokens, refresh);
setRows(data);
} catch (e) {
setError(String(e.message || e));
}
})();
}, [targetId, tokens, refresh]);
return (
<div>
<h2>Query Insights</h2>
<p>Hinweis: Benötigt aktivierte Extension <code>pg_stat_statements</code> auf dem Zielsystem.</p>
{error && <div className="card error">{error}</div>}
<div className="card">
<label>Target </label>
<select value={targetId} onChange={(e) => setTargetId(e.target.value)}>
{targets.map((t) => (
<option key={t.id} value={t.id}>
{t.name}
</option>
))}
</select>
</div>
<div className="card">
<table>
<thead>
<tr>
<th>Time</th>
<th>Calls</th>
<th>Total ms</th>
<th>Mean ms</th>
<th>Rows</th>
<th>Query</th>
</tr>
</thead>
<tbody>
{rows.map((r, i) => (
<tr key={i}>
<td>{new Date(r.ts).toLocaleString()}</td>
<td>{r.calls}</td>
<td>{r.total_time.toFixed(2)}</td>
<td>{r.mean_time.toFixed(2)}</td>
<td>{r.rows}</td>
<td className="query">{r.query_text || "-"}</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
);
}