@evoke-platform/ui-components 1.4.0-testing.1 → 1.4.0-testing.11
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/dist/published/components/core/Alert/Alert.js +1 -1
- package/dist/published/components/core/Autocomplete/Autocomplete.js +3 -3
- package/dist/published/components/custom/CriteriaBuilder/CriteriaBuilder.js +2 -18
- package/dist/published/components/custom/CriteriaBuilder/PropertyTree.js +2 -2
- package/dist/published/components/custom/CriteriaBuilder/ValueEditor.js +25 -17
- package/dist/published/components/custom/CriteriaBuilder/index.d.ts +2 -1
- package/dist/published/components/custom/CriteriaBuilder/index.js +2 -1
- package/dist/published/components/custom/CriteriaBuilder/utils.d.ts +13 -0
- package/dist/published/components/custom/CriteriaBuilder/utils.js +58 -1
- package/dist/published/components/custom/Form/Common/Form.js +37 -26
- package/dist/published/components/custom/Form/Common/FormComponentWrapper.js +2 -1
- package/dist/published/components/custom/Form/FormComponents/CriteriaComponent/Criteria.js +52 -1
- package/dist/published/components/custom/Form/FormComponents/ObjectComponent/ObjectComponent.d.ts +2 -0
- package/dist/published/components/custom/Form/FormComponents/ObjectComponent/ObjectComponent.js +75 -26
- package/dist/published/components/custom/Form/FormComponents/ObjectComponent/ObjectPropertyInput.js +3 -2
- package/dist/published/components/custom/Form/FormComponents/RepeatableFieldComponent/ActionDialog.d.ts +5 -2
- package/dist/published/components/custom/Form/FormComponents/RepeatableFieldComponent/ActionDialog.js +4 -6
- package/dist/published/components/custom/Form/FormComponents/RepeatableFieldComponent/RepeatableField.js +4 -2
- package/dist/published/components/custom/Form/FormComponents/RepeatableFieldComponent/RepeatableFieldComponent.js +31 -13
- package/dist/published/components/custom/Form/tests/Form.test.d.ts +1 -0
- package/dist/published/components/custom/Form/tests/Form.test.js +158 -0
- package/dist/published/components/custom/Form/tests/test-data.d.ts +13 -0
- package/dist/published/components/custom/Form/tests/test-data.js +381 -0
- package/dist/published/components/custom/Form/utils.d.ts +10 -4
- package/dist/published/components/custom/Form/utils.js +213 -90
- package/dist/published/components/custom/FormField/AddressFieldComponent/addressFieldComponent.js +1 -1
- package/dist/published/components/custom/HistoryLog/DisplayedProperty.d.ts +2 -1
- package/dist/published/components/custom/HistoryLog/DisplayedProperty.js +5 -2
- package/dist/published/components/custom/HistoryLog/HistoryData.d.ts +1 -0
- package/dist/published/components/custom/HistoryLog/HistoryData.js +9 -3
- package/dist/published/components/custom/HistoryLog/index.js +24 -2
- package/dist/published/components/custom/index.d.ts +1 -1
- package/dist/published/components/custom/index.js +1 -1
- package/dist/published/index.d.ts +1 -1
- package/dist/published/index.js +1 -1
- package/package.json +3 -4
@@ -31,7 +31,7 @@ const colorMap = {
|
|
31
31
|
const Alert = (props) => {
|
32
32
|
const { children, action, severity, onClose, color } = props;
|
33
33
|
const getIcon = () => {
|
34
|
-
const iconColor = color ? colorMap[color] ?? color : severity ? colorMap[severity] : colorMap['success'];
|
34
|
+
const iconColor = color ? (colorMap[color] ?? color) : severity ? colorMap[severity] : colorMap['success'];
|
35
35
|
switch (severity) {
|
36
36
|
case 'error':
|
37
37
|
return React.createElement(ErrorRounded, { sx: { ...styles.icon, color: iconColor } });
|
@@ -14,7 +14,7 @@ const Autocomplete = (props) => {
|
|
14
14
|
? option
|
15
15
|
: typeof option?.label === 'boolean'
|
16
16
|
? new Boolean(option?.label).toString()
|
17
|
-
: option?.label ?? '',
|
17
|
+
: (option?.label ?? ''),
|
18
18
|
value: option?.value ?? option,
|
19
19
|
};
|
20
20
|
})
|
@@ -62,7 +62,7 @@ const Autocomplete = (props) => {
|
|
62
62
|
marginTop: '3px',
|
63
63
|
borderRadius: '8px',
|
64
64
|
...props.sx,
|
65
|
-
}, options: sortedOptions, popupIcon:
|
65
|
+
}, options: sortedOptions, popupIcon: props.popupIcon ? props.popupIcon : props.readOnly || props.disabled ? null : React.createElement(ExpandMore, null) }),
|
66
66
|
props.error && React.createElement(FieldError, { required: props.required, label: props.errorMessage })));
|
67
67
|
}
|
68
68
|
else {
|
@@ -78,7 +78,7 @@ const Autocomplete = (props) => {
|
|
78
78
|
backgroundColor: props.readOnly ? '#f4f6f8' : 'auto',
|
79
79
|
borderRadius: '8px',
|
80
80
|
...props.sx,
|
81
|
-
}, options: sortedOptions, popupIcon:
|
81
|
+
}, options: sortedOptions, popupIcon: props.popupIcon ? props.popupIcon : props.readOnly || props.disabled ? null : React.createElement(ExpandMore, null) }),
|
82
82
|
props.error && React.createElement(FieldError, { required: props.required, label: props.errorMessage })));
|
83
83
|
}
|
84
84
|
};
|
@@ -12,23 +12,8 @@ import { Box } from '../../layout';
|
|
12
12
|
import { OverflowTextField } from '../OverflowTextField';
|
13
13
|
import { difference } from '../util';
|
14
14
|
import PropertyTree from './PropertyTree';
|
15
|
-
import { parseMongoDB, traversePropertyPath } from './utils';
|
15
|
+
import { ALL_OPERATORS, parseMongoDB, traversePropertyPath } from './utils';
|
16
16
|
import ValueEditor from './ValueEditor';
|
17
|
-
const ALL_OPERATORS = [
|
18
|
-
{ name: '=', label: 'Is' },
|
19
|
-
{ name: '!=', label: 'Is not' },
|
20
|
-
{ name: '<', label: 'Less than' },
|
21
|
-
{ name: '>', label: 'Greater than' },
|
22
|
-
{ name: '<=', label: 'Less than or equal to' },
|
23
|
-
{ name: '>=', label: 'Greater than or equal to' },
|
24
|
-
{ name: 'contains', label: 'Contains' },
|
25
|
-
{ name: 'beginsWith', label: 'Starts with' },
|
26
|
-
{ name: 'endsWith', label: 'Ends with' },
|
27
|
-
{ name: 'null', label: 'Is empty' },
|
28
|
-
{ name: 'notNull', label: 'Is not empty' },
|
29
|
-
{ name: 'in', label: 'In' },
|
30
|
-
{ name: 'notIn', label: 'Not in' },
|
31
|
-
];
|
32
17
|
const styles = {
|
33
18
|
buttons: {
|
34
19
|
padding: '6px 16px',
|
@@ -139,7 +124,7 @@ const customSelector = (props) => {
|
|
139
124
|
.map((option) => ({ name: option.name, label: option.label }));
|
140
125
|
val = val === '=' ? '' : options.find((option) => option.name === val).name;
|
141
126
|
}
|
142
|
-
else if (inputType === 'document') {
|
127
|
+
else if (inputType === 'document' || inputType === 'criteria') {
|
143
128
|
opts = options
|
144
129
|
.filter((option) => ['null', 'notNull'].includes(option.name))
|
145
130
|
.map((option) => ({ name: option.name, label: option.label }));
|
@@ -437,7 +422,6 @@ const CriteriaBuilder = (props) => {
|
|
437
422
|
'.ruleGroup:not(.ruleGroup .ruleGroup)': {
|
438
423
|
borderStyle: 'hidden',
|
439
424
|
background: '#fff',
|
440
|
-
maxWidth: '70vw',
|
441
425
|
},
|
442
426
|
'.ruleGroup-header': {
|
443
427
|
display: 'block',
|
@@ -123,8 +123,8 @@ const PropertyTree = ({ fetchObject, handleTreePropertySelect, rootObject, value
|
|
123
123
|
}, getOptionLabel: (option) => {
|
124
124
|
// Retrieve the full name path from the map
|
125
125
|
const namePath = typeof option === 'string'
|
126
|
-
? objectPropertyNamePathMap[option] ?? ''
|
127
|
-
: objectPropertyNamePathMap[option.value] ?? '';
|
126
|
+
? (objectPropertyNamePathMap[option] ?? '')
|
127
|
+
: (objectPropertyNamePathMap[option.value] ?? '');
|
128
128
|
return truncateNamePath(namePath, NAME_PATH_LIMIT);
|
129
129
|
}, renderInput: (params) => {
|
130
130
|
const fullDisplayName = value && objectPropertyNamePathMap[value];
|
@@ -1,10 +1,10 @@
|
|
1
1
|
import { Instant, LocalDate, LocalDateTime, LocalTime, ZoneId } from '@js-joda/core';
|
2
|
-
import { ClearRounded } from '@mui/icons-material';
|
2
|
+
import { ClearRounded, CodeRounded } from '@mui/icons-material';
|
3
3
|
import { Box, darken, lighten, styled } from '@mui/material';
|
4
4
|
import { TimePicker } from '@mui/x-date-pickers';
|
5
5
|
import React, { useEffect, useRef, useState } from 'react';
|
6
6
|
import { InvalidDate } from '../../../util';
|
7
|
-
import { Autocomplete, Chip, DatePicker, DateTimePicker, LocalizationProvider, Menu, MenuItem, TextField, Typography, } from '../../core';
|
7
|
+
import { Autocomplete, Chip, DatePicker, DateTimePicker, IconButton, LocalizationProvider, Menu, MenuItem, TextField, Typography, } from '../../core';
|
8
8
|
import { NumericFormat } from '../FormField/InputFieldComponent';
|
9
9
|
const GroupHeader = styled('div')(({ theme }) => ({
|
10
10
|
position: 'sticky',
|
@@ -27,10 +27,7 @@ const ValueEditor = (props) => {
|
|
27
27
|
if (!!context.treeViewOpts && !!property) {
|
28
28
|
inputType = property.type;
|
29
29
|
if (property.enum) {
|
30
|
-
values = property.enum.map((item) => ({
|
31
|
-
name: item,
|
32
|
-
label: item,
|
33
|
-
}));
|
30
|
+
values = property.enum.map((item) => ({ name: item, label: item }));
|
34
31
|
}
|
35
32
|
}
|
36
33
|
const [invalidDateTime, setInvalidDateTime] = useState(false);
|
@@ -42,8 +39,8 @@ const ValueEditor = (props) => {
|
|
42
39
|
const disabled = ['null', 'notNull'].includes(operator);
|
43
40
|
const presetValues = context.presetValues?.filter((val) => !val.type || val.type === inputType) ?? [];
|
44
41
|
const isPresetValue = (value) => value?.startsWith('{{{') && value?.endsWith('}}}');
|
45
|
-
const
|
46
|
-
const
|
42
|
+
const presetDisplayValue = presetValues?.find((option) => option.value.name === value)?.label;
|
43
|
+
const isPresetValueSelected = presetValues && typeof value === 'string' && isPresetValue(value) && !!presetDisplayValue;
|
47
44
|
let readOnly = context.disabled;
|
48
45
|
if (!readOnly && context.disabledCriteria) {
|
49
46
|
readOnly =
|
@@ -54,6 +51,7 @@ const ValueEditor = (props) => {
|
|
54
51
|
width: '33%',
|
55
52
|
background: readOnly ? '#f4f6f8' : '#fff',
|
56
53
|
borderRadius: '8px',
|
54
|
+
'& .MuiAutocomplete-tag': { backgroundColor: '#edeff1' },
|
57
55
|
},
|
58
56
|
};
|
59
57
|
useEffect(() => {
|
@@ -178,9 +176,7 @@ const ValueEditor = (props) => {
|
|
178
176
|
console.error('Error processing date value:', error);
|
179
177
|
setInvalidDateTime(true);
|
180
178
|
}
|
181
|
-
}, onClose: onClose, PopperProps: {
|
182
|
-
anchorEl,
|
183
|
-
}, renderInput: (params) => (React.createElement(Box, { sx: styles.input, ref: setAnchorEl },
|
179
|
+
}, onClose: onClose, PopperProps: { anchorEl }, renderInput: (params) => (React.createElement(Box, { sx: styles.input, ref: setAnchorEl },
|
184
180
|
React.createElement(TextField, { ...params, disabled: disabled, onClick: onClick, placeholder: "Value", size: "small", inputRef: inputRef, error: invalidDateTime }))), readOnly: readOnly })));
|
185
181
|
}
|
186
182
|
else if (inputType === 'number' || inputType === 'integer') {
|
@@ -274,14 +270,26 @@ const ValueEditor = (props) => {
|
|
274
270
|
}
|
275
271
|
};
|
276
272
|
return (React.createElement(React.Fragment, null,
|
277
|
-
isPresetValueSelected ? (React.createElement(
|
278
|
-
borderRadius: '8px',
|
279
|
-
fontSize: '14px',
|
273
|
+
isPresetValueSelected ? (React.createElement(Box, { ref: inputRef, sx: {
|
280
274
|
width: '33%',
|
281
|
-
|
282
|
-
padding: '0 5px',
|
275
|
+
display: 'flex',
|
283
276
|
justifyContent: 'space-between',
|
284
|
-
|
277
|
+
alignItems: 'center',
|
278
|
+
height: '40px',
|
279
|
+
border: readOnly ? undefined : '1px solid #d5d5d5',
|
280
|
+
borderRadius: '8px',
|
281
|
+
backgroundColor: readOnly ? '#edeff1' : '#ffffff',
|
282
|
+
} },
|
283
|
+
React.createElement(Chip, { label: presetDisplayValue, sx: {
|
284
|
+
fontSize: '14px',
|
285
|
+
margin: '6px',
|
286
|
+
backgroundColor: '#edeff1',
|
287
|
+
borderRadius: '6px',
|
288
|
+
color: '#212B36',
|
289
|
+
height: '28px',
|
290
|
+
}, icon: React.createElement(CodeRounded, { sx: { height: '18px' } }) }),
|
291
|
+
!readOnly && (React.createElement(IconButton, { onClick: clearValue, sx: { padding: '3px', margin: '3px' } },
|
292
|
+
React.createElement(ClearRounded, { fontSize: "small", sx: { color: 'rgba(0, 0, 0, 0.54)' } }))))) : (getEditor()),
|
285
293
|
!!presetValues?.length && (React.createElement(Menu, { open: openPresetValues, anchorEl: inputRef?.current, PaperProps: { sx: { borderRadius: '8px', width: inputRef?.current?.offsetWidth } }, onClose: onClose }, presetValues &&
|
286
294
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
287
295
|
presetValues.map((option) => (React.createElement(MenuItem, { ...props, onClick: () => setPresetValue(option.value.name), sx: { padding: '8px', minHeight: '25px' } },
|
@@ -1,3 +1,4 @@
|
|
1
|
+
import { Property } from '@evoke-platform/context';
|
1
2
|
import { RuleGroupType } from 'react-querybuilder';
|
2
3
|
import { ExpandedProperty, Obj, ObjectProperty } from '../../../types';
|
3
4
|
/**
|
@@ -61,4 +62,16 @@ export declare const truncateNamePath: (namePath: string, limit?: number) => str
|
|
61
62
|
* @returns {RuleGroupType} - Correctly formatted rule or rules for the query builder.
|
62
63
|
*/
|
63
64
|
export declare function parseMongoDB(mongoQuery: Record<string, unknown>): RuleGroupType;
|
65
|
+
export declare const ALL_OPERATORS: {
|
66
|
+
name: string;
|
67
|
+
label: string;
|
68
|
+
}[];
|
69
|
+
/**
|
70
|
+
* Gets a human readable representation of a MongoDB query.
|
71
|
+
*
|
72
|
+
* @param {Record<string, unknown>} [mongoQuery] - The MongoDB query
|
73
|
+
* @param {Property[]} [properties] - The object properties referenced in the query
|
74
|
+
* @returns {string} The resulting query string.
|
75
|
+
*/
|
76
|
+
export declare const getReadableQuery: (mongoQuery?: Record<string, unknown>, properties?: Property[]) => string;
|
64
77
|
export {};
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import { isArray, isEmpty } from 'lodash';
|
1
|
+
import { isArray, isEmpty, startCase } from 'lodash';
|
2
2
|
/**
|
3
3
|
* Recursively updates a node in a tree structure by applying an updater function to the node with the specified ID.
|
4
4
|
*
|
@@ -302,3 +302,60 @@ export function parseMongoDB(mongoQuery) {
|
|
302
302
|
};
|
303
303
|
}
|
304
304
|
}
|
305
|
+
export const ALL_OPERATORS = [
|
306
|
+
{ name: '=', label: 'Is' },
|
307
|
+
{ name: '!=', label: 'Is not' },
|
308
|
+
{ name: '<', label: 'Less than' },
|
309
|
+
{ name: '>', label: 'Greater than' },
|
310
|
+
{ name: '<=', label: 'Less than or equal to' },
|
311
|
+
{ name: '>=', label: 'Greater than or equal to' },
|
312
|
+
{ name: 'contains', label: 'Contains' },
|
313
|
+
{ name: 'beginsWith', label: 'Starts with' },
|
314
|
+
{ name: 'endsWith', label: 'Ends with' },
|
315
|
+
{ name: 'null', label: 'Is empty' },
|
316
|
+
{ name: 'notNull', label: 'Is not empty' },
|
317
|
+
{ name: 'in', label: 'In' },
|
318
|
+
{ name: 'notIn', label: 'Not in' },
|
319
|
+
];
|
320
|
+
/**
|
321
|
+
* Gets a human readable representation of a MongoDB query.
|
322
|
+
*
|
323
|
+
* @param {Record<string, unknown>} [mongoQuery] - The MongoDB query
|
324
|
+
* @param {Property[]} [properties] - The object properties referenced in the query
|
325
|
+
* @returns {string} The resulting query string.
|
326
|
+
*/
|
327
|
+
export const getReadableQuery = (mongoQuery, properties) => {
|
328
|
+
function isPresetValue(value) {
|
329
|
+
return typeof value === 'string' && value.startsWith('{{{') && value.endsWith('}}}');
|
330
|
+
}
|
331
|
+
function parseValue(val) {
|
332
|
+
if (val && Array.isArray(val)) {
|
333
|
+
return val.map((v) => (isPresetValue(v) ? startCase(v.slice(3, -3)) : v)).join(', ');
|
334
|
+
}
|
335
|
+
else {
|
336
|
+
return isPresetValue(val) ? startCase(val.slice(3, -3)) : `${val}`;
|
337
|
+
}
|
338
|
+
}
|
339
|
+
function getOperatorLabel(operator) {
|
340
|
+
const operatorObj = ALL_OPERATORS.find((o) => o.name === operator);
|
341
|
+
const defaultLabel = operatorObj ? operatorObj.label.toLowerCase() : operator;
|
342
|
+
if (['<', '>', '<=', '>='].includes(operator)) {
|
343
|
+
return `is ${defaultLabel}`;
|
344
|
+
}
|
345
|
+
return defaultLabel;
|
346
|
+
}
|
347
|
+
function buildQueryString(rule) {
|
348
|
+
if ('combinator' in rule) {
|
349
|
+
return rule?.rules?.map(buildQueryString).filter(Boolean).join(` ${rule.combinator.toLowerCase()} `);
|
350
|
+
}
|
351
|
+
else {
|
352
|
+
const property = properties?.find((p) => p.id === rule.field);
|
353
|
+
return `${property?.name ?? rule.field} ${getOperatorLabel(rule.operator)} ${parseValue(rule.value)}`;
|
354
|
+
}
|
355
|
+
}
|
356
|
+
if (!mongoQuery) {
|
357
|
+
return '';
|
358
|
+
}
|
359
|
+
const parsedQuery = parseMongoDB(mongoQuery);
|
360
|
+
return buildQueryString(parsedQuery);
|
361
|
+
};
|
@@ -1,14 +1,14 @@
|
|
1
1
|
import { useApp, useAuthenticationContext, } from '@evoke-platform/context';
|
2
2
|
import { Components, Form as FormIO, Utils } from '@formio/react';
|
3
3
|
import { flatten } from 'flat';
|
4
|
-
import { isEmpty, isEqual, toPairs } from 'lodash';
|
4
|
+
import { isEmpty, isEqual, isObject, omit, pick, toPairs } from 'lodash';
|
5
5
|
import React, { useEffect, useRef, useState } from 'react';
|
6
6
|
import '../../../../styles/form-component.css';
|
7
7
|
import { Skeleton, Snackbar } from '../../../core';
|
8
8
|
import { Box } from '../../../layout';
|
9
9
|
import { ButtonComponent, DocumentComponent, FormFieldComponent, ImageComponent, ObjectComponent, RepeatableFieldComponent, UserComponent, ViewOnlyComponent, } from '../FormComponents';
|
10
10
|
import { CriteriaComponent } from '../FormComponents/CriteriaComponent/CriteriaComponent';
|
11
|
-
import { addObjectPropertiesToComponentProps, buildComponentPropsFromDocumentProperties, buildComponentPropsFromObjectProperties, convertFormToComponents, getFlattenEntries, getPrefixedUrl, } from '../utils';
|
11
|
+
import { addObjectPropertiesToComponentProps, buildComponentPropsFromDocumentProperties, buildComponentPropsFromObjectProperties, convertFormToComponents, flattenFormComponents, getAllCriteriaInputs, getFlattenEntries, getPrefixedUrl, } from '../utils';
|
12
12
|
const usePrevious = (value) => {
|
13
13
|
const ref = useRef();
|
14
14
|
useEffect(() => {
|
@@ -101,24 +101,16 @@ export function Form(props) {
|
|
101
101
|
const buildComponents = async () => {
|
102
102
|
const action = object?.actions?.find((action) => action.id === actionId);
|
103
103
|
let input;
|
104
|
-
|
105
|
-
? action.parameters.filter((param) => param.id !== associatedObject.propertyId)
|
106
|
-
: action?.parameters;
|
107
|
-
if (parameters && object) {
|
104
|
+
if (action?.parameters && object) {
|
108
105
|
input = action?.form?.entries
|
109
|
-
? convertFormToComponents(action.form.entries, parameters, object)
|
110
|
-
: parameters.filter((param) => object.properties?.some((prop) => prop.id === param.id));
|
106
|
+
? convertFormToComponents(action.form.entries, action.parameters, object)
|
107
|
+
: action.parameters.filter((param) => object.properties?.some((prop) => prop.id === param.id));
|
111
108
|
}
|
112
109
|
else {
|
113
110
|
input = action?.inputProperties ?? (action?.type === 'delete' ? [] : undefined);
|
114
111
|
}
|
115
|
-
let visibleObjectProperties = object?.properties;
|
116
|
-
if (associatedObject) {
|
117
|
-
// Eliminates the associated object's field from the form
|
118
|
-
visibleObjectProperties = visibleObjectProperties?.filter((property) => property.id !== associatedObject.propertyId);
|
119
|
-
}
|
120
112
|
let foundDefaultPages = defaultPages;
|
121
|
-
const relatedObjectProperties =
|
113
|
+
const relatedObjectProperties = object?.properties?.filter((property) => property.type === 'object');
|
122
114
|
if (relatedObjectProperties) {
|
123
115
|
foundDefaultPages = await relatedObjectProperties.reduce(async (acc, property) => {
|
124
116
|
const result = await acc;
|
@@ -132,23 +124,37 @@ export function Form(props) {
|
|
132
124
|
}, Promise.resolve({}));
|
133
125
|
}
|
134
126
|
const allDefaultPages = { ...defaultPages, ...foundDefaultPages };
|
135
|
-
|
127
|
+
// visibleObjectProperties
|
128
|
+
if (input && object?.properties) {
|
129
|
+
const allCriteriaInputs = getAllCriteriaInputs(action?.inputProperties ? flattenFormComponents(action.inputProperties) : (action?.parameters ?? []));
|
136
130
|
if (input.length || action?.type !== 'delete') {
|
137
131
|
// formIO builder-configured input properties exist
|
138
|
-
const newComponentProps = await addObjectPropertiesToComponentProps(
|
132
|
+
const newComponentProps = await addObjectPropertiesToComponentProps(object.properties, input, allCriteriaInputs, instance, {
|
139
133
|
...objectInputCommonProps,
|
140
134
|
defaultPages: allDefaultPages,
|
141
135
|
navigateTo,
|
142
136
|
apiServices,
|
143
137
|
user: userAccount,
|
144
|
-
}, undefined, isReadOnly, allDefaultPages, navigateTo, queryAddresses, apiServices, !!closeModal, fieldHeight, richTextEditor);
|
138
|
+
}, associatedObject, undefined, isReadOnly, allDefaultPages, navigateTo, queryAddresses, apiServices, !!closeModal, fieldHeight, richTextEditor);
|
145
139
|
if (!hideButtons && !isReadOnly) {
|
146
140
|
newComponentProps.push(BottomButtons);
|
147
141
|
}
|
142
|
+
if (action?.type !== 'create') {
|
143
|
+
// Add an additional, hidden _instance property on update/delete actions
|
144
|
+
// so that instance data is accessible in conditional display logic.
|
145
|
+
const hiddenComponent = {
|
146
|
+
key: '_instance',
|
147
|
+
type: 'hidden',
|
148
|
+
input: true,
|
149
|
+
tableView: false,
|
150
|
+
defaultValue: instance,
|
151
|
+
};
|
152
|
+
newComponentProps.push(hiddenComponent);
|
153
|
+
}
|
148
154
|
setComponentProps(newComponentProps);
|
149
155
|
}
|
150
156
|
else {
|
151
|
-
const components = await addObjectPropertiesToComponentProps(
|
157
|
+
const components = await addObjectPropertiesToComponentProps(object.properties, [
|
152
158
|
{
|
153
159
|
html: `<p>${action?.type === 'delete' ? 'This action cannot be undone.' : 'Are you sure?'}</p>`,
|
154
160
|
label: 'Content',
|
@@ -216,13 +222,13 @@ export function Form(props) {
|
|
216
222
|
addons: [],
|
217
223
|
id: 'eahbwo',
|
218
224
|
},
|
219
|
-
], instance, {
|
225
|
+
], undefined, instance, {
|
220
226
|
...objectInputCommonProps,
|
221
227
|
defaultPages: allDefaultPages,
|
222
228
|
navigateTo,
|
223
229
|
apiServices,
|
224
230
|
user: userAccount,
|
225
|
-
}, undefined, undefined, undefined, undefined, undefined, undefined, !!closeModal, fieldHeight, richTextEditor);
|
231
|
+
}, undefined, undefined, undefined, undefined, undefined, undefined, undefined, !!closeModal, fieldHeight, richTextEditor);
|
226
232
|
if (!hideButtons) {
|
227
233
|
components.push(BottomButtons);
|
228
234
|
}
|
@@ -319,8 +325,8 @@ export function Form(props) {
|
|
319
325
|
const savedValue = submittedFields[docProperty.id];
|
320
326
|
const originalValue = instance?.[docProperty.id];
|
321
327
|
const documentsToRemove = requestSuccess
|
322
|
-
? originalValue?.filter((file) => !savedValue?.some((f) => f.id === file.id)) ?? []
|
323
|
-
: savedValue?.filter((file) => !originalValue?.some((f) => f.id === file.id)) ?? [];
|
328
|
+
? (originalValue?.filter((file) => !savedValue?.some((f) => f.id === file.id)) ?? [])
|
329
|
+
: (savedValue?.filter((file) => !originalValue?.some((f) => f.id === file.id)) ?? []);
|
324
330
|
for (const doc of documentsToRemove) {
|
325
331
|
try {
|
326
332
|
await apiServices?.delete(getPrefixedUrl(`/objects/${object?.id}/instances/${instance?.id}/documents/${doc.id}`));
|
@@ -343,7 +349,12 @@ export function Form(props) {
|
|
343
349
|
submittedFields[field] = null;
|
344
350
|
}
|
345
351
|
else {
|
346
|
-
|
352
|
+
if (isObject(value) && 'id' in value && 'name' in value) {
|
353
|
+
submittedFields[field] = pick(value, 'id', 'name');
|
354
|
+
}
|
355
|
+
else {
|
356
|
+
submittedFields[field] = value;
|
357
|
+
}
|
347
358
|
}
|
348
359
|
}
|
349
360
|
//OPTIMIZATION TODO: See if type can be inferred from the event target
|
@@ -417,7 +428,7 @@ export function Form(props) {
|
|
417
428
|
key: 'save-draft',
|
418
429
|
variant: 'outlined',
|
419
430
|
isModal: !!closeModal,
|
420
|
-
onClick: async (data, setError, setSubmitting) => await saveHandler(data, 'draft', setError, setSubmitting),
|
431
|
+
onClick: async (data, setError, setSubmitting) => await saveHandler(omit(data, '_instance'), 'draft', setError, setSubmitting),
|
421
432
|
style: { lineHeight: '2.75', margin: '5px', padding: '0 10px' },
|
422
433
|
}
|
423
434
|
: undefined,
|
@@ -438,7 +449,7 @@ export function Form(props) {
|
|
438
449
|
variant: 'contained',
|
439
450
|
isModal: !!closeModal,
|
440
451
|
onClick: (data, setError, setSubmitting) => {
|
441
|
-
saveHandler(data, 'submit', setError, setSubmitting);
|
452
|
+
saveHandler(omit(data, '_instance'), 'submit', setError, setSubmitting);
|
442
453
|
},
|
443
454
|
},
|
444
455
|
],
|
@@ -448,7 +459,7 @@ export function Form(props) {
|
|
448
459
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
449
460
|
, {
|
450
461
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
451
|
-
onChange: (e) => !isEqual(e.data, formData) && setFormData(e.data), key: closeModal ? undefined : formKey, form: {
|
462
|
+
onChange: (e) => !isEqual(omit(e.data, '_instance'), formData) && setFormData(omit(e.data, '_instance')), key: closeModal ? undefined : formKey, form: {
|
452
463
|
display: 'form',
|
453
464
|
components: componentProps,
|
454
465
|
}, formReady: handleFormReady })) : (React.createElement(Box, null,
|
@@ -81,7 +81,8 @@ export const FormComponentWrapper = (props) => {
|
|
81
81
|
property && onChange(property.id, '');
|
82
82
|
} },
|
83
83
|
React.createElement(HighlightOffOutlined, { sx: clearBtnStyles }))))),
|
84
|
-
React.createElement(
|
84
|
+
React.createElement(Box, { sx: { ...(displayOption === 'radioButton' && { display: 'flex' }) } },
|
85
|
+
React.createElement(Typography, { variant: "caption", sx: descriptionStyles }, description)),
|
85
86
|
React.createElement(Box, { sx: { display: 'flex', flexDirection: 'row' } },
|
86
87
|
React.createElement(PrefixSuffix, { prefix: prefix, height: fieldHeight }),
|
87
88
|
React.createElement(Box, { sx: { width: '100%', paddingTop: '6px' } }, children),
|
@@ -18,7 +18,58 @@ export const Criteria = (props) => {
|
|
18
18
|
setLoadingError(true);
|
19
19
|
}
|
20
20
|
if (properties) {
|
21
|
-
|
21
|
+
const flattenProperties = properties.flatMap((prop) => {
|
22
|
+
if (prop.type === 'object' || prop.type === 'user') {
|
23
|
+
return [
|
24
|
+
{
|
25
|
+
id: `${prop.id}.id`,
|
26
|
+
name: `${prop.name} Id`,
|
27
|
+
type: 'string',
|
28
|
+
},
|
29
|
+
{
|
30
|
+
id: `${prop.id}.name`,
|
31
|
+
name: `${prop.name} Name`,
|
32
|
+
type: 'string',
|
33
|
+
},
|
34
|
+
];
|
35
|
+
}
|
36
|
+
else if (prop.type === 'address') {
|
37
|
+
return [
|
38
|
+
{
|
39
|
+
id: `${prop.id}.line1`,
|
40
|
+
name: `${prop.name} Line 1`,
|
41
|
+
type: 'string',
|
42
|
+
},
|
43
|
+
{
|
44
|
+
id: `${prop.id}.line2`,
|
45
|
+
name: `${prop.name} Line 2`,
|
46
|
+
type: 'string',
|
47
|
+
},
|
48
|
+
{
|
49
|
+
id: `${prop.id}.city`,
|
50
|
+
name: `${prop.name} City`,
|
51
|
+
type: 'string',
|
52
|
+
},
|
53
|
+
{
|
54
|
+
id: `${prop.id}.county`,
|
55
|
+
name: `${prop.name} County`,
|
56
|
+
type: 'string',
|
57
|
+
},
|
58
|
+
{
|
59
|
+
id: `${prop.id}.state`,
|
60
|
+
name: `${prop.name} State`,
|
61
|
+
type: 'string',
|
62
|
+
},
|
63
|
+
{
|
64
|
+
id: `${prop.id}.zipCode`,
|
65
|
+
name: `${prop.name} Zip Code`,
|
66
|
+
type: 'string',
|
67
|
+
},
|
68
|
+
];
|
69
|
+
}
|
70
|
+
return prop;
|
71
|
+
});
|
72
|
+
setProperties(flattenProperties);
|
22
73
|
setLoadingError(false);
|
23
74
|
}
|
24
75
|
setLoading(false);
|
package/dist/published/components/custom/Form/FormComponents/ObjectComponent/ObjectComponent.d.ts
CHANGED
@@ -6,6 +6,7 @@ interface ObjectComponentProps extends BaseFormComponentProps {
|
|
6
6
|
mode: 'default' | 'existingOnly';
|
7
7
|
defaultValueCriteria?: Record<string, unknown>;
|
8
8
|
initialValue?: string;
|
9
|
+
allCriteriaInputs: string[];
|
9
10
|
richTextEditor?: typeof ReactComponent;
|
10
11
|
}
|
11
12
|
export declare class ObjectComponent extends ReactComponent {
|
@@ -20,6 +21,7 @@ export declare class ObjectComponent extends ReactComponent {
|
|
20
21
|
updatedDefaultValueCriteria: Record<string, unknown>;
|
21
22
|
constructor(component: ObjectComponentProps, options: any, data: any);
|
22
23
|
init(): void;
|
24
|
+
expandInstance(): Promise<void>;
|
23
25
|
clearErrors(): void;
|
24
26
|
handleValidation(): void;
|
25
27
|
hasErrors(): boolean;
|