feat: disk section enhancements - temperature, partition indentation, duplicate filtering

This commit is contained in:
jasonwitty 2025-10-06 10:30:55 -07:00
parent 47eff3a75c
commit 34e260a612
4 changed files with 71 additions and 7 deletions

View File

@ -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<Constraint> = (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

View File

@ -331,12 +331,56 @@ pub async fn collect_disks(state: &AppState) -> Vec<DiskInfo> {
}
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<DiskInfo> = disks_list
.iter()
.map(|d| DiskInfo {
name: d.name().to_string_lossy().into_owned(),
.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();
{

View File

@ -9,6 +9,8 @@ pub struct DiskInfo {
pub name: String,
pub total: u64,
pub available: u64,
pub temperature: Option<f32>,
pub is_partition: bool,
}
#[derive(Debug, Clone, Serialize)]

View File

@ -15,6 +15,8 @@ pub struct DiskInfo {
pub name: String,
pub total: u64,
pub available: u64,
pub temperature: Option<f32>,
pub is_partition: bool,
}
#[derive(Debug, Clone, Deserialize, Serialize)]