Skip to content

[AI] #216: mobile layout and PWA install - #226

Merged
turtlemonvh merged 3 commits into
masterfrom
ai/issue-216-mobile-pwa
Oct 23, 2026
Merged

turtlemonvh merged 3 commits into
masterfrom
ai/issue-216-mobile-pwa

Conversation

@turtlemonvh

@turtlemonvh turtlemonvh commented Oct 19, 2026 •

Copy link
Copy Markdown
Owner

Decision needed

Nothing blocks merging. Two small calls I made that you may want to flip:

  1. Worker "Stop" has no confirm. The table said every cancel and delete asks first. I left Stop alone: it isn't destructive, since Restart undoes it. Want it to confirm too?
  2. The instance name replaces the old "htmx scaffold" label at the right of the top bar.

Review follow-up (parity between mobile and desktop)

  • Duration on desktop: the task tables (tasks page, a series' past runs) now have a real Duration column, and the task detail table has a Duration row. The card's context line stays phone-only, because on desktop it would only repeat the Exit/Updated/Created/Scheduled columns.
  • Log order is the same everywhere: the "Newest first" toggle and log-order.js are gone. The task and worker logs read oldest first with the newest line at the bottom, on a phone and on a desktop. The pane is top-aligned, so a short log sits at the top. "Pin to bottom" keeps tailing once the log overflows.
  • Confirms on desktop: the hx-confirm attributes were already in the shared row markup, and no CSS or JS limits them to phones, so desktop already showed the dialog. I checked every cancel and delete: task rows, the Upcoming one-time cancel, the series cancel and the stopped-worker delete. All of them confirm. The Playwright confirm journey (dismiss keeps the task, accept deletes, cancel asks) now runs at a 1280×800 viewport as well as the phone one.

What changed

  • Cards (one set of markup): below 640px, app.css restyles the existing task, worker, upcoming and task-type rows as cards. It uses display:grid with grid-template-areas on the <tr> and hides the thead. Above 640px the only change is the new Duration column.
    • A task card shows the state badge and duration, then the type and short ID, then one context line: the worker for a running task, exit code and finish time for a finished one, created/scheduled time otherwise.
    • Tapping anywhere on a card opens the detail page, because the ID link stretches over the whole card. Links and actions inside the card still get their own taps.
    • Progress % is not shown on phones.
  • Duration: the new taskDuration template func computes it on the server. It shows on the phone card, in the desktop Duration column and on the task detail page. A running task shows now − started, a finished one shows its last update − started, and a waiting one shows queued Xm. It refreshes through the existing SSE/Refresh paths; no JavaScript timer.
  • Confirms: every cancel and every delete now has hx-confirm naming the task type. That covers WAITING/SCHEDULED/CLAIMED cancel and terminal delete in the task rows, the Upcoming one-time cancel, and the stopped-worker delete. The existing journeys cancel test now accepts the dialog.
  • Log panes: the worker log's inline styles moved to the shared .log-pane class. Its toolbar now matches the task log's.
  • Navigation: narrow screens get a bottom tab bar: Tasks, Upcoming, Workers, and More (which holds Task Types and About). The current section is marked with aria-current. The top bar keeps only the brand and the instance name.
  • Instance name: the machine's hostname by default. The new optional ui.instanceName key (viper default "", so it shows on the About page) overrides it.
  • PWA:
    • GET /ui/manifest.webmanifest is generated, with name = "Blanket · ", short_name, start_url/scope /ui/, display: standalone, and 192/512/maskable icons.
    • The icons are placeholder PNGs (a "B" on #2a6fb0, each under 2.5 KB). A comment in the code notes that Project branding pass (logo, palette, tagline) #55 replaces them.
    • Added apple-touch-icon, apple-mobile-web-app-capable, theme-color and a favicon.
    • No service worker.
  • Task detail on phones: a summary line with the state, duration and a Log ↓ button. The Progress row is hidden.
  • Docs: docs/usage.md (phone layout, installing, ui.instanceName, the desktop Duration column, log order) and docs/api.md (the manifest route).

Judgment calls

  • The exit code in the card's context line is plain text ("exit 2", red when non-zero), not a second badge. The desktop Exit column's badge is still in the DOM, and two identical badges in one row broke the existing task_output exit-code spec.
  • A task cancelled before it started (no startedTs) shows no duration rather than a misleading one. SCHEDULED tasks and series templates show none either.
  • Tables with only two columns (settings, env) aren't turned into cards. They just wrap long values.

Verification

  • make check-fmt: clean.
  • make docker-test: all 18 packages ok. New tests in server/ui_mobile_test.go cover:
    • fmtDuration, taskDurationAt (each state), exitSummary, and uiInstanceName (hostname default, override, trim, error).
    • The layout's PWA tags, instance name and active tab.
    • The manifest: content type, fields, every icon served, and the 192/512/maskable icons.
    • Confirms on every mutating task-row control.
    • The Duration column header, its cell (no longer phone-only) and the task-detail Duration row.
  • make docker-test-smoke: smoke, restart, migrate, restart-machine and upgrade all OK.
  • make docker-test-browser: 61 passed. tests/e2e/specs/mobile.spec.ts has two blocks:
    • Phone (390×844): manifest, icons and iOS tags are linked; cards render with no sideways scroll; the tab bar and More menu work; the confirm journey; the log journey.
    • Desktop (1280×800): no tab bar; column headers, including Duration, are visible; the same confirm journey; the same log journey.
    • The confirm journey: dismissing a delete keeps the task, accepting removes it, and cancel asks first. It listens with page.on('dialog') and checks that the message names the type.
    • The log journey: oldest first, no order toggle, Pin to bottom checked, and the first line at the top of a short pane.
    • Note: the shared blanket-npm-cache docker volume on this machine holds Playwright 1.63, which doesn't match the 1.64 image. I ran the suite with a fresh volume (blanket-npm-cache-pw164) and didn't run make docker-clean, because other worktrees use the shared one.
  • Cross-compile: GOOS=windows and GOOS=darwin builds are fine.

Closes #216

🤖 Generated with Claude Code

Phone use of blanket is read-mostly: is my job done, how long has it
been running, and what did it print. The desktop tables answer that, but
not on a 390px screen. Per the approved decisions on #216:

- One set of markup. Below 640px app.css restyles the existing task,
  worker, upcoming and task-type rows as cards (grid-template-areas on
  the <tr>, thead hidden); desktop renders exactly as before. A task card
  leads with state + duration, then type + short id, then one context
  line (worker if running; exit code + finish time if terminal). The
  whole card opens the detail page; Progress % is not shown.
- Duration is computed server-side (taskDuration template func) and
  refreshed by the existing SSE/refresh paths, so nothing ticks in JS.
- Every cancel and every delete now has hx-confirm naming the task
  type -- before, only cancelling a RUNNING task asked, and a mis-tap on
  a phone is easy.
- Task and worker logs get a "Newest first" toggle (log-order.js):
  newest-first by default on narrow screens, oldest-first + pin-to-bottom
  on desktop as today. Live panes switch hx-swap to afterbegin so they
  keep tailing at the top.
- Bottom tab bar (Tasks / Upcoming / Workers / More) on narrow screens.
- Header shows the instance name: hostname by default, overridable with
  the new ui.instanceName config key.
- Installable PWA: generated /ui/manifest.webmanifest (name carries the
  instance name), 192/512/maskable placeholder icons until #55, and iOS
  meta tags. No service worker: the data is live, so an offline cache
  would only serve stale states.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

@turtlemonvh turtlemonvh left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comments are mostly about mobile / desktop parity

Comment thread server/ui_mobile.go
Comment thread server/ui/templates/worker_detail.html Outdated
Comment thread server/ui/templates/tasks_rows.html
turtlemonvh and others added 2 commits October 19, 2026 17:24
The review asked for the phone and desktop views to match rather than
diverge:

- Duration was a phone-card-only cell. It is now a real Duration column
  in the desktop task tables (tasks page and a series' past runs) and a
  row in the task detail table. The context cell stays card-only: on
  desktop it would only repeat the Exit/Updated/Created/Scheduled columns.
- The "Newest first" log toggle (log-order.js, matchMedia default,
  sessionStorage) is gone from the task and worker logs. Both read oldest
  first with the newest line at the bottom on every screen size; the pane
  is top-aligned so a short log sits at the top, and "Pin to bottom" keeps
  tailing once it overflows.
- The cancel/delete hx-confirm attributes were already shared markup, so
  desktop got them too; the Playwright confirm journey now runs at a
  desktop viewport as well as the phone one.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@turtlemonvh
turtlemonvh merged commit a1b2230 into master Oct 23, 2026
10 checks passed
@turtlemonvh
turtlemonvh deleted the ai/issue-216-mobile-pwa branch October 23, 2026 15:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PWA configuration for phone access

1 participant