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,