@evoke-platform/ui-components 1.10.0-dev.33 → 1.10.0-dev.35

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (24) hide show
  1. package/dist/published/components/custom/CriteriaBuilder/CriteriaBuilder.js +24 -2
  2. package/dist/published/components/custom/CriteriaBuilder/CriteriaBuilder.test.js +45 -0
  3. package/dist/published/components/custom/FormField/DatePickerSelect/DatePickerSelect.js +22 -6
  4. package/dist/published/components/custom/FormField/FormField.d.ts +3 -1
  5. package/dist/published/components/custom/FormField/FormField.js +17 -5
  6. package/dist/published/components/custom/FormField/InputFieldComponent/InputFieldComponent.js +6 -4
  7. package/dist/published/components/custom/FormV2/FormRenderer.js +17 -0
  8. package/dist/published/components/custom/FormV2/FormRendererContainer.js +66 -83
  9. package/dist/published/components/custom/FormV2/components/DefaultValues.d.ts +2 -2
  10. package/dist/published/components/custom/FormV2/components/DefaultValues.js +36 -28
  11. package/dist/published/components/custom/FormV2/components/FormFieldTypes/relatedObjectFiles/ObjectPropertyInput.js +13 -13
  12. package/dist/published/components/custom/FormV2/components/FormFieldTypes/relatedObjectFiles/RelatedObjectInstance.d.ts +2 -3
  13. package/dist/published/components/custom/FormV2/components/FormFieldTypes/relatedObjectFiles/RelatedObjectInstance.js +5 -4
  14. package/dist/published/components/custom/FormV2/components/PropertyProtection.d.ts +16 -0
  15. package/dist/published/components/custom/FormV2/components/PropertyProtection.js +113 -0
  16. package/dist/published/components/custom/FormV2/components/RecursiveEntryRenderer.js +3 -2
  17. package/dist/published/components/custom/FormV2/components/types.d.ts +1 -0
  18. package/dist/published/components/custom/FormV2/components/utils.d.ts +2 -0
  19. package/dist/published/components/custom/FormV2/components/utils.js +72 -4
  20. package/dist/published/components/custom/FormV2/tests/FormRenderer.test.js +127 -1
  21. package/dist/published/components/custom/ViewDetailsV2/InstanceEntryRenderer.js +13 -3
  22. package/dist/published/stories/CriteriaBuilder.stories.js +6 -0
  23. package/dist/published/types.d.ts +3 -0
  24. package/package.json +1 -1
