use std::collections::BTreeSet;
use eframe::egui;
use nornir_testmatrix::uiplane::{PlaneDriver, Transition, UiPlan, UiPlane, UiSurface};
use super::control::VizCommand;
use super::UrdrThreadsApp;
pub const TAB_PANE_BLOCK: &[(&str, &str)] = &[
("Nornir", "nornir"),
("Timeline", "timeline"),
("DepGraph", "dep_graph"),
("CallGraph", "callgraph"),
("Architecture", "architecture"),
("Funnel", "funnel"),
("TimeTravel", "timetravel"),
("LiveRun", "live"),
("Release", "release"),
("Knowledge", "knowledge"),
("Warehouse", "warehouse"),
("Mcp", "mcp"),
("Search", "search"),
("Gates", "gates"),
("Bench", "bench"),
("Test", "test"),
("Leaderboard", "leaderboard"),
("Security", "security"),
("Holger", "holger"),
("Manual", "manual"),
];
pub const CLICK_TAB: &str = "click_tab:";
fn pane_surface_id(pane_key: &str) -> String {
format!("pane:{pane_key}")
}
pub fn viz_plan(all_tabs: &[String], start: &str) -> UiPlan {
let block_of = |tab: &str| TAB_PANE_BLOCK.iter().find(|(t, _)| *t == tab).map(|(_, b)| *b);
let mut plan = UiPlan::new(start.to_string());
for tab in all_tabs {
let mut plane = UiPlane::new(tab.clone());
if let Some(block) = block_of(tab) {
plane = plane.surface(
UiSurface::new(pane_surface_id(block)).with_label(format!("{tab} pane ({block})")),
);
}
plan = plan.plane(plane);
}
for tab in all_tabs {
if tab != start {
plan = plan.transition(Transition::new(
start.to_string(),
tab.clone(),
format!("{CLICK_TAB}{tab}"),
));
}
}
plan
}
pub struct VizPlaneDriver<'a> {
app: &'a mut UrdrThreadsApp,
settle_frames: usize,
}
impl<'a> VizPlaneDriver<'a> {
pub fn new(app: &'a mut UrdrThreadsApp, settle_frames: usize) -> Self {
Self { app, settle_frames }
}
fn settle(&mut self) {
for _ in 0..self.settle_frames.max(1) {
let ctx = egui::Context::default();
let _ = ctx.run(egui::RawInput::default(), |ctx| self.app.draw_ui(ctx));
}
}
fn pane_state(&mut self) -> (BTreeSet<String>, BTreeSet<String>) {
let mut present = BTreeSet::new();
let mut ran = BTreeSet::new();
let state = self.app.state_json();
let tab = state
.get("tab")
.and_then(|v| v.as_str())
.unwrap_or_default()
.to_string();
if let Some(block) = TAB_PANE_BLOCK.iter().find(|(t, _)| *t == tab).map(|(_, b)| *b) {
let id = pane_surface_id(block);
match state.get(block) {
None | Some(serde_json::Value::Null) => {} Some(v) => {
present.insert(id.clone());
if pane_block_ran(v) {
ran.insert(id);
}
}
}
}
(present, ran)
}
}
pub fn pane_block_ran(v: &serde_json::Value) -> bool {
match v {
serde_json::Value::Null => false,
serde_json::Value::Object(m) => !m.is_empty(),
serde_json::Value::Array(a) => !a.is_empty(),
_ => true,
}
}
impl PlaneDriver for VizPlaneDriver<'_> {
fn current_plane(&mut self) -> String {
self.app
.state_json()
.get("tab")
.and_then(|v| v.as_str())
.unwrap_or_default()
.to_string()
}
fn apply(&mut self, action: &str) -> Result<(), String> {
let tab = action
.strip_prefix(CLICK_TAB)
.ok_or_else(|| format!("VizPlaneDriver: unknown action '{action}'"))?;
self.app.apply_command(&VizCommand {
tab: Some(tab.to_string()),
..Default::default()
});
self.settle();
Ok(())
}
fn surfaces_present(&mut self) -> BTreeSet<String> {
self.pane_state().0
}
fn surfaces_ran(&mut self) -> BTreeSet<String> {
self.pane_state().1
}
}
pub mod wasm {
use std::collections::BTreeSet;
use nornir_testmatrix::uiplane::PlaneDriver;
pub trait BrowserBridge {
fn eval_state(&mut self) -> Result<serde_json::Value, String>;
fn eval_click(&mut self, action: &str) -> Result<(), String>;
}
pub struct WasmPlaneDriver<B: BrowserBridge> {
bridge: B,
block_of: fn(&str) -> Option<&'static str>,
surface_id: fn(&str) -> String,
}
impl<B: BrowserBridge> WasmPlaneDriver<B> {
pub fn new(
bridge: B,
block_of: fn(&str) -> Option<&'static str>,
surface_id: fn(&str) -> String,
) -> Self {
Self { bridge, block_of, surface_id }
}
fn pane_state(&mut self) -> (BTreeSet<String>, BTreeSet<String>) {
let mut present = BTreeSet::new();
let mut ran = BTreeSet::new();
let Ok(state) = self.bridge.eval_state() else {
return (present, ran); };
let tab = state.get("tab").and_then(|v| v.as_str()).unwrap_or_default();
if let Some(block) = (self.block_of)(tab) {
let id = (self.surface_id)(block);
if let Some(v) = state.get(block) {
if !v.is_null() {
present.insert(id.clone());
if super::pane_block_ran(v) {
ran.insert(id);
}
}
}
}
(present, ran)
}
}
impl<B: BrowserBridge> PlaneDriver for WasmPlaneDriver<B> {
fn current_plane(&mut self) -> String {
self.bridge
.eval_state()
.ok()
.and_then(|s| s.get("tab").and_then(|v| v.as_str()).map(String::from))
.unwrap_or_default()
}
fn apply(&mut self, action: &str) -> Result<(), String> {
self.bridge.eval_click(action)
}
fn surfaces_present(&mut self) -> BTreeSet<String> {
self.pane_state().0
}
fn surfaces_ran(&mut self) -> BTreeSet<String> {
self.pane_state().1
}
}
pub fn viz_block_of(tab: &str) -> Option<&'static str> {
super::TAB_PANE_BLOCK
.iter()
.find(|(t, _)| *t == tab)
.map(|(_, b)| *b)
}
}
#[cfg(test)]
mod tests {
use super::*;
use nornir_testmatrix::uiplane::{RobotPlan, SurfaceVerdict};
fn sample_tabs() -> Vec<String> {
["Nornir", "Bench", "Test"].iter().map(|s| s.to_string()).collect()
}
#[test]
fn plan_makes_a_plane_per_tab_and_a_click_from_start() {
let plan = viz_plan(&sample_tabs(), "Nornir");
assert_eq!(plan.planes.len(), 3, "one plane per tab");
assert_eq!(plan.transitions.len(), 2, "Bench + Test reachable from Nornir");
assert!(plan.orphan_planes().is_empty(), "every tab reachable from start");
assert!(plan.dangling_transitions().is_empty(), "every edge lands on a declared plane");
let bench = plan.planes.get("Bench").unwrap();
assert!(bench.surfaces.contains_key(&pane_surface_id("bench")), "Bench pane surface declared");
}
#[test]
fn pane_block_ran_distinguishes_populated_from_empty() {
assert!(!pane_block_ran(&serde_json::json!({})), "empty object ≠ ran");
assert!(!pane_block_ran(&serde_json::json!([])), "empty array ≠ ran");
assert!(!pane_block_ran(&serde_json::Value::Null), "null ≠ ran");
assert!(pane_block_ran(&serde_json::json!({"rows": 3})), "populated object = ran");
assert!(pane_block_ran(&serde_json::json!([1, 2])), "non-empty array = ran");
assert!(pane_block_ran(&serde_json::json!(42)), "a scalar emit = ran");
}
struct FakeBrowser {
tab: String,
blocks: std::collections::BTreeMap<String, serde_json::Value>,
}
impl wasm::BrowserBridge for FakeBrowser {
fn eval_state(&mut self) -> Result<serde_json::Value, String> {
let mut obj = serde_json::Map::new();
obj.insert("tab".into(), serde_json::Value::String(self.tab.clone()));
if let Some(block) = wasm::viz_block_of(&self.tab) {
if let Some(v) = self.blocks.get(&self.tab) {
obj.insert(block.to_string(), v.clone());
}
}
Ok(serde_json::Value::Object(obj))
}
fn eval_click(&mut self, action: &str) -> Result<(), String> {
let tab = action
.strip_prefix(CLICK_TAB)
.ok_or_else(|| format!("bad action {action}"))?;
self.tab = tab.to_string();
Ok(())
}
}
#[test]
fn wasm_seam_walks_the_same_plan_green_when_shipped_panes_populate() {
let tabs = sample_tabs();
let plan = viz_plan(&tabs, "Nornir");
let mut blocks = std::collections::BTreeMap::new();
blocks.insert("Nornir".to_string(), serde_json::json!({"server": "up"}));
blocks.insert("Bench".to_string(), serde_json::json!({"series": [1, 2]}));
blocks.insert("Test".to_string(), serde_json::json!({"runs": 4}));
let bridge = FakeBrowser { tab: "Nornir".into(), blocks };
let mut driver =
wasm::WasmPlaneDriver::new(bridge, wasm::viz_block_of, |b| pane_surface_id(b));
let report = RobotPlan::walk(&plan, &mut driver);
assert!(report.is_green(), "shipped wasm panes populate → GREEN: {}", report.summary());
assert_eq!(report.reached_planes.len(), 3, "every tab reached in the wasm bundle");
}
#[test]
fn wasm_seam_goes_red_when_a_shipped_pane_is_blank() {
let tabs = sample_tabs();
let plan = viz_plan(&tabs, "Nornir");
let mut blocks = std::collections::BTreeMap::new();
blocks.insert("Nornir".to_string(), serde_json::json!({"server": "up"}));
blocks.insert("Bench".to_string(), serde_json::json!({})); blocks.insert("Test".to_string(), serde_json::json!({"runs": 4}));
let bridge = FakeBrowser { tab: "Nornir".into(), blocks };
let mut driver =
wasm::WasmPlaneDriver::new(bridge, wasm::viz_block_of, |b| pane_surface_id(b));
let report = RobotPlan::walk(&plan, &mut driver);
assert!(!report.is_green(), "blank shipped pane → RED");
let bench = report
.rows
.iter()
.find(|r| r.plane == "Bench")
.expect("Bench row present");
assert_eq!(bench.verdict, SurfaceVerdict::ReachableNotRan, "blank pane = present-not-ran");
}
}