@reltio/components 1.4.2177 → 1.4.2179

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.
@@ -28,7 +28,10 @@ export var InlineSimpleAttribute = function (_a) {
28
28
  var id = getLastUriPart(attributeValue.uri);
29
29
  var crosswalkDisabled = isCrosswalkDisabled(crosswalk);
30
30
  var canModifyAttribute = !attributeType.system && !crosswalkDisabled;
31
- var canEdit = canModifyAttribute && !disableEdit && checkMetadataForUpdate(Mode.Editing, attributeType);
31
+ var canEdit = canModifyAttribute &&
32
+ !disableEdit &&
33
+ checkMetadataForUpdate(Mode.Editing, attributeType) &&
34
+ (!attributeValue.masked || isUnmaskingNeeded);
32
35
  var canDelete = canModifyAttribute && !disableDelete && checkMetadataForDelete(Mode.Editing, attributeType);
33
36
  var isTemporary = isTempUri(attributeValue.uri);
34
37
  var hasBasicPermission = checkBasicMetadataPermission(MetadataPermissions.UPDATE, attributeType) && !disableEdit && canModifyAttribute;
@@ -50,8 +50,9 @@ import { render, screen } from '@testing-library/react';
50
50
  import userEvent from '@testing-library/user-event';
51
51
  import { InlineSimpleAttribute } from './InlineSimpleAttribute';
52
52
  import * as crosswalksDisplay from '../contexts/CrosswalksDisplayContext';
53
- import { createNewAttribute } from '@reltio/mdm-sdk';
53
+ import { createNewAttribute, Mode } from '@reltio/mdm-sdk';
54
54
  import { MdmModuleProvider } from '../contexts/MdmModuleContext';
55
+ import { MaskedAttributesProvider } from '../contexts/MaskedAttributesContext';
55
56
  jest.mock('@reltio/mdm-sdk', function () { return (__assign(__assign({}, jest.requireActual('@reltio/mdm-sdk')), { debounce: function (x) { return x; } })); });
56
57
  var defaultProps = {
57
58
  attributeValue: {
@@ -83,13 +84,15 @@ var metadata = {
83
84
  entityTypes: [],
84
85
  sources: []
85
86
  };
86
- var setUp = function (props, skipHover) {
87
+ var setUp = function (props, skipHover, providerValues) {
87
88
  if (props === void 0) { props = {}; }
88
89
  if (skipHover === void 0) { skipHover = false; }
90
+ if (providerValues === void 0) { providerValues = {}; }
89
91
  var user = userEvent.setup({ skipHover: skipHover });
90
92
  var Providers = function (_a) {
91
93
  var children = _a.children;
92
- return (React.createElement(MdmModuleProvider, { values: { metadata: metadata } }, children));
94
+ return (React.createElement(MdmModuleProvider, { values: __assign({ metadata: metadata }, providerValues) },
95
+ React.createElement(MaskedAttributesProvider, null, children)));
93
96
  };
94
97
  return __assign({ user: user }, render(React.createElement(InlineSimpleAttribute, __assign({}, defaultProps, props)), { wrapper: Providers }));
95
98
  };
@@ -231,7 +234,7 @@ describe('Inline simple attribute tests', function () {
231
234
  deleteButton = screen.getByLabelText("You don't have permissions to delete");
232
235
  expect(deleteButton.children[0]).toHaveAttribute('aria-disabled', 'true');
233
236
  expect(deleteButton).toHaveTextContent('Delete');
234
- expect(screen.getByText('Edit').parentElement).not.toHaveAttribute('aria-disabled', 'true');
237
+ expect(screen.getByText('Edit')).not.toBeDisabled();
235
238
  return [2 /*return*/];
236
239
  }
237
240
  });
@@ -457,4 +460,60 @@ describe('Inline simple attribute tests', function () {
457
460
  }
458
461
  });
459
462
  }); });
