diff --git a/Cargo.lock b/Cargo.lock index bcf613f..c11820d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -279,7 +279,7 @@ checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" [[package]] name = "cm-dashboard" -version = "0.1.154" +version = "0.1.155" dependencies = [ "anyhow", "chrono", @@ -301,7 +301,7 @@ dependencies = [ [[package]] name = "cm-dashboard-agent" -version = "0.1.154" +version = "0.1.155" dependencies = [ "anyhow", "async-trait", @@ -324,7 +324,7 @@ dependencies = [ [[package]] name = "cm-dashboard-shared" -version = "0.1.154" +version = "0.1.155" dependencies = [ "chrono", "serde", diff --git a/agent/Cargo.toml b/agent/Cargo.toml index 09c83a2..e547fda 100644 --- a/agent/Cargo.toml +++ b/agent/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cm-dashboard-agent" -version = "0.1.154" +version = "0.1.155" edition = "2021" [dependencies] diff --git a/agent/src/collectors/disk.rs b/agent/src/collectors/disk.rs index 1fc2137..7ffed5a 100644 --- a/agent/src/collectors/disk.rs +++ b/agent/src/collectors/disk.rs @@ -534,6 +534,7 @@ impl DiskCollector { agent_data.system.storage.drives.push(DriveData { name: drive.name.clone(), + serial_number: smart.and_then(|s| s.serial_number.clone()), health: smart.map(|s| s.health.clone()).unwrap_or_else(|| drive.health.clone()), temperature_celsius: smart.and_then(|s| s.temperature_celsius), wear_percent: smart.and_then(|s| s.wear_percent), diff --git a/dashboard/Cargo.toml b/dashboard/Cargo.toml index 367a7b8..82e28ba 100644 --- a/dashboard/Cargo.toml +++ b/dashboard/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cm-dashboard" -version = "0.1.154" +version = "0.1.155" edition = "2021" [dependencies] diff --git a/dashboard/src/ui/widgets/system.rs b/dashboard/src/ui/widgets/system.rs index 8f678e8..8cf463e 100644 --- a/dashboard/src/ui/widgets/system.rs +++ b/dashboard/src/ui/widgets/system.rs @@ -239,8 +239,11 @@ impl SystemWidget { }; // Add drive info + let display_name = drive.serial_number.as_ref() + .map(|s| truncate_serial(s)) + .unwrap_or(drive.name.clone()); let storage_drive = StorageDrive { - name: drive.name.clone(), + name: display_name, temperature: drive.temperature_celsius, wear_percent: drive.wear_percent, status: Status::Ok, @@ -310,8 +313,10 @@ impl SystemWidget { } else { Status::Unknown }; - - let display_name = drive.serial_number.clone().unwrap_or(drive.name.clone()); + + let display_name = drive.serial_number.as_ref() + .map(|s| truncate_serial(s)) + .unwrap_or(drive.name.clone()); let storage_drive = StorageDrive { name: display_name, temperature: drive.temperature_celsius, @@ -333,8 +338,10 @@ impl SystemWidget { } else { Status::Unknown }; - - let display_name = drive.serial_number.clone().unwrap_or(drive.name.clone()); + + let display_name = drive.serial_number.as_ref() + .map(|s| truncate_serial(s)) + .unwrap_or(drive.name.clone()); let storage_drive = StorageDrive { name: display_name, temperature: drive.temperature_celsius, @@ -460,14 +467,13 @@ impl SystemWidget { } let drive_text = if !drive_details.is_empty() { - format!("{} {}", drive.name, drive_details.join(" ")) + format!("Parity: {} {}", drive.name, drive_details.join(" ")) } else { - drive.name.clone() + format!("Parity: {}", drive.name) }; - + let mut parity_spans = vec![ Span::styled(" ├─ ", Typography::tree()), - Span::styled("Parity: ", Typography::secondary()), ]; parity_spans.extend(StatusIcons::create_status_spans(drive.status.clone(), &drive_text)); lines.push(Line::from(parity_spans)); @@ -476,7 +482,8 @@ impl SystemWidget { // Mount point lines.push(Line::from(vec![ - Span::styled(" └─ Mount: ", Typography::tree()), + Span::styled(" └─ ", Typography::tree()), + Span::styled("Mount: ", Typography::secondary()), Span::styled(&pool.mount_point, Typography::secondary()) ])); } @@ -486,6 +493,16 @@ impl SystemWidget { } } +/// Truncate serial number to last 8 characters +fn truncate_serial(serial: &str) -> String { + let len = serial.len(); + if len > 8 { + serial[len - 8..].to_string() + } else { + serial.to_string() + } +} + /// Helper function to render a drive in a MergerFS pool fn render_mergerfs_drive<'a>(drive: &StorageDrive, tree_symbol: &'a str, lines: &mut Vec>) { let mut drive_details = Vec::new(); @@ -542,6 +559,7 @@ impl SystemWidget { // First line: serial number with temperature and wear if let Some(serial) = &self.backup_disk_serial { + let truncated_serial = truncate_serial(serial); let mut details = Vec::new(); if let Some(temp) = self.backup_disk_temperature { details.push(format!("T: {}°C", temp as i32)); @@ -551,9 +569,9 @@ impl SystemWidget { } let disk_text = if !details.is_empty() { - format!("{} {}", serial, details.join(" ")) + format!("{} {}", truncated_serial, details.join(" ")) } else { - serial.clone() + truncated_serial }; let backup_status = match self.backup_status.as_str() { diff --git a/shared/Cargo.toml b/shared/Cargo.toml index 725dab8..d9be99f 100644 --- a/shared/Cargo.toml +++ b/shared/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cm-dashboard-shared" -version = "0.1.154" +version = "0.1.155" edition = "2021" [dependencies] diff --git a/shared/src/agent_data.rs b/shared/src/agent_data.rs index 2f77a3f..58b560e 100644 --- a/shared/src/agent_data.rs +++ b/shared/src/agent_data.rs @@ -66,6 +66,7 @@ pub struct StorageData { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct DriveData { pub name: String, + pub serial_number: Option, pub health: String, pub temperature_celsius: Option, pub wear_percent: Option,