diff --git a/src/tui/managers/env_manager.py b/src/tui/managers/env_manager.py index 7724b760..f869e257 100644 --- a/src/tui/managers/env_manager.py +++ b/src/tui/managers/env_manager.py @@ -79,6 +79,7 @@ class EnvConfig: openrag_config_path: str = "$HOME/.openrag/config" openrag_data_path: str = "$HOME/.openrag/data" # Backend data (conversations, tokens, etc.) opensearch_data_path: str = "$HOME/.openrag/data/opensearch-data" + openrag_tui_config_path_legacy: str = "$HOME/.openrag/tui/config" # Container version (linked to TUI version) openrag_version: str = "" diff --git a/src/tui/screens/monitor.py b/src/tui/screens/monitor.py index 570679d8..80e05f15 100644 --- a/src/tui/screens/monitor.py +++ b/src/tui/screens/monitor.py @@ -502,6 +502,16 @@ class MonitorScreen(Screen): # Recreate empty config directory config_path.mkdir(parents=True, exist_ok=True) + # Also delete legacy TUI config folder if it exists (~/.openrag/tui/config/) + tui_config_path = expand_path(env_manager.config.openrag_tui_config_path_legacy) + if tui_config_path.exists(): + success, msg = await self.container_manager.clear_directory_with_container(tui_config_path) + if not success: + # Fallback to regular rmtree if container method fails + shutil.rmtree(tui_config_path) + # Recreate empty config directory + tui_config_path.mkdir(parents=True, exist_ok=True) + # Delete flow backups only if user chose to (and they actually exist) if self._check_flow_backups(): if delete_backups: diff --git a/src/tui/screens/welcome.py b/src/tui/screens/welcome.py index dc017a3a..7c85808c 100644 --- a/src/tui/screens/welcome.py +++ b/src/tui/screens/welcome.py @@ -23,6 +23,7 @@ class WelcomeScreen(Screen): BINDINGS = [ ("q", "quit", "Quit"), + ("r", "refresh", "Refresh"), ] def __init__(self): @@ -305,16 +306,10 @@ class WelcomeScreen(Screen): else: self.default_button_id = "basic-setup-btn" - # Update the welcome text - try: - welcome_widget = self.query_one("#welcome-text") - welcome_widget.update(self._create_welcome_text()) - except: - pass # Widget might not be mounted yet - - # Focus the appropriate button (the buttons are created correctly in compose, - # the issue was they weren't being updated after service operations) - self.call_after_refresh(self._focus_appropriate_button) + # Refresh the welcome text AND buttons based on the updated async state + # This ensures buttons match the actual service state (fixes issue where + # text showed "All services running" but buttons weren't updated) + await self._refresh_welcome_content() def _focus_appropriate_button(self) -> None: """Focus the appropriate button based on current state.""" @@ -341,8 +336,22 @@ class WelcomeScreen(Screen): os.getenv("MICROSOFT_GRAPH_OAUTH_CLIENT_ID") ) - # Re-detect service state - self._detect_services_sync() + # Re-detect container services using async method for accuracy + if self.container_manager.is_available(): + services = await self.container_manager.get_service_status(force_refresh=True) + expected = set(self.container_manager.expected_services) + running_services = [ + s.name for s in services.values() if s.status == ServiceStatus.RUNNING + ] + starting_services = [ + s.name for s in services.values() if s.status == ServiceStatus.STARTING + ] + self.services_running = len(running_services) == len(expected) and len(starting_services) == 0 + else: + self.services_running = False + + # Re-detect native service state + self.docling_running = self.docling_manager.is_running() # Refresh the welcome content and buttons await self._refresh_welcome_content() @@ -397,6 +406,38 @@ class WelcomeScreen(Screen): self.app.push_screen(DiagnosticsScreen()) + def action_refresh(self) -> None: + """Refresh service state and update welcome screen.""" + self.run_worker(self._refresh_state()) + + async def _refresh_state(self) -> None: + """Async refresh of service state.""" + # Re-detect container services using async method for accuracy + if self.container_manager.is_available(): + services = await self.container_manager.get_service_status(force_refresh=True) + expected = set(self.container_manager.expected_services) + running_services = [ + s.name for s in services.values() if s.status == ServiceStatus.RUNNING + ] + starting_services = [ + s.name for s in services.values() if s.status == ServiceStatus.STARTING + ] + self.services_running = len(running_services) == len(expected) and len(starting_services) == 0 + else: + self.services_running = False + + # Re-detect native service state + self.docling_running = self.docling_manager.is_running() + + # Update OAuth config state + self.has_oauth_config = bool(os.getenv("GOOGLE_OAUTH_CLIENT_ID")) or bool( + os.getenv("MICROSOFT_GRAPH_OAUTH_CLIENT_ID") + ) + + # Refresh the welcome content and buttons + await self._refresh_welcome_content() + self.notify("Refreshed", severity="information", timeout=2) + def action_start_all_services(self) -> None: """Start all services (native first, then containers).""" self.run_worker(self._start_all_services())