463
+ it('should disable edit action for masked attributes when user has no READ permissions', function () { return __awaiter(void 0, void 0, void 0, function () {
464
+ var mockEntity, user, editButton;
465
+ return __generator(this, function (_a) {
466
+ switch (_a.label) {
467
+ case 0:
468
+ mockEntity = {
469
+ uri: 'entities/123',
470
+ type: 'configuration/entityTypes/Individual',
471
+ access: ['READ_MASKED'],
472
+ label: 'Test Entity'
473
+ };
474
+ user = setUp({
475
+ attributeType: __assign(__assign({}, defaultProps.attributeType), { access: ['READ_MASKED'], masking: true }),
476
+ attributeValue: __assign(__assign({}, defaultProps.attributeValue), { masked: true, value: '****' })
477
+ }, true, { entity: mockEntity, showMasking: true, mode: Mode.Viewing }).user;
478
+ return [4 /*yield*/, user.hover(screen.getByText('****'))];
479
+ case 1:
480
+ _a.sent();
481
+ return [4 /*yield*/, user.click(screen.getByLabelText('More actions'))];
482
+ case 2:
483
+ _a.sent();
484
+ editButton = screen.getByLabelText("You don't have permissions to edit");
485
+ expect(editButton.children[0]).toHaveAttribute('aria-disabled', 'true');
486
+ expect(editButton).toHaveTextContent('Edit');
487
+ return [2 /*return*/];
488
+ }
489
+ });
490
+ }); });
491
+ it('should enable edit action for masked attributes when user has needed permissions including READ', function () { return __awaiter(void 0, void 0, void 0, function () {
492
+ var mockEntity, user, editButton;
493
+ return __generator(this, function (_a) {
494
+ switch (_a.label) {
495
+ case 0:
496
+ mockEntity = {
497
+ uri: 'entities/123',
498
+ type: 'configuration/entityTypes/Individual',
499
+ access: ['READ_MASKED', 'READ'],
500
+ label: 'Test Entity'
501
+ };
502
+ user = setUp({
503
+ attributeType: __assign(__assign({}, defaultProps.attributeType), { access: ['UPDATE', 'READ_MASKED', 'READ'], masking: true }),
504
+ attributeValue: __assign(__assign({}, defaultProps.attributeValue), { masked: true, value: '****' })
505
+ }, true, { entity: mockEntity, showMasking: true, mode: Mode.Viewing }).user;
506
+ return [4 /*yield*/, user.hover(screen.getByText('****'))];
507
+ case 1:
508
+ _a.sent();
509
+ return [4 /*yield*/, user.click(screen.getByLabelText('More actions'))];
510
+ case 2:
511
+ _a.sent();
512
+ editButton = screen.getByText('Edit');
513
+ expect(editButton).not.toBeDisabled();
514
+ expect(screen.queryByLabelText("You don't have permissions to edit")).not.toBeInTheDocument();
515
+ return [2 /*return*/];
516
+ }
517
+ });
518
+ }); });
460
519
  });
