Skip to content

Commit 4f15566

Browse files
committed
merge: merge branch 'THU/viewer_security_changes_PROD-14244'
2 parents a4598d6 + c8f2c39 commit 4f15566

File tree

19 files changed

+231
-209
lines changed

19 files changed

+231
-209
lines changed

cypress/commons/constants/generic/TestConstants.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ export const PERMISSIONS = {
120120

121121
export const ROLES_PERMISSIONS_MAP = {
122122
[ROLES.SCENARIO.VIEWER]: {
123-
granted: [PERMISSIONS.SCENARIO.READ, PERMISSIONS.SCENARIO.READ_SECURITY],
123+
granted: [PERMISSIONS.SCENARIO.READ],
124124
notGranted: [
125125
PERMISSIONS.SCENARIO.LAUNCH,
126126
PERMISSIONS.SCENARIO.WRITE,

cypress/e2e/brewery/ScenarioSharing.cy.js

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -147,25 +147,12 @@ describe('Check workspace permissions for Viewer, Editor & Validator', () => {
147147
stub.stop();
148148
});
149149

150-
it('Check Viewer permissions', () => {
150+
it('must show a disabled button when role is Viewer', () => {
151151
const scenario = SHARED_SCENARIOS_LIST[0];
152152
ScenarioSelector.selectScenario(scenario.name, scenario.id, true);
153153

154154
Scenarios.getScenarioValidateButton().should('not.exist');
155-
RolesEdition.getShareButton().should('be.visible').should('not.be.disabled').click();
156-
RolesEdition.getShareDialogAgentsSelect().should('not.exist');
157-
RolesEdition.getRoleEditorAgentName(USERS_LIST[1].email).should('have.text', USERS_LIST[1].email);
158-
RolesEdition.getSelectedOptionByAgent(USERS_LIST[1].email).should('value', ROLES.SCENARIO.VIEWER);
159-
RolesEdition.isRoleEditorSelectorDisabled(USERS_LIST[1].email).should('eq', 'true');
160-
RolesEdition.getRoleEditorAgentName(USERS_LIST[2].email).should('have.text', USERS_LIST[2].email);
161-
RolesEdition.getSelectedOptionByAgent(USERS_LIST[2].email).should('value', ROLES.SCENARIO.EDITOR);
162-
RolesEdition.isRoleEditorSelectorDisabled(USERS_LIST[2].email).should('eq', 'true');
163-
RolesEdition.getRoleEditorAgentName(USERS_LIST[3].email).should('have.text', USERS_LIST[3].email);
164-
RolesEdition.getSelectedOptionByAgent(USERS_LIST[3].email).should('value', ROLES.SCENARIO.VALIDATOR);
165-
RolesEdition.isRoleEditorSelectorDisabled(USERS_LIST[3].email).should('eq', 'true');
166-
RolesEdition.isRoleEditorSelectorDisabled('Workspace').should('eq', 'true');
167-
RolesEdition.getShareDialogConfirmAddAccessButton().should('not.exist');
168-
RolesEdition.getShareDialogFirstCancelButton().click();
155+
RolesEdition.getShareButton().should('be.visible').should('be.disabled');
169156

170157
Scenarios.getScenarioValidateButton().should('not.exist');
171158
Scenarios.getScenarioRejectButton().should('not.exist');
@@ -186,6 +173,21 @@ describe('Check workspace permissions for Viewer, Editor & Validator', () => {
186173
const scenario = SHARED_SCENARIOS_LIST[1];
187174
ScenarioSelector.selectScenario(scenario.name, scenario.id);
188175

176+
RolesEdition.getShareButton().should('be.visible').should('not.be.disabled').click();
177+
RolesEdition.getShareDialogAgentsSelect().should('not.exist');
178+
RolesEdition.getRoleEditorAgentName(USERS_LIST[1].email).should('have.text', USERS_LIST[1].email);
179+
RolesEdition.getSelectedOptionByAgent(USERS_LIST[1].email).should('value', ROLES.SCENARIO.VIEWER);
180+
RolesEdition.isRoleEditorSelectorDisabled(USERS_LIST[1].email).should('eq', 'true');
181+
RolesEdition.getRoleEditorAgentName(USERS_LIST[2].email).should('have.text', USERS_LIST[2].email);
182+
RolesEdition.getSelectedOptionByAgent(USERS_LIST[2].email).should('value', ROLES.SCENARIO.EDITOR);
183+
RolesEdition.isRoleEditorSelectorDisabled(USERS_LIST[2].email).should('eq', 'true');
184+
RolesEdition.getRoleEditorAgentName(USERS_LIST[3].email).should('have.text', USERS_LIST[3].email);
185+
RolesEdition.getSelectedOptionByAgent(USERS_LIST[3].email).should('value', ROLES.SCENARIO.VALIDATOR);
186+
RolesEdition.isRoleEditorSelectorDisabled(USERS_LIST[3].email).should('eq', 'true');
187+
RolesEdition.isRoleEditorSelectorDisabled('Workspace').should('eq', 'true');
188+
RolesEdition.getShareDialogConfirmAddAccessButton().should('not.exist');
189+
RolesEdition.getShareDialogFirstCancelButton().click();
190+
189191
Scenarios.getScenarioValidateButton().should('not.exist');
190192
Scenarios.getScenarioRejectButton().should('not.exist');
191193
ScenarioParameters.getLaunchButton().should('be.visible').should('not.be.disabled');

cypress/fixtures/stubbing/default/organizations.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ export const DEFAULT_ORGANIZATION_PERMISSIONS = [
66
component: 'organization',
77
roles: {
88
none: [],
9-
viewer: ['read', 'read_security'],
9+
viewer: ['read'],
1010
user: ['read', 'read_security', 'create_children'],
1111
editor: ['read', 'read_security', 'create_children', 'write'],
1212
admin: ['read', 'read_security', 'create_children', 'write', 'write_security', 'delete'],
@@ -16,7 +16,7 @@ export const DEFAULT_ORGANIZATION_PERMISSIONS = [
1616
component: 'workspace',
1717
roles: {
1818
none: [],
19-
viewer: ['read', 'read_security'],
19+
viewer: ['read'],
2020
user: ['read', 'read_security', 'create_children'],
2121
editor: ['read', 'read_security', 'create_children', 'write'],
2222
admin: ['read', 'read_security', 'create_children', 'write', 'write_security', 'delete'],
@@ -26,7 +26,7 @@ export const DEFAULT_ORGANIZATION_PERMISSIONS = [
2626
component: 'scenario',
2727
roles: {
2828
none: [],
29-
viewer: ['read', 'read_security'],
29+
viewer: ['read'],
3030
editor: ['read', 'read_security', 'launch', 'write'],
3131
validator: ['read', 'read_security', 'launch', 'write', 'validate'],
3232
admin: ['read', 'read_security', 'launch', 'write', 'validate', 'write_security', 'delete'],

public/locales/en/translation.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,8 @@
421421
"button": {
422422
"label": "Share",
423423
"tooltip": "Modify access",
424-
"editModeTooltip": "Please save or discard current modifications before changing the scenario access permissions"
424+
"editModeTooltip": "Please save or discard current modifications before changing the scenario access permissions",
425+
"noReadSecurityPermissionTooltip": "You are not allowed to share or see the security details of this resource"
425426
},
426427
"dialog": {
427428
"buttons": {

public/locales/fr/translation.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,8 @@
421421
"button": {
422422
"label": "Partager",
423423
"tooltip": "Modifier l'accès",
424-
"editModeTooltip": "Veuillez sauver ou annuler les modifications en cours avant de modifier les permissions d'accès du scénario"
424+
"editModeTooltip": "Veuillez sauver ou annuler les modifications en cours avant de modifier les permissions d'accès du scénario",
425+
"noReadSecurityPermissionTooltip": "Vous n'avez pas les permissions pour partager ou voir les informations de sécurité de cette ressource"
425426
},
426427
"dialog": {
427428
"buttons": {

src/components/ShareCurrentScenarioButton/ShareCurrentScenarioButton.js

Lines changed: 19 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,40 @@
11
// Copyright (c) Cosmo Tech.
22
// Licensed under the MIT license.
33
import React from 'react';
4-
import { PermissionsGate, RolesEditionButton } from '@cosmotech/ui';
5-
import { ACL_PERMISSIONS } from '../../services/config/accessControl';
4+
import { RolesEditionButton } from '@cosmotech/ui';
65
import { useShareCurrentScenarioButton } from './ShareCurrentScenarioButtonHook';
76

87
const ShareCurrentScenarioButton = () => {
98
const {
10-
isDirty,
9+
disabled,
10+
isReadOnly,
1111
accessListSpecific,
1212
applyScenarioSecurityChanges,
1313
defaultRole,
1414
permissionsLabels,
1515
permissionsMapping,
1616
rolesLabels,
1717
shareScenarioDialogLabels,
18-
userPermissionsOnCurrentScenario,
1918
workspaceUsers,
2019
} = useShareCurrentScenarioButton();
2120

2221
return (
23-
<>
24-
<PermissionsGate
25-
userPermissions={userPermissionsOnCurrentScenario}
26-
necessaryPermissions={[ACL_PERMISSIONS.SCENARIO.READ_SECURITY]}
27-
>
28-
<PermissionsGate
29-
userPermissions={userPermissionsOnCurrentScenario}
30-
necessaryPermissions={[ACL_PERMISSIONS.SCENARIO.WRITE_SECURITY]}
31-
noPermissionProps={{ isReadOnly: true }}
32-
>
33-
<RolesEditionButton
34-
data-cy="share-scenario-button"
35-
disabled={isDirty}
36-
labels={shareScenarioDialogLabels}
37-
onConfirmChanges={applyScenarioSecurityChanges}
38-
resourceRolesPermissionsMapping={permissionsMapping.scenario}
39-
agents={workspaceUsers}
40-
specificAccessByAgent={accessListSpecific}
41-
defaultRole={defaultRole}
42-
defaultAccessScope="Workspace"
43-
preventNoneRoleForAgents={true}
44-
allRoles={rolesLabels}
45-
allPermissions={permissionsLabels}
46-
isIconButton={true}
47-
/>
48-
</PermissionsGate>
49-
</PermissionsGate>
50-
</>
22+
<RolesEditionButton
23+
data-cy="share-scenario-button"
24+
disabled={disabled}
25+
isReadOnly={isReadOnly}
26+
labels={shareScenarioDialogLabels}
27+
onConfirmChanges={applyScenarioSecurityChanges}
28+
resourceRolesPermissionsMapping={permissionsMapping.scenario}
29+
agents={workspaceUsers}
30+
specificAccessByAgent={accessListSpecific}
31+
defaultRole={defaultRole}
32+
defaultAccessScope="Workspace"
33+
preventNoneRoleForAgents={true}
34+
allRoles={rolesLabels}
35+
allPermissions={permissionsLabels}
36+
isIconButton={true}
37+
/>
5138
);
5239
};
5340

src/components/ShareCurrentScenarioButton/ShareCurrentScenarioButton.spec.js

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,19 +50,23 @@ describe('ShareCurrentScenarioButton', () => {
5050
mockRoleEditionButtonProps = undefined;
5151
});
5252

53-
test('None role dont display Share Scenario button', () => {
54-
setUp(ROLES.SCENARIO.NONE);
55-
expect(getRolesEditionButton()).not.toBeInTheDocument();
56-
});
53+
test.each([{ role: ROLES.SCENARIO.NONE }, { role: ROLES.SCENARIO.VIEWER }])(
54+
'must show a disabled button when role is $role',
55+
({ role }) => {
56+
setUp(role);
57+
expect(getRolesEditionButton()).toBeInTheDocument();
58+
expect(mockRoleEditionButtonProps.disabled).toEqual(true);
59+
}
60+
);
5761

5862
test.each([
59-
{ role: ROLES.SCENARIO.ADMIN, expected: undefined },
63+
{ role: ROLES.SCENARIO.ADMIN, expected: false },
6064
{ role: ROLES.SCENARIO.EDITOR, expected: true },
6165
{ role: ROLES.SCENARIO.VALIDATOR, expected: true },
62-
{ role: ROLES.SCENARIO.VIEWER, expected: true },
6366
])('$role role display Share Scenario button with isReadOnly $expected', ({ role, expected }) => {
6467
setUp(role);
6568
expect(getRolesEditionButton()).toBeInTheDocument();
69+
expect(mockRoleEditionButtonProps.disabled).toEqual(false);
6670
expect(mockRoleEditionButtonProps.isReadOnly).toEqual(expected);
6771
});
6872
});

src/components/ShareCurrentScenarioButton/ShareCurrentScenarioButtonHook.js

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { useCallback, useMemo } from 'react';
44
import { useFormState } from 'react-hook-form';
55
import { useTranslation } from 'react-i18next';
66
import { useUserPermissionsOnCurrentScenario } from '../../hooks/SecurityHooks';
7+
import { ACL_PERMISSIONS } from '../../services/config/accessControl';
78
import {
89
useApplicationPermissionsMapping,
910
useApplicationRoles,
@@ -29,11 +30,6 @@ export const useShareCurrentScenarioButton = () => {
2930

3031
const applyScenarioSharingSecurity = useApplyScenarioSharingSecurity();
3132

32-
const shareScenarioDialogLabels = useMemo(
33-
() => getShareScenarioDialogLabels(t, currentScenarioData?.name, isDirty),
34-
[currentScenarioData?.name, t, isDirty]
35-
);
36-
3733
const rolesLabels = useMemo(() => {
3834
const rolesNames = Object.values(roles.scenario);
3935
return SecurityUtils.getRolesLabels(t, rolesNames);
@@ -63,9 +59,24 @@ export const useShareCurrentScenarioButton = () => {
6359
[applyScenarioSharingSecurity, currentScenarioData?.id]
6460
);
6561

62+
const hasReadSecurityPermission = useMemo(
63+
() => userPermissionsOnCurrentScenario.includes(ACL_PERMISSIONS.SCENARIO.READ_SECURITY),
64+
[userPermissionsOnCurrentScenario]
65+
);
66+
const disabled = useMemo(() => isDirty || !hasReadSecurityPermission, [isDirty, hasReadSecurityPermission]);
67+
const isReadOnly = useMemo(
68+
() => !userPermissionsOnCurrentScenario.includes(ACL_PERMISSIONS.SCENARIO.WRITE_SECURITY),
69+
[userPermissionsOnCurrentScenario]
70+
);
71+
72+
const shareScenarioDialogLabels = useMemo(
73+
() => getShareScenarioDialogLabels(t, currentScenarioData?.name, isDirty, hasReadSecurityPermission),
74+
[currentScenarioData?.name, t, isDirty, hasReadSecurityPermission]
75+
);
76+
6677
return {
67-
isDirty,
68-
userPermissionsOnCurrentScenario,
78+
disabled,
79+
isReadOnly,
6980
permissionsMapping,
7081
shareScenarioDialogLabels,
7182
rolesLabels,
Lines changed: 62 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,69 @@
11
// Copyright (c) Cosmo Tech.
22
// Licensed under the MIT license.
33

4-
export const getShareScenarioDialogLabels = (t, currentScenarioName, isDirty) => ({
5-
button: {
6-
title: t('commoncomponents.dialog.share.button.label', 'Share'),
7-
tooltip: isDirty
8-
? t(
9-
'commoncomponents.dialog.share.button.editModeTooltip',
10-
'Please save or discard current modifications before changing the scenario access permissions'
11-
)
12-
: t('commoncomponents.dialog.share.button.label', 'Share'),
13-
},
14-
dialog: {
15-
title: t('commoncomponents.dialog.share.dialog.title', 'Share ') + currentScenarioName,
16-
readOnlyTitle: t('commoncomponents.dialog.share.dialog.readOnlyTitle', 'Permissions for ') + currentScenarioName,
17-
addPeople: t('commoncomponents.dialog.share.dialog.select.addPeople', 'Add people'),
18-
cancel: t('commoncomponents.dialog.share.dialog.buttons.cancel', 'Cancel'),
19-
close: t('commoncomponents.dialog.share.dialog.buttons.close', 'Close'),
20-
share: t('commoncomponents.dialog.share.dialog.buttons.share', 'Share'),
21-
noAdminError: t(
22-
'commoncomponents.dialog.share.dialog.error.noAdmin',
23-
'The scenario must have at least one administrator'
24-
),
25-
userSelected: t('commoncomponents.dialog.share.dialog.select.userSelected', 'Selected user'),
26-
usersAccess: t('commoncomponents.dialog.share.dialog.editor.usersAccess', 'Users access'),
27-
generalAccess: t('commoncomponents.dialog.share.dialog.editor.generalAccess', 'General access'),
28-
removeAccess: t('commoncomponents.dialog.share.dialog.editor.removeAccess', 'Remove specific access'),
29-
editor: {
30-
helperText: {
31-
admin: t('commoncomponents.dialog.share.dialog.editor.helperText.admin', 'Anyone in this workspace is admin'),
32-
viewer: t(
33-
'commoncomponents.dialog.share.dialog.editor.helperText.viewer',
34-
'Anyone in this workspace is viewer'
35-
),
36-
validator: t(
37-
'commoncomponents.dialog.share.dialog.editor.helperText.validator',
38-
'Anyone in this workspace is validator'
39-
),
40-
editor: t(
41-
'commoncomponents.dialog.share.dialog.editor.helperText.editor',
42-
'Anyone in this workspace is editor'
43-
),
44-
none: t('commoncomponents.dialog.share.dialog.editor.helperText.none', 'Other users cannot view the scenario'),
45-
},
4+
export const getShareScenarioDialogLabels = (t, currentScenarioName, isDirty, hasReadSecurityPermission) => {
5+
let tooltip = t('commoncomponents.dialog.share.button.label', 'Share');
6+
if (!hasReadSecurityPermission)
7+
tooltip = t(
8+
'commoncomponents.dialog.share.button.noReadSecurityPermissionTooltip',
9+
'You are not allowed to share or see the security details of this resource'
10+
);
11+
else if (isDirty)
12+
tooltip = t(
13+
'commoncomponents.dialog.share.button.editModeTooltip',
14+
'Please save or discard current modifications before changing the scenario access permissions'
15+
);
16+
17+
return {
18+
button: {
19+
title: t('commoncomponents.dialog.share.button.label', 'Share'),
20+
tooltip,
4621
},
47-
add: {
22+
dialog: {
23+
title: t('commoncomponents.dialog.share.dialog.title', 'Share ') + currentScenarioName,
24+
readOnlyTitle: t('commoncomponents.dialog.share.dialog.readOnlyTitle', 'Permissions for ') + currentScenarioName,
25+
addPeople: t('commoncomponents.dialog.share.dialog.select.addPeople', 'Add people'),
4826
cancel: t('commoncomponents.dialog.share.dialog.buttons.cancel', 'Cancel'),
49-
deniedPermissions: t('commoncomponents.dialog.share.dialog.add.deniedPermissions', 'Not granted permissions'),
50-
done: t('commoncomponents.dialog.share.dialog.buttons.done', 'Done'),
51-
grantedPermissions: t('commoncomponents.dialog.share.dialog.add.grantedPermissions', 'Granted permissions'),
52-
rolesTitle: t('commoncomponents.dialog.share.dialog.add.rolesTitle', 'Roles'),
27+
close: t('commoncomponents.dialog.share.dialog.buttons.close', 'Close'),
28+
share: t('commoncomponents.dialog.share.dialog.buttons.share', 'Share'),
29+
noAdminError: t(
30+
'commoncomponents.dialog.share.dialog.error.noAdmin',
31+
'The scenario must have at least one administrator'
32+
),
5333
userSelected: t('commoncomponents.dialog.share.dialog.select.userSelected', 'Selected user'),
54-
rolesHelperText: t('commoncomponents.dialog.share.dialog.add.rolesHelperText', 'Select one role'),
34+
usersAccess: t('commoncomponents.dialog.share.dialog.editor.usersAccess', 'Users access'),
35+
generalAccess: t('commoncomponents.dialog.share.dialog.editor.generalAccess', 'General access'),
36+
removeAccess: t('commoncomponents.dialog.share.dialog.editor.removeAccess', 'Remove specific access'),
37+
editor: {
38+
helperText: {
39+
admin: t('commoncomponents.dialog.share.dialog.editor.helperText.admin', 'Anyone in this workspace is admin'),
40+
viewer: t(
41+
'commoncomponents.dialog.share.dialog.editor.helperText.viewer',
42+
'Anyone in this workspace is viewer'
43+
),
44+
validator: t(
45+
'commoncomponents.dialog.share.dialog.editor.helperText.validator',
46+
'Anyone in this workspace is validator'
47+
),
48+
editor: t(
49+
'commoncomponents.dialog.share.dialog.editor.helperText.editor',
50+
'Anyone in this workspace is editor'
51+
),
52+
none: t(
53+
'commoncomponents.dialog.share.dialog.editor.helperText.none',
54+
'Other users cannot view the scenario'
55+
),
56+
},
57+
},
58+
add: {
59+
cancel: t('commoncomponents.dialog.share.dialog.buttons.cancel', 'Cancel'),
60+
deniedPermissions: t('commoncomponents.dialog.share.dialog.add.deniedPermissions', 'Not granted permissions'),
61+
done: t('commoncomponents.dialog.share.dialog.buttons.done', 'Done'),
62+
grantedPermissions: t('commoncomponents.dialog.share.dialog.add.grantedPermissions', 'Granted permissions'),
63+
rolesTitle: t('commoncomponents.dialog.share.dialog.add.rolesTitle', 'Roles'),
64+
userSelected: t('commoncomponents.dialog.share.dialog.select.userSelected', 'Selected user'),
65+
rolesHelperText: t('commoncomponents.dialog.share.dialog.add.rolesHelperText', 'Select one role'),
66+
},
5567
},
56-
},
57-
});
68+
};
69+
};

0 commit comments

Comments
 (0)