@@ -400,9 +400,31 @@ const CriteriaBuilder = (props) => {
400
400
  const fields = useMemo(() => {
401
401
  return properties
402
402
  .filter(({ type }) => type !== 'collection')
403
- .map((property) => {
403
+ .flatMap((property) => {
404
+ if (property.type === 'object') {
405
+ const result = [
406
+ {
407
+ name: `${property.id}.id`,
408
+ label: `${property.name} ID`,
409
+ inputType: property.type,
410
+ },
411
+ {
412
+ name: `${property.id}.name`,
413
+ label: `${property.name} Name`,
414
+ inputType: property.type,
415
+ },
416
+ ];
417
+ if (!property.objectId) {
418
+ result.push({
419
+ name: `${property.id}.objectId`,
420
+ label: `${property.name} Object ID`,
421
+ inputType: property.type,
422
+ });
423
+ }
424
+ return result;
425
+ }
404
426
  return {
405
- name: property.type === 'object' ? `${property.id}.id` : property.id,
427
+ name: property.id,
406
428
  label: property.name,
407
429
  inputType: property.type,
408
430
  ...(property.enum && {
@@ -56,6 +56,17 @@ const mockProperties = [
56
56
  name: 'Boolean',
57
57
  type: 'boolean',
58
58
  },
59
+ {
60
+ id: 'regularRelatedObject',
61
+ name: 'Regular Related Object',
62
+ type: 'object',
63
+ objectId: 'relatedObjectId',
64
+ },
65
+ {
66
+ id: 'dynamicRelatedObject',
67
+ name: 'Dynamic Related Object',
68
+ type: 'object',
69
+ },
59
70
  ];
60
71
  describe('CriteriaBuilder', () => {
61
72
  // Mock function for setCriteria
@@ -64,6 +75,40 @@ describe('CriteriaBuilder', () => {
64
75
  // Reset the mock before each test
65
76
  setCriteriaMock.mockReset();
66
77
  });
78
+ describe('when passed regular related object fields', () => {
79
+ it('should render the field ID', () => {
80
+ render(React.createElement(CriteriaBuilder, { properties: mockProperties, criteria: {
81
+ 'regularRelatedObject.id': 'relatedInstanceId',
82
+ }, setCriteria: setCriteriaMock }));
83
+ expect(screen.getByRole('combobox', { name: /select property/i })).toHaveValue('Regular Related Object ID');
84
+ });
85
+ it('should render the field Name', () => {
86
+ render(React.createElement(CriteriaBuilder, { properties: mockProperties, criteria: {
87
+ 'regularRelatedObject.name': 'relatedInstanceName',
88
+ }, setCriteria: setCriteriaMock }));
89
+ expect(screen.getByRole('combobox', { name: /select property/i })).toHaveValue('Regular Related Object Name');
90
+ });
91
+ });
92
+ describe('when passed dynamic related object fields', () => {
93
+ it('should render the field ID', () => {
94
+ render(React.createElement(CriteriaBuilder, { properties: mockProperties, criteria: {
95
+ 'dynamicRelatedObject.id': 'relatedInstanceId',
96
+ }, setCriteria: setCriteriaMock }));
97
+ expect(screen.getByRole('combobox', { name: /select property/i })).toHaveValue('Dynamic Related Object ID');
98
+ });
99
+ it('should render the field Name', () => {
100
+ render(React.createElement(CriteriaBuilder, { properties: mockProperties, criteria: {
101
+ 'dynamicRelatedObject.name': 'relatedInstanceName',
102
+ }, setCriteria: setCriteriaMock }));
103
+ expect(screen.getByRole('combobox', { name: /select property/i })).toHaveValue('Dynamic Related Object Name');
104
+ });
105
+ it('should render the field Object ID', () => {
106
+ render(React.createElement(CriteriaBuilder, { properties: mockProperties, criteria: {
107
+ 'dynamicRelatedObject.objectId': 'relatedInstanceObjectId',
108
+ }, setCriteria: setCriteriaMock }));
109
+ expect(screen.getByRole('combobox', { name: /select property/i })).toHaveValue('Dynamic Related Object Object ID');
110
+ });
111
+ });
67
112
  describe('when passed single-select fields', () => {
68
113
  it('should render the field name', () => {
69
114
  render(React.createElement(CriteriaBuilder, { properties: mockProperties, criteria: {
@@ -1,9 +1,10 @@
1
1
  import { DateTimeFormatter } from '@js-joda/core';
2
2
  import { omit } from 'lodash';
3
- import React, { useEffect, useState } from 'react';
3
+ import React, { useCallback, useEffect, useState } from 'react';
4
4
  import { useFormContext } from '../../../../theme/hooks';
5
5
  import { InvalidDate, LocalDate, nativeJs } from '../../../../util';
6
6
  import { DatePicker, LocalizationProvider, TextField } from '../../../core';
7
+ import { obfuscateValue } from '../../FormV2/components/utils';
7
8
  import InputFieldComponent from '../InputFieldComponent/InputFieldComponent';
8
9
  function asCalendarDate(value) {
9
10
  if (!value) {
@@ -28,12 +29,16 @@ const asMonthDayYearFormat = (date) => {
28
29
  }
29
30
  };
30
31
  const DatePickerSelect = (props) => {
31
- const { id, property, defaultValue, error, errorMessage, readOnly, required, size, onBlur, onChange, additionalProps, } = props;
32
- const [value, setValue] = useState(asCalendarDate(defaultValue));
32
+ const { id, property, defaultValue, error, errorMessage, readOnly, required, size, onBlur, onChange, additionalProps, endAdornment, protection, } = props;
33
33
  const { onAutosave } = useFormContext();
34
+ const processValue = useCallback((val) => {
35
+ const isProtected = protection?.maskChar && val === obfuscateValue(val, { protection });
36
+ return isProtected && typeof val === 'string' ? val : asCalendarDate(val);
37
+ }, [protection]);
38
+ const [value, setValue] = useState(() => processValue(defaultValue));
34
39
  useEffect(() => {
35
- setValue(asCalendarDate(defaultValue));
36
- }, [defaultValue]);
40
+ setValue(processValue(defaultValue));
41
+ }, [defaultValue, processValue]);
37
42
  const handleChange = (date) => {
38
43
  setValue(date);
39
44
  onChange && onChange(property.id, date, property);
@@ -49,12 +54,23 @@ const DatePickerSelect = (props) => {
49
54
  }
50
55
  }
51
56
  };
52
- return readOnly ? (React.createElement(InputFieldComponent, { ...{ ...props, defaultValue: asMonthDayYearFormat(value) } })) : (React.createElement(LocalizationProvider, null,
57
+ return readOnly ? (React.createElement(InputFieldComponent, { ...{
58
+ ...props,
59
+ defaultValue: protection?.maskChar && value === obfuscateValue(value, { protection })
60
+ ? value
61
+ : asMonthDayYearFormat(value),
62
+ endAdornment,
63
+ } })) : (React.createElement(LocalizationProvider, null,
53
64
  React.createElement(DatePicker, { value: value, onChange: handleChange, onAccept: handleAccept, inputFormat: "MM/dd/yyyy", renderInput: (params) => (React.createElement(TextField, { ...params, id: id, error: error, errorMessage: errorMessage, onBlur: onBlur, fullWidth: true, required: required, sx: { background: 'white', borderRadius: '8px' }, size: size ?? 'medium',
54
65
  // merges MUI inputProps with additionalProps.inputProps in a way that still shows the value
55
66
  inputProps: {
56
67
  ...params.inputProps,
57
68
  ...(additionalProps?.inputProps ?? {}),
69
+ }, InputProps: {
70
+ ...params.InputProps,
71
+ endAdornment: (React.createElement(React.Fragment, null,
72
+ params.InputProps?.endAdornment,
73
+ endAdornment)),
58
74
  }, ...omit(additionalProps, ['inputProps']) })) })));
59
75
  };
60
76
  export default DatePickerSelect;
@@ -1,4 +1,4 @@
1
- import { SelectOption } from '@evoke-platform/context';
1
+ import { PropertyProtection as PropertyProtectionType, SelectOption } from '@evoke-platform/context';
2
2
  import React, { FocusEventHandler, ReactNode } from 'react';
3
3
  import { ObjectProperty } from '../../../types';
4
4
  import { AutocompleteOption } from '../../core';
@@ -36,6 +36,8 @@ export type FormFieldProps = {
36
36
  description?: string;
37
37
  tooltip?: string;
38
38
  isCombobox?: boolean;
39
+ endAdornment?: ReactNode;
40
+ protection?: PropertyProtectionType;
39
41
  };
40
42
  declare const FormField: (props: FormFieldProps) => React.JSX.Element;
41
43
  export default FormField;
@@ -1,4 +1,5 @@
1
- import React from 'react';
1
+ import React, { useEffect, useState } from 'react';
2
+ import PropertyProtection from '../FormV2/components/PropertyProtection';
2
3
  import AddressFieldComponent from './AddressFieldComponent/addressFieldComponent';
3
4
  import BooleanSelect from './BooleanSelect/BooleanSelect';
4
5
  import DatePickerSelect from './DatePickerSelect/DatePickerSelect';
@@ -8,8 +9,16 @@ import InputFieldComponent from './InputFieldComponent/InputFieldComponent';
8
9
  import Select from './Select/Select';
9
10
  import TimePickerSelect from './TimePickerSelect/TimePickerSelect';
10
11
  const FormField = (props) => {
11
- const { id, defaultValue, error, onChange, property, readOnly, selectOptions, required, strictlyTrue, size, placeholder, errorMessage, onBlur, mask, max, min, isMultiLineText, rows, inputMaskPlaceholderChar, queryAddresses, isOptionEqualToValue, renderOption, disableCloseOnSelect, getOptionLabel, additionalProps, displayOption, sortBy, label, description, tooltip, isCombobox, } = props;
12
- let control;
12
+ const { id, defaultValue, error, onChange, property, readOnly, selectOptions, required, strictlyTrue, size, placeholder, errorMessage, onBlur, mask, max, min, isMultiLineText, rows, inputMaskPlaceholderChar, queryAddresses, isOptionEqualToValue, renderOption, disableCloseOnSelect, getOptionLabel, additionalProps, displayOption, sortBy, label, description, tooltip, isCombobox, protection, } = props;
13
+ const [currentDisplayValue, setCurrentDisplayValue] = useState(defaultValue);
14
+ const isProtectedProperty = !!protection?.maskChar;
15
+ const [protectionMode, setProtectionMode] = useState(isProtectedProperty ? (!currentDisplayValue ? 'edit' : 'mask') : 'full');
16
+ useEffect(() => {
17
+ if (isProtectedProperty && protectionMode === 'edit') {
18
+ setCurrentDisplayValue(defaultValue);
19
+ }
20
+ }, [defaultValue]);
21
+ const protectionComponent = isProtectedProperty && !!defaultValue ? (React.createElement(PropertyProtection, { parameter: property, protection: protection, mask: mask, canEdit: !readOnly, value: defaultValue, handleChange: (value) => onChange?.(property.id, value, property), setCurrentDisplayValue: setCurrentDisplayValue, mode: protectionMode, setMode: setProtectionMode })) : null;
13
22
  const commonProps = {
14
23
  id: id ?? property.id,
15
24
  property,
@@ -17,8 +26,8 @@ const FormField = (props) => {
17
26
  onBlur,
18
27
  error,
19
28
  errorMessage,
20
- readOnly,
21
- defaultValue,
29
+ readOnly: readOnly || (!!isProtectedProperty && protectionMode !== 'edit'),
30
+ defaultValue: isProtectedProperty ? currentDisplayValue : defaultValue,
22
31
  selectOptions,
23
32
  required,
24
33
  strictlyTrue,
@@ -37,7 +46,10 @@ const FormField = (props) => {
37
46
  description,
38
47
  tooltip,
39
48
  isCombobox,
49
+ endAdornment: protectionComponent,
50
+ protection,
40
51
  };
52
+ let control;
41
53
  if (queryAddresses) {
42
54
  control = (React.createElement(AddressFieldComponent, { ...commonProps, mask: mask, inputMaskPlaceholderChar: inputMaskPlaceholderChar, isMultiLineText: isMultiLineText, rows: rows, queryAddresses: queryAddresses }));
43
55
  return control;
@@ -3,6 +3,7 @@ import React, { useEffect, useState } from 'react';
3
3
  import InputMask from 'react-input-mask';
4
4
  import NumberFormat from 'react-number-format';
5
5
  import { Autocomplete, TextField } from '../../../core';
6
+ import { obfuscateValue } from '../../FormV2/components/utils';
6
7
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
7
8
  export const NumericFormat = (props) => {
8
9
  const { inputRef, onChange, defaultValue, ...other } = props;
@@ -15,7 +16,7 @@ export const NumericFormat = (props) => {
15
16
  }, isNumericString: true, fixedDecimalScale: true, allowNegative: true }));
16
17
  };
17
18
  const InputFieldComponent = (props) => {
18
- const { id, property, defaultValue, error, errorMessage, onBlur, readOnly, required, size, placeholder, mask, min, max, isMultiLineText, rows, inputMaskPlaceholderChar, additionalProps, } = props;
19
+ const { id, property, defaultValue, error, errorMessage, onBlur, readOnly, required, size, placeholder, mask, min, max, isMultiLineText, rows, inputMaskPlaceholderChar, additionalProps, endAdornment, protection, } = props;
19
20
  const [value, setValue] = useState(defaultValue ?? '');
20
21
  const [inputValue, setInputValue] = useState('');
21
22
  useEffect(() => {
@@ -43,6 +44,7 @@ const InputFieldComponent = (props) => {
43
44
  : property.type === 'integer'
44
45
  ? { inputProps: { min, max, ...(additionalProps?.inputProps ?? {}) } }
45
46
  : null;
47
+ const isValueProtected = protection?.maskChar && defaultValue === obfuscateValue(defaultValue, { protection, mask });
46
48
  return property.enum && !readOnly ? (React.createElement(Autocomplete, { id: id,
47
49
  // note: this is different between widgets and builder
48
50
  // builder had select options being {label, value}
@@ -53,7 +55,7 @@ const InputFieldComponent = (props) => {
53
55
  ? [...property.enum, defaultValue]
54
56
  : property.enum, onChange: handleSelectChange, renderInput: (params) => (React.createElement(TextField, { ...params, value: value, error: error, errorMessage: errorMessage, fullWidth: true, onBlur: onBlur, size: size ?? 'medium', placeholder: placeholder })), disableClearable: true, value: value, isOptionEqualToValue: (option, value) => {
55
57
  return option.value === value;
56
- }, error: error, required: required, inputValue: inputValue ?? '', onInputChange: handleInputValueChange, ...(additionalProps ?? {}) })) : !mask ? (React.createElement(TextField, { id: id, sx: {
58
+ }, error: error, required: required, inputValue: inputValue ?? '', onInputChange: handleInputValueChange, ...(additionalProps ?? {}) })) : !mask || isValueProtected ? (React.createElement(TextField, { id: id, sx: {
57
59
  background: 'white',
58
60
  borderRadius: '8px',
59
61
  ...(readOnly && {
@@ -65,7 +67,7 @@ const InputFieldComponent = (props) => {
65
67
  backgroundColor: '#f4f6f8',
66
68
  },
67
69
  }),
68
- }, error: error, errorMessage: errorMessage, value: value, onChange: !readOnly ? handleChange : undefined, InputProps: { ...InputProps, readOnly: readOnly }, required: required, fullWidth: true, onBlur: onBlur, placeholder: readOnly ? undefined : placeholder, size: size ?? 'medium', type: property.type === 'integer' ? 'number' : 'text', multiline: property.type === 'string' && !readOnly && isMultiLineText, rows: isMultiLineText ? (rows ? rows : 3) : undefined, ...(additionalProps ?? {}) })) : (React.createElement(InputMask, { mask: mask, maskChar: inputMaskPlaceholderChar ?? '_', value: value, onChange: !readOnly ? handleChange : undefined, onBlur: onBlur, alwaysShowMask: true }, (() => (React.createElement(TextField, { id: id, sx: readOnly
70
+ }, error: error, errorMessage: errorMessage, value: value, onChange: !readOnly ? handleChange : undefined, InputProps: { ...InputProps, endAdornment, readOnly: readOnly }, required: required, fullWidth: true, onBlur: onBlur, placeholder: readOnly ? undefined : placeholder, size: size ?? 'medium', type: property.type === 'integer' ? 'number' : 'text', multiline: property.type === 'string' && !readOnly && isMultiLineText, rows: isMultiLineText ? (rows ? rows : 3) : undefined, ...(additionalProps ?? {}) })) : (React.createElement(InputMask, { mask: mask, maskChar: inputMaskPlaceholderChar ?? '_', value: value, onChange: !readOnly ? handleChange : undefined, onBlur: onBlur, alwaysShowMask: true }, (() => (React.createElement(TextField, { id: id, sx: readOnly
69
71
  ? {
70
72
  '& .MuiOutlinedInput-notchedOutline': {
71
73
  border: 'none',
@@ -75,7 +77,7 @@ const InputFieldComponent = (props) => {
75
77
  backgroundColor: '#f4f6f8',
76
78
  },
77
79
  }
78
- : undefined, required: required, error: error, errorMessage: errorMessage, InputProps: { ...InputProps, readOnly: readOnly }, fullWidth: true, size: size ?? 'medium', type: property.type === 'integer' ? 'number' : 'text', multiline: property.type === 'string' && !readOnly && isMultiLineText, rows: isMultiLineText ? (rows ? rows : 3) : undefined, ...(additionalProps ?? {}) })
80
+ : undefined, required: required, error: error, errorMessage: errorMessage, InputProps: { ...InputProps, endAdornment, readOnly: readOnly }, fullWidth: true, size: size ?? 'medium', type: property.type === 'integer' ? 'number' : 'text', multiline: property.type === 'string' && !readOnly && isMultiLineText, rows: isMultiLineText ? (rows ? rows : 3) : undefined, ...(additionalProps ?? {}) })
79
81
  // Casting to `React.ReactNode` is necessary to resolve TypeScript errors
80
82
  // due to compatibility issues with the outdated `react-input-mask` version
81
83
  // and the newer `@types/react` package.
@@ -122,6 +122,22 @@ const FormRendererInternal = (props) => {
122
122
  }
123
123
  });
124
124
  };
125
+ const removeUneditedProtectedValues = () => {
126
+ const protectedProperties = object?.properties?.filter((prop) => prop.protection?.maskChar);
127
+ if (!protectedProperties || protectedProperties.length === 0) {
128
+ return;
129
+ }
130
+ protectedProperties.forEach((property) => {
131
+ const fieldId = property.id;
132
+ const originalValue = instance?.[fieldId];
133
+ const value = getValues(fieldId);
134
+ // When protected value hasn't been edited or viewed, unregister to
135
+ // avoid saving the obfuscated value.
136
+ if (value === originalValue) {
137
+ processFieldUnregister(fieldId);
138
+ }
139
+ });
140
+ };
125
141
  const processFieldUnregister = (fieldId) => {
126
142
  if (isAddressProperty(fieldId)) {
127
143
  // Unregister entire addressObject to clear hidden field errors, then restore existing values since unregistering address.line1 etc is not working
@@ -145,6 +161,7 @@ const FormRendererInternal = (props) => {
145
161
  };
146
162
  async function unregisterHiddenFieldsAndSubmit() {
147
163
  unregisterHiddenFields(entries ?? []);
164
+ removeUneditedProtectedValues();
148
165
  await handleSubmit((data) => onSubmit && onSubmit(action?.type === 'delete' ? {} : data), (errors) => onSubmitError(errors))();
149
166
  }
150
167
  const headerProps = {
@@ -1,6 +1,6 @@
1
1
  import { useApiServices, useApp, useAuthenticationContext, useNavigate, useObject, } from '@evoke-platform/context';
2
2
  import axios from 'axios';
3
- import { cloneDeep, get, isArray, isEmpty, isEqual, merge, omit, pick, set, uniq } from 'lodash';
3
+ import { cloneDeep, get, isArray, isEmpty, isEqual, omit, pick, set, uniq } from 'lodash';
4
4
  import React, { useEffect, useRef, useState } from 'react';
5
5
  import { Skeleton, Snackbar } from '../../core';
6
6
  import { Box } from '../../layout';
@@ -278,100 +278,83 @@ function FormRendererContainer(props) {
278
278
  };
279
279
  const getDefaultValues = async (entries, instanceData) => {
280
280
  const result = {};
281
- const processEntries = async (entries) => {
282
- if (!entries)
283
- return;
284
- for (const entry of entries) {
285
- if (entry.type === 'sections' || entry.type === 'columns') {
286
- const subEntries = entry.type === 'sections' ? entry.sections : entry.columns;
287
- for (const subEntry of subEntries) {
288
- if (subEntry.entries) {
289
- const nested = await getDefaultValues(subEntry.entries, instanceData);
290
- merge(result, nested);
291
- }
281
+ const unnestedEntries = getUnnestedEntries(entries);
282
+ for (const entry of unnestedEntries) {
283
+ if ((entry.type === 'input' || entry.type === 'inputField') &&
284
+ isAddressProperty(entry.parameterId || entry.input?.id)) {
285
+ const fieldId = getEntryId(entry);
286
+ if (!fieldId)
287
+ continue;
288
+ const fieldValue = get(instanceData, fieldId);
289
+ if ((isEmpty(instanceData) || fieldValue === undefined || fieldValue === null || fieldValue === '') &&
290
+ entry?.display?.defaultValue &&
291
+ parameters) {
292
+ const defaultValuesArray = await evalDefaultVals(parameters, unnestedEntries, entry, fieldValue, fieldId, apiServices, userAccount, instanceData);
293
+ if (isArray(defaultValuesArray)) {
294
+ defaultValuesArray.forEach(({ fieldId, fieldValue }) => {
295
+ set(result, fieldId, fieldValue);
296
+ });
292
297
  }
293
298
  }
294
- if ((entry.type === 'input' || entry.type === 'inputField') &&
295
- isAddressProperty(entry.parameterId || entry.input?.id)) {
296
- const fieldId = getEntryId(entry);
297
- if (!fieldId)
298
- return;
299
- const fieldValue = get(instanceData, fieldId);
300
- if ((isEmpty(instanceData) ||
301
- fieldValue === undefined ||
302
- fieldValue === null ||
303
- fieldValue === '') &&
304
- entry?.display?.defaultValue &&
305
- parameters) {
306
- const defaultValuesArray = await evalDefaultVals(parameters, entry, fieldValue, fieldId, apiServices, userAccount, instanceData);
307
- if (isArray(defaultValuesArray)) {
308
- defaultValuesArray.forEach(({ fieldId, fieldValue }) => {
309
- set(result, fieldId, fieldValue);
310
- });
311
- }
312
- }
313
- else if (fieldValue !== undefined && fieldValue !== null) {
314
- set(result, fieldId, fieldValue);
315
- }
299
+ else if (fieldValue !== undefined && fieldValue !== null) {
300
+ set(result, fieldId, fieldValue);
316
301
  }
317
- else if (entry.type !== 'sections' && entry.type !== 'columns' && entry.type !== 'content') {
318
- const fieldId = entry.type === 'input'
319
- ? entry.parameterId
320
- : entry.type === 'inputField'
321
- ? entry.input?.id
322
- : undefined;
323
- if (fieldId) {
324
- const fieldValue = instanceData?.[fieldId] ??
325
- instanceData?.metadata?.[fieldId];
326
- const parameter = parameters?.find((param) => param.id === fieldId);
327
- if (associatedObject?.propertyId === fieldId &&
328
- associatedObject?.instanceId &&
329
- parameter &&
330
- action?.type === 'create') {
331
- try {
332
- const instance = await apiServices.get(getPrefixedUrl(`/objects/${parameter.objectId}/instances/${associatedObject.instanceId}`));
333
- result[associatedObject.propertyId] = instance;
334
- }
335
- catch (error) {
336
- console.error(error);
337
- }
302
+ }
303
+ else if (entry.type !== 'sections' && entry.type !== 'columns' && entry.type !== 'content') {
304
+ const fieldId = entry.type === 'input'
305
+ ? entry.parameterId
306
+ : entry.type === 'inputField'
307
+ ? entry.input?.id
308
+ : undefined;
309
+ if (fieldId) {
310
+ const fieldValue = instanceData?.[fieldId] ??
311
+ instanceData?.metadata?.[fieldId];
312
+ const parameter = parameters?.find((param) => param.id === fieldId);
313
+ if (associatedObject?.propertyId === fieldId &&
314
+ associatedObject?.instanceId &&
315
+ parameter &&
316
+ action?.type === 'create') {
317
+ try {
318
+ const instance = await apiServices.get(getPrefixedUrl(`/objects/${parameter.objectId}/instances/${associatedObject.instanceId}`));
319
+ result[associatedObject.propertyId] = instance;
338
320
  }
339
- else if (entry.type !== 'readonlyField' &&
340
- isEmptyWithDefault(fieldValue, entry, instanceData)) {
341
- if (fieldId && parameters && parameters.length > 0) {
342
- const defaultValuesArray = await evalDefaultVals(parameters, entry, fieldValue, fieldId, apiServices, userAccount, instanceData);
343
- for (const { fieldId, fieldValue } of defaultValuesArray) {
344
- const parameter = parameters?.find((param) => param.id === fieldId);
345
- if (parameter?.type === 'object') {
346
- const dependentFields = await processValueUpdate(form?.entries, parameters, fieldValue, apiServices, fieldId, formDataRef.current, userAccount);
347
- for (const field of dependentFields) {
348
- set(result, field.fieldId, field.fieldValue);
349
- }
321
+ catch (error) {
322
+ console.error(error);
323
+ }
324
+ }
325
+ else if (entry.type !== 'readonlyField' && isEmptyWithDefault(fieldValue, entry, instanceData)) {
326
+ if (fieldId && parameters && parameters.length > 0) {
327
+ const defaultValuesArray = await evalDefaultVals(parameters, unnestedEntries, entry, fieldValue, fieldId, apiServices, userAccount, instanceData);
328
+ for (const { fieldId, fieldValue } of defaultValuesArray) {
329
+ const parameter = parameters?.find((param) => param.id === fieldId);
330
+ if (parameter?.type === 'object') {
331
+ const dependentFields = await processValueUpdate(unnestedEntries, parameters, fieldValue, apiServices, fieldId, formDataRef.current, userAccount);
332
+ for (const field of dependentFields) {
333
+ set(result, field.fieldId, field.fieldValue);
350
334
  }
351
- set(result, fieldId, fieldValue);
352
335
  }
336
+ set(result, fieldId, fieldValue);
353
337
  }
354
338
  }
355
- else if (parameter?.type === 'boolean' && (fieldValue === undefined || fieldValue === null)) {
356
- result[fieldId] = false;
357
- }
358
- else if (fieldValue !== undefined && fieldValue !== null) {
359
- if (parameter?.type === 'richText' && typeof fieldValue === 'string') {
360
- let RTFFieldValue = fieldValue;
361
- if (!fieldValue.trim().startsWith('{\\rtf')) {
362
- RTFFieldValue = plainTextToRtf(fieldValue);
363
- }
364
- result[fieldId] = RTFFieldValue;
365
- }
366
- else {
367
- result[fieldId] = fieldValue;
339
+ }
340
+ else if (parameter?.type === 'boolean' && (fieldValue === undefined || fieldValue === null)) {
341
+ result[fieldId] = false;
342
+ }
343
+ else if (fieldValue !== undefined && fieldValue !== null) {
344
+ if (parameter?.type === 'richText' && typeof fieldValue === 'string') {
345
+ let RTFFieldValue = fieldValue;
346
+ if (!fieldValue.trim().startsWith('{\\rtf')) {
347
+ RTFFieldValue = plainTextToRtf(fieldValue);
368
348
  }
349
+ result[fieldId] = RTFFieldValue;
350
+ }
351
+ else {
352
+ result[fieldId] = fieldValue;
369
353
  }
370
354
  }
371
355
  }
372
356
  }
373
- };
374
- await processEntries(entries);
357
+ }
375
358
  return result;
376
359
  };
377
360
  const handleAutosave = async (fieldId) => {
@@ -423,7 +406,7 @@ function FormRendererContainer(props) {
423
406
  if (parameter) {
424
407
  if (parameter.type === 'object' && parameters && parameters.length > 0) {
425
408
  // On change of a related object, update default values dependent on that object
426
- const dependentFields = await processValueUpdate(form?.entries, parameters, value, apiServices, id, formDataRef.current, userAccount);
409
+ const dependentFields = await processValueUpdate(entries, parameters, value, apiServices, id, formDataRef.current, userAccount);
427
410
  for (const field of dependentFields) {
428
411
  onChange(field.fieldId, field.fieldValue);
429
412
  }
@@ -1,10 +1,10 @@
1
1
  import { ApiServices, FormEntry, InputField, InputParameter, InputParameterReference, ObjectInstance, Reference, UserAccount } from '@evoke-platform/context';
2
2
  import { FieldValues } from 'react-hook-form';
3
- export declare function evalDefaultVals(parameters: InputParameter[], entry: InputParameterReference | InputField, fieldValue: unknown, fieldId: string, apiServices: ApiServices, userAccount?: UserAccount, formValues?: FieldValues, updatedRelatedObjectValue?: ObjectInstance | null | Reference): Promise<{
3
+ export declare function evalDefaultVals(parameters: InputParameter[], unnestedEntries: FormEntry[], entry: InputParameterReference | InputField, fieldValue: unknown, fieldId: string, apiServices: ApiServices, userAccount?: UserAccount, formValues?: FieldValues, updatedRelatedObjectValue?: ObjectInstance | null | Reference): Promise<{
4
4
  fieldId: string;
5
5
  fieldValue: unknown;
6
6
  }[]>;
7
- export declare function processValueUpdate(entries: FormEntry[] | undefined, parameters: InputParameter[], updatedRelatedObjectValue: ObjectInstance | null | Reference, apiServices: ApiServices, changedEntryId?: string, formValues?: FieldValues, userAccount?: UserAccount): Promise<{
7
+ export declare function processValueUpdate(unnestedEntries: FormEntry[], parameters: InputParameter[], updatedRelatedObjectValue: ObjectInstance | null | Reference, apiServices: ApiServices, changedEntryId?: string, formValues?: FieldValues, userAccount?: UserAccount): Promise<{
8
8
  fieldId: string;
9
9
  fieldValue: unknown;
10
10
  }[]>;