- 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>
108 lines
5.8 KiB
HTML
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">← Retour campagne</a>
|
|
<h1 class="text-xl font-bold" style="color:#00d4ff">Logs — {{ run.label }}</h1>
|
|
<p class="text-xs text-gray-500">S{{ '%02d'|format(run.week_number) }} {{ run.year }} — {{ total_logs }} entré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 é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">É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 %}
|