Show configured resources on the info screen
A new "Resources" section at the top of the info screen shows CPU cores (with sockets for VMs), memory, swap for containers, and each disk with its size. The disks are the same ones the edit dialog offers, so cloud-init and CD drives are left out. A container without a cores limit shows "unlimited". The open info screen reloads after any guest job, so values edited with e show up straight away. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit was merged in pull request #7.
This commit is contained in:
1 parent
0c3669271c
commit
5a3ca5a216
3 files changed
+107
-4
No files matched your search
+32
-3
@@ -407,6 +407,9 @@ class InfoScreen(ModalScreen):
|
||||
def compose(self) -> ComposeResult:
|
||||
with Vertical():
|
||||
yield Static(f"{self.guest['name']} ({self.guest['vmid']})", markup=False)
|
||||
with Vertical(id="resources_section", classes="section") as res:
|
||||
res.border_title = "Resources"
|
||||
yield DataTable(id="resources", show_header=False, cursor_type="none")
|
||||
with Vertical(id="backup_section", classes="section") as backup:
|
||||
backup.border_title = "Backups"
|
||||
yield Static("", id="jobs", markup=False)
|
||||
@@ -422,6 +425,7 @@ class InfoScreen(ModalScreen):
|
||||
yield Footer()
|
||||
|
||||
def on_mount(self) -> None:
|
||||
self.query_one("#resources", DataTable).add_columns("Resource", "Value")
|
||||
self.query_one("#backups", DataTable).add_columns(
|
||||
"Date", "Storage", "Size (GiB)", "Format", "Notes"
|
||||
)
|
||||
@@ -488,6 +492,9 @@ class InfoScreen(ModalScreen):
|
||||
"; ".join(_job_text(j) for j in covering)
|
||||
or "No backup job covers this guest"
|
||||
)
|
||||
table = self.query_one("#resources", DataTable).clear()
|
||||
for name, value in _resources(config, cli.kind(self.guest)):
|
||||
_add_plain(table, name, value)
|
||||
self.backups = backups
|
||||
self._show_backups()
|
||||
table = self.query_one("#nets", DataTable).clear()
|
||||
@@ -828,9 +835,11 @@ class GuestApp(App):
|
||||
self.notify, f"{label} done: {guest['name']} ({guest['vmid']})"
|
||||
)
|
||||
finally:
|
||||
self._reload(
|
||||
acted=guest
|
||||
) # before un-busying, so no context switch can start mid-reload
|
||||
self._reload_infos(
|
||||
guest
|
||||
) # e.g. edited cores show up in an open info screen
|
||||
# before un-busying, so no context switch can start mid-reload
|
||||
self._reload(acted=guest)
|
||||
self.busy.discard(guest["vmid"])
|
||||
|
||||
def action_act(self, name: str) -> None:
|
||||
@@ -1035,6 +1044,26 @@ def _reset_terminal() -> None:
|
||||
sys.stdout.flush()
|
||||
|
||||
|
||||
def _resources(config: dict, kind: str) -> list[tuple[str, str]]:
|
||||
"""Configured CPU, memory (and CT swap) and disks, as (name, value) rows."""
|
||||
cores = config.get("cores")
|
||||
if cores is None and kind == "ct":
|
||||
cpu = "unlimited" # no cores limit: the container may use all host cores
|
||||
else:
|
||||
cores = int(cores or 1)
|
||||
cpu = f"{cores} core{'s' if cores != 1 else ''}"
|
||||
if kind == "vm":
|
||||
sockets = int(config.get("sockets") or 1)
|
||||
cpu += f" × {sockets} socket{'s' if sockets != 1 else ''}"
|
||||
rows = [("CPU", cpu)]
|
||||
if config.get("memory") is not None:
|
||||
rows.append(("Memory", f"{config['memory']} MiB"))
|
||||
if kind == "ct" and config.get("swap") is not None:
|
||||
rows.append(("Swap", f"{config['swap']} MiB"))
|
||||
rows += [(f"Disk {name}", size) for name, size in cli.disks(config, kind).items()]
|
||||
return rows
|
||||
|
||||
|
||||
def _add_plain(table: DataTable, *cells, **kwargs) -> None:
|
||||
"""DataTable parses str cells as markup; names and notes like "a[/b]" must stay literal."""
|
||||
table.add_row(*(Text(c) if isinstance(c, str) else c for c in cells), **kwargs)
|
||||
|
||||
Reference in new issue
Block a user