Compare commits

...

6 Commits

Author SHA1 Message Date
fc6b3424cf Add hostname to NixOS title and make dashboard title bold
All checks were successful
Build and Release / build-and-release (push) Successful in 2m46s
- Change system panel title from 'NixOS:' to 'NixOS hostname:'
- Make main dashboard title 'cm-dashboard' bold in top bar
- Remove unused Typography::title() function to fix warnings
- Update SystemWidget::render_with_scroll to accept hostname parameter
- Update version to 0.1.41 in all Cargo.toml files and dashboard code
2025-10-29 14:24:17 +01:00
35e06c6734 Implement clean NixOS rebuild tmux popup
All checks were successful
Build and Release / build-and-release (push) Successful in 1m22s
- Replace complex ASCII logo with simple text header
- Remove extra blank lines for compact display
- Left-align text for clean appearance
- Add spacing after target line for readability
- Simplify heredoc format for better maintainability
2025-10-28 23:59:05 +01:00
783d233319 Add CM Dashboard ASCII logo to rebuild tmux popup
All checks were successful
Build and Release / build-and-release (push) Successful in 2m9s
- Display branded CM Dashboard ASCII logo in green when rebuild starts
- Shows logo immediately when tmux popup opens for better UX
- Includes rebuild target hostname and visual separator
- Enhances rebuild process with professional branding
- Bump version to v0.1.39
2025-10-28 23:12:09 +01:00
6509a2b91a Make nginx site latency thresholds configurable and simplify status logic
All checks were successful
Build and Release / build-and-release (push) Successful in 4m25s
- Replace hardcoded 500ms/2000ms thresholds with configurable nginx_latency_critical_ms
- Simplify status logic to only OK or Critical (no Warning status)
- Add validation for nginx latency threshold configuration
- Re-enable nginx site collection with configurable thresholds
- Resolves issue where sites showed critical at 2000ms despite 30s timeout setting
- Bump version to v0.1.38
2025-10-28 21:24:34 +01:00
52f8c40b86 Fix title bar layout constraints to prevent text disappearing
All checks were successful
Build and Release / build-and-release (push) Successful in 2m12s
- Set fixed width (15 chars) for left side to prevent chunk collapse
- Resolves issue where "cm-dashboard" text would flash and disappear
- Ensures consistent visibility of title text in dynamic status bar
- Bump version to v0.1.37
2025-10-28 18:56:12 +01:00
a86b5ba8f9 Implement dynamic status-based title bar with infrastructure health indicator
All checks were successful
Build and Release / build-and-release (push) Successful in 1m15s
- Title bar background now dynamically changes based on worst-case status across all hosts
- Green: all OK, Yellow: warnings present, Red: critical issues, Blue: pending, Gray: unknown
- Provides immediate visual feedback of overall infrastructure health
- Added 1-character padding on both sides of title bar
- Maintains dark text for visibility against all status background colors
- Bump version to v0.1.36
2025-10-28 18:47:02 +01:00
11 changed files with 59 additions and 36 deletions

6
Cargo.lock generated
View File

