feat: disk section enhancements - temperature, partition indentation, duplicate filtering
This commit is contained in:
parent
47eff3a75c
commit
34e260a612
@ -24,8 +24,14 @@ pub fn draw_disks(f: &mut ratatui::Frame<'_>, area: Rect, m: Option<&Metrics>) {
|
|||||||
return;
|
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 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)
|
let constraints: Vec<Constraint> = (0..max_cards)
|
||||||
.map(|_| Constraint::Length(per_disk_h))
|
.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);
|
.split(inner);
|
||||||
|
|
||||||
for (i, slot) in rows.iter().enumerate() {
|
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 used = d.total.saturating_sub(d.available);
|
||||||
let ratio = if d.total > 0 {
|
let ratio = if d.total > 0 {
|
||||||
used as f64 / d.total as f64
|
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
|
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!(
|
let title = format!(
|
||||||
"{} {} {} / {} ({}%)",
|
"{}{} {}{} {} / {} ({}%)",
|
||||||
|
indent,
|
||||||
disk_icon(&d.name),
|
disk_icon(&d.name),
|
||||||
truncate_middle(&d.name, (slot.width.saturating_sub(6)) as usize / 2),
|
truncate_middle(&d.name, (slot.width.saturating_sub(6)) as usize / 2),
|
||||||
|
temp_str,
|
||||||
human(used),
|
human(used),
|
||||||
human(d.total),
|
human(d.total),
|
||||||
pct
|
pct
|
||||||
|
|||||||
@ -331,12 +331,56 @@ pub async fn collect_disks(state: &AppState) -> Vec<DiskInfo> {
|
|||||||
}
|
}
|
||||||
let mut disks_list = state.disks.lock().await;
|
let mut disks_list = state.disks.lock().await;
|
||||||
disks_list.refresh(false); // don't drop missing disks
|
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
|
let disks: Vec<DiskInfo> = disks_list
|
||||||
.iter()
|
.iter()
|
||||||
.map(|d| DiskInfo {
|
.map(|d| {
|
||||||
name: d.name().to_string_lossy().into_owned(),
|
let name = d.name().to_string_lossy().into_owned();
|
||||||
total: d.total_space(),
|
// Determine if this is a partition (contains 'p' followed by digit, or just digit after device name)
|
||||||
available: d.available_space(),
|
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();
|
.collect();
|
||||||
{
|
{
|
||||||
|
|||||||
@ -9,6 +9,8 @@ pub struct DiskInfo {
|
|||||||
pub name: String,
|
pub name: String,
|
||||||
pub total: u64,
|
pub total: u64,
|
||||||
pub available: u64,
|
pub available: u64,
|
||||||
|
pub temperature: Option<f32>,
|
||||||
|
pub is_partition: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
|
|||||||
@ -15,6 +15,8 @@ pub struct DiskInfo {
|
|||||||
pub name: String,
|
pub name: String,
|
||||||
pub total: u64,
|
pub total: u64,
|
||||||
pub available: u64,
|
pub available: u64,
|
||||||
|
pub temperature: Option<f32>,
|
||||||
|
pub is_partition: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user