Confirm quitting with a vertical leave dialog

Choosing "quit" or pressing Esc at the top menu asked to leave through a
horizontal Yes/No toggle that sat at odds with the rest of the TUI, which is
select lists everywhere else. Replace it with a small select dialog in that
same style: "Quit and disconnect" is the highlighted default so Enter leaves,
while Esc — or choosing "Stay" — returns to the menu.

select() grows optional filterable/footer_hint passthroughs so this short,
fixed choice skips type-to-filter and shows a tailored "Enter quit · Esc stay"
hint.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Jean-Pierre MartineauandClaude Opus 4.8 committed 2026-07-08 21:45:27 -04:00
1 parent 6b84281d0b
commit ebac6c3a4f
2 files changed
+40 -5

No files matched your search

+22 -1
View File
@@ -186,8 +186,29 @@ async def _menu_loop(ctx: AppContext, session: TuiSession) -> None:
selection = await session.select(
"What would you like to do?", items, default=last_selection
)
# Both picking "quit" and pressing Esc at the top level ask to leave; confirm on a
# small dialog first so a stray key doesn't drop the user out of the session. Enter
# takes the highlighted default (Quit) and leaves; Esc — or choosing "Stay" — returns
# to the menu (select maps a cancel to None).
if selection in (None, "__quit__"):
return
leave = await session.select(
"Leave MeshTerm?",
[
Choice(title="Quit and disconnect", value="quit"),
Choice(title="Stay", value="stay"),
],
default="quit",
wrap=False,
filterable=False,
footer_hint="↑↓ move · Enter quit · Esc stay",
)
if leave == "quit":
return
# Keep the cursor on "quit" when that is what they chose, so a follow-up
# attempt lands where they expect; a stray Esc leaves it where it was.
if selection == "__quit__":
last_selection = "__quit__"
continue
last_selection = selection
await _run_selection(ctx, selection)
+18 -4
View File
@@ -146,12 +146,26 @@ class TuiSession:
self.pop(screen)
async def select(
self, title: str, items: list, *, default: Any = None, wrap: bool = True
self,
title: str,
items: list,
*,
default: Any = None,
wrap: bool = True,
filterable: bool = True,
footer_hint: Optional[str] = None,
) -> Any:
"""Show a select screen; return the chosen value or ``None`` if cancelled."""
result = await self.run_screen(
SelectScreen(title, items, default=default, wrap=wrap)
"""Show a select screen; return the chosen value or ``None`` if cancelled.
``filterable`` and ``footer_hint`` are forwarded to the screen for short, fixed
lists (a yes-or-no style choice) that want no type-to-filter and a tailored hint.
"""
screen = (
SelectScreen(title, items, default=default, wrap=wrap, filterable=filterable, footer_hint=footer_hint)
if footer_hint is not None
else SelectScreen(title, items, default=default, wrap=wrap, filterable=filterable)
)
result = await self.run_screen(screen)
return None if result is CANCEL else result
async def select_startup(