Nimbusv1.0.0

Dashboard Changelog

Release history for the Nimbus Web Dashboard — versioned independently of the controller.

The Nimbus Web Dashboard is versioned independently of the controller, so its UI-only releases (polish, new screens, UX fixes) don't need to wait for a full controller release. The format follows Keep a Changelog.

Dashboard versions use the pattern <controller-major>.<controller-minor>.<controller-patch>-<channel>.<n> (e.g. 0.9.1-beta.1). The leading 0.9.1 tracks which controller release the dashboard was validated against; -beta.1 is the dashboard's own iteration counter on that base.


[1.0.0-stable.1] — 2026-04-25

Controller compatibility: 1.0.0

Visual polish for the stable release: the login page background is upgraded from the hand-rolled SVG pixel sky to real layered pixel-art assets, with separate day and night themes.

Changed

  • Layered pixel-art login background. Replaces the <PixelSky /> SVG component with <LoginBackground />, which composites multiple transparent PNG layers from /public/backgrounds/sky-light/ (3 layers, daytime) and /public/backgrounds/sky-dark/ (6 layers, night) depending on the active colour scheme. Per-layer opacity tuning in dark mode — upper cloud layer (layer 3) at 0.35 opacity so the moon remains visible beneath. image-rendering: pixelated keeps the 576×324 source assets crisp at any viewport size. An SSR-safe fallback gradient prevents a flash of unstyled content before the client mounts and the theme resolves.

[0.11.0-beta.1] — 2026-04-19

Controller compatibility: 0.11.0

Dashboard surface for the new Auth module: multi-user login, a /profile section with TOTP + passkey + session management, a permission-aware navigation that hides what the user can't reach, and a ground-up rewrite of the login screen as a multi-screen wizard.

