patchcenter/app/templates/audit_full_list.html
Khalid MOUTAOUAKIL d283e8ab8c Pagination 50/page, recherche hostname, filtre domaine
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 16:32:07 +02:00

130 lines
8.1 KiB
HTML

{% extends 'base.html' %}
{% block title %}Audit complet{% endblock %}
{% block content %}
<div class="flex justify-between items-center mb-4">
<div>
<h2 class="text-xl font-bold text-cyber-accent">Audit complet serveurs</h2>
<p class="text-xs text-gray-500 mt-1">Applicatif + reseau + correlation — import JSON depuis le standalone</p>
</div>
<div class="flex gap-2 items-center">
<form method="POST" action="/audit-full/import" enctype="multipart/form-data" class="flex gap-2 items-center">
<input type="file" name="file" accept=".json" class="text-xs" required>
<button type="submit" class="btn-primary px-4 py-2 text-sm" data-loading="Import en cours...|Insertion des donnees">Importer JSON</button>
</form>
<a href="/audit-full/flow-map" class="btn-sm bg-cyber-border text-cyber-accent px-4 py-2">Carte flux</a>
</div>
</div>
{% if msg %}
<div class="mb-3 p-2 rounded text-sm {% if 'error' in msg %}bg-red-900/30 text-cyber-red{% else %}bg-green-900/30 text-cyber-green{% endif %}">
{% if msg.startswith('imported_') %}
{% set parts = msg.split('_') %}
{{ parts[1] }} serveur(s) importe(s){% if parts[2]|int > 0 %}, {{ parts[2] }} erreur(s){% endif %}.
{% elif msg.startswith('error_') %}Erreur: {{ msg[6:] }}{% endif %}
</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><a href="/audit-full" class="text-cyber-accent underline">Tout voir</a></div>
{% endif %}
{% endif %}
<!-- Recherche + filtre domaine -->
<div class="card p-3 mb-4 flex gap-3 items-center flex-wrap">
<form method="GET" action="/audit-full" class="flex gap-2 items-center flex-1">
{% if filter %}<input type="hidden" name="filter" value="{{ filter }}">{% endif %}
<input type="text" name="q" value="{{ search }}" placeholder="Rechercher un serveur..." class="text-xs py-1 px-3 flex-1 min-w-[200px] font-mono">
<select name="domain" class="text-xs py-1 px-2" onchange="this.form.submit()">
<option value="">Tous les domaines</option>
{% for d in all_domains %}<option value="{{ d.code }}" {% if domain == d.code %}selected{% endif %}>{{ d.name }}</option>{% endfor %}
</select>
<button type="submit" class="btn-primary px-3 py-1 text-xs">Filtrer</button>
{% if search or domain %}<a href="/audit-full{% if filter %}?filter={{ filter }}{% endif %}" class="text-xs text-gray-400 hover:text-cyber-accent">Reset</a>{% endif %}
</form>
<span class="text-xs text-gray-500">{{ total_filtered }} serveur(s)</span>
</div>
{% if audits %}
<div class="card overflow-x-auto">
<table class="w-full table-cyber text-xs">
<thead><tr>
<th class="text-left p-2">Hostname</th>
<th class="p-2">OS</th>
<th class="p-2">Kernel</th>
<th class="p-2">Uptime</th>
<th class="p-2">Services</th>
<th class="p-2">Process</th>
<th class="p-2">Ports</th>
<th class="p-2">Conn</th>
<th class="p-2">Reboot</th>
<th class="p-2">Date</th>
</tr></thead>
<tbody>
{% for a in audits %}
<tr class="hover:bg-cyber-hover cursor-pointer" onclick="location.href='/audit-full/{{ a.id }}'">
<td class="p-2 font-mono text-cyber-accent font-bold">{{ a.hostname }}</td>
<td class="p-2 text-center text-gray-400">{{ (a.os_release or '')[:30] }}</td>
<td class="p-2 text-center font-mono text-gray-500">{{ (a.kernel or '')[:25] }}</td>
<td class="p-2 text-center text-gray-400">{{ (a.uptime or '')[:20] }}</td>
<td class="p-2 text-center">{{ a.svc_count }}</td>
<td class="p-2 text-center">{{ a.proc_count }}</td>
<td class="p-2 text-center">{{ a.port_count }}</td>
<td class="p-2 text-center">{{ a.conn_count }}</td>
<td class="p-2 text-center">{% if a.reboot_required %}<span class="text-cyber-red">Oui</span>{% else %}<span class="text-cyber-green">Non</span>{% endif %}</td>
<td class="p-2 text-center text-gray-500">{{ a.audit_date.strftime('%d/%m %H:%M') if a.audit_date else '-' }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<!-- Pagination -->
{% if total_pages > 1 %}
<div class="flex justify-between items-center p-3 border-t border-cyber-border">
<span class="text-xs text-gray-500">Page {{ page }}/{{ total_pages }} ({{ total_filtered }} serveurs)</span>
<div class="flex gap-1">
{% if page > 1 %}
<a href="/audit-full?page=1{% if filter %}&filter={{ filter }}{% endif %}{% if search %}&q={{ search }}{% endif %}{% if domain %}&domain={{ domain }}{% endif %}" class="btn-sm bg-cyber-border text-gray-400 px-2 py-1 text-xs">1</a>
{% if page > 2 %}<a href="/audit-full?page={{ page - 1 }}{% if filter %}&filter={{ filter }}{% endif %}{% if search %}&q={{ search }}{% endif %}{% if domain %}&domain={{ domain }}{% endif %}" class="btn-sm bg-cyber-border text-gray-400 px-2 py-1 text-xs">&lt;</a>{% endif %}
{% endif %}
<span class="btn-sm bg-cyber-accent text-black px-2 py-1 text-xs font-bold">{{ page }}</span>
{% if page < total_pages %}
<a href="/audit-full?page={{ page + 1 }}{% if filter %}&filter={{ filter }}{% endif %}{% if search %}&q={{ search }}{% endif %}{% if domain %}&domain={{ domain }}{% endif %}" class="btn-sm bg-cyber-border text-gray-400 px-2 py-1 text-xs">&gt;</a>
<a href="/audit-full?page={{ total_pages }}{% if filter %}&filter={{ filter }}{% endif %}{% if search %}&q={{ search }}{% endif %}{% if domain %}&domain={{ domain }}{% endif %}" class="btn-sm bg-cyber-border text-gray-400 px-2 py-1 text-xs">{{ total_pages }}</a>
{% endif %}
</div>
</div>
{% endif %}
</div>
{% else %}
<div class="card p-8 text-center text-gray-500">
<p class="text-sm">Aucun audit{% if search or domain or filter %} correspondant aux filtres{% endif %}.</p>
{% if not search and not domain and not filter %}
<p class="text-xs mt-2">Lancez le standalone sur vos serveurs puis importez le JSON ici.</p>
{% endif %}
</div>
{% endif %}
{% endblock %}