@@ -270,7 +270,7 @@ checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d"
[[package]]
name = "cm-dashboard"
version = "0.1.34"
version = "0.1.40"
dependencies = [
"anyhow",
"chrono",
@@ -291,7 +291,7 @@ dependencies = [
[[package]]
name = "cm-dashboard-agent"
version = "0.1.34"
version = "0.1.40"
dependencies = [
"anyhow",
"async-trait",
@@ -314,7 +314,7 @@ dependencies = [
[[package]]
name = "cm-dashboard-shared"
version = "0.1.34"
version = "0.1.40"
dependencies = [
"chrono",
"serde",

View File

@@ -1,6 +1,6 @@
[package]
name = "cm-dashboard-agent"
version = "0.1.35"
version = "0.1.41"
edition = "2021"
[dependencies]

View File

@@ -555,10 +555,8 @@ impl SystemdCollector {
for (site_name, url) in &sites {
match self.check_site_latency(url) {
Ok(latency_ms) => {
let status = if latency_ms < 500.0 {
let status = if latency_ms < self.config.nginx_latency_critical_ms {
Status::Ok
} else if latency_ms < 2000.0 {
Status::Warning
} else {
Status::Critical
};

View File

@@ -108,6 +108,7 @@ pub struct SystemdConfig {
pub nginx_check_interval_seconds: u64,
pub http_timeout_seconds: u64,
pub http_connect_timeout_seconds: u64,
pub nginx_latency_critical_ms: f32,
}

View File

@@ -83,6 +83,13 @@ pub fn validate_config(config: &AgentConfig) -> Result<()> {
}
}
// Validate systemd configuration
if config.collectors.systemd.enabled {
if config.collectors.systemd.nginx_latency_critical_ms <= 0.0 {
bail!("Nginx latency critical threshold must be positive");
}
}
// Validate SMTP configuration
if config.notifications.enabled {
if config.notifications.smtp_host.is_empty() {

View File

@@ -1,6 +1,6 @@
[package]
name = "cm-dashboard"
version = "0.1.35"
version = "0.1.41"
edition = "2021"
[dependencies]

View File

@@ -14,7 +14,7 @@ use app::Dashboard;
/// Get hardcoded version
fn get_version() -> &'static str {
"v0.1.33"
"v0.1.41"
}
/// Check if running inside tmux session

View File

@@ -244,16 +244,23 @@ impl TuiApp {
KeyCode::Char('r') => {
// System rebuild command - works on any panel for current host
if let Some(hostname) = self.current_host.clone() {
// Launch tmux popup with SSH using config values
let ssh_command = format!(
"ssh -tt {}@{} 'bash -ic {}'",
// Create command that shows CM Dashboard logo and then rebuilds
let logo_and_rebuild = format!(
r"cat << 'EOF'
NixOS System Rebuild
Target: {}
EOF
ssh -tt {}@{} 'bash -ic {}'",
hostname,
self.config.ssh.rebuild_user,
hostname,
self.config.ssh.rebuild_alias
);
std::process::Command::new("tmux")
.arg("display-popup")
.arg(&ssh_command)
.arg(&logo_and_rebuild)
.spawn()
.ok(); // Ignore errors, tmux will handle them
}
@@ -537,24 +544,34 @@ impl TuiApp {
if self.available_hosts.is_empty() {
let title_text = "cm-dashboard • no hosts discovered";
let title = Paragraph::new(title_text)
.style(Style::default().fg(Theme::background()).bg(Theme::highlight()));
.style(Style::default().fg(Theme::background()).bg(Theme::status_color(Status::Unknown)));
frame.render_widget(title, area);
return;
}
// Calculate worst-case status across all hosts
let mut worst_status = Status::Ok;
for host in &self.available_hosts {
let host_status = self.calculate_host_status(host, metric_store);
worst_status = Status::aggregate(&[worst_status, host_status]);
}
// Use the worst status color as background
let background_color = Theme::status_color(worst_status);
// Split the title bar into left and right sections
let chunks = Layout::default()
.direction(Direction::Horizontal)
.constraints([Constraint::Min(0), Constraint::Min(0)])
.constraints([Constraint::Length(15), Constraint::Min(0)])
.split(area);
// Left side: "cm-dashboard" text
let left_span = Span::styled(
"cm-dashboard",
Style::default().fg(Theme::background()).bg(Theme::highlight())
" cm-dashboard",
Style::default().fg(Theme::background()).bg(background_color).add_modifier(Modifier::BOLD)
);
let left_title = Paragraph::new(Line::from(vec![left_span]))
.style(Style::default().bg(Theme::highlight()));
.style(Style::default().bg(background_color));
frame.render_widget(left_title, chunks[0]);
// Right side: hosts with status indicators
@@ -564,7 +581,7 @@ impl TuiApp {
if i > 0 {
host_spans.push(Span::styled(
" ",
Style::default().fg(Theme::background()).bg(Theme::highlight())
Style::default().fg(Theme::background()).bg(background_color)
));
}
@@ -572,33 +589,39 @@ impl TuiApp {
let host_status = self.calculate_host_status(host, metric_store);
let status_icon = StatusIcons::get_icon(host_status);
// Add status icon with background color as foreground against blue background
// Add status icon with background color as foreground against status background
host_spans.push(Span::styled(
format!("{} ", status_icon),
Style::default().fg(Theme::background()).bg(Theme::highlight()),
Style::default().fg(Theme::background()).bg(background_color),
));
if Some(host) == self.current_host.as_ref() {
// Selected host in bold background color against blue background
// Selected host in bold background color against status background
host_spans.push(Span::styled(
host.clone(),
Style::default()
.fg(Theme::background())
.bg(Theme::highlight())
.bg(background_color)
.add_modifier(Modifier::BOLD),
));
} else {
// Other hosts in normal background color against blue background
// Other hosts in normal background color against status background
host_spans.push(Span::styled(
host.clone(),
Style::default().fg(Theme::background()).bg(Theme::highlight()),
Style::default().fg(Theme::background()).bg(background_color),
));
}
}
// Add right padding
host_spans.push(Span::styled(
" ",
Style::default().fg(Theme::background()).bg(background_color)
));
let host_line = Line::from(host_spans);
let host_title = Paragraph::new(vec![host_line])
.style(Style::default().bg(Theme::highlight()))
.style(Style::default().bg(background_color))
.alignment(ratatui::layout::Alignment::Right);
frame.render_widget(host_title, chunks[1]);
}
@@ -685,7 +708,7 @@ impl TuiApp {
host_widgets.system_scroll_offset
};
let host_widgets = self.get_or_create_host_widgets(&hostname);
host_widgets.system_widget.render_with_scroll(frame, inner_area, scroll_offset);
host_widgets.system_widget.render_with_scroll(frame, inner_area, scroll_offset, &hostname);
}
}

View File

@@ -292,12 +292,6 @@ impl Components {
}
impl Typography {
/// Main title style (dashboard header)
pub fn title() -> Style {
Style::default()
.fg(Theme::primary_text())
.bg(Theme::background())
}
/// Widget title style (panel headers) - bold bright white
pub fn widget_title() -> Style {

View File

@@ -439,12 +439,12 @@ impl Widget for SystemWidget {
impl SystemWidget {
/// Render with scroll offset support
pub fn render_with_scroll(&mut self, frame: &mut Frame, area: Rect, scroll_offset: usize) {
pub fn render_with_scroll(&mut self, frame: &mut Frame, area: Rect, scroll_offset: usize, hostname: &str) {
let mut lines = Vec::new();
// NixOS section
lines.push(Line::from(vec![
Span::styled("NixOS:", Typography::widget_title())
Span::styled(format!("NixOS {}:", hostname), Typography::widget_title())
]));
let build_text = self.nixos_build.as_deref().unwrap_or("unknown");

View File

@@ -1,6 +1,6 @@
[package]
name = "cm-dashboard-shared"
version = "0.1.35"
version = "0.1.41"
edition = "2021"
[dependencies]