tui: start/stop all services

This commit is contained in:
phact 2025-10-06 12:14:03 -04:00
parent ee0d58a627
commit 14c3a8f3d1

View file

@ -118,9 +118,16 @@ class WelcomeScreen(Screen):
welcome_text.append(ascii_art, style="bold white") welcome_text.append(ascii_art, style="bold white")
welcome_text.append("Terminal User Interface for OpenRAG\n\n", style="dim") welcome_text.append("Terminal User Interface for OpenRAG\n\n", style="dim")
if self.services_running: # Check if all services are running
all_services_running = self.services_running and self.docling_running
if all_services_running:
welcome_text.append( welcome_text.append(
"✓ Services are currently running\n\n", style="bold green" "✓ All services are running\n\n", style="bold green"
)
elif self.services_running or self.docling_running:
welcome_text.append(
"⚠ Some services are running\n\n", style="bold yellow"
) )
elif self.has_oauth_config: elif self.has_oauth_config:
welcome_text.append( welcome_text.append(
@ -140,16 +147,19 @@ class WelcomeScreen(Screen):
buttons = [] buttons = []
if self.services_running: # Check if all services (native + container) are running
# Services running - show app link first, then stop services all_services_running = self.services_running and self.docling_running
if all_services_running:
# All services running - show app link first, then stop all
buttons.append( buttons.append(
Button("Launch OpenRAG", variant="success", id="open-app-btn") Button("Launch OpenRAG", variant="success", id="open-app-btn")
) )
buttons.append( buttons.append(
Button("Stop Container Services", variant="error", id="stop-services-btn") Button("Stop All Services", variant="error", id="stop-all-services-btn")
) )
else: else:
# Services not running - show setup options and start services # Some or no services running - show setup options and start all
if has_oauth: if has_oauth:
# If OAuth is configured, only show advanced setup # If OAuth is configured, only show advanced setup
buttons.append( buttons.append(
@ -165,25 +175,7 @@ class WelcomeScreen(Screen):
) )
buttons.append( buttons.append(
Button("Start Container Services", variant="primary", id="start-services-btn") Button("Start All Services", variant="primary", id="start-all-services-btn")
)
# Native services controls
if self.docling_running:
buttons.append(
Button(
"Stop Native Services",
variant="warning",
id="stop-native-services-btn",
)
)
else:
buttons.append(
Button(
"Start Native Services",
variant="primary",
id="start-native-services-btn",
)
) )
# Always show status option # Always show status option
@ -213,7 +205,7 @@ class WelcomeScreen(Screen):
) )
# Set default button focus # Set default button focus
if self.services_running: if self.services_running and self.docling_running:
self.default_button_id = "open-app-btn" self.default_button_id = "open-app-btn"
elif self.has_oauth_config: elif self.has_oauth_config:
self.default_button_id = "advanced-setup-btn" self.default_button_id = "advanced-setup-btn"
@ -234,7 +226,7 @@ class WelcomeScreen(Screen):
def _focus_appropriate_button(self) -> None: def _focus_appropriate_button(self) -> None:
"""Focus the appropriate button based on current state.""" """Focus the appropriate button based on current state."""
try: try:
if self.services_running: if self.services_running and self.docling_running:
self.query_one("#open-app-btn").focus() self.query_one("#open-app-btn").focus()
elif self.has_oauth_config: elif self.has_oauth_config:
self.query_one("#advanced-setup-btn").focus() self.query_one("#advanced-setup-btn").focus()
@ -253,20 +245,16 @@ class WelcomeScreen(Screen):
self.action_monitor() self.action_monitor()
elif event.button.id == "diagnostics-btn": elif event.button.id == "diagnostics-btn":
self.action_diagnostics() self.action_diagnostics()
elif event.button.id == "start-services-btn": elif event.button.id == "start-all-services-btn":
self.action_start_stop_services() self.action_start_all_services()
elif event.button.id == "stop-services-btn": elif event.button.id == "stop-all-services-btn":
self.action_start_stop_services() self.action_stop_all_services()
elif event.button.id == "start-native-services-btn":
self.action_start_native_services()
elif event.button.id == "stop-native-services-btn":
self.action_stop_native_services()
elif event.button.id == "open-app-btn": elif event.button.id == "open-app-btn":
self.action_open_app() self.action_open_app()
def action_default_action(self) -> None: def action_default_action(self) -> None:
"""Handle Enter key - go to default action based on state.""" """Handle Enter key - go to default action based on state."""
if self.services_running: if self.services_running and self.docling_running:
self.action_open_app() self.action_open_app()
elif self.has_oauth_config: elif self.has_oauth_config:
self.action_full_setup() self.action_full_setup()
@ -297,28 +285,13 @@ class WelcomeScreen(Screen):
self.app.push_screen(DiagnosticsScreen()) self.app.push_screen(DiagnosticsScreen())
def action_start_stop_services(self) -> None: def action_start_all_services(self) -> None:
"""Start or stop all services (containers + docling).""" """Start all services (native first, then containers)."""
if self.services_running: self.run_worker(self._start_all_services())
# Stop services - show modal with progress
if self.container_manager.is_available(): def action_stop_all_services(self) -> None:
command_generator = self.container_manager.stop_services() """Stop all services (containers first, then native)."""
modal = CommandOutputModal( self.run_worker(self._stop_all_services())
"Stopping Services",
command_generator,
on_complete=self._on_services_operation_complete,
)
self.app.push_screen(modal)
else:
# Start services - show modal with progress
if self.container_manager.is_available():
command_generator = self.container_manager.start_services()
modal = CommandOutputModal(
"Starting Services",
command_generator,
on_complete=self._on_services_operation_complete,
)
self.app.push_screen(modal)
async def _on_services_operation_complete(self) -> None: async def _on_services_operation_complete(self) -> None:
"""Handle completion of services start/stop operation.""" """Handle completion of services start/stop operation."""
@ -334,7 +307,7 @@ class WelcomeScreen(Screen):
def _update_default_button(self) -> None: def _update_default_button(self) -> None:
"""Update the default button target based on state.""" """Update the default button target based on state."""
if self.services_running: if self.services_running and self.docling_running:
self.default_button_id = "open-app-btn" self.default_button_id = "open-app-btn"
elif self.has_oauth_config: elif self.has_oauth_config:
self.default_button_id = "advanced-setup-btn" self.default_button_id = "advanced-setup-btn"
@ -362,51 +335,74 @@ class WelcomeScreen(Screen):
self.call_after_refresh(self._focus_appropriate_button) self.call_after_refresh(self._focus_appropriate_button)
def action_start_native_services(self) -> None: async def _start_all_services(self) -> None:
"""Start native services (docling).""" """Start all services: native first, then containers."""
if self.docling_running: # Step 1: Start native services (docling-serve)
self.notify("Native services are already running.", severity="warning") if not self.docling_manager.is_running():
return self.notify("Starting native services...", severity="information")
self.run_worker(self._start_native_services())
async def _start_native_services(self) -> None:
"""Worker task to start native services."""
try:
success, message = await self.docling_manager.start() success, message = await self.docling_manager.start()
if success: if success:
self.docling_running = True
self.notify(message, severity="information") self.notify(message, severity="information")
else: else:
self.notify(f"Failed to start native services: {message}", severity="error") self.notify(f"Failed to start native services: {message}", severity="error")
except Exception as exc: # Continue anyway - user might want containers even if native fails
self.notify(f"Error starting native services: {exc}", severity="error") else:
finally: self.notify("Native services already running", severity="information")
self.docling_running = self.docling_manager.is_running()
# Update state
self.docling_running = self.docling_manager.is_running()
# Step 2: Start container services
if self.container_manager.is_available():
command_generator = self.container_manager.start_services()
modal = CommandOutputModal(
"Starting Container Services",
command_generator,
on_complete=self._on_services_operation_complete,
)
self.app.push_screen(modal)
else:
self.notify("No container runtime available", severity="warning")
await self._refresh_welcome_content() await self._refresh_welcome_content()
def action_stop_native_services(self) -> None: async def _stop_all_services(self) -> None:
"""Stop native services (docling).""" """Stop all services: containers first, then native."""
if not self.docling_running and not self.docling_manager.is_running(): # Step 1: Stop container services
self.notify("Native services are not running.", severity="warning") if self.container_manager.is_available() and self.services_running:
return command_generator = self.container_manager.stop_services()
modal = CommandOutputModal(
"Stopping Container Services",
command_generator,
on_complete=self._on_stop_containers_complete,
)
self.app.push_screen(modal)
else:
# No containers to stop, go directly to stopping native services
await self._stop_native_services_after_containers()
self.run_worker(self._stop_native_services()) async def _on_stop_containers_complete(self) -> None:
"""Called after containers are stopped, now stop native services."""
# Update container state
self._detect_services_sync()
async def _stop_native_services(self) -> None: # Now stop native services
"""Worker task to stop native services.""" await self._stop_native_services_after_containers()
try:
async def _stop_native_services_after_containers(self) -> None:
"""Stop native services after containers have been stopped."""
if self.docling_manager.is_running():
self.notify("Stopping native services...", severity="information")
success, message = await self.docling_manager.stop() success, message = await self.docling_manager.stop()
if success: if success:
self.docling_running = False
self.notify(message, severity="information") self.notify(message, severity="information")
else: else:
self.notify(f"Failed to stop native services: {message}", severity="error") self.notify(f"Failed to stop native services: {message}", severity="error")
except Exception as exc: else:
self.notify(f"Error stopping native services: {exc}", severity="error") self.notify("Native services already stopped", severity="information")
finally:
self.docling_running = self.docling_manager.is_running() # Update state
await self._refresh_welcome_content() self.docling_running = self.docling_manager.is_running()
await self._refresh_welcome_content()
def action_open_app(self) -> None: def action_open_app(self) -> None:
"""Open the OpenRAG app in the default browser.""" """Open the OpenRAG app in the default browser."""