[permissions] Rename enum SettingsFeatures --> SettingsPermissions (#10389)

This commit is contained in:
Marie
2025-02-21 17:04:30 +01:00
committed by GitHub
parent bf92860d19
commit 50bd91262f
31 changed files with 119 additions and 109 deletions

View File

@ -1804,7 +1804,7 @@ export enum ServerlessFunctionSyncStatus {
READY = 'READY' READY = 'READY'
} }
export enum SettingsFeatures { export enum SettingsPermissions {
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',
@ -2130,7 +2130,7 @@ export type UserWorkspace = {
deletedAt?: Maybe<Scalars['DateTime']['output']>; deletedAt?: Maybe<Scalars['DateTime']['output']>;
id: Scalars['UUID']['output']; id: Scalars['UUID']['output'];
objectRecordsPermissions?: Maybe<Array<PermissionsOnAllObjectRecords>>; objectRecordsPermissions?: Maybe<Array<PermissionsOnAllObjectRecords>>;
settingsPermissions?: Maybe<Array<SettingsFeatures>>; settingsPermissions?: Maybe<Array<SettingsPermissions>>;
updatedAt: Scalars['DateTime']['output']; updatedAt: Scalars['DateTime']['output'];
user: User; user: User;
userId: Scalars['String']['output']; userId: Scalars['String']['output'];

View File

@ -1604,7 +1604,7 @@ export enum ServerlessFunctionSyncStatus {
READY = 'READY' READY = 'READY'
} }
export enum SettingsFeatures { export enum SettingsPermissions {
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',
@ -1916,7 +1916,7 @@ export type UserWorkspace = {
deletedAt?: Maybe<Scalars['DateTime']>; deletedAt?: Maybe<Scalars['DateTime']>;
id: Scalars['UUID']; id: Scalars['UUID'];
objectRecordsPermissions?: Maybe<Array<PermissionsOnAllObjectRecords>>; objectRecordsPermissions?: Maybe<Array<PermissionsOnAllObjectRecords>>;
settingsPermissions?: Maybe<Array<SettingsFeatures>>; settingsPermissions?: Maybe<Array<SettingsPermissions>>;
updatedAt: Scalars['DateTime']; updatedAt: Scalars['DateTime'];
user: User; user: User;
userId: Scalars['String']; userId: Scalars['String'];
@ -2434,7 +2434,7 @@ export type GetSsoIdentityProvidersQueryVariables = Exact<{ [key: string]: never
export type GetSsoIdentityProvidersQuery = { __typename?: 'Query', getSSOIdentityProviders: Array<{ __typename?: 'FindAvailableSSOIDPOutput', type: IdentityProviderType, id: string, name: string, issuer: string, status: SsoIdentityProviderStatus }> }; export type GetSsoIdentityProvidersQuery = { __typename?: 'Query', getSSOIdentityProviders: Array<{ __typename?: 'FindAvailableSSOIDPOutput', type: IdentityProviderType, id: string, name: string, issuer: string, status: SsoIdentityProviderStatus }> };
export type UserQueryFragmentFragment = { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, onboardingStatus?: OnboardingStatus | null, userVars: any, analyticsTinybirdJwts?: { __typename?: 'AnalyticsTinybirdJwtMap', getWebhookAnalytics: string, getPageviewsAnalytics: string, getUsersAnalytics: string, getServerlessFunctionDuration: string, getServerlessFunctionSuccessRate: string, getServerlessFunctionErrorCount: string } | 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, currentUserWorkspace?: { __typename?: 'UserWorkspace', settingsPermissions?: Array<SettingsFeatures> | null, objectRecordsPermissions?: Array<PermissionsOnAllObjectRecords> | 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, metadataVersion: number, workspaceMembersCount?: number | null, workspaceUrls: { __typename?: 'workspaceUrls', subdomainUrl: string, customUrl?: string | null }, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: FeatureFlagKey, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, interval?: SubscriptionInterval | null } | null, billingSubscriptions: Array<{ __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus }> } | null, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, subdomain: string, customDomain?: string | null, workspaceUrls: { __typename?: 'workspaceUrls', subdomainUrl: string, customUrl?: string | null } } | null }> }; export type UserQueryFragmentFragment = { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, onboardingStatus?: OnboardingStatus | null, userVars: any, analyticsTinybirdJwts?: { __typename?: 'AnalyticsTinybirdJwtMap', getWebhookAnalytics: string, getPageviewsAnalytics: string, getUsersAnalytics: string, getServerlessFunctionDuration: string, getServerlessFunctionSuccessRate: string, getServerlessFunctionErrorCount: string } | 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, currentUserWorkspace?: { __typename?: 'UserWorkspace', settingsPermissions?: Array<SettingsPermissions> | null, objectRecordsPermissions?: Array<PermissionsOnAllObjectRecords> | 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, metadataVersion: number, workspaceMembersCount?: number | null, workspaceUrls: { __typename?: 'workspaceUrls', subdomainUrl: string, customUrl?: string | null }, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: FeatureFlagKey, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, interval?: SubscriptionInterval | null } | null, billingSubscriptions: Array<{ __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus }> } | null, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, subdomain: string, customDomain?: string | null, workspaceUrls: { __typename?: 'workspaceUrls', subdomainUrl: string, customUrl?: string | null } } | null }> };
export type DeleteUserAccountMutationVariables = Exact<{ [key: string]: never; }>; export type DeleteUserAccountMutationVariables = Exact<{ [key: string]: never; }>;
@ -2451,7 +2451,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, canImpersonate: boolean, supportUserHash?: string | null, onboardingStatus?: OnboardingStatus | null, userVars: any, analyticsTinybirdJwts?: { __typename?: 'AnalyticsTinybirdJwtMap', getWebhookAnalytics: string, getPageviewsAnalytics: string, getUsersAnalytics: string, getServerlessFunctionDuration: string, getServerlessFunctionSuccessRate: string, getServerlessFunctionErrorCount: string } | 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, currentUserWorkspace?: { __typename?: 'UserWorkspace', settingsPermissions?: Array<SettingsFeatures> | null, objectRecordsPermissions?: Array<PermissionsOnAllObjectRecords> | 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, metadataVersion: number, workspaceMembersCount?: number | null, workspaceUrls: { __typename?: 'workspaceUrls', subdomainUrl: string, customUrl?: string | null }, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: FeatureFlagKey, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, interval?: SubscriptionInterval | null } | null, billingSubscriptions: Array<{ __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus }> } | null, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, subdomain: string, customDomain?: string | null, workspaceUrls: { __typename?: 'workspaceUrls', subdomainUrl: string, customUrl?: string | null } } | null }> } }; export type GetCurrentUserQuery = { __typename?: 'Query', currentUser: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, onboardingStatus?: OnboardingStatus | null, userVars: any, analyticsTinybirdJwts?: { __typename?: 'AnalyticsTinybirdJwtMap', getWebhookAnalytics: string, getPageviewsAnalytics: string, getUsersAnalytics: string, getServerlessFunctionDuration: string, getServerlessFunctionSuccessRate: string, getServerlessFunctionErrorCount: string } | 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, currentUserWorkspace?: { __typename?: 'UserWorkspace', settingsPermissions?: Array<SettingsPermissions> | null, objectRecordsPermissions?: Array<PermissionsOnAllObjectRecords> | 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, metadataVersion: number, workspaceMembersCount?: number | null, workspaceUrls: { __typename?: 'workspaceUrls', subdomainUrl: string, customUrl?: string | null }, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: FeatureFlagKey, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, interval?: SubscriptionInterval | null } | null, billingSubscriptions: Array<{ __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus }> } | null, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, subdomain: string, customDomain?: string | null, workspaceUrls: { __typename?: 'workspaceUrls', subdomainUrl: string, customUrl?: string | null } } | null }> } };
export type ActivateWorkflowVersionMutationVariables = Exact<{ export type ActivateWorkflowVersionMutationVariables = Exact<{
workflowVersionId: Scalars['String']; workflowVersionId: Scalars['String'];

View File

@ -4,7 +4,7 @@ import { Route, Routes } from 'react-router-dom';
import { SettingsProtectedRouteWrapper } from '@/settings/components/SettingsProtectedRouteWrapper'; import { SettingsProtectedRouteWrapper } from '@/settings/components/SettingsProtectedRouteWrapper';
import { SettingsSkeletonLoader } from '@/settings/components/SettingsSkeletonLoader'; import { SettingsSkeletonLoader } from '@/settings/components/SettingsSkeletonLoader';
import { SettingsPath } from '@/types/SettingsPath'; import { SettingsPath } from '@/types/SettingsPath';
import { SettingsFeatures } from 'twenty-shared'; import { SettingsPermissions } from 'twenty-shared';
import { FeatureFlagKey } from '~/generated-metadata/graphql'; import { FeatureFlagKey } from '~/generated-metadata/graphql';
const SettingsAccountsCalendars = lazy(() => const SettingsAccountsCalendars = lazy(() =>
@ -308,7 +308,7 @@ export const SettingsRoutes = ({
<Route <Route
element={ element={
<SettingsProtectedRouteWrapper <SettingsProtectedRouteWrapper
settingsPermission={SettingsFeatures.WORKSPACE} settingsPermission={SettingsPermissions.WORKSPACE}
/> />
} }
> >
@ -323,7 +323,7 @@ export const SettingsRoutes = ({
<Route <Route
element={ element={
<SettingsProtectedRouteWrapper <SettingsProtectedRouteWrapper
settingsPermission={SettingsFeatures.DATA_MODEL} settingsPermission={SettingsPermissions.DATA_MODEL}
/> />
} }
> >
@ -341,7 +341,7 @@ export const SettingsRoutes = ({
<Route <Route
element={ element={
<SettingsProtectedRouteWrapper <SettingsProtectedRouteWrapper
settingsPermission={SettingsFeatures.ROLES} settingsPermission={SettingsPermissions.ROLES}
requiredFeatureFlag={FeatureFlagKey.IsPermissionsEnabled} requiredFeatureFlag={FeatureFlagKey.IsPermissionsEnabled}
/> />
} }
@ -437,7 +437,7 @@ export const SettingsRoutes = ({
<Route <Route
element={ element={
<SettingsProtectedRouteWrapper <SettingsProtectedRouteWrapper
settingsPermission={SettingsFeatures.WORKSPACE} settingsPermission={SettingsPermissions.WORKSPACE}
/> />
} }
> >

View File

@ -12,7 +12,7 @@ import { ViewType } from '@/views/types/ViewType';
import { useCallback, useContext } from 'react'; import { useCallback, useContext } from 'react';
import { useLocation } from 'react-router-dom'; import { useLocation } from 'react-router-dom';
import { useSetRecoilState } from 'recoil'; import { useSetRecoilState } from 'recoil';
import { isDefined, SettingsFeatures } from 'twenty-shared'; import { isDefined, SettingsPermissions } from 'twenty-shared';
import { IconEyeOff, IconSettings } from 'twenty-ui'; import { IconEyeOff, IconSettings } from 'twenty-ui';
import { useNavigateSettings } from '~/hooks/useNavigateSettings'; import { useNavigateSettings } from '~/hooks/useNavigateSettings';
@ -71,7 +71,7 @@ export const useRecordGroupActions = ({
]); ]);
const hasAccessToDataModelSettings = useHasSettingsPermission( const hasAccessToDataModelSettings = useHasSettingsPermission(
SettingsFeatures.DATA_MODEL, SettingsPermissions.DATA_MODEL,
); );
const recordGroupActions: RecordGroupAction[] = []; const recordGroupActions: RecordGroupAction[] = [];

View File

@ -3,12 +3,12 @@ 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';
import { Navigate, Outlet } from 'react-router-dom'; import { Navigate, Outlet } from 'react-router-dom';
import { FeatureFlagKey, SettingsFeatures } from '~/generated/graphql'; import { FeatureFlagKey, SettingsPermissions } from '~/generated/graphql';
import { getSettingsPath } from '~/utils/navigation/getSettingsPath'; import { getSettingsPath } from '~/utils/navigation/getSettingsPath';
type SettingsProtectedRouteWrapperProps = { type SettingsProtectedRouteWrapperProps = {
children?: ReactNode; children?: ReactNode;
settingsPermission?: SettingsFeatures; settingsPermission?: SettingsPermissions;
requiredFeatureFlag?: FeatureFlagKey; requiredFeatureFlag?: FeatureFlagKey;
}; };

View File

@ -4,7 +4,7 @@ import { renderHook } from '@testing-library/react';
import { ReactNode } from 'react'; import { ReactNode } from 'react';
import { MemoryRouter } from 'react-router-dom'; import { MemoryRouter } from 'react-router-dom';
import { MutableSnapshot, RecoilRoot } from 'recoil'; import { MutableSnapshot, RecoilRoot } from 'recoil';
import { SettingsFeatures } from 'twenty-shared'; import { SettingsPermissions } from 'twenty-shared';
import { Billing, FeatureFlagKey, OnboardingStatus } from '~/generated/graphql'; import { Billing, FeatureFlagKey, OnboardingStatus } from '~/generated/graphql';
import { currentUserState } from '@/auth/states/currentUserState'; import { currentUserState } from '@/auth/states/currentUserState';
@ -56,12 +56,12 @@ jest.mock('@/workspace/hooks/useFeatureFlagsMap', () => ({
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(() => ({ (useSettingsPermissionMap as jest.Mock).mockImplementation(() => ({
[SettingsFeatures.WORKSPACE]: false, [SettingsPermissions.WORKSPACE]: false,
[SettingsFeatures.WORKSPACE_USERS]: false, [SettingsPermissions.WORKSPACE_USERS]: false,
[SettingsFeatures.DATA_MODEL]: false, [SettingsPermissions.DATA_MODEL]: false,
[SettingsFeatures.API_KEYS_AND_WEBHOOKS]: false, [SettingsPermissions.API_KEYS_AND_WEBHOOKS]: false,
[SettingsFeatures.ROLES]: false, [SettingsPermissions.ROLES]: false,
[SettingsFeatures.SECURITY]: false, [SettingsPermissions.SECURITY]: false,
})); }));
const { result } = renderHook(() => useSettingsNavigationItems(), { const { result } = renderHook(() => useSettingsNavigationItems(), {
@ -77,12 +77,12 @@ describe('useSettingsNavigationItems', () => {
it('should show workspace settings when has permissions', () => { it('should show workspace settings when has permissions', () => {
(useSettingsPermissionMap as jest.Mock).mockImplementation(() => ({ (useSettingsPermissionMap as jest.Mock).mockImplementation(() => ({
[SettingsFeatures.WORKSPACE]: true, [SettingsPermissions.WORKSPACE]: true,
[SettingsFeatures.WORKSPACE_USERS]: true, [SettingsPermissions.WORKSPACE_USERS]: true,
[SettingsFeatures.DATA_MODEL]: true, [SettingsPermissions.DATA_MODEL]: true,
[SettingsFeatures.API_KEYS_AND_WEBHOOKS]: true, [SettingsPermissions.API_KEYS_AND_WEBHOOKS]: true,
[SettingsFeatures.ROLES]: true, [SettingsPermissions.ROLES]: true,
[SettingsFeatures.SECURITY]: true, [SettingsPermissions.SECURITY]: true,
})); }));
const { result } = renderHook(() => useSettingsNavigationItems(), { const { result } = renderHook(() => useSettingsNavigationItems(), {

View File

@ -20,7 +20,7 @@ import {
} from 'twenty-ui'; } from 'twenty-ui';
import { SettingsPath } from '@/types/SettingsPath'; import { SettingsPath } from '@/types/SettingsPath';
import { SettingsFeatures } from 'twenty-shared'; import { SettingsPermissions } from 'twenty-shared';
import { FeatureFlagKey } from '~/generated-metadata/graphql'; import { FeatureFlagKey } from '~/generated-metadata/graphql';
import { currentUserState } from '@/auth/states/currentUserState'; import { currentUserState } from '@/auth/states/currentUserState';
@ -105,20 +105,20 @@ const useSettingsNavigationItems = (): SettingsNavigationSection[] => {
label: t`General`, label: t`General`,
path: SettingsPath.Workspace, path: SettingsPath.Workspace,
Icon: IconSettings, Icon: IconSettings,
isHidden: !permissionMap[SettingsFeatures.WORKSPACE], isHidden: !permissionMap[SettingsPermissions.WORKSPACE],
}, },
{ {
label: t`Members`, label: t`Members`,
path: SettingsPath.WorkspaceMembersPage, path: SettingsPath.WorkspaceMembersPage,
Icon: IconUsers, Icon: IconUsers,
isHidden: !permissionMap[SettingsFeatures.WORKSPACE_USERS], isHidden: !permissionMap[SettingsPermissions.WORKSPACE_USERS],
}, },
{ {
label: t`Billing`, label: t`Billing`,
path: SettingsPath.Billing, path: SettingsPath.Billing,
Icon: IconCurrencyDollar, Icon: IconCurrencyDollar,
isHidden: isHidden:
!isBillingEnabled || !permissionMap[SettingsFeatures.WORKSPACE], !isBillingEnabled || !permissionMap[SettingsPermissions.WORKSPACE],
}, },
{ {
label: t`Roles`, label: t`Roles`,
@ -126,26 +126,26 @@ const useSettingsNavigationItems = (): SettingsNavigationSection[] => {
Icon: IconLock, Icon: IconLock,
isHidden: isHidden:
!featureFlags[FeatureFlagKey.IsPermissionsEnabled] || !featureFlags[FeatureFlagKey.IsPermissionsEnabled] ||
!permissionMap[SettingsFeatures.ROLES], !permissionMap[SettingsPermissions.ROLES],
}, },
{ {
label: t`Data model`, label: t`Data model`,
path: SettingsPath.Objects, path: SettingsPath.Objects,
Icon: IconHierarchy2, Icon: IconHierarchy2,
isHidden: !permissionMap[SettingsFeatures.DATA_MODEL], isHidden: !permissionMap[SettingsPermissions.DATA_MODEL],
}, },
{ {
label: t`Integrations`, label: t`Integrations`,
path: SettingsPath.Integrations, path: SettingsPath.Integrations,
Icon: IconApps, Icon: IconApps,
isHidden: !permissionMap[SettingsFeatures.API_KEYS_AND_WEBHOOKS], isHidden: !permissionMap[SettingsPermissions.API_KEYS_AND_WEBHOOKS],
}, },
{ {
label: t`Security`, label: t`Security`,
path: SettingsPath.Security, path: SettingsPath.Security,
Icon: IconKey, Icon: IconKey,
isAdvanced: true, isAdvanced: true,
isHidden: !permissionMap[SettingsFeatures.SECURITY], isHidden: !permissionMap[SettingsPermissions.SECURITY],
}, },
], ],
}, },
@ -158,7 +158,7 @@ const useSettingsNavigationItems = (): SettingsNavigationSection[] => {
path: SettingsPath.Developers, path: SettingsPath.Developers,
Icon: IconCode, Icon: IconCode,
isAdvanced: true, isAdvanced: true,
isHidden: !permissionMap[SettingsFeatures.API_KEYS_AND_WEBHOOKS], isHidden: !permissionMap[SettingsPermissions.API_KEYS_AND_WEBHOOKS],
}, },
{ {
label: t`Functions`, label: t`Functions`,
@ -184,7 +184,7 @@ const useSettingsNavigationItems = (): SettingsNavigationSection[] => {
Icon: IconFlask, Icon: IconFlask,
isHidden: isHidden:
!labPublicFeatureFlags.length || !labPublicFeatureFlags.length ||
!permissionMap[SettingsFeatures.WORKSPACE], !permissionMap[SettingsPermissions.WORKSPACE],
}, },
{ {
label: t`Releases`, label: t`Releases`,

View File

@ -1,9 +1,9 @@
import { currentUserWorkspaceState } from '@/auth/states/currentUserWorkspaceState'; import { currentUserWorkspaceState } from '@/auth/states/currentUserWorkspaceState';
import { useRecoilValue } from 'recoil'; import { useRecoilValue } from 'recoil';
import { SettingsFeatures } from 'twenty-shared'; import { SettingsPermissions } from 'twenty-shared';
export const useHasSettingsPermission = ( export const useHasSettingsPermission = (
settingsPermission?: SettingsFeatures, settingsPermission?: SettingsPermissions,
) => { ) => {
const currentUserWorkspace = useRecoilValue(currentUserWorkspaceState); const currentUserWorkspace = useRecoilValue(currentUserWorkspaceState);

View File

@ -1,12 +1,12 @@
import { currentUserWorkspaceState } from '@/auth/states/currentUserWorkspaceState'; import { currentUserWorkspaceState } from '@/auth/states/currentUserWorkspaceState';
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import { useRecoilValue } from 'recoil'; import { useRecoilValue } from 'recoil';
import { SettingsFeatures } from 'twenty-shared'; import { SettingsPermissions } from 'twenty-shared';
import { FeatureFlagKey } from '~/generated-metadata/graphql'; import { FeatureFlagKey } from '~/generated-metadata/graphql';
import { buildRecordFromKeysWithSameValue } from '~/utils/array/buildRecordFromKeysWithSameValue'; import { buildRecordFromKeysWithSameValue } from '~/utils/array/buildRecordFromKeysWithSameValue';
export const useSettingsPermissionMap = (): Record< export const useSettingsPermissionMap = (): Record<
SettingsFeatures, SettingsPermissions,
boolean boolean
> => { > => {
const currentUserWorkspace = useRecoilValue(currentUserWorkspaceState); const currentUserWorkspace = useRecoilValue(currentUserWorkspaceState);
@ -19,7 +19,7 @@ export const useSettingsPermissionMap = (): Record<
currentUserWorkspace?.settingsPermissions; currentUserWorkspace?.settingsPermissions;
const initialPermissions = buildRecordFromKeysWithSameValue( const initialPermissions = buildRecordFromKeysWithSameValue(
Object.values(SettingsFeatures), Object.values(SettingsPermissions),
!isPermissionEnabled, !isPermissionEnabled,
); );

View File

@ -8,7 +8,7 @@ import {
IconTrashX, IconTrashX,
Section, Section,
} from 'twenty-ui'; } from 'twenty-ui';
import { Role, SettingsFeatures } from '~/generated-metadata/graphql'; import { Role, SettingsPermissions } from '~/generated-metadata/graphql';
import { RolePermissionsObjectsTableHeader } from '~/pages/settings/roles/components/RolePermissionsObjectsTableHeader'; import { RolePermissionsObjectsTableHeader } from '~/pages/settings/roles/components/RolePermissionsObjectsTableHeader';
import { RolePermissionsSettingsTableHeader } from '~/pages/settings/roles/components/RolePermissionsSettingsTableHeader'; import { RolePermissionsSettingsTableHeader } from '~/pages/settings/roles/components/RolePermissionsSettingsTableHeader';
import { RolePermissionsSettingsTableRow } from '~/pages/settings/roles/components/RolePermissionsSettingsTableRow'; import { RolePermissionsSettingsTableRow } from '~/pages/settings/roles/components/RolePermissionsSettingsTableRow';
@ -63,43 +63,43 @@ export const RolePermissions = ({ role }: RolePermissionsProps) => {
const settingsPermissionsConfig = [ const settingsPermissionsConfig = [
{ {
key: SettingsFeatures.API_KEYS_AND_WEBHOOKS, key: SettingsPermissions.API_KEYS_AND_WEBHOOKS,
label: 'API Keys and Webhooks', label: 'API Keys and Webhooks',
type: 'Developer', type: 'Developer',
value: role.canUpdateAllSettings, value: role.canUpdateAllSettings,
}, },
{ {
key: SettingsFeatures.ROLES, key: SettingsPermissions.ROLES,
label: 'Roles', label: 'Roles',
type: 'Members', type: 'Members',
value: role.canUpdateAllSettings, value: role.canUpdateAllSettings,
}, },
{ {
key: SettingsFeatures.WORKSPACE, key: SettingsPermissions.WORKSPACE,
label: 'Workspace Settings', label: 'Workspace Settings',
type: 'General', type: 'General',
value: role.canUpdateAllSettings, value: role.canUpdateAllSettings,
}, },
{ {
key: SettingsFeatures.WORKSPACE_USERS, key: SettingsPermissions.WORKSPACE_USERS,
label: 'Workspace Users', label: 'Workspace Users',
type: 'Members', type: 'Members',
value: role.canUpdateAllSettings, value: role.canUpdateAllSettings,
}, },
{ {
key: SettingsFeatures.DATA_MODEL, key: SettingsPermissions.DATA_MODEL,
label: 'Data Model', label: 'Data Model',
type: 'Data Model', type: 'Data Model',
value: role.canUpdateAllSettings, value: role.canUpdateAllSettings,
}, },
{ {
key: SettingsFeatures.ADMIN_PANEL, key: SettingsPermissions.ADMIN_PANEL,
label: 'Admin Panel', label: 'Admin Panel',
type: 'Admin Panel', type: 'Admin Panel',
value: role.canUpdateAllSettings, value: role.canUpdateAllSettings,
}, },
{ {
key: SettingsFeatures.SECURITY, key: SettingsPermissions.SECURITY,
label: 'Security Settings', label: 'Security Settings',
type: 'Security', type: 'Security',
value: role.canUpdateAllSettings, value: role.canUpdateAllSettings,

View File

@ -3,7 +3,7 @@ import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember';
import { import {
FeatureFlagKey, FeatureFlagKey,
OnboardingStatus, OnboardingStatus,
SettingsFeatures, SettingsPermissions,
SubscriptionInterval, SubscriptionInterval,
SubscriptionStatus, SubscriptionStatus,
User, User,
@ -129,7 +129,7 @@ export const mockedUserData: MockedUser = {
workspaceMember: mockedWorkspaceMemberData, workspaceMember: mockedWorkspaceMemberData,
currentWorkspace: mockCurrentWorkspace, currentWorkspace: mockCurrentWorkspace,
currentUserWorkspace: { currentUserWorkspace: {
settingsPermissions: [SettingsFeatures.WORKSPACE_USERS], settingsPermissions: [SettingsPermissions.WORKSPACE_USERS],
}, },
locale: 'en', locale: 'en',
workspaces: [{ workspace: mockCurrentWorkspace }], workspaces: [{ workspace: mockCurrentWorkspace }],

View File

@ -1,6 +1,6 @@
import { SettingsFeatures } from 'twenty-shared'; import { SettingsPermissions } from 'twenty-shared';
export const SYSTEM_OBJECTS_PERMISSIONS_REQUIREMENTS = { export const SYSTEM_OBJECTS_PERMISSIONS_REQUIREMENTS = {
apiKey: SettingsFeatures.API_KEYS_AND_WEBHOOKS, apiKey: SettingsPermissions.API_KEYS_AND_WEBHOOKS,
webhook: SettingsFeatures.API_KEYS_AND_WEBHOOKS, webhook: SettingsPermissions.API_KEYS_AND_WEBHOOKS,
} as const; } as const;

View File

@ -5,7 +5,7 @@ import {
capitalize, capitalize,
isObjectRecordUnderObjectRecordsPermissions, isObjectRecordUnderObjectRecordsPermissions,
PermissionsOnAllObjectRecords, PermissionsOnAllObjectRecords,
SettingsFeatures, SettingsPermissions,
} from 'twenty-shared'; } from 'twenty-shared';
import { DataSource, ObjectLiteral } from 'typeorm'; import { DataSource, ObjectLiteral } from 'typeorm';
@ -208,7 +208,7 @@ export abstract class GraphqlQueryBaseResolverService<
); );
} }
const permissionRequired: SettingsFeatures = const permissionRequired: SettingsPermissions =
SYSTEM_OBJECTS_PERMISSIONS_REQUIREMENTS[ SYSTEM_OBJECTS_PERMISSIONS_REQUIREMENTS[
objectMetadataItemWithFieldMaps.nameSingular objectMetadataItemWithFieldMaps.nameSingular
]; ];

View File

@ -2,7 +2,7 @@ import { UseFilters, UseGuards } from '@nestjs/common';
import { Args, Context, Mutation, Query, Resolver } from '@nestjs/graphql'; import { Args, Context, Mutation, Query, Resolver } from '@nestjs/graphql';
import { InjectRepository } from '@nestjs/typeorm'; import { InjectRepository } from '@nestjs/typeorm';
import { SettingsFeatures, SOURCE_LOCALE } from 'twenty-shared'; import { SettingsPermissions, SOURCE_LOCALE } from 'twenty-shared';
import { Repository } from 'typeorm'; import { Repository } from 'typeorm';
import omit from 'lodash.omit'; import omit from 'lodash.omit';
@ -342,7 +342,7 @@ export class AuthResolver {
@UseGuards( @UseGuards(
WorkspaceAuthGuard, WorkspaceAuthGuard,
SettingsPermissionsGuard(SettingsFeatures.API_KEYS_AND_WEBHOOKS), SettingsPermissionsGuard(SettingsPermissions.API_KEYS_AND_WEBHOOKS),
) )
@Mutation(() => ApiKeyToken) @Mutation(() => ApiKeyToken)
async generateApiKeyToken( async generateApiKeyToken(

View File

@ -4,7 +4,7 @@ import { UseFilters, UseGuards } from '@nestjs/common';
import { Args, Mutation, Query, Resolver } from '@nestjs/graphql'; import { Args, Mutation, Query, Resolver } from '@nestjs/graphql';
import { GraphQLError } from 'graphql'; import { GraphQLError } from 'graphql';
import { SettingsFeatures } from 'twenty-shared'; import { SettingsPermissions } from 'twenty-shared';
import { BillingCheckoutSessionInput } from 'src/engine/core-modules/billing/dtos/inputs/billing-checkout-session.input'; import { BillingCheckoutSessionInput } from 'src/engine/core-modules/billing/dtos/inputs/billing-checkout-session.input';
import { BillingProductInput } from 'src/engine/core-modules/billing/dtos/inputs/billing-product.input'; import { BillingProductInput } from 'src/engine/core-modules/billing/dtos/inputs/billing-product.input';
@ -71,7 +71,7 @@ export class BillingResolver {
@Query(() => BillingSessionOutput) @Query(() => BillingSessionOutput)
@UseGuards( @UseGuards(
WorkspaceAuthGuard, WorkspaceAuthGuard,
SettingsPermissionsGuard(SettingsFeatures.WORKSPACE), SettingsPermissionsGuard(SettingsPermissions.WORKSPACE),
) )
async billingPortalSession( async billingPortalSession(
@AuthWorkspace() workspace: Workspace, @AuthWorkspace() workspace: Workspace,
@ -158,7 +158,7 @@ export class BillingResolver {
@Mutation(() => BillingUpdateOutput) @Mutation(() => BillingUpdateOutput)
@UseGuards( @UseGuards(
WorkspaceAuthGuard, WorkspaceAuthGuard,
SettingsPermissionsGuard(SettingsFeatures.WORKSPACE), SettingsPermissionsGuard(SettingsPermissions.WORKSPACE),
) )
async updateBillingSubscription(@AuthWorkspace() workspace: Workspace) { async updateBillingSubscription(@AuthWorkspace() workspace: Workspace) {
await this.billingSubscriptionService.applyBillingSubscription(workspace); await this.billingSubscriptionService.applyBillingSubscription(workspace);
@ -202,7 +202,7 @@ export class BillingResolver {
await this.permissionsService.userHasWorkspaceSettingPermission({ await this.permissionsService.userHasWorkspaceSettingPermission({
userWorkspaceId, userWorkspaceId,
workspaceId, workspaceId,
_setting: SettingsFeatures.WORKSPACE, _setting: SettingsPermissions.WORKSPACE,
}); });
if (!userHasPermission) { if (!userHasPermission) {

View File

@ -1,7 +1,7 @@
import { UseFilters, UseGuards } from '@nestjs/common'; import { UseFilters, UseGuards } from '@nestjs/common';
import { Args, Mutation, Resolver } from '@nestjs/graphql'; import { Args, Mutation, Resolver } from '@nestjs/graphql';
import { SettingsFeatures } from 'twenty-shared'; import { SettingsPermissions } from 'twenty-shared';
import { AuthGraphqlApiExceptionFilter } from 'src/engine/core-modules/auth/filters/auth-graphql-api-exception.filter'; import { AuthGraphqlApiExceptionFilter } from 'src/engine/core-modules/auth/filters/auth-graphql-api-exception.filter';
import { FeatureFlag } from 'src/engine/core-modules/feature-flag/feature-flag.entity'; import { FeatureFlag } from 'src/engine/core-modules/feature-flag/feature-flag.entity';
@ -15,7 +15,7 @@ import { PermissionsGraphqlApiExceptionFilter } from 'src/engine/metadata-module
@Resolver() @Resolver()
@UseFilters(AuthGraphqlApiExceptionFilter, PermissionsGraphqlApiExceptionFilter) @UseFilters(AuthGraphqlApiExceptionFilter, PermissionsGraphqlApiExceptionFilter)
@UseGuards(SettingsPermissionsGuard(SettingsFeatures.WORKSPACE)) @UseGuards(SettingsPermissionsGuard(SettingsPermissions.WORKSPACE))
export class LabResolver { export class LabResolver {
constructor(private labService: LabService) {} constructor(private labService: LabService) {}

View File

@ -3,7 +3,7 @@
import { UseFilters, UseGuards } from '@nestjs/common'; import { UseFilters, UseGuards } from '@nestjs/common';
import { Args, Mutation, Query, Resolver } from '@nestjs/graphql'; import { Args, Mutation, Query, Resolver } from '@nestjs/graphql';
import { SettingsFeatures } from 'twenty-shared'; import { SettingsPermissions } from 'twenty-shared';
import { EnterpriseFeaturesEnabledGuard } from 'src/engine/core-modules/auth/guards/enterprise-features-enabled.guard'; import { EnterpriseFeaturesEnabledGuard } from 'src/engine/core-modules/auth/guards/enterprise-features-enabled.guard';
import { DeleteSsoInput } from 'src/engine/core-modules/sso/dtos/delete-sso.input'; import { DeleteSsoInput } from 'src/engine/core-modules/sso/dtos/delete-sso.input';
@ -26,7 +26,7 @@ import { PermissionsGraphqlApiExceptionFilter } from 'src/engine/metadata-module
@Resolver() @Resolver()
@UseFilters(PermissionsGraphqlApiExceptionFilter) @UseFilters(PermissionsGraphqlApiExceptionFilter)
@UseGuards(SettingsPermissionsGuard(SettingsFeatures.SECURITY)) @UseGuards(SettingsPermissionsGuard(SettingsPermissions.SECURITY))
export class SSOResolver { export class SSOResolver {
constructor(private readonly sSOService: SSOService) {} constructor(private readonly sSOService: SSOService) {}

View File

@ -1,7 +1,10 @@
import { Field, ObjectType, registerEnumType } from '@nestjs/graphql'; import { Field, ObjectType, registerEnumType } from '@nestjs/graphql';
import { IDField } from '@ptc-org/nestjs-query-graphql'; import { IDField } from '@ptc-org/nestjs-query-graphql';
import { PermissionsOnAllObjectRecords, SettingsFeatures } from 'twenty-shared'; import {
PermissionsOnAllObjectRecords,
SettingsPermissions,
} from 'twenty-shared';
import { import {
Column, Column,
CreateDateColumn, CreateDateColumn,
@ -21,8 +24,8 @@ import { TwoFactorMethod } from 'src/engine/core-modules/two-factor-method/two-f
import { User } from 'src/engine/core-modules/user/user.entity'; import { User } from 'src/engine/core-modules/user/user.entity';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
registerEnumType(SettingsFeatures, { registerEnumType(SettingsPermissions, {
name: 'SettingsFeatures', name: 'SettingsPermissions',
}); });
registerEnumType(PermissionsOnAllObjectRecords, { registerEnumType(PermissionsOnAllObjectRecords, {
@ -77,8 +80,8 @@ export class UserWorkspace {
) )
twoFactorMethods: Relation<TwoFactorMethod[]>; twoFactorMethods: Relation<TwoFactorMethod[]>;
@Field(() => [SettingsFeatures], { nullable: true }) @Field(() => [SettingsPermissions], { nullable: true })
settingsPermissions?: SettingsFeatures[]; settingsPermissions?: SettingsPermissions[];
@Field(() => [PermissionsOnAllObjectRecords], { nullable: true }) @Field(() => [PermissionsOnAllObjectRecords], { nullable: true })
objectRecordsPermissions?: PermissionsOnAllObjectRecords[]; objectRecordsPermissions?: PermissionsOnAllObjectRecords[];

View File

@ -13,7 +13,10 @@ import crypto from 'crypto';
import { GraphQLJSONObject } from 'graphql-type-json'; import { GraphQLJSONObject } from 'graphql-type-json';
import { FileUpload, GraphQLUpload } from 'graphql-upload'; import { FileUpload, GraphQLUpload } from 'graphql-upload';
import { PermissionsOnAllObjectRecords, SettingsFeatures } from 'twenty-shared'; import {
PermissionsOnAllObjectRecords,
SettingsPermissions,
} from 'twenty-shared';
import { In, Repository } from 'typeorm'; import { In, Repository } from 'typeorm';
import { SupportDriver } from 'src/engine/core-modules/environment/interfaces/support.interface'; import { SupportDriver } from 'src/engine/core-modules/environment/interfaces/support.interface';
@ -119,17 +122,17 @@ export class UserResolver {
workspaceId: workspace.id, workspaceId: workspace.id,
}); });
const permittedFeatures: SettingsFeatures[] = ( const grantedSettingsPermissions: SettingsPermissions[] = (
Object.keys(settingsPermissions) as SettingsFeatures[] Object.keys(settingsPermissions) as SettingsPermissions[]
).filter((feature) => settingsPermissions[feature] === true); ).filter((feature) => settingsPermissions[feature] === true);
const permittedObjectRecordsPermissions = ( const grantedObjectRecordsPermissions = (
Object.keys(objectRecordsPermissions) as PermissionsOnAllObjectRecords[] Object.keys(objectRecordsPermissions) as PermissionsOnAllObjectRecords[]
).filter((permission) => objectRecordsPermissions[permission] === true); ).filter((permission) => objectRecordsPermissions[permission] === true);
currentUserWorkspace.settingsPermissions = permittedFeatures; currentUserWorkspace.settingsPermissions = grantedSettingsPermissions;
currentUserWorkspace.objectRecordsPermissions = currentUserWorkspace.objectRecordsPermissions =
permittedObjectRecordsPermissions; grantedObjectRecordsPermissions;
user.currentUserWorkspace = currentUserWorkspace; user.currentUserWorkspace = currentUserWorkspace;
} }

View File

@ -6,7 +6,7 @@ import assert from 'assert';
import { TypeOrmQueryService } from '@ptc-org/nestjs-query-typeorm'; import { TypeOrmQueryService } from '@ptc-org/nestjs-query-typeorm';
import { import {
isDefined, isDefined,
SettingsFeatures, SettingsPermissions,
WorkspaceActivationStatus, WorkspaceActivationStatus,
} from 'twenty-shared'; } from 'twenty-shared';
import { Repository } from 'typeorm'; import { Repository } from 'typeorm';
@ -416,7 +416,7 @@ export class WorkspaceService extends TypeOrmQueryService<Workspace> {
const userHasPermission = const userHasPermission =
await this.permissionsService.userHasWorkspaceSettingPermission({ await this.permissionsService.userHasWorkspaceSettingPermission({
userWorkspaceId, userWorkspaceId,
_setting: SettingsFeatures.SECURITY, _setting: SettingsPermissions.SECURITY,
workspaceId: workspaceId, workspaceId: workspaceId,
}); });
@ -452,7 +452,7 @@ export class WorkspaceService extends TypeOrmQueryService<Workspace> {
await this.permissionsService.userHasWorkspaceSettingPermission({ await this.permissionsService.userHasWorkspaceSettingPermission({
userWorkspaceId, userWorkspaceId,
workspaceId, workspaceId,
_setting: SettingsFeatures.WORKSPACE, _setting: SettingsPermissions.WORKSPACE,
}); });
if (!userHasPermission) { if (!userHasPermission) {

View File

@ -12,7 +12,7 @@ import { InjectRepository } from '@nestjs/typeorm';
import assert from 'assert'; import assert from 'assert';
import { FileUpload, GraphQLUpload } from 'graphql-upload'; import { FileUpload, GraphQLUpload } from 'graphql-upload';
import { isDefined, SettingsFeatures } from 'twenty-shared'; import { isDefined, SettingsPermissions } from 'twenty-shared';
import { Repository } from 'typeorm'; import { Repository } from 'typeorm';
import { FileFolder } from 'src/engine/core-modules/file/interfaces/file-folder.interface'; import { FileFolder } from 'src/engine/core-modules/file/interfaces/file-folder.interface';
@ -123,7 +123,7 @@ export class WorkspaceResolver {
@Mutation(() => String) @Mutation(() => String)
@UseGuards( @UseGuards(
WorkspaceAuthGuard, WorkspaceAuthGuard,
SettingsPermissionsGuard(SettingsFeatures.WORKSPACE), SettingsPermissionsGuard(SettingsPermissions.WORKSPACE),
) )
async uploadWorkspaceLogo( async uploadWorkspaceLogo(
@AuthWorkspace() { id }: Workspace, @AuthWorkspace() { id }: Workspace,
@ -167,7 +167,7 @@ export class WorkspaceResolver {
@Mutation(() => Workspace) @Mutation(() => Workspace)
@UseGuards( @UseGuards(
WorkspaceAuthGuard, WorkspaceAuthGuard,
SettingsPermissionsGuard(SettingsFeatures.WORKSPACE), SettingsPermissionsGuard(SettingsPermissions.WORKSPACE),
) )
async deleteCurrentWorkspace(@AuthWorkspace() { id }: Workspace) { async deleteCurrentWorkspace(@AuthWorkspace() { id }: Workspace) {
return this.workspaceService.deleteWorkspace(id); return this.workspaceService.deleteWorkspace(id);

View File

@ -7,7 +7,7 @@ import {
} from '@nestjs/common'; } from '@nestjs/common';
import { GqlExecutionContext } from '@nestjs/graphql'; import { GqlExecutionContext } from '@nestjs/graphql';
import { SettingsFeatures } from 'twenty-shared'; import { SettingsPermissions } from 'twenty-shared';
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum'; import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service'; import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
@ -19,7 +19,7 @@ import {
import { PermissionsService } from 'src/engine/metadata-modules/permissions/permissions.service'; import { PermissionsService } from 'src/engine/metadata-modules/permissions/permissions.service';
export const SettingsPermissionsGuard = ( export const SettingsPermissionsGuard = (
requiredPermission: SettingsFeatures, requiredPermission: SettingsPermissions,
): Type<CanActivate> => { ): Type<CanActivate> => {
@Injectable() @Injectable()
class SettingsPermissionsMixin implements CanActivate { class SettingsPermissionsMixin implements CanActivate {

View File

@ -13,7 +13,7 @@ import {
Resolver, Resolver,
} from '@nestjs/graphql'; } from '@nestjs/graphql';
import { FieldMetadataType, SettingsFeatures } from 'twenty-shared'; import { FieldMetadataType, SettingsPermissions } from 'twenty-shared';
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum'; import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service'; import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
@ -72,7 +72,7 @@ export class FieldMetadataResolver {
); );
} }
@UseGuards(SettingsPermissionsGuard(SettingsFeatures.DATA_MODEL)) @UseGuards(SettingsPermissionsGuard(SettingsPermissions.DATA_MODEL))
@Mutation(() => FieldMetadataDTO) @Mutation(() => FieldMetadataDTO)
async createOneField( async createOneField(
@Args('input') input: CreateOneFieldMetadataInput, @Args('input') input: CreateOneFieldMetadataInput,
@ -88,7 +88,7 @@ export class FieldMetadataResolver {
} }
} }
@UseGuards(SettingsPermissionsGuard(SettingsFeatures.DATA_MODEL)) @UseGuards(SettingsPermissionsGuard(SettingsPermissions.DATA_MODEL))
@Mutation(() => FieldMetadataDTO) @Mutation(() => FieldMetadataDTO)
async updateOneField( async updateOneField(
@Args('input') input: UpdateOneFieldMetadataInput, @Args('input') input: UpdateOneFieldMetadataInput,
@ -104,7 +104,7 @@ export class FieldMetadataResolver {
} }
} }
@UseGuards(SettingsPermissionsGuard(SettingsFeatures.DATA_MODEL)) @UseGuards(SettingsPermissionsGuard(SettingsPermissions.DATA_MODEL))
@Mutation(() => FieldMetadataDTO) @Mutation(() => FieldMetadataDTO)
async deleteOneField( async deleteOneField(
@Args('input') input: DeleteOneFieldInput, @Args('input') input: DeleteOneFieldInput,

View File

@ -7,7 +7,7 @@ import {
PagingStrategies, PagingStrategies,
} from '@ptc-org/nestjs-query-graphql'; } from '@ptc-org/nestjs-query-graphql';
import { NestjsQueryTypeOrmModule } from '@ptc-org/nestjs-query-typeorm'; import { NestjsQueryTypeOrmModule } from '@ptc-org/nestjs-query-typeorm';
import { SettingsFeatures } from 'twenty-shared'; import { SettingsPermissions } from 'twenty-shared';
import { TypeORMModule } from 'src/database/typeorm/typeorm.module'; import { TypeORMModule } from 'src/database/typeorm/typeorm.module';
import { FeatureFlag } from 'src/engine/core-modules/feature-flag/feature-flag.entity'; import { FeatureFlag } from 'src/engine/core-modules/feature-flag/feature-flag.entity';
@ -78,7 +78,7 @@ import { UpdateObjectPayload } from './dtos/update-object.input';
}, },
create: { create: {
many: { disabled: true }, many: { disabled: true },
guards: [SettingsPermissionsGuard(SettingsFeatures.DATA_MODEL)], guards: [SettingsPermissionsGuard(SettingsPermissions.DATA_MODEL)],
}, },
update: { disabled: true }, update: { disabled: true },
delete: { disabled: true }, delete: { disabled: true },

View File

@ -8,7 +8,7 @@ import {
Resolver, Resolver,
} from '@nestjs/graphql'; } from '@nestjs/graphql';
import { SettingsFeatures } from 'twenty-shared'; import { SettingsPermissions } from 'twenty-shared';
import { I18nContext } from 'src/engine/core-modules/i18n/types/i18n-context.type'; import { I18nContext } from 'src/engine/core-modules/i18n/types/i18n-context.type';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
@ -73,7 +73,7 @@ export class ObjectMetadataResolver {
); );
} }
@UseGuards(SettingsPermissionsGuard(SettingsFeatures.DATA_MODEL)) @UseGuards(SettingsPermissionsGuard(SettingsPermissions.DATA_MODEL))
@Mutation(() => ObjectMetadataDTO) @Mutation(() => ObjectMetadataDTO)
async deleteOneObject( async deleteOneObject(
@Args('input') input: DeleteOneObjectInput, @Args('input') input: DeleteOneObjectInput,
@ -89,7 +89,7 @@ export class ObjectMetadataResolver {
} }
} }
@UseGuards(SettingsPermissionsGuard(SettingsFeatures.DATA_MODEL)) @UseGuards(SettingsPermissionsGuard(SettingsPermissions.DATA_MODEL))
@Mutation(() => ObjectMetadataDTO) @Mutation(() => ObjectMetadataDTO)
async updateOneObject( async updateOneObject(
@Args('input') input: UpdateOneObjectInput, @Args('input') input: UpdateOneObjectInput,

View File

@ -1,6 +1,9 @@
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { PermissionsOnAllObjectRecords, SettingsFeatures } from 'twenty-shared'; import {
PermissionsOnAllObjectRecords,
SettingsPermissions,
} from 'twenty-shared';
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service'; import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
import { import {
@ -25,7 +28,7 @@ export class PermissionsService {
userWorkspaceId: string; userWorkspaceId: string;
workspaceId: string; workspaceId: string;
}): Promise<{ }): Promise<{
settingsPermissions: Record<SettingsFeatures, boolean>; settingsPermissions: Record<SettingsPermissions, boolean>;
objectRecordsPermissions: Record<PermissionsOnAllObjectRecords, boolean>; objectRecordsPermissions: Record<PermissionsOnAllObjectRecords, boolean>;
}> { }> {
const [roleOfUserWorkspace] = await this.userRoleService const [roleOfUserWorkspace] = await this.userRoleService
@ -41,12 +44,12 @@ export class PermissionsService {
hasPermissionOnSettingFeature = true; hasPermissionOnSettingFeature = true;
} }
const settingsPermissionsMap = Object.keys(SettingsFeatures).reduce( const settingsPermissionsMap = Object.keys(SettingsPermissions).reduce(
(acc, feature) => ({ (acc, feature) => ({
...acc, ...acc,
[feature]: hasPermissionOnSettingFeature, [feature]: hasPermissionOnSettingFeature,
}), }),
{} as Record<SettingsFeatures, boolean>, {} as Record<SettingsPermissions, boolean>,
); );
const objectRecordsPermissionsMap: Record< const objectRecordsPermissionsMap: Record<
@ -76,7 +79,7 @@ export class PermissionsService {
}: { }: {
userWorkspaceId: string; userWorkspaceId: string;
workspaceId: string; workspaceId: string;
_setting: SettingsFeatures; _setting: SettingsPermissions;
}): Promise<boolean> { }): Promise<boolean> {
const [roleOfUserWorkspace] = await this.userRoleService const [roleOfUserWorkspace] = await this.userRoleService
.getRolesByUserWorkspaces({ .getRolesByUserWorkspaces({

View File

@ -5,7 +5,7 @@ import {
PagingStrategies, PagingStrategies,
} from '@ptc-org/nestjs-query-graphql'; } from '@ptc-org/nestjs-query-graphql';
import { NestjsQueryTypeOrmModule } from '@ptc-org/nestjs-query-typeorm'; import { NestjsQueryTypeOrmModule } from '@ptc-org/nestjs-query-typeorm';
import { SettingsFeatures } from 'twenty-shared'; import { SettingsPermissions } from 'twenty-shared';
import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module'; import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module';
import { SettingsPermissionsGuard } from 'src/engine/guards/settings-permissions.guard'; import { SettingsPermissionsGuard } from 'src/engine/guards/settings-permissions.guard';
@ -57,7 +57,7 @@ import { RelationMetadataDTO } from './dtos/relation-metadata.dto';
pagingStrategy: PagingStrategies.CURSOR, pagingStrategy: PagingStrategies.CURSOR,
create: { create: {
many: { disabled: true }, many: { disabled: true },
guards: [SettingsPermissionsGuard(SettingsFeatures.DATA_MODEL)], guards: [SettingsPermissionsGuard(SettingsPermissions.DATA_MODEL)],
}, },
update: { disabled: true }, update: { disabled: true },
delete: { disabled: true }, delete: { disabled: true },

View File

@ -1,7 +1,7 @@
import { UseFilters, UseGuards } from '@nestjs/common'; import { UseFilters, UseGuards } from '@nestjs/common';
import { Args, Mutation, Resolver } from '@nestjs/graphql'; import { Args, Mutation, Resolver } from '@nestjs/graphql';
import { SettingsFeatures } from 'twenty-shared'; import { SettingsPermissions } from 'twenty-shared';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator'; import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator';
@ -21,7 +21,7 @@ export class RelationMetadataResolver {
private readonly relationMetadataService: RelationMetadataService, private readonly relationMetadataService: RelationMetadataService,
) {} ) {}
@UseGuards(SettingsPermissionsGuard(SettingsFeatures.DATA_MODEL)) @UseGuards(SettingsPermissionsGuard(SettingsPermissions.DATA_MODEL))
@Mutation(() => RelationMetadataDTO) @Mutation(() => RelationMetadataDTO)
async deleteOneRelation( async deleteOneRelation(
@Args('input') input: DeleteOneRelationInput, @Args('input') input: DeleteOneRelationInput,

View File

@ -8,7 +8,7 @@ import {
Resolver, Resolver,
} from '@nestjs/graphql'; } from '@nestjs/graphql';
import { isDefined, SettingsFeatures } from 'twenty-shared'; import { isDefined, SettingsPermissions } from 'twenty-shared';
import { UserWorkspaceService } from 'src/engine/core-modules/user-workspace/user-workspace.service'; import { UserWorkspaceService } from 'src/engine/core-modules/user-workspace/user-workspace.service';
import { WorkspaceMember } from 'src/engine/core-modules/user/dtos/workspace-member.dto'; import { WorkspaceMember } from 'src/engine/core-modules/user/dtos/workspace-member.dto';
@ -22,7 +22,7 @@ import { UserRoleService } from 'src/engine/metadata-modules/user-role/user-role
import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity';
@Resolver(() => RoleDTO) @Resolver(() => RoleDTO)
@UseGuards(SettingsPermissionsGuard(SettingsFeatures.ROLES)) @UseGuards(SettingsPermissionsGuard(SettingsPermissions.ROLES))
@UseFilters(PermissionsGraphqlApiExceptionFilter) @UseFilters(PermissionsGraphqlApiExceptionFilter)
export class RoleResolver { export class RoleResolver {
constructor( constructor(

View File

@ -1,4 +1,4 @@
export enum SettingsFeatures { export enum SettingsPermissions {
API_KEYS_AND_WEBHOOKS = 'API_KEYS_AND_WEBHOOKS', API_KEYS_AND_WEBHOOKS = 'API_KEYS_AND_WEBHOOKS',
WORKSPACE = 'WORKSPACE', WORKSPACE = 'WORKSPACE',
WORKSPACE_USERS = 'WORKSPACE_USERS', WORKSPACE_USERS = 'WORKSPACE_USERS',

View File

@ -1,6 +1,7 @@
export * from './FieldForTotalCountAggregateOperation'; export * from './FieldForTotalCountAggregateOperation';
export * from './PermissionsOnAllObjectRecords'; export * from './PermissionsOnAllObjectRecords';
export * from './SettingsFeatures'; export * from './SettingsPermissions';
export * from './StandardObjectRecordsUnderObjectRecordsPermissions'; export * from './StandardObjectRecordsUnderObjectRecordsPermissions';
export * from './TwentyCompaniesBaseUrl'; export * from './TwentyCompaniesBaseUrl';
export * from './TwentyIconsBaseUrl'; export * from './TwentyIconsBaseUrl';