From 4bd321e7c0e62c4aa9572f9940c37c03a730e2e9 Mon Sep 17 00:00:00 2001 From: Edwin Jose Date: Fri, 19 Dec 2025 15:10:45 -0500 Subject: [PATCH 1/2] Handle legacy TUI config directory cleanup Added support for deleting and recreating the legacy TUI config directory (~/.openrag/tui/config/) during the config reset process. This ensures old configuration files are properly removed alongside the current config directory. --- src/tui/managers/env_manager.py | 1 + src/tui/screens/monitor.py | 10 ++++++++++ 2 files changed, 11 insertions(+) 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: From 6812e525101d75a12f4cfab875a523073486b58a Mon Sep 17 00:00:00 2001 From: Edwin Jose Date: Fri, 19 Dec 2025 15:35:26 -0500 Subject: [PATCH 2/2] Add refresh action to WelcomeScreen Introduces a new 'r' key binding to refresh the service state and update the welcome screen. The refresh action asynchronously checks the status of container and native services, updates OAuth config state, and refreshes the UI to ensure consistency between displayed text and button states. --- src/tui/screens/welcome.py | 65 +++++++++++++++++++++++++++++++------- 1 file changed, 53 insertions(+), 12 deletions(-) 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())