diff --git a/packages/twenty-chrome-extension/src/generated/graphql.tsx b/packages/twenty-chrome-extension/src/generated/graphql.tsx index 2ced7aaa8f..095db005ba 100644 --- a/packages/twenty-chrome-extension/src/generated/graphql.tsx +++ b/packages/twenty-chrome-extension/src/generated/graphql.tsx @@ -984,6 +984,8 @@ export type CalendarChannel = { connectedAccount?: Maybe; /** Connected Account id foreign key */ connectedAccountId?: Maybe; + /** Automatically create records for people you participated with in an event. */ + contactAutoCreationPolicy?: Maybe; /** Creation date */ createdAt?: Maybe; /** Handle */ @@ -1030,10 +1032,31 @@ export type CalendarChannelConnection = { totalCount?: Maybe; }; +/** Automatically create records for people you participated with in an event. */ +export enum CalendarChannelContactAutoCreationPolicyEnum { + /** As Organizer */ + AsOrganizer = 'AS_ORGANIZER', + /** As Participant */ + AsParticipant = 'AS_PARTICIPANT', + /** As Participant and Organizer */ + AsParticipantAndOrganizer = 'AS_PARTICIPANT_AND_ORGANIZER', + /** None */ + None = 'NONE' +} + +export type CalendarChannelContactAutoCreationPolicyEnumFilter = { + eq?: InputMaybe; + in?: InputMaybe>>; + is?: InputMaybe; + neq?: InputMaybe; +}; + /** Calendar Channels */ export type CalendarChannelCreateInput = { /** Connected Account id foreign key */ connectedAccountId: Scalars['UUID']; + /** Automatically create records for people you participated with in an event. */ + contactAutoCreationPolicy?: InputMaybe; /** Creation date */ createdAt?: InputMaybe; /** Handle */ @@ -1172,6 +1195,8 @@ export type CalendarChannelFilterInput = { and?: InputMaybe>>; /** Connected Account id foreign key */ connectedAccountId?: InputMaybe; + /** Automatically create records for people you participated with in an event. */ + contactAutoCreationPolicy?: InputMaybe; /** Creation date */ createdAt?: InputMaybe; /** Handle */ @@ -1204,6 +1229,8 @@ export type CalendarChannelFilterInput = { export type CalendarChannelOrderByInput = { /** Connected Account id foreign key */ connectedAccountId?: InputMaybe; + /** Automatically create records for people you participated with in an event. */ + contactAutoCreationPolicy?: InputMaybe; /** Creation date */ createdAt?: InputMaybe; /** Handle */ @@ -1278,6 +1305,8 @@ export type CalendarChannelSyncStatusEnumFilter = { export type CalendarChannelUpdateInput = { /** Connected Account id foreign key */ connectedAccountId?: InputMaybe; + /** Automatically create records for people you participated with in an event. */ + contactAutoCreationPolicy?: InputMaybe; /** Creation date */ createdAt?: InputMaybe; /** Handle */ @@ -2697,8 +2726,14 @@ export type MessageChannel = { connectedAccount?: Maybe; /** Connected Account id foreign key */ connectedAccountId?: Maybe; + /** Automatically create People records when receiving or sending emails */ + contactAutoCreationPolicy?: Maybe; /** Creation date */ createdAt?: Maybe; + /** Exclude group emails */ + excludeGroupEmails?: Maybe; + /** Exclude non professional emails */ + excludeNonProfessionalEmails?: Maybe; /** Handle */ handle?: Maybe; /** Id */ @@ -2749,12 +2784,35 @@ export type MessageChannelConnection = { totalCount?: Maybe; }; +/** Automatically create People records when receiving or sending emails */ +export enum MessageChannelContactAutoCreationPolicyEnum { + /** None */ + None = 'NONE', + /** Sent */ + Sent = 'SENT', + /** Sent and Received */ + SentAndReceived = 'SENT_AND_RECEIVED' +} + +export type MessageChannelContactAutoCreationPolicyEnumFilter = { + eq?: InputMaybe; + in?: InputMaybe>>; + is?: InputMaybe; + neq?: InputMaybe; +}; + /** Message Channels */ export type MessageChannelCreateInput = { /** Connected Account id foreign key */ connectedAccountId: Scalars['UUID']; + /** Automatically create People records when receiving or sending emails */ + contactAutoCreationPolicy?: InputMaybe; /** Creation date */ createdAt?: InputMaybe; + /** Exclude group emails */ + excludeGroupEmails?: InputMaybe; + /** Exclude non professional emails */ + excludeNonProfessionalEmails?: InputMaybe; /** Handle */ handle?: InputMaybe; /** Id */ @@ -2794,8 +2852,14 @@ export type MessageChannelFilterInput = { and?: InputMaybe>>; /** Connected Account id foreign key */ connectedAccountId?: InputMaybe; + /** Automatically create People records when receiving or sending emails */ + contactAutoCreationPolicy?: InputMaybe; /** Creation date */ createdAt?: InputMaybe; + /** Exclude group emails */ + excludeGroupEmails?: InputMaybe; + /** Exclude non professional emails */ + excludeNonProfessionalEmails?: InputMaybe; /** Handle */ handle?: InputMaybe; /** Id */ @@ -2953,8 +3017,14 @@ export type MessageChannelMessageAssociationUpdateInput = { export type MessageChannelOrderByInput = { /** Connected Account id foreign key */ connectedAccountId?: InputMaybe; + /** Automatically create People records when receiving or sending emails */ + contactAutoCreationPolicy?: InputMaybe; /** Creation date */ createdAt?: InputMaybe; + /** Exclude group emails */ + excludeGroupEmails?: InputMaybe; + /** Exclude non professional emails */ + excludeNonProfessionalEmails?: InputMaybe; /** Handle */ handle?: InputMaybe; /** Id */ @@ -3052,8 +3122,14 @@ export type MessageChannelTypeEnumFilter = { export type MessageChannelUpdateInput = { /** Connected Account id foreign key */ connectedAccountId?: InputMaybe; + /** Automatically create People records when receiving or sending emails */ + contactAutoCreationPolicy?: InputMaybe; /** Creation date */ createdAt?: InputMaybe; + /** Exclude group emails */ + excludeGroupEmails?: InputMaybe; + /** Exclude non professional emails */ + excludeNonProfessionalEmails?: InputMaybe; /** Handle */ handle?: InputMaybe; /** Id */ @@ -7389,6 +7465,7 @@ export type Workspace = { inviteHash?: Maybe; logo?: Maybe; updatedAt: Scalars['DateTime']; + workspaceMembersCount?: Maybe; }; diff --git a/packages/twenty-front/src/generated-metadata/graphql.ts b/packages/twenty-front/src/generated-metadata/graphql.ts index 8098afa142..46ef29e77a 100644 --- a/packages/twenty-front/src/generated-metadata/graphql.ts +++ b/packages/twenty-front/src/generated-metadata/graphql.ts @@ -1203,6 +1203,7 @@ export type Workspace = { inviteHash?: Maybe; logo?: Maybe; updatedAt: Scalars['DateTime']['output']; + workspaceMembersCount?: Maybe; }; diff --git a/packages/twenty-front/src/generated/graphql.tsx b/packages/twenty-front/src/generated/graphql.tsx index 124daad290..fd4d821ec3 100644 --- a/packages/twenty-front/src/generated/graphql.tsx +++ b/packages/twenty-front/src/generated/graphql.tsx @@ -919,6 +919,7 @@ export type Workspace = { inviteHash?: Maybe; logo?: Maybe; updatedAt: Scalars['DateTime']; + workspaceMembersCount?: Maybe; }; @@ -1177,7 +1178,7 @@ export type ImpersonateMutationVariables = Exact<{ }>; -export type ImpersonateMutation = { __typename?: 'Mutation', impersonate: { __typename?: 'Verify', user: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, onboardingStatus?: OnboardingStatus | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, interval?: SubscriptionInterval | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } }; +export type ImpersonateMutation = { __typename?: 'Mutation', impersonate: { __typename?: 'Verify', user: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, onboardingStatus?: OnboardingStatus | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, activationStatus: string, currentCacheVersion?: string | null, workspaceMembersCount?: number | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, interval?: SubscriptionInterval | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } }; export type RenewTokenMutationVariables = Exact<{ appToken: Scalars['String']; @@ -1209,7 +1210,7 @@ export type VerifyMutationVariables = Exact<{ }>; -export type VerifyMutation = { __typename?: 'Mutation', verify: { __typename?: 'Verify', user: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, onboardingStatus?: OnboardingStatus | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, interval?: SubscriptionInterval | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } }; +export type VerifyMutation = { __typename?: 'Mutation', verify: { __typename?: 'Verify', user: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, onboardingStatus?: OnboardingStatus | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, activationStatus: string, currentCacheVersion?: string | null, workspaceMembersCount?: number | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, interval?: SubscriptionInterval | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } }; export type CheckUserExistsQueryVariables = Exact<{ email: Scalars['String']; @@ -1263,7 +1264,7 @@ export type SkipSyncEmailOnboardingStepMutationVariables = Exact<{ [key: string] export type SkipSyncEmailOnboardingStepMutation = { __typename?: 'Mutation', skipSyncEmailOnboardingStep: { __typename?: 'OnboardingStepSuccess', success: boolean } }; -export type UserQueryFragmentFragment = { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, onboardingStatus?: OnboardingStatus | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, interval?: SubscriptionInterval | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }; +export type UserQueryFragmentFragment = { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, onboardingStatus?: OnboardingStatus | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, activationStatus: string, currentCacheVersion?: string | null, workspaceMembersCount?: number | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, interval?: SubscriptionInterval | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }; export type DeleteUserAccountMutationVariables = Exact<{ [key: string]: never; }>; @@ -1280,7 +1281,7 @@ export type UploadProfilePictureMutation = { __typename?: 'Mutation', uploadProf export type GetCurrentUserQueryVariables = Exact<{ [key: string]: never; }>; -export type GetCurrentUserQuery = { __typename?: 'Query', currentUser: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, onboardingStatus?: OnboardingStatus | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, interval?: SubscriptionInterval | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: 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, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, activationStatus: string, currentCacheVersion?: string | null, workspaceMembersCount?: number | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, interval?: SubscriptionInterval | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> } }; export type AddUserToWorkspaceMutationVariables = Exact<{ inviteHash: Scalars['String']; @@ -1455,6 +1456,7 @@ export const UserQueryFragmentFragmentDoc = gql` status interval } + workspaceMembersCount } workspaces { workspace { diff --git a/packages/twenty-front/src/modules/auth/states/currentWorkspaceState.ts b/packages/twenty-front/src/modules/auth/states/currentWorkspaceState.ts index 239dfc7930..a66d7bd1cb 100644 --- a/packages/twenty-front/src/modules/auth/states/currentWorkspaceState.ts +++ b/packages/twenty-front/src/modules/auth/states/currentWorkspaceState.ts @@ -12,6 +12,7 @@ export type CurrentWorkspace = Pick< | 'featureFlags' | 'activationStatus' | 'currentBillingSubscription' + | 'workspaceMembersCount' | 'currentCacheVersion' >; diff --git a/packages/twenty-front/src/modules/onboarding/hooks/__tests__/useSetNextOnboardingStatus.test.ts b/packages/twenty-front/src/modules/onboarding/hooks/__tests__/useSetNextOnboardingStatus.test.ts index 223370bce7..260e3d6aa4 100644 --- a/packages/twenty-front/src/modules/onboarding/hooks/__tests__/useSetNextOnboardingStatus.test.ts +++ b/packages/twenty-front/src/modules/onboarding/hooks/__tests__/useSetNextOnboardingStatus.test.ts @@ -11,20 +11,10 @@ import { mockedUserData, } from '~/testing/mock-data/users'; -jest.mock('@/object-record/hooks/useFindManyRecords', () => ({ - useFindManyRecords: jest.fn(), -})); -const setupMockWorkspaceMembers = (withManyWorkspaceMembers = false) => { - jest - .requireMock('@/object-record/hooks/useFindManyRecords') - .useFindManyRecords.mockReturnValue({ - records: withManyWorkspaceMembers ? [{}, {}] : [{}], - }); -}; - const renderHooks = ( onboardingStatus: OnboardingStatus, withCurrentBillingSubscription: boolean, + withOneWorkspaceMember = true, ) => { const { result } = renderHook( () => { @@ -49,6 +39,7 @@ const renderHooks = ( currentBillingSubscription: withCurrentBillingSubscription ? { id: v4(), status: SubscriptionStatus.Active } : undefined, + workspaceMembersCount: withOneWorkspaceMember ? 1 : 2, }); }); act(() => { @@ -59,29 +50,38 @@ const renderHooks = ( describe('useSetNextOnboardingStatus', () => { it('should set next onboarding status for ProfileCreation', () => { - setupMockWorkspaceMembers(); const nextOnboardingStatus = renderHooks( OnboardingStatus.ProfileCreation, false, + true, ); expect(nextOnboardingStatus).toEqual(OnboardingStatus.SyncEmail); }); it('should set next onboarding status for SyncEmail', () => { - setupMockWorkspaceMembers(); - const nextOnboardingStatus = renderHooks(OnboardingStatus.SyncEmail, false); + const nextOnboardingStatus = renderHooks( + OnboardingStatus.SyncEmail, + false, + true, + ); expect(nextOnboardingStatus).toEqual(OnboardingStatus.InviteTeam); }); - it('should skip invite when workspaceMembers exist', () => { - setupMockWorkspaceMembers(true); - const nextOnboardingStatus = renderHooks(OnboardingStatus.SyncEmail, true); + it('should skip invite when more than 1 workspaceMember exist', () => { + const nextOnboardingStatus = renderHooks( + OnboardingStatus.SyncEmail, + true, + false, + ); expect(nextOnboardingStatus).toEqual(OnboardingStatus.Completed); }); it('should set next onboarding status for Completed', () => { - setupMockWorkspaceMembers(); - const nextOnboardingStatus = renderHooks(OnboardingStatus.InviteTeam, true); + const nextOnboardingStatus = renderHooks( + OnboardingStatus.InviteTeam, + true, + true, + ); expect(nextOnboardingStatus).toEqual(OnboardingStatus.Completed); }); }); diff --git a/packages/twenty-front/src/modules/onboarding/hooks/useSetNextOnboardingStatus.ts b/packages/twenty-front/src/modules/onboarding/hooks/useSetNextOnboardingStatus.ts index 30a5f2fae8..abc0a2b318 100644 --- a/packages/twenty-front/src/modules/onboarding/hooks/useSetNextOnboardingStatus.ts +++ b/packages/twenty-front/src/modules/onboarding/hooks/useSetNextOnboardingStatus.ts @@ -1,22 +1,23 @@ import { useRecoilCallback, useRecoilValue } from 'recoil'; import { CurrentUser, currentUserState } from '@/auth/states/currentUserState'; -import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; -import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; -import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember'; +import { + CurrentWorkspace, + currentWorkspaceState, +} from '@/auth/states/currentWorkspaceState'; import { OnboardingStatus } from '~/generated/graphql'; import { isDefined } from '~/utils/isDefined'; const getNextOnboardingStatus = ( currentUser: CurrentUser | null, - workspaceMembers: WorkspaceMember[], + currentWorkspace: CurrentWorkspace | null, ) => { if (currentUser?.onboardingStatus === OnboardingStatus.ProfileCreation) { return OnboardingStatus.SyncEmail; } if ( currentUser?.onboardingStatus === OnboardingStatus.SyncEmail && - workspaceMembers.length === 1 + currentWorkspace?.workspaceMembersCount === 1 ) { return OnboardingStatus.InviteTeam; } @@ -24,17 +25,15 @@ const getNextOnboardingStatus = ( }; export const useSetNextOnboardingStatus = () => { - const { records: workspaceMembers } = useFindManyRecords({ - objectNameSingular: CoreObjectNameSingular.WorkspaceMember, - }); const currentUser = useRecoilValue(currentUserState); + const currentWorkspace = useRecoilValue(currentWorkspaceState); return useRecoilCallback( ({ set }) => () => { const nextOnboardingStatus = getNextOnboardingStatus( currentUser, - workspaceMembers, + currentWorkspace, ); set(currentUserState, (current) => { if (isDefined(current)) { @@ -46,6 +45,6 @@ export const useSetNextOnboardingStatus = () => { return current; }); }, - [workspaceMembers, currentUser], + [currentWorkspace, currentUser], ); }; diff --git a/packages/twenty-front/src/modules/users/graphql/fragments/userQueryFragment.ts b/packages/twenty-front/src/modules/users/graphql/fragments/userQueryFragment.ts index 7b46e794f7..14dcf557a2 100644 --- a/packages/twenty-front/src/modules/users/graphql/fragments/userQueryFragment.ts +++ b/packages/twenty-front/src/modules/users/graphql/fragments/userQueryFragment.ts @@ -39,6 +39,7 @@ export const USER_QUERY_FRAGMENT = gql` status interval } + workspaceMembersCount } workspaces { workspace { diff --git a/packages/twenty-front/src/testing/mock-data/users.ts b/packages/twenty-front/src/testing/mock-data/users.ts index 1afd532d26..806eb6265c 100644 --- a/packages/twenty-front/src/testing/mock-data/users.ts +++ b/packages/twenty-front/src/testing/mock-data/users.ts @@ -66,6 +66,7 @@ export const mockDefaultWorkspace: Workspace = { interval: SubscriptionInterval.Month, status: SubscriptionStatus.Active, }, + workspaceMembersCount: 1, }; export const mockedWorkspaceMemberData: WorkspaceMember = { diff --git a/packages/twenty-server/src/engine/core-modules/workspace/workspace.entity.ts b/packages/twenty-server/src/engine/core-modules/workspace/workspace.entity.ts index bccb5f2cf6..3d8efa2b6c 100644 --- a/packages/twenty-server/src/engine/core-modules/workspace/workspace.entity.ts +++ b/packages/twenty-server/src/engine/core-modules/workspace/workspace.entity.ts @@ -87,6 +87,9 @@ export class Workspace { @Field({ nullable: true }) currentBillingSubscription: BillingSubscription; + @Field({ nullable: true }) + workspaceMembersCount: number; + @Field() activationStatus: 'active' | 'inactive'; diff --git a/packages/twenty-server/src/engine/core-modules/workspace/workspace.resolver.ts b/packages/twenty-server/src/engine/core-modules/workspace/workspace.resolver.ts index a30853ac2c..e8e8a78ee6 100644 --- a/packages/twenty-server/src/engine/core-modules/workspace/workspace.resolver.ts +++ b/packages/twenty-server/src/engine/core-modules/workspace/workspace.resolver.ts @@ -27,6 +27,7 @@ import { DemoEnvGuard } from 'src/engine/guards/demo.env.guard'; import { WorkspaceCacheVersionService } from 'src/engine/metadata-modules/workspace-cache-version/workspace-cache-version.service'; import { SendInviteLink } from 'src/engine/core-modules/workspace/dtos/send-invite-link.entity'; import { SendInviteLinkInput } from 'src/engine/core-modules/workspace/dtos/send-invite-link.input'; +import { UserWorkspaceService } from 'src/engine/core-modules/user-workspace/user-workspace.service'; import { Workspace } from './workspace.entity'; @@ -38,6 +39,7 @@ export class WorkspaceResolver { constructor( private readonly workspaceService: WorkspaceService, private readonly workspaceCacheVersionService: WorkspaceCacheVersionService, + private readonly userWorkspaceService: UserWorkspaceService, private readonly fileUploadService: FileUploadService, private readonly billingService: BillingService, ) {} @@ -125,6 +127,11 @@ export class WorkspaceResolver { }); } + @ResolveField(() => Number) + async workspaceMembersCount(): Promise { + return await this.userWorkspaceService.getWorkspaceMemberCount(); + } + @Mutation(() => SendInviteLink) async sendInviteLink( @Args() sendInviteLinkInput: SendInviteLinkInput,