Gunnar

nordisk/holger-egui

src/lib.rs

//! # holger-server-ui
//!
//! An operator/admin UI for [holger](https://codeberg.org/nordisk/holger).
//!
//! The UI is built in two layers:
//!
//! * [`data`] — the transport-agnostic **view-model**. It drives the core
//!   [`traits::HolgerObject`] API (satisfied by `LocalHolger` for direct,
//!   in-process rust calls into holger core, or `RemoteHolger` over gRPC) and
//!   turns each response into a plain view struct that exposes `state_json()`.
//!   This is the "render-from-data / see-what-the-user-sees as data" law: the UI
//!   can be driven and asserted headlessly with no display and no egui. It is
//!   the default build and carries the unit tests.
//!
//! * [`app`] (behind the `gui` feature) — the egui presentation, built from
//!   [facett](https://codeberg.org/nordisk/facett) components, mirroring the
//!   nornir-viz idiom (one blocking core call per UI action on a private
//!   current-thread runtime).
//!
//! Both layers are generic over `Arc<dyn HolgerObject>`, so the same UI runs
//! embedded (no network) or against a remote holger server.

// ══════════════════════════════════════════════════════════════════════════════
// TIER COHERENCE — the ladder is `gui` ⊃ `gui-mini` ⊃ `gui-mikro`, and the pane
// code gates on the SURFACE marker (`mini` / `mikro`) rather than on each pane
// feature. That is sound exactly as long as a tier is picked: the full tier has
// every pane and no marker, the read-only tiers have the marker and no pane. A
// bare `--features gui-core` would compile the full-tier pane bodies with their
// dependencies absent, and the error would be forty missing-crate messages
// instead of one sentence. So: one sentence.
#[cfg(all(feature = "gui-core", not(any(feature = "gui", feature = "mini"))))]
compile_error!(
    "holger-server-ui: `gui-core` is a building block, not a tier — build with one of \
     `--features gui` (the thin operator UI), `--features gui-mini`, \
     `--features gui-mikro`, or `--features gui-embedded` (the opt-in build that \
     may open state in this process)"
);
// The tiers are mutually exclusive in the same sense the SERVER tiers are: each
// links a different closure, and a union is neither of them.
#[cfg(all(feature = "gui", feature = "mini"))]
compile_error!(
    "holger-server-ui: the UI tiers are mutually exclusive — `gui` (full) and \
     `gui-mini`/`gui-mikro` (read-only) link different dependency closures; pick one"
);
// `demo` drives the UI through the same `pub` hooks a human click would run, and three
// of those are `#[cfg(not(feature = "mini"))]` members the read-only tiers do not
// compile: the `notice` line, `select_graph_node`, and `security_graph`.
//
// No SHIPPED tier combines the two — `gui-embedded` takes `demo` WITHOUT `mini`, and
// `gui-mini`/`gui-mikro` take `mini` without `demo` — so this has never broken a build
// that ships. But nothing DECLARED it either, so the combination was merely unreachable
// by convention, and `--all-features` (what docs.rs runs) failed with three
// `E0609`/`E0599` at `app.rs:888/902/910` instead of a reason. Same argument as the
// guard above: one sentence. Found by the fleet-wide compile sweep, 2026-08-01.
//
// Deliberately a refusal, not a silent skip: making the three actions no-op under
// `mini` would let a demo walk "pass" in a tier where it cannot show anything, which is
// the false-green this fleet keeps paying for.
#[cfg(all(feature = "demo", feature = "mini"))]
compile_error!(
    "holger-server-ui: `demo` needs the full panes — it drives `notice`, \
     `select_graph_node` and `security_graph`, which the read-only `mini`/`mikro` \
     tiers do not compile. Build the demo on the full tier with \
     `--features gui-embedded`, or drop `demo` from a mini build"
);

pub mod data;

/// The **About** identity/branding surface (shared common-framework parity): the
/// holger logo + wordmark + version + the shared components it is built on. The
/// identity oracle is always compiled (headless-assertable); the egui render body is
/// behind `gui`.
pub mod about;

/// **Tools · Demo appliance** — a jera-backed demo container spec + dispatch (the
/// shared "Tools menu starts containers THROUGH jera" pattern). Always compiled so the
/// spec + the ledger dispatch are asserted in the lean, display-free default build;
/// the LIVE boot is behind the `containers` feature.
pub mod infra;

#[cfg(feature = "gui-core")]
pub mod app;

/// **`robot-remote`** (feature-gated) — MOUNT holger-server-ui as a WIRE-REMOTE robot-drive
/// target. Behind `robot-remote` it exposes [`robot_remote::serve_robot_remote`], a
/// `nornir_robotui::cmd_json::CmdJsonServer` over the egui operator shell on a Unix
/// socket the fleet drives (the SAME robotui vocabulary the co-located kittest robot
/// suite uses — REUSE). Reached only via the `holger-server-ui --robot-remote <socket>` flag,
/// so the shipped default binary never mounts a socket. Unix-only.
#[cfg(all(unix, feature = "robot-remote"))]
pub mod robot_remote;

/// **`robot-remote`** (feature-gated) — the per-tab robot **scenario library**
/// ([`scenarios::holger_tab_scenarios`]): one `nornir_robotui::Scenario` per holger
/// operator tab (SELECT → interact → assert over the tab's OWN `state_json`), the
/// SAME wire form the fleet's `CmdJsonClient` drives. Emitted as `serde_json` by
/// `holger-server-ui scenarios` so edda's `fleet` loads holger's real recorded steps by
/// member name (`<dir>/holger.scenarios.json`) instead of a bare liveness probe.
#[cfg(feature = "robot-remote")]
pub mod scenarios;

/// **Sign-in seam** (gui build only) — holger's [`login_seam::HolgerLoginSeam`]
/// implements the shared `facett_auth_ui::LoginSeam` over the shared
/// `nornir-auth-client` RFC 8628 device-code grant, so the operator Sign-in tab
/// mounts the ONE shared `facett_auth_ui::LoginPane` (LAW #5 — never a device-code
/// twin). No method exposes a token/secret VALUE — only the subject + credential
/// NAMES — so a secret can never reach the pane or its `state_json`.
#[cfg(feature = "signin")]
pub mod login_seam;

/// Re-export of the shared sign-in pane crate (gui build only) so robot tests can
/// drive the mounted `LoginPane` through the REAL [`login_seam::HolgerLoginSeam`].
#[cfg(feature = "signin")]
pub use facett_auth_ui;

/// 🎬 Demo mode (gui build only) — fills a dev znippy store with real packages
/// (offline-safe fixture fallback) and ROBOT-DRIVES the holger-server-ui through its
/// views with paced beats so the animations play. See [`demo::DemoWalk`] +
/// [`demo::fill_demo_store`].
#[cfg(feature = "demo")]
pub mod demo;

/// Re-export of the `modgunn` security crate (gui build only) — the Tools#3
/// warehouse-backed scan reads its `warehouse::Warehouse`, and integration tests
/// seed advisories through it without a separate dev-dependency.
#[cfg(feature = "warehouse-scan")]
pub use modgunn;