Fix dashboard UI: correct pending color (blue) and use host_status_summary metric

This commit is contained in:
Christoffer Martinsson 2025-10-21 19:32:37 +02:00
parent 7ead8ee98a
commit f4b5bb814d
5 changed files with 54 additions and 17 deletions

View File

@ -156,14 +156,18 @@ impl Agent {
debug!("Broadcasting all cached metrics via ZMQ"); debug!("Broadcasting all cached metrics via ZMQ");
// Get all cached metrics from the metric manager // Get all cached metrics from the metric manager
let cached_metrics = self.metric_manager.get_all_cached_metrics().await?; let mut cached_metrics = self.metric_manager.get_all_cached_metrics().await?;
// Add the host status summary metric from status manager
let host_status_metric = self.host_status_manager.get_host_status_metric();
cached_metrics.push(host_status_metric);
if cached_metrics.is_empty() { if cached_metrics.is_empty() {
debug!("No cached metrics to broadcast"); debug!("No cached metrics to broadcast");
return Ok(()); return Ok(());
} }
debug!("Broadcasting {} cached metrics", cached_metrics.len()); debug!("Broadcasting {} cached metrics (including host status summary)", cached_metrics.len());
// Create and send message with all cached data // Create and send message with all cached data
let message = MetricMessage::new(self.hostname.clone(), cached_metrics); let message = MetricMessage::new(self.hostname.clone(), cached_metrics);

View File

@ -128,6 +128,21 @@ impl HostStatusManager {
); );
} }
/// Get the current host status as a metric for broadcasting to dashboard
pub fn get_host_status_metric(&self) -> Metric {
Metric {
name: "host_status_summary".to_string(),
value: cm_dashboard_shared::MetricValue::String(format!(
"Host aggregated from {} services",
self.service_statuses.len()
)),
status: self.current_host_status,
timestamp: Utc::now().timestamp() as u64,
description: Some("Aggregated host status from all services".to_string()),
unit: None,
}
}
/// Calculate the overall host status based on all service statuses /// Calculate the overall host status based on all service statuses
fn calculate_host_status(&self) -> Status { fn calculate_host_status(&self) -> Status {
if self.service_statuses.is_empty() { if self.service_statuses.is_empty() {

View File

@ -357,23 +357,41 @@ impl TuiApp {
return Status::Unknown; return Status::Unknown;
} }
// Check if any metric is critical // First check if we have the aggregated host status summary from the agent
if metrics.iter().any(|m| m.status == Status::Critical) { if let Some(host_summary_metric) = metric_store.get_metric(hostname, "host_status_summary") {
return Status::Critical; return host_summary_metric.status;
} }
// Check if any metric is warning // Fallback to old aggregation logic with proper Pending handling
if metrics.iter().any(|m| m.status == Status::Warning) { let mut has_critical = false;
return Status::Warning; let mut has_warning = false;
let mut has_pending = false;
let mut ok_count = 0;
let mut total_count = 0;
for metric in &metrics {
total_count += 1;
match metric.status {
Status::Critical => has_critical = true,
Status::Warning => has_warning = true,
Status::Pending => has_pending = true,
Status::Ok => ok_count += 1,
Status::Unknown => {} // Ignore unknown for aggregation
}
} }
// Check if all metrics are ok // Priority order: Critical > Warning > Pending > Ok > Unknown
if metrics.iter().all(|m| m.status == Status::Ok) { if has_critical {
return Status::Ok; Status::Critical
} else if has_warning {
Status::Warning
} else if has_pending {
Status::Pending
} else if ok_count > 0 {
Status::Ok
} else {
Status::Unknown
} }
// Default to unknown if mixed statuses
Status::Unknown
} }
fn render_system_panel(&mut self, frame: &mut Frame, area: Rect, metric_store: &MetricStore) { fn render_system_panel(&mut self, frame: &mut Frame, area: Rect, metric_store: &MetricStore) {

View File

@ -143,7 +143,7 @@ impl Theme {
pub fn status_color(status: Status) -> Color { pub fn status_color(status: Status) -> Color {
match status { match status {
Status::Ok => Self::success(), Status::Ok => Self::success(),
Status::Pending => Self::info(), // Blue for pending Status::Pending => Self::highlight(), // Blue for pending
Status::Warning => Self::warning(), Status::Warning => Self::warning(),
Status::Critical => Self::error(), Status::Critical => Self::error(),
Status::Unknown => Self::muted_text(), Status::Unknown => Self::muted_text(),
@ -258,7 +258,7 @@ impl StatusIcons {
let icon = Self::get_icon(status); let icon = Self::get_icon(status);
let status_color = match status { let status_color = match status {
Status::Ok => Theme::success(), // Green Status::Ok => Theme::success(), // Green
Status::Pending => Theme::info(), // Blue Status::Pending => Theme::highlight(), // Blue
Status::Warning => Theme::warning(), // Yellow Status::Warning => Theme::warning(), // Yellow
Status::Critical => Theme::error(), // Red Status::Critical => Theme::error(), // Red
Status::Unknown => Theme::muted_text(), // Gray Status::Unknown => Theme::muted_text(), // Gray

View File

@ -156,7 +156,7 @@ impl ServicesWidget {
let status_color = match info.widget_status { let status_color = match info.widget_status {
Status::Ok => Theme::success(), Status::Ok => Theme::success(),
Status::Pending => Theme::info(), Status::Pending => Theme::highlight(),
Status::Warning => Theme::warning(), Status::Warning => Theme::warning(),
Status::Critical => Theme::error(), Status::Critical => Theme::error(),
Status::Unknown => Theme::muted_text(), Status::Unknown => Theme::muted_text(),