Skip to content

[permissions V2] Remove feature flag #12790

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion packages/twenty-front/src/generated-metadata/graphql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -691,7 +691,6 @@ export enum FeatureFlagKey {
IS_AIRTABLE_INTEGRATION_ENABLED = 'IS_AIRTABLE_INTEGRATION_ENABLED',
IS_AI_ENABLED = 'IS_AI_ENABLED',
IS_JSON_FILTER_ENABLED = 'IS_JSON_FILTER_ENABLED',
IS_PERMISSIONS_V2_ENABLED = 'IS_PERMISSIONS_V2_ENABLED',
IS_POSTGRESQL_INTEGRATION_ENABLED = 'IS_POSTGRESQL_INTEGRATION_ENABLED',
IS_STRIPE_INTEGRATION_ENABLED = 'IS_STRIPE_INTEGRATION_ENABLED',
IS_UNIQUE_INDEXES_ENABLED = 'IS_UNIQUE_INDEXES_ENABLED'
Expand Down
1 change: 0 additions & 1 deletion packages/twenty-front/src/generated/graphql.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -647,7 +647,6 @@ export enum FeatureFlagKey {
IS_AIRTABLE_INTEGRATION_ENABLED = 'IS_AIRTABLE_INTEGRATION_ENABLED',
IS_AI_ENABLED = 'IS_AI_ENABLED',
IS_JSON_FILTER_ENABLED = 'IS_JSON_FILTER_ENABLED',
IS_PERMISSIONS_V2_ENABLED = 'IS_PERMISSIONS_V2_ENABLED',
IS_POSTGRESQL_INTEGRATION_ENABLED = 'IS_POSTGRESQL_INTEGRATION_ENABLED',
IS_STRIPE_INTEGRATION_ENABLED = 'IS_STRIPE_INTEGRATION_ENABLED',
IS_UNIQUE_INDEXES_ENABLED = 'IS_UNIQUE_INDEXES_ENABLED'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,10 @@ import { SettingsRolesTableRow } from '@/settings/roles/components/SettingsRoles
import { settingsAllRolesSelector } from '@/settings/roles/states/settingsAllRolesSelector';
import { SettingsPath } from '@/types/SettingsPath';
import { TableCell } from '@/ui/layout/table/components/TableCell';
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import { useRecoilValue } from 'recoil';
import { H2Title, 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';
import { sortByAscString } from '~/utils/array/sortByAscString';

Expand All @@ -35,9 +33,6 @@ const StyledNoRoles = styled(TableCell)`

export const SettingsRolesList = () => {
const navigateSettings = useNavigateSettings();
const isPermissionsV2Enabled = useIsFeatureEnabled(
FeatureFlagKey.IS_PERMISSIONS_V2_ENABLED,
);

const settingsAllRoles = useRecoilValue(settingsAllRolesSelector);

Expand Down Expand Up @@ -69,8 +64,6 @@ export const SettingsRolesList = () => {
title={t`Create Role`}
variant="secondary"
size="small"
soon={!isPermissionsV2Enabled}
disabled={!isPermissionsV2Enabled}
onClick={() => navigateSettings(SettingsPath.RoleCreate)}
/>
</StyledCreateRoleSection>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import { SettingsRolePermissionsObjectLevelSection } from '@/settings/roles/role-permissions/object-level-permissions/components/SettingsRolePermissionsObjectLevelSection';
import { SettingsRolePermissionsObjectsSection } from '@/settings/roles/role-permissions/objects-permissions/components/SettingsRolePermissionsObjectsSection';
import { SettingsRolePermissionsSettingsSection } from '@/settings/roles/role-permissions/settings-permissions/components/SettingsRolePermissionsSettingsSection';
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import styled from '@emotion/styled';
import { FeatureFlagKey } from '~/generated-metadata/graphql';

const StyledRolePermissionsContainer = styled.div`
display: flex;
Expand All @@ -22,17 +20,13 @@ export const SettingsRolePermissions = ({
isEditable,
isCreateMode,
}: SettingsRolePermissionsProps) => {
const isPermissionsV2Enabled = useIsFeatureEnabled(
FeatureFlagKey.IS_PERMISSIONS_V2_ENABLED,
);

return (
<StyledRolePermissionsContainer>
<SettingsRolePermissionsObjectsSection
roleId={roleId}
isEditable={isEditable}
/>
{isPermissionsV2Enabled && !isCreateMode && (
{!isCreateMode && (
<SettingsRolePermissionsObjectLevelSection
roleId={roleId}
isEditable={isEditable}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { SettingsRolePermissionsSettingsTableHeader } from '@/settings/roles/rol
import { SettingsRolePermissionsSettingsTableRow } from '@/settings/roles/role-permissions/settings-permissions/components/SettingsRolePermissionsSettingsTableRow';
import { SettingsRolePermissionsSettingPermission } from '@/settings/roles/role-permissions/settings-permissions/types/SettingsRolePermissionsSettingPermission';
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import styled from '@emotion/styled';
import { t } from '@lingui/core/macro';
import { useRecoilState } from 'recoil';
Expand All @@ -18,10 +17,7 @@ import {
IconUsers,
} from 'twenty-ui/display';
import { AnimatedExpandableContainer, Card, Section } from 'twenty-ui/layout';
import {
FeatureFlagKey,
SettingPermissionType,
} from '~/generated-metadata/graphql';
import { SettingPermissionType } from '~/generated-metadata/graphql';

const StyledTable = styled.div`
border-bottom: 1px solid ${({ theme }) => theme.border.color.light};
Expand All @@ -45,10 +41,6 @@ export const SettingsRolePermissionsSettingsSection = ({
roleId,
isEditable,
}: SettingsRolePermissionsSettingsSectionProps) => {
const isPermissionsV2Enabled = useIsFeatureEnabled(
FeatureFlagKey.IS_PERMISSIONS_V2_ENABLED,
);

const [settingsDraftRole, setSettingsDraftRole] = useRecoilState(
settingsDraftRoleFamilyState(roleId),
);
Expand Down Expand Up @@ -102,23 +94,21 @@ export const SettingsRolePermissionsSettingsSection = ({
return (
<Section>
<H2Title title={t`Settings`} description={t`Settings permissions`} />
{isPermissionsV2Enabled && (
<StyledCard rounded>
<SettingsOptionCardContentToggle
Icon={IconSettings}
title={t`Settings All Access`}
description={t`Ability to edit all settings`}
checked={settingsDraftRole.canUpdateAllSettings}
disabled={!isEditable}
onChange={() => {
setSettingsDraftRole({
...settingsDraftRole,
canUpdateAllSettings: !settingsDraftRole.canUpdateAllSettings,
});
}}
/>
</StyledCard>
)}
<StyledCard rounded>
<SettingsOptionCardContentToggle
Icon={IconSettings}
title={t`Settings All Access`}
description={t`Ability to edit all settings`}
checked={settingsDraftRole.canUpdateAllSettings}
disabled={!isEditable}
onChange={() => {
setSettingsDraftRole({
...settingsDraftRole,
canUpdateAllSettings: !settingsDraftRole.canUpdateAllSettings,
});
}}
/>
</StyledCard>
<AnimatedExpandableContainer
isExpanded={!settingsDraftRole.canUpdateAllSettings}
dimension="height"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,11 @@ import { SettingsRolePermissionsSettingPermission } from '@/settings/roles/role-
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
import { TableCell } from '@/ui/layout/table/components/TableCell';
import { TableRow } from '@/ui/layout/table/components/TableRow';
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { useRecoilState } from 'recoil';
import { Checkbox } from 'twenty-ui/input';
import { v4 } from 'uuid';
import { FeatureFlagKey } from '~/generated-metadata/graphql';

const StyledTableRow = styled(TableRow)<{ isDisabled: boolean }>`
cursor: ${({ isDisabled }) => (isDisabled ? 'default' : 'pointer')};
Expand Down Expand Up @@ -57,9 +55,6 @@ export const SettingsRolePermissionsSettingsTableRow = ({
const [settingsDraftRole, setSettingsDraftRole] = useRecoilState(
settingsDraftRoleFamilyState(roleId),
);
const isPermissionsV2Enabled = useIsFeatureEnabled(
FeatureFlagKey.IS_PERMISSIONS_V2_ENABLED,
);
const canUpdateAllSettings = settingsDraftRole.canUpdateAllSettings;

const isSettingPermissionEnabled =
Expand All @@ -68,8 +63,7 @@ export const SettingsRolePermissionsSettingsTableRow = ({
) ?? false;

const isChecked = isSettingPermissionEnabled || canUpdateAllSettings;
const isDisabled =
!isEditable || canUpdateAllSettings || !isPermissionsV2Enabled;
const isDisabled = !isEditable || canUpdateAllSettings;

const handleChange = (value: boolean) => {
const currentPermissions = settingsDraftRole.settingPermissions ?? [];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,13 @@ import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBa
import { TabList } from '@/ui/layout/tab-list/components/TabList';
import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import { getOperationName } from '@apollo/client/utilities';
import { t } from '@lingui/core/macro';
import { useRecoilState, useRecoilValue } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
import { IconLockOpen, IconSettings, IconUserPlus } from 'twenty-ui/display';
import { v4 } from 'uuid';
import {
FeatureFlagKey,
Role,
useCreateOneRoleMutation,
useUpdateOneRoleMutation,
Expand Down Expand Up @@ -60,10 +58,6 @@ export const SettingsRole = ({ roleId, isCreateMode }: SettingsRoleProps) => {
SETTINGS_ROLE_DETAIL_TABS.COMPONENT_INSTANCE_ID + '-' + roleId,
);

const isPermissionsV2Enabled = useIsFeatureEnabled(
FeatureFlagKey.IS_PERMISSIONS_V2_ENABLED,
);

const navigateSettings = useNavigateSettings();

const [createRole] = useCreateOneRoleMutation();
Expand Down Expand Up @@ -91,7 +85,7 @@ export const SettingsRole = ({ roleId, isCreateMode }: SettingsRoleProps) => {
return <></>;
}

const isRoleEditable = isPermissionsV2Enabled && settingsDraftRole.isEditable;
const isRoleEditable = settingsDraftRole.isEditable;

const tabs = [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/g
import { WorkspaceQueryHookService } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook.service';
import { RESOLVER_METHOD_NAMES } from 'src/engine/api/graphql/workspace-resolver-builder/constants/resolver-method-names';
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
import { workspaceValidator } from 'src/engine/core-modules/workspace/workspace.validate';
import { SettingPermissionType } from 'src/engine/metadata-modules/permissions/constants/setting-permission-type.constants';
import {
PermissionsException,
Expand All @@ -37,7 +38,6 @@ import { UserRoleService } from 'src/engine/metadata-modules/user-role/user-role
import { WorkspaceDataSource } from 'src/engine/twenty-orm/datasource/workspace.datasource';
import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository';
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
import { workspaceValidator } from 'src/engine/core-modules/workspace/workspace.validate';

export type GraphqlQueryResolverExecutionArgs<Input extends ResolverArgs> = {
args: Input;
Expand Down Expand Up @@ -98,18 +98,8 @@ export abstract class GraphqlQueryBaseResolverService<

const featureFlagsMap = workspaceDataSource.featureFlagMap;

const isPermissionsV2Enabled =
featureFlagsMap[FeatureFlagKey.IS_PERMISSIONS_V2_ENABLED];

if (objectMetadataItemWithFieldMaps.isSystem === true) {
await this.validateSettingsPermissionsOnObjectOrThrow(options);
} else {
if (!isPermissionsV2Enabled)
await this.validateObjectRecordPermissionsOrThrow({
objectMetadataId: objectMetadataItemWithFieldMaps.id,
operationName,
options,
});
}

const hookedArgs =
Expand Down Expand Up @@ -228,39 +218,6 @@ export abstract class GraphqlQueryBaseResolverService<
}
}

private async validateObjectRecordPermissionsOrThrow({
objectMetadataId,
operationName,
options,
}: {
objectMetadataId: string;
operationName: WorkspaceResolverBuilderMethodNames;
options: WorkspaceQueryRunnerOptions;
}) {
const requiredPermission =
this.getRequiredPermissionForMethod(operationName);

const workspace = options.authContext.workspace;

workspaceValidator.assertIsDefinedOrThrow(workspace);

const userHasPermission =
await this.permissionsService.userHasObjectRecordsPermission({
userWorkspaceId: options.authContext.userWorkspaceId,
requiredPermission,
workspaceId: workspace.id,
isExecutedByApiKey: isDefined(options.authContext.apiKey),
objectMetadataId,
});

if (!userHasPermission) {
throw new PermissionsException(
PermissionsExceptionMessage.PERMISSION_DENIED,
PermissionsExceptionCode.PERMISSION_DENIED,
);
}
}

private getRequiredPermissionForMethod(
operationName: WorkspaceResolverBuilderMethodNames,
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,5 @@ export enum FeatureFlagKey {
IS_STRIPE_INTEGRATION_ENABLED = 'IS_STRIPE_INTEGRATION_ENABLED',
IS_UNIQUE_INDEXES_ENABLED = 'IS_UNIQUE_INDEXES_ENABLED',
IS_JSON_FILTER_ENABLED = 'IS_JSON_FILTER_ENABLED',
IS_PERMISSIONS_V2_ENABLED = 'IS_PERMISSIONS_V2_ENABLED',
IS_AI_ENABLED = 'IS_AI_ENABLED',
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,6 @@ export class FeatureFlagService {
},
);

if (keys.includes(FeatureFlagKey.IS_PERMISSIONS_V2_ENABLED)) {
await this.workspacePermissionsCacheService.recomputeRolesPermissionsCache(
{ workspaceId, ignoreLock: true },
);
}

await this.workspaceFeatureFlagsMapCacheService.recomputeFeatureFlagsMapCache(
{
workspaceId,
Expand Down Expand Up @@ -144,12 +138,6 @@ export class FeatureFlagService {
},
);

if (featureFlag === FeatureFlagKey.IS_PERMISSIONS_V2_ENABLED) {
await this.workspacePermissionsCacheService.recomputeRolesPermissionsCache(
{ workspaceId, ignoreLock: true },
);
}

return result;
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';

import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module';
import { UserWorkspace } from 'src/engine/core-modules/user-workspace/user-workspace.entity';
import { PermissionsService } from 'src/engine/metadata-modules/permissions/permissions.service';
import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity';
Expand All @@ -12,7 +11,6 @@ import { WorkspacePermissionsCacheModule } from 'src/engine/metadata-modules/wor
@Module({
imports: [
TypeOrmModule.forFeature([RoleEntity, UserWorkspaceRoleEntity], 'core'),
FeatureFlagModule,
TypeOrmModule.forFeature([UserWorkspace], 'core'),
UserRoleModule,
WorkspacePermissionsCacheModule,
Expand Down
Loading