hyperhive/frontend
Repository files (latest commit first)
Filename Latest commit message Latest commit date
iris d4a53d83d3 dashboard: atomic-swap paint for schedules + reminders (#464)
argus flagged + mara confirmed: operators see a brief "blink" on
every poll cycle when refreshState fires. Root cause for the
async-fetch sections (refreshReminders, refreshSchedules): the
`await resp.json()` yield is a paint opportunity the browser can
take BEFORE the renderer's `root.innerHTML = ''` + `root.append`
land. The "loading…" placeholder (or the previous render's stale
content) may briefly show through.

Fix: render off-DOM into a `DocumentFragment`, then atomically
swap into the live root with `replaceChildren`. The browser only
sees the new content; no intermediate empty state is reachable.

Added `paintAtomic(liveRoot, build)` helper near the top of the
IIFE — minimal-churn pattern where each renderer's existing
`root.append(...)` body carries over unchanged, just wrapped in
a builder callback that receives the fragment as its `root`
parameter.

Applied to the async-fetch sections argus's note + mara's report
specifically called out:

- `refreshReminders` (both http-error + catch paths)
- `renderReminders`
- `refreshSchedules` (both error paths)
- `renderScheduleNewForm` (carry read still happens against the
  live root BEFORE the swap so mid-typing values are preserved)
- `renderSchedulesList`

Kept scope tight to the async paths. The sync renderers
(renderContainers / renderTombstones / etc.) run inside the
same JS turn as refreshState's other sync work, so the browser
can't paint between their clear+populate steps — no flash to fix
there. If mara still sees blink on those sections after this
lands, extending the pattern is a clean follow-up.

docs/web-ui.md no change needed; this is an implementation
detail of the existing managed-section render machinery.
2026-05-26 17:07:19 +02:00
..
packages dashboard: atomic-swap paint for schedules + reminders (#464) 2026-05-26 17:07:19 +02:00
.gitignore frontend: add npm workspace scaffold under frontend/ 2026-05-23 14:51:01 +02:00
package-lock.json frontend: lock npm dependencies via package-lock.json 2026-05-23 14:51:01 +02:00
package.json frontend: lock npm dependencies via package-lock.json 2026-05-23 14:51:01 +02:00
README.md frontend: add npm workspace scaffold under frontend/ 2026-05-23 14:51:01 +02:00

hyperhive frontend

npm workspaces project for the hyperhive browser-facing assets:

  • packages/shared/ — shared modules used by both surfaces (terminal pane, Catppuccin palette + body typography).
  • packages/dashboard/ — the hive-c0re dashboard SPA.
  • packages/agent/ — the per-container web UI (default agent page, stats, screen).

Build

npm install            # one-off; uses the checked-in package-lock.json
npm run build          # builds every workspace into packages/*/dist/

The Rust binaries serve packages/dashboard/dist/ and packages/agent/dist/ via tower_http::ServeDir at runtime; the build derivation is wired up in nix/modules/frontend.nix. Per-agent additions are layered on top of the default agent dist via the hyperhive.frontend.extraFiles option in agent.nix.

Why npm + esbuild

  • Hermetic: dependencies vendored via the checked-in lockfile; buildNpmPackage in nix uses it as the source-of-truth so the output is reproducible without network access at build time.
  • esbuild: vanilla-JS bundler, no framework runtime overhead. Each workspace's build.mjs is ~30 lines.
  • Single-PR migration: see issue #273 for the design proposal and the four-commit shape (npm scaffold → nix derivations → container plumbing → Rust cutover).