@evoke-platform/ui-components 1.0.0-dev.217 → 1.0.0-dev.218

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 (58) hide show
  1. package/dist/published/components/custom/Form/Common/Form.d.ts +38 -0
  2. package/dist/published/components/custom/Form/Common/Form.js +413 -0
  3. package/dist/published/components/custom/Form/Common/FormComponentWrapper.d.ts +26 -0
  4. package/dist/published/components/custom/Form/Common/FormComponentWrapper.js +79 -0
  5. package/dist/published/components/custom/Form/Common/index.d.ts +2 -0
  6. package/dist/published/components/custom/Form/Common/index.js +2 -0
  7. package/dist/published/components/custom/Form/FormComponents/ButtonComponent.d.ts +37 -0
  8. package/dist/published/components/custom/Form/FormComponents/ButtonComponent.js +150 -0
  9. package/dist/published/components/custom/Form/FormComponents/DocumentComponent/Document.d.ts +17 -0
  10. package/dist/published/components/custom/Form/FormComponents/DocumentComponent/Document.js +80 -0
  11. package/dist/published/components/custom/Form/FormComponents/DocumentComponent/DocumentComponent.d.ts +23 -0
  12. package/dist/published/components/custom/Form/FormComponents/DocumentComponent/DocumentComponent.js +154 -0
  13. package/dist/published/components/custom/Form/FormComponents/DocumentComponent/DocumentList.d.ts +15 -0
  14. package/dist/published/components/custom/Form/FormComponents/DocumentComponent/DocumentList.js +172 -0
  15. package/dist/published/components/custom/Form/FormComponents/FormFieldComponent.d.ts +41 -0
  16. package/dist/published/components/custom/Form/FormComponents/FormFieldComponent.js +409 -0
  17. package/dist/published/components/custom/Form/FormComponents/ImageComponent/Image.d.ts +15 -0
  18. package/dist/published/components/custom/Form/FormComponents/ImageComponent/Image.js +111 -0
  19. package/dist/published/components/custom/Form/FormComponents/ImageComponent/ImageComponent.d.ts +23 -0
  20. package/dist/published/components/custom/Form/FormComponents/ImageComponent/ImageComponent.js +112 -0
  21. package/dist/published/components/custom/Form/FormComponents/ObjectComponent/InstanceLookup.d.ts +20 -0
  22. package/dist/published/components/custom/Form/FormComponents/ObjectComponent/InstanceLookup.js +229 -0
  23. package/dist/published/components/custom/Form/FormComponents/ObjectComponent/ObjectComponent.d.ts +34 -0
  24. package/dist/published/components/custom/Form/FormComponents/ObjectComponent/ObjectComponent.js +150 -0
  25. package/dist/published/components/custom/Form/FormComponents/ObjectComponent/ObjectPropertyInput.d.ts +3 -0
  26. package/dist/published/components/custom/Form/FormComponents/ObjectComponent/ObjectPropertyInput.js +306 -0
  27. package/dist/published/components/custom/Form/FormComponents/ObjectComponent/RelatedObjectInstance.d.ts +24 -0
  28. package/dist/published/components/custom/Form/FormComponents/ObjectComponent/RelatedObjectInstance.js +126 -0
  29. package/dist/published/components/custom/Form/FormComponents/RepeatableFieldComponent/ActionDialog.d.ts +21 -0
  30. package/dist/published/components/custom/Form/FormComponents/RepeatableFieldComponent/ActionDialog.js +96 -0
  31. package/dist/published/components/custom/Form/FormComponents/RepeatableFieldComponent/ManyToMany/DropdownRepeatableField.d.ts +15 -0
  32. package/dist/published/components/custom/Form/FormComponents/RepeatableFieldComponent/ManyToMany/DropdownRepeatableField.js +158 -0
  33. package/dist/published/components/custom/Form/FormComponents/RepeatableFieldComponent/ManyToMany/DropdownRepeatableFieldInput.d.ts +39 -0
  34. package/dist/published/components/custom/Form/FormComponents/RepeatableFieldComponent/ManyToMany/DropdownRepeatableFieldInput.js +89 -0
  35. package/dist/published/components/custom/Form/FormComponents/RepeatableFieldComponent/RepeatableField.d.ts +12 -0
  36. package/dist/published/components/custom/Form/FormComponents/RepeatableFieldComponent/RepeatableField.js +369 -0
  37. package/dist/published/components/custom/Form/FormComponents/RepeatableFieldComponent/RepeatableFieldComponent.d.ts +20 -0
  38. package/dist/published/components/custom/Form/FormComponents/RepeatableFieldComponent/RepeatableFieldComponent.js +57 -0
  39. package/dist/published/components/custom/Form/FormComponents/UserComponent/UserComponent.d.ts +26 -0
  40. package/dist/published/components/custom/Form/FormComponents/UserComponent/UserComponent.js +99 -0
  41. package/dist/published/components/custom/Form/FormComponents/UserComponent/UserProperty.d.ts +23 -0
  42. package/dist/published/components/custom/Form/FormComponents/UserComponent/UserProperty.js +115 -0
  43. package/dist/published/components/custom/Form/FormComponents/ViewOnlyComponent.d.ts +20 -0
  44. package/dist/published/components/custom/Form/FormComponents/ViewOnlyComponent.js +83 -0
  45. package/dist/published/components/custom/Form/FormComponents/index.d.ts +8 -0
  46. package/dist/published/components/custom/Form/FormComponents/index.js +8 -0
  47. package/dist/published/components/custom/Form/index.d.ts +3 -0
  48. package/dist/published/components/custom/Form/index.js +3 -0
  49. package/dist/published/components/custom/Form/types.d.ts +109 -0
  50. package/dist/published/components/custom/Form/types.js +1 -0
  51. package/dist/published/components/custom/Form/utils.d.ts +45 -0
  52. package/dist/published/components/custom/Form/utils.js +1036 -0
  53. package/dist/published/components/custom/index.d.ts +1 -0
  54. package/dist/published/components/custom/index.js +1 -0
  55. package/dist/published/index.d.ts +1 -1
  56. package/dist/published/index.js +1 -1
  57. package/dist/published/styles/form-component.css +152 -0
  58. package/package.json +18 -5
