Improve service selection: preserve status colors and skip sub-services

Selection Behavior Improvements:
- Limit selection to parent services only (docker, nginx, postgresql, etc.)
- Skip sub-services in navigation (no longer select nginx sub-sites)
- Up/Down arrows now move between actionable services only

Visual Enhancement:
- Preserve original status colors in selection highlighting
- Selected services show blue background with status foreground colors
- Green text for active services, red for failed, even when selected
- Maintains visual health status information during selection

Selection Logic:
- Add parent service index mapping for accurate selection tracking
- Only count parent services in total service count
- Calculate proper parent service index from display line position
- Ensure selection highlights only apply to parent services

This creates a cleaner UX where users only select services they can
actually control (start/stop/restart) while maintaining visual health
status indicators through preserved status colors.
This commit is contained in:
Christoffer Martinsson 2025-10-23 21:46:50 +02:00
parent 999e7b5db5
commit 61287380d3

View File

@ -243,19 +243,38 @@ impl ServicesWidget {
display_lines.get(self.selected_index).map(|(name, _, _, _)| name.clone())
}
/// Get total count of services (parent + sub-services)
/// Get total count of selectable services (parent services only, not sub-services)
pub fn get_total_services_count(&self) -> usize {
let mut count = 0;
// Only count parent services - sub-services are not selectable
self.parent_services.len()
}
/// Calculate which parent service index corresponds to a display line index
fn calculate_parent_service_index(&self, display_line_index: &usize) -> usize {
// Build the same display list to map line index to parent service index
let mut parent_index = 0;
let mut line_index = 0;
// Count parent services
count += self.parent_services.len();
// Count sub-services
for sub_list in self.sub_services.values() {
count += sub_list.len();
let mut parent_services: Vec<_> = self.parent_services.iter().collect();
parent_services.sort_by(|(a, _), (b, _)| a.cmp(b));
for (parent_name, _) in parent_services {
if line_index == *display_line_index {
return parent_index;
}
line_index += 1; // Parent service line
// Skip sub-services but count them in line_index
if let Some(sub_list) = self.sub_services.get(parent_name) {
line_index += sub_list.len();
}
parent_index += 1;
}
count
// If we get here, the display_line_index was probably for a sub-service
// Return the last valid parent index (should not happen with our logic)
parent_index.saturating_sub(1)
}
}
@ -481,7 +500,15 @@ impl ServicesWidget {
for (i, (line_text, line_status, is_sub, sub_info)) in visible_lines.iter().enumerate()
{
let actual_index = effective_scroll + i; // Real index in the full list
let is_selected = actual_index == self.selected_index;
// Only parent services can be selected - calculate parent service index
let is_selected = if !*is_sub {
// This is a parent service - count how many parent services came before this one
let parent_index = self.calculate_parent_service_index(&actual_index);
parent_index == self.selected_index
} else {
false // Sub-services are never selected
};
let mut spans = if *is_sub && sub_info.is_some() {
// Use custom sub-service span creation
@ -492,12 +519,11 @@ impl ServicesWidget {
StatusIcons::create_status_spans(*line_status, line_text)
};
// Apply selection highlighting to spans
if is_selected {
// Apply selection highlighting to parent services only, preserving status colors
if is_selected && !*is_sub {
for span in spans.iter_mut() {
span.style = span.style
.bg(Theme::highlight())
.fg(Theme::background());
// Keep the original foreground color (status color) but add background highlight
span.style = span.style.bg(Theme::highlight());
}
}