Reusable Dioxus admin UI (hero_admin_lib_dx + serve_admin_dioxus) — build + match existing admins 1:1 #13

Open
opened 2026-06-10 11:13:17 +00:00 by timur · 8 comments
Owner

Summary

A reusable Dioxus admin-UI library so any Hero service gets a consistent admin panel (service name left, user right; default tabs Docs / OpenRPC / MCP / Agent / Logs + custom tabs) for near-zero code, served via the standard lifecycle. Goal: match the existing Askama admins 1:1 (dark theme, domain tabs with counts, system-stats sidebar, polished API docs), while keeping the library generic.

What already exists (pushed to development)

  • hero_admin_lib_dx (hero_website_framework/crates/hero_admin_lib_dx, @691f378) — the Dioxus component library: Admin builder (Admin::new("svc").title(..).tab(name, fn).launch()), shell (top bar + tab bar + switcher), tabs (Docs=router.markdown, OpenRPC=schema-driven playground, MCP, Agent=router.agent.run, Logs=hero_proc), JSON-Schema renderer, router transport, discovery. README + QUICKSTART in the crate.
  • hero_lifecycle::ServiceManifest::serve_admin_dioxus::<App>() (hero_lib@035a5d76) — serves an embedded dx bundle on admin.sock with brotli/gzip + SPA fallback, reusing the whole admin lifecycle. Sibling to serve_admin / serve_admin_dashboard.
  • Skill: hero_skills/skills/hero/ui/hero_admin_dioxus.{md,toml} — the full recipe (app crate + server crate + build.rs(dx) + service.toml + lab build/run).
  • Reference example (WIP, alongside the Askama admin, not replacing it): hero_proc/crates/hero_proc_admin_dx_app (Admin::new("hero_proc")), dx-builds + serves; pulls hero_admin_lib_dx from git.

Proven live

Discovery + schema playground (typed form → execute → typed result), Docs/MCP tabs, Logs (live hero_proc lines), switcher, dark mode — all verified in-browser against a running hero_router.

How a service uses it (target ergonomics)

App crate: Admin::new("hero_<svc>").title("Hero <Svc>").tab("Custom", custom_tab).launch();
Server crate: ServiceManifest::from_toml(SERVICE_TOML).serve_admin_dioxus::<App>().await + a one-line build.rs running dx.

Same-origin transport through hero_router → no API URLs, no CORS.

Remaining work (to reach 1:1 with the Askama admins)

  1. Multi-domain via /api/domains.json (depends on the multi-domain migration issue in hero_proc). Discover a service's domains, fetch each /api/{domain}/openrpc.json, route /api/{domain}/rpc. The domains map directly to the admin's domain tabs (Jobs/Logs/Secrets/System) — so this is how we get the rich domain-tab UI generically rather than hand-coding it.
  2. Dark theme default + ensure it applies to all states (empty-state currently renders outside the themed shell).
  3. System-stats sidebar — reusable component (memory/CPU/network sparklines, processes, jobs) from system.stats / hero_proc, matching the Askama sidebar.
  4. Namespace/domain tabs with live counts — derive tabs from method namespaces / domains.json and show counts, matching the Askama tab bar.
  5. Polish the OpenRPC tab to the two-panel method-browser + example/curl layout the Askama "API" tab uses.
  6. Spec fetch from the live endpoint (not just the router cache) — services whose spec isn't cached inline still render.
  7. Service-selection/default fix when bound to a single service.
  8. Migrate chrome from raw Bootstrap CDN to dioxus-bootstrap-css (ecosystem convention) if desired.

Reference (the design to match)

The existing Askama hero_proc_admin (kept running as the 1:1 reference): rich dark UI, domain tabs with counts (Actions/Services/Runs/Jobs/Secrets/Schedules/Logs/Stats/Admin/API/Docs/Terminal), System Stats sidebar, two-panel API docs. Compare side-by-side at …/hero_proc/admin/ (Askama) vs the Dioxus app (dx serve, ?router=…).

Iteration loop

App crate points at local hero_admin_lib_dx (path dep) while iterating; switch back to the git dep + push when a change is ready, so improvements land in the shared library for all services.

  • Multi-domain migration (blocks the rich domain-tab UI): companion issue in hero_proc.

Filed by Claude (owner-mode work for Timur).

