diff --git a/Cargo.lock b/Cargo.lock index d6b2e99..c86e81e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -270,7 +270,7 @@ checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" [[package]] name = "cm-dashboard" -version = "0.1.26" +version = "0.1.27" dependencies = [ "anyhow", "chrono", @@ -291,7 +291,7 @@ dependencies = [ [[package]] name = "cm-dashboard-agent" -version = "0.1.26" +version = "0.1.27" dependencies = [ "anyhow", "async-trait", @@ -314,7 +314,7 @@ dependencies = [ [[package]] name = "cm-dashboard-shared" -version = "0.1.26" +version = "0.1.27" dependencies = [ "chrono", "serde", diff --git a/agent/Cargo.toml b/agent/Cargo.toml index 6ebc0db..c7a3298 100644 --- a/agent/Cargo.toml +++ b/agent/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cm-dashboard-agent" -version = "0.1.27" +version = "0.1.28" edition = "2021" [dependencies] diff --git a/dashboard/Cargo.toml b/dashboard/Cargo.toml index e659a9a..6d6825c 100644 --- a/dashboard/Cargo.toml +++ b/dashboard/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cm-dashboard" -version = "0.1.27" +version = "0.1.28" edition = "2021" [dependencies] diff --git a/dashboard/src/main.rs b/dashboard/src/main.rs index bc9f334..128e804 100644 --- a/dashboard/src/main.rs +++ b/dashboard/src/main.rs @@ -14,7 +14,7 @@ use app::Dashboard; /// Get hardcoded version fn get_version() -> &'static str { - "v0.1.27" + "v0.1.28" } /// Check if running inside tmux session diff --git a/dashboard/src/ui/widgets/services.rs b/dashboard/src/ui/widgets/services.rs index f94c609..4aec77d 100644 --- a/dashboard/src/ui/widgets/services.rs +++ b/dashboard/src/ui/widgets/services.rs @@ -233,13 +233,14 @@ impl ServicesWidget { /// Get currently selected service name (for actions) pub fn get_selected_service(&self) -> Option { // Build the same display list to find the selected service - let mut display_lines: Vec<(String, Status, bool, Option<(ServiceInfo, bool)>)> = Vec::new(); + let mut display_lines: Vec<(String, Status, bool, Option<(ServiceInfo, bool)>, String)> = Vec::new(); let mut parent_services: Vec<_> = self.parent_services.iter().collect(); parent_services.sort_by(|(a, _), (b, _)| a.cmp(b)); for (parent_name, parent_info) in parent_services { - display_lines.push((parent_name.clone(), parent_info.widget_status, false, None)); + let parent_line = self.format_parent_service_line(parent_name, parent_info); + display_lines.push((parent_line, parent_info.widget_status, false, None, parent_name.clone())); if let Some(sub_list) = self.sub_services.get(parent_name) { let mut sorted_subs = sub_list.clone(); @@ -247,17 +248,19 @@ impl ServicesWidget { for (i, (sub_name, sub_info)) in sorted_subs.iter().enumerate() { let is_last_sub = i == sorted_subs.len() - 1; + let full_sub_name = format!("{}_{}", parent_name, sub_name); display_lines.push(( - format!("{}_{}", parent_name, sub_name), // Use parent_sub format for sub-services + sub_name.clone(), sub_info.widget_status, true, Some((sub_info.clone(), is_last_sub)), + full_sub_name, )); } } } - display_lines.get(self.selected_index).map(|(name, _, _, _)| name.clone()) + display_lines.get(self.selected_index).map(|(_, _, _, _, raw_name)| raw_name.clone()) } /// Get total count of selectable services (parent services only, not sub-services) @@ -475,8 +478,8 @@ impl ServicesWidget { /// Render services list with pending transitions awareness fn render_services_with_transitions(&mut self, frame: &mut Frame, area: Rect, is_focused: bool, scroll_offset: usize, pending_transitions: &HashMap) { - // Build hierarchical service list for display (same as existing logic) - let mut display_lines: Vec<(String, Status, bool, Option<(ServiceInfo, bool)>)> = Vec::new(); + // Build hierarchical service list for display - include raw service name for pending transition lookups + let mut display_lines: Vec<(String, Status, bool, Option<(ServiceInfo, bool)>, String)> = Vec::new(); // Added raw service name // Sort parent services alphabetically for consistent order let mut parent_services: Vec<_> = self.parent_services.iter().collect(); @@ -485,7 +488,7 @@ impl ServicesWidget { for (parent_name, parent_info) in parent_services { // Add parent service line let parent_line = self.format_parent_service_line(parent_name, parent_info); - display_lines.push((parent_line, parent_info.widget_status, false, None)); // false = not sub-service + display_lines.push((parent_line, parent_info.widget_status, false, None, parent_name.clone())); // Include raw name // Add sub-services for this parent (if any) if let Some(sub_list) = self.sub_services.get(parent_name) { @@ -495,12 +498,14 @@ impl ServicesWidget { for (i, (sub_name, sub_info)) in sorted_subs.iter().enumerate() { let is_last_sub = i == sorted_subs.len() - 1; + let full_sub_name = format!("{}_{}", parent_name, sub_name); // Store sub-service info for custom span rendering display_lines.push(( sub_name.clone(), sub_info.widget_status, true, Some((sub_info.clone(), is_last_sub)), + full_sub_name, // Raw service name for pending transition lookup )); // true = sub-service, with is_last info } } @@ -533,7 +538,7 @@ impl ServicesWidget { .constraints(vec![Constraint::Length(1); lines_to_show]) .split(area); - for (i, (line_text, line_status, is_sub, sub_info)) in visible_lines.iter().enumerate() + for (i, (line_text, line_status, is_sub, sub_info, raw_service_name)) in visible_lines.iter().enumerate() { let actual_index = effective_scroll + i; // Real index in the full list @@ -551,12 +556,20 @@ impl ServicesWidget { let (service_info, is_last) = sub_info.as_ref().unwrap(); self.create_sub_service_spans_with_transitions(line_text, service_info, *is_last, pending_transitions) } else { - // Parent services - TEMPORARY DEBUG: always show arrow for testing - if line_text == "sshd" { + // Parent services - check if this parent service has a pending transition using RAW service name + if pending_transitions.contains_key(raw_service_name) { + // Create spans with transitional status + let (icon, status_text, status_color) = self.get_service_icon_and_status(raw_service_name, &ServiceInfo { + status: "".to_string(), + memory_mb: None, + disk_gb: None, + latency_ms: None, + widget_status: *line_status + }, pending_transitions); vec![ - ratatui::text::Span::styled("↑ ".to_string(), Style::default().fg(Theme::highlight())), + ratatui::text::Span::styled(format!("{} ", icon), Style::default().fg(status_color)), ratatui::text::Span::styled(line_text.clone(), Style::default().fg(Theme::primary_text())), - ratatui::text::Span::styled(" starting".to_string(), Style::default().fg(Theme::highlight())), + ratatui::text::Span::styled(format!(" {}", status_text), Style::default().fg(status_color)), ] } else { StatusIcons::create_status_spans(*line_status, line_text) @@ -566,7 +579,7 @@ impl ServicesWidget { // Apply selection highlighting to parent services only, preserving status icon color // Only show selection when Services panel is focused // IMPORTANT: Don't override transitional icons that show pending commands - if is_selected && !*is_sub && is_focused && !pending_transitions.contains_key(line_text) { + if is_selected && !*is_sub && is_focused && !pending_transitions.contains_key(raw_service_name) { for (i, span) in spans.iter_mut().enumerate() { if i == 0 { // First span is the status icon - preserve its color diff --git a/shared/Cargo.toml b/shared/Cargo.toml index 0b9779f..134bb2a 100644 --- a/shared/Cargo.toml +++ b/shared/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cm-dashboard-shared" -version = "0.1.27" +version = "0.1.28" edition = "2021" [dependencies]