Files
rag-manager/ingest_pipeline/cli/tui/widgets/tables.py
2025-09-15 12:35:42 -04:00

127 lines
4.8 KiB
Python

"""Enhanced DataTable with improved keyboard navigation."""
from typing import Any
from textual import events
from textual.binding import Binding
from textual.message import Message
from textual.widgets import DataTable
class EnhancedDataTable(DataTable[Any]):
"""DataTable with enhanced keyboard navigation and visual feedback."""
BINDINGS = [
Binding("up,k", "cursor_up", "Cursor Up", show=False),
Binding("down,j", "cursor_down", "Cursor Down", show=False),
Binding("left,h", "cursor_left", "Cursor Left", show=False),
Binding("right,l", "cursor_right", "Cursor Right", show=False),
Binding("home", "cursor_home", "First Row", show=False),
Binding("end", "cursor_end", "Last Row", show=False),
Binding("pageup", "page_up", "Page Up", show=False),
Binding("pagedown", "page_down", "Page Down", show=False),
Binding("enter", "select_cursor", "Select", show=False),
Binding("space", "toggle_selection", "Toggle Selection", show=False),
Binding("ctrl+a", "select_all", "Select All", show=False),
Binding("ctrl+shift+a", "clear_selection", "Clear Selection", show=False),
]
def __init__(self, **kwargs: Any) -> None:
super().__init__(**kwargs)
self.cursor_type = "row" # Default to row selection
self.zebra_stripes = True # Enable zebra striping for better visibility
self.show_cursor = True
def on_key(self, event: events.Key) -> None:
"""Handle additional keyboard shortcuts."""
if event.key == "ctrl+1":
# Jump to first column
self.move_cursor(column=0)
event.prevent_default()
elif event.key == "ctrl+9":
# Jump to last column
if self.columns:
self.move_cursor(column=len(self.columns) - 1)
event.prevent_default()
elif event.key == "/":
# Start quick search (to be implemented by parent)
self.post_message(self.QuickSearch(self))
event.prevent_default()
elif event.key == "escape":
# Clear selection or exit search
# Clear selection by calling action
self.action_clear_selection()
event.prevent_default()
# No else clause needed - just handle our events
def action_cursor_home(self) -> None:
"""Move cursor to first row."""
if self.row_count > 0:
self.move_cursor(row=0)
def action_cursor_end(self) -> None:
"""Move cursor to last row."""
if self.row_count > 0:
self.move_cursor(row=self.row_count - 1)
def action_page_up(self) -> None:
"""Move cursor up by visible page size."""
if self.row_count > 0:
page_size = max(1, self.size.height // 2) # Approximate visible rows
new_row = max(0, self.cursor_coordinate.row - page_size)
self.move_cursor(row=new_row)
def action_page_down(self) -> None:
"""Move cursor down by visible page size."""
if self.row_count > 0:
page_size = max(1, self.size.height // 2) # Approximate visible rows
new_row = min(self.row_count - 1, self.cursor_coordinate.row + page_size)
self.move_cursor(row=new_row)
def action_toggle_selection(self) -> None:
"""Toggle selection of current row."""
if self.row_count > 0:
current_row = self.cursor_coordinate.row
# This will be handled by the parent screen
self.post_message(self.RowToggled(self, current_row))
def action_select_all(self) -> None:
"""Select all rows."""
# This will be handled by the parent screen
self.post_message(self.SelectAll(self))
def action_clear_selection(self) -> None:
"""Clear all selections."""
# This will be handled by the parent screen
self.post_message(self.ClearSelection(self))
# Custom messages for enhanced functionality
class QuickSearch(Message):
"""Posted when user wants to start a quick search."""
def __init__(self, table: "EnhancedDataTable") -> None:
super().__init__()
self.table = table
class RowToggled(Message):
"""Posted when a row selection is toggled."""
def __init__(self, table: "EnhancedDataTable", row_index: int) -> None:
super().__init__()
self.table = table
self.row_index = row_index
class SelectAll(Message):
"""Posted when user wants to select all rows."""
def __init__(self, table: "EnhancedDataTable") -> None:
super().__init__()
self.table = table
class ClearSelection(Message):
"""Posted when user wants to clear selection."""
def __init__(self, table: "EnhancedDataTable") -> None:
super().__init__()
self.table = table