[permissions][FE] followup design fixes 4 (#12737)
## Context - Whole row is now clickable - Fix padding on role tables - Fix tab being persistant between roles - Change various texts/descriptions - Add un/check all on settings permissions - Fix flash between role detail and roles - Add "Granted for X object(s)" - Swap permissions and assignment tabs position - add tooltip for object level permission actions - Add the inherited info on object-level permissions
This commit is contained in:
@ -19,7 +19,7 @@ export const SettingsRolesContainer = () => {
|
|||||||
const settingsAllRoles = useRecoilValue(settingsAllRolesSelector);
|
const settingsAllRoles = useRecoilValue(settingsAllRolesSelector);
|
||||||
const settingsRolesIsLoading = useRecoilValue(settingsRolesIsLoadingState);
|
const settingsRolesIsLoading = useRecoilValue(settingsRolesIsLoadingState);
|
||||||
|
|
||||||
if (settingsRolesIsLoading) {
|
if (settingsRolesIsLoading && !settingsAllRoles) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -60,9 +60,13 @@ export const SettingsRoleDefaultRole = ({
|
|||||||
const options = roles.map((role) => ({
|
const options = roles.map((role) => ({
|
||||||
label: role.label,
|
label: role.label,
|
||||||
value: role.id,
|
value: role.id,
|
||||||
Icon: getIcon(role.icon),
|
Icon: getIcon(role.icon) ?? IconUserPin,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
if (options.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Section>
|
<Section>
|
||||||
<H2Title
|
<H2Title
|
||||||
|
|||||||
@ -49,7 +49,7 @@ export const SettingsRolesList = () => {
|
|||||||
<Section>
|
<Section>
|
||||||
<H2Title
|
<H2Title
|
||||||
title={t`All roles`}
|
title={t`All roles`}
|
||||||
description={t`Assign roles to specify each member's access permissions`}
|
description={t`Assign roles to manage each member’s access and permissions`}
|
||||||
/>
|
/>
|
||||||
<Table>
|
<Table>
|
||||||
<SettingsRolesTableHeader />
|
<SettingsRolesTableHeader />
|
||||||
|
|||||||
@ -113,7 +113,7 @@ export const SettingsRolePermissionsObjectLevelObjectPicker = ({
|
|||||||
[objectMetadataItems, searchFilter, excludedObjectMetadataIds],
|
[objectMetadataItems, searchFilter, excludedObjectMetadataIds],
|
||||||
);
|
);
|
||||||
|
|
||||||
const basicObjects = filteredObjectMetadataItems.filter(
|
const standardObjects = filteredObjectMetadataItems.filter(
|
||||||
(item) => !item.isCustom,
|
(item) => !item.isCustom,
|
||||||
);
|
);
|
||||||
const customObjects = filteredObjectMetadataItems.filter(
|
const customObjects = filteredObjectMetadataItems.filter(
|
||||||
@ -135,11 +135,14 @@ export const SettingsRolePermissionsObjectLevelObjectPicker = ({
|
|||||||
</StyledSearchContainer>
|
</StyledSearchContainer>
|
||||||
</Section>
|
</Section>
|
||||||
|
|
||||||
{basicObjects.length > 0 && (
|
{standardObjects.length > 0 && (
|
||||||
<Section>
|
<Section>
|
||||||
<H2Title title={t`Basics`} description={t`All the basic objects`} />
|
<H2Title
|
||||||
|
title={t`Standard`}
|
||||||
|
description={t`All the standard objects`}
|
||||||
|
/>
|
||||||
<StyledContainer>
|
<StyledContainer>
|
||||||
{basicObjects.map((objectMetadataItem) => {
|
{standardObjects.map((objectMetadataItem) => {
|
||||||
const Icon = getIcon(objectMetadataItem.icon);
|
const Icon = getIcon(objectMetadataItem.icon);
|
||||||
return (
|
return (
|
||||||
<StyledCardContainer
|
<StyledCardContainer
|
||||||
@ -151,7 +154,7 @@ export const SettingsRolePermissionsObjectLevelObjectPicker = ({
|
|||||||
<SettingsCard
|
<SettingsCard
|
||||||
Icon={
|
Icon={
|
||||||
<Icon
|
<Icon
|
||||||
size={theme.icon.size.xl}
|
size={theme.icon.size.lg}
|
||||||
stroke={theme.icon.stroke.sm}
|
stroke={theme.icon.stroke.sm}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
@ -181,7 +184,7 @@ export const SettingsRolePermissionsObjectLevelObjectPicker = ({
|
|||||||
key={objectMetadataItem.id}
|
key={objectMetadataItem.id}
|
||||||
Icon={
|
Icon={
|
||||||
<Icon
|
<Icon
|
||||||
size={theme.icon.size.xl}
|
size={theme.icon.size.lg}
|
||||||
stroke={theme.icon.stroke.sm}
|
stroke={theme.icon.stroke.sm}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,60 +1,83 @@
|
|||||||
|
import { objectPermissionKeyToHumanReadable } from '@/settings/roles/role-permissions/object-level-permissions/utils/objectPermissionKeyToHumanReadableText';
|
||||||
import { PermissionIcon } from '@/settings/roles/role-permissions/objects-permissions/components/PermissionIcon';
|
import { PermissionIcon } from '@/settings/roles/role-permissions/objects-permissions/components/PermissionIcon';
|
||||||
import { SETTINGS_ROLE_OBJECT_LEVEL_PERMISSION_TO_ROLE_OBJECT_PERMISSION_MAPPING } from '@/settings/roles/role-permissions/objects-permissions/constants/settingsRoleObjectLevelPermissionToRoleObjectPermissionMapping';
|
import { SETTINGS_ROLE_OBJECT_LEVEL_PERMISSION_TO_ROLE_OBJECT_PERMISSION_MAPPING } from '@/settings/roles/role-permissions/objects-permissions/constants/settingsRoleObjectLevelPermissionToRoleObjectPermissionMapping';
|
||||||
import { SettingsRoleObjectPermissionKey } from '@/settings/roles/role-permissions/objects-permissions/constants/settingsRoleObjectPermissionIconConfig';
|
import { SettingsRoleObjectPermissionKey } from '@/settings/roles/role-permissions/objects-permissions/constants/settingsRoleObjectPermissionIconConfig';
|
||||||
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
|
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
import { t } from '@lingui/core/macro';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
|
import { AppTooltip, TooltipDelay } from 'twenty-ui/display';
|
||||||
import { ObjectPermission } from '~/generated/graphql';
|
import { ObjectPermission } from '~/generated/graphql';
|
||||||
|
|
||||||
const StyledSettingsRolePermissionsObjectLevelOverrideCell = styled.div`
|
const StyledContainer = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: ${({ theme }) => theme.spacing(1)};
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
type SettingsRolePermissionsObjectLevelOverrideCellProps = {
|
type SettingsRolePermissionsObjectLevelOverrideCellProps = {
|
||||||
objectPermission: ObjectPermission;
|
objectPermissions: ObjectPermission;
|
||||||
|
objectPermissionKey: SettingsRoleObjectPermissionKey;
|
||||||
roleId: string;
|
roleId: string;
|
||||||
|
objectLabel: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SettingsRolePermissionsObjectLevelOverrideCell = ({
|
export const SettingsRolePermissionsObjectLevelOverrideCell = ({
|
||||||
objectPermission,
|
objectPermissions,
|
||||||
|
objectPermissionKey,
|
||||||
roleId,
|
roleId,
|
||||||
|
objectLabel,
|
||||||
}: SettingsRolePermissionsObjectLevelOverrideCellProps) => {
|
}: SettingsRolePermissionsObjectLevelOverrideCellProps) => {
|
||||||
const settingsDraftRole = useRecoilValue(
|
const settingsDraftRole = useRecoilValue(
|
||||||
settingsDraftRoleFamilyState(roleId),
|
settingsDraftRoleFamilyState(roleId),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const roleLabel = settingsDraftRole.label;
|
||||||
|
|
||||||
const permissionMappings =
|
const permissionMappings =
|
||||||
SETTINGS_ROLE_OBJECT_LEVEL_PERMISSION_TO_ROLE_OBJECT_PERMISSION_MAPPING;
|
SETTINGS_ROLE_OBJECT_LEVEL_PERMISSION_TO_ROLE_OBJECT_PERMISSION_MAPPING;
|
||||||
|
|
||||||
const isOverridden = (permission: SettingsRoleObjectPermissionKey) => {
|
const permissionValue = objectPermissions[objectPermissionKey];
|
||||||
const rolePermission = permissionMappings[permission];
|
|
||||||
|
const isOverridden = (
|
||||||
|
objectPermissionKey: SettingsRoleObjectPermissionKey,
|
||||||
|
) => {
|
||||||
|
const rolePermission = permissionMappings[objectPermissionKey];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
isDefined(objectPermission[permission]) &&
|
isDefined(permissionValue) &&
|
||||||
!!settingsDraftRole[rolePermission] !== !!objectPermission[permission]
|
!!settingsDraftRole[rolePermission] !== !!permissionValue
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (!isOverridden(objectPermissionKey)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const humanReadableAction =
|
||||||
|
objectPermissionKeyToHumanReadable(objectPermissionKey);
|
||||||
|
|
||||||
|
const containerId = `object-level-permission-override-${roleId}-${objectPermissionKey}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledSettingsRolePermissionsObjectLevelOverrideCell>
|
<>
|
||||||
{(
|
<StyledContainer id={containerId}>
|
||||||
Object.keys(permissionMappings) as SettingsRoleObjectPermissionKey[]
|
<PermissionIcon
|
||||||
).map((permission) => {
|
permission={objectPermissionKey}
|
||||||
const permissionValue = objectPermission[permission];
|
state={permissionValue === false ? 'revoked' : 'granted'}
|
||||||
|
/>
|
||||||
if (!isOverridden(permission)) {
|
</StyledContainer>
|
||||||
return null;
|
<AppTooltip
|
||||||
|
anchorSelect={`#${containerId}`}
|
||||||
|
content={
|
||||||
|
permissionValue === false
|
||||||
|
? t`${roleLabel} can't ${humanReadableAction} ${objectLabel} records`
|
||||||
|
: t`${roleLabel} can ${humanReadableAction} ${objectLabel} records`
|
||||||
}
|
}
|
||||||
|
delay={TooltipDelay.shortDelay}
|
||||||
return (
|
noArrow
|
||||||
<PermissionIcon
|
place="bottom"
|
||||||
key={permission}
|
positionStrategy="fixed"
|
||||||
permission={permission}
|
/>
|
||||||
state={permissionValue === false ? 'revoked' : 'granted'}
|
</>
|
||||||
/>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</StyledSettingsRolePermissionsObjectLevelOverrideCell>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -0,0 +1,43 @@
|
|||||||
|
import { SETTINGS_ROLE_OBJECT_LEVEL_PERMISSION_TO_ROLE_OBJECT_PERMISSION_MAPPING } from '@/settings/roles/role-permissions/objects-permissions/constants/settingsRoleObjectLevelPermissionToRoleObjectPermissionMapping';
|
||||||
|
import { SettingsRoleObjectPermissionKey } from '@/settings/roles/role-permissions/objects-permissions/constants/settingsRoleObjectPermissionIconConfig';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
import { ObjectPermission } from '~/generated/graphql';
|
||||||
|
import { SettingsRolePermissionsObjectLevelOverrideCell } from './SettingsRolePermissionsObjectLevelOverrideCell';
|
||||||
|
|
||||||
|
const StyledSettingsRolePermissionsObjectLevelOverrideCell = styled.div`
|
||||||
|
display: flex;
|
||||||
|
gap: ${({ theme }) => theme.spacing(1)};
|
||||||
|
`;
|
||||||
|
|
||||||
|
type SettingsRolePermissionsObjectLevelOverrideCellContainerProps = {
|
||||||
|
objectPermissions: ObjectPermission;
|
||||||
|
roleId: string;
|
||||||
|
objectLabel: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const SettingsRolePermissionsObjectLevelOverrideCellContainer = ({
|
||||||
|
objectPermissions,
|
||||||
|
roleId,
|
||||||
|
objectLabel,
|
||||||
|
}: SettingsRolePermissionsObjectLevelOverrideCellContainerProps) => {
|
||||||
|
const permissionMappings =
|
||||||
|
SETTINGS_ROLE_OBJECT_LEVEL_PERMISSION_TO_ROLE_OBJECT_PERMISSION_MAPPING;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<StyledSettingsRolePermissionsObjectLevelOverrideCell>
|
||||||
|
{(
|
||||||
|
Object.keys(permissionMappings) as SettingsRoleObjectPermissionKey[]
|
||||||
|
).map((permissionKey) => {
|
||||||
|
return (
|
||||||
|
<SettingsRolePermissionsObjectLevelOverrideCell
|
||||||
|
key={permissionKey}
|
||||||
|
objectPermissions={objectPermissions}
|
||||||
|
objectPermissionKey={permissionKey}
|
||||||
|
roleId={roleId}
|
||||||
|
objectLabel={objectLabel}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</StyledSettingsRolePermissionsObjectLevelOverrideCell>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -84,8 +84,8 @@ export const SettingsRolePermissionsObjectLevelSection = ({
|
|||||||
return (
|
return (
|
||||||
<Section>
|
<Section>
|
||||||
<H2Title
|
<H2Title
|
||||||
title={t`Object-Level Permissions`}
|
title={t`Object-Level`}
|
||||||
description={t`Ability to interact with specific objects`}
|
description={t`Actions users can perform on specific objects`}
|
||||||
/>
|
/>
|
||||||
<Table>
|
<Table>
|
||||||
<SettingsRolePermissionsObjectLevelTableHeader />
|
<SettingsRolePermissionsObjectLevelTableHeader />
|
||||||
@ -103,7 +103,7 @@ export const SettingsRolePermissionsObjectLevelSection = ({
|
|||||||
/>
|
/>
|
||||||
))
|
))
|
||||||
) : (
|
) : (
|
||||||
<StyledNoOverride>{t`No overrides found`}</StyledNoOverride>
|
<StyledNoOverride>{t`No permissions found`}</StyledNoOverride>
|
||||||
)}
|
)}
|
||||||
</StyledTableRows>
|
</StyledTableRows>
|
||||||
</Table>
|
</Table>
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||||
import { SettingsRolePermissionsObjectLevelOverrideCell } from '@/settings/roles/role-permissions/object-level-permissions/components/SettingsRolePermissionsObjectLevelOverrideCell';
|
import { SettingsRolePermissionsObjectLevelOverrideCellContainer } from '@/settings/roles/role-permissions/object-level-permissions/components/SettingsRolePermissionsObjectLevelOverrideCellContainer';
|
||||||
import { SettingsPath } from '@/types/SettingsPath';
|
import { SettingsPath } from '@/types/SettingsPath';
|
||||||
import { TableCell } from '@/ui/layout/table/components/TableCell';
|
import { TableCell } from '@/ui/layout/table/components/TableCell';
|
||||||
import { TableRow } from '@/ui/layout/table/components/TableRow';
|
import { TableRow } from '@/ui/layout/table/components/TableRow';
|
||||||
@ -44,6 +44,8 @@ export const SettingsRolePermissionsObjectLevelTableRow = ({
|
|||||||
|
|
||||||
const Icon = getIcon(objectMetadataItem.icon);
|
const Icon = getIcon(objectMetadataItem.icon);
|
||||||
|
|
||||||
|
const objectLabel = objectMetadataItem.labelPlural;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TableRow
|
<TableRow
|
||||||
to={getSettingsPath(SettingsPath.RoleObjectLevel, {
|
to={getSettingsPath(SettingsPath.RoleObjectLevel, {
|
||||||
@ -60,14 +62,15 @@ export const SettingsRolePermissionsObjectLevelTableRow = ({
|
|||||||
stroke={theme.icon.stroke.sm}
|
stroke={theme.icon.stroke.sm}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<StyledNameLabel title={objectMetadataItem.labelPlural}>
|
<StyledNameLabel title={objectLabel}>
|
||||||
<OverflowingTextWithTooltip text={objectMetadataItem.labelPlural} />
|
<OverflowingTextWithTooltip text={objectLabel} />
|
||||||
</StyledNameLabel>
|
</StyledNameLabel>
|
||||||
</StyledNameTableCell>
|
</StyledNameTableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<SettingsRolePermissionsObjectLevelOverrideCell
|
<SettingsRolePermissionsObjectLevelOverrideCellContainer
|
||||||
objectPermission={objectPermission}
|
objectPermissions={objectPermission}
|
||||||
roleId={roleId}
|
roleId={roleId}
|
||||||
|
objectLabel={objectLabel}
|
||||||
/>
|
/>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell align={'right'}>
|
<TableCell align={'right'}>
|
||||||
|
|||||||
@ -120,8 +120,8 @@ export const SettingsRolePermissionsObjectLevelObjectFormObjectLevel = ({
|
|||||||
return (
|
return (
|
||||||
<Section>
|
<Section>
|
||||||
<H2Title
|
<H2Title
|
||||||
title={t`Object-Level Permissions`}
|
title={t`Object-Level`}
|
||||||
description={t`Ability to interact with this specific object`}
|
description={t`Actions users can perform on this object`}
|
||||||
/>
|
/>
|
||||||
<StyledTable>
|
<StyledTable>
|
||||||
<SettingsRolePermissionsObjectLevelObjectFormObjectLevelTableHeader />
|
<SettingsRolePermissionsObjectLevelObjectFormObjectLevelTableHeader />
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { OverridableCheckbox } from '@/settings/roles/role-permissions/object-level-permissions/object-form/components/OverridableCheckbox';
|
import { OverridableCheckbox } from '@/settings/roles/role-permissions/object-level-permissions/object-form/components/OverridableCheckbox';
|
||||||
|
import { objectPermissionKeyToHumanReadable } from '@/settings/roles/role-permissions/object-level-permissions/utils/objectPermissionKeyToHumanReadableText';
|
||||||
import { PermissionIcon } from '@/settings/roles/role-permissions/objects-permissions/components/PermissionIcon';
|
import { PermissionIcon } from '@/settings/roles/role-permissions/objects-permissions/components/PermissionIcon';
|
||||||
import { SETTINGS_ROLE_OBJECT_LEVEL_PERMISSION_TO_ROLE_OBJECT_PERMISSION_MAPPING } from '@/settings/roles/role-permissions/objects-permissions/constants/settingsRoleObjectLevelPermissionToRoleObjectPermissionMapping';
|
import { SETTINGS_ROLE_OBJECT_LEVEL_PERMISSION_TO_ROLE_OBJECT_PERMISSION_MAPPING } from '@/settings/roles/role-permissions/objects-permissions/constants/settingsRoleObjectLevelPermissionToRoleObjectPermissionMapping';
|
||||||
import { SettingsRoleObjectPermissionKey } from '@/settings/roles/role-permissions/objects-permissions/constants/settingsRoleObjectPermissionIconConfig';
|
import { SettingsRoleObjectPermissionKey } from '@/settings/roles/role-permissions/objects-permissions/constants/settingsRoleObjectPermissionIconConfig';
|
||||||
@ -13,9 +14,10 @@ import { isDefined } from 'twenty-shared/utils';
|
|||||||
import { ObjectPermission } from '~/generated-metadata/graphql';
|
import { ObjectPermission } from '~/generated-metadata/graphql';
|
||||||
import type { Role } from '~/generated/graphql';
|
import type { Role } from '~/generated/graphql';
|
||||||
|
|
||||||
const StyledTableRow = styled(TableRow)`
|
const StyledTableRow = styled(TableRow)<{ isDisabled: boolean }>`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
cursor: ${({ isDisabled }) => (isDisabled ? 'default' : 'pointer')};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledPermissionCell = styled(TableCell)`
|
const StyledPermissionCell = styled(TableCell)`
|
||||||
@ -93,6 +95,15 @@ export const SettingsRolePermissionsObjectLevelObjectFormObjectLevelTableRow =
|
|||||||
settingsDraftRoleGlobalPermissionValue === true &&
|
settingsDraftRoleGlobalPermissionValue === true &&
|
||||||
isChecked === false;
|
isChecked === false;
|
||||||
|
|
||||||
|
const isGranted =
|
||||||
|
isDefined(settingsDraftRoleObjectPermissionValue) &&
|
||||||
|
settingsDraftRoleGlobalPermissionValue === false &&
|
||||||
|
isChecked === true;
|
||||||
|
|
||||||
|
const isGrantedAndInherited =
|
||||||
|
settingsDraftRoleObjectPermissionValue !== false &&
|
||||||
|
settingsDraftRoleGlobalPermissionValue === true;
|
||||||
|
|
||||||
let checkboxType: OverridableCheckboxType;
|
let checkboxType: OverridableCheckboxType;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@ -118,8 +129,12 @@ export const SettingsRolePermissionsObjectLevelObjectFormObjectLevelTableRow =
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const humanReadableAction = objectPermissionKeyToHumanReadable(
|
||||||
|
permission.key as SettingsRoleObjectPermissionKey,
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledTableRow>
|
<StyledTableRow onClick={handleCheckboxChange} isDisabled={!isEditable}>
|
||||||
<StyledPermissionCell>
|
<StyledPermissionCell>
|
||||||
<StyledPermissionContent>
|
<StyledPermissionContent>
|
||||||
<PermissionIcon
|
<PermissionIcon
|
||||||
@ -134,10 +149,20 @@ export const SettingsRolePermissionsObjectLevelObjectFormObjectLevelTableRow =
|
|||||||
{' · '}
|
{' · '}
|
||||||
{t`Revoked for this object`}
|
{t`Revoked for this object`}
|
||||||
</>
|
</>
|
||||||
|
) : isGranted ? (
|
||||||
|
<>
|
||||||
|
{' · '}
|
||||||
|
{t`Granted for this object`}
|
||||||
|
</>
|
||||||
|
) : isGrantedAndInherited ? (
|
||||||
|
<>
|
||||||
|
{' · '}
|
||||||
|
{t`This role can ${humanReadableAction} all records`}
|
||||||
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
</StyledOverrideInfo>
|
</StyledOverrideInfo>
|
||||||
</StyledPermissionCell>
|
</StyledPermissionCell>
|
||||||
<StyledCheckboxCell>
|
<StyledCheckboxCell onClick={(e) => e.stopPropagation()}>
|
||||||
<OverridableCheckbox
|
<OverridableCheckbox
|
||||||
onChange={handleCheckboxChange}
|
onChange={handleCheckboxChange}
|
||||||
disabled={!isEditable}
|
disabled={!isEditable}
|
||||||
|
|||||||
@ -0,0 +1,15 @@
|
|||||||
|
import { SettingsRoleObjectPermissionKey } from '@/settings/roles/role-permissions/objects-permissions/constants/settingsRoleObjectPermissionIconConfig';
|
||||||
|
import { t } from '@lingui/core/macro';
|
||||||
|
|
||||||
|
export const objectPermissionKeyToHumanReadable = (
|
||||||
|
objectPermissionKey: SettingsRoleObjectPermissionKey,
|
||||||
|
) => {
|
||||||
|
const permissionAction: Record<SettingsRoleObjectPermissionKey, string> = {
|
||||||
|
canReadObjectRecords: t`see`,
|
||||||
|
canUpdateObjectRecords: t`update`,
|
||||||
|
canSoftDeleteObjectRecords: t`delete`,
|
||||||
|
canDestroyObjectRecords: t`destroy`,
|
||||||
|
};
|
||||||
|
|
||||||
|
return permissionAction[objectPermissionKey];
|
||||||
|
};
|
||||||
@ -36,6 +36,12 @@ export const SettingsRolePermissionsObjectsSection = ({
|
|||||||
{
|
{
|
||||||
key: 'canReadObjectRecords',
|
key: 'canReadObjectRecords',
|
||||||
label: t`See Records on All Objects`,
|
label: t`See Records on All Objects`,
|
||||||
|
grantedBy:
|
||||||
|
objectPermissions?.filter(
|
||||||
|
(permission) =>
|
||||||
|
permission.canReadObjectRecords === true &&
|
||||||
|
settingsDraftRole.canReadAllObjectRecords === false,
|
||||||
|
)?.length ?? 0,
|
||||||
revokedBy:
|
revokedBy:
|
||||||
objectPermissions?.filter(
|
objectPermissions?.filter(
|
||||||
(permission) =>
|
(permission) =>
|
||||||
@ -60,6 +66,12 @@ export const SettingsRolePermissionsObjectsSection = ({
|
|||||||
{
|
{
|
||||||
key: 'canUpdateObjectRecords',
|
key: 'canUpdateObjectRecords',
|
||||||
label: t`Edit Records on All Objects`,
|
label: t`Edit Records on All Objects`,
|
||||||
|
grantedBy:
|
||||||
|
objectPermissions?.filter(
|
||||||
|
(permission) =>
|
||||||
|
permission.canUpdateObjectRecords === true &&
|
||||||
|
settingsDraftRole.canUpdateAllObjectRecords === false,
|
||||||
|
)?.length ?? 0,
|
||||||
revokedBy:
|
revokedBy:
|
||||||
objectPermissions?.filter(
|
objectPermissions?.filter(
|
||||||
(permission) =>
|
(permission) =>
|
||||||
@ -82,6 +94,12 @@ export const SettingsRolePermissionsObjectsSection = ({
|
|||||||
{
|
{
|
||||||
key: 'canSoftDeleteObjectRecords',
|
key: 'canSoftDeleteObjectRecords',
|
||||||
label: t`Delete Records on All Objects`,
|
label: t`Delete Records on All Objects`,
|
||||||
|
grantedBy:
|
||||||
|
objectPermissions?.filter(
|
||||||
|
(permission) =>
|
||||||
|
permission.canSoftDeleteObjectRecords === true &&
|
||||||
|
settingsDraftRole.canSoftDeleteAllObjectRecords === false,
|
||||||
|
)?.length ?? 0,
|
||||||
revokedBy:
|
revokedBy:
|
||||||
objectPermissions?.filter(
|
objectPermissions?.filter(
|
||||||
(permission) =>
|
(permission) =>
|
||||||
@ -104,6 +122,12 @@ export const SettingsRolePermissionsObjectsSection = ({
|
|||||||
{
|
{
|
||||||
key: 'canDestroyObjectRecords',
|
key: 'canDestroyObjectRecords',
|
||||||
label: t`Destroy Records on All Objects`,
|
label: t`Destroy Records on All Objects`,
|
||||||
|
grantedBy:
|
||||||
|
objectPermissions?.filter(
|
||||||
|
(permission) =>
|
||||||
|
permission.canDestroyObjectRecords === true &&
|
||||||
|
settingsDraftRole.canDestroyAllObjectRecords === false,
|
||||||
|
)?.length ?? 0,
|
||||||
revokedBy:
|
revokedBy:
|
||||||
objectPermissions?.filter(
|
objectPermissions?.filter(
|
||||||
(permission) =>
|
(permission) =>
|
||||||
@ -128,8 +152,8 @@ export const SettingsRolePermissionsObjectsSection = ({
|
|||||||
return (
|
return (
|
||||||
<Section>
|
<Section>
|
||||||
<H2Title
|
<H2Title
|
||||||
title={t`Objects`}
|
title={t`All objects`}
|
||||||
description={t`Actions you can perform on all objects`}
|
description={t`Actions users can perform on all objects`}
|
||||||
/>
|
/>
|
||||||
<StyledTable>
|
<StyledTable>
|
||||||
<SettingsRolePermissionsObjectsTableHeader
|
<SettingsRolePermissionsObjectsTableHeader
|
||||||
|
|||||||
@ -15,7 +15,7 @@ const StyledActionsHeader = styled(TableHeader)`
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
padding-right: ${({ theme }) => theme.spacing(4)};
|
padding-right: ${({ theme }) => theme.spacing(1)};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
type SettingsRolePermissionsObjectsTableHeaderProps = {
|
type SettingsRolePermissionsObjectsTableHeaderProps = {
|
||||||
|
|||||||
@ -36,12 +36,13 @@ const StyledCheckboxCell = styled(TableCell)`
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
padding-right: ${({ theme }) => theme.spacing(4)};
|
padding-right: ${({ theme }) => theme.spacing(1)};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledTableRow = styled(TableRow)`
|
const StyledTableRow = styled(TableRow)<{ isDisabled: boolean }>`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
cursor: ${({ isDisabled }) => (isDisabled ? 'default' : 'pointer')};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
type SettingsRolePermissionsObjectsTableRowProps = {
|
type SettingsRolePermissionsObjectsTableRowProps = {
|
||||||
@ -54,13 +55,21 @@ export const SettingsRolePermissionsObjectsTableRow = ({
|
|||||||
isEditable,
|
isEditable,
|
||||||
}: SettingsRolePermissionsObjectsTableRowProps) => {
|
}: SettingsRolePermissionsObjectsTableRowProps) => {
|
||||||
const revokedBy = permission.revokedBy;
|
const revokedBy = permission.revokedBy;
|
||||||
|
const grantedBy = permission.grantedBy;
|
||||||
const isRevoked =
|
const isRevoked =
|
||||||
revokedBy !== undefined && revokedBy !== null && revokedBy > 0;
|
revokedBy !== undefined && revokedBy !== null && revokedBy > 0;
|
||||||
const label = permission.label;
|
const label = permission.label;
|
||||||
const pluralizedObject = pluralize('object', revokedBy);
|
const pluralizedRevokedObject = pluralize('object', revokedBy);
|
||||||
|
const pluralizedGrantedObject = pluralize('object', grantedBy);
|
||||||
|
const isDisabled = !isEditable;
|
||||||
|
|
||||||
|
const handleRowClick = () => {
|
||||||
|
if (isDisabled) return;
|
||||||
|
permission.setValue(!permission.value);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledTableRow>
|
<StyledTableRow onClick={handleRowClick} isDisabled={isDisabled}>
|
||||||
<StyledPermissionCell>
|
<StyledPermissionCell>
|
||||||
<StyledPermissionContent>
|
<StyledPermissionContent>
|
||||||
<PermissionIcon
|
<PermissionIcon
|
||||||
@ -70,19 +79,24 @@ export const SettingsRolePermissionsObjectsTableRow = ({
|
|||||||
<StyledPermissionLabel>{label}</StyledPermissionLabel>
|
<StyledPermissionLabel>{label}</StyledPermissionLabel>
|
||||||
</StyledPermissionContent>
|
</StyledPermissionContent>
|
||||||
<StyledOverrideInfo>
|
<StyledOverrideInfo>
|
||||||
{isRevoked ? (
|
{isRevoked && revokedBy > 0 ? (
|
||||||
<>
|
<>
|
||||||
{' · '}
|
{' · '}
|
||||||
{t`Revoked on ${revokedBy} ${pluralizedObject}`}
|
{t`Revoked for ${revokedBy} ${pluralizedRevokedObject}`}
|
||||||
|
</>
|
||||||
|
) : grantedBy && grantedBy > 0 ? (
|
||||||
|
<>
|
||||||
|
{' · '}
|
||||||
|
{t`Granted for ${grantedBy} ${pluralizedGrantedObject}`}
|
||||||
</>
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
</StyledOverrideInfo>
|
</StyledOverrideInfo>
|
||||||
</StyledPermissionCell>
|
</StyledPermissionCell>
|
||||||
<StyledCheckboxCell>
|
<StyledCheckboxCell onClick={(e) => e.stopPropagation()}>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
checked={permission.value ?? false}
|
checked={permission.value ?? false}
|
||||||
onChange={() => permission.setValue(!permission.value)}
|
onChange={() => permission.setValue(!permission.value)}
|
||||||
disabled={!isEditable}
|
disabled={isDisabled}
|
||||||
accent={isRevoked ? CheckboxAccent.Orange : CheckboxAccent.Blue}
|
accent={isRevoked ? CheckboxAccent.Orange : CheckboxAccent.Blue}
|
||||||
/>
|
/>
|
||||||
</StyledCheckboxCell>
|
</StyledCheckboxCell>
|
||||||
|
|||||||
@ -4,6 +4,7 @@ export type SettingsRolePermissionsObjectPermission = {
|
|||||||
label: string | ReactNode;
|
label: string | ReactNode;
|
||||||
value?: boolean;
|
value?: boolean;
|
||||||
setValue: (value: boolean) => void;
|
setValue: (value: boolean) => void;
|
||||||
|
grantedBy?: number;
|
||||||
revokedBy?: number;
|
revokedBy?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -130,7 +130,11 @@ export const SettingsRolePermissionsSettingsSection = ({
|
|||||||
containAnimation={false}
|
containAnimation={false}
|
||||||
>
|
>
|
||||||
<StyledTable>
|
<StyledTable>
|
||||||
<SettingsRolePermissionsSettingsTableHeader />
|
<SettingsRolePermissionsSettingsTableHeader
|
||||||
|
roleId={roleId}
|
||||||
|
settingsPermissionsConfig={settingsPermissionsConfig}
|
||||||
|
isEditable={isEditable}
|
||||||
|
/>
|
||||||
<StyledTableRows>
|
<StyledTableRows>
|
||||||
{settingsPermissionsConfig.map((permission) => (
|
{settingsPermissionsConfig.map((permission) => (
|
||||||
<SettingsRolePermissionsSettingsTableRow
|
<SettingsRolePermissionsSettingsTableRow
|
||||||
|
|||||||
@ -1,11 +1,77 @@
|
|||||||
import { TableHeader } from '@/ui/layout/table/components/TableHeader';
|
import { TableHeader } from '@/ui/layout/table/components/TableHeader';
|
||||||
import { TableRow } from '@/ui/layout/table/components/TableRow';
|
import { TableRow } from '@/ui/layout/table/components/TableRow';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
import { t } from '@lingui/core/macro';
|
import { t } from '@lingui/core/macro';
|
||||||
|
import { Checkbox } from 'twenty-ui/input';
|
||||||
|
|
||||||
export const SettingsRolePermissionsSettingsTableHeader = () => (
|
import { SettingsRolePermissionsSettingPermission } from '@/settings/roles/role-permissions/settings-permissions/types/SettingsRolePermissionsSettingPermission';
|
||||||
<TableRow gridAutoColumns="3fr 4fr 24px">
|
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
|
||||||
<TableHeader>{t`Name`}</TableHeader>
|
import { useRecoilState } from 'recoil';
|
||||||
<TableHeader>{t`Description`}</TableHeader>
|
import { v4 } from 'uuid';
|
||||||
<TableHeader></TableHeader>
|
|
||||||
</TableRow>
|
type SettingsRolePermissionsSettingsTableHeaderProps = {
|
||||||
);
|
roleId: string;
|
||||||
|
settingsPermissionsConfig: SettingsRolePermissionsSettingPermission[];
|
||||||
|
isEditable: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
const StyledActionsHeader = styled(TableHeader)`
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
padding-right: ${({ theme }) => theme.spacing(1)};
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const SettingsRolePermissionsSettingsTableHeader = ({
|
||||||
|
roleId,
|
||||||
|
settingsPermissionsConfig,
|
||||||
|
isEditable,
|
||||||
|
}: SettingsRolePermissionsSettingsTableHeaderProps) => {
|
||||||
|
const [settingsDraftRole, setSettingsDraftRole] = useRecoilState(
|
||||||
|
settingsDraftRoleFamilyState(roleId),
|
||||||
|
);
|
||||||
|
const allSettingsPermissionsEnabled = settingsPermissionsConfig.every(
|
||||||
|
(permission) =>
|
||||||
|
settingsDraftRole.settingPermissions?.some(
|
||||||
|
(settingPermission) => settingPermission.setting === permission.key,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
const someSettingsPermissionsEnabled = settingsPermissionsConfig.some(
|
||||||
|
(permission) =>
|
||||||
|
settingsDraftRole.settingPermissions?.some(
|
||||||
|
(settingPermission) => settingPermission.setting === permission.key,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TableRow gridAutoColumns="3fr 4fr 24px">
|
||||||
|
<TableHeader>{t`Name`}</TableHeader>
|
||||||
|
<TableHeader>{t`Description`}</TableHeader>
|
||||||
|
<StyledActionsHeader aria-label={t`Actions`}>
|
||||||
|
<Checkbox
|
||||||
|
checked={allSettingsPermissionsEnabled}
|
||||||
|
indeterminate={
|
||||||
|
someSettingsPermissionsEnabled && !allSettingsPermissionsEnabled
|
||||||
|
}
|
||||||
|
disabled={!isEditable}
|
||||||
|
aria-label={t`Toggle all settings permissions`}
|
||||||
|
onChange={() => {
|
||||||
|
const newValue = !allSettingsPermissionsEnabled;
|
||||||
|
|
||||||
|
setSettingsDraftRole({
|
||||||
|
...settingsDraftRole,
|
||||||
|
settingPermissions: newValue
|
||||||
|
? settingsPermissionsConfig.map((permission) => ({
|
||||||
|
id: v4(),
|
||||||
|
setting: permission.key,
|
||||||
|
roleId,
|
||||||
|
}))
|
||||||
|
: [],
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</StyledActionsHeader>
|
||||||
|
</TableRow>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|||||||
@ -10,6 +10,10 @@ import { Checkbox } from 'twenty-ui/input';
|
|||||||
import { v4 } from 'uuid';
|
import { v4 } from 'uuid';
|
||||||
import { FeatureFlagKey } from '~/generated-metadata/graphql';
|
import { FeatureFlagKey } from '~/generated-metadata/graphql';
|
||||||
|
|
||||||
|
const StyledTableRow = styled(TableRow)<{ isDisabled: boolean }>`
|
||||||
|
cursor: ${({ isDisabled }) => (isDisabled ? 'default' : 'pointer')};
|
||||||
|
`;
|
||||||
|
|
||||||
const StyledName = styled.span`
|
const StyledName = styled.span`
|
||||||
color: ${({ theme }) => theme.font.color.primary};
|
color: ${({ theme }) => theme.font.color.primary};
|
||||||
`;
|
`;
|
||||||
@ -29,7 +33,7 @@ const StyledCheckboxCell = styled(TableCell)`
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
padding-right: ${({ theme }) => theme.spacing(4)};
|
padding-right: ${({ theme }) => theme.spacing(1)};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledIconContainer = styled.div`
|
const StyledIconContainer = styled.div`
|
||||||
@ -63,6 +67,10 @@ export const SettingsRolePermissionsSettingsTableRow = ({
|
|||||||
(settingPermission) => settingPermission.setting === permission.key,
|
(settingPermission) => settingPermission.setting === permission.key,
|
||||||
) ?? false;
|
) ?? false;
|
||||||
|
|
||||||
|
const isChecked = isSettingPermissionEnabled || canUpdateAllSettings;
|
||||||
|
const isDisabled =
|
||||||
|
!isEditable || canUpdateAllSettings || !isPermissionsV2Enabled;
|
||||||
|
|
||||||
const handleChange = (value: boolean) => {
|
const handleChange = (value: boolean) => {
|
||||||
const currentPermissions = settingsDraftRole.settingPermissions ?? [];
|
const currentPermissions = settingsDraftRole.settingPermissions ?? [];
|
||||||
|
|
||||||
@ -88,8 +96,18 @@ export const SettingsRolePermissionsSettingsTableRow = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleRowClick = () => {
|
||||||
|
if (isDisabled) return;
|
||||||
|
handleChange(!isChecked);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TableRow key={permission.key} gridAutoColumns="3fr 4fr 24px">
|
<StyledTableRow
|
||||||
|
key={permission.key}
|
||||||
|
gridAutoColumns="3fr 4fr 24px"
|
||||||
|
onClick={handleRowClick}
|
||||||
|
isDisabled={isDisabled}
|
||||||
|
>
|
||||||
<StyledPermissionCell>
|
<StyledPermissionCell>
|
||||||
<StyledIconContainer>
|
<StyledIconContainer>
|
||||||
<permission.Icon
|
<permission.Icon
|
||||||
@ -103,15 +121,13 @@ export const SettingsRolePermissionsSettingsTableRow = ({
|
|||||||
<StyledPermissionCell>
|
<StyledPermissionCell>
|
||||||
<StyledDescription>{permission.description}</StyledDescription>
|
<StyledDescription>{permission.description}</StyledDescription>
|
||||||
</StyledPermissionCell>
|
</StyledPermissionCell>
|
||||||
<StyledCheckboxCell>
|
<StyledCheckboxCell onClick={(e) => e.stopPropagation()}>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
checked={isSettingPermissionEnabled || canUpdateAllSettings}
|
checked={isChecked}
|
||||||
disabled={
|
disabled={isDisabled}
|
||||||
!isEditable || canUpdateAllSettings || !isPermissionsV2Enabled
|
|
||||||
}
|
|
||||||
onChange={(event) => handleChange(event.target.checked)}
|
onChange={(event) => handleChange(event.target.checked)}
|
||||||
/>
|
/>
|
||||||
</StyledCheckboxCell>
|
</StyledCheckboxCell>
|
||||||
</TableRow>
|
</StyledTableRow>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -57,7 +57,7 @@ const ROLE_BASIC_KEYS: Array<keyof Role> = [
|
|||||||
export const SettingsRole = ({ roleId, isCreateMode }: SettingsRoleProps) => {
|
export const SettingsRole = ({ roleId, isCreateMode }: SettingsRoleProps) => {
|
||||||
const activeTabId = useRecoilComponentValueV2(
|
const activeTabId = useRecoilComponentValueV2(
|
||||||
activeTabIdComponentState,
|
activeTabIdComponentState,
|
||||||
SETTINGS_ROLE_DETAIL_TABS.COMPONENT_INSTANCE_ID,
|
SETTINGS_ROLE_DETAIL_TABS.COMPONENT_INSTANCE_ID + '-' + roleId,
|
||||||
);
|
);
|
||||||
|
|
||||||
const isPermissionsV2Enabled = useIsFeatureEnabled(
|
const isPermissionsV2Enabled = useIsFeatureEnabled(
|
||||||
@ -94,16 +94,16 @@ export const SettingsRole = ({ roleId, isCreateMode }: SettingsRoleProps) => {
|
|||||||
const isRoleEditable = isPermissionsV2Enabled && settingsDraftRole.isEditable;
|
const isRoleEditable = isPermissionsV2Enabled && settingsDraftRole.isEditable;
|
||||||
|
|
||||||
const tabs = [
|
const tabs = [
|
||||||
{
|
|
||||||
id: SETTINGS_ROLE_DETAIL_TABS.TABS_IDS.ASSIGNMENT,
|
|
||||||
title: t`Assignment`,
|
|
||||||
Icon: IconUserPlus,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: SETTINGS_ROLE_DETAIL_TABS.TABS_IDS.PERMISSIONS,
|
id: SETTINGS_ROLE_DETAIL_TABS.TABS_IDS.PERMISSIONS,
|
||||||
title: t`Permissions`,
|
title: t`Permissions`,
|
||||||
Icon: IconLockOpen,
|
Icon: IconLockOpen,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: SETTINGS_ROLE_DETAIL_TABS.TABS_IDS.ASSIGNMENT,
|
||||||
|
title: t`Assignment`,
|
||||||
|
Icon: IconUserPlus,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: SETTINGS_ROLE_DETAIL_TABS.TABS_IDS.SETTINGS,
|
id: SETTINGS_ROLE_DETAIL_TABS.TABS_IDS.SETTINGS,
|
||||||
title: t`Settings`,
|
title: t`Settings`,
|
||||||
@ -135,7 +135,7 @@ export const SettingsRole = ({ roleId, isCreateMode }: SettingsRoleProps) => {
|
|||||||
if (isCreateMode) {
|
if (isCreateMode) {
|
||||||
const roleId = v4();
|
const roleId = v4();
|
||||||
|
|
||||||
createRole({
|
const { data } = await createRole({
|
||||||
variables: {
|
variables: {
|
||||||
createRoleInput: {
|
createRoleInput: {
|
||||||
id: roleId,
|
id: roleId,
|
||||||
@ -152,60 +152,63 @@ export const SettingsRole = ({ roleId, isCreateMode }: SettingsRoleProps) => {
|
|||||||
settingsDraftRole.canDestroyAllObjectRecords,
|
settingsDraftRole.canDestroyAllObjectRecords,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
onCompleted: async (data) => {
|
refetchQueries: [getOperationName(GET_ROLES) ?? ''],
|
||||||
if (isDefined(dirtyFields.workspaceMembers)) {
|
});
|
||||||
await addWorkspaceMembersToRole({
|
|
||||||
|
if (!data) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isDefined(dirtyFields.workspaceMembers)) {
|
||||||
|
await addWorkspaceMembersToRole({
|
||||||
|
roleId: data.createOneRole.id,
|
||||||
|
workspaceMemberIds: settingsDraftRole.workspaceMembers.map(
|
||||||
|
(member) => member.id,
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isDefined(dirtyFields.settingPermissions)) {
|
||||||
|
await upsertSettingPermissions({
|
||||||
|
variables: {
|
||||||
|
upsertSettingPermissionsInput: {
|
||||||
roleId: data.createOneRole.id,
|
roleId: data.createOneRole.id,
|
||||||
workspaceMemberIds: settingsDraftRole.workspaceMembers.map(
|
settingPermissionKeys:
|
||||||
(member) => member.id,
|
settingsDraftRole.settingPermissions?.map(
|
||||||
),
|
(settingPermission) => settingPermission.setting,
|
||||||
});
|
) ?? [],
|
||||||
}
|
},
|
||||||
|
},
|
||||||
|
refetchQueries: [getOperationName(GET_ROLES) ?? ''],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (isDefined(dirtyFields.settingPermissions)) {
|
if (isDefined(dirtyFields.objectPermissions)) {
|
||||||
await upsertSettingPermissions({
|
await upsertObjectPermissions({
|
||||||
variables: {
|
variables: {
|
||||||
upsertSettingPermissionsInput: {
|
upsertObjectPermissionsInput: {
|
||||||
roleId: data.createOneRole.id,
|
roleId: data.createOneRole.id,
|
||||||
settingPermissionKeys:
|
objectPermissions:
|
||||||
settingsDraftRole.settingPermissions?.map(
|
settingsDraftRole.objectPermissions?.map(
|
||||||
(settingPermission) => settingPermission.setting,
|
(objectPermission) => ({
|
||||||
) ?? [],
|
objectMetadataId: objectPermission.objectMetadataId,
|
||||||
},
|
canReadObjectRecords: objectPermission.canReadObjectRecords,
|
||||||
},
|
canUpdateObjectRecords:
|
||||||
refetchQueries: [getOperationName(GET_ROLES) ?? ''],
|
objectPermission.canUpdateObjectRecords,
|
||||||
});
|
canSoftDeleteObjectRecords:
|
||||||
}
|
objectPermission.canSoftDeleteObjectRecords,
|
||||||
|
canDestroyObjectRecords:
|
||||||
|
objectPermission.canDestroyObjectRecords,
|
||||||
|
}),
|
||||||
|
) ?? [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
refetchQueries: [getOperationName(GET_ROLES) ?? ''],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (isDefined(dirtyFields.objectPermissions)) {
|
navigateSettings(SettingsPath.RoleDetail, {
|
||||||
await upsertObjectPermissions({
|
roleId: data.createOneRole.id,
|
||||||
variables: {
|
|
||||||
upsertObjectPermissionsInput: {
|
|
||||||
roleId: data.createOneRole.id,
|
|
||||||
objectPermissions:
|
|
||||||
settingsDraftRole.objectPermissions?.map(
|
|
||||||
(objectPermission) => ({
|
|
||||||
objectMetadataId: objectPermission.objectMetadataId,
|
|
||||||
canReadObjectRecords:
|
|
||||||
objectPermission.canReadObjectRecords,
|
|
||||||
canUpdateObjectRecords:
|
|
||||||
objectPermission.canUpdateObjectRecords,
|
|
||||||
canSoftDeleteObjectRecords:
|
|
||||||
objectPermission.canSoftDeleteObjectRecords,
|
|
||||||
canDestroyObjectRecords:
|
|
||||||
objectPermission.canDestroyObjectRecords,
|
|
||||||
}),
|
|
||||||
) ?? [],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
refetchQueries: [getOperationName(GET_ROLES) ?? ''],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
navigateSettings(SettingsPath.RoleDetail, {
|
|
||||||
roleId: data.createOneRole.id,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
if (isDefined(dirtyFields.settingPermissions)) {
|
if (isDefined(dirtyFields.settingPermissions)) {
|
||||||
@ -244,6 +247,7 @@ export const SettingsRole = ({ roleId, isCreateMode }: SettingsRoleProps) => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
refetchQueries: [getOperationName(GET_ROLES) ?? ''],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -302,7 +306,9 @@ export const SettingsRole = ({ roleId, isCreateMode }: SettingsRoleProps) => {
|
|||||||
<TabList
|
<TabList
|
||||||
tabs={tabs}
|
tabs={tabs}
|
||||||
className="tab-list"
|
className="tab-list"
|
||||||
componentInstanceId={SETTINGS_ROLE_DETAIL_TABS.COMPONENT_INSTANCE_ID}
|
componentInstanceId={
|
||||||
|
SETTINGS_ROLE_DETAIL_TABS.COMPONENT_INSTANCE_ID + '-' + roleId
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
{activeTabId === SETTINGS_ROLE_DETAIL_TABS.TABS_IDS.ASSIGNMENT && (
|
{activeTabId === SETTINGS_ROLE_DETAIL_TABS.TABS_IDS.ASSIGNMENT && (
|
||||||
<SettingsRoleAssignment roleId={roleId} isCreateMode={isCreateMode} />
|
<SettingsRoleAssignment roleId={roleId} isCreateMode={isCreateMode} />
|
||||||
|
|||||||
@ -18,7 +18,7 @@ export const SettingsRoleCreateEffect = ({
|
|||||||
);
|
);
|
||||||
const setActiveTabId = useSetRecoilComponentStateV2(
|
const setActiveTabId = useSetRecoilComponentStateV2(
|
||||||
activeTabIdComponentState,
|
activeTabIdComponentState,
|
||||||
SETTINGS_ROLE_DETAIL_TABS.COMPONENT_INSTANCE_ID,
|
SETTINGS_ROLE_DETAIL_TABS.COMPONENT_INSTANCE_ID + '-' + roleId,
|
||||||
);
|
);
|
||||||
|
|
||||||
const [isInitialized, setIsInitialized] = useState(false);
|
const [isInitialized, setIsInitialized] = useState(false);
|
||||||
|
|||||||
@ -22,7 +22,7 @@ export const SettingsRoleEditEffect = ({
|
|||||||
const role = useRecoilValue(settingsPersistedRoleFamilyState(roleId));
|
const role = useRecoilValue(settingsPersistedRoleFamilyState(roleId));
|
||||||
const setActiveTabId = useSetRecoilComponentStateV2(
|
const setActiveTabId = useSetRecoilComponentStateV2(
|
||||||
activeTabIdComponentState,
|
activeTabIdComponentState,
|
||||||
SETTINGS_ROLE_DETAIL_TABS.COMPONENT_INSTANCE_ID,
|
SETTINGS_ROLE_DETAIL_TABS.COMPONENT_INSTANCE_ID + '-' + roleId,
|
||||||
);
|
);
|
||||||
|
|
||||||
const updateDraftRoleIfNeeded = useRecoilCallback(
|
const updateDraftRoleIfNeeded = useRecoilCallback(
|
||||||
@ -45,7 +45,7 @@ export const SettingsRoleEditEffect = ({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setActiveTabId(SETTINGS_ROLE_DETAIL_TABS.TABS_IDS.ASSIGNMENT);
|
setActiveTabId(SETTINGS_ROLE_DETAIL_TABS.TABS_IDS.PERMISSIONS);
|
||||||
updateDraftRoleIfNeeded(role);
|
updateDraftRoleIfNeeded(role);
|
||||||
setIsInitialized(true);
|
setIsInitialized(true);
|
||||||
}, [isInitialized, role, setActiveTabId, updateDraftRoleIfNeeded]);
|
}, [isInitialized, role, setActiveTabId, updateDraftRoleIfNeeded]);
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
export const SETTINGS_ROLE_DETAIL_TABS = {
|
export const SETTINGS_ROLE_DETAIL_TABS = {
|
||||||
COMPONENT_INSTANCE_ID: 'settings-role-detail-tabs',
|
COMPONENT_INSTANCE_ID: 'settings-role-detail-tabs',
|
||||||
TABS_IDS: {
|
TABS_IDS: {
|
||||||
ASSIGNMENT: 'assignment',
|
|
||||||
PERMISSIONS: 'permissions',
|
PERMISSIONS: 'permissions',
|
||||||
|
ASSIGNMENT: 'assignment',
|
||||||
SETTINGS: 'settings',
|
SETTINGS: 'settings',
|
||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|||||||
Reference in New Issue
Block a user