From 34e260a612ed3a9c1a2f9993a5201fc5bdb3d692 Mon Sep 17 00:00:00 2001 From: jasonwitty Date: Mon, 6 Oct 2025 10:30:55 -0700 Subject: [PATCH] feat: disk section enhancements - temperature, partition indentation, duplicate filtering --- socktop/src/ui/disks.rs | 22 ++++++++++++-- socktop_agent/src/metrics.rs | 52 +++++++++++++++++++++++++++++++--- socktop_agent/src/types.rs | 2 ++ socktop_connector/src/types.rs | 2 ++ 4 files changed, 71 insertions(+), 7 deletions(-) diff --git a/socktop/src/ui/disks.rs b/socktop/src/ui/disks.rs index d549b87..c1d2bb1 100644 --- a/socktop/src/ui/disks.rs +++ b/socktop/src/ui/disks.rs @@ -24,8 +24,14 @@ pub fn draw_disks(f: &mut ratatui::Frame<'_>, area: Rect, m: Option<&Metrics>) { return; } + // Filter duplicates by keeping first occurrence of each unique name + let mut seen_names = std::collections::HashSet::new(); + let unique_disks: Vec<_> = mm.disks.iter() + .filter(|d| seen_names.insert(d.name.clone())) + .collect(); + let per_disk_h = 3u16; - let max_cards = (inner.height / per_disk_h).min(mm.disks.len() as u16) as usize; + let max_cards = (inner.height / per_disk_h).min(unique_disks.len() as u16) as usize; let constraints: Vec = (0..max_cards) .map(|_| Constraint::Length(per_disk_h)) @@ -36,7 +42,7 @@ pub fn draw_disks(f: &mut ratatui::Frame<'_>, area: Rect, m: Option<&Metrics>) { .split(inner); for (i, slot) in rows.iter().enumerate() { - let d = &mm.disks[i]; + let d = unique_disks[i]; let used = d.total.saturating_sub(d.available); let ratio = if d.total > 0 { used as f64 / d.total as f64 @@ -53,10 +59,20 @@ pub fn draw_disks(f: &mut ratatui::Frame<'_>, area: Rect, m: Option<&Metrics>) { ratatui::style::Color::Red }; + // Add indentation for partitions + let indent = if d.is_partition { " └─" } else { "" }; + + // Add temperature if available + let temp_str = d.temperature + .map(|t| format!(" {}°C", t.round() as i32)) + .unwrap_or_default(); + let title = format!( - "{} {} {} / {} ({}%)", + "{}{} {}{} {} / {} ({}%)", + indent, disk_icon(&d.name), truncate_middle(&d.name, (slot.width.saturating_sub(6)) as usize / 2), + temp_str, human(used), human(d.total), pct diff --git a/socktop_agent/src/metrics.rs b/socktop_agent/src/metrics.rs index ef190cb..50f4c40 100644 --- a/socktop_agent/src/metrics.rs +++ b/socktop_agent/src/metrics.rs @@ -331,12 +331,56 @@ pub async fn collect_disks(state: &AppState) -> Vec { } let mut disks_list = state.disks.lock().await; disks_list.refresh(false); // don't drop missing disks + + // Collect disk temperatures from components + let disk_temps = { + let mut components = state.components.lock().await; + components.refresh(false); + let mut temps = std::collections::HashMap::new(); + for c in components.iter() { + let label = c.label().to_ascii_lowercase(); + // Match common disk/SSD/NVMe sensor labels + if label.contains("nvme") || label.contains("ssd") || label.contains("disk") { + if let Some(temp) = c.temperature() { + // Extract device name from label (e.g., "nvme0" from "Composite nvme0") + for part in label.split_whitespace() { + if part.starts_with("nvme") || part.starts_with("sd") { + temps.insert(part.to_string(), temp); + } + } + } + } + } + temps + }; + let disks: Vec = disks_list .iter() - .map(|d| DiskInfo { - name: d.name().to_string_lossy().into_owned(), - total: d.total_space(), - available: d.available_space(), + .map(|d| { + let name = d.name().to_string_lossy().into_owned(); + // Determine if this is a partition (contains 'p' followed by digit, or just digit after device name) + let is_partition = name.contains("p1") || name.contains("p2") || name.contains("p3") + || name.ends_with('1') || name.ends_with('2') || name.ends_with('3') + || name.ends_with('4') || name.ends_with('5') || name.ends_with('6') + || name.ends_with('7') || name.ends_with('8') || name.ends_with('9'); + + // Try to find temperature for this disk + let temperature = disk_temps.iter() + .find_map(|(key, &temp)| { + if name.starts_with(key) { + Some(temp) + } else { + None + } + }); + + DiskInfo { + name, + total: d.total_space(), + available: d.available_space(), + temperature, + is_partition, + } }) .collect(); { diff --git a/socktop_agent/src/types.rs b/socktop_agent/src/types.rs index 4b7d37c..75e7d97 100644 --- a/socktop_agent/src/types.rs +++ b/socktop_agent/src/types.rs @@ -9,6 +9,8 @@ pub struct DiskInfo { pub name: String, pub total: u64, pub available: u64, + pub temperature: Option, + pub is_partition: bool, } #[derive(Debug, Clone, Serialize)] diff --git a/socktop_connector/src/types.rs b/socktop_connector/src/types.rs index 125e11c..84fdfa9 100644 --- a/socktop_connector/src/types.rs +++ b/socktop_connector/src/types.rs @@ -15,6 +15,8 @@ pub struct DiskInfo { pub name: String, pub total: u64, pub available: u64, + pub temperature: Option, + pub is_partition: bool, } #[derive(Debug, Clone, Deserialize, Serialize)]