@@ -43,6 +43,7 @@ export function Search({
4343 const { t } = useTranslation ( 'search' )
4444 const { currentVersion } = useVersion ( )
4545 const { languages } = useLanguages ( )
46+ const initialRender = useRef ( true )
4647
4748 // Figure out language and version for index
4849 const { searchVersions, nonEnterpriseDefaultVersion } = useMainContext ( )
@@ -61,6 +62,18 @@ export function Search({
6162 }
6263 } , [ ] )
6364
65+ // If the version changed from the dropdown version or language picker
66+ // close the search pane and clear the query
67+ // If the version changed from the search result window, keep the query
68+ // and results but reset the versionFromSearchPane value
69+ useEffect ( ( ) => {
70+ if ( initialRender . current ) {
71+ initialRender . current = false
72+ } else {
73+ closeSearch ( )
74+ }
75+ } , [ currentVersion , language ] )
76+
6477 // When the user finishes typing, update the results
6578 async function onSearch ( e : React . ChangeEvent < HTMLInputElement > ) {
6679 const xquery = e . target ?. value ?. trim ( )
@@ -116,6 +129,9 @@ export function Search({
116129 function closeSearch ( ) {
117130 setQuery ( '' )
118131 setResults ( null )
132+ if ( inputRef . current ) {
133+ inputRef . current . value = ''
134+ }
119135 }
120136
121137 // Prevent the page from refreshing when you "submit" the form
@@ -143,6 +159,7 @@ export function Search({
143159 results = { results }
144160 closeSearch = { closeSearch }
145161 debug = { 'debug' in router . query }
162+ query = { query }
146163 />
147164 </ div >
148165 { /* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */ }
@@ -212,15 +229,34 @@ function ShowSearchResults({
212229 results,
213230 closeSearch,
214231 debug,
232+ query,
215233} : {
216234 anchorRef : RefObject < HTMLElement >
217235 isHeaderSearch : boolean
218236 isLoading : boolean
219237 results : SearchResult [ ] | null
220238 closeSearch : ( ) => void
221239 debug : boolean
240+ query : string | string [ ]
222241} ) {
223242 const { t } = useTranslation ( 'search' )
243+ const router = useRouter ( )
244+ const { currentVersion } = useVersion ( )
245+ const { allVersions } = useMainContext ( )
246+ const searchVersion = allVersions [ currentVersion ] . versionTitle
247+ const latestVersions = new Set (
248+ Object . keys ( allVersions )
249+ . map ( ( version ) => allVersions [ version ] . latestVersion )
250+ . filter ( ( version ) => version !== currentVersion )
251+ )
252+
253+ const versions = Array . from ( latestVersions ) . map ( ( version ) => {
254+ return {
255+ title : allVersions [ version ] . versionTitle ,
256+ version : version ,
257+ }
258+ } )
259+ const redirectQuery = query ? `?query=${ query } ` : ''
224260
225261 if ( results !== null ) {
226262 if ( results . length === 0 ) {
@@ -263,76 +299,88 @@ function ShowSearchResults({
263299 }
264300 }
265301 >
266- < div data-testid = "search-results" className = "mt-n2 mb-n2" >
302+ < div data-testid = "search-results" >
303+ < div className = "my-4" >
304+ < p className = "ml-4" >
305+ You're searching the < span className = "color-fg-attention" > { searchVersion } </ span > { ' ' }
306+ version. Didn't find what you're looking for? Click a different version to try
307+ again.
308+ </ p >
309+ { versions . map ( ( { title, version } ) => {
310+ return (
311+ < button key = { version } className = "btn mr-2 mt-4 ml-4" type = "button" >
312+ < a href = { `/${ router . locale } /${ version } ${ redirectQuery } ` } > { title } </ a >
313+ </ button >
314+ )
315+ } ) }
316+ </ div >
267317 < ActionList
268- items = { results
269- . slice ( 0 , results . length - 1 )
270- . map ( ( { url, breadcrumbs, title, content, score, popularity } ) => {
271- return {
272- key : url ,
273- text : title ,
274- renderItem : ( ) => (
275- < ActionList . Item as = "div" >
276- < Link href = { url } className = "no-underline color-fg-default" >
277- < li
278- key = { url }
279- data-testid = "search-result"
280- className = { cx ( 'list-style-none' ) }
281- >
282- < div className = { cx ( 'py-2 px-3' ) } >
283- { /* Breadcrumbs in search records don't include the page title. These fields may contain <mark> elements that we need to render */ }
284- < Label variant = "small" sx = { { bg : 'accent.emphasis' } } >
285- { breadcrumbs . length === 0
286- ? title . replace ( / < \/ ? [ ^ > ] + ( > | $ ) | ( \/ ) / g, '' )
287- : breadcrumbs
288- . split ( ' / ' )
289- . slice ( 0 , 1 )
290- . join ( ' ' )
291- . replace ( / < \/ ? [ ^ > ] + ( > | $ ) | ( \/ ) / g, '' ) }
292- </ Label >
293- { debug && (
294- < small className = "float-right" >
295- score: { score . toFixed ( 4 ) } popularity: { popularity . toFixed ( 4 ) }
296- </ small >
318+ items = { results . map ( ( { url, breadcrumbs, title, content, score, popularity } ) => {
319+ return {
320+ key : url ,
321+ text : title ,
322+ renderItem : ( ) => (
323+ < ActionList . Item as = "div" >
324+ < Link href = { url } className = "no-underline color-fg-default" >
325+ < li
326+ key = { url }
327+ data-testid = "search-result"
328+ className = { cx ( 'list-style-none' ) }
329+ >
330+ < div className = { cx ( 'py-2 px-3' ) } >
331+ { /* Breadcrumbs in search records don't include the page title. These fields may contain <mark> elements that we need to render */ }
332+ < Label variant = "small" sx = { { bg : 'accent.emphasis' } } >
333+ { breadcrumbs . length === 0
334+ ? title . replace ( / < \/ ? [ ^ > ] + ( > | $ ) | ( \/ ) / g, '' )
335+ : breadcrumbs
336+ . split ( ' / ' )
337+ . slice ( 0 , 1 )
338+ . join ( ' ' )
339+ . replace ( / < \/ ? [ ^ > ] + ( > | $ ) | ( \/ ) / g, '' ) }
340+ </ Label >
341+ { debug && (
342+ < small className = "float-right" >
343+ score: { score . toFixed ( 4 ) } popularity: { popularity . toFixed ( 4 ) }
344+ </ small >
345+ ) }
346+ < div
347+ className = { cx (
348+ styles . searchResultTitle ,
349+ 'mt-2 d-block f4 text-semibold'
350+ ) }
351+ dangerouslySetInnerHTML = { {
352+ __html : title ,
353+ } }
354+ />
355+ < div
356+ className = { cx (
357+ styles . searchResultContent ,
358+ 'mt-1 d-block overflow-hidden'
297359 ) }
298- < div
299- className = { cx (
300- styles . searchResultTitle ,
301- 'mt-2 d-block f4 text-semibold'
302- ) }
303- dangerouslySetInnerHTML = { {
304- __html : title ,
305- } }
306- />
307- < div
308- className = { cx (
309- styles . searchResultContent ,
310- 'mt-1 d-block overflow-hidden'
311- ) }
312- style = { { maxHeight : '2.5rem' } }
313- dangerouslySetInnerHTML = { { __html : content } }
314- />
315- < div
316- className = { 'd-block mt-2 opacity-60 text-small' }
317- dangerouslySetInnerHTML = {
318- breadcrumbs . length === 0
319- ? { __html : `${ title } ` . replace ( / < \/ ? [ ^ > ] + ( > | $ ) | ( \/ ) / g, '' ) }
320- : {
321- __html : breadcrumbs
322- . split ( ' / ' )
323- . slice ( 0 , breadcrumbs . length - 1 )
324- . join ( ' / ' )
325- . replace ( / < \/ ? [ ^ > ] + ( > | $ ) / g, '' ) ,
326- }
327- }
328- />
329- </ div >
330- </ li >
331- </ Link >
332- </ ActionList . Item >
333- ) ,
334- }
335- } ) }
360+ style = { { maxHeight : '2.5rem' } }
361+ dangerouslySetInnerHTML = { { __html : content } }
362+ />
363+ < div
364+ className = { 'd-block mt-2 opacity-60 text-small' }
365+ dangerouslySetInnerHTML = {
366+ breadcrumbs . length === 0
367+ ? { __html : `${ title } ` . replace ( / < \/ ? [ ^ > ] + ( > | $ ) | ( \/ ) / g, '' ) }
368+ : {
369+ __html : breadcrumbs
370+ . split ( ' / ' )
371+ . slice ( 0 , breadcrumbs . length - 1 )
372+ . join ( ' / ' )
373+ . replace ( / < \/ ? [ ^ > ] + ( > | $ ) / g, '' ) ,
374+ }
375+ }
376+ />
377+ </ div >
378+ </ li >
379+ </ Link >
380+ </ ActionList . Item >
381+ ) ,
382+ }
383+ } ) }
336384 />
337385 </ div >
338386 </ Overlay >
0 commit comments