@@ -9,7 +9,8 @@ import FormControl from '@mui/material/FormControl';
99import InputLabel from '@mui/material/InputLabel' ;
1010import CardActions from '@mui/material/CardActions' ;
1111import Card from '@mui/material/Card' ;
12- import { FieldModel , Filter , getOperatorsForField , searchStringToInitialFilters } from '../../utils' ;
12+ import { FieldModel , Filter , searchStringToInitialFilters } from '../../utils' ;
13+ import { OperatorKey , OperatorRegistry } from '../operators' ;
1314import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown' ;
1415import { Box , Menu } from '@mui/material' ;
1516import { styled } from '@mui/material/styles' ;
@@ -77,19 +78,22 @@ const SubmitAndExternal = styled('div')(({ theme }) => ({
7778
7879const FilterForm = ( props : FilterFormProps ) => {
7980 const { handleQuery, setFilters, handleClose, fieldTypeInfo, allowedGroupNames, promotedFilters } = props
80- const [ filters , localSetFilters ] = useState < Filter [ ] > ( searchStringToInitialFilters ( fieldTypeInfo . map ( ( x ) => x . name ) ) ) ;
81+ const initial = searchStringToInitialFilters ( fieldTypeInfo . map ( x => x . name ) )
82+ const [ filters , localSetFilters ] = useState < Filter [ ] > (
83+ initial . length ? initial : [ new Filter ( '' , OperatorKey . None , '' ) ]
84+ )
8185 const [ highlightedInputs , setHighlightedInputs ] = useState < { [ index : number ] : { field : boolean , operator : boolean , value : boolean } } > ( { } ) ;
8286 const [ commonFilterMenuOpen , setCommonFilterMenuOpen ] = useState < boolean > ( false )
8387 const buttonRef = React . useRef ( null ) ;
8488
8589 const handleAddFilter = ( ) => {
86- localSetFilters ( [ ...filters , new Filter ( ) ] ) ;
90+ localSetFilters ( [ ...filters , new Filter ( '' , OperatorKey . None , '' ) ] ) ;
8791 } ;
8892
8993 const handleRemoveFilter = ( index ) => {
9094 // If it's the last filter, just reset its values to default empty values
9195 if ( filters . length === 1 ) {
92- localSetFilters ( [ new Filter ( ) ] ) ;
96+ localSetFilters ( [ new Filter ( '' , OperatorKey . None , '' ) ] ) ;
9397 } else {
9498 // Otherwise, remove the filter normally
9599 localSetFilters (
@@ -103,14 +107,16 @@ const FilterForm = (props: FilterFormProps ) => {
103107 const handleFilterChange = ( index , key , value ) => {
104108 const newFilters = filters . map ( ( filter , i ) => {
105109 if ( i === index ) {
106- const updatedFilter = Object . assign ( new Filter ( ) , { ...filter , [ key ] : value } ) ;
110+ const updatedFilter = Object . assign ( new Filter ( '' , OperatorKey . None , '' ) , { ...filter , [ key ] : value } ) ;
107111
108112 if ( key === "operator" ) {
109- if ( value === "is empty" || value === "is not empty" ) {
113+ updatedFilter . operator = OperatorRegistry [ value as OperatorKey ] ;
114+
115+ if ( value === OperatorKey . IsEmpty || value === OperatorKey . IsNotEmpty ) {
110116 updatedFilter . value = '' ;
111117 }
112118
113- if ( value === "equals one of" || filter . operator === "equals one of" ) {
119+ if ( value === OperatorKey . EqualsOneOf || updatedFilter . operator . key === OperatorKey . EqualsOneOf ) {
114120 updatedFilter . value = '' ;
115121 }
116122 }
@@ -124,40 +130,49 @@ const FilterForm = (props: FilterFormProps ) => {
124130 } ;
125131
126132 const handleSubmit = ( event ) => {
127- event . preventDefault ( ) ;
128- const highlightedInputs = { } ;
129-
130- filters . forEach ( ( filter , index ) => {
131- highlightedInputs [ index ] = { field : false , operator : false , value : false } ;
133+ event . preventDefault ( )
134+ const highlighted : Record < number , { field : boolean ; operator : boolean ; value : boolean } > = { }
132135
133- filter . field = filter . field ?? '' ;
134- filter . operator = filter . operator ?? '' ;
135- filter . value = filter . value ?? '' ;
136-
137- if ( filter . field === '' ) {
138- highlightedInputs [ index ] . field = true ;
139- }
136+ filters . forEach ( ( filter , i ) => {
137+ highlighted [ i ] = { field : false , operator : false , value : false }
140138
141- if ( filter . operator === '' ) {
142- highlightedInputs [ index ] . operator = true ;
143- }
139+ filter . field = filter . field ?? ''
140+ filter . value = filter . value ?? ''
144141
145- if ( filter . operator === 'is empty' || filter . operator === 'is not empty' ) {
146- filter . value = '' ;
147- } else if ( filter . value === '' ) {
148- highlightedInputs [ index ] . value = true ;
149- }
150- } ) ;
142+ if ( ! filter . field ) {
143+ highlighted [ i ] . field = true
144+ }
151145
152- const isSingleEmptyFilter = filters . length === 1 && ! filters [ 0 ] . field && ! filters [ 0 ] . operator && ! filters [ 0 ] . value ;
146+ if ( ! filter . operator . key ) {
147+ highlighted [ i ] . operator = true
148+ }
153149
154- setHighlightedInputs ( highlightedInputs ) ;
155- if ( isSingleEmptyFilter || ! Object . values ( highlightedInputs ) . some ( v => ( v as any ) . field || ( v as any ) . operator || ( v as any ) . value ) ) {
156- handleQuery ( filters ) ;
157- setFilters ( filters ) ;
158- handleClose ( ) ;
150+ if (
151+ filter . operator . key === OperatorKey . IsEmpty ||
152+ filter . operator . key === OperatorKey . IsNotEmpty
153+ ) {
154+ filter . value = ''
155+ } else if ( ! filter . value ) {
156+ highlighted [ i ] . value = true
159157 }
160- } ;
158+ } )
159+
160+ const isSingleEmpty =
161+ filters . length === 1 &&
162+ ! filters [ 0 ] . field &&
163+ ! filters [ 0 ] . operator . key &&
164+ ! filters [ 0 ] . value
165+
166+ setHighlightedInputs ( highlighted )
167+ if (
168+ isSingleEmpty ||
169+ ! Object . values ( highlighted ) . some ( v => v . field || v . operator || v . value )
170+ ) {
171+ handleQuery ( filters )
172+ setFilters ( filters )
173+ handleClose ?.( )
174+ }
175+ }
161176
162177 const handleMenuClose = ( ) => {
163178 setCommonFilterMenuOpen ( false )
@@ -241,34 +256,33 @@ const FilterForm = (props: FilterFormProps ) => {
241256 />
242257 </ FormControlMinWidth >
243258
244- < FormControlMinWidth sx = { highlightedInputs [ index ] ?. operator ? highlightedSx : null } >
245- < InputLabel id = "operator-label" > Operator</ InputLabel >
246- < Select
247- labelId = "operator-label"
248- label = "Operator"
249- value = { filter . operator }
250- onChange = { ( event ) =>
251- handleFilterChange ( index , "operator" , event . target . value )
252- }
253- >
254- < MenuItem value = "None" style = { { display : 'none' } } >
255- < em > None</ em >
256- </ MenuItem >
257-
258- { getOperatorsForField ( fieldTypeInfo . find ( obj => obj . name === filter . field ) ) ? (
259- getOperatorsForField ( fieldTypeInfo . find ( obj => obj . name === filter . field ) ) . map ( ( operator ) => (
260- < MenuItem key = { operator } value = { operator } >
261- { operator }
262- </ MenuItem >
263- ) )
264- ) : (
265- < MenuItem > </ MenuItem >
266- ) }
267-
268- </ Select >
259+ < FormControlMinWidth sx = { highlightedInputs [ index ] ?. operator ? highlightedSx : null } >
260+ < InputLabel id = "operator-label" > Operator</ InputLabel >
261+ < Select
262+ labelId = "operator-label"
263+ label = "Operator"
264+ value = { filter . operator . key }
265+ onChange = { event =>
266+ handleFilterChange ( index , "operator" , event . target . value as OperatorKey )
267+ }
268+ >
269+ < MenuItem value = { OperatorKey . None } >
270+ < em > None</ em >
271+ </ MenuItem >
272+ { ( ( ) => {
273+ const ops = fieldTypeInfo . find ( f => f . name === filter . field ) ?. getOperators ( ) ?? [ ] ;
274+ return ops . length > 0
275+ ? ops . map ( op => (
276+ < MenuItem key = { op . key } value = { op . key } >
277+ { op . label }
278+ </ MenuItem >
279+ ) )
280+ : < MenuItem /> ;
281+ } ) ( ) }
282+ </ Select >
269283 </ FormControlMinWidth >
270284
271- { filter . operator === "equals one of" ? (
285+ { filter . operator . key === OperatorKey . EqualsOneOf ? (
272286 < FormControlMinWidth sx = { highlightedInputs [ index ] ?. value ? highlightedSx : null } >
273287 < InputLabel id = "value-select-label" > Value</ InputLabel >
274288 < Select
@@ -294,7 +308,7 @@ const FilterForm = (props: FilterFormProps ) => {
294308 noOptionsMessage = { ( ) => 'Type to search...' }
295309 menuPortalTarget = { document . body }
296310 menuPosition = { 'fixed' }
297- isDisabled = { filter . operator === "is empty" || filter . operator === "is not empty" }
311+ isDisabled = { filter . operator . key === OperatorKey . IsEmpty || filter . operator . key === OperatorKey . IsNotEmpty }
298312 menuShouldBlockScroll = { true }
299313 // See here: https://stackoverflow.com/questions/77625507/my-react-project-with-react-18-2-0-version-and-react-select-5-4-0-v
300314 styles = { { menuPortal : ( base : any ) => ( { ...base , zIndex : 9999 } ) } }
@@ -309,8 +323,12 @@ const FilterForm = (props: FilterFormProps ) => {
309323 . map ( value => ( { label : value , value} ) )
310324 ) ;
311325 } }
312- onChange = { ( selected ) => handleFilterChange ( index , "value" , selected ?. length > 0 ? selected . map ( s => s . value ) . join ( ',' ) : undefined ) }
313- value = { filter . value ? filter . value . split ( ',' ) . map ( value => ( { label : value , value} ) ) : undefined }
326+ onChange = { ( selected ) => {
327+ const arr = Array . isArray ( selected ) ? selected : [ selected ] . filter ( Boolean )
328+ const val = arr . map ( s => s . value ) . join ( ',' )
329+ handleFilterChange ( index , 'value' , val )
330+ } }
331+ value = { filter . value ? ( filter . value as string ) . split ( ',' ) . map ( value => ( { label : value , value} ) ) : undefined }
314332 />
315333 </ FormControlMinWidth >
316334 ) : fieldTypeInfo . find ( obj => obj . name === filter . field ) ?. allowableValues ?. length > 0 ? (
@@ -321,7 +339,7 @@ const FilterForm = (props: FilterFormProps ) => {
321339 label = "Value"
322340 id = { `value-select-${ index } ` }
323341 value = { filter . value }
324- disabled = { filter . operator === "is empty" || filter . operator === "is not empty" }
342+ disabled = { filter . operator . key === OperatorKey . IsEmpty || filter . operator . key === OperatorKey . IsNotEmpty }
325343 onChange = { ( event ) =>
326344 handleFilterChange ( index , "value" , event . target . value )
327345 }
@@ -340,7 +358,7 @@ const FilterForm = (props: FilterFormProps ) => {
340358 sx = { highlightedInputs [ index ] ?. value ? highlightedSx : null }
341359 variant = "outlined"
342360 value = { filter . value }
343- disabled = { filter . operator === "is empty" || filter . operator === "is not empty" }
361+ disabled = { filter . operator . key === OperatorKey . IsEmpty || filter . operator . key === OperatorKey . IsNotEmpty }
344362 onChange = { ( event ) =>
345363 handleFilterChange ( index , 'value' , event . target . value )
346364 }
0 commit comments