patchcenter/app/templates/specifics.html
Khalid MOUTAOUAKIL 032e91a90c BOC SAP corrigé, stop/start order, patch waves, DMZ zone, préférences patching
- BOC SAP: stop_order ajouté (SolMan→CM→CC→AS→CI→HANA), conforme doc v3.1.4
- 3 serveurs BOC HO ajoutés (vpbocarep1, vpbocasec1, vpbocjump1)
- Patch waves: DNS (V1: 1+3, V2: 2+4), SMTP (V1: smtp2, V2: smtp1)
- Colonnes Stop order / Start order dans Spécifiques
- Campagne: colonne Zone (DMZ rouge, EMV jaune, LAN bleu) + KPI DMZ
- DMZ: filtre par zone au lieu de domaine (27 serveurs récupérés)
- Préférences patching: jour/heure éditables dans serveurs, hérités en campagne
- KPIs campagne en flex (une seule ligne)
- Limites intervenants: layout compact (max-width 400px)
- Tri campagne: domaine → hors-prod/prod → hostname
- Opérateur peut prendre en in_progress + planned
- Actions bulk campagne: prendre/assigner/exclure en masse
- Formulaires inline: fix Alpine.js → JS pur (display:none par défaut)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 03:52:46 +02:00

103 lines
6.1 KiB
HTML

