@evoke-platform/ui-components 1.10.0-testing.2 → 1.10.0-testing.21

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 (64) hide show
  1. package/dist/published/components/custom/CriteriaBuilder/CriteriaBuilder.js +1 -1
  2. package/dist/published/components/custom/CriteriaBuilder/CriteriaBuilder.test.d.ts +1 -0
  3. package/dist/published/components/custom/CriteriaBuilder/CriteriaBuilder.test.js +430 -0
  4. package/dist/published/components/custom/CriteriaBuilder/ValueEditor.js +19 -6
  5. package/dist/published/components/custom/Form/FormComponents/RepeatableFieldComponent/RepeatableField.js +1 -1
  6. package/dist/published/components/custom/Form/utils.js +1 -0
  7. package/dist/published/components/custom/FormField/DatePickerSelect/DatePickerSelect.js +14 -1
  8. package/dist/published/components/custom/FormField/DateTimePickerSelect/DateTimePickerSelect.js +14 -1
  9. package/dist/published/components/custom/FormField/TimePickerSelect/TimePickerSelect.js +14 -1
  10. package/dist/published/components/custom/FormV2/FormRenderer.d.ts +2 -1
  11. package/dist/published/components/custom/FormV2/FormRenderer.js +17 -4
  12. package/dist/published/components/custom/FormV2/FormRendererContainer.js +112 -73
  13. package/dist/published/components/custom/FormV2/components/AccordionSections.js +7 -2
  14. package/dist/published/components/custom/FormV2/components/Body.d.ts +1 -1
  15. package/dist/published/components/custom/FormV2/components/FieldWrapper.js +1 -1
  16. package/dist/published/components/custom/FormV2/components/Footer.d.ts +1 -0
  17. package/dist/published/components/custom/FormV2/components/Footer.js +3 -3
  18. package/dist/published/components/custom/FormV2/components/FormContext.d.ts +3 -2
  19. package/dist/published/components/custom/FormV2/components/FormFieldTypes/AddressFields.d.ts +9 -0
  20. package/dist/published/components/custom/FormV2/components/FormFieldTypes/AddressFields.js +32 -15
  21. package/dist/published/components/custom/FormV2/components/FormFieldTypes/CollectionFiles/ActionDialog.js +1 -1
  22. package/dist/published/components/custom/FormV2/components/FormFieldTypes/CollectionFiles/RepeatableField.d.ts +0 -3
  23. package/dist/published/components/custom/FormV2/components/FormFieldTypes/CollectionFiles/RepeatableField.js +31 -48
  24. package/dist/published/components/custom/FormV2/components/FormFieldTypes/Criteria.js +16 -3
  25. package/dist/published/components/custom/FormV2/components/FormFieldTypes/DocumentFiles/Document.js +16 -4
  26. package/dist/published/components/custom/FormV2/components/FormFieldTypes/DocumentFiles/DocumentList.d.ts +2 -1
  27. package/dist/published/components/custom/FormV2/components/FormFieldTypes/DocumentFiles/DocumentList.js +16 -3
  28. package/dist/published/components/custom/FormV2/components/FormFieldTypes/Image.js +31 -5
  29. package/dist/published/components/custom/FormV2/components/FormFieldTypes/UserProperty.js +15 -3
  30. package/dist/published/components/custom/FormV2/components/FormFieldTypes/relatedObjectFiles/ObjectPropertyInput.js +109 -81
  31. package/dist/published/components/custom/FormV2/components/FormFieldTypes/relatedObjectFiles/RelatedObjectInstance.js +38 -16
  32. package/dist/published/components/custom/FormV2/components/Header.d.ts +13 -3
  33. package/dist/published/components/custom/FormV2/components/Header.js +47 -8
  34. package/dist/published/components/custom/FormV2/components/RecursiveEntryRenderer.js +44 -35
  35. package/dist/published/components/custom/FormV2/components/ValidationFiles/ValidationErrors.js +1 -1
  36. package/dist/published/components/custom/FormV2/components/types.d.ts +1 -0
  37. package/dist/published/components/custom/FormV2/components/utils.d.ts +2 -2
  38. package/dist/published/components/custom/FormV2/components/utils.js +11 -14
  39. package/dist/published/components/custom/FormV2/tests/FormRenderer.test.js +433 -4
  40. package/dist/published/components/custom/FormV2/tests/FormRendererContainer.test.js +642 -13
  41. package/dist/published/components/custom/FormV2/tests/test-data.d.ts +1 -0
  42. package/dist/published/components/custom/FormV2/tests/test-data.js +140 -0
  43. package/dist/published/components/custom/ViewDetailsV2/InstanceEntryRenderer.d.ts +3 -0
  44. package/dist/published/components/custom/ViewDetailsV2/InstanceEntryRenderer.js +155 -0
  45. package/dist/published/components/custom/ViewDetailsV2/ViewDetailsV2Container.d.ts +13 -0
  46. package/dist/published/components/custom/ViewDetailsV2/ViewDetailsV2Container.js +140 -0
  47. package/dist/published/components/custom/ViewDetailsV2/index.d.ts +3 -0
  48. package/dist/published/components/custom/ViewDetailsV2/index.js +2 -0
  49. package/dist/published/components/custom/index.d.ts +2 -0
  50. package/dist/published/components/custom/index.js +1 -0
  51. package/dist/published/index.d.ts +6 -6
  52. package/dist/published/index.js +1 -1
  53. package/dist/published/stories/FormRenderer.stories.d.ts +8 -4
  54. package/dist/published/stories/FormRendererContainer.stories.d.ts +26 -0
  55. package/dist/published/stories/FormRendererContainer.stories.js +5 -0
  56. package/dist/published/stories/FormRendererData.d.ts +12 -0
  57. package/dist/published/stories/FormRendererData.js +27 -44
  58. package/dist/published/stories/ViewDetailsV2Container.stories.d.ts +26 -0
  59. package/dist/published/stories/ViewDetailsV2Container.stories.js +37 -0
  60. package/dist/published/stories/ViewDetailsV2Data.d.ts +4 -0
  61. package/dist/published/stories/ViewDetailsV2Data.js +203 -0
  62. package/dist/published/stories/sharedMswHandlers.js +49 -10
  63. package/dist/published/theme/hooks.d.ts +4 -3
  64. package/package.json +4 -2
