Portable UI schema: four additions the filebrowser module needs (typed-phrase confirm, download, file input, breadcrumb nav) #1

Closed
opened 2026-08-11 23:36:58 +02:00 by julian · 0 comments
Owner

Reviewing core PR OpsDeck/core#31 against module_filebrowser showed the portable UI schema is the ceiling on what the module can do on Android. Four additions, in priority order. The schema types live in core (packages/sdk/ui.ts, validation in packages/server/src/modules/ui-schema.ts) and the renderer here (app/src/main/java/cloud/imhof/opsdeck/ui/schema/SchemaScreen.kt, deserialization in data/model/Ui.kt) — each item needs both sides, plus the web schema renderer. Filing here because the renderer is the larger half; coordinate with a core-side PR for the types.

1. confirmPhrase on action confirms (safety parity)

UiAction.confirm is a plain string (core packages/sdk/ui.ts:293-294), rendered as a one-tap dialog. The web frontend just gained typed-phrase confirmation (ConfirmDialog.confirmPhrase, core PR #31): a recursive delete requires typing the target's name. The same recursive delete on Android (module_filebrowser backend/ui.ts:152-159) is one tap on "Delete this path and everything under it? This cannot be undone." — same destructive power, weaker brake, and a phone tap is more reflexive than a mouse click, not less.

Proposal: optional confirmPhrase?: string beside confirm; the client shows a text field and enables the confirming button only on exact match. Unknown-field-tolerant clients degrade to the plain confirm.

2. A verb that opens a URL (downloads)

No block or action can open a URL, so the filebrowser README documents transfers as web-only ("Mobile cannot download or upload bytes… the Android app gets browse, inspect, preview, create, delete and the scan"). An action kind that hands a module-relative URL to the platform — Android's download manager here, an anchor on the web schema renderer — unlocks file downloads with the module's existing authenticated routes.

3. A file input kind for forms (uploads)

UiInputKind is text | number | password | toggle | select | chips (core packages/sdk/ui.ts:324-330) — nothing picks a file. Adding a file kind (Android document picker, multipart or streamed PUT submit) is the upload half of the same README limitation. Bigger lift than 1 and 2 because the submit path today posts JSON; needs a defined wire shape for binary bodies plus progress reporting.

4. Breadcrumb / parent navigation

The renderer has no "go to the parent" verb, so filebrowser fakes it with a dedicated redirect page (backend/ui.ts:175-200, comment: "the renderer has no 'go to the parent' verb, so the parent is a page whose single action navigates on from it") — an extra page, an extra route, and an extra tap on every upward step of a tree walk. Either a breadcrumbs block (segments + page links, matching core PR #31's web Breadcrumbs) or a page-level back/parent affordance driven by the schema would delete the hack.

Non-goals

The rest of core PR #31's kit (Select, SplitButton, DropZone, CompositionBar) should not be ported 1:1 — those are web interaction idioms; the app owns its own widgets. Live run progress needs no schema change: actions.progressTopic already exists (core packages/sdk/ui.ts:305); the module wiring for it is tracked in OpsDeck/module_filebrowser#1.

Reviewing core PR OpsDeck/core#31 against module_filebrowser showed the portable UI schema is the ceiling on what the module can do on Android. Four additions, in priority order. The schema types live in core (`packages/sdk/ui.ts`, validation in `packages/server/src/modules/ui-schema.ts`) and the renderer here (`app/src/main/java/cloud/imhof/opsdeck/ui/schema/SchemaScreen.kt`, deserialization in `data/model/Ui.kt`) — each item needs both sides, plus the web schema renderer. Filing here because the renderer is the larger half; coordinate with a core-side PR for the types. ## 1. `confirmPhrase` on action confirms (safety parity) `UiAction.confirm` is a plain string (`core packages/sdk/ui.ts:293-294`), rendered as a one-tap dialog. The web frontend just gained typed-phrase confirmation (`ConfirmDialog.confirmPhrase`, core PR #31): a recursive delete requires typing the target's name. The same recursive delete on Android (`module_filebrowser backend/ui.ts:152-159`) is one tap on "Delete this path and everything under it? This cannot be undone." — same destructive power, weaker brake, and a phone tap is more reflexive than a mouse click, not less. Proposal: optional `confirmPhrase?: string` beside `confirm`; the client shows a text field and enables the confirming button only on exact match. Unknown-field-tolerant clients degrade to the plain confirm. ## 2. A verb that opens a URL (downloads) No block or action can open a URL, so the filebrowser README documents transfers as web-only ("Mobile cannot download or upload bytes… the Android app gets browse, inspect, preview, create, delete and the scan"). An action kind that hands a module-relative URL to the platform — Android's download manager here, an anchor on the web schema renderer — unlocks file downloads with the module's existing authenticated routes. ## 3. A `file` input kind for forms (uploads) `UiInputKind` is `text | number | password | toggle | select | chips` (`core packages/sdk/ui.ts:324-330`) — nothing picks a file. Adding a `file` kind (Android document picker, multipart or streamed PUT submit) is the upload half of the same README limitation. Bigger lift than 1 and 2 because the submit path today posts JSON; needs a defined wire shape for binary bodies plus progress reporting. ## 4. Breadcrumb / parent navigation The renderer has no "go to the parent" verb, so filebrowser fakes it with a dedicated redirect page (`backend/ui.ts:175-200`, comment: "the renderer has no 'go to the parent' verb, so the parent is a page whose single action navigates on from it") — an extra page, an extra route, and an extra tap on every upward step of a tree walk. Either a breadcrumbs block (segments + page links, matching core PR #31's web `Breadcrumbs`) or a page-level back/parent affordance driven by the schema would delete the hack. ## Non-goals The rest of core PR #31's kit (Select, SplitButton, DropZone, CompositionBar) should not be ported 1:1 — those are web interaction idioms; the app owns its own widgets. Live run progress needs no schema change: `actions.progressTopic` already exists (`core packages/sdk/ui.ts:305`); the module wiring for it is tracked in OpsDeck/module_filebrowser#1.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
OpsDeck/mobile#1
No description provided.