Compare commits

..
Author SHA1 Message Date
prastoin 314f72abf0 handle apple image format 2026-05-12 15:39:30 +02:00
prastoin d8b50851c9 lint 2026-05-12 15:21:14 +02:00
prastoin b6ce89794e isBufferLike type predicate 2026-05-12 14:50:14 +02:00
prastoin e8ca9d0c85 sanitization error 2026-05-12 14:47:20 +02:00
prastoin ec6a52c370 async sanitize file 2026-05-12 14:40:46 +02:00
prastoin 38fdc76388 sanitize file and unit test 2026-05-12 14:40:34 +02:00
EtienneandGitHub 79b612ee12 Billing - Add default ff (#20480) 2026-05-12 10:16:38 +00:00
Charles BochetandGitHub 5003fcbbf2 chore: remove dead feature flags (#20460)
## Summary

Two related cleanups, following the same pattern as #19916 and #19074.

### Dead feature flags

Drops four feature flags whose only references are the enum entry and
the generated GraphQL/SDK files:

- `IS_COMMAND_MENU_ITEM_ENABLED` — never read anywhere.
- `IS_DATASOURCE_MIGRATED` — already commented `@deprecated`. Zero
non-generated consumers.
- `IS_RICH_TEXT_V1_MIGRATED` — the 1-19 migration that gated it was
removed in #19074; the flag became dead at that point.
- `IS_CONNECTED_ACCOUNT_MIGRATED` — only read by the 1-21
`migrate-messaging-infrastructure-to-metadata` command as an
early-return guard, but the flag was never written anywhere in the
codebase, so the guard never fired (and that workspace command is now
removed entirely — see below).

Generated GraphQL/SDK schemas and the `workspace-entity-manager` test
mock are trimmed to match.

### 1-21 workspace commands

Same pattern as #19074 (which removed workspace commands ≤ 1.18). Twenty
is now on 2-5; the 1-21 workspace commands have long since run on every
active workspace and are dead code.

Removes:

- All 14 workspace commands under `upgrade-version-command/1-21/`
(compose-email menu item, key-value-pair index, datasource backfill,
message-thread backfill, dedup engine commands, select-all fixes, AI
response format migration, edit-layout label, drop messaging FKs, folder
parent-id migration, messaging-infra-to-metadata, navigation refactor,
message-thread label fix, search-menu-item label).
- The `1-21-upgrade-version-command.module.ts` registration and the
`V1_21_UpgradeVersionCommandModule` import from
`WorkspaceCommandProviderModule`.

**Kept** (intentionally): the 3 `1-21-instance-command-fast-*` files.
Unlike workspace commands (which mutate data), instance commands carry
**schema deltas** still required by current entity definitions
(`AddViewFieldGroupIdIndex`, `MigrateMessagingCalendarToCore`,
`AddEmailThreadWidgetType`). They remain registered in
`INSTANCE_COMMANDS` and `'1.21.0'` stays in `TWENTY_PREVIOUS_VERSIONS`.
They will fold away naturally on a future version bump when a
`CoreMigrationCheck`-style snapshot picks them up.

## Test plan

- [x] `npx nx typecheck twenty-shared`
- [x] `npx nx typecheck twenty-server`
- [x] `npx nx typecheck twenty-front`
- [x] `npx prettier --check` on the changed files
- [x] `npx oxlint` on the changed server files
- [x] `npx jest feature-flag` (4 suites, 20 tests pass)
- [x] `npx jest workspace-entity-manager` (1 suite, 5 tests pass)
2026-05-12 11:25:20 +02:00
b6b4824104 ci(preview-env): drop yarn -- separator so --light reaches the seed command (#20479)
## Summary

Follow-up to #20464. That PR added `--light` to the preview env seed
command but left the `--` between `yarn command:prod` and the script
args. After yarn strips its own `--`, nest-commander still sees `argv:
[..., '--', 'workspace:seed:dev', '--light']`. Commander.js treats `--`
as the end-of-options marker, so `--light` is parsed as a positional arg
and silently ignored — the seed runs in full mode (Apple + YCombinator +
Empty3 + Empty4) and Empty4 still ends up as the default workspace.

## Evidence

In the preview run on `f706cc052b` (which had #20464's `--light` flag),
the seed step took only ~40s but the `GqlTypeGenerator` log emits four
regenerations across two workspaces with custom objects:

- 28 standard → 28 + 5 custom (`rocket, surveyResult, employmentHistory,
petCareAgreement, pet`) — matches Apple
- 28 standard → 28 + 1 custom (`surveyResult`) — matches YCombinator

With `--light` actually applied, `getLightConfig` returns `{ objects:
[], fields: [] }` so no custom objects should be generated.

The working `twenty-app-dev` invocation in
`packages/twenty-docker/twenty-app-dev/rootfs/etc/s6-overlay/scripts/init-db.sh:66`
is `yarn command:prod workspace:seed:dev --light` — no `--`. Matching
that fixes it.

## Test plan

- [ ] Trigger the preview-app label on a PR, confirm only the Apple
workspace is created and `tim@apple.dev` signs in there
- [ ] Confirm the seed step still passes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-12 10:50:08 +02:00
245 changed files with 1428 additions and 4896 deletions
+1 -1
View File
@@ -144,7 +144,7 @@ jobs:
run: |
cd packages/twenty-docker/
echo "Seeding light dev workspace (Apple only)..."
if ! docker compose exec -T server yarn command:prod -- workspace:seed:dev --light; then
if ! docker compose exec -T server yarn command:prod workspace:seed:dev --light; then
echo "❌ Seeding light dev workspace failed. Dumping server logs..."
docker compose logs server
exit 1
@@ -1,4 +1,4 @@
import { PermissionFlagGrant, defineRole } from 'twenty-sdk/define';
import { PermissionFlag, defineRole } from 'twenty-sdk/define';
import {
CONTENT_FIELD_UNIVERSAL_IDENTIFIER,
POST_CARD_UNIVERSAL_IDENTIFIER,
@@ -36,5 +36,5 @@ export default defineRole({
canUpdateFieldValue: true,
},
],
permissionFlagGrants: [PermissionFlagGrant.APPLICATIONS],
permissionFlags: [PermissionFlag.APPLICATIONS],
});
@@ -1,4 +1,4 @@
import { PermissionFlagGrant, defineRole } from 'twenty-sdk/define';
import { PermissionFlag, defineRole } from 'twenty-sdk/define';
import {
CONTENT_FIELD_UNIVERSAL_IDENTIFIER,
POST_CARD_UNIVERSAL_IDENTIFIER,
@@ -36,5 +36,5 @@ export default defineRole({
canUpdateFieldValue: false,
},
],
permissionFlagGrants: [PermissionFlagGrant.APPLICATIONS],
permissionFlags: [PermissionFlag.APPLICATIONS],
});
@@ -12,5 +12,5 @@ export default defineRole({
canUpdateAllObjectRecords: true,
canSoftDeleteAllObjectRecords: true,
canDestroyAllObjectRecords: false,
permissionFlagGrants: [PermissionFlagType.UPLOAD_FILE, PermissionFlagType.AI],
permissionFlags: [PermissionFlagType.UPLOAD_FILE, PermissionFlagType.AI],
});
@@ -21,5 +21,5 @@ export default defineRole({
canBeAssignedToApiKeys: false,
objectPermissions: [],
fieldPermissions: [],
permissionFlagGrants: [],
permissionFlags: [],
});
@@ -18,5 +18,5 @@ export default defineRole({
canBeAssignedToApiKeys: false,
objectPermissions: [],
fieldPermissions: [],
permissionFlagGrants: [],
permissionFlags: [],
});
@@ -138,7 +138,7 @@ type UserWorkspace {
createdAt: DateTime!
updatedAt: DateTime!
deletedAt: DateTime
permissionFlagGrants: [PermissionFlagType!]
permissionFlags: [PermissionFlagType!]
objectPermissions: [ObjectPermission!]
objectsPermissions: [ObjectPermission!]
twoFactorAuthenticationMethodSummary: [TwoFactorAuthenticationMethodSummary!]
@@ -244,7 +244,7 @@ type FieldPermission {
canUpdateFieldValue: Boolean
}
type PermissionFlagGrant {
type PermissionFlag {
id: UUID!
roleId: UUID!
flag: PermissionFlagType!
@@ -276,7 +276,7 @@ type Role {
canUpdateAllObjectRecords: Boolean!
canSoftDeleteAllObjectRecords: Boolean!
canDestroyAllObjectRecords: Boolean!
permissionFlagGrants: [PermissionFlagGrant!]
permissionFlags: [PermissionFlag!]
objectPermissions: [ObjectPermission!]
fieldPermissions: [FieldPermission!]
rowLevelPermissionPredicates: [RowLevelPermissionPredicate!]
@@ -1748,19 +1748,14 @@ type FeatureFlag {
enum FeatureFlagKey {
IS_UNIQUE_INDEXES_ENABLED
IS_JSON_FILTER_ENABLED
IS_COMMAND_MENU_ITEM_ENABLED
IS_MARKETPLACE_SETTING_TAB_VISIBLE
IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED
IS_PUBLIC_DOMAIN_ENABLED
IS_EMAILING_DOMAIN_ENABLED
IS_EMAIL_GROUP_ENABLED
IS_JUNCTION_RELATIONS_ENABLED
IS_CONNECTED_ACCOUNT_MIGRATED
IS_RICH_TEXT_V1_MIGRATED
IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED
IS_DATASOURCE_MIGRATED
IS_BILLING_V2_ENABLED
IS_CUSTOM_PERMISSION_FLAGS_ENABLED
}
type WorkspaceUrls {
@@ -2856,23 +2851,6 @@ enum MessageFolderPendingSyncAction {
NONE
}
type PermissionFlag {
id: UUID!
universalIdentifier: UUID!
key: String!
label: String!
description: String
iconKey: String
permissionType: String!
isRelevantForAgents: Boolean!
isRelevantForUsers: Boolean!
isRelevantForApiKeys: Boolean!
isCustom: Boolean!
applicationId: UUID!
createdAt: DateTime!
updatedAt: DateTime!
}
type CollectionHash {
collectionName: AllMetadataName!
hash: String!
@@ -2901,7 +2879,6 @@ enum AllMetadataName {
pageLayoutTab
commandMenuItem
navigationMenuItem
permissionFlagGrant
permissionFlag
objectPermission
fieldPermission
@@ -3039,8 +3016,6 @@ type Query {
myCalendarChannels(connectedAccountId: UUID): [CalendarChannel!]!
webhooks: [Webhook!]!
webhook(id: UUID!): Webhook
permissionFlags: [PermissionFlag!]!
permissionFlag(id: UUID!): PermissionFlag
minimalMetadata: MinimalMetadata!
chatThreads: [AgentChatThread!]!
chatThread(id: UUID!): AgentChatThread!
@@ -3258,7 +3233,7 @@ type Mutation {
updateOneRole(updateRoleInput: UpdateRoleInput!): Role!
deleteOneRole(roleId: UUID!): String!
upsertObjectPermissions(upsertObjectPermissionsInput: UpsertObjectPermissionsInput!): [ObjectPermission!]!
upsertPermissionFlagGrants(upsertPermissionFlagGrantsInput: UpsertPermissionFlagGrantsInput!): [PermissionFlagGrant!]!
upsertPermissionFlags(upsertPermissionFlagsInput: UpsertPermissionFlagsInput!): [PermissionFlag!]!
upsertFieldPermissions(upsertFieldPermissionsInput: UpsertFieldPermissionsInput!): [FieldPermission!]!
upsertRowLevelPermissionPredicates(input: UpsertRowLevelPermissionPredicatesInput!): UpsertRowLevelPermissionPredicatesResult!
assignRoleToAgent(agentId: UUID!, roleId: UUID!): Boolean!
@@ -3282,9 +3257,6 @@ type Mutation {
createWebhook(input: CreateWebhookInput!): Webhook!
updateWebhook(input: UpdateWebhookInput!): Webhook!
deleteWebhook(id: UUID!): Webhook!
createPermissionFlag(input: CreatePermissionFlagInput!): PermissionFlag!
updatePermissionFlag(input: UpdatePermissionFlagInput!): PermissionFlag!
deletePermissionFlag(id: UUID!): PermissionFlag!
createChatThread: AgentChatThread!
sendChatMessage(threadId: UUID!, text: String!, messageId: UUID!, browsingContext: JSON, modelId: String, fileIds: [UUID!]): SendChatMessageResult!
stopAgentChatStream(threadId: UUID!): Boolean!
@@ -4044,9 +4016,9 @@ input ObjectPermissionInput {
canDestroyObjectRecords: Boolean
}
input UpsertPermissionFlagGrantsInput {
input UpsertPermissionFlagsInput {
roleId: UUID!
permissionFlagGrantKeys: [PermissionFlagType!]!
permissionFlagKeys: [PermissionFlagType!]!
}
input UpsertFieldPermissionsInput {
@@ -4248,37 +4220,6 @@ input UpdateWebhookInputUpdates {
secret: String
}
input CreatePermissionFlagInput {
id: UUID
universalIdentifier: UUID
key: String!
label: String!
description: String
iconKey: String
permissionType: String!
isRelevantForAgents: Boolean
isRelevantForUsers: Boolean
isRelevantForApiKeys: Boolean
}
input UpdatePermissionFlagInput {
"""The id of the permission flag definition to update"""
id: UUID!
"""The fields to update"""
update: UpdatePermissionFlagInputUpdates!
}
input UpdatePermissionFlagInputUpdates {
label: String
description: String
iconKey: String
permissionType: String
isRelevantForAgents: Boolean
isRelevantForUsers: Boolean
isRelevantForApiKeys: Boolean
}
input CreateSkillInput {
id: UUID
name: String!
@@ -117,7 +117,7 @@ export interface UserWorkspace {
createdAt: Scalars['DateTime']
updatedAt: Scalars['DateTime']
deletedAt?: Scalars['DateTime']
permissionFlagGrants?: PermissionFlagType[]
permissionFlags?: PermissionFlagType[]
objectPermissions?: ObjectPermission[]
objectsPermissions?: ObjectPermission[]
twoFactorAuthenticationMethodSummary?: TwoFactorAuthenticationMethodSummary[]
@@ -190,11 +190,11 @@ export interface FieldPermission {
__typename: 'FieldPermission'
}
export interface PermissionFlagGrant {
export interface PermissionFlag {
id: Scalars['UUID']
roleId: Scalars['UUID']
flag: PermissionFlagType
__typename: 'PermissionFlagGrant'
__typename: 'PermissionFlag'
}
export interface ApiKeyForRole {
@@ -224,7 +224,7 @@ export interface Role {
canUpdateAllObjectRecords: Scalars['Boolean']
canSoftDeleteAllObjectRecords: Scalars['Boolean']
canDestroyAllObjectRecords: Scalars['Boolean']
permissionFlagGrants?: PermissionFlagGrant[]
permissionFlags?: PermissionFlag[]
objectPermissions?: ObjectPermission[]
fieldPermissions?: FieldPermission[]
rowLevelPermissionPredicates?: RowLevelPermissionPredicate[]
@@ -1389,7 +1389,7 @@ export interface FeatureFlag {
__typename: 'FeatureFlag'
}
export type FeatureFlagKey = 'IS_UNIQUE_INDEXES_ENABLED' | 'IS_JSON_FILTER_ENABLED' | 'IS_COMMAND_MENU_ITEM_ENABLED' | 'IS_MARKETPLACE_SETTING_TAB_VISIBLE' | 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED' | 'IS_PUBLIC_DOMAIN_ENABLED' | 'IS_EMAILING_DOMAIN_ENABLED' | 'IS_EMAIL_GROUP_ENABLED' | 'IS_JUNCTION_RELATIONS_ENABLED' | 'IS_CONNECTED_ACCOUNT_MIGRATED' | 'IS_RICH_TEXT_V1_MIGRATED' | 'IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED' | 'IS_DATASOURCE_MIGRATED' | 'IS_BILLING_V2_ENABLED' | 'IS_CUSTOM_PERMISSION_FLAGS_ENABLED'
export type FeatureFlagKey = 'IS_UNIQUE_INDEXES_ENABLED' | 'IS_JSON_FILTER_ENABLED' | 'IS_MARKETPLACE_SETTING_TAB_VISIBLE' | 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED' | 'IS_PUBLIC_DOMAIN_ENABLED' | 'IS_EMAILING_DOMAIN_ENABLED' | 'IS_EMAIL_GROUP_ENABLED' | 'IS_JUNCTION_RELATIONS_ENABLED' | 'IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED' | 'IS_BILLING_V2_ENABLED'
export interface WorkspaceUrls {
customUrl?: Scalars['String']
@@ -2502,31 +2502,13 @@ export interface MessageFolder {
export type MessageFolderPendingSyncAction = 'FOLDER_DELETION' | 'NONE'
export interface PermissionFlag {
id: Scalars['UUID']
universalIdentifier: Scalars['UUID']
key: Scalars['String']
label: Scalars['String']
description?: Scalars['String']
iconKey?: Scalars['String']
permissionType: Scalars['String']
isRelevantForAgents: Scalars['Boolean']
isRelevantForUsers: Scalars['Boolean']
isRelevantForApiKeys: Scalars['Boolean']
isCustom: Scalars['Boolean']
applicationId: Scalars['UUID']
createdAt: Scalars['DateTime']
updatedAt: Scalars['DateTime']
__typename: 'PermissionFlag'
}
export interface CollectionHash {
collectionName: AllMetadataName
hash: Scalars['String']
__typename: 'CollectionHash'
}
export type AllMetadataName = 'fieldMetadata' | 'objectMetadata' | 'view' | 'viewField' | 'viewFieldGroup' | 'viewGroup' | 'viewSort' | 'rowLevelPermissionPredicate' | 'rowLevelPermissionPredicateGroup' | 'viewFilterGroup' | 'index' | 'logicFunction' | 'viewFilter' | 'role' | 'roleTarget' | 'agent' | 'skill' | 'pageLayout' | 'pageLayoutWidget' | 'pageLayoutTab' | 'commandMenuItem' | 'navigationMenuItem' | 'permissionFlagGrant' | 'permissionFlag' | 'objectPermission' | 'fieldPermission' | 'frontComponent' | 'webhook' | 'applicationVariable' | 'connectionProvider'
export type AllMetadataName = 'fieldMetadata' | 'objectMetadata' | 'view' | 'viewField' | 'viewFieldGroup' | 'viewGroup' | 'viewSort' | 'rowLevelPermissionPredicate' | 'rowLevelPermissionPredicateGroup' | 'viewFilterGroup' | 'index' | 'logicFunction' | 'viewFilter' | 'role' | 'roleTarget' | 'agent' | 'skill' | 'pageLayout' | 'pageLayoutWidget' | 'pageLayoutTab' | 'commandMenuItem' | 'navigationMenuItem' | 'permissionFlag' | 'objectPermission' | 'fieldPermission' | 'frontComponent' | 'webhook' | 'applicationVariable' | 'connectionProvider'
export interface MinimalObjectMetadata {
id: Scalars['UUID']
@@ -2633,8 +2615,6 @@ export interface Query {
myCalendarChannels: CalendarChannel[]
webhooks: Webhook[]
webhook?: Webhook
permissionFlags: PermissionFlag[]
permissionFlag?: PermissionFlag
minimalMetadata: MinimalMetadata
chatThreads: AgentChatThread[]
chatThread: AgentChatThread
@@ -2785,7 +2765,7 @@ export interface Mutation {
updateOneRole: Role
deleteOneRole: Scalars['String']
upsertObjectPermissions: ObjectPermission[]
upsertPermissionFlagGrants: PermissionFlagGrant[]
upsertPermissionFlags: PermissionFlag[]
upsertFieldPermissions: FieldPermission[]
upsertRowLevelPermissionPredicates: UpsertRowLevelPermissionPredicatesResult
assignRoleToAgent: Scalars['Boolean']
@@ -2809,9 +2789,6 @@ export interface Mutation {
createWebhook: Webhook
updateWebhook: Webhook
deleteWebhook: Webhook
createPermissionFlag: PermissionFlag
updatePermissionFlag: PermissionFlag
deletePermissionFlag: PermissionFlag
createChatThread: AgentChatThread
sendChatMessage: SendChatMessageResult
stopAgentChatStream: Scalars['Boolean']
@@ -3026,7 +3003,7 @@ export interface UserWorkspaceGenqlSelection{
createdAt?: boolean | number
updatedAt?: boolean | number
deletedAt?: boolean | number
permissionFlagGrants?: boolean | number
permissionFlags?: boolean | number
objectPermissions?: ObjectPermissionGenqlSelection
objectsPermissions?: ObjectPermissionGenqlSelection
twoFactorAuthenticationMethodSummary?: TwoFactorAuthenticationMethodSummaryGenqlSelection
@@ -3090,7 +3067,7 @@ export interface FieldPermissionGenqlSelection{
__scalar?: boolean | number
}
export interface PermissionFlagGrantGenqlSelection{
export interface PermissionFlagGenqlSelection{
id?: boolean | number
roleId?: boolean | number
flag?: boolean | number
@@ -3126,7 +3103,7 @@ export interface RoleGenqlSelection{
canUpdateAllObjectRecords?: boolean | number
canSoftDeleteAllObjectRecords?: boolean | number
canDestroyAllObjectRecords?: boolean | number
permissionFlagGrants?: PermissionFlagGrantGenqlSelection
permissionFlags?: PermissionFlagGenqlSelection
objectPermissions?: ObjectPermissionGenqlSelection
fieldPermissions?: FieldPermissionGenqlSelection
rowLevelPermissionPredicates?: RowLevelPermissionPredicateGenqlSelection
@@ -5553,25 +5530,6 @@ export interface MessageFolderGenqlSelection{
__scalar?: boolean | number
}
export interface PermissionFlagGenqlSelection{
id?: boolean | number
universalIdentifier?: boolean | number
key?: boolean | number
label?: boolean | number
description?: boolean | number
iconKey?: boolean | number
permissionType?: boolean | number
isRelevantForAgents?: boolean | number
isRelevantForUsers?: boolean | number
isRelevantForApiKeys?: boolean | number
isCustom?: boolean | number
applicationId?: boolean | number
createdAt?: boolean | number
updatedAt?: boolean | number
__typename?: boolean | number
__scalar?: boolean | number
}
export interface CollectionHashGenqlSelection{
collectionName?: boolean | number
hash?: boolean | number
@@ -5706,8 +5664,6 @@ export interface QueryGenqlSelection{
myCalendarChannels?: (CalendarChannelGenqlSelection & { __args?: {connectedAccountId?: (Scalars['UUID'] | null)} })
webhooks?: WebhookGenqlSelection
webhook?: (WebhookGenqlSelection & { __args: {id: Scalars['UUID']} })
permissionFlags?: PermissionFlagGenqlSelection
permissionFlag?: (PermissionFlagGenqlSelection & { __args: {id: Scalars['UUID']} })
minimalMetadata?: MinimalMetadataGenqlSelection
chatThreads?: AgentChatThreadGenqlSelection
chatThread?: (AgentChatThreadGenqlSelection & { __args: {id: Scalars['UUID']} })
@@ -5879,7 +5835,7 @@ export interface MutationGenqlSelection{
updateOneRole?: (RoleGenqlSelection & { __args: {updateRoleInput: UpdateRoleInput} })
deleteOneRole?: { __args: {roleId: Scalars['UUID']} }
upsertObjectPermissions?: (ObjectPermissionGenqlSelection & { __args: {upsertObjectPermissionsInput: UpsertObjectPermissionsInput} })
upsertPermissionFlagGrants?: (PermissionFlagGrantGenqlSelection & { __args: {upsertPermissionFlagGrantsInput: UpsertPermissionFlagGrantsInput} })
upsertPermissionFlags?: (PermissionFlagGenqlSelection & { __args: {upsertPermissionFlagsInput: UpsertPermissionFlagsInput} })
upsertFieldPermissions?: (FieldPermissionGenqlSelection & { __args: {upsertFieldPermissionsInput: UpsertFieldPermissionsInput} })
upsertRowLevelPermissionPredicates?: (UpsertRowLevelPermissionPredicatesResultGenqlSelection & { __args: {input: UpsertRowLevelPermissionPredicatesInput} })
assignRoleToAgent?: { __args: {agentId: Scalars['UUID'], roleId: Scalars['UUID']} }
@@ -5903,9 +5859,6 @@ export interface MutationGenqlSelection{
createWebhook?: (WebhookGenqlSelection & { __args: {input: CreateWebhookInput} })
updateWebhook?: (WebhookGenqlSelection & { __args: {input: UpdateWebhookInput} })
deleteWebhook?: (WebhookGenqlSelection & { __args: {id: Scalars['UUID']} })
createPermissionFlag?: (PermissionFlagGenqlSelection & { __args: {input: CreatePermissionFlagInput} })
updatePermissionFlag?: (PermissionFlagGenqlSelection & { __args: {input: UpdatePermissionFlagInput} })
deletePermissionFlag?: (PermissionFlagGenqlSelection & { __args: {id: Scalars['UUID']} })
createChatThread?: AgentChatThreadGenqlSelection
sendChatMessage?: (SendChatMessageResultGenqlSelection & { __args: {threadId: Scalars['UUID'], text: Scalars['String'], messageId: Scalars['UUID'], browsingContext?: (Scalars['JSON'] | null), modelId?: (Scalars['String'] | null), fileIds?: (Scalars['UUID'][] | null)} })
stopAgentChatStream?: { __args: {threadId: Scalars['UUID']} }
@@ -6222,7 +6175,7 @@ export interface UpsertObjectPermissionsInput {roleId: Scalars['UUID'],objectPer
export interface ObjectPermissionInput {objectMetadataId: Scalars['UUID'],canReadObjectRecords?: (Scalars['Boolean'] | null),canUpdateObjectRecords?: (Scalars['Boolean'] | null),canSoftDeleteObjectRecords?: (Scalars['Boolean'] | null),canDestroyObjectRecords?: (Scalars['Boolean'] | null)}
export interface UpsertPermissionFlagGrantsInput {roleId: Scalars['UUID'],permissionFlagGrantKeys: PermissionFlagType[]}
export interface UpsertPermissionFlagsInput {roleId: Scalars['UUID'],permissionFlagKeys: PermissionFlagType[]}
export interface UpsertFieldPermissionsInput {roleId: Scalars['UUID'],fieldPermissions: FieldPermissionInput[]}
@@ -6296,16 +6249,6 @@ update: UpdateWebhookInputUpdates}
export interface UpdateWebhookInputUpdates {targetUrl?: (Scalars['String'] | null),operations?: (Scalars['String'][] | null),description?: (Scalars['String'] | null),secret?: (Scalars['String'] | null)}
export interface CreatePermissionFlagInput {id?: (Scalars['UUID'] | null),universalIdentifier?: (Scalars['UUID'] | null),key: Scalars['String'],label: Scalars['String'],description?: (Scalars['String'] | null),iconKey?: (Scalars['String'] | null),permissionType: Scalars['String'],isRelevantForAgents?: (Scalars['Boolean'] | null),isRelevantForUsers?: (Scalars['Boolean'] | null),isRelevantForApiKeys?: (Scalars['Boolean'] | null)}
export interface UpdatePermissionFlagInput {
/** The id of the permission flag definition to update */
id: Scalars['UUID'],
/** The fields to update */
update: UpdatePermissionFlagInputUpdates}
export interface UpdatePermissionFlagInputUpdates {label?: (Scalars['String'] | null),description?: (Scalars['String'] | null),iconKey?: (Scalars['String'] | null),permissionType?: (Scalars['String'] | null),isRelevantForAgents?: (Scalars['Boolean'] | null),isRelevantForUsers?: (Scalars['Boolean'] | null),isRelevantForApiKeys?: (Scalars['Boolean'] | null)}
export interface CreateSkillInput {id?: (Scalars['UUID'] | null),name: Scalars['String'],label: Scalars['String'],icon?: (Scalars['String'] | null),description?: (Scalars['String'] | null),content: Scalars['String']}
export interface UpdateSkillInput {id: Scalars['UUID'],name?: (Scalars['String'] | null),label?: (Scalars['String'] | null),icon?: (Scalars['String'] | null),description?: (Scalars['String'] | null),content?: (Scalars['String'] | null),isActive?: (Scalars['Boolean'] | null)}
@@ -6473,10 +6416,10 @@ export interface LogicFunctionLogsInput {applicationId?: (Scalars['UUID'] | null
const PermissionFlagGrant_possibleTypes: string[] = ['PermissionFlagGrant']
export const isPermissionFlagGrant = (obj?: { __typename?: any } | null): obj is PermissionFlagGrant => {
if (!obj?.__typename) throw new Error('__typename is missing in "isPermissionFlagGrant"')
return PermissionFlagGrant_possibleTypes.includes(obj.__typename)
const PermissionFlag_possibleTypes: string[] = ['PermissionFlag']
export const isPermissionFlag = (obj?: { __typename?: any } | null): obj is PermissionFlag => {
if (!obj?.__typename) throw new Error('__typename is missing in "isPermissionFlag"')
return PermissionFlag_possibleTypes.includes(obj.__typename)
}
@@ -8265,14 +8208,6 @@ export interface LogicFunctionLogsInput {applicationId?: (Scalars['UUID'] | null
const PermissionFlag_possibleTypes: string[] = ['PermissionFlag']
export const isPermissionFlag = (obj?: { __typename?: any } | null): obj is PermissionFlag => {
if (!obj?.__typename) throw new Error('__typename is missing in "isPermissionFlag"')
return PermissionFlag_possibleTypes.includes(obj.__typename)
}
const CollectionHash_possibleTypes: string[] = ['CollectionHash']
export const isCollectionHash = (obj?: { __typename?: any } | null): obj is CollectionHash => {
if (!obj?.__typename) throw new Error('__typename is missing in "isCollectionHash"')
@@ -8788,19 +8723,14 @@ export const enumLogicFunctionExecutionStatus = {
export const enumFeatureFlagKey = {
IS_UNIQUE_INDEXES_ENABLED: 'IS_UNIQUE_INDEXES_ENABLED' as const,
IS_JSON_FILTER_ENABLED: 'IS_JSON_FILTER_ENABLED' as const,
IS_COMMAND_MENU_ITEM_ENABLED: 'IS_COMMAND_MENU_ITEM_ENABLED' as const,
IS_MARKETPLACE_SETTING_TAB_VISIBLE: 'IS_MARKETPLACE_SETTING_TAB_VISIBLE' as const,
IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED: 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED' as const,
IS_PUBLIC_DOMAIN_ENABLED: 'IS_PUBLIC_DOMAIN_ENABLED' as const,
IS_EMAILING_DOMAIN_ENABLED: 'IS_EMAILING_DOMAIN_ENABLED' as const,
IS_EMAIL_GROUP_ENABLED: 'IS_EMAIL_GROUP_ENABLED' as const,
IS_JUNCTION_RELATIONS_ENABLED: 'IS_JUNCTION_RELATIONS_ENABLED' as const,
IS_CONNECTED_ACCOUNT_MIGRATED: 'IS_CONNECTED_ACCOUNT_MIGRATED' as const,
IS_RICH_TEXT_V1_MIGRATED: 'IS_RICH_TEXT_V1_MIGRATED' as const,
IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED: 'IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED' as const,
IS_DATASOURCE_MIGRATED: 'IS_DATASOURCE_MIGRATED' as const,
IS_BILLING_V2_ENABLED: 'IS_BILLING_V2_ENABLED' as const,
IS_CUSTOM_PERMISSION_FLAGS_ENABLED: 'IS_CUSTOM_PERMISSION_FLAGS_ENABLED' as const
IS_BILLING_V2_ENABLED: 'IS_BILLING_V2_ENABLED' as const
}
export const enumIdentityProviderType = {
@@ -8962,7 +8892,6 @@ export const enumAllMetadataName = {
pageLayoutTab: 'pageLayoutTab' as const,
commandMenuItem: 'commandMenuItem' as const,
navigationMenuItem: 'navigationMenuItem' as const,
permissionFlagGrant: 'permissionFlagGrant' as const,
permissionFlag: 'permissionFlag' as const,
objectPermission: 'objectPermission' as const,
fieldPermission: 'fieldPermission' as const,
File diff suppressed because it is too large Load Diff
@@ -9,7 +9,7 @@ A **role** is a permission set: which objects an app can read or write, which fi
```ts src/roles/restricted-company-role.ts
import {
defineRole,
PermissionFlagGrant,
PermissionFlag,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';
@@ -45,7 +45,7 @@ export default defineRole({
canUpdateFieldValue: false,
},
],
permissionFlagGrants: [PermissionFlagGrant.APPLICATIONS],
permissionFlags: [PermissionFlag.APPLICATIONS],
});
```
@@ -54,7 +54,7 @@ export default defineRole({
When you scaffold a new app, the CLI creates a default role file declared with `defineApplicationRole()`:
```ts src/roles/default-role.ts
import { defineApplicationRole, PermissionFlagGrant } from 'twenty-sdk/define';
import { defineApplicationRole, PermissionFlag } from 'twenty-sdk/define';
export const DEFAULT_ROLE_UNIVERSAL_IDENTIFIER =
'b648f87b-1d26-4961-b974-0908fd991061';
@@ -73,7 +73,7 @@ export default defineApplicationRole({
canBeAssignedToApiKeys: false,
objectPermissions: [],
fieldPermissions: [],
permissionFlagGrants: [],
permissionFlags: [],
});
```
@@ -88,5 +88,5 @@ Notes:
- Start from the scaffolded role, then progressively restrict it — the default grants broad read access, which is rarely what you want in production.
- Replace `objectPermissions` and `fieldPermissions` with the exact objects and fields your functions actually need.
- `permissionFlagGrants` control access to platform-level capabilities. Keep them minimal.
- `permissionFlags` control access to platform-level capabilities. Keep them minimal.
- See a working example: [`hello-world/src/roles/function-role.ts`](https://github.com/twentyhq/twenty/blob/main/packages/twenty-apps/hello-world/src/roles/function-role.ts).
@@ -57,7 +57,7 @@ const GET_ROLES_QUERY = `
expiresAt
revokedAt
}
permissionFlagGrants {
permissionFlags {
__typename
id
flag
@@ -271,10 +271,6 @@ export type FeatureFlag = {
export enum FeatureFlagKey {
IS_BILLING_V2_ENABLED = 'IS_BILLING_V2_ENABLED',
IS_COMMAND_MENU_ITEM_ENABLED = 'IS_COMMAND_MENU_ITEM_ENABLED',
IS_CONNECTED_ACCOUNT_MIGRATED = 'IS_CONNECTED_ACCOUNT_MIGRATED',
IS_CUSTOM_PERMISSION_FLAGS_ENABLED = 'IS_CUSTOM_PERMISSION_FLAGS_ENABLED',
IS_DATASOURCE_MIGRATED = 'IS_DATASOURCE_MIGRATED',
IS_EMAILING_DOMAIN_ENABLED = 'IS_EMAILING_DOMAIN_ENABLED',
IS_EMAIL_GROUP_ENABLED = 'IS_EMAIL_GROUP_ENABLED',
IS_JSON_FILTER_ENABLED = 'IS_JSON_FILTER_ENABLED',
@@ -283,7 +279,6 @@ export enum FeatureFlagKey {
IS_PUBLIC_DOMAIN_ENABLED = 'IS_PUBLIC_DOMAIN_ENABLED',
IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED = 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED',
IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED = 'IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED',
IS_RICH_TEXT_V1_MIGRATED = 'IS_RICH_TEXT_V1_MIGRATED',
IS_UNIQUE_INDEXES_ENABLED = 'IS_UNIQUE_INDEXES_ENABLED'
}
File diff suppressed because one or more lines are too long
@@ -19,7 +19,7 @@ import {
filterAttachmentsWithFile,
} from '@/activities/files/utils/filterAttachmentsWithFile';
import { getAttachmentUrl } from '@/activities/utils/getAttachmentUrl';
import { useHasPermissionFlagGrant } from '@/settings/roles/hooks/useHasPermissionFlagGrant';
import { useHasPermissionFlag } from '@/settings/roles/hooks/useHasPermissionFlag';
import { useModal } from '@/ui/layout/modal/hooks/useModal';
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
import { isDefined } from 'twenty-shared/utils';
@@ -129,11 +129,11 @@ export const AttachmentList = ({
isAttachmentPreviewEnabledState,
);
const hasDownloadPermission = useHasPermissionFlagGrant(
const hasDownloadPermission = useHasPermissionFlag(
PermissionFlagType.DOWNLOAD_FILE,
);
const hasUploadPermission = useHasPermissionFlagGrant(
const hasUploadPermission = useHasPermissionFlag(
PermissionFlagType.UPLOAD_FILE,
);
@@ -15,7 +15,7 @@ import { getSafeUrl, isDefined } from 'twenty-shared/utils';
import { type AttachmentWithFile } from '@/activities/files/utils/filterAttachmentsWithFile';
import { FileIcon } from '@/file/components/FileIcon';
import { useHasPermissionFlagGrant } from '@/settings/roles/hooks/useHasPermissionFlagGrant';
import { useHasPermissionFlag } from '@/settings/roles/hooks/useHasPermissionFlag';
import { CoreObjectNameSingular } from 'twenty-shared/types';
import { IconCalendar, OverflowingTextWithTooltip } from 'twenty-ui/display';
import { ThemeContext, themeCssVariables } from 'twenty-ui/theme-constants';
@@ -83,7 +83,7 @@ export const AttachmentRow = ({
const { theme } = useContext(ThemeContext);
const [isEditing, setIsEditing] = useState(false);
const hasDownloadPermission = useHasPermissionFlagGrant(
const hasDownloadPermission = useHasPermissionFlag(
PermissionFlagType.DOWNLOAD_FILE,
);
@@ -8,7 +8,7 @@ import { useAttachments } from '@/activities/files/hooks/useAttachments';
import { useUploadAttachmentFile } from '@/activities/files/hooks/useUploadAttachmentFile';
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { useObjectPermissionsForObject } from '@/object-record/hooks/useObjectPermissionsForObject';
import { useHasPermissionFlagGrant } from '@/settings/roles/hooks/useHasPermissionFlagGrant';
import { useHasPermissionFlag } from '@/settings/roles/hooks/useHasPermissionFlag';
import { useTargetRecord } from '@/ui/layout/contexts/useTargetRecord';
import { Trans, useLingui } from '@lingui/react/macro';
import { isDefined } from 'twenty-shared/utils';
@@ -82,7 +82,7 @@ export const FilesCard = () => {
const hasObjectUpdatePermissions = objectPermissions.canUpdateObjectRecords;
const hasUploadPermission = useHasPermissionFlagGrant(
const hasUploadPermission = useHasPermissionFlag(
PermissionFlagType.UPLOAD_FILE,
);
@@ -4,7 +4,7 @@ import { useNumberFormat } from '@/localization/hooks/useNumberFormat';
import { useEndSubscriptionTrialPeriod } from '@/settings/billing/hooks/useEndSubscriptionTrialPeriod';
import { useGetNextResourceCreditPrice } from '@/settings/billing/hooks/useGetNextResourceCreditPrice';
import { useGetNextMeteredBillingPrice } from '@/settings/billing/hooks/useGetNextMeteredBillingPrice';
import { usePermissionFlagGrantMap } from '@/settings/roles/hooks/usePermissionFlagGrantMap';
import { usePermissionFlagMap } from '@/settings/roles/hooks/usePermissionFlagMap';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
import { useModal } from '@/ui/layout/modal/hooks/useModal';
@@ -52,7 +52,7 @@ export const AIChatNoMoreBillingCreditsBanner = () => {
);
const { [PermissionFlagType.WORKSPACE]: hasPermissionToManageBilling } =
usePermissionFlagGrantMap();
usePermissionFlagMap();
if (!hasPermissionToManageBilling) {
return null;
@@ -17,7 +17,7 @@ import { hasTriggeredCreateForDraftState } from '@/ai/states/hasTriggeredCreateF
import { sortChatThreadsByLastActivityDesc } from '@/ai/utils/sortChatThreadsByLastActivityDesc';
import { useUpdateMetadataStoreDraft } from '@/metadata-store/hooks/useUpdateMetadataStoreDraft';
import { metadataStoreState } from '@/metadata-store/states/metadataStoreState';
import { useHasPermissionFlagGrant } from '@/settings/roles/hooks/useHasPermissionFlagGrant';
import { useHasPermissionFlag } from '@/settings/roles/hooks/useHasPermissionFlag';
import { useAtomComponentFamilyStateCallbackState } from '@/ui/utilities/state/jotai/hooks/useAtomComponentFamilyStateCallbackState';
import { useAtomState } from '@/ui/utilities/state/jotai/hooks/useAtomState';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
@@ -31,7 +31,7 @@ import {
export const AgentChatThreadInitializationEffect = () => {
const client = useApolloClient();
const { replaceDraft, applyChanges } = useUpdateMetadataStoreDraft();
const hasAiSettingsPermission = useHasPermissionFlagGrant(
const hasAiSettingsPermission = useHasPermissionFlag(
PermissionFlagType.AI_SETTINGS,
);
@@ -1,5 +1,5 @@
import { AiChatBanner } from '@/ai/components/AiChatBanner';
import { usePermissionFlagGrantMap } from '@/settings/roles/hooks/usePermissionFlagGrantMap';
import { usePermissionFlagMap } from '@/settings/roles/hooks/usePermissionFlagMap';
import { useSubscriptionStatus } from '@/workspace/hooks/useSubscriptionStatus';
import { t } from '@lingui/core/macro';
import { SettingsPath } from 'twenty-shared/types';
@@ -17,7 +17,7 @@ export const AiChatCreditsExhaustedMessage = () => {
const isTrialing = subscriptionStatus === SubscriptionStatus.Trialing;
const { [PermissionFlagType.WORKSPACE]: hasPermissionToManageBilling } =
usePermissionFlagGrantMap();
usePermissionFlagMap();
const handleUpgradeClick = () => {
navigateSettings(SettingsPath.Billing);
@@ -4,7 +4,7 @@ import { type UserWorkspace } from '~/generated-metadata/graphql';
export type CurrentUserWorkspace = Pick<
UserWorkspace,
'permissionFlagGrants' | 'twoFactorAuthenticationMethodSummary'
'permissionFlags' | 'twoFactorAuthenticationMethodSummary'
> & {
objectsPermissions: Array<ObjectPermissions & { objectMetadataId: string }>;
};
@@ -40,10 +40,10 @@ export const StandalonePageCommandMenu = () => {
featureFlags[flag.key] = flag.value === true;
}
const permissionFlagGrants: Record<string, boolean> = {};
const permissionFlags: Record<string, boolean> = {};
for (const flag of currentUserWorkspace?.permissionFlagGrants ?? []) {
permissionFlagGrants[flag] = true;
for (const flag of currentUserWorkspace?.permissionFlags ?? []) {
permissionFlags[flag] = true;
}
const targetObjectReadPermissions: Record<string, boolean> = {};
@@ -82,7 +82,7 @@ export const StandalonePageCommandMenu = () => {
},
selectedRecords: [],
featureFlags,
permissionFlagGrants,
permissionFlags,
targetObjectReadPermissions,
targetObjectWritePermissions,
objectMetadataItem: {},
@@ -90,7 +90,7 @@ export const StandalonePageCommandMenu = () => {
};
}, [
currentWorkspace?.featureFlags,
currentUserWorkspace?.permissionFlagGrants,
currentUserWorkspace?.permissionFlags,
isLayoutCustomizationModeEnabled,
objectMetadataItems,
store,
@@ -24,7 +24,7 @@ export const EMPTY_COMMAND_MENU_CONTEXT_API: CommandMenuContextApi = {
},
selectedRecords: [],
featureFlags: {},
permissionFlagGrants: {},
permissionFlags: {},
targetObjectReadPermissions: {},
targetObjectWritePermissions: {},
objectMetadataItem: {},
@@ -64,7 +64,7 @@ const getWrapper =
},
selectedRecords: [],
featureFlags: {},
permissionFlagGrants: {},
permissionFlags: {},
targetObjectReadPermissions: {},
targetObjectWritePermissions: {},
objectMetadataItem: {},
@@ -145,10 +145,10 @@ export const useCurrentCommandMenuContextApi = (): CommandMenuContextApi => {
const currentUserWorkspace = useAtomStateValue(currentUserWorkspaceState);
const permissionFlagGrants: Record<string, boolean> = {};
const permissionFlags: Record<string, boolean> = {};
for (const flag of currentUserWorkspace?.permissionFlagGrants ?? []) {
permissionFlagGrants[flag] = true;
for (const flag of currentUserWorkspace?.permissionFlags ?? []) {
permissionFlags[flag] = true;
}
const targetObjectReadPermissions: Record<string, boolean> = {};
@@ -185,7 +185,7 @@ export const useCurrentCommandMenuContextApi = (): CommandMenuContextApi => {
objectPermissions,
selectedRecords,
featureFlags,
permissionFlagGrants,
permissionFlags,
targetObjectReadPermissions,
targetObjectWritePermissions,
objectMetadataItem: objectMetadataItem ?? {},
@@ -10,7 +10,7 @@ import { InformationBannerInvalidEnterpriseKey } from '@/information-banner/comp
import { InformationBannerMaintenance } from '@/information-banner/components/maintenance/InformationBannerMaintenance';
import { InformationBannerReconnectAccountEmailAliases } from '@/information-banner/components/reconnect-account/InformationBannerReconnectAccountEmailAliases';
import { InformationBannerReconnectAccountInsufficientPermissions } from '@/information-banner/components/reconnect-account/InformationBannerReconnectAccountInsufficientPermissions';
import { usePermissionFlagGrantMap } from '@/settings/roles/hooks/usePermissionFlagGrantMap';
import { usePermissionFlagMap } from '@/settings/roles/hooks/usePermissionFlagMap';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
import { useIsWorkspaceActivationStatusEqualsTo } from '@/workspace/hooks/useIsWorkspaceActivationStatusEqualsTo';
import { useSubscriptionStatus } from '@/workspace/hooks/useSubscriptionStatus';
@@ -32,7 +32,7 @@ const StyledInformationBannerWrapper = styled.div`
export const InformationBannerWrapper = () => {
const subscriptionStatus = useSubscriptionStatus();
const permissionMap = usePermissionFlagGrantMap();
const permissionMap = usePermissionFlagMap();
const isAccountSyncEnabled =
permissionMap[PermissionFlagType.CONNECTED_ACCOUNTS];
const isWorkspaceSuspended = useIsWorkspaceActivationStatusEqualsTo(
@@ -1,7 +1,7 @@
import { useSnackBarOnQueryError } from '@/apollo/hooks/useSnackBarOnQueryError';
import { useRedirect } from '@/domain-manager/hooks/useRedirect';
import { InformationBanner } from '@/information-banner/components/InformationBanner';
import { usePermissionFlagGrantMap } from '@/settings/roles/hooks/usePermissionFlagGrantMap';
import { usePermissionFlagMap } from '@/settings/roles/hooks/usePermissionFlagMap';
import { t } from '@lingui/core/macro';
import { SettingsPath } from 'twenty-shared/types';
import { getSettingsPath, isDefined } from 'twenty-shared/utils';
@@ -24,7 +24,7 @@ export const InformationBannerBillingSubscriptionPaused = () => {
const {
[PermissionFlagType.WORKSPACE]: hasPermissionToUpdateBillingDetails,
} = usePermissionFlagGrantMap();
} = usePermissionFlagMap();
const openBillingPortal = () => {
if (isDefined(data) && isDefined(data.billingPortalSession.url)) {
@@ -1,6 +1,6 @@
import { useEndSubscriptionTrialPeriod } from '@/settings/billing/hooks/useEndSubscriptionTrialPeriod';
import { InformationBanner } from '@/information-banner/components/InformationBanner';
import { usePermissionFlagGrantMap } from '@/settings/roles/hooks/usePermissionFlagGrantMap';
import { usePermissionFlagMap } from '@/settings/roles/hooks/usePermissionFlagMap';
import { useLingui } from '@lingui/react/macro';
import { PermissionFlagType } from '~/generated-metadata/graphql';
@@ -9,7 +9,7 @@ export const InformationBannerEndTrialPeriod = () => {
const { t } = useLingui();
const { [PermissionFlagType.WORKSPACE]: hasPermissionToEndTrialPeriod } =
usePermissionFlagGrantMap();
usePermissionFlagMap();
return (
<InformationBanner
@@ -1,6 +1,6 @@
import { useRedirect } from '@/domain-manager/hooks/useRedirect';
import { InformationBanner } from '@/information-banner/components/InformationBanner';
import { usePermissionFlagGrantMap } from '@/settings/roles/hooks/usePermissionFlagGrantMap';
import { usePermissionFlagMap } from '@/settings/roles/hooks/usePermissionFlagMap';
import { t } from '@lingui/core/macro';
import { SettingsPath } from 'twenty-shared/types';
import { getSettingsPath, isDefined } from 'twenty-shared/utils';
@@ -21,7 +21,7 @@ export const InformationBannerFailPaymentInfo = () => {
const {
[PermissionFlagType.WORKSPACE]: hasPermissionToUpdateBillingDetails,
} = usePermissionFlagGrantMap();
} = usePermissionFlagMap();
const openBillingPortal = () => {
if (isDefined(data) && isDefined(data.billingPortalSession.url)) {
@@ -1,7 +1,7 @@
import { BILLING_CHECKOUT_SESSION_DEFAULT_VALUE } from '@/settings/billing/constants/BillingCheckoutSessionDefaultValue';
import { useHandleCheckoutSession } from '@/settings/billing/hooks/useHandleCheckoutSession';
import { InformationBanner } from '@/information-banner/components/InformationBanner';
import { usePermissionFlagGrantMap } from '@/settings/roles/hooks/usePermissionFlagGrantMap';
import { usePermissionFlagMap } from '@/settings/roles/hooks/usePermissionFlagMap';
import { t } from '@lingui/core/macro';
import { SettingsPath } from 'twenty-shared/types';
import { getSettingsPath } from 'twenty-shared/utils';
@@ -16,7 +16,7 @@ export const InformationBannerNoBillingSubscription = () => {
});
const { [PermissionFlagType.WORKSPACE]: hasPermissionToSubscribe } =
usePermissionFlagGrantMap();
usePermissionFlagMap();
return (
<InformationBanner
@@ -1,5 +1,5 @@
import { InformationBanner } from '@/information-banner/components/InformationBanner';
import { usePermissionFlagGrantMap } from '@/settings/roles/hooks/usePermissionFlagGrantMap';
import { usePermissionFlagMap } from '@/settings/roles/hooks/usePermissionFlagMap';
import { useLingui } from '@lingui/react/macro';
import { SettingsPath } from 'twenty-shared/types';
import { PermissionFlagType } from '~/generated-metadata/graphql';
@@ -9,7 +9,7 @@ export const InformationBannerNoMoreCredits = () => {
const { t } = useLingui();
const { [PermissionFlagType.WORKSPACE]: hasPermissionToUpdateCreditPlan } =
usePermissionFlagGrantMap();
usePermissionFlagMap();
const navigateSettings = useNavigateSettings();
@@ -30,7 +30,6 @@ export const useMetadataErrorHandler = () => {
viewFilter: t`view filter`,
index: t`index`,
logicFunction: t`logic function`,
permissionFlagGrant: t`permission flag grant`,
permissionFlag: t`permission flag`,
objectPermission: t`object permission`,
fieldPermission: t`field permission`,
@@ -104,9 +104,8 @@ export const UserMetadataProviderInitialEffect = () => {
if (isDefined(userQueryData.currentUser.currentUserWorkspace)) {
setCurrentUserWorkspace({
permissionFlagGrants:
userQueryData.currentUser.currentUserWorkspace.permissionFlagGrants ??
[],
permissionFlags:
userQueryData.currentUser.currentUserWorkspace.permissionFlags ?? [],
twoFactorAuthenticationMethodSummary:
userQueryData.currentUser.currentUserWorkspace
.twoFactorAuthenticationMethodSummary ?? [],
@@ -7,7 +7,7 @@ export type FlatRole = Omit<
| 'workspaceMembers'
| 'fieldPermissions'
| 'objectPermissions'
| 'permissionFlagGrants'
| 'permissionFlags'
| 'rowLevelPermissionPredicateGroups'
| 'rowLevelPermissionPredicates'
>;
@@ -2,7 +2,7 @@ import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
import { NavigationDrawerAiChatContent } from '@/ai/components/NavigationDrawerAiChatContent';
import { MainNavigationDrawerNavigationContent } from '@/navigation/components/MainNavigationDrawerNavigationContent';
import { MainNavigationDrawerTabsRow } from '@/navigation/components/MainNavigationDrawerTabsRow';
import { useHasPermissionFlagGrant } from '@/settings/roles/hooks/useHasPermissionFlagGrant';
import { useHasPermissionFlag } from '@/settings/roles/hooks/useHasPermissionFlag';
import { NavigationDrawer } from '@/ui/navigation/navigation-drawer/components/NavigationDrawer';
import { NavigationDrawerFixedContent } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerFixedContent';
import { NavigationDrawerScrollableContent } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerScrollableContent';
@@ -16,7 +16,7 @@ export const MainNavigationDrawer = ({ className }: { className?: string }) => {
navigationDrawerActiveTabState,
);
const currentWorkspace = useAtomStateValue(currentWorkspaceState);
const hasAiSettingsPermission = useHasPermissionFlagGrant(
const hasAiSettingsPermission = useHasPermissionFlag(
PermissionFlagType.AI_SETTINGS,
);
@@ -12,7 +12,7 @@ import { useIsMobile } from 'twenty-ui/utilities';
import { useContext } from 'react';
import { useSwitchToNewAiChat } from '@/ai/hooks/useSwitchToNewAiChat';
import { useHasPermissionFlagGrant } from '@/settings/roles/hooks/useHasPermissionFlagGrant';
import { useHasPermissionFlag } from '@/settings/roles/hooks/useHasPermissionFlag';
import { NavigationDrawerAnimatedCollapseWrapper } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerAnimatedCollapseWrapper';
import { isNavigationDrawerExpandedState } from '@/ui/navigation/states/isNavigationDrawerExpanded';
import { navigationDrawerActiveTabState } from '@/ui/navigation/states/navigationDrawerActiveTabState';
@@ -144,7 +144,7 @@ export const MainNavigationDrawerTabsRow = () => {
const setIsNavigationDrawerExpanded = useSetAtomState(
isNavigationDrawerExpandedState,
);
const hasAiSettingsPermission = useHasPermissionFlagGrant(
const hasAiSettingsPermission = useHasPermissionFlag(
PermissionFlagType.AI_SETTINGS,
);
@@ -5,7 +5,7 @@ import { useDefaultHomePagePath } from '@/navigation/hooks/useDefaultHomePagePat
import { useIsSettingsPage } from '@/navigation/hooks/useIsSettingsPage';
import { currentMobileNavigationDrawerState } from '@/navigation/states/currentMobileNavigationDrawerState';
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
import { useHasPermissionFlagGrant } from '@/settings/roles/hooks/useHasPermissionFlagGrant';
import { useHasPermissionFlag } from '@/settings/roles/hooks/useHasPermissionFlag';
import { useOpenRecordsSearchPageInSidePanel } from '@/side-panel/hooks/useOpenRecordsSearchPageInSidePanel';
import { useSidePanelMenu } from '@/side-panel/hooks/useSidePanelMenu';
import { isSidePanelOpenedState } from '@/side-panel/states/isSidePanelOpenedState';
@@ -39,7 +39,7 @@ export const MobileNavigationBar = () => {
const { switchToNewChat } = useSwitchToNewAiChat();
const { alphaSortedActiveNonSystemObjectMetadataItems } =
useFilteredObjectMetadataItems();
const hasAiSettingsPermission = useHasPermissionFlagGrant(
const hasAiSettingsPermission = useHasPermissionFlag(
PermissionFlagType.AI_SETTINGS,
);
@@ -151,7 +151,7 @@ export const responseData = {
},
workspaceMembers: [],
currentUserWorkspace: {
permissionFlagGrants: ['DATA_MODEL'],
permissionFlags: ['DATA_MODEL'],
},
currentWorkspace: {
id: 'test-workspace-id',
@@ -1,6 +1,6 @@
import { OBJECT_OPTIONS_DROPDOWN_ID } from '@/object-record/object-options-dropdown/constants/ObjectOptionsDropdownId';
import { useObjectOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsDropdown';
import { useHasPermissionFlagGrant } from '@/settings/roles/hooks/useHasPermissionFlagGrant';
import { useHasPermissionFlag } from '@/settings/roles/hooks/useHasPermissionFlag';
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
@@ -36,9 +36,7 @@ export const ObjectOptionsDropdownVisibilityContent = () => {
const { currentView } = useGetCurrentViewOnly();
const { updateCurrentView } = useUpdateCurrentView();
const { copyToClipboard } = useCopyToClipboard();
const hasViewsPermission = useHasPermissionFlagGrant(
PermissionFlagType.VIEWS,
);
const hasViewsPermission = useHasPermissionFlag(PermissionFlagType.VIEWS);
const { canPersistChanges } = useCanPersistViewChanges();
const selectedItemId = useAtomComponentStateValue(
@@ -1,4 +1,4 @@
import { useHasPermissionFlagGrant } from '@/settings/roles/hooks/useHasPermissionFlagGrant';
import { useHasPermissionFlag } from '@/settings/roles/hooks/useHasPermissionFlag';
import { isNonEmptyString } from '@sniptt/guards';
import { useParams } from 'react-router-dom';
import { PermissionFlagType } from '~/generated-metadata/graphql';
@@ -6,7 +6,7 @@ import { PermissionFlagType } from '~/generated-metadata/graphql';
export const useCanAddSelectOption = (fieldName: string) => {
const { objectNamePlural } = useParams();
const userHasPermissionToEditDataModel = useHasPermissionFlagGrant(
const userHasPermissionToEditDataModel = useHasPermissionFlag(
PermissionFlagType.DATA_MODEL,
);
@@ -7,7 +7,7 @@ import { type RecordGroupAction } from '@/object-record/record-group/types/Recor
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
import { useRecordIndexIdFromCurrentContextStore } from '@/object-record/record-index/hooks/useRecordIndexIdFromCurrentContextStore';
import { recordIndexGroupFieldMetadataItemComponentState } from '@/object-record/record-index/states/recordIndexGroupFieldMetadataComponentState';
import { useHasPermissionFlagGrant } from '@/settings/roles/hooks/useHasPermissionFlagGrant';
import { useHasPermissionFlag } from '@/settings/roles/hooks/useHasPermissionFlag';
import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState';
import { useAtomComponentFamilySelectorValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentFamilySelectorValue';
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
@@ -90,7 +90,7 @@ export const useRecordGroupActions = ({
recordIndexGroupFieldMetadataItem,
]);
const hasAccessToDataModelSettings = useHasPermissionFlagGrant(
const hasAccessToDataModelSettings = useHasPermissionFlag(
PermissionFlagType.DATA_MODEL,
);
const currentIndex = visibleRecordGroupIds.findIndex(
@@ -31,8 +31,7 @@ const renderHooks = (
onboardingStatus: OnboardingStatus,
withCurrentBillingSubscription: boolean,
withOneWorkspaceMember = true,
permissionFlagGrants = mockedUserData.currentUserWorkspace
.permissionFlagGrants,
permissionFlags = mockedUserData.currentUserWorkspace.permissionFlags,
) => {
const { result } = renderHook(
() => {
@@ -58,7 +57,7 @@ const renderHooks = (
result.current.setCurrentUser({ ...mockedUserData, onboardingStatus });
result.current.setCurrentUserWorkspace({
...mockedUserData.currentUserWorkspace,
permissionFlagGrants,
permissionFlags,
});
result.current.setCurrentWorkspace({
...mockCurrentWorkspace,
@@ -9,7 +9,7 @@ import {
currentWorkspaceState,
} from '@/auth/states/currentWorkspaceState';
import { calendarBookingPageIdState } from '@/client-config/states/calendarBookingPageIdState';
import { usePermissionFlagGrantMap } from '@/settings/roles/hooks/usePermissionFlagGrantMap';
import { usePermissionFlagMap } from '@/settings/roles/hooks/usePermissionFlagMap';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
import { useCallback } from 'react';
@@ -67,7 +67,7 @@ export const useSetNextOnboardingStatus = () => {
const currentUser = useAtomStateValue(currentUserState);
const currentWorkspace = useAtomStateValue(currentWorkspaceState);
const calendarBookingPageId = useAtomStateValue(calendarBookingPageIdState);
const permissionMap = usePermissionFlagGrantMap();
const permissionMap = usePermissionFlagMap();
const isAccountSyncEnabled =
permissionMap[PermissionFlagType.CONNECTED_ACCOUNTS];
@@ -1708,7 +1708,7 @@ export const Catalog: CatalogStory<Story, typeof WidgetRenderer> = {
// currentUserWorkspaceState is now a Jotai state, set it directly
if (isRestricted === true) {
jotaiStore.set(currentUserWorkspaceState.atom, {
permissionFlagGrants: [],
permissionFlags: [],
twoFactorAuthenticationMethodSummary: null,
objectsPermissions: [
{
@@ -1725,7 +1725,7 @@ export const Catalog: CatalogStory<Story, typeof WidgetRenderer> = {
});
} else {
jotaiStore.set(currentUserWorkspaceState.atom, {
permissionFlagGrants: [],
permissionFlags: [],
twoFactorAuthenticationMethodSummary: null,
objectsPermissions: [
{
@@ -24,7 +24,7 @@ import { useNextBillingPhase } from '@/settings/billing/hooks/useNextBillingPhas
import { useNextBillingSeats } from '@/settings/billing/hooks/useNextBillingSeats';
import { useNextPlan } from '@/settings/billing/hooks/useNextPlan';
import { useSplitPhaseItemsInPrices } from '@/settings/billing/hooks/useSplitPhaseItemsInPrices';
import { usePermissionFlagGrantMap } from '@/settings/roles/hooks/usePermissionFlagGrantMap';
import { usePermissionFlagMap } from '@/settings/roles/hooks/usePermissionFlagMap';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
import { useModal } from '@/ui/layout/modal/hooks/useModal';
@@ -190,7 +190,7 @@ export const SettingsBillingSubscriptionInfo = ({
useEndSubscriptionTrialPeriod();
const { [PermissionFlagType.WORKSPACE]: hasPermissionToEndTrialPeriod } =
usePermissionFlagGrantMap();
usePermissionFlagMap();
const seats = currentBillingSubscription.billingSubscriptionItems?.find(
(item) =>
@@ -1,5 +1,5 @@
import { useHasAccessTokenPair } from '@/auth/hooks/useHasAccessTokenPair';
import { useHasPermissionFlagGrant } from '@/settings/roles/hooks/useHasPermissionFlagGrant';
import { useHasPermissionFlag } from '@/settings/roles/hooks/useHasPermissionFlag';
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import { type ReactNode } from 'react';
import { Navigate, Outlet } from 'react-router-dom';
@@ -22,7 +22,7 @@ export const SettingsProtectedRouteWrapper = ({
requiredFeatureFlag,
}: SettingsProtectedRouteWrapperProps) => {
const hasAccessTokenPair = useHasAccessTokenPair();
const hasPermission = useHasPermissionFlagGrant(settingsPermission);
const hasPermission = useHasPermissionFlag(settingsPermission);
const requiredFeatureFlagEnabled = useIsFeatureEnabled(
requiredFeatureFlag || null,
);
@@ -12,7 +12,7 @@ import {
import { currentUserState } from '@/auth/states/currentUserState';
import { billingState } from '@/client-config/states/billingState';
import { usePermissionFlagGrantMap } from '@/settings/roles/hooks/usePermissionFlagGrantMap';
import { usePermissionFlagMap } from '@/settings/roles/hooks/usePermissionFlagMap';
import { SnackBarComponentInstanceContext } from '@/ui/feedback/snack-bar-manager/contexts/SnackBarComponentInstanceContext';
import {
jotaiStore,
@@ -65,8 +65,8 @@ const Wrapper = ({ children }: { children: ReactNode }) => (
</MockedProvider>
);
jest.mock('@/settings/roles/hooks/usePermissionFlagGrantMap', () => ({
usePermissionFlagGrantMap: jest.fn(),
jest.mock('@/settings/roles/hooks/usePermissionFlagMap', () => ({
usePermissionFlagMap: jest.fn(),
}));
jest.mock('@/domain-manager/hooks/useRedirectToWorkspaceDomain', () => ({
@@ -83,7 +83,7 @@ describe('useSettingsNavigationItems', () => {
});
it('should hide workspace settings when no permissions', () => {
(usePermissionFlagGrantMap as jest.Mock).mockImplementation(() => ({
(usePermissionFlagMap as jest.Mock).mockImplementation(() => ({
[PermissionFlagType.WORKSPACE]: false,
[PermissionFlagType.WORKSPACE_MEMBERS]: false,
[PermissionFlagType.DATA_MODEL]: false,
@@ -105,7 +105,7 @@ describe('useSettingsNavigationItems', () => {
});
it('should show workspace settings when has permissions', () => {
(usePermissionFlagGrantMap as jest.Mock).mockImplementation(() => ({
(usePermissionFlagMap as jest.Mock).mockImplementation(() => ({
[PermissionFlagType.WORKSPACE]: true,
[PermissionFlagType.WORKSPACE_MEMBERS]: true,
[PermissionFlagType.DATA_MODEL]: true,
@@ -127,7 +127,7 @@ describe('useSettingsNavigationItems', () => {
});
it('should show user section items regardless of permissions', () => {
(usePermissionFlagGrantMap as jest.Mock).mockImplementation(() => ({
(usePermissionFlagMap as jest.Mock).mockImplementation(() => ({
[PermissionFlagType.WORKSPACE]: false,
[PermissionFlagType.WORKSPACE_MEMBERS]: false,
[PermissionFlagType.DATA_MODEL]: false,
@@ -5,7 +5,7 @@ import { currentUserState } from '@/auth/states/currentUserState';
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
import { billingState } from '@/client-config/states/billingState';
import { supportChatState } from '@/client-config/states/supportChatState';
import { usePermissionFlagGrantMap } from '@/settings/roles/hooks/usePermissionFlagGrantMap';
import { usePermissionFlagMap } from '@/settings/roles/hooks/usePermissionFlagMap';
import { getDocumentationUrl } from '@/support/utils/getDocumentationUrl';
import {
type NavigationDrawerItemIndentationLevel,
@@ -72,7 +72,7 @@ const useSettingsNavigationItems = (): SettingsNavigationSection[] => {
supportChat?.supportDriver === 'FRONT' &&
isNonEmptyString(supportChat.supportFrontChatId);
const permissionMap = usePermissionFlagGrantMap();
const permissionMap = usePermissionFlagMap();
return [
{
label: t`User`,
@@ -14,10 +14,9 @@ export const useCanChangePassword = () => {
return { canChangePassword: true };
}
const hasBypassPermission =
currentUserWorkspace?.permissionFlagGrants?.includes(
PermissionFlagType.SSO_BYPASS,
);
const hasBypassPermission = currentUserWorkspace?.permissionFlags?.includes(
PermissionFlagType.SSO_BYPASS,
);
if (!hasBypassPermission) {
return { canChangePassword: false };
@@ -23,8 +23,8 @@ export const useCanEditProfileField = (field: EditableProfileField) => {
const editableFields = currentWorkspace.editableProfileFields ?? [];
const workspaceAllowsField = editableFields.includes(field);
const permissionFlagGrants = currentUserWorkspace.permissionFlagGrants ?? [];
const hasProfilePermission = permissionFlagGrants.includes(
const permissionFlags = currentUserWorkspace.permissionFlags ?? [];
const hasProfilePermission = permissionFlags.includes(
PermissionFlagType.PROFILE_INFORMATION,
);
@@ -0,0 +1,9 @@
import { gql } from '@apollo/client';
export const PERMISSION_FLAG_FRAGMENT = gql`
fragment PermissionFlagFragment on PermissionFlag {
id
flag
roleId
}
`;
@@ -1,9 +0,0 @@
import { gql } from '@apollo/client';
export const PERMISSION_FLAG_GRANT_FRAGMENT = gql`
fragment PermissionFlagGrantFragment on PermissionFlagGrant {
id
flag
roleId
}
`;
@@ -1,15 +0,0 @@
import { PERMISSION_FLAG_GRANT_FRAGMENT } from '@/settings/roles/graphql/fragments/permissionFlagGrantFragment';
import { gql } from '@apollo/client';
export const UPSERT_PERMISSION_FLAG_GRANTS = gql`
${PERMISSION_FLAG_GRANT_FRAGMENT}
mutation UpsertPermissionFlagGrants(
$upsertPermissionFlagGrantsInput: UpsertPermissionFlagGrantsInput!
) {
upsertPermissionFlagGrants(
upsertPermissionFlagGrantsInput: $upsertPermissionFlagGrantsInput
) {
...PermissionFlagGrantFragment
}
}
`;
@@ -0,0 +1,15 @@
import { PERMISSION_FLAG_FRAGMENT } from '@/settings/roles/graphql/fragments/permissionFlagFragment';
import { gql } from '@apollo/client';
export const UPSERT_PERMISSION_FLAGS = gql`
${PERMISSION_FLAG_FRAGMENT}
mutation UpsertPermissionFlags(
$upsertPermissionFlagsInput: UpsertPermissionFlagsInput!
) {
upsertPermissionFlags(
upsertPermissionFlagsInput: $upsertPermissionFlagsInput
) {
...PermissionFlagFragment
}
}
`;
@@ -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_GRANT_FRAGMENT } from '@/settings/roles/graphql/fragments/permissionFlagGrantFragment';
import { PERMISSION_FLAG_FRAGMENT } from '@/settings/roles/graphql/fragments/permissionFlagFragment';
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_GRANT_FRAGMENT}
${PERMISSION_FLAG_FRAGMENT}
${OBJECT_PERMISSION_FRAGMENT}
${FIELD_PERMISSION_FRAGMENT}
${ROW_LEVEL_PERMISSION_PREDICATE_FRAGMENT}
@@ -31,8 +31,8 @@ export const GET_ROLES = gql`
apiKeys {
...ApiKeyForRoleFragment
}
permissionFlagGrants {
...PermissionFlagGrantFragment
permissionFlags {
...PermissionFlagFragment
}
objectPermissions {
...ObjectPermissionFragment
@@ -6,24 +6,22 @@ import {
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
export const useHasPermissionFlagGrant = (
permissionFlagKey?: PermissionFlagType,
) => {
export const useHasPermissionFlag = (permissionFlag?: PermissionFlagType) => {
const currentWorkspace = useAtomStateValue(currentWorkspaceState);
const currentUserWorkspace = useAtomStateValue(currentUserWorkspaceState);
if (!permissionFlagKey) {
if (!permissionFlag) {
return true;
}
if (
permissionFlagKey === PermissionFlagType.WORKSPACE &&
permissionFlag === PermissionFlagType.WORKSPACE &&
currentWorkspace?.activationStatus ===
WorkspaceActivationStatus.PENDING_CREATION
) {
return true;
}
const userFlags = currentUserWorkspace?.permissionFlagGrants ?? [];
return userFlags.includes(permissionFlagKey);
const userFlags = currentUserWorkspace?.permissionFlags ?? [];
return userFlags.includes(permissionFlag);
};
@@ -3,14 +3,11 @@ import { PermissionFlagType } from '~/generated-metadata/graphql';
import { buildRecordFromKeysWithSameValue } from '~/utils/array/buildRecordFromKeysWithSameValue';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
export const usePermissionFlagGrantMap = (): Record<
PermissionFlagType,
boolean
> => {
export const usePermissionFlagMap = (): Record<PermissionFlagType, boolean> => {
const currentUserWorkspace = useAtomStateValue(currentUserWorkspaceState);
const currentUserWorkspaceSettingsPermissions =
currentUserWorkspace?.permissionFlagGrants;
currentUserWorkspace?.permissionFlags;
const initialPermissions = buildRecordFromKeysWithSameValue(
Object.values(PermissionFlagType),
@@ -1,7 +1,7 @@
import { SettingsOptionCardContentToggle } from '@/settings/components/SettingsOptions/SettingsOptionCardContentToggle';
import { SettingsRolePermissionsSettingsTableHeader } from '@/settings/roles/role-permissions/permission-flags/components/SettingsRolePermissionsSettingsTableHeader';
import { SettingsRolePermissionsSettingsTableRow } from '@/settings/roles/role-permissions/permission-flags/components/SettingsRolePermissionsSettingsTableRow';
import { useSettingsRolePermissionFlagGrantConfig } from '@/settings/roles/role-permissions/permission-flags/hooks/useSettingsRolePermissionFlagGrantConfig';
import { useSettingsRolePermissionFlagConfig } from '@/settings/roles/role-permissions/permission-flags/hooks/useSettingsRolePermissionFlagConfig';
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
import { useAtomFamilyStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomFamilyStateValue';
import { useSetAtomFamilyState } from '@/ui/utilities/state/jotai/hooks/useSetAtomFamilyState';
@@ -42,7 +42,7 @@ export const SettingsRolePermissionsSettingsSection = ({
roleId,
);
const settingsPermissionsConfig = useSettingsRolePermissionFlagGrantConfig({
const settingsPermissionsConfig = useSettingsRolePermissionFlagConfig({
assignmentCapabilities: {
canBeAssignedToAgents: settingsDraftRole.canBeAssignedToAgents,
canBeAssignedToUsers: settingsDraftRole.canBeAssignedToUsers,
@@ -31,15 +31,15 @@ export const SettingsRolePermissionsSettingsTableHeader = ({
);
const allSettingsPermissionsEnabled = settingsPermissionsConfig.every(
(permission) =>
settingsDraftRole.permissionFlagGrants?.some(
(permissionFlagGrant) => permissionFlagGrant.flag === permission.key,
settingsDraftRole.permissionFlags?.some(
(permissionFlag) => permissionFlag.flag === permission.key,
),
);
const someSettingsPermissionsEnabled = settingsPermissionsConfig.some(
(permission) =>
settingsDraftRole.permissionFlagGrants?.some(
(permissionFlagGrant) => permissionFlagGrant.flag === permission.key,
settingsDraftRole.permissionFlags?.some(
(permissionFlag) => permissionFlag.flag === permission.key,
),
);
@@ -64,7 +64,7 @@ export const SettingsRolePermissionsSettingsTableHeader = ({
setSettingsDraftRole({
...settingsDraftRole,
permissionFlagGrants: newValue
permissionFlags: newValue
? settingsPermissionsConfig.map((permission) => ({
id: v4(),
flag: permission.key,
@@ -47,8 +47,8 @@ export const SettingsRolePermissionsSettingsTableRow = ({
);
const isPermissionEnabled =
settingsDraftRole.permissionFlagGrants?.some(
(permissionFlagGrant) => permissionFlagGrant.flag === permission.key,
settingsDraftRole.permissionFlags?.some(
(permissionFlag) => permissionFlag.flag === permission.key,
) ?? false;
const isAllSettingsOverride =
@@ -64,12 +64,12 @@ export const SettingsRolePermissionsSettingsTableRow = ({
);
const handleChange = (value: boolean) => {
const currentPermissions = settingsDraftRole.permissionFlagGrants ?? [];
const currentPermissions = settingsDraftRole.permissionFlags ?? [];
if (value === true) {
setSettingsDraftRole({
...settingsDraftRole,
permissionFlagGrants: [
permissionFlags: [
...currentPermissions,
{
id: v4(),
@@ -81,7 +81,7 @@ export const SettingsRolePermissionsSettingsTableRow = ({
} else {
setSettingsDraftRole({
...settingsDraftRole,
permissionFlagGrants: currentPermissions.filter(
permissionFlags: currentPermissions.filter(
(p) => p.flag !== permission.key,
),
});
@@ -1,7 +1,7 @@
import { SettingsOptionCardContentToggle } from '@/settings/components/SettingsOptions/SettingsOptionCardContentToggle';
import { SettingsRolePermissionsSettingsTableHeader } from '@/settings/roles/role-permissions/permission-flags/components/SettingsRolePermissionsSettingsTableHeader';
import { SettingsRolePermissionsSettingsTableRow } from '@/settings/roles/role-permissions/permission-flags/components/SettingsRolePermissionsSettingsTableRow';
import { useActionRolePermissionFlagGrantConfig } from '@/settings/roles/role-permissions/permission-flags/hooks/useActionRolePermissionFlagGrantConfig';
import { useActionRolePermissionFlagConfig } from '@/settings/roles/role-permissions/permission-flags/hooks/useActionRolePermissionFlagConfig';
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
import { useAtomFamilyStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomFamilyStateValue';
import { useSetAtomFamilyState } from '@/ui/utilities/state/jotai/hooks/useSetAtomFamilyState';
@@ -43,7 +43,7 @@ export const SettingsRolePermissionsToolSection = ({
roleId,
);
const toolPermissionsConfig = useActionRolePermissionFlagGrantConfig({
const toolPermissionsConfig = useActionRolePermissionFlagConfig({
assignmentCapabilities: {
canBeAssignedToAgents: settingsDraftRole.canBeAssignedToAgents,
canBeAssignedToUsers: settingsDraftRole.canBeAssignedToUsers,
@@ -15,7 +15,7 @@ import {
} from 'twenty-ui/display';
import { PermissionFlagType } from '~/generated-metadata/graphql';
type UseActionRolePermissionFlagGrantConfigParams = {
type UseActionRolePermissionFlagConfigParams = {
assignmentCapabilities?: {
canBeAssignedToAgents?: boolean;
canBeAssignedToUsers?: boolean;
@@ -23,9 +23,9 @@ type UseActionRolePermissionFlagGrantConfigParams = {
};
};
export const useActionRolePermissionFlagGrantConfig = ({
export const useActionRolePermissionFlagConfig = ({
assignmentCapabilities,
}: UseActionRolePermissionFlagGrantConfigParams = {}): SettingsRolePermissionsSettingPermission[] => {
}: UseActionRolePermissionFlagConfigParams = {}): SettingsRolePermissionsSettingPermission[] => {
const {
canBeAssignedToAgents = false,
canBeAssignedToUsers = false,
@@ -18,7 +18,7 @@ import {
} from 'twenty-ui/display';
import { PermissionFlagType } from '~/generated-metadata/graphql';
type UseSettingsRolePermissionFlagGrantConfigParams = {
type UseSettingsRolePermissionFlagConfigParams = {
assignmentCapabilities?: {
canBeAssignedToAgents?: boolean;
canBeAssignedToUsers?: boolean;
@@ -26,9 +26,9 @@ type UseSettingsRolePermissionFlagGrantConfigParams = {
};
};
export const useSettingsRolePermissionFlagGrantConfig = ({
export const useSettingsRolePermissionFlagConfig = ({
assignmentCapabilities,
}: UseSettingsRolePermissionFlagGrantConfigParams = {}): SettingsRolePermissionsSettingPermission[] => {
}: UseSettingsRolePermissionFlagConfigParams = {}): SettingsRolePermissionsSettingPermission[] => {
const {
canBeAssignedToAgents = false,
canBeAssignedToUsers = false,
@@ -19,7 +19,7 @@ import {
UpdateOneRoleDocument,
UpsertFieldPermissionsDocument,
UpsertObjectPermissionsDocument,
UpsertPermissionFlagGrantsDocument,
UpsertPermissionFlagsDocument,
} from '~/generated-metadata/graphql';
import { getDirtyFields } from '~/utils/getDirtyFields';
@@ -49,9 +49,7 @@ export const useSaveDraftRoleToDB = ({
}) => {
const [createRole] = useMutation(CreateOneRoleDocument);
const [updateRole] = useMutation(UpdateOneRoleDocument);
const [upsertPermissionFlagGrants] = useMutation(
UpsertPermissionFlagGrantsDocument,
);
const [upsertPermissionFlags] = useMutation(UpsertPermissionFlagsDocument);
const [upsertObjectPermissions] = useMutation(
UpsertObjectPermissionsDocument,
);
@@ -166,14 +164,14 @@ export const useSaveDraftRoleToDB = ({
};
const updateExistingRole = async () => {
if (isDefined(dirtyFields.permissionFlagGrants)) {
await upsertPermissionFlagGrants({
if (isDefined(dirtyFields.permissionFlags)) {
await upsertPermissionFlags({
variables: {
upsertPermissionFlagGrantsInput: {
upsertPermissionFlagsInput: {
roleId: roleId,
permissionFlagGrantKeys:
settingsDraftRole.permissionFlagGrants?.map(
(permissionFlagGrant) => permissionFlagGrant.flag,
permissionFlagKeys:
settingsDraftRole.permissionFlags?.map(
(permissionFlag) => permissionFlag.flag,
) ?? [],
},
},
@@ -363,14 +361,14 @@ export const useSaveDraftRoleToDB = ({
};
const upsertRolePermissions = async (targetRoleId: string) => {
if (isDefined(dirtyFields.permissionFlagGrants)) {
await upsertPermissionFlagGrants({
if (isDefined(dirtyFields.permissionFlags)) {
await upsertPermissionFlags({
variables: {
upsertPermissionFlagGrantsInput: {
upsertPermissionFlagsInput: {
roleId: targetRoleId,
permissionFlagGrantKeys:
settingsDraftRole.permissionFlagGrants?.map(
(permissionFlagGrant) => permissionFlagGrant.flag,
permissionFlagKeys:
settingsDraftRole.permissionFlags?.map(
(permissionFlag) => permissionFlag.flag,
) ?? [],
},
},
@@ -20,7 +20,7 @@ export const settingsDraftRoleFamilyState = createAtomFamilyState<
canAccessAllTools: false,
isEditable: false,
workspaceMembers: [],
permissionFlagGrants: [],
permissionFlags: [],
objectPermissions: [],
fieldPermissions: [],
rowLevelPermissionPredicates: [],
@@ -34,7 +34,7 @@ export const USER_QUERY_FRAGMENT = gql`
}
currentUserWorkspace {
id
permissionFlagGrants
permissionFlags
objectsPermissions {
...ObjectPermissionFragment
}
@@ -74,8 +74,7 @@ export const useLoadCurrentUser = () => {
if (isDefined(user.currentUserWorkspace)) {
setCurrentUserWorkspace({
permissionFlagGrants:
user.currentUserWorkspace.permissionFlagGrants ?? [],
permissionFlags: user.currentUserWorkspace.permissionFlags ?? [],
twoFactorAuthenticationMethodSummary:
user.currentUserWorkspace.twoFactorAuthenticationMethodSummary ?? [],
objectsPermissions:
@@ -1,4 +1,4 @@
import { useHasPermissionFlagGrant } from '@/settings/roles/hooks/useHasPermissionFlagGrant';
import { useHasPermissionFlag } from '@/settings/roles/hooks/useHasPermissionFlag';
import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly';
import {
ViewVisibility,
@@ -7,9 +7,7 @@ import {
export const useCanPersistViewChanges = () => {
const { currentView } = useGetCurrentViewOnly();
const hasViewsPermission = useHasPermissionFlagGrant(
PermissionFlagType.VIEWS,
);
const hasViewsPermission = useHasPermissionFlag(PermissionFlagType.VIEWS);
if (!currentView) {
return { canPersistChanges: false };
@@ -1,7 +1,7 @@
import { useEffect } from 'react';
import { useContextStoreObjectMetadataItemOrThrow } from '@/context-store/hooks/useContextStoreObjectMetadataItemOrThrow';
import { useHasPermissionFlagGrant } from '@/settings/roles/hooks/useHasPermissionFlagGrant';
import { useHasPermissionFlag } from '@/settings/roles/hooks/useHasPermissionFlag';
import { useAtomComponentState } from '@/ui/utilities/state/jotai/hooks/useAtomComponentState';
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
import { useSetAtomComponentState } from '@/ui/utilities/state/jotai/hooks/useSetAtomComponentState';
@@ -77,7 +77,7 @@ export const ViewPickerContentEffect = () => {
const { availableFieldsForGrouping } =
useGetAvailableFieldsToGroupRecordsBy();
const { availableFieldsForCalendar } = useGetAvailableFieldsForCalendar();
const hasViewPermission = useHasPermissionFlagGrant(PermissionFlagType.VIEWS);
const hasViewPermission = useHasPermissionFlag(PermissionFlagType.VIEWS);
useEffect(() => {
if (
@@ -1,6 +1,6 @@
import { useCreateManyNavigationMenuItems } from '@/navigation-menu-item/common/hooks/useCreateManyNavigationMenuItems';
import { useNavigationMenuItemsData } from '@/navigation-menu-item/display/hooks/useNavigationMenuItemsData';
import { useHasPermissionFlagGrant } from '@/settings/roles/hooks/useHasPermissionFlagGrant';
import { useHasPermissionFlag } from '@/settings/roles/hooks/useHasPermissionFlag';
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
@@ -53,9 +53,7 @@ export const ViewPickerOptionDropdown = ({
const setViewPickerReferenceViewId = useSetAtomComponentState(
viewPickerReferenceViewIdComponentState,
);
const hasViewsPermission = useHasPermissionFlagGrant(
PermissionFlagType.VIEWS,
);
const hasViewsPermission = useHasPermissionFlag(PermissionFlagType.VIEWS);
const { createManyNavigationMenuItems } = useCreateManyNavigationMenuItems();
const { navigationMenuItems, currentWorkspaceMemberId } =
@@ -6,21 +6,21 @@ import { WorkflowAiAgentPermissionsFlagRow } from './WorkflowAiAgentPermissionsF
type WorkflowAiAgentPermissionsFlagListProps = {
title: string;
permissions: SettingsRolePermissionsSettingPermission[];
enabledPermissionFlagGrantKeys: PermissionFlagType[];
enabledPermissionFlagKeys: PermissionFlagType[];
readonly: boolean;
showDeleteButton?: boolean;
onAddPermissionFlagGrant?: (permissionKey: PermissionFlagType) => void;
onDeletePermissionFlagGrant?: (permissionKey: PermissionFlagType) => void;
onAddPermissionFlag?: (permissionKey: PermissionFlagType) => void;
onDeletePermissionFlag?: (permissionKey: PermissionFlagType) => void;
};
export const WorkflowAiAgentPermissionsFlagList = ({
title,
permissions,
enabledPermissionFlagGrantKeys,
enabledPermissionFlagKeys,
readonly,
showDeleteButton = false,
onAddPermissionFlagGrant,
onDeletePermissionFlagGrant,
onAddPermissionFlag,
onDeletePermissionFlag,
}: WorkflowAiAgentPermissionsFlagListProps) => {
if (permissions.length === 0) {
return null;
@@ -29,9 +29,7 @@ export const WorkflowAiAgentPermissionsFlagList = ({
return (
<SidePanelGroup heading={title}>
{permissions.map((permission) => {
const isEnabled = enabledPermissionFlagGrantKeys.includes(
permission.key,
);
const isEnabled = enabledPermissionFlagKeys.includes(permission.key);
return (
<WorkflowAiAgentPermissionsFlagRow
@@ -40,8 +38,8 @@ export const WorkflowAiAgentPermissionsFlagList = ({
isEnabled={isEnabled}
readonly={readonly}
showDeleteButton={showDeleteButton}
onAdd={() => onAddPermissionFlagGrant?.(permission.key)}
onDelete={() => onDeletePermissionFlagGrant?.(permission.key)}
onAdd={() => onAddPermissionFlag?.(permission.key)}
onDelete={() => onDeletePermissionFlag?.(permission.key)}
/>
);
})}
@@ -1,5 +1,5 @@
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
import { useActionRolePermissionFlagGrantConfig } from '@/settings/roles/role-permissions/permission-flags/hooks/useActionRolePermissionFlagGrantConfig';
import { useActionRolePermissionFlagConfig } from '@/settings/roles/role-permissions/permission-flags/hooks/useActionRolePermissionFlagConfig';
import { SidePanelSubPageNavigationHeader } from '@/side-panel/pages/common/components/SidePanelSubPageNavigationHeader';
import { TextInput } from '@/ui/input/components/TextInput';
import { useAtomState } from '@/ui/utilities/state/jotai/hooks/useAtomState';
@@ -98,14 +98,12 @@ export const WorkflowAiAgentPermissionsTab = ({
(item) => item.id === workflowAiAgentActionAgent?.roleId,
);
const objectPermissions = role?.objectPermissions || [];
const permissionFlagGrantKeys =
role?.permissionFlagGrants?.map(
(permissionFlagGrant) => permissionFlagGrant.flag,
) ?? [];
const permissionFlagKeys =
role?.permissionFlags?.map((permissionFlag) => permissionFlag.flag) ?? [];
const hasRoleWithPermissions =
isDefined(workflowAiAgentActionAgent?.roleId) &&
(objectPermissions.length > 0 || permissionFlagGrantKeys.length > 0);
const actionPermissionsConfig = useActionRolePermissionFlagGrantConfig({
(objectPermissions.length > 0 || permissionFlagKeys.length > 0);
const actionPermissionsConfig = useActionRolePermissionFlagConfig({
assignmentCapabilities: { canBeAssignedToAgents: true },
});
@@ -121,7 +119,7 @@ export const WorkflowAiAgentPermissionsTab = ({
filteredEnabledPermissions: filteredEnabledActionPermissions,
} = getFilteredPermissions({
permissions: actionPermissionsConfig,
permissionFlagGrantKeys,
permissionFlagKeys,
searchQuery,
});
@@ -136,12 +134,12 @@ export const WorkflowAiAgentPermissionsTab = ({
const {
handleAddPermission,
handleDeletePermission,
handleAddPermissionFlagGrant,
handleDeletePermissionFlagGrant,
handleAddPermissionFlag,
handleDeletePermissionFlag,
} = useWorkflowAiAgentPermissionActions({
readonly,
objectPermissions,
permissionFlagGrantKeys,
permissionFlagKeys,
refetchAgentAndRoles,
});
@@ -239,9 +237,9 @@ export const WorkflowAiAgentPermissionsTab = ({
<WorkflowAiAgentPermissionsFlagList
title={t`Actions`}
permissions={filteredActionPermissions}
enabledPermissionFlagGrantKeys={permissionFlagGrantKeys}
enabledPermissionFlagKeys={permissionFlagKeys}
readonly={readonly}
onAddPermissionFlagGrant={handleAddPermissionFlagGrant}
onAddPermissionFlag={handleAddPermissionFlag}
/>
</>
)}
@@ -257,10 +255,10 @@ export const WorkflowAiAgentPermissionsTab = ({
<WorkflowAiAgentPermissionsFlagList
title={t`Actions`}
permissions={filteredEnabledActionPermissions}
enabledPermissionFlagGrantKeys={permissionFlagGrantKeys}
enabledPermissionFlagKeys={permissionFlagKeys}
readonly={readonly}
showDeleteButton={!readonly}
onDeletePermissionFlagGrant={handleDeletePermissionFlagGrant}
onDeletePermissionFlag={handleDeletePermissionFlag}
/>
</>
)}
@@ -10,11 +10,11 @@ export const getFilteredPermissions = <
T extends { key: PermissionFlagType; name: string },
>({
permissions,
permissionFlagGrantKeys,
permissionFlagKeys,
searchQuery,
}: {
permissions: T[];
permissionFlagGrantKeys: PermissionFlagType[];
permissionFlagKeys: PermissionFlagType[];
searchQuery: string;
}): FilteredPermissionsResult<T> => {
const filteredPermissions = filterBySearchQuery<T>({
@@ -24,7 +24,7 @@ export const getFilteredPermissions = <
});
const enabledPermissions = permissions.filter((permission) =>
permissionFlagGrantKeys.includes(permission.key),
permissionFlagKeys.includes(permission.key),
);
const filteredEnabledPermissions = filterBySearchQuery<T>({
@@ -1,7 +1,7 @@
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
import { type SettingsRoleObjectPermissionKey } from '@/settings/roles/role-permissions/objects-permissions/constants/SettingsRoleObjectPermissionIconConfig';
import { useActionRolePermissionFlagGrantConfig } from '@/settings/roles/role-permissions/permission-flags/hooks/useActionRolePermissionFlagGrantConfig';
import { useSettingsRolePermissionFlagGrantConfig } from '@/settings/roles/role-permissions/permission-flags/hooks/useSettingsRolePermissionFlagGrantConfig';
import { useActionRolePermissionFlagConfig } from '@/settings/roles/role-permissions/permission-flags/hooks/useActionRolePermissionFlagConfig';
import { useSettingsRolePermissionFlagConfig } from '@/settings/roles/role-permissions/permission-flags/hooks/useSettingsRolePermissionFlagConfig';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { CRUD_PERMISSIONS } from '@/workflow/workflow-steps/workflow-actions/ai-agent-action/constants/WorkflowAiAgentCrudPermissions';
import { useAtomState } from '@/ui/utilities/state/jotai/hooks/useAtomState';
@@ -20,20 +20,20 @@ import {
AssignRoleToAgentDocument,
CreateOneRoleDocument,
UpsertObjectPermissionsDocument,
UpsertPermissionFlagGrantsDocument,
UpsertPermissionFlagsDocument,
} from '~/generated-metadata/graphql';
type UseWorkflowAiAgentPermissionActionsParams = {
readonly: boolean;
objectPermissions: ObjectPermission[];
permissionFlagGrantKeys: PermissionFlagType[];
permissionFlagKeys: PermissionFlagType[];
refetchAgentAndRoles: () => Promise<{ refetchedAgent?: Agent }>;
};
export const useWorkflowAiAgentPermissionActions = ({
readonly,
objectPermissions,
permissionFlagGrantKeys,
permissionFlagKeys,
refetchAgentAndRoles,
}: UseWorkflowAiAgentPermissionActionsParams) => {
const { enqueueSuccessSnackBar } = useSnackBar();
@@ -41,10 +41,10 @@ export const useWorkflowAiAgentPermissionActions = ({
useAtomState(workflowAiAgentActionAgentState);
const { alphaSortedActiveNonSystemObjectMetadataItems: objectMetadataItems } =
useFilteredObjectMetadataItems();
const settingsPermissionsConfig = useSettingsRolePermissionFlagGrantConfig({
const settingsPermissionsConfig = useSettingsRolePermissionFlagConfig({
assignmentCapabilities: { canBeAssignedToAgents: true },
});
const actionPermissionsConfig = useActionRolePermissionFlagGrantConfig({
const actionPermissionsConfig = useActionRolePermissionFlagConfig({
assignmentCapabilities: { canBeAssignedToAgents: true },
});
@@ -60,13 +60,11 @@ export const useWorkflowAiAgentPermissionActions = ({
const [upsertObjectPermissions] = useMutation(
UpsertObjectPermissionsDocument,
);
const [upsertPermissionFlagGrants] = useMutation(
UpsertPermissionFlagGrantsDocument,
);
const [upsertPermissionFlags] = useMutation(UpsertPermissionFlagsDocument);
const roleId = workflowAiAgentActionAgent?.roleId;
const permissionFlagGrantLabelMap = useMemo(
const permissionFlagLabelMap = useMemo(
() =>
[...settingsPermissionsConfig, ...actionPermissionsConfig].reduce<
Partial<Record<PermissionFlagType, string>>
@@ -298,8 +296,8 @@ export const useWorkflowAiAgentPermissionActions = ({
}
};
const handleAddPermissionFlagGrant = async (
permissionFlagGrantKey: PermissionFlagType,
const handleAddPermissionFlag = async (
permissionFlagKey: PermissionFlagType,
) => {
if (readonly) {
return;
@@ -307,21 +305,15 @@ export const useWorkflowAiAgentPermissionActions = ({
const ensuredRoleId = await ensureRoleId();
if (
!ensuredRoleId ||
permissionFlagGrantKeys.includes(permissionFlagGrantKey)
) {
if (!ensuredRoleId || permissionFlagKeys.includes(permissionFlagKey)) {
return;
}
await upsertPermissionFlagGrants({
await upsertPermissionFlags({
variables: {
upsertPermissionFlagGrantsInput: {
upsertPermissionFlagsInput: {
roleId: ensuredRoleId,
permissionFlagGrantKeys: [
...permissionFlagGrantKeys,
permissionFlagGrantKey,
],
permissionFlagKeys: [...permissionFlagKeys, permissionFlagKey],
},
},
});
@@ -331,33 +323,33 @@ export const useWorkflowAiAgentPermissionActions = ({
setWorkflowAiAgentPermissionsSelectedObjectId(undefined);
};
const handleDeletePermissionFlagGrant = async (
permissionFlagGrantKey: PermissionFlagType,
const handleDeletePermissionFlag = async (
permissionFlagKey: PermissionFlagType,
) => {
if (!isDefined(roleId) || readonly) {
return;
}
if (!permissionFlagGrantKeys.includes(permissionFlagGrantKey)) {
if (!permissionFlagKeys.includes(permissionFlagKey)) {
return;
}
const permissionFlagGrantKeysAfterRemoval = permissionFlagGrantKeys.filter(
(flag) => flag !== permissionFlagGrantKey,
const permissionFlagKeysAfterRemoval = permissionFlagKeys.filter(
(flag) => flag !== permissionFlagKey,
);
await upsertPermissionFlagGrants({
await upsertPermissionFlags({
variables: {
upsertPermissionFlagGrantsInput: {
upsertPermissionFlagsInput: {
roleId,
permissionFlagGrantKeys: permissionFlagGrantKeysAfterRemoval,
permissionFlagKeys: permissionFlagKeysAfterRemoval,
},
},
});
await refetchAgentAndRoles();
const permissionLabel = permissionFlagGrantLabelMap[permissionFlagGrantKey];
const permissionLabel = permissionFlagLabelMap[permissionFlagKey];
if (isDefined(permissionLabel)) {
enqueueSuccessSnackBar({
@@ -369,7 +361,7 @@ export const useWorkflowAiAgentPermissionActions = ({
return {
handleAddPermission,
handleDeletePermission,
handleAddPermissionFlagGrant,
handleDeletePermissionFlagGrant,
handleAddPermissionFlag,
handleDeletePermissionFlag,
};
};
@@ -130,7 +130,7 @@ export const SettingsAgentRoleTab = ({
apiKeys: [],
objectPermissions: [],
fieldPermissions: [],
permissionFlagGrants: [],
permissionFlags: [],
rowLevelPermissionPredicateGroups: [],
rowLevelPermissionPredicates: [],
});
@@ -6,7 +6,7 @@ import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
import { useUpgradeApplication } from '@/marketplace/hooks/useUpgradeApplication';
import { objectMetadataItemsSelector } from '@/object-metadata/states/objectMetadataItemsSelector';
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
import { useHasPermissionFlagGrant } from '@/settings/roles/hooks/useHasPermissionFlagGrant';
import { useHasPermissionFlag } from '@/settings/roles/hooks/useHasPermissionFlag';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
import { TabList } from '@/ui/layout/tab-list/components/TabList';
@@ -112,7 +112,7 @@ export const SettingsApplicationDetails = () => {
const { upgrade, isUpgrading } = useUpgradeApplication();
const canInstallMarketplaceApps = useHasPermissionFlagGrant(
const canInstallMarketplaceApps = useHasPermissionFlag(
PermissionFlagType.MARKETPLACE_APPS,
);
@@ -1,4 +1,4 @@
import { useHasPermissionFlagGrant } from '@/settings/roles/hooks/useHasPermissionFlagGrant';
import { useHasPermissionFlag } from '@/settings/roles/hooks/useHasPermissionFlag';
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
import { TabList } from '@/ui/layout/tab-list/components/TabList';
@@ -22,7 +22,7 @@ const APPLICATIONS_TAB_LIST_ID = 'applications-tab-list';
export const SettingsApplications = () => {
const { t } = useLingui();
const hasDeveloperAccess = useHasPermissionFlagGrant(
const hasDeveloperAccess = useHasPermissionFlag(
PermissionFlagType.API_KEYS_AND_WEBHOOKS,
);
@@ -2,7 +2,7 @@ import { CurrentApplicationContext } from '@/applications/contexts/CurrentApplic
import { useInstallMarketplaceApp } from '@/marketplace/hooks/useInstallMarketplaceApp';
import { useUpgradeApplication } from '@/marketplace/hooks/useUpgradeApplication';
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
import { useHasPermissionFlagGrant } from '@/settings/roles/hooks/useHasPermissionFlagGrant';
import { useHasPermissionFlag } from '@/settings/roles/hooks/useHasPermissionFlag';
import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
import { TabList } from '@/ui/layout/tab-list/components/TabList';
import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
@@ -46,7 +46,7 @@ export const SettingsAvailableApplicationDetails = () => {
const { install, isInstalling } = useInstallMarketplaceApp();
const { upgrade, isUpgrading } = useUpgradeApplication();
const canInstallMarketplaceApps = useHasPermissionFlagGrant(
const canInstallMarketplaceApps = useHasPermissionFlag(
PermissionFlagType.MARKETPLACE_APPS,
);
@@ -121,12 +121,12 @@ const buildSyntheticRole = (
canReadFieldValue: permission.canReadFieldValue,
canUpdateFieldValue: permission.canUpdateFieldValue,
})),
permissionFlagGrants: (defaultRole.permissionFlagGrants ?? []).map(
(permissionFlagGrant) => ({
__typename: 'PermissionFlagGrant' as const,
permissionFlags: (defaultRole.permissionFlags ?? []).map(
(permissionFlag) => ({
__typename: 'PermissionFlag' as const,
id: uuidv4(),
roleId: defaultRole.universalIdentifier,
flag: permissionFlagGrant.flag,
flag: permissionFlag.flag,
}),
),
});
@@ -6,7 +6,7 @@ import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord';
import { useImpersonationSession } from '@/auth/hooks/useImpersonationSession';
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
import { SettingsRolesQueryEffect } from '@/settings/roles/components/SettingsRolesQueryEffect';
import { useHasPermissionFlagGrant } from '@/settings/roles/hooks/useHasPermissionFlagGrant';
import { useHasPermissionFlag } from '@/settings/roles/hooks/useHasPermissionFlag';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
import { useModal } from '@/ui/layout/modal/hooks/useModal';
@@ -54,8 +54,7 @@ export const SettingsWorkspaceMember = () => {
const [impersonate] = useMutation(ImpersonateDocument);
const isImpersonating = useAtomStateValue(isImpersonatingState);
const canImpersonate =
useHasPermissionFlagGrant(PermissionFlagType.IMPERSONATE) &&
!isImpersonating;
useHasPermissionFlag(PermissionFlagType.IMPERSONATE) && !isImpersonating;
const {
roles,
@@ -3,7 +3,7 @@ import { SettingsPath } from 'twenty-shared/types';
import { getSettingsPath } from 'twenty-shared/utils';
import { IconLock, IconUserPlus, IconUsers } from 'twenty-ui/display';
import { useHasPermissionFlagGrant } from '@/settings/roles/hooks/useHasPermissionFlagGrant';
import { useHasPermissionFlag } from '@/settings/roles/hooks/useHasPermissionFlag';
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
import { TabList } from '@/ui/layout/tab-list/components/TabList';
@@ -23,9 +23,7 @@ const MEMBERS_TAB_ROLES_ID = 'roles';
export const SettingsWorkspaceMembers = () => {
const { t } = useLingui();
const hasRolesPermission = useHasPermissionFlagGrant(
PermissionFlagType.ROLES,
);
const hasRolesPermission = useHasPermissionFlag(PermissionFlagType.ROLES);
const activeTabId = useAtomComponentStateValue(
activeTabIdComponentState,
@@ -743,7 +743,7 @@ export const mockedMinimalMetadata: MinimalMetadata =
"hash": "b022456a-bd5b-4314-9fb5-0111c80a8649"
},
{
"collectionName": "permissionFlagGrant",
"collectionName": "permissionFlag",
"hash": "2de6c5b6-3b5c-4f61-8426-92c3d4c5daac"
},
{
@@ -23,7 +23,7 @@ export const mockedRoles: Role[] =
"canBeAssignedToUsers": true,
"canBeAssignedToAgents": false,
"canBeAssignedToApiKeys": true,
"permissionFlagGrants": [],
"permissionFlags": [],
"objectPermissions": [],
"fieldPermissions": [],
"rowLevelPermissionPredicates": [],
@@ -68,7 +68,7 @@ export const mockedRoles: Role[] =
"canBeAssignedToUsers": true,
"canBeAssignedToAgents": false,
"canBeAssignedToApiKeys": false,
"permissionFlagGrants": [],
"permissionFlags": [],
"objectPermissions": [],
"fieldPermissions": [],
"rowLevelPermissionPredicates": [],
@@ -105,7 +105,7 @@ export const mockedRoles: Role[] =
"canBeAssignedToUsers": true,
"canBeAssignedToAgents": true,
"canBeAssignedToApiKeys": true,
"permissionFlagGrants": [],
"permissionFlags": [],
"objectPermissions": [
{
"__typename": "ObjectPermission",
@@ -184,7 +184,7 @@ export const mockedRoles: Role[] =
"canBeAssignedToUsers": true,
"canBeAssignedToAgents": false,
"canBeAssignedToApiKeys": false,
"permissionFlagGrants": [],
"permissionFlags": [],
"objectPermissions": [],
"fieldPermissions": [],
"rowLevelPermissionPredicates": [],
@@ -199,7 +199,7 @@ export const mockedUserData: MockedUser = {
workspaceMember: mockedWorkspaceMemberData,
currentWorkspace: mockCurrentWorkspace,
currentUserWorkspace: {
permissionFlagGrants: [
permissionFlags: [
PermissionFlagType.WORKSPACE_MEMBERS,
PermissionFlagType.CONNECTED_ACCOUNTS,
],
@@ -269,7 +269,7 @@ export const mockedOnboardingUserData = (
workspaceMembers: [],
currentWorkspace: mockCurrentWorkspace,
currentUserWorkspace: {
permissionFlagGrants: [PermissionFlagType.WORKSPACE_MEMBERS],
permissionFlags: [PermissionFlagType.WORKSPACE_MEMBERS],
objectPermissions: getTestEnrichedObjectMetadataItemsMock().map(
(item) => ({
objectMetadataId: item.id,
@@ -330,7 +330,7 @@ export const EXPECTED_MANIFEST: Manifest = {
canBeAssignedToApiKeys: false,
fieldPermissions: [],
objectPermissions: [],
permissionFlagGrants: [],
permissionFlags: [],
},
],
};
@@ -1385,7 +1385,7 @@ export const EXPECTED_MANIFEST: Manifest = {
universalIdentifier: 'c0c1c2c3-c4c5-4000-8000-000000000001',
fieldPermissions: [],
objectPermissions: [],
permissionFlagGrants: [],
permissionFlags: [],
},
{
canBeAssignedToAgents: false,
@@ -1417,7 +1417,7 @@ export const EXPECTED_MANIFEST: Manifest = {
objectUniversalIdentifier: '54b589ca-eeed-4950-a176-358418b85c05',
},
],
permissionFlagGrants: [
permissionFlags: [
{
universalIdentifier: '01d7865a-7700-5d49-b2aa-62623c2cbac7',
flag: PermissionFlagType.APPLICATIONS,
@@ -36,7 +36,7 @@ const buildMockCommandMenuContextApi = (
},
selectedRecords: [],
featureFlags: {},
permissionFlagGrants: {},
permissionFlags: {},
targetObjectReadPermissions: {},
targetObjectWritePermissions: {},
objectMetadataItem: {},
@@ -13,7 +13,7 @@ exports[`stub-twenty-sdk-define plugin > matches the recorded export partition 1
"ObjectRecordGroupByDateGranularity",
"OnDeleteAction",
"PageLayoutTabLayoutMode",
"PermissionFlagGrant",
"PermissionFlag",
"RelationType",
"STANDARD_OBJECT",
"STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS",
@@ -28,13 +28,13 @@ export const fromRoleConfigToRoleManifest = (
),
}),
),
permissionFlagGrants: (roleConfig.permissionFlagGrants ?? []).map(
(permissionFlagGrant) => ({
permissionFlags: (roleConfig.permissionFlags ?? []).map(
(permissionFlag) => ({
universalIdentifier: uuidv5(
`${roleConfig.universalIdentifier}:${permissionFlagGrant}`,
`${roleConfig.universalIdentifier}:${permissionFlag}`,
ROLE_UNIVERSAL_IDENTIFIER_NAMESPACE,
),
flag: permissionFlagGrant,
flag: permissionFlag,
}),
),
};
+1 -1
View File
@@ -86,7 +86,7 @@ export type {
export { defineApplicationRole } from '@/sdk/define/roles/define-application-role';
export { defineRole } from '@/sdk/define/roles/define-role';
export { PermissionFlagGrant } from '@/sdk/define/roles/permission-flag-type';
export { PermissionFlag } from '@/sdk/define/roles/permission-flag-type';
export { defineSkill } from '@/sdk/define/skills/define-skill';
@@ -32,16 +32,16 @@ describe('defineApplicationRole', () => {
expect(result.config?.canReadAllObjectRecords).toBe(true);
});
it('should accept permissionFlagGrants', () => {
it('should accept permissionFlags', () => {
const config = {
...validConfig,
permissionFlagGrants: ['UPLOAD_FILE'],
permissionFlags: ['UPLOAD_FILE'],
};
const result = defineApplicationRole(config as any);
expect(result.success).toBe(true);
expect(result.config?.permissionFlagGrants).toHaveLength(1);
expect(result.config?.permissionFlags).toHaveLength(1);
});
it('should return error when universalIdentifier is missing', () => {
@@ -32,16 +32,16 @@ describe('defineRole', () => {
expect(result.config?.canReadAllObjectRecords).toBe(true);
});
it('should accept permissionFlagGrants', () => {
it('should accept permissionFlags', () => {
const config = {
...validConfig,
permissionFlagGrants: ['UPLOAD_FILE', 'DOWNLOAD_FILE'],
permissionFlags: ['UPLOAD_FILE', 'DOWNLOAD_FILE'],
};
const result = defineRole(config as any);
expect(result.success).toBe(true);
expect(result.config?.permissionFlagGrants).toHaveLength(2);
expect(result.config?.permissionFlags).toHaveLength(2);
});
it('should return error when universalIdentifier is missing', () => {
@@ -1 +1 @@
export { PermissionFlagType as PermissionFlagGrant } from 'twenty-shared/constants';
export { PermissionFlagType as PermissionFlag } from 'twenty-shared/constants';
@@ -7,9 +7,9 @@ import { type PermissionFlagType } from 'twenty-shared/constants';
export type RoleConfig = Omit<
RoleManifest,
'objectPermissions' | 'fieldPermissions' | 'permissionFlagGrants'
'objectPermissions' | 'fieldPermissions' | 'permissionFlags'
> & {
objectPermissions?: Omit<ObjectPermissionManifest, 'universalIdentifier'>[];
fieldPermissions?: Omit<FieldPermissionManifest, 'universalIdentifier'>[];
permissionFlagGrants?: PermissionFlagType[];
permissionFlags?: PermissionFlagType[];
};
@@ -33,7 +33,6 @@ import { ObjectPermissionEntity } from 'src/engine/metadata-modules/object-permi
import { PageLayoutTabEntity } from 'src/engine/metadata-modules/page-layout-tab/entities/page-layout-tab.entity';
import { PageLayoutWidgetEntity } from 'src/engine/metadata-modules/page-layout-widget/entities/page-layout-widget.entity';
import { PageLayoutEntity } from 'src/engine/metadata-modules/page-layout/entities/page-layout.entity';
import { PermissionFlagGrantEntity } from 'src/engine/metadata-modules/permission-flag-grant/permission-flag-grant.entity';
import { PermissionFlagEntity } from 'src/engine/metadata-modules/permission-flag/permission-flag.entity';
import { RoleTargetEntity } from 'src/engine/metadata-modules/role-target/role-target.entity';
import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity';
@@ -68,7 +67,7 @@ const WORKSPACE_RELATED_ENTITIES: EntityTarget<ObjectLiteral>[] = [
ViewFilterGroupEntity,
FieldPermissionEntity,
ObjectPermissionEntity,
PermissionFlagGrantEntity,
PermissionFlagEntity,
RoleTargetEntity,
SearchFieldMetadataEntity,
RowLevelPermissionPredicateEntity,
@@ -83,7 +82,6 @@ const WORKSPACE_RELATED_ENTITIES: EntityTarget<ObjectLiteral>[] = [
// Level 2: Children that depend on core entities
FieldMetadataEntity,
PageLayoutEntity,
PermissionFlagEntity,
SkillEntity,
LogicFunctionEntity,
@@ -2,14 +2,14 @@ import { InjectRepository } from '@nestjs/typeorm';
import { isNonEmptyString } from '@sniptt/guards';
import { Command } from 'nest-commander';
import { FeatureFlagKey } from 'twenty-shared/types';
import { type FeatureFlagKey } from 'twenty-shared/types';
import { Repository } from 'typeorm';
import { ActiveOrSuspendedWorkspaceCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspace.command-runner';
import { type RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspace.command-runner';
import { WorkspaceIteratorService } from 'src/database/commands/command-runners/workspace-iterator.service';
import { RegisteredWorkspaceCommand } from 'src/engine/core-modules/upgrade/decorators/registered-workspace-command.decorator';
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
import { RegisteredWorkspaceCommand } from 'src/engine/core-modules/upgrade/decorators/registered-workspace-command.decorator';
import { UserWorkspaceEntity } from 'src/engine/core-modules/user-workspace/user-workspace.entity';
import { CalendarChannelEntity } from 'src/engine/metadata-modules/calendar-channel/entities/calendar-channel.entity';
import { ConnectedAccountEntity } from 'src/engine/metadata-modules/connected-account/entities/connected-account.entity';
@@ -50,7 +50,7 @@ export class MigrateMessagingInfrastructureToMetadataCommand extends ActiveOrSus
options,
}: RunOnWorkspaceArgs): Promise<void> {
const isMigrated = await this.featureFlagService.isFeatureEnabled(
FeatureFlagKey.IS_CONNECTED_ACCOUNT_MIGRATED,
'IS_CONNECTED_ACCOUNT_MIGRATED' as FeatureFlagKey,
workspaceId,
);
@@ -1,92 +0,0 @@
import { QueryRunner } from 'typeorm';
import { RegisteredInstanceCommand } from 'src/engine/core-modules/upgrade/decorators/registered-instance-command.decorator';
import { FastInstanceCommand } from 'src/engine/core-modules/upgrade/interfaces/fast-instance-command.interface';
@RegisteredInstanceCommand('2.5.0', 1778235340020)
export class RenamePermissionFlagToPermissionFlagGrantFastInstanceCommand
implements FastInstanceCommand
{
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "core"."permissionFlag" RENAME TO "permissionFlagGrant"`,
);
await queryRunner.query(
`ALTER TABLE "core"."permissionFlagGrant" RENAME CONSTRAINT "IDX_PERMISSION_FLAG_FLAG_ROLE_ID_UNIQUE" TO "IDX_PERMISSION_FLAG_GRANT_FLAG_ROLE_ID_UNIQUE"`,
);
await queryRunner.query(
`ALTER INDEX "core"."IDX_PERMISSION_FLAG_ROLE_ID" RENAME TO "IDX_PERMISSION_FLAG_GRANT_ROLE_ID"`,
);
// Re-hash inherited constraints/indexes so TypeORM's schema diff matches
// the renamed table. Original names were derived from "permissionFlag"
// and stay free for the new catalog table created by the next migration.
await queryRunner.query(
`ALTER TABLE "core"."permissionFlagGrant" DROP CONSTRAINT "FK_13f8ca9c517976733a1ce4c10eb"`,
);
await queryRunner.query(
`ALTER TABLE "core"."permissionFlagGrant" DROP CONSTRAINT "FK_835bc9f7ef959debfc5cd268049"`,
);
await queryRunner.query(
`ALTER TABLE "core"."permissionFlagGrant" DROP CONSTRAINT "FK_b26a9d39a88d0e72373c677c6c5"`,
);
await queryRunner.query(
`DROP INDEX "core"."IDX_da8ffd3c24b4a819430a861067"`,
);
await queryRunner.query(
`CREATE UNIQUE INDEX "IDX_49d4aa416a11933e35263390ad" ON "core"."permissionFlagGrant" ("workspaceId", "universalIdentifier")`,
);
await queryRunner.query(
`ALTER TABLE "core"."permissionFlagGrant" ADD CONSTRAINT "FK_272c63f634c6b9364c8ab0e94c9" FOREIGN KEY ("workspaceId") REFERENCES "core"."workspace"("id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "core"."permissionFlagGrant" ADD CONSTRAINT "FK_6090c1bb1c94b4e7260acb4d435" FOREIGN KEY ("applicationId") REFERENCES "core"."application"("id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "core"."permissionFlagGrant" ADD CONSTRAINT "FK_d19956ecbc979cf2e67df6fbd50" FOREIGN KEY ("roleId") REFERENCES "core"."role"("id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "core"."permissionFlagGrant" DROP CONSTRAINT "FK_d19956ecbc979cf2e67df6fbd50"`,
);
await queryRunner.query(
`ALTER TABLE "core"."permissionFlagGrant" DROP CONSTRAINT "FK_6090c1bb1c94b4e7260acb4d435"`,
);
await queryRunner.query(
`ALTER TABLE "core"."permissionFlagGrant" DROP CONSTRAINT "FK_272c63f634c6b9364c8ab0e94c9"`,
);
await queryRunner.query(
`DROP INDEX "core"."IDX_49d4aa416a11933e35263390ad"`,
);
await queryRunner.query(
`CREATE UNIQUE INDEX "IDX_da8ffd3c24b4a819430a861067" ON "core"."permissionFlagGrant" ("workspaceId", "universalIdentifier")`,
);
await queryRunner.query(
`ALTER TABLE "core"."permissionFlagGrant" ADD CONSTRAINT "FK_b26a9d39a88d0e72373c677c6c5" FOREIGN KEY ("applicationId") REFERENCES "core"."application"("id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "core"."permissionFlagGrant" ADD CONSTRAINT "FK_835bc9f7ef959debfc5cd268049" FOREIGN KEY ("workspaceId") REFERENCES "core"."workspace"("id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "core"."permissionFlagGrant" ADD CONSTRAINT "FK_13f8ca9c517976733a1ce4c10eb" FOREIGN KEY ("roleId") REFERENCES "core"."role"("id") ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER INDEX "core"."IDX_PERMISSION_FLAG_GRANT_ROLE_ID" RENAME TO "IDX_PERMISSION_FLAG_ROLE_ID"`,
);
await queryRunner.query(
`ALTER TABLE "core"."permissionFlagGrant" RENAME CONSTRAINT "IDX_PERMISSION_FLAG_GRANT_FLAG_ROLE_ID_UNIQUE" TO "IDX_PERMISSION_FLAG_FLAG_ROLE_ID_UNIQUE"`,
);
await queryRunner.query(
`ALTER TABLE "core"."permissionFlagGrant" RENAME TO "permissionFlag"`,
);
}
}
@@ -1,73 +0,0 @@
import { QueryRunner } from 'typeorm';
import { RegisteredInstanceCommand } from 'src/engine/core-modules/upgrade/decorators/registered-instance-command.decorator';
import { FastInstanceCommand } from 'src/engine/core-modules/upgrade/interfaces/fast-instance-command.interface';
@RegisteredInstanceCommand('2.5.0', 1778235340021)
export class PermissionFlagSyncableEntityFastInstanceCommand
implements FastInstanceCommand
{
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`CREATE TABLE "core"."permissionFlag" (
"id" uuid NOT NULL DEFAULT uuid_generate_v4(),
"workspaceId" uuid NOT NULL,
"applicationId" uuid NOT NULL,
"universalIdentifier" uuid NOT NULL,
"key" varchar NOT NULL,
"label" varchar NOT NULL,
"description" text,
"iconKey" varchar,
"permissionType" varchar NOT NULL,
"isRelevantForAgents" boolean NOT NULL DEFAULT false,
"isRelevantForUsers" boolean NOT NULL DEFAULT false,
"isRelevantForApiKeys" boolean NOT NULL DEFAULT false,
"isCustom" boolean NOT NULL DEFAULT false,
"createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
"updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
CONSTRAINT "IDX_PERMISSION_FLAG_KEY_WORKSPACE_ID_UNIQUE" UNIQUE ("key", "workspaceId"),
CONSTRAINT "PK_permissionFlag_id" PRIMARY KEY ("id")
)`,
);
await queryRunner.query(
`CREATE INDEX "IDX_PERMISSION_FLAG_APPLICATION_ID" ON "core"."permissionFlag" ("applicationId")`,
);
// Reuses canonical hash names freed by the rename migration so TypeORM's
// schema diff matches without further intervention.
await queryRunner.query(
`CREATE UNIQUE INDEX "IDX_da8ffd3c24b4a819430a861067" ON "core"."permissionFlag" ("workspaceId", "universalIdentifier")`,
);
await queryRunner.query(
`ALTER TABLE "core"."permissionFlag"
ADD CONSTRAINT "FK_835bc9f7ef959debfc5cd268049"
FOREIGN KEY ("workspaceId") REFERENCES "core"."workspace"("id")
ON DELETE CASCADE ON UPDATE NO ACTION`,
);
await queryRunner.query(
`ALTER TABLE "core"."permissionFlag"
ADD CONSTRAINT "FK_b26a9d39a88d0e72373c677c6c5"
FOREIGN KEY ("applicationId") REFERENCES "core"."application"("id")
ON DELETE CASCADE ON UPDATE NO ACTION`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "core"."permissionFlag" DROP CONSTRAINT IF EXISTS "FK_b26a9d39a88d0e72373c677c6c5"`,
);
await queryRunner.query(
`ALTER TABLE "core"."permissionFlag" DROP CONSTRAINT IF EXISTS "FK_835bc9f7ef959debfc5cd268049"`,
);
await queryRunner.query(
`DROP INDEX IF EXISTS "core"."IDX_da8ffd3c24b4a819430a861067"`,
);
await queryRunner.query(
`DROP INDEX IF EXISTS "core"."IDX_PERMISSION_FLAG_APPLICATION_ID"`,
);
await queryRunner.query(`DROP TABLE IF EXISTS "core"."permissionFlag"`);
}
}
@@ -29,8 +29,6 @@ import { AddToolAndWorkflowActionTriggerSettingsFastInstanceCommand } from 'src/
import { BackfillApplicationVariableUniversalIdentifierSlowInstanceCommand } from 'src/database/commands/upgrade-version-command/2-3/2-3-instance-command-slow-1777966965588-backfill-application-variable-universal-identifier';
import { MigrateToolTriggerSettingsSlowInstanceCommand } from 'src/database/commands/upgrade-version-command/2-3/2-3-instance-command-slow-1797000002000-migrate-tool-trigger-settings';
import { AddMetadataToBillingPriceFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-4/2-4-instance-command-fast-1777100000000-add-metadata-to-billing-price';
import { RenamePermissionFlagToPermissionFlagGrantFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-5/2-5-instance-command-fast-1778235340020-rename-permission-flag-to-permission-flag-grant';
import { PermissionFlagSyncableEntityFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-5/2-5-instance-command-fast-1778235340021-permission-flag-syncable-entity';
import { AddEmailGroupChannelTypeFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-4/2-4-instance-command-fast-1778256809018-add-email-group-channel-type';
import { AddApplicationIdToPublicDomainFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-4/2-4-instance-command-fast-1798000003000-add-application-id-to-public-domain';
import { AddIsInternalMessagesImportEnabledFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-5/2-5-instance-command-fast-1778525104406-add-is-internal-messages-import-enabled';
@@ -66,8 +64,6 @@ export const INSTANCE_COMMANDS = [
RemoveUserDefaultAvatarUrlFastInstanceCommand,
TransformApplicationVariableToSyncableEntityFastInstanceCommand,
BackfillApplicationVariableUniversalIdentifierSlowInstanceCommand,
RenamePermissionFlagToPermissionFlagGrantFastInstanceCommand,
PermissionFlagSyncableEntityFastInstanceCommand,
AddEmailGroupChannelTypeFastInstanceCommand,
AddApplicationIdToPublicDomainFastInstanceCommand,
AddIsInternalMessagesImportEnabledFastInstanceCommand,
@@ -497,7 +497,11 @@ export class ApplicationInstallService {
file: content,
filename: relativePath,
});
const sanitizedContent = sanitizeFile({ file: content, ext, mimeType });
const sanitizedContent = await sanitizeFile({
file: content,
ext,
mimeType,
});
await this.fileStorageService.writeFile({
sourceFile: sanitizedContent,
@@ -1,23 +0,0 @@
import { type UniversalFlatPermissionFlagGrant } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-permission-flag-grant.type';
import { PermissionFlagGrantManifest } from 'twenty-shared/application';
export const fromPermissionFlagGrantToUniversalFlatPermissionFlagGrant = ({
permissionFlagGrant,
roleUniversalIdentifier,
applicationUniversalIdentifier,
now,
}: {
permissionFlagGrant: PermissionFlagGrantManifest;
roleUniversalIdentifier: string;
applicationUniversalIdentifier: string;
now: string;
}): UniversalFlatPermissionFlagGrant => {
return {
universalIdentifier: permissionFlagGrant.universalIdentifier,
applicationUniversalIdentifier,
roleUniversalIdentifier,
flag: permissionFlagGrant.flag,
createdAt: now,
updatedAt: now,
};
};

Some files were not shown because too many files have changed in this diff Show More