Skip to content

Commit c4e3833

Browse files
committed
typesense with bg events
1 parent 1fe87e5 commit c4e3833

File tree

3 files changed

+51
-74
lines changed

3 files changed

+51
-74
lines changed

pcweb/components/docpage/navbar/navbar.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@ def new_menu_trigger(title: str, url: str = None, active_str: str = "") -> rx.Co
381381

382382

383383
def logo() -> rx.Component:
384-
return rx.link(
384+
return rx.el.a(
385385
rx.fragment(
386386
rx.image(
387387
src="/logos/light/reflex.svg",
@@ -394,8 +394,8 @@ def logo() -> rx.Component:
394394
class_name="shrink-0 hidden dark:block",
395395
),
396396
),
397-
class_name="flex shrink-0 mr-3",
398-
href="/",
397+
class_name="block shrink-0 mr-3",
398+
to="/",
399399
)
400400

401401

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
"""Search bar component for the navbar."""
22

33
import reflex as rx
4-
from .inkeep import inkeep
4+
from .typesense import typesense_search
55

66

77
@rx.memo
88
def search_bar() -> rx.Component:
9-
return inkeep()
9+
return typesense_search()

pcweb/components/docpage/navbar/typesense.py

Lines changed: 46 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@
1111
{"host": os.getenv("TYPESENSE_HOST"), "port": "443", "protocol": "https"}
1212
],
1313
"api_key": os.getenv("TYPESENSE_SEARCH_API_KEY"),
14-
"connection_timeout_seconds": 10,
14+
"connection_timeout_seconds": 2,
1515
}
1616

1717
# Enhanced search parameters with component-aware boosting
1818
BASE_SEARCH_PARAMS = {
19-
"per_page": 20,
19+
"per_page": 15,
2020
"highlight_full_fields": "title,content,components",
21-
"snippet_threshold": 30,
21+
"snippet_threshold": 20,
2222
"num_typos": 2,
2323
"typo_tokens_threshold": 1,
2424
"drop_tokens_threshold": 1,
@@ -76,45 +76,32 @@
7676
)
7777

7878
# Styling for highlights
79-
HIGHLIGHT_STYLE = '<span style="background-color: var(--violet-3); color: var(--violet-11); padding: 2px 4px; border-radius: 3px;">'
79+
HIGHLIGHT_STYLE = '<span class="bg-violet-3 text-violet-11 px-1 py-0.5 rounded-[3px]">'
80+
81+
client = typesense.Client(TYPESENSE_CONFIG)
8082

8183

8284
class TypesenseSearchState(rx.State):
8385
"""Enhanced state management for the Typesense search component."""
8486

8587
# State variables
86-
search_query: str = ""
87-
search_results: list[dict] = []
88-
is_searching: bool = False
88+
search_query: rx.Field[str] = rx.field("")
89+
search_results: rx.Field[list[dict]] = rx.field([])
90+
is_searching: rx.Field[bool] = rx.field(False)
8991
show_results: bool = False
90-
show_modal: bool = False
91-
selected_filter: str = "All"
92-
filter_categories: list[str] = FILTER_CATEGORIES
93-
suggestions: list[dict] = DEFAULT_SUGGESTIONS
94-
95-
def open_modal(self):
96-
"""Open the search modal and reset filter state."""
97-
self.show_modal = True
98-
self.selected_filter = "All"
92+
selected_filter: rx.Field[str] = rx.field("All")
9993

94+
@rx.event(temporal=True)
10095
def close_modal(self):
10196
"""Close the search modal and reset state."""
102-
self.show_modal = False
103-
self._reset_search_state()
104-
105-
def _reset_search_state(self):
106-
"""Reset all search-related state variables."""
107-
self.show_results = False
108-
self.is_searching = False
109-
self.search_query = ""
110-
self.search_results = []
111-
self.selected_filter = "All"
97+
self.reset()
11298

99+
@rx.event(temporal=True)
113100
async def set_filter(self, filter_name: str):
114101
"""Set the selected filter and re-run search if there's an active query."""
115102
self.selected_filter = filter_name
116103
if self.search_query.strip():
117-
await self.search_docs(self.search_query)
104+
yield TypesenseSearchState.search_docs(self.search_query)
118105

119106
def _get_filter_sections(self) -> list[str]:
120107
"""Get sections for current filter."""
@@ -130,29 +117,35 @@ def _expand_query_variants(self, query: str) -> str:
130117
variants = {cleaned, f"rx.{cleaned}", f"reflex.{cleaned}"}
131118
return " ".join(sorted(variants)) # Order doesn't matter
132119

120+
@rx.event(background=True, temporal=True)
133121
async def search_docs(self, query: str):
134122
"""Enhanced search with component-aware logic."""
135-
self.search_query = query
123+
async with self:
124+
self.search_query = query
136125

137-
if not query.strip():
138-
self._clear_search_results()
139-
return
126+
if not query.strip():
127+
self._clear_search_results()
128+
return
140129

141-
self.is_searching = True
130+
self.is_searching = True
131+
yield
142132

143133
try:
144134
results = await self._perform_unified_search(query)
145-
self.search_results = self._format_search_results(results)
146-
self.show_results = True
147-
except Exception as e:
148-
print(f"Search error: {e}")
149-
self._clear_search_results()
150-
151-
self.is_searching = False
135+
formatted_results = self._format_search_results(results)
136+
async with self:
137+
self.search_results = formatted_results
138+
self.show_results = True
139+
except Exception:
140+
async with self:
141+
self._clear_search_results()
142+
143+
finally:
144+
async with self:
145+
self.is_searching = False
152146

153147
async def _perform_unified_search(self, query: str) -> dict:
154148
"""Perform a single search using is_component metadata for boosting/filtering."""
155-
client = typesense.Client(TYPESENSE_CONFIG)
156149

