@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.
Files changed (75) 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/HistoryLog/DisplayedProperty.d.ts +8 -0
  54. package/dist/published/components/custom/HistoryLog/DisplayedProperty.js +70 -0
  55. package/dist/published/components/custom/HistoryLog/Filter.d.ts +11 -0
  56. package/dist/published/components/custom/HistoryLog/Filter.js +55 -0
  57. package/dist/published/components/custom/HistoryLog/HistoryData.d.ts +10 -0
  58. package/dist/published/components/custom/HistoryLog/HistoryData.js +83 -0
  59. package/dist/published/components/custom/HistoryLog/HistoryLoading.d.ts +3 -0
  60. package/dist/published/components/custom/HistoryLog/HistoryLoading.js +39 -0
  61. package/dist/published/components/custom/HistoryLog/index.d.ts +22 -0
  62. package/dist/published/components/custom/HistoryLog/index.js +92 -0
  63. package/dist/published/components/custom/RichTextViewer/index.d.ts +15 -0
  64. package/dist/published/components/custom/RichTextViewer/index.js +47 -0
  65. package/dist/published/components/custom/index.d.ts +3 -0
  66. package/dist/published/components/custom/index.js +3 -0
  67. package/dist/published/index.d.ts +1 -1
  68. package/dist/published/index.js +1 -1
  69. package/dist/published/stories/HistoryLog.stories.d.ts +6 -0
  70. package/dist/published/stories/HistoryLog.stories.js +79 -0
  71. package/dist/published/stories/RichTextViewer.stories.d.ts +6 -0
  72. package/dist/published/stories/RichTextViewer.stories.js +12 -0
  73. package/dist/published/styles/form-component.css +152 -0
  74. package/dist/published/types.d.ts +20 -0
  75. package/package.json +21 -5
