@evoke-platform/ui-components 1.10.0-dev.11 → 1.10.0-dev.13
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/custom/Form/FormComponents/RepeatableFieldComponent/RepeatableField.js +1 -1
- package/dist/published/components/custom/FormField/DatePickerSelect/DatePickerSelect.js +14 -1
- package/dist/published/components/custom/FormField/DateTimePickerSelect/DateTimePickerSelect.js +14 -1
- package/dist/published/components/custom/FormField/TimePickerSelect/TimePickerSelect.js +14 -1
- package/dist/published/components/custom/FormV2/FormRenderer.js +2 -1
- package/dist/published/components/custom/FormV2/FormRendererContainer.js +1 -15
- 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/FieldWrapper.js +1 -1
- package/dist/published/components/custom/FormV2/components/FormContext.d.ts +2 -2
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/AddressFields.d.ts +9 -0
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/AddressFields.js +5 -5
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/Criteria.js +1 -1
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/DocumentFiles/Document.js +1 -1
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/DocumentFiles/DocumentList.d.ts +1 -1
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/DocumentFiles/DocumentList.js +1 -1
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/Image.js +2 -2
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/UserProperty.js +1 -1
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/relatedObjectFiles/ObjectPropertyInput.js +57 -66
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/relatedObjectFiles/RelatedObjectInstance.js +2 -2
- package/dist/published/components/custom/FormV2/components/Header.d.ts +11 -3
- package/dist/published/components/custom/FormV2/components/Header.js +4 -4
- package/dist/published/components/custom/FormV2/components/RecursiveEntryRenderer.js +14 -19
- package/dist/published/components/custom/FormV2/components/types.d.ts +1 -0
- package/dist/published/components/custom/FormV2/components/utils.d.ts +2 -2
- package/dist/published/components/custom/FormV2/components/utils.js +7 -7
- package/dist/published/components/custom/FormV2/tests/FormRendererContainer.test.js +9 -18
- package/dist/published/components/custom/ViewDetailsV2/InstanceEntryRenderer.d.ts +3 -0
- package/dist/published/components/custom/ViewDetailsV2/InstanceEntryRenderer.js +155 -0
- package/dist/published/components/custom/ViewDetailsV2/ViewDetailsV2Renderer.d.ts +13 -0
- package/dist/published/components/custom/ViewDetailsV2/ViewDetailsV2Renderer.js +140 -0
- package/dist/published/components/custom/ViewDetailsV2/index.d.ts +2 -0
- package/dist/published/components/custom/ViewDetailsV2/index.js +2 -0
- package/dist/published/components/custom/index.d.ts +1 -0
- package/dist/published/components/custom/index.js +1 -0
- package/dist/published/index.d.ts +1 -1
- package/dist/published/index.js +1 -1
- package/dist/published/stories/FormRendererData.d.ts +12 -0
- package/dist/published/stories/FormRendererData.js +23 -0
- 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 +3 -3
- package/package.json +2 -2
|
@@ -7,7 +7,7 @@ import { Typography } from '../../../core/Typography';
|
|
|
7
7
|
import Box from '../../../layout/Box/Box';
|
|
8
8
|
import ValidationErrors from './ValidationFiles/ValidationErrors';
|
|
9
9
|
const Header = (props) => {
|
|
10
|
-
const { title, errors, hasAccordions, shouldShowValidationErrors, validationErrorsRef,
|
|
10
|
+
const { title, errors, hasAccordions, shouldShowValidationErrors, validationErrorsRef, sx, isDeleteForm, autosaveEnabled, } = props;
|
|
11
11
|
const { width } = useFormContext();
|
|
12
12
|
const { breakpoints, isBelow } = useWidgetSize({
|
|
13
13
|
scroll: false,
|
|
@@ -24,7 +24,7 @@ const Header = (props) => {
|
|
|
24
24
|
flexWrap: 'wrap',
|
|
25
25
|
paddingY: isSm || isXs ? 2 : 3,
|
|
26
26
|
// when rendering the default delete action, we don't want a border
|
|
27
|
-
borderBottom:
|
|
27
|
+
borderBottom: isDeleteForm ? undefined : '1px solid #e9ecef',
|
|
28
28
|
gap: isSm || isXs ? 2 : 3,
|
|
29
29
|
'.evoke-form-renderer-header': {
|
|
30
30
|
flex: '1 1 100%',
|
|
@@ -37,14 +37,14 @@ const Header = (props) => {
|
|
|
37
37
|
hasAccordions && (React.createElement(Box, { sx: { flex: '0 0 auto', display: 'flex', alignItems: 'center' } },
|
|
38
38
|
React.createElement(Box, { sx: { display: 'flex', alignItems: 'center' } },
|
|
39
39
|
React.createElement(AccordionActions, { ...props })),
|
|
40
|
-
React.createElement(Box, { sx: {
|
|
40
|
+
autosaveEnabled && (React.createElement(Box, { sx: {
|
|
41
41
|
width: '96px',
|
|
42
42
|
minWidth: '72px',
|
|
43
43
|
display: 'flex',
|
|
44
44
|
justifyContent: 'flex-end',
|
|
45
45
|
alignItems: 'center',
|
|
46
46
|
marginLeft: 0.5,
|
|
47
|
-
} }, props.autosaving && isSmall ? React.createElement(SavingIndicator, null) : React.createElement(Box, { sx: { width: '100%' } })))),
|
|
47
|
+
} }, props.autosaving && isSmall ? React.createElement(SavingIndicator, null) : React.createElement(Box, { sx: { width: '100%' } }))))),
|
|
48
48
|
React.createElement("div", { ref: validationErrorsRef, className: 'evoke-form-renderer-header' }, shouldShowValidationErrors && !isEmpty(errors) ? React.createElement(ValidationErrors, { errors: errors }) : null)));
|
|
49
49
|
};
|
|
50
50
|
// Default slot components for convenience
|
|
@@ -38,11 +38,7 @@ function getFieldWrapperProps(fieldDefinition, entry, entryId, fieldValue, displ
|
|
|
38
38
|
}
|
|
39
39
|
export function RecursiveEntryRenderer(props) {
|
|
40
40
|
const { entry } = props;
|
|
41
|
-
const { fetchedOptions, setFetchedOptions, object, getValues, errors, instance, richTextEditor, parameters, handleChange, onAutosave, fieldHeight, triggerFieldReset, associatedObject, form, width, } = useFormContext();
|
|
42
|
-
// If the entry is hidden, clear its value and any nested values, and skip rendering
|
|
43
|
-
if (!entryIsVisible(entry, getValues(), instance)) {
|
|
44
|
-
return null;
|
|
45
|
-
}
|
|
41
|
+
const { fetchedOptions, setFetchedOptions, object, getValues, errors, instance, richTextEditor: RichTextEditor, parameters, handleChange, onAutosave, fieldHeight, triggerFieldReset, associatedObject, form, width, } = useFormContext();
|
|
46
42
|
const { isBelow, breakpoints } = useWidgetSize({
|
|
47
43
|
scroll: false,
|
|
48
44
|
defaultWidth: width,
|
|
@@ -53,20 +49,24 @@ export function RecursiveEntryRenderer(props) {
|
|
|
53
49
|
const userAccount = useAuthenticationContext()?.account;
|
|
54
50
|
const entryId = getEntryId(entry) || 'defaultId';
|
|
55
51
|
const display = 'display' in entry ? entry.display : undefined;
|
|
56
|
-
const fieldValue = entry.type === 'readonlyField' ? instance?.[entryId] : getValues(entryId);
|
|
52
|
+
const fieldValue = entry.type === 'readonlyField' ? instance?.[entryId] : getValues ? getValues(entryId) : undefined;
|
|
57
53
|
const initialMiddleObjectInstances = fetchedOptions[`${entryId}InitialMiddleObjectInstances`];
|
|
58
54
|
const middleObject = fetchedOptions[`${entryId}MiddleObject`];
|
|
59
55
|
const fieldDefinition = useMemo(() => {
|
|
60
56
|
return getFieldDefinition(entry, object, parameters, form?.id === 'documentForm');
|
|
61
57
|
}, [entry, parameters, object]);
|
|
62
58
|
const validation = fieldDefinition?.validation || {};
|
|
63
|
-
if (associatedObject?.propertyId === entryId)
|
|
64
|
-
return null;
|
|
65
59
|
useEffect(() => {
|
|
66
60
|
if (fieldDefinition?.type === 'collection' && fieldDefinition?.manyToManyPropertyId && instance) {
|
|
67
61
|
fetchCollectionData(apiServices, fieldDefinition, setFetchedOptions, instance.id, fetchedOptions, initialMiddleObjectInstances);
|
|
68
62
|
}
|
|
69
63
|
}, [fieldDefinition, instance]);
|
|
64
|
+
if (associatedObject?.propertyId === entryId)
|
|
65
|
+
return null;
|
|
66
|
+
// If the entry is hidden, clear its value and any nested values, and skip rendering
|
|
67
|
+
if (!getValues || !entryIsVisible(entry, instance, getValues())) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
70
|
if (entry.type === 'content') {
|
|
71
71
|
return (React.createElement(Box, { dangerouslySetInnerHTML: { __html: DOMPurify.sanitize(entry.html) }, sx: {
|
|
72
72
|
fontFamily: 'Roboto, Helvetica, Arial, sans-serif',
|
|
@@ -75,7 +75,7 @@ export function RecursiveEntryRenderer(props) {
|
|
|
75
75
|
else if ((entry.type === 'input' || entry.type === 'readonlyField' || entry.type === 'inputField') &&
|
|
76
76
|
fieldDefinition) {
|
|
77
77
|
if (isAddressProperty(entryId)) {
|
|
78
|
-
return React.createElement(AddressFields, { entry: entry, entryId: entryId, fieldDefinition: fieldDefinition });
|
|
78
|
+
return (React.createElement(AddressFields, { entry: entry, entryId: entryId, fieldDefinition: fieldDefinition, readOnly: entry.type === 'readonlyField' }));
|
|
79
79
|
}
|
|
80
80
|
else if (fieldDefinition.type === 'image') {
|
|
81
81
|
return (React.createElement(FieldWrapper, { ...getFieldWrapperProps(fieldDefinition, entry, entryId, fieldValue, display, errors) },
|
|
@@ -118,16 +118,11 @@ export function RecursiveEntryRenderer(props) {
|
|
|
118
118
|
}
|
|
119
119
|
}
|
|
120
120
|
else if (fieldDefinition.type === 'richText') {
|
|
121
|
-
return (React.createElement(FieldWrapper, { ...getFieldWrapperProps(fieldDefinition, entry, entryId, fieldValue, display, errors) },
|
|
121
|
+
return (React.createElement(FieldWrapper, { ...getFieldWrapperProps(fieldDefinition, entry, entryId, fieldValue, display, errors) }, RichTextEditor && handleChange ? (React.createElement(RichTextEditor
|
|
122
|
+
// RichTexts get a uniqueId when the form is loaded to prevent issues with multiple rich text fields on one form
|
|
123
|
+
, {
|
|
122
124
|
// RichTexts get a uniqueId when the form is loaded to prevent issues with multiple rich text fields on one form
|
|
123
|
-
id: entry.uniqueId,
|
|
124
|
-
value: fieldValue,
|
|
125
|
-
handleUpdate: (value) => handleChange(entryId, value),
|
|
126
|
-
format: 'rtf',
|
|
127
|
-
disabled: entry.type === 'readonlyField',
|
|
128
|
-
rows: display?.rowCount,
|
|
129
|
-
hasError: !!errors?.[entryId],
|
|
130
|
-
})) : (React.createElement(FormField, { id: entryId, property: fieldDefinition, defaultValue: fieldValue || getValues(entryId), onChange: handleChange, onBlur: () => {
|
|
125
|
+
id: entry.uniqueId, value: fieldValue, handleUpdate: (value) => handleChange(entryId, value), format: "rtf", disabled: entry.type === 'readonlyField', rows: display?.rowCount, hasError: !!errors?.[entryId] })) : (React.createElement(FormField, { id: entryId, property: fieldDefinition, defaultValue: fieldValue, onChange: handleChange, onBlur: () => {
|
|
131
126
|
onAutosave?.(entryId)?.catch((error) => {
|
|
132
127
|
console.error('Autosave failed:', error);
|
|
133
128
|
});
|
|
@@ -174,7 +169,7 @@ export function RecursiveEntryRenderer(props) {
|
|
|
174
169
|
: `${entryId}-reset-false`, ...getFieldWrapperProps(fieldDefinition, entry, entryId, fieldValue, display, errors), errorMessage: undefined },
|
|
175
170
|
React.createElement(FormField, { id: entryId,
|
|
176
171
|
// TODO: Ideally the FormField prop should be called parameter but can't change the name for backwards compatibility reasons
|
|
177
|
-
property: fieldDefinition, defaultValue: fieldValue
|
|
172
|
+
property: fieldDefinition, defaultValue: fieldValue, onChange: handleChange, onBlur: () => {
|
|
178
173
|
// Blur event - reads current value from formData
|
|
179
174
|
onAutosave?.(entryId)?.catch((error) => {
|
|
180
175
|
console.error('Autosave failed:', error);
|
|
@@ -10,7 +10,7 @@ export declare function isAddressProperty(key: string): boolean;
|
|
|
10
10
|
/**
|
|
11
11
|
* Determine if a form entry is visible or not.
|
|
12
12
|
*/
|
|
13
|
-
export declare const entryIsVisible: (entry: FormEntry,
|
|
13
|
+
export declare const entryIsVisible: (entry: FormEntry, instance?: FieldValues, formValues?: FieldValues) => boolean;
|
|
14
14
|
/**
|
|
15
15
|
* Recursively retrieves all parameter IDs from a given entry of type Sections or Columns.
|
|
16
16
|
*
|
|
@@ -86,7 +86,7 @@ export declare function formatSubmission(submission: FieldValues, apiServices?:
|
|
|
86
86
|
message?: string;
|
|
87
87
|
isError: boolean;
|
|
88
88
|
}>>): Promise<FieldValues>;
|
|
89
|
-
export declare function filterEmptySections(entry: Sections | Columns,
|
|
89
|
+
export declare function filterEmptySections(entry: Sections | Columns, instance?: FieldValues, formData?: FieldValues): Sections | Columns | null;
|
|
90
90
|
export declare function assignIdsToSectionsAndRichText(entries: FormEntry[], object?: Obj, parameters?: InputParameter[]): FormEntry[];
|
|
91
91
|
/**
|
|
92
92
|
* Converts a plain text string to RTF format suitable for a RichTextEditor.
|
|
@@ -68,7 +68,7 @@ export function isAddressProperty(key) {
|
|
|
68
68
|
/**
|
|
69
69
|
* Determine if a form entry is visible or not.
|
|
70
70
|
*/
|
|
71
|
-
export const entryIsVisible = (entry,
|
|
71
|
+
export const entryIsVisible = (entry, instance, formValues) => {
|
|
72
72
|
const display = 'display' in entry ? entry.display : undefined;
|
|
73
73
|
const { visibility } = display ?? ('visibility' in entry ? entry : {});
|
|
74
74
|
if (isObject(visibility) && 'conditions' in visibility && isArray(visibility.conditions)) {
|
|
@@ -669,21 +669,21 @@ export async function formatSubmission(submission, apiServices, objectId, instan
|
|
|
669
669
|
}
|
|
670
670
|
return submission;
|
|
671
671
|
}
|
|
672
|
-
export function filterEmptySections(entry,
|
|
672
|
+
export function filterEmptySections(entry, instance, formData) {
|
|
673
673
|
if (entry.type === 'sections' && isArray(entry.sections)) {
|
|
674
674
|
const visibleSections = entry.sections.filter((section) => {
|
|
675
675
|
if (!section.entries || section.entries.length === 0)
|
|
676
676
|
return false;
|
|
677
677
|
for (const sectionEntry of section.entries) {
|
|
678
678
|
if (sectionEntry.type === 'sections' || sectionEntry.type === 'columns') {
|
|
679
|
-
if (sectionEntry.visibility && !entryIsVisible(sectionEntry,
|
|
679
|
+
if (sectionEntry.visibility && !entryIsVisible(sectionEntry, instance, formData)) {
|
|
680
680
|
return false;
|
|
681
681
|
}
|
|
682
|
-
else if (filterEmptySections(sectionEntry,
|
|
682
|
+
else if (filterEmptySections(sectionEntry, instance, formData)) {
|
|
683
683
|
return true;
|
|
684
684
|
}
|
|
685
685
|
}
|
|
686
|
-
else if (entryIsVisible(sectionEntry,
|
|
686
|
+
else if (entryIsVisible(sectionEntry, instance, formData)) {
|
|
687
687
|
return true;
|
|
688
688
|
}
|
|
689
689
|
}
|
|
@@ -703,13 +703,13 @@ export function filterEmptySections(entry, formData, instance) {
|
|
|
703
703
|
let hasVisibleEntry = false;
|
|
704
704
|
for (const columnEntry of column.entries) {
|
|
705
705
|
if (columnEntry.type === 'sections' || columnEntry.type === 'columns') {
|
|
706
|
-
if (filterEmptySections(columnEntry,
|
|
706
|
+
if (filterEmptySections(columnEntry, instance, formData)) {
|
|
707
707
|
hasVisibleEntry = true;
|
|
708
708
|
break;
|
|
709
709
|
}
|
|
710
710
|
}
|
|
711
711
|
else {
|
|
712
|
-
if (entryIsVisible(columnEntry,
|
|
712
|
+
if (entryIsVisible(columnEntry, instance, formData)) {
|
|
713
713
|
hasVisibleEntry = true;
|
|
714
714
|
break;
|
|
715
715
|
}
|
|
@@ -123,8 +123,7 @@ describe('FormRendererContainer', () => {
|
|
|
123
123
|
license: null,
|
|
124
124
|
});
|
|
125
125
|
}));
|
|
126
|
-
render(React.createElement(
|
|
127
|
-
React.createElement(FormRendererContainer, { objectId: 'specialty', formId: 'specialtyForm', dataType: 'objectInstances', actionId: '_update', instanceId: 'test-instance' })));
|
|
126
|
+
render(React.createElement(FormRendererContainer, { objectId: 'specialty', formId: 'specialtyForm', dataType: 'objectInstances', actionId: '_update', instanceId: 'test-instance' }));
|
|
128
127
|
await waitFor(() => {
|
|
129
128
|
expect(screen.queryByText('Loading...')).not.toBeInTheDocument();
|
|
130
129
|
});
|
|
@@ -174,8 +173,7 @@ describe('FormRendererContainer', () => {
|
|
|
174
173
|
license: null,
|
|
175
174
|
});
|
|
176
175
|
}));
|
|
177
|
-
render(React.createElement(
|
|
178
|
-
React.createElement(FormRendererContainer, { objectId: 'specialty', formId: 'specialtyForm', dataType: 'objectInstances', actionId: '_update', instanceId: 'test-instance' })));
|
|
176
|
+
render(React.createElement(FormRendererContainer, { objectId: 'specialty', formId: 'specialtyForm', dataType: 'objectInstances', actionId: '_update', instanceId: 'test-instance' }));
|
|
179
177
|
await waitFor(() => {
|
|
180
178
|
expect(screen.queryByText('Loading...')).not.toBeInTheDocument();
|
|
181
179
|
});
|
|
@@ -222,8 +220,7 @@ describe('FormRendererContainer', () => {
|
|
|
222
220
|
autosaveActionSpy();
|
|
223
221
|
return HttpResponse.json({ error: 'Save failed' }, { status: 500 });
|
|
224
222
|
}));
|
|
225
|
-
render(React.createElement(
|
|
226
|
-
React.createElement(FormRendererContainer, { objectId: 'specialty', formId: 'specialtyForm', dataType: 'objectInstances', actionId: '_update', instanceId: 'test-instance' })));
|
|
223
|
+
render(React.createElement(FormRendererContainer, { objectId: 'specialty', formId: 'specialtyForm', dataType: 'objectInstances', actionId: '_update', instanceId: 'test-instance' }));
|
|
227
224
|
await waitFor(() => {
|
|
228
225
|
expect(screen.queryByText('Loading...')).not.toBeInTheDocument();
|
|
229
226
|
});
|
|
@@ -267,8 +264,7 @@ describe('FormRendererContainer', () => {
|
|
|
267
264
|
license: null,
|
|
268
265
|
});
|
|
269
266
|
}));
|
|
270
|
-
render(React.createElement(
|
|
271
|
-
React.createElement(FormRendererContainer, { objectId: 'specialty', formId: 'specialtyForm', dataType: 'objectInstances', actionId: '_update', instanceId: 'test-instance' })));
|
|
267
|
+
render(React.createElement(FormRendererContainer, { objectId: 'specialty', formId: 'specialtyForm', dataType: 'objectInstances', actionId: '_update', instanceId: 'test-instance' }));
|
|
272
268
|
await waitFor(() => {
|
|
273
269
|
expect(screen.queryByText('Loading...')).not.toBeInTheDocument();
|
|
274
270
|
});
|
|
@@ -321,8 +317,7 @@ describe('FormRendererContainer', () => {
|
|
|
321
317
|
},
|
|
322
318
|
});
|
|
323
319
|
}));
|
|
324
|
-
render(React.createElement(
|
|
325
|
-
React.createElement(FormRendererContainer, { objectId: 'license', formId: 'licenseForm', dataType: 'objectInstances', actionId: '_update', instanceId: 'test-license' })));
|
|
320
|
+
render(React.createElement(FormRendererContainer, { objectId: 'license', formId: 'licenseForm', dataType: 'objectInstances', actionId: '_update', instanceId: 'test-license' }));
|
|
326
321
|
await waitFor(() => {
|
|
327
322
|
expect(screen.queryByText('Loading...')).not.toBeInTheDocument();
|
|
328
323
|
});
|
|
@@ -382,8 +377,7 @@ describe('FormRendererContainer', () => {
|
|
|
382
377
|
address: body.input.address,
|
|
383
378
|
});
|
|
384
379
|
}));
|
|
385
|
-
render(React.createElement(
|
|
386
|
-
React.createElement(FormRendererContainer, { objectId: 'license', formId: 'licenseForm', dataType: 'objectInstances', actionId: '_update', instanceId: 'test-license' })));
|
|
380
|
+
render(React.createElement(FormRendererContainer, { objectId: 'license', formId: 'licenseForm', dataType: 'objectInstances', actionId: '_update', instanceId: 'test-license' }));
|
|
387
381
|
await waitFor(() => {
|
|
388
382
|
expect(screen.queryByText('Loading...')).not.toBeInTheDocument();
|
|
389
383
|
});
|
|
@@ -444,8 +438,7 @@ describe('FormRendererContainer', () => {
|
|
|
444
438
|
address: body.input.address,
|
|
445
439
|
});
|
|
446
440
|
}));
|
|
447
|
-
render(React.createElement(
|
|
448
|
-
React.createElement(FormRendererContainer, { objectId: 'license', formId: 'licenseForm', dataType: 'objectInstances', actionId: '_update', instanceId: 'test-license' })));
|
|
441
|
+
render(React.createElement(FormRendererContainer, { objectId: 'license', formId: 'licenseForm', dataType: 'objectInstances', actionId: '_update', instanceId: 'test-license' }));
|
|
449
442
|
await waitFor(() => {
|
|
450
443
|
expect(screen.queryByText('Loading...')).not.toBeInTheDocument();
|
|
451
444
|
});
|
|
@@ -492,8 +485,7 @@ describe('FormRendererContainer', () => {
|
|
|
492
485
|
autosaveActionId: '_autosave',
|
|
493
486
|
});
|
|
494
487
|
}));
|
|
495
|
-
render(React.createElement(
|
|
496
|
-
React.createElement(FormRendererContainer, { objectId: 'specialty', formId: 'specialtyForm', dataType: 'objectInstances', actionId: '_update', instanceId: 'test-instance' })));
|
|
488
|
+
render(React.createElement(FormRendererContainer, { objectId: 'specialty', formId: 'specialtyForm', dataType: 'objectInstances', actionId: '_update', instanceId: 'test-instance' }));
|
|
497
489
|
await waitFor(() => {
|
|
498
490
|
expect(screen.queryByText('Loading...')).not.toBeInTheDocument();
|
|
499
491
|
});
|
|
@@ -526,8 +518,7 @@ describe('FormRendererContainer', () => {
|
|
|
526
518
|
});
|
|
527
519
|
}));
|
|
528
520
|
const user = userEvent.setup();
|
|
529
|
-
render(React.createElement(
|
|
530
|
-
React.createElement(FormRendererContainer, { objectId: 'specialty', formId: 'specialtyForm', dataType: 'objectInstances', actionId: '_update', instanceId: 'test-instance' })));
|
|
521
|
+
render(React.createElement(FormRendererContainer, { objectId: 'specialty', formId: 'specialtyForm', dataType: 'objectInstances', actionId: '_update', instanceId: 'test-instance' }));
|
|
531
522
|
await waitFor(() => {
|
|
532
523
|
expect(screen.queryByText('Loading...')).not.toBeInTheDocument();
|
|
533
524
|
});
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { useApiServices, useApp, } from '@evoke-platform/context';
|
|
2
|
+
import { CancelRounded, CheckCircleRounded } from '@mui/icons-material';
|
|
3
|
+
import DOMPurify from 'dompurify';
|
|
4
|
+
import { isEmpty } from 'lodash';
|
|
5
|
+
import { DateTime } from 'luxon';
|
|
6
|
+
import React, { useEffect, useMemo, useState } from 'react';
|
|
7
|
+
import { useFormContext } from '../../../theme/hooks';
|
|
8
|
+
import { Link, Typography } from '../../core';
|
|
9
|
+
import { Box, Grid } from '../../layout';
|
|
10
|
+
import AccordionSections from '../FormV2/components/AccordionSections';
|
|
11
|
+
import FieldWrapper from '../FormV2/components/FieldWrapper';
|
|
12
|
+
import AddressFields from '../FormV2/components/FormFieldTypes/AddressFields';
|
|
13
|
+
import DropdownRepeatableField from '../FormV2/components/FormFieldTypes/CollectionFiles/DropdownRepeatableField';
|
|
14
|
+
import RepeatableField from '../FormV2/components/FormFieldTypes/CollectionFiles/RepeatableField';
|
|
15
|
+
import Criteria from '../FormV2/components/FormFieldTypes/Criteria';
|
|
16
|
+
import { Document } from '../FormV2/components/FormFieldTypes/DocumentFiles/Document';
|
|
17
|
+
import { Image } from '../FormV2/components/FormFieldTypes/Image';
|
|
18
|
+
import { entryIsVisible, fetchCollectionData, filterEmptySections, getDefaultPages, isAddressProperty, } from '../FormV2/components/utils';
|
|
19
|
+
function ViewOnlyEntryRenderer(props) {
|
|
20
|
+
const { entry } = props;
|
|
21
|
+
const { fetchedOptions, setFetchedOptions, object, instance, richTextEditor: RichTextEditor } = useFormContext();
|
|
22
|
+
const entryId = entry.propertyId || 'defaultId';
|
|
23
|
+
const apiServices = useApiServices();
|
|
24
|
+
const { defaultPages, findDefaultPageSlugFor } = useApp();
|
|
25
|
+
const [navigationSlug, setNavigationSlug] = useState(fetchedOptions[`${entryId}NavigationSlug`]);
|
|
26
|
+
const initialMiddleObjectInstances = fetchedOptions[`${entryId}InitialMiddleObjectInstances`];
|
|
27
|
+
const middleObject = fetchedOptions[`${entryId}MiddleObject`];
|
|
28
|
+
const display = 'display' in entry ? entry.display : undefined;
|
|
29
|
+
const fieldDefinition = useMemo(() => {
|
|
30
|
+
const def = entry.type === 'readonlyField'
|
|
31
|
+
? isAddressProperty(entry.propertyId)
|
|
32
|
+
? object?.properties?.find((prop) => prop.id === entry.propertyId.split('.')[0])
|
|
33
|
+
: object?.properties?.find((prop) => prop.id === entry.propertyId)
|
|
34
|
+
: undefined;
|
|
35
|
+
if (def?.enum && def.type === 'string') {
|
|
36
|
+
const cloned = structuredClone(def);
|
|
37
|
+
// single select must be made to be type choices for label and error handling
|
|
38
|
+
cloned.type = 'choices';
|
|
39
|
+
return cloned;
|
|
40
|
+
}
|
|
41
|
+
return def;
|
|
42
|
+
}, [entry, object]);
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
if (fieldDefinition?.type === 'collection' && fieldDefinition?.manyToManyPropertyId && instance) {
|
|
45
|
+
fetchCollectionData(apiServices, fieldDefinition, setFetchedOptions, instance.id, fetchedOptions, initialMiddleObjectInstances);
|
|
46
|
+
}
|
|
47
|
+
}, [fieldDefinition, initialMiddleObjectInstances, setFetchedOptions, instance, fetchedOptions, apiServices]);
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
(async () => {
|
|
50
|
+
if (object?.properties && !fetchedOptions[`${entryId}NavigationSlug`]) {
|
|
51
|
+
const pages = await getDefaultPages(object.properties, defaultPages, findDefaultPageSlugFor);
|
|
52
|
+
if (fieldDefinition?.objectId && pages[fieldDefinition.objectId]) {
|
|
53
|
+
setNavigationSlug(pages[fieldDefinition.objectId]);
|
|
54
|
+
setFetchedOptions({
|
|
55
|
+
[`${entryId}NavigationSlug`]: pages[fieldDefinition.objectId],
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
})();
|
|
60
|
+
}, [object, defaultPages, findDefaultPageSlugFor, fieldDefinition]);
|
|
61
|
+
// If the entry is hidden, clear its value and any nested values, and skip rendering
|
|
62
|
+
if (!entryIsVisible(entry, instance)) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
if (entry.type === 'content') {
|
|
66
|
+
return (React.createElement(Box, { dangerouslySetInnerHTML: { __html: DOMPurify.sanitize(entry.html) }, sx: {
|
|
67
|
+
fontFamily: 'Roboto, Helvetica, Arial, sans-serif',
|
|
68
|
+
} }));
|
|
69
|
+
}
|
|
70
|
+
else if (entry.type === 'readonlyField') {
|
|
71
|
+
if (isAddressProperty(entryId)) {
|
|
72
|
+
return (React.createElement(AddressFields, { entry: entry, viewOnly: true, entryId: entryId, fieldDefinition: fieldDefinition }));
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
let fieldValue = instance?.[entryId] || '';
|
|
76
|
+
switch (fieldDefinition?.type) {
|
|
77
|
+
case 'object':
|
|
78
|
+
if (navigationSlug && fieldDefinition?.objectId) {
|
|
79
|
+
return (React.createElement(FieldWrapper, { inputId: entryId, inputType: "object", label: display?.label || fieldDefinition?.name || 'default', value: fieldValue, required: display?.required || false, viewOnly: true },
|
|
80
|
+
React.createElement(Link, { sx: { cursor: 'pointer', fontFamily: 'sans-serif' }, href: `${'/app'}${navigationSlug.replace(':instanceId', fieldValue.id)}` }, fieldValue.name)));
|
|
81
|
+
}
|
|
82
|
+
fieldValue = fieldValue.name;
|
|
83
|
+
break;
|
|
84
|
+
case 'array':
|
|
85
|
+
if (!isEmpty(fieldValue)) {
|
|
86
|
+
fieldValue = fieldValue && fieldValue.join(', ');
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
fieldValue = '';
|
|
90
|
+
}
|
|
91
|
+
break;
|
|
92
|
+
case 'user':
|
|
93
|
+
fieldValue = fieldValue && fieldValue.name;
|
|
94
|
+
break;
|
|
95
|
+
case 'date':
|
|
96
|
+
fieldValue = fieldValue && DateTime.fromISO(fieldValue).toFormat('MM/dd/yyyy');
|
|
97
|
+
break;
|
|
98
|
+
case 'date-time':
|
|
99
|
+
fieldValue =
|
|
100
|
+
fieldValue && fieldValue instanceof Date
|
|
101
|
+
? DateTime.fromJSDate(fieldValue).toFormat('MM/dd/yyyy hh:mm a')
|
|
102
|
+
: fieldValue && DateTime.fromISO(fieldValue).toFormat('MM/dd/yyyy hh:mm a');
|
|
103
|
+
break;
|
|
104
|
+
case 'time':
|
|
105
|
+
fieldValue =
|
|
106
|
+
fieldValue &&
|
|
107
|
+
DateTime.fromISO(DateTime.now().toISODate() + 'T' + fieldValue).toFormat('hh:mm a');
|
|
108
|
+
break;
|
|
109
|
+
default:
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
if (fieldDefinition) {
|
|
113
|
+
if (fieldDefinition.type === 'image') {
|
|
114
|
+
return (React.createElement(FieldWrapper, { inputId: entryId, inputType: 'image', label: display?.label || fieldDefinition?.name || 'default', value: fieldValue, required: display?.required || false, viewOnly: true },
|
|
115
|
+
React.createElement(Image, { id: entryId, canUpdateProperty: false, value: fieldValue, hasDescription: !!display?.description })));
|
|
116
|
+
}
|
|
117
|
+
else if (fieldDefinition.type === 'richText') {
|
|
118
|
+
return (React.createElement(FieldWrapper, { inputId: entryId, inputType: 'richText', label: display?.label || fieldDefinition?.name || 'default', value: fieldValue, required: display?.required || false, viewOnly: true }, RichTextEditor ? (React.createElement(RichTextEditor
|
|
119
|
+
// RichTexts get a uniqueId when the form is loaded to prevent issues with multiple rich text fields on one form
|
|
120
|
+
, {
|
|
121
|
+
// RichTexts get a uniqueId when the form is loaded to prevent issues with multiple rich text fields on one form
|
|
122
|
+
id: entry.uniqueId, value: fieldValue, format: "rtf", disabled: true, rows: display?.rowCount, hasError: false })) : (React.createElement(Typography, { variant: "body1", key: entryId, sx: { height: '24px' } }, fieldValue))));
|
|
123
|
+
}
|
|
124
|
+
else if (fieldDefinition.type === 'document') {
|
|
125
|
+
return (React.createElement(FieldWrapper, { inputId: entryId, inputType: 'document', label: display?.label || fieldDefinition?.name || 'default', value: fieldValue, required: display?.required || false, prefix: display?.prefix, suffix: display?.suffix, viewOnly: true },
|
|
126
|
+
React.createElement(Document, { id: entryId, error: false, value: fieldValue, canUpdateProperty: false })));
|
|
127
|
+
}
|
|
128
|
+
else if (fieldDefinition.type === 'collection') {
|
|
129
|
+
return fieldDefinition?.manyToManyPropertyId ? (middleObject && initialMiddleObjectInstances && (React.createElement(FieldWrapper, { inputId: entryId, inputType: 'collection', label: display?.label || fieldDefinition?.name || 'default', value: fieldValue, required: display?.required || false, viewOnly: true },
|
|
130
|
+
React.createElement(DropdownRepeatableField, { initialMiddleObjectInstances: fetchedOptions[`${entryId}MiddleObjectInstances`] ||
|
|
131
|
+
initialMiddleObjectInstances, id: entryId, middleObject: middleObject, fieldDefinition: fieldDefinition, readOnly: true })))) : (React.createElement(FieldWrapper, { inputId: entryId, inputType: 'collection', label: display?.label || fieldDefinition?.name || 'default', value: fieldValue, required: display?.required || false, viewOnly: true },
|
|
132
|
+
React.createElement(RepeatableField, { fieldDefinition: fieldDefinition, canUpdateProperty: false, entry: entry, viewLayout: display?.viewLayout })));
|
|
133
|
+
}
|
|
134
|
+
else if (fieldDefinition.type === 'criteria') {
|
|
135
|
+
return (React.createElement(FieldWrapper, { inputId: entryId, inputType: 'criteria', label: display?.label || fieldDefinition?.name || 'default', value: fieldValue, required: display?.required || false, viewOnly: true },
|
|
136
|
+
React.createElement(Criteria, { value: fieldValue, fieldDefinition: fieldDefinition, canUpdateProperty: false })));
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
return (React.createElement(FieldWrapper, { inputId: entryId, inputType: fieldDefinition?.type || 'string', label: display?.label || fieldDefinition?.name || 'default', value: fieldValue, required: display?.required || false, prefix: display?.prefix, suffix: display?.suffix, viewOnly: true }, fieldDefinition?.type === 'boolean' && fieldValue ? (React.createElement(CheckCircleRounded, { "aria-label": "Checked", color: "success" })) : fieldDefinition?.type === 'boolean' ? (React.createElement(CancelRounded, { "aria-label": "Unchecked", color: "error" })) : (React.createElement(Typography, { variant: "body1", key: entryId, sx: { height: '24px' } }, fieldValue))));
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
else if (entry.type === 'columns') {
|
|
145
|
+
return (React.createElement(Grid, { container: true, spacing: 4 }, entry.columns.map((column, colIndex) => (React.createElement(Grid, { item: true, key: colIndex, xs: 12, sm: column.width }, column.entries?.map((columnEntry, entryIndex) => {
|
|
146
|
+
return (React.createElement(ViewOnlyEntryRenderer, { key: entryIndex + (columnEntry?.parameterId ?? ''), entry: columnEntry }));
|
|
147
|
+
}))))));
|
|
148
|
+
}
|
|
149
|
+
else if (entry.type === 'sections') {
|
|
150
|
+
const filteredEntry = filterEmptySections(entry, instance);
|
|
151
|
+
return filteredEntry ? React.createElement(AccordionSections, { entry: filteredEntry, readOnly: true }) : null;
|
|
152
|
+
}
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
export default ViewOnlyEntryRenderer;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React, { ComponentType } from 'react';
|
|
2
|
+
import { FormRendererProps } from '../FormV2/FormRenderer';
|
|
3
|
+
import { BaseProps, SimpleEditorProps } from '../FormV2/components/types';
|
|
4
|
+
export type ViewDetailsV2ContainerProps = BaseProps & {
|
|
5
|
+
panelLayoutId?: string;
|
|
6
|
+
instanceId?: string;
|
|
7
|
+
objectId: string;
|
|
8
|
+
richTextEditor?: ComponentType<SimpleEditorProps>;
|
|
9
|
+
renderHeader?: FormRendererProps['renderHeader'];
|
|
10
|
+
renderBody?: FormRendererProps['renderBody'];
|
|
11
|
+
};
|
|
12
|
+
declare function ViewDetailsV2Container(props: ViewDetailsV2ContainerProps): React.JSX.Element;
|
|
13
|
+
export default ViewDetailsV2Container;
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { useApiServices, useObject, } from '@evoke-platform/context';
|
|
2
|
+
import axios from 'axios';
|
|
3
|
+
import React, { useEffect, useMemo, useState } from 'react';
|
|
4
|
+
import { useWidgetSize } from '../../../theme';
|
|
5
|
+
import { Skeleton, Snackbar } from '../../core';
|
|
6
|
+
import { Box } from '../../layout';
|
|
7
|
+
import ErrorComponent from '../ErrorComponent';
|
|
8
|
+
import { FormContext } from '../FormV2';
|
|
9
|
+
import Header from '../FormV2/components/Header';
|
|
10
|
+
import { assignIdsToSectionsAndRichText, getPrefixedUrl } from '../FormV2/components/utils';
|
|
11
|
+
import ViewOnlyEntryRenderer from './InstanceEntryRenderer';
|
|
12
|
+
function ViewDetailsV2Container(props) {
|
|
13
|
+
const { instanceId, panelLayoutId, objectId, richTextEditor, renderHeader, renderBody } = props;
|
|
14
|
+
const apiServices = useApiServices();
|
|
15
|
+
const [sanitizedObject, setSanitizedObject] = useState();
|
|
16
|
+
const [instance, setInstance] = useState();
|
|
17
|
+
const [error, setError] = useState();
|
|
18
|
+
const [panelLayout, setPanelLayout] = useState();
|
|
19
|
+
const [expandedSections, setExpandedSections] = useState([]);
|
|
20
|
+
const [fetchedOptions, setFetchedOptions] = useState({});
|
|
21
|
+
const [expandAll, setExpandAll] = useState();
|
|
22
|
+
const [snackbarError, setSnackbarError] = useState({
|
|
23
|
+
showAlert: false,
|
|
24
|
+
isError: true,
|
|
25
|
+
});
|
|
26
|
+
function handleExpandAll() {
|
|
27
|
+
setExpandAll(true);
|
|
28
|
+
}
|
|
29
|
+
function handleCollapseAll() {
|
|
30
|
+
setExpandAll(false);
|
|
31
|
+
}
|
|
32
|
+
const updateFetchedOptions = (newData) => {
|
|
33
|
+
setFetchedOptions((prev) => ({
|
|
34
|
+
...prev,
|
|
35
|
+
...newData,
|
|
36
|
+
}));
|
|
37
|
+
};
|
|
38
|
+
const { ref: containerRef, breakpoints, width, } = useWidgetSize({
|
|
39
|
+
scroll: false,
|
|
40
|
+
defaultWidth: 1200,
|
|
41
|
+
});
|
|
42
|
+
const { isXs, isSm } = breakpoints;
|
|
43
|
+
const objectStore = useObject(panelLayout?.objectId ?? objectId);
|
|
44
|
+
const onError = (err) => {
|
|
45
|
+
const code = axios.isAxiosError(err) ? err.response?.status : undefined;
|
|
46
|
+
setSnackbarError({ ...snackbarError, isError: true });
|
|
47
|
+
setError(code ?? true);
|
|
48
|
+
};
|
|
49
|
+
useEffect(() => {
|
|
50
|
+
(async () => {
|
|
51
|
+
try {
|
|
52
|
+
if (instanceId) {
|
|
53
|
+
const instance = await objectStore.getInstance(instanceId);
|
|
54
|
+
setInstance(instance);
|
|
55
|
+
}
|
|
56
|
+
const object = await apiServices.get(getPrefixedUrl(`/objects/${objectId}${instanceId ? `/instances/${instanceId}/object` : '/effective'}`), { params: { sanitizedVersion: true } });
|
|
57
|
+
setSanitizedObject(object);
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
const isAxiosErr = axios.isAxiosError(error);
|
|
61
|
+
console.error(isAxiosErr ? error.message : 'Error while fetching object');
|
|
62
|
+
setError(isAxiosErr ? error.status : true);
|
|
63
|
+
}
|
|
64
|
+
})();
|
|
65
|
+
}, [objectId, instanceId]);
|
|
66
|
+
useEffect(() => {
|
|
67
|
+
if (panelLayoutId || sanitizedObject?.defaultPanelLayoutId) {
|
|
68
|
+
apiServices
|
|
69
|
+
.get(getPrefixedUrl(`/objects/${objectId}/panelLayouts/${panelLayoutId || sanitizedObject?.defaultPanelLayoutId}`))
|
|
70
|
+
.then((evokeForm) => {
|
|
71
|
+
setPanelLayout(evokeForm);
|
|
72
|
+
})
|
|
73
|
+
.catch((error) => {
|
|
74
|
+
onError(error);
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}, [panelLayoutId, sanitizedObject, objectId]);
|
|
78
|
+
const updatedEntries = useMemo(() => {
|
|
79
|
+
return assignIdsToSectionsAndRichText(panelLayout?.entries || []);
|
|
80
|
+
}, [panelLayout?.id]);
|
|
81
|
+
const isLoading = (instanceId && !instance) || !panelLayout || !sanitizedObject;
|
|
82
|
+
const hasSections = updatedEntries.some((entry) => entry.type === 'sections');
|
|
83
|
+
const headerProps = {
|
|
84
|
+
title: panelLayout?.name,
|
|
85
|
+
onExpandAll: handleExpandAll,
|
|
86
|
+
onCollapseAll: handleCollapseAll,
|
|
87
|
+
expandedSections,
|
|
88
|
+
hasAccordions: hasSections,
|
|
89
|
+
autosaveEnabled: false,
|
|
90
|
+
};
|
|
91
|
+
return !error ? (React.createElement(Box, { sx: {
|
|
92
|
+
backgroundColor: '#ffffff',
|
|
93
|
+
borderRadius: '6px',
|
|
94
|
+
padding: '0px',
|
|
95
|
+
border: !isLoading ? '1px solid #dbe0e4' : undefined,
|
|
96
|
+
} },
|
|
97
|
+
!isLoading ? (React.createElement(Box, { ref: containerRef },
|
|
98
|
+
(hasSections || panelLayout.name || renderHeader) &&
|
|
99
|
+
(renderHeader ? renderHeader({ ...headerProps }) : React.createElement(Header, { ...headerProps })),
|
|
100
|
+
React.createElement(Box, { sx: {
|
|
101
|
+
paddingX: isSm || isXs ? 2 : 3,
|
|
102
|
+
borderTop: '1px solid #e9ecef',
|
|
103
|
+
} },
|
|
104
|
+
React.createElement(FormContext.Provider, { value: {
|
|
105
|
+
fetchedOptions,
|
|
106
|
+
setFetchedOptions: updateFetchedOptions,
|
|
107
|
+
object: sanitizedObject,
|
|
108
|
+
instance,
|
|
109
|
+
richTextEditor,
|
|
110
|
+
expandedSections,
|
|
111
|
+
setExpandedSections,
|
|
112
|
+
expandAll,
|
|
113
|
+
setExpandAll,
|
|
114
|
+
width,
|
|
115
|
+
} }, renderBody
|
|
116
|
+
? renderBody({
|
|
117
|
+
isInitializing: isLoading,
|
|
118
|
+
entries: updatedEntries,
|
|
119
|
+
onExpandAll: handleExpandAll,
|
|
120
|
+
onCollapseAll: handleCollapseAll,
|
|
121
|
+
expandedSections,
|
|
122
|
+
hasAccordions: hasSections,
|
|
123
|
+
})
|
|
124
|
+
: updatedEntries.map((entry, index) => (React.createElement(ViewOnlyEntryRenderer, { entry: entry, key: index }))))))) : (React.createElement(Box, { sx: { padding: '20px' } },
|
|
125
|
+
React.createElement(Box, { display: 'flex', width: '100%', justifyContent: 'space-between' },
|
|
126
|
+
React.createElement(Skeleton, { width: '78%', sx: { borderRadius: '8px', height: '40px' } }),
|
|
127
|
+
React.createElement(Skeleton, { width: '20%', sx: { borderRadius: '8px', height: '40px' } })),
|
|
128
|
+
React.createElement(Box, { display: 'flex', width: '100%', justifyContent: 'space-between' },
|
|
129
|
+
React.createElement(Skeleton, { width: '32%', sx: { borderRadius: '8px', height: '40px' } }),
|
|
130
|
+
React.createElement(Skeleton, { width: '33%', sx: { borderRadius: '8px', height: '40px' } }),
|
|
131
|
+
React.createElement(Skeleton, { width: '32%', sx: { borderRadius: '8px', height: '40px' } })),
|
|
132
|
+
React.createElement(Box, { display: 'flex', width: '100%', justifyContent: 'space-between' },
|
|
133
|
+
React.createElement(Skeleton, { width: '49%', sx: { borderRadius: '8px', height: '40px' } }),
|
|
134
|
+
React.createElement(Skeleton, { width: '49%', sx: { borderRadius: '8px', height: '40px' } })))),
|
|
135
|
+
React.createElement(Snackbar, { open: snackbarError.showAlert, handleClose: () => setSnackbarError({
|
|
136
|
+
isError: snackbarError.isError,
|
|
137
|
+
showAlert: false,
|
|
138
|
+
}), message: snackbarError.message, error: snackbarError.isError }))) : (React.createElement(ErrorComponent, { colspan: props.colspan, code: error === 403 ? 'AccessDenied' : error === 404 ? 'NotFound' : 'Misconfigured' }));
|
|
139
|
+
}
|
|
140
|
+
export default ViewDetailsV2Container;
|
|
@@ -14,3 +14,4 @@ export { RepeatableField } from './RepeatableField';
|
|
|
14
14
|
export { ResponsiveOverflow } from './ResponsiveOverflow';
|
|
15
15
|
export { RichTextViewer } from './RichTextViewer';
|
|
16
16
|
export { UserAvatar } from './UserAvatar';
|
|
17
|
+
export { ViewDetailsV2Container, ViewOnlyEntryRenderer } from './ViewDetailsV2';
|
|
@@ -12,3 +12,4 @@ export { RepeatableField } from './RepeatableField';
|
|
|
12
12
|
export { ResponsiveOverflow } from './ResponsiveOverflow';
|
|
13
13
|
export { RichTextViewer } from './RichTextViewer';
|
|
14
14
|
export { UserAvatar } from './UserAvatar';
|
|
15
|
+
export { ViewDetailsV2Container, ViewOnlyEntryRenderer } from './ViewDetailsV2';
|
|
@@ -2,7 +2,7 @@ export { ClickAwayListener, createTheme, darken, lighten, styled, Toolbar, useMe
|
|
|
2
2
|
export { CalendarPicker, DateTimePicker, MonthPicker, PickersDay, StaticDateTimePicker, StaticTimePicker, TimePicker, YearPicker, } from '@mui/x-date-pickers';
|
|
3
3
|
export * from './colors';
|
|
4
4
|
export * from './components/core';
|
|
5
|
-
export { BuilderGrid, CriteriaBuilder, DataGrid, ErrorComponent, Form, FormContext, FormField, FormRenderer, FormRendererContainer, getReadableQuery, HistoryLog, MenuBar, MultiSelect, RecursiveEntryRenderer, RepeatableField, ResponsiveOverflow, RichTextViewer, UserAvatar, } from './components/custom';
|
|
5
|
+
export { BuilderGrid, CriteriaBuilder, DataGrid, ErrorComponent, Form, FormContext, FormField, FormRenderer, FormRendererContainer, getReadableQuery, HistoryLog, MenuBar, MultiSelect, RecursiveEntryRenderer, RepeatableField, ResponsiveOverflow, RichTextViewer, UserAvatar, ViewDetailsV2Container, ViewOnlyEntryRenderer, } from './components/custom';
|
|
6
6
|
export type { BodyProps, FooterProps, FormRef, GridSortModel, HeaderProps } from './components/custom';
|
|
7
7
|
export { NumericFormat } from './components/custom/FormField/InputFieldComponent';
|
|
8
8
|
export { Box, Container, Grid, Stack } from './components/layout';
|