## Summary A **reusable Dioxus admin-UI library** so any Hero service gets a consistent admin panel (service name left, user right; default tabs **Docs / OpenRPC / MCP / Agent / Logs** + custom tabs) for near-zero code, served via the standard lifecycle. Goal: **match the existing Askama admins 1:1** (dark theme, domain tabs with counts, system-stats sidebar, polished API docs), while keeping the library generic. ## What already exists (pushed to `development`) - **`hero_admin_lib_dx`** (`hero_website_framework/crates/hero_admin_lib_dx`, `@691f378`) — the Dioxus component library: `Admin` builder (`Admin::new("svc").title(..).tab(name, fn).launch()`), shell (top bar + tab bar + switcher), tabs (Docs=`router.markdown`, OpenRPC=schema-driven playground, MCP, Agent=`router.agent.run`, Logs=hero_proc), JSON-Schema renderer, router transport, discovery. README + QUICKSTART in the crate. - **`hero_lifecycle::ServiceManifest::serve_admin_dioxus::<App>()`** (`hero_lib@035a5d76`) — serves an embedded `dx` bundle on `admin.sock` with brotli/gzip + SPA fallback, reusing the whole admin lifecycle. Sibling to `serve_admin` / `serve_admin_dashboard`. - **Skill**: `hero_skills/skills/hero/ui/hero_admin_dioxus.{md,toml}` — the full recipe (app crate + server crate + build.rs(dx) + service.toml + lab build/run). - **Reference example (WIP, alongside the Askama admin, not replacing it)**: `hero_proc/crates/hero_proc_admin_dx_app` (`Admin::new("hero_proc")`), dx-builds + serves; pulls `hero_admin_lib_dx` from git. ### Proven live Discovery + schema playground (typed form → execute → typed result), Docs/MCP tabs, Logs (live hero_proc lines), switcher, dark mode — all verified in-browser against a running `hero_router`. ## How a service uses it (target ergonomics) App crate: `Admin::new("hero_<svc>").title("Hero <Svc>").tab("Custom", custom_tab).launch();` Server crate: `ServiceManifest::from_toml(SERVICE_TOML).serve_admin_dioxus::<App>().await` + a one-line `build.rs` running `dx`. Same-origin transport through `hero_router` → no API URLs, no CORS. ## Remaining work (to reach 1:1 with the Askama admins) 1. **Multi-domain via `/api/domains.json`** (depends on the multi-domain migration issue in `hero_proc`). Discover a service's domains, fetch each `/api/{domain}/openrpc.json`, route `/api/{domain}/rpc`. **The domains map directly to the admin's domain tabs** (Jobs/Logs/Secrets/System) — so this is how we get the rich domain-tab UI generically rather than hand-coding it. 2. **Dark theme** default + ensure it applies to all states (empty-state currently renders outside the themed shell). 3. **System-stats sidebar** — reusable component (memory/CPU/network sparklines, processes, jobs) from `system.stats` / hero_proc, matching the Askama sidebar. 4. **Namespace/domain tabs with live counts** — derive tabs from method namespaces / `domains.json` and show counts, matching the Askama tab bar. 5. **Polish the OpenRPC tab** to the two-panel method-browser + example/curl layout the Askama "API" tab uses. 6. **Spec fetch from the live endpoint** (not just the router cache) — services whose spec isn't cached inline still render. 7. Service-selection/default fix when bound to a single service. 8. Migrate chrome from raw Bootstrap CDN to `dioxus-bootstrap-css` (ecosystem convention) if desired. ## Reference (the design to match) The existing Askama `hero_proc_admin` (kept running as the 1:1 reference): rich **dark** UI, domain tabs with counts (Actions/Services/Runs/Jobs/Secrets/Schedules/Logs/Stats/Admin/API/Docs/Terminal), **System Stats** sidebar, two-panel API docs. Compare side-by-side at `…/hero_proc/admin/` (Askama) vs the Dioxus app (`dx serve`, `?router=…`). ## Iteration loop App crate points at **local** `hero_admin_lib_dx` (path dep) while iterating; switch back to the git dep + push when a change is ready, so improvements land in the shared library for all services. ## Related - Multi-domain migration (blocks the rich domain-tab UI): companion issue in `hero_proc`. *Filed by Claude (owner-mode work for Timur).*
Author
Owner

Multi-domain support landed: hero_website_framework@5e9724f.

