Add search autocomplete and fix search state restoration
- Add SuggestFromList with Himalaya keywords for search input autocomplete - Cache and restore metadata_by_id when cancelling search (fixes navigation) - Set search_mode=True when opening panel for consistent Escape behavior - Fix SearchPanel CSS vertical alignment with explicit heights
This commit is contained in:
@@ -77,6 +77,7 @@ class EmailViewerApp(App):
|
|||||||
search_query: Reactive[str] = reactive("") # Current search filter
|
search_query: Reactive[str] = reactive("") # Current search filter
|
||||||
search_mode: Reactive[bool] = reactive(False) # True when showing search results
|
search_mode: Reactive[bool] = reactive(False) # True when showing search results
|
||||||
_cached_envelopes: List[Dict[str, Any]] = [] # Cached envelopes before search
|
_cached_envelopes: List[Dict[str, Any]] = [] # Cached envelopes before search
|
||||||
|
_cached_metadata: Dict[int, Dict[str, Any]] = {} # Cached metadata before search
|
||||||
|
|
||||||
def get_system_commands(self, screen: Screen) -> Iterable[SystemCommand]:
|
def get_system_commands(self, screen: Screen) -> Iterable[SystemCommand]:
|
||||||
yield from super().get_system_commands(screen)
|
yield from super().get_system_commands(screen)
|
||||||
@@ -917,6 +918,8 @@ class EmailViewerApp(App):
|
|||||||
if not search_panel.is_visible:
|
if not search_panel.is_visible:
|
||||||
# Cache current envelopes before searching
|
# Cache current envelopes before searching
|
||||||
self._cached_envelopes = list(self.message_store.envelopes)
|
self._cached_envelopes = list(self.message_store.envelopes)
|
||||||
|
self._cached_metadata = dict(self.message_store.metadata_by_id)
|
||||||
|
self.search_mode = True
|
||||||
search_panel.show(self.search_query)
|
search_panel.show(self.search_query)
|
||||||
|
|
||||||
def on_search_panel_search_requested(
|
def on_search_panel_search_requested(
|
||||||
@@ -938,10 +941,13 @@ class EmailViewerApp(App):
|
|||||||
self.search_mode = False
|
self.search_mode = False
|
||||||
self.search_query = ""
|
self.search_query = ""
|
||||||
|
|
||||||
# Restore cached envelopes
|
# Restore cached envelopes and metadata
|
||||||
if self._cached_envelopes:
|
if self._cached_envelopes:
|
||||||
self.message_store.envelopes = self._cached_envelopes
|
self.message_store.envelopes = self._cached_envelopes
|
||||||
self._cached_envelopes = []
|
self._cached_envelopes = []
|
||||||
|
if self._cached_metadata:
|
||||||
|
self.message_store.metadata_by_id = self._cached_metadata
|
||||||
|
self._cached_metadata = {}
|
||||||
self._populate_list_view()
|
self._populate_list_view()
|
||||||
|
|
||||||
# Restore envelope list title
|
# Restore envelope list title
|
||||||
|
|||||||
@@ -17,6 +17,32 @@ from textual.screen import ModalScreen
|
|||||||
from textual.timer import Timer
|
from textual.timer import Timer
|
||||||
from textual.widget import Widget
|
from textual.widget import Widget
|
||||||
from textual.widgets import Button, Input, Label, Static
|
from textual.widgets import Button, Input, Label, Static
|
||||||
|
from textual.suggester import SuggestFromList
|
||||||
|
|
||||||
|
# Himalaya search keywords for autocomplete
|
||||||
|
HIMALAYA_KEYWORDS = [
|
||||||
|
"from ",
|
||||||
|
"to ",
|
||||||
|
"subject ",
|
||||||
|
"body ",
|
||||||
|
"date ",
|
||||||
|
"before ",
|
||||||
|
"after ",
|
||||||
|
"flag ",
|
||||||
|
"not ",
|
||||||
|
"and ",
|
||||||
|
"or ",
|
||||||
|
"order by ",
|
||||||
|
"order by date ",
|
||||||
|
"order by date asc",
|
||||||
|
"order by date desc",
|
||||||
|
"order by from ",
|
||||||
|
"order by to ",
|
||||||
|
"order by subject ",
|
||||||
|
"flag seen",
|
||||||
|
"flag flagged",
|
||||||
|
"not flag seen",
|
||||||
|
]
|
||||||
|
|
||||||
HIMALAYA_SEARCH_HELP = """
|
HIMALAYA_SEARCH_HELP = """
|
||||||
## Himalaya Search Query Syntax
|
## Himalaya Search Query Syntax
|
||||||
@@ -125,7 +151,7 @@ class SearchPanel(Widget):
|
|||||||
}
|
}
|
||||||
|
|
||||||
SearchPanel > Horizontal {
|
SearchPanel > Horizontal {
|
||||||
height: auto;
|
height: 3;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
align: left middle;
|
align: left middle;
|
||||||
}
|
}
|
||||||
@@ -134,6 +160,7 @@ class SearchPanel(Widget):
|
|||||||
width: auto;
|
width: auto;
|
||||||
padding: 0 1;
|
padding: 0 1;
|
||||||
color: $primary;
|
color: $primary;
|
||||||
|
height: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
SearchPanel Input {
|
SearchPanel Input {
|
||||||
@@ -151,6 +178,7 @@ class SearchPanel(Widget):
|
|||||||
width: auto;
|
width: auto;
|
||||||
padding: 0 1;
|
padding: 0 1;
|
||||||
color: $text-muted;
|
color: $text-muted;
|
||||||
|
height: 1;
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -197,6 +225,7 @@ class SearchPanel(Widget):
|
|||||||
yield Input(
|
yield Input(
|
||||||
placeholder="from <name> or subject <text> or body <text>...",
|
placeholder="from <name> or subject <text> or body <text>...",
|
||||||
id="search-input",
|
id="search-input",
|
||||||
|
suggester=SuggestFromList(HIMALAYA_KEYWORDS, case_sensitive=False),
|
||||||
)
|
)
|
||||||
yield Label("", classes="search-status", id="search-status")
|
yield Label("", classes="search-status", id="search-status")
|
||||||
yield Button("?", variant="default", id="help-btn")
|
yield Button("?", variant="default", id="help-btn")
|
||||||
|
|||||||
Reference in New Issue
Block a user