diff --git a/packages/twenty-server/src/engine/core-modules/workflow/services/workflow-version-core-sync.service.ts b/packages/twenty-server/src/engine/core-modules/workflow/services/workflow-version-core-sync.service.ts index 0a98df8a64..a31dcc9bba 100644 --- a/packages/twenty-server/src/engine/core-modules/workflow/services/workflow-version-core-sync.service.ts +++ b/packages/twenty-server/src/engine/core-modules/workflow/services/workflow-version-core-sync.service.ts @@ -3,18 +3,26 @@ import { InjectRepository } from '@nestjs/typeorm'; import { isDefined } from 'twenty-shared/utils'; import { In, Repository } from 'typeorm'; -import { v4 as uuidv4 } from 'uuid'; +import { v4 as uuidv4, v5 as uuidv5 } from 'uuid'; import { WorkflowVersionEntity, WorkflowVersionStatus, } from 'src/engine/core-modules/workflow/entities/workflow-version.entity'; import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; +import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator'; import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; +import { buildSystemAuthContext } from 'src/engine/twenty-orm/utils/build-system-auth-context.util'; import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service'; import { type WorkflowVersionWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow-version.workspace-entity'; +// Deriving the core id deterministically from workspaceId + record id makes the +// upsert idempotent across retries: a failed write-back re-derives the same id +// instead of orphaning a row or hitting the one-active-per-workflow index. +const CORE_WORKFLOW_VERSION_ID_NAMESPACE = + 'f4988927-0a5c-453a-a262-0bd136d7fdaf'; + @Injectable() export class WorkflowVersionCoreSyncService { constructor( @@ -22,6 +30,7 @@ export class WorkflowVersionCoreSyncService { private readonly workflowVersionRepository: WorkspaceScopedRepository, @InjectRepository(WorkspaceEntity) private readonly workspaceRepository: Repository, + private readonly globalWorkspaceOrmManager: GlobalWorkspaceOrmManager, private readonly workspaceCacheService: WorkspaceCacheService, ) {} @@ -35,10 +44,25 @@ export class WorkflowVersionCoreSyncService { const applicationId = await this.getCustomApplicationIdOrThrow(workspaceId); - await this.workflowVersionRepository.upsert( - workspaceId, - workflowVersions.map((workflowVersion) => ({ - id: workflowVersion.id, + const coreVersionIdByWorkspaceRecordId = new Map(); + + const coreRows = workflowVersions.map((workflowVersion) => { + const coreWorkflowVersionId = + workflowVersion.coreWorkflowVersionId ?? + uuidv5( + `${workspaceId}:${workflowVersion.id}`, + CORE_WORKFLOW_VERSION_ID_NAMESPACE, + ); + + if (!isDefined(workflowVersion.coreWorkflowVersionId)) { + coreVersionIdByWorkspaceRecordId.set( + workflowVersion.id, + coreWorkflowVersionId, + ); + } + + return { + id: coreWorkflowVersionId, workflowId: workflowVersion.workflowId, triggers: isDefined(workflowVersion.trigger) ? [workflowVersion.trigger] @@ -47,13 +71,82 @@ export class WorkflowVersionCoreSyncService { status: workflowVersion.status as unknown as WorkflowVersionStatus, universalIdentifier: uuidv4(), applicationId, - })), - ['id'], + }; + }); + + await this.purgeSharedIdCoreRows( + workspaceId, + Array.from(coreVersionIdByWorkspaceRecordId.keys()), + ); + + await this.workflowVersionRepository.upsert(workspaceId, coreRows, ['id']); + + await this.writeBackCoreVersionIds( + workspaceId, + coreVersionIdByWorkspaceRecordId, ); await this.invalidateAutomatedTriggerMaps(workspaceId); } + async deleteFromCore( + workspaceId: string, + coreWorkflowVersionIds: string[], + ): Promise { + if (coreWorkflowVersionIds.length === 0) { + return; + } + + await this.workflowVersionRepository.delete(workspaceId, { + id: In(coreWorkflowVersionIds), + }); + + await this.invalidateAutomatedTriggerMaps(workspaceId); + } + + // The pre-soft-ref model wrote core rows with id === workspace record id. + // Delete those before creating own-id rows, otherwise re-migration orphans + // them and a second active row collides on the one-active-per-workflow index. + private async purgeSharedIdCoreRows( + workspaceId: string, + workspaceRecordIds: string[], + ): Promise { + if (workspaceRecordIds.length === 0) { + return; + } + + await this.workflowVersionRepository.delete(workspaceId, { + id: In(workspaceRecordIds), + }); + } + + private async writeBackCoreVersionIds( + workspaceId: string, + coreVersionIdByWorkspaceRecordId: Map, + ): Promise { + if (coreVersionIdByWorkspaceRecordId.size === 0) { + return; + } + + await this.globalWorkspaceOrmManager.executeInWorkspaceContext(async () => { + const workflowVersionRepository = + await this.globalWorkspaceOrmManager.getRepository( + workspaceId, + 'workflowVersion', + { shouldBypassPermissionChecks: true }, + ); + + for (const [ + workspaceRecordId, + coreWorkflowVersionId, + ] of coreVersionIdByWorkspaceRecordId) { + await workflowVersionRepository.update(workspaceRecordId, { + coreWorkflowVersionId, + }); + } + }, buildSystemAuthContext(workspaceId)); + } + private async getCustomApplicationIdOrThrow( workspaceId: string, ): Promise { @@ -71,21 +164,6 @@ export class WorkflowVersionCoreSyncService { return workspace.workspaceCustomApplicationId; } - async deleteFromCore( - workspaceId: string, - workflowVersionIds: string[], - ): Promise { - if (workflowVersionIds.length === 0) { - return; - } - - await this.workflowVersionRepository.delete(workspaceId, { - id: In(workflowVersionIds), - }); - - await this.invalidateAutomatedTriggerMaps(workspaceId); - } - private async invalidateAutomatedTriggerMaps( workspaceId: string, ): Promise { 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 4d4b038d93..c3116e40e3 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 @@ -2514,10 +2514,13 @@ exports[`getStandardObjectMetadataRelatedEntityIds should return standard object "workflow": { "fields": { "attachments": { - "id": "00000000-0000-0000-0000-000000000766", + "id": "00000000-0000-0000-0000-000000000767", }, "automatedTriggers": { - "id": "00000000-0000-0000-0000-000000000764", + "id": "00000000-0000-0000-0000-000000000765", + }, + "coreWorkflowId": { + "id": "00000000-0000-0000-0000-000000000761", }, "createdAt": { "id": "00000000-0000-0000-0000-000000000752", @@ -2541,16 +2544,16 @@ exports[`getStandardObjectMetadataRelatedEntityIds should return standard object "id": "00000000-0000-0000-0000-000000000757", }, "runs": { - "id": "00000000-0000-0000-0000-000000000763", + "id": "00000000-0000-0000-0000-000000000764", }, "searchVector": { "id": "00000000-0000-0000-0000-000000000758", }, "statuses": { - "id": "00000000-0000-0000-0000-000000000761", + "id": "00000000-0000-0000-0000-000000000762", }, "timelineActivities": { - "id": "00000000-0000-0000-0000-000000000765", + "id": "00000000-0000-0000-0000-000000000766", }, "updatedAt": { "id": "00000000-0000-0000-0000-000000000753", @@ -2559,32 +2562,32 @@ exports[`getStandardObjectMetadataRelatedEntityIds should return standard object "id": "00000000-0000-0000-0000-000000000756", }, "versions": { - "id": "00000000-0000-0000-0000-000000000762", + "id": "00000000-0000-0000-0000-000000000763", }, }, - "id": "00000000-0000-0000-0000-000000000774", + "id": "00000000-0000-0000-0000-000000000775", "views": { "allWorkflows": { - "id": "00000000-0000-0000-0000-000000000773", + "id": "00000000-0000-0000-0000-000000000774", "viewFieldGroups": {}, "viewFields": { "createdBy": { - "id": "00000000-0000-0000-0000-000000000770", + "id": "00000000-0000-0000-0000-000000000771", }, "name": { - "id": "00000000-0000-0000-0000-000000000767", - }, - "runs": { - "id": "00000000-0000-0000-0000-000000000772", - }, - "statuses": { "id": "00000000-0000-0000-0000-000000000768", }, - "updatedAt": { + "runs": { + "id": "00000000-0000-0000-0000-000000000773", + }, + "statuses": { "id": "00000000-0000-0000-0000-000000000769", }, + "updatedAt": { + "id": "00000000-0000-0000-0000-000000000770", + }, "versions": { - "id": "00000000-0000-0000-0000-000000000771", + "id": "00000000-0000-0000-0000-000000000772", }, }, "viewGroups": {}, @@ -2594,79 +2597,79 @@ exports[`getStandardObjectMetadataRelatedEntityIds should return standard object "workflowAutomatedTrigger": { "fields": { "createdAt": { - "id": "00000000-0000-0000-0000-000000000776", - }, - "createdBy": { - "id": "00000000-0000-0000-0000-000000000779", - }, - "deletedAt": { - "id": "00000000-0000-0000-0000-000000000778", - }, - "id": { - "id": "00000000-0000-0000-0000-000000000775", - }, - "position": { - "id": "00000000-0000-0000-0000-000000000781", - }, - "searchVector": { - "id": "00000000-0000-0000-0000-000000000782", - }, - "settings": { - "id": "00000000-0000-0000-0000-000000000784", - }, - "type": { - "id": "00000000-0000-0000-0000-000000000783", - }, - "updatedAt": { "id": "00000000-0000-0000-0000-000000000777", }, - "updatedBy": { + "createdBy": { "id": "00000000-0000-0000-0000-000000000780", }, - "workflow": { + "deletedAt": { + "id": "00000000-0000-0000-0000-000000000779", + }, + "id": { + "id": "00000000-0000-0000-0000-000000000776", + }, + "position": { + "id": "00000000-0000-0000-0000-000000000782", + }, + "searchVector": { + "id": "00000000-0000-0000-0000-000000000783", + }, + "settings": { "id": "00000000-0000-0000-0000-000000000785", }, + "type": { + "id": "00000000-0000-0000-0000-000000000784", + }, + "updatedAt": { + "id": "00000000-0000-0000-0000-000000000778", + }, + "updatedBy": { + "id": "00000000-0000-0000-0000-000000000781", + }, + "workflow": { + "id": "00000000-0000-0000-0000-000000000786", + }, }, - "id": "00000000-0000-0000-0000-000000000797", + "id": "00000000-0000-0000-0000-000000000798", "views": { "allWorkflowAutomatedTriggers": { - "id": "00000000-0000-0000-0000-000000000789", + "id": "00000000-0000-0000-0000-000000000790", "viewFieldGroups": {}, "viewFields": { "createdAt": { - "id": "00000000-0000-0000-0000-000000000788", + "id": "00000000-0000-0000-0000-000000000789", }, "type": { - "id": "00000000-0000-0000-0000-000000000786", + "id": "00000000-0000-0000-0000-000000000787", }, "workflow": { - "id": "00000000-0000-0000-0000-000000000787", + "id": "00000000-0000-0000-0000-000000000788", }, }, "viewGroups": {}, }, "workflowAutomatedTriggerRecordPageFields": { - "id": "00000000-0000-0000-0000-000000000796", + "id": "00000000-0000-0000-0000-000000000797", "viewFieldGroups": { "general": { - "id": "00000000-0000-0000-0000-000000000794", + "id": "00000000-0000-0000-0000-000000000795", }, "system": { - "id": "00000000-0000-0000-0000-000000000795", + "id": "00000000-0000-0000-0000-000000000796", }, }, "viewFields": { "createdAt": { - "id": "00000000-0000-0000-0000-000000000792", - }, - "createdBy": { "id": "00000000-0000-0000-0000-000000000793", }, + "createdBy": { + "id": "00000000-0000-0000-0000-000000000794", + }, "type": { - "id": "00000000-0000-0000-0000-000000000790", + "id": "00000000-0000-0000-0000-000000000791", }, "workflow": { - "id": "00000000-0000-0000-0000-000000000791", + "id": "00000000-0000-0000-0000-000000000792", }, }, "viewGroups": {}, @@ -2676,134 +2679,134 @@ exports[`getStandardObjectMetadataRelatedEntityIds should return standard object "workflowRun": { "fields": { "createdAt": { - "id": "00000000-0000-0000-0000-000000000799", - }, - "createdBy": { - "id": "00000000-0000-0000-0000-000000000802", - }, - "deletedAt": { - "id": "00000000-0000-0000-0000-000000000801", - }, - "endedAt": { - "id": "00000000-0000-0000-0000-000000000811", - }, - "enqueuedAt": { - "id": "00000000-0000-0000-0000-000000000809", - }, - "id": { - "id": "00000000-0000-0000-0000-000000000798", - }, - "name": { - "id": "00000000-0000-0000-0000-000000000806", - }, - "position": { - "id": "00000000-0000-0000-0000-000000000804", - }, - "searchVector": { - "id": "00000000-0000-0000-0000-000000000805", - }, - "startedAt": { - "id": "00000000-0000-0000-0000-000000000810", - }, - "state": { - "id": "00000000-0000-0000-0000-000000000813", - }, - "status": { - "id": "00000000-0000-0000-0000-000000000812", - }, - "stepLogs": { - "id": "00000000-0000-0000-0000-000000000814", - }, - "timelineActivities": { - "id": "00000000-0000-0000-0000-000000000815", - }, - "updatedAt": { "id": "00000000-0000-0000-0000-000000000800", }, - "updatedBy": { + "createdBy": { "id": "00000000-0000-0000-0000-000000000803", }, - "workflow": { - "id": "00000000-0000-0000-0000-000000000808", + "deletedAt": { + "id": "00000000-0000-0000-0000-000000000802", }, - "workflowVersion": { + "endedAt": { + "id": "00000000-0000-0000-0000-000000000812", + }, + "enqueuedAt": { + "id": "00000000-0000-0000-0000-000000000810", + }, + "id": { + "id": "00000000-0000-0000-0000-000000000799", + }, + "name": { "id": "00000000-0000-0000-0000-000000000807", }, + "position": { + "id": "00000000-0000-0000-0000-000000000805", + }, + "searchVector": { + "id": "00000000-0000-0000-0000-000000000806", + }, + "startedAt": { + "id": "00000000-0000-0000-0000-000000000811", + }, + "state": { + "id": "00000000-0000-0000-0000-000000000814", + }, + "status": { + "id": "00000000-0000-0000-0000-000000000813", + }, + "stepLogs": { + "id": "00000000-0000-0000-0000-000000000815", + }, + "timelineActivities": { + "id": "00000000-0000-0000-0000-000000000816", + }, + "updatedAt": { + "id": "00000000-0000-0000-0000-000000000801", + }, + "updatedBy": { + "id": "00000000-0000-0000-0000-000000000804", + }, + "workflow": { + "id": "00000000-0000-0000-0000-000000000809", + }, + "workflowVersion": { + "id": "00000000-0000-0000-0000-000000000808", + }, }, - "id": "00000000-0000-0000-0000-000000000838", + "id": "00000000-0000-0000-0000-000000000839", "views": { "allWorkflowRuns": { - "id": "00000000-0000-0000-0000-000000000822", + "id": "00000000-0000-0000-0000-000000000823", "viewFieldGroups": {}, "viewFields": { "createdBy": { - "id": "00000000-0000-0000-0000-000000000820", + "id": "00000000-0000-0000-0000-000000000821", }, "name": { - "id": "00000000-0000-0000-0000-000000000816", - }, - "startedAt": { - "id": "00000000-0000-0000-0000-000000000819", - }, - "status": { - "id": "00000000-0000-0000-0000-000000000818", - }, - "workflow": { "id": "00000000-0000-0000-0000-000000000817", }, + "startedAt": { + "id": "00000000-0000-0000-0000-000000000820", + }, + "status": { + "id": "00000000-0000-0000-0000-000000000819", + }, + "workflow": { + "id": "00000000-0000-0000-0000-000000000818", + }, "workflowVersion": { - "id": "00000000-0000-0000-0000-000000000821", + "id": "00000000-0000-0000-0000-000000000822", }, }, "viewGroups": {}, }, "workflowRunRecordPageFields": { - "id": "00000000-0000-0000-0000-000000000837", + "id": "00000000-0000-0000-0000-000000000838", "viewFieldGroups": { "general": { - "id": "00000000-0000-0000-0000-000000000835", + "id": "00000000-0000-0000-0000-000000000836", }, "system": { - "id": "00000000-0000-0000-0000-000000000836", + "id": "00000000-0000-0000-0000-000000000837", }, }, "viewFields": { "createdAt": { - "id": "00000000-0000-0000-0000-000000000828", - }, - "createdBy": { "id": "00000000-0000-0000-0000-000000000829", }, - "endedAt": { - "id": "00000000-0000-0000-0000-000000000827", - }, - "enqueuedAt": { + "createdBy": { "id": "00000000-0000-0000-0000-000000000830", }, - "startedAt": { - "id": "00000000-0000-0000-0000-000000000826", + "endedAt": { + "id": "00000000-0000-0000-0000-000000000828", }, - "state": { + "enqueuedAt": { "id": "00000000-0000-0000-0000-000000000831", }, - "status": { - "id": "00000000-0000-0000-0000-000000000823", + "startedAt": { + "id": "00000000-0000-0000-0000-000000000827", }, - "timelineActivities": { - "id": "00000000-0000-0000-0000-000000000834", - }, - "updatedAt": { + "state": { "id": "00000000-0000-0000-0000-000000000832", }, - "updatedBy": { - "id": "00000000-0000-0000-0000-000000000833", - }, - "workflow": { + "status": { "id": "00000000-0000-0000-0000-000000000824", }, - "workflowVersion": { + "timelineActivities": { + "id": "00000000-0000-0000-0000-000000000835", + }, + "updatedAt": { + "id": "00000000-0000-0000-0000-000000000833", + }, + "updatedBy": { + "id": "00000000-0000-0000-0000-000000000834", + }, + "workflow": { "id": "00000000-0000-0000-0000-000000000825", }, + "workflowVersion": { + "id": "00000000-0000-0000-0000-000000000826", + }, }, "viewGroups": {}, }, @@ -2811,116 +2814,119 @@ exports[`getStandardObjectMetadataRelatedEntityIds should return standard object }, "workflowVersion": { "fields": { + "coreWorkflowVersionId": { + "id": "00000000-0000-0000-0000-000000000854", + }, "createdAt": { - "id": "00000000-0000-0000-0000-000000000840", - }, - "createdBy": { - "id": "00000000-0000-0000-0000-000000000843", - }, - "deletedAt": { - "id": "00000000-0000-0000-0000-000000000842", - }, - "id": { - "id": "00000000-0000-0000-0000-000000000839", - }, - "name": { - "id": "00000000-0000-0000-0000-000000000847", - }, - "position": { - "id": "00000000-0000-0000-0000-000000000845", - }, - "runs": { - "id": "00000000-0000-0000-0000-000000000851", - }, - "searchVector": { - "id": "00000000-0000-0000-0000-000000000846", - }, - "status": { - "id": "00000000-0000-0000-0000-000000000850", - }, - "steps": { - "id": "00000000-0000-0000-0000-000000000852", - }, - "timelineActivities": { - "id": "00000000-0000-0000-0000-000000000853", - }, - "trigger": { - "id": "00000000-0000-0000-0000-000000000849", - }, - "updatedAt": { "id": "00000000-0000-0000-0000-000000000841", }, - "updatedBy": { + "createdBy": { "id": "00000000-0000-0000-0000-000000000844", }, - "workflow": { + "deletedAt": { + "id": "00000000-0000-0000-0000-000000000843", + }, + "id": { + "id": "00000000-0000-0000-0000-000000000840", + }, + "name": { "id": "00000000-0000-0000-0000-000000000848", }, + "position": { + "id": "00000000-0000-0000-0000-000000000846", + }, + "runs": { + "id": "00000000-0000-0000-0000-000000000852", + }, + "searchVector": { + "id": "00000000-0000-0000-0000-000000000847", + }, + "status": { + "id": "00000000-0000-0000-0000-000000000851", + }, + "steps": { + "id": "00000000-0000-0000-0000-000000000853", + }, + "timelineActivities": { + "id": "00000000-0000-0000-0000-000000000855", + }, + "trigger": { + "id": "00000000-0000-0000-0000-000000000850", + }, + "updatedAt": { + "id": "00000000-0000-0000-0000-000000000842", + }, + "updatedBy": { + "id": "00000000-0000-0000-0000-000000000845", + }, + "workflow": { + "id": "00000000-0000-0000-0000-000000000849", + }, }, - "id": "00000000-0000-0000-0000-000000000873", + "id": "00000000-0000-0000-0000-000000000875", "views": { "allWorkflowVersions": { - "id": "00000000-0000-0000-0000-000000000859", + "id": "00000000-0000-0000-0000-000000000861", "viewFieldGroups": {}, "viewFields": { "name": { - "id": "00000000-0000-0000-0000-000000000854", - }, - "runs": { - "id": "00000000-0000-0000-0000-000000000858", - }, - "status": { "id": "00000000-0000-0000-0000-000000000856", }, + "runs": { + "id": "00000000-0000-0000-0000-000000000860", + }, + "status": { + "id": "00000000-0000-0000-0000-000000000858", + }, "updatedAt": { - "id": "00000000-0000-0000-0000-000000000857", + "id": "00000000-0000-0000-0000-000000000859", }, "workflow": { - "id": "00000000-0000-0000-0000-000000000855", + "id": "00000000-0000-0000-0000-000000000857", }, }, "viewGroups": {}, }, "workflowVersionRecordPageFields": { - "id": "00000000-0000-0000-0000-000000000872", + "id": "00000000-0000-0000-0000-000000000874", "viewFieldGroups": { "general": { - "id": "00000000-0000-0000-0000-000000000870", + "id": "00000000-0000-0000-0000-000000000872", }, "system": { - "id": "00000000-0000-0000-0000-000000000871", + "id": "00000000-0000-0000-0000-000000000873", }, }, "viewFields": { "createdAt": { - "id": "00000000-0000-0000-0000-000000000863", - }, - "createdBy": { "id": "00000000-0000-0000-0000-000000000865", }, - "runs": { - "id": "00000000-0000-0000-0000-000000000868", - }, - "status": { - "id": "00000000-0000-0000-0000-000000000860", - }, - "steps": { - "id": "00000000-0000-0000-0000-000000000864", - }, - "timelineActivities": { - "id": "00000000-0000-0000-0000-000000000869", - }, - "trigger": { - "id": "00000000-0000-0000-0000-000000000862", - }, - "updatedAt": { - "id": "00000000-0000-0000-0000-000000000866", - }, - "updatedBy": { + "createdBy": { "id": "00000000-0000-0000-0000-000000000867", }, + "runs": { + "id": "00000000-0000-0000-0000-000000000870", + }, + "status": { + "id": "00000000-0000-0000-0000-000000000862", + }, + "steps": { + "id": "00000000-0000-0000-0000-000000000866", + }, + "timelineActivities": { + "id": "00000000-0000-0000-0000-000000000871", + }, + "trigger": { + "id": "00000000-0000-0000-0000-000000000864", + }, + "updatedAt": { + "id": "00000000-0000-0000-0000-000000000868", + }, + "updatedBy": { + "id": "00000000-0000-0000-0000-000000000869", + }, "workflow": { - "id": "00000000-0000-0000-0000-000000000861", + "id": "00000000-0000-0000-0000-000000000863", }, }, "viewGroups": {}, @@ -2930,125 +2936,125 @@ exports[`getStandardObjectMetadataRelatedEntityIds should return standard object "workspaceMember": { "fields": { "accountOwnerForCompanies": { - "id": "00000000-0000-0000-0000-000000000891", - }, - "assignedTasks": { - "id": "00000000-0000-0000-0000-000000000889", - }, - "avatarUrl": { - "id": "00000000-0000-0000-0000-000000000885", - }, - "blocklist": { "id": "00000000-0000-0000-0000-000000000893", }, - "calendarEventParticipants": { - "id": "00000000-0000-0000-0000-000000000894", + "assignedTasks": { + "id": "00000000-0000-0000-0000-000000000891", }, - "calendarStartDay": { - "id": "00000000-0000-0000-0000-000000000899", - }, - "colorScheme": { - "id": "00000000-0000-0000-0000-000000000883", - }, - "createdAt": { - "id": "00000000-0000-0000-0000-000000000875", - }, - "createdBy": { - "id": "00000000-0000-0000-0000-000000000878", - }, - "dateFormat": { - "id": "00000000-0000-0000-0000-000000000897", - }, - "deletedAt": { - "id": "00000000-0000-0000-0000-000000000877", - }, - "id": { - "id": "00000000-0000-0000-0000-000000000874", - }, - "jobTitle": { + "avatarUrl": { "id": "00000000-0000-0000-0000-000000000887", }, - "locale": { - "id": "00000000-0000-0000-0000-000000000884", - }, - "messageParticipants": { - "id": "00000000-0000-0000-0000-000000000892", - }, - "name": { - "id": "00000000-0000-0000-0000-000000000882", - }, - "numberFormat": { - "id": "00000000-0000-0000-0000-000000000900", - }, - "ownedOpportunities": { - "id": "00000000-0000-0000-0000-000000000890", - }, - "position": { - "id": "00000000-0000-0000-0000-000000000880", - }, - "searchVector": { - "id": "00000000-0000-0000-0000-000000000881", - }, - "timeFormat": { - "id": "00000000-0000-0000-0000-000000000898", - }, - "timeZone": { - "id": "00000000-0000-0000-0000-000000000896", - }, - "timelineActivities": { + "blocklist": { "id": "00000000-0000-0000-0000-000000000895", }, - "updatedAt": { - "id": "00000000-0000-0000-0000-000000000876", + "calendarEventParticipants": { + "id": "00000000-0000-0000-0000-000000000896", }, - "updatedBy": { + "calendarStartDay": { + "id": "00000000-0000-0000-0000-000000000901", + }, + "colorScheme": { + "id": "00000000-0000-0000-0000-000000000885", + }, + "createdAt": { + "id": "00000000-0000-0000-0000-000000000877", + }, + "createdBy": { + "id": "00000000-0000-0000-0000-000000000880", + }, + "dateFormat": { + "id": "00000000-0000-0000-0000-000000000899", + }, + "deletedAt": { "id": "00000000-0000-0000-0000-000000000879", }, - "userEmail": { + "id": { + "id": "00000000-0000-0000-0000-000000000876", + }, + "jobTitle": { + "id": "00000000-0000-0000-0000-000000000889", + }, + "locale": { "id": "00000000-0000-0000-0000-000000000886", }, - "userId": { + "messageParticipants": { + "id": "00000000-0000-0000-0000-000000000894", + }, + "name": { + "id": "00000000-0000-0000-0000-000000000884", + }, + "numberFormat": { + "id": "00000000-0000-0000-0000-000000000902", + }, + "ownedOpportunities": { + "id": "00000000-0000-0000-0000-000000000892", + }, + "position": { + "id": "00000000-0000-0000-0000-000000000882", + }, + "searchVector": { + "id": "00000000-0000-0000-0000-000000000883", + }, + "timeFormat": { + "id": "00000000-0000-0000-0000-000000000900", + }, + "timeZone": { + "id": "00000000-0000-0000-0000-000000000898", + }, + "timelineActivities": { + "id": "00000000-0000-0000-0000-000000000897", + }, + "updatedAt": { + "id": "00000000-0000-0000-0000-000000000878", + }, + "updatedBy": { + "id": "00000000-0000-0000-0000-000000000881", + }, + "userEmail": { "id": "00000000-0000-0000-0000-000000000888", }, + "userId": { + "id": "00000000-0000-0000-0000-000000000890", + }, }, - "id": "00000000-0000-0000-0000-000000000913", + "id": "00000000-0000-0000-0000-000000000915", "views": { "allWorkspaceMembers": { - "id": "00000000-0000-0000-0000-000000000912", + "id": "00000000-0000-0000-0000-000000000914", "viewFieldGroups": {}, "viewFields": { "assignedTasks": { - "id": "00000000-0000-0000-0000-000000000911", + "id": "00000000-0000-0000-0000-000000000913", }, "avatarUrl": { - "id": "00000000-0000-0000-0000-000000000903", - }, - "colorScheme": { - "id": "00000000-0000-0000-0000-000000000904", - }, - "createdAt": { - "id": "00000000-0000-0000-0000-000000000909", - }, - "dateFormat": { - "id": "00000000-0000-0000-0000-000000000907", - }, - "locale": { "id": "00000000-0000-0000-0000-000000000905", }, - "name": { - "id": "00000000-0000-0000-0000-000000000901", - }, - "ownedOpportunities": { - "id": "00000000-0000-0000-0000-000000000910", - }, - "timeFormat": { - "id": "00000000-0000-0000-0000-000000000908", - }, - "timeZone": { + "colorScheme": { "id": "00000000-0000-0000-0000-000000000906", }, + "createdAt": { + "id": "00000000-0000-0000-0000-000000000911", + }, + "dateFormat": { + "id": "00000000-0000-0000-0000-000000000909", + }, + "locale": { + "id": "00000000-0000-0000-0000-000000000907", + }, + "name": { + "id": "00000000-0000-0000-0000-000000000903", + }, + "ownedOpportunities": { + "id": "00000000-0000-0000-0000-000000000912", + }, + "timeFormat": { + "id": "00000000-0000-0000-0000-000000000910", + }, + "timeZone": { + "id": "00000000-0000-0000-0000-000000000908", + }, "userEmail": { - "id": "00000000-0000-0000-0000-000000000902", + "id": "00000000-0000-0000-0000-000000000904", }, }, "viewGroups": {}, diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/compute-workflow-standard-flat-field-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/compute-workflow-standard-flat-field-metadata.util.ts index 2fbbd049d8..ca99590b9a 100644 --- a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/compute-workflow-standard-flat-field-metadata.util.ts +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/compute-workflow-standard-flat-field-metadata.util.ts @@ -136,6 +136,24 @@ export const buildWorkflowStandardFlatFieldMetadatas = ({ twentyStandardApplicationId, now, }), + coreWorkflowId: createStandardFieldFlatMetadata({ + objectName, + workspaceId, + context: { + fieldName: 'coreWorkflowId', + type: FieldMetadataType.UUID, + label: i18nLabel(msg`Core workflow id`), + description: i18nLabel(msg`Reference to the core workflow row`), + icon: 'IconSettingsAutomation', + isSystem: true, + isNullable: true, + isUIEditable: false, + }, + standardObjectMetadataRelatedEntityIds, + dependencyFlatEntityMaps, + twentyStandardApplicationId, + now, + }), statuses: createStandardFieldFlatMetadata({ objectName, workspaceId, diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/compute-workflow-version-standard-flat-field-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/compute-workflow-version-standard-flat-field-metadata.util.ts index aea3e39f54..7c44874109 100644 --- a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/compute-workflow-version-standard-flat-field-metadata.util.ts +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/compute-workflow-version-standard-flat-field-metadata.util.ts @@ -206,6 +206,24 @@ export const buildWorkflowVersionStandardFlatFieldMetadatas = ({ twentyStandardApplicationId, now, }), + coreWorkflowVersionId: createStandardFieldFlatMetadata({ + objectName, + workspaceId, + context: { + fieldName: 'coreWorkflowVersionId', + type: FieldMetadataType.UUID, + label: i18nLabel(msg`Core workflow version id`), + description: i18nLabel(msg`Reference to the core workflowVersion row`), + icon: 'IconSettingsAutomation', + isSystem: true, + isNullable: true, + isUIEditable: false, + }, + standardObjectMetadataRelatedEntityIds, + dependencyFlatEntityMaps, + twentyStandardApplicationId, + now, + }), status: createStandardFieldFlatMetadata({ objectName, workspaceId, diff --git a/packages/twenty-server/src/modules/workflow/common/standard-objects/workflow-version.workspace-entity.ts b/packages/twenty-server/src/modules/workflow/common/standard-objects/workflow-version.workspace-entity.ts index 270ba9f0c2..4c189152c9 100644 --- a/packages/twenty-server/src/modules/workflow/common/standard-objects/workflow-version.workspace-entity.ts +++ b/packages/twenty-server/src/modules/workflow/common/standard-objects/workflow-version.workspace-entity.ts @@ -17,6 +17,7 @@ export class WorkflowVersionWorkspaceEntity extends BaseWorkspaceEntity { name: string | null; trigger: WorkflowTrigger | null; steps: WorkflowAction[] | null; + coreWorkflowVersionId: string | null; status: WorkflowVersionStatus; position: number; searchVector: string; diff --git a/packages/twenty-server/src/modules/workflow/common/standard-objects/workflow.workspace-entity.ts b/packages/twenty-server/src/modules/workflow/common/standard-objects/workflow.workspace-entity.ts index ab806ba8cb..c22bcd139d 100644 --- a/packages/twenty-server/src/modules/workflow/common/standard-objects/workflow.workspace-entity.ts +++ b/packages/twenty-server/src/modules/workflow/common/standard-objects/workflow.workspace-entity.ts @@ -17,6 +17,7 @@ export enum WorkflowStatus { export class WorkflowWorkspaceEntity extends BaseWorkspaceEntity { name: string | null; lastPublishedVersionId: string | null; + coreWorkflowId: string | null; statuses: WorkflowStatus[] | null; position: number; searchVector: string; diff --git a/packages/twenty-server/src/modules/workflow/workflow-version-core-sync/listeners/workflow-version-core-dual-write.listener.ts b/packages/twenty-server/src/modules/workflow/workflow-version-core-sync/listeners/workflow-version-core-dual-write.listener.ts index d1d085ba4d..e0eddf16ae 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-version-core-sync/listeners/workflow-version-core-dual-write.listener.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-version-core-sync/listeners/workflow-version-core-dual-write.listener.ts @@ -67,7 +67,9 @@ export class WorkflowVersionCoreDualWriteListener { ): Promise { await this.deleteFromCore( batchEvent.workspaceId, - batchEvent.events.map((event) => event.properties.before.id), + batchEvent.events + .map((event) => event.properties.before.coreWorkflowVersionId) + .filter(isDefined), ); } @@ -79,7 +81,9 @@ export class WorkflowVersionCoreDualWriteListener { ): Promise { await this.deleteFromCore( batchEvent.workspaceId, - batchEvent.events.map((event) => event.properties.before.id), + batchEvent.events + .map((event) => event.properties.before.coreWorkflowVersionId) + .filter(isDefined), ); } @@ -105,7 +109,7 @@ export class WorkflowVersionCoreDualWriteListener { private async deleteFromCore( workspaceId: string | undefined, - workflowVersionIds: string[], + coreWorkflowVersionIds: string[], ): Promise { if (!isDefined(workspaceId)) { return; @@ -114,7 +118,7 @@ export class WorkflowVersionCoreDualWriteListener { try { await this.workflowVersionCoreSyncService.deleteFromCore( workspaceId, - workflowVersionIds, + coreWorkflowVersionIds, ); } catch (error) { this.exceptionHandlerService.captureExceptions([error], { diff --git a/packages/twenty-shared/src/metadata/__tests__/__snapshots__/standardObjectUniversalIdentifiers.test.ts.snap b/packages/twenty-shared/src/metadata/__tests__/__snapshots__/standardObjectUniversalIdentifiers.test.ts.snap index d8a22ced28..d7e1bcfe39 100644 --- a/packages/twenty-shared/src/metadata/__tests__/__snapshots__/standardObjectUniversalIdentifiers.test.ts.snap +++ b/packages/twenty-shared/src/metadata/__tests__/__snapshots__/standardObjectUniversalIdentifiers.test.ts.snap @@ -2719,6 +2719,9 @@ exports[`STANDARD_OBJECTS universal identifiers should never change without an e "automatedTriggers": { "universalIdentifier": "20202020-3319-4234-a34c-117ecad2b8a9", }, + "coreWorkflowId": { + "universalIdentifier": "20202020-058a-42ad-8eb8-0662a5552aad", + }, "createdAt": { "universalIdentifier": "0be9023c-cf26-56ef-8512-3c2104b849cc", }, @@ -3024,6 +3027,9 @@ exports[`STANDARD_OBJECTS universal identifiers should never change without an e }, "workflowVersion": { "fields": { + "coreWorkflowVersionId": { + "universalIdentifier": "20202020-58b4-46e8-b6d2-f1f3c74cf7f4", + }, "createdAt": { "universalIdentifier": "97b8d13e-ea41-5da4-90df-886ff017f584", }, diff --git a/packages/twenty-shared/src/metadata/constants/standard-object.constant.ts b/packages/twenty-shared/src/metadata/constants/standard-object.constant.ts index cea91cea74..e49d791d3e 100644 --- a/packages/twenty-shared/src/metadata/constants/standard-object.constant.ts +++ b/packages/twenty-shared/src/metadata/constants/standard-object.constant.ts @@ -2162,6 +2162,9 @@ export const STANDARD_OBJECTS = { lastPublishedVersionId: { universalIdentifier: '20202020-326a-4fba-8639-3456c0a169e8', }, + coreWorkflowId: { + universalIdentifier: '20202020-058a-42ad-8eb8-0662a5552aad', + }, statuses: { universalIdentifier: '20202020-357c-4432-8c50-8c31b4a552d9' }, versions: { universalIdentifier: '20202020-9432-416e-8f3c-27ee3153d099' }, runs: { universalIdentifier: '20202020-759b-4340-b58b-e73595c4df4f' }, @@ -2402,6 +2405,9 @@ export const STANDARD_OBJECTS = { }, runs: { universalIdentifier: '20202020-1d08-46df-901a-85045f18099a' }, steps: { universalIdentifier: '20202020-5988-4a64-b94a-1f9b7b989039' }, + coreWorkflowVersionId: { + universalIdentifier: '20202020-58b4-46e8-b6d2-f1f3c74cf7f4', + }, timelineActivities: { universalIdentifier: '20202020-fcb0-4695-b17e-3b43a421c633', },