diff --git a/packages/twenty-front/src/generated-metadata/graphql.ts b/packages/twenty-front/src/generated-metadata/graphql.ts index e51eff303..0ab76b03c 100644 --- a/packages/twenty-front/src/generated-metadata/graphql.ts +++ b/packages/twenty-front/src/generated-metadata/graphql.ts @@ -1888,6 +1888,8 @@ export enum PermissionFlagType { ADMIN_PANEL = 'ADMIN_PANEL', API_KEYS_AND_WEBHOOKS = 'API_KEYS_AND_WEBHOOKS', DATA_MODEL = 'DATA_MODEL', + EXPORT_CSV = 'EXPORT_CSV', + IMPORT_CSV = 'IMPORT_CSV', ROLES = 'ROLES', SECURITY = 'SECURITY', SEND_EMAIL_TOOL = 'SEND_EMAIL_TOOL', @@ -2836,7 +2838,7 @@ export type UserWorkspace = { objectPermissions?: Maybe>; /** @deprecated Use objectPermissions instead */ objectRecordsPermissions?: Maybe>; - settingsPermissions?: Maybe>; + permissionFlags?: Maybe>; twoFactorAuthenticationMethodSummary?: Maybe>; updatedAt: Scalars['DateTime']; user: User; @@ -3839,7 +3841,7 @@ export type VerifyTwoFactorAuthenticationMethodForAuthenticatedUserMutationVaria export type VerifyTwoFactorAuthenticationMethodForAuthenticatedUserMutation = { __typename?: 'Mutation', verifyTwoFactorAuthenticationMethodForAuthenticatedUser: { __typename?: 'VerifyTwoFactorAuthenticationMethodOutput', success: boolean } }; -export type UserQueryFragmentFragment = { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canAccessFullAdminPanel: boolean, canImpersonate: boolean, supportUserHash?: string | null, onboardingStatus?: OnboardingStatus | null, userVars?: any | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, userEmail: string, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, workspaceMembers?: Array<{ __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, userEmail: string, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } }> | null, deletedWorkspaceMembers?: Array<{ __typename?: 'DeletedWorkspaceMember', id: any, avatarUrl?: string | null, userEmail: string, name: { __typename?: 'FullName', firstName: string, lastName: string } }> | null, currentUserWorkspace?: { __typename?: 'UserWorkspace', settingsPermissions?: Array | null, objectRecordsPermissions?: Array | null, objectPermissions?: Array<{ __typename?: 'ObjectPermission', objectMetadataId: string, canReadObjectRecords?: boolean | null, canUpdateObjectRecords?: boolean | null, canSoftDeleteObjectRecords?: boolean | null, canDestroyObjectRecords?: boolean | null }> | null, twoFactorAuthenticationMethodSummary?: Array<{ __typename?: 'TwoFactorAuthenticationMethodDTO', twoFactorAuthenticationMethodId: any, status: string, strategy: string }> | null } | null, currentWorkspace?: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, inviteHash?: string | null, allowImpersonation: boolean, activationStatus: WorkspaceActivationStatus, isPublicInviteLinkEnabled: boolean, isGoogleAuthEnabled: boolean, isMicrosoftAuthEnabled: boolean, isPasswordAuthEnabled: boolean, subdomain: string, hasValidEnterpriseKey: boolean, customDomain?: string | null, isCustomDomainEnabled: boolean, metadataVersion: number, workspaceMembersCount?: number | null, isTwoFactorAuthenticationEnforced: boolean, workspaceUrls: { __typename?: 'WorkspaceUrls', subdomainUrl: string, customUrl?: string | null }, featureFlags?: Array<{ __typename?: 'FeatureFlagDTO', key: FeatureFlagKey, value: boolean }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, interval?: SubscriptionInterval | null, metadata: any, billingSubscriptionItems?: Array<{ __typename?: 'BillingSubscriptionItem', id: any, hasReachedCurrentPeriodCap: boolean, quantity?: number | null, billingProduct?: { __typename?: 'BillingProduct', name: string, description: string, metadata: { __typename?: 'BillingProductMetadata', planKey: BillingPlanKey, priceUsageBased: BillingUsageType, productKey: BillingProductKey } } | null }> | null } | null, billingSubscriptions: Array<{ __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, metadata: any }>, defaultRole?: { __typename?: 'Role', id: string, label: string, description?: string | null, icon?: string | null, canUpdateAllSettings: boolean, canAccessAllTools: boolean, isEditable: boolean, canReadAllObjectRecords: boolean, canUpdateAllObjectRecords: boolean, canSoftDeleteAllObjectRecords: boolean, canDestroyAllObjectRecords: boolean } | null, defaultAgent?: { __typename?: 'Agent', id: any } | null } | null, availableWorkspaces: { __typename?: 'AvailableWorkspaces', availableWorkspacesForSignIn: Array<{ __typename?: 'AvailableWorkspace', id: string, displayName?: string | null, loginToken?: string | null, inviteHash?: string | null, personalInviteToken?: string | null, logo?: string | null, workspaceUrls: { __typename?: 'WorkspaceUrls', subdomainUrl: string, customUrl?: string | null }, sso: Array<{ __typename?: 'SSOConnection', type: IdentityProviderType, id: string, issuer: string, name: string, status: SsoIdentityProviderStatus }> }>, availableWorkspacesForSignUp: Array<{ __typename?: 'AvailableWorkspace', id: string, displayName?: string | null, loginToken?: string | null, inviteHash?: string | null, personalInviteToken?: string | null, logo?: string | null, workspaceUrls: { __typename?: 'WorkspaceUrls', subdomainUrl: string, customUrl?: string | null }, sso: Array<{ __typename?: 'SSOConnection', type: IdentityProviderType, id: string, issuer: string, name: string, status: SsoIdentityProviderStatus }> }> } }; +export type UserQueryFragmentFragment = { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canAccessFullAdminPanel: boolean, canImpersonate: boolean, supportUserHash?: string | null, onboardingStatus?: OnboardingStatus | null, userVars?: any | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, userEmail: string, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, workspaceMembers?: Array<{ __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, userEmail: string, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } }> | null, deletedWorkspaceMembers?: Array<{ __typename?: 'DeletedWorkspaceMember', id: any, avatarUrl?: string | null, userEmail: string, name: { __typename?: 'FullName', firstName: string, lastName: string } }> | null, currentUserWorkspace?: { __typename?: 'UserWorkspace', permissionFlags?: Array | null, objectRecordsPermissions?: Array | null, objectPermissions?: Array<{ __typename?: 'ObjectPermission', objectMetadataId: string, canReadObjectRecords?: boolean | null, canUpdateObjectRecords?: boolean | null, canSoftDeleteObjectRecords?: boolean | null, canDestroyObjectRecords?: boolean | null }> | null, twoFactorAuthenticationMethodSummary?: Array<{ __typename?: 'TwoFactorAuthenticationMethodDTO', twoFactorAuthenticationMethodId: any, status: string, strategy: string }> | null } | null, currentWorkspace?: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, inviteHash?: string | null, allowImpersonation: boolean, activationStatus: WorkspaceActivationStatus, isPublicInviteLinkEnabled: boolean, isGoogleAuthEnabled: boolean, isMicrosoftAuthEnabled: boolean, isPasswordAuthEnabled: boolean, subdomain: string, hasValidEnterpriseKey: boolean, customDomain?: string | null, isCustomDomainEnabled: boolean, metadataVersion: number, workspaceMembersCount?: number | null, isTwoFactorAuthenticationEnforced: boolean, workspaceUrls: { __typename?: 'WorkspaceUrls', subdomainUrl: string, customUrl?: string | null }, featureFlags?: Array<{ __typename?: 'FeatureFlagDTO', key: FeatureFlagKey, value: boolean }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, interval?: SubscriptionInterval | null, metadata: any, billingSubscriptionItems?: Array<{ __typename?: 'BillingSubscriptionItem', id: any, hasReachedCurrentPeriodCap: boolean, quantity?: number | null, billingProduct?: { __typename?: 'BillingProduct', name: string, description: string, metadata: { __typename?: 'BillingProductMetadata', planKey: BillingPlanKey, priceUsageBased: BillingUsageType, productKey: BillingProductKey } } | null }> | null } | null, billingSubscriptions: Array<{ __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, metadata: any }>, defaultRole?: { __typename?: 'Role', id: string, label: string, description?: string | null, icon?: string | null, canUpdateAllSettings: boolean, canAccessAllTools: boolean, isEditable: boolean, canReadAllObjectRecords: boolean, canUpdateAllObjectRecords: boolean, canSoftDeleteAllObjectRecords: boolean, canDestroyAllObjectRecords: boolean } | null, defaultAgent?: { __typename?: 'Agent', id: any } | null } | null, availableWorkspaces: { __typename?: 'AvailableWorkspaces', availableWorkspacesForSignIn: Array<{ __typename?: 'AvailableWorkspace', id: string, displayName?: string | null, loginToken?: string | null, inviteHash?: string | null, personalInviteToken?: string | null, logo?: string | null, workspaceUrls: { __typename?: 'WorkspaceUrls', subdomainUrl: string, customUrl?: string | null }, sso: Array<{ __typename?: 'SSOConnection', type: IdentityProviderType, id: string, issuer: string, name: string, status: SsoIdentityProviderStatus }> }>, availableWorkspacesForSignUp: Array<{ __typename?: 'AvailableWorkspace', id: string, displayName?: string | null, loginToken?: string | null, inviteHash?: string | null, personalInviteToken?: string | null, logo?: string | null, workspaceUrls: { __typename?: 'WorkspaceUrls', subdomainUrl: string, customUrl?: string | null }, sso: Array<{ __typename?: 'SSOConnection', type: IdentityProviderType, id: string, issuer: string, name: string, status: SsoIdentityProviderStatus }> }> } }; export type WorkspaceUrlsFragmentFragment = { __typename?: 'WorkspaceUrls', subdomainUrl: string, customUrl?: string | null }; @@ -3858,7 +3860,7 @@ export type UploadProfilePictureMutation = { __typename?: 'Mutation', uploadProf export type GetCurrentUserQueryVariables = Exact<{ [key: string]: never; }>; -export type GetCurrentUserQuery = { __typename?: 'Query', currentUser: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canAccessFullAdminPanel: boolean, canImpersonate: boolean, supportUserHash?: string | null, onboardingStatus?: OnboardingStatus | null, userVars?: any | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, userEmail: string, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, workspaceMembers?: Array<{ __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, userEmail: string, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } }> | null, deletedWorkspaceMembers?: Array<{ __typename?: 'DeletedWorkspaceMember', id: any, avatarUrl?: string | null, userEmail: string, name: { __typename?: 'FullName', firstName: string, lastName: string } }> | null, currentUserWorkspace?: { __typename?: 'UserWorkspace', settingsPermissions?: Array | null, objectRecordsPermissions?: Array | null, objectPermissions?: Array<{ __typename?: 'ObjectPermission', objectMetadataId: string, canReadObjectRecords?: boolean | null, canUpdateObjectRecords?: boolean | null, canSoftDeleteObjectRecords?: boolean | null, canDestroyObjectRecords?: boolean | null }> | null, twoFactorAuthenticationMethodSummary?: Array<{ __typename?: 'TwoFactorAuthenticationMethodDTO', twoFactorAuthenticationMethodId: any, status: string, strategy: string }> | null } | null, currentWorkspace?: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, inviteHash?: string | null, allowImpersonation: boolean, activationStatus: WorkspaceActivationStatus, isPublicInviteLinkEnabled: boolean, isGoogleAuthEnabled: boolean, isMicrosoftAuthEnabled: boolean, isPasswordAuthEnabled: boolean, subdomain: string, hasValidEnterpriseKey: boolean, customDomain?: string | null, isCustomDomainEnabled: boolean, metadataVersion: number, workspaceMembersCount?: number | null, isTwoFactorAuthenticationEnforced: boolean, workspaceUrls: { __typename?: 'WorkspaceUrls', subdomainUrl: string, customUrl?: string | null }, featureFlags?: Array<{ __typename?: 'FeatureFlagDTO', key: FeatureFlagKey, value: boolean }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, interval?: SubscriptionInterval | null, metadata: any, billingSubscriptionItems?: Array<{ __typename?: 'BillingSubscriptionItem', id: any, hasReachedCurrentPeriodCap: boolean, quantity?: number | null, billingProduct?: { __typename?: 'BillingProduct', name: string, description: string, metadata: { __typename?: 'BillingProductMetadata', planKey: BillingPlanKey, priceUsageBased: BillingUsageType, productKey: BillingProductKey } } | null }> | null } | null, billingSubscriptions: Array<{ __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, metadata: any }>, defaultRole?: { __typename?: 'Role', id: string, label: string, description?: string | null, icon?: string | null, canUpdateAllSettings: boolean, canAccessAllTools: boolean, isEditable: boolean, canReadAllObjectRecords: boolean, canUpdateAllObjectRecords: boolean, canSoftDeleteAllObjectRecords: boolean, canDestroyAllObjectRecords: boolean } | null, defaultAgent?: { __typename?: 'Agent', id: any } | null } | null, availableWorkspaces: { __typename?: 'AvailableWorkspaces', availableWorkspacesForSignIn: Array<{ __typename?: 'AvailableWorkspace', id: string, displayName?: string | null, loginToken?: string | null, inviteHash?: string | null, personalInviteToken?: string | null, logo?: string | null, workspaceUrls: { __typename?: 'WorkspaceUrls', subdomainUrl: string, customUrl?: string | null }, sso: Array<{ __typename?: 'SSOConnection', type: IdentityProviderType, id: string, issuer: string, name: string, status: SsoIdentityProviderStatus }> }>, availableWorkspacesForSignUp: Array<{ __typename?: 'AvailableWorkspace', id: string, displayName?: string | null, loginToken?: string | null, inviteHash?: string | null, personalInviteToken?: string | null, logo?: string | null, workspaceUrls: { __typename?: 'WorkspaceUrls', subdomainUrl: string, customUrl?: string | null }, sso: Array<{ __typename?: 'SSOConnection', type: IdentityProviderType, id: string, issuer: string, name: string, status: SsoIdentityProviderStatus }> }> } } }; +export type GetCurrentUserQuery = { __typename?: 'Query', currentUser: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canAccessFullAdminPanel: boolean, canImpersonate: boolean, supportUserHash?: string | null, onboardingStatus?: OnboardingStatus | null, userVars?: any | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, userEmail: string, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, workspaceMembers?: Array<{ __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, userEmail: string, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } }> | null, deletedWorkspaceMembers?: Array<{ __typename?: 'DeletedWorkspaceMember', id: any, avatarUrl?: string | null, userEmail: string, name: { __typename?: 'FullName', firstName: string, lastName: string } }> | null, currentUserWorkspace?: { __typename?: 'UserWorkspace', permissionFlags?: Array | null, objectRecordsPermissions?: Array | null, objectPermissions?: Array<{ __typename?: 'ObjectPermission', objectMetadataId: string, canReadObjectRecords?: boolean | null, canUpdateObjectRecords?: boolean | null, canSoftDeleteObjectRecords?: boolean | null, canDestroyObjectRecords?: boolean | null }> | null, twoFactorAuthenticationMethodSummary?: Array<{ __typename?: 'TwoFactorAuthenticationMethodDTO', twoFactorAuthenticationMethodId: any, status: string, strategy: string }> | null } | null, currentWorkspace?: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, inviteHash?: string | null, allowImpersonation: boolean, activationStatus: WorkspaceActivationStatus, isPublicInviteLinkEnabled: boolean, isGoogleAuthEnabled: boolean, isMicrosoftAuthEnabled: boolean, isPasswordAuthEnabled: boolean, subdomain: string, hasValidEnterpriseKey: boolean, customDomain?: string | null, isCustomDomainEnabled: boolean, metadataVersion: number, workspaceMembersCount?: number | null, isTwoFactorAuthenticationEnforced: boolean, workspaceUrls: { __typename?: 'WorkspaceUrls', subdomainUrl: string, customUrl?: string | null }, featureFlags?: Array<{ __typename?: 'FeatureFlagDTO', key: FeatureFlagKey, value: boolean }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, interval?: SubscriptionInterval | null, metadata: any, billingSubscriptionItems?: Array<{ __typename?: 'BillingSubscriptionItem', id: any, hasReachedCurrentPeriodCap: boolean, quantity?: number | null, billingProduct?: { __typename?: 'BillingProduct', name: string, description: string, metadata: { __typename?: 'BillingProductMetadata', planKey: BillingPlanKey, priceUsageBased: BillingUsageType, productKey: BillingProductKey } } | null }> | null } | null, billingSubscriptions: Array<{ __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, metadata: any }>, defaultRole?: { __typename?: 'Role', id: string, label: string, description?: string | null, icon?: string | null, canUpdateAllSettings: boolean, canAccessAllTools: boolean, isEditable: boolean, canReadAllObjectRecords: boolean, canUpdateAllObjectRecords: boolean, canSoftDeleteAllObjectRecords: boolean, canDestroyAllObjectRecords: boolean } | null, defaultAgent?: { __typename?: 'Agent', id: any } | null } | null, availableWorkspaces: { __typename?: 'AvailableWorkspaces', availableWorkspacesForSignIn: Array<{ __typename?: 'AvailableWorkspace', id: string, displayName?: string | null, loginToken?: string | null, inviteHash?: string | null, personalInviteToken?: string | null, logo?: string | null, workspaceUrls: { __typename?: 'WorkspaceUrls', subdomainUrl: string, customUrl?: string | null }, sso: Array<{ __typename?: 'SSOConnection', type: IdentityProviderType, id: string, issuer: string, name: string, status: SsoIdentityProviderStatus }> }>, availableWorkspacesForSignUp: Array<{ __typename?: 'AvailableWorkspace', id: string, displayName?: string | null, loginToken?: string | null, inviteHash?: string | null, personalInviteToken?: string | null, logo?: string | null, workspaceUrls: { __typename?: 'WorkspaceUrls', subdomainUrl: string, customUrl?: string | null }, sso: Array<{ __typename?: 'SSOConnection', type: IdentityProviderType, id: string, issuer: string, name: string, status: SsoIdentityProviderStatus }> }> } } }; export type ActivateWorkflowVersionMutationVariables = Exact<{ workflowVersionId: Scalars['String']; @@ -4196,7 +4198,7 @@ export const UserQueryFragmentFragmentDoc = gql` ...DeletedWorkspaceMemberQueryFragment } currentUserWorkspace { - settingsPermissions + permissionFlags objectRecordsPermissions objectPermissions { ...ObjectPermissionFragment diff --git a/packages/twenty-front/src/generated/graphql.ts b/packages/twenty-front/src/generated/graphql.ts index 639c1f725..3a6ae972c 100644 --- a/packages/twenty-front/src/generated/graphql.ts +++ b/packages/twenty-front/src/generated/graphql.ts @@ -1799,6 +1799,8 @@ export enum PermissionFlagType { ADMIN_PANEL = 'ADMIN_PANEL', API_KEYS_AND_WEBHOOKS = 'API_KEYS_AND_WEBHOOKS', DATA_MODEL = 'DATA_MODEL', + EXPORT_CSV = 'EXPORT_CSV', + IMPORT_CSV = 'IMPORT_CSV', ROLES = 'ROLES', SECURITY = 'SECURITY', SEND_EMAIL_TOOL = 'SEND_EMAIL_TOOL', @@ -2664,7 +2666,7 @@ export type UserWorkspace = { objectPermissions?: Maybe>; /** @deprecated Use objectPermissions instead */ objectRecordsPermissions?: Maybe>; - settingsPermissions?: Maybe>; + permissionFlags?: Maybe>; twoFactorAuthenticationMethodSummary?: Maybe>; updatedAt: Scalars['DateTime']; user: User; diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/DefaultRecordActionsConfig.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/DefaultRecordActionsConfig.tsx index 47da913f3..edea06dd2 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/DefaultRecordActionsConfig.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/DefaultRecordActionsConfig.tsx @@ -53,6 +53,7 @@ import { IconTrashX, IconUser, } from 'twenty-ui/display'; +import { PermissionFlagType } from '~/generated-metadata/graphql'; export const DEFAULT_RECORD_ACTIONS_CONFIG: Record< | NoSelectionRecordActionKeys @@ -169,6 +170,7 @@ export const DEFAULT_RECORD_ACTIONS_CONFIG: Record< isDefined(selectedRecord) && !selectedRecord.isRemote, availableOn: [ActionViewType.SHOW_PAGE], component: , + requiredPermissionFlag: PermissionFlagType.EXPORT_CSV, }, [MultipleRecordsActionKeys.EXPORT]: { type: ActionType.Standard, @@ -183,6 +185,7 @@ export const DEFAULT_RECORD_ACTIONS_CONFIG: Record< shouldBeRegistered: () => true, availableOn: [ActionViewType.INDEX_PAGE_BULK_SELECTION], component: , + requiredPermissionFlag: PermissionFlagType.EXPORT_CSV, }, [NoSelectionRecordActionKeys.IMPORT_RECORDS]: { type: ActionType.Standard, @@ -198,6 +201,7 @@ export const DEFAULT_RECORD_ACTIONS_CONFIG: Record< !isSoftDeleteFilterActive, availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION], component: , + requiredPermissionFlag: PermissionFlagType.IMPORT_CSV, }, [NoSelectionRecordActionKeys.EXPORT_VIEW]: { type: ActionType.Standard, @@ -212,6 +216,7 @@ export const DEFAULT_RECORD_ACTIONS_CONFIG: Record< shouldBeRegistered: () => true, availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION], component: , + requiredPermissionFlag: PermissionFlagType.EXPORT_CSV, }, [SingleRecordActionKeys.DELETE]: { type: ActionType.Standard, diff --git a/packages/twenty-front/src/modules/action-menu/actions/types/ActionConfig.ts b/packages/twenty-front/src/modules/action-menu/actions/types/ActionConfig.ts index 60c38ec97..1a03b6f48 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/types/ActionConfig.ts +++ b/packages/twenty-front/src/modules/action-menu/actions/types/ActionConfig.ts @@ -5,6 +5,7 @@ import { ShouldBeRegisteredFunctionParams } from '@/action-menu/actions/types/Sh import { MessageDescriptor } from '@lingui/core'; import { IconComponent } from 'twenty-ui/display'; import { MenuItemAccent } from 'twenty-ui/navigation'; +import { PermissionFlagType } from '~/generated-metadata/graphql'; export type ActionConfig = { type: ActionType; @@ -21,4 +22,5 @@ export type ActionConfig = { shouldBeRegistered: (params: ShouldBeRegisteredFunctionParams) => boolean; component: React.ReactNode; hotKeys?: string[]; + requiredPermissionFlag?: PermissionFlagType; }; diff --git a/packages/twenty-front/src/modules/action-menu/hooks/useRegisteredActions.ts b/packages/twenty-front/src/modules/action-menu/hooks/useRegisteredActions.ts index 73cad9319..5391a229f 100644 --- a/packages/twenty-front/src/modules/action-menu/hooks/useRegisteredActions.ts +++ b/packages/twenty-front/src/modules/action-menu/hooks/useRegisteredActions.ts @@ -6,6 +6,7 @@ import { getActionConfig } from '@/action-menu/actions/utils/getActionConfig'; import { getActionViewType } from '@/action-menu/actions/utils/getActionViewType'; import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState'; import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; +import { usePermissionFlagMap } from '@/settings/roles/hooks/usePermissionFlagMap'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { isDefined } from 'twenty-shared/utils'; import { useIcons } from 'twenty-ui/display'; @@ -48,6 +49,8 @@ export const useRegisteredActions = ( ...recordAgnosticActionConfig, }; + const permissionMap = usePermissionFlagMap(); + const actionsToRegister = isDefined(viewType) ? Object.values(actionsConfig).filter( (action) => @@ -57,7 +60,15 @@ export const useRegisteredActions = ( : []; const actions = actionsToRegister - .filter((action) => action.shouldBeRegistered(shouldBeRegisteredParams)) + .filter((action) => { + if ( + isDefined(action.requiredPermissionFlag) && + !permissionMap[action.requiredPermissionFlag] + ) { + return false; + } + return action.shouldBeRegistered(shouldBeRegisteredParams); + }) .sort((a, b) => a.position - b.position); return actions; diff --git a/packages/twenty-front/src/modules/auth/states/currentUserWorkspaceState.ts b/packages/twenty-front/src/modules/auth/states/currentUserWorkspaceState.ts index a285406cf..3b426b997 100644 --- a/packages/twenty-front/src/modules/auth/states/currentUserWorkspaceState.ts +++ b/packages/twenty-front/src/modules/auth/states/currentUserWorkspaceState.ts @@ -3,7 +3,7 @@ import { UserWorkspace } from '~/generated/graphql'; export type CurrentUserWorkspace = Pick< UserWorkspace, - | 'settingsPermissions' + | 'permissionFlags' | 'objectRecordsPermissions' | 'objectPermissions' | 'twoFactorAuthenticationMethodSummary' diff --git a/packages/twenty-front/src/modules/information-banner/components/billing/InformationBannerBillingSubscriptionPaused.tsx b/packages/twenty-front/src/modules/information-banner/components/billing/InformationBannerBillingSubscriptionPaused.tsx index 521f31cc2..3a0366467 100644 --- a/packages/twenty-front/src/modules/information-banner/components/billing/InformationBannerBillingSubscriptionPaused.tsx +++ b/packages/twenty-front/src/modules/information-banner/components/billing/InformationBannerBillingSubscriptionPaused.tsx @@ -1,6 +1,6 @@ import { useRedirect } from '@/domain-manager/hooks/useRedirect'; import { InformationBanner } from '@/information-banner/components/InformationBanner'; -import { useSettingsPermissionMap } from '@/settings/roles/hooks/useSettingsPermissionMap'; +import { usePermissionFlagMap } from '@/settings/roles/hooks/usePermissionFlagMap'; import { SettingsPath } from '@/types/SettingsPath'; import { t } from '@lingui/core/macro'; import { isDefined } from 'twenty-shared/utils'; @@ -21,7 +21,7 @@ export const InformationBannerBillingSubscriptionPaused = () => { const { [PermissionFlagType.WORKSPACE]: hasPermissionToUpdateBillingDetails, - } = useSettingsPermissionMap(); + } = usePermissionFlagMap(); const openBillingPortal = () => { if (isDefined(data) && isDefined(data.billingPortalSession.url)) { diff --git a/packages/twenty-front/src/modules/information-banner/components/billing/InformationBannerEndTrialPeriod.tsx b/packages/twenty-front/src/modules/information-banner/components/billing/InformationBannerEndTrialPeriod.tsx index 07e8b421e..1c9ffa0a8 100644 --- a/packages/twenty-front/src/modules/information-banner/components/billing/InformationBannerEndTrialPeriod.tsx +++ b/packages/twenty-front/src/modules/information-banner/components/billing/InformationBannerEndTrialPeriod.tsx @@ -1,6 +1,6 @@ import { useEndSubscriptionTrialPeriod } from '@/billing/hooks/useEndSubscriptionTrialPeriod'; import { InformationBanner } from '@/information-banner/components/InformationBanner'; -import { useSettingsPermissionMap } from '@/settings/roles/hooks/useSettingsPermissionMap'; +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 } = - useSettingsPermissionMap(); + usePermissionFlagMap(); return ( { const { [PermissionFlagType.WORKSPACE]: hasPermissionToUpdateBillingDetails, - } = useSettingsPermissionMap(); + } = usePermissionFlagMap(); const openBillingPortal = () => { if (isDefined(data) && isDefined(data.billingPortalSession.url)) { diff --git a/packages/twenty-front/src/modules/information-banner/components/billing/InformationBannerNoBillingSubscription.tsx b/packages/twenty-front/src/modules/information-banner/components/billing/InformationBannerNoBillingSubscription.tsx index 8c889315d..353472624 100644 --- a/packages/twenty-front/src/modules/information-banner/components/billing/InformationBannerNoBillingSubscription.tsx +++ b/packages/twenty-front/src/modules/information-banner/components/billing/InformationBannerNoBillingSubscription.tsx @@ -1,7 +1,7 @@ import { BILLING_CHECKOUT_SESSION_DEFAULT_VALUE } from '@/billing/constants/BillingCheckoutSessionDefaultValue'; import { useHandleCheckoutSession } from '@/billing/hooks/useHandleCheckoutSession'; import { InformationBanner } from '@/information-banner/components/InformationBanner'; -import { useSettingsPermissionMap } from '@/settings/roles/hooks/useSettingsPermissionMap'; +import { usePermissionFlagMap } from '@/settings/roles/hooks/usePermissionFlagMap'; import { SettingsPath } from '@/types/SettingsPath'; import { t } from '@lingui/core/macro'; import { PermissionFlagType } from '~/generated-metadata/graphql'; @@ -16,7 +16,7 @@ export const InformationBannerNoBillingSubscription = () => { }); const { [PermissionFlagType.WORKSPACE]: hasPermissionToSubscribe } = - useSettingsPermissionMap(); + usePermissionFlagMap(); return ( { - const hasPermission = useHasSettingsPermission(settingsPermission); + const hasPermission = useHasPermissionFlag(settingsPermission); const requiredFeatureFlagEnabled = useIsFeatureEnabled( requiredFeatureFlag || null, ); diff --git a/packages/twenty-front/src/modules/settings/hooks/__tests__/useSettingsNavigationItems.test.tsx b/packages/twenty-front/src/modules/settings/hooks/__tests__/useSettingsNavigationItems.test.tsx index ff8882a04..97e01e60d 100644 --- a/packages/twenty-front/src/modules/settings/hooks/__tests__/useSettingsNavigationItems.test.tsx +++ b/packages/twenty-front/src/modules/settings/hooks/__tests__/useSettingsNavigationItems.test.tsx @@ -13,7 +13,7 @@ import { import { currentUserState } from '@/auth/states/currentUserState'; import { billingState } from '@/client-config/states/billingState'; import { labPublicFeatureFlagsState } from '@/client-config/states/labPublicFeatureFlagsState'; -import { useSettingsPermissionMap } from '@/settings/roles/hooks/useSettingsPermissionMap'; +import { usePermissionFlagMap } from '@/settings/roles/hooks/usePermissionFlagMap'; import { SnackBarComponentInstanceContextProvider } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarComponentInstanceContextProvider'; const mockCurrentUser = { @@ -53,13 +53,13 @@ const Wrapper = ({ children }: { children: ReactNode }) => ( ); -jest.mock('@/settings/roles/hooks/useSettingsPermissionMap', () => ({ - useSettingsPermissionMap: jest.fn(), +jest.mock('@/settings/roles/hooks/usePermissionFlagMap', () => ({ + usePermissionFlagMap: jest.fn(), })); describe('useSettingsNavigationItems', () => { it('should hide workspace settings when no permissions', () => { - (useSettingsPermissionMap as jest.Mock).mockImplementation(() => ({ + (usePermissionFlagMap as jest.Mock).mockImplementation(() => ({ [PermissionFlagType.WORKSPACE]: false, [PermissionFlagType.WORKSPACE_MEMBERS]: false, [PermissionFlagType.DATA_MODEL]: false, @@ -80,7 +80,7 @@ describe('useSettingsNavigationItems', () => { }); it('should show workspace settings when has permissions', () => { - (useSettingsPermissionMap as jest.Mock).mockImplementation(() => ({ + (usePermissionFlagMap as jest.Mock).mockImplementation(() => ({ [PermissionFlagType.WORKSPACE]: true, [PermissionFlagType.WORKSPACE_MEMBERS]: true, [PermissionFlagType.DATA_MODEL]: true, diff --git a/packages/twenty-front/src/modules/settings/hooks/useSettingsNavigationItems.tsx b/packages/twenty-front/src/modules/settings/hooks/useSettingsNavigationItems.tsx index c52656b66..fbe8992bc 100644 --- a/packages/twenty-front/src/modules/settings/hooks/useSettingsNavigationItems.tsx +++ b/packages/twenty-front/src/modules/settings/hooks/useSettingsNavigationItems.tsx @@ -4,7 +4,7 @@ import { useAuth } from '@/auth/hooks/useAuth'; import { currentUserState } from '@/auth/states/currentUserState'; import { billingState } from '@/client-config/states/billingState'; import { labPublicFeatureFlagsState } from '@/client-config/states/labPublicFeatureFlagsState'; -import { useSettingsPermissionMap } from '@/settings/roles/hooks/useSettingsPermissionMap'; +import { usePermissionFlagMap } from '@/settings/roles/hooks/usePermissionFlagMap'; import { NavigationDrawerItemIndentationLevel } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerItem'; import { t } from '@lingui/core/macro'; import { useRecoilValue } from 'recoil'; @@ -63,7 +63,7 @@ const useSettingsNavigationItems = (): SettingsNavigationSection[] => { false; const labPublicFeatureFlags = useRecoilValue(labPublicFeatureFlagsState); - const permissionMap = useSettingsPermissionMap(); + const permissionMap = usePermissionFlagMap(); return [ { label: t`User`, diff --git a/packages/twenty-front/src/modules/settings/roles/hooks/useHasSettingsPermission.ts b/packages/twenty-front/src/modules/settings/roles/hooks/useHasPermissionFlag.ts similarity index 83% rename from packages/twenty-front/src/modules/settings/roles/hooks/useHasSettingsPermission.ts rename to packages/twenty-front/src/modules/settings/roles/hooks/useHasPermissionFlag.ts index 75b27faba..972c49cfa 100644 --- a/packages/twenty-front/src/modules/settings/roles/hooks/useHasSettingsPermission.ts +++ b/packages/twenty-front/src/modules/settings/roles/hooks/useHasPermissionFlag.ts @@ -4,9 +4,7 @@ import { useRecoilValue } from 'recoil'; import { WorkspaceActivationStatus } from 'twenty-shared/workspace'; import { PermissionFlagType } from '~/generated/graphql'; -export const useHasSettingsPermission = ( - permissionFlag?: PermissionFlagType, -) => { +export const useHasPermissionFlag = (permissionFlag?: PermissionFlagType) => { const currentWorkspace = useRecoilValue(currentWorkspaceState); const currentUserWorkspace = useRecoilValue(currentUserWorkspaceState); @@ -22,7 +20,7 @@ export const useHasSettingsPermission = ( return true; } - const currentUserWorkspaceSetting = currentUserWorkspace?.settingsPermissions; + const currentUserWorkspaceSetting = currentUserWorkspace?.permissionFlags; if (!currentUserWorkspaceSetting) { return false; diff --git a/packages/twenty-front/src/modules/settings/roles/hooks/useSettingsPermissionMap.ts b/packages/twenty-front/src/modules/settings/roles/hooks/usePermissionFlagMap.ts similarity index 84% rename from packages/twenty-front/src/modules/settings/roles/hooks/useSettingsPermissionMap.ts rename to packages/twenty-front/src/modules/settings/roles/hooks/usePermissionFlagMap.ts index fbf0df912..387a0decb 100644 --- a/packages/twenty-front/src/modules/settings/roles/hooks/useSettingsPermissionMap.ts +++ b/packages/twenty-front/src/modules/settings/roles/hooks/usePermissionFlagMap.ts @@ -3,14 +3,11 @@ import { useRecoilValue } from 'recoil'; import { PermissionFlagType } from '~/generated/graphql'; import { buildRecordFromKeysWithSameValue } from '~/utils/array/buildRecordFromKeysWithSameValue'; -export const useSettingsPermissionMap = (): Record< - PermissionFlagType, - boolean -> => { +export const usePermissionFlagMap = (): Record => { const currentUserWorkspace = useRecoilValue(currentUserWorkspaceState); const currentUserWorkspaceSettingsPermissions = - currentUserWorkspace?.settingsPermissions; + currentUserWorkspace?.permissionFlags; const initialPermissions = buildRecordFromKeysWithSameValue( Object.values(PermissionFlagType), diff --git a/packages/twenty-front/src/modules/settings/roles/role-permissions/permission-flags/components/SettingsRolePermissionsToolSection.tsx b/packages/twenty-front/src/modules/settings/roles/role-permissions/permission-flags/components/SettingsRolePermissionsToolSection.tsx index 12e6c1d3f..fb55d6c91 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-permissions/permission-flags/components/SettingsRolePermissionsToolSection.tsx +++ b/packages/twenty-front/src/modules/settings/roles/role-permissions/permission-flags/components/SettingsRolePermissionsToolSection.tsx @@ -7,7 +7,13 @@ import styled from '@emotion/styled'; import { t } from '@lingui/core/macro'; import { useRecoilState } from 'recoil'; -import { H2Title, IconMail, IconTool } from 'twenty-ui/display'; +import { + H2Title, + IconFileExport, + IconFileImport, + IconMail, + IconTool, +} from 'twenty-ui/display'; import { AnimatedExpandableContainer, Card, Section } from 'twenty-ui/layout'; import { PermissionFlagType } from '~/generated-metadata/graphql'; @@ -45,19 +51,30 @@ export const SettingsRolePermissionsToolSection = ({ Icon: IconMail, isToolPermission: true, }, + { + key: PermissionFlagType.IMPORT_CSV, + name: t`Import CSV`, + description: t`Allow importing data from CSV files`, + Icon: IconFileImport, + isToolPermission: true, + }, + { + key: PermissionFlagType.EXPORT_CSV, + name: t`Export CSV`, + description: t`Allow exporting data to CSV files`, + Icon: IconFileExport, + isToolPermission: true, + }, ]; return (
- + { diff --git a/packages/twenty-front/src/modules/users/graphql/fragments/userQueryFragment.ts b/packages/twenty-front/src/modules/users/graphql/fragments/userQueryFragment.ts index b03ffbf62..d5af2b3bd 100644 --- a/packages/twenty-front/src/modules/users/graphql/fragments/userQueryFragment.ts +++ b/packages/twenty-front/src/modules/users/graphql/fragments/userQueryFragment.ts @@ -34,7 +34,7 @@ export const USER_QUERY_FRAGMENT = gql` ...DeletedWorkspaceMemberQueryFragment } currentUserWorkspace { - settingsPermissions + permissionFlags objectRecordsPermissions objectPermissions { ...ObjectPermissionFragment diff --git a/packages/twenty-front/src/testing/mock-data/users.ts b/packages/twenty-front/src/testing/mock-data/users.ts index d595b5e30..588a24b25 100644 --- a/packages/twenty-front/src/testing/mock-data/users.ts +++ b/packages/twenty-front/src/testing/mock-data/users.ts @@ -125,7 +125,7 @@ export const mockedUserData: MockedUser = { workspaceMember: mockedWorkspaceMemberData, currentWorkspace: mockCurrentWorkspace, currentUserWorkspace: { - settingsPermissions: [PermissionFlagType.WORKSPACE_MEMBERS], + permissionFlags: [PermissionFlagType.WORKSPACE_MEMBERS], objectPermissions: generatedMockObjectMetadataItems.map((item) => ({ objectMetadataId: item.id, canReadObjectRecords: true, diff --git a/packages/twenty-server/src/engine/core-modules/user-workspace/user-workspace.entity.ts b/packages/twenty-server/src/engine/core-modules/user-workspace/user-workspace.entity.ts index a9b0f63e0..6897503f9 100644 --- a/packages/twenty-server/src/engine/core-modules/user-workspace/user-workspace.entity.ts +++ b/packages/twenty-server/src/engine/core-modules/user-workspace/user-workspace.entity.ts @@ -97,7 +97,7 @@ export class UserWorkspace { twoFactorAuthenticationMethods: Relation; @Field(() => [PermissionFlagType], { nullable: true }) - settingsPermissions?: PermissionFlagType[]; + permissionFlags?: PermissionFlagType[]; @Field(() => [PermissionsOnAllObjectRecords], { nullable: true, diff --git a/packages/twenty-server/src/engine/metadata-modules/permissions/constants/permission-flag-type.constants.ts b/packages/twenty-server/src/engine/metadata-modules/permissions/constants/permission-flag-type.constants.ts index 128d2245e..9996bf60b 100644 --- a/packages/twenty-server/src/engine/metadata-modules/permissions/constants/permission-flag-type.constants.ts +++ b/packages/twenty-server/src/engine/metadata-modules/permissions/constants/permission-flag-type.constants.ts @@ -11,4 +11,6 @@ export enum PermissionFlagType { // Tool permissions SEND_EMAIL_TOOL = 'SEND_EMAIL_TOOL', + IMPORT_CSV = 'IMPORT_CSV', + EXPORT_CSV = 'EXPORT_CSV', } diff --git a/packages/twenty-server/src/engine/metadata-modules/permissions/constants/tool-permission-flags.ts b/packages/twenty-server/src/engine/metadata-modules/permissions/constants/tool-permission-flags.ts new file mode 100644 index 000000000..939f25600 --- /dev/null +++ b/packages/twenty-server/src/engine/metadata-modules/permissions/constants/tool-permission-flags.ts @@ -0,0 +1,5 @@ +export const TOOL_PERMISSION_FLAGS = [ + 'SEND_EMAIL_TOOL', + 'IMPORT_CSV', + 'EXPORT_CSV', +]; diff --git a/packages/twenty-server/src/engine/metadata-modules/permissions/permissions.service.ts b/packages/twenty-server/src/engine/metadata-modules/permissions/permissions.service.ts index f408ca0f9..08417381f 100644 --- a/packages/twenty-server/src/engine/metadata-modules/permissions/permissions.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/permissions/permissions.service.ts @@ -10,6 +10,7 @@ import { AuthExceptionCode, } from 'src/engine/core-modules/auth/auth.exception'; import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants'; +import { TOOL_PERMISSION_FLAGS } from 'src/engine/metadata-modules/permissions/constants/tool-permission-flags'; import { PermissionsException, PermissionsExceptionCode, @@ -29,6 +30,10 @@ export class PermissionsService { private readonly roleRepository: Repository, ) {} + private isToolPermission(feature: string) { + return TOOL_PERMISSION_FLAGS.includes(feature); + } + public async getUserWorkspacePermissions({ userWorkspaceId, workspaceId, @@ -43,8 +48,6 @@ export class PermissionsService { }) .then((roles) => roles?.get(userWorkspaceId) ?? []); - let hasPermissionOnSettingFeature = false; - if (!isDefined(roleOfUserWorkspace)) { throw new PermissionsException( PermissionsExceptionMessage.NO_ROLE_FOUND_FOR_USER_WORKSPACE, @@ -52,23 +55,23 @@ export class PermissionsService { ); } - if (roleOfUserWorkspace.canUpdateAllSettings === true) { - hasPermissionOnSettingFeature = true; - } - - const permissionFlags = roleOfUserWorkspace.permissionFlags ?? []; - const defaultSettingsPermissions = - this.getDefaultUserWorkspacePermissions().settingsPermissions; - const settingsPermissions = Object.keys(PermissionFlagType).reduce( - (acc, feature) => ({ - ...acc, - [feature]: - hasPermissionOnSettingFeature || - permissionFlags.some( - (permissionFlag) => permissionFlag.flag === feature, - ), - }), + this.getDefaultUserWorkspacePermissions().permissionFlags; + const permissionFlags = Object.keys(PermissionFlagType).reduce( + (acc, feature) => { + const hasBasePermission = this.isToolPermission(feature) + ? roleOfUserWorkspace.canAccessAllTools + : roleOfUserWorkspace.canUpdateAllSettings; + + return { + ...acc, + [feature]: + hasBasePermission || + roleOfUserWorkspace.permissionFlags.some( + (permissionFlag) => permissionFlag.flag === feature, + ), + }; + }, defaultSettingsPermissions, ); @@ -92,7 +95,7 @@ export class PermissionsService { }; return { - settingsPermissions, + permissionFlags, objectRecordsPermissions, objectPermissions, }; @@ -106,7 +109,7 @@ export class PermissionsService { [PermissionsOnAllObjectRecords.SOFT_DELETE_ALL_OBJECT_RECORDS]: false, [PermissionsOnAllObjectRecords.DESTROY_ALL_OBJECT_RECORDS]: false, }, - settingsPermissions: { + permissionFlags: { [PermissionFlagType.API_KEYS_AND_WEBHOOKS]: false, [PermissionFlagType.WORKSPACE]: false, [PermissionFlagType.WORKSPACE_MEMBERS]: false, @@ -116,6 +119,8 @@ export class PermissionsService { [PermissionFlagType.SECURITY]: false, [PermissionFlagType.WORKFLOWS]: false, [PermissionFlagType.SEND_EMAIL_TOOL]: false, + [PermissionFlagType.IMPORT_CSV]: false, + [PermissionFlagType.EXPORT_CSV]: false, }, objectPermissions: {}, }) as const satisfies UserWorkspacePermissions; diff --git a/packages/twenty-server/src/engine/metadata-modules/permissions/types/user-workspace-permissions.ts b/packages/twenty-server/src/engine/metadata-modules/permissions/types/user-workspace-permissions.ts index 731ac7084..6bce6a0d6 100644 --- a/packages/twenty-server/src/engine/metadata-modules/permissions/types/user-workspace-permissions.ts +++ b/packages/twenty-server/src/engine/metadata-modules/permissions/types/user-workspace-permissions.ts @@ -4,7 +4,7 @@ import { ObjectRecordsPermissions } from 'twenty-shared/types'; import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants'; export type UserWorkspacePermissions = { - settingsPermissions: Record; + permissionFlags: Record; objectRecordsPermissions: Record; objectPermissions: ObjectRecordsPermissions; }; diff --git a/packages/twenty-server/src/engine/metadata-modules/role/dtos/user-workspace-permissions.dto.ts b/packages/twenty-server/src/engine/metadata-modules/role/dtos/user-workspace-permissions.dto.ts index 11f587b45..ae700ee5e 100644 --- a/packages/twenty-server/src/engine/metadata-modules/role/dtos/user-workspace-permissions.dto.ts +++ b/packages/twenty-server/src/engine/metadata-modules/role/dtos/user-workspace-permissions.dto.ts @@ -2,5 +2,5 @@ import { UserWorkspace } from 'src/engine/core-modules/user-workspace/user-works export type UserWorkspacePermissionsDto = Pick< UserWorkspace, - 'objectPermissions' | 'settingsPermissions' | 'objectRecordsPermissions' + 'objectPermissions' | 'permissionFlags' | 'objectRecordsPermissions' >; diff --git a/packages/twenty-server/src/engine/metadata-modules/role/utils/fromUserWorkspacePermissionsToUserWorkspacePermissionsDto.ts b/packages/twenty-server/src/engine/metadata-modules/role/utils/fromUserWorkspacePermissionsToUserWorkspacePermissionsDto.ts index a6d64cf12..c3793c418 100644 --- a/packages/twenty-server/src/engine/metadata-modules/role/utils/fromUserWorkspacePermissionsToUserWorkspacePermissionsDto.ts +++ b/packages/twenty-server/src/engine/metadata-modules/role/utils/fromUserWorkspacePermissionsToUserWorkspacePermissionsDto.ts @@ -7,7 +7,7 @@ import { UserWorkspacePermissionsDto } from 'src/engine/metadata-modules/role/dt export const fromUserWorkspacePermissionsToUserWorkspacePermissionsDto = ({ objectPermissions: rawObjectPermissions, objectRecordsPermissions: rawObjectRecordsPermissions, - settingsPermissions: rawSettingsPermissions, + permissionFlags: rawSettingsPermissions, }: UserWorkspacePermissions): UserWorkspacePermissionsDto => { const objectPermissions = Object.entries(rawObjectPermissions).map( ([objectMetadataId, permissions]) => ({ @@ -19,7 +19,7 @@ export const fromUserWorkspacePermissionsToUserWorkspacePermissionsDto = ({ }), ); - const settingsPermissions = ( + const permissionFlags = ( Object.keys(rawSettingsPermissions) as PermissionFlagType[] ).filter((feature) => rawSettingsPermissions[feature] === true); @@ -30,6 +30,6 @@ export const fromUserWorkspacePermissionsToUserWorkspacePermissionsDto = ({ return { objectPermissions, objectRecordsPermissions, - settingsPermissions, + permissionFlags, }; }; diff --git a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/services/dev-seeder-permissions.service.ts b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/services/dev-seeder-permissions.service.ts index 081f3bebd..7583cdbb1 100644 --- a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/services/dev-seeder-permissions.service.ts +++ b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/services/dev-seeder-permissions.service.ts @@ -110,6 +110,7 @@ export class DevSeederPermissionsService { 'All permissions except read on Rockets and update on Pets', icon: 'custom', canUpdateAllSettings: true, + canAccessAllTools: true, canReadAllObjectRecords: true, canUpdateAllObjectRecords: true, canSoftDeleteAllObjectRecords: true,