Add context listing and switching to the TUI
Press c to list cv4pve-cli contexts and switch between them. The active context is always shown in the header. - Switching runs `cv4pve-cli config use`, which changes the global current context. cv4pve-cli 2.4.0 has no per-call context option. - `config list` has no JSON output, so its text lines are parsed. - The guest table is cleared as soon as another context is chosen, so the old cluster's guests cannot be acted on. - A generation counter drops guest listings that started before a switch, and g and c are refused while a switch runs. Without this, a reload already in flight could refill the table with the old cluster's guests, and VMIDs collide across clusters. 103 tests pass. The switch was tested live from mainframe to mainframe-edge and back. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit was merged in pull request #1.
This commit is contained in:
1 parent
f51aff3db5
commit
62b79ab29e
6 files changed
+543
-9
No files matched your search
@@ -116,3 +116,66 @@ sockets/vCPU/hotplug settings, live auto-refresh.
|
||||
## Open questions
|
||||
|
||||
None blocking.
|
||||
|
||||
---
|
||||
|
||||
# Context switching
|
||||
|
||||
## Problem
|
||||
|
||||
Several cv4pve-cli contexts (clusters) exist; switch between them inside the TUI
|
||||
instead of quitting and running `cv4pve-cli config use`.
|
||||
|
||||
## Decision
|
||||
|
||||
Option A: switching runs `cv4pve-cli config use <name>`, which changes the **global**
|
||||
current context (all shells and scripts follow) and stays after the app exits. cv4pve-cli
|
||||
2.4.0 has no per-call context flag or env var (verified), so there is no app-local option.
|
||||
|
||||
Observed CLI behaviour:
|
||||
|
||||
- `config list` has no `-o json`. Text output, one line per context; current one
|
||||
prefixed with `* `, others with two spaces:
|
||||
`* mainframe mainframe.iot.home.arpa:8006 (api-token)`
|
||||
` mainframe-edge mainframe-edge.home.arpa:8006 (api-token)`
|
||||
- `config use <name>` -> exit 0 on success; unknown name -> exit 3,
|
||||
`Error: Context '<name>' not found.`, current context unchanged.
|
||||
|
||||
### `cli.py`
|
||||
|
||||
- `contexts() -> list[dict]` - `run("config", "list")`, each line parsed to
|
||||
`{"name", "host", "auth", "current": bool}` (regex
|
||||
`^(\*)?\s*(\S+)\s+(\S+)\s+\((.*)\)\s*$`); non-matching lines are ignored.
|
||||
- `use_context(name)` - `run("config", "use", name)`.
|
||||
|
||||
### `app.py` (UI contract)
|
||||
|
||||
- The active context is always visible: `app.sub_title == f"context: {name}"`
|
||||
(shown in the Header). Set on mount from `cli.contexts()` and after every switch.
|
||||
If `contexts()` fails: error notify, sub_title `context: ?`.
|
||||
- Key `c` opens `ContextScreen(ModalScreen[str | None])` with `OptionList#contexts`,
|
||||
one option per context, option id = context name, current one marked with `*`.
|
||||
Selecting an option dismisses with its name; `escape` dismisses with `None`.
|
||||
- `c` while any guest is busy -> warning notify, no screen (VMIDs collide across
|
||||
clusters, so the busy guard would point at the wrong cluster).
|
||||
- Selecting the current context or dismissing -> no CLI call.
|
||||
- A reload started before a switch must not refill the table (generation counter);
|
||||
`g` and `c` are refused while a switch runs; the post-action reload finishes before
|
||||
the guest stops being busy.
|
||||
- Selecting another context: table cleared immediately (old cluster's guests must not
|
||||
stay actionable), then in a worker `cli.use_context(name)`, sub_title updated, guests
|
||||
reloaded. On `CliError`: error notify with summary, sub_title re-read from
|
||||
`cli.contexts()`, guests reloaded.
|
||||
|
||||
## Out of scope
|
||||
|
||||
Adding/editing/deleting contexts, `config verify`, restoring the original context on exit.
|
||||
|
||||
## Steps
|
||||
|
||||
- [x] Tests for `contexts`/`use_context` and the UI contract above - red first.
|
||||
- [x] Implementation - full suite green, ruff clean.
|
||||
- [x] Live: open the list, switch to `mainframe-edge` and back to `mainframe`
|
||||
(only `config use` and read-only listing; no guest actions); final context
|
||||
is `mainframe`.
|
||||
- [ ] Push `feat/guest-tui-mvp`, merge to `main` (user-approved).
|
||||
Reference in new issue
Block a user