@@ -9,7 +9,9 @@ import InputLabel from '@material-ui/core/InputLabel';
99import CardActions from '@material-ui/core/CardActions' ;
1010import Card from '@material-ui/core/Card' ;
1111import CardContent from '@material-ui/core/CardContent' ;
12- import { FieldModel , searchStringToInitialFilters } from '../../utils' ;
12+ import { FieldModel , Filter , getOperatorsForField , searchStringToInitialFilters } from '../../utils' ;
13+ import KeyboardArrowDownIcon from '@material-ui/icons/KeyboardArrowDown' ;
14+ import { Box , Menu } from '@material-ui/core' ;
1315
1416const useStyles = makeStyles ( ( theme ) => ( {
1517 formControl : {
@@ -86,29 +88,31 @@ const useStyles = makeStyles((theme) => ({
8688} ) ) ;
8789
8890export declare type FilterFormProps = {
89- availableOperators : any ,
90- handleQuery : ( filters : string [ ] ) => void ,
91- setFilters : ( filters : string [ ] ) => void ,
91+ handleQuery : ( filters : Filter [ ] ) => void ,
92+ setFilters : ( filters : Filter [ ] ) => void ,
9293 handleClose ?: any ,
93- fieldTypeInfo : FieldModel [ ]
94+ fieldTypeInfo : FieldModel [ ] ,
95+ allowedGroupNames ?: string [ ] ,
96+ promotedFilters ?: Map < string , Filter [ ] >
9497}
9598
9699const FilterForm = ( props : FilterFormProps ) => {
97- const { availableOperators, handleQuery, setFilters, handleClose, fieldTypeInfo } = props
98- // TODO: this should use a typed class for Filter. see utils.ts
99- const [ filters , localSetFilters ] = useState ( searchStringToInitialFilters ( availableOperators ) ) ;
100+ const { handleQuery, setFilters, handleClose, fieldTypeInfo, allowedGroupNames, promotedFilters } = props
101+ const [ filters , localSetFilters ] = useState < Filter [ ] > ( searchStringToInitialFilters ( fieldTypeInfo . map ( ( x ) => x . name ) ) ) ;
100102 const [ highlightedInputs , setHighlightedInputs ] = useState < { [ index : number ] : { field : boolean , operator : boolean , value : boolean } } > ( { } ) ;
103+ const [ commonFilterMenuOpen , setCommonFilterMenuOpen ] = useState < boolean > ( false )
104+ const buttonRef = React . useRef ( null ) ;
101105
102106 const classes = useStyles ( ) ;
103107
104108 const handleAddFilter = ( ) => {
105- localSetFilters ( [ ...filters , { field : "" , operator : "" , value : "" } ] ) ;
109+ localSetFilters ( [ ...filters , new Filter ( ) ] ) ;
106110 } ;
107111
108112 const handleRemoveFilter = ( index ) => {
109113 // If it's the last filter, just reset its values to default empty values
110114 if ( filters . length === 1 ) {
111- localSetFilters ( [ { field : "" , operator : "" , value : "" } ] ) ;
115+ localSetFilters ( [ new Filter ( ) ] ) ;
112116 } else {
113117 // Otherwise, remove the filter normally
114118 localSetFilters (
@@ -119,9 +123,9 @@ const FilterForm = (props: FilterFormProps ) => {
119123 } } ;
120124
121125 const handleFilterChange = ( index , key , value ) => {
122- const newFilters = filters . map ( ( filter , i ) => {
126+ const newFilters = filters . map ( ( filter , i ) => {
123127 if ( i === index ) {
124- return { ...filter , [ key ] : value } ;
128+ return Object . assign ( new Filter ( ) , { ...filter , [ key ] : value } ) ;
125129 }
126130 return filter ;
127131 } ) ;
@@ -159,22 +163,51 @@ const handleSubmit = (event) => {
159163 }
160164 } ;
161165
166+ const handleMenuClose = ( ) => {
167+ setCommonFilterMenuOpen ( false )
168+ }
169+
170+ const handleMenuClick = ( filterLabel : string ) => {
171+ handleMenuClose ( )
172+ const f = promotedFilters . get ( filterLabel )
173+ let toAdd = [ ...filters ] . filter ( ( f ) => f . isEmpty ( ) )
174+ toAdd = Filter . deduplicate ( toAdd . concat ( f ) )
175+
176+ localSetFilters ( toAdd )
177+ }
178+
162179 return (
163180 < Card className = { classes . card } elevation = { 0 } >
164181 < form >
165182 < CardContent className = { classes . centeredContent } >
166183 < div className = { classes . addFilterExternalWrapper } >
184+ < Box padding = { '5px' } >
167185 < Button
168186 variant = "contained"
169187 color = "primary"
170188 onClick = { handleAddFilter }
171189 >
172190 Add Search Filter
173191 </ Button >
192+ < Button
193+ ref = { buttonRef }
194+ style = { { marginLeft : '5px' } }
195+ variant = "contained"
196+ color = "primary"
197+ hidden = { ! ! promotedFilters }
198+ onClick = { ( ) => setCommonFilterMenuOpen ( ! commonFilterMenuOpen ) }
199+ endIcon = { < KeyboardArrowDownIcon /> }
200+ >
201+ Common Filters
202+ </ Button >
203+ < Menu open = { commonFilterMenuOpen } onClose = { handleMenuClose } anchorEl = { buttonRef . current } >
204+ { Array . from ( promotedFilters ?. keys ( ) ) . map ( ( label ) => (
205+ < MenuItem key = { label } onClick = { ( e ) => handleMenuClick ( label ) } > { label } </ MenuItem >
206+ ) ) }
207+ </ Menu >
208+ </ Box >
174209 </ div >
175210
176- { /* TODO: this should read the FieldModel and interpret allowableValues, perhaps isMultiValued, etc. */ }
177- { /* TODO: consider also using something like FieldModel.supportsFilter */ }
178211 < div className = { classes . formScroll } >
179212 { filters . map ( ( filter , index ) => (
180213 < div key = { index } className = { `${ classes . filterRow } ` } >
@@ -190,9 +223,9 @@ const handleSubmit = (event) => {
190223 < MenuItem value = "" >
191224 < em > None</ em >
192225 </ MenuItem >
193- { Object . keys ( availableOperators ) . map ( ( field ) => (
194- < MenuItem key = { field } value = { field } >
195- { fieldTypeInfo . find ( obj => obj . name === field ) . label ?? field }
226+ { fieldTypeInfo . map ( ( field ) => (
227+ < MenuItem key = { field . name } value = { field . name } >
228+ { field . label ?? field . name }
196229 </ MenuItem >
197230 ) ) }
198231 </ Select >
@@ -211,8 +244,8 @@ const handleSubmit = (event) => {
211244 < em > None</ em >
212245 </ MenuItem >
213246
214- { availableOperators [ filter . field ] && availableOperators [ filter . field ] . type ? (
215- availableOperators [ filter . field ] . type . map ( ( operator ) => (
247+ { getOperatorsForField ( fieldTypeInfo . find ( obj => obj . name === filter . field ) ) ? (
248+ getOperatorsForField ( fieldTypeInfo . find ( obj => obj . name === filter . field ) ) . map ( ( operator ) => (
216249 < MenuItem key = { operator } value = { operator } >
217250 { operator }
218251 </ MenuItem >
@@ -234,8 +267,10 @@ const handleSubmit = (event) => {
234267 handleFilterChange ( index , "value" , event . target . value )
235268 }
236269 >
237- { /* TODO: remove this. Maybe make a free-text field?*/ }
238- < MenuItem value = "ONPRC" > ONPRC</ MenuItem >
270+ { allowedGroupNames ?. map ( ( gn ) => (
271+ < MenuItem value = "{gn}" > { gn } </ MenuItem >
272+ ) ) }
273+
239274 </ Select >
240275 </ FormControl >
241276 ) : fieldTypeInfo . find ( obj => obj . name === filter . field ) ?. allowableValues ?. length > 0 ? (
0 commit comments