@@ -57,7 +57,10 @@ var InlineSimpleAttribute = function (_a) {
57
57
  var id = (0, mdm_sdk_1.getLastUriPart)(attributeValue.uri);
58
58
  var crosswalkDisabled = (0, mdm_sdk_1.isCrosswalkDisabled)(crosswalk);
59
59
  var canModifyAttribute = !attributeType.system && !crosswalkDisabled;
60
- var canEdit = canModifyAttribute && !disableEdit && (0, mdm_sdk_1.checkMetadataForUpdate)(mdm_sdk_1.Mode.Editing, attributeType);
60
+ var canEdit = canModifyAttribute &&
61
+ !disableEdit &&
62
+ (0, mdm_sdk_1.checkMetadataForUpdate)(mdm_sdk_1.Mode.Editing, attributeType) &&
63
+ (!attributeValue.masked || isUnmaskingNeeded);
61
64
  var canDelete = canModifyAttribute && !disableDelete && (0, mdm_sdk_1.checkMetadataForDelete)(mdm_sdk_1.Mode.Editing, attributeType);
62
65
  var isTemporary = (0, mdm_sdk_1.isTempUri)(attributeValue.uri);
63
66
  var hasBasicPermission = (0, mdm_sdk_1.checkBasicMetadataPermission)(mdm_sdk_1.MetadataPermissions.UPDATE, attributeType) && !disableEdit && canModifyAttribute;
@@ -80,6 +80,7 @@ var InlineSimpleAttribute_1 = require("./InlineSimpleAttribute");
80
80
  var crosswalksDisplay = __importStar(require("../contexts/CrosswalksDisplayContext"));
81
81
  var mdm_sdk_1 = require("@reltio/mdm-sdk");
82
82
  var MdmModuleContext_1 = require("../contexts/MdmModuleContext");
83
+ var MaskedAttributesContext_1 = require("../contexts/MaskedAttributesContext");
83
84
  jest.mock('@reltio/mdm-sdk', function () { return (__assign(__assign({}, jest.requireActual('@reltio/mdm-sdk')), { debounce: function (x) { return x; } })); });
84
85
  var defaultProps = {
85
86
  attributeValue: {
@@ -111,13 +112,15 @@ var metadata = {
111
112
  entityTypes: [],
112
113
  sources: []
113
114
  };
114
- var setUp = function (props, skipHover) {
115
+ var setUp = function (props, skipHover, providerValues) {
115
116
  if (props === void 0) { props = {}; }
116
117
  if (skipHover === void 0) { skipHover = false; }
118
+ if (providerValues === void 0) { providerValues = {}; }
117
119
  var user = user_event_1.default.setup({ skipHover: skipHover });
118
120
  var Providers = function (_a) {
119
121
  var children = _a.children;
120
- return (react_1.default.createElement(MdmModuleContext_1.MdmModuleProvider, { values: { metadata: metadata } }, children));
122
+ return (react_1.default.createElement(MdmModuleContext_1.MdmModuleProvider, { values: __assign({ metadata: metadata }, providerValues) },
123
+ react_1.default.createElement(MaskedAttributesContext_1.MaskedAttributesProvider, null, children)));
121
124
  };
122
125
  return __assign({ user: user }, (0, react_2.render)(react_1.default.createElement(InlineSimpleAttribute_1.InlineSimpleAttribute, __assign({}, defaultProps, props)), { wrapper: Providers }));
123
126
  };
@@ -259,7 +262,7 @@ describe('Inline simple attribute tests', function () {
259
262
  deleteButton = react_2.screen.getByLabelText("You don't have permissions to delete");
260
263
  expect(deleteButton.children[0]).toHaveAttribute('aria-disabled', 'true');
261
264
  expect(deleteButton).toHaveTextContent('Delete');
262
- expect(react_2.screen.getByText('Edit').parentElement).not.toHaveAttribute('aria-disabled', 'true');
265
+ expect(react_2.screen.getByText('Edit')).not.toBeDisabled();
263
266
  return [2 /*return*/];
264
267
  }
265
268
  });
@@ -485,4 +488,60 @@ describe('Inline simple attribute tests', function () {
485
488
  }
486
489
  });
487
490
  }); });
491
+ it('should disable edit action for masked attributes when user has no READ permissions', function () { return __awaiter(void 0, void 0, void 0, function () {
492
+ var mockEntity, user, editButton;
493
+ return __generator(this, function (_a) {
494
+ switch (_a.label) {
495
+ case 0:
496
+ mockEntity = {
497
+ uri: 'entities/123',
498
+ type: 'configuration/entityTypes/Individual',
499
+ access: ['READ_MASKED'],
500
+ label: 'Test Entity'
501
+ };
502
+ user = setUp({
503
+ attributeType: __assign(__assign({}, defaultProps.attributeType), { access: ['READ_MASKED'], masking: true }),
504
+ attributeValue: __assign(__assign({}, defaultProps.attributeValue), { masked: true, value: '****' })
505
+ }, true, { entity: mockEntity, showMasking: true, mode: mdm_sdk_1.Mode.Viewing }).user;
506
+ return [4 /*yield*/, user.hover(react_2.screen.getByText('****'))];
507
+ case 1:
508
+ _a.sent();
509
+ return [4 /*yield*/, user.click(react_2.screen.getByLabelText('More actions'))];
510
+ case 2:
511
+ _a.sent();
512
+ editButton = react_2.screen.getByLabelText("You don't have permissions to edit");
513
+ expect(editButton.children[0]).toHaveAttribute('aria-disabled', 'true');
514
+ expect(editButton).toHaveTextContent('Edit');
515
+ return [2 /*return*/];
516
+ }
517
+ });
518
+ }); });
519
+ it('should enable edit action for masked attributes when user has needed permissions including READ', function () { return __awaiter(void 0, void 0, void 0, function () {
520
+ var mockEntity, user, editButton;
521
+ return __generator(this, function (_a) {
522
+ switch (_a.label) {
523
+ case 0:
524
+ mockEntity = {
525
+ uri: 'entities/123',
526
+ type: 'configuration/entityTypes/Individual',
527
+ access: ['READ_MASKED', 'READ'],
528
+ label: 'Test Entity'
529
+ };
530
+ user = setUp({
531
+ attributeType: __assign(__assign({}, defaultProps.attributeType), { access: ['UPDATE', 'READ_MASKED', 'READ'], masking: true }),
532
+ attributeValue: __assign(__assign({}, defaultProps.attributeValue), { masked: true, value: '****' })
533
+ }, true, { entity: mockEntity, showMasking: true, mode: mdm_sdk_1.Mode.Viewing }).user;
534
+ return [4 /*yield*/, user.hover(react_2.screen.getByText('****'))];
535
+ case 1:
536
+ _a.sent();
537
+ return [4 /*yield*/, user.click(react_2.screen.getByLabelText('More actions'))];
538
+ case 2:
539
+ _a.sent();
540
+ editButton = react_2.screen.getByText('Edit');
541
+ expect(editButton).not.toBeDisabled();
542
+ expect(react_2.screen.queryByLabelText("You don't have permissions to edit")).not.toBeInTheDocument();
543
+ return [2 /*return*/];
544
+ }
545
+ });
546
+ }); });
488
547
  });
