Add Import CSV and Export CSV Permissions (#13421)
Co-authored-by: Félix Malfait <felix.malfait@gmail.com> Co-authored-by: Félix Malfait <felix@twenty.com>
This commit is contained in:
@ -1888,6 +1888,8 @@ export enum PermissionFlagType {
|
|||||||
ADMIN_PANEL = 'ADMIN_PANEL',
|
ADMIN_PANEL = 'ADMIN_PANEL',
|
||||||
API_KEYS_AND_WEBHOOKS = 'API_KEYS_AND_WEBHOOKS',
|
API_KEYS_AND_WEBHOOKS = 'API_KEYS_AND_WEBHOOKS',
|
||||||
DATA_MODEL = 'DATA_MODEL',
|
DATA_MODEL = 'DATA_MODEL',
|
||||||
|
EXPORT_CSV = 'EXPORT_CSV',
|
||||||
|
IMPORT_CSV = 'IMPORT_CSV',
|
||||||
ROLES = 'ROLES',
|
ROLES = 'ROLES',
|
||||||
SECURITY = 'SECURITY',
|
SECURITY = 'SECURITY',
|
||||||
SEND_EMAIL_TOOL = 'SEND_EMAIL_TOOL',
|
SEND_EMAIL_TOOL = 'SEND_EMAIL_TOOL',
|
||||||
@ -2836,7 +2838,7 @@ export type UserWorkspace = {
|
|||||||
objectPermissions?: Maybe<Array<ObjectPermission>>;
|
objectPermissions?: Maybe<Array<ObjectPermission>>;
|
||||||
/** @deprecated Use objectPermissions instead */
|
/** @deprecated Use objectPermissions instead */
|
||||||
objectRecordsPermissions?: Maybe<Array<PermissionsOnAllObjectRecords>>;
|
objectRecordsPermissions?: Maybe<Array<PermissionsOnAllObjectRecords>>;
|
||||||
settingsPermissions?: Maybe<Array<PermissionFlagType>>;
|
permissionFlags?: Maybe<Array<PermissionFlagType>>;
|
||||||
twoFactorAuthenticationMethodSummary?: Maybe<Array<TwoFactorAuthenticationMethodDto>>;
|
twoFactorAuthenticationMethodSummary?: Maybe<Array<TwoFactorAuthenticationMethodDto>>;
|
||||||
updatedAt: Scalars['DateTime'];
|
updatedAt: Scalars['DateTime'];
|
||||||
user: User;
|
user: User;
|
||||||
@ -3839,7 +3841,7 @@ export type VerifyTwoFactorAuthenticationMethodForAuthenticatedUserMutationVaria
|
|||||||
|
|
||||||
export type VerifyTwoFactorAuthenticationMethodForAuthenticatedUserMutation = { __typename?: 'Mutation', verifyTwoFactorAuthenticationMethodForAuthenticatedUser: { __typename?: 'VerifyTwoFactorAuthenticationMethodOutput', success: boolean } };
|
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<PermissionFlagType> | null, objectRecordsPermissions?: Array<PermissionsOnAllObjectRecords> | 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<PermissionFlagType> | null, objectRecordsPermissions?: Array<PermissionsOnAllObjectRecords> | 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 };
|
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 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<PermissionFlagType> | null, objectRecordsPermissions?: Array<PermissionsOnAllObjectRecords> | 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<PermissionFlagType> | null, objectRecordsPermissions?: Array<PermissionsOnAllObjectRecords> | 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<{
|
export type ActivateWorkflowVersionMutationVariables = Exact<{
|
||||||
workflowVersionId: Scalars['String'];
|
workflowVersionId: Scalars['String'];
|
||||||
@ -4196,7 +4198,7 @@ export const UserQueryFragmentFragmentDoc = gql`
|
|||||||
...DeletedWorkspaceMemberQueryFragment
|
...DeletedWorkspaceMemberQueryFragment
|
||||||
}
|
}
|
||||||
currentUserWorkspace {
|
currentUserWorkspace {
|
||||||
settingsPermissions
|
permissionFlags
|
||||||
objectRecordsPermissions
|
objectRecordsPermissions
|
||||||
objectPermissions {
|
objectPermissions {
|
||||||
...ObjectPermissionFragment
|
...ObjectPermissionFragment
|
||||||
|
|||||||
@ -1799,6 +1799,8 @@ export enum PermissionFlagType {
|
|||||||
ADMIN_PANEL = 'ADMIN_PANEL',
|
ADMIN_PANEL = 'ADMIN_PANEL',
|
||||||
API_KEYS_AND_WEBHOOKS = 'API_KEYS_AND_WEBHOOKS',
|
API_KEYS_AND_WEBHOOKS = 'API_KEYS_AND_WEBHOOKS',
|
||||||
DATA_MODEL = 'DATA_MODEL',
|
DATA_MODEL = 'DATA_MODEL',
|
||||||
|
EXPORT_CSV = 'EXPORT_CSV',
|
||||||
|
IMPORT_CSV = 'IMPORT_CSV',
|
||||||
ROLES = 'ROLES',
|
ROLES = 'ROLES',
|
||||||
SECURITY = 'SECURITY',
|
SECURITY = 'SECURITY',
|
||||||
SEND_EMAIL_TOOL = 'SEND_EMAIL_TOOL',
|
SEND_EMAIL_TOOL = 'SEND_EMAIL_TOOL',
|
||||||
@ -2664,7 +2666,7 @@ export type UserWorkspace = {
|
|||||||
objectPermissions?: Maybe<Array<ObjectPermission>>;
|
objectPermissions?: Maybe<Array<ObjectPermission>>;
|
||||||
/** @deprecated Use objectPermissions instead */
|
/** @deprecated Use objectPermissions instead */
|
||||||
objectRecordsPermissions?: Maybe<Array<PermissionsOnAllObjectRecords>>;
|
objectRecordsPermissions?: Maybe<Array<PermissionsOnAllObjectRecords>>;
|
||||||
settingsPermissions?: Maybe<Array<PermissionFlagType>>;
|
permissionFlags?: Maybe<Array<PermissionFlagType>>;
|
||||||
twoFactorAuthenticationMethodSummary?: Maybe<Array<TwoFactorAuthenticationMethodDto>>;
|
twoFactorAuthenticationMethodSummary?: Maybe<Array<TwoFactorAuthenticationMethodDto>>;
|
||||||
updatedAt: Scalars['DateTime'];
|
updatedAt: Scalars['DateTime'];
|
||||||
user: User;
|
user: User;
|
||||||
|
|||||||
@ -53,6 +53,7 @@ import {
|
|||||||
IconTrashX,
|
IconTrashX,
|
||||||
IconUser,
|
IconUser,
|
||||||
} from 'twenty-ui/display';
|
} from 'twenty-ui/display';
|
||||||
|
import { PermissionFlagType } from '~/generated-metadata/graphql';
|
||||||
|
|
||||||
export const DEFAULT_RECORD_ACTIONS_CONFIG: Record<
|
export const DEFAULT_RECORD_ACTIONS_CONFIG: Record<
|
||||||
| NoSelectionRecordActionKeys
|
| NoSelectionRecordActionKeys
|
||||||
@ -169,6 +170,7 @@ export const DEFAULT_RECORD_ACTIONS_CONFIG: Record<
|
|||||||
isDefined(selectedRecord) && !selectedRecord.isRemote,
|
isDefined(selectedRecord) && !selectedRecord.isRemote,
|
||||||
availableOn: [ActionViewType.SHOW_PAGE],
|
availableOn: [ActionViewType.SHOW_PAGE],
|
||||||
component: <ExportSingleRecordAction />,
|
component: <ExportSingleRecordAction />,
|
||||||
|
requiredPermissionFlag: PermissionFlagType.EXPORT_CSV,
|
||||||
},
|
},
|
||||||
[MultipleRecordsActionKeys.EXPORT]: {
|
[MultipleRecordsActionKeys.EXPORT]: {
|
||||||
type: ActionType.Standard,
|
type: ActionType.Standard,
|
||||||
@ -183,6 +185,7 @@ export const DEFAULT_RECORD_ACTIONS_CONFIG: Record<
|
|||||||
shouldBeRegistered: () => true,
|
shouldBeRegistered: () => true,
|
||||||
availableOn: [ActionViewType.INDEX_PAGE_BULK_SELECTION],
|
availableOn: [ActionViewType.INDEX_PAGE_BULK_SELECTION],
|
||||||
component: <ExportMultipleRecordsAction />,
|
component: <ExportMultipleRecordsAction />,
|
||||||
|
requiredPermissionFlag: PermissionFlagType.EXPORT_CSV,
|
||||||
},
|
},
|
||||||
[NoSelectionRecordActionKeys.IMPORT_RECORDS]: {
|
[NoSelectionRecordActionKeys.IMPORT_RECORDS]: {
|
||||||
type: ActionType.Standard,
|
type: ActionType.Standard,
|
||||||
@ -198,6 +201,7 @@ export const DEFAULT_RECORD_ACTIONS_CONFIG: Record<
|
|||||||
!isSoftDeleteFilterActive,
|
!isSoftDeleteFilterActive,
|
||||||
availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION],
|
availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION],
|
||||||
component: <ImportRecordsNoSelectionRecordAction />,
|
component: <ImportRecordsNoSelectionRecordAction />,
|
||||||
|
requiredPermissionFlag: PermissionFlagType.IMPORT_CSV,
|
||||||
},
|
},
|
||||||
[NoSelectionRecordActionKeys.EXPORT_VIEW]: {
|
[NoSelectionRecordActionKeys.EXPORT_VIEW]: {
|
||||||
type: ActionType.Standard,
|
type: ActionType.Standard,
|
||||||
@ -212,6 +216,7 @@ export const DEFAULT_RECORD_ACTIONS_CONFIG: Record<
|
|||||||
shouldBeRegistered: () => true,
|
shouldBeRegistered: () => true,
|
||||||
availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION],
|
availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION],
|
||||||
component: <ExportMultipleRecordsAction />,
|
component: <ExportMultipleRecordsAction />,
|
||||||
|
requiredPermissionFlag: PermissionFlagType.EXPORT_CSV,
|
||||||
},
|
},
|
||||||
[SingleRecordActionKeys.DELETE]: {
|
[SingleRecordActionKeys.DELETE]: {
|
||||||
type: ActionType.Standard,
|
type: ActionType.Standard,
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import { ShouldBeRegisteredFunctionParams } from '@/action-menu/actions/types/Sh
|
|||||||
import { MessageDescriptor } from '@lingui/core';
|
import { MessageDescriptor } from '@lingui/core';
|
||||||
import { IconComponent } from 'twenty-ui/display';
|
import { IconComponent } from 'twenty-ui/display';
|
||||||
import { MenuItemAccent } from 'twenty-ui/navigation';
|
import { MenuItemAccent } from 'twenty-ui/navigation';
|
||||||
|
import { PermissionFlagType } from '~/generated-metadata/graphql';
|
||||||
|
|
||||||
export type ActionConfig = {
|
export type ActionConfig = {
|
||||||
type: ActionType;
|
type: ActionType;
|
||||||
@ -21,4 +22,5 @@ export type ActionConfig = {
|
|||||||
shouldBeRegistered: (params: ShouldBeRegisteredFunctionParams) => boolean;
|
shouldBeRegistered: (params: ShouldBeRegisteredFunctionParams) => boolean;
|
||||||
component: React.ReactNode;
|
component: React.ReactNode;
|
||||||
hotKeys?: string[];
|
hotKeys?: string[];
|
||||||
|
requiredPermissionFlag?: PermissionFlagType;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { getActionConfig } from '@/action-menu/actions/utils/getActionConfig';
|
|||||||
import { getActionViewType } from '@/action-menu/actions/utils/getActionViewType';
|
import { getActionViewType } from '@/action-menu/actions/utils/getActionViewType';
|
||||||
import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState';
|
import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState';
|
||||||
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
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 { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
import { useIcons } from 'twenty-ui/display';
|
import { useIcons } from 'twenty-ui/display';
|
||||||
@ -48,6 +49,8 @@ export const useRegisteredActions = (
|
|||||||
...recordAgnosticActionConfig,
|
...recordAgnosticActionConfig,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const permissionMap = usePermissionFlagMap();
|
||||||
|
|
||||||
const actionsToRegister = isDefined(viewType)
|
const actionsToRegister = isDefined(viewType)
|
||||||
? Object.values(actionsConfig).filter(
|
? Object.values(actionsConfig).filter(
|
||||||
(action) =>
|
(action) =>
|
||||||
@ -57,7 +60,15 @@ export const useRegisteredActions = (
|
|||||||
: [];
|
: [];
|
||||||
|
|
||||||
const actions = actionsToRegister
|
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);
|
.sort((a, b) => a.position - b.position);
|
||||||
|
|
||||||
return actions;
|
return actions;
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import { UserWorkspace } from '~/generated/graphql';
|
|||||||
|
|
||||||
export type CurrentUserWorkspace = Pick<
|
export type CurrentUserWorkspace = Pick<
|
||||||
UserWorkspace,
|
UserWorkspace,
|
||||||
| 'settingsPermissions'
|
| 'permissionFlags'
|
||||||
| 'objectRecordsPermissions'
|
| 'objectRecordsPermissions'
|
||||||
| 'objectPermissions'
|
| 'objectPermissions'
|
||||||
| 'twoFactorAuthenticationMethodSummary'
|
| 'twoFactorAuthenticationMethodSummary'
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { useRedirect } from '@/domain-manager/hooks/useRedirect';
|
import { useRedirect } from '@/domain-manager/hooks/useRedirect';
|
||||||
import { InformationBanner } from '@/information-banner/components/InformationBanner';
|
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 { SettingsPath } from '@/types/SettingsPath';
|
||||||
import { t } from '@lingui/core/macro';
|
import { t } from '@lingui/core/macro';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
@ -21,7 +21,7 @@ export const InformationBannerBillingSubscriptionPaused = () => {
|
|||||||
|
|
||||||
const {
|
const {
|
||||||
[PermissionFlagType.WORKSPACE]: hasPermissionToUpdateBillingDetails,
|
[PermissionFlagType.WORKSPACE]: hasPermissionToUpdateBillingDetails,
|
||||||
} = useSettingsPermissionMap();
|
} = usePermissionFlagMap();
|
||||||
|
|
||||||
const openBillingPortal = () => {
|
const openBillingPortal = () => {
|
||||||
if (isDefined(data) && isDefined(data.billingPortalSession.url)) {
|
if (isDefined(data) && isDefined(data.billingPortalSession.url)) {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { useEndSubscriptionTrialPeriod } from '@/billing/hooks/useEndSubscriptionTrialPeriod';
|
import { useEndSubscriptionTrialPeriod } from '@/billing/hooks/useEndSubscriptionTrialPeriod';
|
||||||
import { InformationBanner } from '@/information-banner/components/InformationBanner';
|
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 { useLingui } from '@lingui/react/macro';
|
||||||
import { PermissionFlagType } from '~/generated-metadata/graphql';
|
import { PermissionFlagType } from '~/generated-metadata/graphql';
|
||||||
|
|
||||||
@ -9,7 +9,7 @@ export const InformationBannerEndTrialPeriod = () => {
|
|||||||
const { t } = useLingui();
|
const { t } = useLingui();
|
||||||
|
|
||||||
const { [PermissionFlagType.WORKSPACE]: hasPermissionToEndTrialPeriod } =
|
const { [PermissionFlagType.WORKSPACE]: hasPermissionToEndTrialPeriod } =
|
||||||
useSettingsPermissionMap();
|
usePermissionFlagMap();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InformationBanner
|
<InformationBanner
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { useRedirect } from '@/domain-manager/hooks/useRedirect';
|
import { useRedirect } from '@/domain-manager/hooks/useRedirect';
|
||||||
import { InformationBanner } from '@/information-banner/components/InformationBanner';
|
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 { SettingsPath } from '@/types/SettingsPath';
|
||||||
import { t } from '@lingui/core/macro';
|
import { t } from '@lingui/core/macro';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
@ -21,7 +21,7 @@ export const InformationBannerFailPaymentInfo = () => {
|
|||||||
|
|
||||||
const {
|
const {
|
||||||
[PermissionFlagType.WORKSPACE]: hasPermissionToUpdateBillingDetails,
|
[PermissionFlagType.WORKSPACE]: hasPermissionToUpdateBillingDetails,
|
||||||
} = useSettingsPermissionMap();
|
} = usePermissionFlagMap();
|
||||||
|
|
||||||
const openBillingPortal = () => {
|
const openBillingPortal = () => {
|
||||||
if (isDefined(data) && isDefined(data.billingPortalSession.url)) {
|
if (isDefined(data) && isDefined(data.billingPortalSession.url)) {
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { BILLING_CHECKOUT_SESSION_DEFAULT_VALUE } from '@/billing/constants/BillingCheckoutSessionDefaultValue';
|
import { BILLING_CHECKOUT_SESSION_DEFAULT_VALUE } from '@/billing/constants/BillingCheckoutSessionDefaultValue';
|
||||||
import { useHandleCheckoutSession } from '@/billing/hooks/useHandleCheckoutSession';
|
import { useHandleCheckoutSession } from '@/billing/hooks/useHandleCheckoutSession';
|
||||||
import { InformationBanner } from '@/information-banner/components/InformationBanner';
|
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 { SettingsPath } from '@/types/SettingsPath';
|
||||||
import { t } from '@lingui/core/macro';
|
import { t } from '@lingui/core/macro';
|
||||||
import { PermissionFlagType } from '~/generated-metadata/graphql';
|
import { PermissionFlagType } from '~/generated-metadata/graphql';
|
||||||
@ -16,7 +16,7 @@ export const InformationBannerNoBillingSubscription = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const { [PermissionFlagType.WORKSPACE]: hasPermissionToSubscribe } =
|
const { [PermissionFlagType.WORKSPACE]: hasPermissionToSubscribe } =
|
||||||
useSettingsPermissionMap();
|
usePermissionFlagMap();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InformationBanner
|
<InformationBanner
|
||||||
|
|||||||
@ -132,7 +132,7 @@ export const queries = {
|
|||||||
...WorkspaceMemberQueryFragment
|
...WorkspaceMemberQueryFragment
|
||||||
}
|
}
|
||||||
currentUserWorkspace {
|
currentUserWorkspace {
|
||||||
settingsPermissions
|
permissionFlags
|
||||||
objectRecordsPermissions
|
objectRecordsPermissions
|
||||||
}
|
}
|
||||||
currentWorkspace {
|
currentWorkspace {
|
||||||
@ -287,7 +287,7 @@ export const responseData = {
|
|||||||
},
|
},
|
||||||
workspaceMembers: [],
|
workspaceMembers: [],
|
||||||
currentUserWorkspace: {
|
currentUserWorkspace: {
|
||||||
settingsPermissions: ['DATA_MODEL'],
|
permissionFlags: ['DATA_MODEL'],
|
||||||
objectRecordsPermissions: [
|
objectRecordsPermissions: [
|
||||||
PermissionsOnAllObjectRecords.READ_ALL_OBJECT_RECORDS,
|
PermissionsOnAllObjectRecords.READ_ALL_OBJECT_RECORDS,
|
||||||
PermissionsOnAllObjectRecords.UPDATE_ALL_OBJECT_RECORDS,
|
PermissionsOnAllObjectRecords.UPDATE_ALL_OBJECT_RECORDS,
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import { recordGroupFieldMetadataComponentState } from '@/object-record/record-g
|
|||||||
import { visibleRecordGroupIdsComponentFamilySelector } from '@/object-record/record-group/states/selectors/visibleRecordGroupIdsComponentFamilySelector';
|
import { visibleRecordGroupIdsComponentFamilySelector } from '@/object-record/record-group/states/selectors/visibleRecordGroupIdsComponentFamilySelector';
|
||||||
import { RecordGroupAction } from '@/object-record/record-group/types/RecordGroupActions';
|
import { RecordGroupAction } from '@/object-record/record-group/types/RecordGroupActions';
|
||||||
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||||
import { useHasSettingsPermission } from '@/settings/roles/hooks/useHasSettingsPermission';
|
import { useHasPermissionFlag } from '@/settings/roles/hooks/useHasPermissionFlag';
|
||||||
import { SettingsPath } from '@/types/SettingsPath';
|
import { SettingsPath } from '@/types/SettingsPath';
|
||||||
import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState';
|
import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState';
|
||||||
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
|
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
|
||||||
@ -90,7 +90,7 @@ export const useRecordGroupActions = ({
|
|||||||
recordGroupFieldMetadata,
|
recordGroupFieldMetadata,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const hasAccessToDataModelSettings = useHasSettingsPermission(
|
const hasAccessToDataModelSettings = useHasPermissionFlag(
|
||||||
PermissionFlagType.DATA_MODEL,
|
PermissionFlagType.DATA_MODEL,
|
||||||
);
|
);
|
||||||
const currentIndex = visibleRecordGroupIds.findIndex(
|
const currentIndex = visibleRecordGroupIds.findIndex(
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { useHasSettingsPermission } from '@/settings/roles/hooks/useHasSettingsPermission';
|
import { useHasPermissionFlag } from '@/settings/roles/hooks/useHasPermissionFlag';
|
||||||
import { SettingsPath } from '@/types/SettingsPath';
|
import { SettingsPath } from '@/types/SettingsPath';
|
||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
import { ReactNode } from 'react';
|
import { ReactNode } from 'react';
|
||||||
@ -17,7 +17,7 @@ export const SettingsProtectedRouteWrapper = ({
|
|||||||
settingsPermission,
|
settingsPermission,
|
||||||
requiredFeatureFlag,
|
requiredFeatureFlag,
|
||||||
}: SettingsProtectedRouteWrapperProps) => {
|
}: SettingsProtectedRouteWrapperProps) => {
|
||||||
const hasPermission = useHasSettingsPermission(settingsPermission);
|
const hasPermission = useHasPermissionFlag(settingsPermission);
|
||||||
const requiredFeatureFlagEnabled = useIsFeatureEnabled(
|
const requiredFeatureFlagEnabled = useIsFeatureEnabled(
|
||||||
requiredFeatureFlag || null,
|
requiredFeatureFlag || null,
|
||||||
);
|
);
|
||||||
|
|||||||
@ -13,7 +13,7 @@ import {
|
|||||||
import { currentUserState } from '@/auth/states/currentUserState';
|
import { currentUserState } from '@/auth/states/currentUserState';
|
||||||
import { billingState } from '@/client-config/states/billingState';
|
import { billingState } from '@/client-config/states/billingState';
|
||||||
import { labPublicFeatureFlagsState } from '@/client-config/states/labPublicFeatureFlagsState';
|
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';
|
import { SnackBarComponentInstanceContextProvider } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarComponentInstanceContextProvider';
|
||||||
|
|
||||||
const mockCurrentUser = {
|
const mockCurrentUser = {
|
||||||
@ -53,13 +53,13 @@ const Wrapper = ({ children }: { children: ReactNode }) => (
|
|||||||
</MockedProvider>
|
</MockedProvider>
|
||||||
);
|
);
|
||||||
|
|
||||||
jest.mock('@/settings/roles/hooks/useSettingsPermissionMap', () => ({
|
jest.mock('@/settings/roles/hooks/usePermissionFlagMap', () => ({
|
||||||
useSettingsPermissionMap: jest.fn(),
|
usePermissionFlagMap: jest.fn(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
describe('useSettingsNavigationItems', () => {
|
describe('useSettingsNavigationItems', () => {
|
||||||
it('should hide workspace settings when no permissions', () => {
|
it('should hide workspace settings when no permissions', () => {
|
||||||
(useSettingsPermissionMap as jest.Mock).mockImplementation(() => ({
|
(usePermissionFlagMap as jest.Mock).mockImplementation(() => ({
|
||||||
[PermissionFlagType.WORKSPACE]: false,
|
[PermissionFlagType.WORKSPACE]: false,
|
||||||
[PermissionFlagType.WORKSPACE_MEMBERS]: false,
|
[PermissionFlagType.WORKSPACE_MEMBERS]: false,
|
||||||
[PermissionFlagType.DATA_MODEL]: false,
|
[PermissionFlagType.DATA_MODEL]: false,
|
||||||
@ -80,7 +80,7 @@ describe('useSettingsNavigationItems', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should show workspace settings when has permissions', () => {
|
it('should show workspace settings when has permissions', () => {
|
||||||
(useSettingsPermissionMap as jest.Mock).mockImplementation(() => ({
|
(usePermissionFlagMap as jest.Mock).mockImplementation(() => ({
|
||||||
[PermissionFlagType.WORKSPACE]: true,
|
[PermissionFlagType.WORKSPACE]: true,
|
||||||
[PermissionFlagType.WORKSPACE_MEMBERS]: true,
|
[PermissionFlagType.WORKSPACE_MEMBERS]: true,
|
||||||
[PermissionFlagType.DATA_MODEL]: true,
|
[PermissionFlagType.DATA_MODEL]: true,
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { useAuth } from '@/auth/hooks/useAuth';
|
|||||||
import { currentUserState } from '@/auth/states/currentUserState';
|
import { currentUserState } from '@/auth/states/currentUserState';
|
||||||
import { billingState } from '@/client-config/states/billingState';
|
import { billingState } from '@/client-config/states/billingState';
|
||||||
import { labPublicFeatureFlagsState } from '@/client-config/states/labPublicFeatureFlagsState';
|
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 { NavigationDrawerItemIndentationLevel } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerItem';
|
||||||
import { t } from '@lingui/core/macro';
|
import { t } from '@lingui/core/macro';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
@ -63,7 +63,7 @@ const useSettingsNavigationItems = (): SettingsNavigationSection[] => {
|
|||||||
false;
|
false;
|
||||||
const labPublicFeatureFlags = useRecoilValue(labPublicFeatureFlagsState);
|
const labPublicFeatureFlags = useRecoilValue(labPublicFeatureFlagsState);
|
||||||
|
|
||||||
const permissionMap = useSettingsPermissionMap();
|
const permissionMap = usePermissionFlagMap();
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
label: t`User`,
|
label: t`User`,
|
||||||
|
|||||||
@ -4,9 +4,7 @@ import { useRecoilValue } from 'recoil';
|
|||||||
import { WorkspaceActivationStatus } from 'twenty-shared/workspace';
|
import { WorkspaceActivationStatus } from 'twenty-shared/workspace';
|
||||||
import { PermissionFlagType } from '~/generated/graphql';
|
import { PermissionFlagType } from '~/generated/graphql';
|
||||||
|
|
||||||
export const useHasSettingsPermission = (
|
export const useHasPermissionFlag = (permissionFlag?: PermissionFlagType) => {
|
||||||
permissionFlag?: PermissionFlagType,
|
|
||||||
) => {
|
|
||||||
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
||||||
const currentUserWorkspace = useRecoilValue(currentUserWorkspaceState);
|
const currentUserWorkspace = useRecoilValue(currentUserWorkspaceState);
|
||||||
|
|
||||||
@ -22,7 +20,7 @@ export const useHasSettingsPermission = (
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentUserWorkspaceSetting = currentUserWorkspace?.settingsPermissions;
|
const currentUserWorkspaceSetting = currentUserWorkspace?.permissionFlags;
|
||||||
|
|
||||||
if (!currentUserWorkspaceSetting) {
|
if (!currentUserWorkspaceSetting) {
|
||||||
return false;
|
return false;
|
||||||
@ -3,14 +3,11 @@ import { useRecoilValue } from 'recoil';
|
|||||||
import { PermissionFlagType } from '~/generated/graphql';
|
import { PermissionFlagType } from '~/generated/graphql';
|
||||||
import { buildRecordFromKeysWithSameValue } from '~/utils/array/buildRecordFromKeysWithSameValue';
|
import { buildRecordFromKeysWithSameValue } from '~/utils/array/buildRecordFromKeysWithSameValue';
|
||||||
|
|
||||||
export const useSettingsPermissionMap = (): Record<
|
export const usePermissionFlagMap = (): Record<PermissionFlagType, boolean> => {
|
||||||
PermissionFlagType,
|
|
||||||
boolean
|
|
||||||
> => {
|
|
||||||
const currentUserWorkspace = useRecoilValue(currentUserWorkspaceState);
|
const currentUserWorkspace = useRecoilValue(currentUserWorkspaceState);
|
||||||
|
|
||||||
const currentUserWorkspaceSettingsPermissions =
|
const currentUserWorkspaceSettingsPermissions =
|
||||||
currentUserWorkspace?.settingsPermissions;
|
currentUserWorkspace?.permissionFlags;
|
||||||
|
|
||||||
const initialPermissions = buildRecordFromKeysWithSameValue(
|
const initialPermissions = buildRecordFromKeysWithSameValue(
|
||||||
Object.values(PermissionFlagType),
|
Object.values(PermissionFlagType),
|
||||||
@ -7,7 +7,13 @@ import styled from '@emotion/styled';
|
|||||||
import { t } from '@lingui/core/macro';
|
import { t } from '@lingui/core/macro';
|
||||||
import { useRecoilState } from 'recoil';
|
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 { AnimatedExpandableContainer, Card, Section } from 'twenty-ui/layout';
|
||||||
import { PermissionFlagType } from '~/generated-metadata/graphql';
|
import { PermissionFlagType } from '~/generated-metadata/graphql';
|
||||||
|
|
||||||
@ -45,19 +51,30 @@ export const SettingsRolePermissionsToolSection = ({
|
|||||||
Icon: IconMail,
|
Icon: IconMail,
|
||||||
isToolPermission: true,
|
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 (
|
return (
|
||||||
<Section>
|
<Section>
|
||||||
<H2Title
|
<H2Title title={t`Actions`} description={t`Actions permissions`} />
|
||||||
title={t`Action Permissions`}
|
|
||||||
description={t`Permissions for performing automated actions.`}
|
|
||||||
/>
|
|
||||||
<StyledCard rounded>
|
<StyledCard rounded>
|
||||||
<SettingsOptionCardContentToggle
|
<SettingsOptionCardContentToggle
|
||||||
Icon={IconTool}
|
Icon={IconTool}
|
||||||
title={t`All Actions Access`}
|
title={t`All Actions Access`}
|
||||||
description={t`Grants permission to perform all available actions without restriction.`}
|
description={t`Grants permission to perform all available actions without restriction`}
|
||||||
checked={settingsDraftRole.canAccessAllTools}
|
checked={settingsDraftRole.canAccessAllTools}
|
||||||
disabled={!isEditable}
|
disabled={!isEditable}
|
||||||
onChange={() => {
|
onChange={() => {
|
||||||
|
|||||||
@ -34,7 +34,7 @@ export const USER_QUERY_FRAGMENT = gql`
|
|||||||
...DeletedWorkspaceMemberQueryFragment
|
...DeletedWorkspaceMemberQueryFragment
|
||||||
}
|
}
|
||||||
currentUserWorkspace {
|
currentUserWorkspace {
|
||||||
settingsPermissions
|
permissionFlags
|
||||||
objectRecordsPermissions
|
objectRecordsPermissions
|
||||||
objectPermissions {
|
objectPermissions {
|
||||||
...ObjectPermissionFragment
|
...ObjectPermissionFragment
|
||||||
|
|||||||
@ -125,7 +125,7 @@ export const mockedUserData: MockedUser = {
|
|||||||
workspaceMember: mockedWorkspaceMemberData,
|
workspaceMember: mockedWorkspaceMemberData,
|
||||||
currentWorkspace: mockCurrentWorkspace,
|
currentWorkspace: mockCurrentWorkspace,
|
||||||
currentUserWorkspace: {
|
currentUserWorkspace: {
|
||||||
settingsPermissions: [PermissionFlagType.WORKSPACE_MEMBERS],
|
permissionFlags: [PermissionFlagType.WORKSPACE_MEMBERS],
|
||||||
objectPermissions: generatedMockObjectMetadataItems.map((item) => ({
|
objectPermissions: generatedMockObjectMetadataItems.map((item) => ({
|
||||||
objectMetadataId: item.id,
|
objectMetadataId: item.id,
|
||||||
canReadObjectRecords: true,
|
canReadObjectRecords: true,
|
||||||
|
|||||||
@ -97,7 +97,7 @@ export class UserWorkspace {
|
|||||||
twoFactorAuthenticationMethods: Relation<TwoFactorAuthenticationMethod[]>;
|
twoFactorAuthenticationMethods: Relation<TwoFactorAuthenticationMethod[]>;
|
||||||
|
|
||||||
@Field(() => [PermissionFlagType], { nullable: true })
|
@Field(() => [PermissionFlagType], { nullable: true })
|
||||||
settingsPermissions?: PermissionFlagType[];
|
permissionFlags?: PermissionFlagType[];
|
||||||
|
|
||||||
@Field(() => [PermissionsOnAllObjectRecords], {
|
@Field(() => [PermissionsOnAllObjectRecords], {
|
||||||
nullable: true,
|
nullable: true,
|
||||||
|
|||||||
@ -11,4 +11,6 @@ export enum PermissionFlagType {
|
|||||||
|
|
||||||
// Tool permissions
|
// Tool permissions
|
||||||
SEND_EMAIL_TOOL = 'SEND_EMAIL_TOOL',
|
SEND_EMAIL_TOOL = 'SEND_EMAIL_TOOL',
|
||||||
|
IMPORT_CSV = 'IMPORT_CSV',
|
||||||
|
EXPORT_CSV = 'EXPORT_CSV',
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,5 @@
|
|||||||
|
export const TOOL_PERMISSION_FLAGS = [
|
||||||
|
'SEND_EMAIL_TOOL',
|
||||||
|
'IMPORT_CSV',
|
||||||
|
'EXPORT_CSV',
|
||||||
|
];
|
||||||
@ -10,6 +10,7 @@ import {
|
|||||||
AuthExceptionCode,
|
AuthExceptionCode,
|
||||||
} from 'src/engine/core-modules/auth/auth.exception';
|
} from 'src/engine/core-modules/auth/auth.exception';
|
||||||
import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
|
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 {
|
import {
|
||||||
PermissionsException,
|
PermissionsException,
|
||||||
PermissionsExceptionCode,
|
PermissionsExceptionCode,
|
||||||
@ -29,6 +30,10 @@ export class PermissionsService {
|
|||||||
private readonly roleRepository: Repository<RoleEntity>,
|
private readonly roleRepository: Repository<RoleEntity>,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
private isToolPermission(feature: string) {
|
||||||
|
return TOOL_PERMISSION_FLAGS.includes(feature);
|
||||||
|
}
|
||||||
|
|
||||||
public async getUserWorkspacePermissions({
|
public async getUserWorkspacePermissions({
|
||||||
userWorkspaceId,
|
userWorkspaceId,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
@ -43,8 +48,6 @@ export class PermissionsService {
|
|||||||
})
|
})
|
||||||
.then((roles) => roles?.get(userWorkspaceId) ?? []);
|
.then((roles) => roles?.get(userWorkspaceId) ?? []);
|
||||||
|
|
||||||
let hasPermissionOnSettingFeature = false;
|
|
||||||
|
|
||||||
if (!isDefined(roleOfUserWorkspace)) {
|
if (!isDefined(roleOfUserWorkspace)) {
|
||||||
throw new PermissionsException(
|
throw new PermissionsException(
|
||||||
PermissionsExceptionMessage.NO_ROLE_FOUND_FOR_USER_WORKSPACE,
|
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 =
|
const defaultSettingsPermissions =
|
||||||
this.getDefaultUserWorkspacePermissions().settingsPermissions;
|
this.getDefaultUserWorkspacePermissions().permissionFlags;
|
||||||
const settingsPermissions = Object.keys(PermissionFlagType).reduce(
|
const permissionFlags = Object.keys(PermissionFlagType).reduce(
|
||||||
(acc, feature) => ({
|
(acc, feature) => {
|
||||||
...acc,
|
const hasBasePermission = this.isToolPermission(feature)
|
||||||
[feature]:
|
? roleOfUserWorkspace.canAccessAllTools
|
||||||
hasPermissionOnSettingFeature ||
|
: roleOfUserWorkspace.canUpdateAllSettings;
|
||||||
permissionFlags.some(
|
|
||||||
(permissionFlag) => permissionFlag.flag === feature,
|
return {
|
||||||
),
|
...acc,
|
||||||
}),
|
[feature]:
|
||||||
|
hasBasePermission ||
|
||||||
|
roleOfUserWorkspace.permissionFlags.some(
|
||||||
|
(permissionFlag) => permissionFlag.flag === feature,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
},
|
||||||
defaultSettingsPermissions,
|
defaultSettingsPermissions,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -92,7 +95,7 @@ export class PermissionsService {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
settingsPermissions,
|
permissionFlags,
|
||||||
objectRecordsPermissions,
|
objectRecordsPermissions,
|
||||||
objectPermissions,
|
objectPermissions,
|
||||||
};
|
};
|
||||||
@ -106,7 +109,7 @@ export class PermissionsService {
|
|||||||
[PermissionsOnAllObjectRecords.SOFT_DELETE_ALL_OBJECT_RECORDS]: false,
|
[PermissionsOnAllObjectRecords.SOFT_DELETE_ALL_OBJECT_RECORDS]: false,
|
||||||
[PermissionsOnAllObjectRecords.DESTROY_ALL_OBJECT_RECORDS]: false,
|
[PermissionsOnAllObjectRecords.DESTROY_ALL_OBJECT_RECORDS]: false,
|
||||||
},
|
},
|
||||||
settingsPermissions: {
|
permissionFlags: {
|
||||||
[PermissionFlagType.API_KEYS_AND_WEBHOOKS]: false,
|
[PermissionFlagType.API_KEYS_AND_WEBHOOKS]: false,
|
||||||
[PermissionFlagType.WORKSPACE]: false,
|
[PermissionFlagType.WORKSPACE]: false,
|
||||||
[PermissionFlagType.WORKSPACE_MEMBERS]: false,
|
[PermissionFlagType.WORKSPACE_MEMBERS]: false,
|
||||||
@ -116,6 +119,8 @@ export class PermissionsService {
|
|||||||
[PermissionFlagType.SECURITY]: false,
|
[PermissionFlagType.SECURITY]: false,
|
||||||
[PermissionFlagType.WORKFLOWS]: false,
|
[PermissionFlagType.WORKFLOWS]: false,
|
||||||
[PermissionFlagType.SEND_EMAIL_TOOL]: false,
|
[PermissionFlagType.SEND_EMAIL_TOOL]: false,
|
||||||
|
[PermissionFlagType.IMPORT_CSV]: false,
|
||||||
|
[PermissionFlagType.EXPORT_CSV]: false,
|
||||||
},
|
},
|
||||||
objectPermissions: {},
|
objectPermissions: {},
|
||||||
}) as const satisfies UserWorkspacePermissions;
|
}) as const satisfies UserWorkspacePermissions;
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { ObjectRecordsPermissions } from 'twenty-shared/types';
|
|||||||
import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
|
import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
|
||||||
|
|
||||||
export type UserWorkspacePermissions = {
|
export type UserWorkspacePermissions = {
|
||||||
settingsPermissions: Record<PermissionFlagType, boolean>;
|
permissionFlags: Record<PermissionFlagType, boolean>;
|
||||||
objectRecordsPermissions: Record<PermissionsOnAllObjectRecords, boolean>;
|
objectRecordsPermissions: Record<PermissionsOnAllObjectRecords, boolean>;
|
||||||
objectPermissions: ObjectRecordsPermissions;
|
objectPermissions: ObjectRecordsPermissions;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -2,5 +2,5 @@ import { UserWorkspace } from 'src/engine/core-modules/user-workspace/user-works
|
|||||||
|
|
||||||
export type UserWorkspacePermissionsDto = Pick<
|
export type UserWorkspacePermissionsDto = Pick<
|
||||||
UserWorkspace,
|
UserWorkspace,
|
||||||
'objectPermissions' | 'settingsPermissions' | 'objectRecordsPermissions'
|
'objectPermissions' | 'permissionFlags' | 'objectRecordsPermissions'
|
||||||
>;
|
>;
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import { UserWorkspacePermissionsDto } from 'src/engine/metadata-modules/role/dt
|
|||||||
export const fromUserWorkspacePermissionsToUserWorkspacePermissionsDto = ({
|
export const fromUserWorkspacePermissionsToUserWorkspacePermissionsDto = ({
|
||||||
objectPermissions: rawObjectPermissions,
|
objectPermissions: rawObjectPermissions,
|
||||||
objectRecordsPermissions: rawObjectRecordsPermissions,
|
objectRecordsPermissions: rawObjectRecordsPermissions,
|
||||||
settingsPermissions: rawSettingsPermissions,
|
permissionFlags: rawSettingsPermissions,
|
||||||
}: UserWorkspacePermissions): UserWorkspacePermissionsDto => {
|
}: UserWorkspacePermissions): UserWorkspacePermissionsDto => {
|
||||||
const objectPermissions = Object.entries(rawObjectPermissions).map(
|
const objectPermissions = Object.entries(rawObjectPermissions).map(
|
||||||
([objectMetadataId, permissions]) => ({
|
([objectMetadataId, permissions]) => ({
|
||||||
@ -19,7 +19,7 @@ export const fromUserWorkspacePermissionsToUserWorkspacePermissionsDto = ({
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
const settingsPermissions = (
|
const permissionFlags = (
|
||||||
Object.keys(rawSettingsPermissions) as PermissionFlagType[]
|
Object.keys(rawSettingsPermissions) as PermissionFlagType[]
|
||||||
).filter((feature) => rawSettingsPermissions[feature] === true);
|
).filter((feature) => rawSettingsPermissions[feature] === true);
|
||||||
|
|
||||||
@ -30,6 +30,6 @@ export const fromUserWorkspacePermissionsToUserWorkspacePermissionsDto = ({
|
|||||||
return {
|
return {
|
||||||
objectPermissions,
|
objectPermissions,
|
||||||
objectRecordsPermissions,
|
objectRecordsPermissions,
|
||||||
settingsPermissions,
|
permissionFlags,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -110,6 +110,7 @@ export class DevSeederPermissionsService {
|
|||||||
'All permissions except read on Rockets and update on Pets',
|
'All permissions except read on Rockets and update on Pets',
|
||||||
icon: 'custom',
|
icon: 'custom',
|
||||||
canUpdateAllSettings: true,
|
canUpdateAllSettings: true,
|
||||||
|
canAccessAllTools: true,
|
||||||
canReadAllObjectRecords: true,
|
canReadAllObjectRecords: true,
|
||||||
canUpdateAllObjectRecords: true,
|
canUpdateAllObjectRecords: true,
|
||||||
canSoftDeleteAllObjectRecords: true,
|
canSoftDeleteAllObjectRecords: true,
|
||||||
|
|||||||
Reference in New Issue
Block a user