diff --git a/Cargo.lock b/Cargo.lock index 330e942..480ad39 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2182,7 +2182,7 @@ dependencies = [ [[package]] name = "socktop_agent" -version = "1.40.70" +version = "1.50.0" dependencies = [ "anyhow", "assert_cmd", @@ -2213,7 +2213,7 @@ dependencies = [ [[package]] name = "socktop_connector" -version = "0.1.6" +version = "1.50.0" dependencies = [ "flate2", "futures-util", diff --git a/socktop/src/ui/cpu.rs b/socktop/src/ui/cpu.rs index f61cbe7..7c89487 100644 --- a/socktop/src/ui/cpu.rs +++ b/socktop/src/ui/cpu.rs @@ -249,22 +249,52 @@ pub fn draw_cpu_avg_graph( }; let title = if let Some(mm) = m { - format!( - "CPU avg (now: {:>5.1}% | avg: {:>5.1}%)", - mm.cpu_total, avg_cpu - ) + format!("CPU (now: {:>5.1}% | avg: {:>5.1}%)", mm.cpu_total, avg_cpu) } else { "CPU avg".into() }; + + // Build the top-right info (CPU temp and polling intervals) + let top_right_info = if let Some(mm) = m { + mm.cpu_temp_c + .map(|t| { + let icon = if t < 50.0 { + "😎" + } else if t < 85.0 { + "⚠️" + } else { + "🔥" + }; + format!("CPU Temp: {t:.1}°C {icon}") + }) + .unwrap_or_else(|| "CPU Temp: N/A".into()) + } else { + String::new() + }; + let max_points = area.width.saturating_sub(2) as usize; let start = hist.len().saturating_sub(max_points); let data: Vec = hist.iter().skip(start).cloned().collect(); + + // Render the sparkline with title on left let spark = Sparkline::default() .block(Block::default().borders(Borders::ALL).title(title)) .data(&data) .max(100) .style(Style::default().fg(Color::Cyan)); f.render_widget(spark, area); + + // Render the top-right info as text overlay in the top-right corner + if !top_right_info.is_empty() { + let info_area = Rect { + x: area.x + area.width.saturating_sub(top_right_info.len() as u16 + 2), + y: area.y, + width: top_right_info.len() as u16 + 1, + height: 1, + }; + let info_line = Line::from(Span::raw(top_right_info)); + f.render_widget(Paragraph::new(info_line), info_area); + } } /// Draws the per-core CPU bars with sparklines and trends. diff --git a/socktop/src/ui/header.rs b/socktop/src/ui/header.rs index f190d2b..e913c11 100644 --- a/socktop/src/ui/header.rs +++ b/socktop/src/ui/header.rs @@ -3,7 +3,8 @@ use crate::types::Metrics; use ratatui::{ layout::Rect, - widgets::{Block, Borders}, + text::{Line, Span}, + widgets::{Block, Borders, Paragraph}, }; use std::time::Duration; @@ -17,20 +18,7 @@ pub fn draw_header( procs_interval: Duration, ) { let base = if let Some(mm) = m { - let temp = mm - .cpu_temp_c - .map(|t| { - let icon = if t < 50.0 { - "😎" - } else if t < 85.0 { - "⚠️" - } else { - "🔥" - }; - format!("CPU Temp: {t:.1}°C {icon}") - }) - .unwrap_or_else(|| "CPU Temp: N/A".into()); - format!("socktop — host: {} | {}", mm.hostname, temp) + format!("socktop — host: {}", mm.hostname) } else { "socktop — connecting...".into() }; @@ -38,15 +26,30 @@ pub fn draw_header( let tls_txt = if is_tls { "🔒 TLS" } else { "🔒✗ TLS" }; // Token indicator let tok_txt = if has_token { "🔑 token" } else { "" }; - let mi = metrics_interval.as_millis(); - let pi = procs_interval.as_millis(); - let intervals = format!("⏱ {mi}ms metrics | {pi}ms procs"); let mut parts = vec![base, tls_txt.into()]; if !tok_txt.is_empty() { parts.push(tok_txt.into()); } - parts.push(intervals); parts.push("(a: about, h: help, q: quit)".into()); let title = parts.join(" | "); + + // Render the block with left-aligned title f.render_widget(Block::default().title(title).borders(Borders::BOTTOM), area); + + // Render polling intervals on the right side + let mi = metrics_interval.as_millis(); + let pi = procs_interval.as_millis(); + let intervals = format!("⏱ {mi}ms metrics | {pi}ms procs"); + let intervals_width = intervals.len() as u16; + + if area.width > intervals_width + 2 { + let right_area = Rect { + x: area.x + area.width.saturating_sub(intervals_width + 1), + y: area.y, + width: intervals_width, + height: 1, + }; + let intervals_line = Line::from(Span::raw(intervals)); + f.render_widget(Paragraph::new(intervals_line), right_area); + } } diff --git a/socktop_agent/Cargo.toml b/socktop_agent/Cargo.toml index f7011df..de0de13 100644 --- a/socktop_agent/Cargo.toml +++ b/socktop_agent/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "socktop_agent" -version = "1.40.70" +version = "1.50.0" authors = ["Jason Witty "] description = "Socktop agent daemon. Serves host metrics over WebSocket." edition = "2024" diff --git a/socktop_connector/Cargo.toml b/socktop_connector/Cargo.toml index 8c628e3..7ff30c6 100644 --- a/socktop_connector/Cargo.toml +++ b/socktop_connector/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "socktop_connector" -version = "0.1.6" +version = "1.50.0" edition = "2024" license = "MIT" description = "WebSocket connector library for socktop agent communication"