KPIs audit complet: reboot, disque 90%/80%, uptime > 4 mois, filtres cliquables

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Khalid MOUTAOUAKIL 2026-04-06 16:29:52 +02:00
parent 09a039a6fd
commit 2864a15817
2 changed files with 80 additions and 1 deletions

View File

@ -25,9 +25,60 @@ async def audit_full_list(request: Request, db=Depends(get_db)):
return RedirectResponse(url="/dashboard")
audits = get_latest_audits(db)
filtre = request.query_params.get("filter", "")
# KPIs
kpis = db.execute(text("""
SELECT
COUNT(*) as total,
COUNT(*) FILTER (WHERE reboot_required = true) as needs_reboot,
COUNT(*) FILTER (WHERE EXISTS (
SELECT 1 FROM jsonb_array_elements(disk_usage) d
WHERE (d->>'pct')::int >= 90
)) as disk_critical,
COUNT(*) FILTER (WHERE EXISTS (
SELECT 1 FROM jsonb_array_elements(disk_usage) d
WHERE (d->>'pct')::int >= 80 AND (d->>'pct')::int < 90
)) as disk_warning,
COUNT(*) FILTER (WHERE
uptime LIKE '%month%' OR uptime LIKE '%year%'
OR uptime LIKE '%week%' AND (
CASE WHEN uptime ~ '(\d+) week' THEN (substring(uptime from '(\d+) week'))::int ELSE 0 END >= 17
)
) as uptime_long
FROM server_audit_full
WHERE status = 'ok'
AND id IN (SELECT DISTINCT ON (hostname) id FROM server_audit_full WHERE status = 'ok' ORDER BY hostname, audit_date DESC)
""")).fetchone()
# Filtrer si demande
if filtre == "reboot":
audits = [a for a in audits if a.reboot_required]
elif filtre == "disk_critical":
ids = db.execute(text("""
SELECT saf.id FROM server_audit_full saf
WHERE saf.status = 'ok' AND EXISTS (
SELECT 1 FROM jsonb_array_elements(saf.disk_usage) d WHERE (d->>'pct')::int >= 90
) AND saf.id IN (SELECT DISTINCT ON (hostname) id FROM server_audit_full WHERE status = 'ok' ORDER BY hostname, audit_date DESC)
""")).fetchall()
id_set = {r.id for r in ids}
audits = [a for a in audits if a.id in id_set]
elif filtre == "disk_warning":
ids = db.execute(text("""
SELECT saf.id FROM server_audit_full saf
WHERE saf.status = 'ok' AND EXISTS (
SELECT 1 FROM jsonb_array_elements(saf.disk_usage) d WHERE (d->>'pct')::int >= 80
) AND saf.id IN (SELECT DISTINCT ON (hostname) id FROM server_audit_full WHERE status = 'ok' ORDER BY hostname, audit_date DESC)
""")).fetchall()
id_set = {r.id for r in ids}
audits = [a for a in audits if a.id in id_set]
elif filtre == "uptime":
audits = [a for a in audits if a.uptime and ("month" in a.uptime or "year" in a.uptime)]
ctx = base_context(request, db, user)
ctx.update({
"app_name": APP_NAME, "audits": audits,
"app_name": APP_NAME, "audits": audits, "kpis": kpis,
"filter": filtre,
"msg": request.query_params.get("msg"),
})
return templates.TemplateResponse("audit_full_list.html", ctx)

View File

@ -24,6 +24,34 @@
</div>
{% endif %}
{% if kpis %}
<div class="flex gap-3 mb-4">
<a href="/audit-full" class="card p-3 text-center flex-1 hover:bg-cyber-hover {% if not filter %}ring-1 ring-cyber-accent{% endif %}">
<div class="text-lg font-bold text-cyber-accent">{{ kpis.total }}</div>
<div class="text-xs text-gray-500">Total</div>
</a>
<a href="/audit-full?filter=reboot" class="card p-3 text-center flex-1 hover:bg-cyber-hover {% if filter == 'reboot' %}ring-1 ring-cyber-red{% endif %}">
<div class="text-lg font-bold {% if kpis.needs_reboot > 0 %}text-cyber-red{% else %}text-cyber-green{% endif %}">{{ kpis.needs_reboot }}</div>
<div class="text-xs text-gray-500">Reboot requis</div>
</a>
<a href="/audit-full?filter=disk_critical" class="card p-3 text-center flex-1 hover:bg-cyber-hover {% if filter == 'disk_critical' %}ring-1 ring-cyber-red{% endif %}">
<div class="text-lg font-bold {% if kpis.disk_critical > 0 %}text-cyber-red{% else %}text-cyber-green{% endif %}">{{ kpis.disk_critical }}</div>
<div class="text-xs text-gray-500">Disque >= 90%</div>
</a>
<a href="/audit-full?filter=disk_warning" class="card p-3 text-center flex-1 hover:bg-cyber-hover {% if filter == 'disk_warning' %}ring-1 ring-cyber-yellow{% endif %}">
<div class="text-lg font-bold {% if kpis.disk_warning > 0 %}text-cyber-yellow{% else %}text-cyber-green{% endif %}">{{ kpis.disk_warning }}</div>
<div class="text-xs text-gray-500">Disque >= 80%</div>
</a>
<a href="/audit-full?filter=uptime" class="card p-3 text-center flex-1 hover:bg-cyber-hover {% if filter == 'uptime' %}ring-1 ring-cyber-yellow{% endif %}">
<div class="text-lg font-bold {% if kpis.uptime_long > 0 %}text-cyber-yellow{% else %}text-cyber-green{% endif %}">{{ kpis.uptime_long }}</div>
<div class="text-xs text-gray-500">Uptime > 4 mois</div>
</a>
</div>
{% if filter %}
<div class="mb-3 text-xs text-gray-400">Filtre actif : <span class="text-cyber-accent">{{ filter }}</span> ({{ audits|length }} serveurs) — <a href="/audit-full" class="text-cyber-accent underline">Tout voir</a></div>
{% endif %}
{% endif %}
{% if audits %}
<div class="card overflow-x-auto">
<table class="w-full table-cyber text-xs">