#![allow(dead_code)]
use ratatui::layout::Rect;
use ratatui::style::{Modifier, Style};
use ratatui::text::{Line, Span};
use ratatui::Frame;
use crate::normalized::{aggregate_drives, NormalizedSnapshot};
use crate::state::SystemState;
use super::bar;
use super::text;
pub fn render_online(
f: &mut Frame,
area: Rect,
system: &SystemState,
is_selected: bool,
drive_rows_visible: usize,
) {
if area.height < 5 || area.width == 0 {
return;
}
let Some(snap) = &system.latest else {
render_waiting(f, area, system, is_selected);
return;
};
let sel_style = if is_selected {
Style::default().add_modifier(Modifier::REVERSED)
} else {
Style::default()
};
let header = text::header_line(system, area.width);
let header_line = Line::from(Span::styled(header, sel_style));
f.render_widget(header_line, Rect { height: 1, ..area });
let cpu_detail = format!("{} cores", snap.logical_cores);
bar::render_bar(
f,
Rect {
y: area.y.saturating_add(1),
height: 1,
..area
},
"CPU",
snap.usage_pct,
Some(&cpu_detail),
false,
);
let mem_detail = format!(
"{}/{}",
text::format_bytes(snap.memory.used_bytes),
text::format_bytes(snap.memory.total_bytes)
);
bar::render_bar(
f,
Rect {
y: area.y.saturating_add(2),
height: 1,
..area
},
"MEM",
snap.memory.usage_pct,
Some(&mem_detail),
false,
);
render_swap_or_commit_row(f, area, snap);
render_disk_and_drives(f, area, snap, drive_rows_visible);
}
fn render_waiting(f: &mut Frame, area: Rect, system: &SystemState, is_selected: bool) {
let sel_style = if is_selected {
Style::default().add_modifier(Modifier::REVERSED)
} else {
Style::default()
};
let header = text::header_line(system, area.width);
f.render_widget(
Line::from(Span::styled(header, sel_style)),
Rect { height: 1, ..area },
);
f.render_widget(
Line::from(Span::styled("waiting for data…", sel_style)),
Rect {
y: area.y.saturating_add(1),
height: 1,
..area
},
);
}
fn render_disk_and_drives(
f: &mut Frame,
area: Rect,
snap: &NormalizedSnapshot,
drive_rows_visible: usize,
) {
if let Some(drives) = snap.drives.as_deref().and_then(aggregate_drives) {
let disk_detail = format!(
"{} used / {} avail",
text::format_bytes(drives.used_bytes),
text::format_bytes(drives.available_bytes)
);
bar::render_bar(
f,
Rect {
y: area.y.saturating_add(4),
height: 1,
..area
},
"DISK",
drives.usage_pct,
Some(&disk_detail),
false,
);
} else {
bar::render_unavailable(
f,
Rect {
y: area.y.saturating_add(4),
height: 1,
..area
},
"DISK",
);
}
if drive_rows_visible == 0 {
return;
}
let Some(drives) = snap.drives.as_deref() else {
return;
};
for (offset, drive) in drives
.iter()
.filter(|drive| drive.total_bytes > 0 && drive.used_bytes <= drive.total_bytes)
.take(drive_rows_visible)
.enumerate()
{
let row = area
.y
.saturating_add(5 + u16::try_from(offset).unwrap_or(u16::MAX));
if row >= area.y.saturating_add(area.height) {
break;
}
let line = text::drive_detail_line(drive, area.width);
f.render_widget(
Line::from(Span::raw(line)),
Rect {
y: row,
height: 1,
..area
},
);
}
}
fn render_swap_or_commit_row(f: &mut Frame, area: Rect, snap: &NormalizedSnapshot) {
if let Some(ref swap) = snap.swap {
let swap_detail = if swap.total_bytes == 0 {
String::new()
} else {
format!(
"{}/{}",
text::format_bytes(swap.used_bytes),
text::format_bytes(swap.total_bytes)
)
};
bar::render_bar(
f,
Rect {
y: area.y.saturating_add(3),
height: 1,
..area
},
"SWP",
swap.usage_pct,
if swap_detail.is_empty() {
None
} else {
Some(&swap_detail)
},
false,
);
} else if let Some(ref commit) = snap.commit {
let commit_detail = format!(
"{}/{}",
text::format_bytes(commit.used_bytes),
text::format_bytes(commit.limit_bytes)
);
bar::render_bar(
f,
Rect {
y: area.y.saturating_add(3),
height: 1,
..area
},
"COMMIT",
commit.usage_pct,
Some(&commit_detail),
false,
);
} else {
bar::render_bar(
f,
Rect {
y: area.y.saturating_add(3),
height: 1,
..area
},
"SWP",
0.0,
None,
false,
);
}
}
#[allow(clippy::cast_possible_truncation)]
pub fn render_offline(f: &mut Frame, area: Rect, system: &SystemState, is_selected: bool) {
if area.height == 0 || area.width == 0 {
return;
}
let style = if is_selected {
Style::default().add_modifier(Modifier::REVERSED)
} else {
Style::default()
};
let display_name = system
.configured_name
.as_deref()
.unwrap_or(&system.endpoint.host);
let status_text = match system.reachability {
crate::state::Reachability::Offline => "offline",
crate::state::Reachability::Pending => "pending",
crate::state::Reachability::Online => "online",
};
let label_width =
(display_name.len() + system.endpoint.display_address().len() + status_text.len() + 3)
as u16;
let available = area.width.saturating_sub(label_width);
let dot = if available > 0 {
".".repeat(available as usize)
} else {
String::new()
};
let line = Line::from(vec![
Span::styled(
format!(
"{}@{} {status_text} ",
display_name,
system.endpoint.display_address()
),
style,
),
Span::styled(dot, style),
]);
f.render_widget(line, area);
}