The admin now handles the one-socket multi-domain model: it discovers a service's domains via /<svc>/rpc/api/domains.json, fetches each /api/<domain>/openrpc.json, and routes calls to /api/<domain>/rpc (domains.rs + OpenRpcTab). For hero_proc the OpenRPC tab shows domain sub-tabs jobs / logs / secrets / system, each with its schema-driven playground (88 jobs methods render live). Also: dark-theme default, and a discovery filter to the main rpc.sock entry (multi-domain services carry no inline cached spec).

Validated live against new-model hero_proc through hero_router.

Remaining toward 1:1 with the Askama admin:

  • domains as top-level tabs with counts (currently sub-tabs under OpenRPC)
  • System Stats sidebar (mem/CPU/net/jobs)
  • API-docs two-panel polish
  • Docs/MCP for multi-domain (they currently assume an aggregate spec; should aggregate domain specs or go per-domain)
Multi-domain support landed: `hero_website_framework@5e9724f`. The admin now handles the **one-socket multi-domain model**: it discovers a service's domains via `/<svc>/rpc/api/domains.json`, fetches each `/api/<domain>/openrpc.json`, and routes calls to `/api/<domain>/rpc` (`domains.rs` + `OpenRpcTab`). For `hero_proc` the OpenRPC tab shows domain sub-tabs **jobs / logs / secrets / system**, each with its schema-driven playground (88 jobs methods render live). Also: dark-theme default, and a discovery filter to the main `rpc.sock` entry (multi-domain services carry no inline cached spec). Validated live against new-model hero_proc through `hero_router`. Remaining toward 1:1 with the Askama admin: - domains as **top-level tabs with counts** (currently sub-tabs under OpenRPC) - **System Stats** sidebar (mem/CPU/net/jobs) - API-docs **two-panel** polish - Docs/MCP for multi-domain (they currently assume an aggregate spec; should aggregate domain specs or go per-domain)
Author
Owner

Multi-domain support landed: hero_website_framework@5e9724f.

The admin now handles the one-socket multi-domain model: it discovers a service's domains via /<svc>/rpc/api/domains.json, fetches each /api/<domain>/openrpc.json, and routes calls to /api/<domain>/rpc (domains.rs + OpenRpcTab). For hero_proc the OpenRPC tab shows domain sub-tabs jobs / logs / secrets / system, each with its schema-driven playground (88 jobs methods render live). Also: dark-theme default, and a discovery filter to the main rpc.sock entry (multi-domain services carry no inline cached spec).

Validated live against new-model hero_proc through hero_router.

Remaining toward 1:1 with the Askama admin:

  • domains as top-level tabs with counts (currently sub-tabs under OpenRPC)
  • System Stats sidebar (mem/CPU/net/jobs)
  • API-docs two-panel polish
  • Docs/MCP for multi-domain (they currently assume an aggregate spec; should aggregate domain specs or go per-domain)
Multi-domain support landed: `hero_website_framework@5e9724f`. The admin now handles the **one-socket multi-domain model**: it discovers a service's domains via `/<svc>/rpc/api/domains.json`, fetches each `/api/<domain>/openrpc.json`, and routes calls to `/api/<domain>/rpc` (`domains.rs` + `OpenRpcTab`). For `hero_proc` the OpenRPC tab shows domain sub-tabs **jobs / logs / secrets / system**, each with its schema-driven playground (88 jobs methods render live). Also: dark-theme default, and a discovery filter to the main `rpc.sock` entry (multi-domain services carry no inline cached spec). Validated live against new-model hero_proc through `hero_router`. Remaining toward 1:1 with the Askama admin: - domains as **top-level tabs with counts** (currently sub-tabs under OpenRPC) - **System Stats** sidebar (mem/CPU/net/jobs) - API-docs **two-panel** polish - Docs/MCP for multi-domain (they currently assume an aggregate spec; should aggregate domain specs or go per-domain)
Author
Owner

Progress — multi-domain shell now 1:1 with the Askama reference

Pushed to development (hero_website_framework@c9d5ab0). Validated live against new-model hero_proc (one rpc.sock, /api/domains.json) via headless Chrome.

