PAP-14233 · Service controls
Jump to a screen
PAP-14233 · Wireframes

Execution workspace service controls

The current header cluster morphs per state: a red Stop + Restart stack when running, a lone Start when stopped, and a URL that wraps mid-port underneath. This proposal replaces it with one segmented control bar — status · URL · actions — whose geometry is identical in every state, so nothing ever jumps. Transitions are announced by the status segment (spinner + label), not by buttons appearing and disappearing.

5 screens 8 service states Desktop + mobile Lo-fi · monochrome Click any wireframe to zoom
Flow

Service lifecycle

Every state the control bar must render. Solid arrows are user actions and normal progress; dashed arrows are failure paths. The backend model is starting | running | stopped | failed plus a health probe (healthy | unhealthy | unknown); “Stopping…” and “Restarting…” are the in-flight mutation states the UI must also show.

flow.svg1280×400
Service lifecycle state diagram
Step 1 · Anatomy

1.Header context — running

The bar sits where today's button stack lives: right side of the workspace header. Three segments — status (dot + label), URL (monospace host:port with copy and open-in-new-tab), actions (Stop, Restart as quiet icon buttons). Total footprint is one 40px row.

01-header-context.svg1280×320 · desktop
Header with control bar in running state
Reference — current UI (the problem)issue screenshot
Current stop/restart controls with wrapping URL

Annotations

  • 1 — the whole cluster becomes one segmented bar, right-aligned in the header.
  • 2 — status segment: dot + short label. This is the only segment whose content changes between states.
  • 3 — URL segment: host:port in monospace, copy button, open-in-new-tab. Fixed width; long URLs truncate in the middle, never wrap.
  • 4 — action segment: two fixed 32px icon slots (Stop, Restart) with tooltips.
Why this changes: today Stop is a loud red button stacked above Restart, and the URL is free-wrapping text below them (it breaks mid-port in the screenshot). Destructive color for a routine dev-loop action reads as an alarm, and each state renders a different number of controls so the header reflows constantly.
Step 2 · States

2.State matrix — all 8 states

The same bar in every state the model can produce: stopped, starting, running, running-but-unhealthy, stopping, restarting, failed, and no-services. The bar's outer geometry and segment boundaries are identical in all of them.

02-state-matrix.svg1280×672 · desktop
Control bar in all eight states

Annotations

  • Stopped — hollow dot; URL dimmed and inert; Start is the filled primary, spanning both action slots.
  • Starting / Stopping / Restarting — the dot becomes a spinner and the label says what's happening; both actions disable. No control is added or removed.
  • Running — URL becomes a live link with copy + open; Stop and Restart are quiet outline icon buttons (destructive color reserved for confirm surfaces).
  • Unhealthy — running controls, warning-hued dot with probe ring; label flips to “Unhealthy”.
  • Failed — alert dot, Start returns as primary, error detail lives under the bar (screen 4).
  • No services — bar is simply not rendered.
Why this changes: in-flight states currently just disable whichever buttons happen to exist, and success/error text appears elsewhere in the page. Encoding the transition in the status segment gives one stable place to look.
Step 3 · Scale

3.Multiple services

Workspaces can run several services (web, api, worker…). The header bar aggregates: “2/3 running”, the primary service's URL, and whole-workspace actions. The status segment opens a popover with one row per service — each row reuses the exact single-service anatomy.

03-multi-service.svg1280×480 · desktop
Aggregate bar with services popover open

Annotations

  • 1 — aggregate status (“2/3 running”) with a chevron; clicking opens the popover.
  • 2 — one row per service: dot, name, URL (or transitional text), copy/open when live.
  • 3 — per-row actions mirror the single-service slots; footer offers Start all / Stop all / Restart all and a path to the Services tab.
Why this changes: today multiple services render as stacked button groups in the header, each with its own title and wrap behavior — the worst case of "jumping all over the place". Aggregation caps the header at one row no matter how many services exist.
Step 4 · Stability

4.Stopped & failed headers

Side-by-side proof that the header does not reflow: stopped and failed use the same box, same segments, same action-slot footprint. Failure adds exactly one right-aligned detail line under the bar — exit reason, recency, and a View logs link.

04-header-states.svg1280×472 · desktop
Header in stopped and failed states

Annotations

  • A — stopped: Start fills the action area; URL segment keeps its width with the configured port dimmed, so the coming-back-up transition doesn't shift anything.
  • B / 1 — failed: the only addition is the detail line (“dev exited with code 1, 12s ago · View logs”) under the bar. The bar itself is byte-identical in geometry to every other state.
Why this changes: failures currently surface as a red paragraph in a different part of the header while the buttons silently change set — the operator has to hunt. One fixed detail slot under the bar keeps cause and remedy (Start/Restart) adjacent.
Step 5 · Mobile

5.Mobile

Below the small breakpoint the bar becomes a two-row card: status + actions on top, URL row underneath. Same fixed geometry rules — rows never wrap or reflow between states.

05-mobile.svg375×320 · mobile
Mobile control card layout

Annotations

  • 1 — the card stacks the bar's segments into two fixed rows; the URL gets a full row so it never wraps mid-port.
  • Transitional and failed states behave exactly as on desktop: spinner + label in row one, detail line appended below the card when failed.
Why this changes: the current break-all URL text is what produced the wrapped “:4543 / 9” in the issue screenshot; a dedicated row with middle-truncation fixes it at every width.
For reviewer

Open questions

  • Stop confirmation — Stop is currently instant. Keep it instant (dev-loop tool), or require a confirm popover when the workspace has an active run attached?
  • Aggregate actions — with multiple services, header Stop/Restart act on all services (per-service control lives in the popover / Services tab). Acceptable?
  • Unhealthy wording — proposal shows “Unhealthy” as the label while the process is up. Alternative: keep “Running” with a warning dot only.
  • Jobs — one-shot jobs (kind: "job", Run action) stay in the Services tab and are intentionally excluded from the header bar. Confirm.