Portable UI: roots page declares free-space fields it never fills, and task actions stream no progress #1
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Two gaps in the module's portable UI surface, found while reviewing core PR OpsDeck/core#31 for mobile impact. Both are module-side fixes — the schema already supports what's needed.
1. Dead free-space fields on the roots page
backend/ui.tsdeclares a "Free" field and a used/total progress bar on the roots list:ui.ts:83—{ label: "Free", path: "freeBytes", format: "bytes" }ui.ts:86—progress: { used: "usedBytes", total: "totalBytes" }but the route that feeds it hardcodes all three to null (
ui.ts:361-363):So the Android roots page (and the schema renderer anywhere) promises free space and a usage bar and always renders them empty. The df helper already exists —
fsops.ts:322-343(df -Pk, kB→bytes) — and the web routes use it with caching (routes.ts:58: "df is a subprocess; a listing must not pay for it on every keystroke").Either wire the cached df result into
/s/roots, or drop the three bindings from the schema. Wiring it is the better outcome: the README already documents the degradation story ("a deployment without coreutils shows no usage bar rather than a wrong one"), which maps cleanly to leaving the fields null whendfis absent.2. Scan and delete actions stream no progress on mobile
The schema's
actionsblock supportsprogressTopic(corepackages/sdk/ui.ts:305) — an SSE topic whosemsgpayloads stream into a progress log until a message starts withdoneorerror. The module's scan and delete actions (ui.ts:147-171,ui.ts:248-263) don't use it: they start a task run, returnrunId, and the mobile client sees nothing until the next refresh tick (15 s on the scan page).Wiring a topic gives mobile live progress with no schema change. One decision to make: the module's live topics are currently admin-gated (README: "Live topics are admin-gated"), but the scan action is available at
readRoleand delete atwriteRole— a non-admin who can start the run wouldn't see its stream. Either a per-topic role matching the action's role, or an explicitly progress-only topic that carries no path data beyond what the actor already submitted.Context
Both fixed in
1bedb0con main.1. Free-space fields. Wired rather than dropped, as you suggested. The df
helper moved out of
routes.tsintofsops.tsas a sharedUsageCache, so/s/rootsand the web routes go through the same 15-second cache instead ofeach starting one — df is a subprocess and both surfaces ask about the same
roots. Absent df still yields null, so the documented degradation holds: no bar
rather than a wrong one.
Against a running server:
2. Progress topics.
scan-progressanddelete-progress, named on Delete,Scan this directory and Start scan. A real scan watched over SSE:
The
doneprefix is what ends the stream for aprogressTopicclient, so itis the first word rather than merely present.
On the role decision. Core's gate is binary —
ctx.events.adminOnly(topic)and nothing finer — so "a per-topic role matching the action's role" is not
expressible directly. The streams follow the read role instead:
admin-only exactly when reads are, which is the default deployment. Pinning
them admin unconditionally would mean an operator allowed to start a scan
cannot watch the one they started, which seemed like the wrong half to keep.
What makes that safe is the payload rather than the gate, so that is where the
rule lives: a line carries counts and a name the subscriber could already list
— never file content, never a path outside the roots. Both your options
collapse into the same discipline once the gate cannot be finer than binary.
README updated to say this instead of the old flat "live topics are
admin-gated".
Not touched here: the
up/:predirect page stays until the Android renderercan render
parent(core PR OpsDeck/core#35 adds the field). Removing it nowwould take the up-arrow off the phone.