GUI : réparer « Appliquer le plan » (forçait pas) + rendre l'auto-actif visible
Bug racine : /api/instancier appelait « instancier appliquer » SANS --force → refus silencieux dès que le plan divergeait de l'inventaire. Après une édition (disque, état, auto-actif), l'inventaire n'était jamais régénéré → compteurs figés (« 0 actifs » alors qu'un hôte était actif au plan). Le clic « Appliquer » = intention explicite → on force. Aussi : - après matérialisation (creer/deployer/pousser), le frontend régénère l'inventaire (appliquerPlan) au lieu d'un simple rechargement ; - compteur « vivantes » dans l'en-tête (depuis la sonde). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
347e739818
commit
213724f566
2 changed files with 19 additions and 5 deletions
11
CHANGELOG.md
11
CHANGELOG.md
|
|
@ -10,7 +10,16 @@
|
|||
(`/api/sondes`, en parallèle) et affiche un état réel — **● vivante** / **● injoignable**
|
||||
— sur les tuiles et dans le détail (« Plan : … · Réel : … »), distinct du plan.
|
||||
- **Auto-actif** : un hôte qu'on **matérialise** (clone `creer` réussi) ou qu'on
|
||||
**déploie** passe automatiquement `actif` dans le plan (matérialisé = actif).
|
||||
**déploie** passe automatiquement `actif` dans le plan (matérialisé = actif), puis
|
||||
l'inventaire est **régénéré** pour que le changement se voie partout (en-tête inclus).
|
||||
- **Compteur « vivantes »** dans l'en-tête (depuis la sonde), à côté de actifs/planifiés.
|
||||
|
||||
### Corrigé
|
||||
- **Le bouton ⚙ « Appliquer le plan » du GUI refusait en silence** dès que le plan
|
||||
divergeait de l'inventaire (il appelait `instancier appliquer` **sans** `--force`).
|
||||
Résultat : après une édition (disque, état, auto-actif), l'inventaire n'était jamais
|
||||
régénéré et les compteurs restaient figés. Le clic « Appliquer » **est** l'intention
|
||||
explicite → le GUI force désormais (git reste le filet).
|
||||
|
||||
- **Bouton « Pousser » dans le GUI — le flux devient 100 % cliquable.** Chaque objet
|
||||
du détail se matérialise sur son hôte, en streaming console (avec mot de passe vault
|
||||
|
|
|
|||
|
|
@ -979,12 +979,15 @@ HTML = r"""<!doctype html>
|
|||
function dessinerResume() {
|
||||
const actifs = hotes.filter(h => h.etat === 'actif').length;
|
||||
const bloques = hotes.filter(h => hoteBloque(h)).length;
|
||||
const vivantes = hotes.filter(h => sondes[h.nom] === true).length;
|
||||
const sonde = Object.keys(sondes).length > 0;
|
||||
document.getElementById('resume').innerHTML = `
|
||||
${estProduction ? '<span class="badge-prod" title="Instance de PRODUCTION : déploiement sous confirmation renforcée">PROD</span>' : '<span class="badge-lab" title="Instance bac à sable (setops_production: false)">bac à sable</span>'}
|
||||
<span class="chip"><b>${hotes.length}</b> hôtes</span>
|
||||
<span class="chip"><span class="pt actif"></span><b>${actifs}</b> actifs</span>
|
||||
<span class="chip"><span class="pt plan"></span><b>${hotes.length - actifs}</b> planifiés</span>
|
||||
${bloques ? `<span class="chip"><span class="pt bloq"></span><b>${bloques}</b> bloqués</span>` : ''}`;
|
||||
${bloques ? `<span class="chip"><span class="pt bloq"></span><b>${bloques}</b> bloqués</span>` : ''}
|
||||
${sonde ? `<span class="chip" title="État RÉEL : VM joignables (sonde SSH), indépendamment du plan"><span class="pt actif"></span><b>${vivantes}</b> vivantes</span>` : ''}`;
|
||||
}
|
||||
|
||||
function correspondServeur(s) {
|
||||
|
|
@ -1727,8 +1730,8 @@ HTML = r"""<!doctype html>
|
|||
if (rc === null) rc = 1;
|
||||
finirConsole(rc);
|
||||
if (mode === 'verifier' && rc === 0) { verifie[hote] = true; message('Vérification réussie — déploiement débloqué pour ' + hote + '.', 'ok'); }
|
||||
else if (mode === 'creer') { message(rc === 0 ? 'VM « ' + hote + ' » créée.' : 'Échec de la création.', rc === 0 ? 'ok' : 'erreur'); if (rc === 0) charger(); }
|
||||
else if (mode === 'deployer' || mode === 'pousser') { verifie[hote] = false; message(rc === 0 ? 'Poussée terminée.' : 'Poussée en échec.', rc === 0 ? 'ok' : 'erreur'); }
|
||||
else if (mode === 'creer') { message(rc === 0 ? 'VM « ' + hote + ' » créée — hôte marqué actif.' : 'Échec de la création.', rc === 0 ? 'ok' : 'erreur'); if (rc === 0) appliquerPlan(); else sonder(); }
|
||||
else if (mode === 'deployer' || mode === 'pousser') { verifie[hote] = false; message(rc === 0 ? 'Poussée terminée — hôte marqué actif.' : 'Poussée en échec.', rc === 0 ? 'ok' : 'erreur'); if (rc === 0) appliquerPlan(); else sonder(); }
|
||||
} catch (e) {
|
||||
ecrireConsole('Erreur client : ' + e.message + '\n'); finirConsole(1);
|
||||
}
|
||||
|
|
@ -2012,8 +2015,10 @@ class Gestionnaire(BaseHTTPRequestHandler):
|
|||
ecrire_intrants(donnees)
|
||||
self.repondre_json(200, inventaire_api(self.inventaire))
|
||||
elif chemin == "/api/instancier":
|
||||
# Cliquer « Appliquer le plan » EST l'intention explicite : on force
|
||||
# (le diff-refus est un garde-fou CLI ; ici le clic le confirme). git = filet.
|
||||
resultat = subprocess.run(
|
||||
["python3", str(RACINE / "scripts/instancier.py"), "appliquer"],
|
||||
["python3", str(RACINE / "scripts/instancier.py"), "appliquer", "--force"],
|
||||
capture_output=True, text=True, cwd=str(RACINE))
|
||||
self.repondre_json(200, {"ok": resultat.returncode == 0,
|
||||
"sortie": (resultat.stdout + resultat.stderr).strip()})
|
||||
|
|
|
|||
Loading…
Reference in a new issue