mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	feat: add history for search (#5651)
This is simple refactor. Just moving history part out of suggestions component.
This commit is contained in:
		
							parent
							
								
									203d6ac848
								
							
						
					
					
						commit
						848415c5ca
					
				| @ -51,3 +51,18 @@ test('should update saved query without local storage', async () => { | ||||
| 
 | ||||
|     expect(screen.getByText('newquery')).toBeInTheDocument(); // new saved query updated
 | ||||
| }); | ||||
| 
 | ||||
| test('should still render history if no search context', async () => { | ||||
|     const { setValue } = createLocalStorage('Search:localStorageId:v1', {}); | ||||
|     setValue({ | ||||
|         query: 'oldquery', | ||||
|     }); | ||||
| 
 | ||||
|     render(<Search onChange={() => {}} id='localStorageId' />); | ||||
| 
 | ||||
|     const input = screen.getByTestId(SEARCH_INPUT); | ||||
| 
 | ||||
|     input.focus(); | ||||
| 
 | ||||
|     await screen.findByText('oldquery'); | ||||
| }); | ||||
|  | ||||
| @ -1,6 +1,13 @@ | ||||
| import React, { useRef, useState } from 'react'; | ||||
| import React, { useEffect, useRef, useState } from 'react'; | ||||
| import { useAsyncDebounce } from 'react-table'; | ||||
| import { Box, IconButton, InputBase, styled, Tooltip } from '@mui/material'; | ||||
| import { | ||||
|     Box, | ||||
|     IconButton, | ||||
|     InputBase, | ||||
|     Paper, | ||||
|     styled, | ||||
|     Tooltip, | ||||
| } from '@mui/material'; | ||||
| import { Close, Search as SearchIcon } from '@mui/icons-material'; | ||||
| import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; | ||||
| import { SearchSuggestions } from './SearchSuggestions/SearchSuggestions'; | ||||
| @ -10,6 +17,7 @@ import { SEARCH_INPUT } from 'utils/testIds'; | ||||
| import { useOnClickOutside } from 'hooks/useOnClickOutside'; | ||||
| import { useSavedQuery } from './useSavedQuery'; | ||||
| import { useOnBlur } from 'hooks/useOnBlur'; | ||||
| import { SearchHistory } from './SearchSuggestions/SearchHistory'; | ||||
| 
 | ||||
| interface ISearchProps { | ||||
|     id?: string; | ||||
| @ -27,9 +35,26 @@ interface ISearchProps { | ||||
|     expandable?: boolean; | ||||
| } | ||||
| 
 | ||||
| export const SearchPaper = styled(Paper)(({ theme }) => ({ | ||||
|     position: 'absolute', | ||||
|     width: '100%', | ||||
|     left: 0, | ||||
|     top: '20px', | ||||
|     zIndex: 2, | ||||
|     padding: theme.spacing(4, 1.5, 1.5), | ||||
|     borderBottomLeftRadius: theme.spacing(1), | ||||
|     borderBottomRightRadius: theme.spacing(1), | ||||
|     boxShadow: '0px 8px 20px rgba(33, 33, 33, 0.15)', | ||||
|     fontSize: theme.fontSizes.smallBody, | ||||
|     color: theme.palette.text.secondary, | ||||
|     wordBreak: 'break-word', | ||||
| })); | ||||
| 
 | ||||
| const StyledContainer = styled('div', { | ||||
|     shouldForwardProp: (prop) => prop !== 'active', | ||||
| })<{ active: boolean | undefined }>(({ theme, active }) => ({ | ||||
| })<{ | ||||
|     active: boolean | undefined; | ||||
| }>(({ theme, active }) => ({ | ||||
|     display: 'flex', | ||||
|     flexGrow: 1, | ||||
|     alignItems: 'center', | ||||
| @ -93,7 +118,7 @@ export const Search = ({ | ||||
| 
 | ||||
|     const { savedQuery, setSavedQuery } = useSavedQuery(id); | ||||
| 
 | ||||
|     const [value, setValue] = useState(initialValue); | ||||
|     const [value, setValue] = useState<string>(initialValue); | ||||
|     const debouncedOnChange = useAsyncDebounce(onChange, debounceTime); | ||||
| 
 | ||||
|     const onSearchChange = (value: string) => { | ||||
| @ -103,7 +128,11 @@ export const Search = ({ | ||||
|     }; | ||||
| 
 | ||||
|     const hotkey = useKeyboardShortcut( | ||||
|         { modifiers: ['ctrl'], key: 'k', preventDefault: true }, | ||||
|         { | ||||
|             modifiers: ['ctrl'], | ||||
|             key: 'k', | ||||
|             preventDefault: true, | ||||
|         }, | ||||
|         () => { | ||||
|             if (document.activeElement === searchInputRef.current) { | ||||
|                 searchInputRef.current?.blur(); | ||||
| @ -122,6 +151,10 @@ export const Search = ({ | ||||
|     useOnClickOutside([searchContainerRef], hideSuggestions); | ||||
|     useOnBlur(searchContainerRef, hideSuggestions); | ||||
| 
 | ||||
|     useEffect(() => { | ||||
|         setValue(initialValue); | ||||
|     }, [initialValue]); | ||||
| 
 | ||||
|     return ( | ||||
|         <StyledContainer | ||||
|             ref={searchContainerRef} | ||||
| @ -189,6 +222,17 @@ export const Search = ({ | ||||
|                         getSearchContext={getSearchContext!} | ||||
|                     /> | ||||
|                 } | ||||
|                 elseShow={ | ||||
|                     showSuggestions && | ||||
|                     savedQuery && ( | ||||
|                         <SearchPaper className='dropdown-outline'> | ||||
|                             <SearchHistory | ||||
|                                 onSuggestion={onSearchChange} | ||||
|                                 savedQuery={savedQuery} | ||||
|                             /> | ||||
|                         </SearchPaper> | ||||
|                     ) | ||||
|                 } | ||||
|             /> | ||||
|         </StyledContainer> | ||||
|     ); | ||||
|  | ||||
| @ -0,0 +1,56 @@ | ||||
| import { FilterList, History } from '@mui/icons-material'; | ||||
| import { Box, Divider, Paper, styled } from '@mui/material'; | ||||
| import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; | ||||
| import { IGetSearchContextOutput } from 'hooks/useSearch'; | ||||
| import { VFC } from 'react'; | ||||
| import { StyledCode } from './SearchInstructions/SearchInstructions'; | ||||
| import { usePlausibleTracker } from 'hooks/usePlausibleTracker'; | ||||
| import { onEnter } from './onEnter'; | ||||
| 
 | ||||
| const StyledBox = styled(Box)(({ theme }) => ({ | ||||
|     display: 'flex', | ||||
|     gap: theme.spacing(2), | ||||
| })); | ||||
| 
 | ||||
| const StyledHistory = styled(History)(({ theme }) => ({ | ||||
|     color: theme.palette.text.secondary, | ||||
| })); | ||||
| interface ISearchHistoryProps { | ||||
|     onSuggestion: (suggestion: string) => void; | ||||
|     savedQuery?: string; | ||||
| } | ||||
| 
 | ||||
| export const SearchHistory: VFC<ISearchHistoryProps> = ({ | ||||
|     onSuggestion, | ||||
|     savedQuery, | ||||
| }) => { | ||||
|     const { trackEvent } = usePlausibleTracker(); | ||||
|     const onSavedQuery = () => { | ||||
|         onSuggestion(savedQuery || ''); | ||||
|         trackEvent('search-filter-suggestions', { | ||||
|             props: { | ||||
|                 eventType: 'saved query', | ||||
|             }, | ||||
|         }); | ||||
|     }; | ||||
| 
 | ||||
|     return ( | ||||
|         <ConditionallyRender | ||||
|             condition={Boolean(savedQuery)} | ||||
|             show={ | ||||
|                 <> | ||||
|                     <StyledBox> | ||||
|                         <StyledHistory /> | ||||
|                         <StyledCode | ||||
|                             tabIndex={0} | ||||
|                             onClick={onSavedQuery} | ||||
|                             onKeyDown={onEnter(onSavedQuery)} | ||||
|                         > | ||||
|                             <span>{savedQuery}</span> | ||||
|                         </StyledCode> | ||||
|                     </StyledBox> | ||||
|                 </> | ||||
|             } | ||||
|         /> | ||||
|     ); | ||||
| }; | ||||
| @ -7,7 +7,7 @@ import { | ||||
|     getFilterValues, | ||||
|     IGetSearchContextOutput, | ||||
| } from 'hooks/useSearch'; | ||||
| import { VFC } from 'react'; | ||||
| import React, { VFC } from 'react'; | ||||
| import { SearchDescription } from './SearchDescription/SearchDescription'; | ||||
| import { | ||||
|     SearchInstructions, | ||||
| @ -15,21 +15,8 @@ import { | ||||
| } from './SearchInstructions/SearchInstructions'; | ||||
| import { usePlausibleTracker } from 'hooks/usePlausibleTracker'; | ||||
| import { onEnter } from './onEnter'; | ||||
| 
 | ||||
| const StyledPaper = styled(Paper)(({ theme }) => ({ | ||||
|     position: 'absolute', | ||||
|     width: '100%', | ||||
|     left: 0, | ||||
|     top: '20px', | ||||
|     zIndex: 2, | ||||
|     padding: theme.spacing(4, 1.5, 1.5), | ||||
|     borderBottomLeftRadius: theme.spacing(1), | ||||
|     borderBottomRightRadius: theme.spacing(1), | ||||
|     boxShadow: '0px 8px 20px rgba(33, 33, 33, 0.15)', | ||||
|     fontSize: theme.fontSizes.smallBody, | ||||
|     color: theme.palette.text.secondary, | ||||
|     wordBreak: 'break-word', | ||||
| })); | ||||
| import { SearchHistory } from './SearchHistory'; | ||||
| import { SearchPaper } from '../Search'; | ||||
| 
 | ||||
| const StyledBox = styled(Box)(({ theme }) => ({ | ||||
|     display: 'flex', | ||||
| @ -127,36 +114,21 @@ export const SearchSuggestions: VFC<SearchSuggestionsProps> = ({ | ||||
|             }, | ||||
|         }); | ||||
|     }; | ||||
|     const onSavedQuery = () => { | ||||
|         onSuggestion(savedQuery || ''); | ||||
|         trackEvent('search-filter-suggestions', { | ||||
|             props: { | ||||
|                 eventType: 'saved query', | ||||
|             }, | ||||
|         }); | ||||
|     }; | ||||
| 
 | ||||
|     return ( | ||||
|         <StyledPaper className='dropdown-outline'> | ||||
|         <SearchPaper className='dropdown-outline'> | ||||
|             <ConditionallyRender | ||||
|                 condition={Boolean(savedQuery)} | ||||
|                 show={ | ||||
|                     <> | ||||
|                         <StyledBox> | ||||
|                             <StyledHistory /> | ||||
|                             <StyledCode | ||||
|                                 tabIndex={0} | ||||
|                                 onClick={onSavedQuery} | ||||
|                                 onKeyDown={onEnter(onSavedQuery)} | ||||
|                             > | ||||
|                                 <span>{savedQuery}</span> | ||||
|                             </StyledCode> | ||||
|                         </StyledBox> | ||||
|                         <SearchHistory | ||||
|                             onSuggestion={onSuggestion} | ||||
|                             savedQuery={savedQuery} | ||||
|                         /> | ||||
|                         <StyledDivider /> | ||||
|                     </> | ||||
|                 } | ||||
|             /> | ||||
| 
 | ||||
|             <StyledBox> | ||||
|                 <StyledFilterList /> | ||||
|                 <Box> | ||||
| @ -198,6 +170,6 @@ export const SearchSuggestions: VFC<SearchSuggestionsProps> = ({ | ||||
|                     <span>{suggestedTextSearch}</span> | ||||
|                 </StyledCode> | ||||
|             </Box> | ||||
|         </StyledPaper> | ||||
|         </SearchPaper> | ||||
|     ); | ||||
| }; | ||||
|  | ||||
| @ -282,6 +282,7 @@ const FeatureToggleListTableComponent: VFC = () => { | ||||
|                                                 tableState.query || '' | ||||
|                                             } | ||||
|                                             onChange={setSearchValue} | ||||
|                                             id='globalFeatureToggles' | ||||
|                                         /> | ||||
|                                         <PageHeader.Divider /> | ||||
|                                     </> | ||||
| @ -331,6 +332,7 @@ const FeatureToggleListTableComponent: VFC = () => { | ||||
|                             <Search | ||||
|                                 initialValue={tableState.query || ''} | ||||
|                                 onChange={setSearchValue} | ||||
|                                 id='globalFeatureToggles' | ||||
|                             /> | ||||
|                         } | ||||
|                     /> | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user