[permissions] Add field permissions feature flag in lab (#13767)
- Add field permissions feature flag in lab - Fix / configuration of field permissions on roles page should be behind feature flag (@lucasbordeau )
This commit is contained in:
+8
@@ -5,12 +5,14 @@ import { useObjectMetadataItemsThatCanHavePermission } from '@/settings/roles/ro
|
||||
import { SettingsPath } from '@/types/SettingsPath';
|
||||
import { Table } from '@/ui/layout/table/components/Table';
|
||||
import { TableCell } from '@/ui/layout/table/components/TableCell';
|
||||
import { useFeatureFlagsMap } from '@/workspace/hooks/useFeatureFlagsMap';
|
||||
import styled from '@emotion/styled';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { IconPlus } from 'twenty-ui/display';
|
||||
import { Button } from 'twenty-ui/input';
|
||||
import { Section } from 'twenty-ui/layout';
|
||||
import { FeatureFlagKey } from '~/generated/graphql';
|
||||
import { useNavigateSettings } from '~/hooks/useNavigateSettings';
|
||||
|
||||
const StyledCreateObjectOverrideSection = styled(Section)`
|
||||
@@ -68,11 +70,16 @@ export const SettingsRolePermissionsObjectLevelSection = ({
|
||||
isDefined(objectMetadataItemsWithPermissionOverride) &&
|
||||
objectMetadataItemsWithPermissionOverride?.length > 0;
|
||||
|
||||
const featureFlags = useFeatureFlagsMap();
|
||||
const isFieldsPermissionsEnabled =
|
||||
featureFlags[FeatureFlagKey.IS_FIELDS_PERMISSIONS_ENABLED];
|
||||
|
||||
return (
|
||||
<Section>
|
||||
<Table>
|
||||
<SettingsRolePermissionsObjectLevelTableHeader
|
||||
showPermissionsLabel={hasObjectPermissions}
|
||||
isFieldsPermissionsEnabled={isFieldsPermissionsEnabled}
|
||||
/>
|
||||
<StyledTableRows>
|
||||
{hasObjectPermissions ? (
|
||||
@@ -82,6 +89,7 @@ export const SettingsRolePermissionsObjectLevelSection = ({
|
||||
key={objectMetadataItem.id}
|
||||
objectMetadataItem={objectMetadataItem}
|
||||
roleId={roleId}
|
||||
isFieldsPermissionsEnabled={isFieldsPermissionsEnabled}
|
||||
/>
|
||||
),
|
||||
)
|
||||
|
||||
+19
-4
@@ -1,20 +1,35 @@
|
||||
import { OBJECT_LEVEL_PERMISSION_TABLE_GRID_AUTO_COLUMNS } from '@/settings/roles/role-permissions/object-level-permissions/constants/ObjectLevelPermissionTableGridAutoColumns';
|
||||
import {
|
||||
OBJECT_LEVEL_PERMISSION_TABLE_GRID_AUTO_COLUMNS,
|
||||
OBJECT_LEVEL_PERMISSION_TABLE_GRID_AUTO_COLUMNS_WITHOUT_FIELD_PERMISSIONS,
|
||||
} from '@/settings/roles/role-permissions/object-level-permissions/constants/ObjectLevelPermissionTableGridAutoColumns';
|
||||
import { TableHeader } from '@/ui/layout/table/components/TableHeader';
|
||||
import { TableRow } from '@/ui/layout/table/components/TableRow';
|
||||
import { t } from '@lingui/core/macro';
|
||||
|
||||
type SettingsRolePermissionsObjectLevelTableHeaderProps = {
|
||||
showPermissionsLabel?: boolean;
|
||||
isFieldsPermissionsEnabled?: boolean;
|
||||
};
|
||||
|
||||
export const SettingsRolePermissionsObjectLevelTableHeader = ({
|
||||
showPermissionsLabel = true,
|
||||
isFieldsPermissionsEnabled = false,
|
||||
}: SettingsRolePermissionsObjectLevelTableHeaderProps) => (
|
||||
<TableRow gridAutoColumns={OBJECT_LEVEL_PERMISSION_TABLE_GRID_AUTO_COLUMNS}>
|
||||
<TableRow
|
||||
gridAutoColumns={
|
||||
isFieldsPermissionsEnabled
|
||||
? OBJECT_LEVEL_PERMISSION_TABLE_GRID_AUTO_COLUMNS
|
||||
: OBJECT_LEVEL_PERMISSION_TABLE_GRID_AUTO_COLUMNS_WITHOUT_FIELD_PERMISSIONS
|
||||
}
|
||||
>
|
||||
<TableHeader>{t`Object-Level`}</TableHeader>
|
||||
<TableHeader>{showPermissionsLabel ? t`Permissions` : ''}</TableHeader>
|
||||
<TableHeader>{showPermissionsLabel ? t`See Fields` : ''}</TableHeader>
|
||||
<TableHeader>{showPermissionsLabel ? t`Edit Fields` : ''}</TableHeader>
|
||||
{isFieldsPermissionsEnabled && (
|
||||
<>
|
||||
<TableHeader>{showPermissionsLabel ? t`See Fields` : ''}</TableHeader>
|
||||
<TableHeader>{showPermissionsLabel ? t`Edit Fields` : ''}</TableHeader>
|
||||
</>
|
||||
)}
|
||||
<TableHeader></TableHeader>
|
||||
</TableRow>
|
||||
);
|
||||
|
||||
+27
-14
@@ -2,7 +2,10 @@ import { 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 { 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 {
|
||||
OBJECT_LEVEL_PERMISSION_TABLE_GRID_AUTO_COLUMNS,
|
||||
OBJECT_LEVEL_PERMISSION_TABLE_GRID_AUTO_COLUMNS_WITHOUT_FIELD_PERMISSIONS,
|
||||
} from '@/settings/roles/role-permissions/object-level-permissions/constants/ObjectLevelPermissionTableGridAutoColumns';
|
||||
import { SettingsPath } from '@/types/SettingsPath';
|
||||
import { TableCell } from '@/ui/layout/table/components/TableCell';
|
||||
import { TableRow } from '@/ui/layout/table/components/TableRow';
|
||||
@@ -29,11 +32,13 @@ const StyledNameLabel = styled.div`
|
||||
type SettingsRolePermissionsObjectLevelTableRowProps = {
|
||||
objectMetadataItem: ObjectMetadataItem;
|
||||
roleId: string;
|
||||
isFieldsPermissionsEnabled: boolean;
|
||||
};
|
||||
|
||||
export const SettingsRolePermissionsObjectLevelTableRow = ({
|
||||
objectMetadataItem,
|
||||
roleId,
|
||||
isFieldsPermissionsEnabled,
|
||||
}: SettingsRolePermissionsObjectLevelTableRowProps) => {
|
||||
const { getIcon } = useIcons();
|
||||
const theme = useTheme();
|
||||
@@ -48,7 +53,11 @@ export const SettingsRolePermissionsObjectLevelTableRow = ({
|
||||
roleId: roleId,
|
||||
objectMetadataId: objectMetadataItem.id,
|
||||
})}
|
||||
gridAutoColumns={OBJECT_LEVEL_PERMISSION_TABLE_GRID_AUTO_COLUMNS}
|
||||
gridAutoColumns={
|
||||
isFieldsPermissionsEnabled
|
||||
? OBJECT_LEVEL_PERMISSION_TABLE_GRID_AUTO_COLUMNS
|
||||
: OBJECT_LEVEL_PERMISSION_TABLE_GRID_AUTO_COLUMNS_WITHOUT_FIELD_PERMISSIONS
|
||||
}
|
||||
>
|
||||
<StyledNameTableCell>
|
||||
{!!Icon && (
|
||||
@@ -69,18 +78,22 @@ export const SettingsRolePermissionsObjectLevelTableRow = ({
|
||||
objectLabel={objectLabelPlural}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<SettingsRolePermissionsObjectLevelSeeFieldsValueForObject
|
||||
roleId={roleId}
|
||||
objectMetadataItemId={objectMetadataItem.id}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<SettingsRolePermissionsObjectLevelUpdateFieldsValueForObject
|
||||
roleId={roleId}
|
||||
objectMetadataItemId={objectMetadataItem.id}
|
||||
/>
|
||||
</TableCell>
|
||||
{isFieldsPermissionsEnabled && (
|
||||
<>
|
||||
<TableCell>
|
||||
<SettingsRolePermissionsObjectLevelSeeFieldsValueForObject
|
||||
roleId={roleId}
|
||||
objectMetadataItemId={objectMetadataItem.id}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<SettingsRolePermissionsObjectLevelUpdateFieldsValueForObject
|
||||
roleId={roleId}
|
||||
objectMetadataItemId={objectMetadataItem.id}
|
||||
/>
|
||||
</TableCell>
|
||||
</>
|
||||
)}
|
||||
<TableCell align={'right'}>
|
||||
<IconChevronRight
|
||||
size={theme.icon.size.md}
|
||||
|
||||
+3
@@ -1,2 +1,5 @@
|
||||
export const OBJECT_LEVEL_PERMISSION_TABLE_GRID_AUTO_COLUMNS_WITHOUT_FIELD_PERMISSIONS =
|
||||
'180px 1fr 1fr';
|
||||
|
||||
export const OBJECT_LEVEL_PERMISSION_TABLE_GRID_AUTO_COLUMNS =
|
||||
'30% 20% 20% 20% 10%';
|
||||
|
||||
+22
-3
@@ -15,7 +15,11 @@ import { useMemo } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { useIcons } from 'twenty-ui/display';
|
||||
import { v4 } from 'uuid';
|
||||
import { FieldPermission, RelationType } from '~/generated/graphql';
|
||||
import {
|
||||
FieldMetadataType,
|
||||
FieldPermission,
|
||||
RelationType,
|
||||
} from '~/generated/graphql';
|
||||
|
||||
export const StyledObjectFieldTableRow = styled(TableRow)`
|
||||
grid-template-columns: 180px 1fr 60px 60px;
|
||||
@@ -71,6 +75,21 @@ export const SettingsRolePermissionsObjectLevelObjectFieldPermissionTableRow =
|
||||
const { upsertFieldPermissionInDraftRole } =
|
||||
useUpsertFieldPermissionInDraftRole(roleId);
|
||||
|
||||
const fieldIsCreatedBy =
|
||||
fieldMetadataItem.name === 'createdBy' &&
|
||||
fieldMetadataItem.type === FieldMetadataType.ACTOR;
|
||||
|
||||
const fieldIsDeletedAt =
|
||||
fieldMetadataItem.name === 'deletedAt' &&
|
||||
fieldMetadataItem.type === FieldMetadataType.DATE_TIME;
|
||||
|
||||
const fieldIsLabelIdentifier =
|
||||
fieldMetadataItem.id ===
|
||||
objectMetadataItem.labelIdentifierFieldMetadataId;
|
||||
|
||||
const fieldMustBeReadableAndUpdatable =
|
||||
fieldIsLabelIdentifier || fieldIsCreatedBy || fieldIsDeletedAt;
|
||||
|
||||
const handleSeeChange = () => {
|
||||
if (isDefined(fieldPermissionForThisFieldMetadataItem)) {
|
||||
if (
|
||||
@@ -177,7 +196,7 @@ export const SettingsRolePermissionsObjectLevelObjectFieldPermissionTableRow =
|
||||
) : (
|
||||
<TableCell>
|
||||
<OverridableCheckbox
|
||||
disabled={false}
|
||||
disabled={fieldMustBeReadableAndUpdatable ?? false}
|
||||
checked={true}
|
||||
onChange={handleSeeChange}
|
||||
type={isReadRestricted ? 'override' : 'default'}
|
||||
@@ -189,7 +208,7 @@ export const SettingsRolePermissionsObjectLevelObjectFieldPermissionTableRow =
|
||||
) : (
|
||||
<TableCell align="left">
|
||||
<OverridableCheckbox
|
||||
disabled={false}
|
||||
disabled={fieldMustBeReadableAndUpdatable ?? false}
|
||||
checked={true}
|
||||
onChange={handleUpdateChange}
|
||||
type={isUpdateRestricted ? 'override' : 'default'}
|
||||
|
||||
+12
-4
@@ -5,9 +5,11 @@ import { SettingsRolePermissionsObjectLevelObjectFormObjectLevel } from '@/setti
|
||||
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
|
||||
import { SettingsPath } from '@/types/SettingsPath';
|
||||
import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
|
||||
import { useFeatureFlagsMap } from '@/workspace/hooks/useFeatureFlagsMap';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { Button } from 'twenty-ui/input';
|
||||
import { FeatureFlagKey } from '~/generated/graphql';
|
||||
import { getSettingsPath } from '~/utils/navigation/getSettingsPath';
|
||||
|
||||
type SettingsRolePermissionsObjectLevelObjectFormProps = {
|
||||
@@ -23,6 +25,10 @@ export const SettingsRolePermissionsObjectLevelObjectForm = ({
|
||||
settingsDraftRoleFamilyState(roleId),
|
||||
);
|
||||
|
||||
const featureFlags = useFeatureFlagsMap();
|
||||
const isFieldsPermissionsEnabled =
|
||||
featureFlags[FeatureFlagKey.IS_FIELDS_PERMISSIONS_ENABLED];
|
||||
|
||||
const objectMetadata = useObjectMetadataItemById({
|
||||
objectId: objectMetadataId,
|
||||
});
|
||||
@@ -71,10 +77,12 @@ export const SettingsRolePermissionsObjectLevelObjectForm = ({
|
||||
objectMetadataItem={objectMetadataItem}
|
||||
roleId={roleId}
|
||||
/>
|
||||
<SettingsRolePermissionsObjectLevelObjectFieldPermissionTable
|
||||
objectMetadataItem={objectMetadataItem}
|
||||
roleId={roleId}
|
||||
/>
|
||||
{isFieldsPermissionsEnabled && (
|
||||
<SettingsRolePermissionsObjectLevelObjectFieldPermissionTable
|
||||
objectMetadataItem={objectMetadataItem}
|
||||
roleId={roleId}
|
||||
/>
|
||||
)}
|
||||
</SettingsPageContainer>
|
||||
</SubMenuTopBarContainer>
|
||||
);
|
||||
|
||||
+9
@@ -30,6 +30,15 @@ export const PUBLIC_FEATURE_FLAGS: PublicFeatureFlag[] = [
|
||||
imagePath: '',
|
||||
},
|
||||
},
|
||||
{
|
||||
key: FeatureFlagKey.IS_FIELDS_PERMISSIONS_ENABLED,
|
||||
metadata: {
|
||||
label: 'Fields Permissions',
|
||||
description: 'Configure permissions at field-level for your workspace',
|
||||
imagePath:
|
||||
'https://twenty.com/images/lab/is-fields-permissions-enabled.png',
|
||||
},
|
||||
},
|
||||
...(process.env.CLOUDFLARE_API_KEY
|
||||
? [
|
||||
// {
|
||||
|
||||
+11
-1
@@ -6,7 +6,7 @@ import { Repository } from 'typeorm';
|
||||
import { type FeatureFlagMap } from 'src/engine/core-modules/feature-flag/interfaces/feature-flag-map.interface';
|
||||
|
||||
import { type FeatureFlagDTO } from 'src/engine/core-modules/feature-flag/dtos/feature-flag-dto';
|
||||
import { type FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
|
||||
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
|
||||
import { FeatureFlag } from 'src/engine/core-modules/feature-flag/feature-flag.entity';
|
||||
import {
|
||||
FeatureFlagException,
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
import { featureFlagValidator } from 'src/engine/core-modules/feature-flag/validates/feature-flag.validate';
|
||||
import { publicFeatureFlagValidator } from 'src/engine/core-modules/feature-flag/validates/is-public-feature-flag.validate';
|
||||
import { WorkspaceFeatureFlagsMapCacheService } from 'src/engine/metadata-modules/workspace-feature-flags-map-cache/workspace-feature-flags-map-cache.service';
|
||||
import { WorkspacePermissionsCacheService } from 'src/engine/metadata-modules/workspace-permissions-cache/workspace-permissions-cache.service';
|
||||
|
||||
@Injectable()
|
||||
export class FeatureFlagService {
|
||||
@@ -22,6 +23,7 @@ export class FeatureFlagService {
|
||||
@InjectRepository(FeatureFlag, 'core')
|
||||
private readonly featureFlagRepository: Repository<FeatureFlag>,
|
||||
private readonly workspaceFeatureFlagsMapCacheService: WorkspaceFeatureFlagsMapCacheService,
|
||||
private readonly workspacePermissionsCacheService: WorkspacePermissionsCacheService,
|
||||
) {}
|
||||
|
||||
public async isFeatureEnabled(
|
||||
@@ -130,6 +132,14 @@ export class FeatureFlagService {
|
||||
{ workspaceId },
|
||||
);
|
||||
|
||||
if (featureFlag === FeatureFlagKey.IS_FIELDS_PERMISSIONS_ENABLED) {
|
||||
await this.workspacePermissionsCacheService.recomputeRolesPermissionsCache(
|
||||
{
|
||||
workspaceId,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 194 KiB |
Reference in New Issue
Block a user