csi_webclient/ui/
dashboard.rs1use crate::state::AppState;
2
3pub fn render(ui: &mut egui::Ui, state: &mut AppState) {
5 ui.heading("Dashboard");
6 ui.separator();
7
8 ui.horizontal_wrapped(|ui| {
9 ui.strong("Serial:");
10 ui.label(format_tristate(state.runtime.serial_connected, "connected", "disconnected"));
11 ui.separator();
12
13 ui.strong("Firmware:");
14 ui.label(format_tristate(state.runtime.firmware_verified, "verified", "unverified"));
15 ui.separator();
16
17 ui.strong("Collection:");
18 ui.label(format_tristate(state.runtime.collection_running, "running", "idle"));
19 ui.separator();
20
21 ui.strong("Port:");
22 ui.label(state.runtime.port_path.clone().unwrap_or_else(|| "?".to_owned()));
23 });
24
25 ui.separator();
26
27 if let Some(info) = &state.runtime.latest_info {
28 ui.horizontal_wrapped(|ui| {
29 ui.strong("Name:");
30 ui.label(info.name.clone().unwrap_or_default());
31 ui.separator();
32
33 ui.strong("Version:");
34 ui.label(info.version.clone().unwrap_or_default());
35 ui.separator();
36
37 ui.strong("Chip:");
38 ui.label(info.chip.clone().unwrap_or_default());
39 ui.separator();
40
41 ui.strong("Protocol:");
42 ui.label(
43 info.protocol
44 .map(|v| v.to_string())
45 .unwrap_or_else(|| "?".to_owned()),
46 );
47 ui.separator();
48
49 ui.strong("Features:");
50 ui.label(info.features.join(", "));
51 });
52 ui.separator();
53 }
54
55 ui.horizontal_wrapped(|ui| {
56 ui.strong("Collection role:");
57 ui.label(state.persistent.collection_mode.as_api_value());
58 ui.separator();
59
60 ui.strong("Output mode:");
61 ui.label(state.persistent.output_mode.as_api_value());
62 ui.separator();
63
64 ui.strong("Log mode:");
65 ui.label(state.persistent.log_mode.as_api_value());
66 });
67
68 ui.separator();
69
70 ui.horizontal_wrapped(|ui| {
71 ui.label(format!("HTTP Base: {}", state.base_http_url()));
72 ui.separator();
73 ui.label(format!(
74 "WebSocket: {}",
75 if state.runtime.ws_connected {
76 "Connected"
77 } else {
78 "Disconnected"
79 }
80 ));
81 ui.separator();
82 ui.label(format!("Frames: {}", state.runtime.frames_received));
83 ui.separator();
84 ui.label(format!("Bytes: {}", state.runtime.bytes_received));
85 });
86
87 ui.separator();
88 ui.label("Recent events");
89 egui::ScrollArea::vertical()
90 .auto_shrink([false, false])
91 .show(ui, |ui| {
92 for line in state.runtime.events.iter().rev().take(80) {
93 ui.add(egui::Label::new(line).wrap());
94 }
95 });
96}
97
98fn format_tristate(value: Option<bool>, true_label: &str, false_label: &str) -> String {
99 match value {
100 Some(true) => true_label.to_owned(),
101 Some(false) => false_label.to_owned(),
102 None => "?".to_owned(),
103 }
104}