diff --git a/CHANGELOG.md b/CHANGELOG.md
index 587f6eb..a917ec9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -64,6 +64,12 @@
comme valeurs par défaut, surchargeables par hôte.
### Modifié
+- **Détail GUI : section « Groupes (dérivés) » retirée (redondante).** Depuis la fusion
+ en atelier maître-détail, elle ne répétait que le socle (universel), les rôles des
+ applications (déjà dans « Applications ici ») et les intégrations (déjà cochées). Son
+ seul signal unique — le prérequis bloquant — est désormais nommé dans le pied
+ (« Prérequis manquant : … ») ; le panneau Dépendances reste pour la vue d'ensemble.
+ Code mort retiré (`renduGroupe`, `detailGroupe`, `titreGroupe`, CSS `.groupe*`).
- **Nettoyage CSS/HTML du GUI** après la refonte : retrait des règles et éléments
morts (`.message`, `.chips-filtre`/`.chip-f`, `.onglet*`, `.base-ligne`,
`.bases-liste`, `.ch-grp*`/`.ch-fleche`/`.ch-roles`, `.champ-val`, divs `#message`
diff --git a/scripts/inventory_gui.py b/scripts/inventory_gui.py
index 8083db4..22c2632 100644
--- a/scripts/inventory_gui.py
+++ b/scripts/inventory_gui.py
@@ -687,14 +687,6 @@ HTML = r"""
transition: opacity .12s ease, transform .12s ease;
}
#infobulle.on { opacity: 1; transform: none; }
- .groupes-liste { display: grid; gap: 7px; }
- .groupe { display: block; border: 1px solid var(--ligne); border-radius: var(--rayon-sm); padding: 8px 10px; background: var(--surface-2); transition: border-color .12s, background .12s; }
- .groupe.selectionne { border-color: color-mix(in srgb, var(--bleu) 55%, var(--ligne)); background: var(--bleu-fond); }
- .groupe.ok { border-color: color-mix(in srgb, var(--vert) 55%, var(--ligne)); background: var(--vert-fond); }
- .groupe.attente { border-color: color-mix(in srgb, var(--ambre) 55%, var(--ligne)); background: var(--ambre-fond); }
- .groupe.bloque { border-color: color-mix(in srgb, var(--rouge) 60%, var(--ligne)); background: var(--rouge-fond); }
- .groupe-ligne { display: flex; align-items: center; gap: 8px; font-weight: 700; font-size: 13px; overflow-wrap: anywhere; }
- .groupe-detail { color: var(--muted); font-size: 11px; line-height: 1.35; margin: 4px 0 0 23px; }
.pied { padding: 12px 16px; border-top: 1px solid var(--ligne); display: flex; gap: 8px; align-items: center; }
.pied .grandit { flex: 1; }
.pied .hint-dep { color: var(--faint); font-size: 12px; font-style: italic; }
@@ -1305,9 +1297,6 @@ HTML = r"""
const info = infoFonction(s.fonction);
const zoneHint = info ? `${echapper(info.libelle)} · VLAN ${info.vlan}` : '';
const h = hotes.find(x => x.nom === s.nom);
- const grpHtml = h && (h.groupes || []).length
- ? `
${h.groupes.map(g => renduGroupe(h, g)).join('')}
`
- : `${s.statut === 'absent' ? 'Pas encore instancié — « Appliquer le plan ».' : 'Aucun groupe.'}
`;
const apps = applications.filter(a => a.hote === s.nom);
const appsHtml = apps.length
? `${apps.map(a => `
app ${a.expose ? ` → ${echapper(listeDepuisTexte(a.expose).join(', '))}` : ''}
`).join('')}
`
@@ -1325,7 +1314,10 @@ HTML = r"""
`;
} else {
- const txt = !h ? 'Applique le plan pour instancier cet hôte' : (h.etat !== 'actif' ? 'Hôte actif requis pour déployer' : 'Prérequis manquant');
+ const manquants = h ? [...new Set((h.groupes || []).flatMap(g => manquantsPourGroupe(g)))] : [];
+ const txt = !h ? 'Applique le plan pour instancier cet hôte'
+ : (h.etat !== 'actif' ? 'Hôte actif requis pour déployer'
+ : ('Prérequis manquant' + (manquants.length ? ' : ' + manquants.join(', ') : '')));
pied = `${txt}
`;
}
const statBadge = s.statut === 'divergence' ? 'divergent'
@@ -1348,7 +1340,6 @@ HTML = r"""
- Groupes (dérivés)
${grpHtml}
Applications ici
${appsHtml}
Bases ici
${bdHtml}
VMID / IP / VLAN sont dérivés. Sauvegarde (Ctrl+S) puis « Appliquer le plan » pour régénérer l'inventaire.
@@ -1453,38 +1444,6 @@ HTML = r"""
if (bd) { bd.disabled = occupe || !verifie[hote]; bd.title = !verifie[hote] ? 'Vérifiez (dry-run) d\'abord' : 'Applique les playbooks sur la VM réelle'; }
}
- function renduGroupe(hote, groupe) {
- const manquants = manquantsPourGroupe(groupe);
- const config = dependances[groupe] || {};
- let statut = 'selectionne';
- if (hote.etat === 'actif' && manquants.length) statut = 'bloque';
- else if (hote.etat === 'actif') statut = 'ok';
- else if ((config.requiert_groupes_actifs || []).length) statut = 'attente';
- return `
-
- ${echapper(groupe)}
- ${echapper(detailGroupe(groupe, hote))}
-
`;
- }
-
- function detailGroupe(groupe, hote) {
- const requis = ((dependances[groupe] || {}).requiert_groupes_actifs || []);
- if (!requis.length) return 'aucun prérequis actif';
- const manquants = manquantsPourGroupe(groupe);
- if (!manquants.length) return `prérequis actifs : ${requis.join(', ')}`;
- if (hote.etat === 'actif') return `manquant : ${manquants.join(', ')}`;
- return `requerra : ${requis.join(', ')}`;
- }
-
- function titreGroupe(groupe) {
- const config = dependances[groupe] || {};
- const requis = config.requiert_groupes_actifs || [];
- const lignes = [requis.length ? `Prérequis actif : ${requis.join(', ')}` : 'Aucun prérequis actif déclaré.'];
- if (config.raison) lignes.push(config.raison);
- if (config.surveillance) lignes.push(config.surveillance);
- return lignes.join('\n');
- }
-
function fonctionDe(nom) {
const m = (nom || '').match(/^(.+)-(\d+)$/);
return m ? {fonction: m[1], seq: parseInt(m[2], 10)} : {fonction: nom || '', seq: null};