patchcenter/app/templates/quickwin_logs.html
Khalid MOUTAOUAKIL e96d79aae3 QuickWin: prereq/snapshot services, referentiel, logs, correspondance
- Split quickwin services: prereq, snapshot, log services
- Add referentiel router and template
- QuickWin detail: prereq/snapshot terminal divs for production
- Server edit partial updates
- QuickWin correspondance and logs templates
- Base template updates

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 18:13:00 +02:00

108 lines
5.8 KiB
HTML

{% extends "base.html" %}
{% block title %}Logs QuickWin #{{ run.id }}{% endblock %}
{% block content %}
<div class="flex items-center justify-between mb-4">
<div>
<a href="/quickwin/{{ run.id }}" class="text-xs text-gray-500 hover:text-gray-300">&larr; Retour campagne</a>
<h1 class="text-xl font-bold" style="color:#00d4ff">Logs &mdash; {{ run.label }}</h1>
<p class="text-xs text-gray-500">S{{ '%02d'|format(run.week_number) }} {{ run.year }} &mdash; {{ total_logs }} entr&eacute;e(s)</p>
</div>
<div class="flex gap-2 items-center">
<a href="/quickwin/{{ run.id }}" class="btn-sm" style="background:#1e3a5f;color:#94a3b8;padding:4px 14px">Campagne</a>
<form method="post" action="/quickwin/{{ run.id }}/logs/clear" onsubmit="return confirm('Supprimer tous les logs ?')">
<button class="btn-sm btn-danger" style="padding:4px 12px">Vider les logs</button>
</form>
</div>
</div>
{% if msg %}
<div style="background:#1a5a2e;color:#8f8;padding:8px 16px;border-radius:6px;margin-bottom:12px;font-size:0.85rem">{{ msg }}</div>
{% endif %}
<!-- Stats -->
<div style="display:flex;gap:12px;margin-bottom:16px">
<div class="card p-3 text-center" style="flex:1">
<div class="text-xl font-bold" style="color:#fff">{{ total_logs }}</div>
<div class="text-xs text-gray-500">Total</div>
</div>
<div class="card p-3 text-center" style="flex:1">
<div class="text-xl font-bold" style="color:#00ff88">{{ log_stats.get('success', 0) }}</div>
<div class="text-xs text-gray-500">Success</div>
</div>
<div class="card p-3 text-center" style="flex:1">
<div class="text-xl font-bold" style="color:#00d4ff">{{ log_stats.get('info', 0) }}</div>
<div class="text-xs text-gray-500">Info</div>
</div>
<div class="card p-3 text-center" style="flex:1">
<div class="text-xl font-bold" style="color:#ffcc00">{{ log_stats.get('warn', 0) }}</div>
<div class="text-xs text-gray-500">Warn</div>
</div>
<div class="card p-3 text-center" style="flex:1">
<div class="text-xl font-bold" style="color:#ff3366">{{ log_stats.get('error', 0) }}</div>
<div class="text-xs text-gray-500">Error</div>
</div>
</div>
<!-- Filtres -->
<form method="GET" class="card mb-4" style="padding:10px 16px;display:flex;gap:12px;align-items:center;flex-wrap:wrap">
<select name="level" onchange="this.form.submit()" style="width:130px">
<option value="">Tous niveaux</option>
<option value="success" {% if filters.level == 'success' %}selected{% endif %}>Success</option>
<option value="info" {% if filters.level == 'info' %}selected{% endif %}>Info</option>
<option value="warn" {% if filters.level == 'warn' %}selected{% endif %}>Warn</option>
<option value="error" {% if filters.level == 'error' %}selected{% endif %}>Error</option>
</select>
<select name="step" onchange="this.form.submit()" style="width:140px">
<option value="">Toutes &eacute;tapes</option>
{% set steps_seen = logs|map(attribute='step')|unique|sort %}
{% for s in steps_seen %}<option value="{{ s }}" {% if filters.step == s %}selected{% endif %}>{{ s }}</option>{% endfor %}
</select>
<input type="text" name="hostname" value="{{ filters.hostname or '' }}" placeholder="Hostname..." style="width:180px">
<button type="submit" class="btn-primary" style="padding:4px 14px;font-size:0.8rem">Filtrer</button>
<a href="/quickwin/{{ run.id }}/logs" class="text-xs text-gray-500 hover:text-gray-300">Reset</a>
</form>
<!-- Logs table -->
<div class="card">
<div class="table-wrap" style="max-height:70vh;overflow-y:auto">
<table class="table-cyber w-full">
<thead style="position:sticky;top:0;z-index:1"><tr>
<th class="px-2 py-2" style="width:140px">Date</th>
<th class="px-2 py-2" style="width:70px">Niveau</th>
<th class="px-2 py-2" style="width:80px">&Eacute;tape</th>
<th class="px-2 py-2" style="width:120px">Hostname</th>
<th class="px-2 py-2">Message</th>
<th class="px-2 py-2" style="width:100px">Par</th>
</tr></thead>
<tbody>
{% for l in logs %}
<tr style="{% if l.level == 'error' %}background:#ff336610{% elif l.level == 'warn' %}background:#ffcc0008{% endif %}">
<td class="px-2 py-2 text-xs text-gray-500" style="white-space:nowrap">{{ l.created_at.strftime('%d/%m %H:%M:%S') }}</td>
<td class="px-2 py-2 text-center">
{% if l.level == 'success' %}<span class="badge badge-green">OK</span>
{% elif l.level == 'info' %}<span class="badge" style="background:#00d4ff22;color:#00d4ff">INFO</span>
{% elif l.level == 'warn' %}<span class="badge badge-yellow">WARN</span>
{% elif l.level == 'error' %}<span class="badge badge-red">ERR</span>
{% else %}<span class="badge badge-gray">{{ l.level }}</span>{% endif %}
</td>
<td class="px-2 py-2 text-xs text-gray-400">{{ l.step }}</td>
<td class="px-2 py-2 text-xs" style="color:#00d4ff">{{ l.hostname or '' }}</td>
<td class="px-2 py-2 text-sm">
{{ l.message }}
{% if l.detail %}
<div class="text-xs text-gray-500 mt-1" style="max-width:500px;word-break:break-all">{{ l.detail }}</div>
{% endif %}
</td>
<td class="px-2 py-2 text-xs text-gray-500">{{ l.created_by or '' }}</td>
</tr>
{% endfor %}
{% if not logs %}
<tr><td colspan="6" class="px-2 py-8 text-center text-gray-500">Aucun log{% if filters.level or filters.step or filters.hostname %} pour ces filtres{% endif %}</td></tr>
{% endif %}
</tbody>
</table>
</div>
</div>
{% endblock %}