Add the task log: recent tasks with status, Enter shows the log
CI / pytest and ruff (pull_request) Successful in 4m10s
CI / pytest and ruff (push) Successful in 4m32s

l on the main screen opens "Tasks", the recent cluster tasks newest
first. l on the info screen shows only that guest's tasks. Columns:
start, duration (or "running"), node, type, VMID ("-" for node
tasks), user and status. A failed task gets a "!" in the leading
column. Enter opens the task's log in a plain-text widget, so the
output is never parsed as markup.

`task list -o json` has no start or end times, so the list comes from
`/cluster/tasks`. The upid is validated (it must start with "UPID:")
before it goes in as a positional argument.

Review fixes:
- A finished task without a start time no longer crashes the app; its
  duration shows "-".
- "running" now means there is no endtime. A finished task with an
  empty status shows "unknown" and is flagged.

Read-only live check: 25 tasks listed, and the log of the newest
(vzdelsnapshot 104) ends with TASK OK.

Closes #10

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit was merged in pull request #25.
This commit is contained in:
DuckbootandClaude Opus 5.5 committed 2026-11-03 00:03:58 +01:00
1 parent eec65e0585
commit 1ed5e5069b
6 files changed
+546

No files matched your search

+40
View File
@@ -551,3 +551,43 @@ CLI facts (read-only probes):
- otherwise `-`.
A failure of `cli.current` keeps today's behaviour (inline "unavailable", status
unknown -> not running).
---
# Task log (issue #10)
## Decision (user-approved)
`l` on the main screen: all recent cluster tasks. `l` on the info screen: the tasks of
that guest. Enter on a task shows its log.
CLI facts (read-only probes):
- `task list -o json` lacks start/end times. `api get /cluster/tasks -o json` has them:
list of dicts `upid`, `type` (e.g. `vzdump`, `qmstart`, `vzsnapshot`), `id` (VMID as a
string, `""` for node tasks), `node`, `user`, `starttime`, `endtime` (epoch; missing
or null while running), `status` (`OK`, an error text, or missing while running),
`saved`, `tokenid`.
- `task log <upid>` prints the log as plain text lines (e.g. `TASK OK` at the end).
### `cli.py`
- `tasks() -> list[dict]` - `/cluster/tasks`, newest first by `starttime`.
- `task_log(upid) -> str` - `task log <upid>`; ValueError unless `upid` starts with
`UPID:` (positional argument).
### `app.py` (UI contract)
- `TasksScreen(ModalScreen)`, opened by `l` on the main screen (all tasks) and on the
info screen (`vmid` filter: only tasks whose `id == str(vmid)`). Frame `#tasks_section`
titled "Tasks" or "Tasks: <name> (<vmid>)". `DataTable#tasks` (row cursor): Start
(`YYYY-MM-DD HH:MM` local), Duration (`1h 2m`, `3m 12s`, `45s`; `running` without
endtime), Node, Type, VMID (`-` for node tasks), User, Status (`OK`, the error text, or
`running`). A failed task (status present and not `OK`) gets a `!` in a leading
column. `Static#tasks_note` says "No tasks" when empty. Loaded in a thread worker;
failure -> error notify, screen stays. Keys: `enter` open the log, `g` reload,
`escape` close.
- `TaskLogScreen` (DialogScreen style, wide box), title "Log: <type> <vmid or node>",
a read-only plain-text log widget `#tasklog` (no markup parsing), loaded in a worker;
failure -> error notify. `escape` closes.
- Main-screen footer shows `l Tasks`.