feat(admin): Leptos admin UI foundation served at /admin (VS-21) #35

Merged
nrupard merged 2 commits from feat/vervain-admin-leptos-scaffold-VS-21 into main 2026-05-21 20:17:43 +02:00
Owner

What

VS-21 foundation slice: the Leptos admin UI rendered server-side and mounted into the existing axum server, with one read-only operator workflow (list meshes). This is the smallest mergeable slice of the larger epic (one Rust frontend codebase targeting browser, desktop, and mobile via Leptos + Tauri 2).

Changes

  • New crate crates/vervain-admin: Leptos components plus render_admin_html(AdminData) -> String. No database dependency; the web crate fetches data and hands plain props, so the same AdminData shape can later back a #[server] RPC. Each render establishes a fresh reactive Owner, so the output is self-contained and thread-safe with no global runtime.
  • meshcentral-web/src/admin.rs: GET /admin and GET /:domain/admin, both behind session auth (unauthenticated redirects to /login). Loads the operator's meshes via the existing meshes_with_rights path, counts nodes with a single list_by_type("node", domain) (no N+1), sorts by name then id.
  • Wired the crate into the workspace, added the route, README section.

Scope / decisions

Mounted into the existing axum router (single binary serves API + admin UI, reusing session middleware) rather than a standalone cargo-leptos server. Because the build image (rust-builder-musl, rust 1.94, alpine) has no wasm32-unknown-unknown target or cargo-leptos, this slice is SSR-only: the page is static server-rendered HTML (links navigate, forms post) with no client reactivity yet. The render_admin_html seam does not change when hydration lands.

Deliberately out of scope, tracked as separate VS-21 follow-ups: client-side hydration / CSR, #[server] typed RPC, the remaining workflows (view agent, open tunnel, push command, audit log), and the Tauri desktop/mobile shells with signing and store distribution. Code-signing certs, Apple/Play accounts, and the 4-artifact CI are ops items, not code in this PR.

Tests

  • vervain-admin unit tests: full-document render, mesh rows, empty state.
  • meshcentral-web/tests/admin.rs: logs in over TLS, asserts /admin renders the seeded mesh name, type, and device count; asserts an unauthenticated request redirects to login.
  • cargo fmt --check, cargo clippy --all-targets -- -D warnings, and cargo test all green for both crates in the dev docker image.

🤖 Generated with Claude Code

## What VS-21 foundation slice: the Leptos admin UI rendered server-side and mounted into the existing axum server, with one read-only operator workflow (list meshes). This is the smallest mergeable slice of the larger epic (one Rust frontend codebase targeting browser, desktop, and mobile via Leptos + Tauri 2). ## Changes - New crate `crates/vervain-admin`: Leptos components plus `render_admin_html(AdminData) -> String`. No database dependency; the web crate fetches data and hands plain props, so the same `AdminData` shape can later back a `#[server]` RPC. Each render establishes a fresh reactive `Owner`, so the output is self-contained and thread-safe with no global runtime. - `meshcentral-web/src/admin.rs`: `GET /admin` and `GET /:domain/admin`, both behind session auth (unauthenticated redirects to `/login`). Loads the operator's meshes via the existing `meshes_with_rights` path, counts nodes with a single `list_by_type("node", domain)` (no N+1), sorts by name then id. - Wired the crate into the workspace, added the route, README section. ## Scope / decisions Mounted into the existing axum router (single binary serves API + admin UI, reusing session middleware) rather than a standalone cargo-leptos server. Because the build image (`rust-builder-musl`, rust 1.94, alpine) has no `wasm32-unknown-unknown` target or `cargo-leptos`, this slice is SSR-only: the page is static server-rendered HTML (links navigate, forms post) with no client reactivity yet. The `render_admin_html` seam does not change when hydration lands. Deliberately out of scope, tracked as separate VS-21 follow-ups: client-side hydration / CSR, `#[server]` typed RPC, the remaining workflows (view agent, open tunnel, push command, audit log), and the Tauri desktop/mobile shells with signing and store distribution. Code-signing certs, Apple/Play accounts, and the 4-artifact CI are ops items, not code in this PR. ## Tests - `vervain-admin` unit tests: full-document render, mesh rows, empty state. - `meshcentral-web/tests/admin.rs`: logs in over TLS, asserts `/admin` renders the seeded mesh name, type, and device count; asserts an unauthenticated request redirects to login. - `cargo fmt --check`, `cargo clippy --all-targets -- -D warnings`, and `cargo test` all green for both crates in the dev docker image. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
feat(admin): Leptos admin UI foundation served at /admin (VS-21)
Some checks failed
Check / fmt + clippy + build + tests (pull_request) Failing after 3s
f7a5ec013c
VS-21 ships one Rust frontend codebase (Leptos + Tauri 2) targeting browser, desktop, and mobile. This is the foundation slice: the Leptos view layer rendered server-side and mounted into the existing axum server, with one read-only operator workflow (list meshes).

New crate `crates/vervain-admin` holds the Leptos components and `render_admin_html(AdminData) -> String`. It carries no database dependency: the web crate fetches data and passes plain props, so the same shape can later back a `#[server]` RPC without a rewrite. Rendering establishes a fresh reactive `Owner` per call, so the output is self-contained and thread-safe with no global runtime.

`meshcentral-web/src/admin.rs` adds `GET /admin` and `GET /:domain/admin`. Both require an authenticated session (unauthenticated requests redirect to `/login`), then load the operator's meshes via the existing `meshes_with_rights` path and count nodes per mesh with a single `list_by_type("node", domain)` rather than an N+1 lookup. Results are sorted by name then id for stable output.

Out of scope here, tracked as separate VS-21 follow-ups: client-side hydration / CSR (needs the `wasm32-unknown-unknown` target and `cargo-leptos`, neither in the build image yet, so the page is static server-rendered HTML for now), `#[server]` typed RPC, the remaining workflows (view agent, open tunnel, push command, audit log), and the Tauri desktop/mobile shells with signing and store distribution.

Tests: unit tests in `vervain-admin` cover the full-document render, the mesh rows, and the empty state; a new `meshcentral-web/tests/admin.rs` integration test logs in over TLS and asserts `/admin` renders the seeded mesh, its type, and device count, and that an unauthenticated request redirects to login.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
refactor(admin): apply review nits (widen mesh_type, branch over Show, escaping test)
Some checks failed
Check / fmt + clippy + build + tests (pull_request) Failing after 3s
Create release / Create release from merged PR (pull_request) Has been skipped
98d31e4242
- Widen `MeshSummary.mesh_type` from `u8` to `u16` and saturate the `as` cast in the web handler, so an out-of-range stored `meshtype` renders as "unknown" instead of being truncated into a valid-looking type.
- Replace the reactive `Show` in `MeshesPage` with a plain Rust `if/else` returning `AnyView`: the rows are built only when non-empty and nothing is cloned for a fallback. Equivalent output for the once-per-request SSR path.
- Document that the `:domain` path segment on `/:domain/admin` is informational only (identity and visibility come from the session user, not the path).
- Add a `vervain-admin` regression test asserting operator-controlled strings (mesh name, id, user id) are HTML-escaped, plus a test that an unknown `mesh_type` is not truncated.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
nrupard deleted branch feat/vervain-admin-leptos-scaffold-VS-21 2026-05-21 20:17:43 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/vervain-server!35
No description provided.