From 25cc780005c0fb551f52a78eecfb159b982dab03 Mon Sep 17 00:00:00 2001 From: Mathieu Benoit Date: Sat, 1 Aug 2026 06:27:25 -0400 Subject: [PATCH] [FIX] qemu form: tick nothing in the catalog by default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The form opened with the four main versions already ticked, so the plan showed four VMs nobody had asked for. F5 on an untouched form would have created them. Deploying is expensive and hard to undo — the list now starts empty and the choice is made, not inherited. The « * » still marks each distro's main version, and F7 ticks exactly those four in one keystroke, so nothing is lost but the presumption. With an empty list a « 0 VM · 0 vCPU » total teaches nothing, so the footer says what to do instead: tick what to deploy, F7 main versions, F6 all. Verified headless: no box ticked on open, F5 producing no spec at all, F7 giving back the four, and the ticks surviving a switch to « all architectures » (4 of 30) since identity is distro/version/arch, not rank. Co-Authored-By: Claude Opus 4.8 (1M context) --- script/todo/qemu_deploy_form.py | 39 +++++++++++++++++++++------------ script/todo/todo_i18n.py | 8 +++++++ 2 files changed, 33 insertions(+), 14 deletions(-) diff --git a/script/todo/qemu_deploy_form.py b/script/todo/qemu_deploy_form.py index 10420e7..e969f20 100644 --- a/script/todo/qemu_deploy_form.py +++ b/script/todo/qemu_deploy_form.py @@ -453,33 +453,36 @@ def run_deploy_form(ctx, run_app: bool = True): t("Disk"), t("Status"), ) - self._reload_catalog(select_defaults=True) + self._reload_catalog(first_load=True) # -- catalogue et recalcul ------------------------------------- # def _entries(self): return catalog.get(self.arch, []) - def _reload_catalog(self, select_defaults=False): - """Recharge la liste à cocher après un changement d'architecture. - Les cases cochées sont conservées quand la même entrée existe - encore (l'identité est (distro, version, arch), pas le rang).""" + def _reload_catalog(self, first_load=False): + """(Re)charge la liste à cocher. + + RIEN n'est coché d'avance : déployer coûte cher, et une case + pré-cochée ferait créer une VM que personne n'a demandée. Le « * » + marque toujours la version principale, et F7 les coche toutes. + + Après un changement d'architecture, les cases déjà cochées sont + conservées quand l'entrée existe encore — l'identité est + (distro, version, archi), pas le rang dans la liste.""" widget = self.query_one("#f_catalog", SelectionList) - keep = set() - if not select_defaults: - keep = { + keep = ( + set() + if first_load + else { entry_key(self._entries_before[i]) for i in widget.selected if i < len(self._entries_before) } + ) widget.clear_options() entries = self._entries() for i, e in enumerate(entries): - on = ( - e.get("default", False) - if select_defaults - else (entry_key(e) in keep) - ) - widget.add_option((entry_label(e), i, on)) + widget.add_option((entry_label(e), i, entry_key(e) in keep)) self._entries_before = entries self._recompute() @@ -525,6 +528,14 @@ def run_deploy_form(ctx, run_app: bool = True): f"{r['disk_gb']}G", f"{icon}{r['note']}", ) + if not self.rows: + # Rien de coché : un total à zéro n'apprend rien, on dit + # plutôt comment remplir la liste. + self.query_one("#totals", Static).update( + f" {t('Tick what to deploy')} — " + f"{t('F7 main versions · F6 all')}" + ) + return n, cpus, ram, disk = plan_totals(self.rows) warn = "" if free_ram and ram > free_ram: diff --git a/script/todo/todo_i18n.py b/script/todo/todo_i18n.py index 29134cf..155eed5 100644 --- a/script/todo/todo_i18n.py +++ b/script/todo/todo_i18n.py @@ -1475,6 +1475,14 @@ TRANSLATIONS = { "fr": "toutes", "en": "all", }, + "Tick what to deploy": { + "fr": "Cocher ce qu'on veut déployer", + "en": "Tick what to deploy", + }, + "F7 main versions · F6 all": { + "fr": "F7 versions principales · F6 tout", + "en": "F7 main versions · F6 all", + }, "exists - skipped": { "fr": "existe — ignorée", "en": "exists - skipped",