Přidal jsem Health Monitoring do portálu:
Přehled má nové karty: Zdravé služby, Nezdravé služby, Nedostupné služby. Přehled zobrazuje sekci Služby vyžadující pozornost pro unhealthy a unreachable. Snapshot /portal/ws/operations teď obsahuje health data a stránka je aktualizuje přes existující realtime vrstvu. Seznam služeb zobrazuje aktuální health status a poslední kontrolu, včetně řazení Podle zdraví. Detail služby má sekce Zdraví služby a Historie kontrol s posledními 50 záznamy. Přidal jsem audit event service.health.view. Browser title teď používá formát CSBot Services Portal - ..., takže detail služby odpovídá požadavku. Nepoužil jsem ORM, vše je přes SQLite dotazy.
This commit is contained in:
@@ -44,6 +44,21 @@
|
||||
? '<span class="pill pill-success">online</span>'
|
||||
: '<span class="pill pill-danger">offline</span>';
|
||||
|
||||
const healthBadge = (status) => {
|
||||
const value = String(status || "");
|
||||
const normalized = value.toLowerCase();
|
||||
const labels = {
|
||||
healthy: "zdravá",
|
||||
unhealthy: "nezdravá",
|
||||
unreachable: "nedostupná",
|
||||
};
|
||||
let className = "pill pill-muted";
|
||||
if (normalized === "healthy") className = "pill pill-success";
|
||||
if (normalized === "unhealthy") className = "pill pill-warning";
|
||||
if (normalized === "unreachable") className = "pill pill-danger";
|
||||
return `<span class="${className}">${escapeHtml(labels[normalized] || value)}</span>`;
|
||||
};
|
||||
|
||||
const setText = (selector, value) => {
|
||||
document.querySelectorAll(selector).forEach((el) => {
|
||||
el.textContent = value ?? 0;
|
||||
@@ -112,6 +127,24 @@
|
||||
return rows || '<tr><td colspan="6">Zatím nejsou evidované žádné auditní události.</td></tr>';
|
||||
};
|
||||
|
||||
const renderHealthProblems = (items) => {
|
||||
const rows = (items || []).map((item) => {
|
||||
const errorText = String(item.error_text || "");
|
||||
const errorPreview = errorText.length > 120 ? `${errorText.slice(0, 117)}...` : errorText;
|
||||
const serviceName = item.service_name || item.service_id || "";
|
||||
return `
|
||||
<tr>
|
||||
<td><a href="/portal/apps/${encodeURIComponent(item.service_id || "")}">${escapeHtml(serviceName)}</a></td>
|
||||
<td>${healthBadge(item.status)}</td>
|
||||
<td>${escapeHtml(item.checked_at)}</td>
|
||||
<td>${escapeHtml(item.response_time_ms ?? "")}</td>
|
||||
<td>${escapeHtml(errorPreview)}</td>
|
||||
</tr>
|
||||
`;
|
||||
}).join("");
|
||||
return rows || '<tr><td colspan="5">Žádné služby nevyžadují pozornost.</td></tr>';
|
||||
};
|
||||
|
||||
const renderSnapshot = (snapshot) => {
|
||||
setText("[data-live-count='jobs.queued']", snapshot.jobs?.queued);
|
||||
setText("[data-live-count='jobs.running']", snapshot.jobs?.running);
|
||||
@@ -119,6 +152,9 @@
|
||||
setText("[data-live-count='jobs.success_24h']", snapshot.jobs?.success_24h);
|
||||
setText("[data-live-count='apps.active']", snapshot.apps?.active);
|
||||
setText("[data-live-count='apps.problematic']", snapshot.apps?.problematic);
|
||||
setText("[data-live-count='health.healthy']", snapshot.health?.healthy);
|
||||
setText("[data-live-count='health.unhealthy']", snapshot.health?.unhealthy);
|
||||
setText("[data-live-count='health.unreachable']", snapshot.health?.unreachable);
|
||||
setText("[data-live-count='workers.online']", snapshot.workers?.online);
|
||||
setText("[data-live-count='workers.offline']", snapshot.workers?.offline);
|
||||
setText("[data-live-count='workers.total']", (snapshot.workers?.online || 0) + (snapshot.workers?.offline || 0));
|
||||
@@ -133,6 +169,7 @@
|
||||
document.querySelectorAll("[data-live-table='deployments.recent']").forEach((el) => { el.innerHTML = renderDeployments(snapshot.deployments?.recent); });
|
||||
document.querySelectorAll("[data-live-table='deployments.failed']").forEach((el) => { el.innerHTML = renderDeployments(snapshot.deployments?.recent_failed); });
|
||||
document.querySelectorAll("[data-live-table='audit.recent']").forEach((el) => { el.innerHTML = renderAudit(snapshot.audit?.recent); });
|
||||
document.querySelectorAll("[data-live-table='health.problems']").forEach((el) => { el.innerHTML = renderHealthProblems(snapshot.health?.problems); });
|
||||
|
||||
(snapshot.workers?.recent || []).forEach((worker) => {
|
||||
const row = Array.from(document.querySelectorAll("tr[data-worker-id]"))
|
||||
|
||||
Reference in New Issue
Block a user