From 78676173854cf2422158ef2c5134c27a59a5ce17 Mon Sep 17 00:00:00 2001 From: "Abdullah." <125115953+mabdullahabaid@users.noreply.github.com> Date: Wed, 4 Feb 2026 07:53:06 +0500 Subject: [PATCH] Migrate noteTarget and taskTarget to Morph. (#17476) This PR migrates `noteTarget` and `taskTarget` to morph relations behind separate feature flags, following the Attachment/TimelineActivity pattern. It introduces the `IS_NOTE_TARGET_MIGRATED` and `IS_TASK_TARGET_MIGRATED` flags, updates standard field metadata and indexes to use morph relations, and adds two **1.17 workspace migrations** that: - rename `noteTarget.*Id` / `taskTarget.*Id` columns to `target*Id` - convert the corresponding field metadata to `MORPH_RELATION` with a shared `morphId` On the frontend, note/task target read and write paths switch to `target*Id` when the respective flag is enabled. Deleted targets are filtered on reload to prevent reappearing relations. --- .../src/generated-metadata/graphql.ts | 2 + .../twenty-front/src/generated/graphql.ts | 2 + ...findActivitiesOperationSignatureFactory.ts | 14 +- .../useActivityTargetsForTargetableObjects.ts | 23 +- .../usePrepareFindManyActivitiesQuery.ts | 14 +- .../hooks/useUpdateActivityTargetFromCell.ts | 27 +- .../__stories__/TaskGroups.stories.tsx | 2 +- .../modules/activities/types/NoteTarget.ts | 5 + .../modules/activities/types/TaskTarget.ts | 5 + .../generateActivityTargetMorphFieldKeys.ts | 38 +- .../getActivityTargetFieldNameForObject.ts | 22 +- .../utils/getActivityTargetObjectRecords.ts | 105 +++- .../utils/getActivityTargetsFilter.ts | 20 +- .../standard-index-field-names.constant.ts | 299 +++++++++ ...e-attachment-to-morph-relations.command.ts | 17 +- ...-note-target-to-morph-relations.command.ts | 327 ++++++++++ ...-task-target-to-morph-relations.command.ts | 327 ++++++++++ .../1-17-upgrade-version-command.module.ts | 10 + .../upgrade.command.ts | 6 + .../enums/feature-flag-key.enum.ts | 2 + ...-field-metadatas-for-custom-object.util.ts | 8 +- .../workspace-entity-manager.spec.ts | 2 + .../core/utils/seed-feature-flags.util.ts | 10 + .../note-target-data-seeds.constant.ts | 24 +- .../task-target-data-seeds.constant.ts | 24 +- .../timeline-activity-seeder.service.ts | 12 +- ...adata-related-entity-ids.util.spec.ts.snap | 20 +- ...mpany-standard-flat-field-metadata.util.ts | 4 +- ...arget-standard-flat-field-metadata.util.ts | 31 +- ...unity-standard-flat-field-metadata.util.ts | 4 +- ...erson-standard-flat-field-metadata.util.ts | 4 +- ...arget-standard-flat-field-metadata.util.ts | 31 +- ...arget-standard-flat-index-metadata.util.ts | 6 +- ...arget-standard-flat-index-metadata.util.ts | 6 +- .../constant/default-feature-flags.ts | 2 + .../constant/standard-field-ids.ts | 591 ++++++++++++++++++ .../note-target.workspace-entity.ts | 12 +- .../task-target.workspace-entity.ts | 12 +- .../note-targets.integration-spec.ts | 20 +- .../task-targets.integration-spec.ts | 20 +- .../tooManyRelationQueryGqlFields.constant.ts | 16 +- ...bject-metadata-v2.integration-spec.ts.snap | 120 ++-- .../src/metadata/standard-object.constant.ts | 26 +- 43 files changed, 1998 insertions(+), 274 deletions(-) create mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/1-16/constants/standard-index-field-names.constant.ts create mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/1-17/1-17-migrate-note-target-to-morph-relations.command.ts create mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/1-17/1-17-migrate-task-target-to-morph-relations.command.ts create mode 100644 packages/twenty-server/src/engine/workspace-manager/workspace-migration/constant/standard-field-ids.ts diff --git a/packages/twenty-front/src/generated-metadata/graphql.ts b/packages/twenty-front/src/generated-metadata/graphql.ts index 3b812bb66c..79adb7b0ce 100644 --- a/packages/twenty-front/src/generated-metadata/graphql.ts +++ b/packages/twenty-front/src/generated-metadata/graphql.ts @@ -1429,11 +1429,13 @@ export enum FeatureFlagKey { IS_JUNCTION_RELATIONS_ENABLED = 'IS_JUNCTION_RELATIONS_ENABLED', IS_MARKETPLACE_ENABLED = 'IS_MARKETPLACE_ENABLED', IS_NAVIGATION_MENU_ITEM_ENABLED = 'IS_NAVIGATION_MENU_ITEM_ENABLED', + IS_NOTE_TARGET_MIGRATED = 'IS_NOTE_TARGET_MIGRATED', IS_PUBLIC_DOMAIN_ENABLED = 'IS_PUBLIC_DOMAIN_ENABLED', IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED = 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED', IS_RECORD_PAGE_LAYOUT_ENABLED = 'IS_RECORD_PAGE_LAYOUT_ENABLED', IS_ROW_LEVEL_PERMISSION_PREDICATES_ENABLED = 'IS_ROW_LEVEL_PERMISSION_PREDICATES_ENABLED', IS_SSE_DB_EVENTS_ENABLED = 'IS_SSE_DB_EVENTS_ENABLED', + IS_TASK_TARGET_MIGRATED = 'IS_TASK_TARGET_MIGRATED', IS_TIMELINE_ACTIVITY_MIGRATED = 'IS_TIMELINE_ACTIVITY_MIGRATED', IS_UNIQUE_INDEXES_ENABLED = 'IS_UNIQUE_INDEXES_ENABLED' } diff --git a/packages/twenty-front/src/generated/graphql.ts b/packages/twenty-front/src/generated/graphql.ts index ebc6684b54..eb932f7480 100644 --- a/packages/twenty-front/src/generated/graphql.ts +++ b/packages/twenty-front/src/generated/graphql.ts @@ -1401,11 +1401,13 @@ export enum FeatureFlagKey { IS_JUNCTION_RELATIONS_ENABLED = 'IS_JUNCTION_RELATIONS_ENABLED', IS_MARKETPLACE_ENABLED = 'IS_MARKETPLACE_ENABLED', IS_NAVIGATION_MENU_ITEM_ENABLED = 'IS_NAVIGATION_MENU_ITEM_ENABLED', + IS_NOTE_TARGET_MIGRATED = 'IS_NOTE_TARGET_MIGRATED', IS_PUBLIC_DOMAIN_ENABLED = 'IS_PUBLIC_DOMAIN_ENABLED', IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED = 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED', IS_RECORD_PAGE_LAYOUT_ENABLED = 'IS_RECORD_PAGE_LAYOUT_ENABLED', IS_ROW_LEVEL_PERMISSION_PREDICATES_ENABLED = 'IS_ROW_LEVEL_PERMISSION_PREDICATES_ENABLED', IS_SSE_DB_EVENTS_ENABLED = 'IS_SSE_DB_EVENTS_ENABLED', + IS_TASK_TARGET_MIGRATED = 'IS_TASK_TARGET_MIGRATED', IS_TIMELINE_ACTIVITY_MIGRATED = 'IS_TIMELINE_ACTIVITY_MIGRATED', IS_UNIQUE_INDEXES_ENABLED = 'IS_UNIQUE_INDEXES_ENABLED' } diff --git a/packages/twenty-front/src/modules/activities/graphql/operation-signatures/factories/findActivitiesOperationSignatureFactory.ts b/packages/twenty-front/src/modules/activities/graphql/operation-signatures/factories/findActivitiesOperationSignatureFactory.ts index e645ca300d..8ba765d1ee 100644 --- a/packages/twenty-front/src/modules/activities/graphql/operation-signatures/factories/findActivitiesOperationSignatureFactory.ts +++ b/packages/twenty-front/src/modules/activities/graphql/operation-signatures/factories/findActivitiesOperationSignatureFactory.ts @@ -6,6 +6,7 @@ import { type RecordGqlOperationSignatureFactory } from '@/object-record/graphql type FindActivitiesOperationSignatureFactory = { objectMetadataItems: ObjectMetadataItem[]; objectNameSingular: CoreObjectNameSingular; + isMorphRelation: boolean; }; export const findActivitiesOperationSignatureFactory: RecordGqlOperationSignatureFactory< @@ -13,6 +14,7 @@ export const findActivitiesOperationSignatureFactory: RecordGqlOperationSignatur > = ({ objectMetadataItems, objectNameSingular, + isMorphRelation, }: FindActivitiesOperationSignatureFactory) => { const body = { bodyV2: { @@ -62,9 +64,13 @@ export const findActivitiesOperationSignatureFactory: RecordGqlOperationSignatur __typename: true, createdAt: true, updatedAt: true, + deletedAt: true, note: true, noteId: true, - ...generateActivityTargetMorphFieldKeys(objectMetadataItems), + ...generateActivityTargetMorphFieldKeys( + objectMetadataItems, + isMorphRelation, + ), }, } : { @@ -73,9 +79,13 @@ export const findActivitiesOperationSignatureFactory: RecordGqlOperationSignatur __typename: true, createdAt: true, updatedAt: true, + deletedAt: true, task: true, taskId: true, - ...generateActivityTargetMorphFieldKeys(objectMetadataItems), + ...generateActivityTargetMorphFieldKeys( + objectMetadataItems, + isMorphRelation, + ), }, }), }, diff --git a/packages/twenty-front/src/modules/activities/hooks/useActivityTargetsForTargetableObjects.ts b/packages/twenty-front/src/modules/activities/hooks/useActivityTargetsForTargetableObjects.ts index 655284c135..1e9ff0e4ba 100644 --- a/packages/twenty-front/src/modules/activities/hooks/useActivityTargetsForTargetableObjects.ts +++ b/packages/twenty-front/src/modules/activities/hooks/useActivityTargetsForTargetableObjects.ts @@ -1,4 +1,5 @@ import { useRecoilValue } from 'recoil'; +import { type RecordGqlOperationOrderBy } from 'twenty-shared/types'; import { findActivityTargetsOperationSignatureFactory } from '@/activities/graphql/operation-signatures/factories/findActivityTargetsOperationSignatureFactory'; import { type ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity'; @@ -6,9 +7,12 @@ import { type NoteTarget } from '@/activities/types/NoteTarget'; import { type TaskTarget } from '@/activities/types/TaskTarget'; import { getActivityTargetsFilter } from '@/activities/utils/getActivityTargetsFilter'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; -import { type CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; -import { type RecordGqlOperationOrderBy } from 'twenty-shared/types'; +import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; +import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; +import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; + +import { FeatureFlagKey } from '~/generated/graphql'; export const useActivityTargetsForTargetableObjects = ({ objectNameSingular, @@ -28,12 +32,25 @@ export const useActivityTargetsForTargetableObjects = ({ activityTargetsOrderByVariables: RecordGqlOperationOrderBy; limit: number; }) => { - const objectMetadataItems = useRecoilValue(objectMetadataItemsState); + const objectMetadataItems = useRecoilValue( + objectMetadataItemsState, + ); + const isNoteTargetMigrated = useIsFeatureEnabled( + FeatureFlagKey.IS_NOTE_TARGET_MIGRATED, + ); + const isTaskTargetMigrated = useIsFeatureEnabled( + FeatureFlagKey.IS_TASK_TARGET_MIGRATED, + ); + const isMorphRelation = + objectNameSingular === CoreObjectNameSingular.Task + ? isTaskTargetMigrated + : isNoteTargetMigrated; const activityTargetsFilter = getActivityTargetsFilter({ targetableObjects: targetableObjects, activityObjectNameSingular: objectNameSingular, objectMetadataItems, + isMorphRelation, }); const FIND_ACTIVITY_TARGETS_OPERATION_SIGNATURE = diff --git a/packages/twenty-front/src/modules/activities/hooks/usePrepareFindManyActivitiesQuery.ts b/packages/twenty-front/src/modules/activities/hooks/usePrepareFindManyActivitiesQuery.ts index c9583b0722..f34cb2684f 100644 --- a/packages/twenty-front/src/modules/activities/hooks/usePrepareFindManyActivitiesQuery.ts +++ b/packages/twenty-front/src/modules/activities/hooks/usePrepareFindManyActivitiesQuery.ts @@ -7,13 +7,15 @@ import { type TaskTarget } from '@/activities/types/TaskTarget'; import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems'; -import { type CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; +import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { useGetRecordFromCache } from '@/object-record/cache/hooks/useGetRecordFromCache'; import { useUpsertFindManyRecordsQueryInCache } from '@/object-record/cache/hooks/useUpsertFindManyRecordsQueryInCache'; import { getRecordFromCache } from '@/object-record/cache/utils/getRecordFromCache'; import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions'; import { type ObjectRecord } from '@/object-record/types/ObjectRecord'; +import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; import { isDefined } from 'twenty-shared/utils'; +import { FeatureFlagKey } from '~/generated/graphql'; import { sortByAscString } from '~/utils/array/sortByAscString'; export const usePrepareFindManyActivitiesQuery = ({ @@ -33,6 +35,12 @@ export const usePrepareFindManyActivitiesQuery = ({ const cache = useApolloCoreClient().cache; const { objectMetadataItems } = useObjectMetadataItems(); const { objectPermissionsByObjectMetadataId } = useObjectPermissions(); + const isNoteTargetMigrated = useIsFeatureEnabled( + FeatureFlagKey.IS_NOTE_TARGET_MIGRATED, + ); + const isTaskTargetMigrated = useIsFeatureEnabled( + FeatureFlagKey.IS_TASK_TARGET_MIGRATED, + ); const { upsertFindManyRecordsQueryInCache: upsertFindManyActivitiesInCache } = useUpsertFindManyRecordsQueryInCache({ @@ -116,6 +124,10 @@ export const usePrepareFindManyActivitiesQuery = ({ findActivitiesOperationSignatureFactory({ objectNameSingular: activityObjectNameSingular, objectMetadataItems, + isMorphRelation: + activityObjectNameSingular === CoreObjectNameSingular.Task + ? isTaskTargetMigrated + : isNoteTargetMigrated, }); upsertFindManyActivitiesInCache({ diff --git a/packages/twenty-front/src/modules/activities/inline-cell/hooks/useUpdateActivityTargetFromCell.ts b/packages/twenty-front/src/modules/activities/inline-cell/hooks/useUpdateActivityTargetFromCell.ts index 6b777cbcf8..3cefaeeca6 100644 --- a/packages/twenty-front/src/modules/activities/inline-cell/hooks/useUpdateActivityTargetFromCell.ts +++ b/packages/twenty-front/src/modules/activities/inline-cell/hooks/useUpdateActivityTargetFromCell.ts @@ -5,14 +5,17 @@ import { getActivityTargetFieldNameForObject } from '@/activities/utils/getActiv import { getJoinObjectNameSingular } from '@/activities/utils/getJoinObjectNameSingular'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; +import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord'; import { useDeleteOneRecord } from '@/object-record/hooks/useDeleteOneRecord'; import { searchRecordStoreFamilyState } from '@/object-record/record-picker/multiple-record-picker/states/searchRecordStoreComponentFamilyState'; import { type RecordPickerPickableMorphItem } from '@/object-record/record-picker/types/RecordPickerPickableMorphItem'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; +import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; import { useRecoilCallback, useSetRecoilState } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; import { v4 } from 'uuid'; +import { FeatureFlagKey } from '~/generated/graphql'; type UpdateActivityTargetFromCellProps = { recordPickerInstanceId: string; @@ -50,6 +53,16 @@ export const useUpdateActivityTargetFromCell = ({ ? activityObjectNameSingular : joinObjectNameSingular, }); + const isNoteTargetMigrated = useIsFeatureEnabled( + FeatureFlagKey.IS_NOTE_TARGET_MIGRATED, + ); + const isTaskTargetMigrated = useIsFeatureEnabled( + FeatureFlagKey.IS_TASK_TARGET_MIGRATED, + ); + const isMorphRelation = + activityObjectNameSingular === CoreObjectNameSingular.Task + ? isTaskTargetMigrated + : isNoteTargetMigrated; const setActivityFromStore = useSetRecoilState( recordStoreFamilyState(activityId), @@ -67,7 +80,7 @@ export const useUpdateActivityTargetFromCell = ({ : 'note'; const objectMetadataItems = snapshot - .getLoadable(objectMetadataItemsState) + .getLoadable(objectMetadataItemsState) .getValue(); const pickedObjectMetadataItem = objectMetadataItems.find( @@ -83,6 +96,7 @@ export const useUpdateActivityTargetFromCell = ({ activityObjectNameSingular, targetObjectMetadataId: morphItem.objectMetadataId, objectMetadataItems, + isMorphRelation, }); if (!isDefined(targetFieldName)) { @@ -132,7 +146,7 @@ export const useUpdateActivityTargetFromCell = ({ const targetRecord = searchRecord.record; - const activityTarget = + const activityTarget: NoteTarget | TaskTarget = activityObjectNameSingular === CoreObjectNameSingular.Task ? { id: v4(), @@ -167,15 +181,17 @@ export const useUpdateActivityTargetFromCell = ({ ...activityTargetWithTargetRecords.map((activityTarget) => { return activityTarget.activityTarget; }), - activityTarget as NoteTarget | TaskTarget, + activityTarget, ]; - await createOneActivityTarget({ + const activityTargetInput: Partial = { ...activityTarget, [targetObjectName]: undefined, [targetFieldName]: undefined, [`${targetFieldName}Id`]: morphItem.recordId, - } as Partial); + }; + + await createOneActivityTarget(activityTargetInput); } setActivityFromStore((currentActivity) => { @@ -194,6 +210,7 @@ export const useUpdateActivityTargetFromCell = ({ activityObjectNameSingular, createOneActivityTarget, deleteOneActivityTarget, + isMorphRelation, setActivityFromStore, ], ); diff --git a/packages/twenty-front/src/modules/activities/tasks/components/__stories__/TaskGroups.stories.tsx b/packages/twenty-front/src/modules/activities/tasks/components/__stories__/TaskGroups.stories.tsx index e2078c8dc7..6e52a69ec9 100644 --- a/packages/twenty-front/src/modules/activities/tasks/components/__stories__/TaskGroups.stories.tsx +++ b/packages/twenty-front/src/modules/activities/tasks/components/__stories__/TaskGroups.stories.tsx @@ -41,7 +41,7 @@ export const Empty: Story = {}; export const WithTasks: Story = { args: { targetableObject: { - id: mockedTasks[0].taskTargets?.[0].personId, + id: mockedTasks[0].taskTargets?.[0].targetPersonId, targetObjectNameSingular: 'person', } as ActivityTargetableObject, }, diff --git a/packages/twenty-front/src/modules/activities/types/NoteTarget.ts b/packages/twenty-front/src/modules/activities/types/NoteTarget.ts index a3c17d73e3..ad1f6458ff 100644 --- a/packages/twenty-front/src/modules/activities/types/NoteTarget.ts +++ b/packages/twenty-front/src/modules/activities/types/NoteTarget.ts @@ -6,8 +6,13 @@ export type NoteTarget = { id: string; createdAt: string; updatedAt: string; + deletedAt?: string | null; companyId?: string | null; personId?: string | null; + opportunityId?: string | null; + targetCompanyId?: string | null; + targetPersonId?: string | null; + targetOpportunityId?: string | null; note: Pick; person?: Pick | null; company?: Pick | null; diff --git a/packages/twenty-front/src/modules/activities/types/TaskTarget.ts b/packages/twenty-front/src/modules/activities/types/TaskTarget.ts index 29c5976f97..23ae0fc1cf 100644 --- a/packages/twenty-front/src/modules/activities/types/TaskTarget.ts +++ b/packages/twenty-front/src/modules/activities/types/TaskTarget.ts @@ -7,8 +7,13 @@ export type TaskTarget = { id: string; createdAt: string; updatedAt: string; + deletedAt?: string | null; companyId?: string | null; personId?: string | null; + opportunityId?: string | null; + targetCompanyId?: string | null; + targetPersonId?: string | null; + targetOpportunityId?: string | null; taskId: string | null; task: Pick; person?: Pick | null; diff --git a/packages/twenty-front/src/modules/activities/utils/generateActivityTargetMorphFieldKeys.ts b/packages/twenty-front/src/modules/activities/utils/generateActivityTargetMorphFieldKeys.ts index d477e48efd..c2125c585f 100644 --- a/packages/twenty-front/src/modules/activities/utils/generateActivityTargetMorphFieldKeys.ts +++ b/packages/twenty-front/src/modules/activities/utils/generateActivityTargetMorphFieldKeys.ts @@ -1,27 +1,35 @@ +import { getActivityTargetObjectFieldIdName } from '@/activities/utils/getActivityTargetObjectFieldIdName'; import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; export const generateActivityTargetMorphFieldKeys = ( objectMetadataItems: ObjectMetadataItem[], + isMorphRelation: boolean, ) => { + const targetableObjectMetadataItems = objectMetadataItems.filter( + (objectMetadataItem) => + objectMetadataItem.isActive && !objectMetadataItem.isSystem, + ); + const targetableObjects = Object.fromEntries( - objectMetadataItems - .filter( - (objectMetadataItem) => - objectMetadataItem.isActive && !objectMetadataItem.isSystem, - ) - .map((objectMetadataItem) => [objectMetadataItem.nameSingular, true]), + targetableObjectMetadataItems.map((objectMetadataItem) => { + const targetFieldIdName = getActivityTargetObjectFieldIdName({ + nameSingular: objectMetadataItem.nameSingular, + isMorphRelation, + }); + + return [targetFieldIdName.replace(/Id$/, ''), true]; + }), ); const targetableObjectIds = Object.fromEntries( - objectMetadataItems - .filter( - (objectMetadataItem) => - objectMetadataItem.isActive && !objectMetadataItem.isSystem, - ) - .map((objectMetadataItem) => [ - `${objectMetadataItem.nameSingular}Id`, - true, - ]), + targetableObjectMetadataItems.map((objectMetadataItem) => { + const targetFieldIdName = getActivityTargetObjectFieldIdName({ + nameSingular: objectMetadataItem.nameSingular, + isMorphRelation, + }); + + return [targetFieldIdName, true]; + }), ); return { diff --git a/packages/twenty-front/src/modules/activities/utils/getActivityTargetFieldNameForObject.ts b/packages/twenty-front/src/modules/activities/utils/getActivityTargetFieldNameForObject.ts index 9793c5fa7b..3ae4204cca 100644 --- a/packages/twenty-front/src/modules/activities/utils/getActivityTargetFieldNameForObject.ts +++ b/packages/twenty-front/src/modules/activities/utils/getActivityTargetFieldNameForObject.ts @@ -1,3 +1,4 @@ +import { getActivityTargetObjectFieldIdName } from '@/activities/utils/getActivityTargetObjectFieldIdName'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { isDefined } from 'twenty-shared/utils'; @@ -8,12 +9,14 @@ type GetActivityTargetFieldNameForObjectArgs = { | CoreObjectNameSingular.Task; targetObjectMetadataId: string; objectMetadataItems: ObjectMetadataItem[]; + isMorphRelation?: boolean; }; export const getActivityTargetFieldNameForObject = ({ activityObjectNameSingular, targetObjectMetadataId, objectMetadataItems, + isMorphRelation = false, }: GetActivityTargetFieldNameForObjectArgs): string | undefined => { const activityTargetObjectNameSingular = activityObjectNameSingular === CoreObjectNameSingular.Task @@ -29,10 +32,21 @@ export const getActivityTargetFieldNameForObject = ({ return undefined; } - const targetField = activityTargetObjectMetadata.fields.find( - (field) => - field.relation?.targetObjectMetadata.id === targetObjectMetadataId, + const targetObjectMetadataItem = objectMetadataItems.find( + (objectMetadataItem) => objectMetadataItem.id === targetObjectMetadataId, ); - return targetField?.name; + if (isMorphRelation && isDefined(targetObjectMetadataItem)) { + const fieldIdName = getActivityTargetObjectFieldIdName({ + nameSingular: targetObjectMetadataItem.nameSingular, + isMorphRelation: true, + }); + + return fieldIdName.replace(/Id$/, ''); + } + + return activityTargetObjectMetadata.fields.find( + (field) => + field.relation?.targetObjectMetadata.id === targetObjectMetadataId, + )?.name; }; diff --git a/packages/twenty-front/src/modules/activities/utils/getActivityTargetObjectRecords.ts b/packages/twenty-front/src/modules/activities/utils/getActivityTargetObjectRecords.ts index 802ce23397..4fa29944f9 100644 --- a/packages/twenty-front/src/modules/activities/utils/getActivityTargetObjectRecords.ts +++ b/packages/twenty-front/src/modules/activities/utils/getActivityTargetObjectRecords.ts @@ -6,8 +6,8 @@ import { type TaskTarget } from '@/activities/types/TaskTarget'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { type ObjectRecord } from '@/object-record/types/ObjectRecord'; -import { type Nullable } from 'twenty-shared/types'; -import { isDefined } from 'twenty-shared/utils'; +import { FieldMetadataType, type Nullable } from 'twenty-shared/types'; +import { computeMorphRelationFieldName, isDefined } from 'twenty-shared/utils'; type GetActivityTargetObjectRecordsProps = { activityRecord: Note | Task; @@ -47,41 +47,100 @@ export const getActivityTargetObjectRecords = ({ ); const activityTargetRelationFields = - activityTargetObjectMetadata?.fields.filter( - (field) => - isDefined(field.relation?.targetObjectMetadata.id) && - ![CoreObjectNameSingular.Note, CoreObjectNameSingular.Task].includes( - field.relation?.targetObjectMetadata - .nameSingular as CoreObjectNameSingular, - ), - ) ?? []; + activityTargetObjectMetadata?.fields.filter((field) => { + if ( + field.type === FieldMetadataType.MORPH_RELATION && + isDefined(field.morphRelations) && + field.morphRelations.length > 0 + ) { + return true; + } + + const targetObjectNameSingular = + field.relation?.targetObjectMetadata.nameSingular; + + if (!isDefined(field.relation?.targetObjectMetadata.id)) { + return false; + } + + if (!isDefined(targetObjectNameSingular)) { + return false; + } + + return ( + targetObjectNameSingular !== CoreObjectNameSingular.Note && + targetObjectNameSingular !== CoreObjectNameSingular.Task + ); + }) ?? []; const activityTargetObjectRecords = targets .map((activityTarget) => { if (!isDefined(activityTarget)) { throw new Error('Cannot find activity target'); } - const matchingField = activityTargetRelationFields.find((field) => - isDefined(activityTarget[field.name]), - ); - if (!matchingField || !matchingField.relation) { + if (isDefined(activityTarget.deletedAt)) { return undefined; } - const correspondingObjectMetadataItem = objectMetadataItems.find( - (objectMetadataItem) => - objectMetadataItem.id === - matchingField.relation?.targetObjectMetadata.id, - ); + let matchingFieldName: string | undefined; + let correspondingObjectMetadataItem: ObjectMetadataItem | undefined; - if (!correspondingObjectMetadataItem) { + for (const field of activityTargetRelationFields) { + if ( + field.type === FieldMetadataType.MORPH_RELATION && + isDefined(field.morphRelations) + ) { + const matchingMorphRelation = field.morphRelations.find( + (morphRelation) => { + const morphFieldName = computeMorphRelationFieldName({ + fieldName: field.name, + relationType: morphRelation.type, + targetObjectMetadataNameSingular: + morphRelation.targetObjectMetadata.nameSingular, + targetObjectMetadataNamePlural: + morphRelation.targetObjectMetadata.namePlural, + }); + + return isDefined(activityTarget[morphFieldName]); + }, + ); + + if (isDefined(matchingMorphRelation)) { + matchingFieldName = computeMorphRelationFieldName({ + fieldName: field.name, + relationType: matchingMorphRelation.type, + targetObjectMetadataNameSingular: + matchingMorphRelation.targetObjectMetadata.nameSingular, + targetObjectMetadataNamePlural: + matchingMorphRelation.targetObjectMetadata.namePlural, + }); + correspondingObjectMetadataItem = objectMetadataItems.find( + (objectMetadataItem) => + objectMetadataItem.id === + matchingMorphRelation.targetObjectMetadata.id, + ); + break; + } + } else if (isDefined(activityTarget[field.name])) { + matchingFieldName = field.name; + correspondingObjectMetadataItem = objectMetadataItems.find( + (objectMetadataItem) => + objectMetadataItem.id === field.relation?.targetObjectMetadata.id, + ); + break; + } + } + + if ( + !isDefined(matchingFieldName) || + !isDefined(correspondingObjectMetadataItem) + ) { return undefined; } - const targetObjectRecord = activityTarget[matchingField.name] as - | ObjectRecord - | undefined; + const targetObjectRecord: ObjectRecord | undefined = + activityTarget[matchingFieldName]; if (!isDefined(targetObjectRecord)) { throw new Error( diff --git a/packages/twenty-front/src/modules/activities/utils/getActivityTargetsFilter.ts b/packages/twenty-front/src/modules/activities/utils/getActivityTargetsFilter.ts index b73b724473..d1779dfb37 100644 --- a/packages/twenty-front/src/modules/activities/utils/getActivityTargetsFilter.ts +++ b/packages/twenty-front/src/modules/activities/utils/getActivityTargetsFilter.ts @@ -1,4 +1,5 @@ import { type ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity'; +import { getActivityTargetObjectFieldIdName } from '@/activities/utils/getActivityTargetObjectFieldIdName'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { isDefined } from 'twenty-shared/utils'; @@ -7,12 +8,14 @@ export const getActivityTargetsFilter = ({ targetableObjects, activityObjectNameSingular, objectMetadataItems, + isMorphRelation = false, }: { targetableObjects: ActivityTargetableObject[]; activityObjectNameSingular: | CoreObjectNameSingular.Note | CoreObjectNameSingular.Task; objectMetadataItems: ObjectMetadataItem[]; + isMorphRelation?: boolean; }) => { const activityTargetObjectNameSingular = activityObjectNameSingular === CoreObjectNameSingular.Task @@ -36,13 +39,16 @@ export const getActivityTargetsFilter = ({ return undefined; } - const targetField = activityTargetObjectMetadata?.fields.find( - (field) => - field.relation?.targetObjectMetadata.id === - targetObjectMetadataItem.id, - ); - - const joinColumnName = targetField?.settings?.joinColumnName; + const joinColumnName = isMorphRelation + ? getActivityTargetObjectFieldIdName({ + nameSingular: targetObjectMetadataItem.nameSingular, + isMorphRelation: true, + }) + : activityTargetObjectMetadata?.fields.find( + (field) => + field.relation?.targetObjectMetadata.id === + targetObjectMetadataItem.id, + )?.settings?.joinColumnName; if (!isDefined(joinColumnName)) { return undefined; diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/constants/standard-index-field-names.constant.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/constants/standard-index-field-names.constant.ts new file mode 100644 index 0000000000..d793b15a68 --- /dev/null +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/constants/standard-index-field-names.constant.ts @@ -0,0 +1,299 @@ +import { STANDARD_OBJECTS } from 'twenty-shared/metadata'; + +// Maps indexName to its related field universal identifiers for each standard object +export const STANDARD_INDEX_FIELD_UNIVERSAL_IDENTIFIERS: Record< + string, + Record +> = { + attachment: { + taskIdIndex: [ + STANDARD_OBJECTS.attachment.fields.targetTask.universalIdentifier, + ], + noteIdIndex: [ + STANDARD_OBJECTS.attachment.fields.targetNote.universalIdentifier, + ], + personIdIndex: [ + STANDARD_OBJECTS.attachment.fields.targetPerson.universalIdentifier, + ], + companyIdIndex: [ + STANDARD_OBJECTS.attachment.fields.targetCompany.universalIdentifier, + ], + opportunityIdIndex: [ + STANDARD_OBJECTS.attachment.fields.targetOpportunity.universalIdentifier, + ], + dashboardIdIndex: [ + STANDARD_OBJECTS.attachment.fields.targetDashboard.universalIdentifier, + ], + workflowIdIndex: [ + STANDARD_OBJECTS.attachment.fields.targetWorkflow.universalIdentifier, + ], + }, + blocklist: { + workspaceMemberIdIndex: [ + STANDARD_OBJECTS.blocklist.fields.workspaceMember.universalIdentifier, + ], + }, + calendarChannelEventAssociation: { + calendarChannelIdIndex: [ + STANDARD_OBJECTS.calendarChannelEventAssociation.fields.calendarChannel + .universalIdentifier, + ], + calendarEventIdIndex: [ + STANDARD_OBJECTS.calendarChannelEventAssociation.fields.calendarEvent + .universalIdentifier, + ], + }, + calendarChannel: { + connectedAccountIdIndex: [ + STANDARD_OBJECTS.calendarChannel.fields.connectedAccount + .universalIdentifier, + ], + }, + calendarEventParticipant: { + calendarEventIdIndex: [ + STANDARD_OBJECTS.calendarEventParticipant.fields.calendarEvent + .universalIdentifier, + ], + personIdIndex: [ + STANDARD_OBJECTS.calendarEventParticipant.fields.person + .universalIdentifier, + ], + workspaceMemberIdIndex: [ + STANDARD_OBJECTS.calendarEventParticipant.fields.workspaceMember + .universalIdentifier, + ], + }, + company: { + accountOwnerIdIndex: [ + STANDARD_OBJECTS.company.fields.accountOwner.universalIdentifier, + ], + domainNameUniqueIndex: [ + STANDARD_OBJECTS.company.fields.domainName.universalIdentifier, + ], + searchVectorGinIndex: [ + STANDARD_OBJECTS.company.fields.searchVector.universalIdentifier, + ], + }, + connectedAccount: { + accountOwnerIdIndex: [ + STANDARD_OBJECTS.connectedAccount.fields.accountOwner.universalIdentifier, + ], + }, + dashboard: { + searchVectorGinIndex: [ + STANDARD_OBJECTS.dashboard.fields.searchVector.universalIdentifier, + ], + }, + favorite: { + forWorkspaceMemberIdIndex: [ + STANDARD_OBJECTS.favorite.fields.forWorkspaceMember.universalIdentifier, + ], + personIdIndex: [ + STANDARD_OBJECTS.favorite.fields.person.universalIdentifier, + ], + companyIdIndex: [ + STANDARD_OBJECTS.favorite.fields.company.universalIdentifier, + ], + favoriteFolderIdIndex: [ + STANDARD_OBJECTS.favorite.fields.favoriteFolder.universalIdentifier, + ], + opportunityIdIndex: [ + STANDARD_OBJECTS.favorite.fields.opportunity.universalIdentifier, + ], + workflowIdIndex: [ + STANDARD_OBJECTS.favorite.fields.workflow.universalIdentifier, + ], + workflowVersionIdIndex: [ + STANDARD_OBJECTS.favorite.fields.workflowVersion.universalIdentifier, + ], + workflowRunIdIndex: [ + STANDARD_OBJECTS.favorite.fields.workflowRun.universalIdentifier, + ], + taskIdIndex: [STANDARD_OBJECTS.favorite.fields.task.universalIdentifier], + noteIdIndex: [STANDARD_OBJECTS.favorite.fields.note.universalIdentifier], + dashboardIdIndex: [ + STANDARD_OBJECTS.favorite.fields.dashboard.universalIdentifier, + ], + }, + messageChannelMessageAssociation: { + messageChannelIdIndex: [ + STANDARD_OBJECTS.messageChannelMessageAssociation.fields.messageChannel + .universalIdentifier, + ], + messageIdIndex: [ + STANDARD_OBJECTS.messageChannelMessageAssociation.fields.message + .universalIdentifier, + ], + messageChannelIdMessageIdUniqueIndex: [ + STANDARD_OBJECTS.messageChannelMessageAssociation.fields.messageChannel + .universalIdentifier, + STANDARD_OBJECTS.messageChannelMessageAssociation.fields.message + .universalIdentifier, + ], + }, + messageChannel: { + connectedAccountIdIndex: [ + STANDARD_OBJECTS.messageChannel.fields.connectedAccount + .universalIdentifier, + ], + }, + messageFolder: { + messageChannelIdIndex: [ + STANDARD_OBJECTS.messageFolder.fields.messageChannel.universalIdentifier, + ], + }, + messageParticipant: { + messageIdIndex: [ + STANDARD_OBJECTS.messageParticipant.fields.message.universalIdentifier, + ], + personIdIndex: [ + STANDARD_OBJECTS.messageParticipant.fields.person.universalIdentifier, + ], + workspaceMemberIdIndex: [ + STANDARD_OBJECTS.messageParticipant.fields.workspaceMember + .universalIdentifier, + ], + }, + message: { + messageThreadIdIndex: [ + STANDARD_OBJECTS.message.fields.messageThread.universalIdentifier, + ], + }, + note: { + searchVectorGinIndex: [ + STANDARD_OBJECTS.note.fields.searchVector.universalIdentifier, + ], + }, + noteTarget: { + noteIdIndex: [STANDARD_OBJECTS.noteTarget.fields.note.universalIdentifier], + personIdIndex: [ + STANDARD_OBJECTS.noteTarget.fields.targetPerson.universalIdentifier, + ], + companyIdIndex: [ + STANDARD_OBJECTS.noteTarget.fields.targetCompany.universalIdentifier, + ], + opportunityIdIndex: [ + STANDARD_OBJECTS.noteTarget.fields.targetOpportunity.universalIdentifier, + ], + }, + opportunity: { + pointOfContactIdIndex: [ + STANDARD_OBJECTS.opportunity.fields.pointOfContact.universalIdentifier, + ], + companyIdIndex: [ + STANDARD_OBJECTS.opportunity.fields.company.universalIdentifier, + ], + stageIndex: [STANDARD_OBJECTS.opportunity.fields.stage.universalIdentifier], + searchVectorGinIndex: [ + STANDARD_OBJECTS.opportunity.fields.searchVector.universalIdentifier, + ], + }, + person: { + companyIdIndex: [ + STANDARD_OBJECTS.person.fields.company.universalIdentifier, + ], + emailsUniqueIndex: [ + STANDARD_OBJECTS.person.fields.emails.universalIdentifier, + ], + searchVectorGinIndex: [ + STANDARD_OBJECTS.person.fields.searchVector.universalIdentifier, + ], + }, + task: { + assigneeIdIndex: [ + STANDARD_OBJECTS.task.fields.assignee.universalIdentifier, + ], + searchVectorGinIndex: [ + STANDARD_OBJECTS.task.fields.searchVector.universalIdentifier, + ], + }, + taskTarget: { + taskIdIndex: [STANDARD_OBJECTS.taskTarget.fields.task.universalIdentifier], + personIdIndex: [ + STANDARD_OBJECTS.taskTarget.fields.targetPerson.universalIdentifier, + ], + companyIdIndex: [ + STANDARD_OBJECTS.taskTarget.fields.targetCompany.universalIdentifier, + ], + opportunityIdIndex: [ + STANDARD_OBJECTS.taskTarget.fields.targetOpportunity.universalIdentifier, + ], + }, + timelineActivity: { + workspaceMemberIdIndex: [ + STANDARD_OBJECTS.timelineActivity.fields.workspaceMember + .universalIdentifier, + ], + personIdIndex: [ + STANDARD_OBJECTS.timelineActivity.fields.targetPerson.universalIdentifier, + ], + companyIdIndex: [ + STANDARD_OBJECTS.timelineActivity.fields.targetCompany + .universalIdentifier, + ], + opportunityIdIndex: [ + STANDARD_OBJECTS.timelineActivity.fields.targetOpportunity + .universalIdentifier, + ], + noteIdIndex: [ + STANDARD_OBJECTS.timelineActivity.fields.targetNote.universalIdentifier, + ], + taskIdIndex: [ + STANDARD_OBJECTS.timelineActivity.fields.targetTask.universalIdentifier, + ], + workflowIdIndex: [ + STANDARD_OBJECTS.timelineActivity.fields.targetWorkflow + .universalIdentifier, + ], + workflowVersionIdIndex: [ + STANDARD_OBJECTS.timelineActivity.fields.targetWorkflowVersion + .universalIdentifier, + ], + workflowRunIdIndex: [ + STANDARD_OBJECTS.timelineActivity.fields.targetWorkflowRun + .universalIdentifier, + ], + dashboardIdIndex: [ + STANDARD_OBJECTS.timelineActivity.fields.targetDashboard + .universalIdentifier, + ], + }, + workflow: { + searchVectorGinIndex: [ + STANDARD_OBJECTS.workflow.fields.searchVector.universalIdentifier, + ], + }, + workflowAutomatedTrigger: { + workflowIdIndex: [ + STANDARD_OBJECTS.workflowAutomatedTrigger.fields.workflow + .universalIdentifier, + ], + }, + workflowRun: { + workflowVersionIdIndex: [ + STANDARD_OBJECTS.workflowRun.fields.workflowVersion.universalIdentifier, + ], + workflowIdIndex: [ + STANDARD_OBJECTS.workflowRun.fields.workflow.universalIdentifier, + ], + searchVectorGinIndex: [ + STANDARD_OBJECTS.workflowRun.fields.searchVector.universalIdentifier, + ], + }, + workflowVersion: { + workflowIdIndex: [ + STANDARD_OBJECTS.workflowVersion.fields.workflow.universalIdentifier, + ], + searchVectorGinIndex: [ + STANDARD_OBJECTS.workflowVersion.fields.searchVector.universalIdentifier, + ], + }, + workspaceMember: { + userEmailUniqueIndex: [ + STANDARD_OBJECTS.workspaceMember.fields.userEmail.universalIdentifier, + ], + searchVectorGinIndex: [ + STANDARD_OBJECTS.workspaceMember.fields.searchVector.universalIdentifier, + ], + }, +}; diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-17/1-17-migrate-attachment-to-morph-relations.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-17/1-17-migrate-attachment-to-morph-relations.command.ts index 9a7550d797..b087114416 100644 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-17/1-17-migrate-attachment-to-morph-relations.command.ts +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/1-17/1-17-migrate-attachment-to-morph-relations.command.ts @@ -289,11 +289,18 @@ export class MigrateAttachmentToMorphRelationsCommand extends ActiveOrSuspendedW this.logger.log(`Flush cache for workspace ${workspaceId}`); await this.workspaceCacheStorageService.flush(workspaceId); } catch (error) { - await queryRunner.rollbackTransaction(); - this.logger.error( - `Error migrating attachment to morph relations (rolled transaction back on ${workspaceId})`, - error, - ); + if (queryRunner.isTransactionActive) { + await queryRunner.rollbackTransaction(); + this.logger.error( + `Error migrating attachment to morph relations (rolled transaction back on ${workspaceId})`, + error, + ); + } else { + this.logger.error( + `Error migrating attachment to morph relations after commit on ${workspaceId}`, + error, + ); + } throw error; } finally { await queryRunner.release(); diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-17/1-17-migrate-note-target-to-morph-relations.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-17/1-17-migrate-note-target-to-morph-relations.command.ts new file mode 100644 index 0000000000..59d39ce330 --- /dev/null +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/1-17/1-17-migrate-note-target-to-morph-relations.command.ts @@ -0,0 +1,327 @@ +import { InjectDataSource, InjectRepository } from '@nestjs/typeorm'; + +import { Command } from 'nest-commander'; +import { STANDARD_OBJECTS } from 'twenty-shared/metadata'; +import { + FieldMetadataType, + type FieldMetadataSettings, +} from 'twenty-shared/types'; +import { capitalize } from 'twenty-shared/utils'; +import { DataSource, Repository } from 'typeorm'; + +import { ActiveOrSuspendedWorkspacesMigrationCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner'; +import { RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspaces-migration.command-runner'; +import { getFlatFieldsFromFlatObjectMetadata } from 'src/engine/api/graphql/workspace-schema-builder/utils/get-flat-fields-for-flat-object-metadata.util'; +import { type FlatApplicationCacheMaps } from 'src/engine/core-modules/application/types/flat-application-cache-maps.type'; +import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum'; +import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service'; +import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; +import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; +import { computeMorphOrRelationFieldJoinColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-morph-or-relation-field-join-column-name.util'; +import { findFlatEntityByUniversalIdentifier } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-universal-identifier.util'; +import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util'; +import { getMetadataFlatEntityMapsKey } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-flat-entity-maps-key.util'; +import { getMetadataRelatedMetadataNames } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-related-metadata-names.util'; +import { isMorphOrRelationFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-morph-or-relation-flat-field-metadata.util'; +import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type'; +import { WorkspaceMetadataVersionService } from 'src/engine/metadata-modules/workspace-metadata-version/services/workspace-metadata-version.service'; +import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; +import { WorkspaceCacheStorageService } from 'src/engine/workspace-cache-storage/workspace-cache-storage.service'; +import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service'; +import { type WorkspaceCacheKeyName } from 'src/engine/workspace-cache/types/workspace-cache-key.type'; +import { getWorkspaceSchemaName } from 'src/engine/workspace-datasource/utils/get-workspace-schema-name.util'; +import { TWENTY_STANDARD_APPLICATION } from 'src/engine/workspace-manager/twenty-standard-application/constants/twenty-standard-applications'; + +type RelationFieldMetadataSettings = + FieldMetadataSettings; + +@Command({ + name: 'upgrade:1-17:migrate-note-target-to-morph-relations', + description: + 'Migrate noteTarget relations to morph relation fields and set feature flag', +}) +export class MigrateNoteTargetToMorphRelationsCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner { + constructor( + @InjectRepository(WorkspaceEntity) + protected readonly workspaceRepository: Repository, + private readonly featureFlagService: FeatureFlagService, + @InjectDataSource() + private readonly coreDataSource: DataSource, + private readonly twentyORMGlobalManager: GlobalWorkspaceOrmManager, + protected readonly dataSourceService: DataSourceService, + private readonly workspaceCacheStorageService: WorkspaceCacheStorageService, + private readonly workspaceCacheService: WorkspaceCacheService, + private readonly workspaceMetadataVersionService: WorkspaceMetadataVersionService, + ) { + super(workspaceRepository, twentyORMGlobalManager, dataSourceService); + } + + override async runOnWorkspace({ + workspaceId, + options, + }: RunOnWorkspaceArgs): Promise { + const isMigrated = await this.featureFlagService.isFeatureEnabled( + FeatureFlagKey.IS_NOTE_TARGET_MIGRATED, + workspaceId, + ); + + this.logger.log(`Migrating noteTarget for workspace ${workspaceId}`); + + if (isMigrated) { + this.logger.log(`NoteTarget migration already completed. Skipping...`); + + return; + } + + if (options.dryRun) { + this.logger.log( + `Would have migrated noteTarget for workspace ${workspaceId}. Skipping...`, + ); + + return; + } + + const queryRunner = this.coreDataSource.createQueryRunner(); + + await queryRunner.connect(); + await queryRunner.startTransaction(); + + try { + const schemaName = getWorkspaceSchemaName(workspaceId); + const tableName = 'noteTarget'; + + const { + flatObjectMetadataMaps, + flatFieldMetadataMaps, + flatApplicationMaps, + } = await this.workspaceCacheService.getOrRecompute(workspaceId, [ + 'flatObjectMetadataMaps', + 'flatFieldMetadataMaps', + 'flatApplicationMaps', + ]); + + const noteTargetFieldUniversalIdentifiers = new Set([ + STANDARD_OBJECTS.noteTarget.fields.targetPerson.universalIdentifier, + STANDARD_OBJECTS.noteTarget.fields.targetCompany.universalIdentifier, + STANDARD_OBJECTS.noteTarget.fields.targetOpportunity + .universalIdentifier, + ]); + + const noteTargetObjectMetadata = + findFlatEntityByUniversalIdentifier({ + flatEntityMaps: flatObjectMetadataMaps, + universalIdentifier: STANDARD_OBJECTS.noteTarget.universalIdentifier, + }); + + if (!noteTargetObjectMetadata) { + this.logger.error( + `🟥 ${tableName} object metadata not found for workspace ${workspaceId}`, + ); + + return; + } + + const noteTargetFieldMetadatas = getFlatFieldsFromFlatObjectMetadata( + noteTargetObjectMetadata, + flatFieldMetadataMaps, + ); + + const noteTargetRelationFields = noteTargetFieldMetadatas + .filter(isMorphOrRelationFlatFieldMetadata) + .filter((field) => field.type === FieldMetadataType.RELATION) + .filter((field) => { + const isStandardAppField = this.isTwentyStandardApplicationField({ + field, + flatApplicationMaps, + workspaceId, + }); + const isStandardTarget = + isStandardAppField && + noteTargetFieldUniversalIdentifiers.has(field.universalIdentifier); + const targetObjectMetadata = field.relationTargetObjectMetadataId + ? findFlatEntityByIdInFlatEntityMaps({ + flatEntityMaps: flatObjectMetadataMaps, + flatEntityId: field.relationTargetObjectMetadataId, + }) + : undefined; + const isCustomTarget = + !isStandardAppField && targetObjectMetadata?.isCustom === true; + + return isStandardTarget || isCustomTarget; + }); + + const fieldMigrations = noteTargetRelationFields.map((field) => { + const newFieldName = `target${capitalize(field.name)}`; + const relationSettings: RelationFieldMetadataSettings = field.settings; + const oldJoinColumnName = + relationSettings?.joinColumnName ?? + computeMorphOrRelationFieldJoinColumnName({ name: field.name }); + const newJoinColumnName = computeMorphOrRelationFieldJoinColumnName({ + name: newFieldName, + }); + + return { + field, + newFieldName, + oldJoinColumnName, + newJoinColumnName, + }; + }); + + // Rename columns + for (const { oldJoinColumnName, newJoinColumnName } of fieldMigrations) { + if (oldJoinColumnName === newJoinColumnName) { + this.logger.log( + `Column "${oldJoinColumnName}" already renamed. Skipping...`, + ); + continue; + } + + try { + await queryRunner.query( + `ALTER TABLE "${schemaName}"."${tableName}" + RENAME COLUMN "${oldJoinColumnName}" TO "${newJoinColumnName}"`, + ); + this.logger.log( + `Renamed column "${oldJoinColumnName}" to "${newJoinColumnName}" for "${tableName}"`, + ); + } catch (error) { + this.logger.error( + `Error renaming column "${oldJoinColumnName}" to "${newJoinColumnName}" for "${tableName}" in workspace ${workspaceId}`, + error, + ); + + throw error; + } + } + + this.logger.log(`✅ Successfully migrated ${tableName} records`); + + const morphId = + STANDARD_OBJECTS.noteTarget.morphIds.targetMorphId.morphId; + + // Update field metadata + for (const { + field: fieldToMigrate, + newFieldName, + newJoinColumnName, + } of fieldMigrations) { + const settings = { + ...fieldToMigrate.settings, + joinColumnName: newJoinColumnName, + }; + + try { + const result = await queryRunner.query( + `UPDATE core."fieldMetadata" + SET name = $1, type = $5, "morphId" = $3, settings = $4 + WHERE id = $2`, + [ + newFieldName, + fieldToMigrate.id, + morphId, + settings, + FieldMetadataType.MORPH_RELATION, + ], + ); + + const rowsUpdated = result[1] || 0; + + if (rowsUpdated > 0) { + this.logger.log( + `Updated fieldMetadata: ${fieldToMigrate.name} → ${newFieldName} (type: MORPH_RELATION)`, + ); + } + } catch (error) { + this.logger.error( + `Error updating fieldMetadata for field "${fieldToMigrate.name}" in workspace ${workspaceId}`, + error, + ); + + throw error; + } + } + + this.logger.log(`✅ Successfully migrated ${tableName} fieldmetadata`); + + await queryRunner.commitTransaction(); + + await this.featureFlagService.enableFeatureFlags( + [FeatureFlagKey.IS_NOTE_TARGET_MIGRATED], + workspaceId, + ); + + const relatedMetadataNames = + getMetadataRelatedMetadataNames('fieldMetadata'); + const relatedCacheKeysToInvalidate: WorkspaceCacheKeyName[] = + relatedMetadataNames.map(getMetadataFlatEntityMapsKey); + const cacheKeysToInvalidate: WorkspaceCacheKeyName[] = [ + 'flatFieldMetadataMaps', + ...relatedCacheKeysToInvalidate, + 'featureFlagsMap', + ]; + + this.logger.log( + `Invalidating caches: ${cacheKeysToInvalidate.join(' ')}`, + ); + + await this.workspaceCacheService.invalidateAndRecompute( + workspaceId, + cacheKeysToInvalidate, + ); + + await this.workspaceMetadataVersionService.incrementMetadataVersion( + workspaceId, + ); + this.logger.log(`Cache flushed`); + + this.logger.log( + `Set IS_NOTE_TARGET_MIGRATED feature flag for workspace ${workspaceId}`, + ); + + this.logger.log(`Flush cache for workspace ${workspaceId}`); + await this.workspaceCacheStorageService.flush(workspaceId); + } catch (error) { + if (queryRunner.isTransactionActive) { + await queryRunner.rollbackTransaction(); + this.logger.error( + `Error migrating noteTarget to morph relations (rolled transaction back on ${workspaceId})`, + error, + ); + } else { + this.logger.error( + `Error migrating noteTarget to morph relations after commit on ${workspaceId}`, + error, + ); + } + throw error; + } finally { + await queryRunner.release(); + } + } + + private isTwentyStandardApplicationField({ + field, + flatApplicationMaps, + workspaceId, + }: { + field: { id: string; name: string; applicationId: string }; + flatApplicationMaps: FlatApplicationCacheMaps; + workspaceId: string; + }): boolean { + const application = flatApplicationMaps.byId[field.applicationId]; + + if (!application) { + this.logger.error( + `🟥 Application not found for field "${field.name}" (${field.id}) in workspace ${workspaceId} (applicationId: ${field.applicationId})`, + ); + + return false; + } + + return ( + application.universalIdentifier === + TWENTY_STANDARD_APPLICATION.universalIdentifier + ); + } +} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-17/1-17-migrate-task-target-to-morph-relations.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-17/1-17-migrate-task-target-to-morph-relations.command.ts new file mode 100644 index 0000000000..3723c490ba --- /dev/null +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/1-17/1-17-migrate-task-target-to-morph-relations.command.ts @@ -0,0 +1,327 @@ +import { InjectDataSource, InjectRepository } from '@nestjs/typeorm'; + +import { Command } from 'nest-commander'; +import { STANDARD_OBJECTS } from 'twenty-shared/metadata'; +import { + FieldMetadataType, + type FieldMetadataSettings, +} from 'twenty-shared/types'; +import { capitalize } from 'twenty-shared/utils'; +import { DataSource, Repository } from 'typeorm'; + +import { ActiveOrSuspendedWorkspacesMigrationCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner'; +import { RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspaces-migration.command-runner'; +import { getFlatFieldsFromFlatObjectMetadata } from 'src/engine/api/graphql/workspace-schema-builder/utils/get-flat-fields-for-flat-object-metadata.util'; +import { type FlatApplicationCacheMaps } from 'src/engine/core-modules/application/types/flat-application-cache-maps.type'; +import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum'; +import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service'; +import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; +import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; +import { computeMorphOrRelationFieldJoinColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-morph-or-relation-field-join-column-name.util'; +import { findFlatEntityByUniversalIdentifier } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-universal-identifier.util'; +import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util'; +import { getMetadataFlatEntityMapsKey } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-flat-entity-maps-key.util'; +import { getMetadataRelatedMetadataNames } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-related-metadata-names.util'; +import { isMorphOrRelationFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-morph-or-relation-flat-field-metadata.util'; +import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type'; +import { WorkspaceMetadataVersionService } from 'src/engine/metadata-modules/workspace-metadata-version/services/workspace-metadata-version.service'; +import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; +import { WorkspaceCacheStorageService } from 'src/engine/workspace-cache-storage/workspace-cache-storage.service'; +import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service'; +import { type WorkspaceCacheKeyName } from 'src/engine/workspace-cache/types/workspace-cache-key.type'; +import { getWorkspaceSchemaName } from 'src/engine/workspace-datasource/utils/get-workspace-schema-name.util'; +import { TWENTY_STANDARD_APPLICATION } from 'src/engine/workspace-manager/twenty-standard-application/constants/twenty-standard-applications'; + +type RelationFieldMetadataSettings = + FieldMetadataSettings; + +@Command({ + name: 'upgrade:1-17:migrate-task-target-to-morph-relations', + description: + 'Migrate taskTarget relations to morph relation fields and set feature flag', +}) +export class MigrateTaskTargetToMorphRelationsCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner { + constructor( + @InjectRepository(WorkspaceEntity) + protected readonly workspaceRepository: Repository, + private readonly featureFlagService: FeatureFlagService, + @InjectDataSource() + private readonly coreDataSource: DataSource, + private readonly twentyORMGlobalManager: GlobalWorkspaceOrmManager, + protected readonly dataSourceService: DataSourceService, + private readonly workspaceCacheStorageService: WorkspaceCacheStorageService, + private readonly workspaceCacheService: WorkspaceCacheService, + private readonly workspaceMetadataVersionService: WorkspaceMetadataVersionService, + ) { + super(workspaceRepository, twentyORMGlobalManager, dataSourceService); + } + + override async runOnWorkspace({ + workspaceId, + options, + }: RunOnWorkspaceArgs): Promise { + const isMigrated = await this.featureFlagService.isFeatureEnabled( + FeatureFlagKey.IS_TASK_TARGET_MIGRATED, + workspaceId, + ); + + this.logger.log(`Migrating taskTarget for workspace ${workspaceId}`); + + if (isMigrated) { + this.logger.log(`TaskTarget migration already completed. Skipping...`); + + return; + } + + if (options.dryRun) { + this.logger.log( + `Would have migrated taskTarget for workspace ${workspaceId}. Skipping...`, + ); + + return; + } + + const queryRunner = this.coreDataSource.createQueryRunner(); + + await queryRunner.connect(); + await queryRunner.startTransaction(); + + try { + const schemaName = getWorkspaceSchemaName(workspaceId); + const tableName = 'taskTarget'; + + const { + flatObjectMetadataMaps, + flatFieldMetadataMaps, + flatApplicationMaps, + } = await this.workspaceCacheService.getOrRecompute(workspaceId, [ + 'flatObjectMetadataMaps', + 'flatFieldMetadataMaps', + 'flatApplicationMaps', + ]); + + const taskTargetFieldUniversalIdentifiers = new Set([ + STANDARD_OBJECTS.taskTarget.fields.targetPerson.universalIdentifier, + STANDARD_OBJECTS.taskTarget.fields.targetCompany.universalIdentifier, + STANDARD_OBJECTS.taskTarget.fields.targetOpportunity + .universalIdentifier, + ]); + + const taskTargetObjectMetadata = + findFlatEntityByUniversalIdentifier({ + flatEntityMaps: flatObjectMetadataMaps, + universalIdentifier: STANDARD_OBJECTS.taskTarget.universalIdentifier, + }); + + if (!taskTargetObjectMetadata) { + this.logger.error( + `🟥 ${tableName} object metadata not found for workspace ${workspaceId}`, + ); + + return; + } + + const taskTargetFieldMetadatas = getFlatFieldsFromFlatObjectMetadata( + taskTargetObjectMetadata, + flatFieldMetadataMaps, + ); + + const taskTargetRelationFields = taskTargetFieldMetadatas + .filter(isMorphOrRelationFlatFieldMetadata) + .filter((field) => field.type === FieldMetadataType.RELATION) + .filter((field) => { + const isStandardAppField = this.isTwentyStandardApplicationField({ + field, + flatApplicationMaps, + workspaceId, + }); + const isStandardTarget = + isStandardAppField && + taskTargetFieldUniversalIdentifiers.has(field.universalIdentifier); + const targetObjectMetadata = field.relationTargetObjectMetadataId + ? findFlatEntityByIdInFlatEntityMaps({ + flatEntityMaps: flatObjectMetadataMaps, + flatEntityId: field.relationTargetObjectMetadataId, + }) + : undefined; + const isCustomTarget = + !isStandardAppField && targetObjectMetadata?.isCustom === true; + + return isStandardTarget || isCustomTarget; + }); + + const fieldMigrations = taskTargetRelationFields.map((field) => { + const newFieldName = `target${capitalize(field.name)}`; + const relationSettings: RelationFieldMetadataSettings = field.settings; + const oldJoinColumnName = + relationSettings?.joinColumnName ?? + computeMorphOrRelationFieldJoinColumnName({ name: field.name }); + const newJoinColumnName = computeMorphOrRelationFieldJoinColumnName({ + name: newFieldName, + }); + + return { + field, + newFieldName, + oldJoinColumnName, + newJoinColumnName, + }; + }); + + // Rename columns + for (const { oldJoinColumnName, newJoinColumnName } of fieldMigrations) { + if (oldJoinColumnName === newJoinColumnName) { + this.logger.log( + `Column "${oldJoinColumnName}" already renamed. Skipping...`, + ); + continue; + } + + try { + await queryRunner.query( + `ALTER TABLE "${schemaName}"."${tableName}" + RENAME COLUMN "${oldJoinColumnName}" TO "${newJoinColumnName}"`, + ); + this.logger.log( + `Renamed column "${oldJoinColumnName}" to "${newJoinColumnName}" for "${tableName}"`, + ); + } catch (error) { + this.logger.error( + `Error renaming column "${oldJoinColumnName}" to "${newJoinColumnName}" for "${tableName}" in workspace ${workspaceId}`, + error, + ); + + throw error; + } + } + + this.logger.log(`✅ Successfully migrated ${tableName} records`); + + const morphId = + STANDARD_OBJECTS.taskTarget.morphIds.targetMorphId.morphId; + + // Update field metadata + for (const { + field: fieldToMigrate, + newFieldName, + newJoinColumnName, + } of fieldMigrations) { + const settings = { + ...fieldToMigrate.settings, + joinColumnName: newJoinColumnName, + }; + + try { + const result = await queryRunner.query( + `UPDATE core."fieldMetadata" + SET name = $1, type = $5, "morphId" = $3, settings = $4 + WHERE id = $2`, + [ + newFieldName, + fieldToMigrate.id, + morphId, + settings, + FieldMetadataType.MORPH_RELATION, + ], + ); + + const rowsUpdated = result[1] || 0; + + if (rowsUpdated > 0) { + this.logger.log( + `Updated fieldMetadata: ${fieldToMigrate.name} → ${newFieldName} (type: MORPH_RELATION)`, + ); + } + } catch (error) { + this.logger.error( + `Error updating fieldMetadata for field "${fieldToMigrate.name}" in workspace ${workspaceId}`, + error, + ); + + throw error; + } + } + + this.logger.log(`✅ Successfully migrated ${tableName} fieldmetadata`); + + await queryRunner.commitTransaction(); + + await this.featureFlagService.enableFeatureFlags( + [FeatureFlagKey.IS_TASK_TARGET_MIGRATED], + workspaceId, + ); + + const relatedMetadataNames = + getMetadataRelatedMetadataNames('fieldMetadata'); + const relatedCacheKeysToInvalidate: WorkspaceCacheKeyName[] = + relatedMetadataNames.map(getMetadataFlatEntityMapsKey); + const cacheKeysToInvalidate: WorkspaceCacheKeyName[] = [ + 'flatFieldMetadataMaps', + ...relatedCacheKeysToInvalidate, + 'featureFlagsMap', + ]; + + this.logger.log( + `Invalidating caches: ${cacheKeysToInvalidate.join(' ')}`, + ); + + await this.workspaceCacheService.invalidateAndRecompute( + workspaceId, + cacheKeysToInvalidate, + ); + + await this.workspaceMetadataVersionService.incrementMetadataVersion( + workspaceId, + ); + this.logger.log(`Cache flushed`); + + this.logger.log( + `Set IS_TASK_TARGET_MIGRATED feature flag for workspace ${workspaceId}`, + ); + + this.logger.log(`Flush cache for workspace ${workspaceId}`); + await this.workspaceCacheStorageService.flush(workspaceId); + } catch (error) { + if (queryRunner.isTransactionActive) { + await queryRunner.rollbackTransaction(); + this.logger.error( + `Error migrating taskTarget to morph relations (rolled transaction back on ${workspaceId})`, + error, + ); + } else { + this.logger.error( + `Error migrating taskTarget to morph relations after commit on ${workspaceId}`, + error, + ); + } + throw error; + } finally { + await queryRunner.release(); + } + } + + private isTwentyStandardApplicationField({ + field, + flatApplicationMaps, + workspaceId, + }: { + field: { id: string; name: string; applicationId: string }; + flatApplicationMaps: FlatApplicationCacheMaps; + workspaceId: string; + }): boolean { + const application = flatApplicationMaps.byId[field.applicationId]; + + if (!application) { + this.logger.error( + `🟥 Application not found for field "${field.name}" (${field.id}) in workspace ${workspaceId} (applicationId: ${field.applicationId})`, + ); + + return false; + } + + return ( + application.universalIdentifier === + TWENTY_STANDARD_APPLICATION.universalIdentifier + ); + } +} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-17/1-17-upgrade-version-command.module.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-17/1-17-upgrade-version-command.module.ts index 710f41b660..1016ff8f88 100644 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-17/1-17-upgrade-version-command.module.ts +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/1-17/1-17-upgrade-version-command.module.ts @@ -6,7 +6,9 @@ import { DeleteFileRecordsCommand } from 'src/database/commands/upgrade-version- import { IdentifyWebhookMetadataCommand } from 'src/database/commands/upgrade-version-command/1-17/1-17-identify-webhook-metadata.command'; import { MakeWebhookUniversalIdentifierAndApplicationIdNotNullableMigrationCommand } from 'src/database/commands/upgrade-version-command/1-17/1-17-make-webhook-universal-identifier-and-application-id-not-nullable-migration.command'; import { MigrateAttachmentToMorphRelationsCommand } from 'src/database/commands/upgrade-version-command/1-17/1-17-migrate-attachment-to-morph-relations.command'; +import { MigrateNoteTargetToMorphRelationsCommand } from 'src/database/commands/upgrade-version-command/1-17/1-17-migrate-note-target-to-morph-relations.command'; import { MigrateSendEmailRecipientsCommand } from 'src/database/commands/upgrade-version-command/1-17/1-17-migrate-send-email-recipients.command'; +import { MigrateTaskTargetToMorphRelationsCommand } from 'src/database/commands/upgrade-version-command/1-17/1-17-migrate-task-target-to-morph-relations.command'; import { MigrateWorkflowCodeStepsCommand } from 'src/database/commands/upgrade-version-command/1-17/1-17-migrate-workflow-code-steps.command'; import { SeedWorkflowV1_16Command } from 'src/database/commands/upgrade-version-command/1-17/1-17-seed-workflow-v1-16.command'; import { ApplicationModule } from 'src/engine/core-modules/application/application.module'; @@ -30,6 +32,8 @@ import { GlobalWorkspaceDataSourceModule } from 'src/engine/twenty-orm/global-wo import { WorkspaceCacheStorageModule } from 'src/engine/workspace-cache-storage/workspace-cache-storage.module'; import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache.module'; import { AttachmentWorkspaceEntity } from 'src/modules/attachment/standard-objects/attachment.workspace-entity'; +import { NoteTargetWorkspaceEntity } from 'src/modules/note/standard-objects/note-target.workspace-entity'; +import { TaskTargetWorkspaceEntity } from 'src/modules/task/standard-objects/task-target.workspace-entity'; @Module({ imports: [ @@ -40,6 +44,8 @@ import { AttachmentWorkspaceEntity } from 'src/modules/attachment/standard-objec FeatureFlagEntity, AttachmentWorkspaceEntity, WebhookEntity, + NoteTargetWorkspaceEntity, + TaskTargetWorkspaceEntity, FileEntity, LogicFunctionEntity, ]), @@ -59,6 +65,8 @@ import { AttachmentWorkspaceEntity } from 'src/modules/attachment/standard-objec ], providers: [ MigrateAttachmentToMorphRelationsCommand, + MigrateNoteTargetToMorphRelationsCommand, + MigrateTaskTargetToMorphRelationsCommand, IdentifyWebhookMetadataCommand, MakeWebhookUniversalIdentifierAndApplicationIdNotNullableMigrationCommand, DeleteFileRecordsCommand, @@ -69,6 +77,8 @@ import { AttachmentWorkspaceEntity } from 'src/modules/attachment/standard-objec ], exports: [ MigrateAttachmentToMorphRelationsCommand, + MigrateNoteTargetToMorphRelationsCommand, + MigrateTaskTargetToMorphRelationsCommand, IdentifyWebhookMetadataCommand, MakeWebhookUniversalIdentifierAndApplicationIdNotNullableMigrationCommand, DeleteFileRecordsCommand, diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/upgrade.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/upgrade.command.ts index 4afe5b28ce..269a36ba04 100644 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/upgrade.command.ts +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/upgrade.command.ts @@ -14,6 +14,8 @@ import { DeleteFileRecordsCommand } from 'src/database/commands/upgrade-version- import { IdentifyWebhookMetadataCommand } from 'src/database/commands/upgrade-version-command/1-17/1-17-identify-webhook-metadata.command'; import { MakeWebhookUniversalIdentifierAndApplicationIdNotNullableMigrationCommand } from 'src/database/commands/upgrade-version-command/1-17/1-17-make-webhook-universal-identifier-and-application-id-not-nullable-migration.command'; import { MigrateAttachmentToMorphRelationsCommand } from 'src/database/commands/upgrade-version-command/1-17/1-17-migrate-attachment-to-morph-relations.command'; +import { MigrateNoteTargetToMorphRelationsCommand } from 'src/database/commands/upgrade-version-command/1-17/1-17-migrate-note-target-to-morph-relations.command'; +import { MigrateTaskTargetToMorphRelationsCommand } from 'src/database/commands/upgrade-version-command/1-17/1-17-migrate-task-target-to-morph-relations.command'; import { MigrateWorkflowCodeStepsCommand } from 'src/database/commands/upgrade-version-command/1-17/1-17-migrate-workflow-code-steps.command'; import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service'; import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; @@ -38,6 +40,8 @@ export class UpgradeCommand extends UpgradeCommandRunner { protected readonly backfillApplicationPackageFilesCommand: BackfillApplicationPackageFilesCommand, protected readonly deleteFileRecordsCommand: DeleteFileRecordsCommand, protected readonly migrateAttachmentToMorphRelationsCommand: MigrateAttachmentToMorphRelationsCommand, + protected readonly migrateNoteTargetToMorphRelationsCommand: MigrateNoteTargetToMorphRelationsCommand, + protected readonly migrateTaskTargetToMorphRelationsCommand: MigrateTaskTargetToMorphRelationsCommand, protected readonly identifyWebhookMetadataCommand: IdentifyWebhookMetadataCommand, protected readonly makeWebhookUniversalIdentifierAndApplicationIdNotNullableMigrationCommand: MakeWebhookUniversalIdentifierAndApplicationIdNotNullableMigrationCommand, protected readonly migrateWorkflowCodeStepsCommand: MigrateWorkflowCodeStepsCommand, @@ -54,6 +58,8 @@ export class UpgradeCommand extends UpgradeCommandRunner { const commands_1170: VersionCommands = [ this.migrateAttachmentToMorphRelationsCommand, + this.migrateNoteTargetToMorphRelationsCommand, + this.migrateTaskTargetToMorphRelationsCommand, this.identifyWebhookMetadataCommand, this .makeWebhookUniversalIdentifierAndApplicationIdNotNullableMigrationCommand, diff --git a/packages/twenty-server/src/engine/core-modules/feature-flag/enums/feature-flag-key.enum.ts b/packages/twenty-server/src/engine/core-modules/feature-flag/enums/feature-flag-key.enum.ts index 4d3b173b51..307dfd4651 100644 --- a/packages/twenty-server/src/engine/core-modules/feature-flag/enums/feature-flag-key.enum.ts +++ b/packages/twenty-server/src/engine/core-modules/feature-flag/enums/feature-flag-key.enum.ts @@ -12,6 +12,8 @@ export enum FeatureFlagKey { IS_DASHBOARD_V2_ENABLED = 'IS_DASHBOARD_V2_ENABLED', IS_TIMELINE_ACTIVITY_MIGRATED = 'IS_TIMELINE_ACTIVITY_MIGRATED', IS_ATTACHMENT_MIGRATED = 'IS_ATTACHMENT_MIGRATED', + IS_NOTE_TARGET_MIGRATED = 'IS_NOTE_TARGET_MIGRATED', + IS_TASK_TARGET_MIGRATED = 'IS_TASK_TARGET_MIGRATED', IS_ROW_LEVEL_PERMISSION_PREDICATES_ENABLED = 'IS_ROW_LEVEL_PERMISSION_PREDICATES_ENABLED', IS_JUNCTION_RELATIONS_ENABLED = 'IS_JUNCTION_RELATIONS_ENABLED', IS_SSE_DB_EVENTS_ENABLED = 'IS_SSE_DB_EVENTS_ENABLED', diff --git a/packages/twenty-server/src/engine/metadata-modules/object-metadata/utils/build-default-relation-flat-field-metadatas-for-custom-object.util.ts b/packages/twenty-server/src/engine/metadata-modules/object-metadata/utils/build-default-relation-flat-field-metadatas-for-custom-object.util.ts index 07d2ce116b..0fb92f0bc5 100644 --- a/packages/twenty-server/src/engine/metadata-modules/object-metadata/utils/build-default-relation-flat-field-metadatas-for-custom-object.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/object-metadata/utils/build-default-relation-flat-field-metadatas-for-custom-object.util.ts @@ -32,8 +32,8 @@ const morphIdByRelationObjectNameSingular = { STANDARD_OBJECTS.timelineActivity.morphIds.targetMorphId.morphId, favorite: null, attachment: STANDARD_OBJECTS.attachment.morphIds.targetMorphId.morphId, - noteTarget: null, - taskTarget: null, + noteTarget: STANDARD_OBJECTS.noteTarget.morphIds.targetMorphId.morphId, + taskTarget: STANDARD_OBJECTS.taskTarget.morphIds.targetMorphId.morphId, } satisfies Record< (typeof DEFAULT_RELATIONS_OBJECTS_STANDARD_IDS)[number], string | null @@ -97,6 +97,10 @@ export const buildDefaultRelationFlatFieldMetadatasForCustomObject = ({ ]) || (objectMetadataNameSingular === 'attachment' && existingFeatureFlagsMap[FeatureFlagKey.IS_ATTACHMENT_MIGRATED]) || + (objectMetadataNameSingular === 'noteTarget' && + existingFeatureFlagsMap[FeatureFlagKey.IS_NOTE_TARGET_MIGRATED]) || + (objectMetadataNameSingular === 'taskTarget' && + existingFeatureFlagsMap[FeatureFlagKey.IS_TASK_TARGET_MIGRATED]) || false; const isObjectMigratedToMorphRelations = isObjectMigratedFromOlderReleases || isFeatureFlagEnabled; 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 97cfe828c3..5c8203d489 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 @@ -231,6 +231,8 @@ describe('WorkspaceEntityManager', () => { IS_EMAILING_DOMAIN_ENABLED: false, IS_DASHBOARD_V2_ENABLED: false, IS_ATTACHMENT_MIGRATED: false, + IS_NOTE_TARGET_MIGRATED: false, + IS_TASK_TARGET_MIGRATED: false, IS_TIMELINE_ACTIVITY_MIGRATED: false, IS_GLOBAL_WORKSPACE_DATASOURCE_ENABLED: false, IS_ROW_LEVEL_PERMISSION_PREDICATES_ENABLED: false, diff --git a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/seed-feature-flags.util.ts b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/seed-feature-flags.util.ts index f18d284d8f..4e2e450899 100644 --- a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/seed-feature-flags.util.ts +++ b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/seed-feature-flags.util.ts @@ -66,6 +66,16 @@ export const seedFeatureFlags = async ({ workspaceId: workspaceId, value: true, }, + { + key: FeatureFlagKey.IS_NOTE_TARGET_MIGRATED, + workspaceId: workspaceId, + value: true, + }, + { + key: FeatureFlagKey.IS_TASK_TARGET_MIGRATED, + workspaceId: workspaceId, + value: true, + }, { key: FeatureFlagKey.IS_ROW_LEVEL_PERMISSION_PREDICATES_ENABLED, workspaceId: workspaceId, diff --git a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/data/constants/note-target-data-seeds.constant.ts b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/data/constants/note-target-data-seeds.constant.ts index 746eaa4885..8b73b19cf0 100644 --- a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/data/constants/note-target-data-seeds.constant.ts +++ b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/data/constants/note-target-data-seeds.constant.ts @@ -5,17 +5,17 @@ import { PERSON_DATA_SEED_IDS } from 'src/engine/workspace-manager/dev-seeder/da type NoteTargetDataSeed = { id: string; noteId: string | null; - personId: string | null; - companyId: string | null; - opportunityId: string | null; + targetPersonId: string | null; + targetCompanyId: string | null; + targetOpportunityId: string | null; }; export const NOTE_TARGET_DATA_SEED_COLUMNS: (keyof NoteTargetDataSeed)[] = [ 'id', 'noteId', - 'personId', - 'companyId', - 'opportunityId', + 'targetPersonId', + 'targetCompanyId', + 'targetOpportunityId', ]; const GENERATE_NOTE_TARGET_IDS = (): Record => { @@ -47,12 +47,12 @@ const GENERATE_NOTE_TARGET_SEEDS = (): NoteTargetDataSeed[] => { NOTE_TARGET_SEEDS.push({ id: NOTE_TARGET_DATA_SEED_IDS[`ID_${INDEX}`], noteId: NOTE_DATA_SEED_IDS[`ID_${INDEX}`], - personId: + targetPersonId: PERSON_DATA_SEED_IDS[ `ID_${INDEX}` as keyof typeof PERSON_DATA_SEED_IDS ], - companyId: null, - opportunityId: null, + targetCompanyId: null, + targetOpportunityId: null, }); } @@ -62,12 +62,12 @@ const GENERATE_NOTE_TARGET_SEEDS = (): NoteTargetDataSeed[] => { NOTE_TARGET_SEEDS.push({ id: NOTE_TARGET_DATA_SEED_IDS[`ID_${INDEX}`], noteId: NOTE_DATA_SEED_IDS[`ID_${INDEX}`], - personId: null, - companyId: + targetPersonId: null, + targetCompanyId: COMPANY_DATA_SEED_IDS[ `ID_${COMPANY_INDEX}` as keyof typeof COMPANY_DATA_SEED_IDS ], - opportunityId: null, + targetOpportunityId: null, }); } diff --git a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/data/constants/task-target-data-seeds.constant.ts b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/data/constants/task-target-data-seeds.constant.ts index 2648ef9562..2864b95791 100644 --- a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/data/constants/task-target-data-seeds.constant.ts +++ b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/data/constants/task-target-data-seeds.constant.ts @@ -5,17 +5,17 @@ import { TASK_DATA_SEED_IDS } from 'src/engine/workspace-manager/dev-seeder/data type TaskTargetDataSeed = { id: string; taskId: string | null; - personId: string | null; - companyId: string | null; - opportunityId: string | null; + targetPersonId: string | null; + targetCompanyId: string | null; + targetOpportunityId: string | null; }; export const TASK_TARGET_DATA_SEED_COLUMNS: (keyof TaskTargetDataSeed)[] = [ 'id', 'taskId', - 'personId', - 'companyId', - 'opportunityId', + 'targetPersonId', + 'targetCompanyId', + 'targetOpportunityId', ]; // Generate all task target IDs @@ -52,12 +52,12 @@ const GENERATE_TASK_TARGET_SEEDS = (): TaskTargetDataSeed[] => { TASK_TARGET_SEEDS.push({ id: TASK_TARGET_DATA_SEED_IDS[`ID_${INDEX}`], taskId: TASK_DATA_SEED_IDS[`ID_${INDEX}`], - personId: + targetPersonId: PERSON_DATA_SEED_IDS[ `ID_${INDEX}` as keyof typeof PERSON_DATA_SEED_IDS ], - companyId: null, - opportunityId: null, + targetCompanyId: null, + targetOpportunityId: null, }); } @@ -68,12 +68,12 @@ const GENERATE_TASK_TARGET_SEEDS = (): TaskTargetDataSeed[] => { TASK_TARGET_SEEDS.push({ id: TASK_TARGET_DATA_SEED_IDS[`ID_${INDEX}`], taskId: TASK_DATA_SEED_IDS[`ID_${INDEX}`], - personId: null, - companyId: + targetPersonId: null, + targetCompanyId: COMPANY_DATA_SEED_IDS[ `ID_${COMPANY_INDEX}` as keyof typeof COMPANY_DATA_SEED_IDS ], - opportunityId: null, + targetOpportunityId: null, }); } diff --git a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/data/services/timeline-activity-seeder.service.ts b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/data/services/timeline-activity-seeder.service.ts index f7f87645f3..00c7ddc987 100644 --- a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/data/services/timeline-activity-seeder.service.ts +++ b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/data/services/timeline-activity-seeder.service.ts @@ -463,9 +463,9 @@ export class TimelineActivitySeederService { } const targetChecks = [ - { id: noteTargetSeed.personId, type: 'person' }, - { id: noteTargetSeed.companyId, type: 'company' }, - { id: noteTargetSeed.opportunityId, type: 'opportunity' }, + { id: noteTargetSeed.targetPersonId, type: 'person' }, + { id: noteTargetSeed.targetCompanyId, type: 'company' }, + { id: noteTargetSeed.targetOpportunityId, type: 'opportunity' }, ]; for (const { id, type } of targetChecks) { @@ -487,9 +487,9 @@ export class TimelineActivitySeederService { } const targetChecks = [ - { id: taskTargetSeed.personId, type: 'person' }, - { id: taskTargetSeed.companyId, type: 'company' }, - { id: taskTargetSeed.opportunityId, type: 'opportunity' }, + { id: taskTargetSeed.targetPersonId, type: 'person' }, + { id: taskTargetSeed.targetCompanyId, type: 'company' }, + { id: taskTargetSeed.targetOpportunityId, type: 'opportunity' }, ]; for (const { id, type } of targetChecks) { diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/__tests__/__snapshots__/get-standard-object-metadata-related-entity-ids.util.spec.ts.snap b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/__tests__/__snapshots__/get-standard-object-metadata-related-entity-ids.util.spec.ts.snap index c2bb9d6f8f..8b317e3053 100644 --- a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/__tests__/__snapshots__/get-standard-object-metadata-related-entity-ids.util.spec.ts.snap +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/__tests__/__snapshots__/get-standard-object-metadata-related-entity-ids.util.spec.ts.snap @@ -979,9 +979,6 @@ exports[`getStandardObjectMetadataRelatedEntityIds should return standard object }, "noteTarget": { "fields": { - "company": { - "id": "00000000-0000-0000-0000-000000000306", - }, "createdAt": { "id": "00000000-0000-0000-0000-000000000301", }, @@ -994,10 +991,13 @@ exports[`getStandardObjectMetadataRelatedEntityIds should return standard object "note": { "id": "00000000-0000-0000-0000-000000000304", }, - "opportunity": { + "targetCompany": { + "id": "00000000-0000-0000-0000-000000000306", + }, + "targetOpportunity": { "id": "00000000-0000-0000-0000-000000000307", }, - "person": { + "targetPerson": { "id": "00000000-0000-0000-0000-000000000305", }, "updatedAt": { @@ -1417,9 +1417,6 @@ exports[`getStandardObjectMetadataRelatedEntityIds should return standard object }, "taskTarget": { "fields": { - "company": { - "id": "00000000-0000-0000-0000-000000000440", - }, "createdAt": { "id": "00000000-0000-0000-0000-000000000435", }, @@ -1429,10 +1426,13 @@ exports[`getStandardObjectMetadataRelatedEntityIds should return standard object "id": { "id": "00000000-0000-0000-0000-000000000434", }, - "opportunity": { + "targetCompany": { + "id": "00000000-0000-0000-0000-000000000440", + }, + "targetOpportunity": { "id": "00000000-0000-0000-0000-000000000441", }, - "person": { + "targetPerson": { "id": "00000000-0000-0000-0000-000000000439", }, "task": { diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/compute-company-standard-flat-field-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/compute-company-standard-flat-field-metadata.util.ts index 099ad9e741..d1c9891d2d 100644 --- a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/compute-company-standard-flat-field-metadata.util.ts +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/compute-company-standard-flat-field-metadata.util.ts @@ -393,7 +393,7 @@ export const buildCompanyStandardFlatFieldMetadatas = ({ isUIReadOnly: true, isNullable: true, targetObjectName: 'taskTarget', - targetFieldName: 'company', + targetFieldName: 'targetCompany', settings: { relationType: RelationType.ONE_TO_MANY, }, @@ -416,7 +416,7 @@ export const buildCompanyStandardFlatFieldMetadatas = ({ isUIReadOnly: true, isNullable: true, targetObjectName: 'noteTarget', - targetFieldName: 'company', + targetFieldName: 'targetCompany', settings: { relationType: RelationType.ONE_TO_MANY, }, diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/compute-note-target-standard-flat-field-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/compute-note-target-standard-flat-field-metadata.util.ts index 39ea8f02c5..12a8dee1c5 100644 --- a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/compute-note-target-standard-flat-field-metadata.util.ts +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/compute-note-target-standard-flat-field-metadata.util.ts @@ -1,3 +1,4 @@ +import { STANDARD_OBJECTS } from 'twenty-shared/metadata'; import { DateDisplayFormat, FieldMetadataType, @@ -133,13 +134,13 @@ export const buildNoteTargetStandardFlatFieldMetadatas = ({ twentyStandardApplicationId, now, }), - person: createStandardRelationFieldFlatMetadata({ + targetPerson: createStandardRelationFieldFlatMetadata({ objectName, workspaceId, context: { - type: FieldMetadataType.RELATION, - morphId: null, - fieldName: 'person', + type: FieldMetadataType.MORPH_RELATION, + morphId: STANDARD_OBJECTS.noteTarget.morphIds.targetMorphId.morphId, + fieldName: 'targetPerson', label: 'Person', description: 'NoteTarget person', icon: 'IconUser', @@ -150,7 +151,7 @@ export const buildNoteTargetStandardFlatFieldMetadatas = ({ settings: { relationType: RelationType.MANY_TO_ONE, onDelete: RelationOnDeleteAction.CASCADE, - joinColumnName: 'personId', + joinColumnName: 'targetPersonId', }, }, standardObjectMetadataRelatedEntityIds, @@ -158,13 +159,13 @@ export const buildNoteTargetStandardFlatFieldMetadatas = ({ twentyStandardApplicationId, now, }), - company: createStandardRelationFieldFlatMetadata({ + targetCompany: createStandardRelationFieldFlatMetadata({ objectName, workspaceId, context: { - type: FieldMetadataType.RELATION, - morphId: null, - fieldName: 'company', + type: FieldMetadataType.MORPH_RELATION, + morphId: STANDARD_OBJECTS.noteTarget.morphIds.targetMorphId.morphId, + fieldName: 'targetCompany', label: 'Company', description: 'NoteTarget company', icon: 'IconBuildingSkyscraper', @@ -175,7 +176,7 @@ export const buildNoteTargetStandardFlatFieldMetadatas = ({ settings: { relationType: RelationType.MANY_TO_ONE, onDelete: RelationOnDeleteAction.CASCADE, - joinColumnName: 'companyId', + joinColumnName: 'targetCompanyId', }, }, standardObjectMetadataRelatedEntityIds, @@ -183,13 +184,13 @@ export const buildNoteTargetStandardFlatFieldMetadatas = ({ twentyStandardApplicationId, now, }), - opportunity: createStandardRelationFieldFlatMetadata({ + targetOpportunity: createStandardRelationFieldFlatMetadata({ objectName, workspaceId, context: { - type: FieldMetadataType.RELATION, - morphId: null, - fieldName: 'opportunity', + type: FieldMetadataType.MORPH_RELATION, + morphId: STANDARD_OBJECTS.noteTarget.morphIds.targetMorphId.morphId, + fieldName: 'targetOpportunity', label: 'Opportunity', description: 'NoteTarget opportunity', icon: 'IconTargetArrow', @@ -200,7 +201,7 @@ export const buildNoteTargetStandardFlatFieldMetadatas = ({ settings: { relationType: RelationType.MANY_TO_ONE, onDelete: RelationOnDeleteAction.CASCADE, - joinColumnName: 'opportunityId', + joinColumnName: 'targetOpportunityId', }, }, standardObjectMetadataRelatedEntityIds, diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/compute-opportunity-standard-flat-field-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/compute-opportunity-standard-flat-field-metadata.util.ts index 8874454a72..fbbb501925 100644 --- a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/compute-opportunity-standard-flat-field-metadata.util.ts +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/compute-opportunity-standard-flat-field-metadata.util.ts @@ -363,7 +363,7 @@ export const buildOpportunityStandardFlatFieldMetadatas = ({ isUIReadOnly: true, isNullable: true, targetObjectName: 'taskTarget', - targetFieldName: 'opportunity', + targetFieldName: 'targetOpportunity', settings: { relationType: RelationType.ONE_TO_MANY, }, @@ -386,7 +386,7 @@ export const buildOpportunityStandardFlatFieldMetadatas = ({ isUIReadOnly: true, isNullable: true, targetObjectName: 'noteTarget', - targetFieldName: 'opportunity', + targetFieldName: 'targetOpportunity', settings: { relationType: RelationType.ONE_TO_MANY, }, diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/compute-person-standard-flat-field-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/compute-person-standard-flat-field-metadata.util.ts index 04d14fd736..45cd4fb273 100644 --- a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/compute-person-standard-flat-field-metadata.util.ts +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/compute-person-standard-flat-field-metadata.util.ts @@ -370,7 +370,7 @@ export const buildPersonStandardFlatFieldMetadatas = ({ isUIReadOnly: true, isNullable: true, targetObjectName: 'taskTarget', - targetFieldName: 'person', + targetFieldName: 'targetPerson', settings: { relationType: RelationType.ONE_TO_MANY, }, @@ -393,7 +393,7 @@ export const buildPersonStandardFlatFieldMetadatas = ({ isUIReadOnly: true, isNullable: true, targetObjectName: 'noteTarget', - targetFieldName: 'person', + targetFieldName: 'targetPerson', settings: { relationType: RelationType.ONE_TO_MANY, }, diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/compute-task-target-standard-flat-field-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/compute-task-target-standard-flat-field-metadata.util.ts index 9888e4f477..76cf065af0 100644 --- a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/compute-task-target-standard-flat-field-metadata.util.ts +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/compute-task-target-standard-flat-field-metadata.util.ts @@ -1,3 +1,4 @@ +import { STANDARD_OBJECTS } from 'twenty-shared/metadata'; import { DateDisplayFormat, FieldMetadataType, @@ -133,13 +134,13 @@ export const buildTaskTargetStandardFlatFieldMetadatas = ({ twentyStandardApplicationId, now, }), - person: createStandardRelationFieldFlatMetadata({ + targetPerson: createStandardRelationFieldFlatMetadata({ objectName, workspaceId, context: { - type: FieldMetadataType.RELATION, - morphId: null, - fieldName: 'person', + type: FieldMetadataType.MORPH_RELATION, + morphId: STANDARD_OBJECTS.taskTarget.morphIds.targetMorphId.morphId, + fieldName: 'targetPerson', label: 'Person', description: 'TaskTarget person', icon: 'IconUser', @@ -150,7 +151,7 @@ export const buildTaskTargetStandardFlatFieldMetadatas = ({ settings: { relationType: RelationType.MANY_TO_ONE, onDelete: RelationOnDeleteAction.CASCADE, - joinColumnName: 'personId', + joinColumnName: 'targetPersonId', }, }, standardObjectMetadataRelatedEntityIds, @@ -158,13 +159,13 @@ export const buildTaskTargetStandardFlatFieldMetadatas = ({ twentyStandardApplicationId, now, }), - company: createStandardRelationFieldFlatMetadata({ + targetCompany: createStandardRelationFieldFlatMetadata({ objectName, workspaceId, context: { - type: FieldMetadataType.RELATION, - morphId: null, - fieldName: 'company', + type: FieldMetadataType.MORPH_RELATION, + morphId: STANDARD_OBJECTS.taskTarget.morphIds.targetMorphId.morphId, + fieldName: 'targetCompany', label: 'Company', description: 'TaskTarget company', icon: 'IconBuildingSkyscraper', @@ -175,7 +176,7 @@ export const buildTaskTargetStandardFlatFieldMetadatas = ({ settings: { relationType: RelationType.MANY_TO_ONE, onDelete: RelationOnDeleteAction.CASCADE, - joinColumnName: 'companyId', + joinColumnName: 'targetCompanyId', }, }, standardObjectMetadataRelatedEntityIds, @@ -183,13 +184,13 @@ export const buildTaskTargetStandardFlatFieldMetadatas = ({ twentyStandardApplicationId, now, }), - opportunity: createStandardRelationFieldFlatMetadata({ + targetOpportunity: createStandardRelationFieldFlatMetadata({ objectName, workspaceId, context: { - type: FieldMetadataType.RELATION, - morphId: null, - fieldName: 'opportunity', + type: FieldMetadataType.MORPH_RELATION, + morphId: STANDARD_OBJECTS.taskTarget.morphIds.targetMorphId.morphId, + fieldName: 'targetOpportunity', label: 'Opportunity', description: 'TaskTarget opportunity', icon: 'IconTargetArrow', @@ -200,7 +201,7 @@ export const buildTaskTargetStandardFlatFieldMetadatas = ({ settings: { relationType: RelationType.MANY_TO_ONE, onDelete: RelationOnDeleteAction.CASCADE, - joinColumnName: 'opportunityId', + joinColumnName: 'targetOpportunityId', }, }, standardObjectMetadataRelatedEntityIds, diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/index/compute-note-target-standard-flat-index-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/index/compute-note-target-standard-flat-index-metadata.util.ts index 3018c1c627..89c8eab722 100644 --- a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/index/compute-note-target-standard-flat-index-metadata.util.ts +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/index/compute-note-target-standard-flat-index-metadata.util.ts @@ -33,7 +33,7 @@ export const buildNoteTargetStandardFlatIndexMetadatas = ({ workspaceId, context: { indexName: 'personIdIndex', - relatedFieldNames: ['person'], + relatedFieldNames: ['targetPerson'], }, standardObjectMetadataRelatedEntityIds, dependencyFlatEntityMaps, @@ -45,7 +45,7 @@ export const buildNoteTargetStandardFlatIndexMetadatas = ({ workspaceId, context: { indexName: 'companyIdIndex', - relatedFieldNames: ['company'], + relatedFieldNames: ['targetCompany'], }, standardObjectMetadataRelatedEntityIds, dependencyFlatEntityMaps, @@ -57,7 +57,7 @@ export const buildNoteTargetStandardFlatIndexMetadatas = ({ workspaceId, context: { indexName: 'opportunityIdIndex', - relatedFieldNames: ['opportunity'], + relatedFieldNames: ['targetOpportunity'], }, standardObjectMetadataRelatedEntityIds, dependencyFlatEntityMaps, diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/index/compute-task-target-standard-flat-index-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/index/compute-task-target-standard-flat-index-metadata.util.ts index 526c5ef845..cfa0466b7f 100644 --- a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/index/compute-task-target-standard-flat-index-metadata.util.ts +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/index/compute-task-target-standard-flat-index-metadata.util.ts @@ -33,7 +33,7 @@ export const buildTaskTargetStandardFlatIndexMetadatas = ({ workspaceId, context: { indexName: 'personIdIndex', - relatedFieldNames: ['person'], + relatedFieldNames: ['targetPerson'], }, standardObjectMetadataRelatedEntityIds, dependencyFlatEntityMaps, @@ -45,7 +45,7 @@ export const buildTaskTargetStandardFlatIndexMetadatas = ({ workspaceId, context: { indexName: 'companyIdIndex', - relatedFieldNames: ['company'], + relatedFieldNames: ['targetCompany'], }, standardObjectMetadataRelatedEntityIds, dependencyFlatEntityMaps, @@ -57,7 +57,7 @@ export const buildTaskTargetStandardFlatIndexMetadatas = ({ workspaceId, context: { indexName: 'opportunityIdIndex', - relatedFieldNames: ['opportunity'], + relatedFieldNames: ['targetOpportunity'], }, standardObjectMetadataRelatedEntityIds, dependencyFlatEntityMaps, diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration/constant/default-feature-flags.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration/constant/default-feature-flags.ts index 47f2df843e..34fd272252 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-migration/constant/default-feature-flags.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration/constant/default-feature-flags.ts @@ -3,5 +3,7 @@ import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/featu export const DEFAULT_FEATURE_FLAGS = [ FeatureFlagKey.IS_TIMELINE_ACTIVITY_MIGRATED, FeatureFlagKey.IS_ATTACHMENT_MIGRATED, + FeatureFlagKey.IS_NOTE_TARGET_MIGRATED, + FeatureFlagKey.IS_TASK_TARGET_MIGRATED, FeatureFlagKey.IS_RECORD_PAGE_LAYOUT_ENABLED, ] as const satisfies FeatureFlagKey[]; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration/constant/standard-field-ids.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration/constant/standard-field-ids.ts new file mode 100644 index 0000000000..fffc3b0f4f --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration/constant/standard-field-ids.ts @@ -0,0 +1,591 @@ +/** + * /!\ DO NOT EDIT THE IDS OF THIS FILE /!\ + * This file contains static ids for standard objects. + * These ids are used to identify standard objects in the database and compare them even when renamed. + * For readability keys can be edited but the values should not be changed. + */ + +// TODO: check if this can be deleted +export const ACTIVITY_TARGET_STANDARD_FIELD_IDS = { + activity: '20202020-ca58-478c-a4f5-ae825671c30e', + person: '20202020-4afd-4ae7-99c2-de57d795a93f', + company: '20202020-7cc0-44a1-8068-f11171fdd02e', + opportunity: '20202020-1fc2-4af1-8c91-7901ee0fd38b', + custom: '20202020-7f21-442f-94be-32462281b1ca', +} as const; + +// TODO: check if this can be deleted +export const ACTIVITY_STANDARD_FIELD_IDS = { + title: '20202020-24a1-4d94-a071-617f3eeed7b0', + body: '20202020-209b-440a-b2a8-043fa36a7d37', + type: '20202020-0f2b-4aab-8827-ee5d3f07d993', + reminderAt: '20202020-eb06-43e2-ba06-336be0e665a3', + dueAt: '20202020-0336-4511-ba79-565b12801bd9', + completedAt: '20202020-0f4d-4fca-9f2f-6309d9ecb85f', + activityTargets: '20202020-7253-42cb-8586-8cf950e70b79', + attachments: '20202020-5547-4197-bc2e-a07dfc4559ca', + comments: '20202020-6b2e-4d29-bbd1-ecddb330e71a', + author: '20202020-455f-44f2-8e89-1b0ef01cb7fb', + assignee: '20202020-4259-48e4-9e77-6b92991906d5', +} as const; + +export const ATTACHMENT_STANDARD_FIELD_IDS = { + name: '20202020-87a5-48f8-bbf7-ade388825a57', + fullPath: '20202020-0d19-453d-8e8d-fbcda8ca3747', + type: '20202020-a417-49b8-a40b-f6a7874caa0d', + fileCategory: '20202020-8c3f-4d9e-9a1b-2e5f7a8c9d0e', + createdBy: '395be3bd-a5c9-463d-aafe-9bc3bbec3f15', + updatedBy: '376239d1-3e65-4cb6-b5d8-e0917d43cc93', + author: '20202020-6501-4ac5-a4ef-b2f8522ef6cd', + activity: '20202020-b569-481b-a13f-9b94e47e54fe', + targetTask: '20202020-51e5-4621-9cf8-215487951c4b', + targetNote: '20202020-4f4b-4503-a6fc-6b982f3dffb5', + targetPerson: '20202020-0158-4aa2-965c-5cdafe21ffa2', + targetCompany: '20202020-ceab-4a28-b546-73b06b4c08d5', + targetOpportunity: '20202020-7374-499d-bea3-9354890755b5', + targetDashboard: '20202020-5324-43f3-9dbf-1a33e7de0ce6', + targetWorkflow: '20202020-f1e8-4c9d-8a7b-3f5e1d2c9a8b', + targetCustom: '20202020-302d-43b3-9aea-aa4f89282a9f', + targetMorphId: '20202020-f634-435d-ab8d-e1168b375c69', +} as const; + +export const BASE_OBJECT_STANDARD_FIELD_IDS = { + id: '20202020-eda0-4cee-9577-3eb357e3c22b', + createdAt: '20202020-66ac-4502-9975-e4d959c50311', + updatedAt: '20202020-d767-4622-bdcf-d8a084834d86', + deletedAt: '20202020-b9a7-48d8-8387-b9a3090a50ec', +} as const; + +export const BLOCKLIST_STANDARD_FIELD_IDS = { + handle: '20202020-eef3-44ed-aa32-4641d7fd4a3e', + workspaceMember: '20202020-548d-4084-a947-fa20a39f7c06', +} as const; + +export const CALENDAR_CHANNEL_EVENT_ASSOCIATION_STANDARD_FIELD_IDS = { + calendarChannel: '20202020-93ee-4da4-8d58-0282c4a9cb7d', + calendarEvent: '20202020-5aa5-437e-bb86-f42d457783e3', + eventExternalId: '20202020-9ec8-48bb-b279-21d0734a75a1', + recurringEventExternalId: '20202020-c58f-4c69-9bf8-9518fa31aa50', +} as const; + +export const CALENDAR_CHANNEL_STANDARD_FIELD_IDS = { + connectedAccount: '20202020-95b1-4f44-82dc-61b042ae2414', + handle: '20202020-1d08-420a-9aa7-22e0f298232d', + visibility: '20202020-1b07-4796-9f01-d626bab7ca4d', + isContactAutoCreationEnabled: '20202020-50fb-404b-ba28-369911a3793a', + contactAutoCreationPolicy: '20202020-b55d-447d-b4df-226319058775', + isSyncEnabled: '20202020-fe19-4818-8854-21f7b1b43395', + syncCursor: '20202020-bac2-4852-a5cb-7a7898992b70', + calendarChannelEventAssociations: '20202020-afb0-4a9f-979f-2d5087d71d09', + throttleFailureCount: '20202020-525c-4b76-b9bd-0dd57fd11d61', + syncStatus: '20202020-7116-41da-8b4b-035975c4eb6a', + syncStage: '20202020-6246-42e6-b5cd-003bd921782c', + syncStageStartedAt: '20202020-a934-46f1-a8e7-9568b1e3a53e', + syncedAt: '20202020-2ff5-4f70-953a-3d0d36357576', +} as const; + +export const CALENDAR_EVENT_PARTICIPANT_STANDARD_FIELD_IDS = { + calendarEvent: '20202020-fe3a-401c-b889-af4f4657a861', + handle: '20202020-8692-4580-8210-9e09cbd031a7', + displayName: '20202020-ee1e-4f9f-8ac1-5c0b2f69691e', + isOrganizer: '20202020-66e7-4e00-9e06-d06c92650580', + responseStatus: '20202020-cec0-4be8-8fba-c366abc23147', + person: '20202020-5761-4842-8186-e1898ef93966', + workspaceMember: '20202020-20e4-4591-93ed-aeb17a4dcbd2', +} as const; + +export const CALENDAR_EVENT_STANDARD_FIELD_IDS = { + title: '20202020-080e-49d1-b21d-9702a7e2525c', + isCanceled: '20202020-335b-4e04-b470-43b84b64863c', + isFullDay: '20202020-551c-402c-bb6d-dfe9efe86bcb', + startsAt: '20202020-2c57-4c75-93c5-2ac950a6ed67', + endsAt: '20202020-2554-4ee1-a617-17907f6bab21', + externalCreatedAt: '20202020-9f03-4058-a898-346c62181599', + externalUpdatedAt: '20202020-b355-4c18-8825-ef42c8a5a755', + description: '20202020-52c4-4266-a98f-e90af0b4d271', + location: '20202020-641a-4ffe-960d-c3c186d95b17', + iCalUid: '20202020-f24b-45f4-b6a3-d2f9fcb98714', + conferenceSolution: '20202020-1c3f-4b5a-b526-5411a82179eb', + conferenceLink: '20202020-35da-43ef-9ca0-e936e9dc237b', + calendarChannelEventAssociations: '20202020-bdf8-4572-a2cc-ecbb6bcc3a02', + calendarEventParticipants: '20202020-e07e-4ccb-88f5-6f3d00458eec', +} as const; + +// TODO: check if this can be deleted +export const COMMENT_STANDARD_FIELD_IDS = { + body: '20202020-d5eb-49d2-b3e0-1ed04145ebb7', + author: '20202020-2ab1-427e-a981-cf089de3a9bd', + activity: '20202020-c8d9-4c30-a35e-dc7f44388070', +} as const; + +export const COMPANY_STANDARD_FIELD_IDS = { + name: '20202020-4d99-4e2e-a84c-4a27837b1ece', + domainName: '20202020-0c28-43d8-8ba5-3659924d3489', + address_deprecated: '20202020-a82a-4ee2-96cc-a18a3259d953', + address: '20202020-c5ce-4adc-b7b6-9c0979fc55e7', + employees: '20202020-8965-464a-8a75-74bafc152a0b', + linkedinLink: '20202020-ebeb-4beb-b9ad-6848036fb451', + xLink: '20202020-6f64-4fd9-9580-9c1991c7d8c3', + annualRecurringRevenue: '20202020-602a-495c-9776-f5d5b11d227b', + idealCustomerProfile: '20202020-ba6b-438a-8213-2c5ba28d76a2', + position: '20202020-9b4e-462b-991d-a0ee33326454', + createdBy: '20202020-fabc-451d-ab7d-412170916baa', + updatedBy: '7444022e-b38f-4d4f-801b-cd664abc4834', + people: '20202020-3213-4ddf-9494-6422bcff8d7c', + accountOwner: '20202020-95b8-4e10-9881-edb5d4765f9d', + // TODO: check if activityTargets field can be deleted + activityTargets: '20202020-c2a5-4c9b-9d9a-582bcd57fbc8', + taskTargets: '20202020-cb17-4a61-8f8f-3be6730480de', + noteTargets: '20202020-bae0-4556-a74a-a9c686f77a88', + opportunities: '20202020-add3-4658-8e23-d70dccb6d0ec', + favorites: '20202020-4d1d-41ac-b13b-621631298d55', + attachments: '20202020-c1b5-4120-b0f0-987ca401ed53', + timelineActivities: '20202020-0414-4daf-9c0d-64fe7b27f89f', + searchVector: '85c71601-72f9-4b7b-b343-d46100b2c74d', +} as const; + +export const CONNECTED_ACCOUNT_STANDARD_FIELD_IDS = { + handle: '20202020-c804-4a50-bb05-b3a9e24f1dec', + provider: '20202020-ebb0-4516-befc-a9e95935efd5', + accessToken: '20202020-707b-4a0a-8753-2ad42efe1e29', + refreshToken: '20202020-532d-48bd-80a5-c4be6e7f6e49', + accountOwner: '20202020-3517-4896-afac-b1d0aa362af6', + lastSyncHistoryId: '20202020-115c-4a87-b50f-ac4367a971b9', + authFailedAt: '20202020-d268-4c6b-baff-400d402b430a', + lastCredentialsRefreshedAt: '20202020-aa5e-4e85-903b-fdf90a941941', + messageChannels: '20202020-24f7-4362-8468-042204d1e445', + calendarChannels: '20202020-af4a-47bb-99ec-51911c1d3977', + handleAliases: '20202020-8a3d-46be-814f-6228af16c47b', + scopes: '20202020-8a3d-46be-814f-6228af16c47c', + connectionParameters: '20202020-a1b2-46be-814f-6228af16c481', +} as const; + +export const TIMELINE_ACTIVITY_STANDARD_FIELD_IDS = { + happensAt: '20202020-9526-4993-b339-c4318c4d39f0', + type: '20202020-5e7b-4ccd-8b8a-86b94b474134', + name: '20202020-7207-46e8-9dab-849505ae8497', + properties: '20202020-f142-4b04-b91b-6a2b4af3bf11', + workspaceMember: '20202020-af23-4479-9a30-868edc474b36', + targetPerson: '20202020-c414-45b9-a60a-ac27aa96229f', + targetCompany: '20202020-04ad-4221-a744-7a8278a5ce21', + targetOpportunity: '20202020-7664-4a35-a3df-580d389fd527', + targetTask: '20202020-b2f5-415c-9135-a31dfe49501b', + targetNote: '20202020-ec55-4135-8da5-3a20badc0156', + targetWorkflow: '20202020-616c-4ad3-a2e9-c477c341e295', + targetWorkflowVersion: '20202020-74f1-4711-a129-e14ca0ecd744', + targetWorkflowRun: '20202020-96f0-401b-9186-a3a0759225ac', + targetDashboard: '20202020-7864-48f5-af7c-9e4b60140948', + targetCustom: '20202020-4a71-41b0-9f83-9cdcca3f8b14', + linkedRecordCachedName: '20202020-cfdb-4bef-bbce-a29f41230934', + linkedRecordId: '20202020-2e0e-48c0-b445-ee6c1e61687d', + linkedObjectMetadataId: '20202020-c595-449d-9f89-562758c9ee69', + targetMorphId: '20202020-9a2b-4c3d-a4e5-f6a7b8c9d0e1', +} as const; + +export const FAVORITE_STANDARD_FIELD_IDS = { + position: '20202020-dd26-42c6-8c3c-2a7598c204f6', + forWorkspaceMember: '20202020-ce63-49cb-9676-fdc0c45892cd', + person: '20202020-c428-4f40-b6f3-86091511c41c', + company: '20202020-cff5-4682-8bf9-069169e08279', + opportunity: '20202020-dabc-48e1-8318-2781a2b32aa2', + workflow: '20202020-b11b-4dc8-999a-6bd0a947b463', + workflowVersion: '20202020-e1b8-4caf-b55a-3ab4d4cbcd21', + workflowRun: '20202020-db5a-4fe4-9a13-9afa22b1e762', + task: '20202020-1b1b-4b3b-8b1b-7f8d6a1d7d5c', + note: '20202020-1f25-43fe-8b00-af212fdde824', + view: '20202020-5a93-4fa9-acce-e73481a0bbdf', + custom: '20202020-855a-4bc8-9861-79deef37011f', + favoriteFolder: '20202020-f658-4d12-8b4d-248356aa4bd9', + dashboard: '20202020-6ef9-45e4-b440-cc986f687c91', +} as const; + +export const FAVORITE_FOLDER_STANDARD_FIELD_IDS = { + position: '20202020-5278-4bde-8909-2cec74d43744', + name: '20202020-82a3-4537-8ff0-dbce7eec35d6', + favorites: '20202020-b5e3-4b42-8af2-03cd4fd2e4d2', +} as const; + +export const MESSAGE_CHANNEL_MESSAGE_ASSOCIATION_STANDARD_FIELD_IDS = { + messageChannel: '20202020-b658-408f-bd46-3bd2d15d7e52', + message: '20202020-da5d-4ac5-8743-342ab0a0336b', + messageExternalId: '20202020-37d6-438f-b6fd-6503596c8f34', + messageThread: '20202020-fac8-42a8-94dd-44dbc920ae16', + messageThreadExternalId: '20202020-35fb-421e-afa0-0b8e8f7f9018', +} as const; + +export const MESSAGE_CHANNEL_STANDARD_FIELD_IDS = { + visibility: '20202020-6a6b-4532-9767-cbc61b469453', + handle: '20202020-2c96-43c3-93e3-ed6b1acb69bc', + connectedAccount: '20202020-49a2-44a4-b470-282c0440d15d', + type: '20202020-ae95-42d9-a3f1-797a2ea22122', + isContactAutoCreationEnabled: '20202020-fabd-4f14-b7c6-3310f6d132c6', + contactAutoCreationPolicy: '20202020-fc0e-4ba6-b259-a66ca89cfa38', + excludeNonProfessionalEmails: '20202020-1df5-445d-b4f3-2413ad178431', + excludeGroupEmails: '20202020-45a0-4be4-9164-5820a6a109fb', + messageChannelMessageAssociations: '20202020-49b8-4766-88fd-75f1e21b3d5f', + messageFolders: '20202020-cc39-4432-9fe8-ec8ab8bbed94', + messageFolderImportPolicy: '20202020-cc39-4432-9fe8-ec8ab8bbed95', + pendingGroupEmailsAction: '20202020-17c5-4e9f-bc50-af46a89fdd42', + isSyncEnabled: '20202020-d9a6-48e9-990b-b97fdf22e8dd', + syncCursor: '20202020-79d1-41cf-b738-bcf5ed61e256', + syncedAt: '20202020-263d-4c6b-ad51-137ada56f7d4', + syncStatus: '20202020-56a1-4f7e-9880-a8493bb899cc', + syncStage: '20202020-7979-4b08-89fe-99cb5e698767', + syncStageStartedAt: '20202020-8c61-4a42-ae63-73c1c3c52e06', + throttleFailureCount: '20202020-0291-42be-9ad0-d578a51684ab', +} as const; + +export const MESSAGE_FOLDER_STANDARD_FIELD_IDS = { + name: '20202020-7cf8-40bc-a681-b80b771449b7', + parentFolderId: '20202020-e45d-49de-a4aa-587bbf9601f3', + messageChannel: '20202020-b658-408f-bd46-3bd2d15d7e52', + syncCursor: '20202020-98cd-49ed-8dfc-cb5796400e64', + isSentFolder: '20202020-2af5-4a25-b2de-3c9386da941b', + isSynced: '20202020-764f-4e09-8f95-cd46b6bfe3c4', + externalId: '20202020-f3a8-4d2b-9c7e-1b5f9a8e4c6d', + pendingSyncAction: '20202020-4f97-4c79-9517-16387fe237f7', +} as const; + +export const MESSAGE_PARTICIPANT_STANDARD_FIELD_IDS = { + message: '20202020-985b-429a-9db9-9e55f4898a2a', + role: '20202020-65d1-42f4-8729-c9ec1f52aecd', + handle: '20202020-2456-464e-b422-b965a4db4a0b', + displayName: '20202020-36dd-4a4f-ac02-228425be9fac', + person: '20202020-249d-4e0f-82cd-1b9df5cd3da2', + workspaceMember: '20202020-77a7-4845-99ed-1bcbb478be6f', +} as const; + +export const MESSAGE_THREAD_STANDARD_FIELD_IDS = { + messages: '20202020-3115-404f-aade-e1154b28e35a', + messageChannelMessageAssociations: '20202020-314e-40a4-906d-a5d5d6c285f6', + messageThreadSubscribers: '20202020-3b3b-4b3b-8b3b-7f8d6a1d7d5b', +} as const; + +export const MESSAGE_THREAD_SUBSCRIBER_STANDARD_FIELD_IDS = { + messageThread: '20202020-2c8f-4f3e-8b9a-7f8d6a1c7d5b', + workspaceMember: '20202020-7f7b-4b3b-8b3b-7f8d6a1d7d5a', +} as const; + +export const MESSAGE_STANDARD_FIELD_IDS = { + headerMessageId: '20202020-72b5-416d-aed8-b55609067d01', + messageThread: '20202020-30f2-4ccd-9f5c-e41bb9d26214', + direction: '20202020-0203-4118-8e2a-05b9bdae6dab', + subject: '20202020-52d1-4036-b9ae-84bd722bb37a', + text: '20202020-d2ee-4e7e-89de-9a0a9044a143', + receivedAt: '20202020-140a-4a2a-9f86-f13b6a979afc', + messageParticipants: '20202020-7cff-4a74-b63c-73228448cbd9', + messageChannelMessageAssociations: '20202020-3cef-43a3-82c6-50e7cfbc9ae4', +} as const; + +export const NOTE_STANDARD_FIELD_IDS = { + position: '20202020-368d-4dc2-943f-ed8a49c7fdfb', + title: '20202020-faeb-4c76-8ba6-ccbb0b4a965f', + body: '20202020-e63d-4e70-95be-a78cd9abe7ef', + bodyV2: '20202020-a7bb-4d94-be51-8f25181502c8', + createdBy: '20202020-0d79-4e21-ab77-5a394eff97be', + updatedBy: '9b446e89-2484-4044-a3b5-420f6b578c0c', + noteTargets: '20202020-1f25-43fe-8b00-af212fdde823', + attachments: '20202020-4986-4c92-bf19-39934b149b16', + timelineActivities: '20202020-7030-42f8-929c-1a57b25d6bce', + favorites: '20202020-4d1d-41ac-b13b-621631298d67', + searchVector: '20202020-7ea8-44d4-9d4c-51dd2a757950', +} as const; + +export const NOTE_TARGET_STANDARD_FIELD_IDS = { + note: '20202020-57f3-4f50-9599-fc0f671df003', + targetPerson: '20202020-38ca-4aab-92f5-8a605ca2e4c5', + targetCompany: 'c500fbc0-d6f2-4982-a959-5a755431696c', + targetOpportunity: '20202020-4e42-417a-a705-76581c9ade79', + targetCustom: '20202020-3d12-4579-94ee-7117c1bad492', + targetMorphId: '20202020-f635-435d-ab8d-e1168b375c70', +} as const; + +export const OPPORTUNITY_STANDARD_FIELD_IDS = { + name: '20202020-8609-4f65-a2d9-44009eb422b5', + amount: '20202020-583e-4642-8533-db761d5fa82f', + closeDate: '20202020-527e-44d6-b1ac-c4158d307b97', + probabilityDeprecated: '20202020-69d4-45f3-9703-690b09fafcf0', + stage: '20202020-6f76-477d-8551-28cd65b2b4b9', + position: '20202020-806d-493a-bbc6-6313e62958e2', + createdBy: '20202020-a63e-4a62-8e63-42a51828f831', + updatedBy: '3c8a6095-3f64-4e81-a59e-66c2bd181e11', + pointOfContact: '20202020-8dfb-42fc-92b6-01afb759ed16', + company: '20202020-cbac-457e-b565-adece5fc815f', + favorites: '20202020-a1c2-4500-aaae-83ba8a0e827a', + // TODO: check if activityTargets field can be deleted + activityTargets: '20202020-220a-42d6-8261-b2102d6eab35', + taskTargets: '20202020-59c0-4179-a208-4a255f04a5be', + noteTargets: '20202020-dd3f-42d5-a382-db58aabf43d3', + attachments: '20202020-87c7-4118-83d6-2f4031005209', + timelineActivities: '20202020-30e2-421f-96c7-19c69d1cf631', + searchVector: '428a0da5-4b2e-4ce3-b695-89a8b384e6e3', +} as const; + +export const PERSON_STANDARD_FIELD_IDS = { + name: '20202020-3875-44d5-8c33-a6239011cab8', + email: '20202020-a740-42bb-8849-8980fb3f12e1', + emails: '20202020-3c51-43fa-8b6e-af39e29368ab', + linkedinLink: '20202020-f1af-48f7-893b-2007a73dd508', + xLink: '20202020-8fc2-487c-b84a-55a99b145cfd', + jobTitle: '20202020-b0d0-415a-bef9-640a26dacd9b', + phone: '20202020-4564-4b8b-a09f-05445f2e0bce', + phones: '20202020-0638-448e-8825-439134618022', + city: '20202020-5243-4ffb-afc5-2c675da41346', + avatarUrl: '20202020-b8a6-40df-961c-373dc5d2ec21', + position: '20202020-fcd5-4231-aff5-fff583eaa0b1', + createdBy: '20202020-f6ab-4d98-af24-a3d5b664148a', + updatedBy: 'e9e0dd35-184c-4742-84da-afadf45ce59a', + company: '20202020-e2f3-448e-b34c-2d625f0025fd', + pointOfContactForOpportunities: '20202020-911b-4a7d-b67b-918aa9a5b33a', + // TODO: check if activityTargets field can be deleted + activityTargets: '20202020-dee7-4b7f-b50a-1f50bd3be452', + taskTargets: '20202020-584b-4d3e-88b6-53ab1fa03c3a', + noteTargets: '20202020-c8fc-4258-8250-15905d3fcfec', + favorites: '20202020-4073-4117-9cf1-203bcdc91cbd', + attachments: '20202020-cd97-451f-87fa-bcb789bdbf3a', + messageParticipants: '20202020-498e-4c61-8158-fa04f0638334', + calendarEventParticipants: '20202020-52ee-45e9-a702-b64b3753e3a9', + timelineActivities: '20202020-a43e-4873-9c23-e522de906ce5', + searchVector: '57d1d7ad-fa10-44fc-82f3-ad0959ec2534', +} as const; + +export const TASK_STANDARD_FIELD_IDS = { + position: '20202020-7d47-4690-8a98-98b9a0c05dd8', + title: '20202020-b386-4cb7-aa5a-08d4a4d92680', + body: '20202020-ce13-43f4-8821-69388fe1fd26', + bodyV2: '20202020-4aa0-4ae8-898d-7df0afd47ab1', + dueAt: '20202020-fd99-40da-951b-4cb9a352fce3', + status: '20202020-70bc-48f9-89c5-6aa730b151e0', + createdBy: '20202020-1a04-48ab-a567-576965ae5387', + updatedBy: '9e8bf518-f4ab-433e-9674-efb75fba2802', + taskTargets: '20202020-de9c-4d0e-a452-713d4a3e5fc7', + attachments: '20202020-794d-4783-a8ff-cecdb15be139', + assignee: '20202020-065a-4f42-a906-e20422c1753f', + timelineActivities: '20202020-c778-4278-99ee-23a2837aee64', + favorites: '20202020-4d1d-41ac-b13b-621631298d65', + searchVector: '20202020-4746-4e2f-870c-52b02c67c90d', +} as const; + +export const TASK_TARGET_STANDARD_FIELD_IDS = { + task: '20202020-e881-457a-8758-74aaef4ae78a', + targetPerson: '20202020-c8a0-4e85-a016-87e2349cfbec', + targetCompany: '20202020-4703-4a4e-948c-487b0c60a92c', + targetOpportunity: '20202020-6cb2-4c01-a9a5-aca3dbc11d41', + targetCustom: '20202020-41c1-4c9a-8c75-be0971ef89af', + targetMorphId: '20202020-f636-435d-ab8d-e1168b375c71', +} as const; + +export const VIEW_FIELD_STANDARD_FIELD_IDS = { + fieldMetadataId: '20202020-135f-4c5b-b361-15f24870473c', + isVisible: '20202020-e966-473c-9c18-f00d3347e0ba', + size: '20202020-6fab-4bd0-ae72-20f3ee39d581', + position: '20202020-19e5-4e4c-8c15-3a96d1fd0650', + view: '20202020-e8da-4521-afab-d6d231f9fa18', + aggregateOperation: '20202020-2cd7-4f94-ae83-4a14f5731a04', +} as const; + +export const VIEW_GROUP_STANDARD_FIELD_IDS = { + fieldMetadataId: '20202020-8f26-46ae-afed-fdacd7778682', + fieldValue: '20202020-175e-4596-b7a4-1cd9d14e5a30', + isVisible: '20202020-0fed-4b44-88fd-a064c4fcfce4', + position: '20202020-748e-4645-8f32-84aae7726c04', + view: '20202020-5bc7-4110-b23f-fb851fb133b4', +} as const; + +export const VIEW_FILTER_STANDARD_FIELD_IDS = { + fieldMetadataId: '20202020-c9aa-4c94-8d0e-9592f5008fb0', + operand: '20202020-bd23-48c4-9fab-29d1ffb80310', + value: '20202020-1e55-4a1e-a1d2-fefb86a5fce5', + displayValue: '20202020-1270-4ebf-9018-c0ec10d5038e', + view: '20202020-4f5b-487e-829c-3d881c163611', + viewFilterGroupId: '20202020-2580-420a-8328-cab1635c0296', + positionInViewFilterGroup: '20202020-3bb0-4f66-a537-a46fe0dc468f', + subFieldName: '20202020-3bb0-4f66-a537-a46fe0dc469a', +} as const; + +export const VIEW_FILTER_GROUP_STANDARD_FIELD_IDS = { + view: '20202020-ff7a-4b54-8be5-aa0249047b74', + parentViewFilterGroupId: '20202020-edbf-4929-8ede-64f48d6bf2a7', + logicalOperator: '20202020-64d9-4bc5-85ba-c250796ce9aa', + positionInViewFilterGroup: '20202020-90d6-4299-ad87-d05ddd3a0a3f', +} as const; + +export const VIEW_SORT_STANDARD_FIELD_IDS = { + fieldMetadataId: '20202020-8240-4657-aee4-7f0df8e94eca', + direction: '20202020-b06e-4eb3-9b58-0a62e5d79836', + view: '20202020-bd6c-422b-9167-5c105f2d02c8', +} as const; + +export const VIEW_STANDARD_FIELD_IDS = { + name: '20202020-12c6-4f37-b588-c9b9bf57328d', + objectMetadataId: '20202020-d6de-4fd5-84dd-47f9e730368b', + type: '20202020-dd11-4607-9ec7-c57217262a7f', + key: '20202020-298e-49fa-9f4a-7b416b110443', + icon: '20202020-1f08-4fd9-929b-cbc07f317166', + kanbanFieldMetadataId: '20202020-d09b-4f65-ac42-06a2f20ba0e8', + kanbanAggregateOperation: '20202020-8da2-45de-a731-61bed84b17a8', + kanbanAggregateOperationFieldMetadataId: + '20202020-b1b3-4bf3-85e4-dc7d58aa9b02', + mainGroupByFieldMetadataId: '20202020-f782-4f89-96eb-083a02cca887', + position: '20202020-e9db-4303-b271-e8250c450172', + isCompact: '20202020-674e-4314-994d-05754ea7b22b', + openRecordIn: '20202020-086d-4eef-9f03-56c6392eacb8', + viewFields: '20202020-542b-4bdc-b177-b63175d48edf', + viewGroups: '20202020-e1a1-419f-ac81-1986a5ea59a8', + viewFilters: '20202020-ff23-4154-b63c-21fb36cd0967', + viewFilterGroups: '20202020-0318-474a-84a1-bac895ceaa5a', + viewSorts: '20202020-891b-45c3-9fe1-80a75b4aa043', + favorites: '20202020-c818-4a86-8284-9ec0ef0a59a5', + anyFieldFilterValue: '20202020-3143-46c0-bb05-034063ce0703', +} as const; + +export const WORKFLOW_AUTOMATED_TRIGGER_STANDARD_FIELD_IDS = { + type: '20202020-3319-4234-a34c-3f92c1ab56e7', + settings: '20202020-3319-4234-a34c-bac8f903de12', + workflow: '20202020-3319-4234-a34c-8e1a4d2f7c03', +} as const; + +export const WORKFLOW_STANDARD_FIELD_IDS = { + name: '20202020-b3d3-478f-acc0-5d901e725b20', + lastPublishedVersionId: '20202020-326a-4fba-8639-3456c0a169e8', + statuses: '20202020-357c-4432-8c50-8c31b4a552d9', + position: '20202020-39b0-4d8c-8c5f-33c2326deb5f', + versions: '20202020-9432-416e-8f3c-27ee3153d099', + runs: '20202020-759b-4340-b58b-e73595c4df4f', + eventListeners: '20202020-0229-4c66-832e-035c67579a38', + automatedTriggers: '20202020-3319-4234-a34c-117ecad2b8a9', + favorites: '20202020-c554-4c41-be7a-cf9cd4b0d512', + timelineActivities: '20202020-906e-486a-a798-131a5f081faf', + attachments: '20202020-4a8c-4e2d-9b1c-7e5f3a2b4c6d', + createdBy: '20202020-6007-401a-8aa5-e6f48581a6f3', + updatedBy: '3559831e-caf2-4eb5-9db1-b47bf968c774', + searchVector: '20202020-535d-4ffa-b7f3-4fa0d5da1b7a', +} as const; + +export const WORKFLOW_RUN_STANDARD_FIELD_IDS = { + name: '20202020-b840-4253-aef9-4e5013694587', + workflowVersion: '20202020-2f52-4ba8-8dc4-d0d6adb9578d', + workflow: '20202020-8c57-4e7f-84f5-f373f68e1b82', + enqueuedAt: '20202020-f1e3-4de1-a461-b5c4fdbc861d', + startedAt: '20202020-a234-4e2d-bd15-85bcea6bb183', + endedAt: '20202020-e1c1-4b6b-bbbd-b2beaf2e159e', + status: '20202020-6b3e-4f9c-8c2b-2e5b8e6d6f3b', + position: '20202020-7802-4c40-ae89-1f506fe3365c', + createdBy: '20202020-6007-401a-8aa5-e6f38581a6f3', + updatedBy: '730dc1c9-34f5-4c22-84a6-bcb55b7604e2', + output: '20202020-7be4-4db2-8ac6-3ff0d740843d', + context: '20202020-189c-478a-b867-d72feaf5926a', + state: '20202020-611f-45f3-9cde-d64927e8ec57', + favorites: '20202020-4baf-4604-b899-2f7fcfbbf90d', + timelineActivities: '20202020-af4d-4eb0-babc-eb960a45b356', + searchVector: '20202020-0b91-4ded-b1ac-cbd5efa58cb9', +} as const; + +export const WORKFLOW_VERSION_STANDARD_FIELD_IDS = { + name: '20202020-a12f-4cca-9937-a2e40cc65509', + workflow: '20202020-afa3-46c3-91b0-0631ca6aa1c8', + trigger: '20202020-4eae-43e7-86e0-212b41a30b48', + status: '20202020-5a34-440e-8a25-39d8c3d1d4cf', + position: '20202020-791d-4950-ab28-0e704767ae1c', + runs: '20202020-1d08-46df-901a-85045f18099a', + steps: '20202020-5988-4a64-b94a-1f9b7b989039', + favorites: '20202020-b8e0-4e57-928d-b51671cc71f2', + timelineActivities: '20202020-fcb0-4695-b17e-3b43a421c633', + searchVector: '20202020-3f17-44ef-b8c1-b282ae8469b2', +} as const; + +export const WORKSPACE_MEMBER_STANDARD_FIELD_IDS = { + position: '20202020-1810-4591-a93c-d0df97dca843', + name: '20202020-e914-43a6-9c26-3603c59065f4', + colorScheme: '20202020-66bc-47f2-adac-f2ef7c598b63', + locale: '20202020-402e-4695-b169-794fa015afbe', + avatarUrl: '20202020-0ced-4c4f-a376-c98a966af3f6', + userEmail: '20202020-4c5f-4e09-bebc-9e624e21ecf4', + userId: '20202020-75a9-4dfc-bf25-2e4b43e89820', + authoredActivities: '20202020-f139-4f13-a82f-a65a8d290a74', + assignedActivities: '20202020-5c97-42b6-8ca9-c07622cbb33f', + assignedTasks: '20202020-61dc-4a1c-99e8-38ebf8d2bbeb', + favorites: '20202020-f3c1-4faf-b343-cf7681038757', + accountOwnerForCompanies: '20202020-dc29-4bd4-a3c1-29eafa324bee', + authoredAttachments: '20202020-000f-4947-917f-1b09851024fe', + authoredComments: '20202020-5536-4f59-b837-51c45ef43b05', + connectedAccounts: '20202020-e322-4bde-a525-727079b4a100', + messageParticipants: '20202020-8f99-48bc-a5eb-edd33dd54188', + blocklist: '20202020-6cb2-4161-9f29-a4b7f1283859', + calendarEventParticipants: '20202020-0dbc-4841-9ce1-3e793b5b3512', + timelineActivities: '20202020-e15b-47b8-94fe-8200e3c66615', + auditLogs: '20202020-2f54-4739-a5e2-99563385e83d', + messageThreadSubscribers: '20202020-4b3b-4b3b-9b3b-3b3b3b3b3b3b', + timeZone: '20202020-2d33-4c21-a86e-5943b050dd54', + dateFormat: '20202020-af13-4e11-b1e7-b8cf5ea13dc0', + timeFormat: '20202020-8acb-4cf8-a851-a6ed443c8d81', + searchVector: '20202020-46d0-4e7f-bc26-74c0edaeb619', + calendarStartDay: '20202020-92d0-1d7f-a126-25ededa6b142', + numberFormat: '20202020-7f40-4e7f-b126-11c0eda6b141', +} as const; +export const CUSTOM_OBJECT_STANDARD_FIELD_IDS = { + name: '20202020-ba07-4ffd-ba63-009491f5749c', + position: '20202020-c2bd-4e16-bb9a-c8b0411bf49d', + createdBy: '20202020-be0e-4971-865b-32ca87cbb315', + updatedBy: 'd047ccb4-9469-4514-a982-29c4ae49317d', + // TODO: check if activityTargets field can be deleted + activityTargets: '20202020-7f42-40ae-b96c-c8a61acc83bf', + noteTargets: '20202020-01fd-4f37-99dc-9427a444018a', + taskTargets: '20202020-0860-4566-b865-bff3c626c303', + favorites: '20202020-a4a7-4686-b296-1c6c3482ee21', + attachments: '20202020-8d59-46ca-b7b2-73d167712134', + timelineActivities: '20202020-f1ef-4ba4-8f33-1a4577afa477', + searchVector: '70e56537-18ef-4811-b1c7-0a444006b815', +} as const; + +export const DASHBOARD_STANDARD_FIELD_IDS = { + title: '20202020-20ee-4091-95dc-44b57eda3a89', + position: '20202020-38af-409b-95f0-7f08aa5f420f', + pageLayoutId: '20202020-bb53-4648-aa36-1d9d54e6f7f2', + createdBy: '20202020-ff32-4fa1-b7ad-407cc6aa0734', + updatedBy: '53ee42e7-f157-42b5-b278-a5fa9b378307', + timelineActivities: '20202020-9b0c-5d6e-7f8a-9b0c1d2e3f4a', + favorites: '20202020-f032-478f-88fa-6426ff6f1e4c', + attachments: '20202020-bf6f-4220-8c55-2764f1175870', + searchVector: '20202020-0bcc-47a4-8360-2e35a7133f7a', +} as const; + +export const STANDARD_OBJECT_FIELD_IDS = { + activityTarget: ACTIVITY_TARGET_STANDARD_FIELD_IDS, + activity: ACTIVITY_STANDARD_FIELD_IDS, + attachment: ATTACHMENT_STANDARD_FIELD_IDS, + blocklist: BLOCKLIST_STANDARD_FIELD_IDS, + calendarChannelEventAssociation: + CALENDAR_CHANNEL_EVENT_ASSOCIATION_STANDARD_FIELD_IDS, + calendarChannel: CALENDAR_CHANNEL_STANDARD_FIELD_IDS, + calendarEventParticipant: CALENDAR_EVENT_PARTICIPANT_STANDARD_FIELD_IDS, + calendarEvent: CALENDAR_EVENT_STANDARD_FIELD_IDS, + comment: COMMENT_STANDARD_FIELD_IDS, + company: COMPANY_STANDARD_FIELD_IDS, + connectedAccount: CONNECTED_ACCOUNT_STANDARD_FIELD_IDS, + dashboard: DASHBOARD_STANDARD_FIELD_IDS, + favorite: FAVORITE_STANDARD_FIELD_IDS, + messageChannelMessageAssociation: + MESSAGE_CHANNEL_MESSAGE_ASSOCIATION_STANDARD_FIELD_IDS, + messageChannel: MESSAGE_CHANNEL_STANDARD_FIELD_IDS, + messageParticipant: MESSAGE_PARTICIPANT_STANDARD_FIELD_IDS, + messageThread: MESSAGE_THREAD_STANDARD_FIELD_IDS, + messageThreadSubscriber: MESSAGE_THREAD_SUBSCRIBER_STANDARD_FIELD_IDS, + message: MESSAGE_STANDARD_FIELD_IDS, + note: NOTE_STANDARD_FIELD_IDS, + noteTarget: NOTE_TARGET_STANDARD_FIELD_IDS, + opportunity: OPPORTUNITY_STANDARD_FIELD_IDS, + person: PERSON_STANDARD_FIELD_IDS, + task: TASK_STANDARD_FIELD_IDS, + taskTarget: TASK_TARGET_STANDARD_FIELD_IDS, + timelineActivity: TIMELINE_ACTIVITY_STANDARD_FIELD_IDS, + viewField: VIEW_FIELD_STANDARD_FIELD_IDS, + viewGroup: VIEW_GROUP_STANDARD_FIELD_IDS, + viewFilter: VIEW_FILTER_STANDARD_FIELD_IDS, + viewSort: VIEW_SORT_STANDARD_FIELD_IDS, + view: VIEW_STANDARD_FIELD_IDS, + workflow: WORKFLOW_STANDARD_FIELD_IDS, + workflowRun: WORKFLOW_RUN_STANDARD_FIELD_IDS, + workflowVersion: WORKFLOW_VERSION_STANDARD_FIELD_IDS, + workspaceMember: WORKSPACE_MEMBER_STANDARD_FIELD_IDS, +} as const; diff --git a/packages/twenty-server/src/modules/note/standard-objects/note-target.workspace-entity.ts b/packages/twenty-server/src/modules/note/standard-objects/note-target.workspace-entity.ts index 91a4824e22..01f868b66e 100644 --- a/packages/twenty-server/src/modules/note/standard-objects/note-target.workspace-entity.ts +++ b/packages/twenty-server/src/modules/note/standard-objects/note-target.workspace-entity.ts @@ -9,11 +9,11 @@ import { type PersonWorkspaceEntity } from 'src/modules/person/standard-objects/ export class NoteTargetWorkspaceEntity extends BaseWorkspaceEntity { note: EntityRelation | null; noteId: string | null; - person: EntityRelation | null; - personId: string | null; - company: EntityRelation | null; - companyId: string | null; - opportunity: EntityRelation | null; - opportunityId: string | null; + targetPerson: EntityRelation | null; + targetPersonId: string | null; + targetCompany: EntityRelation | null; + targetCompanyId: string | null; + targetOpportunity: EntityRelation | null; + targetOpportunityId: string | null; custom: EntityRelation; } diff --git a/packages/twenty-server/src/modules/task/standard-objects/task-target.workspace-entity.ts b/packages/twenty-server/src/modules/task/standard-objects/task-target.workspace-entity.ts index c7ec9d726d..9abf404a23 100644 --- a/packages/twenty-server/src/modules/task/standard-objects/task-target.workspace-entity.ts +++ b/packages/twenty-server/src/modules/task/standard-objects/task-target.workspace-entity.ts @@ -9,11 +9,11 @@ import { type TaskWorkspaceEntity } from 'src/modules/task/standard-objects/task export class TaskTargetWorkspaceEntity extends BaseWorkspaceEntity { task: EntityRelation | null; taskId: string | null; - person: EntityRelation | null; - personId: string | null; - company: EntityRelation | null; - companyId: string | null; - opportunity: EntityRelation | null; - opportunityId: string | null; + targetPerson: EntityRelation | null; + targetPersonId: string | null; + targetCompany: EntityRelation | null; + targetCompanyId: string | null; + targetOpportunity: EntityRelation | null; + targetOpportunityId: string | null; custom: EntityRelation; } diff --git a/packages/twenty-server/test/integration/graphql/suites/object-generated/note-targets.integration-spec.ts b/packages/twenty-server/test/integration/graphql/suites/object-generated/note-targets.integration-spec.ts index 7b575b4572..b55b9c7360 100644 --- a/packages/twenty-server/test/integration/graphql/suites/object-generated/note-targets.integration-spec.ts +++ b/packages/twenty-server/test/integration/graphql/suites/object-generated/note-targets.integration-spec.ts @@ -15,11 +15,11 @@ describe('noteTargetsResolver (e2e)', () => { updatedAt deletedAt noteId - personId - companyId - opportunityId - petId - surveyResultId + targetPersonId + targetCompanyId + targetOpportunityId + targetPetId + targetSurveyResultId } } } @@ -52,11 +52,11 @@ describe('noteTargetsResolver (e2e)', () => { expect(noteTargets).toHaveProperty('updatedAt'); expect(noteTargets).toHaveProperty('deletedAt'); expect(noteTargets).toHaveProperty('noteId'); - expect(noteTargets).toHaveProperty('personId'); - expect(noteTargets).toHaveProperty('companyId'); - expect(noteTargets).toHaveProperty('opportunityId'); - expect(noteTargets).toHaveProperty('petId'); - expect(noteTargets).toHaveProperty('surveyResultId'); + expect(noteTargets).toHaveProperty('targetPersonId'); + expect(noteTargets).toHaveProperty('targetCompanyId'); + expect(noteTargets).toHaveProperty('targetOpportunityId'); + expect(noteTargets).toHaveProperty('targetPetId'); + expect(noteTargets).toHaveProperty('targetSurveyResultId'); } }); }); diff --git a/packages/twenty-server/test/integration/graphql/suites/object-generated/task-targets.integration-spec.ts b/packages/twenty-server/test/integration/graphql/suites/object-generated/task-targets.integration-spec.ts index b3c7496bc4..0db91318f6 100644 --- a/packages/twenty-server/test/integration/graphql/suites/object-generated/task-targets.integration-spec.ts +++ b/packages/twenty-server/test/integration/graphql/suites/object-generated/task-targets.integration-spec.ts @@ -15,11 +15,11 @@ describe('taskTargetsResolver (e2e)', () => { updatedAt deletedAt taskId - personId - companyId - opportunityId - petId - surveyResultId + targetPersonId + targetCompanyId + targetOpportunityId + targetPetId + targetSurveyResultId } } } @@ -52,11 +52,11 @@ describe('taskTargetsResolver (e2e)', () => { expect(taskTargets).toHaveProperty('updatedAt'); expect(taskTargets).toHaveProperty('deletedAt'); expect(taskTargets).toHaveProperty('taskId'); - expect(taskTargets).toHaveProperty('personId'); - expect(taskTargets).toHaveProperty('companyId'); - expect(taskTargets).toHaveProperty('opportunityId'); - expect(taskTargets).toHaveProperty('petId'); - expect(taskTargets).toHaveProperty('surveyResultId'); + expect(taskTargets).toHaveProperty('targetPersonId'); + expect(taskTargets).toHaveProperty('targetCompanyId'); + expect(taskTargets).toHaveProperty('targetOpportunityId'); + expect(taskTargets).toHaveProperty('targetPetId'); + expect(taskTargets).toHaveProperty('targetSurveyResultId'); } }); }); diff --git a/packages/twenty-server/test/integration/graphql/suites/query-complexity/constants/tooManyRelationQueryGqlFields.constant.ts b/packages/twenty-server/test/integration/graphql/suites/query-complexity/constants/tooManyRelationQueryGqlFields.constant.ts index 5d444b5ea6..fafe42c313 100644 --- a/packages/twenty-server/test/integration/graphql/suites/query-complexity/constants/tooManyRelationQueryGqlFields.constant.ts +++ b/packages/twenty-server/test/integration/graphql/suites/query-complexity/constants/tooManyRelationQueryGqlFields.constant.ts @@ -35,22 +35,22 @@ export const TOO_MANY_RELATION_QUERY_GQL_FIELDS = ` edges { node { id - company { + targetCompany { id } note { id } - person { + targetPerson { id company { id } } - company { + targetCompany { id } - opportunity { + targetOpportunity { id } } @@ -60,19 +60,19 @@ export const TOO_MANY_RELATION_QUERY_GQL_FIELDS = ` edges { node { id - company { + targetCompany { id } - person { + targetPerson { id company { id } } - company { + targetCompany { id } - opportunity { + targetOpportunity { id } } diff --git a/packages/twenty-server/test/integration/metadata/suites/object-metadata/__snapshots__/failing-create-one-object-metadata-v2.integration-spec.ts.snap b/packages/twenty-server/test/integration/metadata/suites/object-metadata/__snapshots__/failing-create-one-object-metadata-v2.integration-spec.ts.snap index 94cf62dee3..c768d5a6ad 100644 --- a/packages/twenty-server/test/integration/metadata/suites/object-metadata/__snapshots__/failing-create-one-object-metadata-v2.integration-spec.ts.snap +++ b/packages/twenty-server/test/integration/metadata/suites/object-metadata/__snapshots__/failing-create-one-object-metadata-v2.integration-spec.ts.snap @@ -322,7 +322,7 @@ exports[`Object metadata creation should fail v2 when labelPlural contains only ], "flatEntityMinimalInformation": { "id": Any, - "name": "listinga", + "name": "targetListinga", "objectMetadataId": Any, "universalIdentifier": Any, }, @@ -340,7 +340,7 @@ exports[`Object metadata creation should fail v2 when labelPlural contains only ], "flatEntityMinimalInformation": { "id": Any, - "name": "listinga", + "name": "targetListinga", "objectMetadataId": Any, "universalIdentifier": Any, }, @@ -1029,7 +1029,7 @@ exports[`Object metadata creation should fail v2 when labelPlural exceeds maximu ], "flatEntityMinimalInformation": { "id": Any, - "name": "listinga", + "name": "targetListinga", "objectMetadataId": Any, "universalIdentifier": Any, }, @@ -1047,7 +1047,7 @@ exports[`Object metadata creation should fail v2 when labelPlural exceeds maximu ], "flatEntityMinimalInformation": { "id": Any, - "name": "listinga", + "name": "targetListinga", "objectMetadataId": Any, "universalIdentifier": Any, }, @@ -1747,7 +1747,7 @@ exports[`Object metadata creation should fail v2 when labelSingular contains onl ], "flatEntityMinimalInformation": { "id": Any, - "name": "listinga", + "name": "targetListinga", "objectMetadataId": Any, "universalIdentifier": Any, }, @@ -1765,7 +1765,7 @@ exports[`Object metadata creation should fail v2 when labelSingular contains onl ], "flatEntityMinimalInformation": { "id": Any, - "name": "listinga", + "name": "targetListinga", "objectMetadataId": Any, "universalIdentifier": Any, }, @@ -2454,7 +2454,7 @@ exports[`Object metadata creation should fail v2 when labelSingular exceeds maxi ], "flatEntityMinimalInformation": { "id": Any, - "name": "listinga", + "name": "targetListinga", "objectMetadataId": Any, "universalIdentifier": Any, }, @@ -2472,7 +2472,7 @@ exports[`Object metadata creation should fail v2 when labelSingular exceeds maxi ], "flatEntityMinimalInformation": { "id": Any, - "name": "listinga", + "name": "targetListinga", "objectMetadataId": Any, "universalIdentifier": Any, }, @@ -3172,7 +3172,7 @@ exports[`Object metadata creation should fail v2 when labels are identical 1`] = ], "flatEntityMinimalInformation": { "id": Any, - "name": "listinga", + "name": "targetListinga", "objectMetadataId": Any, "universalIdentifier": Any, }, @@ -3190,7 +3190,7 @@ exports[`Object metadata creation should fail v2 when labels are identical 1`] = ], "flatEntityMinimalInformation": { "id": Any, - "name": "listinga", + "name": "targetListinga", "objectMetadataId": Any, "universalIdentifier": Any, }, @@ -3879,7 +3879,7 @@ exports[`Object metadata creation should fail v2 when labels with whitespaces re ], "flatEntityMinimalInformation": { "id": Any, - "name": "listinga", + "name": "targetListinga", "objectMetadataId": Any, "universalIdentifier": Any, }, @@ -3897,7 +3897,7 @@ exports[`Object metadata creation should fail v2 when labels with whitespaces re ], "flatEntityMinimalInformation": { "id": Any, - "name": "listinga", + "name": "targetListinga", "objectMetadataId": Any, "universalIdentifier": Any, }, @@ -4600,7 +4600,7 @@ exports[`Object metadata creation should fail v2 when name exceeds maximum lengt "code": "INVALID_FIELD_INPUT", "message": "Name is too long", "userFriendlyMessage": "Name is too long", - "value": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "value": "targetAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", }, { "code": "OBJECT_METADATA_NOT_FOUND", @@ -4610,7 +4610,7 @@ exports[`Object metadata creation should fail v2 when name exceeds maximum lengt ], "flatEntityMinimalInformation": { "id": Any, - "name": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "name": "targetAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "objectMetadataId": Any, "universalIdentifier": Any, }, @@ -4624,7 +4624,7 @@ exports[`Object metadata creation should fail v2 when name exceeds maximum lengt "code": "INVALID_FIELD_INPUT", "message": "Name is too long", "userFriendlyMessage": "Name is too long", - "value": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "value": "targetAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", }, { "code": "OBJECT_METADATA_NOT_FOUND", @@ -4634,7 +4634,7 @@ exports[`Object metadata creation should fail v2 when name exceeds maximum lengt ], "flatEntityMinimalInformation": { "id": Any, - "name": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "name": "targetAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "objectMetadataId": Any, "universalIdentifier": Any, }, @@ -5323,7 +5323,7 @@ exports[`Object metadata creation should fail v2 when namePlural has invalid cha ], "flatEntityMinimalInformation": { "id": Any, - "name": "listinga", + "name": "targetListinga", "objectMetadataId": Any, "universalIdentifier": Any, }, @@ -5341,7 +5341,7 @@ exports[`Object metadata creation should fail v2 when namePlural has invalid cha ], "flatEntityMinimalInformation": { "id": Any, - "name": "listinga", + "name": "targetListinga", "objectMetadataId": Any, "universalIdentifier": Any, }, @@ -6030,7 +6030,7 @@ exports[`Object metadata creation should fail v2 when namePlural is a reserved k ], "flatEntityMinimalInformation": { "id": Any, - "name": "listinga", + "name": "targetListinga", "objectMetadataId": Any, "universalIdentifier": Any, }, @@ -6048,7 +6048,7 @@ exports[`Object metadata creation should fail v2 when namePlural is a reserved k ], "flatEntityMinimalInformation": { "id": Any, - "name": "listinga", + "name": "targetListinga", "objectMetadataId": Any, "universalIdentifier": Any, }, @@ -6748,7 +6748,7 @@ exports[`Object metadata creation should fail v2 when namePlural is not camelCas ], "flatEntityMinimalInformation": { "id": Any, - "name": "listinga", + "name": "targetListinga", "objectMetadataId": Any, "universalIdentifier": Any, }, @@ -6766,7 +6766,7 @@ exports[`Object metadata creation should fail v2 when namePlural is not camelCas ], "flatEntityMinimalInformation": { "id": Any, - "name": "listinga", + "name": "targetListinga", "objectMetadataId": Any, "universalIdentifier": Any, }, @@ -7469,7 +7469,7 @@ exports[`Object metadata creation should fail v2 when nameSingular contains only "code": "INVALID_FIELD_INPUT", "message": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters", "userFriendlyMessage": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters", - "value": "a a", + "value": "targetA a", }, { "code": "OBJECT_METADATA_NOT_FOUND", @@ -7479,7 +7479,7 @@ exports[`Object metadata creation should fail v2 when nameSingular contains only ], "flatEntityMinimalInformation": { "id": Any, - "name": "a a", + "name": "targetA a", "objectMetadataId": Any, "universalIdentifier": Any, }, @@ -7493,7 +7493,7 @@ exports[`Object metadata creation should fail v2 when nameSingular contains only "code": "INVALID_FIELD_INPUT", "message": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters", "userFriendlyMessage": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters", - "value": "a a", + "value": "targetA a", }, { "code": "OBJECT_METADATA_NOT_FOUND", @@ -7503,7 +7503,7 @@ exports[`Object metadata creation should fail v2 when nameSingular contains only ], "flatEntityMinimalInformation": { "id": Any, - "name": "a a", + "name": "targetA a", "objectMetadataId": Any, "universalIdentifier": Any, }, @@ -8196,18 +8196,6 @@ exports[`Object metadata creation should fail v2 when nameSingular contains only }, { "errors": [ - { - "code": "INVALID_FIELD_INPUT", - "message": "Name is too short", - "userFriendlyMessage": "Name is too short", - "value": "", - }, - { - "code": "INVALID_FIELD_INPUT", - "message": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters", - "userFriendlyMessage": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters", - "value": "", - }, { "code": "OBJECT_METADATA_NOT_FOUND", "message": "Relation target object metadata not found", @@ -8216,7 +8204,7 @@ exports[`Object metadata creation should fail v2 when nameSingular contains only ], "flatEntityMinimalInformation": { "id": Any, - "name": "", + "name": "target", "objectMetadataId": Any, "universalIdentifier": Any, }, @@ -8226,18 +8214,6 @@ exports[`Object metadata creation should fail v2 when nameSingular contains only }, { "errors": [ - { - "code": "INVALID_FIELD_INPUT", - "message": "Name is too short", - "userFriendlyMessage": "Name is too short", - "value": "", - }, - { - "code": "INVALID_FIELD_INPUT", - "message": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters", - "userFriendlyMessage": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters", - "value": "", - }, { "code": "OBJECT_METADATA_NOT_FOUND", "message": "Relation target object metadata not found", @@ -8246,7 +8222,7 @@ exports[`Object metadata creation should fail v2 when nameSingular contains only ], "flatEntityMinimalInformation": { "id": Any, - "name": "", + "name": "target", "objectMetadataId": Any, "universalIdentifier": Any, }, @@ -8955,7 +8931,7 @@ exports[`Object metadata creation should fail v2 when nameSingular has invalid c "code": "INVALID_FIELD_INPUT", "message": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters", "userFriendlyMessage": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters", - "value": "μ", + "value": "targetΜ", }, { "code": "OBJECT_METADATA_NOT_FOUND", @@ -8965,7 +8941,7 @@ exports[`Object metadata creation should fail v2 when nameSingular has invalid c ], "flatEntityMinimalInformation": { "id": Any, - "name": "μ", + "name": "targetΜ", "objectMetadataId": Any, "universalIdentifier": Any, }, @@ -8979,7 +8955,7 @@ exports[`Object metadata creation should fail v2 when nameSingular has invalid c "code": "INVALID_FIELD_INPUT", "message": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters", "userFriendlyMessage": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters", - "value": "μ", + "value": "targetΜ", }, { "code": "OBJECT_METADATA_NOT_FOUND", @@ -8989,7 +8965,7 @@ exports[`Object metadata creation should fail v2 when nameSingular has invalid c ], "flatEntityMinimalInformation": { "id": Any, - "name": "μ", + "name": "targetΜ", "objectMetadataId": Any, "universalIdentifier": Any, }, @@ -9676,12 +9652,6 @@ exports[`Object metadata creation should fail v2 when nameSingular is a reserved }, { "errors": [ - { - "code": "INVALID_FIELD_INPUT", - "message": "This name is reserved. Use a different name or the system will add "Custom" suffix.", - "userFriendlyMessage": "This name is reserved. Use a different name or the system will add "Custom" suffix.", - "value": "user", - }, { "code": "OBJECT_METADATA_NOT_FOUND", "message": "Relation target object metadata not found", @@ -9690,7 +9660,7 @@ exports[`Object metadata creation should fail v2 when nameSingular is a reserved ], "flatEntityMinimalInformation": { "id": Any, - "name": "user", + "name": "targetUser", "objectMetadataId": Any, "universalIdentifier": Any, }, @@ -9700,12 +9670,6 @@ exports[`Object metadata creation should fail v2 when nameSingular is a reserved }, { "errors": [ - { - "code": "INVALID_FIELD_INPUT", - "message": "This name is reserved. Use a different name or the system will add "Custom" suffix.", - "userFriendlyMessage": "This name is reserved. Use a different name or the system will add "Custom" suffix.", - "value": "user", - }, { "code": "OBJECT_METADATA_NOT_FOUND", "message": "Relation target object metadata not found", @@ -9714,7 +9678,7 @@ exports[`Object metadata creation should fail v2 when nameSingular is a reserved ], "flatEntityMinimalInformation": { "id": Any, - "name": "user", + "name": "targetUser", "objectMetadataId": Any, "universalIdentifier": Any, }, @@ -10428,7 +10392,7 @@ exports[`Object metadata creation should fail v2 when nameSingular is not camelC "code": "INVALID_FIELD_INPUT", "message": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters", "userFriendlyMessage": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters", - "value": "Not_Camel_Case", + "value": "targetNot_Camel_Case", }, { "code": "OBJECT_METADATA_NOT_FOUND", @@ -10438,7 +10402,7 @@ exports[`Object metadata creation should fail v2 when nameSingular is not camelC ], "flatEntityMinimalInformation": { "id": Any, - "name": "Not_Camel_Case", + "name": "targetNot_Camel_Case", "objectMetadataId": Any, "universalIdentifier": Any, }, @@ -10452,7 +10416,7 @@ exports[`Object metadata creation should fail v2 when nameSingular is not camelC "code": "INVALID_FIELD_INPUT", "message": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters", "userFriendlyMessage": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters", - "value": "Not_Camel_Case", + "value": "targetNot_Camel_Case", }, { "code": "OBJECT_METADATA_NOT_FOUND", @@ -10462,7 +10426,7 @@ exports[`Object metadata creation should fail v2 when nameSingular is not camelC ], "flatEntityMinimalInformation": { "id": Any, - "name": "Not_Camel_Case", + "name": "targetNot_Camel_Case", "objectMetadataId": Any, "universalIdentifier": Any, }, @@ -11151,7 +11115,7 @@ exports[`Object metadata creation should fail v2 when names are identical 1`] = ], "flatEntityMinimalInformation": { "id": Any, - "name": "fooBar", + "name": "targetFooBar", "objectMetadataId": Any, "universalIdentifier": Any, }, @@ -11169,7 +11133,7 @@ exports[`Object metadata creation should fail v2 when names are identical 1`] = ], "flatEntityMinimalInformation": { "id": Any, - "name": "fooBar", + "name": "targetFooBar", "objectMetadataId": Any, "universalIdentifier": Any, }, @@ -11858,7 +11822,7 @@ exports[`Object metadata creation should fail v2 when names with whitespaces res ], "flatEntityMinimalInformation": { "id": Any, - "name": "fooBar", + "name": "targetFooBar", "objectMetadataId": Any, "universalIdentifier": Any, }, @@ -11876,7 +11840,7 @@ exports[`Object metadata creation should fail v2 when names with whitespaces res ], "flatEntityMinimalInformation": { "id": Any, - "name": "fooBar", + "name": "targetFooBar", "objectMetadataId": Any, "universalIdentifier": Any, }, diff --git a/packages/twenty-shared/src/metadata/standard-object.constant.ts b/packages/twenty-shared/src/metadata/standard-object.constant.ts index fc9755e10f..af586c862b 100644 --- a/packages/twenty-shared/src/metadata/standard-object.constant.ts +++ b/packages/twenty-shared/src/metadata/standard-object.constant.ts @@ -1048,12 +1048,19 @@ export const STANDARD_OBJECTS = { universalIdentifier: '20202020-c02d-4124-9d24-ef123456789b', }, note: { universalIdentifier: '20202020-57f3-4f50-9599-fc0f671df003' }, - person: { universalIdentifier: '20202020-38ca-4aab-92f5-8a605ca2e4c5' }, - company: { universalIdentifier: 'c500fbc0-d6f2-4982-a959-5a755431696c' }, - opportunity: { + targetPerson: { + universalIdentifier: '20202020-38ca-4aab-92f5-8a605ca2e4c5', + }, + targetCompany: { + universalIdentifier: 'c500fbc0-d6f2-4982-a959-5a755431696c', + }, + targetOpportunity: { universalIdentifier: '20202020-4e42-417a-a705-76581c9ade79', }, }, + morphIds: { + targetMorphId: { morphId: '20202020-f635-435d-ab8d-e1168b375c70' }, + }, indexes: { noteIdIndex: { universalIdentifier: '9294d9e3-0225-4c7f-9d6e-23b4c25b6b24', @@ -1482,12 +1489,19 @@ export const STANDARD_OBJECTS = { universalIdentifier: '20202020-a03d-4164-9d64-fabcdefabcde', }, task: { universalIdentifier: '20202020-e881-457a-8758-74aaef4ae78a' }, - person: { universalIdentifier: '20202020-c8a0-4e85-a016-87e2349cfbec' }, - company: { universalIdentifier: '20202020-4703-4a4e-948c-487b0c60a92c' }, - opportunity: { + targetPerson: { + universalIdentifier: '20202020-c8a0-4e85-a016-87e2349cfbec', + }, + targetCompany: { + universalIdentifier: '20202020-4703-4a4e-948c-487b0c60a92c', + }, + targetOpportunity: { universalIdentifier: '20202020-6cb2-4c01-a9a5-aca3dbc11d41', }, }, + morphIds: { + targetMorphId: { morphId: '20202020-f636-435d-ab8d-e1168b375c71' }, + }, indexes: { taskIdIndex: { universalIdentifier: '2527e2f6-3558-4d0a-2e9f-56c7d58c9c57',