@evoke-platform/ui-components 1.13.0-dev.6 → 1.13.0
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/CriteriaBuilder/CriteriaBuilder.d.ts +4 -4
- package/dist/published/components/custom/CriteriaBuilder/CriteriaBuilder.js +72 -145
- package/dist/published/components/custom/CriteriaBuilder/CriteriaBuilder.test.js +67 -189
- package/dist/published/components/custom/CriteriaBuilder/PropertyTree.d.ts +6 -6
- package/dist/published/components/custom/CriteriaBuilder/PropertyTree.js +25 -12
- package/dist/published/components/custom/CriteriaBuilder/PropertyTreeItem.d.ts +5 -4
- package/dist/published/components/custom/CriteriaBuilder/PropertyTreeItem.js +22 -34
- package/dist/published/components/custom/CriteriaBuilder/types.d.ts +11 -2
- package/dist/published/components/custom/CriteriaBuilder/utils.d.ts +34 -6
- package/dist/published/components/custom/CriteriaBuilder/utils.js +89 -18
- package/dist/published/components/custom/Form/FormComponents/DocumentComponent/Document.js +1 -1
- package/dist/published/components/custom/Form/FormComponents/DocumentComponent/DocumentList.js +3 -6
- package/dist/published/components/custom/Form/FormComponents/RepeatableFieldComponent/RepeatableField.js +1 -1
- package/dist/published/components/custom/Form/utils.d.ts +0 -1
- package/dist/published/components/custom/FormField/DateTimePickerSelect/DateTimePickerSelect.js +1 -2
- package/dist/published/components/custom/FormV2/FormRenderer.d.ts +1 -1
- package/dist/published/components/custom/FormV2/FormRenderer.js +2 -1
- package/dist/published/components/custom/FormV2/FormRendererContainer.d.ts +3 -1
- package/dist/published/components/custom/FormV2/FormRendererContainer.js +23 -26
- package/dist/published/components/custom/FormV2/components/Body.js +1 -1
- package/dist/published/components/custom/FormV2/components/Footer.js +1 -1
- package/dist/published/components/custom/FormV2/components/FormContext.d.ts +0 -1
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/CollectionFiles/ActionDialog.d.ts +0 -1
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/CollectionFiles/RepeatableField.js +3 -3
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/DocumentFiles/Document.d.ts +2 -3
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/DocumentFiles/Document.js +10 -46
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/DocumentFiles/DocumentList.d.ts +3 -4
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/DocumentFiles/DocumentList.js +23 -29
- package/dist/published/components/custom/FormV2/components/FormFieldTypes/relatedObjectFiles/InstanceLookup.js +1 -1
- package/dist/published/components/custom/FormV2/components/FormSections.js +0 -1
- package/dist/published/components/custom/FormV2/components/Header.d.ts +1 -0
- package/dist/published/components/custom/FormV2/components/Header.js +19 -8
- package/dist/published/components/custom/FormV2/components/HtmlView.d.ts +9 -0
- package/dist/published/components/custom/FormV2/components/HtmlView.js +42 -0
- package/dist/published/components/custom/FormV2/components/RecursiveEntryRenderer.js +4 -8
- package/dist/published/components/custom/FormV2/components/types.d.ts +1 -6
- package/dist/published/components/custom/FormV2/components/utils.d.ts +7 -5
- package/dist/published/components/custom/FormV2/components/utils.js +79 -156
- package/dist/published/components/custom/FormV2/tests/FormRenderer.test.js +2 -2
- package/dist/published/components/custom/FormV2/tests/FormRendererContainer.test.js +84 -0
- package/dist/published/components/custom/HistoryLog/HistoryData.js +1 -2
- package/dist/published/components/custom/HistoryLog/index.js +1 -2
- package/dist/published/components/custom/ViewDetailsV2/InstanceEntryRenderer.js +10 -24
- package/dist/published/components/custom/ViewDetailsV2/ViewDetailsV2Container.d.ts +3 -0
- package/dist/published/components/custom/ViewDetailsV2/ViewDetailsV2Container.js +3 -1
- package/dist/published/stories/Backdrop.stories.d.ts +2 -2
- package/dist/published/stories/CriteriaBuilder.stories.js +22 -70
- package/dist/published/stories/FormLabel.stories.d.ts +2 -2
- package/dist/published/stories/FormRenderer.stories.d.ts +3 -3
- package/dist/published/stories/FormRendererContainer.stories.d.ts +15 -5
- package/dist/published/stories/ViewDetailsV2Container.stories.d.ts +9 -0
- package/dist/published/theme/hooks.d.ts +1 -2
- package/package.json +10 -15
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { TreeItemProps } from '@mui/x-tree-view';
|
|
2
2
|
import React from 'react';
|
|
3
|
-
import {
|
|
3
|
+
import { Obj } from '../../../types';
|
|
4
|
+
import { TreeItem } from './types';
|
|
4
5
|
type PropertyTreeItemProps = TreeItemProps & {
|
|
5
6
|
items: TreeItem[];
|
|
6
7
|
expanded: string[];
|
|
7
8
|
setExpanded: (expanded: string[]) => void;
|
|
8
|
-
updateNodeChildren: (nodeId: string, children:
|
|
9
|
-
fetchObject: (id: string) => Promise<
|
|
10
|
-
handleTreePropertySelect: (propertyId: string) => void
|
|
9
|
+
updateNodeChildren: (nodeId: string, children: TreeItem[]) => void;
|
|
10
|
+
fetchObject: (id: string) => Promise<Obj | undefined>;
|
|
11
|
+
handleTreePropertySelect: (propertyId: string) => Promise<void>;
|
|
11
12
|
};
|
|
12
13
|
export declare const PropertyTreeItem: (props: PropertyTreeItemProps) => React.JSX.Element;
|
|
13
14
|
export {};
|
|
@@ -11,47 +11,35 @@ export const PropertyTreeItem = (props) => {
|
|
|
11
11
|
return;
|
|
12
12
|
}
|
|
13
13
|
const item = findTreeItemById(items, itemId);
|
|
14
|
-
if (item?.type === '
|
|
15
|
-
e.stopPropagation();
|
|
16
|
-
return;
|
|
17
|
-
}
|
|
18
|
-
if (item?.children) {
|
|
14
|
+
if (item?.type === 'object') {
|
|
19
15
|
e.stopPropagation();
|
|
20
16
|
// If the item has an associated "objectId", fetch the properties of the object and expand the item.
|
|
21
|
-
if (item?.type === '
|
|
22
|
-
item.objectId
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
updateNodeChildren(itemId, [
|
|
42
|
-
{
|
|
43
|
-
id: `${itemId}-failed`,
|
|
44
|
-
name: 'Loading Failed',
|
|
45
|
-
type: 'loadingFailed',
|
|
46
|
-
},
|
|
47
|
-
]);
|
|
48
|
-
console.error('Error fetching object:', error);
|
|
17
|
+
if (item.objectId && item.children?.length === 1 && item.children[0].type === 'loading') {
|
|
18
|
+
const object = item.objectId ? await fetchObject(item.objectId) : undefined;
|
|
19
|
+
if (object) {
|
|
20
|
+
updateNodeChildren(itemId, (object.properties ?? []).map((prop) => ({
|
|
21
|
+
id: `${itemId}.${prop.id}`,
|
|
22
|
+
label: prop.name,
|
|
23
|
+
value: `${itemId}.${prop.id}`,
|
|
24
|
+
type: prop.type,
|
|
25
|
+
objectId: prop.objectId,
|
|
26
|
+
children: prop.type === 'object'
|
|
27
|
+
? [
|
|
28
|
+
{
|
|
29
|
+
id: `${itemId}.${prop.id}-loading`,
|
|
30
|
+
label: 'Loading...',
|
|
31
|
+
value: `${itemId}.${prop.id}-loading`,
|
|
32
|
+
type: 'loading',
|
|
33
|
+
},
|
|
34
|
+
]
|
|
35
|
+
: undefined,
|
|
36
|
+
})));
|
|
49
37
|
}
|
|
50
38
|
}
|
|
51
39
|
setExpanded([...expanded, itemId]);
|
|
52
40
|
return;
|
|
53
41
|
}
|
|
54
|
-
handleTreePropertySelect(itemId);
|
|
42
|
+
await handleTreePropertySelect(itemId);
|
|
55
43
|
};
|
|
56
44
|
return React.createElement(RichTreeItem, { itemId: itemId, label: label, children: children, onClick: onClick });
|
|
57
45
|
};
|
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
|
-
import { Property } from '@evoke-platform/context';
|
|
3
2
|
import { BaseSelectorProps } from 'react-querybuilder';
|
|
4
3
|
import { ExpandedProperty } from '../../../types';
|
|
5
4
|
import { AutocompleteOption, TreeViewBaseItem } from '../../core';
|
|
5
|
+
export type ObjectProperty = {
|
|
6
|
+
id: string;
|
|
7
|
+
name: string;
|
|
8
|
+
type: string;
|
|
9
|
+
enum?: string[];
|
|
10
|
+
required?: boolean;
|
|
11
|
+
searchable?: boolean;
|
|
12
|
+
objectId?: string;
|
|
13
|
+
formula?: string;
|
|
14
|
+
};
|
|
6
15
|
export type CustomSelectorProps = BaseSelectorProps & {
|
|
7
16
|
options: AutocompleteOption[] | any[];
|
|
8
17
|
fieldData?: Record<string, any>;
|
|
@@ -19,7 +28,7 @@ export type PresetValue = {
|
|
|
19
28
|
};
|
|
20
29
|
type?: string;
|
|
21
30
|
};
|
|
22
|
-
export type TreeViewProperty =
|
|
31
|
+
export type TreeViewProperty = ObjectProperty & {
|
|
23
32
|
children?: TreeViewProperty[];
|
|
24
33
|
};
|
|
25
34
|
export type TreeViewObject = {
|
|
@@ -1,16 +1,43 @@
|
|
|
1
1
|
import { Property } from '@evoke-platform/context';
|
|
2
2
|
import { RuleGroupType } from 'react-querybuilder';
|
|
3
|
-
import {
|
|
3
|
+
import { Obj, ObjectProperty } from '../../../types';
|
|
4
|
+
import { TreeItem } from './types';
|
|
4
5
|
/**
|
|
5
6
|
* Recursively updates a node in a tree structure by applying an updater function to the node with the specified ID.
|
|
6
7
|
*
|
|
7
|
-
* @param {
|
|
8
|
+
* @param {TreeItem[]} tree - The tree structure to update.
|
|
8
9
|
* @param {string} nodeId - The ID of the node to update.
|
|
9
|
-
* @param {(node:
|
|
10
|
-
* @returns {
|
|
10
|
+
* @param {(node: TreeItem) => TreeItem} updater - The function to apply to the node.
|
|
11
|
+
* @returns {TreeItem[]} - The updated tree structure.
|
|
11
12
|
*/
|
|
12
|
-
export declare const
|
|
13
|
-
|
|
13
|
+
export declare const updateTreeNode: (tree: TreeItem[], nodeId: string, updater: (node: TreeItem) => TreeItem) => TreeItem[];
|
|
14
|
+
type FetchObjectFunction = (id: string) => Promise<Obj | undefined>;
|
|
15
|
+
/**
|
|
16
|
+
* Fetches the display name path for a given property ID within an object hierarchy.
|
|
17
|
+
*
|
|
18
|
+
* @param {string} propertyId - The property ID to find the display name for.
|
|
19
|
+
* @param {Obj} rootObject - The root object to start the search from.
|
|
20
|
+
* @param {FetchObjectFunction} fetchObject - Function to fetch an object by its ID.
|
|
21
|
+
* @returns {Promise<string>} - A promise that resolves to the display name path.
|
|
22
|
+
*/
|
|
23
|
+
export declare const fetchDisplayNamePath: (propertyId: string, rootObject: Obj, fetchObject: FetchObjectFunction) => Promise<string>;
|
|
24
|
+
/**
|
|
25
|
+
* stores full dot-notation path to each property ID in the given array of properties.
|
|
26
|
+
*
|
|
27
|
+
* @param {ObjectProperty[]} properties - The array of properties to update.
|
|
28
|
+
* @param {string} parentPath - The parent path to attach to each property ID.
|
|
29
|
+
* @returns {ObjectProperty[]} The updated array of properties with the parent path attached to each property ID.
|
|
30
|
+
*/
|
|
31
|
+
export declare const setIdPaths: (properties: ObjectProperty[], parentPath: string) => ObjectProperty[];
|
|
32
|
+
/**
|
|
33
|
+
* Traverses a property path within an object hierarchy to retrieve detailed property information.
|
|
34
|
+
*
|
|
35
|
+
* @param {string} propertyPath - The dot-separated path of the property to traverse.
|
|
36
|
+
* @param {Obj} rootObject - The root object from which to start the traversal.
|
|
37
|
+
* @param {FetchObjectFunction} fetchObject - A function to fetch an object by its ID.
|
|
38
|
+
* @returns {Promise<ObjectProperty | null>} A promise that resolves to an ObjectProperty if found, or null otherwise.
|
|
39
|
+
*/
|
|
40
|
+
export declare const traversePropertyPath: (propertyPath: string, rootObject: Obj, fetchObject: (objectId: string) => Promise<Obj | undefined>) => Promise<ObjectProperty | null>;
|
|
14
41
|
/**
|
|
15
42
|
* Truncates the name path if it exceeds the specified character limit.
|
|
16
43
|
*
|
|
@@ -41,3 +68,4 @@ export declare const ALL_OPERATORS: {
|
|
|
41
68
|
*/
|
|
42
69
|
export declare const getReadableQuery: (mongoQuery?: Record<string, unknown>, properties?: Property[]) => string;
|
|
43
70
|
export declare const findTreeItemById: (nodes: TreeItem[], nodeId: string) => TreeItem | null;
|
|
71
|
+
export {};
|
|
@@ -2,32 +2,105 @@ import { isArray, isEmpty, startCase } from 'lodash';
|
|
|
2
2
|
/**
|
|
3
3
|
* Recursively updates a node in a tree structure by applying an updater function to the node with the specified ID.
|
|
4
4
|
*
|
|
5
|
-
* @param {
|
|
5
|
+
* @param {TreeItem[]} tree - The tree structure to update.
|
|
6
6
|
* @param {string} nodeId - The ID of the node to update.
|
|
7
|
-
* @param {(node:
|
|
8
|
-
* @returns {
|
|
7
|
+
* @param {(node: TreeItem) => TreeItem} updater - The function to apply to the node.
|
|
8
|
+
* @returns {TreeItem[]} - The updated tree structure.
|
|
9
9
|
*/
|
|
10
|
-
export const
|
|
10
|
+
export const updateTreeNode = (tree, nodeId, updater) => {
|
|
11
11
|
return tree.map((node) => {
|
|
12
12
|
if (node.id === nodeId) {
|
|
13
13
|
return updater(node);
|
|
14
14
|
}
|
|
15
15
|
else if (node.children) {
|
|
16
|
-
return { ...node, children:
|
|
16
|
+
return { ...node, children: updateTreeNode(node.children, nodeId, updater) };
|
|
17
17
|
}
|
|
18
18
|
else {
|
|
19
19
|
return node;
|
|
20
20
|
}
|
|
21
21
|
});
|
|
22
22
|
};
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
23
|
+
/**
|
|
24
|
+
* Fetches the display name path for a given property ID within an object hierarchy.
|
|
25
|
+
*
|
|
26
|
+
* @param {string} propertyId - The property ID to find the display name for.
|
|
27
|
+
* @param {Obj} rootObject - The root object to start the search from.
|
|
28
|
+
* @param {FetchObjectFunction} fetchObject - Function to fetch an object by its ID.
|
|
29
|
+
* @returns {Promise<string>} - A promise that resolves to the display name path.
|
|
30
|
+
*/
|
|
31
|
+
export const fetchDisplayNamePath = async (propertyId, rootObject, fetchObject) => {
|
|
32
|
+
const propertyInfo = await traversePropertyPath(propertyId, rootObject, fetchObject);
|
|
33
|
+
return propertyInfo ? propertyInfo.name : '';
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* stores full dot-notation path to each property ID in the given array of properties.
|
|
37
|
+
*
|
|
38
|
+
* @param {ObjectProperty[]} properties - The array of properties to update.
|
|
39
|
+
* @param {string} parentPath - The parent path to attach to each property ID.
|
|
40
|
+
* @returns {ObjectProperty[]} The updated array of properties with the parent path attached to each property ID.
|
|
41
|
+
*/
|
|
42
|
+
export const setIdPaths = (properties, parentPath) => {
|
|
43
|
+
return properties.map((prop) => {
|
|
44
|
+
const fullPath = parentPath ? `${parentPath}.${prop.id}` : prop.id;
|
|
45
|
+
return {
|
|
46
|
+
...prop,
|
|
47
|
+
id: fullPath,
|
|
48
|
+
};
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Traverses a property path within an object hierarchy to retrieve detailed property information.
|
|
53
|
+
*
|
|
54
|
+
* @param {string} propertyPath - The dot-separated path of the property to traverse.
|
|
55
|
+
* @param {Obj} rootObject - The root object from which to start the traversal.
|
|
56
|
+
* @param {FetchObjectFunction} fetchObject - A function to fetch an object by its ID.
|
|
57
|
+
* @returns {Promise<ObjectProperty | null>} A promise that resolves to an ObjectProperty if found, or null otherwise.
|
|
58
|
+
*/
|
|
59
|
+
export const traversePropertyPath = async (propertyPath, rootObject, fetchObject) => {
|
|
60
|
+
const segments = propertyPath.split('.');
|
|
61
|
+
let currentObject = rootObject;
|
|
62
|
+
let fullPath = '';
|
|
63
|
+
let namePath = '';
|
|
64
|
+
for (let i = 0; i < segments.length; i++) {
|
|
65
|
+
const remainingPath = segments.slice(i).join('.');
|
|
66
|
+
let prop = currentObject.properties?.find((p) => p.id === remainingPath);
|
|
67
|
+
if (prop) {
|
|
68
|
+
// flattened address or user properties
|
|
69
|
+
fullPath = fullPath ? `${fullPath}.${remainingPath}` : remainingPath;
|
|
70
|
+
namePath = namePath ? `${namePath} / ${prop.name}` : prop.name;
|
|
71
|
+
return {
|
|
72
|
+
...prop,
|
|
73
|
+
id: fullPath,
|
|
74
|
+
name: namePath,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
prop = currentObject.properties?.find((p) => p.id === segments[i]);
|
|
79
|
+
if (!prop) {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
fullPath = fullPath ? `${fullPath}.${prop.id}` : prop.id;
|
|
83
|
+
namePath = namePath ? `${namePath} / ${prop.name}` : prop.name;
|
|
84
|
+
if (i === segments.length - 1) {
|
|
85
|
+
return {
|
|
86
|
+
...prop,
|
|
87
|
+
id: fullPath,
|
|
88
|
+
name: namePath,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
if (prop.type === 'object' && prop.objectId) {
|
|
92
|
+
const fetchedObject = await fetchObject(prop.objectId);
|
|
93
|
+
if (fetchedObject) {
|
|
94
|
+
currentObject = fetchedObject;
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return null;
|
|
103
|
+
};
|
|
31
104
|
/**
|
|
32
105
|
* Truncates the name path if it exceeds the specified character limit.
|
|
33
106
|
*
|
|
@@ -270,11 +343,9 @@ export const findTreeItemById = (nodes, nodeId) => {
|
|
|
270
343
|
for (const node of nodes) {
|
|
271
344
|
if (node.id === nodeId)
|
|
272
345
|
return node;
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
return found;
|
|
277
|
-
}
|
|
346
|
+
const found = node.children && findTreeItemById(node.children, nodeId);
|
|
347
|
+
if (found)
|
|
348
|
+
return found;
|
|
278
349
|
}
|
|
279
350
|
return null;
|
|
280
351
|
};
|
|
@@ -43,7 +43,7 @@ export const Document = (props) => {
|
|
|
43
43
|
// For 'file' type properties, check permissions on the sys__file object
|
|
44
44
|
// For 'document' type properties, check document attachment permissions
|
|
45
45
|
const endpoint = property.type === 'file'
|
|
46
|
-
? getPrefixedUrl(
|
|
46
|
+
? getPrefixedUrl(`/objects/sys__file/instances/${instance.id}/checkAccess?action=update`)
|
|
47
47
|
: getPrefixedUrl(`/objects/${objectId}/instances/${instance.id}/documents/checkAccess?action=update`);
|
|
48
48
|
apiServices
|
|
49
49
|
.get(endpoint)
|
package/dist/published/components/custom/Form/FormComponents/DocumentComponent/DocumentList.js
CHANGED
|
@@ -64,15 +64,12 @@ export const DocumentList = (props) => {
|
|
|
64
64
|
}, []);
|
|
65
65
|
const checkPermissions = () => {
|
|
66
66
|
if (instance?.[property.id]?.length) {
|
|
67
|
-
// For 'file' type properties, check
|
|
67
|
+
// For 'file' type properties, check permissions on the sys__file object
|
|
68
68
|
// For 'document' type properties, check document attachment permissions
|
|
69
69
|
const endpoint = property.type === 'file'
|
|
70
|
-
? getPrefixedUrl(`/objects/sys__file/instances/checkAccess?action=
|
|
70
|
+
? getPrefixedUrl(`/objects/sys__file/instances/${instance.id}/checkAccess?action=view`)
|
|
71
71
|
: getPrefixedUrl(`/objects/${objectId}/instances/${instance.id}/documents/checkAccess?action=view`);
|
|
72
|
-
apiServices
|
|
73
|
-
.get(endpoint)
|
|
74
|
-
.then((accessCheck) => setHasViewPermission(accessCheck.result))
|
|
75
|
-
.catch(() => setHasViewPermission(false));
|
|
72
|
+
apiServices.get(endpoint).then((accessCheck) => setHasViewPermission(accessCheck.result));
|
|
76
73
|
}
|
|
77
74
|
};
|
|
78
75
|
const isFile = (doc) => doc instanceof File;
|
|
@@ -402,7 +402,7 @@ const RepeatableField = (props) => {
|
|
|
402
402
|
React.createElement(Table, { stickyHeader: true, sx: { minWidth: 650 } },
|
|
403
403
|
React.createElement(TableHead, { sx: { backgroundColor: '#F4F6F8' } },
|
|
404
404
|
React.createElement(TableRow, null,
|
|
405
|
-
columns?.map((prop) => React.createElement(TableCell, { sx: styles.tableCell }, prop.name)),
|
|
405
|
+
columns?.map((prop) => (React.createElement(TableCell, { sx: styles.tableCell }, prop.name))),
|
|
406
406
|
canUpdateProperty && React.createElement(TableCell, { sx: { ...styles.tableCell, width: '80px' } }))),
|
|
407
407
|
React.createElement(TableBody, null, relatedInstances?.map((relatedInstance, index) => (React.createElement(TableRow, { key: relatedInstance.id },
|
|
408
408
|
columns?.map((prop) => {
|
|
@@ -25,7 +25,6 @@ export declare function flattenFormComponents(components?: ActionInput[]): Actio
|
|
|
25
25
|
export declare function addObjectPropertiesToComponentProps(properties: Property[], formComponents: any[], allCriteriaInputs?: string[], instance?: ObjectInstance, objectPropertyInputProps?: ObjectPropertyInputProps, associatedObject?: {
|
|
26
26
|
instanceId?: string;
|
|
27
27
|
propertyId?: string;
|
|
28
|
-
objectId?: string;
|
|
29
28
|
}, autoSave?: (data: Record<string, unknown>) => void, readOnly?: boolean, defaultPages?: Record<string, string>, navigateTo?: (path: string) => void, queryAddresses?: (query: string) => Promise<Address[]>, apiServices?: ApiServices, isModal?: boolean, fieldHeight?: 'small' | 'medium', richTextEditor?: typeof ReactComponent): Promise<ActionInput[]>;
|
|
30
29
|
export declare function getDefaultValue(initialValue: unknown, selectOptions?: AutocompleteOption[]): unknown;
|
|
31
30
|
export declare const buildComponentPropsFromObjectProperties: (properties: Property[], objectId: string, instance?: ObjectInstance, objectPropertyInputProps?: ObjectPropertyInputProps, hasActionPermissions?: boolean, autoSave?: ((data: Record<string, unknown>) => void) | undefined, readOnly?: boolean, queryAddresses?: ((query: string) => Promise<Address[]>) | undefined, isModal?: boolean, fieldHeight?: 'small' | 'medium', richTextEditor?: typeof ReactComponent) => unknown[];
|
package/dist/published/components/custom/FormField/DateTimePickerSelect/DateTimePickerSelect.js
CHANGED
|
@@ -5,8 +5,7 @@ import { useFormContext } from '../../../../theme/hooks';
|
|
|
5
5
|
import { InvalidDate } from '../../../../util';
|
|
6
6
|
import { DateTimePicker, LocalizationProvider, TextField } from '../../../core';
|
|
7
7
|
import InputFieldComponent from '../InputFieldComponent/InputFieldComponent';
|
|
8
|
-
|
|
9
|
-
const { format } = require('small-date');
|
|
8
|
+
import { format } from 'small-date';
|
|
10
9
|
function asCalendarDate(value) {
|
|
11
10
|
if (!value) {
|
|
12
11
|
return null;
|
|
@@ -12,6 +12,7 @@ export type FormRendererProps = BaseProps & {
|
|
|
12
12
|
onSubmit?: (data: FieldValues) => void;
|
|
13
13
|
onDiscardChanges?: () => void;
|
|
14
14
|
onSubmitError?: SubmitErrorHandler<FieldValues>;
|
|
15
|
+
hideTitle?: boolean;
|
|
15
16
|
fieldHeight?: 'small' | 'medium';
|
|
16
17
|
form: EvokeForm;
|
|
17
18
|
title?: string | React.ReactNode;
|
|
@@ -21,7 +22,6 @@ export type FormRendererProps = BaseProps & {
|
|
|
21
22
|
associatedObject?: {
|
|
22
23
|
instanceId: string;
|
|
23
24
|
propertyId: string;
|
|
24
|
-
objectId?: string;
|
|
25
25
|
};
|
|
26
26
|
renderHeader?: (props: HeaderProps) => React.ReactNode;
|
|
27
27
|
renderBody?: (props: BodyProps) => React.ReactNode;
|
|
@@ -12,7 +12,7 @@ import { assignIdsToSectionsAndRichText, convertPropertiesToParams, entryIsVisib
|
|
|
12
12
|
import { handleValidation } from './components/ValidationFiles/Validation';
|
|
13
13
|
import ValidationErrors from './components/ValidationFiles/ValidationErrors';
|
|
14
14
|
const FormRendererInternal = (props) => {
|
|
15
|
-
const { onSubmit, onDiscardChanges, onSubmitError: onSubmitErrorOverride, value, fieldHeight, richTextEditor, form, instance, onChange, onAutosave, associatedObject, renderHeader, renderBody, renderFooter, } = props;
|
|
15
|
+
const { onSubmit, onDiscardChanges, onSubmitError: onSubmitErrorOverride, value, hideTitle = false, fieldHeight, richTextEditor, form, instance, onChange, onAutosave, associatedObject, renderHeader, renderBody, renderFooter, } = props;
|
|
16
16
|
const { entries, name: title, objectId, actionId, display } = form;
|
|
17
17
|
const { register, unregister, setValue, reset, handleSubmit, formState: { errors, isSubmitted }, getValues, } = useForm({
|
|
18
18
|
defaultValues: value,
|
|
@@ -177,6 +177,7 @@ const FormRendererInternal = (props) => {
|
|
|
177
177
|
}, (errors) => onSubmitError(errors))();
|
|
178
178
|
}
|
|
179
179
|
const headerProps = {
|
|
180
|
+
hideTitle,
|
|
180
181
|
title,
|
|
181
182
|
onExpandAll: handleExpandAll,
|
|
182
183
|
onCollapseAll: handleCollapseAll,
|
|
@@ -19,6 +19,9 @@ export type FormRendererContainerProps = BaseProps & {
|
|
|
19
19
|
defaultPages?: Record<string, string>;
|
|
20
20
|
pageNavigation?: string;
|
|
21
21
|
dataType?: 'objectInstances';
|
|
22
|
+
title?: {
|
|
23
|
+
hidden?: boolean;
|
|
24
|
+
};
|
|
22
25
|
display?: {
|
|
23
26
|
fieldHeight?: 'small' | 'medium';
|
|
24
27
|
};
|
|
@@ -31,7 +34,6 @@ export type FormRendererContainerProps = BaseProps & {
|
|
|
31
34
|
associatedObject?: {
|
|
32
35
|
instanceId: string;
|
|
33
36
|
propertyId: string;
|
|
34
|
-
objectId?: string;
|
|
35
37
|
};
|
|
36
38
|
renderContainer?: (state: FormRendererState) => React.ReactNode;
|
|
37
39
|
renderHeader?: FormRendererProps['renderHeader'];
|
|
@@ -10,7 +10,7 @@ import Header from './components/Header';
|
|
|
10
10
|
import { convertPropertiesToParams, createFileLinks, deleteDocuments, encodePageSlug, formatSubmission, getEntryId, getPrefixedUrl, getUnnestedEntries, isAddressProperty, isEmptyWithDefault, plainTextToRtf, } from './components/utils';
|
|
11
11
|
import FormRenderer from './FormRenderer';
|
|
12
12
|
function FormRendererContainer(props) {
|
|
13
|
-
const { instanceId, pageNavigation, dataType, display, formId, objectId, actionId, richTextEditor, onSubmit, onDiscardChanges: onDiscardChangesOverride, associatedObject, renderContainer, onSubmitError, sx, renderHeader, renderBody, renderFooter, } = props;
|
|
13
|
+
const { instanceId, pageNavigation, dataType, title, display, formId, objectId, actionId, richTextEditor, onSubmit, onDiscardChanges: onDiscardChangesOverride, associatedObject, renderContainer, onSubmitError, sx, renderHeader, renderBody, renderFooter, } = props;
|
|
14
14
|
const apiServices = useApiServices();
|
|
15
15
|
const navigateTo = useNavigate();
|
|
16
16
|
const { id: appId } = useApp();
|
|
@@ -158,7 +158,7 @@ function FormRendererContainer(props) {
|
|
|
158
158
|
});
|
|
159
159
|
if (navigationSlug) {
|
|
160
160
|
if (navigationSlug.includes(':instanceId')) {
|
|
161
|
-
const navigateInstanceId = action?.type === 'create' ? updatedInstance
|
|
161
|
+
const navigateInstanceId = action?.type === 'create' ? updatedInstance?.id : instanceId;
|
|
162
162
|
navigateTo(`/${appId}/${navigationSlug.replace(':instanceId', navigateInstanceId ?? ':instanceId')}`);
|
|
163
163
|
}
|
|
164
164
|
else {
|
|
@@ -167,17 +167,18 @@ function FormRendererContainer(props) {
|
|
|
167
167
|
}
|
|
168
168
|
setInstance(updatedInstance);
|
|
169
169
|
};
|
|
170
|
-
/**
|
|
171
|
-
* Manually links any newly uploaded files in the submission to the specified instance.
|
|
172
|
-
* @param submission The form submission data
|
|
173
|
-
* @param linkTo The instance to link the files to
|
|
174
|
-
*/
|
|
175
170
|
const linkFiles = async (submission, linkTo) => {
|
|
176
|
-
// Create file links for any uploaded files
|
|
171
|
+
// Create file links for any uploaded files after instance creation
|
|
177
172
|
for (const property of sanitizedObject?.properties?.filter((property) => property.type === 'file') ?? []) {
|
|
178
173
|
const files = submission[property.id];
|
|
179
174
|
if (files?.length) {
|
|
180
|
-
|
|
175
|
+
try {
|
|
176
|
+
await createFileLinks(files, linkTo, apiServices);
|
|
177
|
+
}
|
|
178
|
+
catch (error) {
|
|
179
|
+
console.error('Failed to create file links:', error);
|
|
180
|
+
// Don't fail the entire submission if file linking fails
|
|
181
|
+
}
|
|
181
182
|
}
|
|
182
183
|
}
|
|
183
184
|
};
|
|
@@ -194,9 +195,11 @@ function FormRendererContainer(props) {
|
|
|
194
195
|
?.filter((property) => property.formula || property.type === 'collection')
|
|
195
196
|
.map((property) => property.id) ?? []),
|
|
196
197
|
});
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
198
|
+
if (response) {
|
|
199
|
+
// Manually link files to created instance.
|
|
200
|
+
await linkFiles(submission, { id: response.id, objectId: form.objectId });
|
|
201
|
+
onSubmissionSuccess(response);
|
|
202
|
+
}
|
|
200
203
|
}
|
|
201
204
|
else if (instanceId && action) {
|
|
202
205
|
const response = await objectStore.instanceAction(instanceId, {
|
|
@@ -206,26 +209,21 @@ function FormRendererContainer(props) {
|
|
|
206
209
|
.map((property) => property.id) ?? []),
|
|
207
210
|
});
|
|
208
211
|
if (sanitizedObject && instance) {
|
|
209
|
-
if (!onAutosave) {
|
|
210
|
-
// For non-autosave updates, link any uploaded files to the instance.
|
|
211
|
-
await linkFiles(submission, { id: instanceId, objectId: objectId });
|
|
212
|
-
}
|
|
213
212
|
onSubmissionSuccess(response);
|
|
214
|
-
|
|
215
|
-
await deleteDocuments(submission, true, apiServices, sanitizedObject, instance, action, setSnackbarError);
|
|
213
|
+
deleteDocuments(submission, true, apiServices, sanitizedObject, instance, action, setSnackbarError);
|
|
216
214
|
}
|
|
217
215
|
}
|
|
218
216
|
}
|
|
219
217
|
catch (error) {
|
|
218
|
+
// Handle deleteDocuments for uploaded documents if the main submission fails
|
|
219
|
+
if (instanceId && action && sanitizedObject && instance) {
|
|
220
|
+
deleteDocuments(submission, false, apiServices, sanitizedObject, instance, action, setSnackbarError);
|
|
221
|
+
}
|
|
220
222
|
setSnackbarError({
|
|
221
223
|
isError: true,
|
|
222
224
|
showAlert: true,
|
|
223
225
|
message: error.response?.data?.error?.message ?? 'An error occurred',
|
|
224
226
|
});
|
|
225
|
-
if (instanceId && action && sanitizedObject && instance) {
|
|
226
|
-
// For an update, uploaded documents have been linked to the instance and need to be deleted.
|
|
227
|
-
await deleteDocuments(submission, false, apiServices, sanitizedObject, instance, action, setSnackbarError);
|
|
228
|
-
}
|
|
229
227
|
throw error; // Throw error so caller knows submission failed
|
|
230
228
|
}
|
|
231
229
|
};
|
|
@@ -257,10 +255,10 @@ function FormRendererContainer(props) {
|
|
|
257
255
|
const parameter = parameters?.find((param) => param.id === fieldId);
|
|
258
256
|
if (associatedObject?.propertyId === fieldId &&
|
|
259
257
|
associatedObject?.instanceId &&
|
|
260
|
-
|
|
258
|
+
parameter &&
|
|
261
259
|
action?.type === 'create') {
|
|
262
260
|
try {
|
|
263
|
-
const instance = await apiServices.get(getPrefixedUrl(`/objects/${parameter
|
|
261
|
+
const instance = await apiServices.get(getPrefixedUrl(`/objects/${parameter.objectId}/instances/${associatedObject.instanceId}`));
|
|
264
262
|
result[associatedObject.propertyId] = instance;
|
|
265
263
|
}
|
|
266
264
|
catch (error) {
|
|
@@ -338,7 +336,6 @@ function FormRendererContainer(props) {
|
|
|
338
336
|
?.filter((property) => !property.formula && property.type !== 'collection')
|
|
339
337
|
.map((property) => property.id) ?? []),
|
|
340
338
|
});
|
|
341
|
-
await linkFiles(submission, { id: instanceId, objectId });
|
|
342
339
|
}
|
|
343
340
|
setLastSavedData(cloneDeep(formDataRef.current));
|
|
344
341
|
setIsSaving(false);
|
|
@@ -401,7 +398,7 @@ function FormRendererContainer(props) {
|
|
|
401
398
|
border: !isLoading ? '1px solid #dbe0e4' : undefined,
|
|
402
399
|
...sx,
|
|
403
400
|
} }, !isLoading ? (React.createElement(React.Fragment, null,
|
|
404
|
-
React.createElement(FormRenderer, { onSubmit: onSubmit ? (data) => onSubmit(data, saveHandler) : saveHandler, onSubmitError: onSubmitError, onDiscardChanges: onDiscardChanges, richTextEditor: richTextEditor, fieldHeight: display?.fieldHeight ?? 'medium', value: formDataRef.current, form: form, instance: instance, onChange: onChange, onAutosave: onAutosave, associatedObject: associatedObject, renderHeader: composedRenderHeader, renderBody: renderBody, renderFooter: renderFooter }))) : (React.createElement(Box, { sx: { padding: '20px' } },
|
|
401
|
+
React.createElement(FormRenderer, { onSubmit: onSubmit ? (data) => onSubmit(data, saveHandler) : saveHandler, onSubmitError: onSubmitError, onDiscardChanges: onDiscardChanges, richTextEditor: richTextEditor, hideTitle: title?.hidden, fieldHeight: display?.fieldHeight ?? 'medium', value: formDataRef.current, form: form, instance: instance, onChange: onChange, onAutosave: onAutosave, associatedObject: associatedObject, renderHeader: composedRenderHeader, renderBody: renderBody, renderFooter: renderFooter }))) : (React.createElement(Box, { sx: { padding: '20px' } },
|
|
405
402
|
React.createElement(Box, { display: 'flex', width: '100%', justifyContent: 'space-between' },
|
|
406
403
|
React.createElement(Skeleton, { width: '78%', sx: { borderRadius: '8px', height: '40px' } }),
|
|
407
404
|
React.createElement(Skeleton, { width: '20%', sx: { borderRadius: '8px', height: '40px' } })),
|
|
@@ -22,6 +22,6 @@ export const Body = (props) => {
|
|
|
22
22
|
React.createElement(Skeleton, { width: '32%', sx: { borderRadius: '8px', height: '40px' } })),
|
|
23
23
|
React.createElement(Box, { display: 'flex', width: '100%', justifyContent: 'space-between' },
|
|
24
24
|
React.createElement(Skeleton, { width: '49%', sx: { borderRadius: '8px', height: '40px' } }),
|
|
25
|
-
React.createElement(Skeleton, { width: '49%', sx: { borderRadius: '8px', height: '40px' } })))) : (React.createElement(Box, { sx: { paddingX: isSm || isXs ? 2 : 3, ...sx } }, entries.map((entry, index) => (React.createElement(RecursiveEntryRenderer, { key: index, entry: entry })))))));
|
|
25
|
+
React.createElement(Skeleton, { width: '49%', sx: { borderRadius: '8px', height: '40px' } })))) : (React.createElement(Box, { sx: { paddingX: isSm || isXs ? 2 : 3, paddingY: isSm || isXs ? '6px' : '14px', ...sx } }, entries.map((entry, index) => (React.createElement(RecursiveEntryRenderer, { key: index, entry: entry })))))));
|
|
26
26
|
};
|
|
27
27
|
export default Body;
|
|
@@ -20,7 +20,7 @@ export const Footer = (props) => {
|
|
|
20
20
|
padding: isSmallerThanMd ? '16px' : '20px',
|
|
21
21
|
justifyContent: isXs ? 'center' : 'flex-end',
|
|
22
22
|
alignItems: 'center',
|
|
23
|
-
borderTop: '1px solid #
|
|
23
|
+
borderTop: '1px solid #e9ecef',
|
|
24
24
|
borderRadius: '0px 0px 6px 6px',
|
|
25
25
|
zIndex: 3,
|
|
26
26
|
width: '100%',
|
|
@@ -9,7 +9,7 @@ import { Accordion, AccordionDetails, AccordionSummary, Button, IconButton, Skel
|
|
|
9
9
|
import { Box } from '../../../../../layout';
|
|
10
10
|
import { getReadableQuery } from '../../../../CriteriaBuilder';
|
|
11
11
|
import { retrieveCustomErrorMessage } from '../../../../Form/utils';
|
|
12
|
-
import {
|
|
12
|
+
import { deleteDocuments, formatSubmission, getPrefixedUrl, transformToWhere } from '../../utils';
|
|
13
13
|
import { ActionDialog } from './ActionDialog';
|
|
14
14
|
import { DocumentViewerCell } from './DocumentViewerCell';
|
|
15
15
|
const styles = {
|
|
@@ -344,7 +344,7 @@ const RepeatableField = (props) => {
|
|
|
344
344
|
// when save is called we know that fieldDefinition is a parameter and fieldDefinition.objectId is defined
|
|
345
345
|
input = await formatSubmission(input, apiServices, fieldDefinition.objectId, selectedInstanceId, action?.type === 'update' ? updateForm : undefined, undefined, instance?.id && fieldDefinition.relatedPropertyId
|
|
346
346
|
? { instanceId: instance.id, propertyId: fieldDefinition.relatedPropertyId }
|
|
347
|
-
: undefined
|
|
347
|
+
: undefined);
|
|
348
348
|
if (action?.type === 'create' && entry.display?.createActionId) {
|
|
349
349
|
const updatedInput = {
|
|
350
350
|
...input,
|
|
@@ -529,7 +529,7 @@ const RepeatableField = (props) => {
|
|
|
529
529
|
React.createElement(Table, { stickyHeader: true, sx: { minWidth: 650 } },
|
|
530
530
|
React.createElement(TableHead, { sx: { backgroundColor: '#F4F6F8' } },
|
|
531
531
|
React.createElement(TableRow, null,
|
|
532
|
-
columns?.map((prop) => React.createElement(TableCell, { sx: styles.tableCell }, prop.name)),
|
|
532
|
+
columns?.map((prop) => (React.createElement(TableCell, { sx: styles.tableCell }, prop.name))),
|
|
533
533
|
canUpdateProperty && React.createElement(TableCell, { sx: { ...styles.tableCell, width: '80px' } }))),
|
|
534
534
|
React.createElement(TableBody, null, relatedInstances?.map((relatedInstance, index) => (React.createElement(TableRow, { key: relatedInstance.id },
|
|
535
535
|
columns?.map((prop) => {
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import { DocumentParameterValidation } from '@evoke-platform/context';
|
|
2
2
|
import React from 'react';
|
|
3
|
-
import {
|
|
3
|
+
import { SavedDocumentReference } from '../../types';
|
|
4
4
|
type DocumentProps = {
|
|
5
5
|
id: string;
|
|
6
|
-
fieldType?: 'file' | 'document';
|
|
7
6
|
canUpdateProperty: boolean;
|
|
8
7
|
error: boolean;
|
|
9
8
|
validate?: DocumentParameterValidation;
|
|
10
|
-
value: (File |
|
|
9
|
+
value: (File | SavedDocumentReference)[] | undefined;
|
|
11
10
|
hasDescription?: boolean;
|
|
12
11
|
};
|
|
13
12
|
export declare const Document: (props: DocumentProps) => React.JSX.Element;
|