From c84c1aac2a5102fa972dae3e5d44489b69631817 Mon Sep 17 00:00:00 2001 From: phg Date: Thu, 14 Aug 2025 20:41:12 +0200 Subject: [PATCH] Remove search functionality and related modal from the TUI application to streamline the user interface. --- src/hosts/tui/app.py | 5 - src/hosts/tui/help_modal.py | 4 +- src/hosts/tui/keybindings.py | 1 - src/hosts/tui/search_modal.py | 278 ---------------------------------- 4 files changed, 2 insertions(+), 286 deletions(-) delete mode 100644 src/hosts/tui/search_modal.py diff --git a/src/hosts/tui/app.py b/src/hosts/tui/app.py index f5de683..ab72db3 100644 --- a/src/hosts/tui/app.py +++ b/src/hosts/tui/app.py @@ -460,11 +460,6 @@ class HostsManagerApp(App): self.push_screen(DeleteConfirmationModal(entry), handle_delete_confirmation) - def action_search(self) -> None: - """Focus the search bar for filtering entries.""" - search_input = self.query_one("#search-input", Input) - search_input.focus() - self.update_status("Use the search bar to filter entries") def action_quit(self) -> None: """Quit the application.""" diff --git a/src/hosts/tui/help_modal.py b/src/hosts/tui/help_modal.py index 3c018d7..56249a5 100644 --- a/src/hosts/tui/help_modal.py +++ b/src/hosts/tui/help_modal.py @@ -94,7 +94,7 @@ class HelpModal(ModalScreen): with Vertical(classes="help-section"): yield Static("Main Commands", classes="help-section-title") yield Static( - "[bold]r[/bold] Reload [bold]h[/bold] Help [bold]c[/bold] Config [bold]Ctrl+F[/bold] Search [bold]q[/bold] Quit", + "[bold]r[/bold] Reload [bold]h[/bold] Help [bold]c[/bold] Config [bold]q[/bold] Quit", classes="help-item", ) yield Static( @@ -134,7 +134,7 @@ class HelpModal(ModalScreen): "Special Dialog Commands", classes="help-section-title" ) yield Static( - "[bold]F3[/bold] Search in search dialog [bold]s[/bold] Save changes [bold]d[/bold] Discard changes", + "[bold]s[/bold] Save changes [bold]d[/bold] Discard changes", classes="help-item", ) diff --git a/src/hosts/tui/keybindings.py b/src/hosts/tui/keybindings.py index e333d73..50994e5 100644 --- a/src/hosts/tui/keybindings.py +++ b/src/hosts/tui/keybindings.py @@ -15,7 +15,6 @@ HOSTS_MANAGER_BINDINGS = [ Binding("i", "sort_by_ip", "Sort by IP"), Binding("n", "sort_by_hostname", "Sort by Hostname"), Binding("c", "config", "Config"), - Binding("ctrl+f", "search", "Focus Search"), Binding("ctrl+e", "toggle_edit_mode", "Edit Mode"), Binding("a", "add_entry", "Add Entry", show=False), Binding("d", "delete_entry", "Delete Entry", show=False), diff --git a/src/hosts/tui/search_modal.py b/src/hosts/tui/search_modal.py deleted file mode 100644 index 88ba7fe..0000000 --- a/src/hosts/tui/search_modal.py +++ /dev/null @@ -1,278 +0,0 @@ -""" -Search modal window for the hosts TUI application. - -This module provides a floating search window for finding entries by hostname or IP address. -""" - -from textual.app import ComposeResult -from textual.containers import Vertical, Horizontal -from textual.widgets import Static, Button, Input, DataTable, Label -from textual.screen import ModalScreen -from textual.binding import Binding - -from ..core.models import HostEntry - - -class SearchModal(ModalScreen): - """ - Modal screen for searching host entries. - - Provides a search interface and displays matching results. - """ - - CSS = """ - SearchModal { - align: center middle; - } - - .search-container { - width: 90; - height: 30; - background: $surface; - border: thick $primary; - padding: 1; - } - - .search-title { - text-align: center; - text-style: bold; - color: $primary; - margin-bottom: 1; - } - - .search-section { - margin: 1 0; - } - - .search-input { - margin: 0 2; - width: 1fr; - } - - .results-section { - margin: 1 0; - height: 15; - } - - .search-results { - margin: 0 2; - height: 13; - } - - .button-row { - margin-top: 1; - align: center middle; - } - - .search-button { - margin: 0 1; - min-width: 10; - } - - .results-info { - margin: 0 2; - color: $text-muted; - text-style: italic; - } - """ - - BINDINGS = [ - Binding("escape", "cancel", "Cancel"), - Binding("enter", "select", "Select"), - Binding("f3", "search", "Search"), - ] - - def __init__(self, entries): - super().__init__() - self.entries = entries - self.search_results = [] - - def compose(self) -> ComposeResult: - """Create the search modal layout.""" - with Vertical(classes="search-container"): - yield Static("Search Host Entries", classes="search-title") - - with Vertical(classes="search-section"): - yield Label("Search term (hostname or IP address):") - yield Input( - placeholder="e.g., example.com or 192.168.1.1", - id="search-input", - classes="search-input", - ) - - with Vertical(classes="results-section"): - yield Static("Search Results:", classes="results-info") - yield DataTable( - id="search-results-table", - classes="search-results", - show_header=True, - zebra_stripes=True, - ) - - with Horizontal(classes="button-row"): - yield Button( - "Search", - variant="primary", - id="search-button", - classes="search-button", - ) - yield Button( - "Select", - variant="success", - id="select-button", - classes="search-button", - ) - yield Button( - "Close", - variant="default", - id="close-button", - classes="search-button", - ) - - def on_mount(self) -> None: - """Initialize the search results table and focus search input.""" - # Set up the results table - results_table = self.query_one("#search-results-table", DataTable) - results_table.add_column("IP Address", key="ip") - results_table.add_column("Canonical Hostname", key="hostname") - results_table.add_column("Status", key="status") - results_table.add_column("Comment", key="comment") - - # Focus search input - search_input = self.query_one("#search-input", Input) - search_input.focus() - - # Disable select button initially - select_button = self.query_one("#select-button", Button) - select_button.disabled = True - - def on_button_pressed(self, event: Button.Pressed) -> None: - """Handle button presses.""" - if event.button.id == "search-button": - self.action_search() - elif event.button.id == "select-button": - self.action_select() - elif event.button.id == "close-button": - self.action_cancel() - - def on_input_submitted(self, event: Input.Submitted) -> None: - """Handle enter key in search input.""" - if event.input.id == "search-input": - self.action_search() - - def on_data_table_row_selected(self, event: DataTable.RowSelected) -> None: - """Handle row selection in results table.""" - if event.data_table.id == "search-results-table": - # Enable select button when a row is selected - select_button = self.query_one("#select-button", Button) - select_button.disabled = False - - def action_search(self) -> None: - """Perform search based on input.""" - search_input = self.query_one("#search-input", Input) - search_term = search_input.value.strip().lower() - - if not search_term: - self._update_results_info("Please enter a search term") - return - - # Perform search - self.search_results = self._search_entries(search_term) - - # Update results table - results_table = self.query_one("#search-results-table", DataTable) - results_table.clear() - - if not self.search_results: - self._update_results_info(f"No entries found matching '{search_term}'") - select_button = self.query_one("#select-button", Button) - select_button.disabled = True - return - - # Add results to table - for entry in self.search_results: - status = "✓ Active" if entry.is_active else "✗ Inactive" - comment = entry.comment or "" - results_table.add_row( - entry.ip_address, - entry.canonical_hostname, - status, - comment, - key=str(id(entry)), - ) - - self._update_results_info(f"Found {len(self.search_results)} matching entries") - - def action_select(self) -> None: - """Select the currently highlighted entry and close modal.""" - results_table = self.query_one("#search-results-table", DataTable) - - if results_table.cursor_row is None or not self.search_results: - return - - # Get the selected entry - cursor_row = results_table.cursor_row - if 0 <= cursor_row < len(self.search_results): - selected_entry = self.search_results[cursor_row] - # Find the original index of this entry - original_index = self._find_entry_index(selected_entry) - self.dismiss(original_index) - else: - self.dismiss(None) - - def action_cancel(self) -> None: - """Cancel search and close modal.""" - self.dismiss(None) - - def _search_entries(self, search_term: str) -> list[HostEntry]: - """ - Search entries by hostname or IP address. - - Args: - search_term: The search term to match against - - Returns: - List of matching entries - """ - results = [] - - for entry in self.entries: - # Search in IP address - if search_term in entry.ip_address.lower(): - results.append(entry) - continue - - # Search in hostnames - for hostname in entry.hostnames: - if search_term in hostname.lower(): - results.append(entry) - break - else: - # Search in comment - if entry.comment and search_term in entry.comment.lower(): - results.append(entry) - - return results - - def _find_entry_index(self, target_entry: HostEntry) -> int: - """ - Find the index of an entry in the original entries list. - - Args: - target_entry: Entry to find - - Returns: - Index of the entry, or -1 if not found - """ - for i, entry in enumerate(self.entries): - if entry is target_entry: - return i - return -1 - - def _update_results_info(self, message: str) -> None: - """Update the results info label.""" - try: - results_info = self.query_one(".results-info", Static) - results_info.update(message) - except Exception: - pass