@dartech/arsenal-ui 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. package/.babelrc +12 -0
  2. package/.eslintrc.json +22 -0
  3. package/README.md +7 -0
  4. package/index.ts +3 -0
  5. package/jest.config.js +9 -0
  6. package/package.json +21 -0
  7. package/project.json +69 -0
  8. package/rollup.config.js +135 -0
  9. package/src/interfaces/common.ts +12 -0
  10. package/src/interfaces/definition.ts +143 -0
  11. package/src/interfaces/index.ts +3 -0
  12. package/src/interfaces/ui.ts +35 -0
  13. package/src/lib/Alert/Alert.tsx +108 -0
  14. package/src/lib/Alert/index.ts +1 -0
  15. package/src/lib/Definition/CreateDefinition/CreateDefinition.tsx +74 -0
  16. package/src/lib/Definition/CreateDefinition/index.ts +1 -0
  17. package/src/lib/Definition/DefinitionFiller/DefinitionFiller.tsx +85 -0
  18. package/src/lib/Definition/DefinitionFiller/WidgetDefinitionFiller.tsx +96 -0
  19. package/src/lib/Definition/DefinitionFiller/index.ts +2 -0
  20. package/src/lib/Definition/index.ts +2 -0
  21. package/src/lib/DemPropertyField/DemPropertyField.tsx +93 -0
  22. package/src/lib/DemPropertyField/DemPropertyView/DemPropertyView.tsx +44 -0
  23. package/src/lib/DemPropertyField/DemPropertyView/index.ts +1 -0
  24. package/src/lib/DemPropertyField/MultipleDemField/MultipleDemField.tsx +293 -0
  25. package/src/lib/DemPropertyField/MultipleDemField/index.tsx +1 -0
  26. package/src/lib/DemPropertyField/RestrictedValuesEditor.tsx +63 -0
  27. package/src/lib/DemPropertyField/SingleDemField/SingleDemField.tsx +156 -0
  28. package/src/lib/DemPropertyField/SingleDemField/index.ts +1 -0
  29. package/src/lib/DemPropertyField/index.ts +2 -0
  30. package/src/lib/DemPropertyField/styles.ts +50 -0
  31. package/src/lib/DemPropertyField/widgets/DemBooleanWidget.tsx +26 -0
  32. package/src/lib/DemPropertyField/widgets/DemDateTimeWidget.tsx +34 -0
  33. package/src/lib/DemPropertyField/widgets/DemDateWidget.tsx +33 -0
  34. package/src/lib/DemPropertyField/widgets/DemFieldWidget.tsx +67 -0
  35. package/src/lib/DemPropertyField/widgets/DemFloatWidget.tsx +49 -0
  36. package/src/lib/DemPropertyField/widgets/DemIntegerWidget.tsx +63 -0
  37. package/src/lib/DemPropertyField/widgets/DemJsonWidget.tsx +33 -0
  38. package/src/lib/DemPropertyField/widgets/DemStringWidget.tsx +35 -0
  39. package/src/lib/DemPropertyField/widgets/DemTimeWidget.tsx +46 -0
  40. package/src/lib/DemPropertyField/widgets/index.ts +1 -0
  41. package/src/lib/Forms/BackButton.tsx +45 -0
  42. package/src/lib/Forms/ControlAceEditor.tsx +103 -0
  43. package/src/lib/Forms/ControlAutocomplete.tsx +134 -0
  44. package/src/lib/Forms/ControlCheckbox.tsx +57 -0
  45. package/src/lib/Forms/ControlDebouncedInput.tsx +69 -0
  46. package/src/lib/Forms/ControlInput.tsx +102 -0
  47. package/src/lib/Forms/ControlNumberInput.tsx +144 -0
  48. package/src/lib/Forms/ControlRadioBtn.tsx +46 -0
  49. package/src/lib/Forms/ControlSelect.tsx +135 -0
  50. package/src/lib/Forms/CopyButton.tsx +49 -0
  51. package/src/lib/Forms/index.ts +10 -0
  52. package/src/lib/InfoItem/InfoItem.tsx +39 -0
  53. package/src/lib/InfoItem/index.ts +1 -0
  54. package/src/lib/InfoItem/styles.ts +17 -0
  55. package/src/lib/JsonPathPicker/JsonPathPicker.tsx +71 -0
  56. package/src/lib/JsonPathPicker/PropertyStep.tsx +74 -0
  57. package/src/lib/JsonPathPicker/index.ts +1 -0
  58. package/src/lib/JsonView/JsonView.tsx +43 -0
  59. package/src/lib/JsonView/index.ts +1 -0
  60. package/src/lib/Loader/Loader.tsx +41 -0
  61. package/src/lib/Loader/index.ts +1 -0
  62. package/src/lib/Modals/JsonModalView.tsx +52 -0
  63. package/src/lib/Modals/index.ts +1 -0
  64. package/src/lib/Property/PropertyValueField/BooleanValueField.tsx +41 -0
  65. package/src/lib/Property/PropertyValueField/DateTimeValueField.tsx +59 -0
  66. package/src/lib/Property/PropertyValueField/DateValueField.tsx +59 -0
  67. package/src/lib/Property/PropertyValueField/EntityValueField.tsx +33 -0
  68. package/src/lib/Property/PropertyValueField/JsonValueField.tsx +64 -0
  69. package/src/lib/Property/PropertyValueField/PropertyValue.tsx +97 -0
  70. package/src/lib/Property/PropertyValueField/PropertyValueField.tsx +86 -0
  71. package/src/lib/Property/PropertyValueField/StringValueField.tsx +21 -0
  72. package/src/lib/Property/PropertyValueField/TimeValueField.tsx +68 -0
  73. package/src/lib/Property/PropertyValueField/ValueComponent.tsx +63 -0
  74. package/src/lib/Property/PropertyValueField/index.ts +1 -0
  75. package/src/lib/Property/PropertyWidget/PropertyWidget.tsx +167 -0
  76. package/src/lib/Property/PropertyWidget/index.ts +1 -0
  77. package/src/lib/Property/UpsertProperty/CreatePropertiesList.tsx +131 -0
  78. package/src/lib/Property/UpsertProperty/CreatePropertyFormFields.tsx +147 -0
  79. package/src/lib/Property/UpsertProperty/CustomPropertyField.tsx +40 -0
  80. package/src/lib/Property/UpsertProperty/PropertyAdditionalFields/BigDecimalPropertyFields.tsx +41 -0
  81. package/src/lib/Property/UpsertProperty/PropertyAdditionalFields/DateAdditionalFields.tsx +27 -0
  82. package/src/lib/Property/UpsertProperty/PropertyAdditionalFields/EntityAdditionalFields.tsx +133 -0
  83. package/src/lib/Property/UpsertProperty/PropertyAdditionalFields/EntityReferencePropertyFields.tsx +46 -0
  84. package/src/lib/Property/UpsertProperty/PropertyAdditionalFields/PropertyAdditionalFields.tsx +52 -0
  85. package/src/lib/Property/UpsertProperty/PropertyAdditionalFields/StringPropertyFields.tsx +98 -0
  86. package/src/lib/Property/UpsertProperty/PropertyAdditionalFields/index.ts +1 -0
  87. package/src/lib/Property/UpsertProperty/index.ts +2 -0
  88. package/src/lib/Property/UpsertProperty/useCustomFields.ts +22 -0
  89. package/src/lib/Property/ViewPropertiesList/ViewPropertiesList.tsx +50 -0
  90. package/src/lib/Property/ViewPropertiesList/index.ts +1 -0
  91. package/src/lib/Property/ViewProperty/EntityPropertiesShortView.tsx +41 -0
  92. package/src/lib/Property/ViewProperty/EntityPropertiesView.tsx +48 -0
  93. package/src/lib/Property/ViewProperty/PropertyDataTable.tsx +139 -0
  94. package/src/lib/Property/ViewProperty/PropertyItem.tsx +46 -0
  95. package/src/lib/Property/ViewProperty/ViewProperty.tsx +52 -0
  96. package/src/lib/Property/ViewProperty/index.ts +1 -0
  97. package/src/lib/Property/index.ts +4 -0
  98. package/src/lib/Status/Status.tsx +15 -0
  99. package/src/lib/Status/index.ts +1 -0
  100. package/src/lib/Status/styles.ts +14 -0
  101. package/src/lib/Table/Table.tsx +116 -0
  102. package/src/lib/Table/TableColumnMenu.tsx +12 -0
  103. package/src/lib/Table/TablePagination.tsx +42 -0
  104. package/src/lib/Table/index.ts +1 -0
  105. package/src/lib/Table/styles.ts +59 -0
  106. package/src/lib/Table/usePagination.ts +15 -0
  107. package/src/lib/Table/useTableQueryPagination.ts +49 -0
  108. package/src/lib/Table/useTableQuerySorting.ts +52 -0
  109. package/src/lib/Tabs/RouteTabs.tsx +54 -0
  110. package/src/lib/Tabs/TabPanel.tsx +42 -0
  111. package/src/lib/Tabs/index.ts +2 -0
  112. package/src/lib/TemplateContent/ExpressionDecorator.tsx +7 -0
  113. package/src/lib/TemplateContent/TemplateContentEditor.tsx +144 -0
  114. package/src/lib/TemplateContent/index.ts +1 -0
  115. package/src/lib/index.ts +14 -0
  116. package/src/utils/common.ts +68 -0
  117. package/src/utils/dem.ts +78 -0
  118. package/src/utils/hooks.ts +41 -0
  119. package/src/utils/index.ts +5 -0
  120. package/src/utils/ui-utils.tsx +71 -0
  121. package/src/utils/validators.ts +130 -0
  122. package/tsconfig.json +24 -0
  123. package/tsconfig.lib.json +22 -0
  124. package/tsconfig.spec.json +19 -0