@@ -0,0 +1,38 @@
1
+ import { ApiServices, Obj, ObjectInstance, UserAccount } from '@evoke-platform/context';
2
+ import { ReactNode } from 'react';
3
+ import { Document, ObjectPropertyInputProps } from '../types';
4
+ import '../../../../styles/form-component.css';
5
+ declare type OnSaveResponse = {
6
+ isSuccessful: boolean;
7
+ error?: Record<string, unknown>;
8
+ };
9
+ export declare type FormProps = {
10
+ formKey?: number;
11
+ object?: Obj;
12
+ instance?: ObjectInstance;
13
+ document?: Document;
14
+ user?: UserAccount;
15
+ onSave?: (data: Record<string, unknown>, setSubmitting?: (value: boolean) => void) => Promise<OnSaveResponse>;
16
+ submitButtonLabel?: string;
17
+ isReadOnly?: boolean;
18
+ apiServices?: ApiServices | undefined;
19
+ navigateTo?: (path: string) => void;
20
+ closeModal?: () => void;
21
+ clearable?: boolean;
22
+ objectInputCommonProps?: ObjectPropertyInputProps;
23
+ actionId?: string;
24
+ onAutoSave?: (data: Record<string, unknown>) => Promise<{
25
+ isSuccessful: boolean;
26
+ error?: Record<string, unknown>;
27
+ }>;
28
+ actionType?: string;
29
+ associatedObject?: {
30
+ instanceId?: string;
31
+ propertyId?: string;
32
+ };
33
+ queryAddresses?: unknown;
34
+ fieldHeight?: 'small' | 'medium';
35
+ richTextEditor?: ReactNode;
36
+ };
37
+ export declare function Form(props: FormProps): JSX.Element;
38
+ export default Form;
@@ -0,0 +1,413 @@
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 { useApp, useAuthenticationContext, } from '@evoke-platform/context';
11
+ import { Components, Form as FormIO } from '@formio/react';
12
+ import { flatten } from 'flat';
13
+ import { isEqual, toPairs } from 'lodash';
14
+ import React, { useEffect, useRef, useState } from 'react';
15
+ import { Skeleton, Snackbar } from '../../../core';
16
+ import { Box } from '../../../layout';
17
+ import { ButtonComponent, DocumentComponent, FormFieldComponent, ImageComponent, ObjectComponent, RepeatableFieldComponent, UserComponent, ViewOnlyComponent, } from '../FormComponents';
18
+ import { addObjectPropertiesToComponentProps, buildComponentPropsFromDocumentProperties, buildComponentPropsFromObjectProperties, convertFormToComponents, getFlattenEntries, getPrefixedUrl, } from '../utils';
19
+ import '../../../../styles/form-component.css';
20
+ const usePrevious = (value) => {
21
+ const ref = useRef();
22
+ useEffect(() => {
23
+ ref.current = value;
24
+ });
25
+ return ref.current;
26
+ };
27
+ export function Form(props) {
28
+ var _a;
29
+ const { clearable, closeModal, onSave, submitButtonLabel, instance, object, objectInputCommonProps, actionId, actionType, associatedObject, onAutoSave, apiServices, navigateTo, document, queryAddresses, user, isReadOnly, fieldHeight, richTextEditor, } = props;
30
+ const [formKey, setFormKey] = useState();
31
+ const [componentProps, setComponentProps] = useState([]);
32
+ const [snackbarError, setSnackbarError] = useState();
33
+ const prevFormKey = usePrevious(formKey);
34
+ const userAccount = user !== null && user !== void 0 ? user : (_a = useAuthenticationContext()) === null || _a === void 0 ? void 0 : _a.account;
35
+ const { defaultPages, findDefaultPageSlugFor } = useApp();
36
+ const rebuildFormComponents = () => {
37
+ const viewDetailsComponents = {
38
+ ViewOnlyBoolean: ViewOnlyComponent,
39
+ ViewOnlyDateTime: ViewOnlyComponent,
40
+ ViewOnlyDate: ViewOnlyComponent,
41
+ ViewOnlyDocument: DocumentComponent,
42
+ ViewOnlySelect: ViewOnlyComponent,
43
+ ViewOnlyMultiSelect: ViewOnlyComponent,
44
+ ViewOnlyObject: ViewOnlyComponent,
45
+ ViewOnlyUser: ViewOnlyComponent,
46
+ ViewOnlyTextField: ViewOnlyComponent,
47
+ ViewOnlyDecimal: ViewOnlyComponent,
48
+ ViewOnlyInteger: ViewOnlyComponent,
49
+ ViewOnlyRichText: richTextEditor,
50
+ ViewOnlySection: Components.components.fieldset,
51
+ ViewOnlyManyToManyRepeatableField: RepeatableFieldComponent,
52
+ ViewOnlyRepeatableField: RepeatableFieldComponent,
53
+ ViewOnlyImage: ImageComponent,
54
+ ViewOnlyTime: ViewOnlyComponent,
55
+ };
56
+ Components.setComponents(Object.assign(Object.assign(Object.assign({}, Components.components), { Boolean: FormFieldComponent, Columns: Components.components.columns, DateTime: FormFieldComponent, Date: FormFieldComponent, Select: FormFieldComponent, MultiSelect: FormFieldComponent, Object: ObjectComponent, User: UserComponent, TextField: FormFieldComponent, Decimal: FormFieldComponent, Document: DocumentComponent, Integer: FormFieldComponent, Buttons: ButtonComponent, Content: Components.components.content, RichText: richTextEditor, Section: Components.components.tabs, ManyToManyRepeatableField: RepeatableFieldComponent, RepeatableField: RepeatableFieldComponent, Image: ImageComponent, Time: FormFieldComponent }), (isReadOnly && viewDetailsComponents)));
57
+ buildComponents();
58
+ };
59
+ useEffect(() => {
60
+ // TODO: Check why formKey is not being set for create actions
61
+ if (((actionType === 'update' || actionType === 'delete') && !!instance) || !!document) {
62
+ setFormKey(Date.now());
63
+ }
64
+ rebuildFormComponents();
65
+ }, [object]);
66
+ useEffect(() => {
67
+ if (prevFormKey && formKey && formKey > prevFormKey && (!!instance || !!document)) {
68
+ buildComponents();
69
+ }
70
+ }, [formKey]);
71
+ const buildComponents = () => __awaiter(this, void 0, void 0, function* () {
72
+ var _b, _c, _d;
73
+ const action = (_b = object === null || object === void 0 ? void 0 : object.actions) === null || _b === void 0 ? void 0 : _b.find((action) => action.id === actionId);
74
+ let input;
75
+ const parameters = (associatedObject === null || associatedObject === void 0 ? void 0 : associatedObject.propertyId) && (action === null || action === void 0 ? void 0 : action.parameters)
76
+ ? action.parameters.filter((param) => param.id !== (associatedObject === null || associatedObject === void 0 ? void 0 : associatedObject.propertyId))
77
+ : action === null || action === void 0 ? void 0 : action.parameters;
78
+ if (parameters && object) {
79
+ input = ((_c = action === null || action === void 0 ? void 0 : action.form) === null || _c === void 0 ? void 0 : _c.entries)
80
+ ? convertFormToComponents(action.form.entries, parameters, object)
81
+ : parameters.filter((param) => { var _a; return (_a = object.properties) === null || _a === void 0 ? void 0 : _a.some((prop) => prop.id === param.id); });
82
+ }
83
+ else {
84
+ input = (_d = action === null || action === void 0 ? void 0 : action.inputProperties) !== null && _d !== void 0 ? _d : ((action === null || action === void 0 ? void 0 : action.type) === 'delete' ? [] : undefined);
85
+ }
86
+ let visibleObjectProperties = object === null || object === void 0 ? void 0 : object.properties;
87
+ if (associatedObject) {
88
+ // Eliminates the associated object's field from the form
89
+ visibleObjectProperties = visibleObjectProperties === null || visibleObjectProperties === void 0 ? void 0 : visibleObjectProperties.filter((property) => property.id !== associatedObject.propertyId);
90
+ }
91
+ let foundDefaultPages = defaultPages;
92
+ const relatedObjectProperties = visibleObjectProperties === null || visibleObjectProperties === void 0 ? void 0 : visibleObjectProperties.filter((property) => property.type === 'object');
93
+ if (relatedObjectProperties) {
94
+ foundDefaultPages = yield relatedObjectProperties.reduce((acc, property) => __awaiter(this, void 0, void 0, function* () {
95
+ const result = yield acc;
96
+ if (property.objectId && defaultPages && defaultPages[property.objectId]) {
97
+ const slug = yield findDefaultPageSlugFor(property.objectId);
98
+ if (slug) {
99
+ return Object.assign(Object.assign({}, result), { [property.objectId]: slug });
100
+ }
101
+ }
102
+ return result;
103
+ }), Promise.resolve({}));
104
+ }
105
+ const allDefaultPages = Object.assign(Object.assign({}, defaultPages), foundDefaultPages);
106
+ if (input && visibleObjectProperties) {
107
+ if (input.length || (action === null || action === void 0 ? void 0 : action.type) !== 'delete') {
108
+ // formIO builder-configured input properties exist
109
+ const newComponentProps = yield addObjectPropertiesToComponentProps(visibleObjectProperties, input, instance, Object.assign(Object.assign({}, objectInputCommonProps), { defaultPages: allDefaultPages, navigateTo,
110
+ apiServices, user: userAccount }), undefined, isReadOnly, allDefaultPages, navigateTo, queryAddresses, apiServices, !!closeModal, fieldHeight);
111
+ const components = isReadOnly ? newComponentProps : [...newComponentProps, BottomButtons];
112
+ setComponentProps(components);
113
+ }
114
+ else {
115
+ // this condition is used for the delete action's modal form
116
+ setComponentProps([
117
+ ...(yield addObjectPropertiesToComponentProps(visibleObjectProperties, [
118
+ {
119
+ html: `<p>${(action === null || action === void 0 ? void 0 : action.type) === 'delete' ? 'This action cannot be undone.' : 'Are you sure?'}</p>`,
120
+ label: 'Content',
121
+ customClass: '',
122
+ refreshOnChange: false,
123
+ hidden: false,
124
+ modalEdit: false,
125
+ conditional: {
126
+ show: null,
127
+ when: null,
128
+ eq: '',
129
+ },
130
+ type: 'Content',
131
+ key: 'content',
132
+ input: false,
133
+ placeholder: '',
134
+ prefix: '',
135
+ suffix: '',
136
+ multiple: false,
137
+ defaultValue: null,
138
+ protected: false,
139
+ unique: false,
140
+ persistent: true,
141
+ clearOnHide: true,
142
+ refreshOn: '',
143
+ redrawOn: '',
144
+ tableView: false,
145
+ dataGridLabel: false,
146
+ labelPosition: 'top',
147
+ description: '',
148
+ errorLabel: '',
149
+ tooltip: '',
150
+ hideLabel: false,
151
+ tabindex: '',
152
+ disabled: false,
153
+ autofocus: false,
154
+ dbIndex: false,
155
+ customDefaultValue: '',
156
+ calculateValue: '',
157
+ calculateServer: false,
158
+ widget: null,
159
+ attributes: {},
160
+ validateOn: 'change',
161
+ validate: {
162
+ required: false,
163
+ custom: '',
164
+ customPrivate: false,
165
+ strictDateValidation: false,
166
+ multiple: false,
167
+ unique: false,
168
+ },
169
+ overlay: {
170
+ style: '',
171
+ left: '',
172
+ top: '',
173
+ width: '',
174
+ height: '',
175
+ },
176
+ allowCalculateOverride: false,
177
+ encrypted: false,
178
+ showCharCount: false,
179
+ showWordCount: false,
180
+ properties: {},
181
+ allowMultipleMasks: false,
182
+ addons: [],
183
+ id: 'eahbwo',
184
+ },
185
+ ], instance, Object.assign(Object.assign({}, objectInputCommonProps), { defaultPages: allDefaultPages, navigateTo,
186
+ apiServices, user: userAccount }), undefined, undefined, undefined, undefined, undefined, undefined, !!closeModal, fieldHeight)),
187
+ BottomButtons,
188
+ ]);
189
+ }
190
+ }
191
+ else if (object === null || object === void 0 ? void 0 : object.properties) {
192
+ // If form.io form is not configured and no inputProperties are
193
+ // set, use object properties to build form.
194
+ const propertiesInForm = object.properties.filter((prop) => prop.id !== (associatedObject === null || associatedObject === void 0 ? void 0 : associatedObject.propertyId) && ((action === null || action === void 0 ? void 0 : action.type) !== 'create' || prop.type !== 'document'));
195
+ setComponentProps([
196
+ ...buildComponentPropsFromObjectProperties(propertiesInForm, object.id, instance, Object.assign(Object.assign({}, objectInputCommonProps), { defaultPages: allDefaultPages, navigateTo,
197
+ apiServices,
198
+ user }), !!action, undefined, isReadOnly, queryAddresses, !!closeModal, fieldHeight),
199
+ !isReadOnly && BottomButtons,
200
+ ]);
201
+ }
202
+ else if (document) {
203
+ const documentProperties = toPairs(flatten(document !== null && document !== void 0 ? document : {}));
204
+ setComponentProps([
205
+ ...buildComponentPropsFromDocumentProperties(documentProperties, isReadOnly, undefined, fieldHeight),
206
+ !isReadOnly && BottomButtons,
207
+ ]);
208
+ }
209
+ });
210
+ const uploadDocuments = (files, metadata) => __awaiter(this, void 0, void 0, function* () {
211
+ var _e;
212
+ const allDocuments = [];
213
+ const formData = new FormData();
214
+ for (const [index, file] of files.entries()) {
215
+ if ('size' in file) {
216
+ formData.append(`files[${index}]`, file);
217
+ }
218
+ else {
219
+ allDocuments.push(file);
220
+ }
221
+ }
222
+ if (metadata) {
223
+ for (const [key, value] of Object.entries(metadata)) {
224
+ formData.append(key, value);
225
+ }
226
+ }
227
+ const docs = yield (apiServices === null || apiServices === void 0 ? void 0 : apiServices.post(getPrefixedUrl(`/objects/${object === null || object === void 0 ? void 0 : object.id}/instances/${instance === null || instance === void 0 ? void 0 : instance.id}/documents`), formData));
228
+ return allDocuments.concat((_e = docs === null || docs === void 0 ? void 0 : docs.map((doc) => ({ id: doc.id, name: doc.name }))) !== null && _e !== void 0 ? _e : []);
229
+ });
230
+ const saveDocuments = (submittedFields, action) => __awaiter(this, void 0, void 0, function* () {
231
+ var _f, _g, _h, _j;
232
+ const documentProperties = (action === null || action === void 0 ? void 0 : action.parameters)
233
+ ? action.parameters.filter((param) => param.type === 'document')
234
+ : (_f = object === null || object === void 0 ? void 0 : object.properties) === null || _f === void 0 ? void 0 : _f.filter((prop) => prop.type === 'document');
235
+ let allEntries = null;
236
+ for (const docProperty of documentProperties !== null && documentProperties !== void 0 ? documentProperties : []) {
237
+ const value = submittedFields[docProperty.id];
238
+ // skip if the document list did not change
239
+ if (value === undefined || !instance || isEqual(instance === null || instance === void 0 ? void 0 : instance[docProperty.id], value)) {
240
+ continue;
241
+ }
242
+ let savedDocuments = null;
243
+ if (value && value.some((doc) => doc instanceof File)) {
244
+ if (!allEntries) {
245
+ allEntries = (_j = getFlattenEntries((_h = (_g = action === null || action === void 0 ? void 0 : action.form) === null || _g === void 0 ? void 0 : _g.entries) !== null && _h !== void 0 ? _h : [])) !== null && _j !== void 0 ? _j : [];
246
+ }
247
+ const docEntry = allEntries.find((entry) => entry.parameterId === docProperty.id);
248
+ try {
249
+ savedDocuments = yield uploadDocuments(value, Object.assign({ type: '', view_permission: '' }, docEntry === null || docEntry === void 0 ? void 0 : docEntry.documentMetadata));
250
+ }
251
+ catch (error) {
252
+ setSnackbarError({ message: `An error occurred while uploading associated documents` });
253
+ return false;
254
+ }
255
+ }
256
+ else if (value) {
257
+ // cast as confirmed above that no element in value is a File
258
+ savedDocuments = value;
259
+ }
260
+ submittedFields[docProperty.id] = savedDocuments;
261
+ }
262
+ return true;
263
+ });
264
+ const deleteDocuments = (submittedFields, requestSuccess, action) => __awaiter(this, void 0, void 0, function* () {
265
+ var _k, _l, _m, _o;
266
+ const documentProperties = (action === null || action === void 0 ? void 0 : action.parameters)
267
+ ? action.parameters.filter((param) => param.type === 'document')
268
+ : (_k = object === null || object === void 0 ? void 0 : object.properties) === null || _k === void 0 ? void 0 : _k.filter((prop) => prop.type === 'document');
269
+ for (const docProperty of documentProperties !== null && documentProperties !== void 0 ? documentProperties : []) {
270
+ const savedValue = submittedFields[docProperty.id];
271
+ const originalValue = instance === null || instance === void 0 ? void 0 : instance[docProperty.id];
272
+ const documentsToRemove = requestSuccess
273
+ ? (_l = originalValue === null || originalValue === void 0 ? void 0 : originalValue.filter((file) => !(savedValue === null || savedValue === void 0 ? void 0 : savedValue.some((f) => f.id === file.id)))) !== null && _l !== void 0 ? _l : []
274
+ : (_m = savedValue === null || savedValue === void 0 ? void 0 : savedValue.filter((file) => !(originalValue === null || originalValue === void 0 ? void 0 : originalValue.some((f) => f.id === file.id)))) !== null && _m !== void 0 ? _m : [];
275
+ for (const doc of documentsToRemove) {
276
+ try {
277
+ yield (apiServices === null || apiServices === void 0 ? void 0 : apiServices.delete(getPrefixedUrl(`/objects/${object === null || object === void 0 ? void 0 : object.id}/instances/${instance === null || instance === void 0 ? void 0 : instance.id}/documents/${doc.id}`)));
278
+ }
279
+ catch (error) {
280
+ if (((_o = error.response) === null || _o === void 0 ? void 0 : _o.status) !== 404) {
281
+ setSnackbarError({ message: `An error occurred while removing document '${doc.name}'` });
282
+ }
283
+ }
284
+ }
285
+ }
286
+ });
287
+ const saveHandler = (submission, type, setError, setSubmitting) => __awaiter(this, void 0, void 0, function* () {
288
+ var _p;
289
+ const submittedFields = {};
290
+ for (const field in submission.data) {
291
+ const value = submission.data[field];
292
+ if (value === '' || (Array.isArray(value) && !value.length)) {
293
+ submittedFields[field] = null;
294
+ }
295
+ else {
296
+ submittedFields[field] = value;
297
+ }
298
+ }
299
+ //OPTIMIZATION TODO: See if type can be inferred from the event target
300
+ if (type === 'submit') {
301
+ if (onSave) {
302
+ const action = (_p = object === null || object === void 0 ? void 0 : object.actions) === null || _p === void 0 ? void 0 : _p.find((action) => action.id === actionId);
303
+ const documentsUploaded = yield saveDocuments(submittedFields, action);
304
+ if (documentsUploaded) {
305
+ try {
306
+ const { isSuccessful, error } = yield onSave(submittedFields, setSubmitting);
307
+ setError(error);
308
+ // Delete the documents that were removed if save was successful,
309
+ // otherwise delete the documents that were uploaded.
310
+ yield deleteDocuments(submittedFields, isSuccessful, action);
311
+ !error && !closeModal && setFormKey(Date.now());
312
+ }
313
+ catch (err) {
314
+ // If the save fails, delete the documents that were just uploaded
315
+ yield deleteDocuments(submittedFields, false, action);
316
+ }
317
+ }
318
+ }
319
+ }
320
+ else {
321
+ if (onAutoSave) {
322
+ const documentsUploaded = yield saveDocuments(submittedFields);
323
+ if (!documentsUploaded) {
324
+ return;
325
+ }
326
+ try {
327
+ const { isSuccessful, error } = yield onAutoSave(submittedFields);
328
+ // Delete the documents that were removed if save was successful,
329
+ // otherwise delete the documents that were uploaded.
330
+ deleteDocuments(submittedFields, isSuccessful);
331
+ !error && !closeModal && setFormKey(Date.now());
332
+ }
333
+ catch (err) {
334
+ // If the save fails, delete the documents that were just uploaded
335
+ deleteDocuments(submittedFields, false);
336
+ }
337
+ }
338
+ }
339
+ });
340
+ const BottomButtons = {
341
+ type: 'Buttons',
342
+ key: 'cancel-submit',
343
+ variant: 'contained',
344
+ components: [
345
+ {
346
+ type: 'button',
347
+ action: 'cancel',
348
+ label: `${closeModal ? 'Cancel' : 'Discard Changes'}`,
349
+ style: {
350
+ margin: '5px',
351
+ color: '#000000',
352
+ border: '1px solid rgb(206, 212, 218)',
353
+ '&:hover': { backgroundColor: '#f2f4f7', border: '1px solid rgb(206, 212, 218)' },
354
+ },
355
+ key: 'cancel',
356
+ variant: 'outlined',
357
+ onClick: () => {
358
+ clearable && setFormKey(Date.now());
359
+ closeModal && closeModal();
360
+ },
361
+ },
362
+ onAutoSave
363
+ ? {
364
+ type: 'button',
365
+ action: 'save-draft',
366
+ label: 'Save as draft',
367
+ key: 'save-draft',
368
+ variant: 'outlined',
369
+ isModal: !!closeModal,
370
+ onClick: (data, setError, setSubmitting) => __awaiter(this, void 0, void 0, function* () { return yield saveHandler(data, 'draft', setError, setSubmitting); }),
371
+ style: { lineHeight: '2.75', margin: '5px', padding: '0 10px' },
372
+ }
373
+ : undefined,
374
+ {
375
+ type: 'button',
376
+ action: 'submit',
377
+ label: submitButtonLabel || 'Submit',
378
+ key: 'submit',
379
+ style: {
380
+ lineHeight: '2.75',
381
+ margin: '5px 0 5px 5px',
382
+ padding: '0 23px',
383
+ backgroundColor: props.actionType === 'delete' ? '#A12723' : 'default',
384
+ ':hover': {
385
+ backgroundColor: props.actionType === 'delete' ? '#8c2421' : 'default',
386
+ },
387
+ },
388
+ variant: 'contained',
389
+ isModal: !!closeModal,
390
+ onClick: (data, setError, setSubmitting) => {
391
+ saveHandler(data, 'submit', setError, setSubmitting);
392
+ },
393
+ },
394
+ ],
395
+ };
396
+ return (React.createElement("div", null,
397
+ componentProps.length ? (React.createElement(FormIO, { key: closeModal ? undefined : formKey, form: {
398
+ display: 'form',
399
+ components: componentProps,
400
+ } })) : (React.createElement(Box, null,
401
+ React.createElement(Box, { display: 'flex', width: '100%', justifyContent: 'space-between' },
402
+ React.createElement(Skeleton, { width: '78%', sx: { borderRadius: '8px', height: '40px' } }),
403
+ React.createElement(Skeleton, { width: '20%', sx: { borderRadius: '8px', height: '40px' } })),
404
+ React.createElement(Box, { display: 'flex', width: '100%', justifyContent: 'space-between' },
405
+ React.createElement(Skeleton, { width: '32%', sx: { borderRadius: '8px', height: '40px' } }),
406
+ React.createElement(Skeleton, { width: '33%', sx: { borderRadius: '8px', height: '40px' } }),
407
+ React.createElement(Skeleton, { width: '32%', sx: { borderRadius: '8px', height: '40px' } })),
408
+ React.createElement(Box, { display: 'flex', width: '100%', justifyContent: 'space-between' },
409
+ React.createElement(Skeleton, { width: '48%', sx: { borderRadius: '8px', height: '40px' } }),
410
+ React.createElement(Skeleton, { width: '48%', sx: { borderRadius: '8px', height: '40px' } })))),
411
+ React.createElement(Snackbar, { open: !!(snackbarError === null || snackbarError === void 0 ? void 0 : snackbarError.message), handleClose: () => setSnackbarError(undefined), message: snackbarError === null || snackbarError === void 0 ? void 0 : snackbarError.message, error: true })));
412
+ }
413
+ export default Form;
@@ -0,0 +1,26 @@
1
+ import React from 'react';
2
+ declare type FormComponentWrapperProps = {
3
+ inputId: string;
4
+ label: string;
5
+ description?: string;
6
+ tooltip?: string;
7
+ prefix?: string;
8
+ suffix?: string;
9
+ value?: string;
10
+ validate: {
11
+ maxLength?: number;
12
+ required?: boolean;
13
+ };
14
+ errorMessage?: string;
15
+ showCharCount?: boolean;
16
+ type: string;
17
+ viewOnly: boolean;
18
+ children: React.ReactNode;
19
+ key: string;
20
+ };
21
+ /**
22
+ * A component that wraps a FormField and adds a label,
23
+ * description, tooltip, prefix, suffix and word/char counts
24
+ */
25
+ export declare const FormComponentWrapper: (props: FormComponentWrapperProps) => JSX.Element;
26
+ export {};
@@ -0,0 +1,79 @@
1
+ import React, { useEffect, useRef, useState } from 'react';
2
+ import { ErrorRounded, Help } from '../../../../icons';
3
+ import { IconButton, Tooltip, Typography } from '../../../core';
4
+ import { Box } from '../../../layout';
5
+ const underFieldStyles = {
6
+ display: 'flex',
7
+ flexDirection: 'row',
8
+ justifyContent: 'space-between',
9
+ alignItems: 'center',
10
+ };
11
+ const descriptionStyles = {
12
+ color: '#999',
13
+ whiteSpace: 'normal',
14
+ paddingBottom: '4px',
15
+ };
16
+ const PrefixSuffix = (props) => {
17
+ const { prefix, suffix, height } = props;
18
+ const text = prefix || suffix;
19
+ const prefixSuffixStyles = Object.assign(Object.assign(Object.assign({ display: 'inline-flex', alignItems: 'center', background: '#f5f5f5', padding: '5px', border: '1px solid #ccc' }, (suffix && {
20
+ borderTopRightRadius: '5px',
21
+ borderBottomRightRadius: '5px',
22
+ marginLeft: '-5px',
23
+ paddingLeft: '10px',
24
+ })), (prefix && {
25
+ borderTopLeftRadius: '5px',
26
+ borderBottomLeftRadius: '5px',
27
+ marginRight: '-5px',
28
+ paddingRight: '10px',
29
+ })), { height: height });
30
+ if (!prefix && !suffix)
31
+ return null;
32
+ return (React.createElement(Box, { sx: prefixSuffixStyles },
33
+ React.createElement(Typography, null, text)));
34
+ };
35
+ /**
36
+ * A component that wraps a FormField and adds a label,
37
+ * description, tooltip, prefix, suffix and word/char counts
38
+ */
39
+ export const FormComponentWrapper = (props) => {
40
+ const { inputId, label, description, tooltip, prefix, suffix, value, validate, errorMessage, showCharCount, type, viewOnly, children, } = props;
41
+ const [fieldHeight, setFieldHeight] = useState(40);
42
+ const { maxLength } = validate;
43
+ const fieldRef = useRef(null);
44
+ useEffect(() => {
45
+ // Get the height of the field to sync with height of prefix and suffix.
46
+ const fieldElement = fieldRef.current;
47
+ if (fieldElement && (prefix || suffix)) {
48
+ setFieldHeight(fieldElement.getBoundingClientRect().height - 12);
49
+ }
50
+ }, [fieldRef]);
51
+ let charCount = value && type === 'TextField' ? value.length : 0;
52
+ if (maxLength)
53
+ charCount = maxLength - charCount;
54
+ return (React.createElement(Box, null,
55
+ React.createElement(Box, { sx: { padding: '10px 0' } },
56
+ React.createElement(Typography, { variant: "body2", color: viewOnly ? 'textSecondary' : 'textPrimary', component: "label", htmlFor: inputId },
57
+ label,
58
+ validate.required ? (React.createElement(Typography, { component: 'span', sx: { color: 'red', fontSize: '12px' } },
59
+ ` *`,
60
+ ' ')) : null,
61
+ tooltip && (React.createElement(Tooltip, { placement: "right", title: tooltip },
62
+ React.createElement(IconButton, null,
63
+ React.createElement(Help, { sx: { fontSize: '14px' } }))))),
64
+ React.createElement(Typography, { variant: "caption", sx: descriptionStyles }, description),
65
+ React.createElement(Box, { sx: { display: 'flex', flexDirection: 'row' } },
66
+ React.createElement(PrefixSuffix, { prefix: prefix, height: fieldHeight }),
67
+ React.createElement(Box, { sx: { width: '100%', paddingTop: '6px' } }, children),
68
+ React.createElement(PrefixSuffix, { suffix: suffix, height: fieldHeight }))),
69
+ React.createElement(Box, { sx: underFieldStyles },
70
+ React.createElement(Box, { sx: { width: '100%', display: 'flex', justifyContent: 'space-between' } },
71
+ errorMessage ? (React.createElement(Typography, { sx: { color: 'red', whiteSpace: 'normal', display: 'flex', alignItems: 'center' }, variant: "caption" },
72
+ React.createElement(ErrorRounded, { sx: { fontSize: '15px', paddingRight: '4px' } }),
73
+ errorMessage)) : (React.createElement("span", null)),
74
+ showCharCount && (React.createElement(Typography, { variant: "caption", sx: { color: '#999', whiteSpace: 'nowrap' } },
75
+ charCount,
76
+ " ",
77
+ charCount === 1 ? 'character' : 'characters',
78
+ !!maxLength && ` remaining`))))));
79
+ };
@@ -0,0 +1,2 @@
1
+ export * from './Form';
2
+ export * from './FormComponentWrapper';
@@ -0,0 +1,2 @@
1
+ export * from './Form';
2
+ export * from './FormComponentWrapper';
@@ -0,0 +1,37 @@
1
+ /// <reference types="react" />
2
+ import { ReactComponent } from '@formio/react';
3
+ import { Root } from 'react-dom/client';
4
+ interface ButtonComponentProps {
5
+ components: Button[];
6
+ }
7
+ declare type Button = {
8
+ action: 'cancel' | 'submit' | 'save-draft';
9
+ label: string;
10
+ onClick: (event?: any, setError?: (error?: Record<string, unknown>) => void, isSubmitting?: (val: boolean) => void) => void;
11
+ variant: 'contained' | 'outlined' | 'text';
12
+ style: any;
13
+ isModal: boolean;
14
+ };
15
+ declare type ButtonProps = {
16
+ button: any;
17
+ handleSubmit: (setSubmitting: (value: boolean) => void) => void;
18
+ handleCancel: (event: any) => void;
19
+ handleSaveDraft: (setSubmitting: (value: boolean) => void) => void;
20
+ setButtonKey: (value: string) => void;
21
+ };
22
+ export declare class ButtonComponent extends ReactComponent {
23
+ [x: string]: any;
24
+ component: ButtonComponentProps;
25
+ componentRoot?: Root;
26
+ constructor(component: ButtonComponentProps, options: any, data: any);
27
+ setError(error?: Record<string, unknown>): void;
28
+ getButton: (buttonAction: 'cancel' | 'submit' | 'save-draft') => Button | undefined;
29
+ handleCancel: (event: any) => void;
30
+ handleSaveDraft: (setSubmitting: (value: boolean) => void) => void;
31
+ handleSubmit: (setSubmitting: (value: boolean) => void) => void;
32
+ scrollIntoViewWithOffset: (el: any, offset: number) => void;
33
+ setButtonKey: (value: string) => void;
34
+ attachReact(element: Element): void;
35
+ }
36
+ declare const Button: (props: ButtonProps) => JSX.Element;
37
+ export {};