From d433a576d70ffa8c58992d5878b07651b853feae Mon Sep 17 00:00:00 2001 From: Weiko Date: Tue, 26 Aug 2025 10:54:03 +0200 Subject: [PATCH] Create related records after object creation with migration v2 (view, view filters, favorite) (#14068) ## Context This PR introduces view actions for the migration v2. We should be able to create, update and delete views through the migration runner independently from object actions (this is not 100% true in this PR though as I'm still passing the object metadata to build the view) Note: Once favorite are moved out of the workspace schema, we will have favorite actions as well, in the meantime I have to inject some code at the end of the createOne method from the object metadata service --- .../auth/services/auth.service.ts | 3 + .../object-metadata-v2.service.ts | 28 ++ .../object-metadata/object-metadata.module.ts | 3 +- ...object-metadata-related-records.service.ts | 2 +- .../types/flat-view-field.type.ts | 6 + .../types/flat-view.type.ts | 9 + .../workspace-migration-builder.spec.ts.snap | 333 ++++++++++++++++++ ...pace-migration-builder-object-test-case.ts | 3 + .../workspace-migration-builder.spec.ts | 5 +- ...ration-v2-field-actions-builder.service.ts | 26 +- ...pace-migration-v2-index-actions-builder.ts | 0 ...ation-v2-object-actions-builder.service.ts | 0 ...space-migration-v2-view-actions-builder.ts | 41 +++ .../workspace-migration-builder-v2.service.ts | 14 +- .../workspace-migration-action-common-v2.ts | 4 +- ...workspace-migration-view-action-v2.type.ts | 11 + .../workspace-migration-builder-v2.module.ts | 4 +- .../create-object-action-handler.service.ts | 28 +- .../create-view-action-handler.service.ts | 49 +++ ...migration-runner-action-handlers.module.ts | 3 + ...ion-action-on-flat-object-metadata-maps.ts | 10 +- 21 files changed, 534 insertions(+), 48 deletions(-) create mode 100644 packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/types/flat-view-field.type.ts create mode 100644 packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/types/flat-view.type.ts rename packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/{ => builders/field}/services/workspace-migration-v2-field-actions-builder.service.ts (92%) rename packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/{ => builders/index}/workspace-migration-v2-index-actions-builder.ts (100%) rename packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/{ => builders/object}/services/workspace-migration-v2-object-actions-builder.service.ts (100%) create mode 100644 packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/view/workspace-migration-v2-view-actions-builder.ts create mode 100644 packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-view-action-v2.type.ts create mode 100644 packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/view/services/create-view-action-handler.service.ts diff --git a/packages/twenty-server/src/engine/core-modules/auth/services/auth.service.ts b/packages/twenty-server/src/engine/core-modules/auth/services/auth.service.ts index 1c7bf43709..a079694c28 100644 --- a/packages/twenty-server/src/engine/core-modules/auth/services/auth.service.ts +++ b/packages/twenty-server/src/engine/core-modules/auth/services/auth.service.ts @@ -685,6 +685,9 @@ export class AuthService { throw new AuthException( 'User does not have access to this workspace', AuthExceptionCode.FORBIDDEN_EXCEPTION, + { + userFriendlyMessage: t`User does not have access to this workspace`, + }, ); } } diff --git a/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata-v2.service.ts b/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata-v2.service.ts index 85cc5d7f23..3b8b0d8fda 100644 --- a/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata-v2.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata-v2.service.ts @@ -1,7 +1,11 @@ import { Injectable } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; import { isDefined } from 'twenty-shared/utils'; +import { Repository } from 'typeorm'; +import { View } from 'src/engine/core-modules/view/entities/view.entity'; +import { ViewKey } from 'src/engine/core-modules/view/enums/view-key.enum'; import { addFlatFieldMetadataInFlatObjectMetadataMapsOrThrow } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/add-flat-field-metadata-in-flat-object-metadata-maps-or-throw.util'; import { addFlatObjectMetadataToFlatObjectMetadataMapsOrThrow } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/add-flat-object-metadata-to-flat-object-metadata-maps-or-throw.util'; import { deleteFieldFromFlatObjectMetadataMapsOrThrow } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/delete-field-from-flat-object-metadata-maps-or-throw.util'; @@ -22,6 +26,7 @@ import { ObjectMetadataException, ObjectMetadataExceptionCode, } from 'src/engine/metadata-modules/object-metadata/object-metadata.exception'; +import { ObjectMetadataRelatedRecordsService } from 'src/engine/metadata-modules/object-metadata/services/object-metadata-related-records.service'; import { WorkspaceMetadataCacheService } from 'src/engine/metadata-modules/workspace-metadata-cache/services/workspace-metadata-cache.service'; import { WorkspaceMigrationBuilderExceptionV2 } from 'src/engine/workspace-manager/workspace-migration-v2/exceptions/workspace-migration-builder-exception-v2'; import { WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration-v2/services/workspace-migration-validate-build-and-run-service'; @@ -31,6 +36,9 @@ export class ObjectMetadataServiceV2 { constructor( private readonly workspaceMetadataCacheService: WorkspaceMetadataCacheService, private readonly workspaceMigrationValidateBuildAndRunService: WorkspaceMigrationValidateBuildAndRunService, + private readonly objectMetadataRelatedRecordsService: ObjectMetadataRelatedRecordsService, + @InjectRepository(View, 'core') + private readonly viewRepository: Repository, ) {} async updateOne({ @@ -284,6 +292,26 @@ export class ObjectMetadataServiceV2 { ); } + const [view] = await this.viewRepository.find({ + where: { + objectMetadataId: createdFlatObjectMetadata.id, + key: ViewKey.INDEX, + workspaceId, + }, + }); + + if (!isDefined(view)) { + throw new ObjectMetadataException( + 'View not created', + ObjectMetadataExceptionCode.INTERNAL_SERVER_ERROR, + ); + } + + await this.objectMetadataRelatedRecordsService.createViewWorkspaceFavorite( + workspaceId, + view.id, + ); + return createdFlatObjectMetadata; } } diff --git a/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.module.ts b/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.module.ts index 96aeec54aa..4554d56501 100644 --- a/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.module.ts +++ b/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.module.ts @@ -11,6 +11,7 @@ import { NestjsQueryTypeOrmModule } from '@ptc-org/nestjs-query-typeorm'; import { TypeORMModule } from 'src/database/typeorm/typeorm.module'; import { FeatureFlag } from 'src/engine/core-modules/feature-flag/feature-flag.entity'; import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module'; +import { View } from 'src/engine/core-modules/view/entities/view.entity'; import { SettingsPermissionsGuard } from 'src/engine/guards/settings-permissions.guard'; import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard'; import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module'; @@ -55,7 +56,7 @@ import { WorkspaceMigrationV2Module } from 'src/engine/workspace-manager/workspa [ObjectMetadataEntity, FieldMetadataEntity], 'core', ), - TypeOrmModule.forFeature([FeatureFlag], 'core'), + TypeOrmModule.forFeature([FeatureFlag, View], 'core'), DataSourceModule, WorkspaceMigrationModule, WorkspaceMigrationRunnerModule, diff --git a/packages/twenty-server/src/engine/metadata-modules/object-metadata/services/object-metadata-related-records.service.ts b/packages/twenty-server/src/engine/metadata-modules/object-metadata/services/object-metadata-related-records.service.ts index 4e0b1001c5..2a2ae81c39 100644 --- a/packages/twenty-server/src/engine/metadata-modules/object-metadata/services/object-metadata-related-records.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/object-metadata/services/object-metadata-related-records.service.ts @@ -64,7 +64,7 @@ export class ObjectMetadataRelatedRecordsService { await viewFieldRepository.insert(viewFields); } - private async createViewWorkspaceFavorite( + public async createViewWorkspaceFavorite( workspaceId: string, viewId: string, ): Promise { diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/types/flat-view-field.type.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/types/flat-view-field.type.ts new file mode 100644 index 0000000000..547a9420fe --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/types/flat-view-field.type.ts @@ -0,0 +1,6 @@ +import { type ViewField } from 'src/engine/core-modules/view/entities/view-field.entity'; + +export type FlatViewField = Pick< + ViewField, + 'fieldMetadataId' | 'position' | 'isVisible' | 'size' +>; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/types/flat-view.type.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/types/flat-view.type.ts new file mode 100644 index 0000000000..ba26137371 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/types/flat-view.type.ts @@ -0,0 +1,9 @@ +import { type View } from 'src/engine/core-modules/view/entities/view.entity'; +import { type FlatViewField } from 'src/engine/workspace-manager/workspace-migration-v2/types/flat-view-field.type'; + +export type FlatView = Pick< + View, + 'name' | 'objectMetadataId' | 'type' | 'isCustom' | 'key' | 'icon' +> & { + viewFields: FlatViewField[]; +}; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/__snapshots__/workspace-migration-builder.spec.ts.snap b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/__snapshots__/workspace-migration-builder.spec.ts.snap index fa8b58c877..1adb4e87e9 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/__snapshots__/workspace-migration-builder.spec.ts.snap +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/__snapshots__/workspace-migration-builder.spec.ts.snap @@ -1031,6 +1031,85 @@ exports[`Workspace migration builder object actions test suite It should build a }, "type": "create_object", }, + { + "type": "create_view", + "view": { + "icon": "IconList", + "isCustom": false, + "key": "INDEX", + "name": "All {objectLabelPlural}", + "objectMetadataId": Any, + "type": "TABLE", + "viewFields": [ + { + "fieldMetadataId": Any, + "isVisible": true, + "position": 0, + "size": 180, + }, + { + "fieldMetadataId": Any, + "isVisible": true, + "position": 1, + "size": 180, + }, + { + "fieldMetadataId": Any, + "isVisible": true, + "position": 2, + "size": 180, + }, + { + "fieldMetadataId": Any, + "isVisible": true, + "position": 3, + "size": 180, + }, + { + "fieldMetadataId": Any, + "isVisible": true, + "position": 4, + "size": 180, + }, + { + "fieldMetadataId": Any, + "isVisible": true, + "position": 5, + "size": 180, + }, + { + "fieldMetadataId": Any, + "isVisible": true, + "position": 6, + "size": 180, + }, + { + "fieldMetadataId": Any, + "isVisible": true, + "position": 7, + "size": 180, + }, + { + "fieldMetadataId": Any, + "isVisible": true, + "position": 8, + "size": 180, + }, + { + "fieldMetadataId": Any, + "isVisible": true, + "position": 9, + "size": 180, + }, + { + "fieldMetadataId": Any, + "isVisible": true, + "position": 10, + "size": 180, + }, + ], + }, + }, ] `; @@ -2314,6 +2393,181 @@ exports[`Workspace migration builder object actions test suite It should build a }, "type": "create_object", }, + { + "type": "create_view", + "view": { + "icon": "IconList", + "isCustom": false, + "key": "INDEX", + "name": "All {objectLabelPlural}", + "objectMetadataId": Any, + "type": "TABLE", + "viewFields": [ + { + "fieldMetadataId": Any, + "isVisible": true, + "position": 0, + "size": 180, + }, + { + "fieldMetadataId": Any, + "isVisible": true, + "position": 1, + "size": 180, + }, + { + "fieldMetadataId": Any, + "isVisible": true, + "position": 2, + "size": 180, + }, + { + "fieldMetadataId": Any, + "isVisible": true, + "position": 3, + "size": 180, + }, + { + "fieldMetadataId": Any, + "isVisible": true, + "position": 4, + "size": 180, + }, + { + "fieldMetadataId": Any, + "isVisible": true, + "position": 5, + "size": 180, + }, + { + "fieldMetadataId": Any, + "isVisible": true, + "position": 6, + "size": 180, + }, + { + "fieldMetadataId": Any, + "isVisible": true, + "position": 7, + "size": 180, + }, + { + "fieldMetadataId": Any, + "isVisible": true, + "position": 8, + "size": 180, + }, + { + "fieldMetadataId": Any, + "isVisible": true, + "position": 9, + "size": 180, + }, + { + "fieldMetadataId": Any, + "isVisible": true, + "position": 10, + "size": 180, + }, + { + "fieldMetadataId": Any, + "isVisible": true, + "position": 11, + "size": 180, + }, + { + "fieldMetadataId": Any, + "isVisible": true, + "position": 12, + "size": 180, + }, + { + "fieldMetadataId": Any, + "isVisible": true, + "position": 13, + "size": 180, + }, + { + "fieldMetadataId": Any, + "isVisible": true, + "position": 14, + "size": 180, + }, + { + "fieldMetadataId": Any, + "isVisible": true, + "position": 15, + "size": 180, + }, + { + "fieldMetadataId": Any, + "isVisible": true, + "position": 16, + "size": 180, + }, + { + "fieldMetadataId": Any, + "isVisible": true, + "position": 17, + "size": 180, + }, + { + "fieldMetadataId": Any, + "isVisible": true, + "position": 18, + "size": 180, + }, + { + "fieldMetadataId": Any, + "isVisible": true, + "position": 19, + "size": 180, + }, + { + "fieldMetadataId": Any, + "isVisible": true, + "position": 20, + "size": 180, + }, + { + "fieldMetadataId": Any, + "isVisible": true, + "position": 21, + "size": 180, + }, + { + "fieldMetadataId": Any, + "isVisible": true, + "position": 22, + "size": 180, + }, + { + "fieldMetadataId": Any, + "isVisible": true, + "position": 23, + "size": 180, + }, + { + "fieldMetadataId": Any, + "isVisible": true, + "position": 24, + "size": 180, + }, + { + "fieldMetadataId": Any, + "isVisible": true, + "position": 25, + "size": 180, + }, + { + "fieldMetadataId": Any, + "isVisible": true, + "position": 26, + "size": 180, + }, + ], + }, + }, ] `; @@ -2958,6 +3212,85 @@ exports[`Workspace migration builder object actions test suite It should build a }, "type": "create_index", }, + { + "type": "create_view", + "view": { + "icon": "IconList", + "isCustom": false, + "key": "INDEX", + "name": "All {objectLabelPlural}", + "objectMetadataId": Any, + "type": "TABLE", + "viewFields": [ + { + "fieldMetadataId": Any, + "isVisible": true, + "position": 0, + "size": 180, + }, + { + "fieldMetadataId": Any, + "isVisible": true, + "position": 1, + "size": 180, + }, + { + "fieldMetadataId": Any, + "isVisible": true, + "position": 2, + "size": 180, + }, + { + "fieldMetadataId": Any, + "isVisible": true, + "position": 3, + "size": 180, + }, + { + "fieldMetadataId": Any, + "isVisible": true, + "position": 4, + "size": 180, + }, + { + "fieldMetadataId": Any, + "isVisible": true, + "position": 5, + "size": 180, + }, + { + "fieldMetadataId": Any, + "isVisible": true, + "position": 6, + "size": 180, + }, + { + "fieldMetadataId": Any, + "isVisible": true, + "position": 7, + "size": 180, + }, + { + "fieldMetadataId": Any, + "isVisible": true, + "position": 8, + "size": 180, + }, + { + "fieldMetadataId": Any, + "isVisible": true, + "position": 9, + "size": 180, + }, + { + "fieldMetadataId": Any, + "isVisible": true, + "position": 10, + "size": 180, + }, + ], + }, + }, ] `; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/common/workspace-migration-builder-object-test-case.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/common/workspace-migration-builder-object-test-case.ts index 842f617fa8..8b429375db 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/common/workspace-migration-builder-object-test-case.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/common/workspace-migration-builder-object-test-case.ts @@ -81,6 +81,7 @@ const CREATE_OBJECT_TEST_CASES: WorkspaceMigrationBuilderTestCase[] = [ }, expectedActionsTypeCounter: { createObject: 1, + createView: 1, }, }, }, @@ -102,6 +103,7 @@ const CREATE_OBJECT_TEST_CASES: WorkspaceMigrationBuilderTestCase[] = [ }, expectedActionsTypeCounter: { createObject: 1, + createView: 1, }, }, }, @@ -112,6 +114,7 @@ const CREATE_OBJECT_TEST_CASES: WorkspaceMigrationBuilderTestCase[] = [ expectedActionsTypeCounter: { createIndex: 1, createObject: 1, + createView: 1, }, input: { fromFlatObjectMetadataMaps: diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/workspace-migration-builder.spec.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/workspace-migration-builder.spec.ts index ef8afcc7ef..14c5a5ae17 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/workspace-migration-builder.spec.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/workspace-migration-builder.spec.ts @@ -14,9 +14,9 @@ import { type ExpectedActionCounters, type WorkspaceMigrationBuilderTestCase, } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/__tests__/types/workspace-migration-builder-test-case.type'; +import { WorkspaceMigrationV2FieldActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/field/services/workspace-migration-v2-field-actions-builder.service'; +import { WorkspaceMigrationV2ObjectActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/object/services/workspace-migration-v2-object-actions-builder.service'; import { WorkspaceMigrationBuilderV2Service } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/services/workspace-migration-builder-v2.service'; -import { WorkspaceMigrationV2FieldActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/services/workspace-migration-v2-field-actions-builder.service'; -import { WorkspaceMigrationV2ObjectActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/services/workspace-migration-v2-object-actions-builder.service'; import { type WorkspaceMigrationV2 } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-v2'; const allWorkspaceBuilderTestCases: { @@ -54,6 +54,7 @@ const expectedActionsTypeCounterChecker = ({ deleteObject: 0, updateField: 0, updateObject: 0, + createView: 0, }; const actualActionsTypeCounter = workspaceMigration.actions.reduce( (acc, action) => { diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/services/workspace-migration-v2-field-actions-builder.service.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/field/services/workspace-migration-v2-field-actions-builder.service.ts similarity index 92% rename from packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/services/workspace-migration-v2-field-actions-builder.service.ts rename to packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/field/services/workspace-migration-v2-field-actions-builder.service.ts index 481ff0d910..0b3a7dfcd6 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/services/workspace-migration-v2-field-actions-builder.service.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/field/services/workspace-migration-v2-field-actions-builder.service.ts @@ -1,10 +1,10 @@ import { Injectable } from '@nestjs/common'; -import { FieldMetadataType, FromTo } from 'twenty-shared/types'; +import { FromTo } from 'twenty-shared/types'; import { FlatFieldMetadataValidatorService } from 'src/engine/metadata-modules/flat-field-metadata/services/flat-field-metadata-validator.service'; import { compareTwoFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/compare-two-flat-field-metadata.util'; -import { isFlatFieldMetadataEntityOfType } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-flat-field-metadata-of-type.util'; +import { isRelationFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-relation-flat-field-metadata.util'; import { FlatObjectMetadataMaps } from 'src/engine/metadata-modules/flat-object-metadata-maps/types/flat-object-metadata-maps.type'; import { addFlatFieldMetadataInFlatObjectMetadataMapsOrThrow } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/add-flat-field-metadata-in-flat-object-metadata-maps-or-throw.util'; import { deleteFieldFromFlatObjectMetadataMapsOrThrow } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/delete-field-from-flat-object-metadata-maps-or-throw.util'; @@ -115,20 +115,14 @@ export class WorkspaceMigrationV2FieldActionsBuilderService { } for (const flatFieldMetadataToCreate of createdFlatFieldMetadatas) { - const relationTargetFlatObjectMetadataMaps = - isFlatFieldMetadataEntityOfType( - flatFieldMetadataToCreate, - FieldMetadataType.RELATION, - ) || - isFlatFieldMetadataEntityOfType( - flatFieldMetadataToCreate, - FieldMetadataType.MORPH_RELATION, - ) - ? computeRelationTargetFlatObjectMetadataMaps({ - flatFieldMetadata: flatFieldMetadataToCreate, - flatObjectMetadataMaps: toFlatObjectMetadataMaps, - }) - : undefined; + const relationTargetFlatObjectMetadataMaps = isRelationFlatFieldMetadata( + flatFieldMetadataToCreate, + ) + ? computeRelationTargetFlatObjectMetadataMaps({ + flatFieldMetadata: flatFieldMetadataToCreate, + flatObjectMetadataMaps: toFlatObjectMetadataMaps, + }) + : undefined; const validationErrors = await this.flatFieldMetadataValidatorService.validateFlatFieldMetadataCreation( diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/workspace-migration-v2-index-actions-builder.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/index/workspace-migration-v2-index-actions-builder.ts similarity index 100% rename from packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/workspace-migration-v2-index-actions-builder.ts rename to packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/index/workspace-migration-v2-index-actions-builder.ts diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/services/workspace-migration-v2-object-actions-builder.service.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/object/services/workspace-migration-v2-object-actions-builder.service.ts similarity index 100% rename from packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/services/workspace-migration-v2-object-actions-builder.service.ts rename to packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/object/services/workspace-migration-v2-object-actions-builder.service.ts diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/view/workspace-migration-v2-view-actions-builder.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/view/workspace-migration-v2-view-actions-builder.ts new file mode 100644 index 0000000000..2b93e82478 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/view/workspace-migration-v2-view-actions-builder.ts @@ -0,0 +1,41 @@ +import { ViewKey } from 'src/engine/core-modules/view/enums/view-key.enum'; +import { ViewType } from 'src/engine/core-modules/view/enums/view-type.enum'; +import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type'; +import { + type CreateViewAction, + type WorkspaceMigrationViewActionV2, +} from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-view-action-v2.type'; + +type BuildWorkspaceMigrationViewActionsArgs = { + createdFlatObjectMetadatas: FlatObjectMetadata[]; +}; + +const getCreateViewAction = ( + flatObjectMetadata: FlatObjectMetadata, +): CreateViewAction => { + return { + type: 'create_view', + view: { + objectMetadataId: flatObjectMetadata.id, + type: ViewType.TABLE, + name: `All {objectLabelPlural}`, + key: ViewKey.INDEX, + isCustom: false, + icon: 'IconList', + viewFields: flatObjectMetadata.flatFieldMetadatas + .filter((field) => field.name !== 'id' && field.name !== 'deletedAt') + .map((field, index) => ({ + fieldMetadataId: field.id, + position: index, + isVisible: true, + size: 180, + })), + }, + }; +}; + +export const buildWorkspaceMigrationViewActions = ({ + createdFlatObjectMetadatas, +}: BuildWorkspaceMigrationViewActionsArgs): WorkspaceMigrationViewActionV2[] => { + return createdFlatObjectMetadatas.map(getCreateViewAction); +}; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/services/workspace-migration-builder-v2.service.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/services/workspace-migration-builder-v2.service.ts index 4493642fc3..52632e6018 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/services/workspace-migration-builder-v2.service.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/services/workspace-migration-builder-v2.service.ts @@ -7,13 +7,14 @@ import { type FlatObjectMetadataMaps } from 'src/engine/metadata-modules/flat-ob import { FailedFlatObjectMetadataValidation } from 'src/engine/metadata-modules/flat-object-metadata/types/failed-flat-object-metadata-validation.type'; import { fromFlatObjectMetadataMapsToFlatObjectMetadatas } from 'src/engine/metadata-modules/flat-object-metadata/utils/from-flat-object-metadata-maps-to-flat-object-metadatas.util'; import { deletedCreatedUpdatedMatrixDispatcher } from 'src/engine/workspace-manager/workspace-migration-v2/utils/deleted-created-updated-matrix-dispatcher.util'; -import { WorkspaceMigrationV2FieldActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/services/workspace-migration-v2-field-actions-builder.service'; -import { WorkspaceMigrationV2ObjectActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/services/workspace-migration-v2-object-actions-builder.service'; +import { WorkspaceMigrationV2FieldActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/field/services/workspace-migration-v2-field-actions-builder.service'; +import { buildWorkspaceMigrationIndexActions } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/index/workspace-migration-v2-index-actions-builder'; +import { WorkspaceMigrationV2ObjectActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/object/services/workspace-migration-v2-object-actions-builder.service'; +import { buildWorkspaceMigrationViewActions } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/view/workspace-migration-v2-view-actions-builder'; import { WorkspaceMigrationV2 } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-v2'; import { computeUpdatedObjectMetadataDeletedCreatedUpdatedFieldMatrix } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/compute-updated-object-metadata-deleted-created-updated-field-matrix.util'; import { computeUpdatedObjectMetadataDeletedCreatedUpdatedIndexMatrix } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/compute-updated-object-metadata-deleted-created-updated-index-matrix.util'; import { getWorkspaceMigrationV2CreateIndexAction } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/utils/get-workspace-migration-v2-index-actions'; -import { buildWorkspaceMigrationIndexActions } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/workspace-migration-v2-index-actions-builder'; export type WorkspaceMigrationV2BuilderOptions = { inferDeletionFromMissingObjectFieldIndex: boolean; @@ -117,7 +118,11 @@ export class WorkspaceMigrationBuilderV2Service { inferDeletionFromMissingObjectFieldIndex: buildOptions.inferDeletionFromMissingObjectFieldIndex, }); - /// + + // TODO: Remove this from here when we have a proper builder that handles views diffing independently + const viewWorkspaceMigrationActions = buildWorkspaceMigrationViewActions({ + createdFlatObjectMetadatas, // should be flatViews, not objects. + }); const allValidateAndBuildResultFailures = [ ...objectActionsValidateAndBuildResult.failed, @@ -144,6 +149,7 @@ export class WorkspaceMigrationBuilderV2Service { ...fieldActionsValidateAndBuildResult.updated, ...createdObjectMetadataCreateIndexActions, ...indexWorkspaceMigrationActions, + ...viewWorkspaceMigrationActions, ], }, }; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-action-common-v2.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-action-common-v2.ts index d5e4bcd6ef..1e3430f166 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-action-common-v2.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-action-common-v2.ts @@ -1,11 +1,13 @@ import { type WorkspaceMigrationFieldActionV2 } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-field-action-v2'; import { type WorkspaceMigrationIndexActionV2 } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-index-action-v2'; import { type WorkspaceMigrationObjectActionV2 } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-object-action-v2'; +import { type WorkspaceMigrationViewActionV2 } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-view-action-v2.type'; export type WorkspaceMigrationActionV2 = | WorkspaceMigrationObjectActionV2 | WorkspaceMigrationFieldActionV2 - | WorkspaceMigrationIndexActionV2; + | WorkspaceMigrationIndexActionV2 + | WorkspaceMigrationViewActionV2; export type WorkspaceMigrationActionTypeV2 = WorkspaceMigrationActionV2['type']; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-view-action-v2.type.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-view-action-v2.type.ts new file mode 100644 index 0000000000..6d9b398586 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-view-action-v2.type.ts @@ -0,0 +1,11 @@ +import { type FlatView } from 'src/engine/workspace-manager/workspace-migration-v2/types/flat-view.type'; + +export type CreateViewAction = { + type: 'create_view'; + view: FlatView; +}; + +export type WorkspaceMigrationViewActionV2 = CreateViewAction; + +export type WorkspaceMigrationViewActionTypeV2 = + WorkspaceMigrationViewActionV2['type']; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/workspace-migration-builder-v2.module.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/workspace-migration-builder-v2.module.ts index f18212a584..eb6e406c1f 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/workspace-migration-builder-v2.module.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/workspace-migration-builder-v2.module.ts @@ -4,9 +4,9 @@ import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature- import { FlatFieldMetadataTypeValidatorService } from 'src/engine/metadata-modules/flat-field-metadata/services/flat-field-metadata-type-validator.service'; import { FlatFieldMetadataValidatorService } from 'src/engine/metadata-modules/flat-field-metadata/services/flat-field-metadata-validator.service'; import { FlatObjectMetadataValidatorService } from 'src/engine/metadata-modules/flat-object-metadata/services/flat-object-metadata-validator.service'; +import { WorkspaceMigrationV2FieldActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/field/services/workspace-migration-v2-field-actions-builder.service'; +import { WorkspaceMigrationV2ObjectActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/builders/object/services/workspace-migration-v2-object-actions-builder.service'; import { WorkspaceMigrationBuilderV2Service } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/services/workspace-migration-builder-v2.service'; -import { WorkspaceMigrationV2FieldActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/services/workspace-migration-v2-field-actions-builder.service'; -import { WorkspaceMigrationV2ObjectActionsBuilderService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/services/workspace-migration-v2-object-actions-builder.service'; @Module({ imports: [FeatureFlagModule], diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/object/services/create-object-action-handler.service.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/object/services/create-object-action-handler.service.ts index 5917911a28..8703ce49f8 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/object/services/create-object-action-handler.service.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/object/services/create-object-action-handler.service.ts @@ -4,10 +4,10 @@ import { WorkspaceMigrationRunnerActionHandler } from 'src/engine/workspace-mana import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity'; import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; -import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; import { isCompositeFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-composite-flat-field-metadata.util'; import { isEnumFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-enum-flat-field-metadata.util'; import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; +import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager'; import { WorkspaceSchemaManagerService } from 'src/engine/twenty-orm/workspace-schema-manager/workspace-schema-manager.service'; import { type CreateObjectAction } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-object-action-v2'; import { type WorkspaceMigrationActionRunnerArgs } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/types/workspace-migration-action-runner-args.type'; @@ -25,6 +25,7 @@ export class CreateObjectActionHandlerService extends WorkspaceMigrationRunnerAc ) { constructor( private readonly workspaceSchemaManagerService: WorkspaceSchemaManagerService, + private readonly twentyORMGlobalManager: TwentyORMGlobalManager, ) { super(); } @@ -74,27 +75,26 @@ export class CreateObjectActionHandlerService extends WorkspaceMigrationRunnerAc const { action, queryRunner, workspaceId } = context; const { flatObjectMetadataWithoutFields, createFieldActions } = action; - const flatObjectMetadata = flatObjectMetadataWithoutFields; - const { schemaName, tableName } = getWorkspaceSchemaContextForMigration({ workspaceId, - flatObjectMetadata: flatObjectMetadata, + flatObjectMetadata: flatObjectMetadataWithoutFields, }); - const columnDefinitions = createFieldActions.flatMap((createFieldAction) => + const flatFieldMetadatas = createFieldActions.map( + (createFieldAction) => createFieldAction.flatFieldMetadata, + ); + + const columnDefinitions = flatFieldMetadatas.flatMap((flatFieldMetadata) => generateColumnDefinitions({ - flatFieldMetadata: createFieldAction.flatFieldMetadata, - flatObjectMetadataWithoutFields: flatObjectMetadataWithoutFields, + flatFieldMetadata, + flatObjectMetadataWithoutFields, }), ); - const enumOrCompositeFlatFieldMetadatas = createFieldActions - .map((createFieldAction) => createFieldAction.flatFieldMetadata) - .filter((field): field is FlatFieldMetadata => field != null) - .filter( - (field) => - isEnumFlatFieldMetadata(field) || isCompositeFlatFieldMetadata(field), - ); + const enumOrCompositeFlatFieldMetadatas = flatFieldMetadatas.filter( + (field) => + isEnumFlatFieldMetadata(field) || isCompositeFlatFieldMetadata(field), + ); const enumOperations = collectEnumOperationsForObject({ flatFieldMetadatas: enumOrCompositeFlatFieldMetadatas, diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/view/services/create-view-action-handler.service.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/view/services/create-view-action-handler.service.ts new file mode 100644 index 0000000000..b9b90ea255 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/view/services/create-view-action-handler.service.ts @@ -0,0 +1,49 @@ +import { Injectable } from '@nestjs/common'; + +import { WorkspaceMigrationRunnerActionHandler } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/interfaces/workspace-migration-runner-action-handler-service.interface'; + +import { ViewField } from 'src/engine/core-modules/view/entities/view-field.entity'; +import { View } from 'src/engine/core-modules/view/entities/view.entity'; +import { CreateViewAction } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-view-action-v2.type'; +import { WorkspaceMigrationActionRunnerArgs } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/types/workspace-migration-action-runner-args.type'; + +@Injectable() +export class CreateViewActionHandlerService extends WorkspaceMigrationRunnerActionHandler( + 'create_view', +) { + constructor() { + super(); + } + + async executeForMetadata( + context: WorkspaceMigrationActionRunnerArgs, + ): Promise { + const { action, queryRunner, workspaceId } = context; + const { view } = action; + + const { viewFields } = view; + + const viewRepository = queryRunner.manager.getRepository(View); + const viewFieldRepository = + queryRunner.manager.getRepository(ViewField); + + const createdView = await viewRepository.save({ + ...view, + workspaceId, + }); + + await viewFieldRepository.save( + viewFields.map((viewField) => ({ + ...viewField, + viewId: createdView.id, + workspaceId, + })), + ); + } + + async executeForWorkspaceSchema( + _context: WorkspaceMigrationActionRunnerArgs, + ): Promise { + return; + } +} diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/workspace-schema-migration-runner-action-handlers.module.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/workspace-schema-migration-runner-action-handlers.module.ts index a37c07fb7b..f4e8e93199 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/workspace-schema-migration-runner-action-handlers.module.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/workspace-schema-migration-runner-action-handlers.module.ts @@ -9,6 +9,7 @@ import { DeleteIndexActionHandlerService } from 'src/engine/workspace-manager/wo import { CreateObjectActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/object/services/create-object-action-handler.service'; import { DeleteObjectActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/object/services/delete-object-action-handler.service'; import { UpdateObjectActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/object/services/update-object-action-handler.service'; +import { CreateViewActionHandlerService } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/view/services/create-view-action-handler.service'; @Module({ imports: [WorkspaceSchemaManagerModule], @@ -23,6 +24,8 @@ import { UpdateObjectActionHandlerService } from 'src/engine/workspace-manager/w CreateIndexActionHandlerService, DeleteIndexActionHandlerService, + + CreateViewActionHandlerService, ], }) export class WorkspaceSchemaMigrationRunnerActionHandlersModule {} diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/utils/apply-workspace-migration-action-on-flat-object-metadata-maps.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/utils/apply-workspace-migration-action-on-flat-object-metadata-maps.ts index 1f26b4bf7b..1a93ba7003 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/utils/apply-workspace-migration-action-on-flat-object-metadata-maps.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/utils/apply-workspace-migration-action-on-flat-object-metadata-maps.ts @@ -132,14 +132,10 @@ export const applyWorkspaceMigrationActionOnFlatObjectMetadataMaps = < objectMetadataId: action.objectMetadataId, }); } - case 'create_index': { - // TODO prastoin handle indexes + case 'create_index': + case 'delete_index': + case 'create_view': return flatObjectMetadataMaps; - } - case 'delete_index': { - // TODO prastoin handle indexes - return flatObjectMetadataMaps; - } default: { assertUnreachable( action,