gmao/app_new/templates/admin/template_debug.html
root c4db4a1e12
Some checks are pending
CI - Tests et Syntax / lint-and-test (push) Waiting to run
Distinguer alertes et notifications système
2026-08-21 11:47:58 +00:00

109 lines
7.2 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{% extends "base.html" %}
{% block title %}Audit des templates — Administration{% endblock %}
{% block content %}
<div class="container-fluid py-3">
<div class="d-flex flex-column flex-lg-row justify-content-between align-items-lg-center gap-2 mb-3">
<div>
<h1 class="h3 mb-1"><i class="bi bi-files"></i> Audit des templates</h1>
<p class="text-muted mb-0">Repérez les copies identiques ou divergentes et marquez celles qui ne doivent plus être utilisées.</p>
</div>
<a href="{{ url_for('admin.data_management') }}" class="btn btn-outline-secondary btn-sm"><i class="bi bi-arrow-left"></i> Gestion des données</a>
</div>
<div class="alert alert-info py-2">
<i class="bi bi-info-circle"></i> Le marquage <strong>obsolète</strong> est documentaire : aucun fichier nest supprimé et le fonctionnement du site nest pas modifié.
« Utilisé probablement » reflète lordre des chargeurs Jinja ; vérifiez les routes avant toute suppression manuelle.
</div>
<div class="card border-0 shadow-sm mb-3">
<div class="card-header d-flex justify-content-between align-items-center">
<strong><i class="bi bi-diagram-3"></i> Architecture cible des templates</strong>
<span class="badge bg-primary">Convention recommandée</span>
</div>
<div class="card-body">
<p class="small text-muted">Le domaine métier est propriétaire de ses écrans. Le dossier global reste réservé au socle partagé ; une seule copie canonique doit être conservée par écran.</p>
<div class="row g-2">
{% for node in template_architecture %}
<div class="col-md-6 col-xl-3">
<div class="border rounded h-100 p-2 {% if 'transition' in node.label|lower %}bg-warning-subtle{% else %}bg-light{% endif %}">
<code class="d-block text-break">{{ node.path }}</code>
<strong class="small">{{ node.label }}</strong>
<p class="small text-muted mb-1">{{ node.description }}</p>
<div class="small">{% for child in node.children %}<span class="badge text-bg-secondary me-1 mb-1">{{ child }}</span>{% endfor %}</div>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
<div class="row g-2 mb-3">
{% for label, value, color in [('Templates', stats.total, 'primary'), ('Groupes doublons', stats.duplicate_groups, 'warning'), ('Identiques', stats.identical_groups, 'success'), ('Divergents', stats.divergent_groups, 'danger'), ('Marqués obsolètes', stats.obsolete, 'secondary')] %}
<div class="col-6 col-md"><div class="card border-0 shadow-sm h-100"><div class="card-body py-2"><div class="small text-muted">{{ label }}</div><div class="h4 text-{{ color }} mb-0">{{ value }}</div></div></div></div>
{% endfor %}
</div>
<div class="d-flex flex-wrap gap-2 align-items-center mb-3">
<span class="small text-muted">Afficher :</span>
<div class="btn-group btn-group-sm" role="group" aria-label="Filtre des templates">
<a class="btn {{ 'btn-primary' if selected_filter == 'duplicates' else 'btn-outline-primary' }}" href="{{ url_for('admin.template_debug', filter='duplicates') }}">Doublons actifs</a>
<a class="btn {{ 'btn-primary' if selected_filter == 'identical' else 'btn-outline-primary' }}" href="{{ url_for('admin.template_debug', filter='identical') }}">Identiques</a>
<a class="btn {{ 'btn-primary' if selected_filter == 'divergent' else 'btn-outline-primary' }}" href="{{ url_for('admin.template_debug', filter='divergent') }}">Divergents</a>
<a class="btn {{ 'btn-primary' if selected_filter == 'all' else 'btn-outline-primary' }}" href="{{ url_for('admin.template_debug', filter='all') }}">Tous les actifs</a>
<a class="btn {{ 'btn-secondary' if selected_filter == 'obsolete' else 'btn-outline-secondary' }}" href="{{ url_for('admin.template_debug', filter='obsolete') }}">Traités / obsolètes</a>
</div>
</div>
{% if groups %}
{% for logical_key, templates in groups|dictsort %}
<div class="card border-0 shadow-sm mb-3">
<div class="card-header d-flex flex-wrap justify-content-between gap-2 align-items-center">
<div>
<code>{{ logical_key }}</code>
<span class="text-muted small ms-2">Cible : <code>{{ templates[0].target_path }}</code></span>
</div>
{% if templates[0].duplicate_count > 1 %}
<span class="badge bg-{{ 'success' if templates[0].comparison == 'identique' else 'danger' }}">{{ templates[0].duplicate_count }} copies — {{ templates[0].comparison }}</span>
{% else %}<span class="badge bg-secondary">unique</span>{% endif %}
</div>
<div class="table-responsive">
<table class="table table-sm align-middle mb-0">
<thead><tr><th>Fichier</th><th>Architecture cible</th><th>Source</th><th>État estimé</th><th>Empreinte</th><th>Actions</th><th style="min-width:300px">Décision</th></tr></thead>
<tbody>
{% for template in templates %}
<tr class="{% if template.mark and template.mark.status == 'obsolete' %}table-secondary{% endif %}">
<td><code class="text-break">{{ template.path }}</code></td>
<td><code class="text-break small">{{ template.target_path }}</code></td>
<td><span class="badge bg-{{ 'primary' if template.source == 'global' else 'info' }}">{{ template.source }}</span></td>
<td>
{% if template.mark and template.mark.status == 'obsolete' %}<span class="badge bg-secondary">Obsolète</span>
{% elif template.probable_active %}<span class="badge bg-success">Utilisé probablement</span>
{% else %}<span class="badge bg-warning text-dark">Masqué probablement</span>{% endif %}
</td>
<td><code title="{{ template.hash }}">{{ template.hash[:10] }}</code></td>
<td><a class="btn btn-outline-primary btn-sm" href="{{ url_for('admin.template_debug_preview', path=template.path) }}" target="_blank" rel="noopener"><i class="bi bi-eye"></i> Prévisualiser</a></td>
<td>
<form method="post" action="{{ url_for('admin.template_debug_mark') }}" class="d-flex gap-1">
<input type="hidden" name="path" value="{{ template.path }}">
<input type="hidden" name="return_filter" value="{{ selected_filter }}">
{% if template.mark and template.mark.status == 'obsolete' %}
<span class="small text-muted flex-grow-1">{{ template.mark.notes or 'Aucune note' }}</span>
<button class="btn btn-outline-success btn-sm" name="action" value="restore"><i class="bi bi-arrow-counterclockwise"></i> Réactiver</button>
{% else %}
<input class="form-control form-control-sm" name="notes" placeholder="Raison / remplacement conseillé">
<button class="btn btn-outline-danger btn-sm text-nowrap" name="action" value="obsolete"><i class="bi bi-archive"></i> Obsolète</button>
{% endif %}
</form>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endfor %}
{% else %}
<div class="alert alert-secondary">Aucun template ne correspond à ce filtre.</div>
{% endif %}
</div>
{% endblock %}