@@ -56,7 +56,7 @@ var useRelationsLoader = function (_a) {
56
56
  };
57
57
  var suggested = config.suggested;
58
58
  var options = (0, react_1.useMemo)(function () {
59
- var sendMasked = showMasking && (0, mdm_sdk_1.hasRelationMasking)(metadata) && mode === mdm_sdk_1.Mode.Viewing;
59
+ var sendMasked = showMasking && ((0, mdm_sdk_1.hasRelationMasking)(metadata) || (0, mdm_sdk_1.hasAttributeMasking)(metadata)) && mode === mdm_sdk_1.Mode.Viewing;
60
60
  return (0, mdm_sdk_1.addRelationMaskingOptions)({ searchByOv: searchByOv, searchRelationsWithFilter: searchRelationsWithFilter }, sendMasked);
61
61
  }, [searchByOv, showMasking, metadata, mode, searchRelationsWithFilter]);
62
62
  var filters = (0, react_1.useMemo)(function () {
@@ -12,7 +12,7 @@ var __assign = (this && this.__assign) || function () {
12
12
  import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
13
13
  import { cond, pipe, prop, T, evolve, filter as filterFn, when, identity, times, length, ifElse, always } from 'ramda';
14
14
  import i18n from 'ui-i18n';
15
- import { ActivityFilter, addGlobalFilterToQuery, getRelationsForDataTenantEntity, getRelationsForEntity, isAvailableEntityTypeUri, isAvailableRelationTypeUri, isDataTenantEntity, getInOutRelationUri, isTempUri, Mode, wrapInArrayIfNeeded, hasRelationMasking, addRelationMaskingOptions } from '@reltio/mdm-sdk';
15
+ import { ActivityFilter, addGlobalFilterToQuery, getRelationsForDataTenantEntity, getRelationsForEntity, isAvailableEntityTypeUri, isAvailableRelationTypeUri, isDataTenantEntity, getInOutRelationUri, isTempUri, Mode, wrapInArrayIfNeeded, hasRelationMasking, hasAttributeMasking, addRelationMaskingOptions } from '@reltio/mdm-sdk';
16
16
  import { useSafePromise } from '../useSafePromise';
17
17
  import { usePrevious } from '../usePrevious';
18
18
  import { useMdmAction, useMdmDtssPath, useMdmGlobalSearchRequestOptions, useMdmMetadata, useMdmProfileLastLoadedTime, useMdmShowMasking, useMdmTenant } from '../../contexts/MdmModuleContext';
@@ -50,7 +50,7 @@ export var useRelationsLoader = function (_a) {
50
50
  };
51
51
  var suggested = config.suggested;
52
52
  var options = useMemo(function () {
53
- var sendMasked = showMasking && hasRelationMasking(metadata) && mode === Mode.Viewing;
53
+ var sendMasked = showMasking && (hasRelationMasking(metadata) || hasAttributeMasking(metadata)) && mode === Mode.Viewing;
54
54
  return addRelationMaskingOptions({ searchByOv: searchByOv, searchRelationsWithFilter: searchRelationsWithFilter }, sendMasked);
55
55
  }, [searchByOv, showMasking, metadata, mode, searchRelationsWithFilter]);
56
56
  var filters = useMemo(function () {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reltio/components",
3
- "version": "1.4.2177",
3
+ "version": "1.4.2179",
4
4
  "license": "SEE LICENSE IN LICENSE FILE",
5
5
  "main": "./cjs/index.js",
6
6
  "module": "./index.js",