21720: changed inline prop in typographies
[arvados.git] / services / workbench2 / src / views-components / search-bar / search-bar-advanced-properties-view.tsx
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
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, withStyles, WithStyles, Button } from '@material-ui/core';
11 import { RootState } from 'store/store';
12 import {
13     SEARCH_BAR_ADVANCED_FORM_NAME,
14     changeAdvancedFormProperty,
15     resetAdvancedFormProperty
16 } from 'store/search-bar/search-bar-actions';
17 import { PropertyValue } from 'models/search-bar';
18 import { ArvadosTheme } from 'common/custom-theme';
19 import { SearchBarKeyField, SearchBarValueField } from 'views-components/form-fields/search-bar-form-fields';
20 import { Chips } from 'components/chips/chips';
21 import { formatPropertyValue } from "common/formatters";
22 import { Vocabulary } from 'models/vocabulary';
23 import { connectVocabulary } from '../resource-properties-form/property-field-common';
24 import { isEqual } from 'lodash';
25
26 type CssRules = 'label' | 'button';
27
28 const styles: CustomStyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
29     label: {
30         color: theme.palette.grey["500"],
31         fontSize: '0.8125rem',
32         alignSelf: 'center'
33     },
34     button: {
35         boxShadow: 'none'
36     }
37 });
38
39 interface SearchBarAdvancedPropertiesViewDataProps {
40     submitting: boolean;
41     invalid: boolean;
42     pristine: boolean;
43     propertyValues: PropertyValue;
44     fields: PropertyValue[];
45     vocabulary: Vocabulary;
46 }
47
48 interface SearchBarAdvancedPropertiesViewActionProps {
49     setProps: () => void;
50     addProp: (propertyValues: PropertyValue, properties: PropertyValue[]) => void;
51     getAllFields: (propertyValues: PropertyValue[]) => PropertyValue[] | [];
52 }
53
54 type SearchBarAdvancedPropertiesViewProps = SearchBarAdvancedPropertiesViewDataProps
55     & SearchBarAdvancedPropertiesViewActionProps
56     & InjectedFormProps & WithStyles<CssRules>;
57
58 const selector = formValueSelector(SEARCH_BAR_ADVANCED_FORM_NAME);
59 const mapStateToProps = (state: RootState) => {
60     return {
61         propertyValues: selector(state, 'key', 'value', 'keyID', 'valueID')
62     };
63 };
64
65 const mapDispatchToProps = (dispatch: Dispatch) => ({
66     setProps: (propertyValues: PropertyValue[]) => {
67         dispatch<any>(changeAdvancedFormProperty('properties', propertyValues));
68     },
69     addProp: (propertyValue: PropertyValue, properties: PropertyValue[]) => {
70         // Remove potential duplicates
71         properties = properties.filter(x => ! isEqual(
72             {
73                 key: x.keyID || x.key,
74                 value: x.valueID || x.value
75             }, {
76                 key: propertyValue.keyID || propertyValue.key,
77                 value: propertyValue.valueID || propertyValue.value
78             }));
79         dispatch<any>(changeAdvancedFormProperty(
80             'properties',
81             [...properties, propertyValue]
82         ));
83         dispatch<any>(resetAdvancedFormProperty('key'));
84         dispatch<any>(resetAdvancedFormProperty('value'));
85         dispatch<any>(resetAdvancedFormProperty('keyID'));
86         dispatch<any>(resetAdvancedFormProperty('valueID'));
87     },
88     getAllFields: (fields: any) => {
89         return fields.getAll() || [];
90     }
91 });
92
93 export const SearchBarAdvancedPropertiesView = compose(
94     connectVocabulary,
95     connect(mapStateToProps, mapDispatchToProps))(
96     withStyles(styles)(
97         ({ classes, fields, propertyValues, setProps, addProp, getAllFields, vocabulary }: SearchBarAdvancedPropertiesViewProps) =>
98             <Grid container item xs={12} spacing={2}>
99                 <Grid item xs={2} className={classes.label}>Properties</Grid>
100                 <Grid item xs={4}>
101                     <SearchBarKeyField />
102                 </Grid>
103                 <Grid item xs={4}>
104                     <SearchBarValueField />
105                 </Grid>
106                 <Grid container item xs={2} justify='flex-end' alignItems="center">
107                     <Button className={classes.button} onClick={() => addProp(propertyValues, getAllFields(fields))}
108                         color="primary"
109                         size='small'
110                         variant="contained"
111                         disabled={!Boolean(propertyValues.key && propertyValues.value)}>
112                         Add
113                     </Button>
114                 </Grid>
115                 <Grid item xs={2} />
116                 <Grid container item xs={10} spacing={1}>
117                     <Chips values={getAllFields(fields)}
118                         deletable
119                         onChange={setProps}
120                         getLabel={(field: PropertyValue) => formatPropertyValue(field, vocabulary)} />
121                 </Grid>
122             </Grid>
123     )
124 );