patchcenter/app/templates/referentiel.html

434 lines
22 KiB
HTML

{% extends "base.html" %}
{% block title %}Référentiel{% endblock %}
{% block content %}
<div class="flex items-center justify-between mb-4">
<div>
<h1 class="text-xl font-bold" style="color:#00d4ff">R&eacute;f&eacute;rentiel</h1>
<p class="text-xs text-gray-500">Gestion centralis&eacute;e des domaines, environnements, zones et associations</p>
</div>
</div>
{% set msg = request.query_params.get('msg', '') %}
{% set detail = request.query_params.get('detail', '') %}
{% if msg == 'added' %}
<div style="background:#1a5a2e;color:#8f8;padding:8px 16px;border-radius:6px;margin-bottom:12px;font-size:0.85rem">
El&eacute;ment ajout&eacute; avec succ&egrave;s.
</div>
{% elif msg == 'updated' %}
<div style="background:#1a5a2e;color:#8f8;padding:8px 16px;border-radius:6px;margin-bottom:12px;font-size:0.85rem">
El&eacute;ment mis &agrave; jour.
</div>
{% elif msg == 'deleted' %}
<div style="background:#5a3a1a;color:#ffcc00;padding:8px 16px;border-radius:6px;margin-bottom:12px;font-size:0.85rem">
El&eacute;ment supprim&eacute;.
</div>
{% elif msg == 'nodelete' %}
<div style="background:#5a1a1a;color:#ff3366;padding:8px 16px;border-radius:6px;margin-bottom:12px;font-size:0.85rem">
Suppression impossible : {{ detail }} serveur(s) li&eacute;(s). Dissociez-les d'abord.
</div>
{% elif msg == 'exists' %}
<div style="background:#5a3a1a;color:#ffcc00;padding:8px 16px;border-radius:6px;margin-bottom:12px;font-size:0.85rem">
Cette association domaine &times; environnement existe d&eacute;j&agrave;.
</div>
{% endif %}
<!-- Onglets -->
<div style="display:flex;gap:4px;margin-bottom:16px">
{% for t, label in [('domains','Domaines'), ('envs','Environnements'), ('assocs','Associations'), ('zones','Zones'), ('dns','Domaines DNS')] %}
<a href="/referentiel?tab={{ t }}"
style="padding:8px 20px;border-radius:8px 8px 0 0;font-size:0.85rem;font-weight:600;
{% if tab == t %}background:#1e3a5f;color:#00d4ff;border-bottom:2px solid #00d4ff{% else %}background:#111827;color:#94a3b8{% endif %}">
{{ label }}
</a>
{% endfor %}
</div>
<!-- ============================================================ -->
<!-- ONGLET DOMAINES -->
<!-- ============================================================ -->
{% if tab == 'domains' %}
<!-- Sync iTop -->
{% if can_modify %}
<div class="card mb-4" style="padding:12px 16px; display:flex; align-items:center; gap:12px; flex-wrap:wrap;">
<span class="text-sm text-gray-400" style="margin-right:8px">Synchronisation iTop :</span>
<form method="POST" action="/referentiel/itop/sync-from" style="display:inline">
<button type="submit" class="btn-primary" style="padding:6px 16px;font-size:0.85rem"
onclick="this.disabled=true;this.textContent='Sync en cours...';this.form.submit()">
Importer depuis iTop
</button>
</form>
<form method="POST" action="/referentiel/itop/sync-to" style="display:inline">
<button type="submit" style="padding:6px 16px;font-size:0.85rem;background:#334155;color:#e2e8f0;border:1px solid #475569;border-radius:6px;cursor:pointer"
onclick="this.disabled=true;this.textContent='Export en cours...';this.form.submit()">
Exporter vers iTop
</button>
</form>
{% if 'itop_from' in request.query_params.get('msg','') %}
<span class="text-sm text-green-400">Import iTop OK</span>
{% elif 'itop_to' in request.query_params.get('msg','') %}
<span class="text-sm text-green-400">Export iTop OK</span>
{% elif request.query_params.get('msg') == 'itop_noconfig' %}
<span class="text-sm text-red-400">Configurer iTop dans Settings</span>
{% endif %}
</div>
{% endif %}
<div class="card">
<table class="table-cyber w-full">
<thead><tr>
<th class="px-2 py-2" style="width:40px">ID</th>
<th class="px-2 py-2">Nom</th>
<th class="px-2 py-2" style="width:70px">Code</th>
<th class="px-2 py-2">Description</th>
<th class="px-2 py-2" style="width:70px">Ordre</th>
<th class="px-2 py-2" style="width:70px">Actif</th>
<th class="px-2 py-2" style="width:80px">Serveurs</th>
<th class="px-2 py-2" style="width:140px">Actions</th>
</tr></thead>
<tbody>
{% for d in domains %}
<tr id="dom-row-{{ d.id }}">
<form method="post" action="/referentiel/domains/{{ d.id }}/edit">
<td class="px-2 py-2 text-xs text-gray-500">{{ d.id }}</td>
<td class="px-2 py-2"><input type="text" name="name" value="{{ d.name }}" style="width:100%" required></td>
<td class="px-2 py-2"><input type="text" name="code" value="{{ d.code }}" style="width:100%;text-transform:uppercase" required></td>
<td class="px-2 py-2"><input type="text" name="description" value="{{ d.description or '' }}" style="width:100%"></td>
<td class="px-2 py-2"><input type="number" name="display_order" value="{{ d.display_order }}" style="width:100%"></td>
<td class="px-2 py-2 text-center">
<input type="checkbox" name="is_active" {% if d.is_active %}checked{% endif %}>
</td>
<td class="px-2 py-2 text-center">
<span class="badge badge-blue">{{ dom_srv_counts.get(d.id, 0) }}</span>
</td>
<td class="px-2 py-2 text-center" style="white-space:nowrap">
<input type="hidden" name="default_excludes" value="{{ d.default_excludes or '' }}">
<input type="hidden" name="default_patch_window" value="{{ d.default_patch_window or '' }}">
<button type="submit" class="btn-sm" style="background:#00d4ff22;color:#00d4ff;padding:3px 10px">Sauver</button>
</form>
{% if dom_srv_counts.get(d.id, 0) == 0 %}
<form method="post" action="/referentiel/domains/{{ d.id }}/delete" style="display:inline"
onsubmit="return confirm('Supprimer le domaine {{ d.name }} ?')">
<button type="submit" class="btn-sm" style="background:#ff336622;color:#ff3366;padding:3px 10px">Suppr</button>
</form>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% if can_modify %}
<div class="card mt-3" style="padding:12px 16px">
<h3 class="text-sm font-bold mb-2" style="color:#00ff88">Ajouter un domaine</h3>
<form method="post" action="/referentiel/domains/add" style="display:flex;gap:10px;align-items:end;flex-wrap:wrap">
<div>
<label class="text-xs text-gray-500">Nom *</label>
<input type="text" name="name" required style="width:160px" placeholder="Infrastructure">
</div>
<div>
<label class="text-xs text-gray-500">Code *</label>
<input type="text" name="code" required style="width:80px;text-transform:uppercase" placeholder="INF">
</div>
<div>
<label class="text-xs text-gray-500">Description</label>
<input type="text" name="description" style="width:200px">
</div>
<div>
<label class="text-xs text-gray-500">Excludes par d&eacute;faut</label>
<input type="text" name="default_excludes" style="width:200px">
</div>
<div>
<label class="text-xs text-gray-500">Fen&ecirc;tre patch</label>
<input type="text" name="default_patch_window" style="width:120px" placeholder="mardi 22h">
</div>
<div>
<label class="text-xs text-gray-500">Ordre</label>
<input type="number" name="display_order" value="0" style="width:60px">
</div>
<button type="submit" class="btn-primary" style="padding:6px 18px;font-size:0.85rem">Ajouter</button>
</form>
</div>
{% endif %}
<!-- ============================================================ -->
<!-- ONGLET ENVIRONNEMENTS -->
<!-- ============================================================ -->
{% elif tab == 'envs' %}
<div class="card">
<table class="table-cyber w-full">
<thead><tr>
<th class="px-2 py-2" style="width:40px">ID</th>
<th class="px-2 py-2">Nom</th>
<th class="px-2 py-2" style="width:80px">Code</th>
<th class="px-2 py-2" style="width:80px">Serveurs</th>
<th class="px-2 py-2" style="width:140px">Actions</th>
</tr></thead>
<tbody>
{% for e in envs %}
<tr>
<form method="post" action="/referentiel/envs/{{ e.id }}/edit">
<td class="px-2 py-2 text-xs text-gray-500">{{ e.id }}</td>
<td class="px-2 py-2"><input type="text" name="name" value="{{ e.name }}" style="width:100%" required></td>
<td class="px-2 py-2"><input type="text" name="code" value="{{ e.code }}" style="width:100%;text-transform:uppercase" required></td>
<td class="px-2 py-2 text-center">
<span class="badge badge-blue">{{ env_srv_counts.get(e.id, 0) }}</span>
</td>
<td class="px-2 py-2 text-center" style="white-space:nowrap">
<button type="submit" class="btn-sm" style="background:#00d4ff22;color:#00d4ff;padding:3px 10px">Sauver</button>
</form>
{% if env_srv_counts.get(e.id, 0) == 0 %}
<form method="post" action="/referentiel/envs/{{ e.id }}/delete" style="display:inline"
onsubmit="return confirm('Supprimer l environnement {{ e.name }} ?')">
<button type="submit" class="btn-sm" style="background:#ff336622;color:#ff3366;padding:3px 10px">Suppr</button>
</form>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% if can_modify %}
<div class="card mt-3" style="padding:12px 16px">
<h3 class="text-sm font-bold mb-2" style="color:#00ff88">Ajouter un environnement</h3>
<form method="post" action="/referentiel/envs/add" style="display:flex;gap:10px;align-items:end">
<div>
<label class="text-xs text-gray-500">Nom *</label>
<input type="text" name="name" required style="width:200px" placeholder="Production">
</div>
<div>
<label class="text-xs text-gray-500">Code *</label>
<input type="text" name="code" required style="width:80px;text-transform:uppercase" placeholder="PRD">
</div>
<button type="submit" class="btn-primary" style="padding:6px 18px;font-size:0.85rem">Ajouter</button>
</form>
</div>
{% endif %}
<!-- ============================================================ -->
<!-- ONGLET ASSOCIATIONS -->
<!-- ============================================================ -->
{% elif tab == 'assocs' %}
<div class="card">
<div class="table-wrap" style="max-height:60vh;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:40px">ID</th>
<th class="px-2 py-2">Domaine</th>
<th class="px-2 py-2">Environnement</th>
<th class="px-2 py-2">Responsable</th>
<th class="px-2 py-2">Email resp.</th>
<th class="px-2 py-2">R&eacute;f&eacute;rent</th>
<th class="px-2 py-2">Email r&eacute;f.</th>
<th class="px-2 py-2" style="width:60px">Actif</th>
<th class="px-2 py-2" style="width:60px">Srv</th>
<th class="px-2 py-2" style="width:140px">Actions</th>
</tr></thead>
<tbody>
{% for a in assocs %}
<tr>
<form method="post" action="/referentiel/assocs/{{ a.id }}/edit">
<td class="px-2 py-2 text-xs text-gray-500">{{ a.id }}</td>
<td class="px-2 py-2" style="color:#00d4ff;font-weight:600">{{ a.domain_name }}</td>
<td class="px-2 py-2" style="color:#a78bfa">{{ a.env_name }}</td>
<td class="px-2 py-2"><input type="text" name="responsable_nom" value="{{ a.responsable_nom or '' }}" style="width:100%"></td>
<td class="px-2 py-2"><input type="text" name="responsable_email" value="{{ a.responsable_email or '' }}" style="width:100%"></td>
<td class="px-2 py-2"><input type="text" name="referent_nom" value="{{ a.referent_nom or '' }}" style="width:100%"></td>
<td class="px-2 py-2"><input type="text" name="referent_email" value="{{ a.referent_email or '' }}" style="width:100%"></td>
<td class="px-2 py-2 text-center">
<input type="checkbox" name="is_active" {% if a.is_active %}checked{% endif %}>
</td>
<td class="px-2 py-2 text-center">
<span class="badge badge-blue">{{ a.nb_servers or 0 }}</span>
</td>
<td class="px-2 py-2 text-center" style="white-space:nowrap">
<input type="hidden" name="patch_window" value="{{ a.patch_window or '' }}">
<input type="hidden" name="patch_excludes" value="{{ a.patch_excludes or '' }}">
<button type="submit" class="btn-sm" style="background:#00d4ff22;color:#00d4ff;padding:3px 10px">Sauver</button>
</form>
<form method="post" action="/referentiel/assocs/{{ a.id }}/delete" style="display:inline"
onsubmit="return confirm('Supprimer {{ a.domain_name }} x {{ a.env_name }} ?')">
<button type="submit" class="btn-sm" style="background:#ff336622;color:#ff3366;padding:3px 10px">Suppr</button>
</form>
</td>
</tr>
{% endfor %}
{% if not assocs %}
<tr><td colspan="10" class="px-2 py-8 text-center text-gray-500">Aucune association</td></tr>
{% endif %}
</tbody>
</table>
</div>
</div>
{% if can_modify %}
<div class="card mt-3" style="padding:12px 16px">
<h3 class="text-sm font-bold mb-2" style="color:#00ff88">Ajouter une association</h3>
<form method="post" action="/referentiel/assocs/add" style="display:flex;gap:10px;align-items:end;flex-wrap:wrap">
<div>
<label class="text-xs text-gray-500">Domaine *</label>
<select name="domain_id" required style="width:180px">
<option value="">-- Choisir --</option>
{% for d in domains %}<option value="{{ d.id }}">{{ d.name }} ({{ d.code }})</option>{% endfor %}
</select>
</div>
<div>
<label class="text-xs text-gray-500">Environnement *</label>
<select name="environment_id" required style="width:180px">
<option value="">-- Choisir --</option>
{% for e in envs %}<option value="{{ e.id }}">{{ e.name }} ({{ e.code }})</option>{% endfor %}
</select>
</div>
<div>
<label class="text-xs text-gray-500">Responsable</label>
<input type="text" name="responsable_nom" style="width:140px">
</div>
<div>
<label class="text-xs text-gray-500">Email resp.</label>
<input type="email" name="responsable_email" style="width:180px">
</div>
<div>
<label class="text-xs text-gray-500">R&eacute;f&eacute;rent</label>
<input type="text" name="referent_nom" style="width:140px">
</div>
<div>
<label class="text-xs text-gray-500">Email r&eacute;f.</label>
<input type="email" name="referent_email" style="width:180px">
</div>
<button type="submit" class="btn-primary" style="padding:6px 18px;font-size:0.85rem">Ajouter</button>
</form>
</div>
{% endif %}
<!-- ============================================================ -->
<!-- ONGLET ZONES -->
<!-- ============================================================ -->
{% elif tab == 'zones' %}
<div class="card">
<table class="table-cyber w-full">
<thead><tr>
<th class="px-2 py-2" style="width:40px">ID</th>
<th class="px-2 py-2">Nom</th>
<th class="px-2 py-2">Description</th>
<th class="px-2 py-2" style="width:70px">DMZ</th>
<th class="px-2 py-2" style="width:80px">Serveurs</th>
<th class="px-2 py-2" style="width:140px">Actions</th>
</tr></thead>
<tbody>
{% for z in zones %}
<tr>
<form method="post" action="/referentiel/zones/{{ z.id }}/edit">
<td class="px-2 py-2 text-xs text-gray-500">{{ z.id }}</td>
<td class="px-2 py-2"><input type="text" name="name" value="{{ z.name }}" style="width:100%" required></td>
<td class="px-2 py-2"><input type="text" name="description" value="{{ z.description or '' }}" style="width:100%"></td>
<td class="px-2 py-2 text-center">
<input type="checkbox" name="is_dmz" {% if z.is_dmz %}checked{% endif %}>
</td>
<td class="px-2 py-2 text-center">
<span class="badge badge-blue">{{ zone_srv_counts.get(z.id, 0) }}</span>
</td>
<td class="px-2 py-2 text-center" style="white-space:nowrap">
<button type="submit" class="btn-sm" style="background:#00d4ff22;color:#00d4ff;padding:3px 10px">Sauver</button>
</form>
{% if zone_srv_counts.get(z.id, 0) == 0 %}
<form method="post" action="/referentiel/zones/{{ z.id }}/delete" style="display:inline"
onsubmit="return confirm('Supprimer la zone {{ z.name }} ?')">
<button type="submit" class="btn-sm" style="background:#ff336622;color:#ff3366;padding:3px 10px">Suppr</button>
</form>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% if can_modify %}
<div class="card mt-3" style="padding:12px 16px">
<h3 class="text-sm font-bold mb-2" style="color:#00ff88">Ajouter une zone</h3>
<form method="post" action="/referentiel/zones/add" style="display:flex;gap:10px;align-items:end">
<div>
<label class="text-xs text-gray-500">Nom *</label>
<input type="text" name="name" required style="width:160px" placeholder="LAN">
</div>
<div>
<label class="text-xs text-gray-500">Description</label>
<input type="text" name="description" style="width:250px">
</div>
<div style="display:flex;align-items:center;gap:4px;padding-bottom:2px">
<input type="checkbox" name="is_dmz" id="new-dmz">
<label for="new-dmz" class="text-xs text-gray-400">DMZ</label>
</div>
<button type="submit" class="btn-primary" style="padding:6px 18px;font-size:0.85rem">Ajouter</button>
</form>
</div>
{% endif %}
<!-- ============================================================ -->
<!-- ONGLET DOMAINES DNS -->
<!-- ============================================================ -->
{% elif tab == 'dns' %}
<div class="card">
<div class="p-3" style="border-bottom:1px solid #1e3a5f">
<p class="text-xs text-gray-500">Suffixes DNS utilis&eacute;s dans le champ <code>domain_ltd</code> des serveurs (ex: sanef.groupe, sanef-rec.fr)</p>
</div>
<table class="table-cyber w-full">
<thead><tr>
<th class="px-2 py-2" style="width:40px">ID</th>
<th class="px-2 py-2">Nom (suffixe DNS)</th>
<th class="px-2 py-2">Description</th>
<th class="px-2 py-2" style="width:70px">Actif</th>
<th class="px-2 py-2" style="width:80px">Serveurs</th>
<th class="px-2 py-2" style="width:140px">Actions</th>
</tr></thead>
<tbody>
{% for d in dns_domains %}
<tr>
<form method="post" action="/referentiel/dns/{{ d.id }}/edit">
<td class="px-2 py-2 text-xs text-gray-500">{{ d.id }}</td>
<td class="px-2 py-2"><input type="text" name="name" value="{{ d.name }}" style="width:100%" required></td>
<td class="px-2 py-2"><input type="text" name="description" value="{{ d.description or '' }}" style="width:100%"></td>
<td class="px-2 py-2 text-center">
<input type="checkbox" name="is_active" {% if d.is_active %}checked{% endif %}>
</td>
<td class="px-2 py-2 text-center">
<span class="badge badge-blue">{{ dns_srv_counts.get(d.id, 0) }}</span>
</td>
<td class="px-2 py-2 text-center" style="white-space:nowrap">
<button type="submit" class="btn-sm" style="background:#00d4ff22;color:#00d4ff;padding:3px 10px">Sauver</button>
</form>
{% if dns_srv_counts.get(d.id, 0) == 0 %}
<form method="post" action="/referentiel/dns/{{ d.id }}/delete" style="display:inline"
onsubmit="return confirm('Supprimer {{ d.name }} ?')">
<button type="submit" class="btn-sm" style="background:#ff336622;color:#ff3366;padding:3px 10px">Suppr</button>
</form>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% if can_modify %}
<div class="card mt-3" style="padding:12px 16px">
<h3 class="text-sm font-bold mb-2" style="color:#00ff88">Ajouter un domaine DNS</h3>
<form method="post" action="/referentiel/dns/add" style="display:flex;gap:10px;align-items:end">
<div>
<label class="text-xs text-gray-500">Suffixe DNS *</label>
<input type="text" name="name" required style="width:200px" placeholder="sanef.groupe">
</div>
<div>
<label class="text-xs text-gray-500">Description</label>
<input type="text" name="description" style="width:250px" placeholder="Domaine production SANEF">
</div>
<button type="submit" class="btn-primary" style="padding:6px 18px;font-size:0.85rem">Ajouter</button>
</form>
</div>
{% endif %}
{% endif %}
{% endblock %}