@evoke-platform/ui-components 1.10.0-testing.8 → 1.10.0
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/Autocomplete/Autocomplete.js +4 -2
- package/dist/published/components/core/Autocomplete/Autocomplete.test.js +112 -3
- package/dist/published/components/core/TextField/TextField.js +1 -1
- package/dist/published/components/core/TextField/TextField.test.js +0 -2
- package/dist/published/components/custom/CriteriaBuilder/CriteriaBuilder.js +25 -3
- package/dist/published/components/custom/CriteriaBuilder/CriteriaBuilder.test.d.ts +1 -0
- package/dist/published/components/custom/CriteriaBuilder/CriteriaBuilder.test.js +473 -0
- package/dist/published/components/custom/CriteriaBuilder/ValueEditor.js +19 -6
- package/dist/published/components/custom/Form/FormComponents/DocumentComponent/Document.js +2 -1
- package/dist/published/components/custom/Form/FormComponents/RepeatableFieldComponent/RepeatableField.js +1 -1
- package/dist/published/components/custom/Form/tests/Form.test.js +0 -2
- package/dist/published/components/custom/FormField/DatePickerSelect/DatePickerSelect.js +36 -7
- package/dist/published/components/custom/FormField/DateTimePickerSelect/DateTimePickerSelect.js +14 -1
- package/dist/published/components/custom/FormField/FormField.d.ts +3 -1
- package/dist/published/components/custom/FormField/FormField.js +17 -5
- package/dist/published/components/custom/FormField/InputFieldComponent/InputFieldComponent.js +6 -4
- package/dist/published/components/custom/FormField/InputFieldComponent/InputFieldComponent.test.js +0 -2
- package/dist/published/components/custom/FormField/Select/Select.test.js +0 -2
- package/dist/published/components/custom/FormField/TimePickerSelect/TimePickerSelect.js +14 -1
- package/dist/published/components/custom/FormV2/FormRenderer.d.ts +2 -1
- package/dist/published/components/custom/FormV2/FormRenderer.js +46 -8
- package/dist/published/components/custom/FormV2/FormRendererContainer.js +178 -153
- package/dist/published/components/custom/FormV2/components/AccordionSections.js +7 -2
- package/dist/published/components/custom/FormV2/components/Body.d.ts +1 -1
- package/dist/published/components/custom/FormV2/components/DefaultValues.d.ts +2 -2
- package/dist/published/components/custom/FormV2/components/DefaultValues.js +36 -28
- package/dist/published/components/custom/FormV2/components/FieldWrapper.js +1 -1
- package/dist/published/components/custom/FormV2/components/Footer.d.ts +1 -0
- package/dist/published/components/custom/FormV2/components/Footer.js +8 -5
- package/dist/published/components/custom/FormV2/components/FormContext.d.ts +3 -2
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/AddressFields.d.ts +9 -0
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/AddressFields.js +32 -15
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/CollectionFiles/ActionDialog.js +2 -2
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/CollectionFiles/RepeatableField.js +6 -23
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/Criteria.js +16 -3
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/DocumentFiles/Document.js +22 -4
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/DocumentFiles/DocumentList.d.ts +2 -1
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/DocumentFiles/DocumentList.js +16 -3
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/Image.js +31 -5
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/UserProperty.js +15 -3
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/relatedObjectFiles/ObjectPropertyInput.js +115 -87
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/relatedObjectFiles/RelatedObjectInstance.d.ts +2 -3
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/relatedObjectFiles/RelatedObjectInstance.js +43 -20
- package/dist/published/components/custom/FormV2/components/Header.d.ts +5 -3
- package/dist/published/components/custom/FormV2/components/Header.js +47 -9
- package/dist/published/components/custom/FormV2/components/PropertyProtection.d.ts +16 -0
- package/dist/published/components/custom/FormV2/components/PropertyProtection.js +113 -0
- package/dist/published/components/custom/FormV2/components/RecursiveEntryRenderer.js +47 -24
- package/dist/published/components/custom/FormV2/components/ValidationFiles/ValidationErrors.js +1 -1
- package/dist/published/components/custom/FormV2/components/types.d.ts +2 -0
- package/dist/published/components/custom/FormV2/components/utils.d.ts +6 -4
- package/dist/published/components/custom/FormV2/components/utils.js +83 -13
- package/dist/published/components/custom/FormV2/tests/FormRenderer.test.js +413 -46
- package/dist/published/components/custom/FormV2/tests/FormRendererContainer.test.js +983 -16
- package/dist/published/components/custom/FormV2/tests/test-data.d.ts +1 -0
- package/dist/published/components/custom/FormV2/tests/test-data.js +138 -0
- package/dist/published/components/custom/ViewDetailsV2/InstanceEntryRenderer.d.ts +3 -0
- package/dist/published/components/custom/ViewDetailsV2/InstanceEntryRenderer.js +165 -0
- package/dist/published/components/custom/ViewDetailsV2/ViewDetailsV2Container.d.ts +13 -0
- package/dist/published/components/custom/ViewDetailsV2/ViewDetailsV2Container.js +144 -0
- package/dist/published/components/custom/ViewDetailsV2/index.d.ts +3 -0
- package/dist/published/components/custom/ViewDetailsV2/index.js +2 -0
- package/dist/published/components/custom/index.d.ts +2 -0
- package/dist/published/components/custom/index.js +1 -0
- package/dist/published/index.d.ts +6 -6
- package/dist/published/index.js +1 -1
- package/dist/published/stories/CriteriaBuilder.stories.js +6 -0
- package/dist/published/stories/FormRenderer.stories.d.ts +8 -4
- package/dist/published/stories/FormRendererContainer.stories.d.ts +26 -0
- package/dist/published/stories/FormRendererContainer.stories.js +5 -0
- package/dist/published/stories/FormRendererData.d.ts +12 -0
- package/dist/published/stories/FormRendererData.js +26 -1
- package/dist/published/stories/ViewDetailsV2Container.stories.d.ts +26 -0
- package/dist/published/stories/ViewDetailsV2Container.stories.js +37 -0
- package/dist/published/stories/ViewDetailsV2Data.d.ts +4 -0
- package/dist/published/stories/ViewDetailsV2Data.js +203 -0
- package/dist/published/stories/sharedMswHandlers.js +49 -10
- package/dist/published/theme/hooks.d.ts +4 -3
- package/dist/published/types.d.ts +3 -0
- package/package.json +12 -8
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { isArray, isEmpty, uniq } from 'lodash';
|
|
2
2
|
import { DateTime } from 'luxon';
|
|
3
3
|
import { getEntryId, getPrefixedUrl, isAddressProperty } from './utils';
|
|
4
|
-
export async function evalDefaultVals(parameters, entry, fieldValue, fieldId, apiServices, userAccount, formValues, updatedRelatedObjectValue) {
|
|
4
|
+
export async function evalDefaultVals(parameters, unnestedEntries, entry, fieldValue, fieldId, apiServices, userAccount, formValues, updatedRelatedObjectValue) {
|
|
5
5
|
const updates = [];
|
|
6
6
|
const parameter = parameters.find((param) => param.id === fieldId);
|
|
7
7
|
const defaultValue = entry.display?.defaultValue;
|
|
@@ -15,9 +15,9 @@ export async function evalDefaultVals(parameters, entry, fieldValue, fieldId, ap
|
|
|
15
15
|
const groups = regex.exec(item)?.groups;
|
|
16
16
|
if (groups?.relatedObjectProperty && groups?.nestedProperty) {
|
|
17
17
|
const relatedObjectParameter = parameters.find((param) => param.id === groups?.relatedObjectProperty);
|
|
18
|
-
let
|
|
19
|
-
if (!
|
|
20
|
-
|
|
18
|
+
let relatedObjectInstance = updatedRelatedObjectValue;
|
|
19
|
+
if (!relatedObjectInstance && !isEmpty(formValues)) {
|
|
20
|
+
relatedObjectInstance = formValues[groups.relatedObjectProperty];
|
|
21
21
|
}
|
|
22
22
|
if (updatedRelatedObjectValue?.[groups.nestedProperty]) {
|
|
23
23
|
fieldValue = uniq([
|
|
@@ -28,9 +28,14 @@ export async function evalDefaultVals(parameters, entry, fieldValue, fieldId, ap
|
|
|
28
28
|
]);
|
|
29
29
|
updates.push({ fieldId, fieldValue });
|
|
30
30
|
}
|
|
31
|
-
else if (
|
|
31
|
+
else if (relatedObjectInstance?.id && relatedObjectParameter) {
|
|
32
|
+
let relatedObjectId = relatedObjectParameter.objectId;
|
|
33
|
+
if (!relatedObjectId) {
|
|
34
|
+
const relatedObjectParamEntry = unnestedEntries.find((e) => getEntryId(e) === relatedObjectParameter.id);
|
|
35
|
+
relatedObjectId = relatedObjectParamEntry?.display?.relatedObjectId;
|
|
36
|
+
}
|
|
32
37
|
const instance = await new Promise((resolve) => {
|
|
33
|
-
apiServices.get(getPrefixedUrl(`/objects/${
|
|
38
|
+
apiServices.get(getPrefixedUrl(`/objects/${relatedObjectId}/instances/${relatedObjectInstance?.id}`), (error, instance) => {
|
|
34
39
|
if (error) {
|
|
35
40
|
console.error(error);
|
|
36
41
|
return resolve(undefined);
|
|
@@ -64,17 +69,22 @@ export async function evalDefaultVals(parameters, entry, fieldValue, fieldId, ap
|
|
|
64
69
|
const groups = regex.exec(defaultValue)?.groups;
|
|
65
70
|
if (groups?.relatedObjectProperty && groups?.addressProperty && groups?.nestedAddressProperty) {
|
|
66
71
|
const relatedObjectParameter = parameters.find((param) => param.id === groups?.relatedObjectProperty);
|
|
67
|
-
let
|
|
68
|
-
if (!
|
|
69
|
-
|
|
72
|
+
let relatedObjectInstance = updatedRelatedObjectValue;
|
|
73
|
+
if (!relatedObjectInstance && !isEmpty(formValues)) {
|
|
74
|
+
relatedObjectInstance = formValues[groups.relatedObjectProperty];
|
|
70
75
|
}
|
|
71
76
|
if (updatedRelatedObjectValue?.[groups.addressProperty]?.[groups.nestedAddressProperty]) {
|
|
72
77
|
fieldValue = updatedRelatedObjectValue?.[groups.addressProperty]?.[groups.nestedAddressProperty];
|
|
73
78
|
updates.push({ fieldId, fieldValue });
|
|
74
79
|
}
|
|
75
|
-
else if (
|
|
80
|
+
else if (relatedObjectInstance?.id && relatedObjectParameter) {
|
|
81
|
+
let relatedObjectId = relatedObjectParameter.objectId;
|
|
82
|
+
if (!relatedObjectId) {
|
|
83
|
+
const relatedObjectParamEntry = unnestedEntries.find((e) => getEntryId(e) === relatedObjectParameter.id);
|
|
84
|
+
relatedObjectId = relatedObjectParamEntry?.display?.relatedObjectId;
|
|
85
|
+
}
|
|
76
86
|
const instance = await new Promise((resolve) => {
|
|
77
|
-
apiServices.get(getPrefixedUrl(`/objects/${
|
|
87
|
+
apiServices.get(getPrefixedUrl(`/objects/${relatedObjectId}/instances/${relatedObjectInstance?.id}`), (error, instance) => {
|
|
78
88
|
if (error) {
|
|
79
89
|
console.error(error);
|
|
80
90
|
return resolve(undefined);
|
|
@@ -99,17 +109,22 @@ export async function evalDefaultVals(parameters, entry, fieldValue, fieldId, ap
|
|
|
99
109
|
const groups = regex.exec(defaultValue)?.groups;
|
|
100
110
|
if (groups?.relatedObjectProperty && groups?.nestedProperty) {
|
|
101
111
|
const relatedObjectParameter = parameters.find((param) => param.id === groups?.relatedObjectProperty);
|
|
102
|
-
let
|
|
103
|
-
if (!
|
|
104
|
-
|
|
112
|
+
let relatedObjectInstance = updatedRelatedObjectValue;
|
|
113
|
+
if (!relatedObjectInstance && !isEmpty(formValues)) {
|
|
114
|
+
relatedObjectInstance = formValues[groups.relatedObjectProperty];
|
|
105
115
|
}
|
|
106
116
|
if (updatedRelatedObjectValue?.[groups.nestedProperty]) {
|
|
107
117
|
fieldValue = updatedRelatedObjectValue[groups.nestedProperty];
|
|
108
118
|
updates.push({ fieldId, fieldValue });
|
|
109
119
|
}
|
|
110
|
-
else if (
|
|
120
|
+
else if (relatedObjectInstance?.id && relatedObjectParameter) {
|
|
121
|
+
let relatedObjectId = relatedObjectParameter.objectId;
|
|
122
|
+
if (!relatedObjectId) {
|
|
123
|
+
const relatedObjectParamEntry = unnestedEntries.find((e) => getEntryId(e) === relatedObjectParameter.id);
|
|
124
|
+
relatedObjectId = relatedObjectParamEntry?.display?.relatedObjectId;
|
|
125
|
+
}
|
|
111
126
|
const instance = await new Promise((resolve) => {
|
|
112
|
-
apiServices.get(getPrefixedUrl(`/objects/${
|
|
127
|
+
apiServices.get(getPrefixedUrl(`/objects/${relatedObjectId}/instances/${relatedObjectInstance?.id}`), (error, instance) => {
|
|
113
128
|
if (error) {
|
|
114
129
|
console.error(error);
|
|
115
130
|
return resolve(undefined);
|
|
@@ -153,16 +168,9 @@ export async function evalDefaultVals(parameters, entry, fieldValue, fieldId, ap
|
|
|
153
168
|
}
|
|
154
169
|
return updates;
|
|
155
170
|
}
|
|
156
|
-
export async function processValueUpdate(
|
|
171
|
+
export async function processValueUpdate(unnestedEntries, parameters, updatedRelatedObjectValue, apiServices, changedEntryId, formValues, userAccount) {
|
|
157
172
|
const updates = [];
|
|
158
|
-
for (const entry of
|
|
159
|
-
if (entry.type === 'sections' || entry.type === 'columns') {
|
|
160
|
-
const subEntries = entry.type === 'sections' ? entry.sections : entry.columns;
|
|
161
|
-
for (const subEntry of subEntries) {
|
|
162
|
-
const subUpdates = await processValueUpdate(subEntry.entries, parameters, updatedRelatedObjectValue, apiServices, changedEntryId, formValues, userAccount);
|
|
163
|
-
updates.push(...subUpdates);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
173
|
+
for (const entry of unnestedEntries) {
|
|
166
174
|
if ((entry.type === 'input' || entry.type === 'inputField') && entry?.display?.defaultValue) {
|
|
167
175
|
const parameterId = getEntryId(entry);
|
|
168
176
|
if (!parameterId)
|
|
@@ -175,7 +183,7 @@ export async function processValueUpdate(entries, parameters, updatedRelatedObje
|
|
|
175
183
|
groups?.addressProperty &&
|
|
176
184
|
groups?.nestedAddressProperty &&
|
|
177
185
|
changedEntryId === groups.relatedObjectProperty) {
|
|
178
|
-
const result = await evalDefaultVals(parameters, entry, formValues?.[addressObject]?.[addressField], parameterId, apiServices, userAccount, formValues, updatedRelatedObjectValue);
|
|
186
|
+
const result = await evalDefaultVals(parameters, unnestedEntries, entry, formValues?.[addressObject]?.[addressField], parameterId, apiServices, userAccount, formValues, updatedRelatedObjectValue);
|
|
179
187
|
updates.push(...result);
|
|
180
188
|
}
|
|
181
189
|
}
|
|
@@ -187,7 +195,7 @@ export async function processValueUpdate(entries, parameters, updatedRelatedObje
|
|
|
187
195
|
if (groups?.relatedObjectProperty &&
|
|
188
196
|
groups?.nestedProperty &&
|
|
189
197
|
changedEntryId === groups.relatedObjectProperty) {
|
|
190
|
-
const result = await evalDefaultVals(parameters, entry, entry.display.defaultValue, parameterId, apiServices, userAccount, formValues, updatedRelatedObjectValue);
|
|
198
|
+
const result = await evalDefaultVals(parameters, unnestedEntries, entry, entry.display.defaultValue, parameterId, apiServices, userAccount, formValues, updatedRelatedObjectValue);
|
|
191
199
|
updates.push(...result);
|
|
192
200
|
}
|
|
193
201
|
}
|
|
@@ -198,7 +206,7 @@ export async function processValueUpdate(entries, parameters, updatedRelatedObje
|
|
|
198
206
|
if (groups?.relatedObjectProperty &&
|
|
199
207
|
groups?.nestedProperty &&
|
|
200
208
|
changedEntryId === groups.relatedObjectProperty) {
|
|
201
|
-
const result = await evalDefaultVals(parameters, entry, formValues?.[parameterId], parameterId, apiServices, userAccount, formValues, updatedRelatedObjectValue);
|
|
209
|
+
const result = await evalDefaultVals(parameters, unnestedEntries, entry, formValues?.[parameterId], parameterId, apiServices, userAccount, formValues, updatedRelatedObjectValue);
|
|
202
210
|
updates.push(...result);
|
|
203
211
|
}
|
|
204
212
|
}
|
|
@@ -55,7 +55,7 @@ const FieldWrapper = (props) => {
|
|
|
55
55
|
const remainingChars = maxLength ? maxLength - charCount : undefined;
|
|
56
56
|
return (React.createElement(Box, null,
|
|
57
57
|
React.createElement(Box, { sx: { padding: '10px 0' } },
|
|
58
|
-
inputType !== 'boolean' && (React.createElement(InputLabel, { htmlFor: inputId, sx: {
|
|
58
|
+
(inputType !== 'boolean' || viewOnly) && (React.createElement(InputLabel, { htmlFor: inputId, sx: {
|
|
59
59
|
display: 'flex',
|
|
60
60
|
alignItems: 'center',
|
|
61
61
|
color: viewOnly ? 'text.secondary' : 'text.primary',
|
|
@@ -8,6 +8,7 @@ export type FooterProps = {
|
|
|
8
8
|
submitButtonLabel?: string;
|
|
9
9
|
discardChangesButtonLabel?: string;
|
|
10
10
|
sx?: SxProps;
|
|
11
|
+
disableDiscardChanges?: boolean;
|
|
11
12
|
};
|
|
12
13
|
export declare const Footer: React.FC<FooterProps>;
|
|
13
14
|
export type FooterActionsProps = Omit<FooterProps, 'sx'>;
|
|
@@ -6,7 +6,7 @@ import { Box } from '../../../layout';
|
|
|
6
6
|
import { FormContext } from './FormContext';
|
|
7
7
|
/* Default FormRenderer Footer. Displays a submit button and cancel changes button. */
|
|
8
8
|
export const Footer = (props) => {
|
|
9
|
-
const {
|
|
9
|
+
const { sx } = props;
|
|
10
10
|
const { width } = useContext(FormContext);
|
|
11
11
|
const { isBelow, breakpoints } = useWidgetSize({
|
|
12
12
|
scroll: false,
|
|
@@ -20,15 +20,18 @@ export const Footer = (props) => {
|
|
|
20
20
|
padding: isSmallerThanMd ? '16px' : '20px',
|
|
21
21
|
justifyContent: isXs ? 'center' : 'flex-end',
|
|
22
22
|
alignItems: 'center',
|
|
23
|
-
borderTop:
|
|
23
|
+
borderTop: '1px solid #f4f6f8',
|
|
24
24
|
borderRadius: '0px 0px 6px 6px',
|
|
25
25
|
zIndex: 3,
|
|
26
|
+
width: '100%',
|
|
27
|
+
// this will ensure footer does not exceed form width when form has padding
|
|
28
|
+
maxWidth: width - (isSmallerThanMd ? 32 : 40),
|
|
26
29
|
...sx,
|
|
27
30
|
} },
|
|
28
31
|
React.createElement(FooterActions, { ...props })));
|
|
29
32
|
};
|
|
30
33
|
export const FooterActions = (props) => {
|
|
31
|
-
const { action, onDiscardChanges, onSubmit, submitButtonLabel, discardChangesButtonLabel } = props;
|
|
34
|
+
const { action, onDiscardChanges, onSubmit, submitButtonLabel, discardChangesButtonLabel, disableDiscardChanges } = props;
|
|
32
35
|
const { width } = useContext(FormContext);
|
|
33
36
|
const [loading, setLoading] = React.useState(false);
|
|
34
37
|
const handleSubmit = async () => {
|
|
@@ -46,7 +49,7 @@ export const FooterActions = (props) => {
|
|
|
46
49
|
});
|
|
47
50
|
const { isXs } = breakpoints;
|
|
48
51
|
return (React.createElement(React.Fragment, null,
|
|
49
|
-
React.createElement(Button, { onClick: onDiscardChanges, variant: "outlined", sx: {
|
|
52
|
+
!disableDiscardChanges && (React.createElement(Button, { onClick: onDiscardChanges, variant: "outlined", sx: {
|
|
50
53
|
margin: '5px',
|
|
51
54
|
marginX: isXs ? '0px' : undefined,
|
|
52
55
|
color: 'black',
|
|
@@ -56,7 +59,7 @@ export const FooterActions = (props) => {
|
|
|
56
59
|
backgroundColor: '#f2f4f7',
|
|
57
60
|
border: '1px solid rgb(206, 212, 218)',
|
|
58
61
|
},
|
|
59
|
-
} }, discardChangesButtonLabel),
|
|
62
|
+
} }, discardChangesButtonLabel)),
|
|
60
63
|
React.createElement(LoadingButton, { onClick: handleSubmit, variant: "contained", sx: {
|
|
61
64
|
lineHeight: '2.75',
|
|
62
65
|
margin: '5px 0 5px 5px',
|
|
@@ -5,7 +5,7 @@ import { ExpandedSection, SimpleEditorProps } from './types';
|
|
|
5
5
|
type FormContextType = {
|
|
6
6
|
fetchedOptions: FieldValues;
|
|
7
7
|
setFetchedOptions: (newData: FieldValues) => void;
|
|
8
|
-
getValues
|
|
8
|
+
getValues?: UseFormGetValues<FieldValues>;
|
|
9
9
|
object?: Obj;
|
|
10
10
|
errors?: FieldValues;
|
|
11
11
|
instance?: FieldValues;
|
|
@@ -15,7 +15,8 @@ type FormContextType = {
|
|
|
15
15
|
setExpandedSections?: React.Dispatch<React.SetStateAction<ExpandedSection[]>>;
|
|
16
16
|
setExpandAll?: React.Dispatch<React.SetStateAction<boolean | undefined | null>>;
|
|
17
17
|
parameters?: InputParameter[];
|
|
18
|
-
handleChange
|
|
18
|
+
handleChange?: (name: string, value: unknown) => void | Promise<void>;
|
|
19
|
+
onAutosave?: (fieldId: string) => void | Promise<void>;
|
|
19
20
|
fieldHeight?: 'small' | 'medium';
|
|
20
21
|
triggerFieldReset?: boolean;
|
|
21
22
|
showSubmitError?: boolean;
|
package/dist/published/components/custom/FormV2/components/FormFieldTypes/AddressFields.d.ts
CHANGED
|
@@ -2,7 +2,16 @@ import { InputField, InputParameter, InputParameterReference, Property, Readonly
|
|
|
2
2
|
import React from 'react';
|
|
3
3
|
interface AddressProps {
|
|
4
4
|
entry: InputParameterReference | ReadonlyField | InputField;
|
|
5
|
+
/**
|
|
6
|
+
* Indicates that the field is a readonlyField in an action form.
|
|
7
|
+
* Used for regular form read-only fields.
|
|
8
|
+
*/
|
|
5
9
|
readOnly?: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Indicates that the field should not have a gray background.
|
|
12
|
+
* Used for ViewDetails widgets.
|
|
13
|
+
*/
|
|
14
|
+
viewOnly?: boolean;
|
|
6
15
|
entryId: string;
|
|
7
16
|
fieldDefinition: InputParameter | Property;
|
|
8
17
|
}
|
|
@@ -6,12 +6,12 @@ import FormField from '../../../FormField';
|
|
|
6
6
|
import FieldWrapper from '../FieldWrapper';
|
|
7
7
|
import { getPrefixedUrl, isOptionEqualToValue } from '../utils';
|
|
8
8
|
function AddressFields(props) {
|
|
9
|
-
const { entry, readOnly, entryId, fieldDefinition } = props;
|
|
10
|
-
const { getValues, instance, errors, handleChange, fieldHeight, parameters } = useFormContext();
|
|
9
|
+
const { entry, readOnly, viewOnly, entryId, fieldDefinition } = props;
|
|
10
|
+
const { getValues, instance, errors, handleChange, onAutosave, fieldHeight, parameters } = useFormContext();
|
|
11
11
|
const apiServices = useApiServices();
|
|
12
12
|
const addressObject = entryId.split('.')[0];
|
|
13
13
|
const addressField = entryId.split('.')[1];
|
|
14
|
-
const addressValues = entry.type === 'readonlyField' ? instance?.[addressObject] : getValues(addressObject);
|
|
14
|
+
const addressValues = entry.type === 'readonlyField' ? instance?.[addressObject] : getValues ? getValues(addressObject) : undefined;
|
|
15
15
|
const fieldValue = addressValues?.[addressField];
|
|
16
16
|
const display = entry?.display;
|
|
17
17
|
const validation = fieldDefinition?.validation
|
|
@@ -22,24 +22,41 @@ function AddressFields(props) {
|
|
|
22
22
|
params: { query: query },
|
|
23
23
|
});
|
|
24
24
|
};
|
|
25
|
-
const handleAddressChange = (name, value) => {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
const
|
|
32
|
-
|
|
25
|
+
const handleAddressChange = async (name, value) => {
|
|
26
|
+
try {
|
|
27
|
+
if (addressField === 'line1' && typeof value === 'object' && value.line1) {
|
|
28
|
+
const addressKeys = ['line1', 'city', 'county', 'state', 'zipCode'];
|
|
29
|
+
// Await each handleChange sequentially to ensure proper order
|
|
30
|
+
for (const key of addressKeys) {
|
|
31
|
+
const fullKey = `${addressObject}.${key}`;
|
|
32
|
+
if (parameters?.some((p) => p.id === fullKey)) {
|
|
33
|
+
const fieldValue = value[key];
|
|
34
|
+
handleChange && (await handleChange(fullKey, fieldValue));
|
|
35
|
+
}
|
|
33
36
|
}
|
|
34
|
-
|
|
37
|
+
// Autosave immediately after autocomplete fills all fields
|
|
38
|
+
try {
|
|
39
|
+
await onAutosave?.(entryId);
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
console.error('Autosave failed:', error);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
handleChange && (await handleChange(name, value));
|
|
47
|
+
}
|
|
35
48
|
}
|
|
36
|
-
|
|
37
|
-
|
|
49
|
+
catch (error) {
|
|
50
|
+
console.error('Failed to update field:', error);
|
|
38
51
|
}
|
|
39
52
|
};
|
|
40
53
|
const addressErrors = errors?.[addressObject];
|
|
41
54
|
const addressFieldError = addressErrors?.[addressField];
|
|
42
|
-
return (React.createElement(FieldWrapper, { inputId: entryId, inputType: "string", label: display?.label || 'default', description: !readOnly ? display?.description : undefined, tooltip: display?.tooltip, value: fieldValue, maxLength: 'maxLength' in validation ? validation?.maxLength : 0, required: entry.display?.required || false, showCharCount: !readOnly && display?.charCount, viewOnly: !!readOnly, prefix: display?.prefix, suffix: display?.suffix }, !
|
|
55
|
+
return (React.createElement(FieldWrapper, { inputId: entryId, inputType: "string", label: display?.label || 'default', description: !readOnly ? display?.description : undefined, tooltip: display?.tooltip, value: fieldValue, maxLength: 'maxLength' in validation ? validation?.maxLength : 0, required: entry.display?.required || false, showCharCount: !readOnly && display?.charCount, viewOnly: !!(viewOnly ?? readOnly), prefix: display?.prefix, suffix: display?.suffix }, !viewOnly ? (React.createElement(FormField, { property: fieldDefinition, defaultValue: fieldValue, onChange: handleAddressChange, onBlur: () => {
|
|
56
|
+
onAutosave?.(entryId)?.catch((error) => {
|
|
57
|
+
console.error('Autosave failed:', error);
|
|
58
|
+
});
|
|
59
|
+
}, isMultiLineText: !!display?.rowCount, readOnly: entry.type === 'readonlyField', ...(addressField === 'line1' && { queryAddresses }), mask: validation?.mask, placeholder: display?.placeholder, isOptionEqualToValue: isOptionEqualToValue, size: fieldHeight, error: !!addressFieldError, errorMessage: addressFieldError?.message, additionalProps: {
|
|
43
60
|
...(display?.description && {
|
|
44
61
|
inputProps: {
|
|
45
62
|
'aria-describedby': `${entryId}-description`,
|
|
@@ -84,7 +84,7 @@ export const ActionDialog = (props) => {
|
|
|
84
84
|
objectId: relatedParameter.objectId, onSubmit: handleFormSave, onDiscardChanges: onClose, onSubmitError: handleSaveError, richTextEditor: richTextEditor, associatedObject: associatedObject, renderHeader: (formHeaderProps) => {
|
|
85
85
|
return (React.createElement(DialogTitle, { sx: {
|
|
86
86
|
...styles.dialogTitle,
|
|
87
|
-
borderBottom:
|
|
87
|
+
borderBottom: '1px solid #e9ecef',
|
|
88
88
|
} },
|
|
89
89
|
action && hasAccess && !loading ? action?.name : '',
|
|
90
90
|
React.createElement(IconButton, { sx: styles.closeIcon, onClick: onClose, "aria-label": "Close" },
|
|
@@ -99,7 +99,7 @@ export const ActionDialog = (props) => {
|
|
|
99
99
|
React.createElement("div", { ref: validationErrorsRef }, !isEmpty(bodyProps.errors) && bodyProps.shouldShowValidationErrors ? (React.createElement(ValidationErrors, { errors: bodyProps.errors, sx: {
|
|
100
100
|
my: isSm || isXs ? 2 : 3,
|
|
101
101
|
} })) : null),
|
|
102
|
-
React.createElement(Body, { ...bodyProps, sx: { padding: 0 } }))), renderFooter: (footerProps) => (React.createElement(DialogActions, { sx: { padding: 0 } },
|
|
102
|
+
React.createElement(Body, { ...bodyProps, sx: { padding: 0 } }))), renderFooter: (footerProps) => (React.createElement(DialogActions, { sx: { padding: 0, margin: 0 } },
|
|
103
103
|
React.createElement(Footer, { ...footerProps, discardChangesButtonLabel: "Cancel" }))), renderContainer: ({ status, error, defaultContainer }) => (React.createElement(React.Fragment, null,
|
|
104
104
|
status === 'ready' && defaultContainer,
|
|
105
105
|
status === 'loading' && (React.createElement(DialogContent, null,
|
|
@@ -66,6 +66,8 @@ const RepeatableField = (props) => {
|
|
|
66
66
|
const updateAction = relatedObject?.actions?.find((item) => item.id === entry.display?.updateActionId);
|
|
67
67
|
const deleteAction = relatedObject?.actions?.find((item) => item.id === entry.display?.deleteActionId);
|
|
68
68
|
function getForm(setForm, action, formId) {
|
|
69
|
+
if (formId === '_auto_')
|
|
70
|
+
return;
|
|
69
71
|
if (formId || action?.defaultFormId) {
|
|
70
72
|
apiServices
|
|
71
73
|
.get(getPrefixedUrl(`/forms/${formId || action?.defaultFormId}`))
|
|
@@ -76,27 +78,6 @@ const RepeatableField = (props) => {
|
|
|
76
78
|
console.error(error);
|
|
77
79
|
});
|
|
78
80
|
}
|
|
79
|
-
else if (action) {
|
|
80
|
-
apiServices
|
|
81
|
-
.get(getPrefixedUrl('/forms'), {
|
|
82
|
-
params: {
|
|
83
|
-
filter: {
|
|
84
|
-
where: {
|
|
85
|
-
actionId: action.id,
|
|
86
|
-
objectId: fieldDefinition.objectId,
|
|
87
|
-
},
|
|
88
|
-
},
|
|
89
|
-
},
|
|
90
|
-
})
|
|
91
|
-
.then((matchingForms) => {
|
|
92
|
-
if (matchingForms.length === 1) {
|
|
93
|
-
setForm(matchingForms[0]);
|
|
94
|
-
}
|
|
95
|
-
})
|
|
96
|
-
.catch((error) => {
|
|
97
|
-
console.error(error);
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
81
|
}
|
|
101
82
|
const fetchRelatedInstances = useCallback(async (refetch = false) => {
|
|
102
83
|
let relatedObject;
|
|
@@ -564,7 +545,7 @@ const RepeatableField = (props) => {
|
|
|
564
545
|
entry.display?.deleteActionId && (React.createElement(IconButton, { "aria-label": `delete-collection-instance-${index}`, onClick: () => deleteRow(relatedInstance.id) },
|
|
565
546
|
React.createElement(Tooltip, { title: "Delete" },
|
|
566
547
|
React.createElement(TrashCan, { sx: { ':hover': { color: '#A12723' } } }))))))))))))),
|
|
567
|
-
hasCreateAction && entry.display?.createActionId && (React.createElement(Button, { variant: "contained", sx: styles.addButton, onClick: addRow, "aria-label": 'Add' }, "Add"))),
|
|
548
|
+
hasCreateAction && entry.display?.createActionId && (React.createElement(Button, { variant: "contained", sx: styles.addButton, disabled: !createAction, onClick: addRow, "aria-label": 'Add' }, "Add"))),
|
|
568
549
|
relatedObject && openDialog && (React.createElement(ActionDialog, { object: relatedObject, open: openDialog, onClose: () => setOpenDialog(false), onSubmit: save, action: relatedObject?.actions?.find((a) => a.id ===
|
|
569
550
|
(dialogType === 'create'
|
|
570
551
|
? entry.display?.createActionId
|
|
@@ -575,7 +556,9 @@ const RepeatableField = (props) => {
|
|
|
575
556
|
: dialogType === 'update'
|
|
576
557
|
? updateForm?.id
|
|
577
558
|
: dialogType === 'delete'
|
|
578
|
-
?
|
|
559
|
+
? entry.display?.deleteFormId === '_auto_'
|
|
560
|
+
? '_auto_'
|
|
561
|
+
: deleteForm?.id
|
|
579
562
|
: undefined, instanceId: selectedInstanceId, relatedParameter: fieldDefinition, associatedObject: instance?.id && fieldDefinition.relatedPropertyId
|
|
580
563
|
? { instanceId: instance.id, propertyId: fieldDefinition.relatedPropertyId }
|
|
581
564
|
: undefined })),
|
|
@@ -8,7 +8,7 @@ import { addressProperties, getPrefixedUrl } from '../utils';
|
|
|
8
8
|
export default function Criteria(props) {
|
|
9
9
|
const { value, canUpdateProperty, fieldDefinition, error } = props;
|
|
10
10
|
const apiServices = useApiServices();
|
|
11
|
-
const { fetchedOptions, setFetchedOptions, handleChange } = useFormContext();
|
|
11
|
+
const { fetchedOptions, setFetchedOptions, handleChange, onAutosave } = useFormContext();
|
|
12
12
|
const [loadingError, setLoadingError] = useState(false);
|
|
13
13
|
const [loading, setLoading] = useState(false);
|
|
14
14
|
const [properties, setProperties] = useState(fetchedOptions[`${fieldDefinition.id}Options`] || []);
|
|
@@ -57,9 +57,22 @@ export default function Criteria(props) {
|
|
|
57
57
|
useEffect(() => {
|
|
58
58
|
fetchProperties();
|
|
59
59
|
}, [fetchProperties]);
|
|
60
|
-
const handleUpdate = (criteria) => {
|
|
60
|
+
const handleUpdate = async (criteria) => {
|
|
61
61
|
if (criteria || value) {
|
|
62
|
-
|
|
62
|
+
const newValue = criteria ?? null;
|
|
63
|
+
try {
|
|
64
|
+
handleChange && (await handleChange(fieldDefinition.id, newValue));
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
console.error('Failed to update field:', error);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
try {
|
|
71
|
+
await onAutosave?.(fieldDefinition.id);
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
console.error('Autosave failed:', error);
|
|
75
|
+
}
|
|
63
76
|
}
|
|
64
77
|
};
|
|
65
78
|
if (loadingError) {
|
package/dist/published/components/custom/FormV2/components/FormFieldTypes/DocumentFiles/Document.js
CHANGED
|
@@ -12,7 +12,7 @@ import { DocumentList } from './DocumentList';
|
|
|
12
12
|
export const Document = (props) => {
|
|
13
13
|
const { id, canUpdateProperty, error, value, validate, hasDescription } = props;
|
|
14
14
|
const apiServices = useApiServices();
|
|
15
|
-
const { fetchedOptions, setFetchedOptions, object, handleChange, instance } = useFormContext();
|
|
15
|
+
const { fetchedOptions, setFetchedOptions, object, handleChange, onAutosave: onAutosave, instance, } = useFormContext();
|
|
16
16
|
const [snackbarError, setSnackbarError] = useState();
|
|
17
17
|
const [documents, setDocuments] = useState();
|
|
18
18
|
const [hasUpdatePermission, setHasUpdatePermission] = useState(fetchedOptions[`${id}UpdatePermission`]);
|
|
@@ -42,6 +42,12 @@ export const Document = (props) => {
|
|
|
42
42
|
[`${id}UpdatePermission`]: accessCheck.result,
|
|
43
43
|
});
|
|
44
44
|
setHasUpdatePermission(accessCheck.result);
|
|
45
|
+
})
|
|
46
|
+
.catch(() => {
|
|
47
|
+
setFetchedOptions({
|
|
48
|
+
[`${id}UpdatePermission`]: false,
|
|
49
|
+
});
|
|
50
|
+
setHasUpdatePermission(false);
|
|
45
51
|
});
|
|
46
52
|
}
|
|
47
53
|
}, [canUpdateProperty, fetchedOptions, instance, object]);
|
|
@@ -49,13 +55,25 @@ export const Document = (props) => {
|
|
|
49
55
|
checkPermissions();
|
|
50
56
|
}, [checkPermissions]);
|
|
51
57
|
const handleUpload = async (files) => {
|
|
58
|
+
// Store File objects in form state - they will be uploaded during autosave via formatSubmission()
|
|
52
59
|
const newDocuments = [...(documents ?? []), ...(files ?? [])];
|
|
53
60
|
setDocuments(newDocuments);
|
|
54
|
-
|
|
61
|
+
try {
|
|
62
|
+
handleChange && (await handleChange(id, newDocuments));
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
console.error('Failed to update field:', error);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
try {
|
|
69
|
+
await onAutosave?.(id);
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
console.error('Autosave failed:', error);
|
|
73
|
+
}
|
|
55
74
|
};
|
|
56
75
|
const uploadDisabled = !!validate?.maxDocuments && (documents?.length ?? 0) >= validate.maxDocuments;
|
|
57
76
|
const { getRootProps, getInputProps, open, fileRejections } = useDropzone({
|
|
58
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
59
77
|
onDrop: (files) => handleUpload(files),
|
|
60
78
|
disabled: uploadDisabled,
|
|
61
79
|
accept: validate?.allowedFileExtensions
|
|
@@ -109,7 +127,7 @@ export const Document = (props) => {
|
|
|
109
127
|
} }, validate?.maxDocuments === 1
|
|
110
128
|
? `Maximum size is ${formattedMaxSize}.`
|
|
111
129
|
: `The maximum size of each document is ${formattedMaxSize}.`)))))),
|
|
112
|
-
canUpdateProperty && isNil(hasUpdatePermission) ? (React.createElement(Skeleton, { variant: "rectangular", height: formattedMaxSize || allowedTypesMessage ? '136px' : '115px', sx: { margin: '5px 0', borderRadius: '8px' } })) : (React.createElement(DocumentList, { id: id, handleChange: handleChange, value: value, setSnackbarError: (type, message) => setSnackbarError({ message, type }), canUpdateProperty: canUpdateProperty && !!hasUpdatePermission })),
|
|
130
|
+
canUpdateProperty && isNil(hasUpdatePermission) ? (React.createElement(Skeleton, { variant: "rectangular", height: formattedMaxSize || allowedTypesMessage ? '136px' : '115px', sx: { margin: '5px 0', borderRadius: '8px' } })) : (React.createElement(DocumentList, { id: id, handleChange: handleChange, onAutosave: onAutosave, value: value, setSnackbarError: (type, message) => setSnackbarError({ message, type }), canUpdateProperty: canUpdateProperty && !!hasUpdatePermission })),
|
|
113
131
|
React.createElement(Snackbar, { open: !!snackbarError?.message, handleClose: () => setSnackbarError(null), message: snackbarError?.message, error: snackbarError?.type === 'error' }),
|
|
114
132
|
errors.length > 0 && (React.createElement(Box, { display: 'flex', alignItems: 'center' },
|
|
115
133
|
React.createElement(InfoRounded, { sx: { fontSize: '.75rem', marginRight: '3px', color: '#D3271B' } }),
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { SavedDocumentReference } from '../../types';
|
|
3
3
|
type DocumentListProps = {
|
|
4
|
-
handleChange
|
|
4
|
+
handleChange?: (propertyId: string, value: (File | SavedDocumentReference)[] | undefined) => void;
|
|
5
|
+
onAutosave?: (fieldId: string) => void | Promise<void>;
|
|
5
6
|
id: string;
|
|
6
7
|
canUpdateProperty: boolean;
|
|
7
8
|
value: (File | SavedDocumentReference)[] | undefined;
|
|
@@ -24,7 +24,7 @@ const viewableFileTypes = [
|
|
|
24
24
|
'text/plain',
|
|
25
25
|
];
|
|
26
26
|
export const DocumentList = (props) => {
|
|
27
|
-
const { handleChange, id, canUpdateProperty, value: documents, setSnackbarError } = props;
|
|
27
|
+
const { handleChange, onAutosave, id, canUpdateProperty, value: documents, setSnackbarError } = props;
|
|
28
28
|
const apiServices = useApiServices();
|
|
29
29
|
const { fetchedOptions, setFetchedOptions, object, instance } = useFormContext();
|
|
30
30
|
const [hasViewPermission, setHasViewPermission] = useState(fetchedOptions[`${id}ViewPermission`] ?? true);
|
|
@@ -88,9 +88,22 @@ export const DocumentList = (props) => {
|
|
|
88
88
|
};
|
|
89
89
|
const isFile = (doc) => doc instanceof File;
|
|
90
90
|
const fileExists = (doc) => savedDocuments?.find((d) => d.id === doc.id);
|
|
91
|
-
const handleRemove = (index) => {
|
|
91
|
+
const handleRemove = async (index) => {
|
|
92
92
|
const updatedDocuments = documents?.filter((_, i) => i !== index) ?? [];
|
|
93
|
-
|
|
93
|
+
const newValue = updatedDocuments.length === 0 ? undefined : updatedDocuments;
|
|
94
|
+
try {
|
|
95
|
+
handleChange && (await handleChange(id, newValue));
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
console.error('Failed to update field:', error);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
try {
|
|
102
|
+
await onAutosave?.(id);
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
console.error('Autosave failed:', error);
|
|
106
|
+
}
|
|
94
107
|
};
|
|
95
108
|
const openDocument = async (index) => {
|
|
96
109
|
const doc = documents?.[index];
|
|
@@ -55,7 +55,7 @@ const styles = {
|
|
|
55
55
|
};
|
|
56
56
|
export const Image = (props) => {
|
|
57
57
|
const { id, canUpdateProperty, error, value, hasDescription } = props;
|
|
58
|
-
const { handleChange } = useFormContext();
|
|
58
|
+
const { handleChange, onAutosave: onAutosave } = useFormContext();
|
|
59
59
|
const [image, setImage] = useState();
|
|
60
60
|
useEffect(() => {
|
|
61
61
|
if (typeof value === 'string') {
|
|
@@ -63,15 +63,41 @@ export const Image = (props) => {
|
|
|
63
63
|
}
|
|
64
64
|
}, [value]);
|
|
65
65
|
const handleUpload = async (file) => {
|
|
66
|
+
// max file size 300KB
|
|
66
67
|
if (file?.size && file.size <= 300000) {
|
|
67
|
-
const dataUrl =
|
|
68
|
+
const dataUrl = await blobToDataUrl(file);
|
|
68
69
|
setImage(dataUrl);
|
|
69
|
-
|
|
70
|
+
try {
|
|
71
|
+
handleChange && (await handleChange(id, dataUrl));
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
console.error('Failed to update field:', error);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
try {
|
|
78
|
+
await onAutosave?.(id);
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
console.error('Autosave failed:', error);
|
|
82
|
+
}
|
|
70
83
|
}
|
|
71
84
|
};
|
|
72
|
-
const handleRemove = (e) => {
|
|
85
|
+
const handleRemove = async (e) => {
|
|
73
86
|
setImage(null);
|
|
74
|
-
|
|
87
|
+
try {
|
|
88
|
+
handleChange && (await handleChange(id, ''));
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
console.error('Failed to update field:', error);
|
|
92
|
+
e.stopPropagation();
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
try {
|
|
96
|
+
await onAutosave?.(id);
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
console.error('Autosave failed:', error);
|
|
100
|
+
}
|
|
75
101
|
e.stopPropagation();
|
|
76
102
|
};
|
|
77
103
|
const { getRootProps, getInputProps, open } = useDropzone({
|
|
@@ -6,7 +6,7 @@ import { Autocomplete, IconButton, Paper, TextField, Typography } from '../../..
|
|
|
6
6
|
import { getPrefixedUrl, isOptionEqualToValue } from '../utils';
|
|
7
7
|
const UserProperty = (props) => {
|
|
8
8
|
const { id, error, value, readOnly, hasDescription } = props;
|
|
9
|
-
const { fetchedOptions, setFetchedOptions, handleChange, fieldHeight } = useFormContext();
|
|
9
|
+
const { fetchedOptions, setFetchedOptions, handleChange, onAutosave: onAutosave, fieldHeight } = useFormContext();
|
|
10
10
|
const [loadingOptions, setLoadingOptions] = useState(false);
|
|
11
11
|
const apiServices = useApiServices();
|
|
12
12
|
const [options, setOptions] = useState(fetchedOptions[`${id}Options`] || []);
|
|
@@ -40,9 +40,21 @@ const UserProperty = (props) => {
|
|
|
40
40
|
});
|
|
41
41
|
}
|
|
42
42
|
}, [id]);
|
|
43
|
-
function handleChangeUserProperty(id, value) {
|
|
43
|
+
async function handleChangeUserProperty(id, value) {
|
|
44
44
|
const updatedValue = typeof value?.value === 'string' ? { name: value.label, id: value.value } : null;
|
|
45
|
-
|
|
45
|
+
try {
|
|
46
|
+
handleChange && (await handleChange(id, updatedValue));
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
console.error('Failed to update field:', error);
|
|
50
|
+
return; // Exit early if handleChange fails
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
await onAutosave?.(id);
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
console.error('Autosave failed:', error);
|
|
57
|
+
}
|
|
46
58
|
}
|
|
47
59
|
return (options && (React.createElement(Autocomplete, { id: id, fullWidth: true, open: openOptions, popupIcon: userValue || readOnly ? '' : React.createElement(ExpandMore, null), clearIcon: !loadingOptions && userValue ? (React.createElement(IconButton, { size: "small", disableRipple: true, onKeyDown: (e) => {
|
|
48
60
|
if (e.key === 'Enter') {
|