{% extends 'base.html' %}
{% block title %}Serveurs specifiques{% endblock %}
{% block content %}
<div class="flex justify-between items-center mb-4">
<h2 class="text-xl font-bold text-cyber-accent">Serveurs specifiques <span class="text-sm text-gray-500">({{ entries|length }})</span></h2>
</div>
{% set msg = request.query_params.get('msg') %}
{% if msg %}
<div class="mb-4 p-2 rounded text-sm {% if msg in ('not_found','exists') %}bg-red-900/30 text-cyber-red{% else %}bg-green-900/30 text-cyber-green{% endif %}">
{% if msg == 'saved' %}Specificites sauvegardees.{% elif msg == 'added' %}Serveur ajoute.{% elif msg == 'not_found' %}Hostname non trouve en base.{% elif msg == 'exists' %}Ce serveur a deja des specificites.{% endif %}
</div>
{% endif %}
<!-- Filtres -->
<div class="flex gap-3 mb-4 items-center flex-wrap">
<a href="/specifics" class="btn-sm {% if not filter_type %}bg-cyber-accent text-black{% else %}bg-cyber-border text-gray-300{% endif %}">Tous ({{ entries|length }})</a>
{% for t in types_in_db %}
<a href="/specifics?app_type={{ t }}" class="btn-sm {% if filter_type == t %}bg-cyber-accent text-black{% else %}bg-cyber-border text-gray-300{% endif %}">{{ t }}</a>
{% endfor %}
<form method="GET" action="/specifics" class="flex gap-1 ml-auto">
<input type="text" name="search" value="{{ filter_search or '' }}" placeholder="Hostname..." class="text-xs py-1 px-2 w-36">
<button type="submit" class="btn-sm bg-cyber-border text-cyber-accent">Chercher</button>
</form>
</div>
<!-- Panel édition -->
<div id="edit-panel" class="card mb-4 p-5" style="display:none"></div>
<!-- Table -->
<div class="card overflow-x-auto">
<table class="w-full table-cyber">
<thead><tr>
<th class="text-left p-2">Hostname</th>
<th class="p-2">Type</th>
<th class="p-2">Domaine</th>
<th class="p-2">Env</th>
<th class="p-2">Flags</th>
<th class="p-2">Stop order</th>
<th class="p-2">Start order</th>
<th class="p-2">Wave</th>
<th class="p-2">Auto-restart</th>
<th class="text-left p-2">Note</th>
<th class="p-2">Actions</th>
</tr></thead>
<tbody>
{% for e in entries %}
<tr id="row-{{ e.id }}">
<td class="p-2 font-mono text-sm text-cyber-accent">{{ e.hostname }}</td>
<td class="p-2 text-center"><span class="badge badge-blue">{{ e.app_type or '-' }}</span></td>
<td class="p-2 text-center text-xs">{{ e.domaine or '-' }}</td>
<td class="p-2 text-center"><span class="badge {% if e.environnement == 'Production' %}badge-green{% else %}badge-yellow{% endif %}">{{ (e.environnement or '-')[:6] }}</span></td>
<td class="p-2 text-center">
<div class="flex gap-0.5 justify-center flex-wrap">
{% if e.kernel_update_blocked %}<span class="badge badge-red" title="Kernel bloque">K</span>{% endif %}
{% if e.is_cluster %}<span class="badge badge-blue" title="Cluster">C</span>{% endif %}
{% if e.is_db %}<span class="badge badge-yellow" title="BDD">DB</span>{% endif %}
{% if e.is_middleware %}<span class="badge badge-gray" title="Middleware">MW</span>{% endif %}
{% if e.sentinel_disable_required %}<span class="badge badge-red" title="SentinelOne">S1</span>{% endif %}
{% if e.ip_forwarding_required %}<span class="badge badge-yellow" title="IP Forward">IP</span>{% endif %}
{% if e.rolling_update %}<span class="badge badge-blue" title="Rolling update">RU</span>{% endif %}
{% if e.needs_manual_step %}<span class="badge badge-yellow" title="Etape manuelle">M</span>{% endif %}
{% if e.extra_excludes %}<span class="badge badge-gray" title="Excludes: {{ e.extra_excludes }}">EX</span>{% endif %}
</div>
</td>
<td class="p-2 text-center text-xs">{% if e.stop_order %}#{{ e.stop_order }}{% else %}-{% endif %}</td>
<td class="p-2 text-center text-xs">{% if e.reboot_order %}#{{ e.reboot_order }}{% if e.patch_order_group %} <span class="text-gray-600">({{ e.patch_order_group }})</span>{% endif %}{% else %}-{% endif %}</td>
<td class="p-2 text-center text-xs">{% if e.patch_wave %}<span class="badge badge-blue">V{{ e.patch_wave }}</span> <span class="text-gray-500">{{ e.patch_wave_group or "" }}</span>{% else %}-{% endif %}</td>
<td class="p-2 text-center"><span class="badge {% if e.auto_restart %}badge-green{% else %}badge-red{% endif %}">{{ 'Oui' if e.auto_restart else 'Non' }}</span></td>
<td class="p-2 text-xs text-gray-400" style="max-width:300px">{{ (e.note or '')[:80] }}{% if e.note and e.note|length > 80 %}...{% endif %}</td>
<td class="p-2 text-center">
<button class="btn-sm bg-cyber-border text-cyber-accent"
hx-get="/specifics/{{ e.id }}/edit" hx-target="#edit-panel" hx-swap="innerHTML"
onclick="document.getElementById('edit-panel').style.display='block'; window.scrollTo({top:0,behavior:'smooth'})">Edit</button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<!-- Panel edition -->
<!-- Ajouter -->
<div class="card p-4 mt-4">
<h4 class="text-sm font-bold text-cyber-accent mb-3">Ajouter un serveur specifique</h4>
<form method="POST" action="/specifics/add" class="flex gap-3 items-end">
<div>
<label class="text-xs text-gray-500">Hostname</label>
<input type="text" name="hostname" required placeholder="vpinfaweb1" class="text-xs py-1 px-2 w-44">
</div>
<div>
<label class="text-xs text-gray-500">Type application</label>
<select name="app_type" class="text-xs py-1 px-2">
<option value="">-</option>
{% for t in app_types %}<option value="{{ t }}">{{ t }}</option>{% endfor %}
</select>
</div>
<button type="submit" class="btn-primary px-4 py-1 text-sm">Ajouter</button>
</form>
</div>
{% endblock %}