Added

  • Login wizard at /login. Replaces the old Tabs + ToggleGroup layout with a 7-screen flow (connect → method → code | magic-link | TOTP | API token) and direction-aware slide transitions. One concern per screen, back-arrow navigation, autoFocus per step, stock shadcn primitives end-to-end.
  • Passkey login + enrollment. Thin lib/passkeys.ts wrapper around the browser's native PublicKeyCredential.parseCreationOptionsFromJSON / parseRequestOptionsFromJSON API — no external WebAuthn dependency. Login MethodCard is gated on isPasskeySupported() so unsupported browsers don't see a dead option. New PasskeyCard on /profile/security for labeled enrollment and a list-with-delete of registered credentials. Cancellations and NotAllowedError are silent — the user just sees the login screen again, no stack-traced toast.
  • TOTP setup UI. QR render via api.qrserver.com fallback (no new deps), confirm step, disable. Ten recovery codes presented in a copy-all grid with a one-shot "save these somewhere safe" warning; the grid never re-renders them.
  • /profile section. Layout owns a single PageShell titled Profile with pill-tabs as sub-navigation; sub-pages render section cards directly instead of stacking their own page headers.
    • /profile — avatar, UUID, derived role badge, permission count, totpEnabled flag
    • /profile/security — TOTP card, Passkey card, Sessions card (list with revoke + "sign out everywhere else")
    • /profile/permissions — permission nodes grouped by the second dotted segment, admin callout when the user holds nimbus.dashboard.admin
  • Permission-aware UI.
    • lib/permissions.tsnimbus.dashboard.* node registry + longest-match route-prefix lookup
    • <RequirePermission> / <IfPermission> / <PermissionButton> components for inline gating
    • AppSidebar filters nav items by required permission (API-token auth still sees everything)
    • <RoutePermissionGuard> wraps (dashboard) children and 404-fallbacks routes the user can't access — doesn't leak page existence through the status code
  • NavUser three-mode render.
    • api-token — command-block head (real custom head from minecraft-heads.com, rendered via mc-heads.net with the textures.minecraft.net hash), "API Admin" label, connected-controller URL, Disconnect action
    • user — real mc-heads.net/avatar/<uuid> head, derived role label (Admin / Developer / Moderator / Supporter / User from permission grants), links to Profile / Security / Permissions, theme toggle, Logout
    • anonymous — renders nothing
  • Magic-link deep-link handler in app/login/login-client.tsx with history.replaceState cleanup and a Suspense boundary around useSearchParams. Click a magic link → land on the dashboard authenticated, URL token is stripped so it never shows up in the address bar.
  • Pixel-sky login background. New <PixelSky /> component: Minecraft-style animated sky, day-time vertical gradient, 20 seeded twinkling star pixels, three drifting pixel clouds at different altitudes and speeds. Pure SVG + CSS, no external media. prefers-reduced-motion honoured — the animations freeze to their initial frame and the twinkle holds at full opacity.
  • OTP tile input. New <OtpInput />: six single-digit cells with auto-advance, Backspace-jumps-back, arrow-key nav, full paste-spread, one-time-code autofill. Shared between the login code screen and the TOTP screen. Submit button disabled until the code is complete; auto-submit fires on last-digit entry so the user rarely touches the button.
  • Minecraft-head icons on method cards. Each login method now shows a themed pixel-head:
    • Passkey — keypad head (minecraft-heads.com #43871, texture hash 7e1959dd…)
    • Minecraft Account — MHF_Alex, the default modern skin
    • API Token — command-block head (minecraft-heads.com #120843), same asset reused in the NavUser API-token mode

Changed

  • Login visuals back to stock shadcn primitives. Earlier iterations drifted into custom rounded-2xl, primary-tinted shadows, bespoke hover-lifts, and a floating-circle back button that read as a different product. Reverted: Card uses its stock rounded-4xl + shadow-md + ring-1 ring-foreground/5; back arrow is <Button variant="ghost" size="icon"> with rounded-md; headings are <CardTitle>; submit buttons are <Button size="lg">; MethodCards are <Button variant="secondary"> with a custom inner layout. Pixel-sky background and screen transitions kept.
  • Login collapses to a single choice screen. The intermediate mc-method screen and the magic-link waiting UI are gone from the dashboard — the in-game /nimbus dashboard login code path is friction-free enough on its own, and the extra options made the grid feel cluttered. MethodCards now all use the same secondary variant so nothing implies a default. (The backend magic-link endpoints are still live — the in-game /nimbus dashboard login link command and the Velocity plugin delivery path still depend on them.)
  • apiFetch honours session auth. The client auth state is a union (loading / anonymous / api-token / user), and every request attaches either the bearer token or the session cookie based on the current kind. A silent 5-minute refresh keeps the user state's permission snapshot fresh without round-tripping on every page load.
  • useAuth().hasPermission(node) mirrors backend wildcard semantics (*, a.b.*, nimbus.dashboard.admin shortcut). Single source of truth for permission checks across the UI.
  • Breadcrumbs now render profile / security / permissions with proper casing via routeLabels in site-header.tsx — no more raw URL segments.

Removed

  • Magic-link screen state from login-form.tsxmcName, linkSent, linkTtl, linkTimer, startLinkCountdown, handleSendMagicLink. The nimbus-sparkle CSS keyframes the waiting state relied on are gone too.
  • Inline NimbusLogo, SkinHeadIcon, CoinIcon components from earlier login iterations (~140 lines). The real banner + MC-head CDN cover both needs.

Security hardening

Landed alongside the controller 0.11.0 review pass:

  • WebSocket + SSE auth via short-lived tickets. apiWebSocket() and apiProxyWebSocket() now await fetchWsToken() before opening a connection. For user sessions that call hits the new GET /api/auth/ws-ticket controller endpoint and places a single-use wt_… ticket in the ?token= query param; the long-lived session bearer never lands in a URL. API tokens pass through unchanged (operator-chosen long-lived credential).
  • Session tokens moved to sessionStorage. setUserSessionCredentials() persists to sessionStorage so the login survives a Cmd-R without landing in localStorage (no cross-tab reads, cleared on tab close). getToken() rehydrates the in-memory cache on the first call after a refresh. API-token credentials remain in-memory only.

Notes

  • No dashboard-only changes needed on existing pages. Permission gating is additive: the sidebar filters for user sessions, every other screen works identically whether the caller is an API token or a session-authed user.
  • Beta quality. The new auth flow has been exercised end-to-end against a local controller with all three login methods (code, magic link, passkey) plus TOTP enrolled. Live-testing on your own controller before relying on the browser UI for account-critical operations is still recommended.

[0.10.0-beta.1] — 2026-04-17

Controller compatibility: 0.10.0

Dashboard surface for the new Docker module, landing alongside the controller 0.10.0 release.

Added

  • New page: /modules/docker. Four status cards (module enabled, daemon reachable, daemon version + API version, running/total container counters) plus a table of every Nimbus-managed container with state badges, image, ports, and short ID. Prune button wires to POST /api/docker/prune. Polls at POLL.normal, pauses on tab hide, and silences transient failures so a brief daemon hiccup doesn't spam toasts.
  • Daemon-offline banner on the Docker page that surfaces the configured socket path when reachable: false, so operators see why opted-in services are running as plain processes.
  • Per-group Docker section on GroupEditDialog. Enable switch (switch off = no overrides written, TOML stays clean) plus memory limit, CPU limit, and Java image fields. Empty values mean "inherit module default".
  • Docker badge on the services list. Sky-blue Docker tag next to each containerised service name, backed by a new backedBy field on /api/services. Paired with the existing Dedicated + Persistent badges — no crowding, same row.
  • Sidebar icon. Container lucide icon exposed through @/lib/icons and wired into the module iconMap, so the Docker entry renders with a dedicated icon instead of the generic Box fallback.

Changed

  • GroupResponse now carries a docker sub-object. The types in group-edit-dialog.tsx reflect this; existing screens that don't read the field ignore it.
  • ServiceResponse gained backedBy. Values: "process" (default), "docker", "remote". Future runtime backends can add new values without breaking older dashboards — unknown values fall through without a badge.

Notes

  • No dashboard changes required on the existing /services page beyond the badge. Container-specific deep-links (logs, shell exec) stay out of Phase 1 — the /modules/docker page handles inspection; service-level log streaming continues to flow through the existing Console sheet, which works identically for process- and Docker-backed services.

[0.9.1-beta.1] — 2026-04-15

Controller compatibility: 0.9.1

The dashboard moves from alpha to beta. It is now suitable for day-to-day operation of a single-server or small-cluster Nimbus deployment — most workflows that previously required the console are available in the browser.

Highlights

  • Full group management (create, edit, delete) with typed-name delete confirmation.
  • Per-service console sheet with live log stream and command execution over WebSocket.
  • File and template browser at /files — breadcrumb navigation, upload with progress, mkdir, rename, delete, inline text editor for config-shaped files.
  • Global broadcast dialog in the header (network or per-group).
  • Player row actions: kick and transfer.
  • Maintenance whitelist card on Settings.
  • Cluster bootstrap card on Nodes (fingerprint, WebSocket URL, collapsible PEM reveal).
  • Load balancer card on Nodes (backend health, active connections).
  • Modpack import dialog now shows real upload progress.

Added

  • Beta channel. Dashboard now ships its own version (0.9.1-beta.1), independent of controller patch cadence. A Beta/Alpha badge in the sidebar reflects the channel.
  • Shared UX primitives. New PageShell component, useApiResource hook, and semantic severity color tokens (--severity-ok, --severity-warn, --severity-err, --severity-info).
  • Group CRUD UI with form validation that mirrors the controller's DTO (name regex, memory bounds, scaling ranges, JVM args).
  • Service Console Sheet — opens from the row action on both dynamic services and dedicated services. Raw WebSocket frames, 1000-line ring buffer, ANSI rendering, reconnect-aware.
  • File / Template Browser. Scopes: templates (rw), services (rw), groups (read-only). Multipart upload with XHR progress, mkdir, binary download path.
  • File editor with line numbers, tab-handling (tab inserts two spaces, shift-tab dedents), Ctrl/Cmd+S to save, Ctrl/Cmd+/ to toggle the language-appropriate line comment, dirty indicator, and unsaved-changes guard on page unload.
  • Image preview lightbox. Known image extensions (png, jpg, jpeg, gif, webp, svg, bmp, ico, avif) open in a Dialog with a blob-loaded preview instead of the text editor. Per-row "Preview" action.
  • Broadcast dialog in the site header. Target: network or a specific group.
  • Player row actions — kick (with reason) and transfer (with service/group target).
  • Maintenance whitelist card on the Settings page (toggle + add/remove).
  • Cluster bootstrap card and load balancer card on the Nodes page.
  • Modpack upload progress. Groups import dialog now shows a real percentage bar plus an indeterminate phase while the server resolves the pack.

Changed

  • Every page migrated to PageShell + useApiResource. Loading skeletons, empty states, and error banners are now consistent across the UI.
  • apiFetch auto-surfaces 4xx/5xx errors as toasts. Callers opt out with { silent: true } when rendering their own error UI.
  • Doctor page status colors extracted to semantic tokens. No more hardcoded emerald-* / amber-* / destructive classes in status UI.
  • Polling intervals standardized: POLL.fast (3s), POLL.normal (5s), POLL.slow (30s). Polling pauses while the tab is hidden.

Known backend gaps

These UIs were intentionally not shipped in beta because the controller endpoints aren't there yet:

  • Token management UI — the controller currently only exposes POST /api/tokens (generate) and GET /api/tokens/scopes. List and revoke are missing, so there's nothing sensible to render.
  • Scaling rule editor/api/scaling/schedules is read-only. Create, edit, and delete require new controller routes first.

Both are tracked as controller-side follow-ups; the dashboard will pick them up automatically once the endpoints exist.

Beta quality notes

  • Safe for day-to-day operation of a single-server or small-cluster deployment.
  • Long-running cluster operations (cross-node migration, state-sync troubleshooting) still benefit from the console.
  • Live-testing against a running controller is recommended before relying on the browser UI for critical operations.