@@ -10,12 +10,13 @@ import {
1010 TextInput ,
1111 ValidatedOptions
1212} from '@patternfly/react-core' ;
13- import { SearchIcon } from '@patternfly/react-icons' ;
13+ import { SearchIcon , CaretDownIcon } from '@patternfly/react-icons' ;
1414import { createFilterValue , FilterDefinition , FilterOption , FilterValue } from '../../model/filters' ;
1515import { getHTTPErrorDetails } from '../../utils/errors' ;
1616import { autoCompleteCache } from '../../utils/autocomplete-cache' ;
1717import { Indicator } from './filters-helper' ;
1818import { usePrevious } from '../../utils/previous-hook' ;
19+ import './autocomplete-filter.css' ;
1920
2021const optionsMenuID = 'options-menu-list' ;
2122const isMenuOption = ( elt ?: Element ) => {
@@ -40,16 +41,16 @@ export const AutocompleteFilter: React.FC<AutocompleteFilterProps> = ({
4041 const autocompleteContainerRef = React . useRef < HTMLDivElement | null > ( null ) ;
4142 const searchInputRef = React . useRef < HTMLInputElement | null > ( null ) ;
4243 const optionsRef = React . useRef < HTMLDivElement | null > ( null ) ;
43- const [ autocompleteOptions , setAutocompleteOptions ] = React . useState < FilterOption [ ] > ( [ ] ) ;
44- const [ isPopperVisible , setPopperVisible ] = React . useState ( false ) ;
44+ const [ options , setOptions ] = React . useState < FilterOption [ ] > ( [ ] ) ;
4545 const [ currentValue , setCurrentValue ] = React . useState < string > ( '' ) ;
4646 const previousFilterDefinition = usePrevious ( filterDefinition ) ;
4747
4848 React . useEffect ( ( ) => {
4949 if ( filterDefinition !== previousFilterDefinition ) {
5050 //reset filter value if definition has changed
5151 resetFilterValue ( ) ;
52- searchInputRef ?. current ?. focus ( ) ;
52+ searchInputRef . current ?. focus ( ) ;
53+ searchInputRef . current ?. setAttribute ( 'autocomplete' , 'off' ) ;
5354 autoCompleteCache . clear ( ) ;
5455 } else if ( _ . isEmpty ( currentValue ) ) {
5556 setIndicator ( ValidatedOptions . default ) ;
@@ -61,17 +62,12 @@ export const AutocompleteFilter: React.FC<AutocompleteFilterProps> = ({
6162 // eslint-disable-next-line react-hooks/exhaustive-deps
6263 } , [ currentValue , filterDefinition , setIndicator ] ) ;
6364
64- React . useEffect ( ( ) => {
65- // The menu is hidden if there are no options
66- setPopperVisible ( autocompleteOptions . length > 0 ) ;
67- } , [ autocompleteOptions ] ) ;
68-
6965 const resetFilterValue = React . useCallback ( ( ) => {
7066 setCurrentValue ( '' ) ;
71- setAutocompleteOptions ( [ ] ) ;
67+ setOptions ( [ ] ) ;
7268 setMessageWithDelay ( undefined ) ;
7369 setIndicator ( ValidatedOptions . default ) ;
74- } , [ setCurrentValue , setAutocompleteOptions , setMessageWithDelay , setIndicator ] ) ;
70+ } , [ setCurrentValue , setMessageWithDelay , setIndicator , setOptions ] ) ;
7571
7672 const addFilter = React . useCallback (
7773 ( option : FilterOption ) => {
@@ -90,14 +86,16 @@ export const AutocompleteFilter: React.FC<AutocompleteFilterProps> = ({
9086 setCurrentValue ( newValue ) ;
9187 filterDefinition
9288 . getOptions ( newValue )
93- . then ( setAutocompleteOptions )
89+ . then ( opts => {
90+ setOptions ( opts ) ;
91+ } )
9492 . catch ( err => {
9593 const errorMessage = getHTTPErrorDetails ( err ) ;
9694 setMessageWithDelay ( errorMessage ) ;
97- setAutocompleteOptions ( [ ] ) ;
95+ setOptions ( [ ] ) ;
9896 } ) ;
9997 } ,
100- [ setCurrentValue , filterDefinition , setAutocompleteOptions , setMessageWithDelay ]
98+ [ setOptions , setCurrentValue , filterDefinition , setMessageWithDelay ]
10199 ) ;
102100
103101 const onAutoCompleteOptionSelected = React . useCallback (
@@ -111,28 +109,28 @@ export const AutocompleteFilter: React.FC<AutocompleteFilterProps> = ({
111109 }
112110 } else {
113111 addFilter ( option ) ;
114- setAutocompleteOptions ( [ ] ) ;
112+ setOptions ( [ ] ) ;
115113 }
116114 } ,
117- [ addFilter , onAutoCompleteChange , filterDefinition , currentValue ]
115+ [ addFilter , onAutoCompleteChange , filterDefinition , currentValue , setOptions ]
118116 ) ;
119117
120118 const onAutoCompleteSelect = React . useCallback (
121119 ( e : React . MouseEvent < Element , MouseEvent > | undefined , itemId : string ) => {
122120 e ?. stopPropagation ( ) ;
123- const option = autocompleteOptions . find ( opt => opt . value === itemId ) ;
121+ const option = options . find ( opt => opt . value === itemId ) ;
124122 if ( ! option ) {
125123 return ;
126124 }
127125 onAutoCompleteOptionSelected ( option ) ;
128126 } ,
129- [ autocompleteOptions , onAutoCompleteOptionSelected ]
127+ [ options , onAutoCompleteOptionSelected ]
130128 ) ;
131129
132130 const onEnter = React . useCallback ( ( ) => {
133131 // Only one choice is present, consider this is what is desired
134- if ( autocompleteOptions . length === 1 ) {
135- onAutoCompleteOptionSelected ( autocompleteOptions [ 0 ] ) ;
132+ if ( options . length === 1 ) {
133+ onAutoCompleteOptionSelected ( options [ 0 ] ) ;
136134 return ;
137135 }
138136
@@ -150,7 +148,7 @@ export const AutocompleteFilter: React.FC<AutocompleteFilterProps> = ({
150148 }
151149 } ) ;
152150 } , [
153- autocompleteOptions ,
151+ options ,
154152 filterDefinition ,
155153 currentValue ,
156154 onAutoCompleteOptionSelected ,
@@ -166,7 +164,7 @@ export const AutocompleteFilter: React.FC<AutocompleteFilterProps> = ({
166164 // We need to skip a couple of render frames to get the new focused element
167165 setTimeout ( ( ) => {
168166 if ( ! isMenuOption ( document . activeElement || undefined ) ) {
169- setAutocompleteOptions ( [ ] ) ;
167+ setOptions ( [ ] ) ;
170168 }
171169 } , 50 ) ;
172170 } , [ ] ) ;
@@ -191,10 +189,10 @@ export const AutocompleteFilter: React.FC<AutocompleteFilterProps> = ({
191189 />
192190 }
193191 popper = {
194- < Menu ref = { optionsRef } onSelect = { onAutoCompleteSelect } >
192+ < Menu ref = { optionsRef } onSelect = { onAutoCompleteSelect } isScrollable = { options . length > 8 } >
195193 < MenuContent >
196194 < MenuList id = { optionsMenuID } >
197- { autocompleteOptions . map ( option => (
195+ { options . map ( option => (
198196 < MenuItem data-test = { option . value } itemId = { option . value } key = { option . name } onBlur = { onBlur } >
199197 { option . name }
200198 </ MenuItem >
@@ -203,11 +201,28 @@ export const AutocompleteFilter: React.FC<AutocompleteFilterProps> = ({
203201 </ MenuContent >
204202 </ Menu >
205203 }
206- isVisible = { isPopperVisible }
204+ isVisible = { ! _ . isEmpty ( options ) }
207205 enableFlip = { false }
208206 appendTo = { autocompleteContainerRef . current ! }
209207 />
210208 </ div >
209+ < Button
210+ data-test = "autocomplete-menu-button"
211+ id = "autocomplete-menu-button"
212+ variant = "control"
213+ aria-label = "show values"
214+ onClick = { ( ) =>
215+ setTimeout ( ( ) => {
216+ if ( _ . isEmpty ( options ) ) {
217+ onAutoCompleteChange ( currentValue ) ;
218+ } else {
219+ setOptions ( [ ] ) ;
220+ }
221+ } , 100 )
222+ }
223+ >
224+ < CaretDownIcon />
225+ </ Button >
211226 < Button
212227 data-test = "search-button"
213228 id = "search-button"
0 commit comments