src/viz/dwarves_tab.rs
//! ⚒ The **Dwarves tab** — nornir's build runner.
//!
//! The **Build runner** ([`super::build_tab::BuildTabState`]) reflects a repo's
//! `BuildSurface` into choosable target rows (binary × features × profile ×
//! target), runs `nornir build --attest --seal`, and TEST-BOOTs the result as a
//! job — a *single-target* builder over nornir's own build-thing surface.
//!
//! ## The ⚒ Forge pane that used to live here
//!
//! This tab once carried a second pane, `BrokkrTabState`, which ran **dwarves'
//! brokkr pipeline engine in-process** — the results/tree/DAG/agents/log facets
//! over a hard-coded demo `brokkr.toml`, stepped by `dwarves::runner::DemoRunner`.
//!
//! It was a twin. dwarves-demo's own **Pipeline** tab is that pane, driven by the
//! REAL engine and rendered on the shared `facett-pipeline` viewer — the forge's UI,
//! hosted by the forge. And it was one of the call sites forcing nornir's `dwarves`
//! path-dep, which made `nornir → dwarves → nornir` a cargo dependency cycle and is
//! why the forge could never compile nornir in.
//!
//! Under PRE-PROMPT §L5a a pane may be hosted by either repo but its LOGIC lives
//! with the owner, and running a CI pipeline is as constructive as it gets. So the
//! demo pane is gone (move = delete); the forge UI is dwarves-demo's, and a *running*
//! forge is reachable at `dwarves-server` on `:7900`.
use std::path::PathBuf;
use eframe::egui;
use super::build_tab::BuildTabState;
use super::facett_theme::Theme;
/// ⚒ The Dwarves tab: nornir's single-target build runner.
pub struct DwarvesTabState {
/// 🔨 the single-target build runner. `pub(crate)` so the app can inject a
/// test runner + read its `state_json` slice at the top level.
pub(crate) build: BuildTabState,
}
impl DwarvesTabState {
/// The tab seeded with the build runner over `workspace_root`.
pub fn new(workspace_root: PathBuf) -> Self {
Self {
build: BuildTabState::new(workspace_root),
}
}
/// Push the active palette into the pane.
pub fn set_palette(&mut self, p: Theme) {
self.build.set_palette(p);
}
/// The observable state a headless test / operator reads. `pane` stays in the
/// slice (always `"Build"`) so a matrix row that asserts on it keeps resolving.
pub fn state_json(&self) -> serde_json::Value {
serde_json::json!({
"surface": "dwarves",
"pane": "Build",
"build": self.build.state_json(),
})
}
/// Draw the tab.
pub fn draw(&mut self, ui: &mut egui::Ui) {
ui.push_id("Dwarves", |ui| {
ui.heading("⚒ Dwarves — build runner");
ui.separator();
self.build.draw(ui);
});
}
}