patchcenter/app/templates/quickwin.html
Khalid MOUTAOUAKIL 5cc10c5b6c Module QuickWin complet + filtres serveurs OS/owner
- QuickWin: campagnes patching rapide avec exclusions générales (OS/reboot) et spécifiques (applicatifs)
- Config serveurs: pagination, filtres (search, env, domain, zone, per_page), dry run, bulk edit
- Détail campagne: pagination hprod/prod séparée, filtres (search, status, domain), section prod masquée si hprod non terminé
- Auth: redirection qw_only vers /quickwin, profil lecture seule quickwin
- Serveurs: filtres OS (Linux/Windows) et Owner (secops/ipop/na), exclusion EOL
- Sidebar: lien QuickWin conditionné sur permission campaigns ou quickwin

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-08 16:27:45 +02:00

137 lines
7.4 KiB
HTML

{% extends "base.html" %}
{% block title %}QuickWin{% endblock %}
{% block content %}
<div class="flex items-center justify-between mb-6">
<div>
<h1 class="text-2xl font-bold" style="color:#00d4ff">QuickWin</h1>
<p class="text-sm text-gray-500">Campagnes patching rapide &mdash; exclusions par serveur &mdash; hors-prod d'abord &mdash; pas de reboot n&eacute;cessaire</p>
</div>
<div class="flex gap-2">
{% if can_create %}
<a href="/quickwin/config" class="btn-sm" style="background:#1e3a5f;color:#00d4ff;padding:6px 16px">Config exclusions</a>
<button onclick="document.getElementById('createModal').style.display='flex'" class="btn-primary" style="padding:6px 16px;font-size:0.85rem">+ Nouveau QuickWin</button>
{% endif %}
</div>
</div>
{% if msg %}
<div style="background:#1a5a2e;color:#8f8;padding:8px 16px;border-radius:6px;margin-bottom:12px;font-size:0.85rem">
{% if msg == 'deleted' %}Campagne supprim&eacute;e{% elif msg == 'error' %}Erreur cr&eacute;ation{% elif msg == 'no_servers' %}Aucun serveur configur&eacute;{% else %}{{ msg }}{% endif %}
</div>
{% endif %}
<!-- KPIs -->
<div class="grid grid-cols-4 gap-4 mb-6">
<div class="card p-4 text-center">
<div class="text-3xl font-bold" style="color:#00d4ff">{{ runs|length }}</div>
<div class="text-xs text-gray-500">Campagnes</div>
</div>
<div class="card p-4 text-center">
<div class="text-3xl font-bold" style="color:#00ff88">{{ config_count }}</div>
<div class="text-xs text-gray-500">Serveurs configur&eacute;s</div>
</div>
<div class="card p-4 text-center">
<div class="text-3xl font-bold" style="color:#ffcc00">S{{ current_week }}</div>
<div class="text-xs text-gray-500">Semaine courante</div>
</div>
<div class="card p-4 text-center">
<div class="text-3xl font-bold" style="color:#fff">{{ current_year }}</div>
<div class="text-xs text-gray-500">Ann&eacute;e</div>
</div>
</div>
<!-- Runs list -->
<div class="card">
<div class="p-4 flex items-center justify-between" style="border-bottom:1px solid #1e3a5f">
<h2 class="text-sm font-bold" style="color:#00d4ff">CAMPAGNES QUICKWIN</h2>
<span class="text-xs text-gray-500">{{ runs|length }} campagne(s)</span>
</div>
<div class="table-wrap">
<table class="table-cyber w-full">
<thead>
<tr>
<th class="px-3 py-2">ID</th>
<th class="px-3 py-2">Semaine</th>
<th class="px-3 py-2">Label</th>
<th class="px-3 py-2">Statut</th>
<th class="px-3 py-2">Cr&eacute;&eacute; par</th>
<th class="px-3 py-2">Serveurs</th>
<th class="px-3 py-2">H-Prod</th>
<th class="px-3 py-2">Prod</th>
<th class="px-3 py-2">Patch&eacute;s</th>
<th class="px-3 py-2">KO</th>
<th class="px-3 py-2">Date</th>
<th class="px-3 py-2">Actions</th>
</tr>
</thead>
<tbody>
{% for r in runs %}
<tr onclick="window.location='/quickwin/{{ r.id }}'" style="cursor:pointer">
<td class="px-3 py-2" style="color:#00d4ff;font-weight:bold">#{{ r.id }}</td>
<td class="px-3 py-2">S{{ '%02d'|format(r.week_number) }} {{ r.year }}</td>
<td class="px-3 py-2">{{ r.label }}</td>
<td class="px-3 py-2">
{% if r.status == 'draft' %}<span class="badge badge-gray">Brouillon</span>
{% elif r.status == 'hprod_in_progress' %}<span class="badge badge-yellow">H-Prod en cours</span>
{% elif r.status == 'hprod_done' %}<span class="badge badge-blue">H-Prod termin&eacute;</span>
{% elif r.status == 'prod_in_progress' %}<span class="badge badge-yellow">Prod en cours</span>
{% elif r.status == 'completed' %}<span class="badge badge-green">Termin&eacute;</span>
{% elif r.status == 'cancelled' %}<span class="badge badge-red">Annul&eacute;</span>
{% endif %}
</td>
<td class="px-3 py-2 text-gray-400">{{ r.created_by_name or '?' }}</td>
<td class="px-3 py-2 text-center">{{ r.total_entries }}</td>
<td class="px-3 py-2 text-center">{{ r.hprod_count }}</td>
<td class="px-3 py-2 text-center">{{ r.prod_count }}</td>
<td class="px-3 py-2 text-center" style="color:#00ff88">{{ r.patched_count }}</td>
<td class="px-3 py-2 text-center" style="color:#ff3366">{{ r.failed_count }}</td>
<td class="px-3 py-2 text-gray-500 text-xs">{{ r.created_at.strftime('%d/%m %H:%M') if r.created_at else '' }}</td>
<td class="px-3 py-2">
<a href="/quickwin/{{ r.id }}" class="btn-sm" style="background:#1e3a5f;color:#00d4ff">Voir</a>
</td>
</tr>
{% endfor %}
{% if not runs %}
<tr><td colspan="12" class="px-3 py-8 text-center text-gray-500">Aucune campagne QuickWin</td></tr>
{% endif %}
</tbody>
</table>
</div>
</div>
<!-- Create modal -->
<div id="createModal" style="display:none;position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,.7);z-index:100;align-items:center;justify-content:center" onclick="if(event.target===this)this.style.display='none'">
<div class="card" style="width:500px;max-width:90vw;padding:24px">
<h3 style="color:#00d4ff;font-size:1.1rem;font-weight:bold;margin-bottom:16px">Nouveau QuickWin</h3>
<form method="post" action="/quickwin/create">
<div class="mb-3">
<label class="text-xs text-gray-400 block mb-1">Label</label>
<input type="text" name="label" placeholder="Quick Win S{{ '%02d'|format(current_week) }} {{ current_year }}" style="width:100%">
</div>
<div class="flex gap-3 mb-3">
<div class="flex-1">
<label class="text-xs text-gray-400 block mb-1">Semaine</label>
<input type="number" name="week_number" value="{{ current_week }}" min="1" max="53" style="width:100%">
</div>
<div class="flex-1">
<label class="text-xs text-gray-400 block mb-1">Ann&eacute;e</label>
<input type="number" name="year" value="{{ current_year }}" style="width:100%">
</div>
</div>
<div class="mb-3">
<label class="text-xs text-gray-400 block mb-1">Serveurs (IDs, vide = tous les configur&eacute;s)</label>
<input type="text" name="server_ids" placeholder="Laisser vide pour tous les serveurs configur&eacute;s" style="width:100%">
</div>
<div class="mb-3">
<label class="text-xs text-gray-400 block mb-1">Notes</label>
<textarea name="notes" rows="2" style="width:100%" placeholder="Commentaires..."></textarea>
</div>
<div class="flex gap-2 justify-end mt-4">
<button type="button" class="btn-sm" style="background:#333;color:#ccc;padding:6px 16px" onclick="document.getElementById('createModal').style.display='none'">Annuler</button>
<button type="submit" class="btn-primary" style="padding:6px 20px">Cr&eacute;er</button>
</div>
</form>
</div>
</div>
{% endblock %}