Landed this round:

  • Domains promoted to top-level tabs with method-count badgesjobs 88 / logs 10 / secrets 11 / system 9, then Docs / MCP / Agent / Logs. Each domain tab is the schema-driven playground for that domain (/<svc>/rpc/api/<domain>/rpc). The generic OpenRPC tab is dropped when domains are present, kept as the single-domain fallback.
  • Persistent System Stats left sidebar (Memory / CPU / Network / Processes / Jobs), polled from the system domain's system.stats every 3s. Mounted only when the service exposes a system domain, so it stays generic across services. Live: Memory 11.4 GB (67%), CPU, RX/TX, OS processes 723 / Services 2, Jobs running/pending/failed/total.
  • Docs tab is domain-aware — generates a per-domain reference (methods + summaries) when there's no aggregate spec (fixes the old No cached OpenRPC spec error); single-domain still uses router-generated markdown.
  • MCP tab aggregates tools across all domains (118 tools for hero_proc, was empty).

domains.rs gained list_with_specs() (list + per-domain spec in one pass, reused for both badges and panels) and stats().

Remaining toward full polish: API method panel two-pane refinement (request/response side-by-side); richer per-domain table views (the Askama admin renders Actions/Jobs/Runs as bespoke tables vs. our generic playground); optional bootstrap-icons in the tab bar. The hero_proc app still uses a local path dep on hero_admin_lib_dx for iteration — switch to the git dep once design settles.

Multi-domain socket migration for hero_proc itself remains tracked in hero_proc#148.

### Progress — multi-domain shell now 1:1 with the Askama reference Pushed to `development` (`hero_website_framework@c9d5ab0`). Validated live against new-model `hero_proc` (one `rpc.sock`, `/api/domains.json`) via headless Chrome. **Landed this round:** - **Domains promoted to top-level tabs with method-count badges** — `jobs 88 / logs 10 / secrets 11 / system 9`, then `Docs / MCP / Agent / Logs`. Each domain tab is the schema-driven playground for that domain (`/<svc>/rpc/api/<domain>/rpc`). The generic OpenRPC tab is dropped when domains are present, kept as the single-domain fallback. - **Persistent System Stats left sidebar** (Memory / CPU / Network / Processes / Jobs), polled from the `system` domain's `system.stats` every 3s. Mounted only when the service exposes a `system` domain, so it stays generic across services. Live: `Memory 11.4 GB (67%)`, `CPU`, `RX/TX`, `OS processes 723 / Services 2`, `Jobs running/pending/failed/total`. - **Docs tab is domain-aware** — generates a per-domain reference (methods + summaries) when there's no aggregate spec (fixes the old `No cached OpenRPC spec` error); single-domain still uses router-generated markdown. - **MCP tab aggregates tools across all domains** (118 tools for hero_proc, was empty). `domains.rs` gained `list_with_specs()` (list + per-domain spec in one pass, reused for both badges and panels) and `stats()`. **Remaining toward full polish:** API method panel two-pane refinement (request/response side-by-side); richer per-domain table views (the Askama admin renders Actions/Jobs/Runs as bespoke tables vs. our generic playground); optional bootstrap-icons in the tab bar. The hero_proc app still uses a **local path dep** on `hero_admin_lib_dx` for iteration — switch to the git dep once design settles. Multi-domain socket migration for hero_proc itself remains tracked in hero_proc#148.
Author
Owner

Follow-up (hero_website_framework@0f69939): method panel is now two-pane — Parameters + Execute in a Request card on the left, result in a Response card on the right (stacks on narrow viewports). Validated live: ran jobs.action_list through the router → ["hero_proc_admin","hero_router"] in the Response pane.

Remaining in this issue is now just optional polish: bespoke per-domain table views (the generic schema playground is the reusable equivalent — deferring unless we want service-specific table renderers), tab-bar icons, and switching the hero_proc demo app from its local path dep to the git dep once the design is final.

Follow-up (`hero_website_framework@0f69939`): **method panel is now two-pane** — Parameters + Execute in a `Request` card on the left, result in a `Response` card on the right (stacks on narrow viewports). Validated live: ran `jobs.action_list` through the router → `["hero_proc_admin","hero_router"]` in the Response pane. Remaining in this issue is now just optional polish: bespoke per-domain table views (the generic schema playground is the reusable equivalent — deferring unless we want service-specific table renderers), tab-bar icons, and switching the hero_proc demo app from its local path dep to the git dep once the design is final.
Author
Owner

Redesign — header domain-picker + island layout (hero_website_framework@b00de26)

