- Rust 97.4%
- CSS 1%
- Just 0.9%
- Nushell 0.4%
- JavaScript 0.2%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
All checks were successful
Check / fmt + clippy + build + tests (push) Successful in 1m13s
Reviewed-on: #101 |
||
| .forgejo/workflows | ||
| assets | ||
| ci-build | ||
| common@7397c2a043 | ||
| docker/template/vervain-apps | ||
| src | ||
| .gitignore | ||
| .gitmodules | ||
| Cargo.lock | ||
| Cargo.toml | ||
| Dioxus.toml | ||
| justfile | ||
| package.json | ||
| README.md | ||
| tailwind.config.js | ||
Vervain
Dioxus 0.7 fullstack frontend for vervain-server. Runs as a web app and as a wry desktop window from a single codebase.
| Artifact | Identifier | Where it ships |
|---|---|---|
| Cargo crate / bin | vervain-app |
target/release/vervain-app, Generic Packages registry |
| Container image | vervain-web |
Forgejo Container Registry: dev.a8n.run/<owner>/vervain-web |
This is the Rust port of the Vervain web UI. It does not port the
handlebars views (../vervain-server/views/) or any of the bundled JS in
../vervain-server/public/scripts/. Designed from scratch with information
density as the priority. Two built-in themes, switchable in Settings →
Appearance:
- Pro - dense, dark sidebar, square corners, monospace-friendly.
- Soft - light sidebar, rounded cards, same row density.
Layout
vervain-apps/
Cargo.toml Dioxus 0.7 fullstack crate
Dioxus.toml dx serve config
tailwind.config.js custom font scale, ink/accent palette
package.json tailwindcss build dep (bun, run in Docker by `just build-css`)
justfile dev / build / check recipes
assets/
tailwind.css @tailwind directives
tailwind-built.css (generated, gitignored)
main.css theme variables + shared primitives
src/
main.rs launch + root context providers
theme.rs Theme / Density enums
routes.rs Routable enum
models/ Device, Group, User, Event, ...
server_fns/ #[server] fns proxying vervain-server (control channel + HTTP)
components/
layout.rs sidebar + topbar + statusbar shell
sidebar.rs grouped nav (Overview / Fleet / Admin)
topbar.rs title + breadcrumb + global search
statusbar.rs connection state + theme/density toggles
pages/
dashboard.rs
devices.rs
device_detail.rs
groups.rs
users.rs
events.rs
plugins.rs
relays.rs
settings.rs
Routes
| Path | Page |
|---|---|
/ |
Dashboard |
/devices |
Device list |
/devices/:device_id |
Device detail |
/groups |
Groups |
/users |
Users |
/events |
Event log |
/plugins |
Plugins |
/relays |
Relays |
/settings |
Settings |
Develop
One-time setup:
rustup target add wasm32-unknown-unknown
cargo install dioxus-cli # provides `dx`
Tailwind is built by just build-css inside a pinned oven/bun Docker image,
so the only host requirements for the CSS build (and the recipes that depend on
it, including the just pre-commit hook) are Docker and git. No host bun
install is needed. just install remains for running host bun directly if you
prefer it.
Run the web build with hot reload (in two terminals so Tailwind rebuilds CSS on change):
just watch-css # term 1
just dev-web # term 2
Run the desktop build (single window, embedded server):
just dev-desktop
Checks
just check # cargo check (server + wasm) + clippy + fmt
just fmt
just test
Where the real data comes from
Every page reads from a #[server] fn in src/server_fns/mod.rs. Those fns
proxy vervain-server on behalf of the browser session: list/data actions go
over the /control.ashx WebSocket control channel
(src/server_fns/control.rs), auth and setup go over plain HTTP (POST /login, /api/setup). The vervain-server session token is held in an
HTTP-only vervain_session cookie on this app's origin and forwarded as the
vervain_session cookie vervain-server expects. VERVAIN_SERVER_INTERNAL_URL
points the server side of this app at vervain-server for those server-to-server
hops; VERVAIN_SERVER_PUBLIC_URL is the browser-reachable origin used to build
the relay and control WebSocket URLs the browser opens directly. It must be the
external https:// origin, not the internal address (VAPP-41): the scheme is
derived from it, so an http:// value yields insecure ws:// sockets that a
secure (https) SPA page is mixed-content-blocked from opening, leaving the
terminal/files/desktop relays dead and the statusbar stuck on "disconnected"
(VAPP-45). The corresponding server-side modules are in
../vervain-server/crates/vervain-web/src/.
The desktop build has no container to set those env vars on, so it resolves its
server URL at startup in order (VAPP-58): a build-time baked value first, then a
value the user persisted, then a first-run prompt. Set VERVAIN_BAKED_SERVER_URL
at compile time to ship a branded, pre-configured build (it is read via
option_env!, baked into the binary, and both suppresses the first-run prompt
and makes the Settings "Server URL" read-only). Leave it unset for the generic
self-hosted build: on first launch the login screen prompts for the server URL,
persists it to the OS config dir (src/desktop_config.rs), and reuses it on
later launches. Settings lets a self-hosted user change or clear that URL to
point the app at a different instance without reinstalling.
Caveats that fall out of the server's current API surface:
serverstatsandpluginsare admin-only control actions and the server silently ignores them otherwise; affected widgets render a dash or an explanatory error for non-admins.- Node docs carry no OS string, so the Devices table shows the agent's platform type (Desktop, Laptop, Server, ...) instead.
- There is no per-relay listing; the Relays page shows aggregate counts from
serverstats.