Search in inspector

This commit is contained in:
Yiorgis Gozadinos 2025-11-19 18:07:56 +02:00
parent 2c1c530f3a
commit 82831c8941
No known key found for this signature in database

View file

@ -11,7 +11,8 @@ if TYPE_CHECKING:
try: try:
from textual.app import App from textual.app import App
from textual.binding import Binding from textual.binding import Binding
from textual.widgets import Footer, Header from textual.containers import Container
from textual.widgets import Footer, Header, Input, ListItem, Static
from haiku.rag.inspector.widgets.chunk_list import ChunkList from haiku.rag.inspector.widgets.chunk_list import ChunkList
from haiku.rag.inspector.widgets.detail_view import DetailView from haiku.rag.inspector.widgets.detail_view import DetailView
@ -60,20 +61,39 @@ class InspectorApp(App): # type: ignore[misc]
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
#search-container {
dock: top;
height: 3;
background: $panel;
display: none;
}
#search-container.visible {
display: block;
}
#search-input {
width: 1fr;
}
""" """
BINDINGS = [ BINDINGS = [
Binding("q", "quit", "Quit", show=True), Binding("q", "quit", "Quit", show=True),
Binding("/", "search", "Search", show=True),
] ]
def __init__(self, db_path: Path): def __init__(self, db_path: Path):
super().__init__() super().__init__()
self.db_path = db_path self.db_path = db_path
self.client: HaikuRAG | None = None self.client: HaikuRAG | None = None
self.search_visible = False
def compose(self) -> "ComposeResult": def compose(self) -> "ComposeResult":
"""Compose the UI layout.""" """Compose the UI layout."""
yield Header() yield Header()
with Container(id="search-container"):
yield Input(placeholder="Search chunks...", id="search-input")
yield DocumentList(id="document-list") yield DocumentList(id="document-list")
yield ChunkList(id="chunk-list") yield ChunkList(id="chunk-list")
yield DetailView(id="detail-view") yield DetailView(id="detail-view")
@ -98,6 +118,64 @@ class InspectorApp(App): # type: ignore[misc]
if self.client: if self.client:
await self.client.__aexit__(None, None, None) await self.client.__aexit__(None, None, None)
async def action_search(self) -> None:
"""Toggle search input visibility."""
search_container = self.query_one("#search-container", Container)
search_input = self.query_one("#search-input", Input)
if self.search_visible:
search_container.remove_class("visible")
search_input.value = ""
self.search_visible = False
# Restore full document list
if self.client:
doc_list = self.query_one(DocumentList)
await doc_list.load_documents(self.client)
else:
search_container.add_class("visible")
search_input.focus()
self.search_visible = True
async def on_input_submitted(self, event: Input.Submitted) -> None:
"""Handle search input submission."""
if event.input.id == "search-input" and self.client:
query = event.value.strip()
if query:
chunk_list = self.query_one(ChunkList)
await chunk_list.load_chunks_from_search(self.client, query)
# Get unique document IDs from the search results
doc_ids = list(
{
chunk.document_id
for chunk in chunk_list.chunks
if chunk.document_id
}
)
# Update document list to show only documents with matching chunks
if doc_ids:
doc_list = self.query_one(DocumentList)
documents = []
for doc_id in doc_ids:
doc = await self.client.document_repository.get_by_id(doc_id)
if doc:
documents.append(doc)
# Update the document list with filtered documents
doc_list.documents = documents
if doc_list.list_view:
await doc_list.list_view.clear()
for doc in documents:
title = doc.title or doc.uri or doc.id or "Untitled"
item = ListItem(Static(f"{title}"))
await doc_list.list_view.append(item)
# Focus the chunk list
if chunk_list.list_view:
chunk_list.list_view.focus()
async def on_document_list_document_selected( async def on_document_list_document_selected(
self, message: DocumentList.DocumentSelected self, message: DocumentList.DocumentSelected
) -> None: ) -> None:
@ -130,6 +208,18 @@ class InspectorApp(App): # type: ignore[misc]
detail_view = self.query_one(DetailView) detail_view = self.query_one(DetailView)
await detail_view.show_chunk(message.chunk) await detail_view.show_chunk(message.chunk)
# If chunk has a document_id, select that document in the document list
if message.chunk.document_id and self.client:
doc_list = self.query_one(DocumentList)
# Find the document in the current document list
for idx, doc in enumerate(doc_list.documents):
if doc.id == message.chunk.document_id:
# Select this document in the list view
if doc_list.list_view:
doc_list.list_view.index = idx
break
def run_inspector(db_path: Path | None = None) -> None: def run_inspector(db_path: Path | None = None) -> None:
"""Run the inspector TUI. """Run the inspector TUI.