Implement rebuild progress indicator with host persistence

- Add blue circular arrow (↻) status icon during SystemRebuild commands
- Keep rebuilding hosts visible in dashboard even when temporarily offline
- Extend connection timeout to 5 minutes for hosts undergoing rebuild
- Prevent host switching during rebuild operations
- Update status bar to show rebuild progress immediately when R key pressed
This commit is contained in:
Christoffer Martinsson 2025-10-25 10:16:39 +02:00
parent 71671a8901
commit c48a105c28
3 changed files with 84 additions and 44 deletions

View File

@ -28,16 +28,18 @@ All keyboard navigation and service selection features successfully implemented:
- ✅ **Smart Panel Switching**: Only cycles through panels with data (backup panel conditional) - ✅ **Smart Panel Switching**: Only cycles through panels with data (backup panel conditional)
- ✅ **Scroll Support**: All panels support content scrolling with proper overflow indicators - ✅ **Scroll Support**: All panels support content scrolling with proper overflow indicators
**Current Status - October 23, 2025:** **Current Status - October 24, 2025:**
- All keyboard navigation features working correctly ✅ - All keyboard navigation features working correctly ✅
- Service selection cursor implemented with focus-aware highlighting ✅ - Service selection cursor implemented with focus-aware highlighting ✅
- Panel scrolling fixed for System, Services, and Backup panels ✅ - Panel scrolling fixed for System, Services, and Backup panels ✅
- Build display working: "Build: 25.05.20251004.3bcc93c" ✅ - Build display working: "Build: 25.05.20251004.3bcc93c" ✅
- Configuration hash display implemented: "Config: d16f0d0" ✅
**Layout Achieved:** **Layout Achieved:**
``` ```
NixOS: NixOS:
Build: 25.05.20251004.3bcc93c # Target (currently shows "unknown") Build: 25.05.20251004.3bcc93c
Config: d16f0d0 # Shows actual nixosbox config hash
Active users: cm, simon Active users: cm, simon
CPU: CPU:
● Load: 0.02 0.31 0.86 • 3000MHz ● Load: 0.02 0.31 0.86 • 3000MHz
@ -50,12 +52,10 @@ Storage:
└─ ● 18% 167.4GB/928.2GB └─ ● 18% 167.4GB/928.2GB
``` ```
**Current Status - October 23, 2025:** **System panel layout fully implemented with blue tree symbols ✅**
- System panel layout fully implemented with blue tree symbols ✅ **Tree symbols now use consistent blue theming across all panels ✅**
- Backup panel layout restructured per specification ✅ **Overflow handling restored for all widgets ("... and X more") ✅**
- Tree symbols now use consistent blue theming across all panels ✅ **Agent hash display working correctly ✅**
- Overflow handling restored for all widgets ("... and X more") ✅
- Agent hash display working correctly ✅
### Current Keyboard Navigation Implementation ### Current Keyboard Navigation Implementation
@ -77,28 +77,24 @@ Storage:
- **Focus-Aware Selection**: Selection highlighting only visible when Services panel focused - **Focus-Aware Selection**: Selection highlighting only visible when Services panel focused
- **Dynamic Statusbar**: Context-aware shortcuts based on focused panel - **Dynamic Statusbar**: Context-aware shortcuts based on focused panel
### Current Priority: Visual Feedback Implementation ### Remote Command Execution - WORKING ✅
**Remote Command Execution - PARTIALLY WORKING** ⚠️ **All Issues Resolved (as of 2025-10-24):**
Core infrastructure implemented but issues remain:
- ✅ **ZMQ Command Protocol**: Extended with ServiceControl and SystemRebuild variants - ✅ **ZMQ Command Protocol**: Extended with ServiceControl and SystemRebuild variants
- ✅ **Agent Handlers**: systemctl and nixos-rebuild execution with maintenance mode - ✅ **Agent Handlers**: systemctl and nixos-rebuild execution with maintenance mode
- ✅ **Dashboard Integration**: Existing keyboard shortcuts now execute commands - ✅ **Dashboard Integration**: Keyboard shortcuts execute commands
- ⚠️ **Service Control**: systemctl commands work but Space key toggle needs fixing - ✅ **Service Control**: Fixed toggle logic - replaced with separate 's' (start) and 'S' (stop)
- ❌ **System Rebuild**: nixos-rebuild still failing with permission denied - ✅ **System Rebuild**: Fixed permission issues and sandboxing problems
- ✅ **Git Clone Approach**: Implemented for nixos-rebuild to avoid directory permissions
**Current Issues (as of 2025-10-23):** - ✅ **Visual Feedback**: Directional arrows for service status (↑ starting, ↓ stopping, ↻ restarting)
1. **Service Toggle Bug**: Space key always sends "Start" instead of toggling start/stop
2. **nixos-rebuild Permissions**: Still getting permission denied despite sudo config updates
3. **No Command Completion**: Visual feedback shows ⏳ but never completes (missing response protocol)
**Keyboard Controls Status:** **Keyboard Controls Status:**
- **Services Panel**: - **Services Panel**:
- R (restart) ✅ Working - R (restart) ✅ Working
- Space (start/stop) ❌ Always starts, doesn't toggle - s (start) ✅ Working
- **System Panel**: R (nixos-rebuild) ❌ Permission denied - S (stop) ✅ Working
- **Backup Panel**: B (trigger backup) ❓ Not tested - **System Panel**: R (nixos-rebuild) ✅ Working with --option sandbox false
- **Backup Panel**: B (trigger backup) ❓ Not implemented
**Visual Feedback Implementation - IN PROGRESS:** **Visual Feedback Implementation - IN PROGRESS:**
@ -126,26 +122,21 @@ Latest backup: → Latest backup:
**Next Session Priority Tasks:** **Next Session Priority Tasks:**
**Critical Fixes Needed:** **Remaining Features:**
1. **Fix Service Toggle Logic**: Debug why Space key service status detection isn't working 1. **Command Response Protocol**:
- Check systemd metric format (`systemd_{service}_status`)
- Test service status parsing logic
- Ensure toggle detects active vs inactive correctly
2. **Resolve nixos-rebuild Permissions**:
- Verify sudo rules are actually applied after NixOS rebuild
- Test `sudo -u cm-agent sudo nixos-rebuild --help` manually
- May need different approach for nixos-rebuild access
3. **Implement Command Response Protocol**:
- Agent sends command completion/failure back to dashboard via ZMQ - Agent sends command completion/failure back to dashboard via ZMQ
- Dashboard updates UI status from ⏳ to ● when commands complete - Dashboard updates UI status from ⏳ to ● when commands complete
- Clear success/failure status after timeout - Clear success/failure status after timeout
**Secondary Tasks:** 2. **Backup Panel Features**:
- Implement backup trigger functionality (B key)
- Complete visual feedback for backup operations
- Add backup progress indicators
**Enhancement Tasks:**
- Add confirmation dialogs for destructive actions (stop/restart/rebuild) - Add confirmation dialogs for destructive actions (stop/restart/rebuild)
- Complete visual feedback for System and Backup panels - Implement command history/logging
- Test backup trigger functionality - Add keyboard shortcuts help overlay
**Future Enhanced Navigation:** **Future Enhanced Navigation:**
- Add Page Up/Down for faster scrolling through long service lists - Add Page Up/Down for faster scrolling through long service lists
@ -155,7 +146,7 @@ Latest backup: → Latest backup:
**Future Advanced Features:** **Future Advanced Features:**
- Service dependency visualization - Service dependency visualization
- Historical service status tracking - Historical service status tracking
- Backup trigger functionality with progress indication - Real-time log viewing integration
## Core Architecture Principles - CRITICAL ## Core Architecture Principles - CRITICAL