157150
expanded_query = self._expand_query_variants(query)
158151

@@ -191,20 +184,14 @@ def _format_search_results(self, result: dict) -> list[dict]:
191184
for hit in result["hits"]:
192185
doc = hit["document"]
193186
components = doc.get("components", [])
194-
component_info = None
195-
if components:
196-
component_info = f"Components: {', '.join(components)}"
197187
formatted_result = {
198188
"title": doc["title"],
199189
"content": self._get_highlighted_content(hit),
200190
"url": doc["url"],
201191
"path": doc["path"],
202192
"section": doc.get("section", ""),
203-
"subsection": doc.get("subsection", ""),
204193
"breadcrumb": doc.get("breadcrumb", ""),
205194
"components": components,
206-
"component_info": component_info,
207-
"score": hit.get("text_match", 0),
208195
}
209196
formatted_results.append(formatted_result)
210197

@@ -244,24 +231,14 @@ def fix_component_highlighting(text):
244231
)
245232

246233
# Fallback to truncated plain content
247-
return self._truncate_content(hit["document"]["content"])
234+
return self._truncate_content(hit["document"].get("content", ""))
248235

249236
def _truncate_content(self, content: str, max_length: int = 150) -> str:
250237
"""Truncate content to specified length."""
251238
if len(content) <= max_length:
252239
return content
253240
return content[:max_length] + "..."
254241

255-
def hide_results(self):
256-
"""Hide search results."""
257-
self.show_results = False
258-
259-
def navigate_to_result(self, url: str):
260-
"""Navigate to a search result."""
261-
self.show_results = False
262-
self.show_modal = False
263-
return rx.redirect(url)
264-
265242

266243
# Component functions (keeping your existing UI components)
267244
def filter_pill(filter_name: str) -> rx.Component:
@@ -284,23 +261,26 @@ def filter_pill(filter_name: str) -> rx.Component:
284261
def filter_pills() -> rx.Component:
285262
"""Render the filter pills container."""
286263
return rx.box(
287-
rx.foreach(TypesenseSearchState.filter_categories, filter_pill),
264+
*[filter_pill(filter_name) for filter_name in FILTER_CATEGORIES],
288265
class_name="hidden md:flex md:flex-row gap-x-3 pt-2 overflow-x-auto justify-start w-full",
289266
)
290267

291268

292269
def suggestion_item(title: str, url: str, icon: str = "book-open") -> rx.Component:
293270
"""Render a single suggestion item."""
294-
return rx.box(
271+
return rx.el.a(
295272
rx.hstack(
296-
rx.icon(icon, size=16, color="var(--c-slate-9)"),
273+
rx.icon(icon, size=16, class_name="!text-slate-9"),
297274
rx.text(
298-
title, font_weight="500", color="var(--c-slate-12)", font_size="14px"
275+
title,
276+
font_weight="500",
277+
class_name="!text-slate-12",
278+
font_size="14px",
299279
),
300280
spacing="2",
301281
align_items="center",
302282
),
303-
on_click=lambda: TypesenseSearchState.navigate_to_result(url),
283+
to=url,
304284
class_name="w-full border-b border-slate-4 hover:bg-slate-3 cursor-pointer rounded-[6px] py-2 px-2",
305285
)
306286

@@ -353,7 +333,7 @@ def suggestions_section() -> rx.Component:
353333

354334
def search_result_item(result: rx.Var) -> rx.Component:
355335
"""Enhanced search result item with component information."""
356-
return rx.box(
336+
return rx.el.a(
357337
rx.vstack(
358338
rx.text(
359339
result["breadcrumb"],
@@ -381,7 +361,7 @@ def search_result_item(result: rx.Var) -> rx.Component:
381361
width="100%",
382362
),
383363
class_name="p-2 border border-slate-4 rounded-[8px] cursor-pointer w-full hover:border-slate-5 hover:bg-slate-2 shadow-small",
384-
on_click=lambda: TypesenseSearchState.navigate_to_result(result["url"]),
364+
to=result["url"],
385365
)
386366

387367

@@ -466,8 +446,7 @@ def search_trigger() -> rx.Component:
466446
"max_width": ["6em", "6em", "none"],
467447
"box_shadow": "0px 24px 12px 0px rgba(28, 32, 36, 0.02), 0px 8px 8px 0px rgba(28, 32, 36, 0.02), 0px 2px 6px 0px rgba(28, 32, 36, 0.02)",
468448
},
469-
class_name="w-full hover:bg-slate-3 cursor-pointer flex max-h-[32px] min-h-[32px] border border-slate-5 rounded-[10px] bg-slate-1 transition-bg relative",
470-
on_click=TypesenseSearchState.open_modal,
449+
class_name="w-full hover:bg-slate-3 cursor-pointer flex max-h-[32px] min-h-[32px] border border-slate-5 rounded-[3px] !rounded-[10px] bg-slate-1 transition-bg relative",
471450
)
472451

473452

@@ -493,10 +472,8 @@ def typesense_search() -> rx.Component:
493472
rx.dialog.content(
494473
search_modal(),
495474
class_name="w-full max-w-[640px] mx-auto bg-slate-1 border-none outline-none p-0 lg:!fixed lg:!top-24 lg:!left-1/2 lg:!transform lg:!-translate-x-1/2 lg:!translate-y-0 lg:!m-0",
496-
on_interact_outside=TypesenseSearchState.close_modal,
497-
on_escape_key_down=TypesenseSearchState.close_modal,
498475
),
476+
on_open_change=TypesenseSearchState.close_modal,
499477
),
500478
keyboard_shortcut_script(),
501-
class_name="w-full",
502479
)

0 commit comments

Comments
 (0)