csi_webclient/ui/
dashboard.rs1use crate::state::DeviceState;
2
3pub fn render(ui: &mut egui::Ui, device: &DeviceState) {
5 ui.add(
6 egui::Label::new(format!("Dashboard — {}", device.id))
7 .wrap(),
8 );
9 ui.add_space(10.0);
10
11 ui.strong("Connection");
12 ui.add_space(4.0);
13 stat_row(ui, "Serial", format_tristate(device.serial_connected, "connected", "disconnected"));
14 if let Some(mac) = &device.mac {
15 stat_row(ui, "MAC", mac.clone());
16 }
17 stat_row(ui, "Port", device.port_path.clone().unwrap_or_else(|| "?".to_owned()));
18 if let Some(baud) = device.baud_rate {
19 stat_row(ui, "Baud", baud.to_string());
20 }
21 stat_row(
22 ui,
23 "Firmware",
24 format_tristate(device.firmware_verified, "verified", "unverified"),
25 );
26 stat_row(
27 ui,
28 "Collection",
29 format_tristate(device.collection_running, "running", "idle"),
30 );
31
32 if let Some(info) = &device.latest_info {
33 ui.add_space(10.0);
34 ui.strong("Firmware info");
35 ui.add_space(4.0);
36 stat_row(ui, "Name", info.name.clone().unwrap_or_default());
37 stat_row(ui, "Version", info.version.clone().unwrap_or_default());
38 stat_row(ui, "Chip", info.chip.clone().unwrap_or_default());
39 stat_row(
40 ui,
41 "Protocol",
42 info.protocol
43 .map(|v| v.to_string())
44 .unwrap_or_else(|| "?".to_owned()),
45 );
46 stat_row(ui, "Features", info.features.join(", "));
47 }
48
49 ui.add_space(10.0);
50 ui.strong("Session");
51 ui.add_space(4.0);
52 stat_row(
53 ui,
54 "Collection role",
55 device.forms.collection_mode.as_api_value().to_owned(),
56 );
57 stat_row(
58 ui,
59 "Output mode",
60 device.forms.output_mode.as_api_value().to_owned(),
61 );
62
63 ui.add_space(10.0);
64 ui.strong("Stream");
65 ui.add_space(4.0);
66 stat_row(
67 ui,
68 "WebSocket",
69 if device.ws_connected {
70 "connected".to_owned()
71 } else {
72 "disconnected".to_owned()
73 },
74 );
75 stat_row(ui, "Frames", device.frames_received.to_string());
76 stat_row(ui, "Bytes", device.bytes_received.to_string());
77}
78
79fn stat_row(ui: &mut egui::Ui, label: &str, value: String) {
80 ui.horizontal(|ui| {
81 ui.label(format!("{label}:"));
82 ui.add_space(8.0);
83 ui.add(egui::Label::new(value).wrap());
84 });
85 ui.add_space(2.0);
86}
87
88fn format_tristate(value: Option<bool>, true_label: &str, false_label: &str) -> String {
89 match value {
90 Some(true) => true_label.to_owned(),
91 Some(false) => false_label.to_owned(),
92 None => "?".to_owned(),
93 }
94}