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:
@@ -110,6 +110,46 @@ def render_recent_audit_events(events: list[dict]) -> str:
|
||||
return rows
|
||||
|
||||
|
||||
def render_health_status(status: str | None) -> str:
|
||||
value = status or ""
|
||||
normalized = value.lower()
|
||||
labels = {
|
||||
"healthy": "zdravá",
|
||||
"unhealthy": "nezdravá",
|
||||
"unreachable": "nedostupná",
|
||||
}
|
||||
class_name = "pill pill-muted"
|
||||
if normalized == "healthy":
|
||||
class_name = "pill pill-success"
|
||||
elif normalized == "unhealthy":
|
||||
class_name = "pill pill-warning"
|
||||
elif normalized == "unreachable":
|
||||
class_name = "pill pill-danger"
|
||||
return f'<span class="{class_name}">{html.escape(labels.get(normalized, value))}</span>'
|
||||
|
||||
|
||||
def render_health_problems(items: list[dict]) -> str:
|
||||
rows = ""
|
||||
for item in items:
|
||||
service_id = html.escape(item.get("service_id", "") or "")
|
||||
service_name = html.escape(item.get("service_name") or item.get("service_id", "") or "")
|
||||
error_text = item.get("error_text", "") or ""
|
||||
error_preview = error_text if len(error_text) <= 120 else f"{error_text[:117]}..."
|
||||
rows += f"""
|
||||
<tr>
|
||||
<td><a href="/portal/apps/{quote(service_id, safe='')}">{service_name}</a></td>
|
||||
<td>{render_health_status(item.get("status"))}</td>
|
||||
<td>{html.escape(item.get("checked_at", "") or "")}</td>
|
||||
<td>{html.escape(str(item.get("response_time_ms") or ""))}</td>
|
||||
<td>{html.escape(error_preview)}</td>
|
||||
</tr>
|
||||
"""
|
||||
|
||||
if not rows:
|
||||
rows = '<tr><td colspan="5">Žádné služby nevyžadují pozornost.</td></tr>'
|
||||
return rows
|
||||
|
||||
|
||||
@router.get("/operations", response_class=HTMLResponse)
|
||||
def operations_dashboard(request: Request, user=Depends(require_user)):
|
||||
snapshot = get_operations_snapshot()
|
||||
@@ -145,12 +185,29 @@ def operations_dashboard(request: Request, user=Depends(require_user)):
|
||||
<div class="stats-grid">
|
||||
<div class="stat-card stat-success"><span>Běžící služby</span><strong data-live-count="apps.active">{snapshot["apps"]["active"]}</strong></div>
|
||||
<div class="stat-card stat-danger"><span>Problémové služby</span><strong data-live-count="apps.problematic">{snapshot["apps"]["problematic"]}</strong></div>
|
||||
<div class="stat-card stat-success"><span>Zdravé služby</span><strong data-live-count="health.healthy">{snapshot["health"]["healthy"]}</strong></div>
|
||||
<div class="stat-card stat-warning"><span>Nezdravé služby</span><strong data-live-count="health.unhealthy">{snapshot["health"]["unhealthy"]}</strong></div>
|
||||
<div class="stat-card stat-danger"><span>Nedostupné služby</span><strong data-live-count="health.unreachable">{snapshot["health"]["unreachable"]}</strong></div>
|
||||
<div class="stat-card stat-warning"><span>Aktivní úlohy</span><strong data-live-count="jobs.running">{snapshot["jobs"]["running"]}</strong></div>
|
||||
<div class="stat-card stat-total"><span>Nasazení dnes</span><strong data-live-count="deployments.today">{snapshot["deployments"]["today"]}</strong></div>
|
||||
<div class="stat-card stat-success"><span>Online workery</span><strong data-live-count="workers.online">{snapshot["workers"]["online"]}</strong></div>
|
||||
<div class="stat-card stat-danger"><span>Selhané úlohy (24 h)</span><strong data-live-count="jobs.failed_24h">{snapshot["jobs"]["failed_24h"]}</strong></div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>Služby vyžadující pozornost</h2>
|
||||
<table>
|
||||
<tr>
|
||||
<th>Služba</th>
|
||||
<th>Status</th>
|
||||
<th>Poslední kontrola</th>
|
||||
<th>Odezva</th>
|
||||
<th>Chyba</th>
|
||||
</tr>
|
||||
<tbody data-live-table="health.problems">{render_health_problems(snapshot["health"]["problems"])}</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>Poslední incidenty</h2>
|
||||
<table>
|
||||
|
||||
Reference in New Issue
Block a user