@reltio/components 1.4.2205 → 1.4.2207
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/cjs/contexts/WorkflowTasksContext/index.d.ts +1 -0
- package/cjs/features/workflow/ChangeRequestEditor/components/ChangeItemEditor/ChangeItemEditor.js +12 -9
- package/cjs/features/workflow/ChangeRequestEditor/helpers/helpers.d.ts +2 -1
- package/cjs/features/workflow/ChangeRequestEditor/helpers/helpers.js +40 -1
- package/cjs/features/workflow/WorkflowTaskCard/components/DataChangeRequestTaskCard/DataChangeRequestTaskCard.js +6 -2
- package/cjs/features/workflow/helpers/attributes.js +2 -2
- package/cjs/features/workflow/helpers/attributes.test.js +9 -6
- package/cjs/features/workflow/helpers/merge.js +2 -1
- package/contexts/WorkflowTasksContext/index.d.ts +1 -0
- package/features/workflow/ChangeRequestEditor/components/ChangeItemEditor/ChangeItemEditor.js +14 -11
- package/features/workflow/ChangeRequestEditor/helpers/helpers.d.ts +2 -1
- package/features/workflow/ChangeRequestEditor/helpers/helpers.js +39 -1
- package/features/workflow/WorkflowTaskCard/components/DataChangeRequestTaskCard/DataChangeRequestTaskCard.js +7 -3
- package/features/workflow/helpers/attributes.js +2 -2
- package/features/workflow/helpers/attributes.test.js +9 -6
- package/features/workflow/helpers/merge.js +2 -1
- package/package.json +2 -2
package/cjs/features/workflow/ChangeRequestEditor/components/ChangeItemEditor/ChangeItemEditor.js
CHANGED
|
@@ -28,31 +28,33 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
29
|
exports.ChangeItemEditor = void 0;
|
|
30
30
|
var react_1 = __importStar(require("react"));
|
|
31
|
-
var ramda_1 = require("ramda");
|
|
32
31
|
var classnames_1 = __importDefault(require("classnames"));
|
|
32
|
+
var ramda_1 = require("ramda");
|
|
33
|
+
var ui_i18n_1 = __importDefault(require("ui-i18n"));
|
|
33
34
|
var Replay_1 = __importDefault(require("@mui/icons-material/Replay"));
|
|
34
35
|
var Button_1 = __importDefault(require("@mui/material/Button"));
|
|
35
|
-
var ui_i18n_1 = __importDefault(require("ui-i18n"));
|
|
36
36
|
var mdm_sdk_1 = require("@reltio/mdm-sdk");
|
|
37
37
|
var MdmModuleContext_1 = require("../../../../../contexts/MdmModuleContext");
|
|
38
38
|
var DataTypeValue_1 = require("../../../../../DataTypeValue");
|
|
39
|
+
var SmallIconButton_1 = require("../../../../../SmallIconButton");
|
|
39
40
|
var common_1 = require("../../../helpers/common");
|
|
41
|
+
var helpers_1 = require("../../helpers/helpers");
|
|
40
42
|
var OperationChip_1 = require("../../../OperationChip");
|
|
41
43
|
var RelationEntityLink_1 = require("../../../RelationEntityLink");
|
|
44
|
+
var useChangeRequestEditor_1 = require("../../hooks/useChangeRequestEditor");
|
|
42
45
|
var ChangeItemLabel_1 = require("../ChangeItemLabel");
|
|
43
46
|
var DCRValueEditor_1 = require("../DCRValueEditor");
|
|
44
47
|
var StatusChips_1 = require("../StatusChips");
|
|
45
|
-
var SmallIconButton_1 = require("../../../../../SmallIconButton");
|
|
46
|
-
var useChangeRequestEditor_1 = require("../../hooks/useChangeRequestEditor");
|
|
47
48
|
var ChangeItemEditor_module_css_1 = __importDefault(require("./ChangeItemEditor.module.css"));
|
|
48
49
|
var ChangeItemEditor = function (_a) {
|
|
49
50
|
var _b, _c, _d;
|
|
50
51
|
var change = _a.change, _e = _a.editable, editable = _e === void 0 ? true : _e, classes = _a.classes;
|
|
51
52
|
var metadata = (0, MdmModuleContext_1.useMdmMetadata)();
|
|
52
53
|
var _f = (0, useChangeRequestEditor_1.useChangeRequestEditor)({ change: change }), handleChange = _f.handleChange, handleReject = _f.handleReject, handleRevert = _f.handleRevert, lineData = _f.lineData, isLineRejected = _f.isLineRejected, isParentLineRejected = _f.isParentLineRejected, isUpdated = _f.isUpdated, hasChangeId = _f.hasChangeId;
|
|
54
|
+
var entity = (0, MdmModuleContext_1.useMdmEntity)();
|
|
55
|
+
var entityType = (0, mdm_sdk_1.getEntityType)(metadata, entity === null || entity === void 0 ? void 0 : entity.type);
|
|
53
56
|
var isUpdateOperation = change.operation === mdm_sdk_1.DCROperationTypes.EDITED;
|
|
54
57
|
var isAddOperation = change.operation === mdm_sdk_1.DCROperationTypes.ADDED;
|
|
55
|
-
var hasAnyValue = Boolean(change.oldValue || change.newValue);
|
|
56
58
|
var oldValue = (0, mdm_sdk_1.getAttributeValue)(change.oldValue);
|
|
57
59
|
var currentNewValue = !(0, ramda_1.isNil)(lineData === null || lineData === void 0 ? void 0 : lineData.value) && !isParentLineRejected ? lineData.value : change.newValue;
|
|
58
60
|
var newValue = (0, mdm_sdk_1.getAttributeValue)(currentNewValue);
|
|
@@ -60,17 +62,18 @@ var ChangeItemEditor = function (_a) {
|
|
|
60
62
|
var dataTypeDefinition = (0, react_1.useMemo)(function () {
|
|
61
63
|
return change.attributeType && (0, common_1.getDataTypeDefinition)(change.attributeType, newValue || oldValue);
|
|
62
64
|
}, [change.attributeType, newValue, oldValue]);
|
|
63
|
-
var shouldShowValueEditor = (isUpdateOperation || isAddOperation) && editable;
|
|
64
|
-
var shouldShowOperationChip = hasAnyValue && change.operation;
|
|
65
65
|
var isRolesOrTags = ((_b = change === null || change === void 0 ? void 0 : change.attributeType) === null || _b === void 0 ? void 0 : _b.uri) === mdm_sdk_1.EntityAttrTypes.roles.uri ||
|
|
66
66
|
((_c = change === null || change === void 0 ? void 0 : change.attributeType) === null || _c === void 0 ? void 0 : _c.uri) === mdm_sdk_1.EntityAttrTypes.tags.uri;
|
|
67
|
+
var canEdit = (0, helpers_1.checkCanInitiateChangeRequest)(metadata, entityType, change);
|
|
68
|
+
var shouldShowValueEditor = (isUpdateOperation || isAddOperation) && editable && canEdit;
|
|
67
69
|
var preparedValue = (0, react_1.useMemo)(function () {
|
|
68
70
|
return isRolesOrTags
|
|
69
71
|
? (0, common_1.prepareRolesOrTagsValue)(metadata, newValue, change.attributeType.uri)
|
|
70
72
|
: newValue;
|
|
71
73
|
}, [isRolesOrTags, metadata, newValue, (_d = change.attributeType) === null || _d === void 0 ? void 0 : _d.uri]);
|
|
72
74
|
var showUndoButton = (isUpdated || isLineRejected) && !isParentLineRejected;
|
|
73
|
-
var showRejectButton =
|
|
75
|
+
var showRejectButton = canEdit &&
|
|
76
|
+
!isLineRejected &&
|
|
74
77
|
!isUpdated &&
|
|
75
78
|
!isParentLineRejected &&
|
|
76
79
|
hasChangeId &&
|
|
@@ -84,7 +87,7 @@ var ChangeItemEditor = function (_a) {
|
|
|
84
87
|
shouldShowValueEditor ? (react_1.default.createElement(DCRValueEditor_1.DCRValueEditor, { attributeType: change.attributeType, value: currentNewValue, onChange: handleChange, disabled: !editable || isRejected })) : (hasNewValue && (react_1.default.createElement("div", { className: ChangeItemEditor_module_css_1.default.value },
|
|
85
88
|
react_1.default.createElement(DataTypeValue_1.DataTypeValue, { value: preparedValue, dataTypeDefinition: dataTypeDefinition }))))),
|
|
86
89
|
react_1.default.createElement("div", { className: ChangeItemEditor_module_css_1.default.revertColumn }, showUndoButton && (react_1.default.createElement(SmallIconButton_1.SmallIconButton, { icon: Replay_1.default, onClick: handleRevert, className: ChangeItemEditor_module_css_1.default.revertButton, title: ui_i18n_1.default.text('Undo'), size: "S" }))),
|
|
87
|
-
react_1.default.createElement("div", { className: ChangeItemEditor_module_css_1.default.operationColumn },
|
|
90
|
+
react_1.default.createElement("div", { className: ChangeItemEditor_module_css_1.default.operationColumn }, change.operation && react_1.default.createElement(OperationChip_1.OperationChip, { operation: change.operation, size: "small", variant: "outlined" })),
|
|
88
91
|
react_1.default.createElement("div", { className: ChangeItemEditor_module_css_1.default.statusColumn }, showStatusChips && react_1.default.createElement(StatusChips_1.StatusChips, { showUpdatedChip: isUpdated, showRejectedChip: isLineRejected })),
|
|
89
92
|
react_1.default.createElement("div", { className: ChangeItemEditor_module_css_1.default.rejectColumn }, showRejectButton && (react_1.default.createElement(Button_1.default, { onClick: handleReject, className: (0, classnames_1.default)(ChangeItemEditor_module_css_1.default.rejectButton, classes === null || classes === void 0 ? void 0 : classes.rejectButton), title: ui_i18n_1.default.text('Reject'), size: "medium" }, ui_i18n_1.default.text('Reject'))))));
|
|
90
93
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { DCRChanges, GroupedObjectsInfo, EnrichedDCRChanges } from '@reltio/mdm-sdk';
|
|
1
|
+
import { DCRChanges, GroupedObjectsInfo, EnrichedDCRChanges, TEntityType, Metadata } from '@reltio/mdm-sdk';
|
|
2
2
|
import { Diff, Title } from '../../types';
|
|
3
3
|
export declare const isEditableChange: (change: Diff, entityInfo: GroupedObjectsInfo["entity"]) => boolean;
|
|
4
4
|
export declare const addLineIdToValue: (data: DCRChanges) => EnrichedDCRChanges;
|
|
5
5
|
export declare const isDiffChange: (change: Diff | Title) => change is Diff;
|
|
6
|
+
export declare const checkCanInitiateChangeRequest: (metadata: Metadata, entityType: TEntityType, change: Diff) => any;
|
|
@@ -11,7 +11,7 @@ var __assign = (this && this.__assign) || function () {
|
|
|
11
11
|
return __assign.apply(this, arguments);
|
|
12
12
|
};
|
|
13
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
-
exports.isDiffChange = exports.addLineIdToValue = exports.isEditableChange = void 0;
|
|
14
|
+
exports.checkCanInitiateChangeRequest = exports.isDiffChange = exports.addLineIdToValue = exports.isEditableChange = void 0;
|
|
15
15
|
var ramda_1 = require("ramda");
|
|
16
16
|
var mdm_sdk_1 = require("@reltio/mdm-sdk");
|
|
17
17
|
var isEditableChange = function (change, entityInfo) {
|
|
@@ -107,3 +107,42 @@ var isDiffChange = function (change) {
|
|
|
107
107
|
return (0, ramda_1.has)('level', change);
|
|
108
108
|
};
|
|
109
109
|
exports.isDiffChange = isDiffChange;
|
|
110
|
+
var checkCanInitiateChangeRequest = function (metadata, entityType, change) {
|
|
111
|
+
if (change.relationType) {
|
|
112
|
+
return checkCanInitChangeRequestForRelation(metadata, change.attributeValue, change.relationType);
|
|
113
|
+
}
|
|
114
|
+
if ((0, mdm_sdk_1.isRoleAttrType)(change.attributeType) || (0, mdm_sdk_1.isTagAttrType)(change.attributeType)) {
|
|
115
|
+
return checkCanInitChangeRequestForSpecialAttribute(entityType);
|
|
116
|
+
}
|
|
117
|
+
return checkCanInitChangeRequestForAttribute(metadata, change.attributeValue, change.attributeType);
|
|
118
|
+
};
|
|
119
|
+
exports.checkCanInitiateChangeRequest = checkCanInitiateChangeRequest;
|
|
120
|
+
var checkCanInitChangeRequestForSpecialAttribute = function (entityType) {
|
|
121
|
+
return (0, mdm_sdk_1.checkMetadataPermission)(mdm_sdk_1.MetadataPermissions.INITIATE_CHANGE_REQUEST, entityType);
|
|
122
|
+
};
|
|
123
|
+
var checkCanInitChangeRequestForAttribute = function (metadata, attributeValue, attributeType) {
|
|
124
|
+
var _a;
|
|
125
|
+
var preparedAttributeValue = typeof (attributeValue === null || attributeValue === void 0 ? void 0 : attributeValue.value) === 'object' && 'newValue' in attributeValue.value
|
|
126
|
+
? (_a = attributeValue === null || attributeValue === void 0 ? void 0 : attributeValue.value) === null || _a === void 0 ? void 0 : _a.newValue
|
|
127
|
+
: attributeValue;
|
|
128
|
+
return ((0, mdm_sdk_1.checkMetadataPermission)(mdm_sdk_1.MetadataPermissions.INITIATE_CHANGE_REQUEST, attributeType) &&
|
|
129
|
+
(0, mdm_sdk_1.checkSubAttributesPermissions)(mdm_sdk_1.MetadataPermissions.INITIATE_CHANGE_REQUEST, metadata, preparedAttributeValue, attributeType));
|
|
130
|
+
};
|
|
131
|
+
var checkCanInitChangeRequestForRelation = function (metadata, attributeValue, relationType) {
|
|
132
|
+
var preparedAttributeValue = Object.entries(attributeValue)
|
|
133
|
+
.filter(function (_a) {
|
|
134
|
+
var key = _a[0];
|
|
135
|
+
return relationType.attributes.some(function (attr) { return attr.name === key; });
|
|
136
|
+
})
|
|
137
|
+
.reduce(function (acc, _a) {
|
|
138
|
+
var key = _a[0], value = _a[1];
|
|
139
|
+
acc[key] = value;
|
|
140
|
+
return acc;
|
|
141
|
+
}, {});
|
|
142
|
+
return ((0, mdm_sdk_1.checkMetadataPermission)(mdm_sdk_1.MetadataPermissions.INITIATE_CHANGE_REQUEST, relationType) &&
|
|
143
|
+
Object.keys(preparedAttributeValue).every(function (attributeValueKey) {
|
|
144
|
+
var attributeType = relationType.attributes.find(function (attribute) { return attribute.name === attributeValueKey; });
|
|
145
|
+
return ((0, mdm_sdk_1.checkMetadataPermission)(mdm_sdk_1.MetadataPermissions.INITIATE_CHANGE_REQUEST, attributeType) &&
|
|
146
|
+
(0, mdm_sdk_1.checkSubAttributesPermissions)(mdm_sdk_1.MetadataPermissions.INITIATE_CHANGE_REQUEST, metadata, preparedAttributeValue[attributeValueKey], attributeType));
|
|
147
|
+
}));
|
|
148
|
+
};
|
|
@@ -28,6 +28,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
29
|
exports.DataChangeRequestTaskCard = void 0;
|
|
30
30
|
var react_1 = __importStar(require("react"));
|
|
31
|
+
var ramda_1 = require("ramda");
|
|
31
32
|
var DcrTaskIcon_1 = __importDefault(require("../../../../../icons/DcrTaskIcon"));
|
|
32
33
|
var MdmModuleContext_1 = require("../../../../../contexts/MdmModuleContext");
|
|
33
34
|
var GenericWorkflowTaskCard_1 = require("../GenericWorkflowTaskCard");
|
|
@@ -37,9 +38,12 @@ var useChangeRequest_1 = require("../../../hooks/useChangeRequest");
|
|
|
37
38
|
var common_1 = require("../../../helpers/common");
|
|
38
39
|
var ReviewDCRDialog_1 = require("../../../ReviewDCRDialog");
|
|
39
40
|
var ReviewDCRButton_1 = require("../../../ReviewDCRButton");
|
|
41
|
+
var WorkflowTasksContext_1 = require("../../../../../contexts/WorkflowTasksContext");
|
|
40
42
|
var DataChangeRequestTaskCard = function (_a) {
|
|
41
43
|
var task = _a.task;
|
|
44
|
+
var reviewDCREnabledByEntityType = ((0, react_1.useContext)(WorkflowTasksContext_1.WorkflowTasksContext) || {}).reviewDCR;
|
|
42
45
|
var reviewDCREnabled = (0, MdmModuleContext_1.useMdmReviewDCREnabled)();
|
|
46
|
+
var isReviewDCREnabled = (0, ramda_1.isNil)(reviewDCREnabledByEntityType) ? reviewDCREnabled : reviewDCREnabledByEntityType;
|
|
43
47
|
var username = (0, MdmModuleContext_1.useMdmUsername)();
|
|
44
48
|
var _b = (0, react_1.useState)(false), isReviewDCRDialogOpen = _b[0], setIsReviewDCRDialogOpen = _b[1];
|
|
45
49
|
var objectURIs = task.objectURIs, assignee = task.assignee;
|
|
@@ -51,8 +55,8 @@ var DataChangeRequestTaskCard = function (_a) {
|
|
|
51
55
|
var handleCloseReviewDCRDialog = (0, react_1.useCallback)(function () {
|
|
52
56
|
setIsReviewDCRDialogOpen(false);
|
|
53
57
|
}, []);
|
|
54
|
-
var showReviewDCRButton =
|
|
55
|
-
var showReviewDialog = isReviewDCRDialogOpen && (showReviewDCRButton ||
|
|
58
|
+
var showReviewDCRButton = isReviewDCREnabled && assignee == username;
|
|
59
|
+
var showReviewDialog = isReviewDCRDialogOpen && (showReviewDCRButton || isReviewDCREnabled);
|
|
56
60
|
var customActionsSlot = (0, react_1.useMemo)(function () { return showReviewDCRButton && react_1.default.createElement(ReviewDCRButton_1.ReviewDCRButton, { onClick: handleReviewDCR }); }, [showReviewDCRButton, handleReviewDCR]);
|
|
57
61
|
return (react_1.default.createElement(react_1.default.Fragment, null,
|
|
58
62
|
react_1.default.createElement(GenericWorkflowTaskCard_1.GenericWorkflowTaskCard, { task: task, Icon: DcrTaskIcon_1.default, customActionsSlot: customActionsSlot }, dcr &&
|
|
@@ -116,7 +116,7 @@ exports.getEntityChanges = (0, ramda_1.curry)(function (metadata, entityInfo, ch
|
|
|
116
116
|
var attrTypes = (0, attributesView_1.getFilteredAttrTypes)(metadata, entityInfo.type, [], []);
|
|
117
117
|
return getAttributesList(metadata, attrTypes, changes);
|
|
118
118
|
});
|
|
119
|
-
exports.getRelationChanges = (0, ramda_1.curry)(function (metadata, relationInfo, changes, changeType) {
|
|
119
|
+
exports.getRelationChanges = (0, ramda_1.curry)(function (metadata, relationInfo, changes, changeType, relationChangeLineIds) {
|
|
120
120
|
var addRelationOperationIfNeeded = function (changes, changeType) {
|
|
121
121
|
if (changeType === mdm_sdk_1.DCRTypes.CREATE_RELATIONSHIP || (0, mdm_sdk_1.isEmptyValue)(changes)) {
|
|
122
122
|
var operation = (0, common_1.getOperationType)(changeType);
|
|
@@ -127,7 +127,7 @@ exports.getRelationChanges = (0, ramda_1.curry)(function (metadata, relationInfo
|
|
|
127
127
|
var relationType = (0, mdm_sdk_1.getRelationType)(metadata, relationInfo.type);
|
|
128
128
|
var attrTypes = (0, mdm_sdk_1.getRelationAttributesList)(metadata, relationInfo.type);
|
|
129
129
|
return (0, ramda_1.flatten)([
|
|
130
|
-
__assign({ level: 1, label: (0, ramda_1.propOr)('', 'label', relationType), attributeType: null, relationType: relationType, attributeValue: __assign(__assign({}, relationInfo), changes), lineIds: changes === null || changes === void 0 ? void 0 : changes.lineIds }, addRelationOperationIfNeeded(changes, changeType)),
|
|
130
|
+
__assign({ level: 1, label: (0, ramda_1.propOr)('', 'label', relationType), attributeType: null, relationType: relationType, attributeValue: __assign(__assign({}, relationInfo), changes), lineIds: (changes === null || changes === void 0 ? void 0 : changes.lineIds) || relationChangeLineIds }, addRelationOperationIfNeeded(changes, changeType)),
|
|
131
131
|
getAttributesList(metadata, attrTypes, changes, 2)
|
|
132
132
|
]);
|
|
133
133
|
});
|
|
@@ -141,13 +141,14 @@ describe('attributes helpers tests', function () {
|
|
|
141
141
|
]
|
|
142
142
|
};
|
|
143
143
|
it('should not show operation for relation title', function () {
|
|
144
|
-
expect((0, attributes_1.getRelationChanges)(metadata_test_data_1.metadata, relationInfo, changes, mdm_sdk_1.DCRTypes.INSERT_ATTRIBUTE)).toEqual([
|
|
144
|
+
expect((0, attributes_1.getRelationChanges)(metadata_test_data_1.metadata, relationInfo, changes, mdm_sdk_1.DCRTypes.INSERT_ATTRIBUTE, ['lineIds'])).toEqual([
|
|
145
145
|
{
|
|
146
146
|
attributeType: null,
|
|
147
147
|
relationType: metadata_test_data_1.metadata.relationTypes[1],
|
|
148
148
|
attributeValue: __assign(__assign({}, relationInfo), changes),
|
|
149
149
|
label: metadata_test_data_1.metadata.relationTypes[1].label,
|
|
150
|
-
level: 1
|
|
150
|
+
level: 1,
|
|
151
|
+
lineIds: ['lineIds']
|
|
151
152
|
},
|
|
152
153
|
{
|
|
153
154
|
attributeType: mdm_sdk_1.EntityAttrTypes.startDate,
|
|
@@ -168,14 +169,15 @@ describe('attributes helpers tests', function () {
|
|
|
168
169
|
]);
|
|
169
170
|
});
|
|
170
171
|
it('should show operation for relation title if it is new', function () {
|
|
171
|
-
expect((0, attributes_1.getRelationChanges)(metadata_test_data_1.metadata, relationInfo, changes, mdm_sdk_1.DCRTypes.CREATE_RELATIONSHIP)).toEqual([
|
|
172
|
+
expect((0, attributes_1.getRelationChanges)(metadata_test_data_1.metadata, relationInfo, changes, mdm_sdk_1.DCRTypes.CREATE_RELATIONSHIP, ['lineIds'])).toEqual([
|
|
172
173
|
{
|
|
173
174
|
attributeType: null,
|
|
174
175
|
relationType: metadata_test_data_1.metadata.relationTypes[1],
|
|
175
176
|
attributeValue: __assign(__assign({}, relationInfo), changes),
|
|
176
177
|
label: metadata_test_data_1.metadata.relationTypes[1].label,
|
|
177
178
|
level: 1,
|
|
178
|
-
operation: mdm_sdk_1.DCROperationTypes.ADDED
|
|
179
|
+
operation: mdm_sdk_1.DCROperationTypes.ADDED,
|
|
180
|
+
lineIds: ['lineIds']
|
|
179
181
|
},
|
|
180
182
|
{
|
|
181
183
|
attributeType: mdm_sdk_1.EntityAttrTypes.startDate,
|
|
@@ -196,14 +198,15 @@ describe('attributes helpers tests', function () {
|
|
|
196
198
|
]);
|
|
197
199
|
});
|
|
198
200
|
it('should show operation for relation title if it was deleted and changes are empty', function () {
|
|
199
|
-
expect((0, attributes_1.getRelationChanges)(metadata_test_data_1.metadata, relationInfo, {}, mdm_sdk_1.DCRTypes.DELETE_RELATIONSHIP)).toEqual([
|
|
201
|
+
expect((0, attributes_1.getRelationChanges)(metadata_test_data_1.metadata, relationInfo, {}, mdm_sdk_1.DCRTypes.DELETE_RELATIONSHIP, ['lineIds'])).toEqual([
|
|
200
202
|
{
|
|
201
203
|
attributeType: null,
|
|
202
204
|
relationType: metadata_test_data_1.metadata.relationTypes[1],
|
|
203
205
|
attributeValue: relationInfo,
|
|
204
206
|
label: metadata_test_data_1.metadata.relationTypes[1].label,
|
|
205
207
|
level: 1,
|
|
206
|
-
operation: mdm_sdk_1.DCROperationTypes.DELETED
|
|
208
|
+
operation: mdm_sdk_1.DCROperationTypes.DELETED,
|
|
209
|
+
lineIds: ['lineIds']
|
|
207
210
|
}
|
|
208
211
|
]);
|
|
209
212
|
});
|
|
@@ -256,7 +256,8 @@ var mergeChanges = function (metadata, changes, entityInfo, relationsInfo) {
|
|
|
256
256
|
], changesTree);
|
|
257
257
|
var relationsChanges = (0, ramda_1.flatten)(relationsInfo.map(function (relationInfo, index) {
|
|
258
258
|
var changeType = (0, ramda_1.path)([relationInfo.uri, 0, 'type'], changes);
|
|
259
|
-
|
|
259
|
+
var relationChangeLineIds = (0, ramda_1.path)([relationInfo.uri, 0, 'lineIds'], changes);
|
|
260
|
+
return (0, attributes_1.getRelationChanges)(metadata, relationInfo, relationsTrees[index], changeType, relationChangeLineIds);
|
|
260
261
|
}));
|
|
261
262
|
return [entityChanges, relationsChanges];
|
|
262
263
|
};
|
package/features/workflow/ChangeRequestEditor/components/ChangeItemEditor/ChangeItemEditor.js
CHANGED
|
@@ -1,29 +1,31 @@
|
|
|
1
1
|
import React, { useMemo } from 'react';
|
|
2
|
-
import { isNil } from 'ramda';
|
|
3
2
|
import classnames from 'classnames';
|
|
3
|
+
import { isNil } from 'ramda';
|
|
4
|
+
import i18n from 'ui-i18n';
|
|
4
5
|
import ReplayIcon from '@mui/icons-material/Replay';
|
|
5
6
|
import Button from '@mui/material/Button';
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
8
|
-
import { useMdmMetadata } from '../../../../../contexts/MdmModuleContext';
|
|
7
|
+
import { DCROperationTypes, EntityAttrTypes, getAttributeValue, getEntityType } from '@reltio/mdm-sdk';
|
|
8
|
+
import { useMdmEntity, useMdmMetadata } from '../../../../../contexts/MdmModuleContext';
|
|
9
9
|
import { DataTypeValue } from '../../../../../DataTypeValue';
|
|
10
|
+
import { SmallIconButton } from '../../../../../SmallIconButton';
|
|
10
11
|
import { getDataTypeDefinition, prepareRolesOrTagsValue } from '../../../helpers/common';
|
|
12
|
+
import { checkCanInitiateChangeRequest } from '../../helpers/helpers';
|
|
11
13
|
import { OperationChip } from '../../../OperationChip';
|
|
12
14
|
import { RelationEntityLink } from '../../../RelationEntityLink';
|
|
15
|
+
import { useChangeRequestEditor } from '../../hooks/useChangeRequestEditor';
|
|
13
16
|
import { ChangeItemLabel } from '../ChangeItemLabel';
|
|
14
17
|
import { DCRValueEditor } from '../DCRValueEditor';
|
|
15
18
|
import { StatusChips } from '../StatusChips';
|
|
16
|
-
import { SmallIconButton } from '../../../../../SmallIconButton';
|
|
17
|
-
import { useChangeRequestEditor } from '../../hooks/useChangeRequestEditor';
|
|
18
19
|
import styles from './ChangeItemEditor.module.css';
|
|
19
20
|
export var ChangeItemEditor = function (_a) {
|
|
20
21
|
var _b, _c, _d;
|
|
21
22
|
var change = _a.change, _e = _a.editable, editable = _e === void 0 ? true : _e, classes = _a.classes;
|
|
22
23
|
var metadata = useMdmMetadata();
|
|
23
24
|
var _f = useChangeRequestEditor({ change: change }), handleChange = _f.handleChange, handleReject = _f.handleReject, handleRevert = _f.handleRevert, lineData = _f.lineData, isLineRejected = _f.isLineRejected, isParentLineRejected = _f.isParentLineRejected, isUpdated = _f.isUpdated, hasChangeId = _f.hasChangeId;
|
|
25
|
+
var entity = useMdmEntity();
|
|
26
|
+
var entityType = getEntityType(metadata, entity === null || entity === void 0 ? void 0 : entity.type);
|
|
24
27
|
var isUpdateOperation = change.operation === DCROperationTypes.EDITED;
|
|
25
28
|
var isAddOperation = change.operation === DCROperationTypes.ADDED;
|
|
26
|
-
var hasAnyValue = Boolean(change.oldValue || change.newValue);
|
|
27
29
|
var oldValue = getAttributeValue(change.oldValue);
|
|
28
30
|
var currentNewValue = !isNil(lineData === null || lineData === void 0 ? void 0 : lineData.value) && !isParentLineRejected ? lineData.value : change.newValue;
|
|
29
31
|
var newValue = getAttributeValue(currentNewValue);
|
|
@@ -31,17 +33,18 @@ export var ChangeItemEditor = function (_a) {
|
|
|
31
33
|
var dataTypeDefinition = useMemo(function () {
|
|
32
34
|
return change.attributeType && getDataTypeDefinition(change.attributeType, newValue || oldValue);
|
|
33
35
|
}, [change.attributeType, newValue, oldValue]);
|
|
34
|
-
var shouldShowValueEditor = (isUpdateOperation || isAddOperation) && editable;
|
|
35
|
-
var shouldShowOperationChip = hasAnyValue && change.operation;
|
|
36
36
|
var isRolesOrTags = ((_b = change === null || change === void 0 ? void 0 : change.attributeType) === null || _b === void 0 ? void 0 : _b.uri) === EntityAttrTypes.roles.uri ||
|
|
37
37
|
((_c = change === null || change === void 0 ? void 0 : change.attributeType) === null || _c === void 0 ? void 0 : _c.uri) === EntityAttrTypes.tags.uri;
|
|
38
|
+
var canEdit = checkCanInitiateChangeRequest(metadata, entityType, change);
|
|
39
|
+
var shouldShowValueEditor = (isUpdateOperation || isAddOperation) && editable && canEdit;
|
|
38
40
|
var preparedValue = useMemo(function () {
|
|
39
41
|
return isRolesOrTags
|
|
40
42
|
? prepareRolesOrTagsValue(metadata, newValue, change.attributeType.uri)
|
|
41
43
|
: newValue;
|
|
42
44
|
}, [isRolesOrTags, metadata, newValue, (_d = change.attributeType) === null || _d === void 0 ? void 0 : _d.uri]);
|
|
43
45
|
var showUndoButton = (isUpdated || isLineRejected) && !isParentLineRejected;
|
|
44
|
-
var showRejectButton =
|
|
46
|
+
var showRejectButton = canEdit &&
|
|
47
|
+
!isLineRejected &&
|
|
45
48
|
!isUpdated &&
|
|
46
49
|
!isParentLineRejected &&
|
|
47
50
|
hasChangeId &&
|
|
@@ -55,7 +58,7 @@ export var ChangeItemEditor = function (_a) {
|
|
|
55
58
|
shouldShowValueEditor ? (React.createElement(DCRValueEditor, { attributeType: change.attributeType, value: currentNewValue, onChange: handleChange, disabled: !editable || isRejected })) : (hasNewValue && (React.createElement("div", { className: styles.value },
|
|
56
59
|
React.createElement(DataTypeValue, { value: preparedValue, dataTypeDefinition: dataTypeDefinition }))))),
|
|
57
60
|
React.createElement("div", { className: styles.revertColumn }, showUndoButton && (React.createElement(SmallIconButton, { icon: ReplayIcon, onClick: handleRevert, className: styles.revertButton, title: i18n.text('Undo'), size: "S" }))),
|
|
58
|
-
React.createElement("div", { className: styles.operationColumn },
|
|
61
|
+
React.createElement("div", { className: styles.operationColumn }, change.operation && React.createElement(OperationChip, { operation: change.operation, size: "small", variant: "outlined" })),
|
|
59
62
|
React.createElement("div", { className: styles.statusColumn }, showStatusChips && React.createElement(StatusChips, { showUpdatedChip: isUpdated, showRejectedChip: isLineRejected })),
|
|
60
63
|
React.createElement("div", { className: styles.rejectColumn }, showRejectButton && (React.createElement(Button, { onClick: handleReject, className: classnames(styles.rejectButton, classes === null || classes === void 0 ? void 0 : classes.rejectButton), title: i18n.text('Reject'), size: "medium" }, i18n.text('Reject'))))));
|
|
61
64
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { DCRChanges, GroupedObjectsInfo, EnrichedDCRChanges } from '@reltio/mdm-sdk';
|
|
1
|
+
import { DCRChanges, GroupedObjectsInfo, EnrichedDCRChanges, TEntityType, Metadata } from '@reltio/mdm-sdk';
|
|
2
2
|
import { Diff, Title } from '../../types';
|
|
3
3
|
export declare const isEditableChange: (change: Diff, entityInfo: GroupedObjectsInfo["entity"]) => boolean;
|
|
4
4
|
export declare const addLineIdToValue: (data: DCRChanges) => EnrichedDCRChanges;
|
|
5
5
|
export declare const isDiffChange: (change: Diff | Title) => change is Diff;
|
|
6
|
+
export declare const checkCanInitiateChangeRequest: (metadata: Metadata, entityType: TEntityType, change: Diff) => any;
|
|
@@ -10,7 +10,7 @@ var __assign = (this && this.__assign) || function () {
|
|
|
10
10
|
return __assign.apply(this, arguments);
|
|
11
11
|
};
|
|
12
12
|
import { clone, has, isNil } from 'ramda';
|
|
13
|
-
import { DCROperationTypes, DCRTypes, isRelationTypeUri } from '@reltio/mdm-sdk';
|
|
13
|
+
import { DCROperationTypes, DCRTypes, isRelationTypeUri, MetadataPermissions, checkMetadataPermission, isRoleAttrType, isTagAttrType, checkSubAttributesPermissions } from '@reltio/mdm-sdk';
|
|
14
14
|
export var isEditableChange = function (change, entityInfo) {
|
|
15
15
|
var _a;
|
|
16
16
|
var currentAttributeTypeUri = (_a = change.attributeType) === null || _a === void 0 ? void 0 : _a.uri;
|
|
@@ -101,3 +101,41 @@ export var addLineIdToValue = function (data) {
|
|
|
101
101
|
export var isDiffChange = function (change) {
|
|
102
102
|
return has('level', change);
|
|
103
103
|
};
|
|
104
|
+
export var checkCanInitiateChangeRequest = function (metadata, entityType, change) {
|
|
105
|
+
if (change.relationType) {
|
|
106
|
+
return checkCanInitChangeRequestForRelation(metadata, change.attributeValue, change.relationType);
|
|
107
|
+
}
|
|
108
|
+
if (isRoleAttrType(change.attributeType) || isTagAttrType(change.attributeType)) {
|
|
109
|
+
return checkCanInitChangeRequestForSpecialAttribute(entityType);
|
|
110
|
+
}
|
|
111
|
+
return checkCanInitChangeRequestForAttribute(metadata, change.attributeValue, change.attributeType);
|
|
112
|
+
};
|
|
113
|
+
var checkCanInitChangeRequestForSpecialAttribute = function (entityType) {
|
|
114
|
+
return checkMetadataPermission(MetadataPermissions.INITIATE_CHANGE_REQUEST, entityType);
|
|
115
|
+
};
|
|
116
|
+
var checkCanInitChangeRequestForAttribute = function (metadata, attributeValue, attributeType) {
|
|
117
|
+
var _a;
|
|
118
|
+
var preparedAttributeValue = typeof (attributeValue === null || attributeValue === void 0 ? void 0 : attributeValue.value) === 'object' && 'newValue' in attributeValue.value
|
|
119
|
+
? (_a = attributeValue === null || attributeValue === void 0 ? void 0 : attributeValue.value) === null || _a === void 0 ? void 0 : _a.newValue
|
|
120
|
+
: attributeValue;
|
|
121
|
+
return (checkMetadataPermission(MetadataPermissions.INITIATE_CHANGE_REQUEST, attributeType) &&
|
|
122
|
+
checkSubAttributesPermissions(MetadataPermissions.INITIATE_CHANGE_REQUEST, metadata, preparedAttributeValue, attributeType));
|
|
123
|
+
};
|
|
124
|
+
var checkCanInitChangeRequestForRelation = function (metadata, attributeValue, relationType) {
|
|
125
|
+
var preparedAttributeValue = Object.entries(attributeValue)
|
|
126
|
+
.filter(function (_a) {
|
|
127
|
+
var key = _a[0];
|
|
128
|
+
return relationType.attributes.some(function (attr) { return attr.name === key; });
|
|
129
|
+
})
|
|
130
|
+
.reduce(function (acc, _a) {
|
|
131
|
+
var key = _a[0], value = _a[1];
|
|
132
|
+
acc[key] = value;
|
|
133
|
+
return acc;
|
|
134
|
+
}, {});
|
|
135
|
+
return (checkMetadataPermission(MetadataPermissions.INITIATE_CHANGE_REQUEST, relationType) &&
|
|
136
|
+
Object.keys(preparedAttributeValue).every(function (attributeValueKey) {
|
|
137
|
+
var attributeType = relationType.attributes.find(function (attribute) { return attribute.name === attributeValueKey; });
|
|
138
|
+
return (checkMetadataPermission(MetadataPermissions.INITIATE_CHANGE_REQUEST, attributeType) &&
|
|
139
|
+
checkSubAttributesPermissions(MetadataPermissions.INITIATE_CHANGE_REQUEST, metadata, preparedAttributeValue[attributeValueKey], attributeType));
|
|
140
|
+
}));
|
|
141
|
+
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import React, { useCallback, useMemo, useState } from 'react';
|
|
1
|
+
import React, { useCallback, useContext, useMemo, useState } from 'react';
|
|
2
|
+
import { isNil } from 'ramda';
|
|
2
3
|
import DcrTaskIcon from '../../../../../icons/DcrTaskIcon';
|
|
3
4
|
import { useMdmReviewDCREnabled, useMdmUsername } from '../../../../../contexts/MdmModuleContext';
|
|
4
5
|
import { GenericWorkflowTaskCard } from '../GenericWorkflowTaskCard';
|
|
@@ -8,9 +9,12 @@ import { useChangeRequest } from '../../../hooks/useChangeRequest';
|
|
|
8
9
|
import { getDCRUri } from '../../../helpers/common';
|
|
9
10
|
import { ReviewDCRDialog } from '../../../ReviewDCRDialog';
|
|
10
11
|
import { ReviewDCRButton } from '../../../ReviewDCRButton';
|
|
12
|
+
import { WorkflowTasksContext } from '../../../../../contexts/WorkflowTasksContext';
|
|
11
13
|
export var DataChangeRequestTaskCard = function (_a) {
|
|
12
14
|
var task = _a.task;
|
|
15
|
+
var reviewDCREnabledByEntityType = (useContext(WorkflowTasksContext) || {}).reviewDCR;
|
|
13
16
|
var reviewDCREnabled = useMdmReviewDCREnabled();
|
|
17
|
+
var isReviewDCREnabled = isNil(reviewDCREnabledByEntityType) ? reviewDCREnabled : reviewDCREnabledByEntityType;
|
|
14
18
|
var username = useMdmUsername();
|
|
15
19
|
var _b = useState(false), isReviewDCRDialogOpen = _b[0], setIsReviewDCRDialogOpen = _b[1];
|
|
16
20
|
var objectURIs = task.objectURIs, assignee = task.assignee;
|
|
@@ -22,8 +26,8 @@ export var DataChangeRequestTaskCard = function (_a) {
|
|
|
22
26
|
var handleCloseReviewDCRDialog = useCallback(function () {
|
|
23
27
|
setIsReviewDCRDialogOpen(false);
|
|
24
28
|
}, []);
|
|
25
|
-
var showReviewDCRButton =
|
|
26
|
-
var showReviewDialog = isReviewDCRDialogOpen && (showReviewDCRButton ||
|
|
29
|
+
var showReviewDCRButton = isReviewDCREnabled && assignee == username;
|
|
30
|
+
var showReviewDialog = isReviewDCRDialogOpen && (showReviewDCRButton || isReviewDCREnabled);
|
|
27
31
|
var customActionsSlot = useMemo(function () { return showReviewDCRButton && React.createElement(ReviewDCRButton, { onClick: handleReviewDCR }); }, [showReviewDCRButton, handleReviewDCR]);
|
|
28
32
|
return (React.createElement(React.Fragment, null,
|
|
29
33
|
React.createElement(GenericWorkflowTaskCard, { task: task, Icon: DcrTaskIcon, customActionsSlot: customActionsSlot }, dcr &&
|
|
@@ -113,7 +113,7 @@ export var getEntityChanges = curry(function (metadata, entityInfo, changes) {
|
|
|
113
113
|
var attrTypes = getFilteredAttrTypes(metadata, entityInfo.type, [], []);
|
|
114
114
|
return getAttributesList(metadata, attrTypes, changes);
|
|
115
115
|
});
|
|
116
|
-
export var getRelationChanges = curry(function (metadata, relationInfo, changes, changeType) {
|
|
116
|
+
export var getRelationChanges = curry(function (metadata, relationInfo, changes, changeType, relationChangeLineIds) {
|
|
117
117
|
var addRelationOperationIfNeeded = function (changes, changeType) {
|
|
118
118
|
if (changeType === DCRTypes.CREATE_RELATIONSHIP || isEmptyValue(changes)) {
|
|
119
119
|
var operation = getOperationType(changeType);
|
|
@@ -124,7 +124,7 @@ export var getRelationChanges = curry(function (metadata, relationInfo, changes,
|
|
|
124
124
|
var relationType = getRelationType(metadata, relationInfo.type);
|
|
125
125
|
var attrTypes = getRelationAttributesList(metadata, relationInfo.type);
|
|
126
126
|
return flatten([
|
|
127
|
-
__assign({ level: 1, label: propOr('', 'label', relationType), attributeType: null, relationType: relationType, attributeValue: __assign(__assign({}, relationInfo), changes), lineIds: changes === null || changes === void 0 ? void 0 : changes.lineIds }, addRelationOperationIfNeeded(changes, changeType)),
|
|
127
|
+
__assign({ level: 1, label: propOr('', 'label', relationType), attributeType: null, relationType: relationType, attributeValue: __assign(__assign({}, relationInfo), changes), lineIds: (changes === null || changes === void 0 ? void 0 : changes.lineIds) || relationChangeLineIds }, addRelationOperationIfNeeded(changes, changeType)),
|
|
128
128
|
getAttributesList(metadata, attrTypes, changes, 2)
|
|
129
129
|
]);
|
|
130
130
|
});
|
|
@@ -139,13 +139,14 @@ describe('attributes helpers tests', function () {
|
|
|
139
139
|
]
|
|
140
140
|
};
|
|
141
141
|
it('should not show operation for relation title', function () {
|
|
142
|
-
expect(getRelationChanges(metadata, relationInfo, changes, DCRTypes.INSERT_ATTRIBUTE)).toEqual([
|
|
142
|
+
expect(getRelationChanges(metadata, relationInfo, changes, DCRTypes.INSERT_ATTRIBUTE, ['lineIds'])).toEqual([
|
|
143
143
|
{
|
|
144
144
|
attributeType: null,
|
|
145
145
|
relationType: metadata.relationTypes[1],
|
|
146
146
|
attributeValue: __assign(__assign({}, relationInfo), changes),
|
|
147
147
|
label: metadata.relationTypes[1].label,
|
|
148
|
-
level: 1
|
|
148
|
+
level: 1,
|
|
149
|
+
lineIds: ['lineIds']
|
|
149
150
|
},
|
|
150
151
|
{
|
|
151
152
|
attributeType: EntityAttrTypes.startDate,
|
|
@@ -166,14 +167,15 @@ describe('attributes helpers tests', function () {
|
|
|
166
167
|
]);
|
|
167
168
|
});
|
|
168
169
|
it('should show operation for relation title if it is new', function () {
|
|
169
|
-
expect(getRelationChanges(metadata, relationInfo, changes, DCRTypes.CREATE_RELATIONSHIP)).toEqual([
|
|
170
|
+
expect(getRelationChanges(metadata, relationInfo, changes, DCRTypes.CREATE_RELATIONSHIP, ['lineIds'])).toEqual([
|
|
170
171
|
{
|
|
171
172
|
attributeType: null,
|
|
172
173
|
relationType: metadata.relationTypes[1],
|
|
173
174
|
attributeValue: __assign(__assign({}, relationInfo), changes),
|
|
174
175
|
label: metadata.relationTypes[1].label,
|
|
175
176
|
level: 1,
|
|
176
|
-
operation: DCROperationTypes.ADDED
|
|
177
|
+
operation: DCROperationTypes.ADDED,
|
|
178
|
+
lineIds: ['lineIds']
|
|
177
179
|
},
|
|
178
180
|
{
|
|
179
181
|
attributeType: EntityAttrTypes.startDate,
|
|
@@ -194,14 +196,15 @@ describe('attributes helpers tests', function () {
|
|
|
194
196
|
]);
|
|
195
197
|
});
|
|
196
198
|
it('should show operation for relation title if it was deleted and changes are empty', function () {
|
|
197
|
-
expect(getRelationChanges(metadata, relationInfo, {}, DCRTypes.DELETE_RELATIONSHIP)).toEqual([
|
|
199
|
+
expect(getRelationChanges(metadata, relationInfo, {}, DCRTypes.DELETE_RELATIONSHIP, ['lineIds'])).toEqual([
|
|
198
200
|
{
|
|
199
201
|
attributeType: null,
|
|
200
202
|
relationType: metadata.relationTypes[1],
|
|
201
203
|
attributeValue: relationInfo,
|
|
202
204
|
label: metadata.relationTypes[1].label,
|
|
203
205
|
level: 1,
|
|
204
|
-
operation: DCROperationTypes.DELETED
|
|
206
|
+
operation: DCROperationTypes.DELETED,
|
|
207
|
+
lineIds: ['lineIds']
|
|
205
208
|
}
|
|
206
209
|
]);
|
|
207
210
|
});
|
|
@@ -252,7 +252,8 @@ export var mergeChanges = function (metadata, changes, entityInfo, relationsInfo
|
|
|
252
252
|
], changesTree);
|
|
253
253
|
var relationsChanges = flatten(relationsInfo.map(function (relationInfo, index) {
|
|
254
254
|
var changeType = path([relationInfo.uri, 0, 'type'], changes);
|
|
255
|
-
|
|
255
|
+
var relationChangeLineIds = path([relationInfo.uri, 0, 'lineIds'], changes);
|
|
256
|
+
return getRelationChanges(metadata, relationInfo, relationsTrees[index], changeType, relationChangeLineIds);
|
|
256
257
|
}));
|
|
257
258
|
return [entityChanges, relationsChanges];
|
|
258
259
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reltio/components",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.2207",
|
|
4
4
|
"license": "SEE LICENSE IN LICENSE FILE",
|
|
5
5
|
"main": "./cjs/index.js",
|
|
6
6
|
"module": "./index.js",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"@fluentui/react-context-selector": "^9.1.26",
|
|
12
12
|
"@googlemaps/markerclusterer": "^2.5.3",
|
|
13
13
|
"@react-sigma/core": "3.4.0",
|
|
14
|
-
"@reltio/mdm-sdk": "^1.4.
|
|
14
|
+
"@reltio/mdm-sdk": "^1.4.2009",
|
|
15
15
|
"@vis.gl/react-google-maps": "^1.3.0",
|
|
16
16
|
"d3-cloud": "^1.2.5",
|
|
17
17
|
"d3-geo": "^2.0.1",
|