WIP - making screens common

This commit is contained in:
rajeevrajeshuni 2025-11-29 22:40:58 +05:30
parent 7670c3c172
commit ba6ee4a10a
8 changed files with 157 additions and 279 deletions

View file

@ -18,62 +18,10 @@ class AddTUIScreen(BaseTUIScreen):
]
CSS = BaseTUIScreen.CSS + """
AddTUIScreen {
background: $surface;
}
#add-container {
height: auto;
padding: 1;
content-align: center middle;
}
#add-form {
width: 100%;
height: auto;
border: solid $primary;
padding: 2;
background: $surface;
}
#form-title {
text-align: center;
width: 100%;
text-style: bold;
color: $accent;
margin-bottom: 2;
}
.field-label {
color: $text-muted;
margin-top: 1;
margin-bottom: 1;
}
Input {
width: 100%;
margin-bottom: 1;
}
#data-input {
height: 8;
min-height: 8;
}
#status-message {
margin-top: 2;
text-align: center;
height: auto;
}
#add-footer {
dock: bottom;
padding: 1 0;
background: $boost;
color: $text-muted;
content-align: center middle;
border: solid $primary;
}
"""
def __init__(self):
@ -81,27 +29,27 @@ class AddTUIScreen(BaseTUIScreen):
self.is_processing = False
def compose_content(self) -> ComposeResult:
with Container(id="add-container"):
yield Label("Add Data to Cognee", id="form-title")
with Vertical(id="add-form"):
yield Label("Data (text, file path, URL, or S3 path):", classes="field-label")
with Container(classes="tui-content-container"):
yield Label("Add Data to Cognee", classes="tui-title")
with Vertical(classes="tui-form"):
yield Label("Data (text, file path, URL, or S3 path):", classes="tui-label-spaced")
yield TextArea(
"",
id="data-input",
)
yield Label("Dataset Name:", classes="field-label")
yield Label("Dataset Name:", classes="tui-label-spaced")
yield Input(
placeholder="main_dataset",
value="main_dataset",
id="dataset-input"
)
yield Static("", id="status-message")
yield Static("", classes="tui-status")
def compose_footer(self) -> ComposeResult:
yield Static(
"Ctrl+S: Add • Esc: Back • q: Quit",
id="add-footer"
classes="tui-footer"
)
def on_mount(self) -> None:
@ -136,7 +84,7 @@ class AddTUIScreen(BaseTUIScreen):
"""Process and submit the data."""
data_input = self.query_one("#data-input", TextArea)
dataset_input = self.query_one("#dataset-input", Input)
status = self.query_one("#status-message", Static)
status = self.query_one(".tui-status", Static)
data = data_input.text.strip()
dataset_name = dataset_input.value.strip() or "main_dataset"
@ -158,7 +106,7 @@ class AddTUIScreen(BaseTUIScreen):
async def _add_data_async(self, data: str, dataset_name: str) -> None:
"""Async function to add data to cognee."""
status = self.query_one("#status-message", Static)
status = self.query_one(".tui-status", Static)
try:
import cognee

View file

@ -3,13 +3,14 @@ from textual.app import ComposeResult
from textual.widgets import Static
from cognee.version import get_cognee_version
from cognee.cli.tui.common_styles import COMMON_STYLES
class BaseTUIScreen(Screen):
"""Base screen class with constant header for all TUI screens."""
# Subclasses should override this CSS and add their own styles
CSS = """
CSS = COMMON_STYLES + """
#header {
dock: top;
background: $boost;

View file