@@ -0,0 +1,369 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { useNotification, } from '@evoke-platform/context';
11
+ import { LocalDateTime } from '@js-joda/core';
12
+ import { get, isObject, pick, startCase } from 'lodash';
13
+ import { DateTime } from 'luxon';
14
+ import React, { useCallback, useEffect, useState } from 'react';
15
+ import sift from 'sift';
16
+ import { TrashCan } from '../../../../../icons';
17
+ import { Button, IconButton, Skeleton, Snackbar, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Typography, } from '../../../../core';
18
+ import { Box } from '../../../../layout';
19
+ import { getPrefixedUrl, normalizeDateTime } from '../../utils';
20
+ import { ActionDialog } from './ActionDialog';
21
+ const styles = {
22
+ addButton: {
23
+ backgroundColor: 'rgba(0, 117, 167, 0.08)',
24
+ boxShadow: 'none',
25
+ color: 'rgba(0, 117, 167)',
26
+ marginTop: '15px',
27
+ '&:hover': {
28
+ backgroundColor: 'rgba(0, 117, 167, 0.08)',
29
+ color: 'rgba(0, 117, 167)',
30
+ boxShadow: 'none',
31
+ },
32
+ },
33
+ tableCell: {
34
+ color: '#637381',
35
+ backgroundColor: '#F4F6F8',
36
+ fontSize: '14px',
37
+ fontWeight: '700',
38
+ padding: '8px 20px',
39
+ whiteSpace: 'nowrap',
40
+ },
41
+ };
42
+ const RepeatableField = (props) => {
43
+ var _a, _b, _c, _d, _e;
44
+ const { property, instance, canUpdateProperty, apiServices, queryAddresses, user } = props;
45
+ const [relatedInstances, setRelatedInstances] = useState([]);
46
+ const [relatedObject, setRelatedObject] = useState();
47
+ const [hasCreateAction, setHasCreateAction] = useState(false);
48
+ const [users, setUsers] = useState();
49
+ const [openDialog, setOpenDialog] = useState(false);
50
+ const [dialogType, setDialogType] = useState();
51
+ const [selectedRow, setSelectedRow] = useState();
52
+ const [loading, setLoading] = useState(true);
53
+ const [reloadOnErrorTrigger, setReloadOnErrorTrigger] = useState(true);
54
+ const [snackbarError, setSnackbarError] = useState({
55
+ showAlert: false,
56
+ isError: false,
57
+ });
58
+ const [error, setError] = useState(false);
59
+ const DEFAULT_CREATE_ACTION = '_create';
60
+ const { instanceChanges } = useNotification();
61
+ const fetchRelatedInstances = useCallback(() => __awaiter(void 0, void 0, void 0, function* () {
62
+ if (openDialog)
63
+ return;
64
+ let relatedObject;
65
+ if (property.objectId) {
66
+ try {
67
+ relatedObject = yield apiServices.get(getPrefixedUrl(`/objects/${property.objectId}/effective`));
68
+ setRelatedObject(relatedObject);
69
+ }
70
+ catch (err) {
71
+ console.error(error);
72
+ }
73
+ if (property.relatedPropertyId && (instance === null || instance === void 0 ? void 0 : instance.id)) {
74
+ const filterProperty = `${property.relatedPropertyId}.id`;
75
+ const filter = { where: { [filterProperty]: instance === null || instance === void 0 ? void 0 : instance.id }, limit: 100 };
76
+ const objectId = property.objectId;
77
+ try {
78
+ const timeout = setTimeout(() => {
79
+ setLoading(false);
80
+ }, 300);
81
+ setLoading(true);
82
+ const instances = yield apiServices.get(getPrefixedUrl(`/objects/${objectId}/instances`), {
83
+ params: { filter: JSON.stringify(filter) },
84
+ });
85
+ clearTimeout(timeout);
86
+ setLoading(false);
87
+ if (instances) {
88
+ setRelatedInstances(instances);
89
+ }
90
+ }
91
+ catch (error) {
92
+ setError(true);
93
+ }
94
+ }
95
+ }
96
+ relatedObject && checkCreateAccess(relatedObject);
97
+ }), [apiServices, property]);
98
+ const checkCreateAccess = (relatedObject) => {
99
+ if (property.objectId && canUpdateProperty) {
100
+ apiServices
101
+ .get(getPrefixedUrl(`/objects/${property.objectId}/instances/checkAccess`), {
102
+ params: { action: 'execute', field: '_create', scope: 'data' },
103
+ })
104
+ .then((checkAccess) => {
105
+ var _a, _b, _c, _d, _e;
106
+ const action = (_a = relatedObject.actions) === null || _a === void 0 ? void 0 : _a.find((item) => item.id === '_create');
107
+ if (action) {
108
+ let relatedObjectProperty;
109
+ let validationCriteria;
110
+ if (action.parameters) {
111
+ relatedObjectProperty = action.parameters.find((param) => param.id === property.relatedPropertyId);
112
+ validationCriteria = (_b = relatedObjectProperty === null || relatedObjectProperty === void 0 ? void 0 : relatedObjectProperty.validation) === null || _b === void 0 ? void 0 : _b.criteria;
113
+ }
114
+ else if (action.inputProperties) {
115
+ relatedObjectProperty = action.inputProperties.find((inputProp) => inputProp.key === property.relatedPropertyId);
116
+ validationCriteria = (_c = relatedObjectProperty === null || relatedObjectProperty === void 0 ? void 0 : relatedObjectProperty.validate) === null || _c === void 0 ? void 0 : _c.criteria;
117
+ }
118
+ else {
119
+ relatedObjectProperty = ((_d = relatedObject.properties) !== null && _d !== void 0 ? _d : []).find((prop) => prop.id === property.relatedPropertyId);
120
+ validationCriteria = (_e = relatedObjectProperty === null || relatedObjectProperty === void 0 ? void 0 : relatedObjectProperty.validation) === null || _e === void 0 ? void 0 : _e.criteria;
121
+ }
122
+ if (relatedObjectProperty) {
123
+ if (validationCriteria) {
124
+ if (JSON.stringify(validationCriteria).includes('{{{input.')) {
125
+ setHasCreateAction(checkAccess.result);
126
+ }
127
+ else {
128
+ const criteria = sift(validationCriteria);
129
+ setHasCreateAction(criteria(instance) && checkAccess.result);
130
+ }
131
+ }
132
+ else {
133
+ setHasCreateAction(checkAccess.result);
134
+ }
135
+ }
136
+ }
137
+ else {
138
+ setHasCreateAction(false);
139
+ }
140
+ });
141
+ }
142
+ };
143
+ useEffect(() => {
144
+ (() => __awaiter(void 0, void 0, void 0, function* () {
145
+ try {
146
+ const users = yield apiServices.get(getPrefixedUrl(`/users`));
147
+ setUsers(users);
148
+ }
149
+ catch (error) {
150
+ console.error(error);
151
+ }
152
+ }))();
153
+ }, [apiServices]);
154
+ useEffect(() => {
155
+ fetchRelatedInstances();
156
+ }, [fetchRelatedInstances, reloadOnErrorTrigger, instance]);
157
+ useEffect(() => {
158
+ if (relatedObject === null || relatedObject === void 0 ? void 0 : relatedObject.rootObjectId) {
159
+ const callback = () => fetchRelatedInstances();
160
+ instanceChanges === null || instanceChanges === void 0 ? void 0 : instanceChanges.subscribe(relatedObject === null || relatedObject === void 0 ? void 0 : relatedObject.rootObjectId, callback);
161
+ return () => instanceChanges === null || instanceChanges === void 0 ? void 0 : instanceChanges.unsubscribe(relatedObject === null || relatedObject === void 0 ? void 0 : relatedObject.rootObjectId, callback);
162
+ }
163
+ }, [instanceChanges, relatedObject]);
164
+ const deleteRow = (id) => {
165
+ setDialogType('delete');
166
+ setSelectedRow(id);
167
+ setOpenDialog(true);
168
+ };
169
+ const addRow = () => {
170
+ setDialogType('create');
171
+ setOpenDialog(true);
172
+ };
173
+ const editRow = (id) => {
174
+ setDialogType('update');
175
+ setSelectedRow(id);
176
+ setOpenDialog(true);
177
+ };
178
+ const ErrorComponent = () => loading ? (React.createElement("div", null,
179
+ React.createElement(Typography, { sx: {
180
+ fontSize: '14px',
181
+ color: '#727c84',
182
+ } }, "Loading..."))) : (React.createElement(Typography, { sx: {
183
+ color: 'rgb(114 124 132)',
184
+ fontSize: '14px',
185
+ } },
186
+ "An error occurred when retrieving this data.",
187
+ ' ',
188
+ React.createElement(Button, { sx: {
189
+ padding: 0,
190
+ '&:hover': {
191
+ backgroundColor: 'transparent',
192
+ },
193
+ 'min-width': '44px',
194
+ }, variant: "text", onClick: () => setReloadOnErrorTrigger((prevState) => !prevState) }, "Retry")));
195
+ const save = (actionType, input, instanceId, setSubmitting) => __awaiter(void 0, void 0, void 0, function* () {
196
+ var _f, _g, _h, _j, _k, _l;
197
+ setSubmitting && setSubmitting(true);
198
+ // date-time fields are stored in the database in ISO format so convert all
199
+ // LocalDateTime objects to ISO format.
200
+ if (isObject(input)) {
201
+ input = Object.entries(input).reduce((agg, [key, value]) => Object.assign(agg, {
202
+ [key]: value instanceof LocalDateTime ? normalizeDateTime(value) : value,
203
+ }), {});
204
+ }
205
+ let isSuccessful = false;
206
+ let error;
207
+ if (actionType === 'create') {
208
+ const updatedInput = Object.assign(Object.assign({}, input), { [property === null || property === void 0 ? void 0 : property.relatedPropertyId]: { id: instance === null || instance === void 0 ? void 0 : instance.id } });
209
+ try {
210
+ const instance = yield apiServices.post(getPrefixedUrl(`/objects/${property.objectId}/instances/actions`), {
211
+ actionId: DEFAULT_CREATE_ACTION,
212
+ input: updatedInput,
213
+ });
214
+ const hasAccess = (property === null || property === void 0 ? void 0 : property.relatedPropertyId) && property.relatedPropertyId in instance;
215
+ hasAccess && setRelatedInstances([...relatedInstances, instance]);
216
+ setSubmitting && setSubmitting(false);
217
+ // clear out dialog
218
+ setOpenDialog(false);
219
+ setDialogType(undefined);
220
+ setSelectedRow(undefined);
221
+ isSuccessful = true;
222
+ }
223
+ catch (err) {
224
+ setSnackbarError({
225
+ showAlert: true,
226
+ message: `An error occurred while creating an instance`,
227
+ isError: true,
228
+ });
229
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
230
+ error = (_g = (_f = err.response) === null || _f === void 0 ? void 0 : _f.data) === null || _g === void 0 ? void 0 : _g.error;
231
+ setSubmitting && setSubmitting(false);
232
+ }
233
+ }
234
+ else {
235
+ const relatedObjectId = relatedObject === null || relatedObject === void 0 ? void 0 : relatedObject.id;
236
+ try {
237
+ yield apiServices.post(getPrefixedUrl(`/objects/${relatedObjectId}/instances/${instanceId}/actions`), {
238
+ actionId: `_${actionType}`,
239
+ input: pick(input, (_j = (_h = relatedObject === null || relatedObject === void 0 ? void 0 : relatedObject.properties) === null || _h === void 0 ? void 0 : _h.filter((property) => !property.formula && property.type !== 'collection').map((property) => property.id)) !== null && _j !== void 0 ? _j : []),
240
+ });
241
+ if (actionType === 'delete') {
242
+ setRelatedInstances((prevInstances) => prevInstances.filter((instance) => instance.id !== instanceId));
243
+ setSubmitting && setSubmitting(false);
244
+ }
245
+ else {
246
+ setRelatedInstances((prevInstances) => prevInstances.map((i) => (i.id === (instance === null || instance === void 0 ? void 0 : instance.id) ? instance : i)));
247
+ setSubmitting && setSubmitting(false);
248
+ }
249
+ // clear out dialog
250
+ setOpenDialog(false);
251
+ setDialogType(undefined);
252
+ setSelectedRow(undefined);
253
+ isSuccessful = true;
254
+ }
255
+ catch (err) {
256
+ setSnackbarError({
257
+ showAlert: true,
258
+ message: `An error occurred while ${actionType === 'delete' ? ' deleting' : ' updating'} an instance`,
259
+ isError: true,
260
+ });
261
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
262
+ error = (_l = (_k = err.response) === null || _k === void 0 ? void 0 : _k.data) === null || _l === void 0 ? void 0 : _l.error;
263
+ }
264
+ }
265
+ return { isSuccessful, error };
266
+ });
267
+ const retrieveViewLayout = () => {
268
+ var _a, _b, _c, _d, _e;
269
+ let properties = [];
270
+ if (((_b = (_a = relatedObject === null || relatedObject === void 0 ? void 0 : relatedObject.viewLayout) === null || _a === void 0 ? void 0 : _a.table) === null || _b === void 0 ? void 0 : _b.properties) && relatedObject.viewLayout.table.properties.length > 1) {
271
+ for (const prop of relatedObject.viewLayout.table.properties) {
272
+ const propertyId = prop.id.split('.')[0];
273
+ const property = (_c = relatedObject.properties) === null || _c === void 0 ? void 0 : _c.find((p) => p.id === propertyId);
274
+ if (property) {
275
+ if ((property.type === 'object' && property.id !== property.relatedPropertyId) ||
276
+ property.type === 'address' ||
277
+ property.type === 'user') {
278
+ properties.push(Object.assign(Object.assign({}, property), { id: ['user', 'object'].includes(property.type) && !prop.id.endsWith('.name')
279
+ ? `${prop.id}.name`
280
+ : prop.id, name: property.type === 'address'
281
+ ? `${property.name} - ${startCase(prop.id.split('.')[1])}`
282
+ : property.name }));
283
+ }
284
+ else {
285
+ properties.push(property);
286
+ }
287
+ }
288
+ }
289
+ }
290
+ else {
291
+ properties =
292
+ (_e = (_d = relatedObject === null || relatedObject === void 0 ? void 0 : relatedObject.properties) === null || _d === void 0 ? void 0 : _d.filter((prop) => !['address', 'image', 'collection'].includes(prop.type)).map((prop) => (Object.assign(Object.assign({}, prop), { id: prop.type === 'object' || prop.type === 'user' ? `${prop.id}.name` : prop.id })))) !== null && _e !== void 0 ? _e : [];
293
+ }
294
+ return properties.filter((prop) => prop.id !== 'name');
295
+ };
296
+ const getValue = (relatedInstance, propertyId, propertyType) => {
297
+ const value = get(relatedInstance, propertyId);
298
+ // If the property is not date-like or document then just return the
299
+ // value found at the given path.
300
+ if (!['date', 'date-time', 'time', 'document'].includes(propertyType)) {
301
+ return value;
302
+ }
303
+ // If the date-like value is empty then there is no need to format.
304
+ if (!value) {
305
+ return value;
306
+ }
307
+ // At this point it has been asserted that there is a value
308
+ // and since the property is date-like the value must be
309
+ // a string.
310
+ const stringValue = value;
311
+ if (propertyType === 'date') {
312
+ return DateTime.fromISO(stringValue).toLocaleString(DateTime.DATE_SHORT);
313
+ }
314
+ if (propertyType === 'date-time') {
315
+ return DateTime.fromISO(stringValue).toLocaleString(DateTime.DATETIME_SHORT);
316
+ }
317
+ if (propertyType === 'time') {
318
+ return DateTime.fromISO(stringValue).toLocaleString(DateTime.TIME_SIMPLE);
319
+ }
320
+ if (property.type === 'document') {
321
+ return Array.isArray(value) ? value.map((v) => v.name).join(', ') : value;
322
+ }
323
+ };
324
+ return loading ? (React.createElement(React.Fragment, null,
325
+ React.createElement(Skeleton, null),
326
+ React.createElement(Skeleton, null),
327
+ React.createElement(Skeleton, null))) : (React.createElement(React.Fragment, null,
328
+ React.createElement(Box, { sx: { padding: '10px 0' } },
329
+ !(relatedInstances === null || relatedInstances === void 0 ? void 0 : relatedInstances.length) ? (!error ? (React.createElement(Typography, { sx: { color: 'rgb(114 124 132)', fontSize: '14px' } }, "No items added")) : (React.createElement(ErrorComponent, null))) : (React.createElement(TableContainer, { sx: {
330
+ borderRadius: '6px',
331
+ border: '1px solid #919EAB3D',
332
+ boxShadow: 'none',
333
+ maxHeight: '70vh',
334
+ } },
335
+ React.createElement(Table, { stickyHeader: true, sx: { minWidth: 650 } },
336
+ React.createElement(TableHead, { sx: { backgroundColor: '#F4F6F8' } },
337
+ React.createElement(TableRow, null,
338
+ React.createElement(TableCell, { sx: styles.tableCell }, (_b = (_a = relatedObject === null || relatedObject === void 0 ? void 0 : relatedObject.properties) === null || _a === void 0 ? void 0 : _a.find((p) => p.id === 'name')) === null || _b === void 0 ? void 0 : _b.name), (_c = retrieveViewLayout()) === null || _c === void 0 ? void 0 :
339
+ _c.map((prop) => (React.createElement(TableCell, { sx: styles.tableCell }, prop.name))),
340
+ React.createElement(TableCell, { sx: Object.assign(Object.assign({}, styles.tableCell), { width: '20px' }) }))),
341
+ React.createElement(TableBody, null, relatedInstances === null || relatedInstances === void 0 ? void 0 : relatedInstances.map((relatedInstance, index) => {
342
+ var _a;
343
+ return (React.createElement(TableRow, { key: relatedInstance.id },
344
+ React.createElement(TableCell, { sx: {
345
+ color: '#212B36',
346
+ fontSize: '14px',
347
+ '&:hover': { textDecoration: 'underline', cursor: 'pointer' },
348
+ }, onClick: canUpdateProperty ? () => editRow(relatedInstance.id) : undefined },
349
+ React.createElement(Typography, null, relatedInstance === null || relatedInstance === void 0 ? void 0 : relatedInstance.name)), (_a = retrieveViewLayout()) === null || _a === void 0 ? void 0 :
350
+ _a.map((prop) => {
351
+ var _a;
352
+ return (React.createElement(TableCell, { sx: { color: '#212B36', fontSize: '14px' } },
353
+ React.createElement(Typography, { key: prop.id },
354
+ getValue(relatedInstance, prop.id, prop.type),
355
+ prop.type === 'user' &&
356
+ ((_a = users === null || users === void 0 ? void 0 : users.find((user) => get(relatedInstance, `${prop.id.split('.')[0]}.id`) === user.id)) === null || _a === void 0 ? void 0 : _a.status) === 'Inactive' && React.createElement("span", null, ' (Inactive)'))));
357
+ }),
358
+ canUpdateProperty && (React.createElement(TableCell, { sx: { width: '20px' } },
359
+ React.createElement(IconButton, { "aria-label": `delete-collection-instance-${index}`, onClick: () => deleteRow(relatedInstance.id) },
360
+ React.createElement(TrashCan, { sx: { ':hover': { color: '#A12723' } } }))))));
361
+ }))))),
362
+ hasCreateAction && (React.createElement(Button, { variant: "contained", sx: styles.addButton, onClick: addRow }, "Add"))),
363
+ relatedObject && openDialog && (React.createElement(ActionDialog, { object: relatedObject, open: openDialog, apiServices: apiServices, onClose: () => setOpenDialog(false), instanceInput: dialogType === 'update' ? (_d = relatedInstances.find((i) => i.id === selectedRow)) !== null && _d !== void 0 ? _d : {} : {}, handleSubmit: save,
364
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
365
+ objectInputCommonProps: { apiServices }, action: (_e = relatedObject === null || relatedObject === void 0 ? void 0 : relatedObject.actions) === null || _e === void 0 ? void 0 : _e.find((a) => a.id ===
366
+ (dialogType === 'create' ? '_create' : dialogType === 'update' ? '_update' : '_delete')), instanceId: selectedRow, relatedProperty: property, queryAddresses: queryAddresses, user: user })),
367
+ React.createElement(Snackbar, { open: snackbarError.showAlert, handleClose: () => setSnackbarError({ isError: snackbarError.isError, showAlert: false }), message: snackbarError.message, error: snackbarError.isError })));
368
+ };
369
+ export default RepeatableField;
@@ -0,0 +1,20 @@
1
+ import { ObjWithRoot, ObjectInstance } from '@evoke-platform/context';
2
+ import { ReactComponent } from '@formio/react';
3
+ import { BaseFormComponentProps } from '../../types';
4
+ declare type RepeatableFieldComponentProps = BaseFormComponentProps & {
5
+ middleObject: ObjWithRoot;
6
+ initialMiddleObjectInstances: ObjectInstance[];
7
+ getMiddleObjectInstances: () => Promise<ObjectInstance[]>;
8
+ };
9
+ export declare class RepeatableFieldComponent extends ReactComponent {
10
+ [x: string]: any;
11
+ static schema: any;
12
+ component: RepeatableFieldComponentProps;
13
+ criteria: Record<string, any> | undefined;
14
+ updatedCriteria: Record<string, any>;
15
+ constructor(component: RepeatableFieldComponentProps, options: any, data: any);
16
+ init(): void;
17
+ attachReact(element: Element): void;
18
+ detachReact(element: Element): void;
19
+ }
20
+ export {};
@@ -0,0 +1,57 @@
1
+ import { ApiBaseUrlProvider, NotificationProvider } from '@evoke-platform/context';
2
+ import { ReactComponent } from '@formio/react';
3
+ import dot from 'dot-object';
4
+ import { cloneDeep } from 'lodash';
5
+ import React from 'react';
6
+ import ReactDOM from 'react-dom';
7
+ import { FormComponentWrapper } from '../../Common';
8
+ import { getAllCriteriaInputs, updateCriteriaInputs } from '../../utils';
9
+ import { DropdownRepeatableField } from './ManyToMany/DropdownRepeatableField';
10
+ import RepeatableField from './RepeatableField';
11
+ const apiBaseUrl = process.env.REACT_APP_API_ROOT || `${window.location.origin}/api`;
12
+ export class RepeatableFieldComponent extends ReactComponent {
13
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
14
+ constructor(component, options, data) {
15
+ var _a;
16
+ super(Object.assign(Object.assign({}, component), { canUpdateProperty: !component.readOnly, hideLabel: true }), options, data);
17
+ this.errorDetails = {};
18
+ this.criteria = component.validate.criteria;
19
+ this.updatedCriteria = (_a = cloneDeep(component.validate.criteria)) !== null && _a !== void 0 ? _a : {};
20
+ }
21
+ init() {
22
+ if (this.criteria) {
23
+ const inputProps = getAllCriteriaInputs(this.criteria);
24
+ const data = dot.dot(this.root._data);
25
+ for (const inputProp of inputProps) {
26
+ // Parse data to update criteria when form is loaded.
27
+ updateCriteriaInputs(this.updatedCriteria, inputProp, data[inputProp], true);
28
+ // Parse data to update criteria when form field is updated
29
+ // Need to parse all fields again.
30
+ const compKeyFragments = inputProp.split('.');
31
+ let compKey = compKeyFragments[0];
32
+ if (['line1', 'line2', 'city', 'state', 'zipCode'].includes(compKeyFragments[1])) {
33
+ compKey = inputProp;
34
+ }
35
+ this.on(`changed-${compKey}`, () => {
36
+ var _a;
37
+ const data = dot.dot(this.root._data);
38
+ this.updatedCriteria = (_a = cloneDeep(this.criteria)) !== null && _a !== void 0 ? _a : {};
39
+ for (const inputProp of inputProps) {
40
+ updateCriteriaInputs(this.updatedCriteria, inputProp, data[inputProp], true);
41
+ }
42
+ this.attachReact(this.element);
43
+ });
44
+ }
45
+ }
46
+ }
47
+ attachReact(element) {
48
+ // FormIO uses id for an enclosing div, so we need to give the input field a different id.
49
+ const inputId = `${this.component.id}-input`;
50
+ return ReactDOM.render(React.createElement("div", null, !this.component.hidden ? (React.createElement(ApiBaseUrlProvider, { url: apiBaseUrl },
51
+ React.createElement(NotificationProvider, null,
52
+ React.createElement(FormComponentWrapper, Object.assign({}, this.component, { inputId: inputId, viewOnly: !this.component.canUpdateProperty }), this.component.property.manyToManyPropertyId ? (React.createElement(DropdownRepeatableField, { id: inputId, property: this.component.property, instance: this.component.instance, apiServices: this.component.apiServices, criteria: this.updatedCriteria, readOnly: !this.component.canUpdateProperty, initialMiddleObjectInstances: this.component.initialMiddleObjectInstances, middleObject: this.component.middleObject, getMiddleObjectInstances: this.component.getMiddleObjectInstances, fieldHeight: this.component.fieldHeight })) : (React.createElement(RepeatableField, Object.assign({}, this.component))))))) : null), element);
53
+ }
54
+ detachReact(element) {
55
+ ReactDOM.unmountComponentAtNode(element);
56
+ }
57
+ }
@@ -0,0 +1,26 @@
1
+ import { ReactComponent } from '@formio/react';
2
+ import { Root } from 'react-dom/client';
3
+ import { AutocompleteOption } from '../../../../core';
4
+ import { BaseFormComponentProps } from '../../types';
5
+ export declare class UserComponent extends ReactComponent {
6
+ [x: string]: any;
7
+ static schema: any;
8
+ errorDetails: any;
9
+ component: BaseFormComponentProps;
10
+ componentRoot?: Root;
11
+ criteria: Record<string, unknown> | undefined;
12
+ updatedCriteria: Record<string, unknown>;
13
+ constructor(component: BaseFormComponentProps, options: any, data: any);
14
+ init(): void;
15
+ clearErrors(): void;
16
+ handleValidation(): void;
17
+ hasErrors(): boolean;
18
+ errorMessages(): string;
19
+ /**
20
+ * Synchronizes out-of-the-box formio errors with this field's errorDetails object
21
+ */
22
+ manageFormErrors(): void;
23
+ handleChangeUserProperty: (value: AutocompleteOption) => void;
24
+ beforeSubmit(): void;
25
+ attachReact(element: Element): void;
26
+ }
@@ -0,0 +1,99 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import { ReactComponent } from '@formio/react';
3
+ import { cloneDeep, isEmpty } from 'lodash';
4
+ import React from 'react';
5
+ import { createRoot } from 'react-dom/client';
6
+ import { FormComponentWrapper } from '../../Common';
7
+ import { isPropertyVisible, transformToWhere } from '../../utils';
8
+ import { UserProperty } from './UserProperty';
9
+ export class UserComponent extends ReactComponent {
10
+ constructor(component, options, data) {
11
+ var _a;
12
+ super(Object.assign(Object.assign({}, component), { canUpdateProperty: !component.readOnly, hideLabel: true }), options, data);
13
+ this.handleChangeUserProperty = (value) => {
14
+ // set the value on the form instance at this.root.data
15
+ const updatedValue = value ? { name: value.label, id: value.value } : '';
16
+ this.setValue(updatedValue);
17
+ // update the value in the component instance
18
+ this.updateValue(updatedValue !== null && updatedValue !== void 0 ? updatedValue : {}, { modified: true });
19
+ this.handleValidation();
20
+ this.attach(this.element);
21
+ this.component.autoSave && this.component.autoSave(value);
22
+ };
23
+ this.errorDetails = {};
24
+ this.criteria = component.validate.criteria;
25
+ this.updatedCriteria = (_a = cloneDeep(component.validate.criteria)) !== null && _a !== void 0 ? _a : {};
26
+ this.handleChangeUserProperty = this.handleChangeUserProperty.bind(this);
27
+ }
28
+ init() {
29
+ this.on('changed-' + this.component.conditional.when, (value) => {
30
+ // set default value when conditional field is shown
31
+ if (this.component.defaultValue && value === this.component.conditional.eq) {
32
+ this.setValue(this.component.defaultValue);
33
+ this.updateValue(this.component.defaultValue, { modified: true });
34
+ }
35
+ // clear data and errors when a true conditional field is hidden
36
+ if (this.component.conditional.show && value !== this.component.conditional.eq) {
37
+ this.setValue('');
38
+ this.updateValue('', { modified: true });
39
+ this.clearErrors();
40
+ super.detach();
41
+ // Detach the componentRoot when the component is hidden
42
+ if (this.componentRoot) {
43
+ this.componentRoot.unmount();
44
+ this.componentRoot = undefined;
45
+ }
46
+ }
47
+ });
48
+ }
49
+ clearErrors() {
50
+ this.errorDetails = {};
51
+ this.root.customErrors = this.root.customErrors.filter((error) => error.formattedKeyOrPath !== this.component.key);
52
+ }
53
+ handleValidation() {
54
+ if (!isPropertyVisible(this.component.conditional, this.root.data)) {
55
+ return;
56
+ }
57
+ // check for out-of-the-box formio errors which store on this.root.errors
58
+ this.checkValidity(this.dataValue, true, this.data);
59
+ this.manageFormErrors();
60
+ }
61
+ hasErrors() {
62
+ return !isEmpty(this.errorDetails);
63
+ }
64
+ errorMessages() {
65
+ return Object.values(this.errorDetails).join(', ');
66
+ }
67
+ /**
68
+ * Synchronizes out-of-the-box formio errors with this field's errorDetails object
69
+ */
70
+ manageFormErrors() {
71
+ var _a;
72
+ const outOfTheBoxError = (_a = this.root.errors.find((error) => {
73
+ return error.component.key === this.component.key;
74
+ })) === null || _a === void 0 ? void 0 : _a.message;
75
+ // add OoB formio error to errorDetails object to show under field
76
+ if (outOfTheBoxError) {
77
+ this.errorDetails['rootError'] = outOfTheBoxError;
78
+ }
79
+ else {
80
+ delete this.errorDetails['rootError'];
81
+ }
82
+ }
83
+ beforeSubmit() {
84
+ this.handleValidation();
85
+ this.element && this.attach(this.element);
86
+ }
87
+ attachReact(element) {
88
+ var _a;
89
+ const updatedComponent = Object.assign(Object.assign({}, this.component), { instance: Object.assign(Object.assign({}, this.component.instance), { [this.component.key]: isEmpty(this.dataValue) ? null : this.dataValue }) });
90
+ if (!this.componentRoot) {
91
+ this.componentRoot = createRoot(element, { onRecoverableError: console.error });
92
+ }
93
+ // FormIO uses id for an enclosing div, so we need to give the input field a different id.
94
+ const inputId = `${this.component.id}-input`;
95
+ return this.componentRoot.render(React.createElement("div", null,
96
+ React.createElement(FormComponentWrapper, Object.assign({}, updatedComponent, { inputId: inputId, errorMessage: this.errorMessages() }),
97
+ React.createElement(UserProperty, Object.assign({}, updatedComponent, { id: inputId, value: (_a = this.dataValue) !== null && _a !== void 0 ? _a : '', handleChangeUserProperty: this.handleChangeUserProperty, error: this.hasErrors(), filter: this.criteria ? { where: transformToWhere(this.updatedCriteria) } : undefined })))));
98
+ }
99
+ }
@@ -0,0 +1,23 @@
1
+ /// <reference types="react" />
2
+ import { ApiServices, Property, UserAccount } from '@evoke-platform/context';
3
+ import { AutocompleteOption } from '../../../../core';
4
+ export declare type UserPropertyProps = {
5
+ id: string;
6
+ property: Property;
7
+ apiServices: ApiServices;
8
+ user?: UserAccount;
9
+ handleChangeUserProperty: (user: AutocompleteOption) => void;
10
+ error?: boolean;
11
+ setSnackbarError?: (snackbarError: {
12
+ showAlert: boolean;
13
+ message?: string;
14
+ isError?: boolean;
15
+ }) => void;
16
+ filter?: Record<string, unknown>;
17
+ value?: {
18
+ id: string;
19
+ name: string;
20
+ } | '$_CURRENT';
21
+ fieldHeight?: 'small' | 'medium';
22
+ };
23
+ export declare const UserProperty: (props: UserPropertyProps) => JSX.Element;