batuta/stack/diagnostics/
dashboard.rs1use super::engine::StackDiagnostics;
7
8pub fn render_dashboard(diagnostics: &StackDiagnostics) -> String {
14 let mut output = String::new();
15 let summary = diagnostics.health_summary();
16
17 output
19 .push_str("┌─────────────────────────────────────────────────────────────────────────┐\n");
20 output
21 .push_str("│ SOVEREIGN AI STACK HEALTH DASHBOARD │\n");
22 output.push_str(&format!(
23 "│ Timestamp: {:40} │\n",
24 chrono::Utc::now().format("%Y-%m-%d %H:%M:%S")
25 ));
26 output
27 .push_str("├─────────────────────────────────────────────────────────────────────────┤\n");
28
29 output
31 .push_str("│ │\n");
32 output.push_str(&format!("│ ANDON STATUS: {} {:55}│\n", summary.andon_status, ""));
33 output
34 .push_str("│ │\n");
35
36 output.push_str("│ ═══════════════════════════════════════════════════════════════════ │\n");
38 output
39 .push_str("│ STACK SUMMARY │\n");
40 output.push_str("│ ═══════════════════════════════════════════════════════════════════ │\n");
41 output
42 .push_str("│ │\n");
43 output.push_str(&format!(
44 "│ Total Components: {:3} │\n",
45 summary.total_components
46 ));
47 output.push_str(&format!(
48 "│ Healthy: {:3} ({:.0}%) │\n",
49 summary.green_count,
50 summary.health_percentage()
51 ));
52 output.push_str(&format!(
53 "│ Warnings: {:3} ({:.0}%) │\n",
54 summary.yellow_count,
55 if summary.total_components > 0 {
56 (summary.yellow_count as f64 / summary.total_components as f64) * 100.0
57 } else {
58 0.0
59 }
60 ));
61 output.push_str(&format!(
62 "│ Critical: {:3} ({:.0}%) │\n",
63 summary.red_count,
64 if summary.total_components > 0 {
65 (summary.red_count as f64 / summary.total_components as f64) * 100.0
66 } else {
67 0.0
68 }
69 ));
70 output.push_str(&format!(
71 "│ Average Demo Score: {:.1}/100 │\n",
72 summary.avg_demo_score
73 ));
74 output.push_str(&format!(
75 "│ Average Coverage: {:.1}% │\n",
76 summary.avg_coverage
77 ));
78 output
79 .push_str("│ │\n");
80
81 let anomalies = diagnostics.anomalies();
83 if !anomalies.is_empty() {
84 output.push_str(
85 "│ ═══════════════════════════════════════════════════════════════════ │\n",
86 );
87 output.push_str(
88 "│ ANOMALIES DETECTED │\n",
89 );
90 output.push_str(
91 "│ ═══════════════════════════════════════════════════════════════════ │\n",
92 );
93 output.push_str(
94 "│ │\n",
95 );
96
97 for anomaly in anomalies.iter().take(5) {
98 let icon = if anomaly.is_critical() { "🔴" } else { "⚠️" };
99 output.push_str(&format!(
100 "│ {} {}: {} │\n",
101 icon, anomaly.component, anomaly.description
102 ));
103 }
104 output.push_str(
105 "│ │\n",
106 );
107 }
108
109 output
110 .push_str("└─────────────────────────────────────────────────────────────────────────┘\n");
111
112 output
113}