@ -18,43 +18,6 @@ class CognifyTUIScreen(BaseTUIScreen):
]
CSS = BaseTUIScreen.CSS + """
CognifyTUIScreen {
background: $surface;
}
#cognify-container {
height: auto;
padding: 1;
content-align: center middle;
}
#cognify-form {
width: 100%;
height: auto;
border: solid $primary;
padding: 2;
background: $surface;
}
#form-title {
text-align: center;
width: 100%;
text-style: bold;
color: $accent;
margin-bottom: 2;
}
.field-label {
color: $text-muted;
margin-top: 1;
margin-bottom: 1;
}
Input {
width: 100%;
margin-bottom: 1;
}
Checkbox {
margin-top: 1;
margin-bottom: 1;
@ -69,21 +32,6 @@ class CognifyTUIScreen(BaseTUIScreen):
RadioButton {
height: 1;
}
#status-message {
margin-top: 2;
text-align: center;
height: auto;
}
#cognify-footer {
dock: bottom;
padding: 1 0;
background: $boost;
color: $text-muted;
content-align: center middle;
border: solid $primary;
}
"""
def __init__(self):
@ -91,28 +39,28 @@ class CognifyTUIScreen(BaseTUIScreen):
self.is_processing = False
def compose_content(self) -> ComposeResult:
with Container(id="cognify-container"):
yield Label("⚡ Cognify Data", id="form-title")
with Vertical(id="cognify-form"):
yield Label("Dataset Name (optional, leave empty for all):", classes="field-label")
with Container(classes="tui-content-container"):
yield Label("⚡ Cognify Data", classes="tui-title")
with Vertical(classes="tui-form"):
yield Label("Dataset Name (optional, leave empty for all):", classes="tui-label-spaced")
yield Input(
placeholder="Leave empty to process all datasets",
value="",
id="dataset-input"
)
yield Label("Chunker Type:", classes="field-label")
yield Label("Chunker Type:", classes="tui-label-spaced")
with RadioSet(id="chunker-radio"):
for chunker in CHUNKER_CHOICES:
yield RadioButton(chunker, value=(chunker == "TextChunker"))
yield Checkbox("Run in background", id="background-checkbox")
yield Static("", id="status-message")
yield Static("", classes="tui-status")
def compose_footer(self) -> ComposeResult:
yield Static(
"Ctrl+S: Start • Esc: Back • q: Quit",
id="cognify-footer"
classes="tui-footer"
)
def on_mount(self) -> None:
@ -144,7 +92,7 @@ class CognifyTUIScreen(BaseTUIScreen):
dataset_input = self.query_one("#dataset-input", Input)
chunker_radio = self.query_one("#chunker-radio", RadioSet)
background_checkbox = self.query_one("#background-checkbox", Checkbox)
status = self.query_one("#status-message", Static)
status = self.query_one(".tui-status", Static)
dataset_name = dataset_input.value.strip() or None
chunker_type = str(chunker_radio.pressed_button.label) if chunker_radio.pressed_button else "TextChunker"
@ -164,7 +112,7 @@ class CognifyTUIScreen(BaseTUIScreen):
async def _cognify_async(self, dataset_name: str | None, chunker_type: str, run_background: bool) -> None:
"""Async function to cognify data."""
status = self.query_one("#status-message", Static)
status = self.query_one(".tui-status", Static)
try:
import cognee

View file

@ -0,0 +1,113 @@
"""Common CSS styles for TUI screens to reduce repetition."""
COMMON_STYLES = """
/* Common screen background */
Screen {
background: $surface;
}
/* Common container styles */
.tui-container {
height: 100%;
padding: 1;
}
.tui-content-container {
height: auto;
padding: 1;
content-align: center middle;
}
.tui-form {
width: 100%;
height: auto;
border: solid $primary;
padding: 2;
background: $surface;
}
.tui-form-compact {
border: solid $primary;
padding: 1;
background: $surface;
}
/* Common title styles */
.tui-title {
text-align: center;
text-style: bold;
color: $accent;
margin-bottom: 2;
width: 100%;
}
/* Common label styles */
.tui-label {
color: $text-muted;
margin-bottom: 1;
}
.tui-label-spaced {
color: $text-muted;
margin-top: 1;
margin-bottom: 1;
}
/* Common input styles */
Input {
width: 100%;
margin-bottom: 1;
}
/* Common button styles */
Button {
margin: 0 1;
}
/* Common status message styles */
.tui-status {
text-align: center;
margin-top: 2;
height: auto;
}
/* Common footer styles */
.tui-footer {
dock: bottom;
padding: 1 0;
background: $boost;
color: $text-muted;
content-align: center middle;
border: solid $primary;
}
/* Common dialog/modal styles */
.tui-dialog {
border: thick $warning;
background: $surface;
padding: 2;
}
.tui-dialog-title {
text-align: center;
text-style: bold;
color: $warning;
margin-bottom: 1;
}
.tui-dialog-message {
text-align: center;
margin-bottom: 1;
}
.tui-dialog-buttons {
align: center middle;
height: 3;
}
/* Common input group styles */
.tui-input-group {
height: auto;
margin-bottom: 2;
}
"""

View file

