Skip to content

Commit e1bdb4c

Browse files
committed
fix: [PROD-14244] show disabled share buttons to resources viewers
1 parent 17ee19e commit e1bdb4c

File tree

8 files changed

+186
-168
lines changed

8 files changed

+186
-168
lines changed

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/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+
};

src/components/ShareDatasetButton/ShareDatasetButton.js

Lines changed: 22 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
// Copyright (c) Cosmo Tech.
22
// Licensed under the MIT license.
3-
import React, { useMemo } from 'react';
3+
import React from 'react';
44
import PropTypes from 'prop-types';
55
import { PermissionsGate, RolesEditionButton } from '@cosmotech/ui';
6-
import { INGESTION_STATUS } from '../../services/config/ApiConstants';
76
import { ACL_PERMISSIONS } from '../../services/config/accessControl';
87
import { useShareDatasetButton } from './ShareDatasetButtonHook';
98

@@ -15,40 +14,38 @@ const ShareDatasetButton = ({ dataset }) => {
1514
permissionsLabels,
1615
permissionsMapping,
1716
rolesLabels,
18-
shareDatasetDialogLabels,
17+
buildShareDatasetDialogLabels,
1918
getUserPermissionOnDataset,
2019
workspaceUsers,
2120
} = useShareDatasetButton();
2221

2322
const datasetId = dataset?.id;
24-
const isDisabled = useMemo(() => !dataset || dataset.ingestionStatus === INGESTION_STATUS.PENDING, [dataset]);
23+
const userPermissions = getUserPermissionOnDataset(datasetId);
24+
const hasReadSecurityPermission = userPermissions.includes(ACL_PERMISSIONS.DATASET.READ_SECURITY);
25+
const isDisabled = !dataset || !hasReadSecurityPermission;
26+
const labels = buildShareDatasetDialogLabels(dataset, hasReadSecurityPermission);
2527

2628
return (
2729
<>
2830
<PermissionsGate
2931
userPermissions={getUserPermissionOnDataset(datasetId)}
30-
necessaryPermissions={[ACL_PERMISSIONS.DATASET.READ_SECURITY]}
32+
necessaryPermissions={[ACL_PERMISSIONS.DATASET.WRITE_SECURITY]}
33+
noPermissionProps={{ isReadOnly: true }}
3134
>
32-
<PermissionsGate
33-
userPermissions={getUserPermissionOnDataset(datasetId)}
34-
necessaryPermissions={[ACL_PERMISSIONS.DATASET.WRITE_SECURITY]}
35-
noPermissionProps={{ isReadOnly: true }}
36-
>
37-
<RolesEditionButton
38-
disabled={isDisabled}
39-
isIconButton={true}
40-
labels={shareDatasetDialogLabels(datasetId)}
41-
onConfirmChanges={(security) => updateDatasetSecurity(datasetId, security)}
42-
resourceRolesPermissionsMapping={permissionsMapping.dataset}
43-
agents={workspaceUsers}
44-
specificAccessByAgent={accessListSpecific(datasetId)}
45-
defaultRole={defaultRole(datasetId)}
46-
defaultAccessScope="Workspace"
47-
preventNoneRoleForAgents={true}
48-
allRoles={rolesLabels}
49-
allPermissions={permissionsLabels}
50-
/>
51-
</PermissionsGate>
35+
<RolesEditionButton
36+
disabled={isDisabled}
37+
isIconButton={true}
38+
labels={labels}
39+
onConfirmChanges={(security) => updateDatasetSecurity(datasetId, security)}
40+
resourceRolesPermissionsMapping={permissionsMapping.dataset}
41+
agents={workspaceUsers}
42+
specificAccessByAgent={accessListSpecific(datasetId)}
43+
defaultRole={defaultRole(datasetId)}
44+
defaultAccessScope="Workspace"
45+
preventNoneRoleForAgents={true}
46+
allRoles={rolesLabels}
47+
allPermissions={permissionsLabels}
48+
/>
5249
</PermissionsGate>
5350
</>
5451
);

src/components/ShareDatasetButton/ShareDatasetButtonHook.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ export const useShareDatasetButton = () => {
2828

2929
const updateDatasetSecurity = useUpdateDatasetSecurity();
3030

31-
const shareDatasetDialogLabels = useCallback(
32-
(datasetId) => getShareDatasetDialogLabels(t, findDatasetById(datasetId)?.name),
33-
[findDatasetById, t]
31+
const buildShareDatasetDialogLabels = useCallback(
32+
(dataset, hasReadSecurityPermission) => getShareDatasetDialogLabels(t, dataset?.name, hasReadSecurityPermission),
33+
[t]
3434
);
3535

3636
const rolesLabels = useMemo(() => {
@@ -58,7 +58,7 @@ export const useShareDatasetButton = () => {
5858
return {
5959
getUserPermissionOnDataset,
6060
permissionsMapping,
61-
shareDatasetDialogLabels,
61+
buildShareDatasetDialogLabels,
6262
rolesLabels,
6363
permissionsLabels,
6464
workspaceUsers,

0 commit comments

Comments
 (0)