import html from urllib.parse import quote from fastapi import APIRouter, Depends, Request from fastapi.responses import HTMLResponse from app.auth import require_user from app.db.audit import log_audit_event from app.db.incidents import get_open_incidents, get_recent_incidents from app.templates.layout import page router = APIRouter() def format_duration(seconds) -> str: if seconds is None or seconds == "": return "" try: total = max(0, int(seconds)) except (TypeError, ValueError): return "" hours, remainder = divmod(total, 3600) minutes, secs = divmod(remainder, 60) if hours: return f"{hours} h {minutes} min" if minutes: return f"{minutes} min {secs} s" return f"{secs} s" def render_incident_status(status: str | None) -> str: value = status or "" normalized = value.lower() labels = { "open": "otev\u0159en\u00fd", "resolved": "vy\u0159e\u0161en\u00fd", } class_name = "pill pill-muted" if normalized == "open": class_name = "pill pill-danger" elif normalized == "resolved": class_name = "pill pill-success" return f'{html.escape(labels.get(normalized, value))}' def render_open_incident_rows(incidents: list[dict]) -> str: rows = "" for incident in incidents: service_id = incident.get("service_id", "") or "" service_name = html.escape(incident.get("service_name") or service_id) title = html.escape(incident.get("title", "") or "") started_at = html.escape(incident.get("started_at", "") or "") duration = format_duration(incident.get("duration_seconds")) if not duration: duration = "prob\u00edh\u00e1" rows += f""" {service_name} {title} {started_at} {html.escape(duration)} """ if not rows: rows = '\u017d\u00e1dn\u00e9 aktivn\u00ed incidenty.' return rows def render_incident_history_rows(incidents: list[dict], include_service: bool = True) -> str: rows = "" for incident in incidents: service_id = incident.get("service_id", "") or "" service_name = html.escape(incident.get("service_name") or service_id) title = html.escape(incident.get("title", "") or "") started_at = html.escape(incident.get("started_at", "") or "") ended_at = html.escape(incident.get("ended_at", "") or "") duration = html.escape(format_duration(incident.get("duration_seconds"))) status = render_incident_status(incident.get("status")) service_cell = f'{service_name}' if include_service else "" rows += f""" {service_cell} {title} {started_at} {ended_at} {duration} {status} """ colspan = 6 if include_service else 5 if not rows: rows = f'Zat\u00edm nejsou evidovan\u00e9 \u017e\u00e1dn\u00e9 incidenty.' return rows @router.get("/incidents", response_class=HTMLResponse) def incidents_page(request: Request, user=Depends(require_user)): open_incidents = get_open_incidents() recent_incidents = get_recent_incidents(limit=100) log_audit_event( user, action="incidents.view", target_type="incidents", metadata={"open": len(open_incidents), "history": len(recent_incidents)}, ) return page( "Incidenty", f"""

Incidenty

P\u0159ehled incident\u016f vytv\u00e1\u0159en\u00fdch a uzav\u00edran\u00fdch monitorem.

Aktivn\u00ed incidenty

{render_open_incident_rows(open_incidents)}
Slu\u017eba N\u00e1zev Za\u010d\u00e1tek Trv\u00e1n\u00ed

Historie incident\u016f

{render_incident_history_rows(recent_incidents)}
Slu\u017eba N\u00e1zev Za\u010d\u00e1tek Konec Trv\u00e1n\u00ed Stav
""", user=user, )