@ -34,26 +34,10 @@ class ConfirmModal(Screen):
padding: 1 2;
}
#confirm-title {
text-align: center;
text-style: bold;
color: $warning;
margin-bottom: 1;
}
#confirm-message {
text-align: center;
margin-bottom: 2;
}
#confirm-buttons {
align: center middle;
height: 3;
}
Button {
margin: 0 1;
}
"""
def __init__(self, key: str, default_value: str):
@ -63,10 +47,10 @@ class ConfirmModal(Screen):
def compose(self) -> ComposeResult:
with Container(id="confirm-dialog"):
yield Label("⚠ Reset Configuration", id="confirm-title")
yield Label("⚠ Reset Configuration", classes="tui-dialog-title")
yield Label(f"Reset '{self.key}' to default?", id="confirm-message")
yield Label(f"Default value: {self.default_value}", id="confirm-message")
with Horizontal(id="confirm-buttons"):
with Horizontal(classes="tui-dialog-buttons"):
yield Button("Reset", variant="error", id="confirm-btn")
yield Button("Cancel", variant="default", id="cancel-btn")
@ -94,10 +78,6 @@ class ConfigTUIScreen(BaseTUIScreen):
]
CSS = BaseTUIScreen.CSS + """
ConfigTUIScreen {
background: $surface;
}
#config-container {
height: 100%;
border: solid $primary;
@ -127,15 +107,6 @@ class ConfigTUIScreen(BaseTUIScreen):
#inline-input {
width: 100%;
}
#config-footer {
dock: bottom;
padding: 1 0;
background: $boost;
color: $text-muted;
content-align: center middle;
border: solid $primary;
}
"""
# Config key mappings with defaults (from existing config.py)
@ -158,6 +129,7 @@ class ConfigTUIScreen(BaseTUIScreen):
def compose_content(self) -> ComposeResult:
with Container(id="config-container"):
yield Static("⚙️ Change Config", classes="tui-title")
table = DataTable()
table.cursor_type = "row"
table.zebra_stripes = True
@ -169,7 +141,7 @@ class ConfigTUIScreen(BaseTUIScreen):
def compose_footer(self) -> ComposeResult:
yield Static(
"↑↓: Navigate • e: Edit • Enter: Save • r: Reset • Esc: Back • q: Quit",
id="config-footer"
classes="tui-footer"
)
def on_mount(self) -> None:

View file

@ -19,10 +19,6 @@ class DeleteTUIScreen(BaseTUIScreen):
]
CSS = BaseTUIScreen.CSS + """
DeleteTUIScreen {
background: $surface;
}
#delete-container {
height: auto;
padding: 2;
@ -31,33 +27,6 @@ class DeleteTUIScreen(BaseTUIScreen):
#delete-form {
width: 80;
height: auto;
border: solid $primary;
background: $surface;
padding: 2;
}
#form-title {
text-align: center;
text-style: bold;
color: $accent;
margin-bottom: 2;
width: 100%;
}
.input-group {
height: auto;
margin-bottom: 2;
}
.input-label {
color: $text-muted;
margin-bottom: 1;
}
Input {
width: 100%;
margin-bottom: 1;
}
#button-group {
@ -65,25 +34,6 @@ class DeleteTUIScreen(BaseTUIScreen):
align: center middle;
margin-top: 2;
}
Button {
margin: 0 1;
}
#status-message {
text-align: center;
margin-top: 2;
height: auto;
}
#delete-footer {
dock: bottom;
padding: 1 0;
background: $boost;
color: $text-muted;
content-align: center middle;
border: solid $primary;
}
"""
def __init__(self):
@ -92,18 +42,18 @@ class DeleteTUIScreen(BaseTUIScreen):
def compose_content(self) -> ComposeResult:
with Container(id="delete-container"):
with Vertical(id="delete-form"):
yield Label("🗑️ Delete Data", id="form-title")
with Vertical(id="delete-form", classes="tui-form"):
yield Label("🗑️ Delete Data", classes="tui-title")
with Vertical(classes="input-group"):
yield Label("Dataset Name (optional):", classes="input-label")
with Vertical(classes="tui-input-group"):
yield Label("Dataset Name (optional):", classes="tui-label")
yield Input(
placeholder="Enter dataset name to delete specific dataset",
id="dataset-input"
)
with Vertical(classes="input-group"):
yield Label("User ID (optional):", classes="input-label")
with Vertical(classes="tui-input-group"):
yield Label("User ID (optional):", classes="tui-label")
yield Input(
placeholder="Enter user ID to delete user's data",
id="user-input"
@ -113,12 +63,12 @@ class DeleteTUIScreen(BaseTUIScreen):
yield Button("Delete", variant="error", id="delete-btn")
yield Button("Delete All", variant="error", id="delete-all-btn")
yield Static("", id="status-message")
yield Static("", classes="tui-status")
def compose_footer(self) -> ComposeResult:
yield Static(
"Ctrl+s: Delete • Ctrl+d: Delete All • Esc: Back • q: Quit",
id="delete-footer"
classes="tui-footer"
)
def on_mount(self) -> None:
@ -161,7 +111,7 @@ class DeleteTUIScreen(BaseTUIScreen):
dataset_input = self.query_one("#dataset-input", Input)
user_input = self.query_one("#user-input", Input)
status = self.query_one("#status-message", Static)
status = self.query_one(".tui-status", Static)
dataset_name = dataset_input.value.strip() or None
user_id = user_input.value.strip() or None
@ -224,7 +174,7 @@ class DeleteTUIScreen(BaseTUIScreen):
async def _perform_delete_all(self) -> None:
"""Perform the actual delete all operation."""
status = self.query_one("#status-message", Static)
status = self.query_one(".tui-status", Static)
self.is_processing = True
try:
@ -295,34 +245,20 @@ class DeleteAllConfirmModal(BaseTUIScreen):
margin-bottom: 1;
}
#confirm-message {
text-align: center;
margin-bottom: 1;
}
#confirm-warning {
text-align: center;
color: $warning;
text-style: bold;
margin-bottom: 2;
}
#confirm-buttons {
align: center middle;
height: 3;
}
Button {
margin: 0 1;
}
"""
def compose_content(self) -> ComposeResult:
with Container(id="confirm-dialog"):
yield Label("⚠️ DELETE ALL DATA", id="confirm-title")
yield Label("This will delete ALL data from cognee", id="confirm-message")
yield Label("This will delete ALL data from cognee", classes="tui-dialog-message")
yield Label("This operation is IRREVERSIBLE!", id="confirm-warning")
with Horizontal(id="confirm-buttons"):
with Horizontal(classes="tui-dialog-buttons"):
yield Button("Delete All", variant="error", id="confirm-btn")
yield Button("Cancel", variant="default", id="cancel-btn")

