From 6ad956604309a8ce090f0b14cdef58d8fd6b4cde Mon Sep 17 00:00:00 2001 From: neo773 <62795688+neo773@users.noreply.github.com> Date: Tue, 7 Apr 2026 16:51:27 +0530 Subject: [PATCH] Add messaging upgrade command 1 21 (#19389) ``` [Nest] 50057 - 04/07/2026, 4:14:10 PM LOG [WorkspaceIteratorService] Running on workspace 20202020-1c25-4d02-bf25-6aeccf7ea419 1/2 [Nest] 50057 - 04/07/2026, 4:14:10 PM LOG [MigrateMessagingInfrastructureToMetadataCommand] Migrated 5 connected accounts for workspace 20202020-1c25-4d02-bf25-6aeccf7ea419 [Nest] 50057 - 04/07/2026, 4:14:10 PM LOG [MigrateMessagingInfrastructureToMetadataCommand] Migrated 6 message channels for workspace 20202020-1c25-4d02-bf25-6aeccf7ea419 [Nest] 50057 - 04/07/2026, 4:14:10 PM LOG [MigrateMessagingInfrastructureToMetadataCommand] Migrated 6 calendar channels for workspace 20202020-1c25-4d02-bf25-6aeccf7ea419 [Nest] 50057 - 04/07/2026, 4:14:10 PM LOG [MigrateMessagingInfrastructureToMetadataCommand] Migrated 5 message folders for workspace 20202020-1c25-4d02-bf25-6aeccf7ea419 [Nest] 50057 - 04/07/2026, 4:14:10 PM LOG [WorkspaceIteratorService] Running on workspace 3b8e6458-5fc1-4e63-8563-008ccddaa6db 2/2 [Nest] 50057 - 04/07/2026, 4:14:10 PM LOG [MigrateMessagingInfrastructureToMetadataCommand] Migrated 5 connected accounts for workspace 3b8e6458-5fc1-4e63-8563-008ccddaa6db [Nest] 50057 - 04/07/2026, 4:14:11 PM LOG [MigrateMessagingInfrastructureToMetadataCommand] Migrated 4 message channels for workspace 3b8e6458-5fc1-4e63-8563-008ccddaa6db [Nest] 50057 - 04/07/2026, 4:14:11 PM LOG [MigrateMessagingInfrastructureToMetadataCommand] Migrated 4 calendar channels for workspace 3b8e6458-5fc1-4e63-8563-008ccddaa6db [Nest] 50057 - 04/07/2026, 4:14:11 PM LOG [MigrateMessagingInfrastructureToMetadataCommand] Migrated 10 message folders for workspace 3b8e6458-5fc1-4e63-8563-008ccddaa6db [Nest] 50057 - 04/07/2026, 4:14:11 PM LOG [MigrateMessagingInfrastructureToMetadataCommand] Command completed! ``` --- .../src/metadata/generated/schema.graphql | 1 + .../src/metadata/generated/schema.ts | 3 +- .../src/generated-metadata/graphql.ts | 1 + ...ging-infrastructure-to-metadata.command.ts | 384 ++++++++++++++++++ .../1-21-upgrade-version-command.module.ts | 11 + .../workspace-entity-manager.spec.ts | 1 + .../twenty-shared/src/types/FeatureFlagKey.ts | 1 + 7 files changed, 401 insertions(+), 1 deletion(-) create mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/1-21/1-21-migrate-messaging-infrastructure-to-metadata.command.ts diff --git a/packages/twenty-client-sdk/src/metadata/generated/schema.graphql b/packages/twenty-client-sdk/src/metadata/generated/schema.graphql index 9745297ff1..e7ebc6199c 100644 --- a/packages/twenty-client-sdk/src/metadata/generated/schema.graphql +++ b/packages/twenty-client-sdk/src/metadata/generated/schema.graphql @@ -1736,6 +1736,7 @@ enum FeatureFlagKey { IS_EMAILING_DOMAIN_ENABLED IS_JUNCTION_RELATIONS_ENABLED IS_DRAFT_EMAIL_ENABLED + IS_CONNECTED_ACCOUNT_MIGRATED IS_USAGE_ANALYTICS_ENABLED IS_RICH_TEXT_V1_MIGRATED IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED diff --git a/packages/twenty-client-sdk/src/metadata/generated/schema.ts b/packages/twenty-client-sdk/src/metadata/generated/schema.ts index d8052f248f..de96dde40e 100644 --- a/packages/twenty-client-sdk/src/metadata/generated/schema.ts +++ b/packages/twenty-client-sdk/src/metadata/generated/schema.ts @@ -1429,7 +1429,7 @@ export interface PublicFeatureFlag { __typename: 'PublicFeatureFlag' } -export type FeatureFlagKey = 'IS_UNIQUE_INDEXES_ENABLED' | 'IS_JSON_FILTER_ENABLED' | 'IS_AI_ENABLED' | 'IS_COMMAND_MENU_ITEM_ENABLED' | 'IS_MARKETPLACE_ENABLED' | 'IS_MARKETPLACE_SETTING_TAB_VISIBLE' | 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED' | 'IS_PUBLIC_DOMAIN_ENABLED' | 'IS_EMAILING_DOMAIN_ENABLED' | 'IS_JUNCTION_RELATIONS_ENABLED' | 'IS_DRAFT_EMAIL_ENABLED' | 'IS_USAGE_ANALYTICS_ENABLED' | 'IS_RICH_TEXT_V1_MIGRATED' | 'IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED' | 'IS_RECORD_TABLE_WIDGET_ENABLED' | 'IS_DATASOURCE_MIGRATED' +export type FeatureFlagKey = 'IS_UNIQUE_INDEXES_ENABLED' | 'IS_JSON_FILTER_ENABLED' | 'IS_AI_ENABLED' | 'IS_COMMAND_MENU_ITEM_ENABLED' | 'IS_MARKETPLACE_ENABLED' | 'IS_MARKETPLACE_SETTING_TAB_VISIBLE' | 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED' | 'IS_PUBLIC_DOMAIN_ENABLED' | 'IS_EMAILING_DOMAIN_ENABLED' | 'IS_JUNCTION_RELATIONS_ENABLED' | 'IS_DRAFT_EMAIL_ENABLED' | 'IS_CONNECTED_ACCOUNT_MIGRATED' | 'IS_USAGE_ANALYTICS_ENABLED' | 'IS_RICH_TEXT_V1_MIGRATED' | 'IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED' | 'IS_RECORD_TABLE_WIDGET_ENABLED' | 'IS_DATASOURCE_MIGRATED' export interface ClientConfigMaintenanceMode { startAt: Scalars['DateTime'] @@ -9149,6 +9149,7 @@ export const enumFeatureFlagKey = { IS_EMAILING_DOMAIN_ENABLED: 'IS_EMAILING_DOMAIN_ENABLED' as const, IS_JUNCTION_RELATIONS_ENABLED: 'IS_JUNCTION_RELATIONS_ENABLED' as const, IS_DRAFT_EMAIL_ENABLED: 'IS_DRAFT_EMAIL_ENABLED' as const, + IS_CONNECTED_ACCOUNT_MIGRATED: 'IS_CONNECTED_ACCOUNT_MIGRATED' as const, IS_USAGE_ANALYTICS_ENABLED: 'IS_USAGE_ANALYTICS_ENABLED' as const, IS_RICH_TEXT_V1_MIGRATED: 'IS_RICH_TEXT_V1_MIGRATED' as const, IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED: 'IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED' as const, diff --git a/packages/twenty-front/src/generated-metadata/graphql.ts b/packages/twenty-front/src/generated-metadata/graphql.ts index 85735b2350..ca2d311aa0 100644 --- a/packages/twenty-front/src/generated-metadata/graphql.ts +++ b/packages/twenty-front/src/generated-metadata/graphql.ts @@ -1730,6 +1730,7 @@ export type FeatureFlag = { export enum FeatureFlagKey { IS_AI_ENABLED = 'IS_AI_ENABLED', IS_COMMAND_MENU_ITEM_ENABLED = 'IS_COMMAND_MENU_ITEM_ENABLED', + IS_CONNECTED_ACCOUNT_MIGRATED = 'IS_CONNECTED_ACCOUNT_MIGRATED', IS_DATASOURCE_MIGRATED = 'IS_DATASOURCE_MIGRATED', IS_DRAFT_EMAIL_ENABLED = 'IS_DRAFT_EMAIL_ENABLED', IS_EMAILING_DOMAIN_ENABLED = 'IS_EMAILING_DOMAIN_ENABLED', diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-21/1-21-migrate-messaging-infrastructure-to-metadata.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-21/1-21-migrate-messaging-infrastructure-to-metadata.command.ts new file mode 100644 index 0000000000..e5e560f8ff --- /dev/null +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/1-21/1-21-migrate-messaging-infrastructure-to-metadata.command.ts @@ -0,0 +1,384 @@ +import { InjectRepository } from '@nestjs/typeorm'; + +import { isNonEmptyString } from '@sniptt/guards'; +import { Command } from 'nest-commander'; +import { FeatureFlagKey } from 'twenty-shared/types'; +import { Repository } from 'typeorm'; + +import { ActiveOrSuspendedWorkspaceCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspace.command-runner'; +import { type RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspace.command-runner'; +import { WorkspaceIteratorService } from 'src/database/commands/command-runners/workspace-iterator.service'; +import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service'; +import { UserWorkspaceEntity } from 'src/engine/core-modules/user-workspace/user-workspace.entity'; +import { CalendarChannelEntity } from 'src/engine/metadata-modules/calendar-channel/entities/calendar-channel.entity'; +import { ConnectedAccountEntity } from 'src/engine/metadata-modules/connected-account/entities/connected-account.entity'; +import { MessageChannelEntity } from 'src/engine/metadata-modules/message-channel/entities/message-channel.entity'; +import { MessageFolderEntity } from 'src/engine/metadata-modules/message-folder/entities/message-folder.entity'; +import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; +import { type ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; +import { type MessageFolderWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-folder.workspace-entity'; +import { type WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; + +@Command({ + name: 'upgrade:1-21:migrate-messaging-infrastructure-to-metadata', + description: + 'Backfill connectedAccount, messageChannel, calendarChannel, and messageFolder to core metadata schema', +}) +export class MigrateMessagingInfrastructureToMetadataCommand extends ActiveOrSuspendedWorkspaceCommandRunner { + constructor( + private readonly twentyORMGlobalManager: GlobalWorkspaceOrmManager, + @InjectRepository(ConnectedAccountEntity) + private readonly connectedAccountRepository: Repository, + @InjectRepository(MessageChannelEntity) + private readonly messageChannelRepository: Repository, + @InjectRepository(CalendarChannelEntity) + private readonly calendarChannelRepository: Repository, + @InjectRepository(MessageFolderEntity) + private readonly messageFolderRepository: Repository, + @InjectRepository(UserWorkspaceEntity) + private readonly userWorkspaceRepository: Repository, + private readonly featureFlagService: FeatureFlagService, + protected readonly workspaceIteratorService: WorkspaceIteratorService, + ) { + super(workspaceIteratorService); + } + + override async runOnWorkspace({ + workspaceId, + options, + }: RunOnWorkspaceArgs): Promise { + const isMigrated = await this.featureFlagService.isFeatureEnabled( + FeatureFlagKey.IS_CONNECTED_ACCOUNT_MIGRATED, + workspaceId, + ); + + if (isMigrated) { + this.logger.log( + `Messaging infrastructure migration already completed for workspace ${workspaceId}. Skipping.`, + ); + + return; + } + + const isDryRun = options.dryRun ?? false; + + const connectedAccountWorkspaceRepository = + await this.twentyORMGlobalManager.getRepository( + workspaceId, + 'connectedAccount', + ); + + const messageChannelWorkspaceRepository = + await this.twentyORMGlobalManager.getRepository( + workspaceId, + 'messageChannel', + ); + + const calendarChannelWorkspaceRepository = + await this.twentyORMGlobalManager.getRepository( + workspaceId, + 'calendarChannel', + ); + + const messageFolderWorkspaceRepository = + await this.twentyORMGlobalManager.getRepository( + workspaceId, + 'messageFolder', + ); + + const connectedAccounts = await connectedAccountWorkspaceRepository.find(); + const messageChannels = await messageChannelWorkspaceRepository.find(); + const calendarChannels = await calendarChannelWorkspaceRepository.find(); + const messageFolders = await messageFolderWorkspaceRepository.find(); + + const workspaceMemberIdToUserWorkspaceIdMap = + await this.buildWorkspaceMemberIdToUserWorkspaceIdMap(workspaceId); + + const connectedAccountsWithMissingHandle = connectedAccounts.filter( + (account) => !account.handle, + ); + const connectedAccountsWithUnresolvedOwner = connectedAccounts.filter( + (account) => + !workspaceMemberIdToUserWorkspaceIdMap.has(account.accountOwnerId), + ); + const messageChannelsWithMissingHandle = messageChannels.filter( + (channel) => !channel.handle, + ); + const calendarChannelsWithMissingHandle = calendarChannels.filter( + (channel) => !channel.handle, + ); + + if (isDryRun) { + this.logger.log( + `[DRY RUN] Workspace ${workspaceId}: ` + + `${connectedAccounts.length} connected accounts, ` + + `${messageChannels.length} message channels, ` + + `${calendarChannels.length} calendar channels, ` + + `${messageFolders.length} message folders`, + ); + + if (connectedAccountsWithMissingHandle.length > 0) { + this.logger.warn( + `[DRY RUN] ${connectedAccountsWithMissingHandle.length} connected accounts have empty handle`, + ); + } + + if (connectedAccountsWithUnresolvedOwner.length > 0) { + this.logger.warn( + `[DRY RUN] ${connectedAccountsWithUnresolvedOwner.length} connected accounts have unresolvable accountOwnerId (no matching userWorkspace)`, + ); + } + + if (messageChannelsWithMissingHandle.length > 0) { + this.logger.warn( + `[DRY RUN] ${messageChannelsWithMissingHandle.length} message channels have empty handle`, + ); + } + + if (calendarChannelsWithMissingHandle.length > 0) { + this.logger.warn( + `[DRY RUN] ${calendarChannelsWithMissingHandle.length} calendar channels have empty handle`, + ); + } + + return; + } + + let migratedConnectedAccountIds = new Set( + connectedAccounts.map((account) => account.id), + ); + let migratedMessageChannelIds = new Set( + messageChannels.map((channel) => channel.id), + ); + + if (connectedAccounts.length > 0) { + const coreConnectedAccounts = connectedAccounts + .filter((workspaceEntity) => { + const userWorkspaceId = workspaceMemberIdToUserWorkspaceIdMap.get( + workspaceEntity.accountOwnerId, + ); + + if (!userWorkspaceId) { + this.logger.warn( + `Skipping connected account ${workspaceEntity.id}: no userWorkspace found for workspaceMember ${workspaceEntity.accountOwnerId}`, + ); + + return false; + } + + return true; + }) + .map((workspaceEntity) => { + const handleAliases = isNonEmptyString(workspaceEntity.handleAliases) + ? workspaceEntity.handleAliases + .split(',') + .map((alias) => alias.trim()) + : null; + + return { + id: workspaceEntity.id, + handle: workspaceEntity.handle ?? '', + provider: workspaceEntity.provider, + accessToken: workspaceEntity.accessToken, + refreshToken: workspaceEntity.refreshToken, + lastCredentialsRefreshedAt: + workspaceEntity.lastCredentialsRefreshedAt, + authFailedAt: workspaceEntity.authFailedAt, + handleAliases, + scopes: workspaceEntity.scopes, + connectionParameters: + workspaceEntity.connectionParameters as Record< + string, + unknown + > | null, + userWorkspaceId: workspaceMemberIdToUserWorkspaceIdMap.get( + workspaceEntity.accountOwnerId, + )!, + workspaceId, + createdAt: workspaceEntity.createdAt, + updatedAt: workspaceEntity.updatedAt, + }; + }); + + if (coreConnectedAccounts.length > 0) { + await this.connectedAccountRepository.save(coreConnectedAccounts); + this.logger.log( + `Migrated ${coreConnectedAccounts.length} connected accounts for workspace ${workspaceId}`, + ); + } + + migratedConnectedAccountIds = new Set( + coreConnectedAccounts.map((account) => account.id), + ); + } + + if (messageChannels.length > 0) { + const coreMessageChannels = messageChannels + .filter((workspaceEntity) => + migratedConnectedAccountIds.has(workspaceEntity.connectedAccountId), + ) + .map((workspaceEntity) => ({ + id: workspaceEntity.id, + visibility: workspaceEntity.visibility, + handle: workspaceEntity.handle ?? '', + type: workspaceEntity.type, + isContactAutoCreationEnabled: + workspaceEntity.isContactAutoCreationEnabled, + contactAutoCreationPolicy: workspaceEntity.contactAutoCreationPolicy, + messageFolderImportPolicy: workspaceEntity.messageFolderImportPolicy, + excludeNonProfessionalEmails: + workspaceEntity.excludeNonProfessionalEmails, + excludeGroupEmails: workspaceEntity.excludeGroupEmails, + pendingGroupEmailsAction: workspaceEntity.pendingGroupEmailsAction, + isSyncEnabled: workspaceEntity.isSyncEnabled, + syncCursor: workspaceEntity.syncCursor, + syncedAt: workspaceEntity.syncedAt + ? new Date(workspaceEntity.syncedAt) + : null, + syncStatus: workspaceEntity.syncStatus ?? 'NOT_SYNCED', + syncStage: workspaceEntity.syncStage, + syncStageStartedAt: workspaceEntity.syncStageStartedAt + ? new Date(workspaceEntity.syncStageStartedAt) + : null, + throttleFailureCount: workspaceEntity.throttleFailureCount, + throttleRetryAfter: workspaceEntity.throttleRetryAfter + ? new Date(workspaceEntity.throttleRetryAfter) + : null, + connectedAccountId: workspaceEntity.connectedAccountId, + workspaceId, + createdAt: workspaceEntity.createdAt, + updatedAt: workspaceEntity.updatedAt, + })); + + if (coreMessageChannels.length > 0) { + await this.messageChannelRepository.save( + coreMessageChannels as unknown as MessageChannelEntity[], + ); + this.logger.log( + `Migrated ${coreMessageChannels.length} message channels for workspace ${workspaceId}`, + ); + } + + migratedMessageChannelIds = new Set( + coreMessageChannels.map((channel) => channel.id), + ); + } + + if (calendarChannels.length > 0) { + const coreCalendarChannels = calendarChannels + .filter((workspaceEntity) => + migratedConnectedAccountIds.has(workspaceEntity.connectedAccountId), + ) + .map((workspaceEntity) => ({ + id: workspaceEntity.id, + handle: workspaceEntity.handle ?? '', + syncStatus: workspaceEntity.syncStatus ?? 'NOT_SYNCED', + syncStage: workspaceEntity.syncStage, + visibility: workspaceEntity.visibility, + isContactAutoCreationEnabled: + workspaceEntity.isContactAutoCreationEnabled, + contactAutoCreationPolicy: workspaceEntity.contactAutoCreationPolicy, + isSyncEnabled: workspaceEntity.isSyncEnabled, + syncCursor: workspaceEntity.syncCursor, + syncedAt: workspaceEntity.syncedAt + ? new Date(workspaceEntity.syncedAt) + : null, + syncStageStartedAt: workspaceEntity.syncStageStartedAt + ? new Date(workspaceEntity.syncStageStartedAt) + : null, + throttleFailureCount: workspaceEntity.throttleFailureCount, + connectedAccountId: workspaceEntity.connectedAccountId, + workspaceId, + createdAt: workspaceEntity.createdAt, + updatedAt: workspaceEntity.updatedAt, + })); + + await this.calendarChannelRepository.save( + coreCalendarChannels as unknown as CalendarChannelEntity[], + ); + this.logger.log( + `Migrated ${coreCalendarChannels.length} calendar channels for workspace ${workspaceId}`, + ); + } + + if (messageFolders.length > 0) { + const externalIdToFolderIdMap = new Map( + messageFolders.map((folder) => [folder.externalId, folder.id]), + ); + + const coreMessageFolders = messageFolders + .filter((workspaceEntity) => + migratedMessageChannelIds.has(workspaceEntity.messageChannelId), + ) + .map((workspaceEntity) => { + let resolvedParentFolderId: string | null = null; + + if (isNonEmptyString(workspaceEntity.parentFolderId)) { + resolvedParentFolderId = + externalIdToFolderIdMap.get(workspaceEntity.parentFolderId) ?? + null; + + if (!resolvedParentFolderId) { + this.logger.warn( + `Message folder ${workspaceEntity.id}: could not resolve parentFolderId externalId "${workspaceEntity.parentFolderId}" to a UUID`, + ); + } + } + + return { + id: workspaceEntity.id, + name: workspaceEntity.name, + syncCursor: workspaceEntity.syncCursor, + isSentFolder: workspaceEntity.isSentFolder, + isSynced: workspaceEntity.isSynced, + parentFolderId: resolvedParentFolderId, + externalId: workspaceEntity.externalId, + pendingSyncAction: workspaceEntity.pendingSyncAction, + messageChannelId: workspaceEntity.messageChannelId, + workspaceId, + createdAt: workspaceEntity.createdAt, + updatedAt: workspaceEntity.updatedAt, + }; + }); + + await this.messageFolderRepository.save( + coreMessageFolders as unknown as MessageFolderEntity[], + ); + this.logger.log( + `Migrated ${coreMessageFolders.length} message folders for workspace ${workspaceId}`, + ); + } + } + + private async buildWorkspaceMemberIdToUserWorkspaceIdMap( + workspaceId: string, + ): Promise> { + const workspaceMemberRepository = + await this.twentyORMGlobalManager.getRepository( + workspaceId, + 'workspaceMember', + ); + + const workspaceMembers = await workspaceMemberRepository.find(); + const userWorkspaces = await this.userWorkspaceRepository.find({ + where: { workspaceId }, + select: ['id', 'userId'], + }); + + const userWorkspaceIdByUserId = new Map( + userWorkspaces.map((userWorkspace) => [ + userWorkspace.userId, + userWorkspace.id, + ]), + ); + + return new Map( + workspaceMembers + .filter((member) => userWorkspaceIdByUserId.has(member.userId)) + .map((member) => [ + member.id, + userWorkspaceIdByUserId.get(member.userId)!, + ]), + ); + } +} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-21/1-21-upgrade-version-command.module.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-21/1-21-upgrade-version-command.module.ts index 34e3e1d3e1..ef27428f0a 100644 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-21/1-21-upgrade-version-command.module.ts +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/1-21/1-21-upgrade-version-command.module.ts @@ -3,6 +3,7 @@ import { TypeOrmModule } from '@nestjs/typeorm'; import { WorkspaceIteratorModule } from 'src/database/commands/command-runners/workspace-iterator.module'; import { AddComposeEmailCommandMenuItemCommand } from 'src/database/commands/upgrade-version-command/1-21/1-21-add-compose-email-command-menu-item.command'; +import { MigrateMessagingInfrastructureToMetadataCommand } from 'src/database/commands/upgrade-version-command/1-21/1-21-migrate-messaging-infrastructure-to-metadata.command'; import { AddGlobalKeyValuePairUniqueIndexCommand } from 'src/database/commands/upgrade-version-command/1-21/1-21-workspace-command-add-global-key-value-pair-unique-index.command'; import { BackfillDatasourceToWorkspaceCommand } from 'src/database/commands/upgrade-version-command/1-21/1-21-workspace-command-backfill-datasource-to-workspace.command'; import { BackfillMessageThreadSubjectCommand } from 'src/database/commands/upgrade-version-command/1-21/1-21-workspace-command-backfill-message-thread-subject.command'; @@ -15,9 +16,13 @@ import { MigrateMessageFolderParentIdToExternalIdCommand } from 'src/database/co import { UpdateEditLayoutCommandMenuItemLabelCommand } from 'src/database/commands/upgrade-version-command/1-21/1-21-workspace-command-update-edit-layout-command-menu-item-label.command'; import { ApplicationModule } from 'src/engine/core-modules/application/application.module'; import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module'; +import { UserWorkspaceEntity } from 'src/engine/core-modules/user-workspace/user-workspace.entity'; import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; +import { CalendarChannelEntity } from 'src/engine/metadata-modules/calendar-channel/entities/calendar-channel.entity'; +import { ConnectedAccountEntity } from 'src/engine/metadata-modules/connected-account/entities/connected-account.entity'; import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity'; import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module'; +import { MessageChannelEntity } from 'src/engine/metadata-modules/message-channel/entities/message-channel.entity'; import { MessageFolderEntity } from 'src/engine/metadata-modules/message-folder/entities/message-folder.entity'; import { WorkspaceSchemaManagerModule } from 'src/engine/twenty-orm/workspace-schema-manager/workspace-schema-manager.module'; import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache.module'; @@ -28,7 +33,11 @@ import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace TypeOrmModule.forFeature([ WorkspaceEntity, DataSourceEntity, + CalendarChannelEntity, + ConnectedAccountEntity, + MessageChannelEntity, MessageFolderEntity, + UserWorkspaceEntity, ]), DataSourceModule, WorkspaceCacheModule, @@ -50,6 +59,7 @@ import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace UpdateEditLayoutCommandMenuItemLabelCommand, DropWorkspaceMessagingFksCommand, MigrateMessageFolderParentIdToExternalIdCommand, + MigrateMessagingInfrastructureToMetadataCommand, ], exports: [ AddComposeEmailCommandMenuItemCommand, @@ -63,6 +73,7 @@ import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace UpdateEditLayoutCommandMenuItemLabelCommand, DropWorkspaceMessagingFksCommand, MigrateMessageFolderParentIdToExternalIdCommand, + MigrateMessagingInfrastructureToMetadataCommand, ], }) export class V1_21_UpgradeVersionCommandModule {} diff --git a/packages/twenty-server/src/engine/twenty-orm/entity-manager/workspace-entity-manager.spec.ts b/packages/twenty-server/src/engine/twenty-orm/entity-manager/workspace-entity-manager.spec.ts index 0fc822de24..4a60f67846 100644 --- a/packages/twenty-server/src/engine/twenty-orm/entity-manager/workspace-entity-manager.spec.ts +++ b/packages/twenty-server/src/engine/twenty-orm/entity-manager/workspace-entity-manager.spec.ts @@ -240,6 +240,7 @@ describe('WorkspaceEntityManager', () => { IS_EMAILING_DOMAIN_ENABLED: false, IS_JUNCTION_RELATIONS_ENABLED: false, IS_DRAFT_EMAIL_ENABLED: false, + IS_CONNECTED_ACCOUNT_MIGRATED: false, IS_USAGE_ANALYTICS_ENABLED: false, IS_RICH_TEXT_V1_MIGRATED: false, IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED: false, diff --git a/packages/twenty-shared/src/types/FeatureFlagKey.ts b/packages/twenty-shared/src/types/FeatureFlagKey.ts index 5c61e4c26b..3f1a516970 100644 --- a/packages/twenty-shared/src/types/FeatureFlagKey.ts +++ b/packages/twenty-shared/src/types/FeatureFlagKey.ts @@ -10,6 +10,7 @@ export enum FeatureFlagKey { IS_EMAILING_DOMAIN_ENABLED = 'IS_EMAILING_DOMAIN_ENABLED', IS_JUNCTION_RELATIONS_ENABLED = 'IS_JUNCTION_RELATIONS_ENABLED', IS_DRAFT_EMAIL_ENABLED = 'IS_DRAFT_EMAIL_ENABLED', + IS_CONNECTED_ACCOUNT_MIGRATED = 'IS_CONNECTED_ACCOUNT_MIGRATED', IS_USAGE_ANALYTICS_ENABLED = 'IS_USAGE_ANALYTICS_ENABLED', IS_RICH_TEXT_V1_MIGRATED = 'IS_RICH_TEXT_V1_MIGRATED', IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED = 'IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED',