// // Copyright 2026 James Pace // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. // // This Source Code Form is "Incompatible With Secondary Licenses", as // defined by the Mozilla Public License, v. 2.0. // use crate::diagnostic_graph::DiagnosticGraph; use crate::diagnostic_status::DiagnosticStatus; use crate::error::Result; use alloc::string::String; use alloc::vec::Vec; use serde::{Deserialize, Serialize}; #[derive(Clone, Serialize, Deserialize)] pub struct TreeView { children: Vec, } #[derive(Clone, Serialize, Deserialize)] struct TreeViewNode { id: String, status: DiagnosticStatus, children: Vec, } impl TreeView { fn get_nodes(key: &limbo_graph::Key, graph: &DiagnosticGraph) -> Result> { let children = graph.children_of(&key)?; if children.len() == 0 { return Ok(Vec::::new()); } let mut to_ret = Vec::::new(); for child in children { let status = graph.value_of(&child)?; let node = TreeViewNode { id: graph.full_name_from_key(&child)?, status: status, children: Self::get_nodes(&child, &graph)?, }; to_ret.push(node); } return Ok(to_ret); } pub fn from_graph(graph: &DiagnosticGraph) -> Result { let view = TreeView { children: Self::get_nodes(&graph.root(), &graph)?, }; Ok(view) } pub fn to_json(&self) -> Result { Ok(serde_json::to_string(self)?) } } #[cfg(test)] mod tests { use super::*; use crate::*; use alloc::collections::BTreeMap; fn make_a_status_with_name(name: &str) -> DiagnosticStatus { let level = DiagnosticLevel::OK; let message = "I'm ok"; let hardware_id = ""; let values = BTreeMap::::new(); DiagnosticStatus::new( level, name.to_owned(), message.to_owned(), hardware_id.to_owned(), values, ) } #[test] fn make_view() -> Result<()> { let statuses = vec![ make_a_status_with_name("/a"), make_a_status_with_name("/a/b"), make_a_status_with_name("/a/b/c"), make_a_status_with_name("/a/d/e"), make_a_status_with_name("/a/d"), ]; let mut graph = DiagnosticGraph::new(); graph.add_status_vec(&statuses)?; let view = TreeView::from_graph(&graph)?; // First level is just a assert!(view.children.len() == 1); // a has children b and d. assert!(view.children[0].children.len() == 2); // regardless is this is b or d, it has one child. // TODO: This isn't the best test. assert!(view.children[0].children[0].children.len() == 1); // Just to confirm it doesn't panic. let _js = view.to_json()?; Ok(()) } }