patch header for small monitors and increase cargo version in advance of publish.

This commit is contained in:
jasonwitty 2025-11-17 11:52:22 -08:00
parent 7875f132f7
commit 9d302ad475
5 changed files with 60 additions and 27 deletions

4
Cargo.lock generated
View File

@ -2182,7 +2182,7 @@ dependencies = [
[[package]] [[package]]
name = "socktop_agent" name = "socktop_agent"
version = "1.40.70" version = "1.50.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"assert_cmd", "assert_cmd",
@ -2213,7 +2213,7 @@ dependencies = [
[[package]] [[package]]
name = "socktop_connector" name = "socktop_connector"
version = "0.1.6" version = "1.50.0"
dependencies = [ dependencies = [
"flate2", "flate2",
"futures-util", "futures-util",

View File

@ -249,22 +249,52 @@ pub fn draw_cpu_avg_graph(
}; };
let title = if let Some(mm) = m { let title = if let Some(mm) = m {
format!( format!("CPU (now: {:>5.1}% | avg: {:>5.1}%)", mm.cpu_total, avg_cpu)
"CPU avg (now: {:>5.1}% | avg: {:>5.1}%)",
mm.cpu_total, avg_cpu
)
} else { } else {
"CPU avg".into() "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 max_points = area.width.saturating_sub(2) as usize;
let start = hist.len().saturating_sub(max_points); let start = hist.len().saturating_sub(max_points);
let data: Vec<u64> = hist.iter().skip(start).cloned().collect(); let data: Vec<u64> = hist.iter().skip(start).cloned().collect();
// Render the sparkline with title on left
let spark = Sparkline::default() let spark = Sparkline::default()
.block(Block::default().borders(Borders::ALL).title(title)) .block(Block::default().borders(Borders::ALL).title(title))
.data(&data) .data(&data)
.max(100) .max(100)
.style(Style::default().fg(Color::Cyan)); .style(Style::default().fg(Color::Cyan));
f.render_widget(spark, area); 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. /// Draws the per-core CPU bars with sparklines and trends.

View File

@ -3,7 +3,8 @@
use crate::types::Metrics; use crate::types::Metrics;
use ratatui::{ use ratatui::{
layout::Rect, layout::Rect,
widgets::{Block, Borders}, text::{Line, Span},
widgets::{Block, Borders, Paragraph},
}; };
use std::time::Duration; use std::time::Duration;
@ -17,20 +18,7 @@ pub fn draw_header(
procs_interval: Duration, procs_interval: Duration,
) { ) {
let base = if let Some(mm) = m { let base = if let Some(mm) = m {
let temp = mm format!("socktop — host: {}", mm.hostname)
.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)
} else { } else {
"socktop — connecting...".into() "socktop — connecting...".into()
}; };
@ -38,15 +26,30 @@ pub fn draw_header(
let tls_txt = if is_tls { "🔒 TLS" } else { "🔒✗ TLS" }; let tls_txt = if is_tls { "🔒 TLS" } else { "🔒✗ TLS" };
// Token indicator // Token indicator
let tok_txt = if has_token { "🔑 token" } else { "" }; 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()]; let mut parts = vec![base, tls_txt.into()];
if !tok_txt.is_empty() { if !tok_txt.is_empty() {
parts.push(tok_txt.into()); parts.push(tok_txt.into());
} }
parts.push(intervals);
parts.push("(a: about, h: help, q: quit)".into()); parts.push("(a: about, h: help, q: quit)".into());
let title = parts.join(" | "); let title = parts.join(" | ");
// Render the block with left-aligned title
f.render_widget(Block::default().title(title).borders(Borders::BOTTOM), area); 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);
}
} }

View File

@ -1,6 +1,6 @@
[package] [package]
name = "socktop_agent" name = "socktop_agent"
version = "1.40.70" version = "1.50.0"
authors = ["Jason Witty <jasonpwitty+socktop@proton.me>"] authors = ["Jason Witty <jasonpwitty+socktop@proton.me>"]
description = "Socktop agent daemon. Serves host metrics over WebSocket." description = "Socktop agent daemon. Serves host metrics over WebSocket."
edition = "2024" edition = "2024"

View File

@ -1,6 +1,6 @@
[package] [package]
name = "socktop_connector" name = "socktop_connector"
version = "0.1.6" version = "1.50.0"
edition = "2024" edition = "2024"
license = "MIT" license = "MIT"
description = "WebSocket connector library for socktop agent communication" description = "WebSocket connector library for socktop agent communication"