diff --git a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/components/SettingsRolePermissionsObjectLevelSection.tsx b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/components/SettingsRolePermissionsObjectLevelSection.tsx index ec6c3babbe..01eb3f67c4 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/components/SettingsRolePermissionsObjectLevelSection.tsx +++ b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/components/SettingsRolePermissionsObjectLevelSection.tsx @@ -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 (
{hasObjectPermissions ? ( @@ -82,6 +89,7 @@ export const SettingsRolePermissionsObjectLevelSection = ({ key={objectMetadataItem.id} objectMetadataItem={objectMetadataItem} roleId={roleId} + isFieldsPermissionsEnabled={isFieldsPermissionsEnabled} /> ), ) diff --git a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/components/SettingsRolePermissionsObjectLevelTableHeader.tsx b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/components/SettingsRolePermissionsObjectLevelTableHeader.tsx index 511fba5314..f23ed8b062 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/components/SettingsRolePermissionsObjectLevelTableHeader.tsx +++ b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/components/SettingsRolePermissionsObjectLevelTableHeader.tsx @@ -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) => ( - + {t`Object-Level`} {showPermissionsLabel ? t`Permissions` : ''} - {showPermissionsLabel ? t`See Fields` : ''} - {showPermissionsLabel ? t`Edit Fields` : ''} + {isFieldsPermissionsEnabled && ( + <> + {showPermissionsLabel ? t`See Fields` : ''} + {showPermissionsLabel ? t`Edit Fields` : ''} + + )} ); diff --git a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/components/SettingsRolePermissionsObjectLevelTableRow.tsx b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/components/SettingsRolePermissionsObjectLevelTableRow.tsx index 8e11ea5cb4..9f4a3725fa 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/components/SettingsRolePermissionsObjectLevelTableRow.tsx +++ b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/components/SettingsRolePermissionsObjectLevelTableRow.tsx @@ -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 + } > {!!Icon && ( @@ -69,18 +78,22 @@ export const SettingsRolePermissionsObjectLevelTableRow = ({ objectLabel={objectLabelPlural} /> - - - - - - + {isFieldsPermissionsEnabled && ( + <> + + + + + + + + )} { if (isDefined(fieldPermissionForThisFieldMetadataItem)) { if ( @@ -177,7 +196,7 @@ export const SettingsRolePermissionsObjectLevelObjectFieldPermissionTableRow = ) : ( - + {isFieldsPermissionsEnabled && ( + + )} ); diff --git a/packages/twenty-server/src/engine/core-modules/feature-flag/constants/public-feature-flag.const.ts b/packages/twenty-server/src/engine/core-modules/feature-flag/constants/public-feature-flag.const.ts index 8449031dbe..50815c37db 100644 --- a/packages/twenty-server/src/engine/core-modules/feature-flag/constants/public-feature-flag.const.ts +++ b/packages/twenty-server/src/engine/core-modules/feature-flag/constants/public-feature-flag.const.ts @@ -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 ? [ // { diff --git a/packages/twenty-server/src/engine/core-modules/feature-flag/services/feature-flag.service.ts b/packages/twenty-server/src/engine/core-modules/feature-flag/services/feature-flag.service.ts index 2598901a2d..e973d033cd 100644 --- a/packages/twenty-server/src/engine/core-modules/feature-flag/services/feature-flag.service.ts +++ b/packages/twenty-server/src/engine/core-modules/feature-flag/services/feature-flag.service.ts @@ -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, 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; } } diff --git a/packages/twenty-website/public/images/lab/is-fields-permissions-enabled.png b/packages/twenty-website/public/images/lab/is-fields-permissions-enabled.png new file mode 100644 index 0000000000..a5ed29b9db Binary files /dev/null and b/packages/twenty-website/public/images/lab/is-fields-permissions-enabled.png differ