Feat 17408 : Add remove option for object permissions rule (#17601)
This PR aims to fix: #17408 Main modification includes adding a new column for dropdown in the object permission rule table (containing options for editing and removal). Removal logic is implemented using existing pattern with hook ```useResetObjectPermission``` (relies on existing hooks ```useUpsertFieldPermissionInDraftRole``` and ```useUpsertObjectPermissionInDraftRole```). Feel free to suggest any necessary changes. Functionality (unrestricted access is allowed when permission removal is applied) is already tested. Demo video: https://drive.google.com/file/d/1M4RYHw-JEhDdJksKkL3MY_VyXAV3aS9I/view?usp=sharing --------- Co-authored-by: Etienne <45695613+etiennejouan@users.noreply.github.com>
This commit is contained in:
+1
@@ -16,5 +16,6 @@ export const SettingsRolePermissionsObjectLevelTableHeader = ({
|
||||
<TableHeader>{showPermissionsLabel ? t`See Fields` : ''}</TableHeader>
|
||||
<TableHeader>{showPermissionsLabel ? t`Edit Fields` : ''}</TableHeader>
|
||||
<TableHeader></TableHeader>
|
||||
<TableHeader></TableHeader>
|
||||
</TableRow>
|
||||
);
|
||||
|
||||
+16
-13
@@ -1,6 +1,7 @@
|
||||
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { SettingsRolePermissionsObjectLevelOverrideCellContainer } from '@/settings/roles/role-permissions/object-level-permissions/components/SettingsRolePermissionsObjectLevelOverrideCellContainer';
|
||||
import { SettingsRolePermissionsObjectLevelSeeFieldsValueForObject } from '@/settings/roles/role-permissions/object-level-permissions/components/SettingsRolePermissionsObjectLevelSeeFieldsValueForObject';
|
||||
import { SettingsRolePermissionsObjectLevelTableRowOptionsDropdown } from '@/settings/roles/role-permissions/object-level-permissions/components/SettingsRolePermissionsObjectLevelTableRowOptionsDropdown';
|
||||
import { SettingsRolePermissionsObjectLevelUpdateFieldsValueForObject } from '@/settings/roles/role-permissions/object-level-permissions/components/SettingsRolePermissionsObjectLevelUpdateFieldsValueForObject';
|
||||
import { OBJECT_LEVEL_PERMISSION_TABLE_GRID_AUTO_COLUMNS } from '@/settings/roles/role-permissions/object-level-permissions/constants/ObjectLevelPermissionTableGridAutoColumns';
|
||||
import { TableCell } from '@/ui/layout/table/components/TableCell';
|
||||
@@ -9,11 +10,7 @@ import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { SettingsPath } from 'twenty-shared/types';
|
||||
import { getSettingsPath } from 'twenty-shared/utils';
|
||||
import {
|
||||
IconChevronRight,
|
||||
OverflowingTextWithTooltip,
|
||||
useIcons,
|
||||
} from 'twenty-ui/display';
|
||||
import { OverflowingTextWithTooltip, useIcons } from 'twenty-ui/display';
|
||||
|
||||
const StyledNameTableCell = styled(TableCell)`
|
||||
color: ${({ theme }) => theme.font.color.primary};
|
||||
@@ -26,6 +23,11 @@ const StyledNameLabel = styled.div`
|
||||
overflow: hidden;
|
||||
`;
|
||||
|
||||
const StyledOptionsTableCell = styled(TableCell)`
|
||||
justify-content: flex-end;
|
||||
padding-right: ${({ theme }) => theme.spacing(1)};
|
||||
`;
|
||||
|
||||
type SettingsRolePermissionsObjectLevelTableRowProps = {
|
||||
objectMetadataItem: ObjectMetadataItem;
|
||||
roleId: string;
|
||||
@@ -90,14 +92,15 @@ export const SettingsRolePermissionsObjectLevelTableRow = ({
|
||||
objectMetadataItem={objectMetadataItem}
|
||||
/>
|
||||
</TableCell>
|
||||
{isEditable && (
|
||||
<TableCell align="right">
|
||||
<IconChevronRight
|
||||
size={theme.icon.size.md}
|
||||
color={theme.font.color.tertiary}
|
||||
/>
|
||||
</TableCell>
|
||||
)}
|
||||
<TableCell></TableCell>
|
||||
<StyledOptionsTableCell>
|
||||
<SettingsRolePermissionsObjectLevelTableRowOptionsDropdown
|
||||
roleId={roleId}
|
||||
objectMetadataId={objectMetadataItem.id}
|
||||
objectPermissionDetailUrl={navigationUrl}
|
||||
isEditable={isEditable}
|
||||
/>
|
||||
</StyledOptionsTableCell>
|
||||
</TableRow>
|
||||
);
|
||||
};
|
||||
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
import { useResetObjectPermission } from '@/settings/roles/role-permissions/object-level-permissions/hooks/useResetObjectPermission';
|
||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { IconDotsVertical, IconPencil, IconTrash } from 'twenty-ui/display';
|
||||
import { IconButton } from 'twenty-ui/input';
|
||||
import { MenuItem, UndecoratedLink } from 'twenty-ui/navigation';
|
||||
|
||||
type SettingsRolePermissionsObjectLevelTableRowOptionsDropdownProps = {
|
||||
roleId: string;
|
||||
objectMetadataId: string;
|
||||
objectPermissionDetailUrl: string;
|
||||
isEditable: boolean;
|
||||
};
|
||||
|
||||
export const SettingsRolePermissionsObjectLevelTableRowOptionsDropdown = ({
|
||||
roleId,
|
||||
objectMetadataId,
|
||||
objectPermissionDetailUrl,
|
||||
isEditable,
|
||||
}: SettingsRolePermissionsObjectLevelTableRowOptionsDropdownProps) => {
|
||||
const dropdownId = `settings-role-object-level-options-${objectMetadataId}`;
|
||||
|
||||
const { closeDropdown } = useCloseDropdown();
|
||||
|
||||
const { resetObjectPermission } = useResetObjectPermission(roleId);
|
||||
|
||||
const handleRemove = () => {
|
||||
closeDropdown(dropdownId);
|
||||
resetObjectPermission(objectMetadataId);
|
||||
};
|
||||
|
||||
return (
|
||||
<Dropdown
|
||||
dropdownId={dropdownId}
|
||||
clickableComponent={
|
||||
<IconButton
|
||||
aria-label={t`Object permission options`}
|
||||
variant="tertiary"
|
||||
size="small"
|
||||
Icon={IconDotsVertical}
|
||||
/>
|
||||
}
|
||||
dropdownComponents={
|
||||
<DropdownContent>
|
||||
{isEditable && (
|
||||
<DropdownMenuItemsContainer>
|
||||
<UndecoratedLink
|
||||
fullWidth
|
||||
to={objectPermissionDetailUrl}
|
||||
onClick={() => closeDropdown(dropdownId)}
|
||||
>
|
||||
<MenuItem text={t`Edit`} LeftIcon={IconPencil} />
|
||||
</UndecoratedLink>
|
||||
</DropdownMenuItemsContainer>
|
||||
)}
|
||||
<DropdownMenuItemsContainer>
|
||||
<MenuItem
|
||||
text={t`Remove rule`}
|
||||
onClick={handleRemove}
|
||||
LeftIcon={IconTrash}
|
||||
accent="danger"
|
||||
/>
|
||||
</DropdownMenuItemsContainer>
|
||||
</DropdownContent>
|
||||
}
|
||||
dropdownPlacement="bottom-end"
|
||||
/>
|
||||
);
|
||||
};
|
||||
+1
-1
@@ -4,7 +4,7 @@ const {
|
||||
} = {
|
||||
OBJECT_LEVEL_PERMISSION_TABLE_GRID_AUTO_COLUMNS_WITHOUT_FIELD_PERMISSIONS:
|
||||
'180px 1fr 1fr',
|
||||
OBJECT_LEVEL_PERMISSION_TABLE_GRID_AUTO_COLUMNS: '30% 20% 20% 20% 10%',
|
||||
OBJECT_LEVEL_PERMISSION_TABLE_GRID_AUTO_COLUMNS: '28% 18% 18% 18% 8% 10%',
|
||||
};
|
||||
|
||||
export {
|
||||
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
import { useUpsertFieldPermissionInDraftRole } from '@/settings/roles/role-permissions/object-level-permissions/field-permissions/hooks/useUpsertFieldPermissionInDraftRole';
|
||||
import { useUpsertObjectPermissionInDraftRole } from '@/settings/roles/role-permissions/object-level-permissions/hooks/useUpsertObjectPermissionInDraftRole';
|
||||
import { type SettingsRoleObjectPermissionKey } from '@/settings/roles/role-permissions/objects-permissions/constants/SettingsRoleObjectPermissionIconConfig';
|
||||
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import {
|
||||
type FieldPermission,
|
||||
type ObjectPermission,
|
||||
} from '~/generated-metadata/graphql';
|
||||
|
||||
const OBJECT_PERMISSION_KEYS: SettingsRoleObjectPermissionKey[] = [
|
||||
'canReadObjectRecords',
|
||||
'canUpdateObjectRecords',
|
||||
'canSoftDeleteObjectRecords',
|
||||
'canDestroyObjectRecords',
|
||||
];
|
||||
|
||||
export const useResetObjectPermission = (roleId: string) => {
|
||||
const settingsDraftRole = useRecoilValue(
|
||||
settingsDraftRoleFamilyState(roleId),
|
||||
);
|
||||
|
||||
const { upsertObjectPermissionInDraftRole } =
|
||||
useUpsertObjectPermissionInDraftRole(roleId);
|
||||
|
||||
const { upsertFieldPermissionInDraftRole } =
|
||||
useUpsertFieldPermissionInDraftRole(roleId);
|
||||
|
||||
const resetObjectPermission = (objectMetadataItemId: string) => {
|
||||
const fieldPermissionsForCurrentObject =
|
||||
settingsDraftRole.fieldPermissions?.filter(
|
||||
(permission) => permission.objectMetadataId === objectMetadataItemId,
|
||||
) ?? [];
|
||||
const existingObjectPermission = settingsDraftRole.objectPermissions?.find(
|
||||
(objectPermissionToFind) =>
|
||||
objectPermissionToFind.objectMetadataId === objectMetadataItemId,
|
||||
);
|
||||
|
||||
const resetPermissions = OBJECT_PERMISSION_KEYS.reduce(
|
||||
(acc, permissionKey) => {
|
||||
acc[permissionKey] = null;
|
||||
return acc;
|
||||
},
|
||||
{} as Record<SettingsRoleObjectPermissionKey, null>,
|
||||
);
|
||||
|
||||
if (!isDefined(existingObjectPermission)) {
|
||||
const newObjectPermission = {
|
||||
objectMetadataId: objectMetadataItemId,
|
||||
...resetPermissions,
|
||||
} satisfies ObjectPermission;
|
||||
|
||||
upsertObjectPermissionInDraftRole(newObjectPermission);
|
||||
} else {
|
||||
const updatedObjectPermission = {
|
||||
...existingObjectPermission,
|
||||
...resetPermissions,
|
||||
};
|
||||
|
||||
upsertObjectPermissionInDraftRole(updatedObjectPermission);
|
||||
}
|
||||
|
||||
fieldPermissionsForCurrentObject.forEach(
|
||||
(fieldPermission: FieldPermission) => {
|
||||
upsertFieldPermissionInDraftRole({
|
||||
...fieldPermission,
|
||||
canUpdateFieldValue: null,
|
||||
canReadFieldValue: null,
|
||||
});
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
return {
|
||||
resetObjectPermission,
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user