add checkbox for backup deletion and remove explicit time out from toasts

This commit is contained in:
phact 2025-12-03 13:09:43 -05:00
parent 8afd2e4d45
commit 2d0988e6d4
4 changed files with 37 additions and 18 deletions

View file

@ -469,16 +469,17 @@ class MonitorScreen(Screen):
return return
# Check for flow backups before resetting # Check for flow backups before resetting
delete_backups = False
if self._check_flow_backups(): if self._check_flow_backups():
# Show warning modal and wait for user decision # Show warning modal and wait for user decision
should_continue = await self.app.push_screen_wait( should_continue, delete_backups = await self.app.push_screen_wait(
FlowBackupWarningModal(operation="reset") FlowBackupWarningModal(operation="reset")
) )
if not should_continue: if not should_continue:
self.notify("Factory reset cancelled", severity="information") self.notify("Factory reset cancelled", severity="information")
return return
# Clear config, conversations.json, and flow backups first (before stopping containers) # Clear config, conversations.json, and optionally flow backups (before stopping containers)
try: try:
config_path = Path("config") config_path = Path("config")
conversations_file = Path("conversations.json") conversations_file = Path("conversations.json")
@ -492,17 +493,19 @@ class MonitorScreen(Screen):
if conversations_file.exists(): if conversations_file.exists():
conversations_file.unlink() conversations_file.unlink()
# Delete flow backups if they exist # Delete flow backups only if user chose to
if flows_backup_path.exists(): if delete_backups and flows_backup_path.exists():
shutil.rmtree(flows_backup_path) shutil.rmtree(flows_backup_path)
# Recreate empty backup directory # Recreate empty backup directory
flows_backup_path.mkdir(parents=True, exist_ok=True) flows_backup_path.mkdir(parents=True, exist_ok=True)
self.notify("Flow backups deleted", severity="information")
elif flows_backup_path.exists():
self.notify("Flow backups preserved in ./flows/backup", severity="information")
except Exception as e: except Exception as e:
self.notify( self.notify(
f"Error clearing config: {str(e)}", f"Error clearing config: {str(e)}",
severity="error", severity="error",
timeout=10,
) )
return return

View file

@ -9,7 +9,7 @@ def notify_with_diagnostics(
app: App, app: App,
message: str, message: str,
severity: Literal["information", "warning", "error"] = "error", severity: Literal["information", "warning", "error"] = "error",
timeout: float = 10.0, timeout: float | None = None,
) -> None: ) -> None:
"""Show a notification with a button to open the diagnostics screen. """Show a notification with a button to open the diagnostics screen.
@ -17,7 +17,7 @@ def notify_with_diagnostics(
app: The Textual app app: The Textual app
message: The notification message message: The notification message
severity: The notification severity severity: The notification severity
timeout: The notification timeout in seconds timeout: The notification timeout in seconds (None for default 20s)
""" """
# First show the notification # First show the notification
app.notify(message, severity=severity, timeout=timeout) app.notify(message, severity=severity, timeout=timeout)

View file

@ -9,7 +9,7 @@ def notify_with_diagnostics(
app: App, app: App,
message: str, message: str,
severity: Literal["information", "warning", "error"] = "error", severity: Literal["information", "warning", "error"] = "error",
timeout: float = 10.0, timeout: float | None = None,
) -> None: ) -> None:
"""Show a notification with a button to open the diagnostics screen. """Show a notification with a button to open the diagnostics screen.
@ -17,7 +17,7 @@ def notify_with_diagnostics(
app: The Textual app app: The Textual app
message: The notification message message: The notification message
severity: The notification severity severity: The notification severity
timeout: The notification timeout in seconds timeout: The notification timeout in seconds (None for default 20s)
""" """
# First show the notification # First show the notification
app.notify(message, severity=severity, timeout=timeout) app.notify(message, severity=severity, timeout=timeout)

View file

@ -1,13 +1,16 @@
"""Flow backup warning modal for OpenRAG TUI.""" """Flow backup warning modal for OpenRAG TUI."""
from textual.app import ComposeResult from textual.app import ComposeResult
from textual.containers import Container, Horizontal from textual.containers import Container, Horizontal, Vertical
from textual.screen import ModalScreen from textual.screen import ModalScreen
from textual.widgets import Button, Static, Label from textual.widgets import Button, Static, Label, Checkbox
class FlowBackupWarningModal(ModalScreen[bool]): class FlowBackupWarningModal(ModalScreen[tuple[bool, bool]]):
"""Modal dialog to warn about flow backups before upgrade/reset.""" """Modal dialog to warn about flow backups before upgrade/reset.
Returns tuple of (continue, delete_backups)
"""
DEFAULT_CSS = """ DEFAULT_CSS = """
FlowBackupWarningModal { FlowBackupWarningModal {
@ -37,6 +40,17 @@ class FlowBackupWarningModal(ModalScreen[bool]):
text-align: center; text-align: center;
} }
#checkbox-container {
width: 100%;
height: auto;
align: center middle;
padding: 0 2;
}
#delete-backups-checkbox {
width: auto;
}
#button-row { #button-row {
width: 100%; width: 100%;
height: auto; height: auto;
@ -88,11 +102,12 @@ class FlowBackupWarningModal(ModalScreen[bool]):
yield Static( yield Static(
f"Flow backups found in ./flows/backup\n\n" f"Flow backups found in ./flows/backup\n\n"
f"Proceeding with {self.operation} will reset custom flows to defaults.\n" f"Proceeding with {self.operation} will reset custom flows to defaults.\n"
f"Your customizations are backed up and will need to be\n" f"Your customizations are backed up in ./flows/backup/\n\n"
f"manually imported and upgraded to work with the latest version.\n\n" f"Choose whether to keep or delete the backup files:",
f"Do you want to continue?",
id="message" id="message"
) )
with Vertical(id="checkbox-container"):
yield Checkbox("Delete backup files", id="delete-backups-checkbox", value=False)
with Horizontal(id="button-row"): with Horizontal(id="button-row"):
yield Button("Cancel", id="cancel-btn") yield Button("Cancel", id="cancel-btn")
yield Button(f"Continue {self.operation.title()}", id="continue-btn") yield Button(f"Continue {self.operation.title()}", id="continue-btn")
@ -104,6 +119,7 @@ class FlowBackupWarningModal(ModalScreen[bool]):
def on_button_pressed(self, event: Button.Pressed) -> None: def on_button_pressed(self, event: Button.Pressed) -> None:
"""Handle button presses.""" """Handle button presses."""
if event.button.id == "continue-btn": if event.button.id == "continue-btn":
self.dismiss(True) # User wants to continue delete_backups = self.query_one("#delete-backups-checkbox", Checkbox).value
self.dismiss((True, delete_backups)) # User wants to continue, with delete preference
else: else:
self.dismiss(False) # User cancelled self.dismiss((False, False)) # User cancelled