Role page various fixes (#12324)
Various fixes from fast follows - Sort roles by alphabetical order - Change some tooltips - During role creation, role should have all permissions enabled by default - Changed Permission icons design and refactored duplicating logic in a dedicated component - Changed "Revoked by" design - Display role icon in default role picker - Workspace member avatar was missing in role list and member picker - Set "seeded" member role as editable for new workspaces - Various css fixes
This commit is contained in:
@ -1,34 +1,12 @@
|
||||
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_PERMISSION_ICON_CONFIG } 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 { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { ObjectPermission } from '~/generated/graphql';
|
||||
|
||||
const StyledIconWrapper = styled.div<{ isForbidden?: boolean }>`
|
||||
align-items: center;
|
||||
background: ${({ theme, isForbidden }) =>
|
||||
isForbidden ? theme.adaptiveColors.orange1 : theme.adaptiveColors.blue1};
|
||||
border: 1px solid
|
||||
${({ theme, isForbidden }) =>
|
||||
isForbidden ? theme.adaptiveColors.orange3 : theme.adaptiveColors.blue3};
|
||||
border-radius: ${({ theme }) => theme.border.radius.sm};
|
||||
display: flex;
|
||||
height: ${({ theme }) => theme.spacing(4)};
|
||||
justify-content: center;
|
||||
width: ${({ theme }) => theme.spacing(4)};
|
||||
`;
|
||||
|
||||
const StyledIcon = styled.div<{ isForbidden?: boolean }>`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
color: ${({ theme, isForbidden }) =>
|
||||
isForbidden ? theme.color.orange : theme.color.blue};
|
||||
justify-content: center;
|
||||
`;
|
||||
|
||||
const StyledSettingsRolePermissionsObjectLevelOverrideCell = styled.div`
|
||||
display: flex;
|
||||
gap: ${({ theme }) => theme.spacing(1)};
|
||||
@ -43,8 +21,6 @@ export const SettingsRolePermissionsObjectLevelOverrideCell = ({
|
||||
objectPermission,
|
||||
roleId,
|
||||
}: SettingsRolePermissionsObjectLevelOverrideCellProps) => {
|
||||
const theme = useTheme();
|
||||
|
||||
const settingsDraftRole = useRecoilValue(
|
||||
settingsDraftRoleFamilyState(roleId),
|
||||
);
|
||||
@ -52,44 +28,33 @@ export const SettingsRolePermissionsObjectLevelOverrideCell = ({
|
||||
const permissionMappings =
|
||||
SETTINGS_ROLE_OBJECT_LEVEL_PERMISSION_TO_ROLE_OBJECT_PERMISSION_MAPPING;
|
||||
|
||||
type ObjectPermissionKey = keyof typeof permissionMappings;
|
||||
|
||||
const isOverridden = (permission: ObjectPermissionKey) => {
|
||||
const isOverridden = (permission: SettingsRoleObjectPermissionKey) => {
|
||||
const rolePermission = permissionMappings[permission];
|
||||
return (
|
||||
isDefined(objectPermission[permission]) &&
|
||||
!!settingsDraftRole[rolePermission as keyof typeof settingsDraftRole] !==
|
||||
!!objectPermission[permission]
|
||||
!!settingsDraftRole[rolePermission] !== !!objectPermission[permission]
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledSettingsRolePermissionsObjectLevelOverrideCell>
|
||||
{(Object.keys(permissionMappings) as ObjectPermissionKey[]).map(
|
||||
(permission) => {
|
||||
const { Icon, IconForbidden: IconOverride } =
|
||||
SETTINGS_ROLE_OBJECT_PERMISSION_ICON_CONFIG[permission];
|
||||
const permissionValue = objectPermission[permission];
|
||||
{(
|
||||
Object.keys(permissionMappings) as SettingsRoleObjectPermissionKey[]
|
||||
).map((permission) => {
|
||||
const permissionValue = objectPermission[permission];
|
||||
|
||||
if (!isOverridden(permission)) {
|
||||
return null;
|
||||
}
|
||||
if (!isOverridden(permission)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<StyledIconWrapper
|
||||
key={permission}
|
||||
isForbidden={permissionValue === false}
|
||||
>
|
||||
<StyledIcon isForbidden={permissionValue === false}>
|
||||
{permissionValue === false && (
|
||||
<IconOverride size={theme.icon.size.sm} />
|
||||
)}
|
||||
{permissionValue === true && <Icon size={theme.icon.size.sm} />}
|
||||
</StyledIcon>
|
||||
</StyledIconWrapper>
|
||||
);
|
||||
},
|
||||
)}
|
||||
return (
|
||||
<PermissionIcon
|
||||
key={permission}
|
||||
permission={permission}
|
||||
state={permissionValue === false ? 'revoked' : 'granted'}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</StyledSettingsRolePermissionsObjectLevelOverrideCell>
|
||||
);
|
||||
};
|
||||
|
||||
@ -130,6 +130,7 @@ export const SettingsRolePermissionsObjectLevelSection = ({
|
||||
disabled={!isEditable}
|
||||
/>
|
||||
}
|
||||
dropdownOffset={{ x: 0, y: 4 }}
|
||||
dropdownComponents={
|
||||
<SettingsRolePermissionsObjectLevelObjectPickerDropdownContent
|
||||
excludedObjectMetadataIds={
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import { OverridableCheckbox } from '@/settings/roles/role-permissions/object-level-permissions/object-form/components/OverridableCheckbox';
|
||||
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_PERMISSION_ICON_CONFIG } from '@/settings/roles/role-permissions/objects-permissions/constants/settingsRoleObjectPermissionIconConfig';
|
||||
import { SettingsRoleObjectPermissionKey } from '@/settings/roles/role-permissions/objects-permissions/constants/settingsRoleObjectPermissionIconConfig';
|
||||
import { SettingsRolePermissionsObjectLevelPermission } from '@/settings/roles/role-permissions/objects-permissions/types/SettingsRolePermissionsObjectPermission';
|
||||
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
|
||||
import { TableCell } from '@/ui/layout/table/components/TableCell';
|
||||
import { TableRow } from '@/ui/layout/table/components/TableRow';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
@ -13,25 +13,36 @@ import { isDefined } from 'twenty-shared/utils';
|
||||
import { ObjectPermission } from '~/generated-metadata/graphql';
|
||||
import type { Role } from '~/generated/graphql';
|
||||
|
||||
const StyledLabel = styled.span`
|
||||
color: ${({ theme }) => theme.font.color.primary};
|
||||
`;
|
||||
|
||||
const StyledOverrideInfo = styled.span`
|
||||
background: ${({ theme }) => theme.adaptiveColors.orange1};
|
||||
border-radius: ${({ theme }) => theme.spacing(1)};
|
||||
color: ${({ theme }) => theme.color.orange};
|
||||
padding: ${({ theme }) => theme.spacing(1)};
|
||||
const StyledTableRow = styled(TableRow)`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
`;
|
||||
|
||||
const StyledPermissionCell = styled(TableCell)`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
gap: ${({ theme }) => theme.spacing(2)};
|
||||
gap: ${({ theme }) => theme.spacing(1)};
|
||||
padding-left: ${({ theme }) => theme.spacing(2)};
|
||||
`;
|
||||
|
||||
const StyledPermissionContent = styled.div`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
gap: ${({ theme }) => theme.spacing(2)};
|
||||
`;
|
||||
|
||||
const StyledPermissionLabel = styled.span`
|
||||
color: ${({ theme }) => theme.font.color.primary};
|
||||
`;
|
||||
|
||||
const StyledOverrideInfo = styled.div`
|
||||
align-items: center;
|
||||
color: ${({ theme }) => theme.font.color.tertiary};
|
||||
display: flex;
|
||||
gap: ${({ theme }) => theme.spacing(1)};
|
||||
`;
|
||||
|
||||
const StyledCheckboxCell = styled(TableCell)`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
@ -39,11 +50,6 @@ const StyledCheckboxCell = styled(TableCell)`
|
||||
padding-right: ${({ theme }) => theme.spacing(4)};
|
||||
`;
|
||||
|
||||
const StyledTableRow = styled(TableRow)`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
`;
|
||||
|
||||
type OverridableCheckboxType = 'no_cta' | 'default' | 'override';
|
||||
|
||||
type SettingsRolePermissionsObjectLevelObjectFormObjectLevelTableRowProps = {
|
||||
@ -60,17 +66,12 @@ export const SettingsRolePermissionsObjectLevelObjectFormObjectLevelTableRow =
|
||||
settingsDraftRoleObjectPermissions,
|
||||
roleId,
|
||||
}: SettingsRolePermissionsObjectLevelObjectFormObjectLevelTableRowProps) => {
|
||||
const theme = useTheme();
|
||||
|
||||
const settingsDraftRole = useRecoilValue(
|
||||
settingsDraftRoleFamilyState(roleId),
|
||||
);
|
||||
|
||||
const label = permission.label;
|
||||
|
||||
const { Icon } =
|
||||
SETTINGS_ROLE_OBJECT_PERMISSION_ICON_CONFIG[permission.key];
|
||||
|
||||
const permissionMappings =
|
||||
SETTINGS_ROLE_OBJECT_LEVEL_PERMISSION_TO_ROLE_OBJECT_PERMISSION_MAPPING;
|
||||
|
||||
@ -120,13 +121,21 @@ export const SettingsRolePermissionsObjectLevelObjectFormObjectLevelTableRow =
|
||||
return (
|
||||
<StyledTableRow>
|
||||
<StyledPermissionCell>
|
||||
<Icon size={theme.icon.size.sm} />
|
||||
<StyledLabel>{label}</StyledLabel>
|
||||
{isRevoked ? (
|
||||
<StyledOverrideInfo>
|
||||
{t`Revoked for this object`}
|
||||
</StyledOverrideInfo>
|
||||
) : null}
|
||||
<StyledPermissionContent>
|
||||
<PermissionIcon
|
||||
permission={permission.key as SettingsRoleObjectPermissionKey}
|
||||
state={isRevoked ? 'revoked' : 'granted'}
|
||||
/>
|
||||
<StyledPermissionLabel>{label}</StyledPermissionLabel>
|
||||
</StyledPermissionContent>
|
||||
<StyledOverrideInfo>
|
||||
{isRevoked ? (
|
||||
<>
|
||||
{' · '}
|
||||
{t`Revoked for this object`}
|
||||
</>
|
||||
) : null}
|
||||
</StyledOverrideInfo>
|
||||
</StyledPermissionCell>
|
||||
<StyledCheckboxCell>
|
||||
<OverridableCheckbox
|
||||
|
||||
@ -0,0 +1,51 @@
|
||||
import {
|
||||
SETTINGS_ROLE_OBJECT_PERMISSION_ICON_CONFIG,
|
||||
SettingsRoleObjectPermissionKey,
|
||||
} from '@/settings/roles/role-permissions/objects-permissions/constants/settingsRoleObjectPermissionIconConfig';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
type PermissionIconProps = {
|
||||
permission: SettingsRoleObjectPermissionKey;
|
||||
state: 'granted' | 'revoked';
|
||||
};
|
||||
|
||||
const StyledIconWrapper = styled.div<{ isRevoked?: boolean }>`
|
||||
align-items: center;
|
||||
background: ${({ theme, isRevoked }) =>
|
||||
isRevoked ? theme.adaptiveColors.orange1 : theme.adaptiveColors.blue1};
|
||||
border: 1px solid
|
||||
${({ theme, isRevoked }) =>
|
||||
isRevoked ? theme.adaptiveColors.orange3 : theme.adaptiveColors.blue3};
|
||||
border-radius: ${({ theme }) => theme.border.radius.sm};
|
||||
display: flex;
|
||||
height: ${({ theme }) => theme.spacing(4)};
|
||||
justify-content: center;
|
||||
width: ${({ theme }) => theme.spacing(4)};
|
||||
`;
|
||||
|
||||
const StyledIcon = styled.div<{ isRevoked?: boolean }>`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
color: ${({ theme, isRevoked }) =>
|
||||
isRevoked ? theme.color.orange : theme.color.blue};
|
||||
justify-content: center;
|
||||
`;
|
||||
|
||||
export const PermissionIcon = ({ permission, state }: PermissionIconProps) => {
|
||||
const theme = useTheme();
|
||||
|
||||
const { Icon, IconForbidden } =
|
||||
SETTINGS_ROLE_OBJECT_PERMISSION_ICON_CONFIG[permission];
|
||||
|
||||
const isRevoked = state === 'revoked';
|
||||
|
||||
return (
|
||||
<StyledIconWrapper isRevoked={isRevoked}>
|
||||
<StyledIcon isRevoked={isRevoked}>
|
||||
{isRevoked && <IconForbidden size={theme.icon.size.sm} />}
|
||||
{!isRevoked && <Icon size={theme.icon.size.sm} />}
|
||||
</StyledIcon>
|
||||
</StyledIconWrapper>
|
||||
);
|
||||
};
|
||||
@ -1,32 +1,37 @@
|
||||
import { SETTINGS_ROLE_OBJECT_PERMISSION_ICON_CONFIG } from '@/settings/roles/role-permissions/objects-permissions/constants/settingsRoleObjectPermissionIconConfig';
|
||||
import { PermissionIcon } from '@/settings/roles/role-permissions/objects-permissions/components/PermissionIcon';
|
||||
import { SettingsRoleObjectPermissionKey } from '@/settings/roles/role-permissions/objects-permissions/constants/settingsRoleObjectPermissionIconConfig';
|
||||
import { SettingsRolePermissionsObjectPermission } from '@/settings/roles/role-permissions/objects-permissions/types/SettingsRolePermissionsObjectPermission';
|
||||
import { TableCell } from '@/ui/layout/table/components/TableCell';
|
||||
import { TableRow } from '@/ui/layout/table/components/TableRow';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import pluralize from 'pluralize';
|
||||
import { Checkbox, CheckboxAccent } from 'twenty-ui/input';
|
||||
|
||||
const StyledLabel = styled.span`
|
||||
color: ${({ theme }) => theme.font.color.primary};
|
||||
`;
|
||||
|
||||
const StyledOverrideInfo = styled.span`
|
||||
background: ${({ theme }) => theme.adaptiveColors.orange1};
|
||||
border-radius: ${({ theme }) => theme.spacing(1)};
|
||||
color: ${({ theme }) => theme.color.orange};
|
||||
padding: ${({ theme }) => theme.spacing(1)};
|
||||
`;
|
||||
|
||||
const StyledPermissionCell = styled(TableCell)`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
gap: ${({ theme }) => theme.spacing(2)};
|
||||
gap: ${({ theme }) => theme.spacing(1)};
|
||||
padding-left: ${({ theme }) => theme.spacing(2)};
|
||||
`;
|
||||
|
||||
const StyledPermissionContent = styled.div`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
gap: ${({ theme }) => theme.spacing(2)};
|
||||
`;
|
||||
|
||||
const StyledPermissionLabel = styled.span`
|
||||
color: ${({ theme }) => theme.font.color.primary};
|
||||
`;
|
||||
|
||||
const StyledOverrideInfo = styled.div`
|
||||
align-items: center;
|
||||
color: ${({ theme }) => theme.font.color.tertiary};
|
||||
display: flex;
|
||||
gap: ${({ theme }) => theme.spacing(1)};
|
||||
`;
|
||||
const StyledCheckboxCell = styled(TableCell)`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
@ -48,25 +53,30 @@ export const SettingsRolePermissionsObjectsTableRow = ({
|
||||
permission,
|
||||
isEditable,
|
||||
}: SettingsRolePermissionsObjectsTableRowProps) => {
|
||||
const theme = useTheme();
|
||||
|
||||
const revokedBy = permission.revokedBy;
|
||||
const isRevoked = revokedBy && revokedBy > 0;
|
||||
const isRevoked =
|
||||
revokedBy !== undefined && revokedBy !== null && revokedBy > 0;
|
||||
const label = permission.label;
|
||||
const pluralizedObject = pluralize('object', revokedBy);
|
||||
|
||||
const { Icon } = SETTINGS_ROLE_OBJECT_PERMISSION_ICON_CONFIG[permission.key];
|
||||
|
||||
return (
|
||||
<StyledTableRow>
|
||||
<StyledPermissionCell>
|
||||
<Icon size={theme.icon.size.sm} />
|
||||
<StyledLabel>{label}</StyledLabel>
|
||||
{isRevoked ? (
|
||||
<StyledOverrideInfo>
|
||||
{t`Revoked on ${revokedBy} ${pluralizedObject}`}
|
||||
</StyledOverrideInfo>
|
||||
) : null}
|
||||
<StyledPermissionContent>
|
||||
<PermissionIcon
|
||||
permission={permission.key as SettingsRoleObjectPermissionKey}
|
||||
state={isRevoked ? 'revoked' : 'granted'}
|
||||
/>
|
||||
<StyledPermissionLabel>{label}</StyledPermissionLabel>
|
||||
</StyledPermissionContent>
|
||||
<StyledOverrideInfo>
|
||||
{isRevoked ? (
|
||||
<>
|
||||
{' · '}
|
||||
{t`Revoked on ${revokedBy} ${pluralizedObject}`}
|
||||
</>
|
||||
) : null}
|
||||
</StyledOverrideInfo>
|
||||
</StyledPermissionCell>
|
||||
<StyledCheckboxCell>
|
||||
<Checkbox
|
||||
|
||||
@ -14,8 +14,14 @@ type SettingsRoleObjectPermissionIconConfig = {
|
||||
IconForbidden: IconComponent;
|
||||
};
|
||||
|
||||
export type SettingsRoleObjectPermissionKey =
|
||||
| 'canReadObjectRecords'
|
||||
| 'canUpdateObjectRecords'
|
||||
| 'canSoftDeleteObjectRecords'
|
||||
| 'canDestroyObjectRecords';
|
||||
|
||||
export const SETTINGS_ROLE_OBJECT_PERMISSION_ICON_CONFIG: Record<
|
||||
string,
|
||||
SettingsRoleObjectPermissionKey,
|
||||
SettingsRoleObjectPermissionIconConfig
|
||||
> = {
|
||||
canReadObjectRecords: {
|
||||
|
||||
Reference in New Issue
Block a user