diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-10/1-10-seed-dashboard-view.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-10/1-10-seed-dashboard-view.command.ts index 8eb9986ab4d36..9bcb3c876bdc3 100644 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-10/1-10-seed-dashboard-view.command.ts +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/1-10/1-10-seed-dashboard-view.command.ts @@ -9,6 +9,7 @@ import { ActiveOrSuspendedWorkspacesMigrationCommandRunner, type RunOnWorkspaceArgs, } from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner'; +import { ApplicationService } from 'src/engine/core-modules/application/application.service'; import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity'; import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; @@ -37,6 +38,7 @@ export class SeedDashboardViewCommand extends ActiveOrSuspendedWorkspacesMigrati private readonly dataSourceRepository: Repository, @InjectRepository(ViewEntity) private readonly viewRepository: Repository, + private readonly applicationService: ApplicationService, ) { super(workspaceRepository, twentyORMGlobalManager); } @@ -59,7 +61,17 @@ export class SeedDashboardViewCommand extends ActiveOrSuspendedWorkspacesMigrati ); } - const views = [dashboardsAllView([dashboardObjectMetadata], true)]; + const { twentyStandardFlatApplication } = + await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow( + { workspaceId }, + ); + const views = [ + dashboardsAllView({ + objectMetadataItems: [dashboardObjectMetadata], + useCoreNaming: true, + twentyStandardFlatApplication, + }), + ]; const schema = await this.dataSourceRepository.findOne({ where: { @@ -99,7 +111,12 @@ export class SeedDashboardViewCommand extends ActiveOrSuspendedWorkspacesMigrati await queryRunner.connect(); - const createdViews = await createCoreViews(queryRunner, workspaceId, views); + const createdViews = await createCoreViews( + queryRunner, + workspaceId, + views, + twentyStandardFlatApplication, + ); await prefillWorkspaceFavorites( createdViews.map((view) => view.id), diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-10/1-10-upgrade-version-command.module.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-10/1-10-upgrade-version-command.module.ts index a19929c53dc92..70d6996c10686 100644 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-10/1-10-upgrade-version-command.module.ts +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/1-10/1-10-upgrade-version-command.module.ts @@ -11,9 +11,12 @@ import { MigrateAttachmentTypeToFileCategoryCommand } from 'src/database/command import { MigrateChannelPartialFullSyncStagesCommand } from 'src/database/commands/upgrade-version-command/1-10/1-10-migrate-channel-partial-full-sync-stages.command'; import { RegenerateSearchVectorsCommand } from 'src/database/commands/upgrade-version-command/1-10/1-10-regenerate-search-vectors.command'; import { SeedDashboardViewCommand } from 'src/database/commands/upgrade-version-command/1-10/1-10-seed-dashboard-view.command'; +import { ApplicationEntity } from 'src/engine/core-modules/application/application.entity'; +import { ApplicationModule } from 'src/engine/core-modules/application/application.module'; import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; 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 { WorkspaceManyOrAllFlatEntityMapsCacheModule } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.module'; import { IndexMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-metadata.entity'; import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { ObjectMetadataModule } from 'src/engine/metadata-modules/object-metadata/object-metadata.module'; @@ -30,10 +33,13 @@ import { WorkspaceCacheStorageModule } from 'src/engine/workspace-cache-storage/ IndexMetadataEntity, ViewEntity, DataSourceEntity, + ApplicationEntity, ]), WorkspaceSchemaManagerModule, WorkspaceCacheStorageModule, ObjectMetadataModule, + WorkspaceManyOrAllFlatEntityMapsCacheModule, + ApplicationModule, ], providers: [ MigrateChannelPartialFullSyncStagesCommand, diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-11/1-11-create-twenty-standard-application.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-11/1-11-create-twenty-standard-application.command.ts index a245cea05a371..9e11693fa39fb 100644 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-11/1-11-create-twenty-standard-application.command.ts +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/1-11/1-11-create-twenty-standard-application.command.ts @@ -9,9 +9,9 @@ import { } from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner'; import { ApplicationEntity } from 'src/engine/core-modules/application/application.entity'; import { ApplicationService } from 'src/engine/core-modules/application/application.service'; +import { TWENTY_STANDARD_APPLICATION } from 'src/engine/core-modules/application/constants/twenty-standard-applications'; import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager'; -import { TWENTY_STANDARD_APPLICATION } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/twenty-standard-applications'; @Command({ name: 'upgrade:1-11:create-twenty-standard-application', diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-12/1-12-create-workspace-custom-application.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-12/1-12-create-workspace-custom-application.command.ts new file mode 100644 index 0000000000000..6ba3b7b4eb970 --- /dev/null +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/1-12/1-12-create-workspace-custom-application.command.ts @@ -0,0 +1,65 @@ +import { InjectRepository } from '@nestjs/typeorm'; + +import { Command } from 'nest-commander'; +import { isDefined } from 'twenty-shared/utils'; +import { Repository } from 'typeorm'; + +import { + ActiveOrSuspendedWorkspacesMigrationCommandRunner, + type RunOnWorkspaceArgs, +} from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner'; +import { ApplicationService } from 'src/engine/core-modules/application/application.service'; +import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; +import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager'; + +@Command({ + name: 'upgrade:1-12:create-workspace-custom-application', + description: + 'Create workspace-custom application for workspaces that do not have them', +}) +export class CreateWorkspaceCustomApplicationCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner { + constructor( + @InjectRepository(WorkspaceEntity) + protected readonly workspaceRepository: Repository, + protected readonly twentyORMGlobalManager: TwentyORMGlobalManager, + private readonly applicationService: ApplicationService, + ) { + super(workspaceRepository, twentyORMGlobalManager); + } + + override async runOnWorkspace({ + workspaceId, + }: RunOnWorkspaceArgs): Promise { + this.logger.log( + `Checking standard applications for workspace ${workspaceId}`, + ); + + const workspace = await this.workspaceRepository.findOne({ + where: { id: workspaceId }, + }); + + if (!isDefined(workspace)) { + throw new Error(`${workspaceId} workspace not found`); + } + + if (isDefined(workspace.workspaceCustomApplicationId)) { + this.logger.log( + `${workspaceId} skipping custom workspace application creation as already exists`, + ); + + return; + } + + const customWorkspaceApplication = + await this.applicationService.createWorkspaceCustomApplication({ + workspaceId, + workspaceDisplayName: workspace.displayName, + }); + + await this.workspaceRepository.update(workspace.id, { + workspaceCustomApplicationId: customWorkspaceApplication.id, + }); + + this.logger.log(`Successfully create workspace custom application`); + } +} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-12/1-12-upgrade-version-command.module.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-12/1-12-upgrade-version-command.module.ts index c10e9614c0eb1..84059fb5ed3ef 100644 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-12/1-12-upgrade-version-command.module.ts +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/1-12/1-12-upgrade-version-command.module.ts @@ -1,19 +1,25 @@ import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; +import { CreateWorkspaceCustomApplicationCommand } from 'src/database/commands/upgrade-version-command/1-12/1-12-create-workspace-custom-application.command'; +import { SetStandardApplicationNotUninstallableCommand } from 'src/database/commands/upgrade-version-command/1-12/1-12-set-standard-application-not-uninstallable.command'; +import { ApplicationModule } from 'src/engine/core-modules/application/application.module'; import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; -import { ApplicationEntity } from 'src/engine/core-modules/application/application.entity'; import { WorkspaceSchemaManagerModule } from 'src/engine/twenty-orm/workspace-schema-manager/workspace-schema-manager.module'; -import { ApplicationModule } from 'src/engine/core-modules/application/application.module'; -import { SetStandardApplicationNotUninstallableCommand } from 'src/database/commands/upgrade-version-command/1-12/1-12-set-standard-application-not-uninstallable.command'; @Module({ imports: [ - TypeOrmModule.forFeature([WorkspaceEntity, ApplicationEntity]), + TypeOrmModule.forFeature([WorkspaceEntity]), WorkspaceSchemaManagerModule, ApplicationModule, ], - providers: [SetStandardApplicationNotUninstallableCommand], - exports: [SetStandardApplicationNotUninstallableCommand], + providers: [ + CreateWorkspaceCustomApplicationCommand, + SetStandardApplicationNotUninstallableCommand, + ], + exports: [ + CreateWorkspaceCustomApplicationCommand, + SetStandardApplicationNotUninstallableCommand, + ], }) export class V1_12_UpgradeVersionCommandModule {} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/upgrade-version-command.module.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/upgrade-version-command.module.ts index 25eb635cf9570..07fd82f608045 100644 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/upgrade-version-command.module.ts +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/upgrade-version-command.module.ts @@ -3,6 +3,7 @@ import { TypeOrmModule } from '@nestjs/typeorm'; import { V1_10_UpgradeVersionCommandModule } from 'src/database/commands/upgrade-version-command/1-10/1-10-upgrade-version-command.module'; import { V1_11_UpgradeVersionCommandModule } from 'src/database/commands/upgrade-version-command/1-11/1-11-upgrade-version-command.module'; +import { V1_12_UpgradeVersionCommandModule } from 'src/database/commands/upgrade-version-command/1-12/1-12-upgrade-version-command.module'; import { V1_6_UpgradeVersionCommandModule } from 'src/database/commands/upgrade-version-command/1-6/1-6-upgrade-version-command.module'; import { V1_7_UpgradeVersionCommandModule } from 'src/database/commands/upgrade-version-command/1-7/1-7-upgrade-version-command.module'; import { V1_8_UpgradeVersionCommandModule } from 'src/database/commands/upgrade-version-command/1-8/1-8-upgrade-version-command.module'; diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/upgrade.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/upgrade.command.ts index 50985f8493f27..0d930992a603d 100644 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/upgrade.command.ts +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/upgrade.command.ts @@ -18,10 +18,11 @@ import { MigrateAttachmentAuthorToCreatedByCommand } from 'src/database/commands import { MigrateAttachmentTypeToFileCategoryCommand } from 'src/database/commands/upgrade-version-command/1-10/1-10-migrate-attachment-type-to-file-category.command'; import { MigrateChannelPartialFullSyncStagesCommand } from 'src/database/commands/upgrade-version-command/1-10/1-10-migrate-channel-partial-full-sync-stages.command'; import { RegenerateSearchVectorsCommand } from 'src/database/commands/upgrade-version-command/1-10/1-10-regenerate-search-vectors.command'; -import { SeedDashboardViewCommand } from 'src/database/commands/upgrade-version-command/1-10/1-10-seed-dashboard-view.command'; import { CleanOrphanedRoleTargetsCommand } from 'src/database/commands/upgrade-version-command/1-11/1-11-clean-orphaned-role-targets.command'; import { CleanOrphanedUserWorkspacesCommand } from 'src/database/commands/upgrade-version-command/1-11/1-11-clean-orphaned-user-workspaces.command'; import { CreateTwentyStandardApplicationCommand } from 'src/database/commands/upgrade-version-command/1-11/1-11-create-twenty-standard-application.command'; +import { CreateWorkspaceCustomApplicationCommand } from 'src/database/commands/upgrade-version-command/1-12/1-12-create-workspace-custom-application.command'; +import { SetStandardApplicationNotUninstallableCommand } from 'src/database/commands/upgrade-version-command/1-12/1-12-set-standard-application-not-uninstallable.command'; import { FixLabelIdentifierPositionAndVisibilityCommand } from 'src/database/commands/upgrade-version-command/1-6/1-6-fix-label-identifier-position-and-visibility.command'; import { BackfillWorkflowManualTriggerAvailabilityCommand } from 'src/database/commands/upgrade-version-command/1-7/1-7-backfill-workflow-manual-trigger-availability.command'; import { DeduplicateUniqueFieldsCommand } from 'src/database/commands/upgrade-version-command/1-8/1-8-deduplicate-unique-fields.command'; @@ -33,7 +34,6 @@ import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twent import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager'; import { SyncWorkspaceMetadataCommand } from 'src/engine/workspace-manager/workspace-sync-metadata/commands/sync-workspace-metadata.command'; -import { SetStandardApplicationNotUninstallableCommand } from 'src/database/commands/upgrade-version-command/1-12/1-12-set-standard-application-not-uninstallable.command'; @Command({ name: 'upgrade', @@ -70,7 +70,6 @@ export class UpgradeCommand extends UpgradeCommandRunner { protected readonly cleanOrphanedKanbanAggregateOperationFieldMetadataIdCommand: CleanOrphanedKanbanAggregateOperationFieldMetadataIdCommand, protected readonly migrateChannelPartialFullSyncStagesCommand: MigrateChannelPartialFullSyncStagesCommand, protected readonly makeSureDashboardNamingAvailableCommand: MakeSureDashboardNamingAvailableCommand, - protected readonly seedDashboardViewCommand: SeedDashboardViewCommand, protected readonly createViewKanbanFieldMetadataIdForeignKeyMigrationCommand: CreateViewKanbanFieldMetadataIdForeignKeyMigrationCommand, protected readonly flushWorkspaceCacheCommand: FlushCacheCommand, @@ -81,6 +80,8 @@ export class UpgradeCommand extends UpgradeCommandRunner { // 1.12 Commands protected readonlysetStandardApplicationNotUninstallableCommand: SetStandardApplicationNotUninstallableCommand, + protected readonly createTwentyStandardApplicationCommand: CreateTwentyStandardApplicationCommand, + protected readonly createWorkspaceCustomApplicationCommand: CreateWorkspaceCustomApplicationCommand, ) { super( workspaceRepository, @@ -124,13 +125,12 @@ export class UpgradeCommand extends UpgradeCommandRunner { afterSyncMetadata: [ this.migrateAttachmentAuthorToCreatedByCommand, this.migrateAttachmentTypeToFileCategoryCommand, - this.seedDashboardViewCommand, this.flushWorkspaceCacheCommand, ], }; const commands_1110: VersionCommands = { - beforeSyncMetadata: [this.seedStandardApplicationsCommand], + beforeSyncMetadata: [this.createTwentyStandardApplicationCommand], afterSyncMetadata: [ this.cleanOrphanedUserWorkspacesCommand, this.cleanOrphanedRoleTargetsCommand, @@ -138,7 +138,7 @@ export class UpgradeCommand extends UpgradeCommandRunner { }; const commands_1120: VersionCommands = { - beforeSyncMetadata: [], + beforeSyncMetadata: [this.createWorkspaceCustomApplicationCommand], afterSyncMetadata: [ this.readonlysetStandardApplicationNotUninstallableCommand, ], diff --git a/packages/twenty-server/src/engine/core-modules/application/application-sync.module.ts b/packages/twenty-server/src/engine/core-modules/application/application-sync.module.ts new file mode 100644 index 0000000000000..e7ee0e91cfd09 --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/application/application-sync.module.ts @@ -0,0 +1,38 @@ +import { Module } from '@nestjs/common'; + +import { ApplicationResolver } from 'src/engine/core-modules/application/application.resolver'; +import { ApplicationSyncService } from 'src/engine/core-modules/application/application-sync.service'; +import { ApplicationModule } from 'src/engine/core-modules/application/application.module'; +import { ApplicationVariableEntityModule } from 'src/engine/core-modules/applicationVariable/application-variable.module'; +import { CronTriggerModule } from 'src/engine/metadata-modules/cron-trigger/cron-trigger.module'; +import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module'; +import { DatabaseEventTriggerModule } from 'src/engine/metadata-modules/database-event-trigger/database-event-trigger.module'; +import { FieldMetadataModule } from 'src/engine/metadata-modules/field-metadata/field-metadata.module'; +import { WorkspaceManyOrAllFlatEntityMapsCacheModule } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.module'; +import { ObjectMetadataModule } from 'src/engine/metadata-modules/object-metadata/object-metadata.module'; +import { PermissionsModule } from 'src/engine/metadata-modules/permissions/permissions.module'; +import { RouteTriggerModule } from 'src/engine/metadata-modules/route-trigger/route-trigger.module'; +import { ServerlessFunctionLayerModule } from 'src/engine/metadata-modules/serverless-function-layer/serverless-function-layer.module'; +import { ServerlessFunctionModule } from 'src/engine/metadata-modules/serverless-function/serverless-function.module'; +import { WorkspaceMigrationV2Module } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-v2.module'; + +@Module({ + imports: [ + ApplicationModule, + ApplicationVariableEntityModule, + WorkspaceManyOrAllFlatEntityMapsCacheModule, + ObjectMetadataModule, + FieldMetadataModule, + DataSourceModule, + ServerlessFunctionLayerModule, + ServerlessFunctionModule, + DatabaseEventTriggerModule, + CronTriggerModule, + RouteTriggerModule, + WorkspaceMigrationV2Module, + PermissionsModule, + ], + providers: [ApplicationResolver, ApplicationSyncService], + exports: [ApplicationSyncService], +}) +export class ApplicationSyncModule {} diff --git a/packages/twenty-server/src/engine/core-modules/application/application.module.ts b/packages/twenty-server/src/engine/core-modules/application/application.module.ts index dfb8f7290e7b3..97bb5da309a88 100644 --- a/packages/twenty-server/src/engine/core-modules/application/application.module.ts +++ b/packages/twenty-server/src/engine/core-modules/application/application.module.ts @@ -1,42 +1,19 @@ import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; -import { ApplicationSyncService } from 'src/engine/core-modules/application/application-sync.service'; import { ApplicationEntity } from 'src/engine/core-modules/application/application.entity'; -import { ApplicationResolver } from 'src/engine/core-modules/application/application.resolver'; import { ApplicationService } from 'src/engine/core-modules/application/application.service'; -import { ApplicationVariableEntityModule } from 'src/engine/core-modules/applicationVariable/application-variable.module'; +import { WorkspaceFlatApplicationMapCacheService } from 'src/engine/core-modules/application/services/workspace-flat-application-map-cache.service'; import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; import { AgentEntity } from 'src/engine/metadata-modules/agent/agent.entity'; -import { CronTriggerModule } from 'src/engine/metadata-modules/cron-trigger/cron-trigger.module'; -import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module'; -import { DatabaseEventTriggerModule } from 'src/engine/metadata-modules/database-event-trigger/database-event-trigger.module'; import { WorkspaceManyOrAllFlatEntityMapsCacheModule } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.module'; -import { ObjectMetadataModule } from 'src/engine/metadata-modules/object-metadata/object-metadata.module'; -import { PermissionsModule } from 'src/engine/metadata-modules/permissions/permissions.module'; -import { RouteTriggerModule } from 'src/engine/metadata-modules/route-trigger/route-trigger.module'; -import { ServerlessFunctionLayerModule } from 'src/engine/metadata-modules/serverless-function-layer/serverless-function-layer.module'; -import { ServerlessFunctionModule } from 'src/engine/metadata-modules/serverless-function/serverless-function.module'; -import { WorkspaceMigrationV2Module } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-v2.module'; -import { FieldMetadataModule } from 'src/engine/metadata-modules/field-metadata/field-metadata.module'; @Module({ imports: [ TypeOrmModule.forFeature([ApplicationEntity, AgentEntity, WorkspaceEntity]), WorkspaceManyOrAllFlatEntityMapsCacheModule, - ObjectMetadataModule, - FieldMetadataModule, - DataSourceModule, - ApplicationVariableEntityModule, - ServerlessFunctionLayerModule, - ServerlessFunctionModule, - DatabaseEventTriggerModule, - CronTriggerModule, - RouteTriggerModule, - WorkspaceMigrationV2Module, - PermissionsModule, ], - exports: [ApplicationService], - providers: [ApplicationResolver, ApplicationService, ApplicationSyncService], + exports: [ApplicationService, WorkspaceFlatApplicationMapCacheService], + providers: [ApplicationService, WorkspaceFlatApplicationMapCacheService], }) export class ApplicationModule {} diff --git a/packages/twenty-server/src/engine/core-modules/application/application.service.ts b/packages/twenty-server/src/engine/core-modules/application/application.service.ts index 3311019bcbe12..b9f3c322f2767 100644 --- a/packages/twenty-server/src/engine/core-modules/application/application.service.ts +++ b/packages/twenty-server/src/engine/core-modules/application/application.service.ts @@ -3,23 +3,86 @@ import { InjectRepository } from '@nestjs/typeorm'; import { isDefined } from 'twenty-shared/utils'; import { type QueryRunner, Repository } from 'typeorm'; +import { v4 } from 'uuid'; import { ApplicationEntity } from 'src/engine/core-modules/application/application.entity'; import { ApplicationException, ApplicationExceptionCode, } from 'src/engine/core-modules/application/application.exception'; +import { TWENTY_STANDARD_APPLICATION } from 'src/engine/core-modules/application/constants/twenty-standard-applications'; +import { WorkspaceFlatApplicationMapCacheService } from 'src/engine/core-modules/application/services/workspace-flat-application-map-cache.service'; +import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service'; -import { TWENTY_STANDARD_APPLICATION } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/twenty-standard-applications'; @Injectable() export class ApplicationService { constructor( @InjectRepository(ApplicationEntity) private readonly applicationRepository: Repository, - private readonly flatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService, + private readonly workspaceManyOrAllFlatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService, + private readonly workspaceFlatApplicationMapCacheService: WorkspaceFlatApplicationMapCacheService, + @InjectRepository(WorkspaceEntity) + private readonly workspaceRepository: Repository, ) {} + async findWorkspaceTwentyStandardAndCustomApplicationOrThrow({ + workspaceId, + }: { + workspaceId: string; + }) { + const workspace = await this.workspaceRepository.findOne({ + where: { + id: workspaceId, + }, + }); + + if (!isDefined(workspace)) { + throw new ApplicationException( + `Could not find workspace ${workspaceId}`, + ApplicationExceptionCode.APPLICATION_NOT_FOUND, + ); + } + + const flatApplicationMaps = + await this.workspaceFlatApplicationMapCacheService.getExistingOrRecomputeFlatMaps( + { + workspaceId, + }, + ); + const twentyStandardApplicationId = + flatApplicationMaps.idByUniversalIdentifier[ + TWENTY_STANDARD_APPLICATION.universalIdentifier + ]; + + if (!isDefined(twentyStandardApplicationId)) { + throw new ApplicationException( + `Could not find workspace twenty standard applicationId in cache ${workspaceId}`, + ApplicationExceptionCode.APPLICATION_NOT_FOUND, + ); + } + + const twentyStandardFlatApplication = + flatApplicationMaps.byId[twentyStandardApplicationId]; + const workspaceCustomFlatApplication = + flatApplicationMaps.byId[workspace.workspaceCustomApplicationId]; + + if ( + !isDefined(twentyStandardFlatApplication) || + !isDefined(workspaceCustomFlatApplication) + ) { + throw new ApplicationException( + `Could not find workspace custom and standard applications ${workspace.id}`, + ApplicationExceptionCode.APPLICATION_NOT_FOUND, + ); + } + + return { + twentyStandardFlatApplication, + workspaceCustomFlatApplication, + }; + } + async findManyApplications( workspaceId: string, ): Promise { @@ -82,12 +145,14 @@ export class ApplicationService { async createTwentyStandardApplication( { workspaceId, + skipCacheInvalidation = false, }: { workspaceId: string; + skipCacheInvalidation?: boolean; }, queryRunner?: QueryRunner, ) { - return await this.create( + const twentyStandardApplication = await this.create( { ...TWENTY_STANDARD_APPLICATION, serverlessFunctionLayerId: null, @@ -95,10 +160,47 @@ export class ApplicationService { }, queryRunner, ); + + if (!skipCacheInvalidation) { + await this.workspaceFlatApplicationMapCacheService.invalidateCache({ + workspaceId, + }); + } + + return twentyStandardApplication; + } + + async createWorkspaceCustomApplication( + { + workspaceId, + workspaceDisplayName, + }: { + workspaceId: string; + workspaceDisplayName?: string; + }, + queryRunner?: QueryRunner, + ) { + const applicationId = v4(); + const workspaceCustomApplication = await this.create( + { + description: 'Workspace custom application', + name: `${isDefined(workspaceDisplayName) ? workspaceDisplayName : 'Workspace'}'s custom application`, + sourcePath: 'workspace-custom', + version: '1.0.0', + universalIdentifier: applicationId, + workspaceId: workspaceId, + id: applicationId, + serverlessFunctionLayerId: null, + }, + queryRunner, + ); + + return workspaceCustomApplication; } async create( data: { + id?: string; universalIdentifier?: string; name: string; description?: string; @@ -118,7 +220,13 @@ export class ApplicationService { return queryRunner.manager.save(ApplicationEntity, application); } - return this.applicationRepository.save(application); + const savedApplication = await this.applicationRepository.save(application); + + await this.workspaceFlatApplicationMapCacheService.invalidateCache({ + workspaceId: data.workspaceId, + }); + + return savedApplication; } async update( @@ -127,6 +235,10 @@ export class ApplicationService { ): Promise { await this.applicationRepository.update({ id }, data); + await this.workspaceFlatApplicationMapCacheService.invalidateCache({ + workspaceId: data.workspaceId as string, + }); + const updatedApplication = await this.findById(id); if (!updatedApplication) { @@ -151,8 +263,14 @@ export class ApplicationService { workspaceId, }); - await this.flatEntityMapsCacheService.invalidateFlatEntityMaps({ + await this.workspaceFlatApplicationMapCacheService.invalidateCache({ workspaceId, }); + + await this.workspaceManyOrAllFlatEntityMapsCacheService.invalidateFlatEntityMaps( + { + workspaceId, + }, + ); } } diff --git a/packages/twenty-server/src/engine/core-modules/application/constants/application-entity-relation-properties.constant.ts b/packages/twenty-server/src/engine/core-modules/application/constants/application-entity-relation-properties.constant.ts new file mode 100644 index 0000000000000..373dc2bbde3f1 --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/application/constants/application-entity-relation-properties.constant.ts @@ -0,0 +1,9 @@ +import { type ApplicationEntity } from 'src/engine/core-modules/application/application.entity'; + +export const APPLICATION_ENTITY_RELATION_PROPERTIES = [ + 'workspace', + 'agents', + 'serverlessFunctions', + 'objects', + 'applicationVariables', +] as const satisfies (keyof ApplicationEntity)[]; diff --git a/packages/twenty-server/src/engine/core-modules/application/constants/standard-object.constant.ts b/packages/twenty-server/src/engine/core-modules/application/constants/standard-object.constant.ts new file mode 100644 index 0000000000000..45688d35d3da8 --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/application/constants/standard-object.constant.ts @@ -0,0 +1,1918 @@ +import { + ATTACHMENT_STANDARD_FIELD_IDS, + BLOCKLIST_STANDARD_FIELD_IDS, + CALENDAR_CHANNEL_EVENT_ASSOCIATION_STANDARD_FIELD_IDS, + CALENDAR_CHANNEL_STANDARD_FIELD_IDS, + CALENDAR_EVENT_PARTICIPANT_STANDARD_FIELD_IDS, + CALENDAR_EVENT_STANDARD_FIELD_IDS, + COMPANY_STANDARD_FIELD_IDS, + CONNECTED_ACCOUNT_STANDARD_FIELD_IDS, + DASHBOARD_STANDARD_FIELD_IDS, + FAVORITE_FOLDER_STANDARD_FIELD_IDS, + FAVORITE_STANDARD_FIELD_IDS, + MESSAGE_CHANNEL_MESSAGE_ASSOCIATION_STANDARD_FIELD_IDS, + MESSAGE_CHANNEL_STANDARD_FIELD_IDS, + MESSAGE_FOLDER_STANDARD_FIELD_IDS, + MESSAGE_PARTICIPANT_STANDARD_FIELD_IDS, + MESSAGE_STANDARD_FIELD_IDS, + MESSAGE_THREAD_STANDARD_FIELD_IDS, + NOTE_STANDARD_FIELD_IDS, + NOTE_TARGET_STANDARD_FIELD_IDS, + OPPORTUNITY_STANDARD_FIELD_IDS, + PERSON_STANDARD_FIELD_IDS, + TASK_STANDARD_FIELD_IDS, + TASK_TARGET_STANDARD_FIELD_IDS, + TIMELINE_ACTIVITY_STANDARD_FIELD_IDS, + VIEW_FIELD_STANDARD_FIELD_IDS, + VIEW_FILTER_GROUP_STANDARD_FIELD_IDS, + VIEW_FILTER_STANDARD_FIELD_IDS, + VIEW_GROUP_STANDARD_FIELD_IDS, + VIEW_SORT_STANDARD_FIELD_IDS, + VIEW_STANDARD_FIELD_IDS, + WORKFLOW_AUTOMATED_TRIGGER_STANDARD_FIELD_IDS, + WORKFLOW_RUN_STANDARD_FIELD_IDS, + WORKFLOW_STANDARD_FIELD_IDS, + WORKFLOW_VERSION_STANDARD_FIELD_IDS, + WORKSPACE_MEMBER_STANDARD_FIELD_IDS, +} from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids'; +import { STANDARD_OBJECT_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-object-ids'; + +export const STANDARD_OBJECTS = { + attachment: { + universalIdentifier: STANDARD_OBJECT_IDS.attachment, + fields: { + id: { universalIdentifier: '20202020-a01a-4001-8a01-1d5f8e3c7b2a' }, + createdAt: { + universalIdentifier: '20202020-a01b-4002-9b02-2e6f9f4d8c3b', + }, + updatedAt: { + universalIdentifier: '20202020-a01c-4003-8c03-3f7fa05d9d4c', + }, + deletedAt: { + universalIdentifier: '20202020-a01d-4004-9d04-4f8fb16eae5d', + }, + name: { universalIdentifier: ATTACHMENT_STANDARD_FIELD_IDS.name }, + fullPath: { universalIdentifier: ATTACHMENT_STANDARD_FIELD_IDS.fullPath }, + type: { universalIdentifier: ATTACHMENT_STANDARD_FIELD_IDS.type }, + fileCategory: { + universalIdentifier: ATTACHMENT_STANDARD_FIELD_IDS.fileCategory, + }, + createdBy: { + universalIdentifier: ATTACHMENT_STANDARD_FIELD_IDS.createdBy, + }, + author: { universalIdentifier: ATTACHMENT_STANDARD_FIELD_IDS.author }, + activity: { universalIdentifier: ATTACHMENT_STANDARD_FIELD_IDS.activity }, + task: { universalIdentifier: ATTACHMENT_STANDARD_FIELD_IDS.task }, + note: { universalIdentifier: ATTACHMENT_STANDARD_FIELD_IDS.note }, + person: { universalIdentifier: ATTACHMENT_STANDARD_FIELD_IDS.person }, + company: { universalIdentifier: ATTACHMENT_STANDARD_FIELD_IDS.company }, + opportunity: { + universalIdentifier: ATTACHMENT_STANDARD_FIELD_IDS.opportunity, + }, + dashboard: { + universalIdentifier: ATTACHMENT_STANDARD_FIELD_IDS.dashboard, + }, + workflow: { universalIdentifier: ATTACHMENT_STANDARD_FIELD_IDS.workflow }, + custom: { universalIdentifier: ATTACHMENT_STANDARD_FIELD_IDS.custom }, + }, + views: {}, + }, + blocklist: { + universalIdentifier: STANDARD_OBJECT_IDS.blocklist, + fields: { + id: { universalIdentifier: '20202020-b01a-4011-8b11-5a9fc27fbf6e' }, + createdAt: { + universalIdentifier: '20202020-b01b-4012-9c12-6bafd38fcf7f', + }, + updatedAt: { + universalIdentifier: '20202020-b01c-4013-8d13-7cbfe49fdf8f', + }, + deletedAt: { + universalIdentifier: '20202020-b01d-4014-9e14-8dcff5affef9', + }, + handle: { universalIdentifier: BLOCKLIST_STANDARD_FIELD_IDS.handle }, + workspaceMember: { + universalIdentifier: BLOCKLIST_STANDARD_FIELD_IDS.workspaceMember, + }, + }, + views: {}, + }, + calendarChannelEventAssociation: { + universalIdentifier: STANDARD_OBJECT_IDS.calendarChannelEventAssociation, + fields: { + id: { + universalIdentifier: '20202020-c01a-4021-8a21-9edf06bfef0a', + }, + createdAt: { + universalIdentifier: '20202020-c01b-4022-9b22-afefd7cffefb', + }, + updatedAt: { + universalIdentifier: '20202020-c01c-4023-8c23-bffef8dffef0', + }, + deletedAt: { + universalIdentifier: '20202020-c01d-4024-9d24-cffef9effef1', + }, + calendarChannel: { + universalIdentifier: + CALENDAR_CHANNEL_EVENT_ASSOCIATION_STANDARD_FIELD_IDS.calendarChannel, + }, + calendarEvent: { + universalIdentifier: + CALENDAR_CHANNEL_EVENT_ASSOCIATION_STANDARD_FIELD_IDS.calendarEvent, + }, + eventExternalId: { + universalIdentifier: + CALENDAR_CHANNEL_EVENT_ASSOCIATION_STANDARD_FIELD_IDS.eventExternalId, + }, + recurringEventExternalId: { + universalIdentifier: + CALENDAR_CHANNEL_EVENT_ASSOCIATION_STANDARD_FIELD_IDS.recurringEventExternalId, + }, + }, + views: {}, + }, + calendarChannel: { + universalIdentifier: STANDARD_OBJECT_IDS.calendarChannel, + fields: { + id: { universalIdentifier: '20202020-c02a-4031-8a31-1a2f3b4c5d6e' }, + createdAt: { + universalIdentifier: '20202020-c02b-4032-9b32-2b3f4c5d6e7f', + }, + updatedAt: { + universalIdentifier: '20202020-c02c-4033-8c33-3c4f5d6e7f8a', + }, + deletedAt: { + universalIdentifier: '20202020-c02d-4034-9d34-4d5f6e7f8a9b', + }, + connectedAccount: { + universalIdentifier: + CALENDAR_CHANNEL_STANDARD_FIELD_IDS.connectedAccount, + }, + handle: { + universalIdentifier: CALENDAR_CHANNEL_STANDARD_FIELD_IDS.handle, + }, + visibility: { + universalIdentifier: CALENDAR_CHANNEL_STANDARD_FIELD_IDS.visibility, + }, + isContactAutoCreationEnabled: { + universalIdentifier: + CALENDAR_CHANNEL_STANDARD_FIELD_IDS.isContactAutoCreationEnabled, + }, + contactAutoCreationPolicy: { + universalIdentifier: + CALENDAR_CHANNEL_STANDARD_FIELD_IDS.contactAutoCreationPolicy, + }, + isSyncEnabled: { + universalIdentifier: CALENDAR_CHANNEL_STANDARD_FIELD_IDS.isSyncEnabled, + }, + syncCursor: { + universalIdentifier: CALENDAR_CHANNEL_STANDARD_FIELD_IDS.syncCursor, + }, + calendarChannelEventAssociations: { + universalIdentifier: + CALENDAR_CHANNEL_STANDARD_FIELD_IDS.calendarChannelEventAssociations, + }, + throttleFailureCount: { + universalIdentifier: + CALENDAR_CHANNEL_STANDARD_FIELD_IDS.throttleFailureCount, + }, + syncStatus: { + universalIdentifier: CALENDAR_CHANNEL_STANDARD_FIELD_IDS.syncStatus, + }, + syncStage: { + universalIdentifier: CALENDAR_CHANNEL_STANDARD_FIELD_IDS.syncStage, + }, + syncStageStartedAt: { + universalIdentifier: + CALENDAR_CHANNEL_STANDARD_FIELD_IDS.syncStageStartedAt, + }, + syncedAt: { + universalIdentifier: CALENDAR_CHANNEL_STANDARD_FIELD_IDS.syncedAt, + }, + }, + views: {}, + }, + calendarEventParticipant: { + universalIdentifier: STANDARD_OBJECT_IDS.calendarEventParticipant, + fields: { + id: { + universalIdentifier: '20202020-c03a-4041-8a41-5e6f7a8b9cad', + }, + createdAt: { + universalIdentifier: '20202020-c03b-4042-9b42-6f7a8b9cadbe', + }, + updatedAt: { + universalIdentifier: '20202020-c03c-4043-8c43-7a8b9cadbecf', + }, + deletedAt: { + universalIdentifier: '20202020-c03d-4044-9d44-8b9cadbecd0f', + }, + calendarEvent: { + universalIdentifier: + CALENDAR_EVENT_PARTICIPANT_STANDARD_FIELD_IDS.calendarEvent, + }, + handle: { + universalIdentifier: + CALENDAR_EVENT_PARTICIPANT_STANDARD_FIELD_IDS.handle, + }, + displayName: { + universalIdentifier: + CALENDAR_EVENT_PARTICIPANT_STANDARD_FIELD_IDS.displayName, + }, + isOrganizer: { + universalIdentifier: + CALENDAR_EVENT_PARTICIPANT_STANDARD_FIELD_IDS.isOrganizer, + }, + responseStatus: { + universalIdentifier: + CALENDAR_EVENT_PARTICIPANT_STANDARD_FIELD_IDS.responseStatus, + }, + person: { + universalIdentifier: + CALENDAR_EVENT_PARTICIPANT_STANDARD_FIELD_IDS.person, + }, + workspaceMember: { + universalIdentifier: + CALENDAR_EVENT_PARTICIPANT_STANDARD_FIELD_IDS.workspaceMember, + }, + }, + views: {}, + }, + calendarEvent: { + universalIdentifier: STANDARD_OBJECT_IDS.calendarEvent, + fields: { + id: { universalIdentifier: '20202020-c04a-4051-8a51-9cadbe0f1e2d' }, + createdAt: { + universalIdentifier: '20202020-c04b-4052-9b52-adbecf1f2e3e', + }, + updatedAt: { + universalIdentifier: '20202020-c04c-4053-8c53-becf0f2f3e4f', + }, + deletedAt: { + universalIdentifier: '20202020-c04d-4054-9d54-cd0f1f3f4e5f', + }, + title: { universalIdentifier: CALENDAR_EVENT_STANDARD_FIELD_IDS.title }, + isCanceled: { + universalIdentifier: CALENDAR_EVENT_STANDARD_FIELD_IDS.isCanceled, + }, + isFullDay: { + universalIdentifier: CALENDAR_EVENT_STANDARD_FIELD_IDS.isFullDay, + }, + startsAt: { + universalIdentifier: CALENDAR_EVENT_STANDARD_FIELD_IDS.startsAt, + }, + endsAt: { universalIdentifier: CALENDAR_EVENT_STANDARD_FIELD_IDS.endsAt }, + externalCreatedAt: { + universalIdentifier: + CALENDAR_EVENT_STANDARD_FIELD_IDS.externalCreatedAt, + }, + externalUpdatedAt: { + universalIdentifier: + CALENDAR_EVENT_STANDARD_FIELD_IDS.externalUpdatedAt, + }, + description: { + universalIdentifier: CALENDAR_EVENT_STANDARD_FIELD_IDS.description, + }, + location: { + universalIdentifier: CALENDAR_EVENT_STANDARD_FIELD_IDS.location, + }, + iCalUID: { + universalIdentifier: CALENDAR_EVENT_STANDARD_FIELD_IDS.iCalUID, + }, + conferenceSolution: { + universalIdentifier: + CALENDAR_EVENT_STANDARD_FIELD_IDS.conferenceSolution, + }, + conferenceLink: { + universalIdentifier: CALENDAR_EVENT_STANDARD_FIELD_IDS.conferenceLink, + }, + calendarChannelEventAssociations: { + universalIdentifier: + CALENDAR_EVENT_STANDARD_FIELD_IDS.calendarChannelEventAssociations, + }, + calendarEventParticipants: { + universalIdentifier: + CALENDAR_EVENT_STANDARD_FIELD_IDS.calendarEventParticipants, + }, + }, + views: { + allCalendarEvents: { + universalIdentifier: '20202020-c001-4c01-8c01-ca1ebe0ca001', + viewFields: { + title: { + universalIdentifier: '20202020-cf01-4c01-8c01-ca1ebe0caf01', + }, + startsAt: { + universalIdentifier: '20202020-cf01-4c01-8c01-ca1ebe0caf02', + }, + endsAt: { + universalIdentifier: '20202020-cf01-4c01-8c01-ca1ebe0caf03', + }, + isFullDay: { + universalIdentifier: '20202020-cf01-4c01-8c01-ca1ebe0caf04', + }, + location: { + universalIdentifier: '20202020-cf01-4c01-8c01-ca1ebe0caf05', + }, + conferenceLink: { + universalIdentifier: '20202020-cf01-4c01-8c01-ca1ebe0caf06', + }, + isCanceled: { + universalIdentifier: '20202020-cf01-4c01-8c01-ca1ebe0caf07', + }, + createdAt: { + universalIdentifier: '20202020-cf01-4c01-8c01-ca1ebe0caf08', + }, + }, + }, + }, + }, + company: { + universalIdentifier: STANDARD_OBJECT_IDS.company, + fields: { + id: { universalIdentifier: '20202020-c05a-4061-8a61-1e2f3a4b5c6d' }, + createdAt: { + universalIdentifier: '20202020-c05b-4062-9b62-2f3a4b5c6d7e', + }, + updatedAt: { + universalIdentifier: '20202020-c05c-4063-8c63-3a4b5c6d7e8f', + }, + deletedAt: { + universalIdentifier: '20202020-c05d-4064-9d64-4b5c6d7e8f9a', + }, + name: { universalIdentifier: COMPANY_STANDARD_FIELD_IDS.name }, + domainName: { + universalIdentifier: COMPANY_STANDARD_FIELD_IDS.domainName, + }, + address: { universalIdentifier: COMPANY_STANDARD_FIELD_IDS.address }, + addressOld: { + universalIdentifier: COMPANY_STANDARD_FIELD_IDS.address_deprecated, + }, + employees: { universalIdentifier: COMPANY_STANDARD_FIELD_IDS.employees }, + linkedinLink: { + universalIdentifier: COMPANY_STANDARD_FIELD_IDS.linkedinLink, + }, + xLink: { universalIdentifier: COMPANY_STANDARD_FIELD_IDS.xLink }, + annualRecurringRevenue: { + universalIdentifier: COMPANY_STANDARD_FIELD_IDS.annualRecurringRevenue, + }, + idealCustomerProfile: { + universalIdentifier: COMPANY_STANDARD_FIELD_IDS.idealCustomerProfile, + }, + position: { universalIdentifier: COMPANY_STANDARD_FIELD_IDS.position }, + createdBy: { universalIdentifier: COMPANY_STANDARD_FIELD_IDS.createdBy }, + people: { universalIdentifier: COMPANY_STANDARD_FIELD_IDS.people }, + accountOwner: { + universalIdentifier: COMPANY_STANDARD_FIELD_IDS.accountOwner, + }, + taskTargets: { + universalIdentifier: COMPANY_STANDARD_FIELD_IDS.taskTargets, + }, + noteTargets: { + universalIdentifier: COMPANY_STANDARD_FIELD_IDS.noteTargets, + }, + opportunities: { + universalIdentifier: COMPANY_STANDARD_FIELD_IDS.opportunities, + }, + favorites: { universalIdentifier: COMPANY_STANDARD_FIELD_IDS.favorites }, + attachments: { + universalIdentifier: COMPANY_STANDARD_FIELD_IDS.attachments, + }, + timelineActivities: { + universalIdentifier: COMPANY_STANDARD_FIELD_IDS.timelineActivities, + }, + searchVector: { + universalIdentifier: COMPANY_STANDARD_FIELD_IDS.searchVector, + }, + }, + views: { + allCompanies: { + universalIdentifier: '20202020-a001-4a01-8a01-c0aba11c0001', + viewFields: { + name: { + universalIdentifier: '20202020-af01-4a01-8a01-c0aba11cf001', + }, + domainName: { + universalIdentifier: '20202020-af01-4a01-8a01-c0aba11cf002', + }, + createdBy: { + universalIdentifier: '20202020-af01-4a01-8a01-c0aba11cf003', + }, + accountOwner: { + universalIdentifier: '20202020-af01-4a01-8a01-c0aba11cf004', + }, + createdAt: { + universalIdentifier: '20202020-af01-4a01-8a01-c0aba11cf005', + }, + employees: { + universalIdentifier: '20202020-af01-4a01-8a01-c0aba11cf006', + }, + linkedinLink: { + universalIdentifier: '20202020-af01-4a01-8a01-c0aba11cf007', + }, + address: { + universalIdentifier: '20202020-af01-4a01-8a01-c0aba11cf008', + }, + }, + }, + }, + }, + connectedAccount: { + universalIdentifier: STANDARD_OBJECT_IDS.connectedAccount, + fields: { + id: { universalIdentifier: '20202020-c06a-4071-8a71-5c6d7e8f9aab' }, + createdAt: { + universalIdentifier: '20202020-c06b-4072-9b72-6d7e8f9aabbc', + }, + updatedAt: { + universalIdentifier: '20202020-c06c-4073-8c73-7e8f9aabbccd', + }, + deletedAt: { + universalIdentifier: '20202020-c06d-4074-9d74-8f9aabbccdde', + }, + handle: { + universalIdentifier: CONNECTED_ACCOUNT_STANDARD_FIELD_IDS.handle, + }, + provider: { + universalIdentifier: CONNECTED_ACCOUNT_STANDARD_FIELD_IDS.provider, + }, + accessToken: { + universalIdentifier: CONNECTED_ACCOUNT_STANDARD_FIELD_IDS.accessToken, + }, + refreshToken: { + universalIdentifier: CONNECTED_ACCOUNT_STANDARD_FIELD_IDS.refreshToken, + }, + accountOwner: { + universalIdentifier: CONNECTED_ACCOUNT_STANDARD_FIELD_IDS.accountOwner, + }, + lastSyncHistoryId: { + universalIdentifier: + CONNECTED_ACCOUNT_STANDARD_FIELD_IDS.lastSyncHistoryId, + }, + authFailedAt: { + universalIdentifier: CONNECTED_ACCOUNT_STANDARD_FIELD_IDS.authFailedAt, + }, + lastCredentialsRefreshedAt: { + universalIdentifier: + CONNECTED_ACCOUNT_STANDARD_FIELD_IDS.lastCredentialsRefreshedAt, + }, + messageChannels: { + universalIdentifier: + CONNECTED_ACCOUNT_STANDARD_FIELD_IDS.messageChannels, + }, + calendarChannels: { + universalIdentifier: + CONNECTED_ACCOUNT_STANDARD_FIELD_IDS.calendarChannels, + }, + handleAliases: { + universalIdentifier: CONNECTED_ACCOUNT_STANDARD_FIELD_IDS.handleAliases, + }, + scopes: { + universalIdentifier: CONNECTED_ACCOUNT_STANDARD_FIELD_IDS.scopes, + }, + connectionParameters: { + universalIdentifier: + CONNECTED_ACCOUNT_STANDARD_FIELD_IDS.connectionParameters, + }, + }, + views: {}, + }, + dashboard: { + universalIdentifier: STANDARD_OBJECT_IDS.dashboard, + fields: { + id: { universalIdentifier: '20202020-da1a-41d1-8ad1-abcdefabcdef' }, + createdAt: { + universalIdentifier: '20202020-da1b-41d2-9bd2-bcdefabcdefa', + }, + updatedAt: { + universalIdentifier: '20202020-da1c-41d3-8cd3-cdefabcdefab', + }, + deletedAt: { + universalIdentifier: '20202020-da1d-41d4-9dd4-defabcdefabc', + }, + title: { universalIdentifier: DASHBOARD_STANDARD_FIELD_IDS.title }, + position: { universalIdentifier: DASHBOARD_STANDARD_FIELD_IDS.position }, + pageLayoutId: { + universalIdentifier: DASHBOARD_STANDARD_FIELD_IDS.pageLayoutId, + }, + createdBy: { + universalIdentifier: DASHBOARD_STANDARD_FIELD_IDS.createdBy, + }, + timelineActivities: { + universalIdentifier: DASHBOARD_STANDARD_FIELD_IDS.timelineActivities, + }, + favorites: { + universalIdentifier: DASHBOARD_STANDARD_FIELD_IDS.favorites, + }, + attachments: { + universalIdentifier: DASHBOARD_STANDARD_FIELD_IDS.attachments, + }, + searchVector: { + universalIdentifier: DASHBOARD_STANDARD_FIELD_IDS.searchVector, + }, + }, + views: { + allDashboards: { + universalIdentifier: '20202020-a012-4a12-8a12-da5ab0b0a001', + viewFields: { + title: { + universalIdentifier: '20202020-af12-4a12-8a12-da5ab0b0af01', + }, + createdBy: { + universalIdentifier: '20202020-af12-4a12-8a12-da5ab0b0af02', + }, + createdAt: { + universalIdentifier: '20202020-af12-4a12-8a12-da5ab0b0af03', + }, + updatedAt: { + universalIdentifier: '20202020-af12-4a12-8a12-da5ab0b0af04', + }, + }, + }, + }, + }, + favorite: { + universalIdentifier: STANDARD_OBJECT_IDS.favorite, + fields: { + id: { universalIdentifier: '20202020-f01a-4091-8a91-ddeeffaabbcc' }, + createdAt: { + universalIdentifier: '20202020-f01b-4092-9b92-eeffaabbccdd', + }, + updatedAt: { + universalIdentifier: '20202020-f01c-4093-8c93-ffaabbccddee', + }, + deletedAt: { + universalIdentifier: '20202020-f01d-4094-9d94-aabbccddeeff', + }, + position: { universalIdentifier: FAVORITE_STANDARD_FIELD_IDS.position }, + forWorkspaceMember: { + universalIdentifier: FAVORITE_STANDARD_FIELD_IDS.forWorkspaceMember, + }, + person: { universalIdentifier: FAVORITE_STANDARD_FIELD_IDS.person }, + company: { universalIdentifier: FAVORITE_STANDARD_FIELD_IDS.company }, + opportunity: { + universalIdentifier: FAVORITE_STANDARD_FIELD_IDS.opportunity, + }, + workflow: { universalIdentifier: FAVORITE_STANDARD_FIELD_IDS.workflow }, + workflowVersion: { + universalIdentifier: FAVORITE_STANDARD_FIELD_IDS.workflowVersion, + }, + workflowRun: { + universalIdentifier: FAVORITE_STANDARD_FIELD_IDS.workflowRun, + }, + task: { universalIdentifier: FAVORITE_STANDARD_FIELD_IDS.task }, + note: { universalIdentifier: FAVORITE_STANDARD_FIELD_IDS.note }, + view: { universalIdentifier: FAVORITE_STANDARD_FIELD_IDS.view }, + custom: { universalIdentifier: FAVORITE_STANDARD_FIELD_IDS.custom }, + favoriteFolder: { + universalIdentifier: FAVORITE_STANDARD_FIELD_IDS.favoriteFolder, + }, + dashboard: { universalIdentifier: FAVORITE_STANDARD_FIELD_IDS.dashboard }, + }, + views: {}, + }, + favoriteFolder: { + universalIdentifier: STANDARD_OBJECT_IDS.favoriteFolder, + fields: { + id: { universalIdentifier: '20202020-f02a-40a1-8aa1-1f2e3d4c5b6a' }, + createdAt: { + universalIdentifier: '20202020-f02b-40a2-9ba2-2f3e4d5c6b7a', + }, + updatedAt: { + universalIdentifier: '20202020-f02c-40a3-8ca3-3f4e5d6c7b8a', + }, + deletedAt: { + universalIdentifier: '20202020-f02d-40a4-9da4-4f5e6d7c8b9a', + }, + position: { + universalIdentifier: FAVORITE_FOLDER_STANDARD_FIELD_IDS.position, + }, + name: { universalIdentifier: FAVORITE_FOLDER_STANDARD_FIELD_IDS.name }, + favorites: { + universalIdentifier: FAVORITE_FOLDER_STANDARD_FIELD_IDS.favorites, + }, + }, + views: {}, + }, + messageChannelMessageAssociation: { + universalIdentifier: STANDARD_OBJECT_IDS.messageChannelMessageAssociation, + fields: { + id: { + universalIdentifier: '20202020-b01a-40b1-8ab1-5a6b7c8d9eaf', + }, + createdAt: { + universalIdentifier: '20202020-b01b-40b2-9bb2-6b7c8d9eafba', + }, + updatedAt: { + universalIdentifier: '20202020-b01c-40b3-8cb3-7c8d9eafbacb', + }, + deletedAt: { + universalIdentifier: '20202020-b01d-40b4-9db4-8d9eafbacbdc', + }, + messageChannel: { + universalIdentifier: + MESSAGE_CHANNEL_MESSAGE_ASSOCIATION_STANDARD_FIELD_IDS.messageChannel, + }, + message: { + universalIdentifier: + MESSAGE_CHANNEL_MESSAGE_ASSOCIATION_STANDARD_FIELD_IDS.message, + }, + messageExternalId: { + universalIdentifier: + MESSAGE_CHANNEL_MESSAGE_ASSOCIATION_STANDARD_FIELD_IDS.messageExternalId, + }, + messageThread: { + universalIdentifier: + MESSAGE_CHANNEL_MESSAGE_ASSOCIATION_STANDARD_FIELD_IDS.messageThread, + }, + messageThreadExternalId: { + universalIdentifier: + MESSAGE_CHANNEL_MESSAGE_ASSOCIATION_STANDARD_FIELD_IDS.messageThreadExternalId, + }, + }, + views: {}, + }, + messageChannel: { + universalIdentifier: STANDARD_OBJECT_IDS.messageChannel, + fields: { + id: { universalIdentifier: '20202020-b02a-40c1-8ac1-9eafbacbdced' }, + createdAt: { + universalIdentifier: '20202020-b02b-40c2-9bc2-afbacbdcedfe', + }, + updatedAt: { + universalIdentifier: '20202020-b02c-40c3-8cc3-bacbdcedfefa', + }, + deletedAt: { + universalIdentifier: '20202020-b02d-40c4-9dc4-cbdcedfefaab', + }, + visibility: { + universalIdentifier: MESSAGE_CHANNEL_STANDARD_FIELD_IDS.visibility, + }, + handle: { + universalIdentifier: MESSAGE_CHANNEL_STANDARD_FIELD_IDS.handle, + }, + connectedAccount: { + universalIdentifier: + MESSAGE_CHANNEL_STANDARD_FIELD_IDS.connectedAccount, + }, + type: { universalIdentifier: MESSAGE_CHANNEL_STANDARD_FIELD_IDS.type }, + isContactAutoCreationEnabled: { + universalIdentifier: + MESSAGE_CHANNEL_STANDARD_FIELD_IDS.isContactAutoCreationEnabled, + }, + contactAutoCreationPolicy: { + universalIdentifier: + MESSAGE_CHANNEL_STANDARD_FIELD_IDS.contactAutoCreationPolicy, + }, + excludeNonProfessionalEmails: { + universalIdentifier: + MESSAGE_CHANNEL_STANDARD_FIELD_IDS.excludeNonProfessionalEmails, + }, + excludeGroupEmails: { + universalIdentifier: + MESSAGE_CHANNEL_STANDARD_FIELD_IDS.excludeGroupEmails, + }, + messageChannelMessageAssociations: { + universalIdentifier: + MESSAGE_CHANNEL_STANDARD_FIELD_IDS.messageChannelMessageAssociations, + }, + messageFolders: { + universalIdentifier: MESSAGE_CHANNEL_STANDARD_FIELD_IDS.messageFolders, + }, + messageFolderImportPolicy: { + universalIdentifier: + MESSAGE_CHANNEL_STANDARD_FIELD_IDS.messageFolderImportPolicy, + }, + pendingGroupEmailsAction: { + universalIdentifier: + MESSAGE_CHANNEL_STANDARD_FIELD_IDS.pendingGroupEmailsAction, + }, + isSyncEnabled: { + universalIdentifier: MESSAGE_CHANNEL_STANDARD_FIELD_IDS.isSyncEnabled, + }, + syncCursor: { + universalIdentifier: MESSAGE_CHANNEL_STANDARD_FIELD_IDS.syncCursor, + }, + syncedAt: { + universalIdentifier: MESSAGE_CHANNEL_STANDARD_FIELD_IDS.syncedAt, + }, + syncStatus: { + universalIdentifier: MESSAGE_CHANNEL_STANDARD_FIELD_IDS.syncStatus, + }, + syncStage: { + universalIdentifier: MESSAGE_CHANNEL_STANDARD_FIELD_IDS.syncStage, + }, + syncStageStartedAt: { + universalIdentifier: + MESSAGE_CHANNEL_STANDARD_FIELD_IDS.syncStageStartedAt, + }, + throttleFailureCount: { + universalIdentifier: + MESSAGE_CHANNEL_STANDARD_FIELD_IDS.throttleFailureCount, + }, + }, + views: {}, + }, + messageFolder: { + universalIdentifier: STANDARD_OBJECT_IDS.messageFolder, + fields: { + id: { universalIdentifier: '20202020-b03a-40d1-8ad1-dcedfefaabbc' }, + createdAt: { + universalIdentifier: '20202020-b03b-40d2-9bd2-edfefaabbccd', + }, + updatedAt: { + universalIdentifier: '20202020-b03c-40d3-8cd3-fefaabbccdde', + }, + deletedAt: { + universalIdentifier: '20202020-b03d-40d4-9dd4-faabbccddeef', + }, + name: { universalIdentifier: MESSAGE_FOLDER_STANDARD_FIELD_IDS.name }, + parentFolderId: { + universalIdentifier: MESSAGE_FOLDER_STANDARD_FIELD_IDS.parentFolderId, + }, + messageChannel: { + universalIdentifier: '20202020-c9f8-43db-a3e7-7f2e8b5d9c1a', + }, + syncCursor: { + universalIdentifier: MESSAGE_FOLDER_STANDARD_FIELD_IDS.syncCursor, + }, + isSentFolder: { + universalIdentifier: MESSAGE_FOLDER_STANDARD_FIELD_IDS.isSentFolder, + }, + isSynced: { + universalIdentifier: MESSAGE_FOLDER_STANDARD_FIELD_IDS.isSynced, + }, + externalId: { + universalIdentifier: MESSAGE_FOLDER_STANDARD_FIELD_IDS.externalId, + }, + pendingSyncAction: { + universalIdentifier: + MESSAGE_FOLDER_STANDARD_FIELD_IDS.pendingSyncAction, + }, + }, + views: {}, + }, + messageParticipant: { + universalIdentifier: STANDARD_OBJECT_IDS.messageParticipant, + fields: { + id: { universalIdentifier: '20202020-b04a-40e1-8ae1-1a2b3c4d5e6f' }, + createdAt: { + universalIdentifier: '20202020-b04b-40e2-9be2-2b3c4d5e6f7a', + }, + updatedAt: { + universalIdentifier: '20202020-b04c-40e3-8ce3-3c4d5e6f7a8b', + }, + deletedAt: { + universalIdentifier: '20202020-b04d-40e4-9de4-4d5e6f7a8b9c', + }, + message: { + universalIdentifier: MESSAGE_PARTICIPANT_STANDARD_FIELD_IDS.message, + }, + role: { + universalIdentifier: MESSAGE_PARTICIPANT_STANDARD_FIELD_IDS.role, + }, + handle: { + universalIdentifier: MESSAGE_PARTICIPANT_STANDARD_FIELD_IDS.handle, + }, + displayName: { + universalIdentifier: MESSAGE_PARTICIPANT_STANDARD_FIELD_IDS.displayName, + }, + person: { + universalIdentifier: MESSAGE_PARTICIPANT_STANDARD_FIELD_IDS.person, + }, + workspaceMember: { + universalIdentifier: + MESSAGE_PARTICIPANT_STANDARD_FIELD_IDS.workspaceMember, + }, + }, + views: {}, + }, + messageThread: { + universalIdentifier: STANDARD_OBJECT_IDS.messageThread, + fields: { + id: { universalIdentifier: '20202020-b05a-40f1-8af1-5e6f7a8b9cad' }, + createdAt: { + universalIdentifier: '20202020-b05b-40f2-9bf2-6f7a8b9cadbe', + }, + updatedAt: { + universalIdentifier: '20202020-b05c-40f3-8cf3-7a8b9cadbecf', + }, + deletedAt: { + universalIdentifier: '20202020-b05d-40f4-9df4-8b9cadbecfda', + }, + messages: { + universalIdentifier: MESSAGE_THREAD_STANDARD_FIELD_IDS.messages, + }, + messageChannelMessageAssociations: { + universalIdentifier: + MESSAGE_THREAD_STANDARD_FIELD_IDS.messageChannelMessageAssociations, + }, + messageThreadSubscribers: { + universalIdentifier: + MESSAGE_THREAD_STANDARD_FIELD_IDS.messageThreadSubscribers, + }, + }, + views: { + allMessageThreads: { + universalIdentifier: '20202020-d002-4d02-8d02-ae55a9ba2002', + viewFields: { + messages: { + universalIdentifier: '20202020-df02-4d02-8d02-ae55a9ba2f01', + }, + createdAt: { + universalIdentifier: '20202020-df02-4d02-8d02-ae55a9ba2f02', + }, + }, + }, + }, + }, + message: { + universalIdentifier: STANDARD_OBJECT_IDS.message, + fields: { + id: { universalIdentifier: '20202020-b06a-4101-8a01-9cadbedfaeb1' }, + createdAt: { + universalIdentifier: '20202020-b06b-4102-9b02-adbecfeafbc2', + }, + updatedAt: { + universalIdentifier: '20202020-b06c-4103-8c03-becfdfabfcd3', + }, + deletedAt: { + universalIdentifier: '20202020-b06d-4104-9d04-cfdfabecdde4', + }, + headerMessageId: { + universalIdentifier: MESSAGE_STANDARD_FIELD_IDS.headerMessageId, + }, + messageThread: { + universalIdentifier: MESSAGE_STANDARD_FIELD_IDS.messageThread, + }, + direction: { + universalIdentifier: MESSAGE_STANDARD_FIELD_IDS.direction, + }, + subject: { universalIdentifier: MESSAGE_STANDARD_FIELD_IDS.subject }, + text: { universalIdentifier: MESSAGE_STANDARD_FIELD_IDS.text }, + receivedAt: { + universalIdentifier: MESSAGE_STANDARD_FIELD_IDS.receivedAt, + }, + messageParticipants: { + universalIdentifier: MESSAGE_STANDARD_FIELD_IDS.messageParticipants, + }, + messageChannelMessageAssociations: { + universalIdentifier: + MESSAGE_STANDARD_FIELD_IDS.messageChannelMessageAssociations, + }, + }, + views: { + allMessages: { + universalIdentifier: '20202020-d001-4d01-8d01-ae55a9e5a001', + viewFields: { + subject: { + universalIdentifier: '20202020-df01-4d01-8d01-ae55a9e5af01', + }, + messageThread: { + universalIdentifier: '20202020-df01-4d01-8d01-ae55a9e5af02', + }, + messageParticipants: { + universalIdentifier: '20202020-df01-4d01-8d01-ae55a9e5af03', + }, + receivedAt: { + universalIdentifier: '20202020-df01-4d01-8d01-ae55a9e5af04', + }, + headerMessageId: { + universalIdentifier: '20202020-df01-4d01-8d01-ae55a9e5af05', + }, + text: { + universalIdentifier: '20202020-df01-4d01-8d01-ae55a9e5af06', + }, + createdAt: { + universalIdentifier: '20202020-df01-4d01-8d01-ae55a9e5af07', + }, + }, + }, + }, + }, + note: { + universalIdentifier: STANDARD_OBJECT_IDS.note, + fields: { + id: { universalIdentifier: '20202020-c01a-4111-8a11-dfabcddeef12' }, + createdAt: { + universalIdentifier: '20202020-c01b-4112-9b12-fabcddefe123', + }, + updatedAt: { + universalIdentifier: '20202020-c01c-4113-8c13-abcddeef1234', + }, + deletedAt: { + universalIdentifier: '20202020-c01d-4114-9d14-bcddeef12345', + }, + position: { universalIdentifier: NOTE_STANDARD_FIELD_IDS.position }, + title: { universalIdentifier: NOTE_STANDARD_FIELD_IDS.title }, + body: { universalIdentifier: NOTE_STANDARD_FIELD_IDS.body }, + bodyV2: { universalIdentifier: NOTE_STANDARD_FIELD_IDS.bodyV2 }, + createdBy: { universalIdentifier: NOTE_STANDARD_FIELD_IDS.createdBy }, + noteTargets: { universalIdentifier: NOTE_STANDARD_FIELD_IDS.noteTargets }, + attachments: { universalIdentifier: NOTE_STANDARD_FIELD_IDS.attachments }, + timelineActivities: { + universalIdentifier: NOTE_STANDARD_FIELD_IDS.timelineActivities, + }, + favorites: { universalIdentifier: NOTE_STANDARD_FIELD_IDS.favorites }, + searchVector: { + universalIdentifier: NOTE_STANDARD_FIELD_IDS.searchVector, + }, + }, + views: { + allNotes: { + universalIdentifier: '20202020-a005-4a05-8a05-a0be5a11a000', + viewFields: { + title: { + universalIdentifier: '20202020-af05-4a05-8a05-a0be5a11af00', + }, + noteTargets: { + universalIdentifier: '20202020-af05-4a05-8a05-a0be5a11af01', + }, + bodyV2: { + universalIdentifier: '20202020-af05-4a05-8a05-a0be5a11af02', + }, + createdBy: { + universalIdentifier: '20202020-af05-4a05-8a05-a0be5a11af03', + }, + createdAt: { + universalIdentifier: '20202020-af05-4a05-8a05-a0be5a11af04', + }, + }, + }, + }, + }, + noteTarget: { + universalIdentifier: STANDARD_OBJECT_IDS.noteTarget, + fields: { + id: { universalIdentifier: '20202020-c02a-4121-8a21-cddeef123456' }, + createdAt: { + universalIdentifier: '20202020-c02b-4122-9b22-ddeef1234567', + }, + updatedAt: { + universalIdentifier: '20202020-c02c-4123-8c23-eef12345678a', + }, + deletedAt: { + universalIdentifier: '20202020-c02d-4124-9d24-ef123456789b', + }, + note: { universalIdentifier: NOTE_TARGET_STANDARD_FIELD_IDS.note }, + person: { universalIdentifier: NOTE_TARGET_STANDARD_FIELD_IDS.person }, + company: { universalIdentifier: NOTE_TARGET_STANDARD_FIELD_IDS.company }, + opportunity: { + universalIdentifier: NOTE_TARGET_STANDARD_FIELD_IDS.opportunity, + }, + custom: { universalIdentifier: NOTE_TARGET_STANDARD_FIELD_IDS.custom }, + }, + views: {}, + }, + opportunity: { + universalIdentifier: STANDARD_OBJECT_IDS.opportunity, + fields: { + id: { universalIdentifier: '20202020-d01a-4131-8a31-f123456789ab' }, + createdAt: { + universalIdentifier: '20202020-d01b-4132-9b32-123456789abc', + }, + updatedAt: { + universalIdentifier: '20202020-d01c-4133-8c33-23456789abcd', + }, + deletedAt: { + universalIdentifier: '20202020-d01d-4134-9d34-3456789abcde', + }, + name: { universalIdentifier: OPPORTUNITY_STANDARD_FIELD_IDS.name }, + amount: { universalIdentifier: OPPORTUNITY_STANDARD_FIELD_IDS.amount }, + closeDate: { + universalIdentifier: OPPORTUNITY_STANDARD_FIELD_IDS.closeDate, + }, + stage: { universalIdentifier: OPPORTUNITY_STANDARD_FIELD_IDS.stage }, + position: { + universalIdentifier: OPPORTUNITY_STANDARD_FIELD_IDS.position, + }, + createdBy: { + universalIdentifier: OPPORTUNITY_STANDARD_FIELD_IDS.createdBy, + }, + pointOfContact: { + universalIdentifier: OPPORTUNITY_STANDARD_FIELD_IDS.pointOfContact, + }, + company: { universalIdentifier: OPPORTUNITY_STANDARD_FIELD_IDS.company }, + favorites: { + universalIdentifier: OPPORTUNITY_STANDARD_FIELD_IDS.favorites, + }, + taskTargets: { + universalIdentifier: OPPORTUNITY_STANDARD_FIELD_IDS.taskTargets, + }, + noteTargets: { + universalIdentifier: OPPORTUNITY_STANDARD_FIELD_IDS.noteTargets, + }, + attachments: { + universalIdentifier: OPPORTUNITY_STANDARD_FIELD_IDS.attachments, + }, + timelineActivities: { + universalIdentifier: OPPORTUNITY_STANDARD_FIELD_IDS.timelineActivities, + }, + searchVector: { + universalIdentifier: OPPORTUNITY_STANDARD_FIELD_IDS.searchVector, + }, + }, + views: { + allOpportunities: { + universalIdentifier: '20202020-a003-4a03-8a03-0aa0b1ca1ba0', + viewFields: { + name: { + universalIdentifier: '20202020-af03-4a03-8a03-0aa0b1ca1baf', + }, + amount: { + universalIdentifier: '20202020-af03-4a03-8a03-0aa0b1ca1bb0', + }, + createdBy: { + universalIdentifier: '20202020-af03-4a03-8a03-0aa0b1ca1bb1', + }, + closeDate: { + universalIdentifier: '20202020-af03-4a03-8a03-0aa0b1ca1bb2', + }, + company: { + universalIdentifier: '20202020-af03-4a03-8a03-0aa0b1ca1bb3', + }, + pointOfContact: { + universalIdentifier: '20202020-af03-4a03-8a03-0aa0b1ca1bb4', + }, + }, + }, + byStage: { + universalIdentifier: '20202020-a004-4a04-8a04-0aa0b1ca1ba0', + viewFields: { + name: { + universalIdentifier: '20202020-af04-4a04-8a04-0aa0b2ca2baf', + }, + amount: { + universalIdentifier: '20202020-af04-4a04-8a04-0aa0b2ca2bb0', + }, + createdBy: { + universalIdentifier: '20202020-af04-4a04-8a04-0aa0b2ca2bb1', + }, + closeDate: { + universalIdentifier: '20202020-af04-4a04-8a04-0aa0b2ca2bb2', + }, + company: { + universalIdentifier: '20202020-af04-4a04-8a04-0aa0b2ca2bb3', + }, + pointOfContact: { + universalIdentifier: '20202020-af04-4a04-8a04-0aa0b2ca2bb4', + }, + }, + viewGroups: { + new: { + universalIdentifier: '20202020-af14-4a04-8a04-0aa0b2ca2bf1', + }, + screening: { + universalIdentifier: '20202020-af14-4a04-8a04-0aa0b2ca2bf2', + }, + meeting: { + universalIdentifier: '20202020-af14-4a04-8a04-0aa0b2ca2bf3', + }, + proposal: { + universalIdentifier: '20202020-af14-4a04-8a04-0aa0b2ca2bf4', + }, + customer: { + universalIdentifier: '20202020-af14-4a04-8a04-0aa0b2ca2bf5', + }, + }, + }, + }, + }, + person: { + universalIdentifier: STANDARD_OBJECT_IDS.person, + fields: { + id: { universalIdentifier: '20202020-e01a-4141-8a41-456789abcdef' }, + createdAt: { + universalIdentifier: '20202020-e01b-4142-9b42-56789abcdefa', + }, + updatedAt: { + universalIdentifier: '20202020-e01c-4143-8c43-6789abcdefab', + }, + deletedAt: { + universalIdentifier: '20202020-e01d-4144-9d44-789abcdefabc', + }, + name: { universalIdentifier: PERSON_STANDARD_FIELD_IDS.name }, + email: { universalIdentifier: PERSON_STANDARD_FIELD_IDS.email }, + emails: { universalIdentifier: PERSON_STANDARD_FIELD_IDS.emails }, + linkedinLink: { + universalIdentifier: PERSON_STANDARD_FIELD_IDS.linkedinLink, + }, + xLink: { universalIdentifier: PERSON_STANDARD_FIELD_IDS.xLink }, + jobTitle: { universalIdentifier: PERSON_STANDARD_FIELD_IDS.jobTitle }, + phone: { universalIdentifier: PERSON_STANDARD_FIELD_IDS.phone }, + phones: { universalIdentifier: PERSON_STANDARD_FIELD_IDS.phones }, + city: { universalIdentifier: PERSON_STANDARD_FIELD_IDS.city }, + avatarUrl: { universalIdentifier: PERSON_STANDARD_FIELD_IDS.avatarUrl }, + position: { universalIdentifier: PERSON_STANDARD_FIELD_IDS.position }, + createdBy: { universalIdentifier: PERSON_STANDARD_FIELD_IDS.createdBy }, + company: { universalIdentifier: PERSON_STANDARD_FIELD_IDS.company }, + pointOfContactForOpportunities: { + universalIdentifier: + PERSON_STANDARD_FIELD_IDS.pointOfContactForOpportunities, + }, + taskTargets: { + universalIdentifier: PERSON_STANDARD_FIELD_IDS.taskTargets, + }, + noteTargets: { + universalIdentifier: PERSON_STANDARD_FIELD_IDS.noteTargets, + }, + favorites: { universalIdentifier: PERSON_STANDARD_FIELD_IDS.favorites }, + attachments: { + universalIdentifier: PERSON_STANDARD_FIELD_IDS.attachments, + }, + messageParticipants: { + universalIdentifier: PERSON_STANDARD_FIELD_IDS.messageParticipants, + }, + calendarEventParticipants: { + universalIdentifier: + PERSON_STANDARD_FIELD_IDS.calendarEventParticipants, + }, + timelineActivities: { + universalIdentifier: PERSON_STANDARD_FIELD_IDS.timelineActivities, + }, + searchVector: { + universalIdentifier: PERSON_STANDARD_FIELD_IDS.searchVector, + }, + }, + views: { + allPeople: { + universalIdentifier: '20202020-a002-4a02-8a02-ae0a1ea11a00', + viewFields: { + name: { + universalIdentifier: '20202020-af02-4a02-8a02-ae0a1ea11af0', + }, + emails: { + universalIdentifier: '20202020-af02-4a02-8a02-ae0a1ea11af1', + }, + createdBy: { + universalIdentifier: '20202020-af02-4a02-8a02-ae0a1ea11af2', + }, + company: { + universalIdentifier: '20202020-af02-4a02-8a02-ae0a1ea11af3', + }, + phones: { + universalIdentifier: '20202020-af02-4a02-8a02-ae0a1ea11af4', + }, + createdAt: { + universalIdentifier: '20202020-af02-4a02-8a02-ae0a1ea11af5', + }, + city: { + universalIdentifier: '20202020-af02-4a02-8a02-ae0a1ea11af6', + }, + jobTitle: { + universalIdentifier: '20202020-af02-4a02-8a02-ae0a1ea11af7', + }, + linkedinLink: { + universalIdentifier: '20202020-af02-4a02-8a02-ae0a1ea11af8', + }, + xLink: { + universalIdentifier: '20202020-af02-4a02-8a02-ae0a1ea11af9', + }, + }, + }, + }, + }, + task: { + universalIdentifier: STANDARD_OBJECT_IDS.task, + fields: { + id: { universalIdentifier: '20202020-a02a-4151-8a51-89abcdefabcd' }, + createdAt: { + universalIdentifier: '20202020-a02b-4152-9b52-9abcdefabcde', + }, + updatedAt: { + universalIdentifier: '20202020-a02c-4153-8c53-abcdefabcdef', + }, + deletedAt: { + universalIdentifier: '20202020-a02d-4154-9d54-bcdefabcdefa', + }, + position: { universalIdentifier: TASK_STANDARD_FIELD_IDS.position }, + title: { universalIdentifier: TASK_STANDARD_FIELD_IDS.title }, + body: { universalIdentifier: TASK_STANDARD_FIELD_IDS.body }, + bodyV2: { universalIdentifier: TASK_STANDARD_FIELD_IDS.bodyV2 }, + dueAt: { universalIdentifier: TASK_STANDARD_FIELD_IDS.dueAt }, + status: { universalIdentifier: TASK_STANDARD_FIELD_IDS.status }, + createdBy: { universalIdentifier: TASK_STANDARD_FIELD_IDS.createdBy }, + taskTargets: { universalIdentifier: TASK_STANDARD_FIELD_IDS.taskTargets }, + attachments: { universalIdentifier: TASK_STANDARD_FIELD_IDS.attachments }, + assignee: { universalIdentifier: TASK_STANDARD_FIELD_IDS.assignee }, + timelineActivities: { + universalIdentifier: TASK_STANDARD_FIELD_IDS.timelineActivities, + }, + favorites: { universalIdentifier: TASK_STANDARD_FIELD_IDS.favorites }, + searchVector: { + universalIdentifier: TASK_STANDARD_FIELD_IDS.searchVector, + }, + }, + views: { + allTasks: { + universalIdentifier: '20202020-a006-4a06-8a06-ba5ca11a1ea0', + viewFields: { + title: { + universalIdentifier: '20202020-af06-4a06-8a06-ba5ca11a1eaf', + }, + status: { + universalIdentifier: '20202020-af06-4a06-8a06-ba5ca11a1eb0', + }, + taskTargets: { + universalIdentifier: '20202020-af06-4a06-8a06-ba5ca11a1eb1', + }, + createdBy: { + universalIdentifier: '20202020-af06-4a06-8a06-ba5ca11a1eb2', + }, + dueAt: { + universalIdentifier: '20202020-af06-4a06-8a06-ba5ca11a1eb3', + }, + assignee: { + universalIdentifier: '20202020-af06-4a06-8a06-ba5ca11a1eb4', + }, + bodyV2: { + universalIdentifier: '20202020-af06-4a06-8a06-ba5ca11a1eb5', + }, + createdAt: { + universalIdentifier: '20202020-af06-4a06-8a06-ba5ca11a1eb6', + }, + }, + }, + assignedToMe: { + universalIdentifier: '20202020-a007-4a07-8a07-ba5ca551aaed', + viewFields: { + title: { + universalIdentifier: '20202020-af07-4a07-8a07-ba5ca551aaed', + }, + taskTargets: { + universalIdentifier: '20202020-af07-4a07-8a07-ba5ca551aaee', + }, + createdBy: { + universalIdentifier: '20202020-af07-4a07-8a07-ba5ca551aaef', + }, + dueAt: { + universalIdentifier: '20202020-af07-4a07-8a07-ba5ca551aaf0', + }, + assignee: { + universalIdentifier: '20202020-af07-4a07-8a07-ba5ca551aaf1', + }, + bodyV2: { + universalIdentifier: '20202020-af07-4a07-8a07-ba5ca551aaf2', + }, + createdAt: { + universalIdentifier: '20202020-af07-4a07-8a07-ba5ca551aaf3', + }, + }, + viewFilters: { + assigneeIsMe: { + universalIdentifier: '20202020-af17-4a07-8a07-ba5ca551abf1', + }, + }, + viewGroups: { + todo: { + universalIdentifier: '20202020-af17-4a07-8a07-ba5ca551abf2', + }, + inProgress: { + universalIdentifier: '20202020-af17-4a07-8a07-ba5ca551abf3', + }, + done: { + universalIdentifier: '20202020-af17-4a07-8a07-ba5ca551abf4', + }, + empty: { + universalIdentifier: '20202020-af17-4a07-8a07-ba5ca551abf5', + }, + }, + }, + byStatus: { + universalIdentifier: '20202020-a008-4a08-8a08-ba5cba51aba5', + viewFields: { + title: { + universalIdentifier: '20202020-af08-4a08-8a08-ba5cba5babf0', + }, + status: { + universalIdentifier: '20202020-af08-4a08-8a08-ba5cba5babf1', + }, + dueAt: { + universalIdentifier: '20202020-af08-4a08-8a08-ba5cba5babf2', + }, + assignee: { + universalIdentifier: '20202020-af08-4a08-8a08-ba5cba5babf3', + }, + createdAt: { + universalIdentifier: '20202020-af08-4a08-8a08-ba5cba5babf4', + }, + }, + viewGroups: { + todo: { + universalIdentifier: '20202020-af18-4a08-8a08-ba5cba5bbf01', + }, + inProgress: { + universalIdentifier: '20202020-af18-4a08-8a08-ba5cba5bbf02', + }, + done: { + universalIdentifier: '20202020-af18-4a08-8a08-ba5cba5bbf03', + }, + }, + }, + }, + }, + taskTarget: { + universalIdentifier: STANDARD_OBJECT_IDS.taskTarget, + fields: { + id: { universalIdentifier: '20202020-a03a-4161-8a61-cdefabcdefab' }, + createdAt: { + universalIdentifier: '20202020-a03b-4162-9b62-defabcdefabc', + }, + updatedAt: { + universalIdentifier: '20202020-a03c-4163-8c63-efabcdefabcd', + }, + deletedAt: { + universalIdentifier: '20202020-a03d-4164-9d64-fabcdefabcde', + }, + task: { universalIdentifier: TASK_TARGET_STANDARD_FIELD_IDS.task }, + person: { universalIdentifier: TASK_TARGET_STANDARD_FIELD_IDS.person }, + company: { universalIdentifier: TASK_TARGET_STANDARD_FIELD_IDS.company }, + opportunity: { + universalIdentifier: TASK_TARGET_STANDARD_FIELD_IDS.opportunity, + }, + custom: { universalIdentifier: TASK_TARGET_STANDARD_FIELD_IDS.custom }, + }, + views: {}, + }, + timelineActivity: { + universalIdentifier: STANDARD_OBJECT_IDS.timelineActivity, + fields: { + id: { universalIdentifier: '20202020-a01a-4081-8a81-9aabbccddeff' }, + createdAt: { + universalIdentifier: '20202020-a01b-4082-9b82-aabbccddeeff', + }, + updatedAt: { + universalIdentifier: '20202020-a01c-4083-8c83-bbccddeeffaa', + }, + deletedAt: { + universalIdentifier: '20202020-a01d-4084-9d84-ccddeeffaabb', + }, + happensAt: { + universalIdentifier: TIMELINE_ACTIVITY_STANDARD_FIELD_IDS.happensAt, + }, + type: { universalIdentifier: TIMELINE_ACTIVITY_STANDARD_FIELD_IDS.type }, + name: { universalIdentifier: TIMELINE_ACTIVITY_STANDARD_FIELD_IDS.name }, + properties: { + universalIdentifier: TIMELINE_ACTIVITY_STANDARD_FIELD_IDS.properties, + }, + workspaceMember: { + universalIdentifier: + TIMELINE_ACTIVITY_STANDARD_FIELD_IDS.workspaceMember, + }, + person: { + universalIdentifier: TIMELINE_ACTIVITY_STANDARD_FIELD_IDS.person, + }, + company: { + universalIdentifier: TIMELINE_ACTIVITY_STANDARD_FIELD_IDS.company, + }, + opportunity: { + universalIdentifier: TIMELINE_ACTIVITY_STANDARD_FIELD_IDS.opportunity, + }, + task: { universalIdentifier: TIMELINE_ACTIVITY_STANDARD_FIELD_IDS.task }, + note: { universalIdentifier: TIMELINE_ACTIVITY_STANDARD_FIELD_IDS.note }, + workflow: { + universalIdentifier: TIMELINE_ACTIVITY_STANDARD_FIELD_IDS.workflow, + }, + workflowVersion: { + universalIdentifier: + TIMELINE_ACTIVITY_STANDARD_FIELD_IDS.workflowVersion, + }, + workflowRun: { + universalIdentifier: TIMELINE_ACTIVITY_STANDARD_FIELD_IDS.workflowRun, + }, + dashboard: { + universalIdentifier: TIMELINE_ACTIVITY_STANDARD_FIELD_IDS.dashboard, + }, + custom: { + universalIdentifier: '20202020-a9b2-4f85-b3c7-6d8e9f1a4c2b', + }, + linkedRecordCachedName: { + universalIdentifier: + TIMELINE_ACTIVITY_STANDARD_FIELD_IDS.linkedRecordCachedName, + }, + linkedRecordId: { + universalIdentifier: + TIMELINE_ACTIVITY_STANDARD_FIELD_IDS.linkedRecordId, + }, + linkedObjectMetadataId: { + universalIdentifier: + TIMELINE_ACTIVITY_STANDARD_FIELD_IDS.linkedObjectMetadataId, + }, + }, + views: {}, + }, + view: { + universalIdentifier: STANDARD_OBJECT_IDS.view, + fields: { + name: { universalIdentifier: VIEW_STANDARD_FIELD_IDS.name }, + objectMetadataId: { + universalIdentifier: VIEW_STANDARD_FIELD_IDS.objectMetadataId, + }, + type: { universalIdentifier: VIEW_STANDARD_FIELD_IDS.type }, + key: { universalIdentifier: VIEW_STANDARD_FIELD_IDS.key }, + icon: { universalIdentifier: VIEW_STANDARD_FIELD_IDS.icon }, + kanbanFieldMetadataId: { + universalIdentifier: VIEW_STANDARD_FIELD_IDS.kanbanFieldMetadataId, + }, + kanbanAggregateOperation: { + universalIdentifier: VIEW_STANDARD_FIELD_IDS.kanbanAggregateOperation, + }, + kanbanAggregateOperationFieldMetadataId: { + universalIdentifier: + VIEW_STANDARD_FIELD_IDS.kanbanAggregateOperationFieldMetadataId, + }, + position: { universalIdentifier: VIEW_STANDARD_FIELD_IDS.position }, + isCompact: { universalIdentifier: VIEW_STANDARD_FIELD_IDS.isCompact }, + openRecordIn: { + universalIdentifier: VIEW_STANDARD_FIELD_IDS.openRecordIn, + }, + viewFields: { universalIdentifier: VIEW_STANDARD_FIELD_IDS.viewFields }, + viewGroups: { universalIdentifier: VIEW_STANDARD_FIELD_IDS.viewGroups }, + viewFilters: { universalIdentifier: VIEW_STANDARD_FIELD_IDS.viewFilters }, + viewFilterGroups: { + universalIdentifier: VIEW_STANDARD_FIELD_IDS.viewFilterGroups, + }, + viewSorts: { universalIdentifier: VIEW_STANDARD_FIELD_IDS.viewSorts }, + favorites: { universalIdentifier: VIEW_STANDARD_FIELD_IDS.favorites }, + anyFieldFilterValue: { + universalIdentifier: VIEW_STANDARD_FIELD_IDS.anyFieldFilterValue, + }, + }, + views: {}, + }, + viewField: { + universalIdentifier: STANDARD_OBJECT_IDS.viewField, + fields: { + fieldMetadataId: { + universalIdentifier: VIEW_FIELD_STANDARD_FIELD_IDS.fieldMetadataId, + }, + isVisible: { + universalIdentifier: VIEW_FIELD_STANDARD_FIELD_IDS.isVisible, + }, + size: { universalIdentifier: VIEW_FIELD_STANDARD_FIELD_IDS.size }, + position: { universalIdentifier: VIEW_FIELD_STANDARD_FIELD_IDS.position }, + view: { universalIdentifier: VIEW_FIELD_STANDARD_FIELD_IDS.view }, + aggregateOperation: { + universalIdentifier: VIEW_FIELD_STANDARD_FIELD_IDS.aggregateOperation, + }, + }, + views: {}, + }, + viewFilter: { + universalIdentifier: STANDARD_OBJECT_IDS.viewFilter, + fields: { + fieldMetadataId: { + universalIdentifier: VIEW_FILTER_STANDARD_FIELD_IDS.fieldMetadataId, + }, + operand: { universalIdentifier: VIEW_FILTER_STANDARD_FIELD_IDS.operand }, + value: { universalIdentifier: VIEW_FILTER_STANDARD_FIELD_IDS.value }, + displayValue: { + universalIdentifier: VIEW_FILTER_STANDARD_FIELD_IDS.displayValue, + }, + view: { universalIdentifier: VIEW_FILTER_STANDARD_FIELD_IDS.view }, + viewFilterGroupId: { + universalIdentifier: VIEW_FILTER_STANDARD_FIELD_IDS.viewFilterGroupId, + }, + positionInViewFilterGroup: { + universalIdentifier: + VIEW_FILTER_STANDARD_FIELD_IDS.positionInViewFilterGroup, + }, + subFieldName: { + universalIdentifier: VIEW_FILTER_STANDARD_FIELD_IDS.subFieldName, + }, + }, + views: {}, + }, + viewFilterGroup: { + universalIdentifier: STANDARD_OBJECT_IDS.viewFilterGroup, + fields: { + view: { universalIdentifier: VIEW_FILTER_GROUP_STANDARD_FIELD_IDS.view }, + parentViewFilterGroupId: { + universalIdentifier: + VIEW_FILTER_GROUP_STANDARD_FIELD_IDS.parentViewFilterGroupId, + }, + logicalOperator: { + universalIdentifier: + VIEW_FILTER_GROUP_STANDARD_FIELD_IDS.logicalOperator, + }, + positionInViewFilterGroup: { + universalIdentifier: + VIEW_FILTER_GROUP_STANDARD_FIELD_IDS.positionInViewFilterGroup, + }, + }, + views: {}, + }, + viewGroup: { + universalIdentifier: STANDARD_OBJECT_IDS.viewGroup, + fields: { + fieldMetadataId: { + universalIdentifier: VIEW_GROUP_STANDARD_FIELD_IDS.fieldMetadataId, + }, + fieldValue: { + universalIdentifier: VIEW_GROUP_STANDARD_FIELD_IDS.fieldValue, + }, + isVisible: { + universalIdentifier: VIEW_GROUP_STANDARD_FIELD_IDS.isVisible, + }, + position: { universalIdentifier: VIEW_GROUP_STANDARD_FIELD_IDS.position }, + view: { universalIdentifier: VIEW_GROUP_STANDARD_FIELD_IDS.view }, + }, + views: {}, + }, + viewSort: { + universalIdentifier: STANDARD_OBJECT_IDS.viewSort, + fields: { + fieldMetadataId: { + universalIdentifier: VIEW_SORT_STANDARD_FIELD_IDS.fieldMetadataId, + }, + direction: { + universalIdentifier: VIEW_SORT_STANDARD_FIELD_IDS.direction, + }, + view: { universalIdentifier: VIEW_SORT_STANDARD_FIELD_IDS.view }, + }, + views: {}, + }, + workflow: { + universalIdentifier: STANDARD_OBJECT_IDS.workflow, + fields: { + id: { universalIdentifier: '20202020-f02a-4181-8a81-efabcdefabcd' }, + createdAt: { + universalIdentifier: '20202020-f02b-4182-9b82-fabcdefabcde', + }, + updatedAt: { + universalIdentifier: '20202020-f02c-4183-8c83-abcdefabcdef', + }, + deletedAt: { + universalIdentifier: '20202020-f02d-4184-9d84-bcdefabcdefa', + }, + name: { universalIdentifier: WORKFLOW_STANDARD_FIELD_IDS.name }, + lastPublishedVersionId: { + universalIdentifier: WORKFLOW_STANDARD_FIELD_IDS.lastPublishedVersionId, + }, + statuses: { universalIdentifier: WORKFLOW_STANDARD_FIELD_IDS.statuses }, + position: { universalIdentifier: WORKFLOW_STANDARD_FIELD_IDS.position }, + versions: { universalIdentifier: WORKFLOW_STANDARD_FIELD_IDS.versions }, + runs: { universalIdentifier: WORKFLOW_STANDARD_FIELD_IDS.runs }, + eventListeners: { + universalIdentifier: WORKFLOW_STANDARD_FIELD_IDS.eventListeners, + }, + automatedTriggers: { + universalIdentifier: WORKFLOW_STANDARD_FIELD_IDS.automatedTriggers, + }, + favorites: { universalIdentifier: WORKFLOW_STANDARD_FIELD_IDS.favorites }, + timelineActivities: { + universalIdentifier: WORKFLOW_STANDARD_FIELD_IDS.timelineActivities, + }, + attachments: { + universalIdentifier: WORKFLOW_STANDARD_FIELD_IDS.attachments, + }, + createdBy: { universalIdentifier: WORKFLOW_STANDARD_FIELD_IDS.createdBy }, + searchVector: { + universalIdentifier: WORKFLOW_STANDARD_FIELD_IDS.searchVector, + }, + }, + views: { + allWorkflows: { + universalIdentifier: '20202020-a009-4a09-8a09-a0bcf10aa11a', + viewFields: { + name: { + universalIdentifier: '20202020-af09-4a09-8a09-a0bcf10aa11a', + }, + statuses: { + universalIdentifier: '20202020-af09-4a09-8a09-a0bcf10aa11b', + }, + updatedAt: { + universalIdentifier: '20202020-af09-4a09-8a09-a0bcf10aa11c', + }, + createdBy: { + universalIdentifier: '20202020-af09-4a09-8a09-a0bcf10aa11d', + }, + versions: { + universalIdentifier: '20202020-af09-4a09-8a09-a0bcf10aa11e', + }, + runs: { + universalIdentifier: '20202020-af09-4a09-8a09-a0bcf10aa11f', + }, + }, + }, + }, + }, + workflowAutomatedTrigger: { + universalIdentifier: STANDARD_OBJECT_IDS.workflowAutomatedTrigger, + fields: { + id: { + universalIdentifier: '20202020-f01a-4171-8a71-abcdefabcdef', + }, + createdAt: { + universalIdentifier: '20202020-f01b-4172-9b72-bcdefabcdefa', + }, + updatedAt: { + universalIdentifier: '20202020-f01c-4173-8c73-cdefabcdefab', + }, + deletedAt: { + universalIdentifier: '20202020-f01d-4174-9d74-defabcdefabc', + }, + type: { + universalIdentifier: WORKFLOW_AUTOMATED_TRIGGER_STANDARD_FIELD_IDS.type, + }, + settings: { + universalIdentifier: + WORKFLOW_AUTOMATED_TRIGGER_STANDARD_FIELD_IDS.settings, + }, + workflow: { + universalIdentifier: + WORKFLOW_AUTOMATED_TRIGGER_STANDARD_FIELD_IDS.workflow, + }, + }, + views: {}, + }, + workflowRun: { + universalIdentifier: STANDARD_OBJECT_IDS.workflowRun, + fields: { + id: { universalIdentifier: '20202020-f03a-4191-8a91-cdefabcdefab' }, + createdAt: { + universalIdentifier: '20202020-f03b-4192-9b92-defabcdefabc', + }, + updatedAt: { + universalIdentifier: '20202020-f03c-4193-8c93-efabcdefabcd', + }, + deletedAt: { + universalIdentifier: '20202020-f03d-4194-9d94-fabcdefabcde', + }, + name: { universalIdentifier: WORKFLOW_RUN_STANDARD_FIELD_IDS.name }, + workflowVersion: { + universalIdentifier: WORKFLOW_RUN_STANDARD_FIELD_IDS.workflowVersion, + }, + workflow: { + universalIdentifier: WORKFLOW_RUN_STANDARD_FIELD_IDS.workflow, + }, + enqueuedAt: { + universalIdentifier: WORKFLOW_RUN_STANDARD_FIELD_IDS.enqueuedAt, + }, + startedAt: { + universalIdentifier: WORKFLOW_RUN_STANDARD_FIELD_IDS.startedAt, + }, + endedAt: { universalIdentifier: WORKFLOW_RUN_STANDARD_FIELD_IDS.endedAt }, + status: { universalIdentifier: WORKFLOW_RUN_STANDARD_FIELD_IDS.status }, + position: { + universalIdentifier: WORKFLOW_RUN_STANDARD_FIELD_IDS.position, + }, + createdBy: { + universalIdentifier: WORKFLOW_RUN_STANDARD_FIELD_IDS.createdBy, + }, + output: { universalIdentifier: WORKFLOW_RUN_STANDARD_FIELD_IDS.output }, + context: { universalIdentifier: WORKFLOW_RUN_STANDARD_FIELD_IDS.context }, + state: { universalIdentifier: WORKFLOW_RUN_STANDARD_FIELD_IDS.state }, + favorites: { + universalIdentifier: WORKFLOW_RUN_STANDARD_FIELD_IDS.favorites, + }, + timelineActivities: { + universalIdentifier: WORKFLOW_RUN_STANDARD_FIELD_IDS.timelineActivities, + }, + searchVector: { + universalIdentifier: WORKFLOW_RUN_STANDARD_FIELD_IDS.searchVector, + }, + }, + views: { + allWorkflowRuns: { + universalIdentifier: '20202020-a011-4a11-8a11-a0bcf10abca5', + viewFields: { + name: { + universalIdentifier: '20202020-af11-4a11-8a11-a0bcf10abcaf', + }, + workflow: { + universalIdentifier: '20202020-af11-4a11-8a11-a0bcf10abcb0', + }, + status: { + universalIdentifier: '20202020-af11-4a11-8a11-a0bcf10abcb1', + }, + startedAt: { + universalIdentifier: '20202020-af11-4a11-8a11-a0bcf10abcb2', + }, + createdBy: { + universalIdentifier: '20202020-af11-4a11-8a11-a0bcf10abcb3', + }, + workflowVersion: { + universalIdentifier: '20202020-af11-4a11-8a11-a0bcf10abcb4', + }, + }, + }, + }, + }, + workflowVersion: { + universalIdentifier: STANDARD_OBJECT_IDS.workflowVersion, + fields: { + id: { universalIdentifier: '20202020-f04a-41a1-8aa1-abcdefabcdef' }, + createdAt: { + universalIdentifier: '20202020-f04b-41a2-9ba2-bcdefabcdefa', + }, + updatedAt: { + universalIdentifier: '20202020-f04c-41a3-8ca3-cdefabcdefab', + }, + deletedAt: { + universalIdentifier: '20202020-f04d-41a4-9da4-defabcdefabc', + }, + name: { universalIdentifier: WORKFLOW_VERSION_STANDARD_FIELD_IDS.name }, + workflow: { + universalIdentifier: WORKFLOW_VERSION_STANDARD_FIELD_IDS.workflow, + }, + trigger: { + universalIdentifier: WORKFLOW_VERSION_STANDARD_FIELD_IDS.trigger, + }, + status: { + universalIdentifier: WORKFLOW_VERSION_STANDARD_FIELD_IDS.status, + }, + position: { + universalIdentifier: WORKFLOW_VERSION_STANDARD_FIELD_IDS.position, + }, + runs: { universalIdentifier: WORKFLOW_VERSION_STANDARD_FIELD_IDS.runs }, + steps: { universalIdentifier: WORKFLOW_VERSION_STANDARD_FIELD_IDS.steps }, + favorites: { + universalIdentifier: WORKFLOW_VERSION_STANDARD_FIELD_IDS.favorites, + }, + timelineActivities: { + universalIdentifier: + WORKFLOW_VERSION_STANDARD_FIELD_IDS.timelineActivities, + }, + searchVector: { + universalIdentifier: WORKFLOW_VERSION_STANDARD_FIELD_IDS.searchVector, + }, + }, + views: { + allWorkflowVersions: { + universalIdentifier: '20202020-a010-4a10-8a10-a0bcf10aae15', + viewFields: { + name: { + universalIdentifier: '20202020-af10-4a10-8a10-a0bcf10aaeaf', + }, + workflow: { + universalIdentifier: '20202020-af10-4a10-8a10-a0bcf10aaeb0', + }, + status: { + universalIdentifier: '20202020-af10-4a10-8a10-a0bcf10aaeb1', + }, + updatedAt: { + universalIdentifier: '20202020-af10-4a10-8a10-a0bcf10aaeb2', + }, + runs: { + universalIdentifier: '20202020-af10-4a10-8a10-a0bcf10aaeb3', + }, + }, + }, + }, + }, + workspaceMember: { + universalIdentifier: STANDARD_OBJECT_IDS.workspaceMember, + fields: { + id: { universalIdentifier: '20202020-fb1a-41b1-8ab1-efabcdefabcd' }, + createdAt: { + universalIdentifier: '20202020-fb1b-41b2-9bb2-fabcdefabcde', + }, + updatedAt: { + universalIdentifier: '20202020-fb1c-41b3-8cb3-abcdefabcdef', + }, + deletedAt: { + universalIdentifier: '20202020-fb1d-41b4-9db4-bcdefabcdefa', + }, + position: { + universalIdentifier: WORKSPACE_MEMBER_STANDARD_FIELD_IDS.position, + }, + name: { universalIdentifier: WORKSPACE_MEMBER_STANDARD_FIELD_IDS.name }, + colorScheme: { + universalIdentifier: WORKSPACE_MEMBER_STANDARD_FIELD_IDS.colorScheme, + }, + locale: { + universalIdentifier: WORKSPACE_MEMBER_STANDARD_FIELD_IDS.locale, + }, + avatarUrl: { + universalIdentifier: WORKSPACE_MEMBER_STANDARD_FIELD_IDS.avatarUrl, + }, + userEmail: { + universalIdentifier: WORKSPACE_MEMBER_STANDARD_FIELD_IDS.userEmail, + }, + userId: { + universalIdentifier: WORKSPACE_MEMBER_STANDARD_FIELD_IDS.userId, + }, + authoredActivities: { + universalIdentifier: + WORKSPACE_MEMBER_STANDARD_FIELD_IDS.authoredActivities, + }, + assignedActivities: { + universalIdentifier: + WORKSPACE_MEMBER_STANDARD_FIELD_IDS.assignedActivities, + }, + assignedTasks: { + universalIdentifier: WORKSPACE_MEMBER_STANDARD_FIELD_IDS.assignedTasks, + }, + favorites: { + universalIdentifier: WORKSPACE_MEMBER_STANDARD_FIELD_IDS.favorites, + }, + accountOwnerForCompanies: { + universalIdentifier: + WORKSPACE_MEMBER_STANDARD_FIELD_IDS.accountOwnerForCompanies, + }, + authoredAttachments: { + universalIdentifier: + WORKSPACE_MEMBER_STANDARD_FIELD_IDS.authoredAttachments, + }, + authoredComments: { + universalIdentifier: + WORKSPACE_MEMBER_STANDARD_FIELD_IDS.authoredComments, + }, + connectedAccounts: { + universalIdentifier: + WORKSPACE_MEMBER_STANDARD_FIELD_IDS.connectedAccounts, + }, + messageParticipants: { + universalIdentifier: + WORKSPACE_MEMBER_STANDARD_FIELD_IDS.messageParticipants, + }, + blocklist: { + universalIdentifier: WORKSPACE_MEMBER_STANDARD_FIELD_IDS.blocklist, + }, + calendarEventParticipants: { + universalIdentifier: + WORKSPACE_MEMBER_STANDARD_FIELD_IDS.calendarEventParticipants, + }, + timelineActivities: { + universalIdentifier: + WORKSPACE_MEMBER_STANDARD_FIELD_IDS.timelineActivities, + }, + auditLogs: { + universalIdentifier: WORKSPACE_MEMBER_STANDARD_FIELD_IDS.auditLogs, + }, + messageThreadSubscribers: { + universalIdentifier: + WORKSPACE_MEMBER_STANDARD_FIELD_IDS.messageThreadSubscribers, + }, + timeZone: { + universalIdentifier: WORKSPACE_MEMBER_STANDARD_FIELD_IDS.timeZone, + }, + dateFormat: { + universalIdentifier: WORKSPACE_MEMBER_STANDARD_FIELD_IDS.dateFormat, + }, + timeFormat: { + universalIdentifier: WORKSPACE_MEMBER_STANDARD_FIELD_IDS.timeFormat, + }, + searchVector: { + universalIdentifier: WORKSPACE_MEMBER_STANDARD_FIELD_IDS.searchVector, + }, + calendarStartDay: { + universalIdentifier: + WORKSPACE_MEMBER_STANDARD_FIELD_IDS.calendarStartDay, + }, + numberFormat: { + universalIdentifier: WORKSPACE_MEMBER_STANDARD_FIELD_IDS.numberFormat, + }, + }, + views: { + allWorkspaceMembers: { + universalIdentifier: '20202020-e001-4e01-8e01-a0bcaeabe100', + viewFields: { + name: { + universalIdentifier: '20202020-ef01-4e01-8e01-a0bcaeabe1f0', + }, + userEmail: { + universalIdentifier: '20202020-ef01-4e01-8e01-a0bcaeabe1f1', + }, + avatarUrl: { + universalIdentifier: '20202020-ef01-4e01-8e01-a0bcaeabe1f2', + }, + colorScheme: { + universalIdentifier: '20202020-ef01-4e01-8e01-a0bcaeabe1f3', + }, + locale: { + universalIdentifier: '20202020-ef01-4e01-8e01-a0bcaeabe1f4', + }, + timeZone: { + universalIdentifier: '20202020-ef01-4e01-8e01-a0bcaeabe1f5', + }, + dateFormat: { + universalIdentifier: '20202020-ef01-4e01-8e01-a0bcaeabe1f6', + }, + timeFormat: { + universalIdentifier: '20202020-ef01-4e01-8e01-a0bcaeabe1f7', + }, + createdAt: { + universalIdentifier: '20202020-ef01-4e01-8e01-a0bcaeabe1f8', + }, + }, + }, + }, + }, +} as const satisfies Record< + string, + { + universalIdentifier: string; + fields: Record; + views: Record< + string, + { + universalIdentifier: string; + viewFields: Record; + viewFilters?: Record; + viewGroups?: Record; + } + >; + } +>; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/constants/twenty-standard-applications.ts b/packages/twenty-server/src/engine/core-modules/application/constants/twenty-standard-applications.ts similarity index 58% rename from packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/constants/twenty-standard-applications.ts rename to packages/twenty-server/src/engine/core-modules/application/constants/twenty-standard-applications.ts index e5a3829023196..bbdf76913d80c 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/constants/twenty-standard-applications.ts +++ b/packages/twenty-server/src/engine/core-modules/application/constants/twenty-standard-applications.ts @@ -8,20 +8,12 @@ export const TWENTY_STANDARD_APPLICATION = { version: '1.0.0', sourcePath: 'cli-sync', sourceType: 'local', - canBeUninstalled: false, -} as const satisfies CreateApplicationInput; - -export type CreateApplicationInput = Omit< +} as const satisfies Pick< ApplicationEntity, - | 'workspaceId' - | 'serverlessFunctionLayerId' - | 'id' - | 'createdAt' - | 'updatedAt' - | 'deletedAt' - | 'workspace' - | 'agents' - | 'applicationVariables' - | 'objects' - | 'serverlessFunctions' + | 'universalIdentifier' + | 'name' + | 'description' + | 'version' + | 'sourcePath' + | 'sourceType' >; diff --git a/packages/twenty-server/src/engine/core-modules/application/services/workspace-flat-application-map-cache.service.ts b/packages/twenty-server/src/engine/core-modules/application/services/workspace-flat-application-map-cache.service.ts new file mode 100644 index 0000000000000..f58d6b3533289 --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/application/services/workspace-flat-application-map-cache.service.ts @@ -0,0 +1,60 @@ +import { Injectable } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; + +import { AllMetadataName } from 'twenty-shared/metadata'; +import { Repository } from 'typeorm'; + +import { ApplicationEntity } from 'src/engine/core-modules/application/application.entity'; +import { FlatApplicationCacheMaps } from 'src/engine/core-modules/application/types/flat-application-cache-maps.type'; +import { fromApplicationEntityToFlatApplication } from 'src/engine/core-modules/application/utils/from-application-entity-to-flat-application.util'; +import { InjectCacheStorage } from 'src/engine/core-modules/cache-storage/decorators/cache-storage.decorator'; +import { CacheStorageService } from 'src/engine/core-modules/cache-storage/services/cache-storage.service'; +import { CacheStorageNamespace } from 'src/engine/core-modules/cache-storage/types/cache-storage-namespace.enum'; +import { MetadataToFlatEntityMapsKey } from 'src/engine/metadata-modules/flat-entity/types/metadata-to-flat-entity-maps-key'; +import { WorkspaceFlatMapCache } from 'src/engine/workspace-flat-map-cache/decorators/workspace-flat-map-cache.decorator'; +import { WorkspaceFlatMapCacheService } from 'src/engine/workspace-flat-map-cache/services/workspace-flat-map-cache.service'; + +@Injectable() +@WorkspaceFlatMapCache( + 'flatApplicationMaps' as MetadataToFlatEntityMapsKey, +) // TODO prastoin introduce SyncableMetadata notion +export class WorkspaceFlatApplicationMapCacheService extends WorkspaceFlatMapCacheService { + constructor( + @InjectCacheStorage(CacheStorageNamespace.EngineWorkspace) + cacheStorageService: CacheStorageService, + @InjectRepository(ApplicationEntity) + private readonly applicationRepository: Repository, + ) { + super(cacheStorageService); + } + + protected async computeFlatMap({ + workspaceId, + }: { + workspaceId: string; + }): Promise { + const applicationEntities = await this.applicationRepository.find({ + where: { + workspaceId, + }, + withDeleted: true, + }); + + const flatApplicationMaps: FlatApplicationCacheMaps = { + byId: {}, + idByUniversalIdentifier: {}, + }; + + for (const applicationEntity of applicationEntities) { + const flatApplication = + fromApplicationEntityToFlatApplication(applicationEntity); + + flatApplicationMaps.byId[flatApplication.id] = flatApplication; + flatApplicationMaps.idByUniversalIdentifier[ + flatApplication.universalIdentifier + ] = flatApplication.id; + } + + return flatApplicationMaps; + } +} diff --git a/packages/twenty-server/src/engine/core-modules/application/types/application-entity-relation-properties.type.ts b/packages/twenty-server/src/engine/core-modules/application/types/application-entity-relation-properties.type.ts new file mode 100644 index 0000000000000..1bf3b37cf1bce --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/application/types/application-entity-relation-properties.type.ts @@ -0,0 +1,4 @@ +import { type APPLICATION_ENTITY_RELATION_PROPERTIES } from 'src/engine/core-modules/application/constants/application-entity-relation-properties.constant'; + +export type ApplicationEntityRelationProperties = + (typeof APPLICATION_ENTITY_RELATION_PROPERTIES)[number]; diff --git a/packages/twenty-server/src/engine/core-modules/application/types/flat-application-cache-maps.type.ts b/packages/twenty-server/src/engine/core-modules/application/types/flat-application-cache-maps.type.ts new file mode 100644 index 0000000000000..377e65ba56857 --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/application/types/flat-application-cache-maps.type.ts @@ -0,0 +1,6 @@ +import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type'; + +export type FlatApplicationCacheMaps = { + byId: Partial>; + idByUniversalIdentifier: Partial>; +}; diff --git a/packages/twenty-server/src/engine/core-modules/application/types/flat-application.type.ts b/packages/twenty-server/src/engine/core-modules/application/types/flat-application.type.ts new file mode 100644 index 0000000000000..d8ce8e75f11ac --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/application/types/flat-application.type.ts @@ -0,0 +1,7 @@ +import { type ApplicationEntity } from 'src/engine/core-modules/application/application.entity'; +import { type ApplicationEntityRelationProperties } from 'src/engine/core-modules/application/types/application-entity-relation-properties.type'; + +export type FlatApplication = Omit< + ApplicationEntity, + ApplicationEntityRelationProperties +>; diff --git a/packages/twenty-server/src/engine/core-modules/application/utils/from-application-entity-to-flat-application.util.ts b/packages/twenty-server/src/engine/core-modules/application/utils/from-application-entity-to-flat-application.util.ts new file mode 100644 index 0000000000000..eb451dcf40213 --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/application/utils/from-application-entity-to-flat-application.util.ts @@ -0,0 +1,13 @@ +import { removePropertiesFromRecord } from 'twenty-shared/utils'; + +import { type ApplicationEntity } from 'src/engine/core-modules/application/application.entity'; +import { APPLICATION_ENTITY_RELATION_PROPERTIES } from 'src/engine/core-modules/application/constants/application-entity-relation-properties.constant'; +import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type'; + +export const fromApplicationEntityToFlatApplication = ( + applicationEntity: ApplicationEntity, +): FlatApplication => + removePropertiesFromRecord( + applicationEntity, + APPLICATION_ENTITY_RELATION_PROPERTIES, + ); diff --git a/packages/twenty-server/src/engine/core-modules/auth/services/sign-in-up.service.ts b/packages/twenty-server/src/engine/core-modules/auth/services/sign-in-up.service.ts index 4898e6b61885c..ddabe788a7aba 100644 --- a/packages/twenty-server/src/engine/core-modules/auth/services/sign-in-up.service.ts +++ b/packages/twenty-server/src/engine/core-modules/auth/services/sign-in-up.service.ts @@ -11,6 +11,7 @@ import { v4 } from 'uuid'; import { USER_SIGNUP_EVENT_NAME } from 'src/engine/api/graphql/workspace-query-runner/constants/user-signup-event-name.constants'; import { type AppTokenEntity } from 'src/engine/core-modules/app-token/app-token.entity'; import { ApplicationService } from 'src/engine/core-modules/application/application.service'; +import { WorkspaceFlatApplicationMapCacheService } from 'src/engine/core-modules/application/services/workspace-flat-application-map-cache.service'; import { AuthException, AuthExceptionCode, @@ -39,7 +40,6 @@ import { WorkspaceInvitationService } from 'src/engine/core-modules/workspace-in import { AuthProviderEnum } from 'src/engine/core-modules/workspace/types/workspace.type'; import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; import { WorkspaceEventEmitter } from 'src/engine/workspace-event-emitter/workspace-event-emitter'; -import { computeWorkspaceCustomCreateApplicationInput } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/compute-workspace-custom-create-application-input'; import { getDomainNameByEmail } from 'src/utils/get-domain-name-by-email'; import { isWorkEmail } from 'src/utils/is-work-email'; @@ -60,6 +60,7 @@ export class SignInUpService { private readonly subdomainManagerService: SubdomainManagerService, private readonly userService: UserService, private readonly metricsService: MetricsService, + private readonly workspaceFlatApplicationMapCacheService: WorkspaceFlatApplicationMapCacheService, private readonly applicationService: ApplicationService, @InjectDataSource() private readonly dataSource: DataSource, @@ -459,26 +460,19 @@ export class SignInUpService { isWorkEmailFound && (await isLogoUrlValid()) ? logoUrl : undefined; const workspaceId = v4(); - const workspaceCustomApplicationCreateInput = - computeWorkspaceCustomCreateApplicationInput({ - workspace: { - id: workspaceId, - }, - }); - const queryRunner = this.dataSource.createQueryRunner(); await queryRunner.connect(); await queryRunner.startTransaction(); try { - const workspaceCustomApplication = await this.applicationService.create( - { - ...workspaceCustomApplicationCreateInput, - serverlessFunctionLayerId: null, - }, - queryRunner, - ); + const workspaceCustomApplication = + await this.applicationService.createWorkspaceCustomApplication( + { + workspaceId, + }, + queryRunner, + ); const workspaceToCreate = this.workspaceRepository.create({ id: workspaceId, @@ -532,6 +526,9 @@ export class SignInUpService { ); await queryRunner.commitTransaction(); + await this.workspaceFlatApplicationMapCacheService.invalidateCache({ + workspaceId, + }); return { user, workspace }; } catch (error) { diff --git a/packages/twenty-server/src/engine/core-modules/core-engine.module.ts b/packages/twenty-server/src/engine/core-modules/core-engine.module.ts index 56d1c1558f504..013667991b470 100644 --- a/packages/twenty-server/src/engine/core-modules/core-engine.module.ts +++ b/packages/twenty-server/src/engine/core-modules/core-engine.module.ts @@ -9,6 +9,7 @@ import { AiModule } from 'src/engine/core-modules/ai/ai.module'; import { ApiKeyModule } from 'src/engine/core-modules/api-key/api-key.module'; import { AppTokenModule } from 'src/engine/core-modules/app-token/app-token.module'; import { ApplicationModule } from 'src/engine/core-modules/application/application.module'; +import { ApplicationSyncModule } from 'src/engine/core-modules/application/application-sync.module'; import { ApprovedAccessDomainModule } from 'src/engine/core-modules/approved-access-domain/approved-access-domain.module'; import { AuthModule } from 'src/engine/core-modules/auth/auth.module'; import { BillingWebhookModule } from 'src/engine/core-modules/billing-webhook/billing-webhook.module'; @@ -77,6 +78,7 @@ import { FileModule } from './file/file.module'; FileModule, OpenApiModule, ApplicationModule, + ApplicationSyncModule, AppTokenModule, TimelineMessagingModule, TimelineCalendarEventModule, diff --git a/packages/twenty-server/src/engine/metadata-modules/cron-trigger/cron-trigger.module.ts b/packages/twenty-server/src/engine/metadata-modules/cron-trigger/cron-trigger.module.ts index e073bc8258a2c..915badb1316fa 100644 --- a/packages/twenty-server/src/engine/metadata-modules/cron-trigger/cron-trigger.module.ts +++ b/packages/twenty-server/src/engine/metadata-modules/cron-trigger/cron-trigger.module.ts @@ -1,6 +1,7 @@ import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; +import { ApplicationModule } from 'src/engine/core-modules/application/application.module'; import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; import { CronTriggerCronCommand } from 'src/engine/metadata-modules/cron-trigger/crons/commands/cron-trigger.cron.command'; import { CronTriggerCronJob } from 'src/engine/metadata-modules/cron-trigger/crons/jobs/cron-trigger.cron.job'; @@ -15,6 +16,7 @@ import { WorkspaceMigrationV2Module } from 'src/engine/workspace-manager/workspa @Module({ imports: [ TypeOrmModule.forFeature([WorkspaceEntity, CronTriggerEntity]), + ApplicationModule, WorkspaceManyOrAllFlatEntityMapsCacheModule, PermissionsModule, WorkspaceMigrationV2Module, diff --git a/packages/twenty-server/src/engine/metadata-modules/cron-trigger/services/cron-trigger-v2.service.ts b/packages/twenty-server/src/engine/metadata-modules/cron-trigger/services/cron-trigger-v2.service.ts index a4282937b3d95..0a042f665f2f9 100644 --- a/packages/twenty-server/src/engine/metadata-modules/cron-trigger/services/cron-trigger-v2.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/cron-trigger/services/cron-trigger-v2.service.ts @@ -2,6 +2,7 @@ import { Injectable } from '@nestjs/common'; import { isDefined } from 'twenty-shared/utils'; +import { ApplicationService } from 'src/engine/core-modules/application/application.service'; import { CreateCronTriggerInput } from 'src/engine/metadata-modules/cron-trigger/dtos/create-cron-trigger.input'; import { CronTriggerIdInput } from 'src/engine/metadata-modules/cron-trigger/dtos/cron-trigger-id.input'; import { UpdateCronTriggerInput } from 'src/engine/metadata-modules/cron-trigger/dtos/update-cron-trigger.input'; @@ -23,12 +24,20 @@ export class CronTriggerV2Service { constructor( private readonly flatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService, private readonly workspaceMigrationValidateBuildAndRunService: WorkspaceMigrationValidateBuildAndRunService, + private readonly applicationService: ApplicationService, ) {} async createOne( cronTriggerInput: CreateCronTriggerInput, workspaceId: string, ) { + const { workspaceCustomFlatApplication } = + await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow( + { + workspaceId, + }, + ); + const flatEntityMaps = await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps( { @@ -43,6 +52,7 @@ export class CronTriggerV2Service { { createCronTriggerInput: cronTriggerInput, workspaceId, + workspaceCustomApplicationId: workspaceCustomFlatApplication.id, }, ); diff --git a/packages/twenty-server/src/engine/metadata-modules/cron-trigger/utils/from-create-cron-trigger-input-to-flat-cron-trigger.util.ts b/packages/twenty-server/src/engine/metadata-modules/cron-trigger/utils/from-create-cron-trigger-input-to-flat-cron-trigger.util.ts index 7af92a743f4b5..1e274aafa4232 100644 --- a/packages/twenty-server/src/engine/metadata-modules/cron-trigger/utils/from-create-cron-trigger-input-to-flat-cron-trigger.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/cron-trigger/utils/from-create-cron-trigger-input-to-flat-cron-trigger.util.ts @@ -6,18 +6,21 @@ import { type FlatCronTrigger } from 'src/engine/metadata-modules/cron-trigger/t export const fromCreateCronTriggerInputToFlatCronTrigger = ({ createCronTriggerInput, workspaceId, + workspaceCustomApplicationId, }: { createCronTriggerInput: CreateCronTriggerInput; workspaceId: string; + workspaceCustomApplicationId: string; }): FlatCronTrigger => { const now = new Date(); + const id = v4(); return { - id: v4(), - universalIdentifier: createCronTriggerInput.universalIdentifier ?? v4(), + id, + universalIdentifier: createCronTriggerInput.universalIdentifier ?? id, settings: createCronTriggerInput.settings, serverlessFunctionId: createCronTriggerInput.serverlessFunctionId, - applicationId: createCronTriggerInput.applicationId ?? null, + applicationId: workspaceCustomApplicationId, workspaceId, createdAt: now, updatedAt: now, diff --git a/packages/twenty-server/src/engine/metadata-modules/database-event-trigger/database-event-trigger.module.ts b/packages/twenty-server/src/engine/metadata-modules/database-event-trigger/database-event-trigger.module.ts index 441dcbd59411f..be891e6d911ab 100644 --- a/packages/twenty-server/src/engine/metadata-modules/database-event-trigger/database-event-trigger.module.ts +++ b/packages/twenty-server/src/engine/metadata-modules/database-event-trigger/database-event-trigger.module.ts @@ -1,6 +1,7 @@ import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; +import { ApplicationModule } from 'src/engine/core-modules/application/application.module'; import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; import { DatabaseEventTriggerEntity } from 'src/engine/metadata-modules/database-event-trigger/entities/database-event-trigger.entity'; import { CallDatabaseEventTriggerJobsJob } from 'src/engine/metadata-modules/database-event-trigger/jobs/call-database-event-trigger-jobs.job'; @@ -14,6 +15,7 @@ import { WorkspaceMigrationV2Module } from 'src/engine/workspace-manager/workspa @Module({ imports: [ TypeOrmModule.forFeature([WorkspaceEntity, DatabaseEventTriggerEntity]), + ApplicationModule, WorkspaceManyOrAllFlatEntityMapsCacheModule, PermissionsModule, WorkspaceMigrationV2Module, diff --git a/packages/twenty-server/src/engine/metadata-modules/database-event-trigger/services/database-event-trigger-v2.service.ts b/packages/twenty-server/src/engine/metadata-modules/database-event-trigger/services/database-event-trigger-v2.service.ts index 8ed046b4d585f..848fe399e54c8 100644 --- a/packages/twenty-server/src/engine/metadata-modules/database-event-trigger/services/database-event-trigger-v2.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/database-event-trigger/services/database-event-trigger-v2.service.ts @@ -2,6 +2,7 @@ import { Injectable } from '@nestjs/common'; import { isDefined } from 'twenty-shared/utils'; +import { ApplicationService } from 'src/engine/core-modules/application/application.service'; import { CreateDatabaseEventTriggerInput } from 'src/engine/metadata-modules/database-event-trigger/dtos/create-database-event-trigger.input'; import { DatabaseEventTriggerIdInput } from 'src/engine/metadata-modules/database-event-trigger/dtos/database-event-trigger-id.input'; import { UpdateDatabaseEventTriggerInput } from 'src/engine/metadata-modules/database-event-trigger/dtos/update-database-event-trigger.input'; @@ -23,12 +24,20 @@ export class DatabaseEventTriggerV2Service { constructor( private readonly flatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService, private readonly workspaceMigrationValidateBuildAndRunService: WorkspaceMigrationValidateBuildAndRunService, + private readonly applicationService: ApplicationService, ) {} async createOne( databaseEventTriggerInput: CreateDatabaseEventTriggerInput, workspaceId: string, ) { + const { workspaceCustomFlatApplication } = + await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow( + { + workspaceId, + }, + ); + const flatEntityMaps = await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps( { @@ -47,6 +56,7 @@ export class DatabaseEventTriggerV2Service { fromCreateDatabaseEventTriggerInputToFlatDatabaseEventTrigger({ createDatabaseEventTriggerInput: databaseEventTriggerInput, workspaceId, + workspaceCustomApplicationId: workspaceCustomFlatApplication.id, }); const validateAndBuildResult = diff --git a/packages/twenty-server/src/engine/metadata-modules/database-event-trigger/utils/from-create-database-event-trigger-input-to-flat-database-event-trigger.util.ts b/packages/twenty-server/src/engine/metadata-modules/database-event-trigger/utils/from-create-database-event-trigger-input-to-flat-database-event-trigger.util.ts index d42ae02e9d0a4..86d49ac46df67 100644 --- a/packages/twenty-server/src/engine/metadata-modules/database-event-trigger/utils/from-create-database-event-trigger-input-to-flat-database-event-trigger.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/database-event-trigger/utils/from-create-database-event-trigger-input-to-flat-database-event-trigger.util.ts @@ -6,21 +6,24 @@ import { type FlatDatabaseEventTrigger } from 'src/engine/metadata-modules/datab export const fromCreateDatabaseEventTriggerInputToFlatDatabaseEventTrigger = ({ createDatabaseEventTriggerInput, workspaceId, + workspaceCustomApplicationId, }: { createDatabaseEventTriggerInput: CreateDatabaseEventTriggerInput; workspaceId: string; + workspaceCustomApplicationId: string; }): FlatDatabaseEventTrigger => { const now = new Date(); + const id = uuidV4(); return { - id: uuidV4(), + id, universalIdentifier: - createDatabaseEventTriggerInput.universalIdentifier ?? uuidV4(), + createDatabaseEventTriggerInput.universalIdentifier ?? id, settings: createDatabaseEventTriggerInput.settings, serverlessFunctionId: createDatabaseEventTriggerInput.serverlessFunctionId, workspaceId, createdAt: now, updatedAt: now, - applicationId: createDatabaseEventTriggerInput.applicationId ?? null, + applicationId: workspaceCustomApplicationId, }; }; diff --git a/packages/twenty-server/src/engine/metadata-modules/field-metadata/field-metadata.module.ts b/packages/twenty-server/src/engine/metadata-modules/field-metadata/field-metadata.module.ts index e13cd8fc10f2d..4b7bc6194c9d4 100644 --- a/packages/twenty-server/src/engine/metadata-modules/field-metadata/field-metadata.module.ts +++ b/packages/twenty-server/src/engine/metadata-modules/field-metadata/field-metadata.module.ts @@ -9,6 +9,7 @@ import { NestjsQueryTypeOrmModule } from '@ptc-org/nestjs-query-typeorm'; import { TypeORMModule } from 'src/database/typeorm/typeorm.module'; import { ActorModule } from 'src/engine/core-modules/actor/actor.module'; +import { ApplicationModule } from 'src/engine/core-modules/application/application.module'; import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module'; import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard'; import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module'; @@ -60,6 +61,7 @@ import { UpdateFieldInput } from './dtos/update-field.input'; DataSourceModule, TypeORMModule, ActorModule, + ApplicationModule, FeatureFlagModule, ViewModule, ViewFieldModule, diff --git a/packages/twenty-server/src/engine/metadata-modules/field-metadata/services/field-metadata.service-v2.ts b/packages/twenty-server/src/engine/metadata-modules/field-metadata/services/field-metadata.service-v2.ts index 4e0de4386dcad..b12b0df3fe264 100644 --- a/packages/twenty-server/src/engine/metadata-modules/field-metadata/services/field-metadata.service-v2.ts +++ b/packages/twenty-server/src/engine/metadata-modules/field-metadata/services/field-metadata.service-v2.ts @@ -5,6 +5,7 @@ import { TypeOrmQueryService } from '@ptc-org/nestjs-query-typeorm'; import { isDefined } from 'twenty-shared/utils'; import { FindOneOptions, Repository } from 'typeorm'; +import { ApplicationService } from 'src/engine/core-modules/application/application.service'; import { type CreateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/create-field.input'; import { type DeleteOneFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/delete-field.input'; import { type UpdateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/update-field.input'; @@ -32,6 +33,7 @@ export class FieldMetadataServiceV2 extends TypeOrmQueryService, private readonly flatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService, private readonly workspaceMigrationValidateBuildAndRunService: WorkspaceMigrationValidateBuildAndRunService, + private readonly applicationService: ApplicationService, ) { super(fieldMetadataRepository); } @@ -291,6 +293,13 @@ export class FieldMetadataServiceV2 extends TypeOrmQueryService; workspaceId: string; + workspaceCustomApplicationId: string; } & Pick; export const fromCreateFieldInputToFlatFieldMetadatasToCreate = async ({ createFieldInput: rawCreateFieldInput, workspaceId, flatObjectMetadataMaps: existingFlatObjectMetadataMaps, + workspaceCustomApplicationId, }: FromCreateFieldInputToFlatObjectMetadataArgs): Promise< FieldInputTranspilationResult<{ flatFieldMetadatas: FlatFieldMetadata[]; @@ -71,6 +73,7 @@ export const fromCreateFieldInputToFlatFieldMetadatasToCreate = async ({ createFieldInput, workspaceId, fieldMetadataId, + workspaceCustomApplicationId, }); switch (createFieldInput.type) { @@ -83,6 +86,7 @@ export const fromCreateFieldInputToFlatFieldMetadatasToCreate = async ({ existingFlatObjectMetadataMaps, sourceFlatObjectMetadata: parentFlatObjectMetadata, workspaceId, + workspaceCustomApplicationId, }); } case FieldMetadataType.RELATION: { @@ -94,6 +98,7 @@ export const fromCreateFieldInputToFlatFieldMetadatasToCreate = async ({ type: createFieldInput.type, }, workspaceId, + workspaceCustomApplicationId, }); } case FieldMetadataType.RATING: { diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/utils/from-morph-relation-create-field-input-to-flat-field-metadatas.util.ts b/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/utils/from-morph-relation-create-field-input-to-flat-field-metadatas.util.ts index 90aaeb7162169..ac9b3c1ebe93b 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/utils/from-morph-relation-create-field-input-to-flat-field-metadatas.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/utils/from-morph-relation-create-field-input-to-flat-field-metadatas.util.ts @@ -21,12 +21,14 @@ type FromMorphRelationCreateFieldInputToFlatFieldMetadatasArgs = { existingFlatObjectMetadataMaps: FlatEntityMaps; sourceFlatObjectMetadata: FlatObjectMetadata; workspaceId: string; + workspaceCustomApplicationId: string; }; export const fromMorphRelationCreateFieldInputToFlatFieldMetadatas = async ({ createFieldInput, existingFlatObjectMetadataMaps, sourceFlatObjectMetadata, workspaceId, + workspaceCustomApplicationId, }: FromMorphRelationCreateFieldInputToFlatFieldMetadatasArgs): Promise< FieldInputTranspilationResult<{ flatFieldMetadatas: FlatFieldMetadata[]; @@ -90,6 +92,7 @@ export const fromMorphRelationCreateFieldInputToFlatFieldMetadatas = async ({ targetFlatObjectMetadata, workspaceId, morphId, + workspaceCustomApplicationId, }); return { diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/utils/from-relation-create-field-input-to-flat-field-metadatas.util.ts b/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/utils/from-relation-create-field-input-to-flat-field-metadatas.util.ts index 04ab543590173..06ba47486cea4 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/utils/from-relation-create-field-input-to-flat-field-metadatas.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/utils/from-relation-create-field-input-to-flat-field-metadatas.util.ts @@ -21,12 +21,14 @@ type FromRelationCreateFieldInputToFlatFieldMetadataArgs = { existingFlatObjectMetadataMaps: FlatEntityMaps; sourceFlatObjectMetadata: FlatObjectMetadata; workspaceId: string; + workspaceCustomApplicationId: string; }; export const fromRelationCreateFieldInputToFlatFieldMetadatas = async ({ existingFlatObjectMetadataMaps, sourceFlatObjectMetadata, createFieldInput, workspaceId, + workspaceCustomApplicationId, }: FromRelationCreateFieldInputToFlatFieldMetadataArgs): Promise< FieldInputTranspilationResult > => { @@ -67,6 +69,7 @@ export const fromRelationCreateFieldInputToFlatFieldMetadatas = async ({ sourceFlatObjectMetadata, targetFlatObjectMetadata, workspaceId, + workspaceCustomApplicationId, }); return { diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/utils/generate-index-for-flat-field-metadata.util.ts b/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/utils/generate-index-for-flat-field-metadata.util.ts index 0de64f1a0f8db..80cb8501447c9 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/utils/generate-index-for-flat-field-metadata.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/utils/generate-index-for-flat-field-metadata.util.ts @@ -44,7 +44,7 @@ export const generateIndexForFlatFieldMetadata = ({ universalIdentifier: indexId, updatedAt: createdAt, workspaceId, - applicationId: null, + applicationId: flatFieldMetadata.applicationId, }, flatObjectMetadata, }, diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/utils/generate-morph-or-relation-flat-field-metadata-pair.util.ts b/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/utils/generate-morph-or-relation-flat-field-metadata-pair.util.ts index d361c18c9468d..1167e01656175 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/utils/generate-morph-or-relation-flat-field-metadata-pair.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/utils/generate-morph-or-relation-flat-field-metadata-pair.util.ts @@ -1,7 +1,7 @@ import { FieldMetadataType, - RelationType, RelationOnDeleteAction, + RelationType, } from 'twenty-shared/types'; import { v4 } from 'uuid'; @@ -46,6 +46,7 @@ type GenerateMorphOrRelationFlatFieldMetadataPairArgs = { > & { type: MorphOrRelationFieldMetadataType }; workspaceId: string; morphId?: string | null; + workspaceCustomApplicationId: string; }; export type SourceTargetMorphOrRelationFlatFieldAndFlatIndex = { @@ -58,6 +59,7 @@ export const generateMorphOrRelationFlatFieldMetadataPair = ({ sourceFlatObjectMetadata, targetFlatObjectMetadata, workspaceId, + workspaceCustomApplicationId, sourceFlatObjectMetadataJoinColumnName, morphId = null, }: GenerateMorphOrRelationFlatFieldMetadataPairArgs): SourceTargetMorphOrRelationFlatFieldAndFlatIndex => { @@ -78,6 +80,7 @@ export const generateMorphOrRelationFlatFieldMetadataPair = ({ createFieldInput, workspaceId, fieldMetadataId: sourceRelationTargetFieldMetadataId, + workspaceCustomApplicationId, }), morphId, objectMetadataId: sourceFlatObjectMetadata.id, @@ -116,6 +119,7 @@ export const generateMorphOrRelationFlatFieldMetadataPair = ({ createFieldInput: targetCreateFieldInput, workspaceId, fieldMetadataId: targetRelationTargetFieldMetadataId, + workspaceCustomApplicationId, }), type: FieldMetadataType.RELATION, defaultValue: null, diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/utils/get-default-flat-field-metadata-from-create-field-input.util.ts b/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/utils/get-default-flat-field-metadata-from-create-field-input.util.ts index 8d86e548f816e..f9a822d08ebf1 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/utils/get-default-flat-field-metadata-from-create-field-input.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/utils/get-default-flat-field-metadata-from-create-field-input.util.ts @@ -9,11 +9,13 @@ type GetDefaultFlatFieldMetadataArgs = { fieldMetadataId: string; createFieldInput: Omit; workspaceId: string; + workspaceCustomApplicationId: string; }; export const getDefaultFlatFieldMetadata = ({ createFieldInput, fieldMetadataId, workspaceId, + workspaceCustomApplicationId, }: GetDefaultFlatFieldMetadataArgs) => { const { defaultValue, settings } = extractAndSanitizeObjectStringFields( createFieldInput, @@ -56,7 +58,7 @@ export const getDefaultFlatFieldMetadata = ({ updatedAt: createdAt, isUIReadOnly: createFieldInput.isUIReadOnly ?? false, morphId: null, - applicationId: createFieldInput.applicationId ?? null, + applicationId: workspaceCustomApplicationId, viewFilterIds: [], viewGroupIds: [], kanbanAggregateOperationViewIds: [], diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/utils/from-create-object-input-to-flat-object-metadata-and-flat-field-metadatas-to-create.util.ts b/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/utils/from-create-object-input-to-flat-object-metadata-and-flat-field-metadatas-to-create.util.ts index 554fbfdef8a51..4d5c528fee3ac 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/utils/from-create-object-input-to-flat-object-metadata-and-flat-field-metadatas-to-create.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/utils/from-create-object-input-to-flat-object-metadata-and-flat-field-metadatas-to-create.util.ts @@ -17,11 +17,13 @@ type FromCreateObjectInputToFlatObjectMetadataAndFlatFieldMetadatasToCreateArgs { createObjectInput: CreateObjectInput; workspaceId: string; + workspaceCustomApplicationId: string; } & Pick; export const fromCreateObjectInputToFlatObjectMetadataAndFlatFieldMetadatasToCreate = ({ createObjectInput: rawCreateObjectInput, workspaceId, + workspaceCustomApplicationId, flatObjectMetadataMaps: existingFlatObjectMetadataMaps, }: FromCreateObjectInputToFlatObjectMetadataAndFlatFieldMetadatasToCreateArgs): { flatObjectMetadataToCreate: FlatObjectMetadata; @@ -48,7 +50,7 @@ export const fromCreateObjectInputToFlatObjectMetadataAndFlatFieldMetadatasToCre buildDefaultFlatFieldMetadatasForCustomObject({ flatObjectMetadata: { id: objectMetadataId, - applicationId: createObjectInput.applicationId ?? null, + applicationId: workspaceCustomApplicationId, }, workspaceId, }); @@ -81,7 +83,7 @@ export const fromCreateObjectInputToFlatObjectMetadataAndFlatFieldMetadatasToCre shortcut: createObjectInput.shortcut ?? null, standardId: createObjectInput.standardId ?? null, standardOverrides: null, - applicationId: createObjectInput.applicationId ?? null, + applicationId: workspaceCustomApplicationId, universalIdentifier: objectMetadataId, targetTableName: 'DEPRECATED', workspaceId, diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-view-field/utils/from-create-view-field-input-to-flat-view-field-to-create.util.ts b/packages/twenty-server/src/engine/metadata-modules/flat-view-field/utils/from-create-view-field-input-to-flat-view-field-to-create.util.ts index 27eec01202db5..f6d2883a149fd 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-view-field/utils/from-create-view-field-input-to-flat-view-field-to-create.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-view-field/utils/from-create-view-field-input-to-flat-view-field-to-create.util.ts @@ -8,11 +8,13 @@ import { DEFAULT_VIEW_FIELD_SIZE } from 'src/engine/workspace-manager/standard-o export type FromCreateViewFieldInputToFlatViewFieldToCreateArgs = { createViewFieldInput: CreateViewFieldInput; workspaceId: string; + workspaceCustomApplicationId: string; }; export const fromCreateViewFieldInputToFlatViewFieldToCreate = ({ createViewFieldInput: rawCreateViewFieldInput, workspaceId, + workspaceCustomApplicationId, }: FromCreateViewFieldInputToFlatViewFieldToCreateArgs): FlatViewField => { const { fieldMetadataId, viewId, ...createViewFieldInput } = trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties( @@ -37,6 +39,6 @@ export const fromCreateViewFieldInputToFlatViewFieldToCreate = ({ size: createViewFieldInput.size ?? DEFAULT_VIEW_FIELD_SIZE, position: createViewFieldInput.position ?? 0, aggregateOperation: createViewFieldInput.aggregateOperation ?? null, - applicationId: createViewFieldInput.applicationId ?? null, + applicationId: workspaceCustomApplicationId, }; }; diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-view-filter/utils/from-create-view-filter-input-to-flat-view-filter-to-create.util.ts b/packages/twenty-server/src/engine/metadata-modules/flat-view-filter/utils/from-create-view-filter-input-to-flat-view-filter-to-create.util.ts index 5c1019d2a30a5..4e0966a59b7ab 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-view-filter/utils/from-create-view-filter-input-to-flat-view-filter-to-create.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-view-filter/utils/from-create-view-filter-input-to-flat-view-filter-to-create.util.ts @@ -8,9 +8,11 @@ import { type CreateViewFilterInput } from 'src/engine/metadata-modules/view-fil export const fromCreateViewFilterInputToFlatViewFilterToCreate = ({ createViewFilterInput: rawCreateViewFilterInput, workspaceId, + workspaceCustomApplicationId, }: { createViewFilterInput: CreateViewFilterInput; workspaceId: string; + workspaceCustomApplicationId: string; }): FlatViewFilter => { const { fieldMetadataId, viewId, value, ...createViewFilterInput } = trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties( @@ -44,6 +46,6 @@ export const fromCreateViewFilterInputToFlatViewFilterToCreate = ({ positionInViewFilterGroup: createViewFilterInput.positionInViewFilterGroup ?? null, subFieldName: createViewFilterInput.subFieldName ?? null, - applicationId: createViewFilterInput.applicationId ?? null, + applicationId: workspaceCustomApplicationId, }; }; diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-view-group/utils/from-create-view-group-input-to-flat-view-group-to-create.util.ts b/packages/twenty-server/src/engine/metadata-modules/flat-view-group/utils/from-create-view-group-input-to-flat-view-group-to-create.util.ts index 85d8ab7fbc464..872bcac15a3c8 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-view-group/utils/from-create-view-group-input-to-flat-view-group-to-create.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-view-group/utils/from-create-view-group-input-to-flat-view-group-to-create.util.ts @@ -7,9 +7,11 @@ import { type CreateViewGroupInput } from 'src/engine/metadata-modules/view-grou export const fromCreateViewGroupInputToFlatViewGroupToCreate = ({ createViewGroupInput: rawCreateViewGroupInput, workspaceId, + workspaceCustomApplicationId, }: { createViewGroupInput: CreateViewGroupInput; workspaceId: string; + workspaceCustomApplicationId: string; }): FlatViewGroup => { const { fieldMetadataId, viewId, ...createViewGroupInput } = trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties( @@ -33,6 +35,6 @@ export const fromCreateViewGroupInputToFlatViewGroupToCreate = ({ isVisible: createViewGroupInput.isVisible ?? true, fieldValue: createViewGroupInput.fieldValue, position: createViewGroupInput.position ?? 0, - applicationId: createViewGroupInput.applicationId ?? null, + applicationId: workspaceCustomApplicationId, }; }; diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-view/utils/from-create-view-input-to-flat-view-to-create.util.ts b/packages/twenty-server/src/engine/metadata-modules/flat-view/utils/from-create-view-input-to-flat-view-to-create.util.ts index f8aadb163a5f5..6cd9697e07333 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-view/utils/from-create-view-input-to-flat-view-to-create.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-view/utils/from-create-view-input-to-flat-view-to-create.util.ts @@ -11,10 +11,12 @@ export const fromCreateViewInputToFlatViewToCreate = ({ createViewInput: rawCreateViewInput, workspaceId, createdByUserWorkspaceId, + workspaceCustomApplicationId, }: { createViewInput: CreateViewInput; workspaceId: string; createdByUserWorkspaceId?: string; + workspaceCustomApplicationId: string; }): FlatView => { const { objectMetadataId, ...createViewInput } = trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties( @@ -52,6 +54,6 @@ export const fromCreateViewInputToFlatViewToCreate = ({ viewFieldIds: [], viewFilterIds: [], viewGroupIds: [], - applicationId: createViewInput.applicationId ?? null, + applicationId: workspaceCustomApplicationId, }; }; 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 1b15ed9d76548..305275bbbb352 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 @@ -5,6 +5,7 @@ import { TypeOrmQueryService } from '@ptc-org/nestjs-query-typeorm'; import { fromArrayToUniqueKeyRecord, isDefined } from 'twenty-shared/utils'; import { FindManyOptions, FindOneOptions, Repository } from 'typeorm'; +import { ApplicationService } from 'src/engine/core-modules/application/application.service'; import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service'; import { computeFlatEntityMapsFromTo } from 'src/engine/metadata-modules/flat-entity/utils/compute-flat-entity-maps-from-to.util'; import { findManyFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-many-flat-entity-by-id-in-flat-entity-maps-or-throw.util'; @@ -43,6 +44,7 @@ export class ObjectMetadataServiceV2 extends TypeOrmQueryService { + const { workspaceCustomFlatApplication } = + await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow( + { + workspaceId, + }, + ); const { flatObjectMetadataMaps: existingFlatObjectMetadataMaps, flatViewMaps: existingFlatViewMaps, @@ -354,6 +362,7 @@ export class ObjectMetadataServiceV2 extends TypeOrmQueryService & { id: string }> => [ - { - id: v4(), - standardId: BASE_OBJECT_STANDARD_FIELD_IDS.id, - type: FieldMetadataType.UUID, - name: 'id', - label: 'Id', - icon: 'Icon123', - description: 'Id', - isNullable: false, - isActive: true, - isCustom: false, - isSystem: true, - isUIReadOnly: true, - workspaceId, - defaultValue: 'uuid', - }, - { - id: v4(), - standardId: CUSTOM_OBJECT_STANDARD_FIELD_IDS.name, - type: FieldMetadataType.TEXT, - name: 'name', - label: 'Name', - icon: 'IconAbc', - description: 'Name', - isNullable: false, - isActive: true, - isCustom: false, - isUIReadOnly: false, - workspaceId, - defaultValue: "''", - }, - { - id: v4(), - standardId: BASE_OBJECT_STANDARD_FIELD_IDS.createdAt, - type: FieldMetadataType.DATE_TIME, - name: 'createdAt', - label: 'Creation date', - icon: 'IconCalendar', - description: 'Creation date', - isNullable: false, - isActive: true, - isCustom: false, - isUIReadOnly: false, - workspaceId, - defaultValue: 'now', - }, - { - id: v4(), - standardId: BASE_OBJECT_STANDARD_FIELD_IDS.updatedAt, - type: FieldMetadataType.DATE_TIME, - name: 'updatedAt', - label: 'Last update', - icon: 'IconCalendarClock', - description: 'Last time the record was changed', - isNullable: false, - isActive: true, - isCustom: false, - isSystem: false, - isUIReadOnly: false, - workspaceId, - defaultValue: 'now', - }, - { - id: v4(), - standardId: BASE_OBJECT_STANDARD_FIELD_IDS.deletedAt, - type: FieldMetadataType.DATE_TIME, - name: 'deletedAt', - label: 'Deleted at', - icon: 'IconCalendarClock', - description: 'Deletion date', - isNullable: true, - isActive: true, - isCustom: false, - isSystem: false, - isUIReadOnly: true, - workspaceId, - defaultValue: null, - }, - { - id: v4(), - standardId: CUSTOM_OBJECT_STANDARD_FIELD_IDS.createdBy, - type: FieldMetadataType.ACTOR, - name: 'createdBy', - label: 'Created by', - icon: 'IconCreativeCommonsSa', - description: 'The creator of the record', - isNullable: false, - isActive: true, - isCustom: false, - isSystem: false, - isUIReadOnly: true, - workspaceId, - defaultValue: { name: "''", source: "'MANUAL'" }, - }, - { - id: v4(), - standardId: CUSTOM_OBJECT_STANDARD_FIELD_IDS.position, - type: FieldMetadataType.POSITION, - name: 'position', - label: 'Position', - icon: 'IconHierarchy2', - description: 'Position', - isNullable: false, - isActive: true, - isCustom: false, - isSystem: true, - isUIReadOnly: false, - workspaceId, - defaultValue: 0, - }, -]; diff --git a/packages/twenty-server/src/engine/metadata-modules/object-metadata/utils/build-default-flat-field-metadatas-for-custom-object.util.ts b/packages/twenty-server/src/engine/metadata-modules/object-metadata/utils/build-default-flat-field-metadatas-for-custom-object.util.ts index 831cc31b239e2..954b028274ec4 100644 --- a/packages/twenty-server/src/engine/metadata-modules/object-metadata/utils/build-default-flat-field-metadatas-for-custom-object.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/object-metadata/utils/build-default-flat-field-metadatas-for-custom-object.util.ts @@ -3,11 +3,7 @@ import { v4 } from 'uuid'; import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type'; -import { - BASE_OBJECT_STANDARD_FIELD_IDS, - CUSTOM_OBJECT_STANDARD_FIELD_IDS, -} from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids'; -import { createDeterministicUuid } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/create-deterministic-uuid.util'; +import { BASE_OBJECT_STANDARD_FIELD_IDS, CUSTOM_OBJECT_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids'; import { getTsVectorColumnExpressionFromFields } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/get-ts-vector-column-expression.util'; type BuildDefaultFlatFieldMetadataForCustomObjectArgs = { @@ -24,9 +20,10 @@ export const buildDefaultFlatFieldMetadatasForCustomObject = ({ flatObjectMetadata: { id: objectMetadataId, applicationId }, }: BuildDefaultFlatFieldMetadataForCustomObjectArgs) => { const createdAt = new Date(); + const idFieldId = v4(); const idField: FlatFieldMetadata = { type: FieldMetadataType.UUID, - id: v4(), + id: idFieldId, viewFieldIds: [], viewGroupIds: [], kanbanAggregateOperationViewIds: [], @@ -34,10 +31,7 @@ export const buildDefaultFlatFieldMetadatasForCustomObject = ({ isLabelSyncedWithName: false, isUnique: true, objectMetadataId, - universalIdentifier: createDeterministicUuid([ - objectMetadataId, - BASE_OBJECT_STANDARD_FIELD_IDS.id, - ]), + universalIdentifier: idFieldId, workspaceId, standardId: BASE_OBJECT_STANDARD_FIELD_IDS.id, name: 'id', @@ -63,9 +57,10 @@ export const buildDefaultFlatFieldMetadatasForCustomObject = ({ applicationId: applicationId ?? null, }; + const nameFieldId = v4(); const nameField: FlatFieldMetadata = { type: FieldMetadataType.TEXT, - id: v4(), + id: nameFieldId, viewFieldIds: [], viewGroupIds: [], kanbanAggregateOperationViewIds: [], @@ -73,10 +68,7 @@ export const buildDefaultFlatFieldMetadatasForCustomObject = ({ isLabelSyncedWithName: false, isUnique: false, objectMetadataId, - universalIdentifier: createDeterministicUuid([ - objectMetadataId, - CUSTOM_OBJECT_STANDARD_FIELD_IDS.name, - ]), + universalIdentifier: nameFieldId, workspaceId, standardId: CUSTOM_OBJECT_STANDARD_FIELD_IDS.name, name: 'name', @@ -102,9 +94,10 @@ export const buildDefaultFlatFieldMetadatasForCustomObject = ({ applicationId: applicationId ?? null, }; + const createdAtFieldId = v4(); const createdAtField: FlatFieldMetadata = { type: FieldMetadataType.DATE_TIME, - id: v4(), + id: createdAtFieldId, viewFieldIds: [], viewGroupIds: [], kanbanAggregateOperationViewIds: [], @@ -112,10 +105,7 @@ export const buildDefaultFlatFieldMetadatasForCustomObject = ({ isLabelSyncedWithName: false, isUnique: false, objectMetadataId, - universalIdentifier: createDeterministicUuid([ - objectMetadataId, - BASE_OBJECT_STANDARD_FIELD_IDS.createdAt, - ]), + universalIdentifier: createdAtFieldId, workspaceId, standardId: BASE_OBJECT_STANDARD_FIELD_IDS.createdAt, name: 'createdAt', @@ -141,9 +131,10 @@ export const buildDefaultFlatFieldMetadatasForCustomObject = ({ applicationId: applicationId ?? null, }; + const updatedAtFieldId = v4(); const updatedAtField: FlatFieldMetadata = { type: FieldMetadataType.DATE_TIME, - id: v4(), + id: updatedAtFieldId, viewFieldIds: [], viewGroupIds: [], kanbanAggregateOperationViewIds: [], @@ -151,10 +142,7 @@ export const buildDefaultFlatFieldMetadatasForCustomObject = ({ isLabelSyncedWithName: false, isUnique: false, objectMetadataId, - universalIdentifier: createDeterministicUuid([ - objectMetadataId, - BASE_OBJECT_STANDARD_FIELD_IDS.updatedAt, - ]), + universalIdentifier: updatedAtFieldId, workspaceId, standardId: BASE_OBJECT_STANDARD_FIELD_IDS.updatedAt, name: 'updatedAt', @@ -180,9 +168,10 @@ export const buildDefaultFlatFieldMetadatasForCustomObject = ({ applicationId: applicationId ?? null, }; + const deletedAtFieldId = v4(); const deletedAtField: FlatFieldMetadata = { type: FieldMetadataType.DATE_TIME, - id: v4(), + id: deletedAtFieldId, viewFieldIds: [], viewGroupIds: [], kanbanAggregateOperationViewIds: [], @@ -190,10 +179,7 @@ export const buildDefaultFlatFieldMetadatasForCustomObject = ({ isLabelSyncedWithName: false, isUnique: false, objectMetadataId, - universalIdentifier: createDeterministicUuid([ - objectMetadataId, - BASE_OBJECT_STANDARD_FIELD_IDS.deletedAt, - ]), + universalIdentifier: deletedAtFieldId, workspaceId, standardId: BASE_OBJECT_STANDARD_FIELD_IDS.deletedAt, name: 'deletedAt', @@ -219,9 +205,10 @@ export const buildDefaultFlatFieldMetadatasForCustomObject = ({ applicationId: applicationId ?? null, }; + const createdByFieldId = v4(); const createdByField: FlatFieldMetadata = { type: FieldMetadataType.ACTOR, - id: v4(), + id: createdByFieldId, viewFieldIds: [], viewGroupIds: [], kanbanAggregateOperationViewIds: [], @@ -229,10 +216,7 @@ export const buildDefaultFlatFieldMetadatasForCustomObject = ({ isLabelSyncedWithName: false, isUnique: false, objectMetadataId, - universalIdentifier: createDeterministicUuid([ - objectMetadataId, - CUSTOM_OBJECT_STANDARD_FIELD_IDS.createdBy, - ]), + universalIdentifier: createdByFieldId, workspaceId, standardId: CUSTOM_OBJECT_STANDARD_FIELD_IDS.createdBy, name: 'createdBy', @@ -257,9 +241,10 @@ export const buildDefaultFlatFieldMetadatasForCustomObject = ({ applicationId: applicationId ?? null, }; + const positionFieldId = v4(); const positionField: FlatFieldMetadata = { type: FieldMetadataType.POSITION, - id: v4(), + id: positionFieldId, viewFieldIds: [], viewGroupIds: [], kanbanAggregateOperationViewIds: [], @@ -267,10 +252,7 @@ export const buildDefaultFlatFieldMetadatasForCustomObject = ({ isLabelSyncedWithName: false, isUnique: false, objectMetadataId, - universalIdentifier: createDeterministicUuid([ - objectMetadataId, - CUSTOM_OBJECT_STANDARD_FIELD_IDS.position, - ]), + universalIdentifier: positionFieldId, workspaceId, standardId: CUSTOM_OBJECT_STANDARD_FIELD_IDS.position, name: 'position', @@ -296,20 +278,18 @@ export const buildDefaultFlatFieldMetadatasForCustomObject = ({ applicationId: applicationId ?? null, }; + const searchVectorFieldId = v4(); const searchVectorField: FlatFieldMetadata = { type: FieldMetadataType.TS_VECTOR, viewFieldIds: [], viewGroupIds: [], kanbanAggregateOperationViewIds: [], calendarViewIds: [], - id: v4(), + id: searchVectorFieldId, isLabelSyncedWithName: false, isUnique: false, objectMetadataId, - universalIdentifier: createDeterministicUuid([ - objectMetadataId, - CUSTOM_OBJECT_STANDARD_FIELD_IDS.searchVector, - ]), + universalIdentifier: searchVectorFieldId, workspaceId, standardId: CUSTOM_OBJECT_STANDARD_FIELD_IDS.searchVector, name: 'searchVector', diff --git a/packages/twenty-server/src/engine/metadata-modules/object-metadata/utils/build-default-relation-flat-field-metadatas-for-custom-object.util.ts b/packages/twenty-server/src/engine/metadata-modules/object-metadata/utils/build-default-relation-flat-field-metadatas-for-custom-object.util.ts index 9ea3048099a83..0914570d17fb1 100644 --- a/packages/twenty-server/src/engine/metadata-modules/object-metadata/utils/build-default-relation-flat-field-metadatas-for-custom-object.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/object-metadata/utils/build-default-relation-flat-field-metadatas-for-custom-object.util.ts @@ -1,7 +1,7 @@ +import { type STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; import { FieldMetadataType, RelationOnDeleteAction } from 'twenty-shared/types'; import { capitalize, isDefined } from 'twenty-shared/utils'; import { v4 } from 'uuid'; -import { type STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface'; @@ -16,13 +16,9 @@ import { } from 'src/engine/metadata-modules/object-metadata/object-metadata.exception'; import { buildDescriptionForRelationFieldMetadataOnFromField } from 'src/engine/metadata-modules/object-metadata/utils/build-description-for-relation-field-on-from-field.util'; import { buildDescriptionForRelationFieldMetadataOnToField } from 'src/engine/metadata-modules/object-metadata/utils/build-description-for-relation-field-on-to-field.util'; -import { - CUSTOM_OBJECT_STANDARD_FIELD_IDS, - STANDARD_OBJECT_FIELD_IDS, -} from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids'; +import { STANDARD_OBJECT_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids'; import { STANDARD_OBJECT_ICONS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-object-icons'; import { - createDeterministicUuid, createRelationDeterministicUuid, } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/create-deterministic-uuid.util'; @@ -49,17 +45,6 @@ const generateSourceFlatFieldMetadata = ({ STANDARD_OBJECT_ICONS[ targetFlatObjectMetadata.nameSingular as keyof typeof STANDARD_OBJECT_ICONS ] || 'IconBuildingSkyscraper'; - const standardId = - CUSTOM_OBJECT_STANDARD_FIELD_IDS[ - targetFlatObjectMetadata.namePlural as keyof typeof CUSTOM_OBJECT_STANDARD_FIELD_IDS - ]; - - if (!isDefined(standardId)) { - throw new ObjectMetadataException( - `Standard field ID not found for target object ${targetFlatObjectMetadata.namePlural}`, - ObjectMetadataExceptionCode.INTERNAL_SERVER_ERROR, - ); - } return { calendarViewIds: [], @@ -89,16 +74,13 @@ const generateSourceFlatFieldMetadata = ({ settings: { relationType: RelationType.ONE_TO_MANY, }, - standardId, + standardId: null, standardOverrides: null, type: FieldMetadataType.RELATION, - universalIdentifier: createDeterministicUuid([ - sourceFlatObjectMetadata.id, - standardId, - ]), + universalIdentifier: sourceFieldMetadataId, workspaceId, morphId: null, - applicationId: sourceFlatObjectMetadata.applicationId ?? null, + applicationId: sourceFlatObjectMetadata.applicationId, }; }; @@ -165,11 +147,8 @@ const generateTargetFlatFieldMetadata = ({ relationTargetFieldMetadataId: sourceFlatFieldMetadata.id, relationTargetObjectMetadataId: sourceFlatObjectMetadata.id, standardOverrides: null, - universalIdentifier: createDeterministicUuid([ - targetFlatObjectMetadata.id, - standardId, - ]), - applicationId: sourceFlatObjectMetadata.applicationId ?? null, + universalIdentifier: sourceFlatFieldMetadata.relationTargetFieldMetadataId, + applicationId: sourceFlatObjectMetadata.applicationId, }; }; diff --git a/packages/twenty-server/src/engine/metadata-modules/role/role.module.ts b/packages/twenty-server/src/engine/metadata-modules/role/role.module.ts index c55b5c65a5693..8629ba92d9888 100644 --- a/packages/twenty-server/src/engine/metadata-modules/role/role.module.ts +++ b/packages/twenty-server/src/engine/metadata-modules/role/role.module.ts @@ -2,6 +2,7 @@ import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; import { ApiKeyModule } from 'src/engine/core-modules/api-key/api-key.module'; +import { ApplicationModule } from 'src/engine/core-modules/application/application.module'; import { FileModule } from 'src/engine/core-modules/file/file.module'; import { UserWorkspaceEntity } from 'src/engine/core-modules/user-workspace/user-workspace.entity'; import { UserWorkspaceModule } from 'src/engine/core-modules/user-workspace/user-workspace.module'; @@ -30,6 +31,7 @@ import { WorkspacePermissionsCacheModule } from 'src/engine/metadata-modules/wor PermissionFlagModule, WorkspacePermissionsCacheModule, FileModule, + ApplicationModule, ], providers: [RoleService, RoleResolver], exports: [RoleService], diff --git a/packages/twenty-server/src/engine/metadata-modules/role/role.service.ts b/packages/twenty-server/src/engine/metadata-modules/role/role.service.ts index 59f5fd90a1c4e..b3252f63a77c0 100644 --- a/packages/twenty-server/src/engine/metadata-modules/role/role.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/role/role.service.ts @@ -3,7 +3,9 @@ import { InjectRepository } from '@nestjs/typeorm'; import { msg } from '@lingui/core/macro'; import { isDefined } from 'twenty-shared/utils'; import { Repository } from 'typeorm'; +import { v4 } from 'uuid'; +import { ApplicationService } from 'src/engine/core-modules/application/application.service'; import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; import { MEMBER_ROLE_LABEL } from 'src/engine/metadata-modules/permissions/constants/member-role-label.constants'; import { @@ -29,6 +31,7 @@ export class RoleService { private readonly roleRepository: Repository, private readonly userRoleService: UserRoleService, private readonly workspacePermissionsCacheService: WorkspacePermissionsCacheService, + private readonly applicationService: ApplicationService, ) {} public async getWorkspaceRoles(workspaceId: string): Promise { @@ -70,10 +73,18 @@ export class RoleService { input: CreateRoleInput; workspaceId: string; }): Promise { + const { workspaceCustomFlatApplication } = + await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow( + { + workspaceId, + }, + ); + await this.validateRoleInputOrThrow({ input, workspaceId }); + const id = input.id ?? v4(); const role = await this.roleRepository.save({ - id: input.id, + id, label: input.label, description: input.description, icon: input.icon, @@ -88,6 +99,8 @@ export class RoleService { canBeAssignedToApiKeys: input.canBeAssignedToApiKeys, isEditable: true, workspaceId, + applicationId: workspaceCustomFlatApplication.id, + universalIdentifier: id, }); await this.workspacePermissionsCacheService.recomputeRolesPermissionsCache({ @@ -198,9 +211,13 @@ export class RoleService { public async createMemberRole({ workspaceId, + applicationId, }: { + applicationId: string; workspaceId: string; }): Promise { + const id = v4(); + return this.roleRepository.save({ label: MEMBER_ROLE_LABEL, description: 'Member role', @@ -216,15 +233,22 @@ export class RoleService { canBeAssignedToApiKeys: false, isEditable: true, workspaceId, + applicationId, + id, + universalIdentifier: id, }); } // Only used for dev seeding and testing public async createGuestRole({ workspaceId, + applicationId, }: { workspaceId: string; + applicationId: string; }): Promise { + const id = v4(); + return this.roleRepository.save({ label: 'Guest', description: 'Guest role', @@ -240,6 +264,9 @@ export class RoleService { canBeAssignedToApiKeys: false, isEditable: false, workspaceId, + applicationId, + id, + universalIdentifier: id, }); } diff --git a/packages/twenty-server/src/engine/metadata-modules/route-trigger/route-trigger.module.ts b/packages/twenty-server/src/engine/metadata-modules/route-trigger/route-trigger.module.ts index 9209ee210ad9b..30821fe0fb339 100644 --- a/packages/twenty-server/src/engine/metadata-modules/route-trigger/route-trigger.module.ts +++ b/packages/twenty-server/src/engine/metadata-modules/route-trigger/route-trigger.module.ts @@ -1,6 +1,7 @@ import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; +import { ApplicationModule } from 'src/engine/core-modules/application/application.module'; import { TokenModule } from 'src/engine/core-modules/auth/token/token.module'; import { WorkspaceDomainsModule } from 'src/engine/core-modules/domain/workspace-domains/workspace-domains.module'; import { WorkspaceManyOrAllFlatEntityMapsCacheModule } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.module'; @@ -17,6 +18,7 @@ import { WorkspaceMigrationV2Module } from 'src/engine/workspace-manager/workspa @Module({ imports: [ TypeOrmModule.forFeature([RouteTriggerEntity]), + ApplicationModule, TokenModule, WorkspaceDomainsModule, ServerlessFunctionModule, diff --git a/packages/twenty-server/src/engine/metadata-modules/route-trigger/services/route-trigger-v2.service.ts b/packages/twenty-server/src/engine/metadata-modules/route-trigger/services/route-trigger-v2.service.ts index 2227b62509116..a8c4ba14a44aa 100644 --- a/packages/twenty-server/src/engine/metadata-modules/route-trigger/services/route-trigger-v2.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/route-trigger/services/route-trigger-v2.service.ts @@ -2,6 +2,7 @@ import { Injectable } from '@nestjs/common'; import { isDefined } from 'twenty-shared/utils'; +import { ApplicationService } from 'src/engine/core-modules/application/application.service'; import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service'; import { computeFlatEntityMapsFromTo } from 'src/engine/metadata-modules/flat-entity/utils/compute-flat-entity-maps-from-to.util'; import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util'; @@ -23,12 +24,20 @@ export class RouteTriggerV2Service { constructor( private readonly flatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService, private readonly workspaceMigrationValidateBuildAndRunService: WorkspaceMigrationValidateBuildAndRunService, + private readonly applicationService: ApplicationService, ) {} async createOne( routeTriggerInput: CreateRouteTriggerInput, workspaceId: string, ) { + const { workspaceCustomFlatApplication } = + await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow( + { + workspaceId, + }, + ); + const flatEntityMaps = await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps( { @@ -43,6 +52,7 @@ export class RouteTriggerV2Service { fromCreateRouteTriggerInputToFlatRouteTrigger({ createRouteTriggerInput: routeTriggerInput, workspaceId, + workspaceCustomApplicationId: workspaceCustomFlatApplication.id, }); const validateAndBuildResult = diff --git a/packages/twenty-server/src/engine/metadata-modules/route-trigger/utils/from-create-route-trigger-input-to-flat-route-trigger.util.ts b/packages/twenty-server/src/engine/metadata-modules/route-trigger/utils/from-create-route-trigger-input-to-flat-route-trigger.util.ts index 1dc5cdd98b138..510f2d3f124e4 100644 --- a/packages/twenty-server/src/engine/metadata-modules/route-trigger/utils/from-create-route-trigger-input-to-flat-route-trigger.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/route-trigger/utils/from-create-route-trigger-input-to-flat-route-trigger.util.ts @@ -6,16 +6,18 @@ import { type FlatRouteTrigger } from 'src/engine/metadata-modules/route-trigger export const fromCreateRouteTriggerInputToFlatRouteTrigger = ({ createRouteTriggerInput, workspaceId, + workspaceCustomApplicationId, }: { createRouteTriggerInput: CreateRouteTriggerInput; workspaceId: string; + workspaceCustomApplicationId: string; }): FlatRouteTrigger => { const now = new Date(); + const id = uuidV4(); return { - id: uuidV4(), - universalIdentifier: - createRouteTriggerInput.universalIdentifier ?? uuidV4(), + id, + universalIdentifier: createRouteTriggerInput.universalIdentifier ?? id, path: createRouteTriggerInput.path, isAuthRequired: createRouteTriggerInput.isAuthRequired, httpMethod: createRouteTriggerInput.httpMethod, @@ -23,6 +25,6 @@ export const fromCreateRouteTriggerInputToFlatRouteTrigger = ({ workspaceId, createdAt: now, updatedAt: now, - applicationId: createRouteTriggerInput.applicationId ?? null, + applicationId: workspaceCustomApplicationId, }; }; diff --git a/packages/twenty-server/src/engine/metadata-modules/serverless-function/serverless-function.module.ts b/packages/twenty-server/src/engine/metadata-modules/serverless-function/serverless-function.module.ts index af2edd96f8476..920ea6a3fc796 100644 --- a/packages/twenty-server/src/engine/metadata-modules/serverless-function/serverless-function.module.ts +++ b/packages/twenty-server/src/engine/metadata-modules/serverless-function/serverless-function.module.ts @@ -3,6 +3,7 @@ import { TypeOrmModule } from '@nestjs/typeorm'; import { NestjsQueryTypeOrmModule } from '@ptc-org/nestjs-query-typeorm'; +import { ApplicationModule } from 'src/engine/core-modules/application/application.module'; import { AuditModule } from 'src/engine/core-modules/audit/audit.module'; import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity'; import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module'; @@ -35,6 +36,7 @@ import { WorkspaceMigrationV2Module } from 'src/engine/workspace-manager/workspa ]), FileModule, ThrottlerModule, + ApplicationModule, AuditModule, FeatureFlagModule, PermissionsModule, diff --git a/packages/twenty-server/src/engine/metadata-modules/serverless-function/services/serverless-function-v2.service.ts b/packages/twenty-server/src/engine/metadata-modules/serverless-function/services/serverless-function-v2.service.ts index 2e3b6bee226fd..677df79b588c2 100644 --- a/packages/twenty-server/src/engine/metadata-modules/serverless-function/services/serverless-function-v2.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/serverless-function/services/serverless-function-v2.service.ts @@ -2,6 +2,7 @@ import { Injectable } from '@nestjs/common'; import { isDefined } from 'twenty-shared/utils'; +import { ApplicationService } from 'src/engine/core-modules/application/application.service'; import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service'; import { computeFlatEntityMapsFromTo } from 'src/engine/metadata-modules/flat-entity/utils/compute-flat-entity-maps-from-to.util'; import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util'; @@ -23,6 +24,7 @@ export class ServerlessFunctionV2Service { constructor( private readonly flatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService, private readonly workspaceMigrationValidateBuildAndRunService: WorkspaceMigrationValidateBuildAndRunService, + private readonly applicationService: ApplicationService, ) {} async createOne({ @@ -34,6 +36,13 @@ export class ServerlessFunctionV2Service { }; workspaceId: string; }) { + const { workspaceCustomFlatApplication } = + await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow( + { + workspaceId, + }, + ); + const flatEntityMaps = await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps( { @@ -49,6 +58,7 @@ export class ServerlessFunctionV2Service { fromCreateServerlessFunctionInputToFlatServerlessFunction({ createServerlessFunctionInput, workspaceId, + workspaceCustomApplicationId: workspaceCustomFlatApplication.id, }); const validateAndBuildResult = diff --git a/packages/twenty-server/src/engine/metadata-modules/serverless-function/utils/from-create-serverless-function-input-to-flat-serverless-function.util.ts b/packages/twenty-server/src/engine/metadata-modules/serverless-function/utils/from-create-serverless-function-input-to-flat-serverless-function.util.ts index ae248c071dcf1..3eb63f5506cd5 100644 --- a/packages/twenty-server/src/engine/metadata-modules/serverless-function/utils/from-create-serverless-function-input-to-flat-serverless-function.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/serverless-function/utils/from-create-serverless-function-input-to-flat-serverless-function.util.ts @@ -14,11 +14,13 @@ export type FromCreateServerlessFunctionInputToFlatServerlessFunctionArgs = { serverlessFunctionLayerId: string; }; workspaceId: string; + workspaceCustomApplicationId: string; }; export const fromCreateServerlessFunctionInputToFlatServerlessFunction = ({ createServerlessFunctionInput: rawCreateServerlessFunctionInput, workspaceId, + workspaceCustomApplicationId, }: FromCreateServerlessFunctionInputToFlatServerlessFunctionArgs): FlatServerlessFunction => { const id = v4(); const currentDate = new Date(); @@ -35,13 +37,13 @@ export const fromCreateServerlessFunctionInputToFlatServerlessFunction = ({ handlerName: rawCreateServerlessFunctionInput.handlerName ?? DEFAULT_HANDLER_NAME, universalIdentifier: - rawCreateServerlessFunctionInput.universalIdentifier ?? v4(), + rawCreateServerlessFunctionInput.universalIdentifier ?? id, createdAt: currentDate, updatedAt: currentDate, deletedAt: null, latestVersion: null, publishedVersions: [], - applicationId: rawCreateServerlessFunctionInput.applicationId ?? null, + applicationId: workspaceCustomApplicationId, runtime: ServerlessFunctionRuntime.NODE22, timeoutSeconds: rawCreateServerlessFunctionInput.timeoutSeconds ?? 300, serverlessFunctionLayerId: diff --git a/packages/twenty-server/src/engine/metadata-modules/view-field/services/view-field-v2.service.ts b/packages/twenty-server/src/engine/metadata-modules/view-field/services/view-field-v2.service.ts index 08cbd33513c66..1b5db84daff4b 100644 --- a/packages/twenty-server/src/engine/metadata-modules/view-field/services/view-field-v2.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/view-field/services/view-field-v2.service.ts @@ -4,6 +4,7 @@ import { InjectRepository } from '@nestjs/typeorm'; import { isDefined } from 'twenty-shared/utils'; import { IsNull, Repository } from 'typeorm'; +import { ApplicationService } from 'src/engine/core-modules/application/application.service'; import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service'; import { computeFlatEntityMapsFromTo } from 'src/engine/metadata-modules/flat-entity/utils/compute-flat-entity-maps-from-to.util'; import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util'; @@ -32,6 +33,7 @@ export class ViewFieldV2Service { private readonly workspaceManyOrAllFlatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService, @InjectRepository(ViewFieldEntity) private readonly viewFieldRepository: Repository, + private readonly applicationService: ApplicationService, ) {} async createOne({ @@ -67,6 +69,13 @@ export class ViewFieldV2Service { return []; } + const { workspaceCustomFlatApplication } = + await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow( + { + workspaceId, + }, + ); + const { flatViewFieldMaps: existingFlatViewFieldMaps, flatViewMaps, @@ -89,6 +98,7 @@ export class ViewFieldV2Service { fromCreateViewFieldInputToFlatViewFieldToCreate({ createViewFieldInput, workspaceId, + workspaceCustomApplicationId: workspaceCustomFlatApplication.id, }), ); diff --git a/packages/twenty-server/src/engine/metadata-modules/view-field/view-field.module.ts b/packages/twenty-server/src/engine/metadata-modules/view-field/view-field.module.ts index 21d3e3983dab7..5d167a5c993ec 100644 --- a/packages/twenty-server/src/engine/metadata-modules/view-field/view-field.module.ts +++ b/packages/twenty-server/src/engine/metadata-modules/view-field/view-field.module.ts @@ -1,6 +1,7 @@ import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; +import { ApplicationModule } from 'src/engine/core-modules/application/application.module'; import { WorkspaceManyOrAllFlatEntityMapsCacheModule } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.module'; import { PermissionsModule } from 'src/engine/metadata-modules/permissions/permissions.module'; import { ViewFieldController } from 'src/engine/metadata-modules/view-field/controllers/view-field.controller'; @@ -16,6 +17,7 @@ import { WorkspaceMigrationV2Module } from 'src/engine/workspace-manager/workspa imports: [ TypeOrmModule.forFeature([ViewFieldEntity, ViewEntity]), WorkspaceCacheStorageModule, + ApplicationModule, PermissionsModule, WorkspaceMigrationV2Module, WorkspaceManyOrAllFlatEntityMapsCacheModule, diff --git a/packages/twenty-server/src/engine/metadata-modules/view-filter/services/view-filter-v2.service.ts b/packages/twenty-server/src/engine/metadata-modules/view-filter/services/view-filter-v2.service.ts index 74c23a49b48d6..edab766c754aa 100644 --- a/packages/twenty-server/src/engine/metadata-modules/view-filter/services/view-filter-v2.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/view-filter/services/view-filter-v2.service.ts @@ -2,6 +2,7 @@ import { Injectable } from '@nestjs/common'; import { isDefined } from 'twenty-shared/utils'; +import { ApplicationService } from 'src/engine/core-modules/application/application.service'; import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service'; import { computeFlatEntityMapsFromTo } from 'src/engine/metadata-modules/flat-entity/utils/compute-flat-entity-maps-from-to.util'; import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util'; @@ -22,6 +23,7 @@ export class ViewFilterV2Service { constructor( private readonly workspaceMigrationValidateBuildAndRunService: WorkspaceMigrationValidateBuildAndRunService, private readonly flatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService, + private readonly applicationService: ApplicationService, ) {} async createOne({ @@ -31,6 +33,13 @@ export class ViewFilterV2Service { createViewFilterInput: CreateViewFilterInput; workspaceId: string; }): Promise { + const { workspaceCustomFlatApplication } = + await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow( + { + workspaceId, + }, + ); + const { flatViewFilterMaps: existingFlatViewFilterMaps, flatViewMaps, @@ -52,6 +61,7 @@ export class ViewFilterV2Service { fromCreateViewFilterInputToFlatViewFilterToCreate({ createViewFilterInput, workspaceId, + workspaceCustomApplicationId: workspaceCustomFlatApplication.id, }); const validateAndBuildResult = diff --git a/packages/twenty-server/src/engine/metadata-modules/view-filter/view-filter.module.ts b/packages/twenty-server/src/engine/metadata-modules/view-filter/view-filter.module.ts index e99f93f6cdee0..4b98784badc02 100644 --- a/packages/twenty-server/src/engine/metadata-modules/view-filter/view-filter.module.ts +++ b/packages/twenty-server/src/engine/metadata-modules/view-filter/view-filter.module.ts @@ -1,6 +1,7 @@ import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; +import { ApplicationModule } from 'src/engine/core-modules/application/application.module'; import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module'; import { WorkspaceManyOrAllFlatEntityMapsCacheModule } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.module'; import { PermissionsModule } from 'src/engine/metadata-modules/permissions/permissions.module'; @@ -18,6 +19,7 @@ import { WorkspaceMigrationV2Module } from 'src/engine/workspace-manager/workspa imports: [ TypeOrmModule.forFeature([ViewFilterEntity, ViewEntity]), WorkspaceCacheStorageModule, + ApplicationModule, FeatureFlagModule, PermissionsModule, WorkspaceMigrationV2Module, diff --git a/packages/twenty-server/src/engine/metadata-modules/view-group/services/view-group-v2.service.ts b/packages/twenty-server/src/engine/metadata-modules/view-group/services/view-group-v2.service.ts index 188a16e8d1162..7b7ffaa89ca91 100644 --- a/packages/twenty-server/src/engine/metadata-modules/view-group/services/view-group-v2.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/view-group/services/view-group-v2.service.ts @@ -2,6 +2,7 @@ import { Injectable } from '@nestjs/common'; import { isDefined } from 'twenty-shared/utils'; +import { ApplicationService } from 'src/engine/core-modules/application/application.service'; import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service'; import { computeFlatEntityMapsFromTo } from 'src/engine/metadata-modules/flat-entity/utils/compute-flat-entity-maps-from-to.util'; import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util'; @@ -27,6 +28,7 @@ export class ViewGroupV2Service { constructor( private readonly workspaceMigrationValidateBuildAndRunService: WorkspaceMigrationValidateBuildAndRunService, private readonly flatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService, + private readonly applicationService: ApplicationService, ) {} async createOne({ @@ -62,6 +64,13 @@ export class ViewGroupV2Service { return []; } + const { workspaceCustomFlatApplication } = + await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow( + { + workspaceId, + }, + ); + const { flatViewGroupMaps: existingFlatViewGroupMaps, flatViewMaps, @@ -82,6 +91,7 @@ export class ViewGroupV2Service { fromCreateViewGroupInputToFlatViewGroupToCreate({ createViewGroupInput, workspaceId, + workspaceCustomApplicationId: workspaceCustomFlatApplication.id, }), ); diff --git a/packages/twenty-server/src/engine/metadata-modules/view-group/view-group.module.ts b/packages/twenty-server/src/engine/metadata-modules/view-group/view-group.module.ts index 35ef3c32e75d4..9fe5ae2de8f02 100644 --- a/packages/twenty-server/src/engine/metadata-modules/view-group/view-group.module.ts +++ b/packages/twenty-server/src/engine/metadata-modules/view-group/view-group.module.ts @@ -1,6 +1,7 @@ import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; +import { ApplicationModule } from 'src/engine/core-modules/application/application.module'; import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module'; import { WorkspaceManyOrAllFlatEntityMapsCacheModule } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.module'; import { PermissionsModule } from 'src/engine/metadata-modules/permissions/permissions.module'; @@ -18,6 +19,7 @@ import { WorkspaceMigrationV2Module } from 'src/engine/workspace-manager/workspa imports: [ TypeOrmModule.forFeature([ViewGroupEntity, ViewEntity]), WorkspaceCacheStorageModule, + ApplicationModule, FeatureFlagModule, PermissionsModule, WorkspaceMigrationV2Module, diff --git a/packages/twenty-server/src/engine/metadata-modules/view/services/view-v2.service.ts b/packages/twenty-server/src/engine/metadata-modules/view/services/view-v2.service.ts index 11d513b6efd01..8e8f8776bf1b5 100644 --- a/packages/twenty-server/src/engine/metadata-modules/view/services/view-v2.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/view/services/view-v2.service.ts @@ -2,6 +2,7 @@ import { Injectable } from '@nestjs/common'; import { isDefined } from 'twenty-shared/utils'; +import { ApplicationService } from 'src/engine/core-modules/application/application.service'; import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service'; import { computeFlatEntityMapsFromTo } from 'src/engine/metadata-modules/flat-entity/utils/compute-flat-entity-maps-from-to.util'; import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util'; @@ -22,6 +23,7 @@ export class ViewV2Service { constructor( private readonly workspaceMigrationValidateBuildAndRunService: WorkspaceMigrationValidateBuildAndRunService, private readonly flatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService, + private readonly applicationService: ApplicationService, ) {} async createOne({ @@ -33,6 +35,13 @@ export class ViewV2Service { workspaceId: string; createdByUserWorkspaceId?: string; }): Promise { + const { workspaceCustomFlatApplication } = + await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow( + { + workspaceId, + }, + ); + const { flatObjectMetadataMaps, flatViewMaps: existingFlatViewMaps, @@ -52,6 +61,7 @@ export class ViewV2Service { createViewInput, workspaceId, createdByUserWorkspaceId, + workspaceCustomApplicationId: workspaceCustomFlatApplication.id, }); const validateAndBuildResult = diff --git a/packages/twenty-server/src/engine/metadata-modules/view/view.module.ts b/packages/twenty-server/src/engine/metadata-modules/view/view.module.ts index 852da8b7c5f25..d42dbca7d0015 100644 --- a/packages/twenty-server/src/engine/metadata-modules/view/view.module.ts +++ b/packages/twenty-server/src/engine/metadata-modules/view/view.module.ts @@ -1,6 +1,7 @@ import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; +import { ApplicationModule } from 'src/engine/core-modules/application/application.module'; import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module'; import { I18nModule } from 'src/engine/core-modules/i18n/i18n.module'; import { WorkspaceManyOrAllFlatEntityMapsCacheModule } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.module'; @@ -32,6 +33,7 @@ import { WorkspaceMigrationV2Module } from 'src/engine/workspace-manager/workspa ViewGroupModule, ViewSortModule, I18nModule, + ApplicationModule, FeatureFlagModule, PermissionsModule, UserRoleModule, diff --git a/packages/twenty-server/src/engine/workspace-flat-map-cache/services/workspace-flat-map-cache.service.ts b/packages/twenty-server/src/engine/workspace-flat-map-cache/services/workspace-flat-map-cache.service.ts index 806205b074768..46936ab7e0b49 100644 --- a/packages/twenty-server/src/engine/workspace-flat-map-cache/services/workspace-flat-map-cache.service.ts +++ b/packages/twenty-server/src/engine/workspace-flat-map-cache/services/workspace-flat-map-cache.service.ts @@ -8,8 +8,6 @@ import { isDefined } from 'twenty-shared/utils'; import { InjectCacheStorage } from 'src/engine/core-modules/cache-storage/decorators/cache-storage.decorator'; import { CacheStorageService } from 'src/engine/core-modules/cache-storage/services/cache-storage.service'; import { CacheStorageNamespace } from 'src/engine/core-modules/cache-storage/types/cache-storage-namespace.enum'; -import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type'; -import { type FlatEntity } from 'src/engine/metadata-modules/flat-entity/types/flat-entity.type'; import { WORKSPACE_FLAT_MAP_CACHE_KEY } from 'src/engine/workspace-flat-map-cache/decorators/workspace-flat-map-cache.decorator'; import { WorkspaceFlatMapCacheException, @@ -17,9 +15,7 @@ import { } from 'src/engine/workspace-flat-map-cache/exceptions/workspace-flat-map-cache.exception'; @Injectable() -export abstract class WorkspaceFlatMapCacheService< - T extends FlatEntityMaps, -> { +export abstract class WorkspaceFlatMapCacheService { protected readonly logger = new Logger(this.constructor.name); private readonly localCacheFlatMaps = new Map(); diff --git a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/services/dev-seeder-permissions.service.ts b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/services/dev-seeder-permissions.service.ts index 68d03fc34aeed..515338ccc7e48 100644 --- a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/services/dev-seeder-permissions.service.ts +++ b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/services/dev-seeder-permissions.service.ts @@ -4,6 +4,7 @@ import { InjectDataSource, InjectRepository } from '@nestjs/typeorm'; import { WorkspaceActivationStatus } from 'twenty-shared/workspace'; import { DataSource, Repository } from 'typeorm'; +import { ApplicationEntity } from 'src/engine/core-modules/application/application.entity'; import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { FieldPermissionService } from 'src/engine/metadata-modules/object-permission/field-permission/field-permission.service'; @@ -41,7 +42,13 @@ export class DevSeederPermissionsService { private readonly coreDataSource: DataSource, ) {} - public async initPermissions(workspaceId: string) { + public async initPermissions({ + twentyStandardApplication, + workspaceId, + }: { + workspaceId: string; + twentyStandardApplication: ApplicationEntity; + }) { const adminRole = await this.roleRepository.findOne({ where: { standardId: ADMIN_ROLE.standardId, @@ -100,6 +107,7 @@ export class DevSeederPermissionsService { const guestRole = await this.roleService.createGuestRole({ workspaceId, + applicationId: twentyStandardApplication.id, }); await this.userRoleService.assignRoleToUserWorkspace({ @@ -135,6 +143,7 @@ export class DevSeederPermissionsService { const memberRole = await this.roleService.createMemberRole({ workspaceId, + applicationId: twentyStandardApplication.id, }); await this.coreDataSource diff --git a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/seed-core-schema.util.ts b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/seed-core-schema.util.ts index 248e6f4ea850a..9cc6d5b1319d2 100644 --- a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/seed-core-schema.util.ts +++ b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/seed-core-schema.util.ts @@ -13,7 +13,6 @@ import { seedFeatureFlags } from 'src/engine/workspace-manager/dev-seeder/core/u import { seedUserWorkspaces } from 'src/engine/workspace-manager/dev-seeder/core/utils/seed-user-workspaces.util'; import { seedUsers } from 'src/engine/workspace-manager/dev-seeder/core/utils/seed-users.util'; import { createWorkspace } from 'src/engine/workspace-manager/dev-seeder/core/utils/seed-workspace.util'; -import { computeWorkspaceCustomCreateApplicationInput } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/compute-workspace-custom-create-application-input'; import { extractVersionMajorMinorPatch } from 'src/utils/version/extract-version-major-minor-patch'; type SeedCoreSchemaArgs = { @@ -36,14 +35,6 @@ export const seedCoreSchema = async ({ const schemaName = 'core'; const createWorkspaceStaticInput = SEEDER_CREATE_WORKSPACE_INPUT[workspaceId]; - const workspaceCustomApplicationCreateInput = - computeWorkspaceCustomCreateApplicationInput({ - workspace: { - id: workspaceId, - displayName: createWorkspaceStaticInput.displayName, - }, - }); - const version = extractVersionMajorMinorPatch(appVersion); const queryRunner = dataSource.createQueryRunner(); @@ -51,13 +42,14 @@ export const seedCoreSchema = async ({ await queryRunner.startTransaction(); try { - const customWorkspaceApplication = await applicationService.create( - { - ...workspaceCustomApplicationCreateInput, - serverlessFunctionLayerId: null, - }, - queryRunner, - ); + const customWorkspaceApplication = + await applicationService.createWorkspaceCustomApplication( + { + workspaceId, + workspaceDisplayName: createWorkspaceStaticInput.displayName, + }, + queryRunner, + ); await createWorkspace({ queryRunner, @@ -76,6 +68,7 @@ export const seedCoreSchema = async ({ await applicationService.createTwentyStandardApplication( { workspaceId, + skipCacheInvalidation: true, }, queryRunner, ); diff --git a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/metadata/services/dev-seeder-metadata.service.ts b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/metadata/services/dev-seeder-metadata.service.ts index 7c6681135f636..b9e2e52510a93 100644 --- a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/metadata/services/dev-seeder-metadata.service.ts +++ b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/metadata/services/dev-seeder-metadata.service.ts @@ -4,6 +4,7 @@ import { InjectDataSource } from '@nestjs/typeorm'; import { isDefined } from 'twenty-shared/utils'; import { DataSource } from 'typeorm'; +import { FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type'; import { type DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity'; import { CreateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/create-field.input'; import { FieldMetadataServiceV2 } from 'src/engine/metadata-modules/field-metadata/services/field-metadata.service-v2'; @@ -85,9 +86,11 @@ export class DevSeederMetadataService { dataSourceMetadata, workspaceId, featureFlags, + twentyStandardFlatApplication, }: { dataSourceMetadata: DataSourceEntity; workspaceId: string; + twentyStandardFlatApplication: FlatApplication; featureFlags?: Record; }) { const config = this.workspaceConfigs[workspaceId]; @@ -98,6 +101,7 @@ export class DevSeederMetadataService { ); } + // TODO get for (const obj of config.objects) { await this.seedCustomObject({ dataSourceId: dataSourceMetadata.id, @@ -126,6 +130,7 @@ export class DevSeederMetadataService { workspaceId, dataSourceMetadata, featureFlags, + twentyStandardFlatApplication, }); } @@ -181,10 +186,12 @@ export class DevSeederMetadataService { workspaceId, dataSourceMetadata, featureFlags, + twentyStandardFlatApplication, }: { workspaceId: string; dataSourceMetadata: DataSourceEntity; featureFlags?: Record; + twentyStandardFlatApplication: FlatApplication; }): Promise { const createdObjectMetadata = await this.objectMetadataServiceV2.findManyWithinWorkspace(workspaceId); @@ -195,6 +202,7 @@ export class DevSeederMetadataService { objectMetadataItems: createdObjectMetadata, workspaceSchemaName: dataSourceMetadata.schema, featureFlags, + twentyStandardFlatApplication, }); } diff --git a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/services/dev-seeder.service.ts b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/services/dev-seeder.service.ts index 25c17dde7b3c9..02e078a030cfb 100644 --- a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/services/dev-seeder.service.ts +++ b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/services/dev-seeder.service.ts @@ -5,6 +5,8 @@ import { isDefined } from 'twenty-shared/utils'; import { DataSource } from 'typeorm'; import { ApplicationService } from 'src/engine/core-modules/application/application.service'; +import { TWENTY_STANDARD_APPLICATION } from 'src/engine/core-modules/application/constants/twenty-standard-applications'; +import { WorkspaceFlatApplicationMapCacheService } from 'src/engine/core-modules/application/services/workspace-flat-application-map-cache.service'; import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum'; import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service'; import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service'; @@ -21,7 +23,6 @@ import { seedPageLayoutWidgets } from 'src/engine/workspace-manager/dev-seeder/c import { seedPageLayouts } from 'src/engine/workspace-manager/dev-seeder/core/utils/seed-page-layouts.util'; import { DevSeederDataService } from 'src/engine/workspace-manager/dev-seeder/data/services/dev-seeder-data.service'; import { DevSeederMetadataService } from 'src/engine/workspace-manager/dev-seeder/metadata/services/dev-seeder-metadata.service'; -import { TWENTY_STANDARD_APPLICATION } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/twenty-standard-applications'; import { WorkspaceSyncMetadataService } from 'src/engine/workspace-manager/workspace-sync-metadata/workspace-sync-metadata.service'; @Injectable() @@ -38,6 +39,7 @@ export class DevSeederService { private readonly flatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService, private readonly devSeederDataService: DevSeederDataService, private readonly applicationService: ApplicationService, + private readonly workspaceFlatApplicationMapCacheService: WorkspaceFlatApplicationMapCacheService, @InjectDataSource() private readonly coreDataSource: DataSource, ) {} @@ -59,6 +61,10 @@ export class DevSeederService { workspaceId, ); + await this.workspaceFlatApplicationMapCacheService.invalidateCache({ + workspaceId, + }); + const dataSourceMetadata = await this.dataSourceService.createDataSourceMetadata( workspaceId, @@ -80,6 +86,13 @@ export class DevSeederService { ); } + const { twentyStandardFlatApplication } = + await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow( + { + workspaceId, + }, + ); + await this.workspaceSyncMetadataService.synchronize({ workspaceId: workspaceId, dataSourceId: dataSourceMetadata.id, @@ -90,13 +103,17 @@ export class DevSeederService { dataSourceMetadata, workspaceId, featureFlags, + twentyStandardFlatApplication, }); await this.devSeederMetadataService.seedRelations({ workspaceId, }); - await this.devSeederPermissionsService.initPermissions(workspaceId); + await this.devSeederPermissionsService.initPermissions({ + workspaceId, + twentyStandardApplication, + }); await seedPageLayouts(this.coreDataSource, 'core', workspaceId); await seedPageLayoutTabs(this.coreDataSource, 'core', workspaceId); diff --git a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/prefill-core-views.ts b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/prefill-core-views.ts index 0da404bb20087..2f88a42e77bfe 100644 --- a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/prefill-core-views.ts +++ b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/prefill-core-views.ts @@ -1,7 +1,7 @@ import { isString } from '@sniptt/guards'; import { type DataSource, type QueryRunner } from 'typeorm'; -import { v4 } from 'uuid'; +import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type'; import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { ViewFieldEntity } from 'src/engine/metadata-modules/view-field/entities/view-field.entity'; import { ViewFilterEntity } from 'src/engine/metadata-modules/view-filter/entities/view-filter.entity'; @@ -39,6 +39,7 @@ type PrefillCoreViewsArgs = { objectMetadataItems: ObjectMetadataEntity[]; featureFlags?: Record; workspaceSchemaName: string; + twentyStandardFlatApplication: FlatApplication; }; export const prefillCoreViews = async ({ @@ -46,25 +47,32 @@ export const prefillCoreViews = async ({ workspaceId, objectMetadataItems, workspaceSchemaName, + twentyStandardFlatApplication, }: PrefillCoreViewsArgs): Promise => { const views = [ - companiesAllView(objectMetadataItems, true), - peopleAllView(objectMetadataItems, true), - opportunitiesAllView(objectMetadataItems, true), - opportunitiesByStageView(objectMetadataItems, true), - notesAllView(objectMetadataItems, true), - tasksAllView(objectMetadataItems, true), - tasksAssignedToMeView(objectMetadataItems, true), - tasksByStatusView(objectMetadataItems, true), - workflowsAllView(objectMetadataItems, true), - workflowVersionsAllView(objectMetadataItems, true), - workflowRunsAllView(objectMetadataItems, true), - dashboardsAllView(objectMetadataItems, true), - workspaceMembersAllView(objectMetadataItems, true), - messagesAllView(objectMetadataItems, true), - messageThreadsAllView(objectMetadataItems, true), - calendarEventsAllView(objectMetadataItems, true), - ]; + companiesAllView, + peopleAllView, + opportunitiesAllView, + opportunitiesByStageView, + notesAllView, + tasksAllView, + tasksAssignedToMeView, + tasksByStatusView, + workflowsAllView, + workflowVersionsAllView, + workflowRunsAllView, + dashboardsAllView, + workspaceMembersAllView, + messagesAllView, + messageThreadsAllView, + calendarEventsAllView, + ].map((seeder) => + seeder({ + objectMetadataItems, + useCoreNaming: true, + twentyStandardFlatApplication, + }), + ); const queryRunner = coreDataSource.createQueryRunner(); @@ -73,7 +81,12 @@ export const prefillCoreViews = async ({ try { await queryRunner.startTransaction(); - const createdViews = await createCoreViews(queryRunner, workspaceId, views); + const createdViews = await createCoreViews( + queryRunner, + workspaceId, + views, + twentyStandardFlatApplication, + ); await prefillWorkspaceFavorites( createdViews @@ -112,13 +125,9 @@ export const createCoreViews = async ( queryRunner: QueryRunner, workspaceId: string, viewDefinitions: ViewDefinition[], + twentyStandardFlatApplication: FlatApplication, ): Promise => { - const viewDefinitionsWithId = viewDefinitions.map((viewDefinition) => ({ - ...viewDefinition, - id: v4(), - })); - - const coreViews: Partial[] = viewDefinitionsWithId.map( + const coreViews: Partial[] = viewDefinitions.map( ({ id, name, @@ -131,6 +140,8 @@ export const createCoreViews = async ( openRecordIn, kanbanAggregateOperation, kanbanAggregateOperationFieldMetadataId, + applicationId, + universalIdentifier, }) => ({ id, name: isString(name) ? name : name.message || '', @@ -150,13 +161,15 @@ export const createCoreViews = async ( workspaceId, anyFieldFilterValue: null, visibility: ViewVisibility.WORKSPACE, + applicationId, + universalIdentifier, }), ); const viewRepository = queryRunner.manager.getRepository(ViewEntity); const createdViews = await viewRepository.save(coreViews); - for (const viewDefinition of viewDefinitionsWithId) { + for (const viewDefinition of viewDefinitions) { if (viewDefinition.fields && viewDefinition.fields.length > 0) { const coreViewFields: Partial[] = viewDefinition.fields.map((field) => ({ @@ -166,6 +179,8 @@ export const createCoreViews = async ( size: field.size, viewId: viewDefinition.id, workspaceId, + applicationId: twentyStandardFlatApplication.id, + universalIdentifier: field.universalIdentifier, })); const viewFieldRepository = @@ -182,6 +197,8 @@ export const createCoreViews = async ( operand: filter.operand, value: filter.value, workspaceId, + applicationId: twentyStandardFlatApplication.id, + universalIdentifier: filter.universalIdentifier, })); const viewFilterRepository = @@ -203,6 +220,8 @@ export const createCoreViews = async ( position: group.position, viewId: viewDefinition.id, workspaceId, + applicationId: twentyStandardFlatApplication.id, + universalIdentifier: group.universalIdentifier, })); const viewGroupRepository = diff --git a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface.ts b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface.ts index e5e0f42b4621d..5bdd006801aa8 100644 --- a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface.ts +++ b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface.ts @@ -11,13 +11,18 @@ export interface ViewDefinition { type: string; key: string | null; position: number; + applicationId: string; + universalIdentifier: string; icon?: string; isCustom?: boolean; openRecordIn?: ViewOpenRecordInType; kanbanFieldMetadataId?: string; kanbanAggregateOperation?: AggregateOperations; kanbanAggregateOperationFieldMetadataId?: string; + calendarFieldMetadataId?: string; + calendarLayout?: string; fields?: { + universalIdentifier: string; fieldMetadataId: string; position: number; isVisible: boolean; @@ -25,12 +30,14 @@ export interface ViewDefinition { aggregateOperation?: AggregateOperations; }[]; filters?: { + universalIdentifier: string; fieldMetadataId: string; displayValue: string; operand: ViewFilterOperand; value: string; }[]; groups?: { + universalIdentifier: string; fieldMetadataId: string; isVisible: boolean; fieldValue: string; diff --git a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/calendar-events-all.view.ts b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/calendar-events-all.view.ts index 0b2f61e53461b..11d4be3e46008 100644 --- a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/calendar-events-all.view.ts +++ b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/calendar-events-all.view.ts @@ -1,17 +1,26 @@ import { msg } from '@lingui/core/macro'; import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; +import { v4 } from 'uuid'; +import { STANDARD_OBJECTS } from 'src/engine/core-modules/application/constants/standard-object.constant'; +import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type'; import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; +import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface'; import { DEFAULT_VIEW_FIELD_SIZE } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/constants/DEFAULT_VIEW_FIELD_SIZE'; import { BASE_OBJECT_STANDARD_FIELD_IDS, CALENDAR_EVENT_STANDARD_FIELD_IDS, } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids'; -export const calendarEventsAllView = ( - objectMetadataItems: ObjectMetadataEntity[], - useCoreNaming = false, -) => { +export const calendarEventsAllView = ({ + objectMetadataItems, + twentyStandardFlatApplication, + useCoreNaming, +}: { + objectMetadataItems: ObjectMetadataEntity[]; + useCoreNaming?: boolean; + twentyStandardFlatApplication: FlatApplication; +}): ViewDefinition => { const calendarEventObjectMetadata = objectMetadataItems.find( (object) => object.standardId === STANDARD_OBJECT_IDS.calendarEvent, ); @@ -20,7 +29,13 @@ export const calendarEventsAllView = ( throw new Error('CalendarEvent object metadata not found'); } + const viewUniversalIdentifier = + STANDARD_OBJECTS.calendarEvent.views.allCalendarEvents.universalIdentifier; + return { + id: v4(), + universalIdentifier: viewUniversalIdentifier, + applicationId: twentyStandardFlatApplication.id, name: useCoreNaming ? msg`All {objectLabelPlural}` : 'All Calendar Events', objectMetadataId: calendarEventObjectMetadata.id ?? '', type: 'calendar', @@ -45,6 +60,9 @@ export const calendarEventsAllView = ( position: 0, isVisible: true, size: DEFAULT_VIEW_FIELD_SIZE, + universalIdentifier: + STANDARD_OBJECTS.calendarEvent.views.allCalendarEvents.viewFields + .title.universalIdentifier, }, { fieldMetadataId: @@ -55,6 +73,9 @@ export const calendarEventsAllView = ( position: 1, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.calendarEvent.views.allCalendarEvents.viewFields + .startsAt.universalIdentifier, }, { fieldMetadataId: @@ -65,6 +86,9 @@ export const calendarEventsAllView = ( position: 2, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.calendarEvent.views.allCalendarEvents.viewFields + .endsAt.universalIdentifier, }, { fieldMetadataId: @@ -75,6 +99,9 @@ export const calendarEventsAllView = ( position: 3, isVisible: true, size: 100, + universalIdentifier: + STANDARD_OBJECTS.calendarEvent.views.allCalendarEvents.viewFields + .isFullDay.universalIdentifier, }, { fieldMetadataId: @@ -85,6 +112,9 @@ export const calendarEventsAllView = ( position: 4, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.calendarEvent.views.allCalendarEvents.viewFields + .location.universalIdentifier, }, { fieldMetadataId: @@ -96,6 +126,9 @@ export const calendarEventsAllView = ( position: 5, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.calendarEvent.views.allCalendarEvents.viewFields + .conferenceLink.universalIdentifier, }, { fieldMetadataId: @@ -106,6 +139,9 @@ export const calendarEventsAllView = ( position: 6, isVisible: true, size: 100, + universalIdentifier: + STANDARD_OBJECTS.calendarEvent.views.allCalendarEvents.viewFields + .isCanceled.universalIdentifier, }, { fieldMetadataId: @@ -116,6 +152,9 @@ export const calendarEventsAllView = ( position: 7, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.calendarEvent.views.allCalendarEvents.viewFields + .createdAt.universalIdentifier, }, ], }; diff --git a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/companies-all.view.ts b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/companies-all.view.ts index ac7d94b7744aa..6712f77776acf 100644 --- a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/companies-all.view.ts +++ b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/companies-all.view.ts @@ -1,18 +1,27 @@ import { msg } from '@lingui/core/macro'; import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; +import { v4 } from 'uuid'; import { AggregateOperations } from 'src/engine/api/graphql/graphql-query-runner/constants/aggregate-operations.constant'; +import { STANDARD_OBJECTS } from 'src/engine/core-modules/application/constants/standard-object.constant'; +import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type'; import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; +import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface'; import { DEFAULT_VIEW_FIELD_SIZE } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/constants/DEFAULT_VIEW_FIELD_SIZE'; import { BASE_OBJECT_STANDARD_FIELD_IDS, COMPANY_STANDARD_FIELD_IDS, } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids'; -export const companiesAllView = ( - objectMetadataItems: ObjectMetadataEntity[], +export const companiesAllView = ({ + objectMetadataItems, useCoreNaming = false, -) => { + twentyStandardFlatApplication, +}: { + objectMetadataItems: ObjectMetadataEntity[]; + useCoreNaming?: boolean; + twentyStandardFlatApplication: FlatApplication; +}): ViewDefinition => { const companyObjectMetadata = objectMetadataItems.find( (object) => object.standardId === STANDARD_OBJECT_IDS.company, ); @@ -21,7 +30,13 @@ export const companiesAllView = ( throw new Error('Company object metadata not found'); } + const viewUniversalIdentifier = + STANDARD_OBJECTS.company.views.allCompanies.universalIdentifier; + return { + id: v4(), + universalIdentifier: viewUniversalIdentifier, + applicationId: twentyStandardFlatApplication.id, name: useCoreNaming ? msg`All {objectLabelPlural}` : 'All Companies', objectMetadataId: companyObjectMetadata.id ?? '', type: 'table', @@ -39,6 +54,9 @@ export const companiesAllView = ( position: 0, isVisible: true, size: DEFAULT_VIEW_FIELD_SIZE, + universalIdentifier: + STANDARD_OBJECTS.company.views.allCompanies.viewFields.name + .universalIdentifier, }, { fieldMetadataId: @@ -50,6 +68,9 @@ export const companiesAllView = ( isVisible: true, size: 100, aggregateOperation: AggregateOperations.COUNT, + universalIdentifier: + STANDARD_OBJECTS.company.views.allCompanies.viewFields.domainName + .universalIdentifier, }, { fieldMetadataId: @@ -60,6 +81,9 @@ export const companiesAllView = ( position: 2, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.company.views.allCompanies.viewFields.createdBy + .universalIdentifier, }, { fieldMetadataId: @@ -70,6 +94,9 @@ export const companiesAllView = ( position: 3, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.company.views.allCompanies.viewFields.accountOwner + .universalIdentifier, }, { fieldMetadataId: @@ -80,6 +107,9 @@ export const companiesAllView = ( position: 4, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.company.views.allCompanies.viewFields.createdAt + .universalIdentifier, }, { fieldMetadataId: @@ -91,6 +121,9 @@ export const companiesAllView = ( isVisible: true, size: 150, aggregateOperation: AggregateOperations.MAX, + universalIdentifier: + STANDARD_OBJECTS.company.views.allCompanies.viewFields.employees + .universalIdentifier, }, { fieldMetadataId: @@ -102,6 +135,9 @@ export const companiesAllView = ( isVisible: true, size: 170, aggregateOperation: AggregateOperations.PERCENTAGE_EMPTY, + universalIdentifier: + STANDARD_OBJECTS.company.views.allCompanies.viewFields.linkedinLink + .universalIdentifier, }, { fieldMetadataId: @@ -112,6 +148,9 @@ export const companiesAllView = ( isVisible: true, size: 170, aggregateOperation: AggregateOperations.COUNT_NOT_EMPTY, + universalIdentifier: + STANDARD_OBJECTS.company.views.allCompanies.viewFields.address + .universalIdentifier, }, ], }; diff --git a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/custom-all.view.ts b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/custom-all.view.ts deleted file mode 100644 index ae8a315d15e47..0000000000000 --- a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/custom-all.view.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { msg } from '@lingui/core/macro'; - -import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; -import { DEFAULT_VIEW_FIELD_SIZE } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/constants/DEFAULT_VIEW_FIELD_SIZE'; - -export const customAllView = ( - objectMetadataItem: ObjectMetadataEntity, - useCoreNaming = false, -) => { - const nameField = objectMetadataItem.fields.find( - (field) => field.name === 'name', - ); - - const otherFields = objectMetadataItem.fields.filter( - (field) => field.name !== 'name', - ); - - if (!nameField) { - throw new Error( - `Name field not found while creating All ${objectMetadataItem.namePlural} view`, - ); - } - - return { - name: useCoreNaming - ? msg`All {objectLabelPlural}` - : `All ${objectMetadataItem.labelPlural}`, - objectMetadataId: objectMetadataItem.id, - type: 'table', - key: 'INDEX', - position: 0, - icon: 'IconList', - isCustom: false, - kanbanFieldMetadataId: '', - filters: [], - fields: [ - { - fieldMetadataId: - objectMetadataItem.fields.find((field) => field.name === 'name') - ?.id ?? '', - position: 0, - isVisible: true, - size: DEFAULT_VIEW_FIELD_SIZE, - }, - ...otherFields.map((field, index) => ({ - fieldMetadataId: field.id, - position: index + 1, - isVisible: true, - size: DEFAULT_VIEW_FIELD_SIZE, - })), - ], - }; -}; diff --git a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/dashboards-all.view.ts b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/dashboards-all.view.ts index 9886114ef75cf..cccb70c52a50c 100644 --- a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/dashboards-all.view.ts +++ b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/dashboards-all.view.ts @@ -1,17 +1,26 @@ import { msg } from '@lingui/core/macro'; import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; +import { v4 } from 'uuid'; +import { STANDARD_OBJECTS } from 'src/engine/core-modules/application/constants/standard-object.constant'; +import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type'; import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { ViewOpenRecordInType } from 'src/engine/metadata-modules/view/types/view-open-record-in-type.type'; +import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface'; import { BASE_OBJECT_STANDARD_FIELD_IDS, DASHBOARD_STANDARD_FIELD_IDS, } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids'; -export const dashboardsAllView = ( - objectMetadataItems: ObjectMetadataEntity[], +export const dashboardsAllView = ({ + objectMetadataItems, useCoreNaming = false, -) => { + twentyStandardFlatApplication, +}: { + objectMetadataItems: ObjectMetadataEntity[]; + useCoreNaming?: boolean; + twentyStandardFlatApplication: FlatApplication; +}): ViewDefinition => { const dashboardObjectMetadata = objectMetadataItems.find( (object) => object.standardId === STANDARD_OBJECT_IDS.dashboard, ); @@ -20,7 +29,13 @@ export const dashboardsAllView = ( throw new Error('Dashboard object metadata not found'); } + const viewUniversalIdentifier = + STANDARD_OBJECTS.dashboard.views.allDashboards.universalIdentifier; + return { + id: v4(), + universalIdentifier: viewUniversalIdentifier, + applicationId: twentyStandardFlatApplication.id, name: useCoreNaming ? msg`All {objectLabelPlural}` : 'All Dashboards', objectMetadataId: dashboardObjectMetadata.id ?? '', type: 'table', @@ -39,6 +54,9 @@ export const dashboardsAllView = ( position: 0, isVisible: true, size: 200, + universalIdentifier: + STANDARD_OBJECTS.dashboard.views.allDashboards.viewFields.title + .universalIdentifier, }, { fieldMetadataId: @@ -49,6 +67,9 @@ export const dashboardsAllView = ( position: 1, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.dashboard.views.allDashboards.viewFields.createdBy + .universalIdentifier, }, { fieldMetadataId: @@ -59,6 +80,9 @@ export const dashboardsAllView = ( position: 2, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.dashboard.views.allDashboards.viewFields.createdAt + .universalIdentifier, }, { fieldMetadataId: @@ -69,6 +93,9 @@ export const dashboardsAllView = ( position: 3, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.dashboard.views.allDashboards.viewFields.updatedAt + .universalIdentifier, }, ], }; diff --git a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/message-threads-all.view.ts b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/message-threads-all.view.ts index d671745ac37e7..c23ea32c97705 100644 --- a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/message-threads-all.view.ts +++ b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/message-threads-all.view.ts @@ -1,17 +1,26 @@ import { msg } from '@lingui/core/macro'; import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; +import { v4 } from 'uuid'; +import { STANDARD_OBJECTS } from 'src/engine/core-modules/application/constants/standard-object.constant'; +import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type'; import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; +import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface'; import { DEFAULT_VIEW_FIELD_SIZE } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/constants/DEFAULT_VIEW_FIELD_SIZE'; import { BASE_OBJECT_STANDARD_FIELD_IDS, MESSAGE_THREAD_STANDARD_FIELD_IDS, } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids'; -export const messageThreadsAllView = ( - objectMetadataItems: ObjectMetadataEntity[], - useCoreNaming = false, -) => { +export const messageThreadsAllView = ({ + objectMetadataItems, + twentyStandardFlatApplication, + useCoreNaming, +}: { + objectMetadataItems: ObjectMetadataEntity[]; + useCoreNaming?: boolean; + twentyStandardFlatApplication: FlatApplication; +}): ViewDefinition => { const messageThreadObjectMetadata = objectMetadataItems.find( (object) => object.standardId === STANDARD_OBJECT_IDS.messageThread, ); @@ -20,7 +29,13 @@ export const messageThreadsAllView = ( throw new Error('MessageThread object metadata not found'); } + const viewUniversalIdentifier = + STANDARD_OBJECTS.messageThread.views.allMessageThreads.universalIdentifier; + return { + id: v4(), + universalIdentifier: viewUniversalIdentifier, + applicationId: twentyStandardFlatApplication.id, name: useCoreNaming ? msg`All {objectLabelPlural}` : 'All Message Threads', objectMetadataId: messageThreadObjectMetadata.id ?? '', type: 'table', @@ -39,6 +54,9 @@ export const messageThreadsAllView = ( position: 0, isVisible: true, size: DEFAULT_VIEW_FIELD_SIZE, + universalIdentifier: + STANDARD_OBJECTS.messageThread.views.allMessageThreads.viewFields + .messages.universalIdentifier, }, { fieldMetadataId: @@ -49,6 +67,9 @@ export const messageThreadsAllView = ( position: 1, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.messageThread.views.allMessageThreads.viewFields + .createdAt.universalIdentifier, }, ], }; diff --git a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/messages-all.view.ts b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/messages-all.view.ts index 56ac8c18047c4..d29fe8f44632b 100644 --- a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/messages-all.view.ts +++ b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/messages-all.view.ts @@ -1,17 +1,26 @@ import { msg } from '@lingui/core/macro'; import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; +import { v4 } from 'uuid'; +import { STANDARD_OBJECTS } from 'src/engine/core-modules/application/constants/standard-object.constant'; +import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type'; import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; +import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface'; import { DEFAULT_VIEW_FIELD_SIZE } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/constants/DEFAULT_VIEW_FIELD_SIZE'; import { BASE_OBJECT_STANDARD_FIELD_IDS, MESSAGE_STANDARD_FIELD_IDS, } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids'; -export const messagesAllView = ( - objectMetadataItems: ObjectMetadataEntity[], - useCoreNaming = false, -) => { +export const messagesAllView = ({ + objectMetadataItems, + twentyStandardFlatApplication, + useCoreNaming, +}: { + objectMetadataItems: ObjectMetadataEntity[]; + useCoreNaming?: boolean; + twentyStandardFlatApplication: FlatApplication; +}): ViewDefinition => { const messageObjectMetadata = objectMetadataItems.find( (object) => object.standardId === STANDARD_OBJECT_IDS.message, ); @@ -20,7 +29,13 @@ export const messagesAllView = ( throw new Error('Message object metadata not found'); } + const viewUniversalIdentifier = + STANDARD_OBJECTS.message.views.allMessages.universalIdentifier; + return { + id: v4(), + universalIdentifier: viewUniversalIdentifier, + applicationId: twentyStandardFlatApplication.id, name: useCoreNaming ? msg`All {objectLabelPlural}` : 'All Messages', objectMetadataId: messageObjectMetadata.id ?? '', type: 'table', @@ -38,6 +53,9 @@ export const messagesAllView = ( position: 0, isVisible: true, size: DEFAULT_VIEW_FIELD_SIZE, + universalIdentifier: + STANDARD_OBJECTS.message.views.allMessages.viewFields.subject + .universalIdentifier, }, { fieldMetadataId: @@ -48,6 +66,9 @@ export const messagesAllView = ( position: 1, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.message.views.allMessages.viewFields.messageThread + .universalIdentifier, }, { fieldMetadataId: @@ -59,6 +80,9 @@ export const messagesAllView = ( position: 2, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.message.views.allMessages.viewFields + .messageParticipants.universalIdentifier, }, { fieldMetadataId: @@ -69,6 +93,9 @@ export const messagesAllView = ( position: 3, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.message.views.allMessages.viewFields.receivedAt + .universalIdentifier, }, { fieldMetadataId: @@ -79,6 +106,9 @@ export const messagesAllView = ( position: 4, isVisible: true, size: 180, + universalIdentifier: + STANDARD_OBJECTS.message.views.allMessages.viewFields.headerMessageId + .universalIdentifier, }, { fieldMetadataId: @@ -88,6 +118,9 @@ export const messagesAllView = ( position: 5, isVisible: true, size: 200, + universalIdentifier: + STANDARD_OBJECTS.message.views.allMessages.viewFields.text + .universalIdentifier, }, { fieldMetadataId: @@ -98,6 +131,9 @@ export const messagesAllView = ( position: 6, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.message.views.allMessages.viewFields.createdAt + .universalIdentifier, }, ], }; diff --git a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/notes-all.view.ts b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/notes-all.view.ts index c708e28dbb0a8..a5b8527f20be2 100644 --- a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/notes-all.view.ts +++ b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/notes-all.view.ts @@ -1,16 +1,25 @@ import { msg } from '@lingui/core/macro'; import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; +import { v4 } from 'uuid'; +import { STANDARD_OBJECTS } from 'src/engine/core-modules/application/constants/standard-object.constant'; +import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type'; import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; +import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface'; import { BASE_OBJECT_STANDARD_FIELD_IDS, NOTE_STANDARD_FIELD_IDS, } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids'; -export const notesAllView = ( - objectMetadataItems: ObjectMetadataEntity[], +export const notesAllView = ({ + objectMetadataItems, useCoreNaming = false, -) => { + twentyStandardFlatApplication, +}: { + objectMetadataItems: ObjectMetadataEntity[]; + useCoreNaming?: boolean; + twentyStandardFlatApplication: FlatApplication; +}): ViewDefinition => { const noteObjectMetadata = objectMetadataItems.find( (object) => object.standardId === STANDARD_OBJECT_IDS.note, ); @@ -19,7 +28,13 @@ export const notesAllView = ( throw new Error('Note object metadata not found'); } + const viewUniversalIdentifier = + STANDARD_OBJECTS.note.views.allNotes.universalIdentifier; + return { + id: v4(), + universalIdentifier: viewUniversalIdentifier, + applicationId: twentyStandardFlatApplication.id, name: useCoreNaming ? msg`All {objectLabelPlural}` : 'All Notes', objectMetadataId: noteObjectMetadata.id, type: 'table', @@ -37,6 +52,9 @@ export const notesAllView = ( position: 0, isVisible: true, size: 210, + universalIdentifier: + STANDARD_OBJECTS.note.views.allNotes.viewFields.title + .universalIdentifier, }, { fieldMetadataId: @@ -46,6 +64,9 @@ export const notesAllView = ( position: 1, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.note.views.allNotes.viewFields.noteTargets + .universalIdentifier, }, { fieldMetadataId: @@ -55,6 +76,9 @@ export const notesAllView = ( position: 2, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.note.views.allNotes.viewFields.bodyV2 + .universalIdentifier, }, { fieldMetadataId: @@ -64,6 +88,9 @@ export const notesAllView = ( position: 3, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.note.views.allNotes.viewFields.createdBy + .universalIdentifier, }, { fieldMetadataId: @@ -74,18 +101,19 @@ export const notesAllView = ( position: 4, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.note.views.allNotes.viewFields.createdAt + .universalIdentifier, }, /* TODO: Add later, since we don't have real-time it probably doesn't work well? { fieldMetadataId: - objectMetadataMap[STANDARD_OBJECT_IDS.note].fields[ - BASE_OBJECT_STANDARD_FIELD_IDS.updatedAt + objectMetadataMap[STANDARD_OBJECT_IDS.note].fields[.updatedAt ], position: 0, isVisible: true, - size: 210, - }, + size: 210}, */ ], }; diff --git a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/opportunities-all.view.ts b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/opportunities-all.view.ts index 0d1b3de6ec777..679f516c3c47b 100644 --- a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/opportunities-all.view.ts +++ b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/opportunities-all.view.ts @@ -1,14 +1,23 @@ import { msg } from '@lingui/core/macro'; import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; +import { v4 } from 'uuid'; import { AggregateOperations } from 'src/engine/api/graphql/graphql-query-runner/constants/aggregate-operations.constant'; +import { STANDARD_OBJECTS } from 'src/engine/core-modules/application/constants/standard-object.constant'; +import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type'; import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; +import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface'; import { OPPORTUNITY_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids'; -export const opportunitiesAllView = ( - objectMetadataItems: ObjectMetadataEntity[], +export const opportunitiesAllView = ({ + objectMetadataItems, useCoreNaming = false, -) => { + twentyStandardFlatApplication, +}: { + objectMetadataItems: ObjectMetadataEntity[]; + useCoreNaming?: boolean; + twentyStandardFlatApplication: FlatApplication; +}): ViewDefinition => { const opportunityObjectMetadata = objectMetadataItems.find( (object) => object.standardId === STANDARD_OBJECT_IDS.opportunity, ); @@ -17,7 +26,13 @@ export const opportunitiesAllView = ( throw new Error('Opportunity object metadata not found'); } + const viewUniversalIdentifier = + STANDARD_OBJECTS.opportunity.views.allOpportunities.universalIdentifier; + return { + id: v4(), + universalIdentifier: viewUniversalIdentifier, + applicationId: twentyStandardFlatApplication.id, name: useCoreNaming ? msg`All {objectLabelPlural}` : 'All Opportunities', objectMetadataId: opportunityObjectMetadata.id, type: 'table', @@ -35,6 +50,9 @@ export const opportunitiesAllView = ( position: 0, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.opportunity.views.allOpportunities.viewFields.name + .universalIdentifier, }, { fieldMetadataId: @@ -46,6 +64,9 @@ export const opportunitiesAllView = ( isVisible: true, size: 150, aggregateOperation: AggregateOperations.AVG, + universalIdentifier: + STANDARD_OBJECTS.opportunity.views.allOpportunities.viewFields.amount + .universalIdentifier, }, { fieldMetadataId: @@ -56,6 +77,9 @@ export const opportunitiesAllView = ( position: 2, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.opportunity.views.allOpportunities.viewFields + .createdBy.universalIdentifier, }, { fieldMetadataId: @@ -67,6 +91,9 @@ export const opportunitiesAllView = ( isVisible: true, size: 150, aggregateOperation: AggregateOperations.MIN, + universalIdentifier: + STANDARD_OBJECTS.opportunity.views.allOpportunities.viewFields + .closeDate.universalIdentifier, }, { fieldMetadataId: @@ -77,6 +104,9 @@ export const opportunitiesAllView = ( position: 4, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.opportunity.views.allOpportunities.viewFields.company + .universalIdentifier, }, { fieldMetadataId: @@ -88,6 +118,9 @@ export const opportunitiesAllView = ( position: 5, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.opportunity.views.allOpportunities.viewFields + .pointOfContact.universalIdentifier, }, ], }; diff --git a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/opportunity-by-stage.view.ts b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/opportunity-by-stage.view.ts index 59a466aa537d5..0727c7873c03e 100644 --- a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/opportunity-by-stage.view.ts +++ b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/opportunity-by-stage.view.ts @@ -1,14 +1,23 @@ import { msg } from '@lingui/core/macro'; import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; +import { v4 } from 'uuid'; import { AggregateOperations } from 'src/engine/api/graphql/graphql-query-runner/constants/aggregate-operations.constant'; +import { STANDARD_OBJECTS } from 'src/engine/core-modules/application/constants/standard-object.constant'; +import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type'; import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; +import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface'; import { OPPORTUNITY_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids'; -export const opportunitiesByStageView = ( - objectMetadataItems: ObjectMetadataEntity[], +export const opportunitiesByStageView = ({ + objectMetadataItems, useCoreNaming = false, -) => { + twentyStandardFlatApplication, +}: { + objectMetadataItems: ObjectMetadataEntity[]; + useCoreNaming?: boolean; + twentyStandardFlatApplication: FlatApplication; +}): ViewDefinition => { const opportunityObjectMetadata = objectMetadataItems.find( (object) => object.standardId === STANDARD_OBJECT_IDS.opportunity, ); @@ -17,7 +26,13 @@ export const opportunitiesByStageView = ( throw new Error('Opportunity object metadata not found'); } + const viewUniversalIdentifier = + STANDARD_OBJECTS.opportunity.views.byStage.universalIdentifier; + return { + id: v4(), + universalIdentifier: viewUniversalIdentifier, + applicationId: twentyStandardFlatApplication.id, name: useCoreNaming ? msg`By Stage` : 'By Stage', objectMetadataId: opportunityObjectMetadata.id, type: 'kanban', @@ -43,6 +58,9 @@ export const opportunitiesByStageView = ( position: 0, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.opportunity.views.byStage.viewFields.name + .universalIdentifier, }, { fieldMetadataId: @@ -53,6 +71,9 @@ export const opportunitiesByStageView = ( position: 1, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.opportunity.views.byStage.viewFields.amount + .universalIdentifier, }, { fieldMetadataId: @@ -63,6 +84,9 @@ export const opportunitiesByStageView = ( position: 2, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.opportunity.views.byStage.viewFields.createdBy + .universalIdentifier, }, { fieldMetadataId: @@ -73,6 +97,9 @@ export const opportunitiesByStageView = ( position: 3, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.opportunity.views.byStage.viewFields.closeDate + .universalIdentifier, }, { fieldMetadataId: @@ -83,6 +110,9 @@ export const opportunitiesByStageView = ( position: 4, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.opportunity.views.byStage.viewFields.company + .universalIdentifier, }, { fieldMetadataId: @@ -94,6 +124,9 @@ export const opportunitiesByStageView = ( position: 5, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.opportunity.views.byStage.viewFields.pointOfContact + .universalIdentifier, }, ], groups: [ @@ -106,6 +139,9 @@ export const opportunitiesByStageView = ( isVisible: true, fieldValue: 'NEW', position: 0, + universalIdentifier: + STANDARD_OBJECTS.opportunity.views.byStage.viewGroups!.new + .universalIdentifier, }, { fieldMetadataId: @@ -116,6 +152,9 @@ export const opportunitiesByStageView = ( isVisible: true, fieldValue: 'SCREENING', position: 1, + universalIdentifier: + STANDARD_OBJECTS.opportunity.views.byStage.viewGroups!.screening + .universalIdentifier, }, { fieldMetadataId: @@ -126,6 +165,9 @@ export const opportunitiesByStageView = ( isVisible: true, fieldValue: 'MEETING', position: 2, + universalIdentifier: + STANDARD_OBJECTS.opportunity.views.byStage.viewGroups!.meeting + .universalIdentifier, }, { fieldMetadataId: @@ -136,6 +178,9 @@ export const opportunitiesByStageView = ( isVisible: true, fieldValue: 'PROPOSAL', position: 3, + universalIdentifier: + STANDARD_OBJECTS.opportunity.views.byStage.viewGroups!.proposal + .universalIdentifier, }, { fieldMetadataId: @@ -146,6 +191,9 @@ export const opportunitiesByStageView = ( isVisible: true, fieldValue: 'CUSTOMER', position: 4, + universalIdentifier: + STANDARD_OBJECTS.opportunity.views.byStage.viewGroups!.customer + .universalIdentifier, }, ], }; diff --git a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/opportunity-table-by-stage.view.ts b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/opportunity-table-by-stage.view.ts deleted file mode 100644 index 62d32ebb9b8da..0000000000000 --- a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/opportunity-table-by-stage.view.ts +++ /dev/null @@ -1,150 +0,0 @@ -import { msg } from '@lingui/core/macro'; -import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; - -import { AggregateOperations } from 'src/engine/api/graphql/graphql-query-runner/constants/aggregate-operations.constant'; -import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; -import { OPPORTUNITY_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids'; - -export const opportunitiesTableByStageView = ( - objectMetadataItems: ObjectMetadataEntity[], - useCoreNaming = false, -) => { - const opportunityObjectMetadata = objectMetadataItems.find( - (object) => object.standardId === STANDARD_OBJECT_IDS.opportunity, - ); - - if (!opportunityObjectMetadata) { - throw new Error('Opportunity object metadata not found'); - } - - return { - name: useCoreNaming ? msg`By Stage` : 'By Stage', - objectMetadataId: opportunityObjectMetadata.id, - type: 'table', - key: null, - position: 1, - icon: 'IconList', - kanbanFieldMetadataId: - opportunityObjectMetadata.fields.find( - (field) => field.standardId === OPPORTUNITY_STANDARD_FIELD_IDS.stage, - )?.id ?? '', - filters: [], - fields: [ - { - fieldMetadataId: - opportunityObjectMetadata.fields.find( - (field) => field.standardId === OPPORTUNITY_STANDARD_FIELD_IDS.name, - )?.id ?? '', - position: 0, - isVisible: true, - size: 150, - }, - { - fieldMetadataId: - opportunityObjectMetadata.fields.find( - (field) => - field.standardId === OPPORTUNITY_STANDARD_FIELD_IDS.amount, - )?.id ?? '', - position: 1, - isVisible: true, - size: 150, - aggregateOperation: AggregateOperations.AVG, - }, - { - fieldMetadataId: - opportunityObjectMetadata.fields.find( - (field) => - field.standardId === OPPORTUNITY_STANDARD_FIELD_IDS.createdBy, - )?.id ?? '', - position: 2, - isVisible: true, - size: 150, - }, - { - fieldMetadataId: - opportunityObjectMetadata.fields.find( - (field) => - field.standardId === OPPORTUNITY_STANDARD_FIELD_IDS.closeDate, - )?.id ?? '', - position: 3, - isVisible: true, - size: 150, - aggregateOperation: AggregateOperations.MAX, - }, - { - fieldMetadataId: - opportunityObjectMetadata.fields.find( - (field) => - field.standardId === OPPORTUNITY_STANDARD_FIELD_IDS.company, - )?.id ?? '', - position: 4, - isVisible: true, - size: 150, - aggregateOperation: AggregateOperations.COUNT, - }, - { - fieldMetadataId: - opportunityObjectMetadata.fields.find( - (field) => - field.standardId === - OPPORTUNITY_STANDARD_FIELD_IDS.pointOfContact, - )?.id ?? '', - position: 5, - isVisible: true, - size: 150, - }, - ], - groups: [ - { - fieldMetadataId: - opportunityObjectMetadata.fields.find( - (field) => - field.standardId === OPPORTUNITY_STANDARD_FIELD_IDS.stage, - )?.id ?? '', - isVisible: true, - fieldValue: 'NEW', - position: 0, - }, - { - fieldMetadataId: - opportunityObjectMetadata.fields.find( - (field) => - field.standardId === OPPORTUNITY_STANDARD_FIELD_IDS.stage, - )?.id ?? '', - isVisible: true, - fieldValue: 'SCREENING', - position: 1, - }, - { - fieldMetadataId: - opportunityObjectMetadata.fields.find( - (field) => - field.standardId === OPPORTUNITY_STANDARD_FIELD_IDS.stage, - )?.id ?? '', - isVisible: true, - fieldValue: 'MEETING', - position: 2, - }, - { - fieldMetadataId: - opportunityObjectMetadata.fields.find( - (field) => - field.standardId === OPPORTUNITY_STANDARD_FIELD_IDS.stage, - )?.id ?? '', - isVisible: true, - fieldValue: 'PROPOSAL', - position: 3, - }, - { - fieldMetadataId: - opportunityObjectMetadata.fields.find( - (field) => - field.standardId === OPPORTUNITY_STANDARD_FIELD_IDS.stage, - )?.id ?? '', - isVisible: true, - fieldValue: 'CUSTOMER', - position: 4, - }, - ], - }; -}; diff --git a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/people-all.view.ts b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/people-all.view.ts index 3eaccca0a7c5d..452c69b4740ff 100644 --- a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/people-all.view.ts +++ b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/people-all.view.ts @@ -1,17 +1,26 @@ import { msg } from '@lingui/core/macro'; import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; +import { v4 } from 'uuid'; import { AggregateOperations } from 'src/engine/api/graphql/graphql-query-runner/constants/aggregate-operations.constant'; +import { STANDARD_OBJECTS } from 'src/engine/core-modules/application/constants/standard-object.constant'; +import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type'; import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; +import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface'; import { BASE_OBJECT_STANDARD_FIELD_IDS, PERSON_STANDARD_FIELD_IDS, } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids'; -export const peopleAllView = ( - objectMetadataItems: ObjectMetadataEntity[], +export const peopleAllView = ({ + objectMetadataItems, useCoreNaming = false, -) => { + twentyStandardFlatApplication, +}: { + objectMetadataItems: ObjectMetadataEntity[]; + useCoreNaming?: boolean; + twentyStandardFlatApplication: FlatApplication; +}): ViewDefinition => { const personObjectMetadata = objectMetadataItems.find( (object) => object.standardId === STANDARD_OBJECT_IDS.person, ); @@ -20,7 +29,13 @@ export const peopleAllView = ( throw new Error('Person object metadata not found'); } + const viewUniversalIdentifier = + STANDARD_OBJECTS.person.views.allPeople.universalIdentifier; + return { + id: v4(), + universalIdentifier: viewUniversalIdentifier, + applicationId: twentyStandardFlatApplication.id, name: useCoreNaming ? msg`All {objectLabelPlural}` : 'All People', objectMetadataId: personObjectMetadata.id, type: 'table', @@ -38,6 +53,9 @@ export const peopleAllView = ( position: 0, isVisible: true, size: 210, + universalIdentifier: + STANDARD_OBJECTS.person.views.allPeople.viewFields.name + .universalIdentifier, }, { fieldMetadataId: @@ -48,6 +66,9 @@ export const peopleAllView = ( isVisible: true, size: 150, aggregateOperation: AggregateOperations.COUNT_UNIQUE_VALUES, + universalIdentifier: + STANDARD_OBJECTS.person.views.allPeople.viewFields.emails + .universalIdentifier, }, { fieldMetadataId: @@ -57,6 +78,9 @@ export const peopleAllView = ( position: 2, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.person.views.allPeople.viewFields.createdBy + .universalIdentifier, }, { fieldMetadataId: @@ -66,6 +90,9 @@ export const peopleAllView = ( position: 3, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.person.views.allPeople.viewFields.company + .universalIdentifier, }, { fieldMetadataId: @@ -76,6 +103,9 @@ export const peopleAllView = ( isVisible: true, size: 150, aggregateOperation: AggregateOperations.PERCENTAGE_EMPTY, + universalIdentifier: + STANDARD_OBJECTS.person.views.allPeople.viewFields.phones + .universalIdentifier, }, { fieldMetadataId: @@ -87,6 +117,9 @@ export const peopleAllView = ( isVisible: true, size: 150, aggregateOperation: AggregateOperations.MIN, + universalIdentifier: + STANDARD_OBJECTS.person.views.allPeople.viewFields.createdAt + .universalIdentifier, }, { fieldMetadataId: @@ -96,6 +129,9 @@ export const peopleAllView = ( position: 6, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.person.views.allPeople.viewFields.city + .universalIdentifier, }, { fieldMetadataId: @@ -105,6 +141,9 @@ export const peopleAllView = ( position: 7, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.person.views.allPeople.viewFields.jobTitle + .universalIdentifier, }, { fieldMetadataId: @@ -115,6 +154,9 @@ export const peopleAllView = ( position: 8, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.person.views.allPeople.viewFields.linkedinLink + .universalIdentifier, }, { fieldMetadataId: @@ -124,6 +166,9 @@ export const peopleAllView = ( position: 9, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.person.views.allPeople.viewFields.xLink + .universalIdentifier, }, ], }; diff --git a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/tasks-all.view.ts b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/tasks-all.view.ts index e621081ee0c0e..846f3e2a9d8bd 100644 --- a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/tasks-all.view.ts +++ b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/tasks-all.view.ts @@ -1,16 +1,25 @@ import { msg } from '@lingui/core/macro'; import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; +import { v4 } from 'uuid'; +import { STANDARD_OBJECTS } from 'src/engine/core-modules/application/constants/standard-object.constant'; +import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type'; import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; +import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface'; import { BASE_OBJECT_STANDARD_FIELD_IDS, TASK_STANDARD_FIELD_IDS, } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids'; -export const tasksAllView = ( - objectMetadataItems: ObjectMetadataEntity[], +export const tasksAllView = ({ + objectMetadataItems, useCoreNaming = false, -) => { + twentyStandardFlatApplication, +}: { + objectMetadataItems: ObjectMetadataEntity[]; + useCoreNaming?: boolean; + twentyStandardFlatApplication: FlatApplication; +}): ViewDefinition => { const taskObjectMetadata = objectMetadataItems.find( (object) => object.standardId === STANDARD_OBJECT_IDS.task, ); @@ -19,7 +28,13 @@ export const tasksAllView = ( throw new Error('Task object metadata not found'); } + const viewUniversalIdentifier = + STANDARD_OBJECTS.task.views.allTasks.universalIdentifier; + return { + id: v4(), + universalIdentifier: viewUniversalIdentifier, + applicationId: twentyStandardFlatApplication.id, name: useCoreNaming ? msg`All {objectLabelPlural}` : 'All Tasks', objectMetadataId: taskObjectMetadata.id, type: 'table', @@ -35,8 +50,7 @@ export const tasksAllView = ( ], displayValue: 'Task', operand: 'is', - value: '["TASK"]', - }, + value: '["TASK"]'}, ],*/, fields: [ { @@ -47,6 +61,9 @@ export const tasksAllView = ( position: 0, isVisible: true, size: 210, + universalIdentifier: + STANDARD_OBJECTS.task.views.allTasks.viewFields.title + .universalIdentifier, }, { fieldMetadataId: @@ -56,6 +73,9 @@ export const tasksAllView = ( position: 2, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.task.views.allTasks.viewFields.status + .universalIdentifier, }, { fieldMetadataId: @@ -65,6 +85,9 @@ export const tasksAllView = ( position: 3, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.task.views.allTasks.viewFields.taskTargets + .universalIdentifier, }, { fieldMetadataId: @@ -74,6 +97,9 @@ export const tasksAllView = ( position: 4, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.task.views.allTasks.viewFields.createdBy + .universalIdentifier, }, { fieldMetadataId: @@ -83,6 +109,9 @@ export const tasksAllView = ( position: 5, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.task.views.allTasks.viewFields.dueAt + .universalIdentifier, }, { fieldMetadataId: @@ -92,6 +121,9 @@ export const tasksAllView = ( position: 6, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.task.views.allTasks.viewFields.assignee + .universalIdentifier, }, { fieldMetadataId: @@ -101,6 +133,9 @@ export const tasksAllView = ( position: 7, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.task.views.allTasks.viewFields.bodyV2 + .universalIdentifier, }, { fieldMetadataId: @@ -111,18 +146,19 @@ export const tasksAllView = ( position: 8, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.task.views.allTasks.viewFields.createdAt + .universalIdentifier, }, /* TODO: Add later, since we don't have real-time it probably doesn't work well? { fieldMetadataId: - objectMetadataMap[STANDARD_OBJECT_IDS.task].fields[ - BASE_OBJECT_STANDARD_FIELD_IDS.updatedAt + objectMetadataMap[STANDARD_OBJECT_IDS.task].fields[.updatedAt ], position: 0, isVisible: true, - size: 210, - }, + size: 210}, */ ], }; diff --git a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/tasks-assigned-to-me.ts b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/tasks-assigned-to-me.ts index 3b05888037726..2c127de84898b 100644 --- a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/tasks-assigned-to-me.ts +++ b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/tasks-assigned-to-me.ts @@ -1,17 +1,26 @@ import { msg } from '@lingui/core/macro'; -import { ViewFilterOperand } from 'twenty-shared/types'; import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; +import { ViewFilterOperand } from 'twenty-shared/types'; +import { v4 } from 'uuid'; +import { STANDARD_OBJECTS } from 'src/engine/core-modules/application/constants/standard-object.constant'; +import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type'; import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; +import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface'; import { BASE_OBJECT_STANDARD_FIELD_IDS, TASK_STANDARD_FIELD_IDS, } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids'; -export const tasksAssignedToMeView = ( - objectMetadataItems: ObjectMetadataEntity[], +export const tasksAssignedToMeView = ({ + objectMetadataItems, useCoreNaming = false, -) => { + twentyStandardFlatApplication, +}: { + objectMetadataItems: ObjectMetadataEntity[]; + useCoreNaming?: boolean; + twentyStandardFlatApplication: FlatApplication; +}): ViewDefinition => { const taskObjectMetadata = objectMetadataItems.find( (object) => object.standardId === STANDARD_OBJECT_IDS.task, ); @@ -20,7 +29,13 @@ export const tasksAssignedToMeView = ( throw new Error('Task object metadata not found'); } + const viewUniversalIdentifier = + STANDARD_OBJECTS.task.views.assignedToMe.universalIdentifier; + return { + id: v4(), + universalIdentifier: viewUniversalIdentifier, + applicationId: twentyStandardFlatApplication.id, name: useCoreNaming ? msg`Assigned to Me` : 'Assigned to Me', objectMetadataId: taskObjectMetadata.id, type: 'table', @@ -40,6 +55,9 @@ export const tasksAssignedToMeView = ( isCurrentWorkspaceMemberSelected: true, selectedRecordIds: [], }), + universalIdentifier: + STANDARD_OBJECTS.task.views.assignedToMe.viewFilters!.assigneeIsMe + .universalIdentifier, }, ], fields: [ @@ -51,6 +69,9 @@ export const tasksAssignedToMeView = ( position: 0, isVisible: true, size: 210, + universalIdentifier: + STANDARD_OBJECTS.task.views.assignedToMe.viewFields.title + .universalIdentifier, }, /*{ fieldMetadataId: @@ -59,8 +80,7 @@ export const tasksAssignedToMeView = ( ], position: 2, isVisible: true, - size: 150, - },*/ + size: 150},*/ { fieldMetadataId: taskObjectMetadata.fields.find( @@ -69,6 +89,9 @@ export const tasksAssignedToMeView = ( position: 3, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.task.views.assignedToMe.viewFields.taskTargets + .universalIdentifier, }, { fieldMetadataId: @@ -78,6 +101,9 @@ export const tasksAssignedToMeView = ( position: 4, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.task.views.assignedToMe.viewFields.createdBy + .universalIdentifier, }, { fieldMetadataId: @@ -87,6 +113,9 @@ export const tasksAssignedToMeView = ( position: 5, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.task.views.assignedToMe.viewFields.dueAt + .universalIdentifier, }, { fieldMetadataId: @@ -96,6 +125,9 @@ export const tasksAssignedToMeView = ( position: 6, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.task.views.assignedToMe.viewFields.assignee + .universalIdentifier, }, { fieldMetadataId: @@ -105,6 +137,9 @@ export const tasksAssignedToMeView = ( position: 7, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.task.views.assignedToMe.viewFields.bodyV2 + .universalIdentifier, }, { fieldMetadataId: @@ -115,6 +150,9 @@ export const tasksAssignedToMeView = ( position: 8, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.task.views.assignedToMe.viewFields.createdAt + .universalIdentifier, }, ], groups: [ @@ -126,6 +164,9 @@ export const tasksAssignedToMeView = ( isVisible: true, fieldValue: 'TODO', position: 0, + universalIdentifier: + STANDARD_OBJECTS.task.views.assignedToMe.viewGroups!.todo + .universalIdentifier, }, { fieldMetadataId: @@ -135,6 +176,9 @@ export const tasksAssignedToMeView = ( isVisible: true, fieldValue: 'IN_PROGRESS', position: 1, + universalIdentifier: + STANDARD_OBJECTS.task.views.assignedToMe.viewGroups!.inProgress + .universalIdentifier, }, { fieldMetadataId: @@ -144,6 +188,9 @@ export const tasksAssignedToMeView = ( isVisible: true, fieldValue: 'DONE', position: 2, + universalIdentifier: + STANDARD_OBJECTS.task.views.assignedToMe.viewGroups!.done + .universalIdentifier, }, { fieldMetadataId: @@ -153,6 +200,9 @@ export const tasksAssignedToMeView = ( isVisible: true, fieldValue: '', position: 3, + universalIdentifier: + STANDARD_OBJECTS.task.views.assignedToMe.viewGroups!.empty + .universalIdentifier, }, ], }; diff --git a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/tasks-by-status.view.ts b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/tasks-by-status.view.ts index d300fda2af2d7..bf83d96382dd2 100644 --- a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/tasks-by-status.view.ts +++ b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/tasks-by-status.view.ts @@ -1,16 +1,25 @@ import { msg } from '@lingui/core/macro'; import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; +import { v4 } from 'uuid'; +import { STANDARD_OBJECTS } from 'src/engine/core-modules/application/constants/standard-object.constant'; +import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type'; import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; +import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface'; import { BASE_OBJECT_STANDARD_FIELD_IDS, TASK_STANDARD_FIELD_IDS, } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids'; -export const tasksByStatusView = ( - objectMetadataItems: ObjectMetadataEntity[], +export const tasksByStatusView = ({ + objectMetadataItems, useCoreNaming = false, -) => { + twentyStandardFlatApplication, +}: { + objectMetadataItems: ObjectMetadataEntity[]; + useCoreNaming?: boolean; + twentyStandardFlatApplication: FlatApplication; +}): ViewDefinition => { const taskObjectMetadata = objectMetadataItems.find( (object) => object.standardId === STANDARD_OBJECT_IDS.task, ); @@ -19,7 +28,13 @@ export const tasksByStatusView = ( throw new Error('Task object metadata not found'); } + const viewUniversalIdentifier = + STANDARD_OBJECTS.task.views.byStatus.universalIdentifier; + return { + id: v4(), + universalIdentifier: viewUniversalIdentifier, + applicationId: twentyStandardFlatApplication.id, name: useCoreNaming ? msg`By Status` : 'By Status', objectMetadataId: taskObjectMetadata.id, type: 'kanban', @@ -38,8 +53,7 @@ export const tasksByStatusView = ( ], displayValue: 'Task', operand: 'is', - value: '["TASK"]', - }, + value: '["TASK"]'}, ],*/, fields: [ { @@ -50,6 +64,9 @@ export const tasksByStatusView = ( position: 0, isVisible: true, size: 210, + universalIdentifier: + STANDARD_OBJECTS.task.views.byStatus.viewFields.title + .universalIdentifier, }, { fieldMetadataId: @@ -59,6 +76,9 @@ export const tasksByStatusView = ( position: 2, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.task.views.byStatus.viewFields.status + .universalIdentifier, }, { fieldMetadataId: @@ -68,6 +88,9 @@ export const tasksByStatusView = ( position: 3, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.task.views.byStatus.viewFields.dueAt + .universalIdentifier, }, { fieldMetadataId: @@ -77,6 +100,9 @@ export const tasksByStatusView = ( position: 4, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.task.views.byStatus.viewFields.assignee + .universalIdentifier, }, { fieldMetadataId: @@ -87,18 +113,19 @@ export const tasksByStatusView = ( position: 6, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.task.views.byStatus.viewFields.createdAt + .universalIdentifier, }, /* TODO: Add later, since we don't have real-time it probably doesn't work well? { fieldMetadataId: - objectMetadataMap[STANDARD_OBJECT_IDS.task].fields[ - BASE_OBJECT_STANDARD_FIELD_IDS.updatedAt + objectMetadataMap[STANDARD_OBJECT_IDS.task].fields[.updatedAt ], position: 0, isVisible: true, - size: 210, - }, + size: 210}, */ ], groups: [ @@ -110,6 +137,9 @@ export const tasksByStatusView = ( isVisible: true, fieldValue: 'TODO', position: 0, + universalIdentifier: + STANDARD_OBJECTS.task.views.byStatus.viewGroups!.todo + .universalIdentifier, }, { fieldMetadataId: @@ -119,6 +149,9 @@ export const tasksByStatusView = ( isVisible: true, fieldValue: 'IN_PROGRESS', position: 1, + universalIdentifier: + STANDARD_OBJECTS.task.views.byStatus.viewGroups!.inProgress + .universalIdentifier, }, { fieldMetadataId: @@ -128,6 +161,9 @@ export const tasksByStatusView = ( isVisible: true, fieldValue: 'DONE', position: 2, + universalIdentifier: + STANDARD_OBJECTS.task.views.byStatus.viewGroups!.done + .universalIdentifier, }, ], }; diff --git a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/tmp.ts b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/tmp.ts new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/workflow-runs-all.view.ts b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/workflow-runs-all.view.ts index 9791ae7b37f08..47be82050faa9 100644 --- a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/workflow-runs-all.view.ts +++ b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/workflow-runs-all.view.ts @@ -1,14 +1,23 @@ import { msg } from '@lingui/core/macro'; import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; +import { v4 } from 'uuid'; +import { STANDARD_OBJECTS } from 'src/engine/core-modules/application/constants/standard-object.constant'; +import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type'; import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { ViewOpenRecordInType } from 'src/engine/metadata-modules/view/types/view-open-record-in-type.type'; +import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface'; import { WORKFLOW_RUN_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids'; -export const workflowRunsAllView = ( - objectMetadataItems: ObjectMetadataEntity[], +export const workflowRunsAllView = ({ + objectMetadataItems, useCoreNaming = false, -) => { + twentyStandardFlatApplication, +}: { + objectMetadataItems: ObjectMetadataEntity[]; + useCoreNaming?: boolean; + twentyStandardFlatApplication: FlatApplication; +}): ViewDefinition => { const workflowRunObjectMetadata = objectMetadataItems.find( (object) => object.standardId === STANDARD_OBJECT_IDS.workflowRun, ); @@ -17,7 +26,13 @@ export const workflowRunsAllView = ( throw new Error('Workflow run object metadata not found'); } + const viewUniversalIdentifier = + STANDARD_OBJECTS.workflowRun.views.allWorkflowRuns.universalIdentifier; + return { + id: v4(), + universalIdentifier: viewUniversalIdentifier, + applicationId: twentyStandardFlatApplication.id, name: useCoreNaming ? msg`All {objectLabelPlural}` : 'All Workflow Runs', objectMetadataId: workflowRunObjectMetadata.id, type: 'table', @@ -37,6 +52,9 @@ export const workflowRunsAllView = ( position: 0, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.workflowRun.views.allWorkflowRuns.viewFields.name + .universalIdentifier, }, { fieldMetadataId: @@ -47,6 +65,9 @@ export const workflowRunsAllView = ( position: 1, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.workflowRun.views.allWorkflowRuns.viewFields.workflow + .universalIdentifier, }, { fieldMetadataId: @@ -57,6 +78,9 @@ export const workflowRunsAllView = ( position: 2, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.workflowRun.views.allWorkflowRuns.viewFields.status + .universalIdentifier, }, { fieldMetadataId: @@ -67,6 +91,9 @@ export const workflowRunsAllView = ( position: 3, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.workflowRun.views.allWorkflowRuns.viewFields + .startedAt.universalIdentifier, }, { fieldMetadataId: @@ -77,6 +104,9 @@ export const workflowRunsAllView = ( position: 4, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.workflowRun.views.allWorkflowRuns.viewFields + .createdBy.universalIdentifier, }, { fieldMetadataId: @@ -88,6 +118,9 @@ export const workflowRunsAllView = ( position: 5, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.workflowRun.views.allWorkflowRuns.viewFields + .workflowVersion.universalIdentifier, }, ], }; diff --git a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/workflow-versions-all.view.ts b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/workflow-versions-all.view.ts index 106c938900be2..87ba9c8173e33 100644 --- a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/workflow-versions-all.view.ts +++ b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/workflow-versions-all.view.ts @@ -1,17 +1,26 @@ import { msg } from '@lingui/core/macro'; import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; +import { v4 } from 'uuid'; +import { STANDARD_OBJECTS } from 'src/engine/core-modules/application/constants/standard-object.constant'; +import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type'; import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { ViewOpenRecordInType } from 'src/engine/metadata-modules/view/types/view-open-record-in-type.type'; +import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface'; import { BASE_OBJECT_STANDARD_FIELD_IDS, WORKFLOW_VERSION_STANDARD_FIELD_IDS, } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids'; -export const workflowVersionsAllView = ( - objectMetadataItems: ObjectMetadataEntity[], +export const workflowVersionsAllView = ({ + objectMetadataItems, useCoreNaming = false, -) => { + twentyStandardFlatApplication, +}: { + objectMetadataItems: ObjectMetadataEntity[]; + useCoreNaming?: boolean; + twentyStandardFlatApplication: FlatApplication; +}): ViewDefinition => { const workflowVersionObjectMetadata = objectMetadataItems.find( (object) => object.standardId === STANDARD_OBJECT_IDS.workflowVersion, ); @@ -20,7 +29,14 @@ export const workflowVersionsAllView = ( throw new Error('Workflow version object metadata not found'); } + const viewUniversalIdentifier = + STANDARD_OBJECTS.workflowVersion.views.allWorkflowVersions + .universalIdentifier; + return { + id: v4(), + universalIdentifier: viewUniversalIdentifier, + applicationId: twentyStandardFlatApplication.id, name: useCoreNaming ? msg`All {objectLabelPlural}` : 'All Workflow Versions', @@ -42,6 +58,9 @@ export const workflowVersionsAllView = ( position: 0, isVisible: true, size: 210, + universalIdentifier: + STANDARD_OBJECTS.workflowVersion.views.allWorkflowVersions.viewFields + .name.universalIdentifier, }, { fieldMetadataId: @@ -52,6 +71,9 @@ export const workflowVersionsAllView = ( position: 1, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.workflowVersion.views.allWorkflowVersions.viewFields + .workflow.universalIdentifier, }, { fieldMetadataId: @@ -62,6 +84,9 @@ export const workflowVersionsAllView = ( position: 2, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.workflowVersion.views.allWorkflowVersions.viewFields + .status.universalIdentifier, }, { fieldMetadataId: @@ -72,6 +97,9 @@ export const workflowVersionsAllView = ( position: 3, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.workflowVersion.views.allWorkflowVersions.viewFields + .updatedAt.universalIdentifier, }, { fieldMetadataId: @@ -82,6 +110,9 @@ export const workflowVersionsAllView = ( position: 4, isVisible: false, size: 150, + universalIdentifier: + STANDARD_OBJECTS.workflowVersion.views.allWorkflowVersions.viewFields + .runs.universalIdentifier, }, ], }; diff --git a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/workflows-all.view.ts b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/workflows-all.view.ts index 381d5d9e69d74..cf8fadfb66b01 100644 --- a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/workflows-all.view.ts +++ b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/workflows-all.view.ts @@ -1,17 +1,26 @@ import { msg } from '@lingui/core/macro'; import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; +import { v4 } from 'uuid'; +import { STANDARD_OBJECTS } from 'src/engine/core-modules/application/constants/standard-object.constant'; +import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type'; import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { ViewOpenRecordInType } from 'src/engine/metadata-modules/view/types/view-open-record-in-type.type'; +import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface'; import { BASE_OBJECT_STANDARD_FIELD_IDS, WORKFLOW_STANDARD_FIELD_IDS, } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids'; -export const workflowsAllView = ( - objectMetadataItems: ObjectMetadataEntity[], +export const workflowsAllView = ({ + objectMetadataItems, useCoreNaming = false, -) => { + twentyStandardFlatApplication, +}: { + objectMetadataItems: ObjectMetadataEntity[]; + useCoreNaming?: boolean; + twentyStandardFlatApplication: FlatApplication; +}): ViewDefinition => { const workflowObjectMetadata = objectMetadataItems.find( (object) => object.standardId === STANDARD_OBJECT_IDS.workflow, ); @@ -20,7 +29,13 @@ export const workflowsAllView = ( throw new Error('Workflow object metadata not found'); } + const viewUniversalIdentifier = + STANDARD_OBJECTS.workflow.views.allWorkflows.universalIdentifier; + return { + id: v4(), + universalIdentifier: viewUniversalIdentifier, + applicationId: twentyStandardFlatApplication.id, name: useCoreNaming ? msg`All {objectLabelPlural}` : 'All Workflows', objectMetadataId: workflowObjectMetadata.id, type: 'table', @@ -39,6 +54,9 @@ export const workflowsAllView = ( position: 0, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.workflow.views.allWorkflows.viewFields.name + .universalIdentifier, }, { fieldMetadataId: @@ -49,6 +67,9 @@ export const workflowsAllView = ( position: 1, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.workflow.views.allWorkflows.viewFields.statuses + .universalIdentifier, }, { fieldMetadataId: @@ -59,6 +80,9 @@ export const workflowsAllView = ( position: 2, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.workflow.views.allWorkflows.viewFields.updatedAt + .universalIdentifier, }, { fieldMetadataId: @@ -69,6 +93,9 @@ export const workflowsAllView = ( position: 3, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.workflow.views.allWorkflows.viewFields.createdBy + .universalIdentifier, }, { fieldMetadataId: @@ -79,6 +106,9 @@ export const workflowsAllView = ( position: 4, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.workflow.views.allWorkflows.viewFields.versions + .universalIdentifier, }, { fieldMetadataId: @@ -88,6 +118,9 @@ export const workflowsAllView = ( position: 5, isVisible: false, size: 150, + universalIdentifier: + STANDARD_OBJECTS.workflow.views.allWorkflows.viewFields.runs + .universalIdentifier, }, ], }; diff --git a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/workspace-members-all.view.ts b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/workspace-members-all.view.ts index 2c66d3172e2f7..c87f8d86fa076 100644 --- a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/workspace-members-all.view.ts +++ b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/workspace-members-all.view.ts @@ -1,17 +1,26 @@ import { msg } from '@lingui/core/macro'; import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; +import { v4 } from 'uuid'; +import { STANDARD_OBJECTS } from 'src/engine/core-modules/application/constants/standard-object.constant'; +import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type'; import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; +import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface'; import { DEFAULT_VIEW_FIELD_SIZE } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/constants/DEFAULT_VIEW_FIELD_SIZE'; import { BASE_OBJECT_STANDARD_FIELD_IDS, WORKSPACE_MEMBER_STANDARD_FIELD_IDS, } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids'; -export const workspaceMembersAllView = ( - objectMetadataItems: ObjectMetadataEntity[], - useCoreNaming = false, -) => { +export const workspaceMembersAllView = ({ + objectMetadataItems, + twentyStandardFlatApplication, + useCoreNaming, +}: { + objectMetadataItems: ObjectMetadataEntity[]; + useCoreNaming?: boolean; + twentyStandardFlatApplication: FlatApplication; +}): ViewDefinition => { const workspaceMemberObjectMetadata = objectMetadataItems.find( (object) => object.standardId === STANDARD_OBJECT_IDS.workspaceMember, ); @@ -20,7 +29,14 @@ export const workspaceMembersAllView = ( throw new Error('WorkspaceMember object metadata not found'); } + const viewUniversalIdentifier = + STANDARD_OBJECTS.workspaceMember.views.allWorkspaceMembers + .universalIdentifier; + return { + id: v4(), + universalIdentifier: viewUniversalIdentifier, + applicationId: twentyStandardFlatApplication.id, name: useCoreNaming ? msg`All {objectLabelPlural}` : 'All Workspace Members', @@ -41,6 +57,9 @@ export const workspaceMembersAllView = ( position: 0, isVisible: true, size: DEFAULT_VIEW_FIELD_SIZE, + universalIdentifier: + STANDARD_OBJECTS.workspaceMember.views.allWorkspaceMembers.viewFields + .name.universalIdentifier, }, { fieldMetadataId: @@ -52,6 +71,9 @@ export const workspaceMembersAllView = ( position: 1, isVisible: true, size: 180, + universalIdentifier: + STANDARD_OBJECTS.workspaceMember.views.allWorkspaceMembers.viewFields + .userEmail.universalIdentifier, }, { fieldMetadataId: @@ -63,6 +85,9 @@ export const workspaceMembersAllView = ( position: 2, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.workspaceMember.views.allWorkspaceMembers.viewFields + .avatarUrl.universalIdentifier, }, { fieldMetadataId: @@ -74,6 +99,9 @@ export const workspaceMembersAllView = ( position: 3, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.workspaceMember.views.allWorkspaceMembers.viewFields + .colorScheme.universalIdentifier, }, { fieldMetadataId: @@ -84,6 +112,9 @@ export const workspaceMembersAllView = ( position: 4, isVisible: true, size: 120, + universalIdentifier: + STANDARD_OBJECTS.workspaceMember.views.allWorkspaceMembers.viewFields + .locale.universalIdentifier, }, { fieldMetadataId: @@ -94,6 +125,9 @@ export const workspaceMembersAllView = ( position: 5, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.workspaceMember.views.allWorkspaceMembers.viewFields + .timeZone.universalIdentifier, }, { fieldMetadataId: @@ -105,6 +139,9 @@ export const workspaceMembersAllView = ( position: 6, isVisible: true, size: 120, + universalIdentifier: + STANDARD_OBJECTS.workspaceMember.views.allWorkspaceMembers.viewFields + .dateFormat.universalIdentifier, }, { fieldMetadataId: @@ -116,6 +153,9 @@ export const workspaceMembersAllView = ( position: 7, isVisible: true, size: 120, + universalIdentifier: + STANDARD_OBJECTS.workspaceMember.views.allWorkspaceMembers.viewFields + .timeFormat.universalIdentifier, }, { fieldMetadataId: @@ -126,6 +166,9 @@ export const workspaceMembersAllView = ( position: 8, isVisible: true, size: 150, + universalIdentifier: + STANDARD_OBJECTS.workspaceMember.views.allWorkspaceMembers.viewFields + .createdAt.universalIdentifier, }, ], }; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-manager.service.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-manager.service.ts index 0a55ca6dfa631..38fda2b961071 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-manager.service.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-manager.service.ts @@ -4,6 +4,7 @@ import { InjectDataSource, InjectRepository } from '@nestjs/typeorm'; import { DataSource, Repository } from 'typeorm'; import { ApplicationService } from 'src/engine/core-modules/application/application.service'; +import { FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type'; import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service'; import { UserWorkspaceEntity } from 'src/engine/core-modules/user-workspace/user-workspace.entity'; import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; @@ -79,9 +80,10 @@ export class WorkspaceManagerService { const featureFlags = await this.featureFlagService.getWorkspaceFeatureFlagsMap(workspaceId); - await this.applicationService.createTwentyStandardApplication({ - workspaceId, - }); + const twentyStandardApplication = + await this.applicationService.createTwentyStandardApplication({ + workspaceId, + }); // TODO later replace by twenty-standard installation aka workspaceMigration run await this.workspaceSyncMetadataService.synchronize({ @@ -96,7 +98,18 @@ export class WorkspaceManagerService { `Metadata creation took ${dataSourceMetadataCreationEnd - dataSourceMetadataCreationStart}ms`, ); - await this.setupDefaultRoles(workspaceId, userId); + const { workspaceCustomFlatApplication } = + await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow( + { + workspaceId, + }, + ); + + await this.setupDefaultRoles({ + workspaceId, + userId, + workspaceCustomFlatApplication, + }); const prefillStandardObjectsStart = performance.now(); @@ -104,6 +117,7 @@ export class WorkspaceManagerService { dataSourceMetadata, workspaceId, featureFlags, + twentyStandardApplication, ); const prefillStandardObjectsEnd = performance.now(); @@ -117,6 +131,7 @@ export class WorkspaceManagerService { dataSourceMetadata: DataSourceEntity, workspaceId: string, featureFlags: Record, + twentyStandardFlatApplication: FlatApplication, ) { const createdObjectMetadata = await this.objectMetadataServiceV2.findManyWithinWorkspace(workspaceId); @@ -128,6 +143,7 @@ export class WorkspaceManagerService { ); await prefillCoreViews({ + twentyStandardFlatApplication, coreDataSource: this.coreDataSource, workspaceId, objectMetadataItems: createdObjectMetadata, @@ -155,10 +171,15 @@ export class WorkspaceManagerService { await this.workspaceDataSourceService.deleteWorkspaceDBSchema(workspaceId); } - private async setupDefaultRoles( - workspaceId: string, - userId: string, - ): Promise { + private async setupDefaultRoles({ + userId, + workspaceId, + workspaceCustomFlatApplication, + }: { + workspaceId: string; + userId: string; + workspaceCustomFlatApplication: FlatApplication; + }): Promise { const adminRole = await this.roleRepository.findOne({ where: { standardId: ADMIN_ROLE.standardId, @@ -180,6 +201,7 @@ export class WorkspaceManagerService { const memberRole = await this.roleService.createMemberRole({ workspaceId, + applicationId: workspaceCustomFlatApplication.id, }); await this.workspaceRepository.update(workspaceId, { diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/comparators/workspace-agent.comparator.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/comparators/workspace-agent.comparator.ts index 43916d447f05b..d3e3928347bcf 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/comparators/workspace-agent.comparator.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/comparators/workspace-agent.comparator.ts @@ -18,7 +18,14 @@ type AgentComparatorResult = { type WorkspaceAgentComparatorArgs = FromTo; -const agentPropertiesToIgnore = ['id', 'createdAt', 'updatedAt', 'workspaceId']; +const agentPropertiesToIgnore = [ + 'id', + 'createdAt', + 'updatedAt', + 'workspaceId', + 'universalIdentifier', + 'applicationId', +]; @Injectable() export class WorkspaceAgentComparator { diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/comparators/workspace-field.comparator.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/comparators/workspace-field.comparator.ts index 2c68d0b82eab7..ca4581bbcb3a6 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/comparators/workspace-field.comparator.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/comparators/workspace-field.comparator.ts @@ -29,6 +29,8 @@ const commonFieldPropertiesToIgnore = [ 'relationTargetObjectMetadataId', 'relationTargetFieldMetadata', 'relationTargetObjectMetadata', + 'universalIdentifier', + 'applicationId', ]; const fieldPropertiesToStringify = ['defaultValue'] as const; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/comparators/workspace-index.comparator.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/comparators/workspace-index.comparator.ts index 15cad414e5cd4..977e1801c0a41 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/comparators/workspace-index.comparator.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/comparators/workspace-index.comparator.ts @@ -10,7 +10,13 @@ import { import { type IndexMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-metadata.entity'; import { transformMetadataForComparison } from 'src/engine/workspace-manager/workspace-sync-metadata/comparators/utils/transform-metadata-for-comparison.util'; -const propertiesToIgnore = ['createdAt', 'updatedAt', 'indexFieldMetadatas']; +const propertiesToIgnore = [ + 'createdAt', + 'updatedAt', + 'indexFieldMetadatas', + 'universalIdentifier', + 'applicationId', +]; @Injectable() export class WorkspaceIndexComparator { diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/comparators/workspace-object.comparator.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/comparators/workspace-object.comparator.ts index 4bdc8933571c6..abe3f9944f134 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/comparators/workspace-object.comparator.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/comparators/workspace-object.comparator.ts @@ -20,6 +20,8 @@ const objectPropertiesToIgnore = [ 'imageIdentifierFieldMetadataId', 'isActive', 'fields', + 'universalIdentifier', + 'applicationId', ]; @Injectable() diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/comparators/workspace-role.comparator.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/comparators/workspace-role.comparator.ts index f0c17568e8b30..caa29fe687b66 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/comparators/workspace-role.comparator.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/comparators/workspace-role.comparator.ts @@ -37,6 +37,8 @@ const rolePropertiesToIgnore = [ 'permissionFlags', 'objectPermissions', 'fieldPermissions', + 'universalIdentifier', + 'applicationId', ]; @Injectable() diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids.ts index b2309f2eb97bb..104ff64090bad 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids.ts @@ -157,33 +157,6 @@ export const CONNECTED_ACCOUNT_STANDARD_FIELD_IDS = { connectionParameters: '20202020-a1b2-46be-814f-6228af16c481', } as const; -export const EVENT_STANDARD_FIELD_IDS = { - properties: '20202020-f142-4b04-b91b-6a2b4af3bf10', - workspaceMember: '20202020-af23-4479-9a30-868edc474b35', - person: '20202020-c414-45b9-a60a-ac27aa96229e', - company: '20202020-04ad-4221-a744-7a8278a5ce20', - opportunity: '20202020-7664-4a35-a3df-580d389fd5f0', - custom: '20202020-4a71-41b0-9f83-9cdcca3f8b14', -} as const; - -export const AUDIT_LOGS_STANDARD_FIELD_IDS = { - name: '20202020-2462-4b9d-b5d9-745febb3b095', - properties: '20202020-5d36-470e-8fad-d56ea3ab2fd0', - context: '20202020-b9d1-4058-9a75-7469cab5ca8c', - objectName: '20202020-76ba-4c47-b7e5-96034005d00a', - objectMetadataId: '20202020-127b-409d-9864-0ec44aa9ed98', - recordId: '20202020-c578-4acf-bf94-eb53b035cea2', - workspaceMember: '20202020-6e96-4300-b3f5-67a707147385', -} as const; - -export const BEHAVIORAL_EVENT_STANDARD_FIELD_IDS = { - name: '20202020-2462-4b9d-b5d9-745febb3b095', - properties: '20202020-5d36-470e-8fad-d56ea3ab2fd0', - context: '20202020-bd62-4b5b-8385-6caeed8f8078', - objectName: '20202020-a744-406c-a2e1-9d83d74f4341', - recordId: '20202020-6d8b-4ca5-9869-f882cb335673', -} as const; - export const TIMELINE_ACTIVITY_STANDARD_FIELD_IDS = { happensAt: '20202020-9526-4993-b339-c4318c4d39f0', type: '20202020-5e7b-4ccd-8b8a-86b94b474134', @@ -537,7 +510,6 @@ export const WORKSPACE_MEMBER_STANDARD_FIELD_IDS = { calendarStartDay: '20202020-92d0-1d7f-a126-25ededa6b142', numberFormat: '20202020-7f40-4e7f-b126-11c0eda6b141', } as const; - export const CUSTOM_OBJECT_STANDARD_FIELD_IDS = { name: '20202020-ba07-4ffd-ba63-009491f5749c', position: '20202020-c2bd-4e16-bb9a-c8b0411bf49d', @@ -568,7 +540,6 @@ export const STANDARD_OBJECT_FIELD_IDS = { activity: ACTIVITY_STANDARD_FIELD_IDS, attachment: ATTACHMENT_STANDARD_FIELD_IDS, blocklist: BLOCKLIST_STANDARD_FIELD_IDS, - behavioralEvent: BEHAVIORAL_EVENT_STANDARD_FIELD_IDS, calendarChannelEventAssociation: CALENDAR_CHANNEL_EVENT_ASSOCIATION_STANDARD_FIELD_IDS, calendarChannel: CALENDAR_CHANNEL_STANDARD_FIELD_IDS, @@ -579,7 +550,6 @@ export const STANDARD_OBJECT_FIELD_IDS = { connectedAccount: CONNECTED_ACCOUNT_STANDARD_FIELD_IDS, dashboard: DASHBOARD_STANDARD_FIELD_IDS, favorite: FAVORITE_STANDARD_FIELD_IDS, - auditLog: AUDIT_LOGS_STANDARD_FIELD_IDS, messageChannelMessageAssociation: MESSAGE_CHANNEL_MESSAGE_ASSOCIATION_STANDARD_FIELD_IDS, messageChannel: MESSAGE_CHANNEL_STANDARD_FIELD_IDS, diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/interfaces/workspace-sync-context.interface.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/interfaces/workspace-sync-context.interface.ts index a55121157a643..511ebb385d19d 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/interfaces/workspace-sync-context.interface.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/interfaces/workspace-sync-context.interface.ts @@ -1,5 +1,4 @@ import { type FeatureFlagMap } from 'src/engine/core-modules/feature-flag/interfaces/feature-flag-map.interface'; - export interface WorkspaceSyncContext { workspaceId: string; dataSourceId: string; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/utils/compute-workspace-custom-create-application-input.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/utils/compute-workspace-custom-create-application-input.ts deleted file mode 100644 index f56ad58995990..0000000000000 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/utils/compute-workspace-custom-create-application-input.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { isDefined } from 'twenty-shared/utils'; -import { v4 } from 'uuid'; - -import { type WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; -import { type CreateApplicationInput } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/twenty-standard-applications'; - -export const computeWorkspaceCustomCreateApplicationInput = ({ - workspace, - applicationId = v4(), -}: { - applicationId?: string; - workspace: Pick; -}) => - ({ - description: 'Workspace custom application', - name: `${isDefined(workspace.displayName) ? `${workspace.displayName}'s ` : ''}custom application`, - sourcePath: 'workspace-custom', - sourceType: 'local', - version: '1.0.0', - universalIdentifier: applicationId, - workspaceId: workspace.id, - id: applicationId, - canBeUninstalled: false, - }) as const satisfies CreateApplicationInput & { - workspaceId: string; - id: string; - }; diff --git a/packages/twenty-server/test/integration/graphql/suites/workspace/successful-user-and-workspace-creation.integration-spec.ts b/packages/twenty-server/test/integration/graphql/suites/workspace/successful-user-and-workspace-creation.integration-spec.ts index 8f5531f6a242f..e34cbd8be9fc9 100644 --- a/packages/twenty-server/test/integration/graphql/suites/workspace/successful-user-and-workspace-creation.integration-spec.ts +++ b/packages/twenty-server/test/integration/graphql/suites/workspace/successful-user-and-workspace-creation.integration-spec.ts @@ -10,7 +10,7 @@ import { jestExpectToBeDefined } from 'test/utils/jest-expect-to-be-defined.util import { isDefined } from 'twenty-shared/utils'; import { WorkspaceActivationStatus } from 'twenty-shared/workspace'; -import { TWENTY_STANDARD_APPLICATION } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/twenty-standard-applications'; +import { TWENTY_STANDARD_APPLICATION } from 'src/engine/core-modules/application/constants/twenty-standard-applications'; describe('Successful user and workspace creation', () => { let createdUserAccessToken: string | undefined;