@evoke-platform/ui-components 1.0.0-dev.217 → 1.0.0-dev.219
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/Common/Form.d.ts +38 -0
- package/dist/published/components/custom/Form/Common/Form.js +413 -0
- package/dist/published/components/custom/Form/Common/FormComponentWrapper.d.ts +26 -0
- package/dist/published/components/custom/Form/Common/FormComponentWrapper.js +79 -0
- package/dist/published/components/custom/Form/Common/index.d.ts +2 -0
- package/dist/published/components/custom/Form/Common/index.js +2 -0
- package/dist/published/components/custom/Form/FormComponents/ButtonComponent.d.ts +37 -0
- package/dist/published/components/custom/Form/FormComponents/ButtonComponent.js +150 -0
- package/dist/published/components/custom/Form/FormComponents/DocumentComponent/Document.d.ts +17 -0
- package/dist/published/components/custom/Form/FormComponents/DocumentComponent/Document.js +80 -0
- package/dist/published/components/custom/Form/FormComponents/DocumentComponent/DocumentComponent.d.ts +23 -0
- package/dist/published/components/custom/Form/FormComponents/DocumentComponent/DocumentComponent.js +154 -0
- package/dist/published/components/custom/Form/FormComponents/DocumentComponent/DocumentList.d.ts +15 -0
- package/dist/published/components/custom/Form/FormComponents/DocumentComponent/DocumentList.js +172 -0
- package/dist/published/components/custom/Form/FormComponents/FormFieldComponent.d.ts +41 -0
- package/dist/published/components/custom/Form/FormComponents/FormFieldComponent.js +409 -0
- package/dist/published/components/custom/Form/FormComponents/ImageComponent/Image.d.ts +15 -0
- package/dist/published/components/custom/Form/FormComponents/ImageComponent/Image.js +111 -0
- package/dist/published/components/custom/Form/FormComponents/ImageComponent/ImageComponent.d.ts +23 -0
- package/dist/published/components/custom/Form/FormComponents/ImageComponent/ImageComponent.js +112 -0
- package/dist/published/components/custom/Form/FormComponents/ObjectComponent/InstanceLookup.d.ts +20 -0
- package/dist/published/components/custom/Form/FormComponents/ObjectComponent/InstanceLookup.js +229 -0
- package/dist/published/components/custom/Form/FormComponents/ObjectComponent/ObjectComponent.d.ts +34 -0
- package/dist/published/components/custom/Form/FormComponents/ObjectComponent/ObjectComponent.js +150 -0
- package/dist/published/components/custom/Form/FormComponents/ObjectComponent/ObjectPropertyInput.d.ts +3 -0
- package/dist/published/components/custom/Form/FormComponents/ObjectComponent/ObjectPropertyInput.js +306 -0
- package/dist/published/components/custom/Form/FormComponents/ObjectComponent/RelatedObjectInstance.d.ts +24 -0
- package/dist/published/components/custom/Form/FormComponents/ObjectComponent/RelatedObjectInstance.js +126 -0
- package/dist/published/components/custom/Form/FormComponents/RepeatableFieldComponent/ActionDialog.d.ts +21 -0
- package/dist/published/components/custom/Form/FormComponents/RepeatableFieldComponent/ActionDialog.js +96 -0
- package/dist/published/components/custom/Form/FormComponents/RepeatableFieldComponent/ManyToMany/DropdownRepeatableField.d.ts +15 -0
- package/dist/published/components/custom/Form/FormComponents/RepeatableFieldComponent/ManyToMany/DropdownRepeatableField.js +158 -0
- package/dist/published/components/custom/Form/FormComponents/RepeatableFieldComponent/ManyToMany/DropdownRepeatableFieldInput.d.ts +39 -0
- package/dist/published/components/custom/Form/FormComponents/RepeatableFieldComponent/ManyToMany/DropdownRepeatableFieldInput.js +89 -0
- package/dist/published/components/custom/Form/FormComponents/RepeatableFieldComponent/RepeatableField.d.ts +12 -0
- package/dist/published/components/custom/Form/FormComponents/RepeatableFieldComponent/RepeatableField.js +369 -0
- package/dist/published/components/custom/Form/FormComponents/RepeatableFieldComponent/RepeatableFieldComponent.d.ts +20 -0
- package/dist/published/components/custom/Form/FormComponents/RepeatableFieldComponent/RepeatableFieldComponent.js +57 -0
- package/dist/published/components/custom/Form/FormComponents/UserComponent/UserComponent.d.ts +26 -0
- package/dist/published/components/custom/Form/FormComponents/UserComponent/UserComponent.js +99 -0
- package/dist/published/components/custom/Form/FormComponents/UserComponent/UserProperty.d.ts +23 -0
- package/dist/published/components/custom/Form/FormComponents/UserComponent/UserProperty.js +115 -0
- package/dist/published/components/custom/Form/FormComponents/ViewOnlyComponent.d.ts +20 -0
- package/dist/published/components/custom/Form/FormComponents/ViewOnlyComponent.js +83 -0
- package/dist/published/components/custom/Form/FormComponents/index.d.ts +8 -0
- package/dist/published/components/custom/Form/FormComponents/index.js +8 -0
- package/dist/published/components/custom/Form/index.d.ts +3 -0
- package/dist/published/components/custom/Form/index.js +3 -0
- package/dist/published/components/custom/Form/types.d.ts +109 -0
- package/dist/published/components/custom/Form/types.js +1 -0
- package/dist/published/components/custom/Form/utils.d.ts +45 -0
- package/dist/published/components/custom/Form/utils.js +1036 -0
- package/dist/published/components/custom/HistoryLog/DisplayedProperty.d.ts +8 -0
- package/dist/published/components/custom/HistoryLog/DisplayedProperty.js +70 -0
- package/dist/published/components/custom/HistoryLog/Filter.d.ts +11 -0
- package/dist/published/components/custom/HistoryLog/Filter.js +55 -0
- package/dist/published/components/custom/HistoryLog/HistoryData.d.ts +10 -0
- package/dist/published/components/custom/HistoryLog/HistoryData.js +83 -0
- package/dist/published/components/custom/HistoryLog/HistoryLoading.d.ts +3 -0
- package/dist/published/components/custom/HistoryLog/HistoryLoading.js +39 -0
- package/dist/published/components/custom/HistoryLog/index.d.ts +22 -0
- package/dist/published/components/custom/HistoryLog/index.js +92 -0
- package/dist/published/components/custom/RichTextViewer/index.d.ts +15 -0
- package/dist/published/components/custom/RichTextViewer/index.js +47 -0
- package/dist/published/components/custom/index.d.ts +3 -0
- package/dist/published/components/custom/index.js +3 -0
- package/dist/published/index.d.ts +1 -1
- package/dist/published/index.js +1 -1
- package/dist/published/stories/HistoryLog.stories.d.ts +6 -0
- package/dist/published/stories/HistoryLog.stories.js +79 -0
- package/dist/published/stories/RichTextViewer.stories.d.ts +6 -0
- package/dist/published/stories/RichTextViewer.stories.js +12 -0
- package/dist/published/styles/form-component.css +152 -0
- package/dist/published/types.d.ts +20 -0
- package/package.json +21 -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;
|