Keep documents when moving from main view to search and back

This commit is contained in:
Yiorgis Gozadinos 2025-11-20 16:27:25 +02:00
parent 59eba31267
commit 0d126d894e
No known key found for this signature in database
3 changed files with 97 additions and 24 deletions

View file

@ -90,6 +90,10 @@ class InspectorApp(App): # type: ignore[misc]
self.db_path = db_path self.db_path = db_path
self.client: HaikuRAG | None = None self.client: HaikuRAG | None = None
self.search_visible = False self.search_visible = False
self.search_active = False
# Track current selection for easy restoration
self.current_document_id: str | None = None
self.current_chunk_id: str | None = None
def compose(self) -> "ComposeResult": def compose(self) -> "ComposeResult":
"""Compose the UI layout.""" """Compose the UI layout."""
@ -111,6 +115,21 @@ class InspectorApp(App): # type: ignore[misc]
doc_list = self.query_one(DocumentList) doc_list = self.query_one(DocumentList)
await doc_list.load_documents(self.client) await doc_list.load_documents(self.client)
# Select first document and load its chunks
if doc_list.documents and doc_list.list_view:
doc_list.list_view.index = 0
first_doc = doc_list.documents[0]
self.current_document_id = first_doc.id
if first_doc.id:
chunk_list = self.query_one(ChunkList)
await chunk_list.load_chunks_for_document(self.client, first_doc.id)
# Select first chunk
if chunk_list.chunks and chunk_list.list_view:
chunk_list.list_view.index = 0
self.current_chunk_id = chunk_list.chunks[0].id
# Focus the document list view # Focus the document list view
if doc_list.list_view: if doc_list.list_view:
doc_list.list_view.focus() doc_list.list_view.focus()
@ -129,11 +148,52 @@ class InspectorApp(App): # type: ignore[misc]
search_container.remove_class("visible") search_container.remove_class("visible")
search_input.value = "" search_input.value = ""
self.search_visible = False self.search_visible = False
self.search_active = False
# Restore full document list # Restore full document list and reload chunks for selected document
if self.client: if self.client:
doc_list = self.query_one(DocumentList) doc_list = self.query_one(DocumentList)
chunk_list = self.query_one(ChunkList)
# Reload all documents
await doc_list.load_documents(self.client) await doc_list.load_documents(self.client)
# Restore document and chunk selection
if (
self.current_document_id
and doc_list.list_view
and doc_list.documents
):
# Find and select the document
doc_found = False
for idx, doc in enumerate(doc_list.documents):
if doc.id == self.current_document_id:
doc_list.list_view.index = idx
doc_found = True
break
# Reload chunks for this document (without scores)
if doc_found:
await chunk_list.load_chunks_for_document(
self.client, self.current_document_id
)
# Restore chunk selection and show it in detail view
if (
self.current_chunk_id
and chunk_list.list_view
and chunk_list.chunks
):
for idx, chunk in enumerate(chunk_list.chunks):
if chunk.id == self.current_chunk_id:
chunk_list.list_view.index = idx
# Show the chunk in detail view
detail_view = self.query_one(DetailView)
await detail_view.show_chunk(chunk)
break
# Focus back to document list to show selection
doc_list.list_view.focus()
else: else:
search_container.add_class("visible") search_container.add_class("visible")
search_input.focus() search_input.focus()
@ -144,6 +204,7 @@ class InspectorApp(App): # type: ignore[misc]
if event.input.id == "search-input" and self.client: if event.input.id == "search-input" and self.client:
query = event.value.strip() query = event.value.strip()
if query: if query:
self.search_active = True
chunk_list = self.query_one(ChunkList) chunk_list = self.query_one(ChunkList)
await chunk_list.load_chunks_from_search(self.client, query) await chunk_list.load_chunks_from_search(self.client, query)
@ -174,8 +235,10 @@ class InspectorApp(App): # type: ignore[misc]
item = ListItem(Static(f"{title}")) item = ListItem(Static(f"{title}"))
await doc_list.list_view.append(item) await doc_list.list_view.append(item)
# Focus the chunk list # Select first chunk and focus the chunk list
if chunk_list.list_view: if chunk_list.list_view:
if chunk_list.chunks:
chunk_list.list_view.index = 0
chunk_list.list_view.focus() chunk_list.list_view.focus()
async def on_document_list_document_selected( async def on_document_list_document_selected(
@ -189,12 +252,15 @@ class InspectorApp(App): # type: ignore[misc]
if not self.client: if not self.client:
return return
# Always track current document (even during search)
self.current_document_id = message.document.id
# Show document details # Show document details
detail_view = self.query_one(DetailView) detail_view = self.query_one(DetailView)
await detail_view.show_document(message.document) await detail_view.show_document(message.document)
# Load chunks for this document # Load chunks for this document (but not during search - preserve search results)
if message.document.id: if message.document.id and not self.search_active:
chunk_list = self.query_one(ChunkList) chunk_list = self.query_one(ChunkList)
await chunk_list.load_chunks_for_document(self.client, message.document.id) await chunk_list.load_chunks_for_document(self.client, message.document.id)
@ -206,21 +272,16 @@ class InspectorApp(App): # type: ignore[misc]
Args: Args:
message: Message containing selected chunk message: Message containing selected chunk
""" """
# Always track current chunk (even during search)
self.current_chunk_id = message.chunk.id
# Show chunk details # Show chunk details
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 # Track the document this chunk belongs to
if message.chunk.document_id and self.client: if message.chunk.document_id:
doc_list = self.query_one(DocumentList) self.current_document_id = message.chunk.document_id
# 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:

View file

@ -80,8 +80,16 @@ class ChunkList(VerticalScroll):
item = ListItem(Static(f"[{score:.2f}] {first_line}")) item = ListItem(Static(f"[{score:.2f}] {first_line}"))
await self.list_view.append(item) await self.list_view.append(item)
async def on_list_view_highlighted(self, event: ListView.Highlighted) -> None:
"""Handle chunk navigation (arrow keys)."""
if event.list_view == self.list_view and event.item is not None:
idx = event.list_view.index
if idx is not None and 0 <= idx < len(self.chunks):
chunk = self.chunks[idx]
self.post_message(self.ChunkSelected(chunk))
async def on_list_view_selected(self, event: ListView.Selected) -> None: async def on_list_view_selected(self, event: ListView.Selected) -> None:
"""Handle chunk selection.""" """Handle chunk selection (Enter key)."""
if event.list_view == self.list_view: if event.list_view == self.list_view:
idx = event.list_view.index idx = event.list_view.index
if idx is not None and 0 <= idx < len(self.chunks): if idx is not None and 0 <= idx < len(self.chunks):

View file

@ -30,20 +30,16 @@ class DocumentList(VerticalScroll):
self.list_view = ListView() self.list_view = ListView()
yield self.list_view yield self.list_view
async def load_documents( async def load_documents(self, client: HaikuRAG) -> None:
self, client: HaikuRAG, limit: int = 100, offset: int = 0 """Load all documents from the database.
) -> None:
"""Load documents from the database.
Args: Args:
client: HaikuRAG client instance client: HaikuRAG client instance
limit: Maximum number of documents to load
offset: Offset for pagination
""" """
if self.list_view is None: if self.list_view is None:
return return
self.documents = await client.list_documents(limit=limit, offset=offset) self.documents = await client.list_documents(limit=None)
# Clear existing items # Clear existing items
await self.list_view.clear() await self.list_view.clear()
@ -54,8 +50,16 @@ class DocumentList(VerticalScroll):
item = ListItem(Static(f"{title}")) item = ListItem(Static(f"{title}"))
await self.list_view.append(item) await self.list_view.append(item)
async def on_list_view_highlighted(self, event: ListView.Highlighted) -> None:
"""Handle document navigation (arrow keys)."""
if event.list_view == self.list_view and event.item is not None:
idx = event.list_view.index
if idx is not None and 0 <= idx < len(self.documents):
document = self.documents[idx]
self.post_message(self.DocumentSelected(document))
async def on_list_view_selected(self, event: ListView.Selected) -> None: async def on_list_view_selected(self, event: ListView.Selected) -> None:
"""Handle document selection.""" """Handle document selection (Enter key)."""
if event.list_view == self.list_view: if event.list_view == self.list_view:
idx = event.list_view.index idx = event.list_view.index
if idx is not None and 0 <= idx < len(self.documents): if idx is not None and 0 <= idx < len(self.documents):