View File

@ -238,9 +238,25 @@ impl Dashboard {
// Update TUI with new hosts and metrics (only if not headless) // Update TUI with new hosts and metrics (only if not headless)
if let Some(ref mut tui_app) = self.tui_app { if let Some(ref mut tui_app) = self.tui_app {
let connected_hosts = self let mut connected_hosts = self
.metric_store .metric_store
.get_connected_hosts(Duration::from_secs(30)); .get_connected_hosts(Duration::from_secs(30));
// Add hosts that are rebuilding but may be temporarily disconnected
// Use extended timeout (5 minutes) for rebuilding hosts
let rebuilding_hosts = self
.metric_store
.get_connected_hosts(Duration::from_secs(300));
for host in rebuilding_hosts {
if !connected_hosts.contains(&host) {
// Check if this host is rebuilding in the UI
if tui_app.is_host_rebuilding(&host) {
connected_hosts.push(host);
}
}
}
tui_app.update_hosts(connected_hosts); tui_app.update_hosts(connected_hosts);
tui_app.update_metrics(&self.metric_store); tui_app.update_metrics(&self.metric_store);
} }

View File

@ -226,6 +226,16 @@ impl TuiApp {
pub fn update_hosts(&mut self, hosts: Vec<String>) { pub fn update_hosts(&mut self, hosts: Vec<String>) {
// Sort hosts alphabetically // Sort hosts alphabetically
let mut sorted_hosts = hosts.clone(); let mut sorted_hosts = hosts.clone();
// Keep hosts that are undergoing SystemRebuild even if they're offline
for (hostname, host_widgets) in &self.host_widgets {
if let Some(CommandStatus::InProgress { command_type: CommandType::SystemRebuild, .. }) = &host_widgets.command_status {
if !sorted_hosts.contains(hostname) {
sorted_hosts.push(hostname.clone());
}
}
}
sorted_hosts.sort(); sorted_hosts.sort();
self.available_hosts = sorted_hosts; self.available_hosts = sorted_hosts;
@ -375,6 +385,18 @@ impl TuiApp {
info!("Switched to host: {}", self.current_host.as_ref().unwrap()); info!("Switched to host: {}", self.current_host.as_ref().unwrap());
} }
/// Check if a host is currently rebuilding
pub fn is_host_rebuilding(&self, hostname: &str) -> bool {
if let Some(host_widgets) = self.host_widgets.get(hostname) {
matches!(
&host_widgets.command_status,
Some(CommandStatus::InProgress { command_type: CommandType::SystemRebuild, .. })
)
} else {
false
}
}
/// Switch to next panel (Shift+Tab) - only cycles through visible panels /// Switch to next panel (Shift+Tab) - only cycles through visible panels
pub fn next_panel(&mut self) { pub fn next_panel(&mut self) {
let visible_panels = self.get_visible_panels(); let visible_panels = self.get_visible_panels();
@ -660,10 +682,21 @@ impl TuiApp {
spans.push(Span::styled(" ", Typography::title())); spans.push(Span::styled(" ", Typography::title()));
} }
// Calculate overall host status from metrics // Check if this host has a SystemRebuild command in progress
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); let host_status = self.calculate_host_status(host, metric_store);
let status_icon = StatusIcons::get_icon(host_status); (StatusIcons::get_icon(host_status), Theme::status_color(host_status))
let status_color = Theme::status_color(host_status); }
} else {
// No host widgets yet, use normal status
let host_status = self.calculate_host_status(host, metric_store);
(StatusIcons::get_icon(host_status), Theme::status_color(host_status))
};
// Add status icon // Add status icon
spans.push(Span::styled( spans.push(Span::styled(