Reworked the shell per design review:

  • Domain selection moved from the tab bar to a header dropdown next to the service name (domain: All domains ▾, each option shows its method count). The built-in tabs now render scoped to the selected domain (or all when none is picked).
  • Fixed tabs are Playground / Docs / MCP / Agent, rendered as rounded pills inside the content area (right of the sidebar) — no longer a full-width bar.
  • Left column is an always-on service summary: a System Stats island on top, a Logs island below.
  • Everything is laid out as floating islands (rounded, bordered, gaps) instead of flush rectangles.

Playground is domain-aware: a specific domain shows its panel; All shows every domain's methods grouped, each routed to its own /api/<domain>/rpc. Docs/MCP filter to the selected domain.

Logs were rewired onto the new one-socket logs domain (/<svc>/rpc/api/logs/rpc find with the required LogFilter fields error_only/limit/offset), mapping LogEntry{content,src,epoch} → line, stripping ANSI, and classifying severity from the message text (the capture's error flag only means from stderr). The hero_proc admin shows all activity; other services scope to their own source prefix.

Validated live: domain picker scopes the playground (secrets → 11 methods) and docs; the Logs island populates 80 clean lines.

Note / follow-up: the playground executes destructive methods (system.shutdown / reboot / wipe_all) live with no confirmation — worth a confirm guard in the method panel, since running shutdown takes down hero_proc (the supervisor) and the whole managed stack with it.

### Redesign — header domain-picker + island layout (`hero_website_framework@b00de26`) Reworked the shell per design review: - **Domain selection moved from the tab bar to a header dropdown** next to the service name (`domain: All domains ▾`, each option shows its method count). The built-in tabs now render **scoped to the selected domain** (or all when none is picked). - **Fixed tabs are Playground / Docs / MCP / Agent**, rendered as rounded pills **inside the content area** (right of the sidebar) — no longer a full-width bar. - **Left column is an always-on service summary**: a System Stats island on top, a Logs island below. - **Everything is laid out as floating islands** (rounded, bordered, gaps) instead of flush rectangles. Playground is domain-aware: a specific domain shows its panel; **All** shows every domain's methods grouped, each routed to its own `/api/<domain>/rpc`. Docs/MCP filter to the selected domain. **Logs** were rewired onto the new one-socket logs domain (`/<svc>/rpc/api/logs/rpc` `find` with the required `LogFilter` fields `error_only/limit/offset`), mapping `LogEntry{content,src,epoch}` → line, stripping ANSI, and classifying severity from the message text (the capture's `error` flag only means *from stderr*). The hero_proc admin shows all activity; other services scope to their own source prefix. Validated live: domain picker scopes the playground (`secrets` → 11 methods) and docs; the Logs island populates 80 clean lines. **Note / follow-up:** the playground executes destructive methods (`system.shutdown` / `reboot` / `wipe_all`) live with no confirmation — worth a confirm guard in the method panel, since running shutdown takes down hero_proc (the supervisor) and the whole managed stack with it.
Author
Owner

Generic shell + service-defined tabs — hero_proc views ported

Architecture landed (hero_website_framework@f9842db): the sidebar/shell is now a generic service UI any admin reuses — service name (+switcher), description, per-socket health dots, domain selector, and the service's logs (aggregated across its job sources, filterable). No service-specific UI in the shell. All bespoke views are service-defined tabs via Admin::tab(label, fn).

hero_proc app (hero_proc@12170e9, now committed + on the git dep to development) demonstrates the pattern with the full Askama view set ported as tabs:

  • Jobsjob_list_full table + Restart / Stop / Delete
  • Servicesservice_list_full table + Start / Restart / Stop
  • Runsrun_list_full table + Delete
  • Schedulesschedule_list_full table + Delete
  • Secretssecret_list_full (secrets domain) + Delete; surfaces backend errors (the local secrets DB is currently malformed, shown as a banner)
  • Stats — system memory / CPU / network / processes / services / jobs
  • Admin — Stop All / Restart Failed / Clean Jobs / Reboot / Shutdown

Safety: destructive actions (Stop/Delete/Restart/Admin ops) use an inline arm-then-confirm (first click → red "Confirm", second runs) so a stray click can't stop hero_router and cut the admin off.

Validated live via headless Chrome (tables populate, badges, actions, arm guard, error banners).

Remaining: Terminal. It can't be a pure app tab — there's no PTY method on the RPC domain, the router doesn't proxy the PTY WebSocket path (returns 400), and the interactive PTY is served by the admin's own web server. A working Terminal needs backend plumbing (expose/proxy the PTY WS via serve_admin_dioxus or the router) plus xterm.js interop in the WASM frontend — a separate cross-cutting feature, deliberately deferred rather than shipped broken.

### Generic shell + service-defined tabs — hero_proc views ported **Architecture landed** (`hero_website_framework@f9842db`): the sidebar/shell is now a **generic service UI** any admin reuses — service name (+switcher), description, per-socket health dots, domain selector, and the service's logs (aggregated across its job sources, filterable). No service-specific UI in the shell. All bespoke views are **service-defined tabs** via `Admin::tab(label, fn)`. **hero_proc app** (`hero_proc@12170e9`, now committed + on the git dep to development) demonstrates the pattern with the full Askama view set ported as tabs: - **Jobs** — `job_list_full` table + Restart / Stop / Delete - **Services** — `service_list_full` table + Start / Restart / Stop - **Runs** — `run_list_full` table + Delete - **Schedules** — `schedule_list_full` table + Delete - **Secrets** — `secret_list_full` (secrets domain) + Delete; surfaces backend errors (the local secrets DB is currently malformed, shown as a banner) - **Stats** — system memory / CPU / network / processes / services / jobs - **Admin** — Stop All / Restart Failed / Clean Jobs / Reboot / Shutdown **Safety:** destructive actions (Stop/Delete/Restart/Admin ops) use an inline **arm-then-confirm** (first click → red "Confirm", second runs) so a stray click can't stop hero_router and cut the admin off. Validated live via headless Chrome (tables populate, badges, actions, arm guard, error banners). **Remaining: Terminal.** It can't be a pure app tab — there's no PTY method on the RPC domain, the router doesn't proxy the PTY WebSocket path (returns 400), and the interactive PTY is served by the admin's own web server. A working Terminal needs backend plumbing (expose/proxy the PTY WS via `serve_admin_dioxus` or the router) plus xterm.js interop in the WASM frontend — a separate cross-cutting feature, deliberately deferred rather than shipped broken.
Author
Owner

Second service proves the shell is generic — hero_router admin (hero_router@ffc955d)

Built a coexisting Dioxus admin for hero_router on the same generic shell (hero_admin_lib_dx), alongside its existing Askama admin — no shell changes were needed, which is the point.

Generic shell (unchanged): Playground / Docs / MCP / Agent + the service sidebar (identity Hero Router v0.2.1 + description, per-socket health, logs scoped to the router source). The Playground drives the router's own 38 router.* methods via its cached spec.

Router-specific tabs (router.* RPC):

  • Services — the discovered-service registry (router.services): title, context, health, method count, version, last checked, + Rescan.
  • Status — discovery summary (total / healthy / inactive / auto / manual) + uptime + last scan.
  • Access — the IP allowlist (router.access.list) with context/state + Clear (here it shows hero_proc_unreachable, surfaced in a banner, because the local hero_proc secrets DB is malformed).
  • SSH Keysrouter.ssh_keys.list.
  • Admin — Rescan / Health Check / Clean (destructive arm-then-confirm).

Validated live against the running router: 5 services listed, status 5 total / 4 healthy / 1 inactive, uptime ~10h, access state surfaced.

App pattern is identical to the hero_proc one: an isolated wasm [workspace] crate depending on hero_admin_lib_dx via the git (development) dep, adding service tabs with Admin::tab(..). Terminal remains the one deferred view for both services (needs PTY-WS backend plumbing).

### Second service proves the shell is generic — hero_router admin (`hero_router@ffc955d`) Built a coexisting Dioxus admin for **hero_router** on the same generic shell (`hero_admin_lib_dx`), alongside its existing Askama admin — no shell changes were needed, which is the point. Generic shell (unchanged): Playground / Docs / MCP / Agent + the service sidebar (identity `Hero Router v0.2.1` + description, per-socket health, logs scoped to the `router` source). The Playground drives the router's own 38 `router.*` methods via its cached spec. Router-specific tabs (`router.*` RPC): - **Services** — the discovered-service registry (`router.services`): title, context, health, method count, version, last checked, + Rescan. - **Status** — discovery summary (total / healthy / inactive / auto / manual) + uptime + last scan. - **Access** — the IP allowlist (`router.access.list`) with context/state + Clear (here it shows `hero_proc_unreachable`, surfaced in a banner, because the local hero_proc secrets DB is malformed). - **SSH Keys** — `router.ssh_keys.list`. - **Admin** — Rescan / Health Check / Clean (destructive arm-then-confirm). Validated live against the running router: 5 services listed, status 5 total / 4 healthy / 1 inactive, uptime ~10h, access state surfaced. App pattern is identical to the hero_proc one: an isolated wasm `[workspace]` crate depending on `hero_admin_lib_dx` via the git (development) dep, adding service tabs with `Admin::tab(..)`. Terminal remains the one deferred view for both services (needs PTY-WS backend plumbing).
Author
Owner

Dioxus admins now served behind hero_router (serve_admin_dioxus validated end-to-end)

The Dioxus admins are now reachable through hero_router exactly like the existing service admin UIs — not just dx serve dev. Per the hero_skills convention (/hero_sockets, /hero_web_default_routes): a service admin UI is a web app on a <svc>/<stem>.sock that exposes /health.json + /heroservice.json; the router discovers it and proxies it at /{svc}/{socket_stem}/.

Implemented a tiny server crate per service (hero_proc_admin_dx, hero_router_admin_dxhero_proc@f5bfead, hero_router@1457df1):

  • Isolated [workspace] crate; deps = hero_lifecycle {git, branch=development, features=[webserver-admin]} + rust-embed + tokio.
  • main.rs is 3 lines: ServiceManifest::from_toml(TOML).peer("<svc>").serve_admin_dioxus::<App>().await with App = #[derive(RustEmbed)] #[folder="app_dist/"].
  • service.toml declares an admin manifest on <svc>/admindx.sock (coexists with the Askama admin.sock).
  • build.rs runs dx build --platform web --base-path <svc>/admindx on the sibling app crate and stages web/publicapp_dist/. The base-path equals the router proxy segment so the SPA's absolute asset URLs resolve behind the proxy; RPC calls go same-origin to the router (no ?router= needed).

Reachable at http://<router:9988>/hero_proc/admindx/ and /hero_router/admindx/ — validated live: the full admin renders and Jobs lists live jobs through the router.

This validates hero_lifecycle::serve_admin_dioxus (035a5d76) end-to-end for the first time. Follow-up: register these admin servers with lab/zinit so they autostart alongside each service.

### Dioxus admins now served behind hero_router (serve_admin_dioxus validated end-to-end) The Dioxus admins are now reachable **through hero_router** exactly like the existing service admin UIs — not just `dx serve` dev. Per the hero_skills convention (`/hero_sockets`, `/hero_web_default_routes`): a service admin UI is a web app on a `<svc>/<stem>.sock` that exposes `/health.json` + `/heroservice.json`; the router discovers it and proxies it at `/{svc}/{socket_stem}/`. Implemented a tiny **server crate** per service (`hero_proc_admin_dx`, `hero_router_admin_dx` — `hero_proc@f5bfead`, `hero_router@1457df1`): - Isolated `[workspace]` crate; deps = `hero_lifecycle {git, branch=development, features=[webserver-admin]}` + rust-embed + tokio. - `main.rs` is 3 lines: `ServiceManifest::from_toml(TOML).peer("<svc>").serve_admin_dioxus::<App>().await` with `App = #[derive(RustEmbed)] #[folder="app_dist/"]`. - `service.toml` declares an admin manifest on `<svc>/admindx.sock` (coexists with the Askama `admin.sock`). - `build.rs` runs `dx build --platform web --base-path <svc>/admindx` on the sibling app crate and stages `web/public` → `app_dist/`. The base-path equals the router proxy segment so the SPA's absolute asset URLs resolve behind the proxy; RPC calls go same-origin to the router (no `?router=` needed). **Reachable at** `http://<router:9988>/hero_proc/admindx/` and `/hero_router/admindx/` — validated live: the full admin renders and Jobs lists live jobs through the router. This validates `hero_lifecycle::serve_admin_dioxus` (035a5d76) end-to-end for the first time. Follow-up: register these admin servers with lab/zinit so they autostart alongside each service.
Sign in to join this conversation.
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
lhumina_code/hero_website_framework#13
No description provided.