diff --git a/CHANGELOG.md b/CHANGELOG.md index 55c3588..9dfe0d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,39 @@ ## 2026-06-30 ### Ajouté +- **Fluidité d'exploitation du GUI** (sans dépendance, stdlib pure) : + - **Notifications empilées (toasts)** auto-effaçables au lieu d'une bannière unique + écrasée ; les erreurs restent plus longtemps, les opérations longues mettent à + jour leur propre toast. + - **Durée d'exécution** affichée en direct dans la console (Vérifier / Déployer) et + suivi vivant de « Appliquer le plan ». + - **Navigation clavier** : `1-5` changent de vue, `j/k` parcourent les hôtes, + `v`/`d` vérifient/déploient l'hôte sélectionné, `/` cible le filtre, `Ctrl+S` + sauvegarde la vue éditable courante (ignorés pendant la saisie). + - **Validation inline** des champs du plan (vue Serveurs) : nom `fonction-NN`, + mémoire, cœurs, disque — liseré rouge et blocage avant l'envoi. + - **Garde-fou anti-perte** : confirmation `beforeunload` si des éditions de plan ne + sont pas sauvegardées. + - Le bouton **Sauvegarder** de l'en-tête devient contextuel (sauve la vue éditable, + désactivé en lecture seule) — fin de l'impasse 409 ; suppression du code mort. + +### Modifié +- **Vue Inventaire (cartes) : détail converti en inspection lecture seule.** La vue + affichait « généré depuis le plan (lecture seule) » tout en exposant une surface + d'édition (+ Hôte, ✕, bascule actif/planifié, ✨ Proposer, champs et cases de + groupes éditables) qui ne pouvait pas être persistée (l'inventaire est généré ; + `/api/inventaire` renvoie 409). Ces contrôles orphelins sont retirés : nom, champs + Réseau/Proxmox et groupes en lecture seule, état affiché en badge. **Vérifier / + Déployer** et les onglets d'inspection sont conservés. L'édition reste dans les vues + **Serveurs / Applications / Bases**. Code mort supprimé (`ajouterHote`, + `supprimerHote`, `definir`, `definirNom`, `definirEtat`, `basculerGroupe`, + `proposer`, `autoProposer`, `prochainSeqLibre`, `marquerModifie`, état `modifie`). +- **Référence des paramètres de `make config`** (`docs/config-proxmox.md`). + Explique un par un les 16 paramètres Proxmox non sensibles + les secrets API + demandés par l'assistant : sens, valeur par défaut, quoi saisir, et quels champs + sont des constantes vs des défauts surchargeables par hôte. Renvois ajoutés depuis + `make help` et `QUICKSTART.md`. Comble un trou : ces invites n'étaient expliquées + nulle part de façon pérenne (impératif « exploitable sans IA »). - **Panneau « Intrants de base » dans le GUI.** Un bouton ⚙ Intrants ouvre une fenêtre unique pour saisir les valeurs communes à tout l'écosystème, avec une distinction visible entre **constantes** (valeur unique, non surchargeable) et **défauts** diff --git a/scripts/inventory_gui.py b/scripts/inventory_gui.py index f94a630..fafb439 100644 --- a/scripts/inventory_gui.py +++ b/scripts/inventory_gui.py @@ -556,6 +556,14 @@ HTML = r""" main { padding: 16px 22px 44px; display: grid; grid-template-columns: minmax(0, 1fr) minmax(330px, 380px); gap: 20px; align-items: start; max-width: 1640px; margin: 0 auto; } .message { min-height: 18px; font-size: 13px; font-weight: 650; color: var(--bleu); margin: 0 2px 12px; } .message.erreur { color: var(--rouge); } .message.ok { color: var(--vert); } + .toasts { position: fixed; top: 14px; right: 14px; z-index: 60; display: flex; flex-direction: column; gap: 8px; max-width: min(380px, 92vw); pointer-events: none; } + .toast { pointer-events: auto; background: var(--surface-2); border: 1px solid var(--ligne-forte); border-left: 3px solid var(--bleu); border-radius: var(--rayon-sm); box-shadow: var(--ombre-forte); padding: 9px 12px; font-size: 13px; font-weight: 600; color: var(--texte); display: flex; gap: 9px; align-items: flex-start; animation: toast-in .18s ease-out; } + .toast.ok { border-left-color: var(--vert); } .toast.erreur { border-left-color: var(--rouge); } + .toast.sortant { opacity: 0; transform: translateX(12px); transition: opacity .25s, transform .25s; } + .toast .x { margin-left: auto; cursor: pointer; opacity: .5; font-weight: 800; background: none; border: 0; color: inherit; padding: 0 2px; font-size: 15px; line-height: 1; } + .toast .x:hover { opacity: 1; } + @keyframes toast-in { from { opacity: 0; transform: translateX(12px); } } + input.invalide, select.invalide { border-color: var(--rouge) !important; box-shadow: 0 0 0 1px var(--rouge); } .chips-filtre { display: flex; gap: 7px; flex-wrap: wrap; margin-bottom: 16px; } .chip-f { padding: 6px 13px; border-radius: 999px; border: 1px solid var(--ligne-forte); background: var(--surface-2); color: var(--muted); font-weight: 700; font-size: 12.5px; cursor: pointer; display: inline-flex; align-items: center; gap: 7px; transition: all .14s; } @@ -601,13 +609,7 @@ HTML = r""" .detail.bloque { border-color: color-mix(in srgb, var(--rouge) 50%, var(--ligne)); } .detail-tete { display: flex; align-items: center; gap: 10px; padding: 14px 16px 12px; border-bottom: 1px solid var(--ligne); flex-wrap: wrap; } .detail-nom { flex: 1 1 150px; min-width: 0; } - .detail-nom input { font-weight: 800; font-size: 17px; border-color: transparent; background: transparent; padding: 4px 7px; } - .detail-nom input:hover { background: var(--surface-2); border-color: var(--ligne); } .zone-hint { display: inline-block; margin: 4px 0 0 8px; font-size: 11px; font-weight: 700; color: var(--teal); } - .etat-bascule { display: inline-flex; border: 1px solid var(--ligne-forte); border-radius: 999px; padding: 2px; background: var(--surface-3); gap: 2px; flex: none; } - .etat-bascule button { border: none; background: transparent; border-radius: 999px; padding: 5px 12px; font-size: 12px; font-weight: 750; color: var(--muted); box-shadow: none; } - .etat-bascule button.on { background: var(--surface); color: var(--texte); } - .etat-bascule button.on.actif { color: var(--vert); } .stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(64px, 1fr)); gap: 8px; padding: 14px 16px; } .stat { background: var(--surface-2); border: 1px solid var(--ligne); border-radius: var(--rayon-sm); padding: 9px 10px; min-width: 0; } .stat .v { font-size: 18px; font-weight: 800; line-height: 1.1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } @@ -623,6 +625,9 @@ HTML = r""" .champ > span { color: var(--muted); font-size: 11px; font-weight: 700; } .champ .unite { color: var(--faint); font-weight: 600; } .champ > span.a-aide { cursor: help; border-bottom: 1px dotted var(--ligne-forte); width: fit-content; } + .champ .champ-val { font-size: 13px; font-weight: 600; color: var(--texte); padding: 5px 2px; min-height: 18px; overflow-wrap: anywhere; } + .champ .champ-val.vide { color: var(--faint); } + .detail-nom-txt { font-weight: 800; font-size: 17px; padding: 4px 7px; display: inline-block; overflow-wrap: anywhere; } #infobulle { position: fixed; z-index: 200; max-width: 260px; pointer-events: none; background: var(--surface-3); color: var(--texte); @@ -633,14 +638,12 @@ HTML = r""" } #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); cursor: pointer; transition: border-color .12s, background .12s; } - .groupe:hover { border-color: var(--ligne-forte); } + .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-ligne input { width: 15px; height: 15px; flex: none; accent-color: var(--teal); } .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; } @@ -720,12 +723,13 @@ HTML = r"""
+