[1/3] Rename permissionFlag to rolePermissionFlag + add permissionFlag catalog/backfill (#20481)
Split of #20377. ## Summary This PR separates available permission flags from per-role permission flag grants. Previously, `core.permissionFlag` stored the role assignment directly: `roleId + flag`. This PR renames that legacy grant table to `core.rolePermissionFlag`, then recreates `core.permissionFlag` as the catalog of available permission flags. ## What changed - Rename the existing `core.permissionFlag` grant table to `core.rolePermissionFlag`. - Add the new syncable `core.permissionFlag` catalog entity with key, label, description, icon, permission type, relevance flags, and custom/standard metadata. - Add stable `SystemPermissionFlag` universal identifiers for the built-in `PermissionFlagType` values. - Seed the standard permission flags for every workspace under the Twenty standard application. - Backfill existing role grants: - create missing catalog rows for existing grant keys, - add `rolePermissionFlag.permissionFlagId`, - migrate grants from the old string `flag` column to the new catalog FK, - replace the old `(flag, roleId)` uniqueness with `(permissionFlagId, roleId)`. - Rewire role permission flag caches, permission checks, role DTO mapping, and `upsertPermissionFlags` to resolve through the catalog. - Keep the existing public role permission API shape: product/app surfaces still talk about `permissionFlags` and return `{ id, roleId, flag }`. - Update metadata flat-entity machinery, migration builders, validators, action handlers, snapshots, generated schemas, docs, and app fixtures for the new `permissionFlag` / `rolePermissionFlag` split. ## Behavior after this PR - Existing permission flag grants keep working. - Existing GraphQL role permission flows keep the same public naming. - Standard permission flags are represented as catalog rows. - Permission checks now compare grants through catalog universal identifiers instead of the legacy `flag` column. - Workspace deletion cleanup now verifies both `permissionFlag` and `rolePermissionFlag`. ## What is not in this PR - Public GraphQL CRUD for custom permission flags. - App manifest support for declaring new custom permission flags. - Frontend UI for creating or assigning custom permission flags beyond the existing role permission flow. --------- Co-authored-by: Weiko <corentin@twenty.com>
This commit is contained in:
+1
@@ -30,6 +30,7 @@ export const useMetadataErrorHandler = () => {
|
||||
viewFilter: t`view filter`,
|
||||
index: t`index`,
|
||||
logicFunction: t`logic function`,
|
||||
rolePermissionFlag: t`role permission flag`,
|
||||
permissionFlag: t`permission flag`,
|
||||
objectPermission: t`object permission`,
|
||||
fieldPermission: t`field permission`,
|
||||
|
||||
-9
@@ -1,9 +0,0 @@
|
||||
import { gql } from '@apollo/client';
|
||||
|
||||
export const PERMISSION_FLAG_FRAGMENT = gql`
|
||||
fragment PermissionFlagFragment on PermissionFlag {
|
||||
id
|
||||
flag
|
||||
roleId
|
||||
}
|
||||
`;
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
import { gql } from '@apollo/client';
|
||||
|
||||
export const ROLE_PERMISSION_FLAG_FRAGMENT = gql`
|
||||
fragment RolePermissionFlagFragment on RolePermissionFlag {
|
||||
id
|
||||
flag
|
||||
roleId
|
||||
}
|
||||
`;
|
||||
+3
-3
@@ -1,15 +1,15 @@
|
||||
import { PERMISSION_FLAG_FRAGMENT } from '@/settings/roles/graphql/fragments/permissionFlagFragment';
|
||||
import { ROLE_PERMISSION_FLAG_FRAGMENT } from '@/settings/roles/graphql/fragments/rolePermissionFlagFragment';
|
||||
import { gql } from '@apollo/client';
|
||||
|
||||
export const UPSERT_PERMISSION_FLAGS = gql`
|
||||
${PERMISSION_FLAG_FRAGMENT}
|
||||
${ROLE_PERMISSION_FLAG_FRAGMENT}
|
||||
mutation UpsertPermissionFlags(
|
||||
$upsertPermissionFlagsInput: UpsertPermissionFlagsInput!
|
||||
) {
|
||||
upsertPermissionFlags(
|
||||
upsertPermissionFlagsInput: $upsertPermissionFlagsInput
|
||||
) {
|
||||
...PermissionFlagFragment
|
||||
...RolePermissionFlagFragment
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -2,7 +2,7 @@ import { AGENT_FRAGMENT } from '@/ai/graphql/fragments/agentFragment';
|
||||
import { API_KEY_FOR_ROLE_FRAGMENT } from '@/settings/roles/graphql/fragments/apiKeyForRoleFragment';
|
||||
import { FIELD_PERMISSION_FRAGMENT } from '@/settings/roles/graphql/fragments/fieldPermissionFragment';
|
||||
import { OBJECT_PERMISSION_FRAGMENT } from '@/settings/roles/graphql/fragments/objectPermissionFragment';
|
||||
import { PERMISSION_FLAG_FRAGMENT } from '@/settings/roles/graphql/fragments/permissionFlagFragment';
|
||||
import { ROLE_PERMISSION_FLAG_FRAGMENT } from '@/settings/roles/graphql/fragments/rolePermissionFlagFragment';
|
||||
import { ROLE_FRAGMENT } from '@/settings/roles/graphql/fragments/roleFragment';
|
||||
import { ROW_LEVEL_PERMISSION_PREDICATE_FRAGMENT } from '@/settings/roles/graphql/fragments/rowLevelPermissionPredicateFragment';
|
||||
import { ROW_LEVEL_PERMISSION_PREDICATE_GROUP_FRAGMENT } from '@/settings/roles/graphql/fragments/rowLevelPermissionPredicateGroupFragment';
|
||||
@@ -14,7 +14,7 @@ export const GET_ROLES = gql`
|
||||
${ROLE_FRAGMENT}
|
||||
${AGENT_FRAGMENT}
|
||||
${API_KEY_FOR_ROLE_FRAGMENT}
|
||||
${PERMISSION_FLAG_FRAGMENT}
|
||||
${ROLE_PERMISSION_FLAG_FRAGMENT}
|
||||
${OBJECT_PERMISSION_FRAGMENT}
|
||||
${FIELD_PERMISSION_FRAGMENT}
|
||||
${ROW_LEVEL_PERMISSION_PREDICATE_FRAGMENT}
|
||||
@@ -32,7 +32,7 @@ export const GET_ROLES = gql`
|
||||
...ApiKeyForRoleFragment
|
||||
}
|
||||
permissionFlags {
|
||||
...PermissionFlagFragment
|
||||
...RolePermissionFlagFragment
|
||||
}
|
||||
objectPermissions {
|
||||
...ObjectPermissionFragment
|
||||
|
||||
@@ -6,16 +6,18 @@ import {
|
||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
||||
|
||||
export const useHasPermissionFlag = (permissionFlag?: PermissionFlagType) => {
|
||||
export const useHasPermissionFlag = (
|
||||
permissionFlagKey?: PermissionFlagType,
|
||||
) => {
|
||||
const currentWorkspace = useAtomStateValue(currentWorkspaceState);
|
||||
const currentUserWorkspace = useAtomStateValue(currentUserWorkspaceState);
|
||||
|
||||
if (!permissionFlag) {
|
||||
if (!permissionFlagKey) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (
|
||||
permissionFlag === PermissionFlagType.WORKSPACE &&
|
||||
permissionFlagKey === PermissionFlagType.WORKSPACE &&
|
||||
currentWorkspace?.activationStatus ===
|
||||
WorkspaceActivationStatus.PENDING_CREATION
|
||||
) {
|
||||
@@ -23,5 +25,5 @@ export const useHasPermissionFlag = (permissionFlag?: PermissionFlagType) => {
|
||||
}
|
||||
|
||||
const userFlags = currentUserWorkspace?.permissionFlags ?? [];
|
||||
return userFlags.includes(permissionFlag);
|
||||
return userFlags.includes(permissionFlagKey);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user