125 lines
3.5 KiB
Python
125 lines
3.5 KiB
Python
"""Flow backup warning modal for OpenRAG TUI."""
|
|
|
|
from textual.app import ComposeResult
|
|
from textual.containers import Container, Horizontal, Vertical
|
|
from textual.screen import ModalScreen
|
|
from textual.widgets import Button, Static, Label, Checkbox
|
|
|
|
|
|
class FlowBackupWarningModal(ModalScreen[tuple[bool, bool]]):
|
|
"""Modal dialog to warn about flow backups before upgrade/reset.
|
|
|
|
Returns tuple of (continue, delete_backups)
|
|
"""
|
|
|
|
DEFAULT_CSS = """
|
|
FlowBackupWarningModal {
|
|
align: center middle;
|
|
}
|
|
|
|
#dialog {
|
|
width: 70;
|
|
height: auto;
|
|
border: solid #3f3f46;
|
|
background: #27272a;
|
|
padding: 0;
|
|
}
|
|
|
|
#title {
|
|
background: #3f3f46;
|
|
color: #fafafa;
|
|
padding: 1 2;
|
|
text-align: center;
|
|
width: 100%;
|
|
text-style: bold;
|
|
}
|
|
|
|
#message {
|
|
padding: 2;
|
|
color: #fafafa;
|
|
text-align: center;
|
|
}
|
|
|
|
#checkbox-container {
|
|
width: 100%;
|
|
height: auto;
|
|
align: center middle;
|
|
padding: 0 2;
|
|
}
|
|
|
|
#delete-backups-checkbox {
|
|
width: auto;
|
|
}
|
|
|
|
#button-row {
|
|
width: 100%;
|
|
height: auto;
|
|
align: center middle;
|
|
padding: 1;
|
|
margin-top: 1;
|
|
}
|
|
|
|
#button-row Button {
|
|
margin: 0 1;
|
|
min-width: 16;
|
|
background: #27272a;
|
|
color: #fafafa;
|
|
border: round #52525b;
|
|
text-style: none;
|
|
tint: transparent 0%;
|
|
}
|
|
|
|
#button-row Button:hover {
|
|
background: #27272a !important;
|
|
color: #fafafa !important;
|
|
border: round #52525b;
|
|
tint: transparent 0%;
|
|
text-style: none;
|
|
}
|
|
|
|
#button-row Button:focus {
|
|
background: #27272a !important;
|
|
color: #fafafa !important;
|
|
border: round #ec4899;
|
|
tint: transparent 0%;
|
|
text-style: none;
|
|
}
|
|
"""
|
|
|
|
def __init__(self, operation: str = "upgrade"):
|
|
"""Initialize the warning modal.
|
|
|
|
Args:
|
|
operation: The operation being performed ("upgrade" or "reset")
|
|
"""
|
|
super().__init__()
|
|
self.operation = operation
|
|
|
|
def compose(self) -> ComposeResult:
|
|
"""Create the modal dialog layout."""
|
|
with Container(id="dialog"):
|
|
yield Label("⚠ Flow Backups Detected", id="title")
|
|
yield Static(
|
|
f"Flow backups found in your flows/backup directory.\n\n"
|
|
f"Proceeding with {self.operation} will reset custom flows to defaults.\n"
|
|
f"Your customizations are backed up in the flows/backup/ directory.\n\n"
|
|
f"Choose whether to keep or delete the backup files:",
|
|
id="message"
|
|
)
|
|
with Vertical(id="checkbox-container"):
|
|
yield Checkbox("Delete backup files", id="delete-backups-checkbox", value=False)
|
|
with Horizontal(id="button-row"):
|
|
yield Button("Cancel", id="cancel-btn")
|
|
yield Button(f"Continue {self.operation.title()}", id="continue-btn")
|
|
|
|
def on_mount(self) -> None:
|
|
"""Focus the cancel button by default for safety."""
|
|
self.query_one("#cancel-btn", Button).focus()
|
|
|
|
def on_button_pressed(self, event: Button.Pressed) -> None:
|
|
"""Handle button presses."""
|
|
if event.button.id == "continue-btn":
|
|
delete_backups = self.query_one("#delete-backups-checkbox", Checkbox).value
|
|
self.dismiss((True, delete_backups)) # User wants to continue, with delete preference
|
|
else:
|
|
self.dismiss((False, False)) # User cancelled
|