1- import React , { useEffect , useMemo , useRef , useState } from "react" ;
1+ import React , { useEffect , useMemo , useState } from "react" ;
22import {
33 Button ,
44 Icon ,
@@ -8,16 +8,13 @@ import {
88 SpinnerSize ,
99 Tag ,
1010} from "@blueprintjs/core" ;
11- import MiniSearch from "minisearch" ;
1211import getDiscourseNodes from "~/utils/getDiscourseNodes" ;
13- import type { DockedSearchState } from "~/utils/openDgSearchInSidebar" ;
1412import {
1513 DEBOUNCE_MS ,
14+ type DockedSearchState ,
1615 type SearchResult ,
1716 buildSearchIndex ,
1817 getSearchKeywords ,
19- searchIndexedNodes ,
20- sortSearchResults ,
2118} from "./utils" ;
2219import { hasActiveTypeFilter } from "~/utils/discourseNodeTypeFilter" ;
2320import { formatHexColor } from "~/components/settings/DiscourseNodeCanvasSettings" ;
@@ -27,6 +24,10 @@ import type { DiscourseNode } from "~/utils/getDiscourseNodes";
2724import { getNodeTagStyles } from "~/utils/getDiscourseNodeColors" ;
2825import { splitWithHighlights , stripTypePrefix } from "./utils" ;
2926import { openSearchResultFromLinkEvent } from "~/utils/advancedSearchFooterUtils" ;
27+ import {
28+ type SearchIndex ,
29+ useAdvancedNodeSearchResults ,
30+ } from "./useAdvancedNodeSearchResults" ;
3031
3132const renderHighlightedText = (
3233 text : string ,
@@ -168,13 +169,6 @@ type AdvancedSearchDockedFiltersProps = {
168169const getNodeIndicatorColor = ( node : DiscourseNode ) : string =>
169170 formatHexColor ( node . canvasSettings ?. color ) || "#6b7280" ;
170171
171- type SidebarIndexCache = {
172- miniSearch : MiniSearch < SearchResult & { id : string } > ;
173- results : SearchResult [ ] ;
174- } ;
175-
176- let cachedSidebarIndex : SidebarIndexCache | null = null ;
177-
178172const AdvancedSearchDockedFilters = ( {
179173 discourseNodes,
180174 selectedNodeTypeIds,
@@ -193,15 +187,13 @@ const AdvancedSearchDockedFilters = ({
193187 if ( ! isTypeFilterActive && ! showSort ) return null ;
194188
195189 return (
196- < div className = "dg-node-search-sidebar__filters mb-1 ml-[9px] mr-2 flex flex-col gap-1.5" >
190+ < div className = "dg-node-search-sidebar__filters mb-1 ml-2 mr-2 flex flex-col gap-1.5" >
197191 { isTypeFilterActive && (
198192 < div className = "mt-1 flex flex-wrap items-center gap-1" >
199- < span className = "shrink-0 text-[0.8em] text-gray-500" >
200- Filtered to
201- </ span >
193+ < span className = "shrink-0 text-xs text-gray-500" > Filter:</ span >
202194 { selectedNodes . map ( ( node ) => (
203195 < Tag
204- className = "!text-[0.8em] "
196+ className = "!text-xs "
205197 key = { node . type }
206198 minimal
207199 round
@@ -222,7 +214,7 @@ const AdvancedSearchDockedFilters = ({
222214 </ div >
223215 ) }
224216 { showSort && (
225- < p className = "text-[0.8em] text-gray-500" >
217+ < p className = "text-xs text-gray-500" >
226218 Sorted by { SORT_FIELD_LABELS [ sort . field ] } (
227219 { sort . direction === "asc" ? "ascending" : "descending" } )
228220 </ p >
@@ -232,11 +224,17 @@ const AdvancedSearchDockedFilters = ({
232224} ;
233225
234226type AdvancedSearchSidebarPanelProps = {
227+ dgSearchId : string ;
235228 dockedState : DockedSearchState ;
229+ onPersistState : ( state : DockedSearchState ) => void ;
230+ windowId : string ;
236231} ;
237232
238233export const AdvancedSearchSidebarPanel = ( {
234+ dgSearchId,
239235 dockedState,
236+ onPersistState,
237+ windowId,
240238} : AdvancedSearchSidebarPanelProps ) => {
241239 const {
242240 query,
@@ -247,21 +245,15 @@ export const AdvancedSearchSidebarPanel = ({
247245
248246 const [ searchTerm , setSearchTerm ] = useState ( query ) ;
249247 const [ debouncedSearchTerm , setDebouncedSearchTerm ] = useState ( query ) ;
250- const [ results , setResults ] = useState < SearchResult [ ] > ( dockedResults ) ;
248+ const [ searchIndex , setSearchIndex ] = useState < SearchIndex | null > ( null ) ;
251249 const [ isIndexLoading , setIsIndexLoading ] = useState ( true ) ;
252250 const [ indexError , setIndexError ] = useState ( false ) ;
253251
254- const miniSearchRef = useRef < MiniSearch <
255- SearchResult & { id : string }
256- > | null > ( null ) ;
257- const allResultsRef = useRef < SearchResult [ ] > ( [ ] ) ;
258-
259252 const discourseNodes = useMemo (
260253 ( ) => getDiscourseNodes ( ) . filter ( ( node ) => node . backedBy === "user" ) ,
261254 [ ] ,
262255 ) ;
263256 const keywords = getSearchKeywords ( debouncedSearchTerm ) ;
264- const isDockedQuery = debouncedSearchTerm . trim ( ) === query . trim ( ) ;
265257
266258 useEffect ( ( ) => {
267259 const timeout = setTimeout (
@@ -275,31 +267,13 @@ export const AdvancedSearchSidebarPanel = ({
275267 let cancelled = false ;
276268 setIsIndexLoading ( true ) ;
277269 setIndexError ( false ) ;
278-
279- const applyIndex = ( {
280- miniSearch,
281- results : indexedResults ,
282- } : SidebarIndexCache ) : void => {
283- if ( cancelled ) return ;
284- miniSearchRef . current = miniSearch ;
285- allResultsRef . current = indexedResults ;
286- setIsIndexLoading ( false ) ;
287- } ;
288-
289- if ( cachedSidebarIndex ) {
290- applyIndex ( cachedSidebarIndex ) ;
291- return ( ) => {
292- cancelled = true ;
293- } ;
294- }
270+ setSearchIndex ( null ) ;
295271
296272 void buildSearchIndex ( discourseNodes )
297273 . then ( ( { miniSearch, results : indexedResults } ) => {
298- cachedSidebarIndex = {
299- miniSearch,
300- results : indexedResults ,
301- } ;
302- applyIndex ( cachedSidebarIndex ) ;
274+ if ( cancelled ) return ;
275+ setSearchIndex ( { miniSearch, allResults : indexedResults } ) ;
276+ setIsIndexLoading ( false ) ;
303277 } )
304278 . catch ( ( error ) => {
305279 console . error (
@@ -317,32 +291,36 @@ export const AdvancedSearchSidebarPanel = ({
317291 } ;
318292 } , [ discourseNodes ] ) ;
319293
320- useEffect ( ( ) => {
321- if ( ! debouncedSearchTerm ) {
322- setResults ( [ ] ) ;
323- return ;
324- }
325-
326- if ( isIndexLoading || indexError || ! miniSearchRef . current ) {
327- if ( ! isDockedQuery ) setResults ( [ ] ) ;
328- return ;
329- }
294+ const results = useAdvancedNodeSearchResults ( {
295+ debouncedSearchTerm,
296+ selectedNodeTypeIds ,
297+ sort ,
298+ isIndexLoading ,
299+ indexError ,
300+ searchIndex ,
301+ dockedQuery : query ,
302+ dockedResults ,
303+ } ) ;
330304
331- const scoredHits = searchIndexedNodes ( {
332- miniSearch : miniSearchRef . current ,
333- allResults : allResultsRef . current ,
334- searchTerm : debouncedSearchTerm ,
335- typeFilter : selectedNodeTypeIds . length ? selectedNodeTypeIds : undefined ,
305+ useEffect ( ( ) => {
306+ if ( ! debouncedSearchTerm ) return ;
307+
308+ onPersistState ( {
309+ query : debouncedSearchTerm ,
310+ results,
311+ selectedNodeTypeIds,
312+ sort,
313+ windowId,
314+ dgSearchId,
336315 } ) ;
337-
338- setResults ( sortSearchResults ( { hits : scoredHits , sort } ) ) ;
339316 } , [
340317 debouncedSearchTerm ,
341- indexError ,
342- isDockedQuery ,
343- isIndexLoading ,
318+ dgSearchId ,
319+ onPersistState ,
320+ results ,
344321 selectedNodeTypeIds ,
345322 sort ,
323+ windowId ,
346324 ] ) ;
347325
348326 const resultLabel =
@@ -376,7 +354,7 @@ export const AdvancedSearchSidebarPanel = ({
376354 />
377355 ) : (
378356 < >
379- < span className = "ml-[9px] text-[0.9em] " >
357+ < span className = "ml-2 text-xs " >
380358 { isIndexLoading && ! results . length
381359 ? "Loading…"
382360 : debouncedSearchTerm
0 commit comments