messaging post migration cleanup (#19365)

Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
neo773
2026-04-07 14:26:49 +05:30
committed by GitHub
parent 601dc02ed7
commit b23d2b4e73
32 changed files with 155 additions and 353 deletions
@@ -2771,6 +2771,7 @@ type ConnectedAccountDTO {
authFailedAt: DateTime authFailedAt: DateTime
handleAliases: [String!] handleAliases: [String!]
scopes: [String!] scopes: [String!]
connectionParameters: ImapSmtpCaldavConnectionParameters
lastSignedInAt: DateTime lastSignedInAt: DateTime
userWorkspaceId: UUID! userWorkspaceId: UUID!
createdAt: DateTime! createdAt: DateTime!
@@ -2424,6 +2424,7 @@ export interface ConnectedAccountDTO {
authFailedAt?: Scalars['DateTime'] authFailedAt?: Scalars['DateTime']
handleAliases?: Scalars['String'][] handleAliases?: Scalars['String'][]
scopes?: Scalars['String'][] scopes?: Scalars['String'][]
connectionParameters?: ImapSmtpCaldavConnectionParameters
lastSignedInAt?: Scalars['DateTime'] lastSignedInAt?: Scalars['DateTime']
userWorkspaceId: Scalars['UUID'] userWorkspaceId: Scalars['UUID']
createdAt: Scalars['DateTime'] createdAt: Scalars['DateTime']
@@ -5630,6 +5631,7 @@ export interface ConnectedAccountDTOGenqlSelection{
authFailedAt?: boolean | number authFailedAt?: boolean | number
handleAliases?: boolean | number handleAliases?: boolean | number
scopes?: boolean | number scopes?: boolean | number
connectionParameters?: ImapSmtpCaldavConnectionParametersGenqlSelection
lastSignedInAt?: boolean | number lastSignedInAt?: boolean | number
userWorkspaceId?: boolean | number userWorkspaceId?: boolean | number
createdAt?: boolean | number createdAt?: boolean | number
@@ -5479,6 +5479,9 @@ export default {
"scopes": [ "scopes": [
1 1
], ],
"connectionParameters": [
291
],
"lastSignedInAt": [ "lastSignedInAt": [
4 4
], ],
@@ -1019,6 +1019,7 @@ export type ConfigVariablesGroupData = {
export type ConnectedAccountDto = { export type ConnectedAccountDto = {
__typename?: 'ConnectedAccountDTO'; __typename?: 'ConnectedAccountDTO';
authFailedAt?: Maybe<Scalars['DateTime']>; authFailedAt?: Maybe<Scalars['DateTime']>;
connectionParameters?: Maybe<ImapSmtpCaldavConnectionParameters>;
createdAt: Scalars['DateTime']; createdAt: Scalars['DateTime'];
handle: Scalars['String']; handle: Scalars['String'];
handleAliases?: Maybe<Array<Scalars['String']>>; handleAliases?: Maybe<Array<Scalars['String']>>;
@@ -7073,7 +7074,7 @@ export type MyCalendarChannelsQuery = { __typename?: 'Query', myCalendarChannels
export type MyConnectedAccountsQueryVariables = Exact<{ [key: string]: never; }>; export type MyConnectedAccountsQueryVariables = Exact<{ [key: string]: never; }>;
export type MyConnectedAccountsQuery = { __typename?: 'Query', myConnectedAccounts: Array<{ __typename?: 'ConnectedAccountDTO', id: string, handle: string, provider: string, authFailedAt?: string | null, scopes?: Array<string> | null, handleAliases?: Array<string> | null, lastSignedInAt?: string | null, userWorkspaceId: string, createdAt: string, updatedAt: string }> }; export type MyConnectedAccountsQuery = { __typename?: 'Query', myConnectedAccounts: Array<{ __typename?: 'ConnectedAccountDTO', id: string, handle: string, provider: string, authFailedAt?: string | null, scopes?: Array<string> | null, handleAliases?: Array<string> | null, lastSignedInAt?: string | null, userWorkspaceId: string, createdAt: string, updatedAt: string, connectionParameters?: { __typename?: 'ImapSmtpCaldavConnectionParameters', IMAP?: { __typename?: 'ConnectionParametersOutput', host: string, port: number, secure?: boolean | null, username?: string | null, password: string } | null, SMTP?: { __typename?: 'ConnectionParametersOutput', host: string, port: number, secure?: boolean | null, username?: string | null, password: string } | null, CALDAV?: { __typename?: 'ConnectionParametersOutput', host: string, username?: string | null, password: string } | null } | null }> };
export type MyMessageChannelsQueryVariables = Exact<{ export type MyMessageChannelsQueryVariables = Exact<{
connectedAccountId?: InputMaybe<Scalars['UUID']>; connectedAccountId?: InputMaybe<Scalars['UUID']>;
@@ -8386,7 +8387,7 @@ export const UpdateMessageFolderDocument = {"kind":"Document","definitions":[{"k
export const UpdateMessageFoldersDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateMessageFolders"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UpdateMessageFoldersInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"updateMessageFolders"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"isSynced"}}]}}]}}]} as unknown as DocumentNode<UpdateMessageFoldersMutation, UpdateMessageFoldersMutationVariables>; export const UpdateMessageFoldersDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateMessageFolders"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UpdateMessageFoldersInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"updateMessageFolders"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"isSynced"}}]}}]}}]} as unknown as DocumentNode<UpdateMessageFoldersMutation, UpdateMessageFoldersMutationVariables>;
export const GetConnectedImapSmtpCaldavAccountDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetConnectedImapSmtpCaldavAccount"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getConnectedImapSmtpCaldavAccount"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"handle"}},{"kind":"Field","name":{"kind":"Name","value":"provider"}},{"kind":"Field","name":{"kind":"Name","value":"userWorkspaceId"}},{"kind":"Field","name":{"kind":"Name","value":"connectionParameters"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"IMAP"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"host"}},{"kind":"Field","name":{"kind":"Name","value":"port"}},{"kind":"Field","name":{"kind":"Name","value":"secure"}},{"kind":"Field","name":{"kind":"Name","value":"username"}},{"kind":"Field","name":{"kind":"Name","value":"password"}}]}},{"kind":"Field","name":{"kind":"Name","value":"SMTP"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"host"}},{"kind":"Field","name":{"kind":"Name","value":"username"}},{"kind":"Field","name":{"kind":"Name","value":"port"}},{"kind":"Field","name":{"kind":"Name","value":"secure"}},{"kind":"Field","name":{"kind":"Name","value":"password"}}]}},{"kind":"Field","name":{"kind":"Name","value":"CALDAV"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"host"}},{"kind":"Field","name":{"kind":"Name","value":"username"}},{"kind":"Field","name":{"kind":"Name","value":"password"}}]}}]}}]}}]}}]} as unknown as DocumentNode<GetConnectedImapSmtpCaldavAccountQuery, GetConnectedImapSmtpCaldavAccountQueryVariables>; export const GetConnectedImapSmtpCaldavAccountDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetConnectedImapSmtpCaldavAccount"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getConnectedImapSmtpCaldavAccount"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"handle"}},{"kind":"Field","name":{"kind":"Name","value":"provider"}},{"kind":"Field","name":{"kind":"Name","value":"userWorkspaceId"}},{"kind":"Field","name":{"kind":"Name","value":"connectionParameters"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"IMAP"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"host"}},{"kind":"Field","name":{"kind":"Name","value":"port"}},{"kind":"Field","name":{"kind":"Name","value":"secure"}},{"kind":"Field","name":{"kind":"Name","value":"username"}},{"kind":"Field","name":{"kind":"Name","value":"password"}}]}},{"kind":"Field","name":{"kind":"Name","value":"SMTP"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"host"}},{"kind":"Field","name":{"kind":"Name","value":"username"}},{"kind":"Field","name":{"kind":"Name","value":"port"}},{"kind":"Field","name":{"kind":"Name","value":"secure"}},{"kind":"Field","name":{"kind":"Name","value":"password"}}]}},{"kind":"Field","name":{"kind":"Name","value":"CALDAV"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"host"}},{"kind":"Field","name":{"kind":"Name","value":"username"}},{"kind":"Field","name":{"kind":"Name","value":"password"}}]}}]}}]}}]}}]} as unknown as DocumentNode<GetConnectedImapSmtpCaldavAccountQuery, GetConnectedImapSmtpCaldavAccountQueryVariables>;
export const MyCalendarChannelsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"MyCalendarChannels"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"connectedAccountId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"myCalendarChannels"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"connectedAccountId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"connectedAccountId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"handle"}},{"kind":"Field","name":{"kind":"Name","value":"visibility"}},{"kind":"Field","name":{"kind":"Name","value":"syncStatus"}},{"kind":"Field","name":{"kind":"Name","value":"syncStage"}},{"kind":"Field","name":{"kind":"Name","value":"syncStageStartedAt"}},{"kind":"Field","name":{"kind":"Name","value":"isContactAutoCreationEnabled"}},{"kind":"Field","name":{"kind":"Name","value":"contactAutoCreationPolicy"}},{"kind":"Field","name":{"kind":"Name","value":"isSyncEnabled"}},{"kind":"Field","name":{"kind":"Name","value":"connectedAccountId"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]}}]} as unknown as DocumentNode<MyCalendarChannelsQuery, MyCalendarChannelsQueryVariables>; export const MyCalendarChannelsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"MyCalendarChannels"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"connectedAccountId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"myCalendarChannels"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"connectedAccountId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"connectedAccountId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"handle"}},{"kind":"Field","name":{"kind":"Name","value":"visibility"}},{"kind":"Field","name":{"kind":"Name","value":"syncStatus"}},{"kind":"Field","name":{"kind":"Name","value":"syncStage"}},{"kind":"Field","name":{"kind":"Name","value":"syncStageStartedAt"}},{"kind":"Field","name":{"kind":"Name","value":"isContactAutoCreationEnabled"}},{"kind":"Field","name":{"kind":"Name","value":"contactAutoCreationPolicy"}},{"kind":"Field","name":{"kind":"Name","value":"isSyncEnabled"}},{"kind":"Field","name":{"kind":"Name","value":"connectedAccountId"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]}}]} as unknown as DocumentNode<MyCalendarChannelsQuery, MyCalendarChannelsQueryVariables>;
export const MyConnectedAccountsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"MyConnectedAccounts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"myConnectedAccounts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"handle"}},{"kind":"Field","name":{"kind":"Name","value":"provider"}},{"kind":"Field","name":{"kind":"Name","value":"authFailedAt"}},{"kind":"Field","name":{"kind":"Name","value":"scopes"}},{"kind":"Field","name":{"kind":"Name","value":"handleAliases"}},{"kind":"Field","name":{"kind":"Name","value":"lastSignedInAt"}},{"kind":"Field","name":{"kind":"Name","value":"userWorkspaceId"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]}}]} as unknown as DocumentNode<MyConnectedAccountsQuery, MyConnectedAccountsQueryVariables>; export const MyConnectedAccountsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"MyConnectedAccounts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"myConnectedAccounts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"handle"}},{"kind":"Field","name":{"kind":"Name","value":"provider"}},{"kind":"Field","name":{"kind":"Name","value":"authFailedAt"}},{"kind":"Field","name":{"kind":"Name","value":"scopes"}},{"kind":"Field","name":{"kind":"Name","value":"handleAliases"}},{"kind":"Field","name":{"kind":"Name","value":"lastSignedInAt"}},{"kind":"Field","name":{"kind":"Name","value":"userWorkspaceId"}},{"kind":"Field","name":{"kind":"Name","value":"connectionParameters"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"IMAP"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"host"}},{"kind":"Field","name":{"kind":"Name","value":"port"}},{"kind":"Field","name":{"kind":"Name","value":"secure"}},{"kind":"Field","name":{"kind":"Name","value":"username"}},{"kind":"Field","name":{"kind":"Name","value":"password"}}]}},{"kind":"Field","name":{"kind":"Name","value":"SMTP"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"host"}},{"kind":"Field","name":{"kind":"Name","value":"port"}},{"kind":"Field","name":{"kind":"Name","value":"secure"}},{"kind":"Field","name":{"kind":"Name","value":"username"}},{"kind":"Field","name":{"kind":"Name","value":"password"}}]}},{"kind":"Field","name":{"kind":"Name","value":"CALDAV"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"host"}},{"kind":"Field","name":{"kind":"Name","value":"username"}},{"kind":"Field","name":{"kind":"Name","value":"password"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]}}]} as unknown as DocumentNode<MyConnectedAccountsQuery, MyConnectedAccountsQueryVariables>;
export const MyMessageChannelsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"MyMessageChannels"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"connectedAccountId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"myMessageChannels"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"connectedAccountId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"connectedAccountId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"handle"}},{"kind":"Field","name":{"kind":"Name","value":"visibility"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"isContactAutoCreationEnabled"}},{"kind":"Field","name":{"kind":"Name","value":"contactAutoCreationPolicy"}},{"kind":"Field","name":{"kind":"Name","value":"messageFolderImportPolicy"}},{"kind":"Field","name":{"kind":"Name","value":"excludeNonProfessionalEmails"}},{"kind":"Field","name":{"kind":"Name","value":"excludeGroupEmails"}},{"kind":"Field","name":{"kind":"Name","value":"isSyncEnabled"}},{"kind":"Field","name":{"kind":"Name","value":"syncStatus"}},{"kind":"Field","name":{"kind":"Name","value":"syncStage"}},{"kind":"Field","name":{"kind":"Name","value":"syncStageStartedAt"}},{"kind":"Field","name":{"kind":"Name","value":"connectedAccountId"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]}}]} as unknown as DocumentNode<MyMessageChannelsQuery, MyMessageChannelsQueryVariables>; export const MyMessageChannelsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"MyMessageChannels"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"connectedAccountId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"myMessageChannels"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"connectedAccountId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"connectedAccountId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"handle"}},{"kind":"Field","name":{"kind":"Name","value":"visibility"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"isContactAutoCreationEnabled"}},{"kind":"Field","name":{"kind":"Name","value":"contactAutoCreationPolicy"}},{"kind":"Field","name":{"kind":"Name","value":"messageFolderImportPolicy"}},{"kind":"Field","name":{"kind":"Name","value":"excludeNonProfessionalEmails"}},{"kind":"Field","name":{"kind":"Name","value":"excludeGroupEmails"}},{"kind":"Field","name":{"kind":"Name","value":"isSyncEnabled"}},{"kind":"Field","name":{"kind":"Name","value":"syncStatus"}},{"kind":"Field","name":{"kind":"Name","value":"syncStage"}},{"kind":"Field","name":{"kind":"Name","value":"syncStageStartedAt"}},{"kind":"Field","name":{"kind":"Name","value":"connectedAccountId"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]}}]} as unknown as DocumentNode<MyMessageChannelsQuery, MyMessageChannelsQueryVariables>;
export const MyMessageFoldersDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"MyMessageFolders"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"messageChannelId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"myMessageFolders"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"messageChannelId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"messageChannelId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"isSynced"}},{"kind":"Field","name":{"kind":"Name","value":"isSentFolder"}},{"kind":"Field","name":{"kind":"Name","value":"parentFolderId"}},{"kind":"Field","name":{"kind":"Name","value":"externalId"}},{"kind":"Field","name":{"kind":"Name","value":"messageChannelId"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]}}]} as unknown as DocumentNode<MyMessageFoldersQuery, MyMessageFoldersQueryVariables>; export const MyMessageFoldersDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"MyMessageFolders"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"messageChannelId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"myMessageFolders"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"messageChannelId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"messageChannelId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"isSynced"}},{"kind":"Field","name":{"kind":"Name","value":"isSentFolder"}},{"kind":"Field","name":{"kind":"Name","value":"parentFolderId"}},{"kind":"Field","name":{"kind":"Name","value":"externalId"}},{"kind":"Field","name":{"kind":"Name","value":"messageChannelId"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]}}]} as unknown as DocumentNode<MyMessageFoldersQuery, MyMessageFoldersQueryVariables>;
export const AddAiProviderDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"AddAiProvider"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"providerName"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"providerConfig"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"addAiProvider"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"providerName"},"value":{"kind":"Variable","name":{"kind":"Name","value":"providerName"}}},{"kind":"Argument","name":{"kind":"Name","value":"providerConfig"},"value":{"kind":"Variable","name":{"kind":"Name","value":"providerConfig"}}}]}]}}]} as unknown as DocumentNode<AddAiProviderMutation, AddAiProviderMutationVariables>; export const AddAiProviderDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"AddAiProvider"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"providerName"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"providerConfig"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"addAiProvider"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"providerName"},"value":{"kind":"Variable","name":{"kind":"Name","value":"providerName"}}},{"kind":"Argument","name":{"kind":"Name","value":"providerConfig"},"value":{"kind":"Variable","name":{"kind":"Name","value":"providerConfig"}}}]}]}}]} as unknown as DocumentNode<AddAiProviderMutation, AddAiProviderMutationVariables>;
@@ -1,41 +1,22 @@
import {
type CalendarChannelContactAutoCreationPolicy,
type CalendarChannelSyncStage,
type CalendarChannelSyncStatus,
} from 'twenty-shared/types';
import { type CalendarChannelVisibility } from '~/generated/graphql'; import { type CalendarChannelVisibility } from '~/generated/graphql';
export enum CalendarChannelSyncStatus {
NOT_SYNCED = 'NOT_SYNCED',
ONGOING = 'ONGOING',
ACTIVE = 'ACTIVE',
FAILED_INSUFFICIENT_PERMISSIONS = 'FAILED_INSUFFICIENT_PERMISSIONS',
FAILED_UNKNOWN = 'FAILED_UNKNOWN',
}
export enum CalendarChannelSyncStage {
PENDING_CONFIGURATION = 'PENDING_CONFIGURATION',
CALENDAR_EVENT_LIST_FETCH_PENDING = 'CALENDAR_EVENT_LIST_FETCH_PENDING',
CALENDAR_EVENT_LIST_FETCH_SCHEDULED = 'CALENDAR_EVENT_LIST_FETCH_SCHEDULED',
CALENDAR_EVENT_LIST_FETCH_ONGOING = 'CALENDAR_EVENT_LIST_FETCH_ONGOING',
CALENDAR_EVENTS_IMPORT_PENDING = 'CALENDAR_EVENTS_IMPORT_PENDING',
CALENDAR_EVENTS_IMPORT_SCHEDULED = 'CALENDAR_EVENTS_IMPORT_SCHEDULED',
CALENDAR_EVENTS_IMPORT_ONGOING = 'CALENDAR_EVENTS_IMPORT_ONGOING',
FAILED = 'FAILED',
}
export enum CalendarChannelContactAutoCreationPolicy {
AS_PARTICIPANT_AND_ORGANIZER = 'AS_PARTICIPANT_AND_ORGANIZER',
AS_PARTICIPANT = 'AS_PARTICIPANT',
AS_ORGANIZER = 'AS_ORGANIZER',
NONE = 'NONE',
}
export type CalendarChannel = { export type CalendarChannel = {
id: string; id: string;
handle: string; handle: string;
visibility: CalendarChannelVisibility;
isContactAutoCreationEnabled: boolean; isContactAutoCreationEnabled: boolean;
contactAutoCreationPolicy: CalendarChannelContactAutoCreationPolicy; contactAutoCreationPolicy: CalendarChannelContactAutoCreationPolicy;
isSyncEnabled: boolean; isSyncEnabled: boolean;
visibility: CalendarChannelVisibility;
syncStatus: CalendarChannelSyncStatus; syncStatus: CalendarChannelSyncStatus;
syncStage: CalendarChannelSyncStage; syncStage: CalendarChannelSyncStage;
syncCursor: string; syncStageStartedAt: string | null;
syncStageStartedAt: Date; connectedAccountId: string;
throttleFailureCount: number; createdAt: string;
updatedAt: string;
__typename: 'CalendarChannel'; __typename: 'CalendarChannel';
}; };
@@ -7,14 +7,15 @@ export type ConnectedAccount = {
id: string; id: string;
handle: string; handle: string;
provider: ConnectedAccountProvider; provider: ConnectedAccountProvider;
accessToken: string; authFailedAt: string | null;
refreshToken: string; scopes: string[] | null;
accountOwnerId: string; handleAliases: string[] | null;
lastSyncHistoryId: string; lastSignedInAt: string | null;
authFailedAt: Date | null; userWorkspaceId: string;
connectionParameters: ImapSmtpCaldavAccount | null;
createdAt: string;
updatedAt: string;
messageChannels: MessageChannel[]; messageChannels: MessageChannel[];
calendarChannels: CalendarChannel[]; calendarChannels: CalendarChannel[];
scopes: string[] | null;
connectionParameters?: ImapSmtpCaldavAccount;
__typename: 'ConnectedAccount'; __typename: 'ConnectedAccount';
}; };
@@ -1,57 +1,27 @@
import { type ImapSmtpCaldavAccount } from '@/accounts/types/ImapSmtpCaldavAccount'; import {
import { type MessageFolder } from '@/accounts/types/MessageFolder'; type MessageChannelContactAutoCreationPolicy,
import { type ConnectedAccountProvider } from 'twenty-shared/types'; type MessageChannelSyncStage,
type MessageChannelSyncStatus,
type MessageFolderImportPolicy,
} from 'twenty-shared/types';
import { type MessageChannelVisibility } from '~/generated/graphql'; import { type MessageChannelVisibility } from '~/generated/graphql';
export enum MessageChannelContactAutoCreationPolicy {
SENT_AND_RECEIVED = 'SENT_AND_RECEIVED',
SENT = 'SENT',
NONE = 'NONE',
}
export enum MessageFolderImportPolicy {
ALL_FOLDERS = 'ALL_FOLDERS',
SELECTED_FOLDERS = 'SELECTED_FOLDERS',
}
export enum MessageChannelSyncStatus {
NOT_SYNCED = 'NOT_SYNCED',
ONGOING = 'ONGOING',
ACTIVE = 'ACTIVE',
FAILED_INSUFFICIENT_PERMISSIONS = 'FAILED_INSUFFICIENT_PERMISSIONS',
FAILED_UNKNOWN = 'FAILED_UNKNOWN',
}
export enum MessageChannelSyncStage {
PENDING_CONFIGURATION = 'PENDING_CONFIGURATION',
MESSAGE_LIST_FETCH_PENDING = 'MESSAGE_LIST_FETCH_PENDING',
MESSAGE_LIST_FETCH_SCHEDULED = 'MESSAGE_LIST_FETCH_SCHEDULED',
MESSAGE_LIST_FETCH_ONGOING = 'MESSAGE_LIST_FETCH_ONGOING',
MESSAGES_IMPORT_PENDING = 'MESSAGES_IMPORT_PENDING',
MESSAGES_IMPORT_SCHEDULED = 'MESSAGES_IMPORT_SCHEDULED',
MESSAGES_IMPORT_ONGOING = 'MESSAGES_IMPORT_ONGOING',
FAILED = 'FAILED',
}
export type MessageChannel = { export type MessageChannel = {
id: string; id: string;
handle: string; handle: string;
visibility: MessageChannelVisibility;
type: string;
isContactAutoCreationEnabled: boolean;
contactAutoCreationPolicy: MessageChannelContactAutoCreationPolicy; contactAutoCreationPolicy: MessageChannelContactAutoCreationPolicy;
messageFolderImportPolicy: MessageFolderImportPolicy;
excludeNonProfessionalEmails: boolean; excludeNonProfessionalEmails: boolean;
excludeGroupEmails: boolean; excludeGroupEmails: boolean;
isSyncEnabled: boolean; isSyncEnabled: boolean;
messageFolders: MessageFolder[];
visibility: MessageChannelVisibility;
messageFolderImportPolicy: MessageFolderImportPolicy;
syncStatus: MessageChannelSyncStatus; syncStatus: MessageChannelSyncStatus;
syncStage: MessageChannelSyncStage; syncStage: MessageChannelSyncStage;
syncCursor: string; syncStageStartedAt: string | null;
syncStageStartedAt: Date; connectedAccountId: string;
throttleFailureCount: number; createdAt: string;
connectedAccount?: { updatedAt: string;
id: string;
provider: ConnectedAccountProvider;
connectionParameters?: ImapSmtpCaldavAccount;
};
__typename: 'MessageChannel'; __typename: 'MessageChannel';
}; };
@@ -1,11 +1,12 @@
export type MessageFolder = { export type MessageFolder = {
id: string; id: string;
name: string; name: string;
syncCursor: string;
isSentFolder: boolean;
isSynced: boolean; isSynced: boolean;
messageChannelId: string; isSentFolder: boolean;
parentFolderId: string | null; parentFolderId: string | null;
externalId: string | null; externalId: string | null;
messageChannelId: string;
createdAt: string;
updatedAt: string;
__typename: 'MessageFolder'; __typename: 'MessageFolder';
}; };
@@ -8,6 +8,7 @@ import { TabList } from '@/ui/layout/tab-list/components/TabList';
import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState'; import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue'; import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
import React from 'react'; import React from 'react';
import { CalendarChannelSyncStage } from 'twenty-shared/types';
import { themeCssVariables } from 'twenty-ui/theme-constants'; import { themeCssVariables } from 'twenty-ui/theme-constants';
const StyledCalenderContainer = styled.div` const StyledCalenderContainer = styled.div`
@@ -20,7 +21,12 @@ export const SettingsAccountsCalendarChannelsContainer = () => {
SETTINGS_ACCOUNT_CALENDAR_CHANNELS_TAB_LIST_COMPONENT_ID, SETTINGS_ACCOUNT_CALENDAR_CHANNELS_TAB_LIST_COMPONENT_ID,
); );
const { channels: calendarChannels } = useMyCalendarChannels(); const { channels: allCalendarChannels } = useMyCalendarChannels();
const calendarChannels = allCalendarChannels.filter(
(channel) =>
channel.syncStage !== CalendarChannelSyncStage.PENDING_CONFIGURATION,
);
const tabs = [ const tabs = [
...calendarChannels.map((calendarChannel) => ({ ...calendarChannels.map((calendarChannel) => ({
@@ -1,7 +1,7 @@
import { MessageChannelContactAutoCreationPolicy } from '@/accounts/types/MessageChannel';
import { SettingsAccountsMessageAutoCreationIcon } from '@/settings/accounts/components/SettingsAccountsMessageAutoCreationIcon'; import { SettingsAccountsMessageAutoCreationIcon } from '@/settings/accounts/components/SettingsAccountsMessageAutoCreationIcon';
import { SettingsAccountsRadioSettingsCard } from '@/settings/accounts/components/SettingsAccountsRadioSettingsCard'; import { SettingsAccountsRadioSettingsCard } from '@/settings/accounts/components/SettingsAccountsRadioSettingsCard';
import { msg } from '@lingui/core/macro'; import { msg } from '@lingui/core/macro';
import { MessageChannelContactAutoCreationPolicy } from 'twenty-shared/types';
type SettingsAccountsMessageAutoCreationCardProps = { type SettingsAccountsMessageAutoCreationCardProps = {
onChange: (nextValue: MessageChannelContactAutoCreationPolicy) => void; onChange: (nextValue: MessageChannelContactAutoCreationPolicy) => void;
@@ -1,10 +1,6 @@
import { styled } from '@linaria/react'; import { styled } from '@linaria/react';
import { import { type MessageChannel } from '@/accounts/types/MessageChannel';
type MessageChannel,
type MessageChannelContactAutoCreationPolicy,
type MessageFolderImportPolicy,
} from '@/accounts/types/MessageChannel';
import { UPDATE_MESSAGE_CHANNEL } from '@/settings/accounts/graphql/mutations/updateMessageChannel'; import { UPDATE_MESSAGE_CHANNEL } from '@/settings/accounts/graphql/mutations/updateMessageChannel';
import { useMutation } from '@apollo/client/react'; import { useMutation } from '@apollo/client/react';
import { SettingsAccountsMessageAutoCreationCard } from '@/settings/accounts/components/SettingsAccountsMessageAutoCreationCard'; import { SettingsAccountsMessageAutoCreationCard } from '@/settings/accounts/components/SettingsAccountsMessageAutoCreationCard';
@@ -16,6 +12,10 @@ import { H2Title, IconBriefcase, IconUsers } from 'twenty-ui/display';
import { Card, Section } from 'twenty-ui/layout'; import { Card, Section } from 'twenty-ui/layout';
import { themeCssVariables } from 'twenty-ui/theme-constants'; import { themeCssVariables } from 'twenty-ui/theme-constants';
import { type MessageChannelVisibility } from '~/generated/graphql'; import { type MessageChannelVisibility } from '~/generated/graphql';
import {
type MessageChannelContactAutoCreationPolicy,
type MessageFolderImportPolicy,
} from 'twenty-shared/types';
type SettingsAccountsMessageChannelDetailsProps = { type SettingsAccountsMessageChannelDetailsProps = {
messageChannel: Pick< messageChannel: Pick<
@@ -26,7 +26,6 @@ type SettingsAccountsMessageChannelDetailsProps = {
| 'excludeNonProfessionalEmails' | 'excludeNonProfessionalEmails'
| 'excludeGroupEmails' | 'excludeGroupEmails'
| 'isSyncEnabled' | 'isSyncEnabled'
| 'messageFolders'
| 'messageFolderImportPolicy' | 'messageFolderImportPolicy'
>; >;
}; };
@@ -11,6 +11,7 @@ import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTab
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue'; import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState'; import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState';
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import { MessageChannelSyncStage } from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils'; import { isDefined } from 'twenty-shared/utils';
import { themeCssVariables } from 'twenty-ui/theme-constants'; import { themeCssVariables } from 'twenty-ui/theme-constants';
@@ -27,7 +28,13 @@ export const SettingsAccountsMessageChannelsContainer = () => {
settingsAccountsSelectedMessageChannelState, settingsAccountsSelectedMessageChannelState,
); );
const { channels: messageChannels } = useMyMessageChannels(); const { channels: allMessageChannels } = useMyMessageChannels();
const messageChannels = allMessageChannels.filter(
(channel) =>
channel.isSyncEnabled &&
channel.syncStage !== MessageChannelSyncStage.PENDING_CONFIGURATION,
);
const tabs = messageChannels.map((messageChannel) => ({ const tabs = messageChannels.map((messageChannel) => ({
id: messageChannel.id, id: messageChannel.id,
@@ -1,8 +1,8 @@
import { MessageFolderImportPolicy } from '@/accounts/types/MessageChannel';
import { SettingsAccountsMessageFoldersCard } from '@/settings/accounts/components/message-folders/SettingsAccountsMessageFoldersCard'; import { SettingsAccountsMessageFoldersCard } from '@/settings/accounts/components/message-folders/SettingsAccountsMessageFoldersCard';
import { SettingsAccountsMessageFolderIcon } from '@/settings/accounts/components/SettingsAccountsMessageFolderIcon'; import { SettingsAccountsMessageFolderIcon } from '@/settings/accounts/components/SettingsAccountsMessageFolderIcon';
import { SettingsAccountsRadioSettingsCard } from '@/settings/accounts/components/SettingsAccountsRadioSettingsCard'; import { SettingsAccountsRadioSettingsCard } from '@/settings/accounts/components/SettingsAccountsRadioSettingsCard';
import { msg } from '@lingui/core/macro'; import { msg } from '@lingui/core/macro';
import { MessageFolderImportPolicy } from 'twenty-shared/types';
type SettingsAccountsMessageFolderCardProps = { type SettingsAccountsMessageFolderCardProps = {
onChange: (nextValue: MessageFolderImportPolicy) => void; onChange: (nextValue: MessageFolderImportPolicy) => void;
@@ -1,6 +1,6 @@
import { styled } from '@linaria/react'; import { styled } from '@linaria/react';
import { MessageFolderImportPolicy } from 'twenty-shared/types';
import { MessageFolderImportPolicy } from '@/accounts/types/MessageChannel';
import { themeCssVariables } from 'twenty-ui/theme-constants'; import { themeCssVariables } from 'twenty-ui/theme-constants';
type SettingsAccountsMessageFolderIconProps = { type SettingsAccountsMessageFolderIconProps = {
@@ -1,8 +1,11 @@
import { useApolloClient, useMutation } from '@apollo/client/react';
import { type ConnectedAccount } from '@/accounts/types/ConnectedAccount'; import { type ConnectedAccount } from '@/accounts/types/ConnectedAccount';
import { CalendarChannelSyncStage } from '@/accounts/types/CalendarChannel'; import { useApolloClient, useMutation } from '@apollo/client/react';
import { MessageChannelSyncStage } from '@/accounts/types/MessageChannel'; import {
import { ConnectedAccountProvider, SettingsPath } from 'twenty-shared/types'; CalendarChannelSyncStage,
ConnectedAccountProvider,
MessageChannelSyncStage,
SettingsPath,
} from 'twenty-shared/types';
import { useTriggerProviderReconnect } from '@/settings/accounts/hooks/useTriggerProviderReconnect'; import { useTriggerProviderReconnect } from '@/settings/accounts/hooks/useTriggerProviderReconnect';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
@@ -3,7 +3,7 @@ import { type Meta, type StoryObj } from '@storybook/react-vite';
import { import {
MessageChannelContactAutoCreationPolicy, MessageChannelContactAutoCreationPolicy,
MessageFolderImportPolicy, MessageFolderImportPolicy,
} from '@/accounts/types/MessageChannel'; } from 'twenty-shared/types';
import { SettingsAccountsMessageChannelDetails } from '@/settings/accounts/components/SettingsAccountsMessageChannelDetails'; import { SettingsAccountsMessageChannelDetails } from '@/settings/accounts/components/SettingsAccountsMessageChannelDetails';
import { ComponentDecorator } from 'twenty-ui/testing'; import { ComponentDecorator } from 'twenty-ui/testing';
import { MessageChannelVisibility } from '~/generated/graphql'; import { MessageChannelVisibility } from '~/generated/graphql';
@@ -27,7 +27,6 @@ const meta: Meta<typeof SettingsAccountsMessageChannelDetails> = {
excludeGroupEmails: false, excludeGroupEmails: false,
isSyncEnabled: true, isSyncEnabled: true,
visibility: MessageChannelVisibility.SHARE_EVERYTHING, visibility: MessageChannelVisibility.SHARE_EVERYTHING,
messageFolders: [],
messageFolderImportPolicy: MessageFolderImportPolicy.ALL_FOLDERS, messageFolderImportPolicy: MessageFolderImportPolicy.ALL_FOLDERS,
}, },
}, },
@@ -15,6 +15,7 @@ describe('computeFolderIdsForSyncToggle', () => {
externalId?: string | null; externalId?: string | null;
isSynced?: boolean; isSynced?: boolean;
}): MessageFolder => ({ }): MessageFolder => ({
__typename: 'MessageFolder',
id, id,
name, name,
parentFolderId, parentFolderId,
@@ -22,8 +23,8 @@ describe('computeFolderIdsForSyncToggle', () => {
isSentFolder: false, isSentFolder: false,
isSynced, isSynced,
messageChannelId: 'channel-1', messageChannelId: 'channel-1',
__typename: 'MessageFolder', createdAt: '2026-01-01T00:00:00Z',
syncCursor: '', updatedAt: '2026-01-01T00:00:00Z',
}); });
describe('when syncing a folder', () => { describe('when syncing a folder', () => {
@@ -8,6 +8,7 @@ describe('computeMessageFolderTree', () => {
parentFolderId: string | null = null, parentFolderId: string | null = null,
externalId: string | null = null, externalId: string | null = null,
): MessageFolder => ({ ): MessageFolder => ({
__typename: 'MessageFolder',
id, id,
name, name,
parentFolderId, parentFolderId,
@@ -15,8 +16,8 @@ describe('computeMessageFolderTree', () => {
isSentFolder: false, isSentFolder: false,
isSynced: false, isSynced: false,
messageChannelId: '20202020-1c25-4d02-bf25-6aeccf7ea419', messageChannelId: '20202020-1c25-4d02-bf25-6aeccf7ea419',
__typename: 'MessageFolder', createdAt: '2026-01-01T00:00:00Z',
syncCursor: '', updatedAt: '2026-01-01T00:00:00Z',
}); });
it('should return empty array for empty input', () => { it('should return empty array for empty input', () => {
@@ -11,6 +11,27 @@ export const GET_MY_CONNECTED_ACCOUNTS = gql`
handleAliases handleAliases
lastSignedInAt lastSignedInAt
userWorkspaceId userWorkspaceId
connectionParameters {
IMAP {
host
port
secure
username
password
}
SMTP {
host
port
secure
username
password
}
CALDAV {
host
username
password
}
}
createdAt createdAt
updatedAt updatedAt
} }
@@ -1,66 +1,18 @@
import { type CalendarChannel } from '@/accounts/types/CalendarChannel'; import { type CalendarChannel } from '@/accounts/types/CalendarChannel';
import { GET_MY_CALENDAR_CHANNELS } from '@/settings/accounts/graphql/queries/getMyCalendarChannels'; import { GET_MY_CALENDAR_CHANNELS } from '@/settings/accounts/graphql/queries/getMyCalendarChannels';
import { useApolloClient, useQuery } from '@apollo/client/react'; import { useApolloClient, useQuery } from '@apollo/client/react';
import { useMemo } from 'react';
type MetadataCalendarChannel = {
id: string;
handle: string;
visibility: string;
syncStatus: string;
syncStage: string;
syncStageStartedAt: string | null;
isContactAutoCreationEnabled: boolean;
contactAutoCreationPolicy: string;
isSyncEnabled: boolean;
connectedAccountId: string;
createdAt: string;
updatedAt: string;
};
export const useMyCalendarChannels = () => { export const useMyCalendarChannels = () => {
const apolloClient = useApolloClient(); const apolloClient = useApolloClient();
const { data: metadataData, loading: metadataLoading } = useQuery<{ const { data, loading } = useQuery<{
myCalendarChannels: MetadataCalendarChannel[]; myCalendarChannels: CalendarChannel[];
}>(GET_MY_CALENDAR_CHANNELS, { }>(GET_MY_CALENDAR_CHANNELS, {
client: apolloClient, client: apolloClient,
}); });
const channels = useMemo(() => {
if (!metadataData?.myCalendarChannels) {
return [];
}
return metadataData.myCalendarChannels
.filter(
(channel: MetadataCalendarChannel) =>
channel.syncStage !== 'PENDING_CONFIGURATION',
)
.map(
(channel: MetadataCalendarChannel) =>
({
id: channel.id,
handle: channel.handle,
visibility: channel.visibility,
isContactAutoCreationEnabled: channel.isContactAutoCreationEnabled,
contactAutoCreationPolicy: channel.contactAutoCreationPolicy,
isSyncEnabled: channel.isSyncEnabled,
syncStatus: channel.syncStatus,
syncStage: channel.syncStage,
syncCursor: '',
syncStageStartedAt: channel.syncStageStartedAt
? new Date(channel.syncStageStartedAt)
: null,
throttleFailureCount: 0,
connectedAccountId: channel.connectedAccountId,
__typename: 'CalendarChannel',
}) as CalendarChannel,
);
}, [metadataData]);
return { return {
channels, channels: data?.myCalendarChannels ?? [],
loading: metadataLoading, loading,
}; };
}; };
@@ -5,24 +5,16 @@ import { useMyMessageChannels } from '@/settings/accounts/hooks/useMyMessageChan
import { useApolloClient, useQuery } from '@apollo/client/react'; import { useApolloClient, useQuery } from '@apollo/client/react';
import { useMemo } from 'react'; import { useMemo } from 'react';
type MetadataConnectedAccount = { type CoreConnectedAccount = Omit<
id: string; ConnectedAccount,
handle: string; 'messageChannels' | 'calendarChannels'
provider: string; >;
authFailedAt: string | null;
scopes: string[] | null;
handleAliases: string[] | null;
lastSignedInAt: string | null;
userWorkspaceId: string;
createdAt: string;
updatedAt: string;
};
export const useMyConnectedAccounts = () => { export const useMyConnectedAccounts = () => {
const apolloClient = useApolloClient(); const apolloClient = useApolloClient();
const { data: metadataData, loading: metadataLoading } = useQuery<{ const { data, loading: accountsLoading } = useQuery<{
myConnectedAccounts: MetadataConnectedAccount[]; myConnectedAccounts: CoreConnectedAccount[];
}>(GET_MY_CONNECTED_ACCOUNTS, { }>(GET_MY_CONNECTED_ACCOUNTS, {
client: apolloClient, client: apolloClient,
}); });
@@ -33,48 +25,24 @@ export const useMyConnectedAccounts = () => {
useMyCalendarChannels(); useMyCalendarChannels();
const accounts = useMemo<ConnectedAccount[]>(() => { const accounts = useMemo<ConnectedAccount[]>(() => {
if (!metadataData?.myConnectedAccounts) { if (!data?.myConnectedAccounts) {
return []; return [];
} }
return metadataData.myConnectedAccounts return data.myConnectedAccounts.map((account) => ({
.map( ...account,
(account: MetadataConnectedAccount) => messageChannels: messageChannels.filter(
({ (channel) => channel.connectedAccountId === account.id,
id: account.id, ),
handle: account.handle, calendarChannels: calendarChannels.filter(
provider: account.provider, (channel) => channel.connectedAccountId === account.id,
accessToken: '', ),
refreshToken: '', }));
accountOwnerId: account.userWorkspaceId, }, [data, messageChannels, calendarChannels]);
lastSyncHistoryId: '',
authFailedAt: account.authFailedAt
? new Date(account.authFailedAt)
: null,
messageChannels: messageChannels.filter(
(channel) =>
'connectedAccountId' in channel &&
channel.connectedAccountId === account.id,
),
calendarChannels: calendarChannels.filter(
(channel) =>
'connectedAccountId' in channel &&
channel.connectedAccountId === account.id,
),
scopes: account.scopes,
__typename: 'ConnectedAccount',
}) as ConnectedAccount,
)
.filter(
(account) =>
account.messageChannels.length > 0 ||
account.calendarChannels.length > 0,
);
}, [metadataData, messageChannels, calendarChannels]);
return { return {
accounts, accounts,
loading: loading:
metadataLoading || messageChannelsLoading || calendarChannelsLoading, accountsLoading || messageChannelsLoading || calendarChannelsLoading,
}; };
}; };
@@ -1,74 +1,18 @@
import { type MessageChannel } from '@/accounts/types/MessageChannel'; import { type MessageChannel } from '@/accounts/types/MessageChannel';
import { GET_MY_MESSAGE_CHANNELS } from '@/settings/accounts/graphql/queries/getMyMessageChannels'; import { GET_MY_MESSAGE_CHANNELS } from '@/settings/accounts/graphql/queries/getMyMessageChannels';
import { useApolloClient, useQuery } from '@apollo/client/react'; import { useApolloClient, useQuery } from '@apollo/client/react';
import { useMemo } from 'react';
type MetadataMessageChannel = {
id: string;
handle: string;
visibility: string;
type: string;
isContactAutoCreationEnabled: boolean;
contactAutoCreationPolicy: string;
messageFolderImportPolicy: string;
excludeNonProfessionalEmails: boolean;
excludeGroupEmails: boolean;
isSyncEnabled: boolean;
syncStatus: string;
syncStage: string;
syncStageStartedAt: string | null;
connectedAccountId: string;
createdAt: string;
updatedAt: string;
};
export const useMyMessageChannels = () => { export const useMyMessageChannels = () => {
const apolloClient = useApolloClient(); const apolloClient = useApolloClient();
const { data: metadataData, loading: metadataLoading } = useQuery<{ const { data, loading } = useQuery<{
myMessageChannels: MetadataMessageChannel[]; myMessageChannels: MessageChannel[];
}>(GET_MY_MESSAGE_CHANNELS, { }>(GET_MY_MESSAGE_CHANNELS, {
client: apolloClient, client: apolloClient,
}); });
const channels = useMemo(() => {
if (!metadataData?.myMessageChannels) {
return [];
}
return metadataData.myMessageChannels
.filter(
(channel: MetadataMessageChannel) =>
channel.isSyncEnabled &&
channel.syncStage !== 'PENDING_CONFIGURATION',
)
.map(
(channel: MetadataMessageChannel) =>
({
id: channel.id,
handle: channel.handle,
visibility: channel.visibility,
contactAutoCreationPolicy: channel.contactAutoCreationPolicy,
excludeNonProfessionalEmails: channel.excludeNonProfessionalEmails,
excludeGroupEmails: channel.excludeGroupEmails,
isSyncEnabled: channel.isSyncEnabled,
messageFolders: [],
messageFolderImportPolicy: channel.messageFolderImportPolicy,
syncStatus: channel.syncStatus,
syncStage: channel.syncStage,
syncCursor: '',
syncStageStartedAt: channel.syncStageStartedAt
? new Date(channel.syncStageStartedAt)
: null,
throttleFailureCount: 0,
connectedAccountId: channel.connectedAccountId,
__typename: 'MessageChannel',
}) as MessageChannel,
);
}, [metadataData]);
return { return {
channels, channels: data?.myMessageChannels ?? [],
loading: metadataLoading, loading,
}; };
}; };
@@ -1,52 +1,19 @@
import { type MessageFolder } from '@/accounts/types/MessageFolder'; import { type MessageFolder } from '@/accounts/types/MessageFolder';
import { GET_MY_MESSAGE_FOLDERS } from '@/settings/accounts/graphql/queries/getMyMessageFolders'; import { GET_MY_MESSAGE_FOLDERS } from '@/settings/accounts/graphql/queries/getMyMessageFolders';
import { useApolloClient, useQuery } from '@apollo/client/react'; import { useApolloClient, useQuery } from '@apollo/client/react';
import { useMemo } from 'react';
type MetadataMessageFolder = {
id: string;
name: string | null;
isSynced: boolean;
isSentFolder: boolean;
parentFolderId: string | null;
externalId: string | null;
messageChannelId: string;
createdAt: string;
updatedAt: string;
};
export const useMyMessageFolders = (messageChannelId?: string) => { export const useMyMessageFolders = (messageChannelId?: string) => {
const apolloClient = useApolloClient(); const apolloClient = useApolloClient();
const { data: metadataData, loading: metadataLoading } = useQuery<{ const { data, loading } = useQuery<{
myMessageFolders: MetadataMessageFolder[]; myMessageFolders: MessageFolder[];
}>(GET_MY_MESSAGE_FOLDERS, { }>(GET_MY_MESSAGE_FOLDERS, {
client: apolloClient, client: apolloClient,
variables: messageChannelId ? { messageChannelId } : undefined, variables: messageChannelId ? { messageChannelId } : undefined,
}); });
const messageFolders = useMemo<MessageFolder[]>(() => {
if (!metadataData?.myMessageFolders) {
return [];
}
return metadataData.myMessageFolders.map(
(folder: MetadataMessageFolder) => ({
id: folder.id,
name: folder.name ?? '',
syncCursor: '',
isSynced: folder.isSynced,
isSentFolder: folder.isSentFolder,
parentFolderId: folder.parentFolderId,
messageChannelId: folder.messageChannelId,
externalId: folder.externalId,
__typename: 'MessageFolder' as const,
}),
);
}, [metadataData]);
return { return {
messageFolders, messageFolders: data?.myMessageFolders ?? [],
loading: metadataLoading, loading,
}; };
}; };
@@ -1,13 +1,11 @@
import { SyncStatus } from '@/settings/accounts/constants/SyncStatus';
import { computeSyncStatus } from '@/settings/accounts/utils/computeSyncStatus';
import { import {
CalendarChannelSyncStage, CalendarChannelSyncStage,
CalendarChannelSyncStatus, CalendarChannelSyncStatus,
} from '@/accounts/types/CalendarChannel';
import {
MessageChannelSyncStage, MessageChannelSyncStage,
MessageChannelSyncStatus, MessageChannelSyncStatus,
} from '@/accounts/types/MessageChannel'; } from 'twenty-shared/types';
import { SyncStatus } from '@/settings/accounts/constants/SyncStatus';
import { computeSyncStatus } from '@/settings/accounts/utils/computeSyncStatus';
describe('computeSyncStatus', () => { describe('computeSyncStatus', () => {
test('should return PENDING_CONFIGURATION when message channel sync stage is PENDING_CONFIGURATION', () => { test('should return PENDING_CONFIGURATION when message channel sync stage is PENDING_CONFIGURATION', () => {
@@ -1,14 +1,12 @@
import { type CalendarChannel } from '@/accounts/types/CalendarChannel';
import { type MessageChannel } from '@/accounts/types/MessageChannel';
import { SyncStatus } from '@/settings/accounts/constants/SyncStatus';
import { import {
type CalendarChannel,
CalendarChannelSyncStage, CalendarChannelSyncStage,
CalendarChannelSyncStatus, CalendarChannelSyncStatus,
} from '@/accounts/types/CalendarChannel';
import {
type MessageChannel,
MessageChannelSyncStage, MessageChannelSyncStage,
MessageChannelSyncStatus, MessageChannelSyncStatus,
} from '@/accounts/types/MessageChannel'; } from 'twenty-shared/types';
import { SyncStatus } from '@/settings/accounts/constants/SyncStatus';
export const computeSyncStatus = ( export const computeSyncStatus = (
messageChannel?: Pick<MessageChannel, 'syncStatus' | 'syncStage'>, messageChannel?: Pick<MessageChannel, 'syncStatus' | 'syncStage'>,
@@ -113,7 +113,7 @@ export const WorkflowEditActionEmailBase = ({
const filter: { or: object[] } = { const filter: { or: object[] } = {
or: [ or: [
{ {
accountOwnerId: { userWorkspaceId: {
eq: currentWorkspaceMember?.id, eq: currentWorkspaceMember?.id,
}, },
}, },
@@ -139,7 +139,7 @@ export const WorkflowEditActionEmailBase = ({
handle: true, handle: true,
provider: true, provider: true,
scopes: true, scopes: true,
accountOwnerId: true, userWorkspaceId: true,
connectionParameters: true, connectionParameters: true,
}, },
}); });
@@ -181,7 +181,7 @@ export const WorkflowEditActionEmailBase = ({
label: account.handle, label: account.handle,
value: account.id, value: account.id,
}; };
if (account.accountOwnerId === currentWorkspaceMember?.id) { if (account.userWorkspaceId === currentWorkspaceMember?.id) {
connectedAccountOptions.push(selectOption); connectedAccountOptions.push(selectOption);
} else { } else {
emptyOption = selectOption; emptyOption = selectOption;
@@ -53,8 +53,7 @@ const CONFIGURED_SEND_EMAIL_ACTION: WorkflowSendEmailAction = {
valid: true, valid: true,
settings: { settings: {
input: { input: {
connectedAccountId: mockedConnectedAccountRecords[0] connectedAccountId: mockedConnectedAccountRecords[0].id as string,
.accountOwnerId as string,
recipients: { recipients: {
to: 'test@twenty.com', to: 'test@twenty.com',
cc: '', cc: '',
@@ -10,6 +10,7 @@ import {
} from 'class-validator'; } from 'class-validator';
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars'; import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
import { ImapSmtpCaldavConnectionParametersDTO } from 'src/engine/core-modules/imap-smtp-caldav-connection/dtos/imap-smtp-caldav-connection.dto';
@ObjectType('ConnectedAccountDTO') @ObjectType('ConnectedAccountDTO')
export class ConnectedAccountDTO { export class ConnectedAccountDTO {
@@ -54,8 +55,9 @@ export class ConnectedAccountDTO {
@Field(() => [String], { nullable: true }) @Field(() => [String], { nullable: true })
scopes: string[] | null; scopes: string[] | null;
@HideField() @IsOptional()
connectionParameters: Record<string, unknown> | null; @Field(() => ImapSmtpCaldavConnectionParametersDTO, { nullable: true })
connectionParameters: ImapSmtpCaldavConnectionParametersDTO | null;
@IsDateString() @IsDateString()
@IsOptional() @IsOptional()
@@ -331,7 +331,7 @@ describe('SyncMessageFoldersService', () => {
id: 'folder-1', id: 'folder-1',
externalId: 'child-ext', externalId: 'child-ext',
name: 'Projects', name: 'Projects',
parentFolderId: 'old-parent-uuid', parentFolderId: 'old-parent-ext',
}); });
const discoveredFolders = [ const discoveredFolders = [
createMockDiscoveredFolder({ createMockDiscoveredFolder({
@@ -360,7 +360,7 @@ describe('SyncMessageFoldersService', () => {
expect(mockMessageFolderRepository.update).toHaveBeenCalledWith( expect(mockMessageFolderRepository.update).toHaveBeenCalledWith(
{ id: 'folder-1', messageChannelId: 'channel-123', workspaceId }, { id: 'folder-1', messageChannelId: 'channel-123', workspaceId },
expect.objectContaining({ expect.objectContaining({
parentFolderId: 'new-parent-uuid', parentFolderId: 'new-parent-id',
}), }),
); );
}); });
@@ -115,12 +115,6 @@ export class SyncMessageFoldersService {
messageChannelId: string, messageChannelId: string,
workspaceId: string, workspaceId: string,
): Promise<MessageFolder[]> { ): Promise<MessageFolder[]> {
const externalIdToUuidMap = new Map(
existingFolders
.filter((folder) => isDefined(folder.externalId))
.map((folder) => [folder.externalId as string, folder.id]),
);
const foldersToCreate = computeFoldersToCreate({ const foldersToCreate = computeFoldersToCreate({
discoveredFolders, discoveredFolders,
existingFolders, existingFolders,
@@ -130,7 +124,6 @@ export class SyncMessageFoldersService {
const foldersToUpdate = computeFoldersToUpdate({ const foldersToUpdate = computeFoldersToUpdate({
discoveredFolders, discoveredFolders,
existingFolders, existingFolders,
externalIdToUuidMap,
}); });
const folderIdsToDelete = computeFolderIdsToDelete({ const folderIdsToDelete = computeFolderIdsToDelete({
@@ -2,8 +2,6 @@ import { MessageFolderPendingSyncAction } from 'twenty-shared/types';
import { computeFoldersToUpdate } from 'src/modules/messaging/message-folder-manager/utils/compute-folders-to-update.util'; import { computeFoldersToUpdate } from 'src/modules/messaging/message-folder-manager/utils/compute-folders-to-update.util';
describe('computeFoldersToUpdate', () => { describe('computeFoldersToUpdate', () => {
const emptyMap = new Map<string, string>();
it('should detect folder rename from provider', () => { it('should detect folder rename from provider', () => {
const discoveredFolders = [ const discoveredFolders = [
{ {
@@ -31,15 +29,12 @@ describe('computeFoldersToUpdate', () => {
const result = computeFoldersToUpdate({ const result = computeFoldersToUpdate({
discoveredFolders, discoveredFolders,
existingFolders, existingFolders,
externalIdToUuidMap: emptyMap,
}); });
expect(result.get('folder-id')?.name).toBe('Work Emails'); expect(result.get('folder-id')?.name).toBe('Work Emails');
}); });
it('should detect folder moved to different parent', () => { it('should detect folder moved to different parent', () => {
const existingParentUuid = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee';
const discoveredFolders = [ const discoveredFolders = [
{ {
name: 'Subfolder', name: 'Subfolder',
@@ -57,23 +52,18 @@ describe('computeFoldersToUpdate', () => {
externalId: 'sub-1', externalId: 'sub-1',
isSynced: true, isSynced: true,
isSentFolder: false, isSentFolder: false,
parentFolderId: 'old-parent-uuid', parentFolderId: 'old-parent-ext',
syncCursor: 'cursor', syncCursor: 'cursor',
pendingSyncAction: MessageFolderPendingSyncAction.NONE, pendingSyncAction: MessageFolderPendingSyncAction.NONE,
}, },
]; ];
const externalIdToUuidMap = new Map([
['new-parent-ext', existingParentUuid],
]);
const result = computeFoldersToUpdate({ const result = computeFoldersToUpdate({
discoveredFolders, discoveredFolders,
existingFolders, existingFolders,
externalIdToUuidMap,
}); });
expect(result.get('folder-id')?.parentFolderId).toBe(existingParentUuid); expect(result.get('folder-id')?.parentFolderId).toBe('new-parent-ext');
}); });
it('should not flag unchanged folders for update', () => { it('should not flag unchanged folders for update', () => {
@@ -98,7 +88,6 @@ describe('computeFoldersToUpdate', () => {
const result = computeFoldersToUpdate({ const result = computeFoldersToUpdate({
discoveredFolders, discoveredFolders,
existingFolders, existingFolders,
externalIdToUuidMap: emptyMap,
}); });
expect(result.size).toBe(0); expect(result.size).toBe(0);
@@ -131,7 +120,6 @@ describe('computeFoldersToUpdate', () => {
const result = computeFoldersToUpdate({ const result = computeFoldersToUpdate({
discoveredFolders, discoveredFolders,
existingFolders, existingFolders,
externalIdToUuidMap: emptyMap,
}); });
expect(result.size).toBe(0); expect(result.size).toBe(0);
@@ -11,11 +11,9 @@ import { type MessageFolderEntity } from 'src/engine/metadata-modules/message-fo
export const computeFoldersToUpdate = ({ export const computeFoldersToUpdate = ({
discoveredFolders, discoveredFolders,
existingFolders, existingFolders,
externalIdToUuidMap,
}: { }: {
discoveredFolders: DiscoveredMessageFolder[]; discoveredFolders: DiscoveredMessageFolder[];
existingFolders: MessageFolder[]; existingFolders: MessageFolder[];
externalIdToUuidMap: Map<string, string>;
}): Map<string, Partial<MessageFolderEntity>> => { }): Map<string, Partial<MessageFolderEntity>> => {
const existingFoldersByExternalId = new Map( const existingFoldersByExternalId = new Map(
existingFolders.map((folder) => [folder.externalId, folder]), existingFolders.map((folder) => [folder.externalId, folder]),
@@ -32,16 +30,14 @@ export const computeFoldersToUpdate = ({
continue; continue;
} }
const resolvedParentFolderId = isNonEmptyString( const parentFolderId = isNonEmptyString(discoveredFolder.parentFolderId)
discoveredFolder.parentFolderId, ? discoveredFolder.parentFolderId
)
? (externalIdToUuidMap.get(discoveredFolder.parentFolderId) ?? null)
: null; : null;
const discoveredFolderData = { const discoveredFolderData = {
name: discoveredFolder.name, name: discoveredFolder.name,
isSentFolder: discoveredFolder.isSentFolder, isSentFolder: discoveredFolder.isSentFolder,
parentFolderId: resolvedParentFolderId, parentFolderId,
}; };
const existingFolderData = { const existingFolderData = {