aboutsummaryrefslogtreecommitdiff
path: root/app/ui/hub.py
diff options
context:
space:
mode:
Diffstat (limited to 'app/ui/hub.py')
-rw-r--r--app/ui/hub.py42
1 files changed, 36 insertions, 6 deletions
diff --git a/app/ui/hub.py b/app/ui/hub.py
index f937b84..d20b28e 100644
--- a/app/ui/hub.py
+++ b/app/ui/hub.py
@@ -10,10 +10,10 @@ The entire hub runs in one curses session, driven by a single ``tui.Wizard``
stack of screens (the ``_Hub`` class below). Every menu/action is a screen
that returns the next screen, ``Wizard.BACK`` (Esc/q) to pop one screen, or
None to quit. Backend setup wizards and the conversion run view run as
-opaque leaf screens on this same session (the wizards' long setup tails and
-model downloads run inside the ``ui.taskview`` task view, and only the quick
-uninstall/start/stop actions use ``tui.suspend``); a leaf screen finishes by
-returning ``Wizard.BACK``, so
+opaque leaf screens on this same session; every long step — setup tails,
+model downloads, server start/stop, and uninstall — runs inside the
+``ui.taskview`` task view, so the user is never dropped to the console.
+A leaf screen finishes by returning ``Wizard.BACK``, so
the stack lands back on the menu that launched it. Esc therefore steps back
exactly one screen everywhere — on the main menu (an empty stack) it quits.
'q' mirrors Esc on every screen that has no typed text.
@@ -253,11 +253,41 @@ class _Hub:
return self.screen_setup(info)
def screen_uninstall(self):
+ """Pick a backend, confirm, then uninstall it inside the task view.
+
+ Esc on the picker or the confirm (or answering No) backs out
+ untouched. A confirmed uninstall runs as one task-view step on this
+ session — no console drop: the backend's ``uninstall`` stops its
+ servers, pip-uninstalls, and deletes its files, honoring cancel
+ between phases only. A flash summarizes the result and the stack
+ lands back on the Configure menu, whose status table re-detects the
+ removal.
+ """
info = self._pick_backend(installed_only=True)
if info is None:
return tui.Wizard.BACK
- with tui.suspend(self.stdscr):
- info.uninstall()
+ answer = tui.confirm(
+ self.stdscr, f"Uninstall {info.label}?",
+ body=[f"This permanently removes {info.label} from this "
+ "machine: managed servers are stopped and every installed "
+ "file — including downloaded models — is deleted."],
+ default=False, cancel_value=tui.Wizard.BACK)
+ if answer is not True:
+ return tui.Wizard.BACK
+ title = f"Uninstall {info.label}"
+ step = taskview.TaskStep(
+ title,
+ lambda emit, cancel: info.uninstall(emit=emit, cancel=cancel))
+ rc = taskview.run_steps(self.stdscr, title, [step],
+ wait_on_finish=False)
+ # The uninstallers warn-and-continue (a failed pip step still
+ # returns 0), so rc == 0 means "finished"; anything else covers a
+ # failure or an Esc-cancelled run between phases.
+ if rc == 0:
+ tui.flash(self.stdscr, f"{info.label} uninstalled.", "ok")
+ else:
+ tui.flash(self.stdscr,
+ f"Could not fully uninstall {info.label}.", "err")
return tui.Wizard.BACK
def _pick_backend(self, installed_only: bool):