View file

@ -35,10 +35,6 @@ class HomeScreen(BaseTUIScreen):
]
CSS = BaseTUIScreen.CSS + """
HomeScreen {
background: $surface;
}
#main-container {
height: 100%;
border: solid $primary;
@ -64,13 +60,6 @@ class HomeScreen(BaseTUIScreen):
margin-bottom: 2;
}
#title-sub {
text-align: center;
width: auto;
color: $text-muted;
padding-bottom: 1;
margin-bottom: 1;
}
ListView > ListItem {
width: 100%;
@ -144,15 +133,6 @@ class HomeScreen(BaseTUIScreen):
padding-left: 1;
color: $text-muted;
}
#home-footer {
dock: bottom;
padding: 1 0;
background: $boost;
color: $text-muted;
content-align: center middle;
border: solid $primary;
}
"""
def __init__(self):
@ -177,7 +157,7 @@ class HomeScreen(BaseTUIScreen):
def compose_footer(self) -> ComposeResult:
yield Static(
"↑↓: Navigate • Enter: Select • q/Esc: Quit",
id="home-footer"
classes="tui-footer"
)
def on_mount(self) -> None:

View file

@ -17,10 +17,11 @@ class SearchTUIScreen(BaseTUIScreen):
]
CSS = BaseTUIScreen.CSS + """
SearchTUIScreen {
background: $surface;
#search-container {
height: 100%;
padding: 1;
}
#form-title {
text-align: center;
text-style: bold;
@ -29,12 +30,6 @@ class SearchTUIScreen(BaseTUIScreen):
width: 100%;
}
#search-container {
height: 100%;
padding: 1;
}
#search-form {
height: auto;
border: solid $primary;
@ -67,21 +62,6 @@ class SearchTUIScreen(BaseTUIScreen):
height: 1fr;
overflow-y: auto;
}
.field-label {
color: $text-muted;
margin-top: 1;
margin-bottom: 1;
}
#search-footer {
dock: bottom;
padding: 1 0;
background: $boost;
color: $text-muted;
content-align: center middle;
border: solid $primary;
}
"""
def __init__(self):
@ -92,9 +72,9 @@ class SearchTUIScreen(BaseTUIScreen):
with Container(id="search-container"):
yield Label("🔍 Search Data", id="form-title")
with Vertical(id="search-form"):
yield Label("Query:", classes="field-label")
yield Label("Query:", classes="tui-label-spaced")
yield Input(placeholder="Enter your search query...", id="query-input")
yield Label("Search Type:", classes="field-label")
yield Label("Search Type:", classes="tui-label-spaced")
yield Select(
[
("Graph Completion (Recommended)", "GRAPH_COMPLETION"),
@ -114,7 +94,7 @@ class SearchTUIScreen(BaseTUIScreen):
def compose_footer(self) -> ComposeResult:
yield Static(
"Ctrl+S: Search • Esc: Back • q: Quit",
id="search-footer"
classes="tui-footer"
)
def on_mount(self) -> None: