Remove search functionality and related modal from the TUI application to streamline the user interface.
This commit is contained in:
		
							parent
							
								
									8d884aeb65
								
							
						
					
					
						commit
						c84c1aac2a
					
				
					 4 changed files with 2 additions and 286 deletions
				
			
		| 
						 | 
				
			
			@ -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."""
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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",
 | 
			
		||||
                    )
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue