1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
5 import React from 'react';
6 import { Dispatch, compose } from 'redux';
7 import { connect } from 'react-redux';
8 import { InjectedFormProps, formValueSelector } from 'redux-form';
9 import { CustomStyleRulesCallback } from 'common/custom-theme';
10 import { Grid, Button } from '@mui/material';
11 import { WithStyles } from '@mui/styles';
12 import withStyles from '@mui/styles/withStyles';
13 import { RootState } from 'store/store';
15 SEARCH_BAR_ADVANCED_FORM_NAME,
16 changeAdvancedFormProperty,
17 resetAdvancedFormProperty
18 } from 'store/search-bar/search-bar-actions';
19 import { PropertyValue } from 'models/search-bar';
20 import { ArvadosTheme } from 'common/custom-theme';
21 import { SearchBarKeyField, SearchBarValueField } from 'views-components/form-fields/search-bar-form-fields';
22 import { Chips } from 'components/chips/chips';
23 import { formatPropertyValue } from "common/formatters";
24 import { Vocabulary } from 'models/vocabulary';
25 import { connectVocabulary } from '../resource-properties-form/property-field-common';
26 import { isEqual } from 'lodash';
28 type CssRules = 'label' | 'button';
30 const styles: CustomStyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
32 color: theme.palette.grey["500"],
33 fontSize: '0.8125rem',
41 interface SearchBarAdvancedPropertiesViewDataProps {
45 propertyValues: PropertyValue;
46 fields: PropertyValue[];
47 vocabulary: Vocabulary;
50 interface SearchBarAdvancedPropertiesViewActionProps {
52 addProp: (propertyValues: PropertyValue, properties: PropertyValue[]) => void;
53 getAllFields: (propertyValues: PropertyValue[]) => PropertyValue[] | [];
56 type SearchBarAdvancedPropertiesViewProps = SearchBarAdvancedPropertiesViewDataProps
57 & SearchBarAdvancedPropertiesViewActionProps
58 & InjectedFormProps & WithStyles<CssRules>;
60 const selector = formValueSelector(SEARCH_BAR_ADVANCED_FORM_NAME);
61 const mapStateToProps = (state: RootState) => {
63 propertyValues: selector(state, 'key', 'value', 'keyID', 'valueID')
67 const mapDispatchToProps = (dispatch: Dispatch) => ({
68 setProps: (propertyValues: PropertyValue[]) => {
69 dispatch<any>(changeAdvancedFormProperty('properties', propertyValues));
71 addProp: (propertyValue: PropertyValue, properties: PropertyValue[]) => {
72 // Remove potential duplicates
73 properties = properties.filter(x => ! isEqual(
75 key: x.keyID || x.key,
76 value: x.valueID || x.value
78 key: propertyValue.keyID || propertyValue.key,
79 value: propertyValue.valueID || propertyValue.value
81 dispatch<any>(changeAdvancedFormProperty(
83 [...properties, propertyValue]
85 dispatch<any>(resetAdvancedFormProperty('key'));
86 dispatch<any>(resetAdvancedFormProperty('value'));
87 dispatch<any>(resetAdvancedFormProperty('keyID'));
88 dispatch<any>(resetAdvancedFormProperty('valueID'));
90 getAllFields: (fields: any) => {
91 return fields.getAll() || [];
95 export const SearchBarAdvancedPropertiesView = compose(
97 connect(mapStateToProps, mapDispatchToProps))(
99 ({ classes, fields, propertyValues, setProps, addProp, getAllFields, vocabulary }: SearchBarAdvancedPropertiesViewProps) =>
100 <Grid container item xs={12} spacing={2}>
101 <Grid item xs={2} className={classes.label}>Properties</Grid>
103 <SearchBarKeyField />
106 <SearchBarValueField />
108 <Grid container item xs={2} justifyContent='flex-end' alignItems="center">
109 <Button className={classes.button} onClick={() => addProp(propertyValues, getAllFields(fields))}
113 disabled={!Boolean(propertyValues.key && propertyValues.value)}>
118 <Grid container item xs={10} spacing={1}>
119 <Chips values={getAllFields(fields)}
122 getLabel={(field: PropertyValue) => formatPropertyValue(field, vocabulary)} />