Fix rebuild indicator with proper timeout and completion detection
- Add automatic timeout mechanism (5 minutes for rebuilds, 30 seconds for services) - Implement agent hash change detection for rebuild completion - Add visual feedback states: blue ↻ (in progress), green ✓ (success), red ✗ (failed) - Clear status automatically after timeout or completion - Fix command status lifecycle management
This commit is contained in:
parent
c48a105c28
commit
a7e237e2ff
@ -7,7 +7,7 @@ use ratatui::{
|
||||
Frame,
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
use std::time::Instant;
|
||||
use std::time::{Duration, Instant};
|
||||
use tracing::info;
|
||||
|
||||
pub mod theme;
|
||||
@ -34,9 +34,9 @@ pub enum CommandStatus {
|
||||
/// Command is executing
|
||||
InProgress { command_type: CommandType, target: String, start_time: std::time::Instant },
|
||||
/// Command completed successfully
|
||||
Success { command_type: CommandType, target: String, duration: std::time::Duration },
|
||||
Success { command_type: CommandType, target: String, duration: std::time::Duration, completed_at: std::time::Instant },
|
||||
/// Command failed
|
||||
Failed { command_type: CommandType, target: String, error: String },
|
||||
Failed { command_type: CommandType, target: String, error: String, failed_at: std::time::Instant },
|
||||
}
|
||||
|
||||
/// Types of commands for status tracking
|
||||
@ -156,6 +156,12 @@ impl TuiApp {
|
||||
|
||||
/// Update widgets with metrics from store (only for current host)
|
||||
pub fn update_metrics(&mut self, metric_store: &MetricStore) {
|
||||
// Check for command timeouts first
|
||||
self.check_command_timeouts();
|
||||
|
||||
// Check for rebuild completion by agent hash change
|
||||
self.check_rebuild_completion(metric_store);
|
||||
|
||||
if let Some(hostname) = self.current_host.clone() {
|
||||
// Only update widgets if we have metrics for this host
|
||||
let all_metrics = metric_store.get_metrics_for_host(&hostname);
|
||||
@ -491,10 +497,8 @@ impl TuiApp {
|
||||
command_type: command_type.clone(),
|
||||
target: target.clone(),
|
||||
duration,
|
||||
completed_at: Instant::now(),
|
||||
});
|
||||
|
||||
// Clear success status after 3 seconds
|
||||
// TODO: Implement timer to clear this
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -507,14 +511,76 @@ impl TuiApp {
|
||||
command_type: command_type.clone(),
|
||||
target: target.clone(),
|
||||
error,
|
||||
failed_at: Instant::now(),
|
||||
});
|
||||
|
||||
// Clear error status after 5 seconds
|
||||
// TODO: Implement timer to clear this
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Check for command timeouts and automatically clear them
|
||||
pub fn check_command_timeouts(&mut self) {
|
||||
let now = Instant::now();
|
||||
let mut hosts_to_clear = Vec::new();
|
||||
|
||||
for (hostname, host_widgets) in &self.host_widgets {
|
||||
if let Some(CommandStatus::InProgress { command_type, start_time, .. }) = &host_widgets.command_status {
|
||||
let timeout_duration = match command_type {
|
||||
CommandType::SystemRebuild => Duration::from_secs(300), // 5 minutes for rebuilds
|
||||
_ => Duration::from_secs(30), // 30 seconds for service commands
|
||||
};
|
||||
|
||||
if now.duration_since(*start_time) > timeout_duration {
|
||||
hosts_to_clear.push(hostname.clone());
|
||||
}
|
||||
}
|
||||
// Also clear success/failed status after display time
|
||||
else if let Some(CommandStatus::Success { completed_at, .. }) = &host_widgets.command_status {
|
||||
if now.duration_since(*completed_at) > Duration::from_secs(3) {
|
||||
hosts_to_clear.push(hostname.clone());
|
||||
}
|
||||
}
|
||||
else if let Some(CommandStatus::Failed { failed_at, .. }) = &host_widgets.command_status {
|
||||
if now.duration_since(*failed_at) > Duration::from_secs(5) {
|
||||
hosts_to_clear.push(hostname.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clear timed out commands
|
||||
for hostname in hosts_to_clear {
|
||||
if let Some(host_widgets) = self.host_widgets.get_mut(&hostname) {
|
||||
host_widgets.command_status = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Check for rebuild completion by detecting agent hash changes
|
||||
pub fn check_rebuild_completion(&mut self, metric_store: &MetricStore) {
|
||||
let mut hosts_to_complete = Vec::new();
|
||||
|
||||
for (hostname, host_widgets) in &self.host_widgets {
|
||||
if let Some(CommandStatus::InProgress { command_type: CommandType::SystemRebuild, .. }) = &host_widgets.command_status {
|
||||
// Check if agent hash has changed (indicating successful rebuild)
|
||||
if let Some(agent_hash_metric) = metric_store.get_metric(hostname, "system_agent_hash") {
|
||||
if let cm_dashboard_shared::MetricValue::String(current_hash) = &agent_hash_metric.value {
|
||||
// Compare with stored hash (if we have one)
|
||||
if let Some(stored_hash) = host_widgets.system_widget.get_agent_hash() {
|
||||
if current_hash != stored_hash {
|
||||
// Agent hash changed - rebuild completed successfully
|
||||
hosts_to_complete.push(hostname.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mark rebuilds as completed
|
||||
for hostname in hosts_to_complete {
|
||||
self.complete_command(&hostname);
|
||||
}
|
||||
}
|
||||
|
||||
/// Scroll the focused panel up or down
|
||||
pub fn scroll_focused_panel(&mut self, direction: i32) {
|
||||
if let Some(hostname) = self.current_host.clone() {
|
||||
@ -682,15 +748,26 @@ impl TuiApp {
|
||||
spans.push(Span::styled(" ", Typography::title()));
|
||||
}
|
||||
|
||||
// Check if this host has a SystemRebuild command in progress
|
||||
// Check if this host has a command status that affects the icon
|
||||
let (status_icon, status_color) = if let Some(host_widgets) = self.host_widgets.get(host) {
|
||||
if let Some(CommandStatus::InProgress { command_type: CommandType::SystemRebuild, .. }) = &host_widgets.command_status {
|
||||
// Show blue circular arrow during rebuild
|
||||
("↻", Theme::highlight())
|
||||
} else {
|
||||
// Normal status icon based on metrics
|
||||
let host_status = self.calculate_host_status(host, metric_store);
|
||||
(StatusIcons::get_icon(host_status), Theme::status_color(host_status))
|
||||
match &host_widgets.command_status {
|
||||
Some(CommandStatus::InProgress { command_type: CommandType::SystemRebuild, .. }) => {
|
||||
// Show blue circular arrow during rebuild
|
||||
("↻", Theme::highlight())
|
||||
}
|
||||
Some(CommandStatus::Success { command_type: CommandType::SystemRebuild, .. }) => {
|
||||
// Show green checkmark for successful rebuild
|
||||
("✓", Theme::success())
|
||||
}
|
||||
Some(CommandStatus::Failed { command_type: CommandType::SystemRebuild, .. }) => {
|
||||
// Show red X for failed rebuild
|
||||
("✗", Theme::error())
|
||||
}
|
||||
_ => {
|
||||
// Normal status icon based on metrics
|
||||
let host_status = self.calculate_host_status(host, metric_store);
|
||||
(StatusIcons::get_icon(host_status), Theme::status_color(host_status))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// No host widgets yet, use normal status
|
||||
|
||||
@ -128,6 +128,11 @@ impl SystemWidget {
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the current agent hash for rebuild completion detection
|
||||
pub fn get_agent_hash(&self) -> Option<&String> {
|
||||
self.agent_hash.as_ref()
|
||||
}
|
||||
|
||||
/// Get mount point for a pool name
|
||||
fn get_mount_point_for_pool(&self, pool_name: &str) -> String {
|
||||
match pool_name {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user