@@ -23,3 +23,4 @@ export declare const users: {
23
23
  email: string;
24
24
  name: string;
25
25
  }[];
26
+ export declare const licenseForm: EvokeForm;
@@ -116,6 +116,8 @@ export const UpdateAccessibilityFormOne = {
116
116
  display: {
117
117
  label: 'License',
118
118
  relatedObjectDisplay: 'dropdown',
119
+ createActionId: '_create',
120
+ createFormId: 'specialtyForm',
119
121
  },
120
122
  },
121
123
  ],
@@ -164,6 +166,11 @@ export const licenseObject = {
164
166
  type: 'object',
165
167
  objectId: 'licenseType',
166
168
  },
169
+ {
170
+ id: 'address',
171
+ name: 'Licensee Address',
172
+ type: 'address',
173
+ },
167
174
  ],
168
175
  actions: [
169
176
  {
@@ -171,6 +178,96 @@ export const licenseObject = {
171
178
  name: 'Update',
172
179
  type: 'update',
173
180
  outputEvent: 'License Updated',
181
+ parameters: [
182
+ {
183
+ id: 'name',
184
+ name: 'License Number',
185
+ type: 'string',
186
+ },
187
+ {
188
+ id: 'status',
189
+ name: 'Status',
190
+ type: 'string',
191
+ },
192
+ {
193
+ id: 'address.line1',
194
+ name: 'Address Line 1',
195
+ type: 'string',
196
+ },
197
+ {
198
+ id: 'address.line2',
199
+ name: 'Address Line 2',
200
+ type: 'string',
201
+ },
202
+ {
203
+ id: 'address.city',
204
+ name: 'City',
205
+ type: 'string',
206
+ },
207
+ {
208
+ id: 'address.county',
209
+ name: 'County',
210
+ type: 'string',
211
+ },
212
+ {
213
+ id: 'address.state',
214
+ name: 'State',
215
+ type: 'string',
216
+ },
217
+ {
218
+ id: 'address.zipCode',
219
+ name: 'Zip Code',
220
+ type: 'string',
221
+ },
222
+ ],
223
+ },
224
+ {
225
+ id: '_autosave',
226
+ name: 'Autosave',
227
+ type: 'update',
228
+ outputEvent: 'License Autosaved',
229
+ parameters: [
230
+ {
231
+ id: 'name',
232
+ name: 'License Number',
233
+ type: 'string',
234
+ },
235
+ {
236
+ id: 'status',
237
+ name: 'Status',
238
+ type: 'string',
239
+ },
240
+ {
241
+ id: 'address.line1',
242
+ name: 'Address Line 1',
243
+ type: 'string',
244
+ },
245
+ {
246
+ id: 'address.line2',
247
+ name: 'Address Line 2',
248
+ type: 'string',
249
+ },
250
+ {
251
+ id: 'address.city',
252
+ name: 'City',
253
+ type: 'string',
254
+ },
255
+ {
256
+ id: 'address.county',
257
+ name: 'County',
258
+ type: 'string',
259
+ },
260
+ {
261
+ id: 'address.state',
262
+ name: 'State',
263
+ type: 'string',
264
+ },
265
+ {
266
+ id: 'address.zipCode',
267
+ name: 'Zip Code',
268
+ type: 'string',
269
+ },
270
+ ],
174
271
  },
175
272
  {
176
273
  id: '_delete',
@@ -526,3 +623,46 @@ export const users = [
526
623
  name: 'User 2',
527
624
  },
528
625
  ];
626
+ export const licenseForm = {
627
+ id: 'licenseForm',
628
+ name: 'License Form',
629
+ objectId: 'license',
630
+ actionId: '_update',
631
+ entries: [
632
+ {
633
+ parameterId: 'name',
634
+ type: 'input',
635
+ display: {
636
+ label: 'License Number',
637
+ },
638
+ },
639
+ {
640
+ parameterId: 'address.line1',
641
+ type: 'input',
642
+ display: {
643
+ label: 'Address Line 1',
644
+ },
645
+ },
646
+ {
647
+ parameterId: 'address.city',
648
+ type: 'input',
649
+ display: {
650
+ label: 'City',
651
+ },
652
+ },
653
+ {
654
+ parameterId: 'address.state',
655
+ type: 'input',
656
+ display: {
657
+ label: 'State',
658
+ },
659
+ },
660
+ {
661
+ parameterId: 'address.zipCode',
662
+ type: 'input',
663
+ display: {
664
+ label: 'Zip Code',
665
+ },
666
+ },
667
+ ],
668
+ };
@@ -0,0 +1,3 @@
1
+ import { EntryRendererProps } from '../FormV2/components/types';
2
+ declare function ViewOnlyEntryRenderer(props: EntryRendererProps): any;
3
+ export default ViewOnlyEntryRenderer;
@@ -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 { BaseProps, SimpleEditorProps } from '../FormV2/components/types';
3
+ import { FormRendererProps } from '../FormV2/FormRenderer';
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;
@@ -0,0 +1,3 @@
1
+ export { default as ViewOnlyEntryRenderer } from './InstanceEntryRenderer';
2
+ export { default as ViewDetailsV2Container } from './ViewDetailsV2Container';
3
+ export type { ViewDetailsV2ContainerProps } from './ViewDetailsV2Container';
@@ -0,0 +1,2 @@
1
+ export { default as ViewOnlyEntryRenderer } from './InstanceEntryRenderer';
2
+ export { default as ViewDetailsV2Container } from './ViewDetailsV2Container';
@@ -14,3 +14,5 @@ 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';
18
+ export type { ViewDetailsV2ContainerProps } 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';
@@ -1,15 +1,15 @@
1
1
  export { ClickAwayListener, createTheme, darken, lighten, styled, Toolbar, useMediaQuery, useTheme, } from '@mui/material';
2
+ export type { AutocompleteRenderGroupParams, ButtonBaseActions, ButtonBaseClasses, FormControlProps, FormHelperTextProps, GridSize, MenuItemClasses, TextFieldProps, Theme, } from '@mui/material';
3
+ export type { TouchRippleActions, TouchRippleProps } from '@mui/material/ButtonBase/TouchRipple';
4
+ export type { CommonProps } from '@mui/material/OverridableComponent';
5
+ export type { SxProps } from '@mui/system';
2
6
  export { CalendarPicker, DateTimePicker, MonthPicker, PickersDay, StaticDateTimePicker, StaticTimePicker, TimePicker, YearPicker, } from '@mui/x-date-pickers';
3
7
  export * from './colors';
4
8
  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';
6
- export type { BodyProps, FooterProps, FormRef, GridSortModel, HeaderProps } from './components/custom';
9
+ export { BuilderGrid, CriteriaBuilder, DataGrid, ErrorComponent, Form, FormContext, FormField, FormRenderer, FormRendererContainer, getReadableQuery, HistoryLog, MenuBar, MultiSelect, RecursiveEntryRenderer, RepeatableField, ResponsiveOverflow, RichTextViewer, UserAvatar, ViewDetailsV2Container, ViewOnlyEntryRenderer, } from './components/custom';
10
+ export type { BodyProps, FooterProps, FormRef, GridSortModel, HeaderProps, ViewDetailsV2ContainerProps, } from './components/custom';
7
11
  export { NumericFormat } from './components/custom/FormField/InputFieldComponent';
8
12
  export { Box, Container, Grid, Stack } from './components/layout';
9
13
  export * from './theme';
10
14
  export * as EVOKE_TYPES from './types';
11
15
  export * from './util';
12
- export type { AutocompleteRenderGroupParams, ButtonBaseActions, ButtonBaseClasses, FormControlProps, FormHelperTextProps, GridSize, MenuItemClasses, TextFieldProps, Theme, } from '@mui/material';
13
- export type { TouchRippleActions, TouchRippleProps } from '@mui/material/ButtonBase/TouchRipple';
14
- export type { CommonProps } from '@mui/material/OverridableComponent';
15
- export type { SxProps } from '@mui/system';
@@ -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 { NumericFormat } from './components/custom/FormField/InputFieldComponent';
7
7
  export { Box, Container, Grid, Stack } from './components/layout';
8
8
  export * from './theme';
@@ -9,7 +9,8 @@ declare const _default: import("@storybook/types").ComponentAnnotations<import("
9
9
  form: import("@evoke-platform/context").EvokeForm;
10
10
  title?: React.ReactNode;
11
11
  instance?: import("../components/custom/FormV2/components/types").Document | import("@evoke-platform/context").ObjectInstance | undefined;
12
- onChange: (id: string, value: unknown) => void;
12
+ onChange: (id: string, value: unknown) => void | Promise<void>;
13
+ onAutosave?: ((fieldId: string) => void | Promise<void>) | undefined;
13
14
  associatedObject?: {
14
15
  instanceId?: string | undefined;
15
16
  propertyId?: string | undefined;
@@ -29,7 +30,8 @@ export declare const Editable: import("@storybook/types").AnnotatedStoryFn<impor
29
30
  form: import("@evoke-platform/context").EvokeForm;
30
31
  title?: React.ReactNode;
31
32
  instance?: import("../components/custom/FormV2/components/types").Document | import("@evoke-platform/context").ObjectInstance | undefined;
32
- onChange: (id: string, value: unknown) => void;
33
+ onChange: (id: string, value: unknown) => void | Promise<void>;
34
+ onAutosave?: ((fieldId: string) => void | Promise<void>) | undefined;
33
35
  associatedObject?: {
34
36
  instanceId?: string | undefined;
35
37
  propertyId?: string | undefined;
@@ -48,7 +50,8 @@ export declare const NoButtons: import("@storybook/types").AnnotatedStoryFn<impo
48
50
  form: import("@evoke-platform/context").EvokeForm;
49
51
  title?: React.ReactNode;
50
52
  instance?: import("../components/custom/FormV2/components/types").Document | import("@evoke-platform/context").ObjectInstance | undefined;
51
- onChange: (id: string, value: unknown) => void;
53
+ onChange: (id: string, value: unknown) => void | Promise<void>;
54
+ onAutosave?: ((fieldId: string) => void | Promise<void>) | undefined;
52
55
  associatedObject?: {
53
56
  instanceId?: string | undefined;
54
57
  propertyId?: string | undefined;
@@ -67,7 +70,8 @@ export declare const DocumentForm: import("@storybook/types").AnnotatedStoryFn<i
67
70
  form: import("@evoke-platform/context").EvokeForm;
68
71
  title?: React.ReactNode;
69
72
  instance?: import("../components/custom/FormV2/components/types").Document | import("@evoke-platform/context").ObjectInstance | undefined;
70
- onChange: (id: string, value: unknown) => void;
73
+ onChange: (id: string, value: unknown) => void | Promise<void>;
74
+ onAutosave?: ((fieldId: string) => void | Promise<void>) | undefined;
71
75
  associatedObject?: {
72
76
  instanceId?: string | undefined;
73
77
  propertyId?: string | undefined;
@@ -52,6 +52,32 @@ export declare const Editable: import("@storybook/types").AnnotatedStoryFn<impor
52
52
  renderFooter?: ((props: import("../components/custom").FooterProps) => React.ReactNode) | undefined;
53
53
  sx?: import("@mui/material").SxProps<{}> | undefined;
54
54
  }>;
55
+ export declare const DefaultForm: import("@storybook/types").AnnotatedStoryFn<import("@storybook/react/dist/types-0fc72a6d").R, import("../components/custom/FormV2/components/types").BaseProps & {
56
+ formId?: string | undefined;
57
+ instanceId?: string | undefined;
58
+ defaultPages?: Record<string, string> | undefined;
59
+ pageNavigation?: string | undefined;
60
+ documentId?: string | undefined;
61
+ dataType?: "documents" | "objectInstances" | undefined;
62
+ display?: {
63
+ fieldHeight?: "medium" | "small" | undefined;
64
+ } | undefined;
65
+ actionId?: string | undefined;
66
+ objectId: string;
67
+ richTextEditor?: React.ComponentType<import("../components/custom/FormV2/components/types").SimpleEditorProps> | undefined;
68
+ onSubmit?: ((submission: Record<string, unknown>, defaultSubmitHandler: (submission: Record<string, unknown>) => Promise<void>) => Promise<void>) | undefined;
69
+ onDiscardChanges?: (() => void) | undefined;
70
+ onSubmitError?: import("react-hook-form").SubmitErrorHandler<import("react-hook-form").FieldValues> | undefined;
71
+ associatedObject?: {
72
+ instanceId?: string | undefined;
73
+ propertyId?: string | undefined;
74
+ } | undefined;
75
+ renderContainer?: ((state: import("../components/custom/FormV2/FormRendererContainer").FormRendererState) => React.ReactNode) | undefined;
76
+ renderHeader?: ((props: import("../components/custom").HeaderProps) => React.ReactNode) | undefined;
77
+ renderBody?: ((props: import("../components/custom").BodyProps) => React.ReactNode) | undefined;
78
+ renderFooter?: ((props: import("../components/custom").FooterProps) => React.ReactNode) | undefined;
79
+ sx?: import("@mui/material").SxProps<{}> | undefined;
80
+ }>;
55
81
  export declare const NoButtons: import("@storybook/types").AnnotatedStoryFn<import("@storybook/react/dist/types-0fc72a6d").R, import("../components/custom/FormV2/components/types").BaseProps & {
56
82
  formId?: string | undefined;
57
83
  instanceId?: string | undefined;
@@ -46,6 +46,11 @@ export const Editable = Template.bind({});
46
46
  Editable.args = {
47
47
  ...mockProps,
48
48
  };
49
+ export const DefaultForm = Template.bind({});
50
+ DefaultForm.args = {
51
+ ...mockProps,
52
+ formId: undefined,
53
+ };
49
54
  export const NoButtons = Template.bind({});
50
55
  NoButtons.args = {
51
56
  ...mockProps,
@@ -121,3 +121,15 @@ export declare const users: {
121
121
  email: string;
122
122
  name: string;
123
123
  }[];
124
+ export declare const customerLayout: {
125
+ id: string;
126
+ name: string;
127
+ properties: {
128
+ id: string;
129
+ }[];
130
+ sort: {
131
+ colId: string;
132
+ sort: string;
133
+ };
134
+ objectId: string;
135
+ };