Testing
This commit is contained in:
parent
d76302e1c4
commit
42aaebf6a7
@ -149,17 +149,56 @@ impl SystemCollector {
|
||||
}
|
||||
|
||||
if total_time > 0 && !cstate_times.is_empty() {
|
||||
// Sort by time spent (highest first)
|
||||
cstate_times.sort_by(|a, b| b.1.cmp(&a.1));
|
||||
// Sort by C-state order: POLL, C1, C1E, C3, C6, C7s, C8, C9, C10
|
||||
cstate_times.sort_by(|a, b| {
|
||||
let order_a = match a.0.as_str() {
|
||||
"POLL" => 0,
|
||||
"C1" => 1,
|
||||
"C1E" => 2,
|
||||
"C3" => 3,
|
||||
"C6" => 4,
|
||||
"C7s" => 5,
|
||||
"C8" => 6,
|
||||
"C9" => 7,
|
||||
"C10" => 8,
|
||||
_ => 99,
|
||||
};
|
||||
let order_b = match b.0.as_str() {
|
||||
"POLL" => 0,
|
||||
"C1" => 1,
|
||||
"C1E" => 2,
|
||||
"C3" => 3,
|
||||
"C6" => 4,
|
||||
"C7s" => 5,
|
||||
"C8" => 6,
|
||||
"C9" => 7,
|
||||
"C10" => 8,
|
||||
_ => 99,
|
||||
};
|
||||
order_a.cmp(&order_b)
|
||||
});
|
||||
|
||||
// Format all C-states with percentages
|
||||
// Format C-states as description lines (split into two rows for readability)
|
||||
let mut result = Vec::new();
|
||||
let mut current_line = Vec::new();
|
||||
|
||||
for (name, time) in cstate_times {
|
||||
let percent = (time as f32 / total_time as f32) * 100.0;
|
||||
if percent >= 0.1 { // Only show states with at least 0.1% time
|
||||
result.push(format!("{}: {:.1}%", name, percent));
|
||||
current_line.push(format!("{}: {:.1}%", name, percent));
|
||||
|
||||
// Split into two rows when we have 4 items
|
||||
if current_line.len() == 4 {
|
||||
result.push(current_line.join(", "));
|
||||
current_line.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add remaining items as second line
|
||||
if !current_line.is_empty() {
|
||||
result.push(current_line.join(", "));
|
||||
}
|
||||
|
||||
return Some(result);
|
||||
}
|
||||
|
||||
@ -475,8 +475,26 @@ impl App {
|
||||
targets.push(HostTarget::from_name(local));
|
||||
}
|
||||
}
|
||||
} else if let Some(local) = local_host {
|
||||
targets.push(HostTarget::from_name(local));
|
||||
} else {
|
||||
// No config file - use auto-discovery with known CMTEC hosts
|
||||
let known_hosts = vec![
|
||||
"cmbox", "labbox", "simonbox", "steambox", "srv01"
|
||||
];
|
||||
|
||||
if let Some(local) = local_host.as_ref() {
|
||||
targets.push(HostTarget::from_name(local.clone()));
|
||||
}
|
||||
|
||||
// Add all known hosts for auto-discovery
|
||||
for hostname in known_hosts {
|
||||
if targets
|
||||
.iter()
|
||||
.any(|existing| existing.name.eq_ignore_ascii_case(hostname))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
targets.push(HostTarget::from_name(hostname.to_string()));
|
||||
}
|
||||
}
|
||||
|
||||
if targets.is_empty() {
|
||||
|
||||
@ -49,102 +49,6 @@ fn render_metrics(
|
||||
// Use agent-calculated statuses
|
||||
let memory_status = status_level_from_agent_status(summary.memory_status.as_ref());
|
||||
let cpu_status = status_level_from_agent_status(summary.cpu_status.as_ref());
|
||||
// Dashboard should NOT calculate colors - agent is the source of truth
|
||||
|
||||
// Memory dataset - use agent-calculated status
|
||||
let mut memory_dataset = WidgetDataSet::new(vec!["Memory usage".to_string()], Some(WidgetStatus::new(memory_status)));
|
||||
memory_dataset.add_row(
|
||||
Some(WidgetStatus::new(memory_status)),
|
||||
vec![],
|
||||
vec![format!("{:.1} / {:.1} GB", summary.memory_used_mb / 1000.0, summary.memory_total_mb / 1000.0)],
|
||||
);
|
||||
|
||||
// CPU dataset - use agent-calculated status
|
||||
let mut cpu_dataset = WidgetDataSet::new(vec!["CPU load".to_string(), "CPU temp".to_string()], Some(WidgetStatus::new(cpu_status)));
|
||||
cpu_dataset.add_row(
|
||||
Some(WidgetStatus::new(cpu_status)),
|
||||
vec![],
|
||||
vec![
|
||||
format!("{:.2} • {:.2} • {:.2}", summary.cpu_load_1, summary.cpu_load_5, summary.cpu_load_15),
|
||||
format_optional_metric(summary.cpu_temp_c, "°C"),
|
||||
],
|
||||
);
|
||||
|
||||
// C-state dataset - all C-states as columns in one row, ordered properly
|
||||
let mut cstate_headers = Vec::new();
|
||||
let mut cstate_values = Vec::new();
|
||||
|
||||
if let Some(cstates) = summary.cpu_cstate.as_ref() {
|
||||
// Parse all C-states first
|
||||
let mut parsed_cstates: Vec<(String, String)> = Vec::new();
|
||||
for cstate_info in cstates {
|
||||
if let Some((state, percent)) = cstate_info.split_once(": ") {
|
||||
parsed_cstates.push((state.to_string(), percent.to_string()));
|
||||
}
|
||||
}
|
||||
|
||||
// Sort by C-state order: POLL, C1, C1E, C3, C6, C7s, C8, C9, C10
|
||||
parsed_cstates.sort_by(|a, b| {
|
||||
let order_a = match a.0.as_str() {
|
||||
"POLL" => 0,
|
||||
"C1" => 1,
|
||||
"C1E" => 2,
|
||||
"C3" => 3,
|
||||
"C6" => 4,
|
||||
"C7s" => 5,
|
||||
"C8" => 6,
|
||||
"C9" => 7,
|
||||
"C10" => 8,
|
||||
_ => 99,
|
||||
};
|
||||
let order_b = match b.0.as_str() {
|
||||
"POLL" => 0,
|
||||
"C1" => 1,
|
||||
"C1E" => 2,
|
||||
"C3" => 3,
|
||||
"C6" => 4,
|
||||
"C7s" => 5,
|
||||
"C8" => 6,
|
||||
"C9" => 7,
|
||||
"C10" => 8,
|
||||
_ => 99,
|
||||
};
|
||||
order_a.cmp(&order_b)
|
||||
});
|
||||
|
||||
// Take all available C-states (or limit to fit display)
|
||||
for (state, percent) in parsed_cstates.into_iter().take(8) {
|
||||
cstate_headers.push(state);
|
||||
cstate_values.push(percent);
|
||||
}
|
||||
}
|
||||
|
||||
let mut cstate_dataset = WidgetDataSet::new(cstate_headers, Some(WidgetStatus::new(StatusLevel::Ok)));
|
||||
if !cstate_values.is_empty() {
|
||||
cstate_dataset.add_row(
|
||||
Some(WidgetStatus::new(StatusLevel::Ok)),
|
||||
vec![],
|
||||
cstate_values,
|
||||
);
|
||||
} else {
|
||||
cstate_dataset.add_row(
|
||||
Some(WidgetStatus::new(StatusLevel::Unknown)),
|
||||
vec![],
|
||||
vec!["No data".to_string()],
|
||||
);
|
||||
}
|
||||
|
||||
// GPU dataset - GPU data remains in ServiceMetrics, not SystemMetrics
|
||||
let gpu_status = StatusLevel::Unknown; // GPU not available in SystemMetrics
|
||||
let mut gpu_dataset = WidgetDataSet::new(vec!["GPU load".to_string(), "GPU temp".to_string()], Some(WidgetStatus::new(gpu_status)));
|
||||
gpu_dataset.add_row(
|
||||
Some(WidgetStatus::new(gpu_status)),
|
||||
vec![],
|
||||
vec![
|
||||
"—".to_string(), // GPU data not in SystemMetrics
|
||||
"—".to_string(), // GPU data not in SystemMetrics
|
||||
],
|
||||
);
|
||||
|
||||
// Determine overall widget status based on worst case from agent statuses
|
||||
let overall_status_level = match (memory_status, cpu_status) {
|
||||
@ -155,8 +59,27 @@ fn render_metrics(
|
||||
};
|
||||
let overall_status = Some(WidgetStatus::new(overall_status_level));
|
||||
|
||||
// Render all datasets in a single combined widget
|
||||
render_combined_widget_data(frame, area, "System".to_string(), overall_status, vec![memory_dataset, cpu_dataset, cstate_dataset, gpu_dataset]);
|
||||
// Single dataset with RAM, CPU load, CPU temp as columns
|
||||
let mut system_dataset = WidgetDataSet::new(
|
||||
vec!["RAM usage".to_string(), "CPU load".to_string(), "CPU temp".to_string()],
|
||||
overall_status.clone()
|
||||
);
|
||||
|
||||
// Use agent-provided C-states as description (agent decides what goes in descriptions)
|
||||
let cstate_description = summary.cpu_cstate.clone().unwrap_or_default();
|
||||
|
||||
system_dataset.add_row(
|
||||
overall_status.clone(),
|
||||
cstate_description,
|
||||
vec![
|
||||
format!("{:.1} / {:.1} GB", summary.memory_used_mb / 1000.0, summary.memory_total_mb / 1000.0),
|
||||
format!("{:.2} • {:.2} • {:.2}", summary.cpu_load_1, summary.cpu_load_5, summary.cpu_load_15),
|
||||
format_optional_metric(summary.cpu_temp_c, "°C"),
|
||||
],
|
||||
);
|
||||
|
||||
// Render single dataset
|
||||
render_combined_widget_data(frame, area, "System".to_string(), overall_status, vec![system_dataset]);
|
||||
}
|
||||
|
||||
fn format_optional_metric(value: Option<f32>, unit: &str) -> String {
|
||||
|
||||
@ -286,6 +286,43 @@ fn render_dataset_with_wrapping(frame: &mut Frame, dataset: &WidgetDataSet, inne
|
||||
break;
|
||||
}
|
||||
|
||||
// Check if this is a sub-service - if so, render as full-width row
|
||||
if row.sub_service.is_some() && col_start == 0 {
|
||||
// Sub-service: render as full-width spanning row
|
||||
let is_last_sub_service = is_last_sub_service_in_group(&dataset.rows, row_idx, &row.sub_service);
|
||||
let tree_char = if is_last_sub_service { "└─" } else { "├─" };
|
||||
let service_name = row.values.get(0).cloned().unwrap_or_default();
|
||||
|
||||
let status_icon = match &row.status {
|
||||
Some(s) => {
|
||||
let color = s.status.to_color();
|
||||
let icon = s.status.to_icon();
|
||||
Span::styled(icon.to_string(), Style::default().fg(color))
|
||||
},
|
||||
None => Span::raw(""),
|
||||
};
|
||||
|
||||
let full_content = format!("{} {}", tree_char, service_name);
|
||||
let full_cell = Cell::from(Line::from(vec![
|
||||
status_icon,
|
||||
Span::raw(" "),
|
||||
Span::styled(full_content, neutral_text_style()),
|
||||
]));
|
||||
|
||||
let full_row = Row::new(vec![full_cell]);
|
||||
let full_constraints = vec![Constraint::Length(inner.width)];
|
||||
let full_table = Table::new(vec![full_row])
|
||||
.widths(&full_constraints)
|
||||
.style(neutral_text_style());
|
||||
|
||||
frame.render_widget(full_table, Rect {
|
||||
x: inner.x,
|
||||
y: current_y,
|
||||
width: inner.width,
|
||||
height: 1,
|
||||
});
|
||||
} else if row.sub_service.is_none() {
|
||||
// Regular service: render with columns as normal
|
||||
let mut cells = vec![];
|
||||
|
||||
// Status cell (only show on first section)
|
||||
@ -311,18 +348,8 @@ fn render_dataset_with_wrapping(frame: &mut Frame, dataset: &WidgetDataSet, inne
|
||||
if content.is_empty() {
|
||||
cells.push(Cell::from(""));
|
||||
} else {
|
||||
// Check if this is the first column (service name) and if it's a sub-service
|
||||
let display_content = if col_idx == 0 && row.sub_service.is_some() {
|
||||
// Determine if this is the last sub-service for this parent
|
||||
let is_last_sub_service = is_last_sub_service_in_group(&dataset.rows, row_idx, &row.sub_service);
|
||||
let tree_char = if is_last_sub_service { "└─" } else { "├─" };
|
||||
format!("{} {}", tree_char, content)
|
||||
} else {
|
||||
content.to_string()
|
||||
};
|
||||
|
||||
cells.push(Cell::from(Line::from(vec![Span::styled(
|
||||
display_content,
|
||||
content.to_string(),
|
||||
neutral_text_style(),
|
||||
)])));
|
||||
}
|
||||
@ -343,6 +370,7 @@ fn render_dataset_with_wrapping(frame: &mut Frame, dataset: &WidgetDataSet, inne
|
||||
width: inner.width,
|
||||
height: 1,
|
||||
});
|
||||
}
|
||||
current_y += 1;
|
||||
|
||||
// Render description rows if any exist
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user