Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Dashboard

The dashboard is a Leptos application compiled to WebAssembly and embedded in the daemon binary. See the dashboard page of the user guide for what it does.

Development

Building the dashboard needs only Cargo and the wasm32-unknown-unknown target, which rust-toolchain.toml installs. nix develop provides the same toolchain plus just and Nextest. Docker must be accessible to your user and support a single-node Swarm. Start the development workflow:

just dev

This watches the daemon and dashboard sources, rebuilds the embedded bundle, and restarts this worktree’s isolated development instance, served on its own localhost port. Refresh the browser after a rebuild. See development instances.

Compile the browser client and dashboard without building the bundle with:

just ui-check

The browser modules separate dashboard navigation and lists, editor state, configuration forms, deployment history, navigation guards, and shared presentation primitives (browser/ui.rs for icons, badges, notices, dialogs, and tabs; browser/format.rs for relative times, durations, and sizes). Logic that needs no browser, such as form drafts and the changes they save, lives in crate-root modules (application, deployments, editor, environments, overview, secrets, state, terminal, and others) that compile natively, so their unit tests run with cargo nextest. Styles are plain CSS: a base reset adapted from Tailwind’s preflight, theme tokens, shell layout, and component rules, in apps/piqueld-ui/styles/. To format view macros as well as Rust, run leptosfmt from apps/piqueld-ui (it reads the local leptosfmt.toml), followed by cargo fmt --all.

The logo’s mark is apps/piqueld-ui/assets/favicon.svg, with favicon.png as its 512-pixel raster. The dashboard inlines the SVG next to its name and serves both as its icons, and the documentation book uses them as its favicon. The wordmark, mark and name together, is docs/images/wordmark.svg. The name is drawn with Inter outlines, so it needs no font. The build fails on a file of assets/ that index.html doesn’t reference, and the book reads that directory as its mdBook theme, so keep only the shell’s icons there.

Production assets

The release dashboard ships inside the daemon binary itself, and Cargo builds it. With the embedded-ui feature, the daemon build script:

  1. compiles piqueld-ui for wasm32-unknown-unknown with the size-optimized dashboard profile, using a nested Cargo with its own target directory;
  2. generates the JavaScript bindings in-process with wasm-bindgen-cli-support, pinned to the exact wasm-bindgen version;
  3. concatenates styles/ in cascade order, and writes a small loader module;
  4. copies the logo and other files of assets/ with content hashes;
  5. fills the placeholders in apps/piqueld-ui/index.html with the content-hashed file names, and embeds every file.

Setting PIQUELD_DASHBOARD_WASM to a compiled piqueld-ui.wasm skips step 1 and embeds that module instead, and the build warns that changes under apps/piqueld-ui are not included. The Nix packages pass their own cached dashboard build this way, so daemon-only changes don’t recompile the UI.

No Trunk, wasm-bindgen CLI, binaryen, Tailwind, or Node is involved. The shell has no inline scripts, so the Content-Security-Policy is a constant. See ADR 0002 for the reasoning and the planned move to Cargo artifact dependencies, which would remove the nested Cargo invocation.

cargo build --release --package piqueld --bin piqueld --features embedded-ui --locked
# Build both the embedded daemon and CLI: just build-embedded

The published piqueld crate can’t build the dashboard: piqueld-ui isn’t published, and installing it would need the wasm32 target. Instead, cargo xtask publish builds the bundle as above and ships it in the crate as apps/piqueld/dashboard/, which is gitignored and removed once the crates are published; see releasing. A build without embedded-ui embeds that bundle when the crate has one, so cargo install piqueld includes the dashboard.

There is no runtime UI configuration: the dashboard exists exactly when the binary embeds a bundle, and binaries built without one are API-only. The combined Nix package (.#combined, the default .# on Linux) includes piquelctl and a daemon with the release dashboard embedded, built by the same build script. The .#daemon output contains only the daemon without the feature, and the .#cli output (the default on macOS) contains only piquelctl.

The TCP router serves bundle files below /dashboard/ and uses index.html only for extensionless dashboard paths. API, health, and unknown paths never receive the SPA shell. Content-hashed asset filenames are served with immutable caching; the shell is always revalidated.

The dashboard performs one initial refresh, then bounded pagination and environment-status and recent-deployment reads. Background polls run every 15 seconds after success and back off to at most 120 seconds after failures. Polls pause while the document is hidden, never overlap, and a manual refresh remains available. A failed refresh keeps the last successful view visible and marks it stale.

Browser tests

The Playwright suite exercises the embedded dashboard against an isolated API fixture. Run just setup-playwright once, then just test-playwright. Chromium is provided by a pinned Docker image; the tests need no system browser, Python, or ChromeDriver. The browser-playwright CI job retains failure traces and screenshots.