@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.
- package/.babelrc +12 -0
- package/.eslintrc.json +22 -0
- package/README.md +7 -0
- package/index.ts +3 -0
- package/jest.config.js +9 -0
- package/package.json +21 -0
- package/project.json +69 -0
- package/rollup.config.js +135 -0
- package/src/interfaces/common.ts +12 -0
- package/src/interfaces/definition.ts +143 -0
- package/src/interfaces/index.ts +3 -0
- package/src/interfaces/ui.ts +35 -0
- package/src/lib/Alert/Alert.tsx +108 -0
- package/src/lib/Alert/index.ts +1 -0
- package/src/lib/Definition/CreateDefinition/CreateDefinition.tsx +74 -0
- package/src/lib/Definition/CreateDefinition/index.ts +1 -0
- package/src/lib/Definition/DefinitionFiller/DefinitionFiller.tsx +85 -0
- package/src/lib/Definition/DefinitionFiller/WidgetDefinitionFiller.tsx +96 -0
- package/src/lib/Definition/DefinitionFiller/index.ts +2 -0
- package/src/lib/Definition/index.ts +2 -0
- package/src/lib/DemPropertyField/DemPropertyField.tsx +93 -0
- package/src/lib/DemPropertyField/DemPropertyView/DemPropertyView.tsx +44 -0
- package/src/lib/DemPropertyField/DemPropertyView/index.ts +1 -0
- package/src/lib/DemPropertyField/MultipleDemField/MultipleDemField.tsx +293 -0
- package/src/lib/DemPropertyField/MultipleDemField/index.tsx +1 -0
- package/src/lib/DemPropertyField/RestrictedValuesEditor.tsx +63 -0
- package/src/lib/DemPropertyField/SingleDemField/SingleDemField.tsx +156 -0
- package/src/lib/DemPropertyField/SingleDemField/index.ts +1 -0
- package/src/lib/DemPropertyField/index.ts +2 -0
- package/src/lib/DemPropertyField/styles.ts +50 -0
- package/src/lib/DemPropertyField/widgets/DemBooleanWidget.tsx +26 -0
- package/src/lib/DemPropertyField/widgets/DemDateTimeWidget.tsx +34 -0
- package/src/lib/DemPropertyField/widgets/DemDateWidget.tsx +33 -0
- package/src/lib/DemPropertyField/widgets/DemFieldWidget.tsx +67 -0
- package/src/lib/DemPropertyField/widgets/DemFloatWidget.tsx +49 -0
- package/src/lib/DemPropertyField/widgets/DemIntegerWidget.tsx +63 -0
- package/src/lib/DemPropertyField/widgets/DemJsonWidget.tsx +33 -0
- package/src/lib/DemPropertyField/widgets/DemStringWidget.tsx +35 -0
- package/src/lib/DemPropertyField/widgets/DemTimeWidget.tsx +46 -0
- package/src/lib/DemPropertyField/widgets/index.ts +1 -0
- package/src/lib/Forms/BackButton.tsx +45 -0
- package/src/lib/Forms/ControlAceEditor.tsx +103 -0
- package/src/lib/Forms/ControlAutocomplete.tsx +134 -0
- package/src/lib/Forms/ControlCheckbox.tsx +57 -0
- package/src/lib/Forms/ControlDebouncedInput.tsx +69 -0
- package/src/lib/Forms/ControlInput.tsx +102 -0
- package/src/lib/Forms/ControlNumberInput.tsx +144 -0
- package/src/lib/Forms/ControlRadioBtn.tsx +46 -0
- package/src/lib/Forms/ControlSelect.tsx +135 -0
- package/src/lib/Forms/CopyButton.tsx +49 -0
- package/src/lib/Forms/index.ts +10 -0
- package/src/lib/InfoItem/InfoItem.tsx +39 -0
- package/src/lib/InfoItem/index.ts +1 -0
- package/src/lib/InfoItem/styles.ts +17 -0
- package/src/lib/JsonPathPicker/JsonPathPicker.tsx +71 -0
- package/src/lib/JsonPathPicker/PropertyStep.tsx +74 -0
- package/src/lib/JsonPathPicker/index.ts +1 -0
- package/src/lib/JsonView/JsonView.tsx +43 -0
- package/src/lib/JsonView/index.ts +1 -0
- package/src/lib/Loader/Loader.tsx +41 -0
- package/src/lib/Loader/index.ts +1 -0
- package/src/lib/Modals/JsonModalView.tsx +52 -0
- package/src/lib/Modals/index.ts +1 -0
- package/src/lib/Property/PropertyValueField/BooleanValueField.tsx +41 -0
- package/src/lib/Property/PropertyValueField/DateTimeValueField.tsx +59 -0
- package/src/lib/Property/PropertyValueField/DateValueField.tsx +59 -0
- package/src/lib/Property/PropertyValueField/EntityValueField.tsx +33 -0
- package/src/lib/Property/PropertyValueField/JsonValueField.tsx +64 -0
- package/src/lib/Property/PropertyValueField/PropertyValue.tsx +97 -0
- package/src/lib/Property/PropertyValueField/PropertyValueField.tsx +86 -0
- package/src/lib/Property/PropertyValueField/StringValueField.tsx +21 -0
- package/src/lib/Property/PropertyValueField/TimeValueField.tsx +68 -0
- package/src/lib/Property/PropertyValueField/ValueComponent.tsx +63 -0
- package/src/lib/Property/PropertyValueField/index.ts +1 -0
- package/src/lib/Property/PropertyWidget/PropertyWidget.tsx +167 -0
- package/src/lib/Property/PropertyWidget/index.ts +1 -0
- package/src/lib/Property/UpsertProperty/CreatePropertiesList.tsx +131 -0
- package/src/lib/Property/UpsertProperty/CreatePropertyFormFields.tsx +147 -0
- package/src/lib/Property/UpsertProperty/CustomPropertyField.tsx +40 -0
- package/src/lib/Property/UpsertProperty/PropertyAdditionalFields/BigDecimalPropertyFields.tsx +41 -0
- package/src/lib/Property/UpsertProperty/PropertyAdditionalFields/DateAdditionalFields.tsx +27 -0
- package/src/lib/Property/UpsertProperty/PropertyAdditionalFields/EntityAdditionalFields.tsx +133 -0
- package/src/lib/Property/UpsertProperty/PropertyAdditionalFields/EntityReferencePropertyFields.tsx +46 -0
- package/src/lib/Property/UpsertProperty/PropertyAdditionalFields/PropertyAdditionalFields.tsx +52 -0
- package/src/lib/Property/UpsertProperty/PropertyAdditionalFields/StringPropertyFields.tsx +98 -0
- package/src/lib/Property/UpsertProperty/PropertyAdditionalFields/index.ts +1 -0
- package/src/lib/Property/UpsertProperty/index.ts +2 -0
- package/src/lib/Property/UpsertProperty/useCustomFields.ts +22 -0
- package/src/lib/Property/ViewPropertiesList/ViewPropertiesList.tsx +50 -0
- package/src/lib/Property/ViewPropertiesList/index.ts +1 -0
- package/src/lib/Property/ViewProperty/EntityPropertiesShortView.tsx +41 -0
- package/src/lib/Property/ViewProperty/EntityPropertiesView.tsx +48 -0
- package/src/lib/Property/ViewProperty/PropertyDataTable.tsx +139 -0
- package/src/lib/Property/ViewProperty/PropertyItem.tsx +46 -0
- package/src/lib/Property/ViewProperty/ViewProperty.tsx +52 -0
- package/src/lib/Property/ViewProperty/index.ts +1 -0
- package/src/lib/Property/index.ts +4 -0
- package/src/lib/Status/Status.tsx +15 -0
- package/src/lib/Status/index.ts +1 -0
- package/src/lib/Status/styles.ts +14 -0
- package/src/lib/Table/Table.tsx +116 -0
- package/src/lib/Table/TableColumnMenu.tsx +12 -0
- package/src/lib/Table/TablePagination.tsx +42 -0
- package/src/lib/Table/index.ts +1 -0
- package/src/lib/Table/styles.ts +59 -0
- package/src/lib/Table/usePagination.ts +15 -0
- package/src/lib/Table/useTableQueryPagination.ts +49 -0
- package/src/lib/Table/useTableQuerySorting.ts +52 -0
- package/src/lib/Tabs/RouteTabs.tsx +54 -0
- package/src/lib/Tabs/TabPanel.tsx +42 -0
- package/src/lib/Tabs/index.ts +2 -0
- package/src/lib/TemplateContent/ExpressionDecorator.tsx +7 -0
- package/src/lib/TemplateContent/TemplateContentEditor.tsx +144 -0
- package/src/lib/TemplateContent/index.ts +1 -0
- package/src/lib/index.ts +14 -0
- package/src/utils/common.ts +68 -0
- package/src/utils/dem.ts +78 -0
- package/src/utils/hooks.ts +41 -0
- package/src/utils/index.ts +5 -0
- package/src/utils/ui-utils.tsx +71 -0
- package/src/utils/validators.ts +130 -0
- package/tsconfig.json +24 -0
- package/tsconfig.lib.json +22 -0
- 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,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;
|