Remove sync-metadata and IS_WORKSPACE_CREATION_V2_ENABLED feature flag (#16997)

# Introduction
Followup of
https://github.com/twentyhq/twenty/pull/17001#pullrequestreview-3638508738
close https://github.com/twentyhq/core-team-issues/issues/1910

We've completely decom the `sync-metadata` in production. We're now then
removing its implementation in favor of the v2.

## TODO:
- [x] Remove sync-metadata implem and commands
- [x] Remove workspace decorators 
- [x] Type each deprecated field to deprecated on their workspaceEntity
- [x] Remove the `workspace-sync-metadata` folder entirely
- [x] remove workspace migration
- [x] workspace migration removal migration
- [x] remove the `v2` references from workspace manager file names
- [x] remove the `v2` references from workspace manager modules
- [ ] Double check impact on translation file path updates


## Note
- Removed the gate logic
- Remains some service v2 naming, serverless needs to be migrated on v2
fully
- Removed workspaceMigration service app health consumption, making it
always returning up ( no more down ) cc @FelixMalfait ( quite obsolete
health check now, will require complete refactor once we introduce inter
app dependency etc )
This commit is contained in:
Paul Rastoin
2026-01-08 16:45:12 +01:00
committed by GitHub
parent f1aee7fd18
commit 942d2fef83
629 changed files with 1985 additions and 21492 deletions
@@ -1,126 +1,15 @@
import { msg } from '@lingui/core/macro';
import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata';
import { FieldMetadataType, RelationOnDeleteAction } from 'twenty-shared/types';
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
import { type Relation } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/relation.interface';
import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity';
import { WorkspaceEntity } from 'src/engine/twenty-orm/decorators/workspace-entity.decorator';
import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field.decorator';
import { WorkspaceIndex } from 'src/engine/twenty-orm/decorators/workspace-index.decorator';
import { WorkspaceIsFieldUIReadOnly } from 'src/engine/twenty-orm/decorators/workspace-is-field-ui-readonly.decorator';
import { WorkspaceIsNotAuditLogged } from 'src/engine/twenty-orm/decorators/workspace-is-not-audit-logged.decorator';
import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator';
import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator';
import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator';
import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator';
import {
MESSAGE_CHANNEL_MESSAGE_ASSOCIATION_STANDARD_FIELD_IDS,
MESSAGE_STANDARD_FIELD_IDS,
} from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids';
import { STANDARD_OBJECT_ICONS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-object-icons';
import { MessageDirection } from 'src/modules/messaging/common/enums/message-direction.enum';
import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity';
import { MessageWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message.workspace-entity';
import { type EntityRelation } from 'src/engine/workspace-manager/workspace-migration/types/entity-relation.interface';
import { type MessageDirection } from 'src/modules/messaging/common/enums/message-direction.enum';
import { type MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity';
import { type MessageWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message.workspace-entity';
@WorkspaceEntity({
standardId: STANDARD_OBJECT_IDS.messageChannelMessageAssociation,
namePlural: 'messageChannelMessageAssociations',
labelSingular: msg`Message Channel Message Association`,
labelPlural: msg`Message Channel Message Associations`,
description: msg`Message Synced with a Message Channel`,
icon: STANDARD_OBJECT_ICONS.messageChannelMessageAssociation,
})
@WorkspaceIsNotAuditLogged()
@WorkspaceIsSystem()
@WorkspaceIndex(['messageChannelId', 'messageId'], {
isUnique: true,
indexWhereClause: '"deletedAt" IS NULL',
})
export class MessageChannelMessageAssociationWorkspaceEntity extends BaseWorkspaceEntity {
@WorkspaceField({
standardId:
MESSAGE_CHANNEL_MESSAGE_ASSOCIATION_STANDARD_FIELD_IDS.messageExternalId,
type: FieldMetadataType.TEXT,
label: msg`Message External Id`,
description: msg`Message id from the messaging provider`,
icon: 'IconHash',
})
@WorkspaceIsFieldUIReadOnly()
@WorkspaceIsNullable()
messageExternalId: string | null;
@WorkspaceField({
standardId:
MESSAGE_CHANNEL_MESSAGE_ASSOCIATION_STANDARD_FIELD_IDS.messageThreadExternalId,
type: FieldMetadataType.TEXT,
label: msg`Thread External Id`,
description: msg`Thread id from the messaging provider`,
icon: 'IconHash',
})
@WorkspaceIsFieldUIReadOnly()
@WorkspaceIsNullable()
messageThreadExternalId: string | null;
@WorkspaceField({
standardId: MESSAGE_STANDARD_FIELD_IDS.direction,
type: FieldMetadataType.SELECT,
label: msg`Direction`,
description: msg`Message Direction`,
icon: 'IconDirection',
options: [
{
value: MessageDirection.INCOMING,
label: 'Incoming',
position: 0,
color: 'green',
},
{
value: MessageDirection.OUTGOING,
label: 'Outgoing',
position: 1,
color: 'blue',
},
],
defaultValue: `'${MessageDirection.INCOMING}'`,
})
@WorkspaceIsFieldUIReadOnly()
direction: MessageDirection;
@WorkspaceRelation({
standardId:
MESSAGE_CHANNEL_MESSAGE_ASSOCIATION_STANDARD_FIELD_IDS.messageChannel,
type: RelationType.MANY_TO_ONE,
label: msg`Message Channel Id`,
description: msg`Message Channel Id`,
icon: 'IconHash',
inverseSideTarget: () => MessageChannelWorkspaceEntity,
inverseSideFieldKey: 'messageChannelMessageAssociations',
onDelete: RelationOnDeleteAction.CASCADE,
})
@WorkspaceIsFieldUIReadOnly()
@WorkspaceIsNullable()
messageChannel: Relation<MessageChannelWorkspaceEntity> | null;
@WorkspaceJoinColumn('messageChannel')
messageChannel: EntityRelation<MessageChannelWorkspaceEntity> | null;
messageChannelId: string;
@WorkspaceRelation({
standardId: MESSAGE_CHANNEL_MESSAGE_ASSOCIATION_STANDARD_FIELD_IDS.message,
type: RelationType.MANY_TO_ONE,
label: msg`Message Id`,
description: msg`Message Id`,
icon: 'IconHash',
inverseSideTarget: () => MessageWorkspaceEntity,
inverseSideFieldKey: 'messageChannelMessageAssociations',
onDelete: RelationOnDeleteAction.CASCADE,
})
@WorkspaceIsFieldUIReadOnly()
@WorkspaceIsNullable()
message: Relation<MessageWorkspaceEntity> | null;
@WorkspaceJoinColumn('message')
message: EntityRelation<MessageWorkspaceEntity> | null;
messageId: string;
}
@@ -1,26 +1,10 @@
import { registerEnumType } from '@nestjs/graphql';
import { msg } from '@lingui/core/macro';
import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata';
import { FieldMetadataType, RelationOnDeleteAction } from 'twenty-shared/types';
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
import { Relation } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/relation.interface';
import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity';
import { WorkspaceEntity } from 'src/engine/twenty-orm/decorators/workspace-entity.decorator';
import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field.decorator';
import { WorkspaceIsFieldUIReadOnly } from 'src/engine/twenty-orm/decorators/workspace-is-field-ui-readonly.decorator';
import { WorkspaceIsNotAuditLogged } from 'src/engine/twenty-orm/decorators/workspace-is-not-audit-logged.decorator';
import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator';
import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator';
import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator';
import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator';
import { MESSAGE_CHANNEL_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids';
import { STANDARD_OBJECT_ICONS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-object-icons';
import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity';
import { MessageChannelMessageAssociationWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel-message-association.workspace-entity';
import { MessageFolderWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-folder.workspace-entity';
import { type EntityRelation } from 'src/engine/workspace-manager/workspace-migration/types/entity-relation.interface';
import { type ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity';
import { type MessageChannelMessageAssociationWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel-message-association.workspace-entity';
import { type MessageFolderWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-folder.workspace-entity';
export enum MessageChannelSyncStatus {
NOT_SYNCED = 'NOT_SYNCED',
@@ -97,408 +81,27 @@ registerEnumType(MessageChannelPendingGroupEmailsAction, {
name: 'MessageChannelPendingGroupEmailsAction',
});
@WorkspaceEntity({
standardId: STANDARD_OBJECT_IDS.messageChannel,
namePlural: 'messageChannels',
labelSingular: msg`Message Channel`,
labelPlural: msg`Message Channels`,
description: msg`Message Channels`,
icon: STANDARD_OBJECT_ICONS.messageChannel,
labelIdentifierStandardId: MESSAGE_CHANNEL_STANDARD_FIELD_IDS.handle,
})
@WorkspaceIsNotAuditLogged()
@WorkspaceIsSystem()
export class MessageChannelWorkspaceEntity extends BaseWorkspaceEntity {
@WorkspaceField({
standardId: MESSAGE_CHANNEL_STANDARD_FIELD_IDS.visibility,
type: FieldMetadataType.SELECT,
label: msg`Visibility`,
description: msg`Visibility`,
icon: 'IconEyeglass',
options: [
{
value: MessageChannelVisibility.METADATA,
label: 'Metadata',
position: 0,
color: 'green',
},
{
value: MessageChannelVisibility.SUBJECT,
label: 'Subject',
position: 1,
color: 'blue',
},
{
value: MessageChannelVisibility.SHARE_EVERYTHING,
label: 'Share Everything',
position: 2,
color: 'orange',
},
],
defaultValue: `'${MessageChannelVisibility.SHARE_EVERYTHING}'`,
})
@WorkspaceIsFieldUIReadOnly()
visibility: string;
@WorkspaceField({
standardId: MESSAGE_CHANNEL_STANDARD_FIELD_IDS.handle,
type: FieldMetadataType.TEXT,
label: msg`Handle`,
description: msg`Handle`,
icon: 'IconAt',
})
@WorkspaceIsFieldUIReadOnly()
@WorkspaceIsNullable()
handle: string | null;
@WorkspaceField({
standardId: MESSAGE_CHANNEL_STANDARD_FIELD_IDS.type,
type: FieldMetadataType.SELECT,
label: msg`Type`,
description: msg`Channel Type`,
icon: 'IconMessage',
options: [
{
value: MessageChannelType.EMAIL,
label: 'Email',
position: 0,
color: 'green',
},
{
value: MessageChannelType.SMS,
label: 'SMS',
position: 1,
color: 'blue',
},
],
defaultValue: `'${MessageChannelType.EMAIL}'`,
})
@WorkspaceIsFieldUIReadOnly()
type: string;
// TODO: Deprecate this field and migrate data to contactAutoCreationFor
@WorkspaceField({
standardId: MESSAGE_CHANNEL_STANDARD_FIELD_IDS.isContactAutoCreationEnabled,
type: FieldMetadataType.BOOLEAN,
label: msg`Is Contact Auto Creation Enabled`,
description: msg`Is Contact Auto Creation Enabled`,
icon: 'IconUserCircle',
defaultValue: true,
})
@WorkspaceIsFieldUIReadOnly()
isContactAutoCreationEnabled: boolean;
@WorkspaceField({
standardId: MESSAGE_CHANNEL_STANDARD_FIELD_IDS.contactAutoCreationPolicy,
type: FieldMetadataType.SELECT,
label: msg`Contact auto creation policy`,
description: msg`Automatically create People records when receiving or sending emails`,
icon: 'IconUserCircle',
options: [
{
value: MessageChannelContactAutoCreationPolicy.SENT_AND_RECEIVED,
label: 'Sent and Received',
position: 0,
color: 'green',
},
{
value: MessageChannelContactAutoCreationPolicy.SENT,
label: 'Sent',
position: 1,
color: 'blue',
},
{
value: MessageChannelContactAutoCreationPolicy.NONE,
label: 'None',
position: 2,
color: 'red',
},
],
defaultValue: `'${MessageChannelContactAutoCreationPolicy.SENT}'`,
})
@WorkspaceIsFieldUIReadOnly()
contactAutoCreationPolicy: MessageChannelContactAutoCreationPolicy;
@WorkspaceField({
standardId: MESSAGE_CHANNEL_STANDARD_FIELD_IDS.messageFolderImportPolicy,
type: FieldMetadataType.SELECT,
label: msg`Message folder import policy`,
description: msg`Message folder import policy`,
icon: 'IconFolder',
options: [
{
value: MessageFolderImportPolicy.ALL_FOLDERS,
label: 'All folders',
position: 0,
color: 'green',
},
{
value: MessageFolderImportPolicy.SELECTED_FOLDERS,
label: 'Selected folders',
position: 1,
color: 'blue',
},
],
defaultValue: `'${MessageFolderImportPolicy.ALL_FOLDERS}'`,
})
@WorkspaceIsFieldUIReadOnly()
messageFolderImportPolicy: MessageFolderImportPolicy;
@WorkspaceField({
standardId: MESSAGE_CHANNEL_STANDARD_FIELD_IDS.excludeNonProfessionalEmails,
type: FieldMetadataType.BOOLEAN,
label: msg`Exclude non professional emails`,
description: msg`Exclude non professional emails`,
icon: 'IconBriefcase',
defaultValue: true,
})
@WorkspaceIsFieldUIReadOnly()
excludeNonProfessionalEmails: boolean;
@WorkspaceField({
standardId: MESSAGE_CHANNEL_STANDARD_FIELD_IDS.excludeGroupEmails,
type: FieldMetadataType.BOOLEAN,
label: msg`Exclude group emails`,
description: msg`Exclude group emails`,
icon: 'IconUsersGroup',
defaultValue: true,
})
@WorkspaceIsFieldUIReadOnly()
excludeGroupEmails: boolean;
@WorkspaceField({
standardId: MESSAGE_CHANNEL_STANDARD_FIELD_IDS.pendingGroupEmailsAction,
type: FieldMetadataType.SELECT,
label: msg`Pending group emails action`,
description: msg`Pending action for group emails`,
icon: 'IconUsersGroup',
options: [
{
value: MessageChannelPendingGroupEmailsAction.GROUP_EMAILS_DELETION,
label: 'Group emails deletion',
position: 0,
color: 'red',
},
{
value: MessageChannelPendingGroupEmailsAction.GROUP_EMAILS_IMPORT,
label: 'Group emails import',
position: 1,
color: 'green',
},
{
value: MessageChannelPendingGroupEmailsAction.NONE,
label: 'None',
position: 2,
color: 'blue',
},
],
defaultValue: `'${MessageChannelPendingGroupEmailsAction.NONE}'`,
})
@WorkspaceIsFieldUIReadOnly()
pendingGroupEmailsAction: MessageChannelPendingGroupEmailsAction;
@WorkspaceField({
standardId: MESSAGE_CHANNEL_STANDARD_FIELD_IDS.isSyncEnabled,
type: FieldMetadataType.BOOLEAN,
label: msg`Is Sync Enabled`,
description: msg`Is Sync Enabled`,
icon: 'IconRefresh',
defaultValue: true,
})
@WorkspaceIsFieldUIReadOnly()
isSyncEnabled: boolean;
@WorkspaceField({
standardId: MESSAGE_CHANNEL_STANDARD_FIELD_IDS.syncCursor,
type: FieldMetadataType.TEXT,
label: msg`Last sync cursor`,
description: msg`Last sync cursor`,
icon: 'IconHistory',
})
@WorkspaceIsFieldUIReadOnly()
@WorkspaceIsNullable()
syncCursor: string | null;
@WorkspaceField({
standardId: MESSAGE_CHANNEL_STANDARD_FIELD_IDS.syncedAt,
type: FieldMetadataType.DATE_TIME,
label: msg`Last sync date`,
description: msg`Last sync date`,
icon: 'IconHistory',
})
@WorkspaceIsFieldUIReadOnly()
@WorkspaceIsNullable()
syncedAt: string | null;
@WorkspaceField({
standardId: MESSAGE_CHANNEL_STANDARD_FIELD_IDS.syncStatus,
type: FieldMetadataType.SELECT,
label: msg`Sync status`,
description: msg`Sync status`,
icon: 'IconStatusChange',
options: [
{
value: MessageChannelSyncStatus.ONGOING,
label: 'Ongoing',
position: 1,
color: 'yellow',
},
{
value: MessageChannelSyncStatus.NOT_SYNCED,
label: 'Not Synced',
position: 2,
color: 'blue',
},
{
value: MessageChannelSyncStatus.ACTIVE,
label: 'Active',
position: 3,
color: 'green',
},
{
value: MessageChannelSyncStatus.FAILED_INSUFFICIENT_PERMISSIONS,
label: 'Failed Insufficient Permissions',
position: 4,
color: 'red',
},
{
value: MessageChannelSyncStatus.FAILED_UNKNOWN,
label: 'Failed Unknown',
position: 5,
color: 'red',
},
],
})
@WorkspaceIsFieldUIReadOnly()
@WorkspaceIsNullable()
syncStatus: MessageChannelSyncStatus | null;
@WorkspaceField({
standardId: MESSAGE_CHANNEL_STANDARD_FIELD_IDS.syncStage,
type: FieldMetadataType.SELECT,
label: msg`Sync stage`,
description: msg`Sync stage`,
icon: 'IconStatusChange',
options: [
{
value: MessageChannelSyncStage.MESSAGE_LIST_FETCH_PENDING,
label: 'Messages list fetch pending',
position: 0,
color: 'blue',
},
{
value: MessageChannelSyncStage.MESSAGE_LIST_FETCH_SCHEDULED,
label: 'Messages list fetch scheduled',
position: 1,
color: 'green',
},
{
value: MessageChannelSyncStage.MESSAGE_LIST_FETCH_ONGOING,
label: 'Messages list fetch ongoing',
position: 2,
color: 'orange',
},
{
value: MessageChannelSyncStage.MESSAGES_IMPORT_PENDING,
label: 'Messages import pending',
position: 3,
color: 'blue',
},
{
value: MessageChannelSyncStage.MESSAGES_IMPORT_SCHEDULED,
label: 'Messages import scheduled',
position: 4,
color: 'green',
},
{
value: MessageChannelSyncStage.MESSAGES_IMPORT_ONGOING,
label: 'Messages import ongoing',
position: 5,
color: 'orange',
},
{
value: MessageChannelSyncStage.FAILED,
label: 'Failed',
position: 6,
color: 'red',
},
{
value: MessageChannelSyncStage.PENDING_CONFIGURATION,
label: 'Pending configuration',
position: 7,
color: 'gray',
},
],
defaultValue: `'${MessageChannelSyncStage.PENDING_CONFIGURATION}'`,
})
@WorkspaceIsFieldUIReadOnly()
syncStage: MessageChannelSyncStage;
@WorkspaceField({
standardId: MESSAGE_CHANNEL_STANDARD_FIELD_IDS.syncStageStartedAt,
type: FieldMetadataType.DATE_TIME,
label: msg`Sync stage started at`,
description: msg`Sync stage started at`,
icon: 'IconHistory',
})
@WorkspaceIsFieldUIReadOnly()
@WorkspaceIsNullable()
syncStageStartedAt: string | null;
@WorkspaceField({
standardId: MESSAGE_CHANNEL_STANDARD_FIELD_IDS.throttleFailureCount,
type: FieldMetadataType.NUMBER,
label: msg`Throttle Failure Count`,
description: msg`Throttle Failure Count`,
icon: 'IconX',
defaultValue: 0,
})
@WorkspaceIsFieldUIReadOnly()
throttleFailureCount: number;
@WorkspaceRelation({
standardId: MESSAGE_CHANNEL_STANDARD_FIELD_IDS.connectedAccount,
type: RelationType.MANY_TO_ONE,
label: msg`Connected Account`,
description: msg`Connected Account`,
icon: 'IconUserCircle',
inverseSideTarget: () => ConnectedAccountWorkspaceEntity,
inverseSideFieldKey: 'messageChannels',
onDelete: RelationOnDeleteAction.CASCADE,
})
@WorkspaceIsFieldUIReadOnly()
connectedAccount: Relation<ConnectedAccountWorkspaceEntity>;
@WorkspaceJoinColumn('connectedAccount')
connectedAccount: EntityRelation<ConnectedAccountWorkspaceEntity>;
connectedAccountId: string;
@WorkspaceRelation({
standardId:
MESSAGE_CHANNEL_STANDARD_FIELD_IDS.messageChannelMessageAssociations,
type: RelationType.ONE_TO_MANY,
label: msg`Message Channel Association`,
description: msg`Messages from the channel.`,
icon: 'IconMessage',
inverseSideTarget: () => MessageChannelMessageAssociationWorkspaceEntity,
onDelete: RelationOnDeleteAction.CASCADE,
})
@WorkspaceIsFieldUIReadOnly()
@WorkspaceIsNullable()
messageChannelMessageAssociations: Relation<
messageChannelMessageAssociations: EntityRelation<
MessageChannelMessageAssociationWorkspaceEntity[]
>;
@WorkspaceRelation({
standardId: MESSAGE_CHANNEL_STANDARD_FIELD_IDS.messageFolders,
type: RelationType.ONE_TO_MANY,
label: msg`Message Folders`,
description: msg`Message Folders`,
icon: 'IconFolder',
inverseSideTarget: () => MessageFolderWorkspaceEntity,
onDelete: RelationOnDeleteAction.CASCADE,
})
@WorkspaceIsFieldUIReadOnly()
@WorkspaceIsNullable()
messageFolders: Relation<MessageFolderWorkspaceEntity[]>;
messageFolders: EntityRelation<MessageFolderWorkspaceEntity[]>;
}
@@ -1,25 +1,8 @@
import { registerEnumType } from '@nestjs/graphql';
import { msg } from '@lingui/core/macro';
import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata';
import { FieldMetadataType, RelationOnDeleteAction } from 'twenty-shared/types';
import { Relation } from 'typeorm';
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity';
import { WorkspaceEntity } from 'src/engine/twenty-orm/decorators/workspace-entity.decorator';
import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field.decorator';
import { WorkspaceIndex } from 'src/engine/twenty-orm/decorators/workspace-index.decorator';
import { WorkspaceIsFieldUIReadOnly } from 'src/engine/twenty-orm/decorators/workspace-is-field-ui-readonly.decorator';
import { WorkspaceIsNotAuditLogged } from 'src/engine/twenty-orm/decorators/workspace-is-not-audit-logged.decorator';
import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator';
import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator';
import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator';
import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator';
import { MESSAGE_FOLDER_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids';
import { STANDARD_OBJECT_ICONS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-object-icons';
import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity';
import { type EntityRelation } from 'src/engine/workspace-manager/workspace-migration/types/entity-relation.interface';
import { type MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity';
export enum MessageFolderPendingSyncAction {
FOLDER_DELETION = 'FOLDER_DELETION',
@@ -30,128 +13,14 @@ registerEnumType(MessageFolderPendingSyncAction, {
name: 'MessageFolderPendingSyncAction',
});
@WorkspaceEntity({
standardId: STANDARD_OBJECT_IDS.messageFolder,
namePlural: 'messageFolders',
labelSingular: msg`Message Folder`,
labelPlural: msg`Message Folders`,
description: msg`Folder for Message Channel`,
icon: STANDARD_OBJECT_ICONS.messageFolder,
})
@WorkspaceIsNotAuditLogged()
@WorkspaceIsSystem()
@WorkspaceIndex(['messageChannelId', 'externalId'], {
isUnique: true,
indexWhereClause: '"deletedAt" IS NULL',
})
export class MessageFolderWorkspaceEntity extends BaseWorkspaceEntity {
@WorkspaceField({
standardId: MESSAGE_FOLDER_STANDARD_FIELD_IDS.name,
type: FieldMetadataType.TEXT,
label: msg`Name`,
description: msg`Folder name`,
icon: 'IconFolder',
})
@WorkspaceIsFieldUIReadOnly()
@WorkspaceIsNullable()
name: string | null;
@WorkspaceRelation({
standardId: MESSAGE_FOLDER_STANDARD_FIELD_IDS.messageChannel,
type: RelationType.MANY_TO_ONE,
label: msg`Message Channel`,
description: msg`Message Channel`,
icon: 'IconMessage',
inverseSideTarget: () => MessageChannelWorkspaceEntity,
inverseSideFieldKey: 'messageFolders',
onDelete: RelationOnDeleteAction.CASCADE,
})
@WorkspaceIsFieldUIReadOnly()
messageChannel: Relation<MessageChannelWorkspaceEntity>;
@WorkspaceField({
standardId: MESSAGE_FOLDER_STANDARD_FIELD_IDS.syncCursor,
type: FieldMetadataType.TEXT,
label: msg`Sync Cursor`,
description: msg`Sync Cursor`,
icon: 'IconHash',
})
@WorkspaceIsFieldUIReadOnly()
@WorkspaceIsNullable()
messageChannel: EntityRelation<MessageChannelWorkspaceEntity>;
syncCursor: string | null;
@WorkspaceField({
standardId: MESSAGE_FOLDER_STANDARD_FIELD_IDS.isSentFolder,
type: FieldMetadataType.BOOLEAN,
label: msg`Is Sent Folder`,
description: msg`Is Sent Folder`,
icon: 'IconCheck',
defaultValue: false,
})
@WorkspaceIsFieldUIReadOnly()
isSentFolder: boolean;
@WorkspaceField({
standardId: MESSAGE_FOLDER_STANDARD_FIELD_IDS.isSynced,
type: FieldMetadataType.BOOLEAN,
label: msg`Is Synced`,
description: msg`Is Synced`,
icon: 'IconCheck',
defaultValue: false,
})
@WorkspaceIsFieldUIReadOnly()
isSynced: boolean;
@WorkspaceField({
standardId: MESSAGE_FOLDER_STANDARD_FIELD_IDS.parentFolderId,
type: FieldMetadataType.TEXT,
label: msg`Parent Folder ID`,
description: msg`Parent Folder ID`,
icon: 'IconFolder',
defaultValue: null,
})
@WorkspaceIsFieldUIReadOnly()
@WorkspaceIsNullable()
parentFolderId: string | null;
@WorkspaceField({
standardId: MESSAGE_FOLDER_STANDARD_FIELD_IDS.externalId,
type: FieldMetadataType.TEXT,
label: msg`External ID`,
description: msg`External ID`,
icon: 'IconHash',
defaultValue: null,
})
@WorkspaceIsFieldUIReadOnly()
@WorkspaceIsNullable()
externalId: string | null;
@WorkspaceField({
standardId: MESSAGE_FOLDER_STANDARD_FIELD_IDS.pendingSyncAction,
type: FieldMetadataType.SELECT,
label: msg`Pending Sync Action`,
description: msg`Pending action for folder sync`,
icon: 'IconReload',
options: [
{
value: MessageFolderPendingSyncAction.FOLDER_DELETION,
label: 'Folder deletion',
position: 0,
color: 'red',
},
{
value: MessageFolderPendingSyncAction.NONE,
label: 'None',
position: 1,
color: 'blue',
},
],
defaultValue: `'${MessageFolderPendingSyncAction.NONE}'`,
})
@WorkspaceIsFieldUIReadOnly()
pendingSyncAction: MessageFolderPendingSyncAction;
@WorkspaceJoinColumn('messageChannel')
messageChannelId: string;
}
@@ -1,148 +1,19 @@
import { msg } from '@lingui/core/macro';
import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata';
import {
FieldMetadataType,
MessageParticipantRole,
RelationOnDeleteAction,
} from 'twenty-shared/types';
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
import { Relation } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/relation.interface';
import { type MessageParticipantRole } from 'twenty-shared/types';
import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity';
import { WorkspaceEntity } from 'src/engine/twenty-orm/decorators/workspace-entity.decorator';
import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field.decorator';
import { WorkspaceIsFieldUIReadOnly } from 'src/engine/twenty-orm/decorators/workspace-is-field-ui-readonly.decorator';
import { WorkspaceIsNotAuditLogged } from 'src/engine/twenty-orm/decorators/workspace-is-not-audit-logged.decorator';
import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator';
import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator';
import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator';
import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator';
import { MESSAGE_PARTICIPANT_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids';
import { STANDARD_OBJECT_ICONS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-object-icons';
import { MessageWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message.workspace-entity';
import { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/person.workspace-entity';
import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity';
import { type EntityRelation } from 'src/engine/workspace-manager/workspace-migration/types/entity-relation.interface';
import { type MessageWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message.workspace-entity';
import { type PersonWorkspaceEntity } from 'src/modules/person/standard-objects/person.workspace-entity';
import { type WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity';
@WorkspaceEntity({
standardId: STANDARD_OBJECT_IDS.messageParticipant,
namePlural: 'messageParticipants',
labelSingular: msg`Message Participant`,
labelPlural: msg`Message Participants`,
description: msg`Message Participants`,
icon: STANDARD_OBJECT_ICONS.messageParticipant,
labelIdentifierStandardId: MESSAGE_PARTICIPANT_STANDARD_FIELD_IDS.handle,
})
@WorkspaceIsNotAuditLogged()
@WorkspaceIsSystem()
export class MessageParticipantWorkspaceEntity extends BaseWorkspaceEntity {
@WorkspaceField({
standardId: MESSAGE_PARTICIPANT_STANDARD_FIELD_IDS.role,
type: FieldMetadataType.SELECT,
label: msg`Role`,
description: msg`Role`,
icon: 'IconAt',
options: [
{
value: MessageParticipantRole.FROM,
label: 'From',
position: 0,
color: 'green',
},
{
value: MessageParticipantRole.TO,
label: 'To',
position: 1,
color: 'blue',
},
{
value: MessageParticipantRole.CC,
label: 'Cc',
position: 2,
color: 'orange',
},
{
value: MessageParticipantRole.BCC,
label: 'Bcc',
position: 3,
color: 'red',
},
],
defaultValue: `'${MessageParticipantRole.FROM}'`,
})
@WorkspaceIsFieldUIReadOnly()
role: MessageParticipantRole;
@WorkspaceField({
standardId: MESSAGE_PARTICIPANT_STANDARD_FIELD_IDS.handle,
type: FieldMetadataType.TEXT,
label: msg`Handle`,
description: msg`Handle`,
icon: 'IconAt',
})
@WorkspaceIsFieldUIReadOnly()
@WorkspaceIsNullable()
handle: string | null;
@WorkspaceField({
standardId: MESSAGE_PARTICIPANT_STANDARD_FIELD_IDS.displayName,
type: FieldMetadataType.TEXT,
label: msg`Display Name`,
description: msg`Display Name`,
icon: 'IconUser',
})
@WorkspaceIsFieldUIReadOnly()
@WorkspaceIsNullable()
displayName: string | null;
@WorkspaceRelation({
standardId: MESSAGE_PARTICIPANT_STANDARD_FIELD_IDS.message,
type: RelationType.MANY_TO_ONE,
label: msg`Message`,
description: msg`Message`,
icon: 'IconMessage',
inverseSideTarget: () => MessageWorkspaceEntity,
inverseSideFieldKey: 'messageParticipants',
onDelete: RelationOnDeleteAction.CASCADE,
})
@WorkspaceIsFieldUIReadOnly()
message: Relation<MessageWorkspaceEntity>;
@WorkspaceJoinColumn('message')
message: EntityRelation<MessageWorkspaceEntity>;
messageId: string;
@WorkspaceRelation({
standardId: MESSAGE_PARTICIPANT_STANDARD_FIELD_IDS.person,
type: RelationType.MANY_TO_ONE,
label: msg`Person`,
description: msg`Person`,
icon: 'IconUser',
inverseSideTarget: () => PersonWorkspaceEntity,
inverseSideFieldKey: 'messageParticipants',
onDelete: RelationOnDeleteAction.SET_NULL,
})
@WorkspaceIsFieldUIReadOnly()
@WorkspaceIsNullable()
person: Relation<PersonWorkspaceEntity> | null;
@WorkspaceJoinColumn('person')
person: EntityRelation<PersonWorkspaceEntity> | null;
personId: string | null;
@WorkspaceRelation({
standardId: MESSAGE_PARTICIPANT_STANDARD_FIELD_IDS.workspaceMember,
type: RelationType.MANY_TO_ONE,
label: msg`Workspace Member`,
description: msg`Workspace member`,
icon: 'IconCircleUser',
inverseSideTarget: () => WorkspaceMemberWorkspaceEntity,
inverseSideFieldKey: 'messageParticipants',
onDelete: RelationOnDeleteAction.SET_NULL,
})
@WorkspaceIsFieldUIReadOnly()
@WorkspaceIsNullable()
workspaceMember: Relation<WorkspaceMemberWorkspaceEntity> | null;
@WorkspaceJoinColumn('workspaceMember')
workspaceMember: EntityRelation<WorkspaceMemberWorkspaceEntity> | null;
workspaceMemberId: string | null;
}
@@ -1,43 +1,7 @@
import { msg } from '@lingui/core/macro';
import { RelationOnDeleteAction } from 'twenty-shared/types';
import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata';
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
import { Relation } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/relation.interface';
import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity';
import { WorkspaceEntity } from 'src/engine/twenty-orm/decorators/workspace-entity.decorator';
import { WorkspaceIsFieldUIReadOnly } from 'src/engine/twenty-orm/decorators/workspace-is-field-ui-readonly.decorator';
import { WorkspaceIsNotAuditLogged } from 'src/engine/twenty-orm/decorators/workspace-is-not-audit-logged.decorator';
import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator';
import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator';
import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator';
import { MESSAGE_THREAD_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids';
import { STANDARD_OBJECT_ICONS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-object-icons';
import { MessageWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message.workspace-entity';
import { type EntityRelation } from 'src/engine/workspace-manager/workspace-migration/types/entity-relation.interface';
import { type MessageWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message.workspace-entity';
@WorkspaceEntity({
standardId: STANDARD_OBJECT_IDS.messageThread,
namePlural: 'messageThreads',
labelSingular: msg`Message Thread`,
labelPlural: msg`Message Threads`,
description: msg`A group of related messages (e.g. email thread, chat thread)`,
icon: STANDARD_OBJECT_ICONS.messageThread,
})
@WorkspaceIsNotAuditLogged()
@WorkspaceIsSystem()
export class MessageThreadWorkspaceEntity extends BaseWorkspaceEntity {
@WorkspaceRelation({
standardId: MESSAGE_THREAD_STANDARD_FIELD_IDS.messages,
type: RelationType.ONE_TO_MANY,
label: msg`Messages`,
description: msg`Messages from the thread.`,
icon: 'IconMessage',
inverseSideTarget: () => MessageWorkspaceEntity,
onDelete: RelationOnDeleteAction.CASCADE,
})
@WorkspaceIsFieldUIReadOnly()
@WorkspaceIsNullable()
messages: Relation<MessageWorkspaceEntity[]>;
messages: EntityRelation<MessageWorkspaceEntity[]>;
}
@@ -1,124 +1,18 @@
import { msg } from '@lingui/core/macro';
import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata';
import { FieldMetadataType, RelationOnDeleteAction } from 'twenty-shared/types';
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
import { Relation } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/relation.interface';
import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity';
import { WorkspaceEntity } from 'src/engine/twenty-orm/decorators/workspace-entity.decorator';
import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field.decorator';
import { WorkspaceIsFieldUIReadOnly } from 'src/engine/twenty-orm/decorators/workspace-is-field-ui-readonly.decorator';
import { WorkspaceIsNotAuditLogged } from 'src/engine/twenty-orm/decorators/workspace-is-not-audit-logged.decorator';
import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator';
import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator';
import { WorkspaceJoinColumn } from 'src/engine/twenty-orm/decorators/workspace-join-column.decorator';
import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator';
import { MESSAGE_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids';
import { STANDARD_OBJECT_ICONS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-object-icons';
import { MessageChannelMessageAssociationWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel-message-association.workspace-entity';
import { MessageParticipantWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-participant.workspace-entity';
import { MessageThreadWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-thread.workspace-entity';
import { type EntityRelation } from 'src/engine/workspace-manager/workspace-migration/types/entity-relation.interface';
import { type MessageChannelMessageAssociationWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel-message-association.workspace-entity';
import { type MessageParticipantWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-participant.workspace-entity';
import { type MessageThreadWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-thread.workspace-entity';
@WorkspaceEntity({
standardId: STANDARD_OBJECT_IDS.message,
namePlural: 'messages',
labelSingular: msg`Message`,
labelPlural: msg`Messages`,
description: msg`A message sent or received through a messaging channel (email, chat, etc.)`,
icon: STANDARD_OBJECT_ICONS.message,
labelIdentifierStandardId: MESSAGE_STANDARD_FIELD_IDS.subject,
})
@WorkspaceIsNotAuditLogged()
@WorkspaceIsSystem()
export class MessageWorkspaceEntity extends BaseWorkspaceEntity {
@WorkspaceField({
standardId: MESSAGE_STANDARD_FIELD_IDS.headerMessageId,
type: FieldMetadataType.TEXT,
label: msg`Header message Id`,
description: msg`Message id from the message header`,
icon: 'IconHash',
})
@WorkspaceIsFieldUIReadOnly()
@WorkspaceIsNullable()
headerMessageId: string | null;
@WorkspaceField({
standardId: MESSAGE_STANDARD_FIELD_IDS.subject,
type: FieldMetadataType.TEXT,
label: msg`Subject`,
description: msg`Subject`,
icon: 'IconMessage',
})
@WorkspaceIsFieldUIReadOnly()
@WorkspaceIsNullable()
subject: string | null;
@WorkspaceField({
standardId: MESSAGE_STANDARD_FIELD_IDS.text,
type: FieldMetadataType.TEXT,
label: msg`Text`,
description: msg`Text`,
icon: 'IconMessage',
})
@WorkspaceIsFieldUIReadOnly()
@WorkspaceIsNullable()
text: string | null;
@WorkspaceField({
standardId: MESSAGE_STANDARD_FIELD_IDS.receivedAt,
type: FieldMetadataType.DATE_TIME,
label: msg`Received At`,
description: msg`The date the message was received`,
icon: 'IconCalendar',
})
@WorkspaceIsFieldUIReadOnly()
@WorkspaceIsNullable()
receivedAt: Date | null;
@WorkspaceRelation({
standardId: MESSAGE_STANDARD_FIELD_IDS.messageThread,
type: RelationType.MANY_TO_ONE,
label: msg`Message Thread Id`,
description: msg`Message Thread Id`,
icon: 'IconHash',
inverseSideTarget: () => MessageThreadWorkspaceEntity,
inverseSideFieldKey: 'messages',
onDelete: RelationOnDeleteAction.CASCADE,
})
@WorkspaceIsFieldUIReadOnly()
@WorkspaceIsNullable()
messageThread: Relation<MessageThreadWorkspaceEntity> | null;
@WorkspaceJoinColumn('messageThread')
messageThread: EntityRelation<MessageThreadWorkspaceEntity> | null;
messageThreadId: string | null;
@WorkspaceRelation({
standardId: MESSAGE_STANDARD_FIELD_IDS.messageParticipants,
type: RelationType.ONE_TO_MANY,
label: msg`Message Participants`,
description: msg`Message Participants`,
icon: 'IconUserCircle',
inverseSideTarget: () => MessageParticipantWorkspaceEntity,
onDelete: RelationOnDeleteAction.CASCADE,
})
@WorkspaceIsFieldUIReadOnly()
@WorkspaceIsNullable()
messageParticipants: Relation<MessageParticipantWorkspaceEntity[]>;
@WorkspaceRelation({
standardId: MESSAGE_STANDARD_FIELD_IDS.messageChannelMessageAssociations,
type: RelationType.ONE_TO_MANY,
label: msg`Message Channel Association`,
description: msg`Messages from the channel.`,
icon: 'IconMessage',
inverseSideTarget: () => MessageChannelMessageAssociationWorkspaceEntity,
onDelete: RelationOnDeleteAction.CASCADE,
})
@WorkspaceIsFieldUIReadOnly()
@WorkspaceIsNullable()
messageChannelMessageAssociations: Relation<
messageParticipants: EntityRelation<MessageParticipantWorkspaceEntity[]>;
messageChannelMessageAssociations: EntityRelation<
MessageChannelMessageAssociationWorkspaceEntity[]
>;
}