Skip to content

Add sandbox prerequisites status bar item and install modal - #24

Merged
jasonsmithio merged 1 commit into
mainfrom
feat/sandbox-prereqs-ui
May 14, 2026
Merged

Add sandbox prerequisites status bar item and install modal#24
jasonsmithio merged 1 commit into
mainfrom
feat/sandbox-prereqs-ui

Conversation

@jasonsmithio

Copy link
Copy Markdown
Collaborator

Summary

Second half of the sandbox-prerequisites feature. PR #23 shipped the detection layer (data + CLI). This PR layers the in-editor UI on top: a status-bar indicator and an install-guidance modal.

PR-C (enforcement: tool gating + settings) is still to come and is intentionally scoped out here.

Architecture

New crate paddleboard_sandbox_prereqs_ui (~390 lines, one file). Three pieces hang together:

  • SandboxPrereqs — a gpui::Global holding Option<SandboxStatus> plus a refreshing flag. The probe runs on tokio's pool via gpui_tokio::Tokio::spawn (necessary because the underlying check() uses tokio::process::Command), and the result is written back to the global with cx.update_global on the foreground thread. Views observe via cx.observe_global::<SandboxPrereqs> and re-render when the probe completes.

  • SandboxStatusItem — implements workspace::StatusItemView. An IconButton with IconName::Box, colored by severity (Unknown / Ok / Warning / Error). Click dispatches paddleboard::OpenSandboxPrereqs. Tooltip is severity-specific ("Sandbox: gVisor not configured", "Sandbox: Podman not running", etc.).

  • SandboxPrereqsModal — implements workspace::ModalView. Renders the two status rows + the install instructions from the data crate, with a per-step Copy button (writes to clipboard via cx.write_to_clipboard(ClipboardItem::new_string(...))) and a Refresh button that re-runs the probe.

init(cx) is the single entry point: registers the global, kicks off the first probe, and uses cx.observe_new to wire the OpenSandboxPrereqs action into every workspace as it opens.

Severity → color mapping

State Color Tooltip
Podman = Missing red (Color::Error) "Sandbox: Podman not installed"
Podman = InstalledNotRunning red "Sandbox: Podman not running"
Podman = Ready, Gvisor = NotConfigured amber (Color::Warning) "Sandbox: gVisor not configured"
Podman = Ready, Gvisor = Available / NotApplicable green (Color::Success) "Sandbox: ready"
no probe completed yet muted "Sandbox: checking…"

The NotApplicable case is Windows — there's no gVisor path on Windows today, so Podman alone counts as the satisfied state. The user gets a different tooltip pre-merge once we land tool gating; the visibility layer is correct either way.

Wire-up

Two-line edit in crates/paddleboard/src/main.rs (call init right after gpui_tokio::init, since the probe needs tokio's handle in scope).

Five-line edit in crates/paddleboard/src/zed.rs:initialize_workspace to instantiate the status item and register it via status_bar.add_right_item. Both edits tagged with // PaddleBoard: comments so future upstream merges keep the change.

What's not in this PR (PR-C)

  • Tool gating: sandbox_tool, sandbox_service_tool, and sandboxed_stdio_transport still launch podman without checking the cached prereq status. A user with no Podman installed sees a confusing process-not-found error instead of the modal.
  • Settings: no sandbox.on_missing_runtime policy (block / fall_back_to_host / warn_once) yet.
  • No setting to disable the status indicator.

PR-C is the larger piece — it touches three tool entry points and has policy implications worth designing carefully.

Verification

  • cargo check -p paddleboard — clean.
  • cargo build -p paddleboard — clean (exit 0).
  • ./script/clippy -p paddleboard_sandbox_prereqs_ui -p paddleboard_sandbox_prereqs — clean.
  • Pre-existing llm_picker clippy failure on main is unrelated to this PR — confirmed by stashing changes and rerunning.
  • Not interactively driven yet. The status item and modal compile and pass lint, but I haven't clicked through the UI myself in a running editor. Smoke test before merging — at minimum, confirm: (1) the icon appears in the right of the status bar after launch, (2) the tooltip is accurate, (3) clicking opens the modal, (4) Refresh re-probes (the icon should briefly flash to the muted "checking" state), (5) Copy buttons copy correct commands.

Diffstat

8 files changed, 436 insertions(+)

Test plan

  • Build + launch PaddleBoard.
  • Status bar (right side) shows a Box icon with severity color matching paddleboard --check-sandbox output.
  • Hover → tooltip describes the state.
  • Click icon → modal opens with the install steps from PR-A.
  • Copy buttons place the right command on the clipboard.
  • Refresh button reruns the probe (icon → muted, then back).
  • paddleboard::OpenSandboxPrereqs action in the command palette opens the same modal.

Release Notes:

  • Added a sandbox prerequisites indicator to the status bar and an install-guidance modal explaining how to set up Podman + gVisor.

Layers a UI surface on top of PR #23's paddleboard_sandbox_prereqs data
crate. PR-B (visibility unit) of a planned two-part feature; PR-C
(enforcement unit) will gate the sandbox tools and add policy settings.

New crate paddleboard_sandbox_prereqs_ui:
- SandboxPrereqs is a gpui::Global holding the latest SandboxStatus plus
  a refreshing flag. Initialised at app startup; views observe it via
  cx.observe_global and re-render when the probe completes or is rerun.
- The async probe runs on tokio's pool via gpui_tokio::Tokio::spawn
  (needed for tokio::process::Command). The result is written back to
  the global with cx.update_global on the foreground thread, which is
  how observers know to notify.
- SandboxStatusItem implements workspace::StatusItemView. Renders an
  IconName::Box colored by severity (Unknown / Ok / Warning / Error).
  Click dispatches paddleboard::OpenSandboxPrereqs.
- SandboxPrereqsModal implements workspace::ModalView. Shows Podman +
  gVisor status rows, the formatted install instructions from the data
  crate, a Copy button per command step, and a Refresh button that calls
  SandboxPrereqs::refresh.
- paddleboard_sandbox_prereqs_ui::init(cx) registers the global, kicks
  off the first probe, and uses cx.observe_new to wire the
  OpenSandboxPrereqs action into every Workspace as it opens.

Wire-up in the paddleboard binary:
- Call paddleboard_sandbox_prereqs_ui::init in main.rs right after
  gpui_tokio::init (the probe needs tokio's handle in scope).
- Register the status item in zed.rs's initialize_workspace, tagged with
  // PaddleBoard: comments at the declaration and the add_right_item call
  so future upstream merges keep the change.

Verified:
- cargo check -p paddleboard clean.
- ./script/clippy -p paddleboard_sandbox_prereqs_ui -p paddleboard_sandbox_prereqs clean.
- cargo build -p paddleboard clean (exit 0).
- Pre-existing llm_picker clippy failure on main is unrelated to this PR.
- Not interactively driven: status bar icon + modal compile and pass
  lint, but I haven't clicked through the UI myself. Smoke test before
  merging.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@jasonsmithio
jasonsmithio merged commit bba0c30 into main May 14, 2026
@jasonsmithio
jasonsmithio deleted the feat/sandbox-prereqs-ui branch May 16, 2026 23:26
jasonsmithio added a commit that referenced this pull request May 31, 2026
Add sandbox prerequisites status bar item and install modal
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.

1 participant