@@ -0,0 +1,85 @@
1
+ import Box from '@material-ui/core/Box';
2
+ import Grid from '@material-ui/core/Grid';
3
+ import Stepper from '@material-ui/core/Stepper';
4
+ import Step from '@material-ui/core/Step';
5
+ import StepLabel from '@material-ui/core/StepLabel';
6
+ import StepContent from '@material-ui/core/StepContent';
7
+ import StepConnector from '@material-ui/core/StepConnector';
8
+
9
+ import PropertyValue from '../../Property/PropertyValueField/PropertyValue';
10
+ import { PropertiesArrayType } from '../../../interfaces';
11
+ import { makeStyles } from '@material-ui/core';
12
+
13
+ type Props = {
14
+ properties: PropertiesArrayType;
15
+ dataFieldName: string;
16
+ };
17
+
18
+ const useStyles = makeStyles(() => ({
19
+ content: {
20
+ marginLeft: '4px',
21
+ },
22
+ connector: {
23
+ marginLeft: '4px',
24
+ },
25
+ stepper: {
26
+ padding: '12px',
27
+ },
28
+ label: {
29
+ display: 'flex',
30
+ alignItems: 'flex-start',
31
+ },
32
+ }));
33
+
34
+ const StepIcon = () => (
35
+ <div
36
+ style={{
37
+ display: 'inline-block',
38
+ width: '10px',
39
+ height: '10px',
40
+ borderRadius: '50%',
41
+ backgroundColor: '#536DFE',
42
+ marginTop: '5px',
43
+ }}
44
+ />
45
+ );
46
+
47
+ export const DefinitionFiller = ({ properties, dataFieldName }: Props) => {
48
+ const classes = useStyles();
49
+
50
+ return (
51
+ <Grid container item direction="column" spacing={2}>
52
+ {properties?.length ? (
53
+ <Stepper
54
+ nonLinear
55
+ orientation="vertical"
56
+ className={classes.stepper}
57
+ connector={<StepConnector className={classes.connector} />}
58
+ >
59
+ {properties.map((property, index) => (
60
+ <Step expanded key={index}>
61
+ <StepLabel
62
+ className={classes.label}
63
+ StepIconComponent={StepIcon}
64
+ StepIconProps={{ icon: '', completed: false, active: true }}
65
+ >
66
+ <Box display="flex" flexDirection="column">
67
+ <b>{property.name}</b>
68
+ <span>
69
+ {property.propertyType} | Key: {property.key}
70
+ </span>
71
+ </Box>
72
+ </StepLabel>
73
+ <StepContent className={classes.content}>
74
+ <PropertyValue name={`${dataFieldName}.${property.key}`} property={property} label={property.name} />
75
+ </StepContent>
76
+ </Step>
77
+ ))}
78
+ <Step />
79
+ </Stepper>
80
+ ) : null}
81
+ </Grid>
82
+ );
83
+ };
84
+
85
+ export default DefinitionFiller;
@@ -0,0 +1,96 @@
1
+ import Box from '@material-ui/core/Box';
2
+ import Grid from '@material-ui/core/Grid';
3
+ import Stepper from '@material-ui/core/Stepper';
4
+ import Step from '@material-ui/core/Step';
5
+ import StepLabel from '@material-ui/core/StepLabel';
6
+ import StepContent from '@material-ui/core/StepContent';
7
+ import StepConnector from '@material-ui/core/StepConnector';
8
+
9
+ import { useMemo } from 'react';
10
+ import { makeStyles } from '@material-ui/core';
11
+ import { PropertiesArrayType, PropertiesObjectType } from '../../../interfaces';
12
+ import { PropertyWidget } from '../../Property/PropertyWidget';
13
+ import { propertiesObjectToArray } from '../../../utils';
14
+
15
+ type Props = {
16
+ properties: PropertiesArrayType | PropertiesObjectType;
17
+ dataFieldName: string;
18
+ nullable?: boolean;
19
+ };
20
+
21
+ const useStyles = makeStyles(() => ({
22
+ content: {
23
+ marginLeft: '4px',
24
+ paddingLeft: '14px',
25
+ },
26
+ connector: {
27
+ marginLeft: '4px',
28
+ },
29
+ stepper: {
30
+ padding: '12px',
31
+ },
32
+ label: {
33
+ display: 'flex',
34
+ alignItems: 'flex-start',
35
+ },
36
+ }));
37
+
38
+ const StepIcon = () => (
39
+ <div
40
+ style={{
41
+ display: 'inline-block',
42
+ width: '10px',
43
+ height: '10px',
44
+ borderRadius: '50%',
45
+ backgroundColor: '#536DFE',
46
+ marginTop: '5px',
47
+ }}
48
+ />
49
+ );
50
+
51
+ export const WidgetDefinitionFiller = ({ properties, dataFieldName, nullable = false }: Props) => {
52
+ const classes = useStyles();
53
+
54
+ const propertiesList = useMemo(() => {
55
+ if (Array.isArray(properties)) {
56
+ return propertiesObjectToArray(properties);
57
+ }
58
+ return properties;
59
+ }, [properties]);
60
+
61
+ return (
62
+ <Grid container item direction="column" spacing={2}>
63
+ {propertiesList?.length ? (
64
+ <Stepper
65
+ nonLinear
66
+ orientation="vertical"
67
+ className={classes.stepper}
68
+ connector={<StepConnector className={classes.connector} />}
69
+ >
70
+ {(propertiesList as PropertiesArrayType).map((property, index) => (
71
+ <Step expanded key={index}>
72
+ <StepLabel
73
+ className={classes.label}
74
+ StepIconComponent={StepIcon}
75
+ StepIconProps={{ icon: '', completed: false, active: true }}
76
+ >
77
+ <Box display="flex" flexDirection="column">
78
+ <b>{property.name}</b>
79
+ <span>
80
+ {property.propertyType} | Key: {property.key}
81
+ </span>
82
+ </Box>
83
+ </StepLabel>
84
+ <StepContent className={classes.content}>
85
+ <PropertyWidget property={property} nullable={nullable} name={`${dataFieldName}.${property.key}`} />
86
+ </StepContent>
87
+ </Step>
88
+ ))}
89
+ <Step />
90
+ </Stepper>
91
+ ) : null}
92
+ </Grid>
93
+ );
94
+ };
95
+
96
+ export default WidgetDefinitionFiller;
@@ -0,0 +1,2 @@
1
+ export * from './DefinitionFiller';
2
+ export * from './WidgetDefinitionFiller';
@@ -0,0 +1,2 @@
1
+ export * from './CreateDefinition';
2
+ export * from './DefinitionFiller';
@@ -0,0 +1,93 @@
1
+ import { useMemo } from 'react';
2
+ import { Control } from 'react-hook-form';
3
+ import { PropertyUnion } from '../../interfaces';
4
+ import { MultipleDemField } from './MultipleDemField';
5
+ import { SingleDemField } from './SingleDemField';
6
+
7
+ /**
8
+ * This interface is referencing the [[DemPropertyField]] component props.
9
+ * @category DEM Property Field
10
+ */
11
+ export interface DemPropertyFieldProps {
12
+ /**
13
+ * Material-UI TextField `variant` prop
14
+ */
15
+ variant?: 'standard' | 'outlined' | 'filled';
16
+ /**
17
+ * Parent field name for nest field
18
+ */
19
+ parentKey?: string;
20
+ /**
21
+ * propKey for React Hook Form control name propery
22
+ */
23
+ propKey: string;
24
+ /**
25
+ * React Hook Form `control`
26
+ */
27
+ control: Control<any>;
28
+ /**
29
+ * React Hook Form `errors` object
30
+ */
31
+ errors: Record<string, any>;
32
+ /**
33
+ * Is readOnly field flag
34
+ */
35
+ readOnly?: boolean;
36
+ /**
37
+ * Is nullable value flag
38
+ */
39
+ isNullable?: boolean;
40
+ /**
41
+ * DEM property
42
+ */
43
+ property: PropertyUnion;
44
+ /**
45
+ * @ignore Validation function for JSON type field
46
+ */
47
+ jsonValidator?: (attrs: { name: string; errors: any[] }) => void;
48
+ hasBooleanProperties?: boolean;
49
+ /**
50
+ * React Hook Form `watch` function
51
+ */
52
+ watch?: any;
53
+ hideCopy?: boolean;
54
+ }
55
+ /**
56
+ * Main DEM property field component
57
+ * @category DEM Property Field
58
+ */
59
+ export const DemPropertyField = ({ propKey, property, parentKey }: DemPropertyFieldProps) => {
60
+ const name = useMemo(() => (parentKey ? `${parentKey}.${propKey}` : propKey), [propKey, parentKey]);
61
+ const label = useMemo(() => `${property?.name || propKey} ${property?.isRequired ? '*' : ''}`, [propKey, property]);
62
+
63
+ // const propsKeys = useMemo(() => {
64
+ // if (property?.properties) {
65
+ // const { properties } = property;
66
+ // return Object.keys(properties).sort((keyA, keyB) => properties[keyA].sortOrder - properties[keyB].sortOrder);
67
+ // }
68
+ // return [];
69
+ // }, [property]);
70
+
71
+ if (property.isMultiple) {
72
+ return <MultipleDemField property={property} name={name} label={label} />;
73
+ } else {
74
+ return <SingleDemField property={property} name={name} label={label} />;
75
+ }
76
+
77
+ // case EntityPropertyTypes.ENTITY: {
78
+ // return (
79
+ // <Box marginLeft={parentKey ? 2 : 0} paddingY={parentKey ? 4 : 0}>
80
+ // <Typography variant="subtitle1">{property.name}</Typography>
81
+ // {propsKeys.map((key) => (
82
+ // <DemPropertyField
83
+ // propKey={key}
84
+ // control={control}
85
+ // property={property.properties[key]}
86
+ // errors={errors}
87
+ // parentKey={name}
88
+ // />
89
+ // ))}
90
+ // </Box>
91
+ // );
92
+ // }
93
+ };
@@ -0,0 +1,44 @@
1
+ import Grid from '@material-ui/core/Grid';
2
+ import { InfoItem } from '../../InfoItem';
3
+
4
+ import { PropertyUnion } from '../../../interfaces';
5
+ import { useMemo } from 'react';
6
+
7
+ type Props = {
8
+ property: PropertyUnion;
9
+ value: any;
10
+ };
11
+
12
+ export const DemPropertyView = ({ property, value }: Props) => {
13
+ const infoProps = useMemo(() => {
14
+ const res: { title: string; text?: string; json?: any } = {
15
+ title: '',
16
+ };
17
+
18
+ if (property && value) {
19
+ res.title = property.name;
20
+
21
+ switch (property.propertyType) {
22
+ case 'JSON':
23
+ res.json = JSON.stringify(value, null, 2);
24
+ break;
25
+ case 'BOOLEAN':
26
+ res.json = value.toString();
27
+ break;
28
+ default:
29
+ res.text = value;
30
+ break;
31
+ }
32
+ }
33
+
34
+ return res;
35
+ }, [property, value]);
36
+
37
+ return (
38
+ <Grid item xs={12}>
39
+ <InfoItem {...infoProps} />
40
+ </Grid>
41
+ );
42
+ };
43
+
44
+ export default DemPropertyView;
@@ -0,0 +1 @@
1
+ export * from './DemPropertyView';
@@ -0,0 +1,293 @@
1
+ import Grid from '@material-ui/core/Grid';
2
+ import Button from '@material-ui/core/Button';
3
+ import MenuItem from '@material-ui/core/MenuItem';
4
+ import TextField from '@material-ui/core/TextField';
5
+ import Typography from '@material-ui/core/Typography';
6
+ import CloseIcon from '@material-ui/icons/Close';
7
+ import IconButton from '@material-ui/core/IconButton';
8
+ import { DemFieldWidget } from '../widgets';
9
+
10
+ import { useEffect, useState } from 'react';
11
+ import { useController, useFormContext } from 'react-hook-form';
12
+ import { validateJson } from '../../../utils';
13
+ import useStyles from '../styles';
14
+
15
+ import { PropertyUnion } from '../../../interfaces';
16
+
17
+ type Props = {
18
+ property: PropertyUnion;
19
+ name: string;
20
+ label: string;
21
+ };
22
+
23
+ type MainFillOptions = 'null' | 'expression' | 'widgets';
24
+
25
+ const fillOptionsDefault = [
26
+ { value: 'null', label: 'NULL' },
27
+ { value: 'expression', label: 'Expression' },
28
+ { value: 'widget', label: 'Widget' },
29
+ ];
30
+
31
+ const replaceArrayItem = (arr, value, index) => {
32
+ const newArr = [...arr];
33
+ newArr[index] = value;
34
+ return newArr;
35
+ };
36
+
37
+ const removeArrayItem = (arr, index) => {
38
+ const newArr = [...arr];
39
+ newArr.splice(index, 1);
40
+ return newArr;
41
+ };
42
+
43
+ export const MultipleDemField = ({ property, label, name }: Props) => {
44
+ const classes = useStyles();
45
+ const { setValue, getValues, setError, clearErrors, control } = useFormContext();
46
+ const {
47
+ fieldState: { error },
48
+ } = useController({
49
+ name,
50
+ control,
51
+ });
52
+
53
+ const [mainFillOptions, setMainFillOptions] = useState([
54
+ { value: 'expression', label: 'Expression' },
55
+ { value: 'widgets', label: 'Array of Values' },
56
+ ]);
57
+ const [mainFillOption, setMainFillOption] = useState<MainFillOptions>(null);
58
+ const [mainExpression, setMainExpression] = useState('');
59
+ const [fillOptions, setFillOptions] = useState(fillOptionsDefault);
60
+ const [valuesFillOptions, setValuesFillOptions] = useState([]);
61
+ const [values, setValues] = useState([]);
62
+
63
+ const handleMainFillOptionChange = (e) => {
64
+ const { value } = e.target;
65
+ setMainFillOption(value);
66
+ clearErrors(name);
67
+
68
+ if (value === 'null') {
69
+ setValue(name, null);
70
+ }
71
+ };
72
+
73
+ const handleMainExpressionChange = (e) => {
74
+ const { value } = e.target;
75
+ setMainExpression(value);
76
+ setValue(name, value);
77
+
78
+ if (property.isRequired && !value.length) {
79
+ setError(name, { type: 'custom', message: 'Please, fill this field' });
80
+ } else {
81
+ clearErrors(name);
82
+ }
83
+ };
84
+
85
+ const handleValueFillOptionChange = (e, index) => {
86
+ const { value } = e.target;
87
+ const fieldName = `${name}.${index}`;
88
+
89
+ setValuesFillOptions((prevState) => replaceArrayItem(prevState, value, index));
90
+ if (value === 'widget' && property.propertyType === 'BOOLEAN') {
91
+ setValues((prevState) => replaceArrayItem(prevState, false, index));
92
+ } else {
93
+ setValues((prevState) => replaceArrayItem(prevState, '', index));
94
+ }
95
+ clearErrors(fieldName);
96
+ };
97
+
98
+ const handleValueChange = (value, index) => {
99
+ const fieldName = `${name}.${index}`;
100
+
101
+ setValues((prevState) => replaceArrayItem(prevState, value, index));
102
+
103
+ if (property.isRequired && !(value + '').length) {
104
+ setError(fieldName, { type: 'custom', message: 'Please, fill this field' });
105
+ } else if (property.propertyType === 'JSON' && !validateJson(value)) {
106
+ setError(fieldName, { type: 'custom', message: `Not valid JSON at value - ${index + 1}` });
107
+ } else {
108
+ clearErrors(fieldName);
109
+ }
110
+ };
111
+
112
+ const handleAddValue = () => {
113
+ setValues((prevState) => [...prevState, null]);
114
+ setValuesFillOptions((prevState) => [...prevState, 'null']);
115
+ };
116
+
117
+ const handleDeleteValue = (index) => {
118
+ setValuesFillOptions((prevState) => removeArrayItem(prevState, index));
119
+ setValues((prevState) => removeArrayItem(prevState, index));
120
+ };
121
+
122
+ useEffect(() => {
123
+ if (mainFillOption === 'widgets') {
124
+ setValue(name, values);
125
+ }
126
+ }, [mainFillOption, values]);
127
+
128
+ useEffect(() => {
129
+ if (property) {
130
+ if (!property.isRequired) {
131
+ setMainFillOptions((prevState) => [{ value: 'null', label: 'NULL' }, ...prevState]);
132
+ }
133
+ if (
134
+ property.propertyType === 'DATE' ||
135
+ property.propertyType === 'DATE_TIME' ||
136
+ property.propertyType === 'TIME'
137
+ ) {
138
+ setFillOptions((prevState) => [...prevState, { value: 'string', label: 'String' }]);
139
+ }
140
+ }
141
+ }, [property]);
142
+
143
+ useEffect(() => {
144
+ if (property) {
145
+ const { defaultValue } = property;
146
+ const value = getValues(name) || defaultValue;
147
+
148
+ if (Array.isArray(value)) {
149
+ setMainFillOption('widgets');
150
+ setValues(
151
+ value.map((val) => {
152
+ if (typeof val === 'object') {
153
+ return JSON.stringify(val);
154
+ }
155
+ return val;
156
+ })
157
+ );
158
+ setValuesFillOptions(
159
+ value.map((value) => {
160
+ if (value === null || value === 'null') {
161
+ return 'null';
162
+ } else if (value && typeof value === 'string' && value.startsWith('$')) {
163
+ return 'expression';
164
+ } else {
165
+ return 'widget';
166
+ }
167
+ })
168
+ );
169
+ } else if (typeof value === 'string') {
170
+ setMainFillOption('expression');
171
+ setMainExpression(value);
172
+ } else {
173
+ setMainFillOption('null');
174
+ }
175
+ }
176
+ }, [property, name]);
177
+
178
+ return (
179
+ <Grid container spacing={2}>
180
+ <Grid item sm={12}>
181
+ <Typography className={classes.inputParameterTitle}>{label}</Typography>
182
+ </Grid>
183
+ <Grid item sm={12}>
184
+ <TextField
185
+ select
186
+ fullWidth
187
+ size="small"
188
+ variant="outlined"
189
+ value={mainFillOption}
190
+ onChange={handleMainFillOptionChange}
191
+ >
192
+ {mainFillOptions.map((option) => (
193
+ <MenuItem key={option.value} value={option.value}>
194
+ {option.label}
195
+ </MenuItem>
196
+ ))}
197
+ </TextField>
198
+ </Grid>
199
+ {mainFillOption === 'expression' && (
200
+ <Grid item sm={12}>
201
+ <TextField
202
+ fullWidth
203
+ variant="outlined"
204
+ size="small"
205
+ label="Expression"
206
+ value={mainExpression}
207
+ onChange={handleMainExpressionChange}
208
+ />
209
+ </Grid>
210
+ )}
211
+ {mainFillOption === 'widgets' && (
212
+ <>
213
+ {values.map((value, index) => (
214
+ <Grid container item sm={12} key={index} spacing={1} className={classes.multipleValueContainer}>
215
+ <Grid item sm={12} className={classes.multipleValueTitle}>
216
+ <Typography variant="subtitle1">value-{index + 1}</Typography>
217
+ <IconButton size="small" onClick={() => handleDeleteValue(index)}>
218
+ <CloseIcon fontSize="small" />
219
+ </IconButton>
220
+ </Grid>
221
+ <Grid item sm={12}>
222
+ <TextField
223
+ select
224
+ fullWidth
225
+ variant="outlined"
226
+ size="small"
227
+ value={valuesFillOptions[index]}
228
+ onChange={(e) => handleValueFillOptionChange(e, index)}
229
+ >
230
+ {fillOptions.map((option) => (
231
+ <MenuItem key={option.value} value={option.value}>
232
+ {option.label}
233
+ </MenuItem>
234
+ ))}
235
+ </TextField>
236
+ </Grid>
237
+ {valuesFillOptions[index] === 'widget' && (
238
+ <DemFieldWidget
239
+ property={property}
240
+ label={`${label} : value-${index + 1}`}
241
+ name={`${name}.${index}`}
242
+ value={value}
243
+ onChange={(value) => handleValueChange(value, index)}
244
+ />
245
+ )}
246
+ {valuesFillOptions[index] === 'expression' && (
247
+ <Grid item sm={12}>
248
+ <TextField
249
+ fullWidth
250
+ variant="outlined"
251
+ size="small"
252
+ label="Expression"
253
+ value={value}
254
+ onChange={(e) => handleValueChange(e.target.value, index)}
255
+ />
256
+ </Grid>
257
+ )}
258
+ {valuesFillOptions[index] === 'string' && (
259
+ <Grid item sm={12}>
260
+ <TextField
261
+ fullWidth
262
+ variant="outlined"
263
+ size="small"
264
+ label="String value"
265
+ value={value}
266
+ onChange={(e) => handleValueChange(e.target.value, index)}
267
+ />
268
+ </Grid>
269
+ )}
270
+ {error?.[index]?.message && (
271
+ <Grid item sm={12}>
272
+ <Typography color="secondary">{error?.[index]?.message}</Typography>
273
+ </Grid>
274
+ )}
275
+ </Grid>
276
+ ))}
277
+ <Grid item sm={12}>
278
+ <Button variant="outlined" color="primary" onClick={handleAddValue}>
279
+ Add value
280
+ </Button>
281
+ </Grid>
282
+ </>
283
+ )}
284
+ {error?.message && (
285
+ <Grid item sm={12}>
286
+ <Typography color="secondary">{error.message}</Typography>
287
+ </Grid>
288
+ )}
289
+ </Grid>
290
+ );
291
+ };
292
+
293
+ export default MultipleDemField;
@@ -0,0 +1 @@
1
+ export * from './MultipleDemField';
@@ -0,0 +1,63 @@
1
+ import Grid from '@material-ui/core/Grid';
2
+ import Chip from '@material-ui/core/Chip';
3
+ import TextField from '@material-ui/core/TextField';
4
+ import Button from '@material-ui/core/Button';
5
+
6
+ import { useState } from 'react';
7
+ import { useFormContext } from 'react-hook-form';
8
+ import useStyles from './styles';
9
+
10
+ type Props = {
11
+ name: string;
12
+ };
13
+
14
+ const RestrictedValuesEditor = ({ name }: Props) => {
15
+ const { setValue, watch } = useFormContext();
16
+ const classes = useStyles();
17
+ const values = watch(name);
18
+
19
+ const [addValue, setAddValue] = useState('');
20
+
21
+ const handleAddValueChange = (e) => {
22
+ setAddValue(e.target.value);
23
+ };
24
+
25
+ const handleDelete = (value: string) => {
26
+ const filteredValues = values.filter((val) => val !== value);
27
+ setValue(name, filteredValues);
28
+ };
29
+
30
+ const handleAdd = () => {
31
+ if (values && values.length) {
32
+ setValue(name, [...values, addValue]);
33
+ } else {
34
+ setValue(name, [addValue]);
35
+ }
36
+ setAddValue('');
37
+ };
38
+
39
+ return (
40
+ <Grid item sm={12}>
41
+ <div className={classes.restrictedValuesContainer}>
42
+ {values && values.length
43
+ ? values.map((value) => <Chip key={value} label={value} onDelete={() => handleDelete(value)} />)
44
+ : null}
45
+ </div>
46
+ <div className={classes.restrictedValuesContainer}>
47
+ <TextField
48
+ fullWidth
49
+ variant="outlined"
50
+ size="small"
51
+ label="Restricted value"
52
+ value={addValue}
53
+ onChange={handleAddValueChange}
54
+ />
55
+ <Button variant="contained" size="small" color="primary" onClick={handleAdd}>
56
+ Add
57
+ </Button>
58
+ </div>
59
+ </Grid>
60
+ );
61
+ };
62
+
63
+ export default RestrictedValuesEditor;