From 75921e79bf621cf41cdd84264f0f108858e37813 Mon Sep 17 00:00:00 2001 From: Paul Rastoin <45004772+prastoin@users.noreply.github.com> Date: Mon, 2 Feb 2026 15:26:27 +0100 Subject: [PATCH] `[FIXES_MAIN]` Remove `objectMetadata` `standardId` (#17632) # Introduction In this PR we're deprecating the object metadata standard id and replacing it to the universalIdentifier usage As we've totally removed its insertion for both new field and object in https://github.com/twentyhq/twenty/pull/17572 ## Note - Removed upgrade commands before `1.17` --- ...ge-layout-universal-identifiers.command.ts | 183 -------- ...mpty-string-null-in-text-fields.command.ts | 197 -------- .../1-13-deduplicate-role-targets.command.ts | 129 ------ ...grate-standard-invalid-entities.command.ts | 380 ---------------- ...ine-activity-to-morph-relations.command.ts | 267 ----------- .../1-13/1-13-rename-index.command.ts | 206 --------- ...ets-unique-constraint-migration.command.ts | 77 ---- .../1-13-upgrade-version-command.module.ts | 78 ---- .../1-14-delete-removed-agents.command.ts | 157 ------- .../1-14-update-created-by-enum.command.ts | 98 ---- .../1-14-upgrade-version-command.module.ts | 26 -- ...orkspace-foreign-keys-migration.command.ts | 68 --- .../1-15-backfill-updated-by-field.command.ts | 191 -------- ...ix-nan-position-values-in-notes.command.ts | 95 ---- ...age-layout-widget-configuration.command.ts | 299 ------------- .../1-15-upgrade-version-command.module.ts | 49 -- ...ackfill-opportunity-owner-field.command.ts | 321 ------------- ...-backfill-standard-page-layouts.command.ts | 257 ----------- ...-and-increment-metadata-version.command.ts | 54 --- .../1-16-identify-agent-metadata.command.ts | 168 ------- .../1-16-identify-field-metadata.command.ts | 241 ---------- .../1-16-identify-index-metadata.command.ts | 341 -------------- .../1-16-identify-object-metadata.command.ts | 233 ---------- ...ify-remaining-entities-metadata.command.ts | 190 -------- .../1-16-identify-role-metadata.command.ts | 166 ------- ...16-identify-view-field-metadata.command.ts | 383 ---------------- ...6-identify-view-filter-metadata.command.ts | 221 --------- ...16-identify-view-group-metadata.command.ts | 340 -------------- .../1-16-identify-view-metadata.command.ts | 378 ---------------- ...ation-id-not-nullable-migration.command.ts | 71 --- ...ation-id-not-nullable-migration.command.ts | 71 --- ...ation-id-not-nullable-migration.command.ts | 71 --- ...ation-id-not-nullable-migration.command.ts | 71 --- ...ation-id-not-nullable-migration.command.ts | 71 --- ...ation-id-not-nullable-migration.command.ts | 71 --- ...ation-id-not-nullable-migration.command.ts | 71 --- ...ation-id-not-nullable-migration.command.ts | 71 --- ...ation-id-not-nullable-migration.command.ts | 71 --- ...ation-id-not-nullable-migration.command.ts | 71 --- ...16-update-task-on-delete-action.command.ts | 341 -------------- .../1-16-upgrade-version-command.module.ts | 130 ------ .../standard-index-field-names.constant.ts | 299 ------------- .../utils/compute-formatted-view-name.util.ts | 16 - ...t-widgets-with-workspace-field-ids.util.ts | 422 ------------------ .../1-17-delete-all-files.command.ts} | 0 .../1-17-upgrade-version-command.module.ts | 2 +- .../upgrade-version-command.module.ts | 8 - .../upgrade.command.ts | 152 +------ ...1718-remove-object-metadata-standard-id.ts | 19 + .../__mocks__/mockPersonObjectMetadata.ts | 1 - .../mockObjectMetadataItemsWithFieldMaps.ts | 4 - .../object-record-changed-values.spec.ts | 1 - .../utils/object-record-changed-values.ts | 23 +- .../is-workflow-related-object.util.spec.ts | 25 +- .../utils/is-workflow-related-object.util.ts | 21 +- .../utils/is-workflow-run-object.util.ts | 20 +- .../__mocks__/attachment-flat-object.mock.ts | 1 - .../__mocks__/company-flat-object.mock.ts | 1 - .../__mocks__/favorite-flat-object.mock.ts | 1 - .../favorite-folder-flat-object.mock.ts | 1 - .../get-flat-object-metadata.mock.ts | 2 - .../__mocks__/note-flat-object.mock.ts | 1 - .../__mocks__/note-target-flat-object.mock.ts | 1 - .../__mocks__/opportunity-flat-object.mock.ts | 1 - .../__mocks__/person-flat-object.mock.ts | 1 - .../__mocks__/pet-flat-object.mock.ts | 1 - .../__mocks__/rocket-flat-object.mock.ts | 1 - .../__mocks__/task-flat-object.mock.ts | 1 - .../__mocks__/task-target-flat-object.mock.ts | 1 - .../timeline-activity-flat-object.mock.ts | 1 - ...and-flat-field-metadatas-to-create.util.ts | 1 - .../object-metadata/object-metadata.entity.ts | 3 - ...-field-metadatas-for-custom-object.util.ts | 6 +- ...rkspace-roles-permissions-cache.service.ts | 23 +- .../workspace-entity-manager.spec.ts | 3 +- ...umn-name-to-field-metadata-id.util.spec.ts | 1 - ...tadata-id-to-column-names-map.util.spec.ts | 1 - ...ow-level-permission-predicate.util.spec.ts | 1 - ...-orm-event-to-database-batch-event.util.ts | 7 +- .../utils/should-seed-workspace-favorite.ts | 11 +- ...t-page-layout-widget-data-seeds-v2.util.ts | 12 +- .../get-page-layout-widget-data-seeds.util.ts | 15 +- .../constants/standard-object.constant.ts | 60 ++- ...eate-standard-object-flat-metadata.util.ts | 1 - .../standard-company-page-layout.config.ts | 5 +- .../standard-note-page-layout.config.ts | 5 +- ...standard-opportunity-page-layout.config.ts | 5 +- .../standard-person-page-layout.config.ts | 5 +- .../standard-task-page-layout.config.ts | 5 +- .../standard-workflow-page-layout.config.ts | 5 +- ...tandard-workflow-run-page-layout.config.ts | 5 +- ...ard-workflow-version-page-layout.config.ts | 6 +- ...standard-page-layout-flat-metadata.util.ts | 6 +- ...t-metadata-to-flat-object-metadata.util.ts | 1 - ...ected-account-delete-one.pre-query.hook.ts | 4 +- .../__tests__/create-company.service.spec.ts | 4 +- .../get-object-metadata-entity.mock.ts | 1 - .../src/metadata/standard-object-ids.ts | 1 + 98 files changed, 165 insertions(+), 8040 deletions(-) delete mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/1-13/1-13-backfill-page-layout-universal-identifiers.command.ts delete mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/1-13/1-13-clean-empty-string-null-in-text-fields.command.ts delete mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/1-13/1-13-deduplicate-role-targets.command.ts delete mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/1-13/1-13-migrate-standard-invalid-entities.command.ts delete mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/1-13/1-13-migrate-timeline-activity-to-morph-relations.command.ts delete mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/1-13/1-13-rename-index.command.ts delete mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/1-13/1-13-update-role-targets-unique-constraint-migration.command.ts delete mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/1-13/1-13-upgrade-version-command.module.ts delete mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/1-14/1-14-delete-removed-agents.command.ts delete mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/1-14/1-14-update-created-by-enum.command.ts delete mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/1-14/1-14-upgrade-version-command.module.ts delete mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/1-15/1-15-add-workspace-foreign-keys-migration.command.ts delete mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/1-15/1-15-backfill-updated-by-field.command.ts delete mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/1-15/1-15-fix-nan-position-values-in-notes.command.ts delete mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/1-15/1-15-migrate-page-layout-widget-configuration.command.ts delete mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/1-15/1-15-upgrade-version-command.module.ts delete mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-backfill-opportunity-owner-field.command.ts delete mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-backfill-standard-page-layouts.command.ts delete mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-flush-v2-cache-and-increment-metadata-version.command.ts delete mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-identify-agent-metadata.command.ts delete mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-identify-field-metadata.command.ts delete mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-identify-index-metadata.command.ts delete mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-identify-object-metadata.command.ts delete mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-identify-remaining-entities-metadata.command.ts delete mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-identify-role-metadata.command.ts delete mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-identify-view-field-metadata.command.ts delete mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-identify-view-filter-metadata.command.ts delete mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-identify-view-group-metadata.command.ts delete mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-identify-view-metadata.command.ts delete mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-make-agent-universal-identifier-and-application-id-not-nullable-migration.command.ts delete mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-make-field-metadata-universal-identifier-and-application-id-not-nullable-migration.command.ts delete mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-make-index-metadata-universal-identifier-and-application-id-not-nullable-migration.command.ts delete mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-make-object-metadata-universal-identifier-and-application-id-not-nullable-migration.command.ts delete mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-make-remaining-entities-universal-identifier-and-application-id-not-nullable-migration.command.ts delete mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-make-role-universal-identifier-and-application-id-not-nullable-migration.command.ts delete mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-make-view-field-universal-identifier-and-application-id-not-nullable-migration.command.ts delete mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-make-view-filter-universal-identifier-and-application-id-not-nullable-migration.command.ts delete mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-make-view-group-universal-identifier-and-application-id-not-nullable-migration.command.ts delete mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-make-view-universal-identifier-and-application-id-not-nullable-migration.command.ts delete mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-update-task-on-delete-action.command.ts delete mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-upgrade-version-command.module.ts delete mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/1-16/constants/standard-index-field-names.constant.ts delete mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/1-16/utils/compute-formatted-view-name.util.ts delete mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/1-16/utils/update-standard-page-layout-widgets-with-workspace-field-ids.util.ts rename packages/twenty-server/src/database/commands/upgrade-version-command/{1-16/1-16-delete-all-files.command.ts => 1-17/1-17-delete-all-files.command.ts} (100%) create mode 100644 packages/twenty-server/src/database/typeorm/core/migrations/common/1770040351718-remove-object-metadata-standard-id.ts diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-13/1-13-backfill-page-layout-universal-identifiers.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-13/1-13-backfill-page-layout-universal-identifiers.command.ts deleted file mode 100644 index 68085dab7c..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-13/1-13-backfill-page-layout-universal-identifiers.command.ts +++ /dev/null @@ -1,183 +0,0 @@ -import { InjectRepository } from '@nestjs/typeorm'; - -import { Command } from 'nest-commander'; -import { IsNull, Repository } from 'typeorm'; -import { v4 } from 'uuid'; - -import { ActiveOrSuspendedWorkspacesMigrationCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner'; -import { RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspaces-migration.command-runner'; -import { ApplicationService } from 'src/engine/core-modules/application/services/application.service'; -import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; -import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; -import { PageLayoutTabEntity } from 'src/engine/metadata-modules/page-layout-tab/entities/page-layout-tab.entity'; -import { PageLayoutWidgetEntity } from 'src/engine/metadata-modules/page-layout-widget/entities/page-layout-widget.entity'; -import { PageLayoutEntity } from 'src/engine/metadata-modules/page-layout/entities/page-layout.entity'; -import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; -import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service'; - -@Command({ - name: 'upgrade:1-13:backfill-page-layout-universal-identifiers', - description: - 'Backfill universalIdentifier and applicationId for pageLayout, pageLayoutTab and pageLayoutWidget', -}) -export class BackfillPageLayoutUniversalIdentifiersCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner { - constructor( - @InjectRepository(WorkspaceEntity) - protected readonly workspaceRepository: Repository, - @InjectRepository(PageLayoutWidgetEntity) - private readonly pageLayoutWidgetRepository: Repository, - @InjectRepository(PageLayoutTabEntity) - private readonly pageLayoutTabRepository: Repository, - @InjectRepository(PageLayoutEntity) - private readonly pageLayoutRepository: Repository, - protected readonly twentyORMGlobalManager: GlobalWorkspaceOrmManager, - protected readonly dataSourceService: DataSourceService, - private readonly applicationService: ApplicationService, - private readonly workspaceCacheService: WorkspaceCacheService, - ) { - super(workspaceRepository, twentyORMGlobalManager, dataSourceService); - } - - override async runOnWorkspace({ - workspaceId, - options, - }: RunOnWorkspaceArgs): Promise { - this.logger.log( - `Starting backfill of universalIdentifier and applicationId for workspace ${workspaceId}`, - ); - - const { workspaceCustomFlatApplication } = - await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow( - { - workspaceId, - }, - ); - - const applicationId = workspaceCustomFlatApplication.id; - - const pageLayoutsToUpdate = await this.pageLayoutRepository.find({ - where: [ - { workspaceId, universalIdentifier: IsNull() }, - { workspaceId, applicationId: IsNull() }, - ], - select: ['id', 'workspaceId'], - }); - - this.logger.log( - `Found ${pageLayoutsToUpdate.length} pageLayout records to backfill`, - ); - - for (const pageLayout of pageLayoutsToUpdate) { - const universalIdentifier = v4(); - - if (options.dryRun) { - this.logger.log( - `[DRY RUN] Would update pageLayout ${pageLayout.id} with universalIdentifier ${universalIdentifier} and applicationId ${applicationId}`, - ); - } else { - await this.pageLayoutRepository.update( - { id: pageLayout.id }, - { - universalIdentifier, - applicationId, - }, - ); - } - - this.logger.log( - `Updated pageLayout ${pageLayout.id} with universalIdentifier ${universalIdentifier}`, - ); - } - - const tabsToUpdate = await this.pageLayoutTabRepository.find({ - where: [ - { workspaceId, universalIdentifier: IsNull() }, - { workspaceId, applicationId: IsNull() }, - ], - select: ['id', 'workspaceId'], - }); - - this.logger.log( - `Found ${tabsToUpdate.length} pageLayoutTab records to backfill`, - ); - - for (const tab of tabsToUpdate) { - const universalIdentifier = v4(); - - if (options.dryRun) { - this.logger.log( - `[DRY RUN] Would update pageLayoutTab ${tab.id} with universalIdentifier ${universalIdentifier} and applicationId ${applicationId}`, - ); - } else { - await this.pageLayoutTabRepository.update( - { id: tab.id }, - { - universalIdentifier, - applicationId, - }, - ); - - this.logger.log( - `Updated pageLayoutTab ${tab.id} with universalIdentifier ${universalIdentifier}`, - ); - } - } - - const widgetsToUpdate = await this.pageLayoutWidgetRepository.find({ - where: [ - { workspaceId, universalIdentifier: IsNull() }, - { workspaceId, applicationId: IsNull() }, - ], - select: ['id', 'workspaceId'], - }); - - this.logger.log( - `Found ${widgetsToUpdate.length} pageLayoutWidget records to backfill`, - ); - - for (const widget of widgetsToUpdate) { - const universalIdentifier = v4(); - - if (options.dryRun) { - this.logger.log( - `[DRY RUN] Would update pageLayoutWidget ${widget.id} with universalIdentifier ${universalIdentifier} and applicationId ${applicationId}`, - ); - } else { - await this.pageLayoutWidgetRepository.update( - { id: widget.id }, - { - universalIdentifier, - applicationId, - }, - ); - - this.logger.log( - `Updated pageLayoutWidget ${widget.id} with universalIdentifier ${universalIdentifier}`, - ); - } - } - - this.logger.log( - `${options.dryRun ? '[DRY RUN] Would have ' : ''}Successfully backfilled ${pageLayoutsToUpdate.length} pageLayouts, ${tabsToUpdate.length} pageLayoutTabs and ${widgetsToUpdate.length} pageLayoutWidgets`, - ); - - if ( - !options.dryRun && - (pageLayoutsToUpdate.length > 0 || - tabsToUpdate.length > 0 || - widgetsToUpdate.length > 0) - ) { - this.logger.log( - `Invalidating and recomputing cache for workspace ${workspaceId}`, - ); - - await this.workspaceCacheService.invalidateAndRecompute(workspaceId, [ - 'flatPageLayoutMaps', - 'flatPageLayoutTabMaps', - 'flatPageLayoutWidgetMaps', - ]); - - this.logger.log(`Cache invalidated and recomputed successfully`); - } - } -} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-13/1-13-clean-empty-string-null-in-text-fields.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-13/1-13-clean-empty-string-null-in-text-fields.command.ts deleted file mode 100644 index 9d5d50df33..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-13/1-13-clean-empty-string-null-in-text-fields.command.ts +++ /dev/null @@ -1,197 +0,0 @@ -import { Logger } from '@nestjs/common'; -import { InjectRepository } from '@nestjs/typeorm'; - -import { Command } from 'nest-commander'; -import { FieldMetadataType } from 'twenty-shared/types'; -import { isDefined } from 'twenty-shared/utils'; -import { Repository } from 'typeorm'; - -import { ActiveOrSuspendedWorkspacesMigrationCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner'; -import { RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspaces-migration.command-runner'; -import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; -import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; -import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; -import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; -import { GlobalWorkspaceDataSource } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-datasource'; -import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; -import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target-table.util'; -import { getWorkspaceSchemaName } from 'src/engine/workspace-datasource/utils/get-workspace-schema-name.util'; - -@Command({ - name: 'upgrade:1-13:clean-empty-string-null-in-text-fields', - description: - 'Clean up empty string defaults in TEXT fields and convert them to NULL', -}) -export class CleanEmptyStringNullInTextFieldsCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner { - protected readonly logger = new Logger( - CleanEmptyStringNullInTextFieldsCommand.name, - ); - - constructor( - @InjectRepository(WorkspaceEntity) - protected readonly workspaceRepository: Repository, - protected readonly globalWorkspaceOrmManager: GlobalWorkspaceOrmManager, - @InjectRepository(ObjectMetadataEntity) - protected readonly objectMetadataRepository: Repository, - @InjectRepository(FieldMetadataEntity) - protected readonly fieldMetadataRepository: Repository, - protected readonly dataSourceService: DataSourceService, - ) { - super(workspaceRepository, globalWorkspaceOrmManager, dataSourceService); - } - - override async runOnWorkspace({ - workspaceId, - options, - dataSource, - }: RunOnWorkspaceArgs): Promise { - const isDryRun = options.dryRun || false; - - if (!isDefined(dataSource)) { - throw new Error( - `Could not find data source for workspace ${workspaceId}, should never occur`, - ); - } - - const workspace = await this.workspaceRepository.findOne({ - where: { id: workspaceId }, - }); - - if (!isDefined(workspace)) { - throw new Error( - `Could not find workspace ${workspaceId}, should never occur`, - ); - } - - const schemaName = getWorkspaceSchemaName(workspaceId); - - if (isDryRun) { - this.logger.log('Dry run mode: No changes will be applied'); - } - - const objectMetadataItems = await this.objectMetadataRepository.find({ - where: { workspaceId }, - relations: ['fields'], - }); - - for (const objectMetadataItem of objectMetadataItems) { - try { - const tableName = computeObjectTargetTable(objectMetadataItem); - - if (!objectMetadataItem.isCustom) { - await this.cleanUpEmptyStringDefaultsInTextFieldsInStandardObjects( - objectMetadataItem, - tableName, - schemaName, - dataSource, - isDryRun, - ); - } - - if (objectMetadataItem.isCustom) { - await this.cleanUpEmptyStringDefaultsAndSetNullableInNameFieldInCustomObjects( - objectMetadataItem, - tableName, - schemaName, - dataSource, - isDryRun, - ); - } - } catch (error) { - this.logger.error( - `Could not cleanup ${objectMetadataItem.isCustom ? 'custom' : 'standard'} object ${objectMetadataItem.nameSingular} records for workspace ${workspaceId}`, - ); - this.logger.error(error); - } - } - } - - private async cleanUpEmptyStringDefaultsInTextFieldsInStandardObjects( - objectMetadataItem: ObjectMetadataEntity, - tableName: string, - schemaName: string, - dataSource: GlobalWorkspaceDataSource, - isDryRun: boolean, - ): Promise { - const textFields = objectMetadataItem.fields.filter( - (field) => - field.type === FieldMetadataType.TEXT && - field.isNullable === true && - field.defaultValue === null, - ); - - for (const field of textFields) { - this.logger.log( - `Checking field ${field.name} on standard object ${objectMetadataItem.nameSingular} (Table: ${tableName})`, - ); - - this.logger.log( - `Cleaning up empty string default for field ${field.name} on ${tableName}`, - ); - - if (!isDryRun) { - await dataSource.query( - `ALTER TABLE "${schemaName}"."${tableName}" ALTER COLUMN "${field.name}" DROP DEFAULT`, - [], - undefined, - { shouldBypassPermissionChecks: true }, - ); - - await dataSource.query( - `UPDATE "${schemaName}"."${tableName}" SET "${field.name}" = NULL WHERE "${field.name}" = ''`, - [], - undefined, - { shouldBypassPermissionChecks: true }, - ); - } - } - } - - private async cleanUpEmptyStringDefaultsAndSetNullableInNameFieldInCustomObjects( - objectMetadataItem: ObjectMetadataEntity, - tableName: string, - schemaName: string, - dataSource: GlobalWorkspaceDataSource, - isDryRun: boolean, - ): Promise { - const nameField = objectMetadataItem.fields.find( - (field) => - field.name === 'name' && - field.type === FieldMetadataType.TEXT && - field.defaultValue === "''", - ); - - if (!isDefined(nameField)) { - return; - } - - this.logger.log( - `Found "name" field with empty string default on ${objectMetadataItem.nameSingular} (Table: ${tableName})`, - ); - - if (!isDryRun) { - await dataSource.query( - `ALTER TABLE "${schemaName}"."${tableName}" ALTER COLUMN "name" DROP DEFAULT, ALTER COLUMN "name" DROP NOT NULL`, - [], - undefined, - { shouldBypassPermissionChecks: true }, - ); - - await dataSource.query( - `UPDATE "${schemaName}"."${tableName}" SET "name" = NULL WHERE "name" = ''`, - [], - undefined, - { shouldBypassPermissionChecks: true }, - ); - - await this.fieldMetadataRepository.update(nameField.id, { - defaultValue: null, - isNullable: true, - }); - - this.logger.log( - `Updated "name" field metadata and cleaned empty strings for ${objectMetadataItem.nameSingular}`, - ); - } - } -} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-13/1-13-deduplicate-role-targets.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-13/1-13-deduplicate-role-targets.command.ts deleted file mode 100644 index cbea2855d3..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-13/1-13-deduplicate-role-targets.command.ts +++ /dev/null @@ -1,129 +0,0 @@ -import { InjectRepository } from '@nestjs/typeorm'; - -import { Command } from 'nest-commander'; -import { In, type Repository } from 'typeorm'; - -import { ActiveOrSuspendedWorkspacesMigrationCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner'; -import { RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspaces-migration.command-runner'; -import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; -import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; -import { RoleTargetEntity } from 'src/engine/metadata-modules/role-target/role-target.entity'; -import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; - -type DuplicateKey = 'apiKeyId' | 'agentId' | 'userWorkspaceId'; - -type DuplicateGroup = { - foreignKeyId: string; - duplicateKey: DuplicateKey; -}; - -@Command({ - name: 'upgrade:1-13:deduplicate-role-targets', - description: - 'Remove duplicate roleTargets keeping only the most recently updated one for each unique constraint', -}) -export class DeduplicateRoleTargetsCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner { - constructor( - @InjectRepository(RoleTargetEntity) - private readonly roleTargetRepository: Repository, - @InjectRepository(WorkspaceEntity) - protected readonly workspaceRepository: Repository, - protected readonly twentyORMGlobalManager: GlobalWorkspaceOrmManager, - protected readonly dataSourceService: DataSourceService, - ) { - super(workspaceRepository, twentyORMGlobalManager, dataSourceService); - } - - override async runOnWorkspace({ - options, - workspaceId, - }: RunOnWorkspaceArgs): Promise { - const isDryRun = options.dryRun || false; - - const duplicateGroups = - await this.findDuplicateGroupsForWorkspace(workspaceId); - - if (duplicateGroups.length === 0) { - return; - } - - const idsToDelete: string[] = []; - - for (const duplicateGroup of duplicateGroups) { - const duplicateIds = await this.findDuplicateIdsToDelete( - workspaceId, - duplicateGroup, - ); - - idsToDelete.push(...duplicateIds); - } - - if (idsToDelete.length === 0) { - return; - } - - if (isDryRun) { - this.logger.log( - `DRY RUN: Would delete ${idsToDelete.length} duplicate roleTarget(s)`, - ); - - return; - } - - await this.roleTargetRepository.delete({ id: In(idsToDelete) }); - - this.logger.log(`Deleted ${idsToDelete.length} duplicate roleTarget(s)`); - } - - private async findDuplicateGroupsForWorkspace( - workspaceId: string, - ): Promise { - const duplicateGroups: DuplicateGroup[] = []; - - const duplicateKeys: DuplicateKey[] = [ - 'apiKeyId', - 'agentId', - 'userWorkspaceId', - ]; - - for (const duplicateKey of duplicateKeys) { - const duplicates = await this.roleTargetRepository - .createQueryBuilder('roleTarget') - .select([`roleTarget.${duplicateKey} AS "foreignKeyId"`]) - .where('roleTarget.workspaceId = :workspaceId', { workspaceId }) - .andWhere(`roleTarget.${duplicateKey} IS NOT NULL`) - .groupBy(`roleTarget.${duplicateKey}`) - .having('COUNT(*) > 1') - .getRawMany<{ foreignKeyId: string }>(); - - for (const duplicate of duplicates) { - duplicateGroups.push({ - foreignKeyId: duplicate.foreignKeyId, - duplicateKey, - }); - } - } - - return duplicateGroups; - } - - private async findDuplicateIdsToDelete( - workspaceId: string, - duplicateGroup: DuplicateGroup, - ): Promise { - const { foreignKeyId, duplicateKey } = duplicateGroup; - - const roleTargets = await this.roleTargetRepository.find({ - where: { - workspaceId, - [duplicateKey]: foreignKeyId, - }, - order: { - updatedAt: 'DESC', - }, - }); - - // Keep the first one (most recently updated), delete the rest - return roleTargets.slice(1).map((roleTarget) => roleTarget.id); - } -} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-13/1-13-migrate-standard-invalid-entities.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-13/1-13-migrate-standard-invalid-entities.command.ts deleted file mode 100644 index dde6fd2a25..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-13/1-13-migrate-standard-invalid-entities.command.ts +++ /dev/null @@ -1,380 +0,0 @@ -import { InjectRepository } from '@nestjs/typeorm'; - -import { Command } from 'nest-commander'; -import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; -import { - type FieldMetadataComplexOption, - type FieldMetadataDefaultValue, - FieldMetadataType, - type FromTo, -} from 'twenty-shared/types'; -import { isDefined } from 'twenty-shared/utils'; -import { type Repository } from 'typeorm'; - -import { ActiveOrSuspendedWorkspacesMigrationCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner'; -import { type RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspaces-migration.command-runner'; -import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; -import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; -import { FieldMetadataService } from 'src/engine/metadata-modules/field-metadata/services/field-metadata.service'; -import { type MetadataFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/metadata-flat-entity-maps.type'; -import { findManyFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-many-flat-entity-by-id-in-flat-entity-maps-or-throw.util'; -import { isFlatFieldMetadataOfType } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-flat-field-metadata-of-type.util'; -import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type'; -import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; -import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service'; -import { type AllStandardObjectFieldName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-field-name.type'; -import { type AllStandardObjectName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-name.type'; -import { - CALENDAR_EVENT_STANDARD_FIELD_IDS, - MESSAGE_CHANNEL_STANDARD_FIELD_IDS, - MESSAGE_PARTICIPANT_STANDARD_FIELD_IDS, - MESSAGE_STANDARD_FIELD_IDS, - WORKSPACE_MEMBER_STANDARD_FIELD_IDS, -} from 'src/engine/workspace-manager/workspace-migration/constant/standard-field-ids'; - -const findStandardFlatObjectMetadataOrThrow = ({ - flatObjectMetadataMaps, - standardId, -}: { - flatObjectMetadataMaps: MetadataFlatEntityMaps<'objectMetadata'>; - standardId: string; -}): FlatObjectMetadata => { - const flatObjectMetadata = Object.values(flatObjectMetadataMaps.byId).find( - (flatObjectMetadata) => flatObjectMetadata?.standardId === standardId, - ); - - if (!isDefined(flatObjectMetadata)) { - throw new Error(`Could not find standard object ${standardId}`); - } - - return flatObjectMetadata; -}; - -const findStandardFlatFieldMetadatawOrThrow = ({ - flatFieldMetadataMaps, - flatObjectMetadata, - standardId, -}: { - standardId: string; - flatObjectMetadata: FlatObjectMetadata; - flatFieldMetadataMaps: MetadataFlatEntityMaps<'fieldMetadata'>; -}) => { - const objectFlatFieldMetadata = findManyFlatEntityByIdInFlatEntityMapsOrThrow( - { - flatEntityIds: flatObjectMetadata.fieldIds, - flatEntityMaps: flatFieldMetadataMaps, - }, - ); - - const flatFieldMetadata = objectFlatFieldMetadata.find( - (flatFieldMetadata) => flatFieldMetadata.standardId === standardId, - ); - - if (!isDefined(flatFieldMetadata)) { - throw new Error(`Could not find standard field ${standardId}`); - } - - return flatFieldMetadata; -}; - -const ENUM_FIELD_OPTIONS_TO_MUTATE = { - messageChannelMessageAssociation: { - fieldStandardId: MESSAGE_STANDARD_FIELD_IDS.direction, - field: 'direction', - defaultValue: { - fromDefaultValue: "'incoming'", - toDefaultValue: "'INCOMING'", - }, - options: [ - { - fromOption: { - value: 'incoming', - label: 'Incoming', - position: 0, - color: 'green', - }, - toOption: { - value: 'INCOMING', - label: 'Incoming', - position: 0, - color: 'green', - }, - }, - { - fromOption: { - value: 'outgoing', - label: 'Outgoing', - position: 1, - color: 'blue', - }, - toOption: { - value: 'OUTGOING', - label: 'Outgoing', - position: 1, - color: 'blue', - }, - }, - ], - }, - messageChannel: { - fieldStandardId: MESSAGE_CHANNEL_STANDARD_FIELD_IDS.type, - field: 'type', - defaultValue: { fromDefaultValue: "'email'", toDefaultValue: "'EMAIL'" }, - options: [ - { - fromOption: { - value: 'email', - label: 'Email', - position: 0, - color: 'green', - }, - toOption: { - value: 'EMAIL', - label: 'Email', - position: 0, - color: 'green', - }, - }, - { - fromOption: { value: 'sms', label: 'SMS', position: 1, color: 'blue' }, - toOption: { value: 'SMS', label: 'SMS', position: 1, color: 'blue' }, - }, - ], - }, - messageParticipant: { - fieldStandardId: MESSAGE_PARTICIPANT_STANDARD_FIELD_IDS.role, - field: 'role', - defaultValue: { fromDefaultValue: "'from'", toDefaultValue: "'FROM'" }, - options: [ - { - fromOption: { - value: 'from', - label: 'From', - position: 0, - color: 'green', - }, - toOption: { value: 'FROM', label: 'From', position: 0, color: 'green' }, - }, - { - fromOption: { value: 'to', label: 'To', position: 1, color: 'blue' }, - toOption: { value: 'TO', label: 'To', position: 1, color: 'blue' }, - }, - { - fromOption: { value: 'cc', label: 'Cc', position: 2, color: 'orange' }, - toOption: { value: 'CC', label: 'Cc', position: 2, color: 'orange' }, - }, - { - fromOption: { value: 'bcc', label: 'Bcc', position: 3, color: 'red' }, - toOption: { value: 'BCC', label: 'Bcc', position: 3, color: 'red' }, - }, - ], - }, - workspaceMember: { - fieldStandardId: WORKSPACE_MEMBER_STANDARD_FIELD_IDS.numberFormat, - field: 'numberFormat', - defaultValue: { fromDefaultValue: "'system'", toDefaultValue: "'SYSTEM'" }, - options: [ - { - fromOption: { - value: 'SYSTEM', - label: 'System', - position: 0, - color: 'turquoise', - }, - toOption: { - value: 'SYSTEM', - label: 'System', - position: 0, - color: 'turquoise', - }, - }, - { - fromOption: { - value: 'COMMAS_AND_DOT', - label: 'Commas and dot (1,234.56)', - position: 1, - color: 'blue', - }, - toOption: { - value: 'COMMAS_AND_DOT', - label: 'Commas and dot', - position: 1, - color: 'blue', - }, - }, - { - fromOption: { - value: 'SPACES_AND_COMMA', - label: 'Spaces and comma (1 234,56)', - position: 2, - color: 'green', - }, - toOption: { - value: 'SPACES_AND_COMMA', - label: 'Spaces and comma', - position: 2, - color: 'green', - }, - }, - { - fromOption: { - value: 'DOTS_AND_COMMA', - label: 'Dots and comma (1.234,56)', - position: 3, - color: 'orange', - }, - toOption: { - value: 'DOTS_AND_COMMA', - label: 'Dots and comma', - position: 3, - color: 'orange', - }, - }, - { - fromOption: { - value: 'APOSTROPHE_AND_DOT', - label: "Apostrophe and dot (1'234.56)", - position: 4, - color: 'purple', - }, - toOption: { - value: 'APOSTROPHE_AND_DOT', - label: 'Apostrophe and dot', - position: 4, - color: 'purple', - }, - }, - ], - }, -} as const satisfies { - [P in AllStandardObjectName]?: { - fieldStandardId: string; - field: AllStandardObjectFieldName

; - options: FromTo[]; - defaultValue: FromTo; - }; -}; - -@Command({ - name: 'upgrade:1-13:migrate-standard-invalid-entities', - description: 'Migrate standard invalid entities', -}) -export class MigrateStandardInvalidEntitiesCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner { - constructor( - @InjectRepository(WorkspaceEntity) - protected readonly workspaceRepository: Repository, - protected readonly twentyORMGlobalManager: GlobalWorkspaceOrmManager, - protected readonly dataSourceService: DataSourceService, - private readonly workspaceCacheService: WorkspaceCacheService, - private readonly fieldMetadataService: FieldMetadataService, - ) { - super(workspaceRepository, twentyORMGlobalManager, dataSourceService); - } - - override async runOnWorkspace({ - options, - workspaceId, - }: RunOnWorkspaceArgs): Promise { - const isDryRun = options.dryRun || false; - - this.logger.log( - `MigrateStandardInvalidEntitiesCommand starting for workspace ${workspaceId}`, - ); - const { flatFieldMetadataMaps, flatObjectMetadataMaps } = - await this.workspaceCacheService.getOrRecompute(workspaceId, [ - 'flatFieldMetadataMaps', - 'flatObjectMetadataMaps', - ]); - - const flatCalendarEventObject = findStandardFlatObjectMetadataOrThrow({ - standardId: STANDARD_OBJECT_IDS.calendarEvent, - flatObjectMetadataMaps, - }); - - const iCalUidFieldId = findStandardFlatFieldMetadatawOrThrow({ - flatFieldMetadataMaps, - flatObjectMetadata: flatCalendarEventObject, - standardId: CALENDAR_EVENT_STANDARD_FIELD_IDS.iCalUid, - }).id; - - const allAffectedObjectNames = Object.keys( - ENUM_FIELD_OPTIONS_TO_MUTATE, - ).filter(isDefined) as (keyof typeof ENUM_FIELD_OPTIONS_TO_MUTATE)[]; - - const flatEnumFieldMetadatasToUpdate = allAffectedObjectNames.flatMap<{ - id: string; - options: FieldMetadataComplexOption[]; - defaultValue: FieldMetadataDefaultValue; - }>((objectName) => { - const { defaultValue, field, options, fieldStandardId } = - ENUM_FIELD_OPTIONS_TO_MUTATE[objectName]; - - const objectStandardId = STANDARD_OBJECT_IDS[objectName]; - - const flatObjectMetadata = findStandardFlatObjectMetadataOrThrow({ - flatObjectMetadataMaps, - standardId: objectStandardId, - }); - - const flatFieldMetadata = findStandardFlatFieldMetadatawOrThrow({ - flatFieldMetadataMaps, - flatObjectMetadata, - standardId: fieldStandardId, - }); - - if ( - flatFieldMetadata.name !== field || - !isFlatFieldMetadataOfType(flatFieldMetadata, FieldMetadataType.SELECT) - ) { - throw new Error( - `Retrieved flat field is not the one expected expected ${field} got ${flatFieldMetadata.name} in workspace ${workspaceId}`, - ); - } - - const updatedOptions = flatFieldMetadata.options.map((option) => { - const matchingNewOption = options.find( - ({ fromOption }) => fromOption.value === option.value, - ); - - if (!isDefined(matchingNewOption)) { - return option; - } - - return { - ...matchingNewOption.toOption, - id: option.id, - }; - }); - - const updatedDefaultValue: FieldMetadataDefaultValue = - flatFieldMetadata.defaultValue === defaultValue.fromDefaultValue - ? defaultValue.toDefaultValue - : flatFieldMetadata.defaultValue; - - return { - id: flatFieldMetadata.id, - options: updatedOptions, - defaultValue: updatedDefaultValue, - }; - }); - - const allUpdates = [ - { - id: iCalUidFieldId, - name: 'iCalUid', - }, - ...flatEnumFieldMetadatasToUpdate, - ]; - - if (!isDryRun) { - for (const updateFieldInput of allUpdates) { - await this.fieldMetadataService.updateOneField({ - updateFieldInput, - workspaceId, - isSystemBuild: true, - }); - } - } - this.logger.log('Migrated standard invalid entities'); - } -} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-13/1-13-migrate-timeline-activity-to-morph-relations.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-13/1-13-migrate-timeline-activity-to-morph-relations.command.ts deleted file mode 100644 index 2a35c411c5..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-13/1-13-migrate-timeline-activity-to-morph-relations.command.ts +++ /dev/null @@ -1,267 +0,0 @@ -import { InjectDataSource, InjectRepository } from '@nestjs/typeorm'; - -import { Command } from 'nest-commander'; -import { capitalize } from 'twenty-shared/utils'; -import { DataSource, Repository } from 'typeorm'; - -import { ActiveOrSuspendedWorkspacesMigrationCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner'; -import { RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspaces-migration.command-runner'; -import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum'; -import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service'; -import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; -import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; -import { computeMorphOrRelationFieldJoinColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-morph-or-relation-field-join-column-name.util'; -import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; -import { WorkspaceMetadataVersionService } from 'src/engine/metadata-modules/workspace-metadata-version/services/workspace-metadata-version.service'; -import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; -import { WorkspaceCacheStorageService } from 'src/engine/workspace-cache-storage/workspace-cache-storage.service'; -import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service'; -import { getWorkspaceSchemaName } from 'src/engine/workspace-datasource/utils/get-workspace-schema-name.util'; -import { TIMELINE_ACTIVITY_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-migration/constant/standard-field-ids'; -import { buildTimelineActivityRelatedMorphFieldMetadataName } from 'src/modules/timeline/utils/timeline-activity-related-morph-field-metadata-name-builder.util'; - -@Command({ - name: 'upgrade:1-13:migrate-timeline-activity-to-morph-relations', - description: - 'Migrate timeline activity relations to morph relation fields and set feature flag', -}) -export class MigrateTimelineActivityToMorphRelationsCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner { - constructor( - @InjectRepository(WorkspaceEntity) - protected readonly workspaceRepository: Repository, - private readonly featureFlagService: FeatureFlagService, - @InjectRepository(ObjectMetadataEntity) - private readonly objectMetadataRepository: Repository, - @InjectDataSource() - private readonly coreDataSource: DataSource, - private readonly twentyORMGlobalManager: GlobalWorkspaceOrmManager, - protected readonly dataSourceService: DataSourceService, - private readonly workspaceCacheStorageService: WorkspaceCacheStorageService, - private readonly workspaceCacheService: WorkspaceCacheService, - private readonly workspaceMetadataVersionService: WorkspaceMetadataVersionService, - ) { - super(workspaceRepository, twentyORMGlobalManager, dataSourceService); - } - - override async runOnWorkspace({ - workspaceId, - options, - }: RunOnWorkspaceArgs): Promise { - const isMigrated = await this.featureFlagService.isFeatureEnabled( - FeatureFlagKey.IS_TIMELINE_ACTIVITY_MIGRATED, - workspaceId, - ); - - this.logger.log(`Migrating timelineActivity for workspace ${workspaceId}`); - - if (isMigrated) { - this.logger.log( - `Timeline activity migration already completed. Skipping...`, - ); - - return; - } - - if (options.dryRun) { - this.logger.log( - `Would have migrated timeline activities for workspace ${workspaceId}. Skipping...`, - ); - - return; - } - - const queryRunner = this.coreDataSource.createQueryRunner(); - - await queryRunner.connect(); - await queryRunner.startTransaction(); - - try { - const schemaName = getWorkspaceSchemaName(workspaceId); - const tableName = 'timelineActivity'; - - const customObjectMetadata = await this.objectMetadataRepository.find({ - where: { - workspaceId, - isCustom: true, - }, - }); - const customObjectMetadataNames = customObjectMetadata.map( - (objectMetadata) => objectMetadata.nameSingular, - ); - - const fieldNameMigrations = [ - { old: 'company', new: 'targetCompany' }, - { old: 'person', new: 'targetPerson' }, - { old: 'opportunity', new: 'targetOpportunity' }, - { old: 'note', new: 'targetNote' }, - { old: 'task', new: 'targetTask' }, - { old: 'workflow', new: 'targetWorkflow' }, - { old: 'workflowVersion', new: 'targetWorkflowVersion' }, - { old: 'workflowRun', new: 'targetWorkflowRun' }, - { old: 'dashboard', new: 'targetDashboard' }, - ...customObjectMetadataNames.map((customObjectName) => ({ - old: `${customObjectName}`, - new: `target${capitalize(customObjectName)}`, - })), - ]; - - const fieldMigrations = fieldNameMigrations.map( - ({ old: oldFieldName, new: newFieldName }) => ({ - old: `${oldFieldName}Id`, - new: `${newFieldName}Id`, - }), - ); - - const timelineActivityObjectMetadata = - await this.objectMetadataRepository.findOne({ - where: { - workspaceId, - nameSingular: 'timelineActivity', - }, - relations: ['fields'], - }); - - if (!timelineActivityObjectMetadata) { - this.logger.error( - `🟥 Timeline activity object metadata not found for workspace ${workspaceId}`, - ); - - return; - } - - for (const { new: newField, old: oldField } of fieldMigrations) { - try { - await queryRunner.query( - `ALTER TABLE "${schemaName}"."${tableName}" - RENAME COLUMN "${oldField}" TO "${newField}"`, - ); - this.logger.log( - `Renamed column "${oldField}" to "${newField}" for "${tableName}"`, - ); - } catch (error) { - this.logger.error( - `Error renaming column "${oldField}" to "${newField}" for "${tableName}" in workspace ${workspaceId}`, - error, - ); - - throw error; - } - } - - this.logger.log(`✅ Successfully migrated timeline activity records`); - - const objectNamesToMigrate = fieldNameMigrations.map( - ({ old: oldFieldName }) => oldFieldName, - ); - - const relatedObjectMetadata = await this.objectMetadataRepository.find({ - where: { - workspaceId, - }, - }); - - const relatedObjectMetadataMap = new Map( - relatedObjectMetadata.map((obj) => [obj.nameSingular, obj]), - ); - - const morphId = TIMELINE_ACTIVITY_STANDARD_FIELD_IDS.targetMorphId; - - for (const objectName of objectNamesToMigrate) { - const relatedObject = relatedObjectMetadataMap.get(objectName); - - if (!relatedObject) { - this.logger.warn( - `Related object metadata not found for ${objectName} in workspace ${workspaceId}`, - ); - continue; - } - - const fieldToMigrate = timelineActivityObjectMetadata.fields.find( - (field) => - field.type === 'RELATION' && - field.relationTargetObjectMetadataId === relatedObject.id, - ); - - if (!fieldToMigrate) { - this.logger.log( - `No RELATION field found for ${objectName} in timelineActivity`, - ); - continue; - } - - const newFieldName = buildTimelineActivityRelatedMorphFieldMetadataName( - fieldToMigrate.name, - ); - - const settings = { - ...fieldToMigrate.settings, - joinColumnName: computeMorphOrRelationFieldJoinColumnName({ - name: newFieldName, - }), - }; - - try { - const result = await queryRunner.query( - `UPDATE core."fieldMetadata" - SET name = $1, type = 'MORPH_RELATION', "morphId" = $3, settings = $4 - WHERE id = $2`, - [newFieldName, fieldToMigrate.id, morphId, settings], - ); - - const rowsUpdated = result[1] || 0; - - if (rowsUpdated > 0) { - this.logger.log( - `Updated fieldMetadata: ${fieldToMigrate.name} → ${newFieldName} (type: MORPH_RELATION)`, - ); - } - } catch (error) { - this.logger.error( - `Error updating fieldMetadata for ${objectName} in workspace ${workspaceId}`, - error, - ); - - throw error; - } - } - - this.logger.log( - `✅ Successfully migrated timeline activity fieldmetadata`, - ); - - await queryRunner.commitTransaction(); - - await this.featureFlagService.enableFeatureFlags( - [FeatureFlagKey.IS_TIMELINE_ACTIVITY_MIGRATED], - workspaceId, - ); - - await this.workspaceCacheService.invalidateAndRecompute(workspaceId, [ - 'flatFieldMetadataMaps', - 'flatObjectMetadataMaps', - 'featureFlagsMap', - ]); - - await this.workspaceMetadataVersionService.incrementMetadataVersion( - workspaceId, - ); - this.logger.log(`Cache flushed`); - - this.logger.log( - `Set IS_TIMELINE_ACTIVITY_MIGRATED feature flag for workspace ${workspaceId}`, - ); - - this.logger.log(`Flush cache for workspace ${workspaceId}`); - await this.workspaceCacheStorageService.flush(workspaceId); - } catch (error) { - await queryRunner.rollbackTransaction(); - this.logger.error( - `Error migrating timeline activity to morph relations (rolled transaction back on ${workspaceId})`, - error, - ); - throw error; - } finally { - await queryRunner.release(); - } - } -} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-13/1-13-rename-index.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-13/1-13-rename-index.command.ts deleted file mode 100644 index 6ab8e6a6b0..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-13/1-13-rename-index.command.ts +++ /dev/null @@ -1,206 +0,0 @@ -import { Logger } from '@nestjs/common'; -import { InjectDataSource, InjectRepository } from '@nestjs/typeorm'; - -import { Command } from 'nest-commander'; -import { isDefined } from 'twenty-shared/utils'; -import { DataSource, Repository } from 'typeorm'; - -import { ActiveOrSuspendedWorkspacesMigrationCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner'; -import { RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspaces-migration.command-runner'; -import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; -import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; -import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util'; -import { findManyFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-many-flat-entity-by-id-in-flat-entity-maps-or-throw.util'; -import { IndexMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-metadata.entity'; -import { generateFlatIndexMetadataWithNameOrThrow } from 'src/engine/metadata-modules/index-metadata/utils/generate-flat-index.util'; -import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; -import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service'; -import { getWorkspaceSchemaName } from 'src/engine/workspace-datasource/utils/get-workspace-schema-name.util'; - -@Command({ - name: 'upgrade:1-13:rename-index-name', - description: 'Rename indexes to use the new v2 index name format', -}) -export class RenameIndexNameCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner { - protected readonly logger = new Logger(RenameIndexNameCommand.name); - - constructor( - @InjectRepository(WorkspaceEntity) - protected readonly workspaceRepository: Repository, - protected readonly twentyORMGlobalManager: GlobalWorkspaceOrmManager, - protected readonly workspaceCacheService: WorkspaceCacheService, - protected readonly dataSourceService: DataSourceService, - @InjectDataSource() - private readonly coreDataSource: DataSource, - ) { - super(workspaceRepository, twentyORMGlobalManager, dataSourceService); - } - - override async runOnWorkspace({ - workspaceId, - options, - dataSource, - }: RunOnWorkspaceArgs): Promise { - const isDryRun = options.dryRun || false; - - if (!isDefined(dataSource)) { - throw new Error( - `Could not find data source for workspace ${workspaceId}, should never occur`, - ); - } - - const schemaName = getWorkspaceSchemaName(workspaceId); - - if (isDryRun) { - this.logger.log('Dry run mode: No changes will be applied'); - } - - const { flatIndexMaps, flatObjectMetadataMaps, flatFieldMetadataMaps } = - await this.workspaceCacheService.getOrRecompute(workspaceId, [ - 'flatIndexMaps', - 'flatObjectMetadataMaps', - 'flatFieldMetadataMaps', - ]); - - const indexMetadataByName = new Map( - Object.values(flatIndexMaps.byId) - .filter(isDefined) - .map((index) => [index.name, index]), - ); - - let hasIndexNameChanges = false; - let hasRemovedIndexMetadata = false; - - for (const index of Object.values(flatIndexMaps.byId).filter(isDefined)) { - const flatObjectMetadata = findFlatEntityByIdInFlatEntityMapsOrThrow({ - flatEntityId: index.objectMetadataId, - flatEntityMaps: flatObjectMetadataMaps, - }); - - const flatFieldMetadatas = findManyFlatEntityByIdInFlatEntityMapsOrThrow({ - flatEntityIds: flatObjectMetadata.fieldIds, - flatEntityMaps: flatFieldMetadataMaps, - }); - - const { name: indexNameV2 } = generateFlatIndexMetadataWithNameOrThrow({ - flatObjectMetadata, - objectFlatFieldMetadatas: flatFieldMetadatas, - flatIndex: index, - }); - - if (indexNameV2 === index.name) { - this.logger.log(`Index ${index.name} is V2`); - continue; - } - - // Check if another metadata entry already has the v2 name - const existingV2Metadata = indexMetadataByName.get(indexNameV2); - - if (isDefined(existingV2Metadata) && existingV2Metadata.id !== index.id) { - // V2 metadata already exists, this v1 metadata is stale - this.logger.log( - `Index metadata with v2 name ${indexNameV2} already exists, removing stale v1 metadata and index ${index.name}`, - ); - - if (!isDryRun) { - const queryRunner = this.coreDataSource.createQueryRunner(); - - await queryRunner.connect(); - await queryRunner.startTransaction(); - - try { - await queryRunner.manager.delete(IndexMetadataEntity, index.id); - await queryRunner.query( - `DROP INDEX IF EXISTS "${schemaName}"."${index.name}"`, - ); - await queryRunner.commitTransaction(); - hasRemovedIndexMetadata = true; - } catch (error) { - await queryRunner.rollbackTransaction(); - throw error; - } finally { - await queryRunner.release(); - } - } - continue; - } - - this.logger.log(`Renaming index ${index.name} to ${indexNameV2}`); - - if (isDryRun) { - continue; - } - - const queryRunner = this.coreDataSource.createQueryRunner(); - - await queryRunner.connect(); - await queryRunner.startTransaction(); - - try { - await queryRunner.query( - `ALTER INDEX "${schemaName}"."${index.name}" RENAME TO "${indexNameV2}"`, - ); - - await queryRunner.manager.update(IndexMetadataEntity, index.id, { - name: indexNameV2, - }); - - await queryRunner.commitTransaction(); - hasIndexNameChanges = true; - } catch (error) { - await queryRunner.rollbackTransaction(); - - // PostgreSQL error codes for non-existent index: - // - 42704: undefined_object - // - 42P01: undefined_table (index treated as relation) - if (error.code === '42704' || error.code === '42P01') { - this.logger.log( - `Index ${index.name} does not exist in schema ${schemaName}, removing metadata`, - ); - - await this.coreDataSource.manager.delete( - IndexMetadataEntity, - index.id, - ); - hasRemovedIndexMetadata = true; - } else if (error.code === '42P07') { - // PostgreSQL error code 42P07: duplicate_table (v2 index already exists) - // The v2 index already exists, remove stale v1 metadata and index - this.logger.log( - `Index ${indexNameV2} already exists at PG level, removing stale v1 metadata and index ${index.name}`, - ); - - await this.coreDataSource.manager.delete( - IndexMetadataEntity, - index.id, - ); - - await this.coreDataSource.query( - `DROP INDEX IF EXISTS "${schemaName}"."${index.name}"`, - ); - - hasRemovedIndexMetadata = true; - } else { - this.logger.error( - `Failed to rename index ${index.name}, error code: ${error.code}`, - ); - throw error; - } - } finally { - await queryRunner.release(); - } - } - - const shouldInvalidateCache = - hasIndexNameChanges || hasRemovedIndexMetadata; - - if (shouldInvalidateCache) { - this.logger.log('Invalidating workspace cache'); - - await this.workspaceCacheService.invalidateAndRecompute(workspaceId, [ - 'flatFieldMetadataMaps', - 'flatIndexMaps', - ]); - } - } -} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-13/1-13-update-role-targets-unique-constraint-migration.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-13/1-13-update-role-targets-unique-constraint-migration.command.ts deleted file mode 100644 index 3a118ef151..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-13/1-13-update-role-targets-unique-constraint-migration.command.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { InjectDataSource, InjectRepository } from '@nestjs/typeorm'; - -import { Command } from 'nest-commander'; -import { DataSource, Repository } from 'typeorm'; - -import { ActiveOrSuspendedWorkspacesMigrationCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner'; -import { RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspaces-migration.command-runner'; -import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; -import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; -import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; - -@Command({ - name: 'upgrade:1-13:update-role-targets-unique-constraint-migration', - description: - 'Update roleTargets unique constraints from combined to separate constraints', -}) -export class UpdateRoleTargetsUniqueConstraintMigrationCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner { - private hasRunOnce = false; - - constructor( - @InjectRepository(WorkspaceEntity) - protected readonly workspaceRepository: Repository, - protected readonly twentyORMGlobalManager: GlobalWorkspaceOrmManager, - protected readonly dataSourceService: DataSourceService, - @InjectDataSource() - private readonly coreDataSource: DataSource, - ) { - super(workspaceRepository, twentyORMGlobalManager, dataSourceService); - } - - override async runOnWorkspace({ - options, - }: RunOnWorkspaceArgs): Promise { - if (this.hasRunOnce) { - this.logger.log( - 'Skipping has already been run once UpdateRoleTargetsUniqueConstraintMigrationCommand', - ); - - return; - } - - const queryRunner = this.coreDataSource.createQueryRunner(); - - await queryRunner.connect(); - await queryRunner.startTransaction(); - - if (!options.dryRun) { - try { - await queryRunner.query( - `ALTER TABLE "core"."roleTarget" DROP CONSTRAINT "IDX_ROLE_TARGETS_UNIQUE"`, - ); - await queryRunner.query( - `ALTER TABLE "core"."roleTarget" ADD CONSTRAINT "IDX_ROLE_TARGET_UNIQUE_API_KEY" UNIQUE ("workspaceId", "apiKeyId")`, - ); - await queryRunner.query( - `ALTER TABLE "core"."roleTarget" ADD CONSTRAINT "IDX_ROLE_TARGET_UNIQUE_AGENT" UNIQUE ("workspaceId", "agentId")`, - ); - await queryRunner.query( - `ALTER TABLE "core"."roleTarget" ADD CONSTRAINT "IDX_ROLE_TARGET_UNIQUE_USER_WORKSPACE" UNIQUE ("workspaceId", "userWorkspaceId")`, - ); - - await queryRunner.commitTransaction(); - this.logger.log( - 'Successfully run UpdateRoleTargetsUniqueConstraintMigrationCommand', - ); - this.hasRunOnce = true; - } catch (error) { - await queryRunner.rollbackTransaction(); - this.logger.log( - `Rollbacking UpdateRoleTargetsUniqueConstraintMigrationCommand: ${error.message}`, - ); - } finally { - await queryRunner.release(); - } - } - } -} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-13/1-13-upgrade-version-command.module.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-13/1-13-upgrade-version-command.module.ts deleted file mode 100644 index c43ca1b1d0..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-13/1-13-upgrade-version-command.module.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { Module } from '@nestjs/common'; -import { TypeOrmModule } from '@nestjs/typeorm'; - -import { BackfillPageLayoutUniversalIdentifiersCommand } from 'src/database/commands/upgrade-version-command/1-13/1-13-backfill-page-layout-universal-identifiers.command'; -import { CleanEmptyStringNullInTextFieldsCommand } from 'src/database/commands/upgrade-version-command/1-13/1-13-clean-empty-string-null-in-text-fields.command'; -import { DeduplicateRoleTargetsCommand } from 'src/database/commands/upgrade-version-command/1-13/1-13-deduplicate-role-targets.command'; -import { MigrateStandardInvalidEntitiesCommand } from 'src/database/commands/upgrade-version-command/1-13/1-13-migrate-standard-invalid-entities.command'; -import { MigrateTimelineActivityToMorphRelationsCommand } from 'src/database/commands/upgrade-version-command/1-13/1-13-migrate-timeline-activity-to-morph-relations.command'; -import { RenameIndexNameCommand } from 'src/database/commands/upgrade-version-command/1-13/1-13-rename-index.command'; -import { UpdateRoleTargetsUniqueConstraintMigrationCommand } from 'src/database/commands/upgrade-version-command/1-13/1-13-update-role-targets-unique-constraint-migration.command'; -import { ApplicationModule } from 'src/engine/core-modules/application/application.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'; -import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; -import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module'; -import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; -import { FieldMetadataModule } from 'src/engine/metadata-modules/field-metadata/field-metadata.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'; -import { PageLayoutTabEntity } from 'src/engine/metadata-modules/page-layout-tab/entities/page-layout-tab.entity'; -import { PageLayoutWidgetEntity } from 'src/engine/metadata-modules/page-layout-widget/entities/page-layout-widget.entity'; -import { PageLayoutEntity } from 'src/engine/metadata-modules/page-layout/entities/page-layout.entity'; -import { RoleTargetEntity } from 'src/engine/metadata-modules/role-target/role-target.entity'; -import { ViewGroupEntity } from 'src/engine/metadata-modules/view-group/entities/view-group.entity'; -import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity'; -import { WorkspaceMetadataVersionModule } from 'src/engine/metadata-modules/workspace-metadata-version/workspace-metadata-version.module'; -import { WorkspaceSchemaManagerModule } from 'src/engine/twenty-orm/workspace-schema-manager/workspace-schema-manager.module'; -import { WorkspaceCacheStorageModule } from 'src/engine/workspace-cache-storage/workspace-cache-storage.module'; -import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache.module'; -import { TimelineActivityWorkspaceEntity } from 'src/modules/timeline/standard-objects/timeline-activity.workspace-entity'; - -@Module({ - imports: [ - TypeOrmModule.forFeature([ - WorkspaceEntity, - ObjectMetadataEntity, - FieldMetadataEntity, - IndexMetadataEntity, - ViewEntity, - ViewGroupEntity, - FeatureFlagEntity, - RoleTargetEntity, - PageLayoutEntity, - PageLayoutWidgetEntity, - PageLayoutTabEntity, - TimelineActivityWorkspaceEntity, - ]), - DataSourceModule, - WorkspaceSchemaManagerModule, - WorkspaceCacheStorageModule, - WorkspaceMetadataVersionModule, - FeatureFlagModule, - WorkspaceCacheModule, - FieldMetadataModule, - ObjectMetadataModule, - ApplicationModule, - ], - providers: [ - CleanEmptyStringNullInTextFieldsCommand, - BackfillPageLayoutUniversalIdentifiersCommand, - DeduplicateRoleTargetsCommand, - RenameIndexNameCommand, - MigrateStandardInvalidEntitiesCommand, - UpdateRoleTargetsUniqueConstraintMigrationCommand, - MigrateTimelineActivityToMorphRelationsCommand, - ], - exports: [ - CleanEmptyStringNullInTextFieldsCommand, - BackfillPageLayoutUniversalIdentifiersCommand, - DeduplicateRoleTargetsCommand, - RenameIndexNameCommand, - MigrateStandardInvalidEntitiesCommand, - UpdateRoleTargetsUniqueConstraintMigrationCommand, - MigrateTimelineActivityToMorphRelationsCommand, - ], -}) -export class V1_13_UpgradeVersionCommandModule {} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-14/1-14-delete-removed-agents.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-14/1-14-delete-removed-agents.command.ts deleted file mode 100644 index 24eddb723a..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-14/1-14-delete-removed-agents.command.ts +++ /dev/null @@ -1,157 +0,0 @@ -import { InjectRepository } from '@nestjs/typeorm'; - -import { Command } from 'nest-commander'; -import { isDefined } from 'twenty-shared/utils'; -import { type Repository } from 'typeorm'; - -import { ActiveOrSuspendedWorkspacesMigrationCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner'; -import { RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspaces-migration.command-runner'; -import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; -import { AgentService } from 'src/engine/metadata-modules/ai/ai-agent/agent.service'; -import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; -import { FlatAgentMaps } from 'src/engine/metadata-modules/flat-agent/types/flat-agent-maps.type'; -import { MetadataFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/metadata-flat-entity-maps.type'; -import { RoleService } from 'src/engine/metadata-modules/role/role.service'; -import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; -import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service'; - -const REMOVED_AGENT_STANDARD_IDS = [ - '20202020-0002-0001-0001-000000000006', // dashboard-builder - '20202020-0002-0001-0001-000000000003', // data-manipulator - '20202020-0002-0001-0001-000000000007', // metadata-builder - '20202020-0002-0001-0001-000000000005', // researcher - '20202020-0002-0001-0001-000000000001', // workflow-builder -]; - -const REMOVED_ROLE_STANDARD_IDS = [ - '20202020-0001-0001-0001-000000000002', // workflow-manager - '20202020-0001-0001-0001-000000000004', // data-manipulator - '20202020-0001-0001-0001-000000000005', // dashboard-manager - '20202020-0001-0001-0001-000000000006', // data-model-manager -]; - -@Command({ - name: 'upgrade:1-14:delete-removed-agents', - description: 'Delete agents and roles that were removed from the codebase', -}) -export class DeleteRemovedAgentsCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner { - constructor( - @InjectRepository(WorkspaceEntity) - protected readonly workspaceRepository: Repository, - protected readonly twentyORMGlobalManager: GlobalWorkspaceOrmManager, - protected readonly dataSourceService: DataSourceService, - private readonly workspaceCacheService: WorkspaceCacheService, - private readonly agentService: AgentService, - private readonly roleService: RoleService, - ) { - super(workspaceRepository, twentyORMGlobalManager, dataSourceService); - } - - override async runOnWorkspace({ - options, - workspaceId, - }: RunOnWorkspaceArgs): Promise { - const isDryRun = options.dryRun || false; - - const { flatAgentMaps, flatRoleMaps } = - await this.workspaceCacheService.getOrRecompute(workspaceId, [ - 'flatAgentMaps', - 'flatRoleMaps', - ]); - - await this.deleteRemovedAgents({ flatAgentMaps, workspaceId, isDryRun }); - await this.deleteRemovedRoles({ flatRoleMaps, workspaceId, isDryRun }); - } - - private async deleteRemovedAgents({ - flatAgentMaps, - workspaceId, - isDryRun, - }: { - flatAgentMaps: FlatAgentMaps; - workspaceId: string; - isDryRun: boolean; - }): Promise { - const allAgents = Object.values(flatAgentMaps.byId).filter(isDefined); - - const agentsToDelete = allAgents.filter((agent) => - REMOVED_AGENT_STANDARD_IDS.includes(agent.standardId ?? ''), - ); - - const agentNames = agentsToDelete.map((agent) => agent.name).join(', '); - - this.logger.log( - `DRY RUN: Would delete ${agentsToDelete.length} removed agent(s): ${agentNames}`, - ); - - if (agentsToDelete.length === 0 || isDryRun) { - return; - } - - const agentIds = agentsToDelete.map((agent) => agent.id); - - try { - await this.agentService.deleteManyAgents({ - ids: agentIds, - workspaceId, - isSystemBuild: true, - }); - } catch (error) { - this.logger.error( - `Failed to delete workspace agents \n ${JSON.stringify(error, null, 2)}`, - ); - - throw error; - } - - this.logger.log( - `Deleted ${agentsToDelete.length} removed agent(s): ${agentNames}`, - ); - } - - private async deleteRemovedRoles({ - flatRoleMaps, - workspaceId, - isDryRun, - }: { - flatRoleMaps: MetadataFlatEntityMaps<'role'>; - workspaceId: string; - isDryRun: boolean; - }): Promise { - const allRoles = Object.values(flatRoleMaps.byId).filter(isDefined); - - const rolesToDelete = allRoles.filter((role) => - REMOVED_ROLE_STANDARD_IDS.includes(role.standardId ?? ''), - ); - - const roleLabels = rolesToDelete.map((role) => role.label).join(', '); - - this.logger.log( - `DRY RUN: Would delete ${rolesToDelete.length} removed role(s): ${roleLabels}`, - ); - - if (rolesToDelete.length === 0 || isDryRun) { - return; - } - - const roleIds = rolesToDelete.map((role) => role.id); - - try { - await this.roleService.deleteManyRoles({ - ids: roleIds, - workspaceId, - isSystemBuild: true, - }); - } catch (error) { - this.logger.error( - `Failed to delete workspace roles \n ${JSON.stringify(error, null, 2)}`, - ); - - throw error; - } - - this.logger.log( - `Deleted ${rolesToDelete.length} removed role(s): ${roleLabels}`, - ); - } -} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-14/1-14-update-created-by-enum.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-14/1-14-update-created-by-enum.command.ts deleted file mode 100644 index 7d15346f31..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-14/1-14-update-created-by-enum.command.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { Logger } from '@nestjs/common'; -import { InjectDataSource, InjectRepository } from '@nestjs/typeorm'; - -import { Command } from 'nest-commander'; -import { FieldMetadataType } from 'twenty-shared/types'; -import { isDefined } from 'twenty-shared/utils'; -import { DataSource, Repository } from 'typeorm'; - -import { ActiveOrSuspendedWorkspacesMigrationCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner'; -import { RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspaces-migration.command-runner'; -import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; -import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; -import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; -import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; -import { computeTableName } from 'src/engine/utils/compute-table-name.util'; -import { getWorkspaceSchemaName } from 'src/engine/workspace-datasource/utils/get-workspace-schema-name.util'; -import { computePostgresEnumName } from 'src/engine/workspace-manager/workspace-migration/utils/compute-postgres-enum-name.util'; - -@Command({ - name: 'upgrade:1-14:udpate-created-by-enum', - description: 'Add new APPLICATION value to createdBy enum', -}) -export class UpdateCreatedByEnumCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner { - protected readonly logger = new Logger(UpdateCreatedByEnumCommand.name); - - constructor( - @InjectRepository(WorkspaceEntity) - protected readonly workspaceRepository: Repository, - protected readonly twentyORMGlobalManager: GlobalWorkspaceOrmManager, - protected readonly dataSourceService: DataSourceService, - @InjectRepository(FieldMetadataEntity) - protected readonly fieldMetadataRepository: Repository, - @InjectDataSource() - private readonly coreDataSource: DataSource, - ) { - super(workspaceRepository, twentyORMGlobalManager, dataSourceService); - } - - override async runOnWorkspace({ - workspaceId, - options, - dataSource, - }: RunOnWorkspaceArgs): Promise { - const isDryRun = options.dryRun || false; - - if (!isDefined(dataSource)) { - throw new Error( - `Could not find data source for workspace ${workspaceId}, should never occur`, - ); - } - - const schemaName = getWorkspaceSchemaName(workspaceId); - - const queryRunner = this.coreDataSource.createQueryRunner(); - - await queryRunner.connect(); - await queryRunner.startTransaction(); - - const createdByFields = await this.fieldMetadataRepository.find({ - where: { workspaceId, name: 'createdBy', type: FieldMetadataType.ACTOR }, - relations: ['object'], - }); - - if (isDryRun) { - this.logger.log( - `Dry run mode: found ${createdByFields.length} createdBy enums to update`, - ); - } - - if (!options.dryRun) { - this.logger.log(`Updating ${createdByFields.length} createdBy enums`); - try { - for (const createdByField of createdByFields) { - const tableName = computeTableName( - createdByField.object.nameSingular, - createdByField.object.isCustom, - ); - const createdByEnumName = computePostgresEnumName({ - tableName, - columnName: 'createdBySource', - }); - - await queryRunner.query( - `ALTER TYPE "${schemaName}"."${createdByEnumName}" ADD VALUE IF NOT EXISTS 'APPLICATION'`, - ); - } - await queryRunner.commitTransaction(); - } catch (error) { - await queryRunner.rollbackTransaction(); - this.logger.log( - `Rollbacking UpdateCreatedByEnumCommand: ${error.message}`, - ); - } finally { - await queryRunner.release(); - } - } - } -} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-14/1-14-upgrade-version-command.module.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-14/1-14-upgrade-version-command.module.ts deleted file mode 100644 index 92b6b9a326..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-14/1-14-upgrade-version-command.module.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Module } from '@nestjs/common'; -import { TypeOrmModule } from '@nestjs/typeorm'; - -import { DeleteRemovedAgentsCommand } from 'src/database/commands/upgrade-version-command/1-14/1-14-delete-removed-agents.command'; -import { UpdateCreatedByEnumCommand } from 'src/database/commands/upgrade-version-command/1-14/1-14-update-created-by-enum.command'; -import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; -import { AiAgentModule } from 'src/engine/metadata-modules/ai/ai-agent/ai-agent.module'; -import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module'; -import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; -import { RoleModule } from 'src/engine/metadata-modules/role/role.module'; -import { WorkspaceSchemaManagerModule } from 'src/engine/twenty-orm/workspace-schema-manager/workspace-schema-manager.module'; -import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache.module'; - -@Module({ - imports: [ - TypeOrmModule.forFeature([WorkspaceEntity, FieldMetadataEntity]), - DataSourceModule, - AiAgentModule, - RoleModule, - WorkspaceSchemaManagerModule, - WorkspaceCacheModule, - ], - providers: [UpdateCreatedByEnumCommand, DeleteRemovedAgentsCommand], - exports: [DeleteRemovedAgentsCommand, UpdateCreatedByEnumCommand], -}) -export class V1_14_UpgradeVersionCommandModule {} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-15/1-15-add-workspace-foreign-keys-migration.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-15/1-15-add-workspace-foreign-keys-migration.command.ts deleted file mode 100644 index a8987fe230..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-15/1-15-add-workspace-foreign-keys-migration.command.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { InjectDataSource, InjectRepository } from '@nestjs/typeorm'; - -import { Command } from 'nest-commander'; -import { DataSource, Repository } from 'typeorm'; - -import { ActiveOrSuspendedWorkspacesMigrationCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner'; -import { RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspaces-migration.command-runner'; -import { addWorkspaceForeignKeysQueries } from 'src/database/typeorm/core/migrations/utils/1767002571103-addWorkspaceForeignKeys.util'; -import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; -import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; -import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; - -@Command({ - name: 'upgrade:1-15:add-workspace-foreign-keys-migration', - description: 'Add foreign key constraints for workspaceId on core tables', -}) -export class AddWorkspaceForeignKeysMigrationCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner { - private hasRunOnce = false; - - constructor( - @InjectRepository(WorkspaceEntity) - protected readonly workspaceRepository: Repository, - protected readonly twentyORMGlobalManager: GlobalWorkspaceOrmManager, - protected readonly dataSourceService: DataSourceService, - @InjectDataSource() - private readonly coreDataSource: DataSource, - ) { - super(workspaceRepository, twentyORMGlobalManager, dataSourceService); - } - - override async runOnWorkspace({ - options, - }: RunOnWorkspaceArgs): Promise { - if (this.hasRunOnce) { - this.logger.log( - 'Skipping has already been run once AddWorkspaceForeignKeysMigrationCommand', - ); - - return; - } - - if (options.dryRun) { - return; - } - - const queryRunner = this.coreDataSource.createQueryRunner(); - - await queryRunner.connect(); - await queryRunner.startTransaction(); - - try { - await addWorkspaceForeignKeysQueries(queryRunner); - - await queryRunner.commitTransaction(); - this.logger.log( - 'Successfully run AddWorkspaceForeignKeysMigrationCommand', - ); - this.hasRunOnce = true; - } catch (error) { - await queryRunner.rollbackTransaction(); - this.logger.log( - `Rollbacking AddWorkspaceForeignKeysMigrationCommand: ${error.message}`, - ); - } finally { - await queryRunner.release(); - } - } -} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-15/1-15-backfill-updated-by-field.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-15/1-15-backfill-updated-by-field.command.ts deleted file mode 100644 index ffc74199ae..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-15/1-15-backfill-updated-by-field.command.ts +++ /dev/null @@ -1,191 +0,0 @@ -import { Logger } from '@nestjs/common'; -import { InjectRepository } from '@nestjs/typeorm'; - -import { Command } from 'nest-commander'; -import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; -import { FieldMetadataType } from 'twenty-shared/types'; -import { isDefined } from 'twenty-shared/utils'; -import { Repository } from 'typeorm'; -import { v4 } from 'uuid'; - -import { ActiveOrSuspendedWorkspacesMigrationCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner'; -import { RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspaces-migration.command-runner'; -import { ApplicationService } from 'src/engine/core-modules/application/services/application.service'; -import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; -import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; -import { CreateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/create-field.input'; -import { FieldMetadataService } from 'src/engine/metadata-modules/field-metadata/services/field-metadata.service'; -import { findManyFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-many-flat-entity-by-id-in-flat-entity-maps-or-throw.util'; -import { belongsToTwentyStandardApp } from 'src/engine/metadata-modules/utils/belongs-to-twenty-standard-app.util'; -import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; -import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service'; -import { - ATTACHMENT_STANDARD_FIELD_IDS, - COMPANY_STANDARD_FIELD_IDS, - CUSTOM_OBJECT_STANDARD_FIELD_IDS, - DASHBOARD_STANDARD_FIELD_IDS, - NOTE_STANDARD_FIELD_IDS, - OPPORTUNITY_STANDARD_FIELD_IDS, - PERSON_STANDARD_FIELD_IDS, - TASK_STANDARD_FIELD_IDS, - WORKFLOW_RUN_STANDARD_FIELD_IDS, - WORKFLOW_STANDARD_FIELD_IDS, -} from 'src/engine/workspace-manager/workspace-migration/constant/standard-field-ids'; - -@Command({ - name: 'upgrade:1-15:backfill-updated-by-field', - description: 'Backfill updatedBy field for all objects', -}) -export class BackfillUpdatedByFieldCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner { - protected readonly logger = new Logger(BackfillUpdatedByFieldCommand.name); - - private readonly objectToUpdatedByStandardIdMap: Record = { - [STANDARD_OBJECT_IDS.attachment]: ATTACHMENT_STANDARD_FIELD_IDS.updatedBy, - [STANDARD_OBJECT_IDS.company]: COMPANY_STANDARD_FIELD_IDS.updatedBy, - [STANDARD_OBJECT_IDS.person]: PERSON_STANDARD_FIELD_IDS.updatedBy, - [STANDARD_OBJECT_IDS.note]: NOTE_STANDARD_FIELD_IDS.updatedBy, - [STANDARD_OBJECT_IDS.task]: TASK_STANDARD_FIELD_IDS.updatedBy, - [STANDARD_OBJECT_IDS.opportunity]: OPPORTUNITY_STANDARD_FIELD_IDS.updatedBy, - [STANDARD_OBJECT_IDS.workflow]: WORKFLOW_STANDARD_FIELD_IDS.updatedBy, - [STANDARD_OBJECT_IDS.workflowRun]: - WORKFLOW_RUN_STANDARD_FIELD_IDS.updatedBy, - [STANDARD_OBJECT_IDS.dashboard]: DASHBOARD_STANDARD_FIELD_IDS.updatedBy, - }; - - constructor( - @InjectRepository(WorkspaceEntity) - protected readonly workspaceRepository: Repository, - protected readonly twentyORMGlobalManager: GlobalWorkspaceOrmManager, - protected readonly dataSourceService: DataSourceService, - private readonly fieldMetadataService: FieldMetadataService, - private readonly workspaceCacheService: WorkspaceCacheService, - private readonly applicationService: ApplicationService, - ) { - super(workspaceRepository, twentyORMGlobalManager, dataSourceService); - } - - override async runOnWorkspace({ - workspaceId, - options, - }: RunOnWorkspaceArgs): Promise { - this.logger.log( - `Starting backfill of updatedBy field for workspace ${workspaceId}`, - ); - - const { twentyStandardFlatApplication, workspaceCustomFlatApplication } = - await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow( - { - workspaceId, - }, - ); - - const { flatFieldMetadataMaps, flatObjectMetadataMaps } = - await this.workspaceCacheService.getOrRecompute(workspaceId, [ - 'flatObjectMetadataMaps', - 'flatFieldMetadataMaps', - ]); - - const objectMetadataList = Object.values( - flatObjectMetadataMaps.byId, - ).filter(isDefined); - - if (objectMetadataList.length === 0) { - this.logger.log( - `No objects found that need updatedBy field for workspace ${workspaceId}`, - ); - - return; - } - - const createFieldInputs: CreateFieldInput[] = []; - - for (const flatObjectMetadata of objectMetadataList) { - const isStandardObject = belongsToTwentyStandardApp(flatObjectMetadata); - const updatedByStandardId = !isStandardObject - ? CUSTOM_OBJECT_STANDARD_FIELD_IDS.updatedBy - : isDefined(flatObjectMetadata.standardId) - ? this.objectToUpdatedByStandardIdMap[flatObjectMetadata.standardId] - : undefined; - - if (!isDefined(updatedByStandardId)) { - continue; - } - - const flatFieldMetadatas = findManyFlatEntityByIdInFlatEntityMapsOrThrow({ - flatEntityIds: flatObjectMetadata.fieldIds, - flatEntityMaps: flatFieldMetadataMaps, - }); - - const updatedByField = flatFieldMetadatas.find( - (field) => field.standardId === updatedByStandardId, - ); - - if (isDefined(updatedByField)) { - this.logger.log( - `Object ${flatObjectMetadata.nameSingular} (${flatObjectMetadata.standardId || 'custom'}) already has updatedBy field, skipping`, - ); - continue; - } - - const applicationId = isStandardObject - ? twentyStandardFlatApplication.id - : workspaceCustomFlatApplication.id; - const universalIdentifier = isStandardObject ? updatedByStandardId : v4(); - - createFieldInputs.push({ - workspaceId, - objectMetadataId: flatObjectMetadata.id, - name: 'updatedBy', - type: FieldMetadataType.ACTOR, - label: 'Updated by', - description: 'The user who last updated the record', - icon: 'IconUserCircle', - isNullable: true, - isUIReadOnly: true, - isCustom: false, - isSystem: false, - isActive: true, - standardId: updatedByStandardId, - universalIdentifier, - applicationId, - }); - } - - if (createFieldInputs.length === 0) { - this.logger.log( - `All objects already have updatedBy field for workspace ${workspaceId}`, - ); - - return; - } - - this.logger.log( - `Found ${createFieldInputs.length} objects that need updatedBy field`, - ); - - if (options.dryRun) { - this.logger.log( - `[DRY RUN] Would create updatedBy field for ${createFieldInputs.length} objects`, - ); - - return; - } - - try { - await this.fieldMetadataService.createManyFields({ - createFieldInputs, - workspaceId, - isSystemBuild: true, - }); - } catch (error) { - this.logger.error( - `Failed to create many fields \n ${JSON.stringify(error, null, 2)}`, - ); - throw error; - } - - this.logger.log( - `Successfully backfilled updatedBy field for ${createFieldInputs.length} objects in workspace ${workspaceId}`, - ); - } -} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-15/1-15-fix-nan-position-values-in-notes.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-15/1-15-fix-nan-position-values-in-notes.command.ts deleted file mode 100644 index 16f8cdc154..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-15/1-15-fix-nan-position-values-in-notes.command.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { Logger } from '@nestjs/common'; -import { InjectRepository } from '@nestjs/typeorm'; - -import { Command } from 'nest-commander'; -import { isDefined } from 'twenty-shared/utils'; -import { Repository } from 'typeorm'; - -import { ActiveOrSuspendedWorkspacesMigrationCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner'; -import { RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspaces-migration.command-runner'; -import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; -import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; -import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; - -@Command({ - name: 'upgrade:1-15:fix-nan-position-values-in-notes', - description: 'Fix NaN position values in notes by replacing them with 2', -}) -export class FixNanPositionValuesInNotesCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner { - protected readonly logger = new Logger( - FixNanPositionValuesInNotesCommand.name, - ); - - constructor( - @InjectRepository(WorkspaceEntity) - protected readonly workspaceRepository: Repository, - protected readonly globalWorkspaceOrmManager: GlobalWorkspaceOrmManager, - protected readonly dataSourceService: DataSourceService, - ) { - super(workspaceRepository, globalWorkspaceOrmManager, dataSourceService); - } - - override async runOnWorkspace({ - workspaceId, - options, - dataSource, - }: RunOnWorkspaceArgs): Promise { - const isDryRun = options.dryRun || false; - - if (!isDefined(dataSource)) { - throw new Error( - `Could not find data source for workspace ${workspaceId}, should never occur`, - ); - } - - if (isDryRun) { - this.logger.log('Dry run mode: No changes will be applied'); - } - - try { - // Count NaN position values in notes - const noteRepository = await this.globalWorkspaceOrmManager.getRepository( - workspaceId, - 'note', - { shouldBypassPermissionChecks: true }, - ); - - const nanCount = await noteRepository.count({ - where: { position: 'NaN' }, - }); - - this.logger.log( - `Found ${nanCount} note(s) with NaN position values in workspace ${workspaceId}`, - ); - - if (nanCount === 0) { - this.logger.log('No NaN position values to fix'); - - return; - } - - if (!isDryRun) { - // Update NaN position values to 2 because 1 is first position - await noteRepository - .createQueryBuilder() - .update() - .set({ position: 2 }) - .where('position = :nanString', { nanString: 'NaN' }) - .execute(); - - this.logger.log( - `Fixed ${nanCount} NaN position value(s) in notes for workspace ${workspaceId}`, - ); - } else { - this.logger.log( - `DRY RUN: Would fix ${nanCount} NaN position value(s) in notes for workspace ${workspaceId}`, - ); - } - } catch (error) { - this.logger.error( - `Could not fix NaN position values in notes for workspace ${workspaceId}`, - ); - this.logger.error(error); - } - } -} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-15/1-15-migrate-page-layout-widget-configuration.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-15/1-15-migrate-page-layout-widget-configuration.command.ts deleted file mode 100644 index c92b09591f..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-15/1-15-migrate-page-layout-widget-configuration.command.ts +++ /dev/null @@ -1,299 +0,0 @@ -import { InjectRepository } from '@nestjs/typeorm'; - -import { Command } from 'nest-commander'; -import { assertUnreachable, isDefined } from 'twenty-shared/utils'; -import { Repository } from 'typeorm'; - -import { ActiveOrSuspendedWorkspacesMigrationCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner'; -import { RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspaces-migration.command-runner'; -import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; -import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; -import { getMetadataFlatEntityMapsKey } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-flat-entity-maps-key.util'; -import { getMetadataRelatedMetadataNames } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-related-metadata-names.util'; -import { PageLayoutWidgetEntity } from 'src/engine/metadata-modules/page-layout-widget/entities/page-layout-widget.entity'; -import { BarChartLayout } from 'src/engine/metadata-modules/page-layout-widget/enums/bar-chart-layout.enum'; -import { WidgetConfigurationType } from 'src/engine/metadata-modules/page-layout-widget/enums/widget-configuration-type.type'; -import { WidgetType } from 'src/engine/metadata-modules/page-layout-widget/enums/widget-type.enum'; -import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; -import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service'; - -enum DeprecatedGraphType { - VERTICAL_BAR = 'VERTICAL_BAR', - HORIZONTAL_BAR = 'HORIZONTAL_BAR', - PIE = 'PIE', - LINE = 'LINE', - AGGREGATE = 'AGGREGATE', - GAUGE = 'GAUGE', -} - -const migrateConfiguration = ( - widgetType: WidgetType, - configuration: Record, -): Record => { - const existingConfigurationType = configuration.configurationType as - | string - | undefined; - - if (isDefined(existingConfigurationType)) { - return configuration; - } - - switch (widgetType) { - case WidgetType.GRAPH: - return migrateGraphConfiguration(configuration); - case WidgetType.IFRAME: - return { - ...configuration, - configurationType: WidgetConfigurationType.IFRAME, - }; - case WidgetType.STANDALONE_RICH_TEXT: - return { - ...configuration, - configurationType: WidgetConfigurationType.STANDALONE_RICH_TEXT, - }; - case WidgetType.VIEW: - return { - ...configuration, - configurationType: WidgetConfigurationType.VIEW, - }; - case WidgetType.FIELDS: - return { - ...configuration, - configurationType: WidgetConfigurationType.FIELDS, - }; - case WidgetType.TIMELINE: - return { - ...configuration, - configurationType: WidgetConfigurationType.TIMELINE, - }; - case WidgetType.TASKS: - return { - ...configuration, - configurationType: WidgetConfigurationType.TASKS, - }; - case WidgetType.NOTES: - return { - ...configuration, - configurationType: WidgetConfigurationType.NOTES, - }; - case WidgetType.FILES: - return { - ...configuration, - configurationType: WidgetConfigurationType.FILES, - }; - case WidgetType.EMAILS: - return { - ...configuration, - configurationType: WidgetConfigurationType.EMAILS, - }; - case WidgetType.CALENDAR: - return { - ...configuration, - configurationType: WidgetConfigurationType.CALENDAR, - }; - case WidgetType.FIELD_RICH_TEXT: - return { - ...configuration, - configurationType: WidgetConfigurationType.FIELD_RICH_TEXT, - }; - case WidgetType.WORKFLOW: - return { - ...configuration, - configurationType: WidgetConfigurationType.WORKFLOW, - }; - case WidgetType.WORKFLOW_VERSION: - return { - ...configuration, - configurationType: WidgetConfigurationType.WORKFLOW_VERSION, - }; - case WidgetType.WORKFLOW_RUN: - return { - ...configuration, - configurationType: WidgetConfigurationType.WORKFLOW_RUN, - }; - case WidgetType.FIELD: - return { - ...configuration, - configurationType: WidgetConfigurationType.FIELD, - }; - case WidgetType.FRONT_COMPONENT: - return { - ...configuration, - configurationType: WidgetConfigurationType.FRONT_COMPONENT, - }; - default: - assertUnreachable(widgetType); - } -}; - -const migrateGraphConfiguration = ( - configuration: Record, -): Record => { - const { graphType: _, ...restConfig } = configuration; - const graphType = configuration.graphType as DeprecatedGraphType | undefined; - - if (!isDefined(graphType)) { - return configuration; - } - - switch (graphType) { - case DeprecatedGraphType.VERTICAL_BAR: - return { - ...restConfig, - configurationType: WidgetConfigurationType.BAR_CHART, - layout: BarChartLayout.VERTICAL, - }; - case DeprecatedGraphType.HORIZONTAL_BAR: - return { - ...restConfig, - configurationType: WidgetConfigurationType.BAR_CHART, - layout: BarChartLayout.HORIZONTAL, - }; - case DeprecatedGraphType.PIE: - return { - ...restConfig, - configurationType: WidgetConfigurationType.PIE_CHART, - }; - case DeprecatedGraphType.LINE: - return { - ...restConfig, - configurationType: WidgetConfigurationType.LINE_CHART, - }; - case DeprecatedGraphType.AGGREGATE: - return { - ...restConfig, - configurationType: WidgetConfigurationType.AGGREGATE_CHART, - }; - case DeprecatedGraphType.GAUGE: - return { - ...restConfig, - configurationType: WidgetConfigurationType.GAUGE_CHART, - }; - default: - assertUnreachable(graphType); - } -}; - -const needsMigration = ( - widgetType: WidgetType, - configuration: Record, -): boolean => { - const graphType = configuration.graphType as DeprecatedGraphType | undefined; - const configurationType = configuration.configurationType as - | WidgetConfigurationType - | undefined; - - if (isDefined(graphType)) { - return true; - } - - if ( - !isDefined(configurationType) && - (widgetType === WidgetType.IFRAME || - widgetType === WidgetType.STANDALONE_RICH_TEXT) - ) { - return true; - } - - return false; -}; - -@Command({ - name: 'upgrade:1-15:migrate-page-layout-widget-configuration', - description: - 'Migrate page layout widget configurations to use configurationType', -}) -export class MigratePageLayoutWidgetConfigurationCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner { - constructor( - @InjectRepository(WorkspaceEntity) - protected readonly workspaceRepository: Repository, - @InjectRepository(PageLayoutWidgetEntity) - private readonly pageLayoutWidgetRepository: Repository, - protected readonly twentyORMGlobalManager: GlobalWorkspaceOrmManager, - protected readonly dataSourceService: DataSourceService, - private readonly workspaceCacheService: WorkspaceCacheService, - ) { - super(workspaceRepository, twentyORMGlobalManager, dataSourceService); - } - - override async runOnWorkspace({ - workspaceId, - options, - }: RunOnWorkspaceArgs): Promise { - this.logger.log( - `Starting migration of page layout widget configurations for workspace ${workspaceId}`, - ); - - const widgets = await this.pageLayoutWidgetRepository.find({ - where: { workspaceId }, - select: ['id', 'type', 'configuration'], - }); - - const widgetsWithNullConfiguration = widgets.filter( - (widget) => !isDefined(widget.configuration), - ); - - for (const widget of widgetsWithNullConfiguration) { - this.logger.log( - `Widget ${widget.id} has a corrupted configuration (null). Skipping migration.`, - ); - } - - const widgetsToMigrate = widgets.filter( - (widget) => - isDefined(widget.configuration) && - needsMigration( - widget.type, - widget.configuration as unknown as Record, - ), - ); - - this.logger.log( - `Found ${widgetsToMigrate.length} widget(s) needing migration out of ${widgets.length} total`, - ); - - if (widgetsToMigrate.length === 0) { - return; - } - - for (const widget of widgetsToMigrate) { - const migratedConfiguration = migrateConfiguration( - widget.type, - widget.configuration as unknown as Record, - ); - - if (options.dryRun) { - this.logger.log( - `[DRY RUN] Would update widget ${widget.id} configuration from ${JSON.stringify(widget.configuration)} to ${JSON.stringify(migratedConfiguration)}`, - ); - } else { - await this.pageLayoutWidgetRepository.update( - { id: widget.id }, - { configuration: migratedConfiguration }, - ); - - this.logger.log(`Updated widget ${widget.id} configuration`); - } - } - - this.logger.log( - `${options.dryRun ? '[DRY RUN] Would have migrated' : 'Successfully migrated'} ${widgetsToMigrate.length} widget(s)`, - ); - - if (!options.dryRun && widgetsToMigrate.length > 0) { - this.logger.log( - `Invalidating and recomputing cache for workspace ${workspaceId}`, - ); - - const flatCacheToInvalidate = - getMetadataRelatedMetadataNames('pageLayoutWidget'); - - await this.workspaceCacheService.invalidateAndRecompute(workspaceId, [ - 'flatPageLayoutWidgetMaps', - ...flatCacheToInvalidate.map(getMetadataFlatEntityMapsKey), - ]); - - this.logger.log(`Cache invalidated and recomputed successfully`); - } - } -} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-15/1-15-upgrade-version-command.module.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-15/1-15-upgrade-version-command.module.ts deleted file mode 100644 index f3d3e24333..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-15/1-15-upgrade-version-command.module.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { Module } from '@nestjs/common'; -import { TypeOrmModule } from '@nestjs/typeorm'; - -import { AddWorkspaceForeignKeysMigrationCommand } from 'src/database/commands/upgrade-version-command/1-15/1-15-add-workspace-foreign-keys-migration.command'; -import { BackfillUpdatedByFieldCommand } from 'src/database/commands/upgrade-version-command/1-15/1-15-backfill-updated-by-field.command'; -import { FixNanPositionValuesInNotesCommand } from 'src/database/commands/upgrade-version-command/1-15/1-15-fix-nan-position-values-in-notes.command'; -import { MigratePageLayoutWidgetConfigurationCommand } from 'src/database/commands/upgrade-version-command/1-15/1-15-migrate-page-layout-widget-configuration.command'; -import { ApplicationModule } from 'src/engine/core-modules/application/application.module'; -import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; -import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module'; -import { FieldMetadataModule } from 'src/engine/metadata-modules/field-metadata/field-metadata.module'; -import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; -import { PageLayoutWidgetEntity } from 'src/engine/metadata-modules/page-layout-widget/entities/page-layout-widget.entity'; -import { ViewFieldEntity } from 'src/engine/metadata-modules/view-field/entities/view-field.entity'; -import { ViewFieldModule } from 'src/engine/metadata-modules/view-field/view-field.module'; -import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity'; -import { WorkspaceSchemaManagerModule } from 'src/engine/twenty-orm/workspace-schema-manager/workspace-schema-manager.module'; -import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache.module'; - -@Module({ - imports: [ - TypeOrmModule.forFeature([ - WorkspaceEntity, - PageLayoutWidgetEntity, - ObjectMetadataEntity, - ViewEntity, - ViewFieldEntity, - ]), - DataSourceModule, - WorkspaceSchemaManagerModule, - WorkspaceCacheModule, - FieldMetadataModule, - ViewFieldModule, - ApplicationModule, - ], - providers: [ - MigratePageLayoutWidgetConfigurationCommand, - FixNanPositionValuesInNotesCommand, - BackfillUpdatedByFieldCommand, - AddWorkspaceForeignKeysMigrationCommand, - ], - exports: [ - MigratePageLayoutWidgetConfigurationCommand, - FixNanPositionValuesInNotesCommand, - BackfillUpdatedByFieldCommand, - AddWorkspaceForeignKeysMigrationCommand, - ], -}) -export class V1_15_UpgradeVersionCommandModule {} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-backfill-opportunity-owner-field.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-backfill-opportunity-owner-field.command.ts deleted file mode 100644 index f3645d6861..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-backfill-opportunity-owner-field.command.ts +++ /dev/null @@ -1,321 +0,0 @@ -import { Logger } from '@nestjs/common'; -import { InjectRepository } from '@nestjs/typeorm'; - -import { Command } from 'nest-commander'; -import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; -import { FieldMetadataType, RelationType } from 'twenty-shared/types'; -import { isDefined } from 'twenty-shared/utils'; -import { Repository } from 'typeorm'; - -import { ActiveOrSuspendedWorkspacesMigrationCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner'; -import { RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspaces-migration.command-runner'; -import { ApplicationService } from 'src/engine/core-modules/application/services/application.service'; -import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; -import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; -import { CreateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/create-field.input'; -import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; -import { FieldMetadataService } from 'src/engine/metadata-modules/field-metadata/services/field-metadata.service'; -import { MetadataFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/metadata-flat-entity-maps.type'; -import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util'; -import { findManyFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-many-flat-entity-by-id-in-flat-entity-maps-or-throw.util'; -import { FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; -import { isMorphOrRelationFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-morph-or-relation-flat-field-metadata.util'; -import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; -import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service'; -import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; - -@Command({ - name: 'upgrade:1-16:backfill-opportunity-owner-field', - description: 'Backfill owner field for opportunity object', -}) -export class BackfillOpportunityOwnerFieldCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner { - protected readonly logger = new Logger( - BackfillOpportunityOwnerFieldCommand.name, - ); - - constructor( - @InjectRepository(WorkspaceEntity) - protected readonly workspaceRepository: Repository, - @InjectRepository(FieldMetadataEntity) - private readonly fieldMetadataRepository: Repository, - protected readonly twentyORMGlobalManager: GlobalWorkspaceOrmManager, - protected readonly dataSourceService: DataSourceService, - private readonly fieldMetadataService: FieldMetadataService, - private readonly workspaceCacheService: WorkspaceCacheService, - private readonly applicationService: ApplicationService, - ) { - super(workspaceRepository, twentyORMGlobalManager, dataSourceService); - } - - override async runOnWorkspace({ - workspaceId, - options, - }: RunOnWorkspaceArgs): Promise { - this.logger.log( - `Starting backfill of owner field for opportunity in workspace ${workspaceId}`, - ); - - const { twentyStandardFlatApplication } = - await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow( - { - workspaceId, - }, - ); - - const { flatFieldMetadataMaps, flatObjectMetadataMaps } = - await this.workspaceCacheService.getOrRecompute(workspaceId, [ - 'flatObjectMetadataMaps', - 'flatFieldMetadataMaps', - ]); - - const opportunityObjectMetadata = Object.values( - flatObjectMetadataMaps.byId, - ).find( - (obj) => - isDefined(obj) && obj.standardId === STANDARD_OBJECT_IDS.opportunity, - ); - - if (!isDefined(opportunityObjectMetadata)) { - this.logger.log( - `Opportunity object not found for workspace ${workspaceId}, skipping`, - ); - - return; - } - - const workspaceMemberObjectMetadata = Object.values( - flatObjectMetadataMaps.byId, - ).find( - (obj) => - isDefined(obj) && - obj.standardId === STANDARD_OBJECT_IDS.workspaceMember, - ); - - if (!isDefined(workspaceMemberObjectMetadata)) { - this.logger.log( - `WorkspaceMember object not found for workspace ${workspaceId}, skipping`, - ); - - return; - } - - const flatFieldMetadatas = findManyFlatEntityByIdInFlatEntityMapsOrThrow({ - flatEntityIds: opportunityObjectMetadata.fieldIds, - flatEntityMaps: flatFieldMetadataMaps, - }); - - const ownerUniversalIdentifier = - STANDARD_OBJECTS.opportunity.fields.owner.universalIdentifier; - - const ownerField = flatFieldMetadatas.find( - (field) => field.universalIdentifier === ownerUniversalIdentifier, - ); - - if (isDefined(ownerField)) { - this.logger.log( - `Opportunity already has owner field in workspace ${workspaceId}, skipping`, - ); - - return; - } - - const customOwnerField = - flatFieldMetadatas.find( - (field) => - field.name === 'owner' && - field.universalIdentifier !== ownerUniversalIdentifier, - // Some self hoster might have run the name renaming successfully but not the joinColumnName - // Rather than asking them to restore db also grabbing them here - ) ?? flatFieldMetadatas.find((field) => field.name === 'ownerOld'); - - if (isDefined(customOwnerField)) { - await this.renameCustomOwnerFieldToOwnerOld({ - customOwnerField, - flatFieldMetadataMaps, - workspaceId, - dryRun: options.dryRun, - }); - } - - if (options.dryRun) { - this.logger.log( - `[DRY RUN] Would create owner field for opportunity in workspace ${workspaceId}`, - ); - - return; - } - - const createFieldInput: CreateFieldInput = { - workspaceId, - objectMetadataId: opportunityObjectMetadata.id, - name: 'owner', - type: FieldMetadataType.RELATION, - label: 'Owner', - description: 'Opportunity owner', - icon: 'IconUserCircle', - isNullable: true, - isCustom: false, - isSystem: false, - isActive: true, - standardId: ownerUniversalIdentifier, - universalIdentifier: ownerUniversalIdentifier, - applicationId: twentyStandardFlatApplication.id, - relationCreationPayload: { - type: RelationType.MANY_TO_ONE, - targetObjectMetadataId: workspaceMemberObjectMetadata.id, - targetFieldLabel: 'Owned opportunities', - targetFieldIcon: 'IconTargetArrow', - }, - }; - - const ownedOpportunitiesUniversalIdentifier = - STANDARD_OBJECTS.workspaceMember.fields.ownedOpportunities - .universalIdentifier; - - try { - await this.fieldMetadataService.createManyFields({ - createFieldInputs: [createFieldInput], - workspaceId, - isSystemBuild: true, - }); - - this.logger.log( - `Created owner field for opportunity in workspace ${workspaceId}`, - ); - - const ownedOpportunitiesField = - await this.fieldMetadataRepository.findOne({ - where: { - workspaceId, - objectMetadataId: workspaceMemberObjectMetadata.id, - name: 'ownedOpportunities', - }, - }); - - if (isDefined(ownedOpportunitiesField)) { - await this.fieldMetadataRepository.update( - { id: ownedOpportunitiesField.id }, - { - universalIdentifier: ownedOpportunitiesUniversalIdentifier, - standardId: ownedOpportunitiesUniversalIdentifier, - applicationId: twentyStandardFlatApplication.id, - }, - ); - - this.logger.log( - `Updated ownedOpportunities field universalIdentifier in workspace ${workspaceId}`, - ); - - await this.workspaceCacheService.invalidateAndRecompute(workspaceId, [ - 'flatFieldMetadataMaps', - ]); - } else { - throw new Error( - `Should never occur could not find the created ownedOpportunities field`, - ); - } - - this.logger.log( - `Successfully backfilled owner field for opportunity in workspace ${workspaceId}`, - ); - } catch (error) { - this.logger.error( - `Failed to create owner field for opportunity in workspace ${workspaceId}`, - error, - ); - throw error; - } - } - - private async renameCustomOwnerFieldToOwnerOld({ - customOwnerField, - flatFieldMetadataMaps, - workspaceId, - dryRun, - }: { - customOwnerField: FlatFieldMetadata; - flatFieldMetadataMaps: MetadataFlatEntityMaps<'fieldMetadata'>; - workspaceId: string; - dryRun?: boolean; - }): Promise { - if (dryRun) { - this.logger.log( - `[DRY RUN] Would rename custom owner field to 'ownerOld' in workspace and search for colliding foreignKey ${workspaceId}`, - ); - - return; - } - - const isMorphOrRelationField = - isMorphOrRelationFlatFieldMetadata(customOwnerField); - const hasCollidingJoinColumnName = - isMorphOrRelationField && - isDefined(customOwnerField.settings.joinColumnName) && - customOwnerField.settings.joinColumnName === 'ownerId'; - - await this.fieldMetadataService.updateOneField({ - updateFieldInput: { - id: customOwnerField.id, - name: 'ownerOld', - label: 'Owner (Old)', - ...(hasCollidingJoinColumnName - ? { - settings: { - ...customOwnerField.settings, - joinColumnName: `ownerOldId`, - }, - } - : {}), - }, - workspaceId, - isSystemBuild: true, - }); - this.logger.log( - `Renamed custom owner field to 'ownerOld' in workspace ${workspaceId}`, - ); - - if (!isMorphOrRelationField || hasCollidingJoinColumnName) { - return; - } - - const relatedFlatFieldMetadata = findFlatEntityByIdInFlatEntityMaps({ - flatEntityId: customOwnerField.relationTargetFieldMetadataId, - flatEntityMaps: flatFieldMetadataMaps, - }); - - if ( - !isDefined(relatedFlatFieldMetadata) || - !isMorphOrRelationFlatFieldMetadata(relatedFlatFieldMetadata) - ) { - this.logger.error( - `Could not find custom owner relation target field ${customOwnerField.relationTargetFieldMetadataId}`, - ); - - return; - } - - const targetHasCollidingJoinColumnName = - isDefined(relatedFlatFieldMetadata.settings.joinColumnName) && - relatedFlatFieldMetadata.settings.joinColumnName === 'ownerId'; - - if (!targetHasCollidingJoinColumnName) { - return; - } - - await this.fieldMetadataService.updateOneField({ - updateFieldInput: { - id: relatedFlatFieldMetadata.id, - settings: { - ...relatedFlatFieldMetadata.settings, - joinColumnName: `ownerOldId`, - }, - }, - workspaceId, - isSystemBuild: true, - }); - - this.logger.log( - `Renamed custom owner field target related field join column name to 'ownerOldId' in workspace ${workspaceId}`, - ); - } -} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-backfill-standard-page-layouts.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-backfill-standard-page-layouts.command.ts deleted file mode 100644 index 62bf8c367d..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-backfill-standard-page-layouts.command.ts +++ /dev/null @@ -1,257 +0,0 @@ -import { Logger } from '@nestjs/common'; -import { InjectRepository } from '@nestjs/typeorm'; - -import { Command } from 'nest-commander'; -import { FieldActorSource } from 'twenty-shared/types'; -import { isDefined } from 'twenty-shared/utils'; -import { Repository } from 'typeorm'; - -import { ActiveOrSuspendedWorkspacesMigrationCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner'; -import { RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspaces-migration.command-runner'; -import { updateStandardPageLayoutWidgetsWithWorkspaceFieldIds } from 'src/database/commands/upgrade-version-command/1-16/utils/update-standard-page-layout-widgets-with-workspace-field-ids.util'; -import { ApplicationService } from 'src/engine/core-modules/application/services/application.service'; -import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service'; -import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; -import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; -import { findFlatEntityByUniversalIdentifier } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-universal-identifier.util'; -import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; -import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service'; -import { MY_FIRST_DASHBOARD_ID } from 'src/engine/workspace-manager/standard-objects-prefill-data/prefill-dashboards'; -import { STANDARD_PAGE_LAYOUTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-page-layout.constant'; -import { computeTwentyStandardApplicationAllFlatEntityMaps } from 'src/engine/workspace-manager/twenty-standard-application/utils/twenty-standard-application-all-flat-entity-maps.constant'; -import { WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration/services/workspace-migration-validate-build-and-run-service'; -import { DashboardWorkspaceEntity } from 'src/modules/dashboard/standard-objects/dashboard.workspace-entity'; - -@Command({ - name: 'upgrade:1-16:backfill-standard-page-layouts', - description: 'Backfill standard page layouts and dashboard records', -}) -export class BackfillStandardPageLayoutsCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner { - protected readonly logger = new Logger( - BackfillStandardPageLayoutsCommand.name, - ); - - constructor( - @InjectRepository(WorkspaceEntity) - protected readonly workspaceRepository: Repository, - protected readonly twentyORMGlobalManager: GlobalWorkspaceOrmManager, - protected readonly dataSourceService: DataSourceService, - private readonly applicationService: ApplicationService, - private readonly twentyConfigService: TwentyConfigService, - private readonly workspaceCacheService: WorkspaceCacheService, - private readonly workspaceMigrationValidateBuildAndRunService: WorkspaceMigrationValidateBuildAndRunService, - ) { - super(workspaceRepository, twentyORMGlobalManager, dataSourceService); - } - - override async runOnWorkspace({ - workspaceId, - options, - }: RunOnWorkspaceArgs): Promise { - this.logger.log( - `Starting backfill of standard page layouts for workspace ${workspaceId}`, - ); - - await this.backfillStandardPageLayoutMetadata({ workspaceId, options }); - await this.backfillDashboardRecord({ workspaceId, options }); - - this.logger.log( - `Successfully backfilled standard page layouts for workspace ${workspaceId}`, - ); - } - - private async backfillStandardPageLayoutMetadata({ - workspaceId, - options, - }: { - workspaceId: string; - options: RunOnWorkspaceArgs['options']; - }): Promise { - const { - flatPageLayoutMaps: fromFlatPageLayoutMaps, - flatPageLayoutTabMaps: fromFlatPageLayoutTabMaps, - flatPageLayoutWidgetMaps: fromFlatPageLayoutWidgetMaps, - featureFlagsMap, - flatObjectMetadataMaps, - flatFieldMetadataMaps, - } = await this.workspaceCacheService.getOrRecompute(workspaceId, [ - 'flatPageLayoutMaps', - 'flatPageLayoutWidgetMaps', - 'flatPageLayoutTabMaps', - 'featureFlagsMap', - 'flatObjectMetadataMaps', - 'flatFieldMetadataMaps', - ]); - - const flatPageLayout = findFlatEntityByUniversalIdentifier({ - flatEntityMaps: fromFlatPageLayoutMaps, - universalIdentifier: - STANDARD_PAGE_LAYOUTS.myFirstDashboard.universalIdentifier, - }); - - if (isDefined(flatPageLayout)) { - this.logger.log( - `Standard page layout already exists in workspace ${workspaceId}, skipping metadata backfill`, - ); - - return; - } - - const { twentyStandardFlatApplication } = - await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow( - { - workspaceId, - }, - ); - - const shouldIncludeRecordPageLayouts = this.twentyConfigService.get( - 'SHOULD_SEED_STANDARD_RECORD_PAGE_LAYOUTS', - ); - - const { - flatPageLayoutMaps: toFlatPageLayoutMaps, - flatPageLayoutTabMaps: toFlatPageLayoutTabMaps, - flatPageLayoutWidgetMaps: rawToFlatPageLayoutWidgetMaps, - } = computeTwentyStandardApplicationAllFlatEntityMaps({ - now: new Date().toISOString(), - workspaceId, - twentyStandardApplicationId: twentyStandardFlatApplication.id, - shouldIncludeRecordPageLayouts, - }); - - const toFlatPageLayoutWidgetMaps = - updateStandardPageLayoutWidgetsWithWorkspaceFieldIds({ - flatFieldMetadataMaps, - flatObjectMetadataMaps, - flatPageLayoutWidgetMaps: rawToFlatPageLayoutWidgetMaps, - }); - - if (options.dryRun) { - this.logger.log( - `[DRY RUN] Would create standard page layout entities ${workspaceId}`, - ); - - return; - } - - const validateAndbuildResult = - await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigrationFromTo( - { - additionalCacheDataMaps: { - featureFlagsMap, - }, - buildOptions: { - isSystemBuild: true, - }, - fromToAllFlatEntityMaps: { - flatPageLayoutMaps: { - from: fromFlatPageLayoutMaps, - to: toFlatPageLayoutMaps, - }, - flatPageLayoutTabMaps: { - from: fromFlatPageLayoutTabMaps, - to: toFlatPageLayoutTabMaps, - }, - flatPageLayoutWidgetMaps: { - from: fromFlatPageLayoutWidgetMaps, - to: toFlatPageLayoutWidgetMaps, - }, - }, - workspaceId, - dependencyAllFlatEntityMaps: { - flatObjectMetadataMaps, - }, - applicationUniversalIdentifier: - twentyStandardFlatApplication.universalIdentifier, - }, - ); - - if (isDefined(validateAndbuildResult)) { - this.logger.error( - `Failed to create many fields \n ${JSON.stringify(validateAndbuildResult, null, 2)}`, - ); - throw new Error( - `Failed to create standard page layout/tab/widgets on workspace ${workspaceId}`, - ); - } - - this.logger.log( - `Successfully backfilled standard page layout metadata for workspace ${workspaceId}`, - ); - } - - private async backfillDashboardRecord({ - workspaceId, - options, - }: { - workspaceId: string; - options: RunOnWorkspaceArgs['options']; - }): Promise { - const dashboardRepository = - await this.twentyORMGlobalManager.getRepository( - workspaceId, - 'dashboard', - { shouldBypassPermissionChecks: true }, - ); - - const existingDashboard = await dashboardRepository.findOne({ - where: { id: MY_FIRST_DASHBOARD_ID }, - }); - - if (isDefined(existingDashboard)) { - this.logger.log( - `Dashboard already exists for workspace ${workspaceId}, skipping dashboard backfill`, - ); - - return; - } - - if (options.dryRun) { - this.logger.log( - `[DRY RUN] Would create dashboard record for workspace ${workspaceId}`, - ); - - return; - } - - const { flatPageLayoutMaps } = - await this.workspaceCacheService.getOrRecompute(workspaceId, [ - 'flatPageLayoutMaps', - ]); - - const myFirstDashboardPageLayout = findFlatEntityByUniversalIdentifier({ - flatEntityMaps: flatPageLayoutMaps, - universalIdentifier: - STANDARD_PAGE_LAYOUTS.myFirstDashboard.universalIdentifier, - }); - - if (!isDefined(myFirstDashboardPageLayout)) { - throw new Error( - `Page layout with universalIdentifier '${STANDARD_PAGE_LAYOUTS.myFirstDashboard.universalIdentifier}' not found`, - ); - } - - await dashboardRepository.insert({ - id: MY_FIRST_DASHBOARD_ID, - title: 'My First Dashboard', - pageLayoutId: myFirstDashboardPageLayout.id, - position: 0, - createdBy: { - source: FieldActorSource.SYSTEM, - workspaceMemberId: null, - name: 'System', - context: {}, - }, - updatedBy: { - source: FieldActorSource.SYSTEM, - workspaceMemberId: null, - name: 'System', - context: {}, - }, - }); - - this.logger.log( - `Successfully backfilled dashboard record for workspace ${workspaceId}`, - ); - } -} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-flush-v2-cache-and-increment-metadata-version.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-flush-v2-cache-and-increment-metadata-version.command.ts deleted file mode 100644 index f579badc4f..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-flush-v2-cache-and-increment-metadata-version.command.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { InjectRepository } from '@nestjs/typeorm'; - -import { Command } from 'nest-commander'; -import { Repository } from 'typeorm'; - -import { ActiveOrSuspendedWorkspacesMigrationCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner'; -import { RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspaces-migration.command-runner'; -import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; -import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; -import { ALL_FLAT_ENTITY_MAPS_PROPERTIES } from 'src/engine/metadata-modules/flat-entity/constant/all-flat-entity-maps-properties.constant'; -import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; -import { WorkspaceMigrationRunnerService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/services/workspace-migration-runner.service'; - -@Command({ - name: 'upgrade:1-16:flush-v2-cache-and-increment-metadata-version', - description: 'Flush the whole v2 cache and increment the metadata version', -}) -export class FlushV2CacheAndIncrementMetadataVersionCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner { - constructor( - @InjectRepository(WorkspaceEntity) - protected readonly workspaceRepository: Repository, - protected readonly globalWorkspaceOrmManager: GlobalWorkspaceOrmManager, - protected readonly dataSourceService: DataSourceService, - private readonly workspaceMigrationRunnerService: WorkspaceMigrationRunnerService, - ) { - super(workspaceRepository, globalWorkspaceOrmManager, dataSourceService); - } - - override async runOnWorkspace({ - workspaceId, - options, - }: RunOnWorkspaceArgs): Promise { - this.logger.log( - `Flushing v2 cache and incrementing metadata version for workspace ${workspaceId}`, - ); - - if (options.dryRun) { - this.logger.log( - `DRY RUN: Would flush v2 cache and increment metadata version for workspace ${workspaceId}`, - ); - - return; - } - - await this.workspaceMigrationRunnerService.invalidateCache({ - allFlatEntityMapsKeys: ALL_FLAT_ENTITY_MAPS_PROPERTIES, - workspaceId, - }); - - this.logger.log( - `Successfully flushed v2 cache and incremented metadata version for workspace ${workspaceId}`, - ); - } -} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-identify-agent-metadata.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-identify-agent-metadata.command.ts deleted file mode 100644 index 3e7ce67784..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-identify-agent-metadata.command.ts +++ /dev/null @@ -1,168 +0,0 @@ -import { InjectRepository } from '@nestjs/typeorm'; - -import { Command } from 'nest-commander'; -import { isDefined } from 'twenty-shared/utils'; -import { IsNull, Repository } from 'typeorm'; -import { v4 } from 'uuid'; - -import { ActiveOrSuspendedWorkspacesMigrationCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner'; -import { RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspaces-migration.command-runner'; -import { ApplicationService } from 'src/engine/core-modules/application/services/application.service'; -import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; -import { AgentEntity } from 'src/engine/metadata-modules/ai/ai-agent/entities/agent.entity'; -import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; -import { getMetadataFlatEntityMapsKey } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-flat-entity-maps-key.util'; -import { getMetadataRelatedMetadataNames } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-related-metadata-names.util'; -import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; -import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service'; -import { STANDARD_AGENT } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-agent.constant'; - -@Command({ - name: 'upgrade:1-16:identify-agent-metadata', - description: 'Identify standard agent metadata', -}) -export class IdentifyAgentMetadataCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner { - constructor( - @InjectRepository(WorkspaceEntity) - protected readonly workspaceRepository: Repository, - @InjectRepository(AgentEntity) - private readonly agentRepository: Repository, - protected readonly twentyORMGlobalManager: GlobalWorkspaceOrmManager, - protected readonly dataSourceService: DataSourceService, - protected readonly applicationService: ApplicationService, - protected readonly workspaceCacheService: WorkspaceCacheService, - ) { - super(workspaceRepository, twentyORMGlobalManager, dataSourceService); - } - - override async runOnWorkspace({ - workspaceId, - options, - }: RunOnWorkspaceArgs): Promise { - this.logger.log( - `Running identify standard agent metadata for workspace ${workspaceId}`, - ); - - const { twentyStandardFlatApplication, workspaceCustomFlatApplication } = - await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow( - { workspaceId }, - ); - - await this.identifyStandardAgent({ - workspaceId, - twentyStandardApplicationId: twentyStandardFlatApplication.id, - dryRun: options.dryRun ?? false, - }); - - await this.identifyCustomAgents({ - workspaceId, - workspaceCustomApplicationId: workspaceCustomFlatApplication.id, - dryRun: options.dryRun ?? false, - }); - - const relatedMetadataNames = getMetadataRelatedMetadataNames('agent'); - const relatedCacheKeysToInvalidate = relatedMetadataNames.map( - getMetadataFlatEntityMapsKey, - ); - - this.logger.log( - `Invalidating caches: flatAgentMaps ${relatedCacheKeysToInvalidate.join(' ')}`, - ); - if (!options.dryRun) { - await this.workspaceCacheService.invalidateAndRecompute(workspaceId, [ - 'flatAgentMaps', - ...relatedCacheKeysToInvalidate, - ]); - } - } - - private async identifyStandardAgent({ - workspaceId, - twentyStandardApplicationId, - dryRun, - }: { - workspaceId: string; - twentyStandardApplicationId: string; - dryRun: boolean; - }): Promise { - const helperAgent = await this.agentRepository.findOne({ - select: { - id: true, - name: true, - universalIdentifier: true, - applicationId: true, - }, - where: { - workspaceId, - name: 'helper', - isCustom: false, - }, - withDeleted: true, - }); - - if (!isDefined(helperAgent)) { - this.logger.warn( - `Standard agent "helper" not found for workspace ${workspaceId}, skipping standard agent identification`, - ); - - return; - } - - if (isDefined(helperAgent.applicationId)) { - this.logger.warn( - `Standard agent "helper" already has applicationId set, skipping`, - ); - - return; - } - - this.logger.log( - ` - Standard agent "helper" (id=${helperAgent.id}) -> universalIdentifier=${STANDARD_AGENT.helper.universalIdentifier}`, - ); - - if (!dryRun) { - await this.agentRepository.save({ - id: helperAgent.id, - universalIdentifier: STANDARD_AGENT.helper.universalIdentifier, - applicationId: twentyStandardApplicationId, - }); - } - } - - private async identifyCustomAgents({ - workspaceId, - workspaceCustomApplicationId, - dryRun, - }: { - workspaceId: string; - workspaceCustomApplicationId: string; - dryRun: boolean; - }): Promise { - const remainingCustomAgents = await this.agentRepository.find({ - select: { - id: true, - universalIdentifier: true, - applicationId: true, - }, - where: { - workspaceId, - applicationId: IsNull(), - }, - withDeleted: true, - }); - - const customUpdates = remainingCustomAgents.map((agentEntity) => ({ - id: agentEntity.id, - universalIdentifier: agentEntity.universalIdentifier ?? v4(), - applicationId: workspaceCustomApplicationId, - })); - - this.logger.log( - `Found ${customUpdates.length} custom agent(s) to update for workspace ${workspaceId}`, - ); - - if (!dryRun) { - await this.agentRepository.save(customUpdates); - } - } -} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-identify-field-metadata.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-identify-field-metadata.command.ts deleted file mode 100644 index 3b87a6e909..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-identify-field-metadata.command.ts +++ /dev/null @@ -1,241 +0,0 @@ -import { InjectRepository } from '@nestjs/typeorm'; - -import { Command } from 'nest-commander'; -import { isDefined } from 'twenty-shared/utils'; -import { WorkspaceActivationStatus } from 'twenty-shared/workspace'; -import { IsNull, Repository } from 'typeorm'; -import { v4 } from 'uuid'; - -import { - RunOnWorkspaceArgs, - WorkspacesMigrationCommandRunner, -} from 'src/database/commands/command-runners/workspaces-migration.command-runner'; -import { ApplicationService } from 'src/engine/core-modules/application/services/application.service'; -import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; -import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; -import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; -import { getMetadataFlatEntityMapsKey } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-flat-entity-maps-key.util'; -import { getMetadataRelatedMetadataNames } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-related-metadata-names.util'; -import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; -import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service'; -import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; - -type CustomFieldMetadata = { - fieldMetadataEntity: FieldMetadataEntity; - fromStandard: boolean; -}; - -type StandardFieldMetadata = { - fieldMetadataEntity: FieldMetadataEntity; - universalIdentifier: string; -}; - -type AllWarnings = 'unknown_standard_id'; - -type FieldMetadataWarning = { - fieldMetadataEntity: FieldMetadataEntity; - warning: AllWarnings; -}; - -type AllExceptions = 'existing_universal_id_mismatch'; - -type FieldMetadataException = { - fieldMetadataEntity: FieldMetadataEntity; - exception: AllExceptions; -}; - -@Command({ - name: 'upgrade:1-16:identify-field-metadata', - description: 'Identify standard field metadata', -}) -export class IdentifyFieldMetadataCommand extends WorkspacesMigrationCommandRunner { - constructor( - @InjectRepository(WorkspaceEntity) - protected readonly workspaceRepository: Repository, - @InjectRepository(FieldMetadataEntity) - private readonly fieldMetadataRepository: Repository, - protected readonly twentyORMGlobalManager: GlobalWorkspaceOrmManager, - protected readonly dataSourceService: DataSourceService, - protected readonly applicationService: ApplicationService, - protected readonly workspaceCacheService: WorkspaceCacheService, - ) { - super(workspaceRepository, twentyORMGlobalManager, dataSourceService, [ - WorkspaceActivationStatus.ACTIVE, - WorkspaceActivationStatus.SUSPENDED, - WorkspaceActivationStatus.ONGOING_CREATION, - WorkspaceActivationStatus.PENDING_CREATION, - ]); - } - - override async runOnWorkspace({ - workspaceId, - options, - }: RunOnWorkspaceArgs): Promise { - this.logger.log( - `Running identify standard field metadata for workspace ${workspaceId}`, - ); - - const { twentyStandardFlatApplication, workspaceCustomFlatApplication } = - await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow( - { workspaceId }, - ); - - const allFieldMetadataEntities = await this.fieldMetadataRepository.find({ - select: { - id: true, - universalIdentifier: true, - applicationId: true, - name: true, - standardId: true, - object: { - nameSingular: true, - }, - isCustom: true, - }, - relations: ['object'], - where: { - workspaceId, - applicationId: IsNull(), - }, - }); - - const customFieldMetadataEntities: CustomFieldMetadata[] = []; - const standardFieldMetadataEntities: StandardFieldMetadata[] = []; - const warnings: FieldMetadataWarning[] = []; - const exceptions: FieldMetadataException[] = []; - - for (const fieldMetadataEntity of allFieldMetadataEntities) { - const shouldBelongToTwentyStandardApp = - !fieldMetadataEntity.isCustom && - isDefined(fieldMetadataEntity.standardId); - - if (!shouldBelongToTwentyStandardApp) { - customFieldMetadataEntities.push({ - fieldMetadataEntity, - fromStandard: false, - }); - - continue; - } - - const objectConfig = - STANDARD_OBJECTS[ - fieldMetadataEntity.object - .nameSingular as keyof typeof STANDARD_OBJECTS - ]; - const universalIdentifier = - objectConfig?.fields[ - fieldMetadataEntity.name as keyof typeof objectConfig.fields - ]?.universalIdentifier; - - if (!isDefined(universalIdentifier)) { - warnings.push({ - fieldMetadataEntity, - warning: 'unknown_standard_id', - }); - customFieldMetadataEntities.push({ - fieldMetadataEntity, - fromStandard: true, - }); - continue; - } - - if ( - isDefined(fieldMetadataEntity.universalIdentifier) && - fieldMetadataEntity.universalIdentifier !== universalIdentifier - ) { - exceptions.push({ - fieldMetadataEntity, - exception: 'existing_universal_id_mismatch', - }); - continue; - } - - standardFieldMetadataEntities.push({ - fieldMetadataEntity, - universalIdentifier: - fieldMetadataEntity.universalIdentifier ?? universalIdentifier, - }); - } - - const totalUpdates = - customFieldMetadataEntities.length + standardFieldMetadataEntities.length; - - if (warnings.length > 0) { - this.logger.warn( - `Found ${warnings.length} warning(s) while processing field metadata for workspace ${workspaceId}. These fields will become custom.`, - ); - - for (const { fieldMetadataEntity, warning } of warnings) { - this.logger.warn( - `Warning for field "${fieldMetadataEntity.name}" on object "${fieldMetadataEntity.object.nameSingular}" (id=${fieldMetadataEntity.id} standardId=${fieldMetadataEntity.standardId}): ${warning}`, - ); - } - } - - if (exceptions.length > 0) { - this.logger.error( - `Found ${exceptions.length} exception(s) while processing field metadata for workspace ${workspaceId}. No updates will be applied.`, - ); - - for (const { fieldMetadataEntity, exception } of exceptions) { - this.logger.error( - `Exception for field "${fieldMetadataEntity.name}" on object "${fieldMetadataEntity.object.nameSingular}" (id=${fieldMetadataEntity.id} standardId=${fieldMetadataEntity.standardId}): ${exception}`, - ); - } - - throw new Error( - `Aborting migration for workspace ${workspaceId} due to ${exceptions.length} exception(s). See logs above for details.`, - ); - } - - this.logger.log( - `Successfully validated ${totalUpdates}/${allFieldMetadataEntities.length} field metadata update(s) for workspace ${workspaceId} (${customFieldMetadataEntities.length} custom, ${standardFieldMetadataEntities.length} standard)`, - ); - - if (!options.dryRun) { - const customUpdates = customFieldMetadataEntities.map( - ({ fieldMetadataEntity }) => ({ - id: fieldMetadataEntity.id, - universalIdentifier: fieldMetadataEntity.universalIdentifier ?? v4(), - applicationId: workspaceCustomFlatApplication.id, - }), - ); - - const standardUpdates = standardFieldMetadataEntities.map( - ({ fieldMetadataEntity, universalIdentifier }) => ({ - id: fieldMetadataEntity.id, - universalIdentifier, - applicationId: twentyStandardFlatApplication.id, - }), - ); - - await this.fieldMetadataRepository.save([ - ...customUpdates, - ...standardUpdates, - ]); - - const relatedMetadataNames = - getMetadataRelatedMetadataNames('fieldMetadata'); - const relatedCacheKeysToInvalidate = relatedMetadataNames.map( - getMetadataFlatEntityMapsKey, - ); - - this.logger.log( - `Invalidating caches: flatFieldMetadataMaps ${relatedCacheKeysToInvalidate.join(' ')}`, - ); - await this.workspaceCacheService.invalidateAndRecompute(workspaceId, [ - 'flatFieldMetadataMaps', - ...relatedCacheKeysToInvalidate, - ]); - - this.logger.log( - `Applied ${totalUpdates} field metadata update(s) for workspace ${workspaceId}`, - ); - } else { - this.logger.log( - `Dry run: would apply ${totalUpdates} field metadata update(s) for workspace ${workspaceId}`, - ); - } - } -} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-identify-index-metadata.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-identify-index-metadata.command.ts deleted file mode 100644 index 14cbef1c41..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-identify-index-metadata.command.ts +++ /dev/null @@ -1,341 +0,0 @@ -import { InjectRepository } from '@nestjs/typeorm'; - -import { Command } from 'nest-commander'; -import { isDefined } from 'twenty-shared/utils'; -import { IsNull, Repository } from 'typeorm'; -import { v4 } from 'uuid'; - -import { ActiveOrSuspendedWorkspacesMigrationCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner'; -import { RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspaces-migration.command-runner'; -import { ApplicationService } from 'src/engine/core-modules/application/services/application.service'; -import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; -import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; -import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service'; -import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type'; -import { findFlatEntityByUniversalIdentifier } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-universal-identifier.util'; -import { findManyFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-many-flat-entity-by-id-in-flat-entity-maps-or-throw.util'; -import { getMetadataFlatEntityMapsKey } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-flat-entity-maps-key.util'; -import { getMetadataRelatedMetadataNames } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-related-metadata-names.util'; -import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; -import { type FlatIndexMetadata } from 'src/engine/metadata-modules/flat-index-metadata/types/flat-index-metadata.type'; -import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type'; -import { IndexMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-metadata.entity'; -import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; -import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service'; -import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; - -import { STANDARD_INDEX_FIELD_UNIVERSAL_IDENTIFIERS } from './constants/standard-index-field-names.constant'; - -type StandardIndexUpdate = { - flatIndexMetadata: FlatIndexMetadata; - universalIdentifier: string; - objectNameSingular: string; - indexName: string; -}; - -@Command({ - name: 'upgrade:1-16:identify-index-metadata', - description: 'Identify standard index metadata', -}) -export class IdentifyIndexMetadataCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner { - constructor( - @InjectRepository(WorkspaceEntity) - protected readonly workspaceRepository: Repository, - @InjectRepository(IndexMetadataEntity) - private readonly indexMetadataRepository: Repository, - protected readonly twentyORMGlobalManager: GlobalWorkspaceOrmManager, - protected readonly dataSourceService: DataSourceService, - protected readonly applicationService: ApplicationService, - protected readonly workspaceCacheService: WorkspaceCacheService, - private readonly flatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService, - ) { - super(workspaceRepository, twentyORMGlobalManager, dataSourceService); - } - - override async runOnWorkspace({ - workspaceId, - options, - }: RunOnWorkspaceArgs): Promise { - this.logger.log( - `Running identify standard index metadata for workspace ${workspaceId}`, - ); - - const { twentyStandardFlatApplication, workspaceCustomFlatApplication } = - await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow( - { workspaceId }, - ); - - const { flatObjectMetadataMaps, flatFieldMetadataMaps, flatIndexMaps } = - await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps( - { - workspaceId, - flatMapsKeys: [ - 'flatObjectMetadataMaps', - 'flatFieldMetadataMaps', - 'flatIndexMaps', - ], - }, - ); - - await this.identifyStandardIndexesOrThrow({ - workspaceId, - flatObjectMetadataMaps, - flatFieldMetadataMaps, - flatIndexMaps, - twentyStandardApplicationId: twentyStandardFlatApplication.id, - dryRun: options.dryRun ?? false, - }); - - await this.identifyCustomIndexes({ - workspaceId, - flatObjectMetadataMaps, - workspaceCustomApplicationId: workspaceCustomFlatApplication.id, - dryRun: options.dryRun ?? false, - }); - - const relatedMetadataNames = getMetadataRelatedMetadataNames('index'); - const relatedCacheKeysToInvalidate = relatedMetadataNames.map( - getMetadataFlatEntityMapsKey, - ); - - this.logger.log( - `Invalidating caches: ${relatedCacheKeysToInvalidate.join(' ')}`, - ); - if (!options.dryRun) { - await this.workspaceCacheService.invalidateAndRecompute(workspaceId, [ - 'flatIndexMaps', - ...relatedCacheKeysToInvalidate, - ]); - } - } - - private async identifyStandardIndexesOrThrow({ - workspaceId, - flatObjectMetadataMaps, - flatFieldMetadataMaps, - flatIndexMaps, - twentyStandardApplicationId, - dryRun, - }: { - workspaceId: string; - flatObjectMetadataMaps: FlatEntityMaps; - flatFieldMetadataMaps: FlatEntityMaps; - flatIndexMaps: FlatEntityMaps; - twentyStandardApplicationId: string; - dryRun: boolean; - }): Promise { - const standardIndexUpdates: StandardIndexUpdate[] = []; - - for (const [objectNameSingular, objectConfig] of Object.entries( - STANDARD_OBJECTS, - )) { - const objectIndexes = - 'indexes' in objectConfig - ? (objectConfig.indexes as Record< - string, - { universalIdentifier: string } | undefined - >) - : null; - - if ( - !isDefined(objectIndexes) || - Object.keys(objectIndexes).length === 0 - ) { - continue; - } - - const flatObjectMetadata = findFlatEntityByUniversalIdentifier({ - flatEntityMaps: flatObjectMetadataMaps, - universalIdentifier: objectConfig.universalIdentifier, - }); - - if (!isDefined(flatObjectMetadata)) { - this.logger.error( - `Standard object "${objectNameSingular}" not found in workspace, this needs investigation, skipping`, - ); - continue; - } - - const objectFlatIndexMetadatas = - findManyFlatEntityByIdInFlatEntityMapsOrThrow({ - flatEntityIds: flatObjectMetadata.indexMetadataIds, - flatEntityMaps: flatIndexMaps, - }); - - for (const [indexName, indexConfig] of Object.entries(objectIndexes)) { - if (!isDefined(indexConfig)) { - continue; - } - - const indexUniversalIdentifier = indexConfig.universalIdentifier; - - if (!isDefined(indexUniversalIdentifier)) { - this.logger.warn( - `Index "${indexName}" config not found for object "${objectNameSingular}", skipping`, - ); - continue; - } - - const relatedFieldUniversalIdentifiers = - STANDARD_INDEX_FIELD_UNIVERSAL_IDENTIFIERS[objectNameSingular]?.[ - indexName - ]; - - if ( - !isDefined(relatedFieldUniversalIdentifiers) || - relatedFieldUniversalIdentifiers.length === 0 - ) { - this.logger.warn( - `No field mapping found for index "${indexName}" on object "${objectNameSingular}", skipping`, - ); - continue; - } - - const expectedFlatFieldMetadatas = relatedFieldUniversalIdentifiers - .map((fieldUniversalIdentifier) => - findFlatEntityByUniversalIdentifier({ - flatEntityMaps: flatFieldMetadataMaps, - universalIdentifier: fieldUniversalIdentifier, - }), - ) - .filter(isDefined); - - if ( - expectedFlatFieldMetadatas.length !== - relatedFieldUniversalIdentifiers.length - ) { - this.logger.warn( - `Could not resolve all field metadata for index "${indexName}" on object "${objectNameSingular}", skipping`, - ); - continue; - } - - const expectedFieldMetadataIds = new Set( - expectedFlatFieldMetadatas.map((flatField) => flatField.id), - ); - const matchingFlatIndexMetadata = objectFlatIndexMetadatas.find( - (flatIndex) => { - const indexFieldMetadataIds = new Set( - flatIndex.flatIndexFieldMetadatas.map( - (indexField) => indexField.fieldMetadataId, - ), - ); - - return this.setsEqual( - indexFieldMetadataIds, - expectedFieldMetadataIds, - ); - }, - ); - - if (!isDefined(matchingFlatIndexMetadata)) { - this.logger.warn( - `Could not find matching index for "${indexName}" on object "${objectNameSingular}", skipping`, - ); - continue; - } - - if (isDefined(matchingFlatIndexMetadata.applicationId)) { - continue; - } - - standardIndexUpdates.push({ - flatIndexMetadata: matchingFlatIndexMetadata, - universalIdentifier: indexUniversalIdentifier, - objectNameSingular: flatObjectMetadata.nameSingular, - indexName, - }); - } - } - - const standardUpdates = standardIndexUpdates.map( - ({ flatIndexMetadata, universalIdentifier }) => ({ - id: flatIndexMetadata.id, - universalIdentifier, - applicationId: twentyStandardApplicationId, - }), - ); - - this.logger.log( - `Found ${standardUpdates.length} standard index(es) to update for workspace ${workspaceId}`, - ); - - for (const { - flatIndexMetadata, - universalIdentifier, - objectNameSingular, - indexName, - } of standardIndexUpdates) { - this.logger.log( - ` - Standard index "${indexName}" on object "${objectNameSingular}" (id=${flatIndexMetadata.id}) -> universalIdentifier=${universalIdentifier}`, - ); - } - - if (!dryRun) { - await this.indexMetadataRepository.save(standardUpdates); - } - } - - private async identifyCustomIndexes({ - workspaceId, - flatObjectMetadataMaps, - workspaceCustomApplicationId, - dryRun, - }: { - workspaceId: string; - flatObjectMetadataMaps: FlatEntityMaps; - workspaceCustomApplicationId: string; - dryRun: boolean; - }): Promise { - const remainingCustomIndexes = await this.indexMetadataRepository.find({ - select: { - id: true, - universalIdentifier: true, - applicationId: true, - name: true, - objectMetadataId: true, - }, - where: { - workspaceId, - applicationId: IsNull(), - }, - }); - - const customUpdates = remainingCustomIndexes.map((indexEntity) => ({ - id: indexEntity.id, - universalIdentifier: indexEntity.universalIdentifier ?? v4(), - applicationId: workspaceCustomApplicationId, - })); - - this.logger.log( - `Found ${customUpdates.length} custom index(es) to update for workspace ${workspaceId}`, - ); - - for (const indexEntity of remainingCustomIndexes) { - const flatObjectMetadata = - flatObjectMetadataMaps.byId[indexEntity.objectMetadataId]; - - this.logger.log( - ` - Custom index "${indexEntity.name}" on object "${flatObjectMetadata?.nameSingular ?? 'unknown'}" (id=${indexEntity.id})`, - ); - } - - if (!dryRun) { - await this.indexMetadataRepository.save(customUpdates); - } - } - - private setsEqual(a: Set, b: Set): boolean { - if (a.size !== b.size) { - return false; - } - - for (const value of a) { - if (!b.has(value)) { - return false; - } - } - - return true; - } -} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-identify-object-metadata.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-identify-object-metadata.command.ts deleted file mode 100644 index 2f2502e29b..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-identify-object-metadata.command.ts +++ /dev/null @@ -1,233 +0,0 @@ -import { InjectRepository } from '@nestjs/typeorm'; - -import { Command } from 'nest-commander'; -import { isDefined } from 'twenty-shared/utils'; -import { WorkspaceActivationStatus } from 'twenty-shared/workspace'; -import { IsNull, Repository } from 'typeorm'; -import { v4 } from 'uuid'; - -import { - RunOnWorkspaceArgs, - WorkspacesMigrationCommandRunner, -} from 'src/database/commands/command-runners/workspaces-migration.command-runner'; -import { ApplicationService } from 'src/engine/core-modules/application/services/application.service'; -import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; -import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; -import { getMetadataFlatEntityMapsKey } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-flat-entity-maps-key.util'; -import { getMetadataRelatedMetadataNames } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-related-metadata-names.util'; -import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; -import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; -import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service'; -import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; - -type CustomObjectMetadata = { - objectMetadataEntity: ObjectMetadataEntity; - fromStandard: boolean; -}; - -type StandardObjectMetadata = { - objectMetadataEntity: ObjectMetadataEntity; - universalIdentifier: string; -}; - -type AllWarnings = 'unknown_standard_id'; - -type ObjectMetadataWarning = { - objectMetadataEntity: ObjectMetadataEntity; - warning: AllWarnings; -}; - -type AllExceptions = 'existing_universal_id_mismatch'; - -type ObjectMetadataException = { - objectMetadataEntity: ObjectMetadataEntity; - exception: AllExceptions; -}; - -@Command({ - name: 'upgrade:1-16:identify-object-metadata', - description: 'Identify standard object metadata', -}) -export class IdentifyObjectMetadataCommand extends WorkspacesMigrationCommandRunner { - constructor( - @InjectRepository(WorkspaceEntity) - protected readonly workspaceRepository: Repository, - @InjectRepository(ObjectMetadataEntity) - private readonly objectMetadataRepository: Repository, - protected readonly twentyORMGlobalManager: GlobalWorkspaceOrmManager, - protected readonly dataSourceService: DataSourceService, - protected readonly applicationService: ApplicationService, - protected readonly workspaceCacheService: WorkspaceCacheService, - ) { - super(workspaceRepository, twentyORMGlobalManager, dataSourceService, [ - WorkspaceActivationStatus.ACTIVE, - WorkspaceActivationStatus.SUSPENDED, - WorkspaceActivationStatus.ONGOING_CREATION, - ]); - } - - override async runOnWorkspace({ - workspaceId, - options, - }: RunOnWorkspaceArgs): Promise { - this.logger.log( - `Running identify standard object metadata for workspace ${workspaceId}`, - ); - - const { twentyStandardFlatApplication, workspaceCustomFlatApplication } = - await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow( - { workspaceId }, - ); - - const allObjectMetadataEntities = await this.objectMetadataRepository.find({ - select: { - id: true, - universalIdentifier: true, - applicationId: true, - nameSingular: true, - standardId: true, - isCustom: true, - }, - where: { - workspaceId, - applicationId: IsNull(), - }, - }); - - const customObjectMetadataEntities: CustomObjectMetadata[] = []; - const standardObjectMetadataEntities: StandardObjectMetadata[] = []; - const warnings: ObjectMetadataWarning[] = []; - const exceptions: ObjectMetadataException[] = []; - - for (const objectMetadataEntity of allObjectMetadataEntities) { - const shouldBelongToTwentyStandardApp = - !objectMetadataEntity.isCustom && - isDefined(objectMetadataEntity.standardId); - - if (!shouldBelongToTwentyStandardApp) { - customObjectMetadataEntities.push({ - objectMetadataEntity, - fromStandard: false, - }); - - continue; - } - - const objectConfig = - STANDARD_OBJECTS[ - objectMetadataEntity.nameSingular as keyof typeof STANDARD_OBJECTS - ]; - const universalIdentifier = objectConfig?.universalIdentifier; - - if (!isDefined(universalIdentifier)) { - warnings.push({ - objectMetadataEntity, - warning: 'unknown_standard_id', - }); - customObjectMetadataEntities.push({ - objectMetadataEntity, - fromStandard: true, - }); - continue; - } - - if ( - isDefined(objectMetadataEntity.universalIdentifier) && - objectMetadataEntity.universalIdentifier !== universalIdentifier - ) { - exceptions.push({ - objectMetadataEntity, - exception: 'existing_universal_id_mismatch', - }); - continue; - } - - standardObjectMetadataEntities.push({ - objectMetadataEntity, - universalIdentifier: - objectMetadataEntity.universalIdentifier ?? universalIdentifier, - }); - } - - const totalUpdates = - customObjectMetadataEntities.length + - standardObjectMetadataEntities.length; - - if (warnings.length > 0) { - this.logger.warn( - `Found ${warnings.length} warning(s) while processing object metadata for workspace ${workspaceId}. These objects will become custom.`, - ); - - for (const { objectMetadataEntity, warning } of warnings) { - this.logger.warn( - `Warning for object "${objectMetadataEntity.nameSingular}" (id=${objectMetadataEntity.id} standardId=${objectMetadataEntity.standardId}): ${warning}`, - ); - } - } - - if (exceptions.length > 0) { - this.logger.error( - `Found ${exceptions.length} exception(s) while processing object metadata for workspace ${workspaceId}. No updates will be applied.`, - ); - - for (const { objectMetadataEntity, exception } of exceptions) { - this.logger.error( - `Exception for object "${objectMetadataEntity.nameSingular}" (id=${objectMetadataEntity.id} standardId=${objectMetadataEntity.standardId}): ${exception}`, - ); - } - - throw new Error( - `Aborting migration for workspace ${workspaceId} due to ${exceptions.length} exception(s). See logs above for details.`, - ); - } - - this.logger.log( - `Successfully validated ${totalUpdates}/${allObjectMetadataEntities.length} object metadata update(s) for workspace ${workspaceId} (${customObjectMetadataEntities.length} custom, ${standardObjectMetadataEntities.length} standard)`, - ); - - if (!options.dryRun) { - const customUpdates = customObjectMetadataEntities.map( - ({ objectMetadataEntity }) => ({ - id: objectMetadataEntity.id, - universalIdentifier: objectMetadataEntity.universalIdentifier ?? v4(), - applicationId: workspaceCustomFlatApplication.id, - }), - ); - - const standardUpdates = standardObjectMetadataEntities.map( - ({ objectMetadataEntity, universalIdentifier }) => ({ - id: objectMetadataEntity.id, - universalIdentifier, - applicationId: twentyStandardFlatApplication.id, - }), - ); - - await this.objectMetadataRepository.save([ - ...customUpdates, - ...standardUpdates, - ]); - - const relatedMetadataNames = - getMetadataRelatedMetadataNames('objectMetadata'); - const relatedCacheKeysToInvalidate = relatedMetadataNames.map( - getMetadataFlatEntityMapsKey, - ); - - this.logger.log( - `Invalidating caches: flatObjectMetadataMaps ${relatedCacheKeysToInvalidate.join(' ')}`, - ); - await this.workspaceCacheService.invalidateAndRecompute(workspaceId, [ - 'flatObjectMetadataMaps', - ...relatedCacheKeysToInvalidate, - ]); - - this.logger.log( - `Applied ${totalUpdates} object metadata update(s) for workspace ${workspaceId}`, - ); - } else { - this.logger.log( - `Dry run: would apply ${totalUpdates} object metadata update(s) for workspace ${workspaceId}`, - ); - } - } -} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-identify-remaining-entities-metadata.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-identify-remaining-entities-metadata.command.ts deleted file mode 100644 index 14eda591b1..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-identify-remaining-entities-metadata.command.ts +++ /dev/null @@ -1,190 +0,0 @@ -import { InjectDataSource, InjectRepository } from '@nestjs/typeorm'; - -import { Command } from 'nest-commander'; -import { type AllMetadataName } from 'twenty-shared/metadata'; -import { DataSource, IsNull, Repository } from 'typeorm'; -import { v4 } from 'uuid'; - -import { ActiveOrSuspendedWorkspacesMigrationCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner'; -import { RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspaces-migration.command-runner'; -import { ApplicationService } from 'src/engine/core-modules/application/services/application.service'; -import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; -import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; -import { ALL_METADATA_ENTITY_BY_METADATA_NAME } from 'src/engine/metadata-modules/flat-entity/constant/all-metadata-entity-by-metadata-name.constant'; -import { getMetadataFlatEntityMapsKey } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-flat-entity-maps-key.util'; -import { getMetadataRelatedMetadataNames } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-related-metadata-names.util'; -import { ViewSortEntity } from 'src/engine/metadata-modules/view-sort/entities/view-sort.entity'; -import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; -import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service'; -import { SyncableEntity } from 'src/engine/workspace-manager/types/syncable-entity.interface'; - -const REMAINING_ENTITIES_METADATA_NAMES = [ - 'roleTarget', - 'rowLevelPermissionPredicate', - 'rowLevelPermissionPredicateGroup', - 'viewFilterGroup', - 'logicFunction', - 'skill', - 'pageLayoutWidget', - 'pageLayout', - 'pageLayoutTab', -] as const satisfies AllMetadataName[]; - -@Command({ - name: 'upgrade:1-16:identify-remaining-entities-metadata', - description: - 'Identify remaining entities metadata (roleTarget, rowLevelPermissionPredicate, rowLevelPermissionPredicateGroup, viewFilterGroup, viewSort, logicFunction, skill, pageLayoutWidget, pageLayout, pageLayoutTab)', -}) -export class IdentifyRemainingEntitiesMetadataCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner { - constructor( - @InjectRepository(WorkspaceEntity) - protected readonly workspaceRepository: Repository, - protected readonly twentyORMGlobalManager: GlobalWorkspaceOrmManager, - protected readonly dataSourceService: DataSourceService, - protected readonly applicationService: ApplicationService, - protected readonly workspaceCacheService: WorkspaceCacheService, - @InjectDataSource() - private readonly coreDataSource: DataSource, - ) { - super(workspaceRepository, twentyORMGlobalManager, dataSourceService); - } - - override async runOnWorkspace({ - workspaceId, - options, - }: RunOnWorkspaceArgs): Promise { - this.logger.log( - `Running identify remaining entities metadata for workspace ${workspaceId}`, - ); - - const { workspaceCustomFlatApplication } = - await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow( - { workspaceId }, - ); - - for (const metadataName of REMAINING_ENTITIES_METADATA_NAMES) { - await this.identifyEntitiesForMetadataName({ - metadataName, - workspaceId, - workspaceCustomApplicationId: workspaceCustomFlatApplication.id, - dryRun: options.dryRun ?? false, - }); - } - - await this.identifyViewSortEntities({ - workspaceId, - workspaceCustomApplicationId: workspaceCustomFlatApplication.id, - dryRun: options.dryRun ?? false, - }); - } - - private async identifyEntitiesForMetadataName({ - metadataName, - workspaceId, - workspaceCustomApplicationId, - dryRun, - }: { - metadataName: AllMetadataName; - workspaceId: string; - workspaceCustomApplicationId: string; - dryRun: boolean; - }): Promise { - const entityClass = ALL_METADATA_ENTITY_BY_METADATA_NAME[metadataName]; - const repository = this.coreDataSource.getRepository(entityClass); - - const entitiesWithoutApplicationId = await repository.find({ - select: ['id', 'universalIdentifier', 'applicationId'], - where: { - workspaceId, - applicationId: IsNull(), - }, - withDeleted: true, - }); - - if (entitiesWithoutApplicationId.length === 0) { - this.logger.log( - `No ${metadataName} entities found without applicationId for workspace ${workspaceId}`, - ); - - return; - } - - const updates = entitiesWithoutApplicationId.map( - (entity: SyncableEntity & { id: string }) => ({ - id: entity.id, - universalIdentifier: entity.universalIdentifier ?? v4(), - applicationId: workspaceCustomApplicationId, - }), - ); - - this.logger.log( - `Found ${updates.length} ${metadataName} entities to update for workspace ${workspaceId}`, - ); - - if (!dryRun) { - await repository.save(updates); - } - - const relatedMetadataNames = getMetadataRelatedMetadataNames(metadataName); - const relatedCacheKeysToInvalidate = relatedMetadataNames.map( - getMetadataFlatEntityMapsKey, - ); - - const flatEntityMapsKey = getMetadataFlatEntityMapsKey(metadataName); - - this.logger.log( - `Invalidating caches: ${flatEntityMapsKey} ${relatedCacheKeysToInvalidate.join(' ')}`, - ); - - if (!dryRun) { - await this.workspaceCacheService.invalidateAndRecompute(workspaceId, [ - flatEntityMapsKey, - ...relatedCacheKeysToInvalidate, - ]); - } - } - - private async identifyViewSortEntities({ - workspaceId, - workspaceCustomApplicationId, - dryRun, - }: { - workspaceId: string; - workspaceCustomApplicationId: string; - dryRun: boolean; - }): Promise { - const viewSortRepository = - this.coreDataSource.getRepository(ViewSortEntity); - - const viewSortsWithoutApplicationId = await viewSortRepository.find({ - select: ['id', 'universalIdentifier', 'applicationId'], - where: { - workspaceId, - applicationId: IsNull(), - }, - withDeleted: true, - }); - - if (viewSortsWithoutApplicationId.length === 0) { - this.logger.log( - `No viewSort entities found without applicationId for workspace ${workspaceId}`, - ); - - return; - } - - const updates = viewSortsWithoutApplicationId.map((viewSort) => ({ - id: viewSort.id, - universalIdentifier: viewSort.universalIdentifier ?? v4(), - applicationId: workspaceCustomApplicationId, - })); - - this.logger.log( - `Found ${updates.length} viewSort entities to update for workspace ${workspaceId}`, - ); - - if (!dryRun) { - await viewSortRepository.save(updates); - } - } -} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-identify-role-metadata.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-identify-role-metadata.command.ts deleted file mode 100644 index a5a62c2ac2..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-identify-role-metadata.command.ts +++ /dev/null @@ -1,166 +0,0 @@ -import { InjectRepository } from '@nestjs/typeorm'; - -import { Command } from 'nest-commander'; -import { isDefined } from 'twenty-shared/utils'; -import { IsNull, Repository } from 'typeorm'; -import { v4 } from 'uuid'; - -import { ActiveOrSuspendedWorkspacesMigrationCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner'; -import { RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspaces-migration.command-runner'; -import { ApplicationService } from 'src/engine/core-modules/application/services/application.service'; -import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; -import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; -import { getMetadataFlatEntityMapsKey } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-flat-entity-maps-key.util'; -import { getMetadataRelatedMetadataNames } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-related-metadata-names.util'; -import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity'; -import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; -import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service'; -import { STANDARD_ROLE } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-role.constant'; - -@Command({ - name: 'upgrade:1-16:identify-role-metadata', - description: 'Identify standard role metadata', -}) -export class IdentifyRoleMetadataCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner { - constructor( - @InjectRepository(WorkspaceEntity) - protected readonly workspaceRepository: Repository, - @InjectRepository(RoleEntity) - private readonly roleRepository: Repository, - protected readonly twentyORMGlobalManager: GlobalWorkspaceOrmManager, - protected readonly dataSourceService: DataSourceService, - protected readonly applicationService: ApplicationService, - protected readonly workspaceCacheService: WorkspaceCacheService, - ) { - super(workspaceRepository, twentyORMGlobalManager, dataSourceService); - } - - override async runOnWorkspace({ - workspaceId, - options, - }: RunOnWorkspaceArgs): Promise { - this.logger.log( - `Running identify standard role metadata for workspace ${workspaceId}`, - ); - - const { twentyStandardFlatApplication, workspaceCustomFlatApplication } = - await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow( - { workspaceId }, - ); - - await this.identifyStandardRole({ - workspaceId, - twentyStandardApplicationId: twentyStandardFlatApplication.id, - dryRun: options.dryRun ?? false, - }); - - await this.identifyCustomRoles({ - workspaceId, - workspaceCustomApplicationId: workspaceCustomFlatApplication.id, - dryRun: options.dryRun ?? false, - }); - - const relatedMetadataNames = getMetadataRelatedMetadataNames('role'); - const relatedCacheKeysToInvalidate = relatedMetadataNames.map( - getMetadataFlatEntityMapsKey, - ); - - this.logger.log( - `Invalidating caches: flatRoleMaps ${relatedCacheKeysToInvalidate.join(' ')}`, - ); - if (!options.dryRun) { - await this.workspaceCacheService.invalidateAndRecompute(workspaceId, [ - 'flatRoleMaps', - ...relatedCacheKeysToInvalidate, - ]); - } - } - - private async identifyStandardRole({ - workspaceId, - twentyStandardApplicationId, - dryRun, - }: { - workspaceId: string; - twentyStandardApplicationId: string; - dryRun: boolean; - }): Promise { - const adminRole = await this.roleRepository.findOne({ - select: { - id: true, - label: true, - universalIdentifier: true, - applicationId: true, - }, - where: { - workspaceId, - label: 'Admin', - isEditable: false, - }, - }); - - if (!isDefined(adminRole)) { - this.logger.warn( - `Standard role "Admin" not found for workspace ${workspaceId}, skipping standard role identification`, - ); - - return; - } - - if (isDefined(adminRole.applicationId)) { - this.logger.warn( - `Standard role "Admin" already has applicationId set, skipping`, - ); - - return; - } - - this.logger.log( - ` - Standard role "Admin" (id=${adminRole.id}) -> universalIdentifier=${STANDARD_ROLE.admin.universalIdentifier}`, - ); - - if (!dryRun) { - await this.roleRepository.save({ - id: adminRole.id, - universalIdentifier: STANDARD_ROLE.admin.universalIdentifier, - applicationId: twentyStandardApplicationId, - }); - } - } - - private async identifyCustomRoles({ - workspaceId, - workspaceCustomApplicationId, - dryRun, - }: { - workspaceId: string; - workspaceCustomApplicationId: string; - dryRun: boolean; - }): Promise { - const remainingCustomRoles = await this.roleRepository.find({ - select: { - id: true, - universalIdentifier: true, - applicationId: true, - }, - where: { - workspaceId, - applicationId: IsNull(), - }, - }); - - const customUpdates = remainingCustomRoles.map((roleEntity) => ({ - id: roleEntity.id, - universalIdentifier: roleEntity.universalIdentifier ?? v4(), - applicationId: workspaceCustomApplicationId, - })); - - this.logger.log( - `Found ${customUpdates.length} custom role(s) to update for workspace ${workspaceId}`, - ); - - if (!dryRun) { - await this.roleRepository.save(customUpdates); - } - } -} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-identify-view-field-metadata.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-identify-view-field-metadata.command.ts deleted file mode 100644 index e522afe7d2..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-identify-view-field-metadata.command.ts +++ /dev/null @@ -1,383 +0,0 @@ -import { InjectRepository } from '@nestjs/typeorm'; - -import { Command } from 'nest-commander'; -import { isDefined } from 'twenty-shared/utils'; -import { IsNull, Repository } from 'typeorm'; -import { v4 } from 'uuid'; - -import { ActiveOrSuspendedWorkspacesMigrationCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner'; -import { RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspaces-migration.command-runner'; -import { ApplicationService } from 'src/engine/core-modules/application/services/application.service'; -import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; -import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; -import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service'; -import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type'; -import { findFlatEntityByUniversalIdentifier } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-universal-identifier.util'; -import { findManyFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-many-flat-entity-by-id-in-flat-entity-maps-or-throw.util'; -import { getMetadataFlatEntityMapsKey } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-flat-entity-maps-key.util'; -import { getMetadataRelatedMetadataNames } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-related-metadata-names.util'; -import { 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 { type FlatViewField } from 'src/engine/metadata-modules/flat-view-field/types/flat-view-field.type'; -import { type FlatView } from 'src/engine/metadata-modules/flat-view/types/flat-view.type'; -import { ViewFieldEntity } from 'src/engine/metadata-modules/view-field/entities/view-field.entity'; -import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; -import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service'; -import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; - -type StandardViewFieldUpdate = { - flatViewField: FlatViewField; - universalIdentifier: string; - objectNameSingular: string; - viewName: string; - fieldName: string; -}; - -type AllExceptions = 'unknown_standard_view_field'; - -type ViewFieldMetadataException = { - flatViewField: FlatViewField; - exception: AllExceptions; - objectNameSingular: string; - viewName: string; - fieldName: string; -}; - -@Command({ - name: 'upgrade:1-16:identify-view-field-metadata', - description: 'Identify standard view field metadata', -}) -export class IdentifyViewFieldMetadataCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner { - constructor( - @InjectRepository(WorkspaceEntity) - protected readonly workspaceRepository: Repository, - @InjectRepository(ViewFieldEntity) - private readonly viewFieldRepository: Repository, - protected readonly twentyORMGlobalManager: GlobalWorkspaceOrmManager, - protected readonly dataSourceService: DataSourceService, - protected readonly applicationService: ApplicationService, - protected readonly workspaceCacheService: WorkspaceCacheService, - private readonly flatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService, - ) { - super(workspaceRepository, twentyORMGlobalManager, dataSourceService); - } - - override async runOnWorkspace({ - workspaceId, - options, - }: RunOnWorkspaceArgs): Promise { - this.logger.log( - `Running identify standard view field metadata for workspace ${workspaceId}`, - ); - - const { twentyStandardFlatApplication, workspaceCustomFlatApplication } = - await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow( - { workspaceId }, - ); - - const { - flatObjectMetadataMaps, - flatFieldMetadataMaps, - flatViewMaps, - flatViewFieldMaps, - } = - await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps( - { - workspaceId, - flatMapsKeys: [ - 'flatObjectMetadataMaps', - 'flatFieldMetadataMaps', - 'flatViewMaps', - 'flatViewFieldMaps', - ], - }, - ); - - await this.identifyStandardViewFieldsOrThrow({ - workspaceId, - flatObjectMetadataMaps, - flatFieldMetadataMaps, - flatViewMaps, - flatViewFieldMaps, - twentyStandardApplicationId: twentyStandardFlatApplication.id, - dryRun: options.dryRun ?? false, - }); - - await this.identifyCustomViewFields({ - workspaceId, - flatObjectMetadataMaps, - flatViewMaps, - flatFieldMetadataMaps, - workspaceCustomApplicationId: workspaceCustomFlatApplication.id, - dryRun: options.dryRun ?? false, - }); - - const relatedMetadataNames = getMetadataRelatedMetadataNames('viewField'); - const relatedCacheKeysToInvalidate = relatedMetadataNames.map( - getMetadataFlatEntityMapsKey, - ); - - this.logger.log( - `Invalidating caches: ${relatedCacheKeysToInvalidate.join(' ')}`, - ); - if (!options.dryRun) { - await this.workspaceCacheService.invalidateAndRecompute(workspaceId, [ - 'flatViewFieldMaps', - ...relatedCacheKeysToInvalidate, - ]); - } - } - - private async identifyStandardViewFieldsOrThrow({ - workspaceId, - flatObjectMetadataMaps, - flatFieldMetadataMaps, - flatViewMaps, - flatViewFieldMaps, - twentyStandardApplicationId, - dryRun, - }: { - workspaceId: string; - flatObjectMetadataMaps: FlatEntityMaps; - flatFieldMetadataMaps: FlatEntityMaps; - flatViewMaps: FlatEntityMaps; - flatViewFieldMaps: FlatEntityMaps; - twentyStandardApplicationId: string; - dryRun: boolean; - }): Promise { - const standardViewFieldUpdates: StandardViewFieldUpdate[] = []; - const exceptions: ViewFieldMetadataException[] = []; - - for (const [objectNameSingular, objectConfig] of Object.entries( - STANDARD_OBJECTS, - )) { - const objectViews = - 'views' in objectConfig - ? (objectConfig.views as Record< - string, - | { - universalIdentifier: string; - viewFields?: Record< - string, - { universalIdentifier: string } | undefined - >; - } - | undefined - >) - : null; - - if (!isDefined(objectViews)) { - continue; - } - - const flatObjectMetadata = findFlatEntityByUniversalIdentifier({ - flatEntityMaps: flatObjectMetadataMaps, - universalIdentifier: objectConfig.universalIdentifier, - }); - - if (!isDefined(flatObjectMetadata)) { - this.logger.error( - `Standard object "${objectNameSingular}" not found in workspace, this needs investigation, skipping`, - ); - continue; - } - - // Iterate over view configs and find views by their universalIdentifier - // (views have already been identified by the view identification command) - for (const [viewName, viewConfig] of Object.entries(objectViews)) { - if (!isDefined(viewConfig) || !isDefined(viewConfig.viewFields)) { - continue; - } - - const flatView = findFlatEntityByUniversalIdentifier({ - flatEntityMaps: flatViewMaps, - universalIdentifier: viewConfig.universalIdentifier, - }); - - if (!isDefined(flatView)) { - this.logger.warn( - `Standard view "${viewName}" not found for object "${flatObjectMetadata.nameSingular}", skipping view fields`, - ); - continue; - } - - const relatedFlatViewFields = - findManyFlatEntityByIdInFlatEntityMapsOrThrow({ - flatEntityIds: flatView.viewFieldIds, - flatEntityMaps: flatViewFieldMaps, - }); - - // Iterate over expected view fields from config - for (const [fieldName, viewFieldConfig] of Object.entries( - viewConfig.viewFields, - )) { - if (!isDefined(viewFieldConfig)) { - continue; - } - - const fieldUniversalIdentifier = - objectConfig.fields[fieldName as keyof typeof objectConfig.fields] - ?.universalIdentifier; - - if (!isDefined(fieldUniversalIdentifier)) { - this.logger.warn( - `Field "${fieldName}" config not found for object "${flatObjectMetadata.nameSingular}", skipping view field`, - ); - continue; - } - - const viewFieldUniversalIdentifier = - viewConfig.viewFields[fieldName]?.universalIdentifier; - - if (!isDefined(viewFieldUniversalIdentifier)) { - this.logger.warn( - `View field for field "${fieldName}" config not found for object "${flatObjectMetadata.nameSingular}", skipping view field`, - ); - continue; - } - - // Find the field metadata by universal identifier - const flatFieldMetadata = findFlatEntityByUniversalIdentifier({ - flatEntityMaps: flatFieldMetadataMaps, - universalIdentifier: fieldUniversalIdentifier, - }); - - if (!isDefined(flatFieldMetadata)) { - this.logger.warn( - `Field "${fieldName}" not found in workspace for object "${flatObjectMetadata.nameSingular}", skipping view field`, - ); - continue; - } - - // Find the existing view field that matches this field - const matchingFlatViewField = relatedFlatViewFields.find( - (viewField) => viewField.fieldMetadataId === flatFieldMetadata.id, - ); - - if ( - !isDefined(matchingFlatViewField) || - isDefined(matchingFlatViewField.applicationId) - ) { - continue; - } - - standardViewFieldUpdates.push({ - flatViewField: matchingFlatViewField, - universalIdentifier: viewFieldUniversalIdentifier, - objectNameSingular: flatObjectMetadata.nameSingular, - viewName: flatView.name, - fieldName, - }); - } - } - } - - if (exceptions.length > 0) { - this.logger.error( - `Found ${exceptions.length} exception(s) while processing view field metadata for workspace ${workspaceId}. No updates will be applied.`, - ); - - for (const { - flatViewField, - exception, - objectNameSingular, - viewName, - fieldName, - } of exceptions) { - this.logger.error( - `Exception for view field "${fieldName}" on view "${viewName}" of object "${objectNameSingular}" (id=${flatViewField.id}): ${exception}`, - ); - } - - throw new Error( - `Aborting migration for workspace ${workspaceId} due to ${exceptions.length} exception(s). See logs above for details.`, - ); - } - - const standardUpdates = standardViewFieldUpdates.map( - ({ flatViewField, universalIdentifier }) => ({ - id: flatViewField.id, - universalIdentifier, - applicationId: twentyStandardApplicationId, - }), - ); - - this.logger.log( - `Found ${standardUpdates.length} standard view field(s) to update for workspace ${workspaceId}`, - ); - - for (const { - flatViewField, - universalIdentifier, - objectNameSingular, - viewName, - fieldName, - } of standardViewFieldUpdates) { - this.logger.log( - ` - Standard view field "${fieldName}" on view "${viewName}" of object "${objectNameSingular}" (id=${flatViewField.id}) -> universalIdentifier=${universalIdentifier}`, - ); - } - - if (!dryRun) { - await this.viewFieldRepository.save(standardUpdates); - } - } - - private async identifyCustomViewFields({ - workspaceId, - flatObjectMetadataMaps, - flatViewMaps, - flatFieldMetadataMaps, - workspaceCustomApplicationId, - dryRun, - }: { - workspaceId: string; - flatObjectMetadataMaps: FlatEntityMaps; - flatViewMaps: FlatEntityMaps; - flatFieldMetadataMaps: FlatEntityMaps; - workspaceCustomApplicationId: string; - dryRun: boolean; - }): Promise { - const remainingCustomViewFields = await this.viewFieldRepository.find({ - select: { - id: true, - universalIdentifier: true, - applicationId: true, - viewId: true, - fieldMetadataId: true, - }, - where: { - workspaceId, - applicationId: IsNull(), - }, - withDeleted: true, - }); - - const customUpdates = remainingCustomViewFields.map((viewFieldEntity) => ({ - id: viewFieldEntity.id, - universalIdentifier: viewFieldEntity.universalIdentifier ?? v4(), - applicationId: workspaceCustomApplicationId, - })); - - this.logger.log( - `Found ${customUpdates.length} custom view field(s) to update for workspace ${workspaceId}`, - ); - - for (const viewFieldEntity of remainingCustomViewFields) { - const flatView = flatViewMaps.byId[viewFieldEntity.viewId]; - const flatObjectMetadata = isDefined(flatView) - ? flatObjectMetadataMaps.byId[flatView.objectMetadataId] - : undefined; - const flatFieldMetadata = - flatFieldMetadataMaps.byId[viewFieldEntity.fieldMetadataId]; - - this.logger.log( - ` - Custom view field for field "${flatFieldMetadata?.name ?? 'unknown'}" on view "${flatView?.name ?? 'unknown'}" of object "${flatObjectMetadata?.nameSingular ?? 'unknown'}" (id=${viewFieldEntity.id})`, - ); - } - - if (!dryRun) { - await this.viewFieldRepository.save(customUpdates); - } - } -} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-identify-view-filter-metadata.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-identify-view-filter-metadata.command.ts deleted file mode 100644 index f4964bf143..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-identify-view-filter-metadata.command.ts +++ /dev/null @@ -1,221 +0,0 @@ -import { InjectRepository } from '@nestjs/typeorm'; - -import { Command } from 'nest-commander'; -import { isDefined } from 'twenty-shared/utils'; -import { IsNull, Repository } from 'typeorm'; -import { v4 } from 'uuid'; - -import { ActiveOrSuspendedWorkspacesMigrationCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner'; -import { RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspaces-migration.command-runner'; -import { ApplicationService } from 'src/engine/core-modules/application/services/application.service'; -import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; -import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; -import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service'; -import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type'; -import { findFlatEntityByUniversalIdentifier } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-universal-identifier.util'; -import { findManyFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-many-flat-entity-by-id-in-flat-entity-maps-or-throw.util'; -import { getMetadataFlatEntityMapsKey } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-flat-entity-maps-key.util'; -import { getMetadataRelatedMetadataNames } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-related-metadata-names.util'; -import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; -import { type FlatViewFilter } from 'src/engine/metadata-modules/flat-view-filter/types/flat-view-filter.type'; -import { type FlatView } from 'src/engine/metadata-modules/flat-view/types/flat-view.type'; -import { ViewFilterEntity } from 'src/engine/metadata-modules/view-filter/entities/view-filter.entity'; -import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; -import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service'; -import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; - -@Command({ - name: 'upgrade:1-16:identify-view-filter-metadata', - description: 'Identify standard view filter metadata', -}) -export class IdentifyViewFilterMetadataCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner { - constructor( - @InjectRepository(WorkspaceEntity) - protected readonly workspaceRepository: Repository, - @InjectRepository(ViewFilterEntity) - private readonly viewFilterRepository: Repository, - protected readonly twentyORMGlobalManager: GlobalWorkspaceOrmManager, - protected readonly dataSourceService: DataSourceService, - protected readonly applicationService: ApplicationService, - protected readonly workspaceCacheService: WorkspaceCacheService, - private readonly flatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService, - ) { - super(workspaceRepository, twentyORMGlobalManager, dataSourceService); - } - - override async runOnWorkspace({ - workspaceId, - options, - }: RunOnWorkspaceArgs): Promise { - this.logger.log( - `Running identify standard view filter metadata for workspace ${workspaceId}`, - ); - - const { twentyStandardFlatApplication, workspaceCustomFlatApplication } = - await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow( - { workspaceId }, - ); - - const { flatFieldMetadataMaps, flatViewMaps, flatViewFilterMaps } = - await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps( - { - workspaceId, - flatMapsKeys: [ - 'flatFieldMetadataMaps', - 'flatViewMaps', - 'flatViewFilterMaps', - ], - }, - ); - - await this.identifyStandardViewFilter({ - flatFieldMetadataMaps, - flatViewMaps, - flatViewFilterMaps, - twentyStandardApplicationId: twentyStandardFlatApplication.id, - dryRun: options.dryRun ?? false, - }); - - await this.identifyCustomViewFilters({ - workspaceId, - workspaceCustomApplicationId: workspaceCustomFlatApplication.id, - dryRun: options.dryRun ?? false, - }); - - const relatedMetadataNames = getMetadataRelatedMetadataNames('viewFilter'); - const relatedCacheKeysToInvalidate = relatedMetadataNames.map( - getMetadataFlatEntityMapsKey, - ); - - this.logger.log( - `Invalidating caches: ${relatedCacheKeysToInvalidate.join(' ')}`, - ); - if (!options.dryRun) { - await this.workspaceCacheService.invalidateAndRecompute(workspaceId, [ - 'flatViewFilterMaps', - ...relatedCacheKeysToInvalidate, - ]); - } - } - - private async identifyStandardViewFilter({ - flatFieldMetadataMaps, - flatViewMaps, - flatViewFilterMaps, - twentyStandardApplicationId, - dryRun, - }: { - flatFieldMetadataMaps: FlatEntityMaps; - flatViewMaps: FlatEntityMaps; - flatViewFilterMaps: FlatEntityMaps; - twentyStandardApplicationId: string; - dryRun: boolean; - }): Promise { - const flatView = findFlatEntityByUniversalIdentifier({ - flatEntityMaps: flatViewMaps, - universalIdentifier: - STANDARD_OBJECTS.task.views.assignedToMe.universalIdentifier, - }); - - if (!isDefined(flatView)) { - this.logger.warn( - `Standard view "assignedToMe" not found for task object, skipping standard view filter identification`, - ); - - return; - } - - const flatFieldMetadata = findFlatEntityByUniversalIdentifier({ - flatEntityMaps: flatFieldMetadataMaps, - universalIdentifier: - STANDARD_OBJECTS.task.fields.assignee.universalIdentifier, - }); - - if (!isDefined(flatFieldMetadata)) { - this.logger.warn( - `Field "assignee" not found for task object, skipping standard view filter identification`, - ); - - return; - } - - const relatedFlatViewFilters = - findManyFlatEntityByIdInFlatEntityMapsOrThrow({ - flatEntityIds: flatView.viewFilterIds, - flatEntityMaps: flatViewFilterMaps, - }); - - const matchingFlatViewFilter = relatedFlatViewFilters.find( - (viewFilter) => viewFilter.fieldMetadataId === flatFieldMetadata.id, - ); - - if (!isDefined(matchingFlatViewFilter)) { - this.logger.warn( - `Standard view filter "assigneeIsMe" not found for view "assignedToMe" of task object, skipping`, - ); - - return; - } - - if (isDefined(matchingFlatViewFilter.applicationId)) { - this.logger.warn( - `Standard view filter "assigneeIsMe" already has applicationId set, skipping`, - ); - - return; - } - - this.logger.log( - ` - Standard view filter "assigneeIsMe" on view "assignedToMe" of object "task" (id=${matchingFlatViewFilter.id}) -> universalIdentifier=${STANDARD_OBJECTS.task.views.assignedToMe.viewFilters.assigneeIsMe.universalIdentifier}`, - ); - - if (!dryRun) { - await this.viewFilterRepository.save({ - id: matchingFlatViewFilter.id, - universalIdentifier: - STANDARD_OBJECTS.task.views.assignedToMe.viewFilters.assigneeIsMe - .universalIdentifier, - applicationId: twentyStandardApplicationId, - }); - } - } - - private async identifyCustomViewFilters({ - workspaceId, - workspaceCustomApplicationId, - dryRun, - }: { - workspaceId: string; - workspaceCustomApplicationId: string; - dryRun: boolean; - }): Promise { - const remainingCustomViewFilters = await this.viewFilterRepository.find({ - select: { - id: true, - universalIdentifier: true, - applicationId: true, - }, - where: { - workspaceId, - applicationId: IsNull(), - }, - withDeleted: true, - }); - - const customUpdates = remainingCustomViewFilters.map( - (viewFilterEntity) => ({ - id: viewFilterEntity.id, - universalIdentifier: viewFilterEntity.universalIdentifier ?? v4(), - applicationId: workspaceCustomApplicationId, - }), - ); - - this.logger.log( - `Found ${customUpdates.length} custom view filter(s) to update for workspace ${workspaceId}`, - ); - - if (!dryRun) { - await this.viewFilterRepository.save(customUpdates); - } - } -} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-identify-view-group-metadata.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-identify-view-group-metadata.command.ts deleted file mode 100644 index 8995d2dacf..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-identify-view-group-metadata.command.ts +++ /dev/null @@ -1,340 +0,0 @@ -import { InjectRepository } from '@nestjs/typeorm'; - -import { Command } from 'nest-commander'; -import { isDefined } from 'twenty-shared/utils'; -import { IsNull, Repository } from 'typeorm'; -import { v4 } from 'uuid'; - -import { ActiveOrSuspendedWorkspacesMigrationCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner'; -import { RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspaces-migration.command-runner'; -import { ApplicationService } from 'src/engine/core-modules/application/services/application.service'; -import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; -import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; -import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service'; -import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type'; -import { findFlatEntityByUniversalIdentifier } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-universal-identifier.util'; -import { findManyFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-many-flat-entity-by-id-in-flat-entity-maps-or-throw.util'; -import { getMetadataFlatEntityMapsKey } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-flat-entity-maps-key.util'; -import { getMetadataRelatedMetadataNames } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-related-metadata-names.util'; -import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type'; -import { type FlatViewGroup } from 'src/engine/metadata-modules/flat-view-group/types/flat-view-group.type'; -import { type FlatView } from 'src/engine/metadata-modules/flat-view/types/flat-view.type'; -import { ViewGroupEntity } from 'src/engine/metadata-modules/view-group/entities/view-group.entity'; -import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; -import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service'; -import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; - -const VIEW_GROUP_TO_FIELD_VALUE_MAPPING: Record< - string, - Record> -> = { - opportunity: { - byStage: { - new: 'NEW', - screening: 'SCREENING', - meeting: 'MEETING', - proposal: 'PROPOSAL', - customer: 'CUSTOMER', - }, - }, - task: { - assignedToMe: { - todo: 'TODO', - inProgress: 'IN_PROGRESS', - done: 'DONE', - empty: '', - }, - byStatus: { - todo: 'TODO', - inProgress: 'IN_PROGRESS', - done: 'DONE', - }, - }, -}; - -type StandardViewGroupUpdate = { - flatViewGroup: FlatViewGroup; - universalIdentifier: string; - objectNameSingular: string; - viewName: string; - viewGroupName: string; -}; - -@Command({ - name: 'upgrade:1-16:identify-view-group-metadata', - description: 'Identify standard view group metadata', -}) -export class IdentifyViewGroupMetadataCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner { - constructor( - @InjectRepository(WorkspaceEntity) - protected readonly workspaceRepository: Repository, - @InjectRepository(ViewGroupEntity) - private readonly viewGroupRepository: Repository, - protected readonly twentyORMGlobalManager: GlobalWorkspaceOrmManager, - protected readonly dataSourceService: DataSourceService, - protected readonly applicationService: ApplicationService, - protected readonly workspaceCacheService: WorkspaceCacheService, - private readonly flatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService, - ) { - super(workspaceRepository, twentyORMGlobalManager, dataSourceService); - } - - override async runOnWorkspace({ - workspaceId, - options, - }: RunOnWorkspaceArgs): Promise { - this.logger.log( - `Running identify standard view group metadata for workspace ${workspaceId}`, - ); - - const { twentyStandardFlatApplication, workspaceCustomFlatApplication } = - await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow( - { workspaceId }, - ); - - const { flatObjectMetadataMaps, flatViewMaps, flatViewGroupMaps } = - await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps( - { - workspaceId, - flatMapsKeys: [ - 'flatObjectMetadataMaps', - 'flatViewMaps', - 'flatViewGroupMaps', - ], - }, - ); - - await this.identifyStandardViewGroups({ - flatObjectMetadataMaps, - flatViewMaps, - flatViewGroupMaps, - twentyStandardApplicationId: twentyStandardFlatApplication.id, - dryRun: options.dryRun ?? false, - }); - - await this.identifyCustomViewGroups({ - workspaceId, - flatObjectMetadataMaps, - flatViewMaps, - workspaceCustomApplicationId: workspaceCustomFlatApplication.id, - dryRun: options.dryRun ?? false, - }); - - const relatedMetadataNames = getMetadataRelatedMetadataNames('viewGroup'); - const relatedCacheKeysToInvalidate = relatedMetadataNames.map( - getMetadataFlatEntityMapsKey, - ); - - this.logger.log( - `Invalidating caches: ${relatedCacheKeysToInvalidate.join(' ')}`, - ); - if (!options.dryRun) { - await this.workspaceCacheService.invalidateAndRecompute(workspaceId, [ - 'flatViewGroupMaps', - ...relatedCacheKeysToInvalidate, - ]); - } - } - - private async identifyStandardViewGroups({ - flatObjectMetadataMaps, - flatViewMaps, - flatViewGroupMaps, - twentyStandardApplicationId, - dryRun, - }: { - flatObjectMetadataMaps: FlatEntityMaps; - flatViewMaps: FlatEntityMaps; - flatViewGroupMaps: FlatEntityMaps; - twentyStandardApplicationId: string; - dryRun: boolean; - }): Promise { - const standardViewGroupUpdates: StandardViewGroupUpdate[] = []; - - for (const [objectNameSingular, objectConfig] of Object.entries( - STANDARD_OBJECTS, - )) { - const objectViews = - 'views' in objectConfig - ? (objectConfig.views as Record< - string, - | { - universalIdentifier: string; - viewGroups?: Record< - string, - { universalIdentifier: string } | undefined - >; - } - | undefined - >) - : null; - - if (!isDefined(objectViews)) { - continue; - } - - const flatObjectMetadata = findFlatEntityByUniversalIdentifier({ - flatEntityMaps: flatObjectMetadataMaps, - universalIdentifier: objectConfig.universalIdentifier, - }); - - if (!isDefined(flatObjectMetadata)) { - this.logger.error( - `Standard object "${objectNameSingular}" not found in workspace, this needs investigation, skipping`, - ); - continue; - } - - const objectViewGroupMapping = - VIEW_GROUP_TO_FIELD_VALUE_MAPPING[objectNameSingular]; - - for (const [viewName, viewConfig] of Object.entries(objectViews)) { - if (!isDefined(viewConfig) || !isDefined(viewConfig.viewGroups)) { - continue; - } - - const flatView = findFlatEntityByUniversalIdentifier({ - flatEntityMaps: flatViewMaps, - universalIdentifier: viewConfig.universalIdentifier, - }); - - if (!isDefined(flatView)) { - this.logger.warn( - `Standard view "${viewName}" not found for object "${flatObjectMetadata.nameSingular}", skipping view groups`, - ); - continue; - } - - const relatedFlatViewGroups = - findManyFlatEntityByIdInFlatEntityMapsOrThrow({ - flatEntityIds: flatView.viewGroupIds, - flatEntityMaps: flatViewGroupMaps, - }); - - const viewGroupMapping = objectViewGroupMapping?.[viewName]; - - for (const [viewGroupName, viewGroupConfig] of Object.entries( - viewConfig.viewGroups, - )) { - if (!isDefined(viewGroupConfig)) { - continue; - } - - const fieldValue = viewGroupMapping?.[viewGroupName]; - - if (!isDefined(fieldValue) && fieldValue !== '') { - this.logger.warn( - `Field value mapping for view group "${viewGroupName}" not found for view "${viewName}" of object "${flatObjectMetadata.nameSingular}", skipping view group`, - ); - continue; - } - - const matchingFlatViewGroup = relatedFlatViewGroups.find( - (viewGroup) => viewGroup.fieldValue === fieldValue, - ); - - if (!isDefined(matchingFlatViewGroup)) { - this.logger.warn( - `Standard view group "${viewGroupName}" with fieldValue="${fieldValue}" not found for view "${viewName}" of object "${flatObjectMetadata.nameSingular}", skipping`, - ); - continue; - } - - if (isDefined(matchingFlatViewGroup.applicationId)) { - continue; - } - - standardViewGroupUpdates.push({ - flatViewGroup: matchingFlatViewGroup, - universalIdentifier: viewGroupConfig.universalIdentifier, - objectNameSingular: flatObjectMetadata.nameSingular, - viewName: flatView.name, - viewGroupName, - }); - } - } - } - - const standardUpdates = standardViewGroupUpdates.map( - ({ flatViewGroup, universalIdentifier }) => ({ - id: flatViewGroup.id, - universalIdentifier, - applicationId: twentyStandardApplicationId, - }), - ); - - this.logger.log( - `Found ${standardUpdates.length} standard view group(s) to update`, - ); - - for (const { - flatViewGroup, - universalIdentifier, - objectNameSingular, - viewName, - viewGroupName, - } of standardViewGroupUpdates) { - this.logger.log( - ` - Standard view group "${viewGroupName}" on view "${viewName}" of object "${objectNameSingular}" (id=${flatViewGroup.id}) -> universalIdentifier=${universalIdentifier}`, - ); - } - - if (!dryRun) { - await this.viewGroupRepository.save(standardUpdates); - } - } - - private async identifyCustomViewGroups({ - workspaceId, - flatObjectMetadataMaps, - flatViewMaps, - workspaceCustomApplicationId, - dryRun, - }: { - workspaceId: string; - flatObjectMetadataMaps: FlatEntityMaps; - flatViewMaps: FlatEntityMaps; - workspaceCustomApplicationId: string; - dryRun: boolean; - }): Promise { - const remainingCustomViewGroups = await this.viewGroupRepository.find({ - select: { - id: true, - universalIdentifier: true, - applicationId: true, - viewId: true, - fieldValue: true, - }, - where: { - workspaceId, - applicationId: IsNull(), - }, - withDeleted: true, - }); - - const customUpdates = remainingCustomViewGroups.map((viewGroupEntity) => ({ - id: viewGroupEntity.id, - universalIdentifier: viewGroupEntity.universalIdentifier ?? v4(), - applicationId: workspaceCustomApplicationId, - })); - - this.logger.log( - `Found ${customUpdates.length} custom view group(s) to update for workspace ${workspaceId}`, - ); - - for (const viewGroupEntity of remainingCustomViewGroups) { - const flatView = flatViewMaps.byId[viewGroupEntity.viewId]; - const flatObjectMetadata = isDefined(flatView) - ? flatObjectMetadataMaps.byId[flatView.objectMetadataId] - : undefined; - - this.logger.log( - ` - Custom view group with fieldValue="${viewGroupEntity.fieldValue}" on view "${flatView?.name ?? 'unknown'}" of object "${flatObjectMetadata?.nameSingular ?? 'unknown'}" (id=${viewGroupEntity.id})`, - ); - } - - if (!dryRun) { - await this.viewGroupRepository.save(customUpdates); - } - } -} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-identify-view-metadata.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-identify-view-metadata.command.ts deleted file mode 100644 index 6fd6c5ba37..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-identify-view-metadata.command.ts +++ /dev/null @@ -1,378 +0,0 @@ -import { InjectRepository } from '@nestjs/typeorm'; - -import { Command } from 'nest-commander'; -import { capitalize, isDefined, uncapitalize } from 'twenty-shared/utils'; -import { IsNull, Repository } from 'typeorm'; -import { v4 } from 'uuid'; - -import { ActiveOrSuspendedWorkspacesMigrationCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner'; -import { RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspaces-migration.command-runner'; -import { ALL_ENTITY_VIEW_NAME } from 'src/database/commands/upgrade-version-command/1-16/utils/compute-formatted-view-name.util'; -import { ApplicationService } from 'src/engine/core-modules/application/services/application.service'; -import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; -import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; -import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service'; -import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type'; -import { findFlatEntityByUniversalIdentifier } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-universal-identifier.util'; -import { findManyFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-many-flat-entity-by-id-in-flat-entity-maps-or-throw.util'; -import { getMetadataFlatEntityMapsKey } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-flat-entity-maps-key.util'; -import { getMetadataRelatedMetadataNames } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-related-metadata-names.util'; -import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type'; -import { type FlatView } from 'src/engine/metadata-modules/flat-view/types/flat-view.type'; -import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity'; -import { ViewKey } from 'src/engine/metadata-modules/view/enums/view-key.enum'; -import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; -import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service'; -import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; - -type StandardViewUpdate = { - flatView: FlatView; - universalIdentifier: string; - objectNameSingular: string; -}; - -type AllExceptions = 'unknown_standard_view'; - -type ViewMetadataException = { - flatView: FlatView; - exception: AllExceptions; - objectNameSingular?: string; -}; - -type DuplicateStandardView = { - skippedFlatView: FlatView; - keptFlatView: FlatView; - objectNameSingular: string; - universalIdentifier: string; -}; - -@Command({ - name: 'upgrade:1-16:identify-view-metadata', - description: 'Identify standard view metadata', -}) -export class IdentifyViewMetadataCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner { - constructor( - @InjectRepository(WorkspaceEntity) - protected readonly workspaceRepository: Repository, - @InjectRepository(ViewEntity) - private readonly viewRepository: Repository, - protected readonly twentyORMGlobalManager: GlobalWorkspaceOrmManager, - protected readonly dataSourceService: DataSourceService, - protected readonly applicationService: ApplicationService, - protected readonly workspaceCacheService: WorkspaceCacheService, - private readonly flatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService, - ) { - super(workspaceRepository, twentyORMGlobalManager, dataSourceService); - } - - override async runOnWorkspace({ - workspaceId, - options, - }: RunOnWorkspaceArgs): Promise { - this.logger.log( - `Running identify standard view metadata for workspace ${workspaceId}`, - ); - - const { twentyStandardFlatApplication, workspaceCustomFlatApplication } = - await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow( - { workspaceId }, - ); - - const { flatObjectMetadataMaps, flatViewMaps } = - await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps( - { - workspaceId, - flatMapsKeys: ['flatObjectMetadataMaps', 'flatViewMaps'], - }, - ); - - await this.identifyStandardViewsOrThrow({ - workspaceId, - flatObjectMetadataMaps, - flatViewMaps, - twentyStandardApplicationId: twentyStandardFlatApplication.id, - dryRun: options.dryRun ?? false, - }); - - await this.identifyCustomViews({ - workspaceId, - flatObjectMetadataMaps, - workspaceCustomApplicationId: workspaceCustomFlatApplication.id, - dryRun: options.dryRun ?? false, - }); - - const relatedMetadataNames = getMetadataRelatedMetadataNames('view'); - const relatedCacheKeysToInvalidate = relatedMetadataNames.map( - getMetadataFlatEntityMapsKey, - ); - - this.logger.log( - `Invalidating caches: ${relatedCacheKeysToInvalidate.join(' ')}`, - ); - if (!options.dryRun) { - await this.workspaceCacheService.invalidateAndRecompute(workspaceId, [ - 'flatViewMaps', - ...relatedCacheKeysToInvalidate, - ]); - } - } - - private async identifyStandardViewsOrThrow({ - workspaceId, - flatObjectMetadataMaps, - flatViewMaps, - twentyStandardApplicationId, - dryRun, - }: { - workspaceId: string; - flatObjectMetadataMaps: FlatEntityMaps; - flatViewMaps: FlatEntityMaps; - twentyStandardApplicationId: string; - dryRun: boolean; - }): Promise { - const standardViewUpdates: StandardViewUpdate[] = []; - const exceptions: ViewMetadataException[] = []; - - for (const [objectNameSingular, objectConfig] of Object.entries( - STANDARD_OBJECTS, - )) { - const objectViews = - 'views' in objectConfig - ? (objectConfig.views as Record< - string, - { universalIdentifier: string } | undefined - >) - : null; - - if (!isDefined(objectViews)) { - continue; - } - const flatObjectMetadata = findFlatEntityByUniversalIdentifier({ - flatEntityMaps: flatObjectMetadataMaps, - universalIdentifier: objectConfig.universalIdentifier, - }); - - if (!isDefined(flatObjectMetadata)) { - this.logger.error( - `Standard object "${objectNameSingular}" not found in workspace, this needs investigation, skipping`, - ); - continue; - } - - const relatedFlatViews = findManyFlatEntityByIdInFlatEntityMapsOrThrow({ - flatEntityIds: flatObjectMetadata.viewIds, - flatEntityMaps: flatViewMaps, - }); - - for (const flatView of relatedFlatViews) { - if (isDefined(flatView.applicationId)) { - continue; - } - - // INDEX views -> forward to standard (if object has views config) - if ( - flatView.key === ViewKey.INDEX && - flatView.name === ALL_ENTITY_VIEW_NAME - ) { - const formattedViewName = `all${capitalize(flatObjectMetadata.namePlural)}`; - - const viewConfig = objectViews[formattedViewName]; - const universalIdentifier = viewConfig?.universalIdentifier; - - if (!isDefined(universalIdentifier)) { - exceptions.push({ - exception: 'unknown_standard_view', - flatView, - objectNameSingular: flatObjectMetadata.nameSingular, - }); - continue; - } - - standardViewUpdates.push({ - flatView, - universalIdentifier, - objectNameSingular: flatObjectMetadata.nameSingular, - }); - continue; - } - - // Views with "All" name pattern but not INDEX -> forward to custom - if (flatView.name.startsWith('All ')) { - continue; - } - - // Remaining views (like assignedToMe, byStatus, etc.) - const formattedViewName = uncapitalize( - flatView.name.split(' ').map(capitalize).join(''), - ); - - const viewConfig = objectViews[formattedViewName]; - const universalIdentifier = viewConfig?.universalIdentifier; - - if (!isDefined(universalIdentifier)) { - continue; - } - - standardViewUpdates.push({ - flatView, - universalIdentifier, - objectNameSingular: flatObjectMetadata.nameSingular, - }); - } - } - - if (exceptions.length > 0) { - this.logger.error( - `Found ${exceptions.length} exception(s) while processing view metadata for workspace ${workspaceId}. No updates will be applied.`, - ); - - for (const { flatView, exception, objectNameSingular } of exceptions) { - this.logger.error( - ` - Exception for view "${flatView.name}" on object "${objectNameSingular ?? 'unknown'}" (id=${flatView.id}): ${exception}`, - ); - } - - throw new Error( - `Aborting migration for workspace ${workspaceId} due to ${exceptions.length} exception(s). See logs above for details.`, - ); - } - - // Detect duplicate universalIdentifiers and keep the oldest view (created during workspace setup) - const seenUniversalIdentifiers = new Map(); - const duplicates: DuplicateStandardView[] = []; - - for (const update of standardViewUpdates) { - const existingUpdate = seenUniversalIdentifiers.get( - update.universalIdentifier, - ); - - if (isDefined(existingUpdate)) { - const currentCreatedAt = new Date(update.flatView.createdAt).getTime(); - const existingCreatedAt = new Date( - existingUpdate.flatView.createdAt, - ).getTime(); - - // Keep the oldest view, skip the newer one - if (currentCreatedAt < existingCreatedAt) { - // Current is older, replace existing - duplicates.push({ - skippedFlatView: existingUpdate.flatView, - keptFlatView: update.flatView, - objectNameSingular: update.objectNameSingular, - universalIdentifier: update.universalIdentifier, - }); - seenUniversalIdentifiers.set(update.universalIdentifier, update); - } else { - // Existing is older, skip current - duplicates.push({ - skippedFlatView: update.flatView, - keptFlatView: existingUpdate.flatView, - objectNameSingular: update.objectNameSingular, - universalIdentifier: update.universalIdentifier, - }); - } - continue; - } - - seenUniversalIdentifiers.set(update.universalIdentifier, update); - } - - if (duplicates.length > 0) { - this.logger.warn( - `Found ${duplicates.length} duplicate standard view(s) for workspace ${workspaceId}. Keeping oldest, newer duplicates will be treated as custom views.`, - ); - - for (const { - skippedFlatView, - keptFlatView, - objectNameSingular, - universalIdentifier, - } of duplicates) { - this.logger.warn( - ` - Duplicate view "${skippedFlatView.name}" on object "${objectNameSingular}" (id=${skippedFlatView.id}, createdAt=${skippedFlatView.createdAt}) skipped in favor of older view (id=${keptFlatView.id}, createdAt=${keptFlatView.createdAt}) for universalIdentifier=${universalIdentifier}`, - ); - } - } - - const deduplicatedStandardViewUpdates = Array.from( - seenUniversalIdentifiers.values(), - ); - - const standardUpdates = deduplicatedStandardViewUpdates.map( - ({ flatView, universalIdentifier }) => ({ - id: flatView.id, - universalIdentifier, - applicationId: twentyStandardApplicationId, - }), - ); - - this.logger.log( - `Found ${standardUpdates.length} standard view(s) to update for workspace ${workspaceId}`, - ); - - for (const { - flatView, - universalIdentifier, - objectNameSingular, - } of deduplicatedStandardViewUpdates) { - this.logger.log( - ` - Standard view "${flatView.name}" on object "${objectNameSingular}" (id=${flatView.id}) -> universalIdentifier=${universalIdentifier}`, - ); - } - - if (!dryRun) { - await this.viewRepository.save(standardUpdates); - } - } - - private async identifyCustomViews({ - workspaceId, - flatObjectMetadataMaps, - workspaceCustomApplicationId, - dryRun, - }: { - workspaceId: string; - flatObjectMetadataMaps: FlatEntityMaps; - workspaceCustomApplicationId: string; - dryRun: boolean; - }): Promise { - const remainingCustomViews = await this.viewRepository.find({ - select: { - id: true, - universalIdentifier: true, - applicationId: true, - name: true, - objectMetadataId: true, - isCustom: true, - }, - where: { - workspaceId, - applicationId: IsNull(), - }, - withDeleted: true, - }); - - const customUpdates = remainingCustomViews.map((viewEntity) => ({ - id: viewEntity.id, - universalIdentifier: viewEntity.universalIdentifier ?? v4(), - applicationId: workspaceCustomApplicationId, - })); - - this.logger.log( - `Found ${customUpdates.length} custom view(s) to update for workspace ${workspaceId}`, - ); - - for (const viewEntity of remainingCustomViews) { - const flatObjectMetadata = - flatObjectMetadataMaps.byId[viewEntity.objectMetadataId]; - - this.logger.log( - ` - Custom view "${viewEntity.name}" on object "${flatObjectMetadata?.nameSingular ?? 'unknown'}" (id=${viewEntity.id})`, - ); - } - - if (!dryRun) { - await this.viewRepository.save(customUpdates); - } - } -} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-make-agent-universal-identifier-and-application-id-not-nullable-migration.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-make-agent-universal-identifier-and-application-id-not-nullable-migration.command.ts deleted file mode 100644 index 0c361307d6..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-make-agent-universal-identifier-and-application-id-not-nullable-migration.command.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { InjectDataSource, InjectRepository } from '@nestjs/typeorm'; - -import { Command } from 'nest-commander'; -import { DataSource, Repository } from 'typeorm'; - -import { ActiveOrSuspendedWorkspacesMigrationCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner'; -import { RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspaces-migration.command-runner'; -import { makeAgentUniversalIdentifierAndApplicationIdNotNullableQueries } from 'src/database/typeorm/core/migrations/utils/1768213174274-makeAgentUniversalIdentifierAndApplicationIdNotNullable.util'; -import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; -import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; -import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; - -@Command({ - name: 'upgrade:1-16:make-agent-universal-identifier-and-application-id-not-nullable-migration', - description: - 'Make universalIdentifier and applicationId columns NOT NULL on agent table', -}) -export class MakeAgentUniversalIdentifierAndApplicationIdNotNullableMigrationCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner { - private hasRunOnce = false; - - constructor( - @InjectRepository(WorkspaceEntity) - protected readonly workspaceRepository: Repository, - protected readonly twentyORMGlobalManager: GlobalWorkspaceOrmManager, - protected readonly dataSourceService: DataSourceService, - @InjectDataSource() - private readonly coreDataSource: DataSource, - ) { - super(workspaceRepository, twentyORMGlobalManager, dataSourceService); - } - - override async runOnWorkspace({ - options, - }: RunOnWorkspaceArgs): Promise { - if (this.hasRunOnce) { - this.logger.warn( - 'Skipping has already been run once MakeAgentUniversalIdentifierAndApplicationIdNotNullableMigrationCommand', - ); - - return; - } - - if (options.dryRun) { - return; - } - - const queryRunner = this.coreDataSource.createQueryRunner(); - - await queryRunner.connect(); - await queryRunner.startTransaction(); - - try { - await makeAgentUniversalIdentifierAndApplicationIdNotNullableQueries( - queryRunner, - ); - - await queryRunner.commitTransaction(); - this.logger.log( - 'Successfully run MakeAgentUniversalIdentifierAndApplicationIdNotNullableMigrationCommand', - ); - this.hasRunOnce = true; - } catch (error) { - await queryRunner.rollbackTransaction(); - this.logger.error( - `Rolling back MakeAgentUniversalIdentifierAndApplicationIdNotNullableMigrationCommand: ${error.message}`, - ); - } finally { - await queryRunner.release(); - } - } -} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-make-field-metadata-universal-identifier-and-application-id-not-nullable-migration.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-make-field-metadata-universal-identifier-and-application-id-not-nullable-migration.command.ts deleted file mode 100644 index 04e066b1a5..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-make-field-metadata-universal-identifier-and-application-id-not-nullable-migration.command.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { InjectDataSource, InjectRepository } from '@nestjs/typeorm'; - -import { Command } from 'nest-commander'; -import { DataSource, Repository } from 'typeorm'; - -import { ActiveOrSuspendedWorkspacesMigrationCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner'; -import { RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspaces-migration.command-runner'; -import { makeFieldMetadataUniversalIdentifierAndApplicationIdNotNullableQueries } from 'src/database/typeorm/core/migrations/utils/1767277454048-makeFieldMetadataUniversalIdentifierAndApplicationIdNotNullable.util'; -import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; -import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; -import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; - -@Command({ - name: 'upgrade:1-16:make-field-metadata-universal-identifier-and-application-id-not-nullable-migration', - description: - 'Make universalIdentifier and applicationId columns NOT NULL on fieldMetadata table', -}) -export class MakeFieldMetadataUniversalIdentifierAndApplicationIdNotNullableMigrationCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner { - private hasRunOnce = false; - - constructor( - @InjectRepository(WorkspaceEntity) - protected readonly workspaceRepository: Repository, - protected readonly twentyORMGlobalManager: GlobalWorkspaceOrmManager, - protected readonly dataSourceService: DataSourceService, - @InjectDataSource() - private readonly coreDataSource: DataSource, - ) { - super(workspaceRepository, twentyORMGlobalManager, dataSourceService); - } - - override async runOnWorkspace({ - options, - }: RunOnWorkspaceArgs): Promise { - if (this.hasRunOnce) { - this.logger.warn( - 'Skipping has already been run once MakeFieldMetadataUniversalIdentifierAndApplicationIdNotNullableMigrationCommand', - ); - - return; - } - - if (options.dryRun) { - return; - } - - const queryRunner = this.coreDataSource.createQueryRunner(); - - await queryRunner.connect(); - await queryRunner.startTransaction(); - - try { - await makeFieldMetadataUniversalIdentifierAndApplicationIdNotNullableQueries( - queryRunner, - ); - - await queryRunner.commitTransaction(); - this.logger.log( - 'Successfully run MakeFieldMetadataUniversalIdentifierAndApplicationIdNotNullableMigrationCommand', - ); - this.hasRunOnce = true; - } catch (error) { - await queryRunner.rollbackTransaction(); - this.logger.log( - `Rollbacking MakeFieldMetadataUniversalIdentifierAndApplicationIdNotNullableMigrationCommand: ${error.message}`, - ); - } finally { - await queryRunner.release(); - } - } -} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-make-index-metadata-universal-identifier-and-application-id-not-nullable-migration.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-make-index-metadata-universal-identifier-and-application-id-not-nullable-migration.command.ts deleted file mode 100644 index eff95f11ec..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-make-index-metadata-universal-identifier-and-application-id-not-nullable-migration.command.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { InjectDataSource, InjectRepository } from '@nestjs/typeorm'; - -import { Command } from 'nest-commander'; -import { DataSource, Repository } from 'typeorm'; - -import { ActiveOrSuspendedWorkspacesMigrationCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner'; -import { RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspaces-migration.command-runner'; -import { makeIndexMetadataUniversalIdentifierAndApplicationIdNotNullableQueries } from 'src/database/typeorm/core/migrations/utils/1768830235328-makeIndexMetadataUniversalIdentifierAndApplicationIdNotNullable.util'; -import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; -import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; -import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; - -@Command({ - name: 'upgrade:1-16:make-index-metadata-universal-identifier-and-application-id-not-nullable-migration', - description: - 'Make universalIdentifier and applicationId columns NOT NULL on indexMetadata table', -}) -export class MakeIndexMetadataUniversalIdentifierAndApplicationIdNotNullableMigrationCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner { - private hasRunOnce = false; - - constructor( - @InjectRepository(WorkspaceEntity) - protected readonly workspaceRepository: Repository, - protected readonly twentyORMGlobalManager: GlobalWorkspaceOrmManager, - protected readonly dataSourceService: DataSourceService, - @InjectDataSource() - private readonly coreDataSource: DataSource, - ) { - super(workspaceRepository, twentyORMGlobalManager, dataSourceService); - } - - override async runOnWorkspace({ - options, - }: RunOnWorkspaceArgs): Promise { - if (this.hasRunOnce) { - this.logger.warn( - 'Skipping has already been run once MakeIndexMetadataUniversalIdentifierAndApplicationIdNotNullableMigrationCommand', - ); - - return; - } - - if (options.dryRun) { - return; - } - - const queryRunner = this.coreDataSource.createQueryRunner(); - - await queryRunner.connect(); - await queryRunner.startTransaction(); - - try { - await makeIndexMetadataUniversalIdentifierAndApplicationIdNotNullableQueries( - queryRunner, - ); - - await queryRunner.commitTransaction(); - this.logger.log( - 'Successfully run MakeIndexMetadataUniversalIdentifierAndApplicationIdNotNullableMigrationCommand', - ); - this.hasRunOnce = true; - } catch (error) { - await queryRunner.rollbackTransaction(); - this.logger.error( - `Rolling back MakeIndexMetadataUniversalIdentifierAndApplicationIdNotNullableMigrationCommand: ${error.message}`, - ); - } finally { - await queryRunner.release(); - } - } -} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-make-object-metadata-universal-identifier-and-application-id-not-nullable-migration.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-make-object-metadata-universal-identifier-and-application-id-not-nullable-migration.command.ts deleted file mode 100644 index 1eb4c44717..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-make-object-metadata-universal-identifier-and-application-id-not-nullable-migration.command.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { InjectDataSource, InjectRepository } from '@nestjs/typeorm'; - -import { Command } from 'nest-commander'; -import { DataSource, Repository } from 'typeorm'; - -import { ActiveOrSuspendedWorkspacesMigrationCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner'; -import { RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspaces-migration.command-runner'; -import { makeObjectMetadataUniversalIdentifierAndApplicationIdNotNullableQueries } from 'src/database/typeorm/core/migrations/utils/1768212224801-makeObjectMetadataUniversalIdentifierAndApplicationIdNotNullable.util'; -import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; -import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; -import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; - -@Command({ - name: 'upgrade:1-16:make-object-metadata-universal-identifier-and-application-id-not-nullable-migration', - description: - 'Make universalIdentifier and applicationId columns NOT NULL on objectMetadata table', -}) -export class MakeObjectMetadataUniversalIdentifierAndApplicationIdNotNullableMigrationCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner { - private hasRunOnce = false; - - constructor( - @InjectRepository(WorkspaceEntity) - protected readonly workspaceRepository: Repository, - protected readonly twentyORMGlobalManager: GlobalWorkspaceOrmManager, - protected readonly dataSourceService: DataSourceService, - @InjectDataSource() - private readonly coreDataSource: DataSource, - ) { - super(workspaceRepository, twentyORMGlobalManager, dataSourceService); - } - - override async runOnWorkspace({ - options, - }: RunOnWorkspaceArgs): Promise { - if (this.hasRunOnce) { - this.logger.warn( - 'Skipping has already been run once MakeObjectMetadataUniversalIdentifierAndApplicationIdNotNullableMigrationCommand', - ); - - return; - } - - if (options.dryRun) { - return; - } - - const queryRunner = this.coreDataSource.createQueryRunner(); - - await queryRunner.connect(); - await queryRunner.startTransaction(); - - try { - await makeObjectMetadataUniversalIdentifierAndApplicationIdNotNullableQueries( - queryRunner, - ); - - await queryRunner.commitTransaction(); - this.logger.log( - 'Successfully run MakeObjectMetadataUniversalIdentifierAndApplicationIdNotNullableMigrationCommand', - ); - this.hasRunOnce = true; - } catch (error) { - await queryRunner.rollbackTransaction(); - this.logger.log( - `Roll backing MakeObjectMetadataUniversalIdentifierAndApplicationIdNotNullableMigrationCommand: ${error.message}`, - ); - } finally { - await queryRunner.release(); - } - } -} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-make-remaining-entities-universal-identifier-and-application-id-not-nullable-migration.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-make-remaining-entities-universal-identifier-and-application-id-not-nullable-migration.command.ts deleted file mode 100644 index 999a23c2e6..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-make-remaining-entities-universal-identifier-and-application-id-not-nullable-migration.command.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { InjectDataSource, InjectRepository } from '@nestjs/typeorm'; - -import { Command } from 'nest-commander'; -import { DataSource, Repository } from 'typeorm'; - -import { ActiveOrSuspendedWorkspacesMigrationCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner'; -import { RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspaces-migration.command-runner'; -import { makeRemainingEntitiesUniversalIdentifierAndApplicationIdNotNullableQueries } from 'src/database/typeorm/core/migrations/utils/1768916632478-makeRemainingEntitiesUniversalIdentifierAndApplicationIdNotNullable.util'; -import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; -import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; -import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; - -@Command({ - name: 'upgrade:1-16:make-remaining-entities-universal-identifier-and-application-id-not-nullable-migration', - description: - 'Make universalIdentifier and applicationId columns NOT NULL on remaining entities (roleTarget, rowLevelPermissionPredicate, rowLevelPermissionPredicateGroup, viewFilterGroup, viewSort, cronTrigger, databaseEventTrigger, routeTrigger, logicFunction, skill, pageLayoutWidget, pageLayout, pageLayoutTab)', -}) -export class MakeRemainingEntitiesUniversalIdentifierAndApplicationIdNotNullableMigrationCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner { - private hasRunOnce = false; - - constructor( - @InjectRepository(WorkspaceEntity) - protected readonly workspaceRepository: Repository, - protected readonly twentyORMGlobalManager: GlobalWorkspaceOrmManager, - protected readonly dataSourceService: DataSourceService, - @InjectDataSource() - private readonly coreDataSource: DataSource, - ) { - super(workspaceRepository, twentyORMGlobalManager, dataSourceService); - } - - override async runOnWorkspace({ - options, - }: RunOnWorkspaceArgs): Promise { - if (this.hasRunOnce) { - this.logger.warn( - 'Skipping has already been run once MakeRemainingEntitiesUniversalIdentifierAndApplicationIdNotNullableMigrationCommand', - ); - - return; - } - - if (options.dryRun) { - return; - } - - const queryRunner = this.coreDataSource.createQueryRunner(); - - await queryRunner.connect(); - await queryRunner.startTransaction(); - - try { - await makeRemainingEntitiesUniversalIdentifierAndApplicationIdNotNullableQueries( - queryRunner, - ); - - await queryRunner.commitTransaction(); - this.logger.log( - 'Successfully run MakeRemainingEntitiesUniversalIdentifierAndApplicationIdNotNullableMigrationCommand', - ); - this.hasRunOnce = true; - } catch (error) { - await queryRunner.rollbackTransaction(); - this.logger.error( - `Rolling back MakeRemainingEntitiesUniversalIdentifierAndApplicationIdNotNullableMigrationCommand: ${error.message}`, - ); - } finally { - await queryRunner.release(); - } - } -} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-make-role-universal-identifier-and-application-id-not-nullable-migration.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-make-role-universal-identifier-and-application-id-not-nullable-migration.command.ts deleted file mode 100644 index 13ce4db25e..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-make-role-universal-identifier-and-application-id-not-nullable-migration.command.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { InjectDataSource, InjectRepository } from '@nestjs/typeorm'; - -import { Command } from 'nest-commander'; -import { DataSource, Repository } from 'typeorm'; - -import { ActiveOrSuspendedWorkspacesMigrationCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner'; -import { RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspaces-migration.command-runner'; -import { makeRoleUniversalIdentifierAndApplicationIdNotNullableQueries } from 'src/database/typeorm/core/migrations/utils/1768213174275-makeRoleUniversalIdentifierAndApplicationIdNotNullable.util'; -import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; -import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; -import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; - -@Command({ - name: 'upgrade:1-16:make-role-universal-identifier-and-application-id-not-nullable-migration', - description: - 'Make universalIdentifier and applicationId columns NOT NULL on role table', -}) -export class MakeRoleUniversalIdentifierAndApplicationIdNotNullableMigrationCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner { - private hasRunOnce = false; - - constructor( - @InjectRepository(WorkspaceEntity) - protected readonly workspaceRepository: Repository, - protected readonly twentyORMGlobalManager: GlobalWorkspaceOrmManager, - protected readonly dataSourceService: DataSourceService, - @InjectDataSource() - private readonly coreDataSource: DataSource, - ) { - super(workspaceRepository, twentyORMGlobalManager, dataSourceService); - } - - override async runOnWorkspace({ - options, - }: RunOnWorkspaceArgs): Promise { - if (this.hasRunOnce) { - this.logger.warn( - 'Skipping has already been run once MakeRoleUniversalIdentifierAndApplicationIdNotNullableMigrationCommand', - ); - - return; - } - - if (options.dryRun) { - return; - } - - const queryRunner = this.coreDataSource.createQueryRunner(); - - await queryRunner.connect(); - await queryRunner.startTransaction(); - - try { - await makeRoleUniversalIdentifierAndApplicationIdNotNullableQueries( - queryRunner, - ); - - await queryRunner.commitTransaction(); - this.logger.log( - 'Successfully run MakeRoleUniversalIdentifierAndApplicationIdNotNullableMigrationCommand', - ); - this.hasRunOnce = true; - } catch (error) { - await queryRunner.rollbackTransaction(); - this.logger.error( - `Rolling back MakeRoleUniversalIdentifierAndApplicationIdNotNullableMigrationCommand: ${error.message}`, - ); - } finally { - await queryRunner.release(); - } - } -} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-make-view-field-universal-identifier-and-application-id-not-nullable-migration.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-make-view-field-universal-identifier-and-application-id-not-nullable-migration.command.ts deleted file mode 100644 index 320c13f41b..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-make-view-field-universal-identifier-and-application-id-not-nullable-migration.command.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { InjectDataSource, InjectRepository } from '@nestjs/typeorm'; - -import { Command } from 'nest-commander'; -import { DataSource, Repository } from 'typeorm'; - -import { ActiveOrSuspendedWorkspacesMigrationCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner'; -import { RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspaces-migration.command-runner'; -import { makeViewFieldUniversalIdentifierAndApplicationIdNotNullableQueries } from 'src/database/typeorm/core/migrations/utils/1768213174272-makeViewFieldUniversalIdentifierAndApplicationIdNotNullable.util'; -import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; -import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; -import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; - -@Command({ - name: 'upgrade:1-16:make-view-field-universal-identifier-and-application-id-not-nullable-migration', - description: - 'Make universalIdentifier and applicationId columns NOT NULL on viewField table', -}) -export class MakeViewFieldUniversalIdentifierAndApplicationIdNotNullableMigrationCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner { - private hasRunOnce = false; - - constructor( - @InjectRepository(WorkspaceEntity) - protected readonly workspaceRepository: Repository, - protected readonly twentyORMGlobalManager: GlobalWorkspaceOrmManager, - protected readonly dataSourceService: DataSourceService, - @InjectDataSource() - private readonly coreDataSource: DataSource, - ) { - super(workspaceRepository, twentyORMGlobalManager, dataSourceService); - } - - override async runOnWorkspace({ - options, - }: RunOnWorkspaceArgs): Promise { - if (this.hasRunOnce) { - this.logger.warn( - 'Skipping has already been run once MakeViewFieldUniversalIdentifierAndApplicationIdNotNullableMigrationCommand', - ); - - return; - } - - if (options.dryRun) { - return; - } - - const queryRunner = this.coreDataSource.createQueryRunner(); - - await queryRunner.connect(); - await queryRunner.startTransaction(); - - try { - await makeViewFieldUniversalIdentifierAndApplicationIdNotNullableQueries( - queryRunner, - ); - - await queryRunner.commitTransaction(); - this.logger.log( - 'Successfully run MakeViewFieldUniversalIdentifierAndApplicationIdNotNullableMigrationCommand', - ); - this.hasRunOnce = true; - } catch (error) { - await queryRunner.rollbackTransaction(); - this.logger.error( - `Rolling back MakeViewFieldUniversalIdentifierAndApplicationIdNotNullableMigrationCommand: ${error.message}`, - ); - } finally { - await queryRunner.release(); - } - } -} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-make-view-filter-universal-identifier-and-application-id-not-nullable-migration.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-make-view-filter-universal-identifier-and-application-id-not-nullable-migration.command.ts deleted file mode 100644 index 0495fb09cb..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-make-view-filter-universal-identifier-and-application-id-not-nullable-migration.command.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { InjectDataSource, InjectRepository } from '@nestjs/typeorm'; - -import { Command } from 'nest-commander'; -import { DataSource, Repository } from 'typeorm'; - -import { ActiveOrSuspendedWorkspacesMigrationCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner'; -import { RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspaces-migration.command-runner'; -import { makeViewFilterUniversalIdentifierAndApplicationIdNotNullableQueries } from 'src/database/typeorm/core/migrations/utils/1768213174273-makeViewFilterUniversalIdentifierAndApplicationIdNotNullable.util'; -import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; -import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; -import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; - -@Command({ - name: 'upgrade:1-16:make-view-filter-universal-identifier-and-application-id-not-nullable-migration', - description: - 'Make universalIdentifier and applicationId columns NOT NULL on viewFilter table', -}) -export class MakeViewFilterUniversalIdentifierAndApplicationIdNotNullableMigrationCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner { - private hasRunOnce = false; - - constructor( - @InjectRepository(WorkspaceEntity) - protected readonly workspaceRepository: Repository, - protected readonly twentyORMGlobalManager: GlobalWorkspaceOrmManager, - protected readonly dataSourceService: DataSourceService, - @InjectDataSource() - private readonly coreDataSource: DataSource, - ) { - super(workspaceRepository, twentyORMGlobalManager, dataSourceService); - } - - override async runOnWorkspace({ - options, - }: RunOnWorkspaceArgs): Promise { - if (this.hasRunOnce) { - this.logger.warn( - 'Skipping has already been run once MakeViewFilterUniversalIdentifierAndApplicationIdNotNullableMigrationCommand', - ); - - return; - } - - if (options.dryRun) { - return; - } - - const queryRunner = this.coreDataSource.createQueryRunner(); - - await queryRunner.connect(); - await queryRunner.startTransaction(); - - try { - await makeViewFilterUniversalIdentifierAndApplicationIdNotNullableQueries( - queryRunner, - ); - - await queryRunner.commitTransaction(); - this.logger.log( - 'Successfully run MakeViewFilterUniversalIdentifierAndApplicationIdNotNullableMigrationCommand', - ); - this.hasRunOnce = true; - } catch (error) { - await queryRunner.rollbackTransaction(); - this.logger.error( - `Rolling back MakeViewFilterUniversalIdentifierAndApplicationIdNotNullableMigrationCommand: ${error.message}`, - ); - } finally { - await queryRunner.release(); - } - } -} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-make-view-group-universal-identifier-and-application-id-not-nullable-migration.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-make-view-group-universal-identifier-and-application-id-not-nullable-migration.command.ts deleted file mode 100644 index b171ecc71a..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-make-view-group-universal-identifier-and-application-id-not-nullable-migration.command.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { InjectDataSource, InjectRepository } from '@nestjs/typeorm'; - -import { Command } from 'nest-commander'; -import { DataSource, Repository } from 'typeorm'; - -import { ActiveOrSuspendedWorkspacesMigrationCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner'; -import { RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspaces-migration.command-runner'; -import { makeViewGroupUniversalIdentifierAndApplicationIdNotNullableQueries } from 'src/database/typeorm/core/migrations/utils/1768213174274-makeViewGroupUniversalIdentifierAndApplicationIdNotNullable.util'; -import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; -import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; -import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; - -@Command({ - name: 'upgrade:1-16:make-view-group-universal-identifier-and-application-id-not-nullable-migration', - description: - 'Make universalIdentifier and applicationId columns NOT NULL on viewGroup table', -}) -export class MakeViewGroupUniversalIdentifierAndApplicationIdNotNullableMigrationCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner { - private hasRunOnce = false; - - constructor( - @InjectRepository(WorkspaceEntity) - protected readonly workspaceRepository: Repository, - protected readonly twentyORMGlobalManager: GlobalWorkspaceOrmManager, - protected readonly dataSourceService: DataSourceService, - @InjectDataSource() - private readonly coreDataSource: DataSource, - ) { - super(workspaceRepository, twentyORMGlobalManager, dataSourceService); - } - - override async runOnWorkspace({ - options, - }: RunOnWorkspaceArgs): Promise { - if (this.hasRunOnce) { - this.logger.warn( - 'Skipping has already been run once MakeViewGroupUniversalIdentifierAndApplicationIdNotNullableMigrationCommand', - ); - - return; - } - - if (options.dryRun) { - return; - } - - const queryRunner = this.coreDataSource.createQueryRunner(); - - await queryRunner.connect(); - await queryRunner.startTransaction(); - - try { - await makeViewGroupUniversalIdentifierAndApplicationIdNotNullableQueries( - queryRunner, - ); - - await queryRunner.commitTransaction(); - this.logger.log( - 'Successfully run MakeViewGroupUniversalIdentifierAndApplicationIdNotNullableMigrationCommand', - ); - this.hasRunOnce = true; - } catch (error) { - await queryRunner.rollbackTransaction(); - this.logger.error( - `Rolling back MakeViewGroupUniversalIdentifierAndApplicationIdNotNullableMigrationCommand: ${error.message}`, - ); - } finally { - await queryRunner.release(); - } - } -} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-make-view-universal-identifier-and-application-id-not-nullable-migration.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-make-view-universal-identifier-and-application-id-not-nullable-migration.command.ts deleted file mode 100644 index 948f443a17..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-make-view-universal-identifier-and-application-id-not-nullable-migration.command.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { InjectDataSource, InjectRepository } from '@nestjs/typeorm'; - -import { Command } from 'nest-commander'; -import { DataSource, Repository } from 'typeorm'; - -import { ActiveOrSuspendedWorkspacesMigrationCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner'; -import { RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspaces-migration.command-runner'; -import { makeViewUniversalIdentifierAndApplicationIdNotNullableQueries } from 'src/database/typeorm/core/migrations/utils/1768213174271-makeViewUniversalIdentifierAndApplicationIdNotNullable.util'; -import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; -import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; -import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; - -@Command({ - name: 'upgrade:1-16:make-view-universal-identifier-and-application-id-not-nullable-migration', - description: - 'Make universalIdentifier and applicationId columns NOT NULL on view table', -}) -export class MakeViewUniversalIdentifierAndApplicationIdNotNullableMigrationCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner { - private hasRunOnce = false; - - constructor( - @InjectRepository(WorkspaceEntity) - protected readonly workspaceRepository: Repository, - protected readonly twentyORMGlobalManager: GlobalWorkspaceOrmManager, - protected readonly dataSourceService: DataSourceService, - @InjectDataSource() - private readonly coreDataSource: DataSource, - ) { - super(workspaceRepository, twentyORMGlobalManager, dataSourceService); - } - - override async runOnWorkspace({ - options, - }: RunOnWorkspaceArgs): Promise { - if (this.hasRunOnce) { - this.logger.warn( - 'Skipping has already been run once MakeViewUniversalIdentifierAndApplicationIdNotNullableMigrationCommand', - ); - - return; - } - - if (options.dryRun) { - return; - } - - const queryRunner = this.coreDataSource.createQueryRunner(); - - await queryRunner.connect(); - await queryRunner.startTransaction(); - - try { - await makeViewUniversalIdentifierAndApplicationIdNotNullableQueries( - queryRunner, - ); - - await queryRunner.commitTransaction(); - this.logger.log( - 'Successfully run MakeViewUniversalIdentifierAndApplicationIdNotNullableMigrationCommand', - ); - this.hasRunOnce = true; - } catch (error) { - await queryRunner.rollbackTransaction(); - this.logger.error( - `Rolling back MakeViewUniversalIdentifierAndApplicationIdNotNullableMigrationCommand: ${error.message}`, - ); - } finally { - await queryRunner.release(); - } - } -} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-update-task-on-delete-action.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-update-task-on-delete-action.command.ts deleted file mode 100644 index f372ef515f..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-update-task-on-delete-action.command.ts +++ /dev/null @@ -1,341 +0,0 @@ -import { Logger } from '@nestjs/common'; -import { InjectRepository } from '@nestjs/typeorm'; - -import { Command } from 'nest-commander'; -import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; -import { - FieldMetadataSettingsMapping, - FieldMetadataType, - RelationOnDeleteAction, -} from 'twenty-shared/types'; -import { isDefined } from 'twenty-shared/utils'; -import { IsNull, Repository } from 'typeorm'; - -import { ActiveOrSuspendedWorkspacesMigrationCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner'; -import { RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspaces-migration.command-runner'; -import { ApplicationService } from 'src/engine/core-modules/application/services/application.service'; -import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; -import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; -import { findManyFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-many-flat-entity-by-id-in-flat-entity-maps-or-throw.util'; -import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; -import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service'; -import { TASK_TARGET_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-migration/constant/standard-field-ids'; -import { WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration/services/workspace-migration-validate-build-and-run-service'; - -@Command({ - name: 'upgrade:1-16:update-task-on-delete-action', - description: - 'Update task relation onDelete action to CASCADE and delete orphaned taskTarget records', -}) -export class UpdateTaskOnDeleteActionCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner { - protected readonly logger = new Logger(UpdateTaskOnDeleteActionCommand.name); - - constructor( - @InjectRepository(WorkspaceEntity) - protected readonly workspaceRepository: Repository, - protected readonly globalWorkspaceOrmManager: GlobalWorkspaceOrmManager, - protected readonly dataSourceService: DataSourceService, - private readonly workspaceCacheService: WorkspaceCacheService, - private readonly workspaceMigrationValidateBuildAndRunService: WorkspaceMigrationValidateBuildAndRunService, - private readonly applicationService: ApplicationService, - ) { - super(workspaceRepository, globalWorkspaceOrmManager, dataSourceService); - } - - override async runOnWorkspace({ - workspaceId, - options, - }: RunOnWorkspaceArgs): Promise { - const isDryRun = options.dryRun ?? false; - - this.logger.log( - `Running UpdateTaskOnDeleteActionCommand for workspace ${workspaceId} (dryRun: ${isDryRun})`, - ); - - this.logger.log( - `[Phase 1] Starting task relation onDelete action update for workspace ${workspaceId}`, - ); - - await this.updateTaskRelationOnDeleteAction(workspaceId, isDryRun); - - this.logger.log( - `[Phase 1] Completed task relation onDelete action update for workspace ${workspaceId}`, - ); - - this.logger.log( - `[Phase 2] Starting orphaned taskTarget cleanup for workspace ${workspaceId}`, - ); - - await this.deleteOrphanedTaskTargets(workspaceId, isDryRun); - - this.logger.log( - `[Phase 2] Completed orphaned taskTarget cleanup for workspace ${workspaceId}`, - ); - - this.logger.log( - `UpdateTaskOnDeleteActionCommand completed successfully for workspace ${workspaceId}`, - ); - } - - private async updateTaskRelationOnDeleteAction( - workspaceId: string, - isDryRun: boolean, - ): Promise { - this.logger.log( - `[Step 1/4] Fetching workspace cache for workspace ${workspaceId}`, - ); - - const { flatFieldMetadataMaps, flatObjectMetadataMaps } = - await this.workspaceCacheService.getOrRecompute(workspaceId, [ - 'flatFieldMetadataMaps', - 'flatObjectMetadataMaps', - ]); - - this.logger.log( - `[Step 2/4] Looking for taskTarget object metadata in workspace ${workspaceId}`, - ); - - const taskTargetObjectMetadata = Object.values( - flatObjectMetadataMaps.byId, - ).find( - (objectMetadata) => - objectMetadata?.standardId === STANDARD_OBJECT_IDS.taskTarget, - ); - - if (!isDefined(taskTargetObjectMetadata)) { - this.logger.warn( - `TaskTarget object metadata not found in workspace ${workspaceId}`, - ); - - return; - } - - this.logger.log( - `[Step 2/4] Found taskTarget object metadata with id ${taskTargetObjectMetadata.id} that has ${taskTargetObjectMetadata.fieldIds.length} field(s) in workspace ${workspaceId}`, - ); - - this.logger.log( - `[Step 3/4] Looking for task field on taskTarget object in workspace ${workspaceId}`, - ); - - const taskTargetFields = findManyFlatEntityByIdInFlatEntityMapsOrThrow({ - flatEntityIds: taskTargetObjectMetadata.fieldIds, - flatEntityMaps: flatFieldMetadataMaps, - }); - - const taskField = taskTargetFields.find( - (field) => field.standardId === TASK_TARGET_STANDARD_FIELD_IDS.task, - ); - - if (!isDefined(taskField)) { - this.logger.warn( - `Task field not found on taskTarget object in workspace ${workspaceId}`, - ); - - return; - } - - this.logger.log( - `[Step 3/4] Found task field with id ${taskField.id} in workspace ${workspaceId}`, - ); - - if (taskField.type !== FieldMetadataType.RELATION) { - this.logger.warn( - `Task field is not a relation field (type: ${taskField.type}) in workspace ${workspaceId}`, - ); - - return; - } - - const taskFieldSettings = - taskField.settings as FieldMetadataSettingsMapping['RELATION']; - - if (taskFieldSettings?.onDelete === RelationOnDeleteAction.CASCADE) { - this.logger.log( - `[Step 4/4] Task relation already has CASCADE onDelete in workspace ${workspaceId}, skipping update`, - ); - - return; - } - - this.logger.log( - `[Step 4/4] Updating task relation onDelete from ${taskFieldSettings?.onDelete ?? 'undefined'} to CASCADE in workspace ${workspaceId}`, - ); - - if (!isDryRun) { - const updatedSettings: FieldMetadataSettingsMapping['RELATION'] = { - ...taskFieldSettings, - onDelete: RelationOnDeleteAction.CASCADE, - }; - - const updatedTaskField = { - ...taskField, - settings: updatedSettings, - updatedAt: new Date().toISOString(), - }; - - this.logger.log( - `[Step 4/4] Calling validateBuildAndRunWorkspaceMigration for field ${taskField.id} in workspace ${workspaceId}`, - ); - - try { - const { twentyStandardFlatApplication } = - await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow( - { workspaceId }, - ); - - const validateAndBuildResult = - await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration( - { - allFlatEntityOperationByMetadataName: { - fieldMetadata: { - flatEntityToCreate: [], - flatEntityToDelete: [], - flatEntityToUpdate: [updatedTaskField], - }, - }, - workspaceId, - isSystemBuild: true, - applicationUniversalIdentifier: - twentyStandardFlatApplication.universalIdentifier, - }, - ); - - this.logger.error( - `[Step 4/4] Validation result: ${JSON.stringify(validateAndBuildResult, null, 2)}`, - ); - - if (isDefined(validateAndBuildResult)) { - this.logger.error( - `[Step 4/4] Failed to update task relation onDelete in workspace ${workspaceId}`, - ); - - throw new Error( - `Failed to update task relation onDelete in workspace ${workspaceId}`, - ); - } - - this.logger.log( - `[Step 4/4] Successfully updated task relation onDelete to CASCADE in workspace ${workspaceId}`, - ); - } catch (error) { - this.logger.error( - `[Step 4/4] Failed to update task relation onDelete in workspace ${workspaceId}`, - ); - this.logger.error( - `[Step 4/4] Field id: ${taskField.id}, current settings: ${JSON.stringify(taskFieldSettings)}`, - ); - this.logger.error( - `[Step 4/4] Target settings: ${JSON.stringify(updatedSettings)}`, - ); - this.logger.error( - `[Step 4/4] Error message: ${error instanceof Error ? error.message : String(error)}`, - ); - this.logger.error( - `[Step 4/4] Error stack: ${error instanceof Error ? error.stack : 'No stack available'}`, - ); - - this.logger.error(JSON.stringify(error, null, 2)); - - throw error; - } - } else { - this.logger.log( - `[Step 4/4] DRY RUN: Would update task relation onDelete to CASCADE in workspace ${workspaceId}`, - ); - } - } - - private async deleteOrphanedTaskTargets( - workspaceId: string, - isDryRun: boolean, - ): Promise { - this.logger.log( - `[Orphan cleanup 1/3] Getting taskTarget repository for workspace ${workspaceId}`, - ); - - const taskTargetRepository = - await this.globalWorkspaceOrmManager.getRepository( - workspaceId, - 'taskTarget', - { shouldBypassPermissionChecks: true }, - ); - - this.logger.log( - `[Orphan cleanup 2/3] Searching for orphaned taskTarget records (taskId is null) in workspace ${workspaceId}`, - ); - - const orphanedTaskTargets = await taskTargetRepository.find({ - withDeleted: true, - select: ['id'], - where: { - taskId: IsNull(), - }, - }); - - const orphanedCount = orphanedTaskTargets.length; - - this.logger.log( - `[Orphan cleanup 2/3] Found ${orphanedCount} orphaned taskTarget record(s) in workspace ${workspaceId}`, - ); - - if (orphanedCount === 0) { - this.logger.log( - `[Orphan cleanup 3/3] No orphaned records to delete in workspace ${workspaceId}`, - ); - - return; - } - - if (!isDryRun) { - const orphanedIds = orphanedTaskTargets.map((record) => record.id); - - const batchSize = 100; - const totalBatches = Math.ceil(orphanedIds.length / batchSize); - - this.logger.log( - `[Orphan cleanup 3/3] Deleting ${orphanedCount} orphaned taskTarget record(s) in ${totalBatches} batch(es) in workspace ${workspaceId}`, - ); - - for (let i = 0; i < orphanedIds.length; i += batchSize) { - const batch = orphanedIds.slice(i, i + batchSize); - const batchNumber = Math.floor(i / batchSize) + 1; - - this.logger.log( - `[Orphan cleanup 3/3] Deleting batch ${batchNumber}/${totalBatches} (${batch.length} records) in workspace ${workspaceId}`, - ); - - try { - await taskTargetRepository - .createQueryBuilder() - .delete() - .whereInIds(batch) - .execute(); - } catch (error) { - this.logger.error( - `[Orphan cleanup 3/3] Failed to delete batch ${batchNumber}/${totalBatches} in workspace ${workspaceId}`, - ); - this.logger.error( - `[Orphan cleanup 3/3] Batch record ids: ${JSON.stringify(batch)}`, - ); - this.logger.error( - `[Orphan cleanup 3/3] Error message: ${error instanceof Error ? error.message : String(error)}`, - ); - this.logger.error( - `[Orphan cleanup 3/3] Error stack: ${error instanceof Error ? error.stack : 'No stack available'}`, - ); - - throw error; - } - } - - this.logger.log( - `[Orphan cleanup 3/3] Successfully deleted ${orphanedCount} orphaned taskTarget record(s) in workspace ${workspaceId}`, - ); - } else { - this.logger.log( - `[Orphan cleanup 3/3] DRY RUN: Would delete ${orphanedCount} orphaned taskTarget record(s) in workspace ${workspaceId}`, - ); - } - } -} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-upgrade-version-command.module.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-upgrade-version-command.module.ts deleted file mode 100644 index c49f283d4c..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-upgrade-version-command.module.ts +++ /dev/null @@ -1,130 +0,0 @@ -import { Module } from '@nestjs/common'; -import { TypeOrmModule } from '@nestjs/typeorm'; - -import { BackfillOpportunityOwnerFieldCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-backfill-opportunity-owner-field.command'; -import { BackfillStandardPageLayoutsCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-backfill-standard-page-layouts.command'; -import { DeleteFileRecordsCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-delete-all-files.command'; -import { FlushV2CacheAndIncrementMetadataVersionCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-flush-v2-cache-and-increment-metadata-version.command'; -import { IdentifyAgentMetadataCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-identify-agent-metadata.command'; -import { IdentifyFieldMetadataCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-identify-field-metadata.command'; -import { IdentifyIndexMetadataCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-identify-index-metadata.command'; -import { IdentifyObjectMetadataCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-identify-object-metadata.command'; -import { IdentifyRemainingEntitiesMetadataCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-identify-remaining-entities-metadata.command'; -import { IdentifyRoleMetadataCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-identify-role-metadata.command'; -import { IdentifyViewFieldMetadataCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-identify-view-field-metadata.command'; -import { IdentifyViewFilterMetadataCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-identify-view-filter-metadata.command'; -import { IdentifyViewGroupMetadataCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-identify-view-group-metadata.command'; -import { IdentifyViewMetadataCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-identify-view-metadata.command'; -import { MakeAgentUniversalIdentifierAndApplicationIdNotNullableMigrationCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-make-agent-universal-identifier-and-application-id-not-nullable-migration.command'; -import { MakeFieldMetadataUniversalIdentifierAndApplicationIdNotNullableMigrationCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-make-field-metadata-universal-identifier-and-application-id-not-nullable-migration.command'; -import { MakeIndexMetadataUniversalIdentifierAndApplicationIdNotNullableMigrationCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-make-index-metadata-universal-identifier-and-application-id-not-nullable-migration.command'; -import { MakeObjectMetadataUniversalIdentifierAndApplicationIdNotNullableMigrationCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-make-object-metadata-universal-identifier-and-application-id-not-nullable-migration.command'; -import { MakeRemainingEntitiesUniversalIdentifierAndApplicationIdNotNullableMigrationCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-make-remaining-entities-universal-identifier-and-application-id-not-nullable-migration.command'; -import { MakeRoleUniversalIdentifierAndApplicationIdNotNullableMigrationCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-make-role-universal-identifier-and-application-id-not-nullable-migration.command'; -import { MakeViewFieldUniversalIdentifierAndApplicationIdNotNullableMigrationCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-make-view-field-universal-identifier-and-application-id-not-nullable-migration.command'; -import { MakeViewFilterUniversalIdentifierAndApplicationIdNotNullableMigrationCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-make-view-filter-universal-identifier-and-application-id-not-nullable-migration.command'; -import { MakeViewGroupUniversalIdentifierAndApplicationIdNotNullableMigrationCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-make-view-group-universal-identifier-and-application-id-not-nullable-migration.command'; -import { MakeViewUniversalIdentifierAndApplicationIdNotNullableMigrationCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-make-view-universal-identifier-and-application-id-not-nullable-migration.command'; -import { UpdateTaskOnDeleteActionCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-update-task-on-delete-action.command'; -import { ApplicationModule } from 'src/engine/core-modules/application/application.module'; -import { FileEntity } from 'src/engine/core-modules/file/entities/file.entity'; -import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; -import { AgentEntity } from 'src/engine/metadata-modules/ai/ai-agent/entities/agent.entity'; -import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module'; -import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; -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 { IndexMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-metadata.entity'; -import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; -import { RoleEntity } from 'src/engine/metadata-modules/role/role.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'; -import { ViewGroupEntity } from 'src/engine/metadata-modules/view-group/entities/view-group.entity'; -import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity'; -import { GlobalWorkspaceDataSourceModule } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-datasource.module'; -import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache.module'; -import { TwentyStandardApplicationModule } from 'src/engine/workspace-manager/twenty-standard-application/twenty-standard-application.module'; -import { WorkspaceMigrationRunnerModule } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/workspace-migration-runner.module'; -import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace-migration/workspace-migration.module'; - -@Module({ - imports: [ - TypeOrmModule.forFeature([ - WorkspaceEntity, - AgentEntity, - FieldMetadataEntity, - IndexMetadataEntity, - ObjectMetadataEntity, - RoleEntity, - ViewEntity, - ViewFieldEntity, - ViewFilterEntity, - ViewGroupEntity, - FileEntity, - ]), - DataSourceModule, - WorkspaceCacheModule, - FieldMetadataModule, - ApplicationModule, - GlobalWorkspaceDataSourceModule, - TwentyStandardApplicationModule, - WorkspaceMigrationModule, - WorkspaceMigrationRunnerModule, - WorkspaceManyOrAllFlatEntityMapsCacheModule, - ], - providers: [ - UpdateTaskOnDeleteActionCommand, - BackfillOpportunityOwnerFieldCommand, - BackfillStandardPageLayoutsCommand, - DeleteFileRecordsCommand, - IdentifyAgentMetadataCommand, - IdentifyFieldMetadataCommand, - IdentifyIndexMetadataCommand, - IdentifyObjectMetadataCommand, - IdentifyRoleMetadataCommand, - IdentifyViewMetadataCommand, - IdentifyViewFieldMetadataCommand, - IdentifyViewFilterMetadataCommand, - MakeAgentUniversalIdentifierAndApplicationIdNotNullableMigrationCommand, - IdentifyViewGroupMetadataCommand, - MakeFieldMetadataUniversalIdentifierAndApplicationIdNotNullableMigrationCommand, - MakeObjectMetadataUniversalIdentifierAndApplicationIdNotNullableMigrationCommand, - MakeRoleUniversalIdentifierAndApplicationIdNotNullableMigrationCommand, - MakeViewUniversalIdentifierAndApplicationIdNotNullableMigrationCommand, - MakeViewFieldUniversalIdentifierAndApplicationIdNotNullableMigrationCommand, - MakeViewFilterUniversalIdentifierAndApplicationIdNotNullableMigrationCommand, - MakeViewGroupUniversalIdentifierAndApplicationIdNotNullableMigrationCommand, - MakeIndexMetadataUniversalIdentifierAndApplicationIdNotNullableMigrationCommand, - MakeRemainingEntitiesUniversalIdentifierAndApplicationIdNotNullableMigrationCommand, - IdentifyRemainingEntitiesMetadataCommand, - FlushV2CacheAndIncrementMetadataVersionCommand, - ], - exports: [ - UpdateTaskOnDeleteActionCommand, - BackfillOpportunityOwnerFieldCommand, - BackfillStandardPageLayoutsCommand, - DeleteFileRecordsCommand, - IdentifyAgentMetadataCommand, - IdentifyFieldMetadataCommand, - IdentifyIndexMetadataCommand, - IdentifyObjectMetadataCommand, - IdentifyRoleMetadataCommand, - IdentifyViewMetadataCommand, - IdentifyViewFieldMetadataCommand, - IdentifyViewFilterMetadataCommand, - MakeAgentUniversalIdentifierAndApplicationIdNotNullableMigrationCommand, - IdentifyViewGroupMetadataCommand, - MakeFieldMetadataUniversalIdentifierAndApplicationIdNotNullableMigrationCommand, - MakeObjectMetadataUniversalIdentifierAndApplicationIdNotNullableMigrationCommand, - MakeRoleUniversalIdentifierAndApplicationIdNotNullableMigrationCommand, - MakeViewUniversalIdentifierAndApplicationIdNotNullableMigrationCommand, - MakeViewFieldUniversalIdentifierAndApplicationIdNotNullableMigrationCommand, - MakeViewFilterUniversalIdentifierAndApplicationIdNotNullableMigrationCommand, - MakeViewGroupUniversalIdentifierAndApplicationIdNotNullableMigrationCommand, - MakeIndexMetadataUniversalIdentifierAndApplicationIdNotNullableMigrationCommand, - MakeRemainingEntitiesUniversalIdentifierAndApplicationIdNotNullableMigrationCommand, - IdentifyRemainingEntitiesMetadataCommand, - FlushV2CacheAndIncrementMetadataVersionCommand, - ], -}) -export class V1_16_UpgradeVersionCommandModule {} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/constants/standard-index-field-names.constant.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/constants/standard-index-field-names.constant.ts deleted file mode 100644 index e7fa7fa7fc..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/constants/standard-index-field-names.constant.ts +++ /dev/null @@ -1,299 +0,0 @@ -import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; - -// Maps indexName to its related field universal identifiers for each standard object -export const STANDARD_INDEX_FIELD_UNIVERSAL_IDENTIFIERS: Record< - string, - Record -> = { - attachment: { - taskIdIndex: [ - STANDARD_OBJECTS.attachment.fields.targetTask.universalIdentifier, - ], - noteIdIndex: [ - STANDARD_OBJECTS.attachment.fields.targetNote.universalIdentifier, - ], - personIdIndex: [ - STANDARD_OBJECTS.attachment.fields.targetPerson.universalIdentifier, - ], - companyIdIndex: [ - STANDARD_OBJECTS.attachment.fields.targetCompany.universalIdentifier, - ], - opportunityIdIndex: [ - STANDARD_OBJECTS.attachment.fields.targetOpportunity.universalIdentifier, - ], - dashboardIdIndex: [ - STANDARD_OBJECTS.attachment.fields.targetDashboard.universalIdentifier, - ], - workflowIdIndex: [ - STANDARD_OBJECTS.attachment.fields.targetWorkflow.universalIdentifier, - ], - }, - blocklist: { - workspaceMemberIdIndex: [ - STANDARD_OBJECTS.blocklist.fields.workspaceMember.universalIdentifier, - ], - }, - calendarChannelEventAssociation: { - calendarChannelIdIndex: [ - STANDARD_OBJECTS.calendarChannelEventAssociation.fields.calendarChannel - .universalIdentifier, - ], - calendarEventIdIndex: [ - STANDARD_OBJECTS.calendarChannelEventAssociation.fields.calendarEvent - .universalIdentifier, - ], - }, - calendarChannel: { - connectedAccountIdIndex: [ - STANDARD_OBJECTS.calendarChannel.fields.connectedAccount - .universalIdentifier, - ], - }, - calendarEventParticipant: { - calendarEventIdIndex: [ - STANDARD_OBJECTS.calendarEventParticipant.fields.calendarEvent - .universalIdentifier, - ], - personIdIndex: [ - STANDARD_OBJECTS.calendarEventParticipant.fields.person - .universalIdentifier, - ], - workspaceMemberIdIndex: [ - STANDARD_OBJECTS.calendarEventParticipant.fields.workspaceMember - .universalIdentifier, - ], - }, - company: { - accountOwnerIdIndex: [ - STANDARD_OBJECTS.company.fields.accountOwner.universalIdentifier, - ], - domainNameUniqueIndex: [ - STANDARD_OBJECTS.company.fields.domainName.universalIdentifier, - ], - searchVectorGinIndex: [ - STANDARD_OBJECTS.company.fields.searchVector.universalIdentifier, - ], - }, - connectedAccount: { - accountOwnerIdIndex: [ - STANDARD_OBJECTS.connectedAccount.fields.accountOwner.universalIdentifier, - ], - }, - dashboard: { - searchVectorGinIndex: [ - STANDARD_OBJECTS.dashboard.fields.searchVector.universalIdentifier, - ], - }, - favorite: { - forWorkspaceMemberIdIndex: [ - STANDARD_OBJECTS.favorite.fields.forWorkspaceMember.universalIdentifier, - ], - personIdIndex: [ - STANDARD_OBJECTS.favorite.fields.person.universalIdentifier, - ], - companyIdIndex: [ - STANDARD_OBJECTS.favorite.fields.company.universalIdentifier, - ], - favoriteFolderIdIndex: [ - STANDARD_OBJECTS.favorite.fields.favoriteFolder.universalIdentifier, - ], - opportunityIdIndex: [ - STANDARD_OBJECTS.favorite.fields.opportunity.universalIdentifier, - ], - workflowIdIndex: [ - STANDARD_OBJECTS.favorite.fields.workflow.universalIdentifier, - ], - workflowVersionIdIndex: [ - STANDARD_OBJECTS.favorite.fields.workflowVersion.universalIdentifier, - ], - workflowRunIdIndex: [ - STANDARD_OBJECTS.favorite.fields.workflowRun.universalIdentifier, - ], - taskIdIndex: [STANDARD_OBJECTS.favorite.fields.task.universalIdentifier], - noteIdIndex: [STANDARD_OBJECTS.favorite.fields.note.universalIdentifier], - dashboardIdIndex: [ - STANDARD_OBJECTS.favorite.fields.dashboard.universalIdentifier, - ], - }, - messageChannelMessageAssociation: { - messageChannelIdIndex: [ - STANDARD_OBJECTS.messageChannelMessageAssociation.fields.messageChannel - .universalIdentifier, - ], - messageIdIndex: [ - STANDARD_OBJECTS.messageChannelMessageAssociation.fields.message - .universalIdentifier, - ], - messageChannelIdMessageIdUniqueIndex: [ - STANDARD_OBJECTS.messageChannelMessageAssociation.fields.messageChannel - .universalIdentifier, - STANDARD_OBJECTS.messageChannelMessageAssociation.fields.message - .universalIdentifier, - ], - }, - messageChannel: { - connectedAccountIdIndex: [ - STANDARD_OBJECTS.messageChannel.fields.connectedAccount - .universalIdentifier, - ], - }, - messageFolder: { - messageChannelIdIndex: [ - STANDARD_OBJECTS.messageFolder.fields.messageChannel.universalIdentifier, - ], - }, - messageParticipant: { - messageIdIndex: [ - STANDARD_OBJECTS.messageParticipant.fields.message.universalIdentifier, - ], - personIdIndex: [ - STANDARD_OBJECTS.messageParticipant.fields.person.universalIdentifier, - ], - workspaceMemberIdIndex: [ - STANDARD_OBJECTS.messageParticipant.fields.workspaceMember - .universalIdentifier, - ], - }, - message: { - messageThreadIdIndex: [ - STANDARD_OBJECTS.message.fields.messageThread.universalIdentifier, - ], - }, - note: { - searchVectorGinIndex: [ - STANDARD_OBJECTS.note.fields.searchVector.universalIdentifier, - ], - }, - noteTarget: { - noteIdIndex: [STANDARD_OBJECTS.noteTarget.fields.note.universalIdentifier], - personIdIndex: [ - STANDARD_OBJECTS.noteTarget.fields.person.universalIdentifier, - ], - companyIdIndex: [ - STANDARD_OBJECTS.noteTarget.fields.company.universalIdentifier, - ], - opportunityIdIndex: [ - STANDARD_OBJECTS.noteTarget.fields.opportunity.universalIdentifier, - ], - }, - opportunity: { - pointOfContactIdIndex: [ - STANDARD_OBJECTS.opportunity.fields.pointOfContact.universalIdentifier, - ], - companyIdIndex: [ - STANDARD_OBJECTS.opportunity.fields.company.universalIdentifier, - ], - stageIndex: [STANDARD_OBJECTS.opportunity.fields.stage.universalIdentifier], - searchVectorGinIndex: [ - STANDARD_OBJECTS.opportunity.fields.searchVector.universalIdentifier, - ], - }, - person: { - companyIdIndex: [ - STANDARD_OBJECTS.person.fields.company.universalIdentifier, - ], - emailsUniqueIndex: [ - STANDARD_OBJECTS.person.fields.emails.universalIdentifier, - ], - searchVectorGinIndex: [ - STANDARD_OBJECTS.person.fields.searchVector.universalIdentifier, - ], - }, - task: { - assigneeIdIndex: [ - STANDARD_OBJECTS.task.fields.assignee.universalIdentifier, - ], - searchVectorGinIndex: [ - STANDARD_OBJECTS.task.fields.searchVector.universalIdentifier, - ], - }, - taskTarget: { - taskIdIndex: [STANDARD_OBJECTS.taskTarget.fields.task.universalIdentifier], - personIdIndex: [ - STANDARD_OBJECTS.taskTarget.fields.person.universalIdentifier, - ], - companyIdIndex: [ - STANDARD_OBJECTS.taskTarget.fields.company.universalIdentifier, - ], - opportunityIdIndex: [ - STANDARD_OBJECTS.taskTarget.fields.opportunity.universalIdentifier, - ], - }, - timelineActivity: { - workspaceMemberIdIndex: [ - STANDARD_OBJECTS.timelineActivity.fields.workspaceMember - .universalIdentifier, - ], - personIdIndex: [ - STANDARD_OBJECTS.timelineActivity.fields.targetPerson.universalIdentifier, - ], - companyIdIndex: [ - STANDARD_OBJECTS.timelineActivity.fields.targetCompany - .universalIdentifier, - ], - opportunityIdIndex: [ - STANDARD_OBJECTS.timelineActivity.fields.targetOpportunity - .universalIdentifier, - ], - noteIdIndex: [ - STANDARD_OBJECTS.timelineActivity.fields.targetNote.universalIdentifier, - ], - taskIdIndex: [ - STANDARD_OBJECTS.timelineActivity.fields.targetTask.universalIdentifier, - ], - workflowIdIndex: [ - STANDARD_OBJECTS.timelineActivity.fields.targetWorkflow - .universalIdentifier, - ], - workflowVersionIdIndex: [ - STANDARD_OBJECTS.timelineActivity.fields.targetWorkflowVersion - .universalIdentifier, - ], - workflowRunIdIndex: [ - STANDARD_OBJECTS.timelineActivity.fields.targetWorkflowRun - .universalIdentifier, - ], - dashboardIdIndex: [ - STANDARD_OBJECTS.timelineActivity.fields.targetDashboard - .universalIdentifier, - ], - }, - workflow: { - searchVectorGinIndex: [ - STANDARD_OBJECTS.workflow.fields.searchVector.universalIdentifier, - ], - }, - workflowAutomatedTrigger: { - workflowIdIndex: [ - STANDARD_OBJECTS.workflowAutomatedTrigger.fields.workflow - .universalIdentifier, - ], - }, - workflowRun: { - workflowVersionIdIndex: [ - STANDARD_OBJECTS.workflowRun.fields.workflowVersion.universalIdentifier, - ], - workflowIdIndex: [ - STANDARD_OBJECTS.workflowRun.fields.workflow.universalIdentifier, - ], - searchVectorGinIndex: [ - STANDARD_OBJECTS.workflowRun.fields.searchVector.universalIdentifier, - ], - }, - workflowVersion: { - workflowIdIndex: [ - STANDARD_OBJECTS.workflowVersion.fields.workflow.universalIdentifier, - ], - searchVectorGinIndex: [ - STANDARD_OBJECTS.workflowVersion.fields.searchVector.universalIdentifier, - ], - }, - workspaceMember: { - userEmailUniqueIndex: [ - STANDARD_OBJECTS.workspaceMember.fields.userEmail.universalIdentifier, - ], - searchVectorGinIndex: [ - STANDARD_OBJECTS.workspaceMember.fields.searchVector.universalIdentifier, - ], - }, -}; diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/utils/compute-formatted-view-name.util.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/utils/compute-formatted-view-name.util.ts deleted file mode 100644 index cd1e87208f..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/utils/compute-formatted-view-name.util.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { capitalize, uncapitalize } from 'twenty-shared/utils'; - -import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type'; - -export const ALL_ENTITY_VIEW_NAME = 'All {objectLabelPlural}'; - -export const computeFormattedViewName = ({ - viewName, - flatObjectMetadata, -}: { - viewName: string; - flatObjectMetadata: FlatObjectMetadata; -}) => - viewName === ALL_ENTITY_VIEW_NAME - ? `all${capitalize(flatObjectMetadata.namePlural)}` - : uncapitalize(viewName.split(' ').map(capitalize).join('')); diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/utils/update-standard-page-layout-widgets-with-workspace-field-ids.util.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/utils/update-standard-page-layout-widgets-with-workspace-field-ids.util.ts deleted file mode 100644 index 9038587430..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/utils/update-standard-page-layout-widgets-with-workspace-field-ids.util.ts +++ /dev/null @@ -1,422 +0,0 @@ -import { isDefined, type RecordFilter } from 'twenty-shared/utils'; - -import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type'; -import { findFlatEntityByUniversalIdentifierOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-universal-identifier-or-throw.util'; -import { replaceFlatEntityInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/replace-flat-entity-in-flat-entity-maps-or-throw.util'; -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 { type FlatPageLayoutWidget } from 'src/engine/metadata-modules/flat-page-layout-widget/types/flat-page-layout-widget.type'; -import { isFlatPageLayoutWidgetConfigurationOfType } from 'src/engine/metadata-modules/flat-page-layout-widget/utils/is-flat-page-layout-widget-configuration-of-type.util'; -import { WidgetConfigurationType } from 'src/engine/metadata-modules/page-layout-widget/enums/widget-configuration-type.type'; -import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; -import { STANDARD_PAGE_LAYOUTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-page-layout.constant'; - -type UpdateStandardPageLayoutWidgetsArgs = { - flatFieldMetadataMaps: FlatEntityMaps; - flatObjectMetadataMaps: FlatEntityMaps; - flatPageLayoutWidgetMaps: FlatEntityMaps; -}; - -const findWidgetByUniversalIdentifierOrThrow = < - T extends WidgetConfigurationType, ->({ - flatPageLayoutWidgetMaps, - universalIdentifier, - widgetDescription, - expectedConfigurationType, -}: { - flatPageLayoutWidgetMaps: FlatEntityMaps; - universalIdentifier: string; - widgetDescription: string; - expectedConfigurationType: T; -}): FlatPageLayoutWidget => { - const flatPageLayoutWidget = findFlatEntityByUniversalIdentifierOrThrow({ - flatEntityMaps: flatPageLayoutWidgetMaps, - universalIdentifier, - }); - - if ( - !isFlatPageLayoutWidgetConfigurationOfType( - flatPageLayoutWidget, - expectedConfigurationType, - ) - ) { - throw new Error( - `Widget ${widgetDescription} has unexpected configuration type ${flatPageLayoutWidget.configuration.configurationType}, expected ${expectedConfigurationType}`, - ); - } - - return flatPageLayoutWidget; -}; - -// Widget updater: dealsByCompany (PIE_CHART) -const updateDealsByCompanyWidget = ({ - flatFieldMetadataMaps, - flatObjectMetadataMaps, - flatPageLayoutWidgetMaps, -}: UpdateStandardPageLayoutWidgetsArgs): FlatEntityMaps => { - const opportunityIdField = findFlatEntityByUniversalIdentifierOrThrow({ - flatEntityMaps: flatFieldMetadataMaps, - universalIdentifier: - STANDARD_OBJECTS.opportunity.fields.id.universalIdentifier, - }); - - const opportunityCompanyField = findFlatEntityByUniversalIdentifierOrThrow({ - flatEntityMaps: flatFieldMetadataMaps, - universalIdentifier: - STANDARD_OBJECTS.opportunity.fields.company.universalIdentifier, - }); - - const opportunityObject = findFlatEntityByUniversalIdentifierOrThrow({ - flatEntityMaps: flatObjectMetadataMaps, - universalIdentifier: STANDARD_OBJECTS.opportunity.universalIdentifier, - }); - - const widget = findWidgetByUniversalIdentifierOrThrow({ - flatPageLayoutWidgetMaps, - universalIdentifier: - STANDARD_PAGE_LAYOUTS.myFirstDashboard.tabs.tab1.widgets.dealsByCompany - .universalIdentifier, - widgetDescription: 'dealsByCompany', - expectedConfigurationType: WidgetConfigurationType.PIE_CHART, - }); - - const updatedWidget: FlatPageLayoutWidget = - { - ...widget, - objectMetadataId: opportunityObject.id, - configuration: { - ...widget.configuration, - aggregateFieldMetadataId: opportunityIdField.id, - groupByFieldMetadataId: opportunityCompanyField.id, - }, - }; - - return replaceFlatEntityInFlatEntityMapsOrThrow({ - flatEntity: updatedWidget, - flatEntityMaps: flatPageLayoutWidgetMaps, - }); -}; - -// Widget updater: pipelineValueByStage (BAR_CHART) -const updatePipelineValueByStageWidget = ({ - flatFieldMetadataMaps, - flatObjectMetadataMaps, - flatPageLayoutWidgetMaps, -}: UpdateStandardPageLayoutWidgetsArgs): FlatEntityMaps => { - const opportunityAmountField = findFlatEntityByUniversalIdentifierOrThrow({ - flatEntityMaps: flatFieldMetadataMaps, - universalIdentifier: - STANDARD_OBJECTS.opportunity.fields.amount.universalIdentifier, - }); - - const opportunityStageField = findFlatEntityByUniversalIdentifierOrThrow({ - flatEntityMaps: flatFieldMetadataMaps, - universalIdentifier: - STANDARD_OBJECTS.opportunity.fields.stage.universalIdentifier, - }); - - const opportunityCompanyField = findFlatEntityByUniversalIdentifierOrThrow({ - flatEntityMaps: flatFieldMetadataMaps, - universalIdentifier: - STANDARD_OBJECTS.opportunity.fields.company.universalIdentifier, - }); - - const opportunityObject = findFlatEntityByUniversalIdentifierOrThrow({ - flatEntityMaps: flatObjectMetadataMaps, - universalIdentifier: STANDARD_OBJECTS.opportunity.universalIdentifier, - }); - - const widget = findWidgetByUniversalIdentifierOrThrow({ - flatPageLayoutWidgetMaps, - universalIdentifier: - STANDARD_PAGE_LAYOUTS.myFirstDashboard.tabs.tab1.widgets - .pipelineValueByStage.universalIdentifier, - widgetDescription: 'pipelineValueByStage', - expectedConfigurationType: WidgetConfigurationType.BAR_CHART, - }); - - const updatedWidget: FlatPageLayoutWidget = - { - ...widget, - objectMetadataId: opportunityObject.id, - configuration: { - ...widget.configuration, - aggregateFieldMetadataId: opportunityAmountField.id, - primaryAxisGroupByFieldMetadataId: opportunityStageField.id, - secondaryAxisGroupByFieldMetadataId: opportunityCompanyField.id, - }, - }; - - return replaceFlatEntityInFlatEntityMapsOrThrow({ - flatEntity: updatedWidget, - flatEntityMaps: flatPageLayoutWidgetMaps, - }); -}; - -// Widget updater: revenueTimeline (LINE_CHART) -const updateRevenueTimelineWidget = ({ - flatFieldMetadataMaps, - flatObjectMetadataMaps, - flatPageLayoutWidgetMaps, -}: UpdateStandardPageLayoutWidgetsArgs): FlatEntityMaps => { - const opportunityAmountField = findFlatEntityByUniversalIdentifierOrThrow({ - flatEntityMaps: flatFieldMetadataMaps, - universalIdentifier: - STANDARD_OBJECTS.opportunity.fields.amount.universalIdentifier, - }); - - const opportunityCloseDateField = findFlatEntityByUniversalIdentifierOrThrow({ - flatEntityMaps: flatFieldMetadataMaps, - universalIdentifier: - STANDARD_OBJECTS.opportunity.fields.closeDate.universalIdentifier, - }); - - const opportunityObject = findFlatEntityByUniversalIdentifierOrThrow({ - flatEntityMaps: flatObjectMetadataMaps, - universalIdentifier: STANDARD_OBJECTS.opportunity.universalIdentifier, - }); - - const widget = findWidgetByUniversalIdentifierOrThrow({ - flatPageLayoutWidgetMaps, - universalIdentifier: - STANDARD_PAGE_LAYOUTS.myFirstDashboard.tabs.tab1.widgets.revenueTimeline - .universalIdentifier, - widgetDescription: 'revenueTimeline', - expectedConfigurationType: WidgetConfigurationType.LINE_CHART, - }); - - const updatedWidget: FlatPageLayoutWidget = - { - ...widget, - objectMetadataId: opportunityObject.id, - configuration: { - ...widget.configuration, - aggregateFieldMetadataId: opportunityAmountField.id, - primaryAxisGroupByFieldMetadataId: opportunityCloseDateField.id, - }, - }; - - return replaceFlatEntityInFlatEntityMapsOrThrow({ - flatEntity: updatedWidget, - flatEntityMaps: flatPageLayoutWidgetMaps, - }); -}; - -// Widget updater: opportunitiesByOwner (BAR_CHART) -const updateOpportunitiesByOwnerWidget = ({ - flatFieldMetadataMaps, - flatObjectMetadataMaps, - flatPageLayoutWidgetMaps, -}: UpdateStandardPageLayoutWidgetsArgs): FlatEntityMaps => { - const opportunityIdField = findFlatEntityByUniversalIdentifierOrThrow({ - flatEntityMaps: flatFieldMetadataMaps, - universalIdentifier: - STANDARD_OBJECTS.opportunity.fields.id.universalIdentifier, - }); - - const opportunityOwnerField = findFlatEntityByUniversalIdentifierOrThrow({ - flatEntityMaps: flatFieldMetadataMaps, - universalIdentifier: - STANDARD_OBJECTS.opportunity.fields.owner.universalIdentifier, - }); - - const opportunityObject = findFlatEntityByUniversalIdentifierOrThrow({ - flatEntityMaps: flatObjectMetadataMaps, - universalIdentifier: STANDARD_OBJECTS.opportunity.universalIdentifier, - }); - - const widget = findWidgetByUniversalIdentifierOrThrow({ - flatPageLayoutWidgetMaps, - universalIdentifier: - STANDARD_PAGE_LAYOUTS.myFirstDashboard.tabs.tab1.widgets - .opportunitiesByOwner.universalIdentifier, - widgetDescription: 'opportunitiesByOwner', - expectedConfigurationType: WidgetConfigurationType.BAR_CHART, - }); - - const updatedWidget: FlatPageLayoutWidget = - { - ...widget, - objectMetadataId: opportunityObject.id, - configuration: { - ...widget.configuration, - aggregateFieldMetadataId: opportunityIdField.id, - primaryAxisGroupByFieldMetadataId: opportunityOwnerField.id, - secondaryAxisGroupByFieldMetadataId: opportunityOwnerField.id, - }, - }; - - return replaceFlatEntityInFlatEntityMapsOrThrow({ - flatEntity: updatedWidget, - flatEntityMaps: flatPageLayoutWidgetMaps, - }); -}; - -// Widget updater: dealsCreatedThisMonth (AGGREGATE_CHART) -const updateDealsCreatedThisMonthWidget = ({ - flatFieldMetadataMaps, - flatObjectMetadataMaps, - flatPageLayoutWidgetMaps, -}: UpdateStandardPageLayoutWidgetsArgs): FlatEntityMaps => { - const opportunityIdField = findFlatEntityByUniversalIdentifierOrThrow({ - flatEntityMaps: flatFieldMetadataMaps, - universalIdentifier: - STANDARD_OBJECTS.opportunity.fields.id.universalIdentifier, - }); - - const opportunityCreatedAtField = findFlatEntityByUniversalIdentifierOrThrow({ - flatEntityMaps: flatFieldMetadataMaps, - universalIdentifier: - STANDARD_OBJECTS.opportunity.fields.createdAt.universalIdentifier, - }); - - const opportunityObject = findFlatEntityByUniversalIdentifierOrThrow({ - flatEntityMaps: flatObjectMetadataMaps, - universalIdentifier: STANDARD_OBJECTS.opportunity.universalIdentifier, - }); - - const widget = findWidgetByUniversalIdentifierOrThrow({ - flatPageLayoutWidgetMaps, - universalIdentifier: - STANDARD_PAGE_LAYOUTS.myFirstDashboard.tabs.tab1.widgets - .dealsCreatedThisMonth.universalIdentifier, - widgetDescription: 'dealsCreatedThisMonth', - expectedConfigurationType: WidgetConfigurationType.AGGREGATE_CHART, - }); - - const updatedRecordFilters = widget.configuration.filter?.recordFilters?.map( - (filter: RecordFilter) => ({ - ...filter, - fieldMetadataId: opportunityCreatedAtField.id, - }), - ); - - const updatedWidget: FlatPageLayoutWidget = - { - ...widget, - objectMetadataId: opportunityObject.id, - configuration: { - ...widget.configuration, - aggregateFieldMetadataId: opportunityIdField.id, - filter: isDefined(widget.configuration.filter) - ? { - ...widget.configuration.filter, - recordFilters: updatedRecordFilters, - } - : undefined, - }, - }; - - return replaceFlatEntityInFlatEntityMapsOrThrow({ - flatEntity: updatedWidget, - flatEntityMaps: flatPageLayoutWidgetMaps, - }); -}; - -// Widget updater: dealValueCreatedThisMonth (AGGREGATE_CHART) -const updateDealValueCreatedThisMonthWidget = ({ - flatFieldMetadataMaps, - flatObjectMetadataMaps, - flatPageLayoutWidgetMaps, -}: UpdateStandardPageLayoutWidgetsArgs): FlatEntityMaps => { - const opportunityAmountField = findFlatEntityByUniversalIdentifierOrThrow({ - flatEntityMaps: flatFieldMetadataMaps, - universalIdentifier: - STANDARD_OBJECTS.opportunity.fields.amount.universalIdentifier, - }); - - const opportunityCreatedAtField = findFlatEntityByUniversalIdentifierOrThrow({ - flatEntityMaps: flatFieldMetadataMaps, - universalIdentifier: - STANDARD_OBJECTS.opportunity.fields.createdAt.universalIdentifier, - }); - - const opportunityObject = findFlatEntityByUniversalIdentifierOrThrow({ - flatEntityMaps: flatObjectMetadataMaps, - universalIdentifier: STANDARD_OBJECTS.opportunity.universalIdentifier, - }); - - const widget = findWidgetByUniversalIdentifierOrThrow({ - flatPageLayoutWidgetMaps, - universalIdentifier: - STANDARD_PAGE_LAYOUTS.myFirstDashboard.tabs.tab1.widgets - .dealValueCreatedThisMonth.universalIdentifier, - widgetDescription: 'dealValueCreatedThisMonth', - expectedConfigurationType: WidgetConfigurationType.AGGREGATE_CHART, - }); - - const updatedRecordFilters = widget.configuration.filter?.recordFilters?.map( - (filter: RecordFilter) => ({ - ...filter, - fieldMetadataId: opportunityCreatedAtField.id, - }), - ); - - const updatedWidget: FlatPageLayoutWidget = - { - ...widget, - objectMetadataId: opportunityObject.id, - configuration: { - ...widget.configuration, - aggregateFieldMetadataId: opportunityAmountField.id, - filter: isDefined(widget.configuration.filter) - ? { - ...widget.configuration.filter, - recordFilters: updatedRecordFilters, - } - : undefined, - }, - }; - - return replaceFlatEntityInFlatEntityMapsOrThrow({ - flatEntity: updatedWidget, - flatEntityMaps: flatPageLayoutWidgetMaps, - }); -}; - -export const updateStandardPageLayoutWidgetsWithWorkspaceFieldIds = ({ - flatFieldMetadataMaps, - flatObjectMetadataMaps, - flatPageLayoutWidgetMaps, -}: UpdateStandardPageLayoutWidgetsArgs): FlatEntityMaps => { - let updatedMaps = flatPageLayoutWidgetMaps; - - updatedMaps = updateDealsByCompanyWidget({ - flatFieldMetadataMaps, - flatObjectMetadataMaps, - flatPageLayoutWidgetMaps: updatedMaps, - }); - - updatedMaps = updatePipelineValueByStageWidget({ - flatFieldMetadataMaps, - flatObjectMetadataMaps, - flatPageLayoutWidgetMaps: updatedMaps, - }); - - updatedMaps = updateRevenueTimelineWidget({ - flatFieldMetadataMaps, - flatObjectMetadataMaps, - flatPageLayoutWidgetMaps: updatedMaps, - }); - - updatedMaps = updateOpportunitiesByOwnerWidget({ - flatFieldMetadataMaps, - flatObjectMetadataMaps, - flatPageLayoutWidgetMaps: updatedMaps, - }); - - updatedMaps = updateDealsCreatedThisMonthWidget({ - flatFieldMetadataMaps, - flatObjectMetadataMaps, - flatPageLayoutWidgetMaps: updatedMaps, - }); - - updatedMaps = updateDealValueCreatedThisMonthWidget({ - flatFieldMetadataMaps, - flatObjectMetadataMaps, - flatPageLayoutWidgetMaps: updatedMaps, - }); - - return updatedMaps; -}; diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-delete-all-files.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-17/1-17-delete-all-files.command.ts similarity index 100% rename from packages/twenty-server/src/database/commands/upgrade-version-command/1-16/1-16-delete-all-files.command.ts rename to packages/twenty-server/src/database/commands/upgrade-version-command/1-17/1-17-delete-all-files.command.ts diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-17/1-17-upgrade-version-command.module.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-17/1-17-upgrade-version-command.module.ts index dcdbf3ca49..b932a72d56 100644 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-17/1-17-upgrade-version-command.module.ts +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/1-17/1-17-upgrade-version-command.module.ts @@ -1,7 +1,7 @@ import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; -import { DeleteFileRecordsCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-delete-all-files.command'; +import { DeleteFileRecordsCommand } from 'src/database/commands/upgrade-version-command/1-17/1-17-delete-all-files.command'; import { IdentifyWebhookMetadataCommand } from 'src/database/commands/upgrade-version-command/1-17/1-17-identify-webhook-metadata.command'; import { MakeWebhookUniversalIdentifierAndApplicationIdNotNullableMigrationCommand } from 'src/database/commands/upgrade-version-command/1-17/1-17-make-webhook-universal-identifier-and-application-id-not-nullable-migration.command'; import { MigrateAttachmentToMorphRelationsCommand } from 'src/database/commands/upgrade-version-command/1-17/1-17-migrate-attachment-to-morph-relations.command'; 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 6cfcea8aac..5e96efb297 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 @@ -1,10 +1,6 @@ import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; -import { V1_13_UpgradeVersionCommandModule } from 'src/database/commands/upgrade-version-command/1-13/1-13-upgrade-version-command.module'; -import { V1_14_UpgradeVersionCommandModule } from 'src/database/commands/upgrade-version-command/1-14/1-14-upgrade-version-command.module'; -import { V1_15_UpgradeVersionCommandModule } from 'src/database/commands/upgrade-version-command/1-15/1-15-upgrade-version-command.module'; -import { V1_16_UpgradeVersionCommandModule } from 'src/database/commands/upgrade-version-command/1-16/1-16-upgrade-version-command.module'; import { V1_17_UpgradeVersionCommandModule } from 'src/database/commands/upgrade-version-command/1-17/1-17-upgrade-version-command.module'; import { UpgradeCommand } from 'src/database/commands/upgrade-version-command/upgrade.command'; import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; @@ -13,10 +9,6 @@ import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-s @Module({ imports: [ TypeOrmModule.forFeature([WorkspaceEntity]), - V1_13_UpgradeVersionCommandModule, - V1_14_UpgradeVersionCommandModule, - V1_15_UpgradeVersionCommandModule, - V1_16_UpgradeVersionCommandModule, V1_17_UpgradeVersionCommandModule, DataSourceModule, ], 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 7e09940a96..401cf56645 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 @@ -9,44 +9,7 @@ import { UpgradeCommandRunner, type VersionCommands, } from 'src/database/commands/command-runners/upgrade.command-runner'; -import { BackfillPageLayoutUniversalIdentifiersCommand } from 'src/database/commands/upgrade-version-command/1-13/1-13-backfill-page-layout-universal-identifiers.command'; -import { CleanEmptyStringNullInTextFieldsCommand } from 'src/database/commands/upgrade-version-command/1-13/1-13-clean-empty-string-null-in-text-fields.command'; -import { DeduplicateRoleTargetsCommand } from 'src/database/commands/upgrade-version-command/1-13/1-13-deduplicate-role-targets.command'; -import { MigrateStandardInvalidEntitiesCommand } from 'src/database/commands/upgrade-version-command/1-13/1-13-migrate-standard-invalid-entities.command'; -import { MigrateTimelineActivityToMorphRelationsCommand } from 'src/database/commands/upgrade-version-command/1-13/1-13-migrate-timeline-activity-to-morph-relations.command'; -import { RenameIndexNameCommand } from 'src/database/commands/upgrade-version-command/1-13/1-13-rename-index.command'; -import { UpdateRoleTargetsUniqueConstraintMigrationCommand } from 'src/database/commands/upgrade-version-command/1-13/1-13-update-role-targets-unique-constraint-migration.command'; -import { DeleteRemovedAgentsCommand } from 'src/database/commands/upgrade-version-command/1-14/1-14-delete-removed-agents.command'; -import { UpdateCreatedByEnumCommand } from 'src/database/commands/upgrade-version-command/1-14/1-14-update-created-by-enum.command'; -import { AddWorkspaceForeignKeysMigrationCommand } from 'src/database/commands/upgrade-version-command/1-15/1-15-add-workspace-foreign-keys-migration.command'; -import { BackfillUpdatedByFieldCommand } from 'src/database/commands/upgrade-version-command/1-15/1-15-backfill-updated-by-field.command'; -import { FixNanPositionValuesInNotesCommand } from 'src/database/commands/upgrade-version-command/1-15/1-15-fix-nan-position-values-in-notes.command'; -import { MigratePageLayoutWidgetConfigurationCommand } from 'src/database/commands/upgrade-version-command/1-15/1-15-migrate-page-layout-widget-configuration.command'; -import { BackfillOpportunityOwnerFieldCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-backfill-opportunity-owner-field.command'; -import { BackfillStandardPageLayoutsCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-backfill-standard-page-layouts.command'; -import { DeleteFileRecordsCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-delete-all-files.command'; -import { FlushV2CacheAndIncrementMetadataVersionCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-flush-v2-cache-and-increment-metadata-version.command'; -import { IdentifyAgentMetadataCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-identify-agent-metadata.command'; -import { IdentifyFieldMetadataCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-identify-field-metadata.command'; -import { IdentifyIndexMetadataCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-identify-index-metadata.command'; -import { IdentifyObjectMetadataCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-identify-object-metadata.command'; -import { IdentifyRemainingEntitiesMetadataCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-identify-remaining-entities-metadata.command'; -import { IdentifyRoleMetadataCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-identify-role-metadata.command'; -import { IdentifyViewFieldMetadataCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-identify-view-field-metadata.command'; -import { IdentifyViewFilterMetadataCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-identify-view-filter-metadata.command'; -import { IdentifyViewGroupMetadataCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-identify-view-group-metadata.command'; -import { IdentifyViewMetadataCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-identify-view-metadata.command'; -import { MakeAgentUniversalIdentifierAndApplicationIdNotNullableMigrationCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-make-agent-universal-identifier-and-application-id-not-nullable-migration.command'; -import { MakeFieldMetadataUniversalIdentifierAndApplicationIdNotNullableMigrationCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-make-field-metadata-universal-identifier-and-application-id-not-nullable-migration.command'; -import { MakeIndexMetadataUniversalIdentifierAndApplicationIdNotNullableMigrationCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-make-index-metadata-universal-identifier-and-application-id-not-nullable-migration.command'; -import { MakeObjectMetadataUniversalIdentifierAndApplicationIdNotNullableMigrationCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-make-object-metadata-universal-identifier-and-application-id-not-nullable-migration.command'; -import { MakeRemainingEntitiesUniversalIdentifierAndApplicationIdNotNullableMigrationCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-make-remaining-entities-universal-identifier-and-application-id-not-nullable-migration.command'; -import { MakeRoleUniversalIdentifierAndApplicationIdNotNullableMigrationCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-make-role-universal-identifier-and-application-id-not-nullable-migration.command'; -import { MakeViewFieldUniversalIdentifierAndApplicationIdNotNullableMigrationCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-make-view-field-universal-identifier-and-application-id-not-nullable-migration.command'; -import { MakeViewFilterUniversalIdentifierAndApplicationIdNotNullableMigrationCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-make-view-filter-universal-identifier-and-application-id-not-nullable-migration.command'; -import { MakeViewGroupUniversalIdentifierAndApplicationIdNotNullableMigrationCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-make-view-group-universal-identifier-and-application-id-not-nullable-migration.command'; -import { MakeViewUniversalIdentifierAndApplicationIdNotNullableMigrationCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-make-view-universal-identifier-and-application-id-not-nullable-migration.command'; -import { UpdateTaskOnDeleteActionCommand } from 'src/database/commands/upgrade-version-command/1-16/1-16-update-task-on-delete-action.command'; +import { DeleteFileRecordsCommand } from 'src/database/commands/upgrade-version-command/1-17/1-17-delete-all-files.command'; import { IdentifyWebhookMetadataCommand } from 'src/database/commands/upgrade-version-command/1-17/1-17-identify-webhook-metadata.command'; import { MakeWebhookUniversalIdentifierAndApplicationIdNotNullableMigrationCommand } from 'src/database/commands/upgrade-version-command/1-17/1-17-make-webhook-universal-identifier-and-application-id-not-nullable-migration.command'; import { MigrateAttachmentToMorphRelationsCommand } from 'src/database/commands/upgrade-version-command/1-17/1-17-migrate-attachment-to-morph-relations.command'; @@ -69,53 +32,8 @@ export class UpgradeCommand extends UpgradeCommandRunner { protected readonly globalWorkspaceOrmManager: GlobalWorkspaceOrmManager, protected readonly dataSourceService: DataSourceService, - // 1.13 Commands - protected readonly migrateTimelineActivityToMorphRelationsCommand: MigrateTimelineActivityToMorphRelationsCommand, - protected readonly deduplicateRoleTargetsCommand: DeduplicateRoleTargetsCommand, - protected readonly updateRoleTargetsUniqueConstraintMigrationCommand: UpdateRoleTargetsUniqueConstraintMigrationCommand, - protected readonly backfillPageLayoutUniversalIdentifiersCommand: BackfillPageLayoutUniversalIdentifiersCommand, - protected readonly migrateStandardInvalidEntitiesCommand: MigrateStandardInvalidEntitiesCommand, - protected readonly cleanEmptyStringNullInTextFieldsCommand: CleanEmptyStringNullInTextFieldsCommand, - protected readonly renameIndexNameCommand: RenameIndexNameCommand, - - // 1.14 Commands - protected readonly updateCreatedByEnumCommand: UpdateCreatedByEnumCommand, - protected readonly deleteRemovedAgentsCommand: DeleteRemovedAgentsCommand, - - // 1.15 Commands - protected readonly migratePageLayoutWidgetConfigurationCommand: MigratePageLayoutWidgetConfigurationCommand, - protected readonly fixNanPositionValuesInNotesCommand: FixNanPositionValuesInNotesCommand, - protected readonly backfillUpdatedByFieldCommand: BackfillUpdatedByFieldCommand, - protected readonly addWorkspaceForeignKeysMigrationCommand: AddWorkspaceForeignKeysMigrationCommand, - - // 1.16 Commands - protected readonly updateTaskOnDeleteActionCommand: UpdateTaskOnDeleteActionCommand, - protected readonly backfillOpportunityOwnerFieldCommand: BackfillOpportunityOwnerFieldCommand, - protected readonly backfillStandardPageLayoutsCommand: BackfillStandardPageLayoutsCommand, - protected readonly identifyAgentMetadataCommand: IdentifyAgentMetadataCommand, - protected readonly identifyFieldMetadataCommand: IdentifyFieldMetadataCommand, - protected readonly identifyIndexMetadataCommand: IdentifyIndexMetadataCommand, - protected readonly identifyObjectMetadataCommand: IdentifyObjectMetadataCommand, - protected readonly identifyRoleMetadataCommand: IdentifyRoleMetadataCommand, - protected readonly identifyViewMetadataCommand: IdentifyViewMetadataCommand, - protected readonly identifyViewFieldMetadataCommand: IdentifyViewFieldMetadataCommand, - protected readonly identifyViewFilterMetadataCommand: IdentifyViewFilterMetadataCommand, - protected readonly makeAgentUniversalIdentifierAndApplicationIdNotNullableMigrationCommand: MakeAgentUniversalIdentifierAndApplicationIdNotNullableMigrationCommand, - protected readonly identifyViewGroupMetadataCommand: IdentifyViewGroupMetadataCommand, - protected readonly makeFieldMetadataUniversalIdentifierAndApplicationIdNotNullableMigrationCommand: MakeFieldMetadataUniversalIdentifierAndApplicationIdNotNullableMigrationCommand, - protected readonly makeObjectMetadataUniversalIdentifierAndApplicationIdNotNullableMigrationCommand: MakeObjectMetadataUniversalIdentifierAndApplicationIdNotNullableMigrationCommand, - protected readonly makeRoleUniversalIdentifierAndApplicationIdNotNullableMigrationCommand: MakeRoleUniversalIdentifierAndApplicationIdNotNullableMigrationCommand, - protected readonly makeViewUniversalIdentifierAndApplicationIdNotNullableMigrationCommand: MakeViewUniversalIdentifierAndApplicationIdNotNullableMigrationCommand, - protected readonly makeViewFieldUniversalIdentifierAndApplicationIdNotNullableMigrationCommand: MakeViewFieldUniversalIdentifierAndApplicationIdNotNullableMigrationCommand, - protected readonly makeViewFilterUniversalIdentifierAndApplicationIdNotNullableMigrationCommand: MakeViewFilterUniversalIdentifierAndApplicationIdNotNullableMigrationCommand, - protected readonly makeViewGroupUniversalIdentifierAndApplicationIdNotNullableMigrationCommand: MakeViewGroupUniversalIdentifierAndApplicationIdNotNullableMigrationCommand, - protected readonly makeIndexMetadataUniversalIdentifierAndApplicationIdNotNullableMigrationCommand: MakeIndexMetadataUniversalIdentifierAndApplicationIdNotNullableMigrationCommand, - protected readonly identifyRemainingEntitiesMetadataCommand: IdentifyRemainingEntitiesMetadataCommand, - protected readonly makeRemainingEntitiesUniversalIdentifierAndApplicationIdNotNullableMigrationCommand: MakeRemainingEntitiesUniversalIdentifierAndApplicationIdNotNullableMigrationCommand, - protected readonly flushV2CacheAndIncrementMetadataVersionCommand: FlushV2CacheAndIncrementMetadataVersionCommand, - protected readonly deleteFileRecordsCommand: DeleteFileRecordsCommand, - // 1.17 Commands + protected readonly deleteFileRecordsCommand: DeleteFileRecordsCommand, protected readonly migrateAttachmentToMorphRelationsCommand: MigrateAttachmentToMorphRelationsCommand, protected readonly identifyWebhookMetadataCommand: IdentifyWebhookMetadataCommand, protected readonly makeWebhookUniversalIdentifierAndApplicationIdNotNullableMigrationCommand: MakeWebhookUniversalIdentifierAndApplicationIdNotNullableMigrationCommand, @@ -128,67 +46,7 @@ export class UpgradeCommand extends UpgradeCommandRunner { ); // Note: Required empty commands array to allow retrieving previous version - const commands_1120: VersionCommands = []; - - const commands_1130: VersionCommands = [ - this.migrateTimelineActivityToMorphRelationsCommand, - this.deduplicateRoleTargetsCommand, - this.updateRoleTargetsUniqueConstraintMigrationCommand, - this.backfillPageLayoutUniversalIdentifiersCommand, - this.migrateStandardInvalidEntitiesCommand, - this.cleanEmptyStringNullInTextFieldsCommand, - this.renameIndexNameCommand, - ]; - - const commands_1140: VersionCommands = [ - this.updateCreatedByEnumCommand, - this.deleteRemovedAgentsCommand, - ]; - - const commands_1150: VersionCommands = [ - this.migratePageLayoutWidgetConfigurationCommand, - this.fixNanPositionValuesInNotesCommand, - this.backfillUpdatedByFieldCommand, - this.addWorkspaceForeignKeysMigrationCommand, - ]; - - const commands_1160: VersionCommands = [ - this.identifyAgentMetadataCommand, - this.identifyFieldMetadataCommand, - this.identifyObjectMetadataCommand, - this.identifyRoleMetadataCommand, - this.identifyViewMetadataCommand, - this.identifyViewFieldMetadataCommand, - this.identifyViewFilterMetadataCommand, - this.identifyViewGroupMetadataCommand, - this.identifyIndexMetadataCommand, - this.backfillOpportunityOwnerFieldCommand, - this.backfillStandardPageLayoutsCommand, - this - .makeAgentUniversalIdentifierAndApplicationIdNotNullableMigrationCommand, - this - .makeFieldMetadataUniversalIdentifierAndApplicationIdNotNullableMigrationCommand, - this - .makeObjectMetadataUniversalIdentifierAndApplicationIdNotNullableMigrationCommand, - this - .makeRoleUniversalIdentifierAndApplicationIdNotNullableMigrationCommand, - this - .makeViewUniversalIdentifierAndApplicationIdNotNullableMigrationCommand, - this - .makeViewFieldUniversalIdentifierAndApplicationIdNotNullableMigrationCommand, - this - .makeViewFilterUniversalIdentifierAndApplicationIdNotNullableMigrationCommand, - this - .makeViewGroupUniversalIdentifierAndApplicationIdNotNullableMigrationCommand, - this - .makeIndexMetadataUniversalIdentifierAndApplicationIdNotNullableMigrationCommand, - this.identifyRemainingEntitiesMetadataCommand, - this - .makeRemainingEntitiesUniversalIdentifierAndApplicationIdNotNullableMigrationCommand, - this.flushV2CacheAndIncrementMetadataVersionCommand, - this.updateTaskOnDeleteActionCommand, - this.deleteFileRecordsCommand, - ]; + const commands_1160: VersionCommands = []; const commands_1170: VersionCommands = [ this.migrateAttachmentToMorphRelationsCommand, @@ -199,10 +57,6 @@ export class UpgradeCommand extends UpgradeCommandRunner { ]; this.allCommands = { - '1.12.0': commands_1120, - '1.13.0': commands_1130, - '1.14.0': commands_1140, - '1.15.0': commands_1150, '1.16.0': commands_1160, '1.17.0': commands_1170, }; diff --git a/packages/twenty-server/src/database/typeorm/core/migrations/common/1770040351718-remove-object-metadata-standard-id.ts b/packages/twenty-server/src/database/typeorm/core/migrations/common/1770040351718-remove-object-metadata-standard-id.ts new file mode 100644 index 0000000000..030c5ab3ff --- /dev/null +++ b/packages/twenty-server/src/database/typeorm/core/migrations/common/1770040351718-remove-object-metadata-standard-id.ts @@ -0,0 +1,19 @@ +import { type MigrationInterface, type QueryRunner } from 'typeorm'; + +export class RemoveObjectMetadataStandardId1770040351718 + implements MigrationInterface +{ + name = 'RemoveObjectMetadataStandardId1770040351718'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "core"."objectMetadata" DROP COLUMN "standardId"`, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "core"."objectMetadata" ADD "standardId" uuid`, + ); + } +} diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/__mocks__/mockPersonObjectMetadata.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/__mocks__/mockPersonObjectMetadata.ts index c297e8c5be..59242f8bab 100644 --- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/__mocks__/mockPersonObjectMetadata.ts +++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/__mocks__/mockPersonObjectMetadata.ts @@ -135,7 +135,6 @@ export const mockPersonFlatObjectMetadata = ( ): FlatObjectMetadata => ({ id: objectMetadataId, icon: 'Icon123', - standardId: '', nameSingular: 'person', namePlural: 'people', labelSingular: 'Person', diff --git a/packages/twenty-server/src/engine/core-modules/__mocks__/mockObjectMetadataItemsWithFieldMaps.ts b/packages/twenty-server/src/engine/core-modules/__mocks__/mockObjectMetadataItemsWithFieldMaps.ts index 431377bbbb..57cb49197f 100644 --- a/packages/twenty-server/src/engine/core-modules/__mocks__/mockObjectMetadataItemsWithFieldMaps.ts +++ b/packages/twenty-server/src/engine/core-modules/__mocks__/mockObjectMetadataItemsWithFieldMaps.ts @@ -18,7 +18,6 @@ const customObjectImageFieldId = 'imageIdentifierFieldMetadataId'; const personFlatObject = getFlatObjectMetadataMock({ id: '20202020-8dec-43d5-b2ff-6eef05095bec', - standardId: '20202020-8dec-43d5-b2ff-6eef05095bec', nameSingular: 'person', namePlural: 'people', labelSingular: 'Person', @@ -43,7 +42,6 @@ const personFlatObject = getFlatObjectMetadataMock({ const companyFlatObject = getFlatObjectMetadataMock({ id: '20202020-c03c-45d6-a4b0-04afe1357c5c', - standardId: '20202020-c03c-45d6-a4b0-04afe1357c5c', nameSingular: 'company', namePlural: 'companies', labelSingular: 'Company', @@ -68,7 +66,6 @@ const companyFlatObject = getFlatObjectMetadataMock({ const customObjectFlatObject = getFlatObjectMetadataMock({ id: '20202020-3d75-4aab-bacd-ee176c5f63ca', - standardId: null, nameSingular: 'regular-custom-object', namePlural: 'regular-custom-objects', labelSingular: 'Regular Custom Object', @@ -93,7 +90,6 @@ const customObjectFlatObject = getFlatObjectMetadataMock({ const nonSearchableFlatObject = getFlatObjectMetadataMock({ id: '20202020-540c-4397-b872-2a90ea2fb809', - standardId: '20202020-540c-4397-b872-2a90ea2fb809', nameSingular: 'non-searchable-object', namePlural: 'non-searchable-objects', labelSingular: '', diff --git a/packages/twenty-server/src/engine/core-modules/event-emitter/utils/__tests__/object-record-changed-values.spec.ts b/packages/twenty-server/src/engine/core-modules/event-emitter/utils/__tests__/object-record-changed-values.spec.ts index 058fb068b5..87bc33d43a 100644 --- a/packages/twenty-server/src/engine/core-modules/event-emitter/utils/__tests__/object-record-changed-values.spec.ts +++ b/packages/twenty-server/src/engine/core-modules/event-emitter/utils/__tests__/object-record-changed-values.spec.ts @@ -30,7 +30,6 @@ const mockObjectMetadata: FlatObjectMetadata = { description: null, standardOverrides: null, isUIReadOnly: false, - standardId: null, labelIdentifierFieldMetadataId: null, imageIdentifierFieldMetadataId: null, duplicateCriteria: null, diff --git a/packages/twenty-server/src/engine/core-modules/event-emitter/utils/object-record-changed-values.ts b/packages/twenty-server/src/engine/core-modules/event-emitter/utils/object-record-changed-values.ts index e3d269f2ad..04b47559b1 100644 --- a/packages/twenty-server/src/engine/core-modules/event-emitter/utils/object-record-changed-values.ts +++ b/packages/twenty-server/src/engine/core-modules/event-emitter/utils/object-record-changed-values.ts @@ -1,5 +1,4 @@ import deepEqual from 'deep-equal'; -import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; import { FieldMetadataType, type ObjectRecord } from 'twenty-shared/types'; import { fastDeepEqual } from 'twenty-shared/utils'; @@ -7,24 +6,26 @@ import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/typ import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; import { buildFieldMapsFromFlatObjectMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/build-field-maps-from-flat-object-metadata.util'; import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type'; +import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; const LARGE_JSON_FIELDS: Record> = { - [STANDARD_OBJECT_IDS.workflowVersion]: new Set(['steps', 'trigger']), - [STANDARD_OBJECT_IDS.workflowAutomatedTrigger]: new Set(['settings']), - [STANDARD_OBJECT_IDS.workflowRun]: new Set(['state']), + [STANDARD_OBJECTS.workflowVersion.universalIdentifier]: new Set([ + 'steps', + 'trigger', + ]), + [STANDARD_OBJECTS.workflowAutomatedTrigger.universalIdentifier]: new Set([ + 'settings', + ]), + [STANDARD_OBJECTS.workflowRun.universalIdentifier]: new Set(['state']), }; const isLargeJsonField = ( - objectMetadataItem: Pick, + objectMetadataItem: Pick, key: string, ): boolean => { - const standardId = objectMetadataItem.standardId; + const universalIdentifier = objectMetadataItem.universalIdentifier; - if (!standardId) { - return false; - } - - return LARGE_JSON_FIELDS[standardId]?.has(key) ?? false; + return LARGE_JSON_FIELDS[universalIdentifier]?.has(key) ?? false; }; export const objectRecordChangedValues = ( diff --git a/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent/utils/__tests__/is-workflow-related-object.util.spec.ts b/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent/utils/__tests__/is-workflow-related-object.util.spec.ts index 8c0cc48265..81a4255af6 100644 --- a/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent/utils/__tests__/is-workflow-related-object.util.spec.ts +++ b/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent/utils/__tests__/is-workflow-related-object.util.spec.ts @@ -1,40 +1,39 @@ -import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; - import { isWorkflowRelatedObject } from 'src/engine/metadata-modules/ai/ai-agent/utils/is-workflow-related-object.util'; -import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; +import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; describe('isWorkflowRelatedObject', () => { it('should return true for workflow-related objects', () => { expect( isWorkflowRelatedObject({ - standardId: STANDARD_OBJECT_IDS.workflow, - } as ObjectMetadataEntity), + universalIdentifier: STANDARD_OBJECTS.workflow.universalIdentifier, + }), ).toBe(true); expect( isWorkflowRelatedObject({ - standardId: STANDARD_OBJECT_IDS.workflowRun, - } as ObjectMetadataEntity), + universalIdentifier: STANDARD_OBJECTS.workflowRun.universalIdentifier, + }), ).toBe(true); expect( isWorkflowRelatedObject({ - standardId: STANDARD_OBJECT_IDS.workflowVersion, - } as ObjectMetadataEntity), + universalIdentifier: + STANDARD_OBJECTS.workflowVersion.universalIdentifier, + }), ).toBe(true); }); it('should return false for non-workflow objects', () => { expect( isWorkflowRelatedObject({ - standardId: STANDARD_OBJECT_IDS.person, - } as ObjectMetadataEntity), + universalIdentifier: STANDARD_OBJECTS.person.universalIdentifier, + }), ).toBe(false); expect( isWorkflowRelatedObject({ - standardId: null, - } as ObjectMetadataEntity), + universalIdentifier: 'some-custom-object-uuid', + }), ).toBe(false); }); }); diff --git a/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent/utils/is-workflow-related-object.util.ts b/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent/utils/is-workflow-related-object.util.ts index 703f06e7f6..05101280b0 100644 --- a/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent/utils/is-workflow-related-object.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent/utils/is-workflow-related-object.util.ts @@ -1,20 +1,17 @@ -import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; +import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; // All workflow-related standard object IDs that should be filtered out from agent access -const WORKFLOW_STANDARD_OBJECT_IDS = [ - STANDARD_OBJECT_IDS.workflow, - STANDARD_OBJECT_IDS.workflowRun, - STANDARD_OBJECT_IDS.workflowVersion, - STANDARD_OBJECT_IDS.workflowAutomatedTrigger, +const WORKFLOW_STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS = [ + STANDARD_OBJECTS.workflow.universalIdentifier, + STANDARD_OBJECTS.workflowRun.universalIdentifier, + STANDARD_OBJECTS.workflowVersion.universalIdentifier, + STANDARD_OBJECTS.workflowAutomatedTrigger.universalIdentifier, ] as const; export const isWorkflowRelatedObject = (objectMetadata: { - standardId: string | null; + universalIdentifier: string; }): boolean => { - return ( - objectMetadata.standardId !== null && - WORKFLOW_STANDARD_OBJECT_IDS.includes( - objectMetadata.standardId as (typeof WORKFLOW_STANDARD_OBJECT_IDS)[number], - ) + return WORKFLOW_STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.includes( + objectMetadata.universalIdentifier as (typeof WORKFLOW_STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS)[number], ); }; diff --git a/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent/utils/is-workflow-run-object.util.ts b/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent/utils/is-workflow-run-object.util.ts index 9cdc361f41..295193bd5d 100644 --- a/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent/utils/is-workflow-run-object.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent/utils/is-workflow-run-object.util.ts @@ -1,22 +1,18 @@ -import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; - import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; +import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; // All workflow-related standard object IDs that should be filtered out from agent access -const WORKFLOW_STANDARD_OBJECT_IDS = [ - STANDARD_OBJECT_IDS.workflow, - STANDARD_OBJECT_IDS.workflowRun, - STANDARD_OBJECT_IDS.workflowVersion, - STANDARD_OBJECT_IDS.workflowAutomatedTrigger, +const WORKFLOW_STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS = [ + STANDARD_OBJECTS.workflow.universalIdentifier, + STANDARD_OBJECTS.workflowRun.universalIdentifier, + STANDARD_OBJECTS.workflowVersion.universalIdentifier, + STANDARD_OBJECTS.workflowAutomatedTrigger.universalIdentifier, ] as const; export const isWorkflowRelatedObject = ( objectMetadata: ObjectMetadataEntity, ): boolean => { - return ( - objectMetadata.standardId !== null && - WORKFLOW_STANDARD_OBJECT_IDS.includes( - objectMetadata.standardId as (typeof WORKFLOW_STANDARD_OBJECT_IDS)[number], - ) + return WORKFLOW_STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.includes( + objectMetadata.universalIdentifier as (typeof WORKFLOW_STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS)[number], ); }; diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/attachment-flat-object.mock.ts b/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/attachment-flat-object.mock.ts index 51015a6ca8..c4b4cffd2e 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/attachment-flat-object.mock.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/attachment-flat-object.mock.ts @@ -2,7 +2,6 @@ import { getFlatObjectMetadataMock } from 'src/engine/metadata-modules/flat-obje export const ATTACHMENT_FLAT_OBJECT_MOCK = getFlatObjectMetadataMock({ id: '819ed5ff-312f-4423-8e95-02a691cf5c27', - standardId: '20202020-bd3d-4c60-8dca-571c71d4447a', nameSingular: 'attachment', namePlural: 'attachments', labelSingular: 'Attachment', diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/company-flat-object.mock.ts b/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/company-flat-object.mock.ts index e89b358705..3dccfc9cab 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/company-flat-object.mock.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/company-flat-object.mock.ts @@ -2,7 +2,6 @@ import { getFlatObjectMetadataMock } from 'src/engine/metadata-modules/flat-obje export const COMPANY_FLAT_OBJECT_MOCK = getFlatObjectMetadataMock({ id: '7f5c2c7a-bb23-46fb-b59d-9b7a52a8d1cc', - standardId: '20202020-b374-4779-a561-80086cb2e17f', nameSingular: 'company', namePlural: 'companies', labelSingular: 'Company', diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/favorite-flat-object.mock.ts b/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/favorite-flat-object.mock.ts index ff137ec5f8..a67b0f2c44 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/favorite-flat-object.mock.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/favorite-flat-object.mock.ts @@ -2,7 +2,6 @@ import { getFlatObjectMetadataMock } from 'src/engine/metadata-modules/flat-obje export const FAVORITE_FLAT_OBJECT_MOCK = getFlatObjectMetadataMock({ id: 'f4749ffb-dde8-44ff-8b01-d3fc82df0ba2', - standardId: '20202020-ab56-4e05-92a3-e2414a499860', nameSingular: 'favorite', namePlural: 'favorites', labelSingular: 'Favorite', diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/favorite-folder-flat-object.mock.ts b/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/favorite-folder-flat-object.mock.ts index 242aa9200b..bd4349b85a 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/favorite-folder-flat-object.mock.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/favorite-folder-flat-object.mock.ts @@ -2,7 +2,6 @@ import { getFlatObjectMetadataMock } from 'src/engine/metadata-modules/flat-obje export const FAVORITE_FOLDER_FLAT_OBJECT_MOCK = getFlatObjectMetadataMock({ id: '35763b74-1abe-4c4b-9eab-27693f0ee06d', - standardId: '20202020-7cf8-401f-8211-a9587d27fd2d', nameSingular: 'favoriteFolder', namePlural: 'favoriteFolders', labelSingular: 'Favorite Folder', diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/get-flat-object-metadata.mock.ts b/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/get-flat-object-metadata.mock.ts index f9ac28fdf4..a0583c9c3b 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/get-flat-object-metadata.mock.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/get-flat-object-metadata.mock.ts @@ -38,7 +38,6 @@ export const getFlatObjectMetadataMock = ( namePlural: 'defaultflatObjectMetadataNamePlural', nameSingular: 'defaultflatObjectMetadataNameSingular', shortcut: 'shortcut', - standardId: null, applicationId, standardOverrides: null, targetTableName: '', @@ -62,7 +61,6 @@ export const getStandardFlatObjectMetadataMock = ( overrides: Omit, ) => { return getFlatObjectMetadataMock({ - standardId: faker.string.uuid(), standardOverrides: {}, isCustom: false, isSystem: true, diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/note-flat-object.mock.ts b/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/note-flat-object.mock.ts index bd7a90b88f..785e366f24 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/note-flat-object.mock.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/note-flat-object.mock.ts @@ -2,7 +2,6 @@ import { getFlatObjectMetadataMock } from 'src/engine/metadata-modules/flat-obje export const NOTE_FLAT_OBJECT_MOCK = getFlatObjectMetadataMock({ id: '1253e3e5-5b00-4a34-93b8-02f3dc6e2b7c', - standardId: '20202020-0b00-45cd-b6f6-6cd806fc6804', nameSingular: 'note', namePlural: 'notes', labelSingular: 'Note', diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/note-target-flat-object.mock.ts b/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/note-target-flat-object.mock.ts index f1a3c35ae1..b4ddbbcf66 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/note-target-flat-object.mock.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/note-target-flat-object.mock.ts @@ -2,7 +2,6 @@ import { getFlatObjectMetadataMock } from 'src/engine/metadata-modules/flat-obje export const NOTE_TARGET_FLAT_OBJECT_MOCK = getFlatObjectMetadataMock({ id: '12e3cb51-c3de-4192-b0d5-965d48d001c0', - standardId: '20202020-fff0-4b44-be82-bda313884400', nameSingular: 'noteTarget', namePlural: 'noteTargets', labelSingular: 'Note Target', diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/opportunity-flat-object.mock.ts b/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/opportunity-flat-object.mock.ts index b21fe20537..128313d820 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/opportunity-flat-object.mock.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/opportunity-flat-object.mock.ts @@ -2,7 +2,6 @@ import { getFlatObjectMetadataMock } from 'src/engine/metadata-modules/flat-obje export const OPPORTUNITY_FLAT_OBJECT_MOCK = getFlatObjectMetadataMock({ id: 'e6996bbf-dd41-423a-9324-8546f5b22fa7', - standardId: '20202020-9549-49dd-b2b2-883999db8938', nameSingular: 'opportunity', namePlural: 'opportunities', labelSingular: 'Opportunity', diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/person-flat-object.mock.ts b/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/person-flat-object.mock.ts index 7cadd3740f..169cd19fb5 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/person-flat-object.mock.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/person-flat-object.mock.ts @@ -2,7 +2,6 @@ import { getFlatObjectMetadataMock } from 'src/engine/metadata-modules/flat-obje export const PERSON_FLAT_OBJECT_MOCK = getFlatObjectMetadataMock({ id: '843e0b67-9619-4628-91c4-2fa62256a611', - standardId: '20202020-e674-48e5-a542-72570eee7213', nameSingular: 'person', namePlural: 'people', labelSingular: 'Person', diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/pet-flat-object.mock.ts b/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/pet-flat-object.mock.ts index b68e394091..78f56b91de 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/pet-flat-object.mock.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/pet-flat-object.mock.ts @@ -2,7 +2,6 @@ import { getFlatObjectMetadataMock } from 'src/engine/metadata-modules/flat-obje export const PET_FLAT_OBJECT_MOCK = getFlatObjectMetadataMock({ id: 'd34e0f07-1b8c-4de0-938e-599cf05e1f7f', - standardId: null, nameSingular: 'pet', namePlural: 'pets', labelSingular: 'Pet', diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/rocket-flat-object.mock.ts b/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/rocket-flat-object.mock.ts index aab4b63433..f611ce6968 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/rocket-flat-object.mock.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/rocket-flat-object.mock.ts @@ -2,7 +2,6 @@ import { getFlatObjectMetadataMock } from 'src/engine/metadata-modules/flat-obje export const ROCKET_FLAT_OBJECT_MOCK = getFlatObjectMetadataMock({ id: 'd78ec657-74a4-4652-a350-1f44ff62970a', - standardId: null, nameSingular: 'rocket', namePlural: 'rockets', labelSingular: 'Rocket', diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/task-flat-object.mock.ts b/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/task-flat-object.mock.ts index 29a44a8bb9..0b4f24cd81 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/task-flat-object.mock.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/task-flat-object.mock.ts @@ -2,7 +2,6 @@ import { getFlatObjectMetadataMock } from 'src/engine/metadata-modules/flat-obje export const TASK_FLAT_OBJECT_MOCK = getFlatObjectMetadataMock({ id: '3186920d-2a15-4b5f-96c7-2bf6567024b0', - standardId: '20202020-1ba1-48ba-bc83-ef7e5990ed10', nameSingular: 'task', namePlural: 'tasks', labelSingular: 'Task', diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/task-target-flat-object.mock.ts b/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/task-target-flat-object.mock.ts index 02c3c631e0..df21072636 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/task-target-flat-object.mock.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/task-target-flat-object.mock.ts @@ -2,7 +2,6 @@ import { getFlatObjectMetadataMock } from 'src/engine/metadata-modules/flat-obje export const TASK_TARGET_FLAT_OBJECT_MOCK = getFlatObjectMetadataMock({ id: 'bb2b29b8-7f46-4106-a8ae-3a32df9c9166', - standardId: '20202020-5a9a-44e8-95df-771cd06d0fb1', nameSingular: 'taskTarget', namePlural: 'taskTargets', labelSingular: 'Task Target', diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/timeline-activity-flat-object.mock.ts b/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/timeline-activity-flat-object.mock.ts index 6e85a0c0cb..3cc376703b 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/timeline-activity-flat-object.mock.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/__mocks__/timeline-activity-flat-object.mock.ts @@ -2,7 +2,6 @@ import { getFlatObjectMetadataMock } from 'src/engine/metadata-modules/flat-obje export const TIMELINE_ACTIVITY_FLAT_OBJECT_MOCK = getFlatObjectMetadataMock({ id: '3090f830-c4b1-41a1-8e18-815760830bec', - standardId: '20202020-6736-4337-b5c4-8b39fae325a5', nameSingular: 'timelineActivity', namePlural: 'timelineActivities', labelSingular: 'Timeline Activity', 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 ea37a51e10..14351276c3 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 @@ -98,7 +98,6 @@ export const fromCreateObjectInputToFlatObjectMetadataAndFlatFieldMetadatasToCre namePlural: createObjectInput.namePlural, nameSingular: createObjectInput.nameSingular, shortcut: createObjectInput.shortcut ?? null, - standardId: createObjectInput.standardId ?? null, standardOverrides: null, applicationId: flatApplication.id, universalIdentifier, diff --git a/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.entity.ts b/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.entity.ts index 72e3ca6232..86a6c41bfd 100644 --- a/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.entity.ts +++ b/packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.entity.ts @@ -39,9 +39,6 @@ export class ObjectMetadataEntity @PrimaryGeneratedColumn('uuid') id: string; - @Column({ nullable: true, type: 'uuid' }) - standardId: string | null; - @Column({ nullable: false, type: 'uuid' }) dataSourceId: string; 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 6fdd60039a..e894c9ff39 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,4 +1,3 @@ -import { type STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; import { FieldMetadataType } from 'twenty-shared/types'; import { capitalize, isDefined } from 'twenty-shared/utils'; @@ -23,6 +22,7 @@ import { TIMELINE_ACTIVITY_STANDARD_FIELD_IDS, } from 'src/engine/workspace-manager/workspace-migration/constant/standard-field-ids'; import { STANDARD_OBJECT_ICONS } from 'src/engine/workspace-manager/workspace-migration/constant/standard-object-icons'; +import { type STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; const DEFAULT_RELATIONS_OBJECTS_STANDARD_IDS = [ 'timelineActivity', @@ -30,7 +30,7 @@ const DEFAULT_RELATIONS_OBJECTS_STANDARD_IDS = [ 'attachment', 'noteTarget', 'taskTarget', -] as const satisfies (keyof typeof STANDARD_OBJECT_IDS)[]; +] as const satisfies (keyof typeof STANDARD_OBJECTS)[]; const morphIdByRelationObjectNameSingular = { timelineActivity: TIMELINE_ACTIVITY_STANDARD_FIELD_IDS.targetMorphId, @@ -47,7 +47,7 @@ const morphIdByRelationObjectNameSingular = { // once we migrate timeline activity to morph relations, we can add it. // another way to check if an object is migrated to morph relations is to check if the feature flag is enabled const DEFAULT_MORPH_RELATIONS_OBJECTS_STANDARD_IDS = - [] as const satisfies (keyof typeof STANDARD_OBJECT_IDS)[]; + [] as const satisfies (keyof typeof STANDARD_OBJECTS)[]; export type BuildDefaultRelationFieldsForCustomObjectArgs = { existingFeatureFlagsMap: FeatureFlagMap; diff --git a/packages/twenty-server/src/engine/metadata-modules/role/services/workspace-roles-permissions-cache.service.ts b/packages/twenty-server/src/engine/metadata-modules/role/services/workspace-roles-permissions-cache.service.ts index b8e54e422f..c04bc51891 100644 --- a/packages/twenty-server/src/engine/metadata-modules/role/services/workspace-roles-permissions-cache.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/role/services/workspace-roles-permissions-cache.service.ts @@ -2,7 +2,6 @@ import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { PermissionFlagType } from 'twenty-shared/constants'; -import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; import { type ObjectsPermissions, type ObjectsPermissionsByRoleId, @@ -16,11 +15,12 @@ import { WorkspaceCacheProvider } from 'src/engine/workspace-cache/interfaces/wo import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity'; import { WorkspaceCache } from 'src/engine/workspace-cache/decorators/workspace-cache.decorator'; +import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; -const WORKFLOW_STANDARD_OBJECT_IDS = [ - STANDARD_OBJECT_IDS.workflow, - STANDARD_OBJECT_IDS.workflowRun, - STANDARD_OBJECT_IDS.workflowVersion, +const WORKFLOW_STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS = [ + STANDARD_OBJECTS.workflow.universalIdentifier, + STANDARD_OBJECTS.workflowRun.universalIdentifier, + STANDARD_OBJECTS.workflowVersion.universalIdentifier, ] as const; @Injectable() @@ -60,7 +60,11 @@ export class WorkspaceRolesPermissionsCacheService extends WorkspaceCacheProvide const objectRecordsPermissions: ObjectsPermissions = {}; for (const objectMetadata of workspaceObjectMetadataCollection) { - const { id: objectMetadataId, isSystem, standardId } = objectMetadata; + const { + id: objectMetadataId, + isSystem, + universalIdentifier, + } = objectMetadata; let canRead = role.canReadAllObjectRecords; let canUpdate = role.canUpdateAllObjectRecords; @@ -69,9 +73,8 @@ export class WorkspaceRolesPermissionsCacheService extends WorkspaceCacheProvide const restrictedFields: RestrictedFieldsPermissions = {}; if ( - standardId && - WORKFLOW_STANDARD_OBJECT_IDS.includes( - standardId as (typeof WORKFLOW_STANDARD_OBJECT_IDS)[number], + WORKFLOW_STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.includes( + universalIdentifier as (typeof WORKFLOW_STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS)[number], ) ) { const hasWorkflowsPermissions = this.hasWorkflowsPermissions(role); @@ -169,7 +172,7 @@ export class WorkspaceRolesPermissionsCacheService extends WorkspaceCacheProvide select: [ 'id', 'isSystem', - 'standardId', + 'universalIdentifier', 'labelIdentifierFieldMetadataId', ], }); diff --git a/packages/twenty-server/src/engine/twenty-orm/entity-manager/workspace-entity-manager.spec.ts b/packages/twenty-server/src/engine/twenty-orm/entity-manager/workspace-entity-manager.spec.ts index d337cf3805..dabfff5b33 100644 --- a/packages/twenty-server/src/engine/twenty-orm/entity-manager/workspace-entity-manager.spec.ts +++ b/packages/twenty-server/src/engine/twenty-orm/entity-manager/workspace-entity-manager.spec.ts @@ -115,7 +115,6 @@ describe('WorkspaceEntityManager', () => { imageIdentifierFieldMetadataId: null, labelIdentifierFieldMetadataId: null, shortcut: null, - standardId: null, standardOverrides: null, applicationId: 'test-application-id', isLabelSyncedWithName: false, @@ -242,8 +241,8 @@ describe('WorkspaceEntityManager', () => { IS_NAVIGATION_MENU_ITEM_ENABLED: false, IS_FILES_FIELD_ENABLED: false, IS_APPLICATION_INSTALLATION_FROM_TARBALL_ENABLED: false, - IS_MARKETPLACE_ENABLED: false, IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED: false, + IS_MARKETPLACE_ENABLED: false, }, userWorkspaceRoleMap: {}, eventEmitterService: { diff --git a/packages/twenty-server/src/engine/twenty-orm/utils/__tests__/get-column-name-to-field-metadata-id.util.spec.ts b/packages/twenty-server/src/engine/twenty-orm/utils/__tests__/get-column-name-to-field-metadata-id.util.spec.ts index ae19329d14..ac800a0d10 100644 --- a/packages/twenty-server/src/engine/twenty-orm/utils/__tests__/get-column-name-to-field-metadata-id.util.spec.ts +++ b/packages/twenty-server/src/engine/twenty-orm/utils/__tests__/get-column-name-to-field-metadata-id.util.spec.ts @@ -35,7 +35,6 @@ describe('getColumnNameToFieldMetadataIdMap', () => { description: null, standardOverrides: null, isUIReadOnly: false, - standardId: null, labelIdentifierFieldMetadataId: null, imageIdentifierFieldMetadataId: null, duplicateCriteria: null, diff --git a/packages/twenty-server/src/engine/twenty-orm/utils/__tests__/get-field-metadata-id-to-column-names-map.util.spec.ts b/packages/twenty-server/src/engine/twenty-orm/utils/__tests__/get-field-metadata-id-to-column-names-map.util.spec.ts index 461fa4c3f6..1cc78c8413 100644 --- a/packages/twenty-server/src/engine/twenty-orm/utils/__tests__/get-field-metadata-id-to-column-names-map.util.spec.ts +++ b/packages/twenty-server/src/engine/twenty-orm/utils/__tests__/get-field-metadata-id-to-column-names-map.util.spec.ts @@ -35,7 +35,6 @@ describe('getFieldMetadataIdToColumnNamesMap', () => { description: null, standardOverrides: null, isUIReadOnly: false, - standardId: null, labelIdentifierFieldMetadataId: null, imageIdentifierFieldMetadataId: null, duplicateCriteria: null, diff --git a/packages/twenty-server/src/engine/twenty-orm/utils/__tests__/is-record-matching-rls-row-level-permission-predicate.util.spec.ts b/packages/twenty-server/src/engine/twenty-orm/utils/__tests__/is-record-matching-rls-row-level-permission-predicate.util.spec.ts index 0a7e7bd66d..354dc50b24 100644 --- a/packages/twenty-server/src/engine/twenty-orm/utils/__tests__/is-record-matching-rls-row-level-permission-predicate.util.spec.ts +++ b/packages/twenty-server/src/engine/twenty-orm/utils/__tests__/is-record-matching-rls-row-level-permission-predicate.util.spec.ts @@ -35,7 +35,6 @@ describe('isRecordMatchingRLSRowLevelPermissionPredicate', () => { description: null, standardOverrides: null, isUIReadOnly: false, - standardId: null, labelIdentifierFieldMetadataId: null, imageIdentifierFieldMetadataId: null, duplicateCriteria: null, diff --git a/packages/twenty-server/src/engine/twenty-orm/utils/format-twenty-orm-event-to-database-batch-event.util.ts b/packages/twenty-server/src/engine/twenty-orm/utils/format-twenty-orm-event-to-database-batch-event.util.ts index d474ef3d7d..41caaf9c5c 100644 --- a/packages/twenty-server/src/engine/twenty-orm/utils/format-twenty-orm-event-to-database-batch-event.util.ts +++ b/packages/twenty-server/src/engine/twenty-orm/utils/format-twenty-orm-event-to-database-batch-event.util.ts @@ -7,7 +7,6 @@ import { ObjectRecordUpsertEvent, type ObjectRecordDiff, } from 'twenty-shared/database-events'; -import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; import { assertUnreachable, isDefined, @@ -27,6 +26,7 @@ import { TwentyORMExceptionCode, } from 'src/engine/twenty-orm/exceptions/twenty-orm.exception'; import { type DatabaseBatchEventInput } from 'src/engine/workspace-event-emitter/workspace-event-emitter'; +import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; export const formatTwentyOrmEventToDatabaseBatchEvent = < T extends ObjectLiteral, @@ -47,7 +47,10 @@ export const formatTwentyOrmEventToDatabaseBatchEvent = < recordsAfter?: T[]; recordsBefore?: T[]; }): DatabaseBatchEventInput | undefined => { - if (objectMetadataItem.standardId === STANDARD_OBJECT_IDS.timelineActivity) { + if ( + objectMetadataItem.universalIdentifier === + STANDARD_OBJECTS.timelineActivity.universalIdentifier + ) { return; } diff --git a/packages/twenty-server/src/engine/utils/should-seed-workspace-favorite.ts b/packages/twenty-server/src/engine/utils/should-seed-workspace-favorite.ts index 2331fb8ba7..7767743b75 100644 --- a/packages/twenty-server/src/engine/utils/should-seed-workspace-favorite.ts +++ b/packages/twenty-server/src/engine/utils/should-seed-workspace-favorite.ts @@ -1,6 +1,5 @@ -import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; - import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; +import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; export const shouldSeedWorkspaceFavorite = ( objectMetadataId: string, @@ -8,9 +7,13 @@ export const shouldSeedWorkspaceFavorite = ( ): boolean => objectMetadataId !== objectMetadataItems.find( - (item) => item.standardId === STANDARD_OBJECT_IDS.workflowVersion, + (item) => + item.universalIdentifier === + STANDARD_OBJECTS.workflowVersion.universalIdentifier, )?.id && objectMetadataId !== objectMetadataItems.find( - (item) => item.standardId === STANDARD_OBJECT_IDS.workflowRun, + (item) => + item.universalIdentifier === + STANDARD_OBJECTS.workflowRun.universalIdentifier, )?.id; diff --git a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/get-page-layout-widget-data-seeds-v2.util.ts b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/get-page-layout-widget-data-seeds-v2.util.ts index 1b6a37825a..6422072fa5 100644 --- a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/get-page-layout-widget-data-seeds-v2.util.ts +++ b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/get-page-layout-widget-data-seeds-v2.util.ts @@ -1,5 +1,4 @@ import { CalendarStartDay } from 'twenty-shared/constants'; -import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; import { isDefined } from 'twenty-shared/utils'; import { AggregateOperations } from 'src/engine/api/graphql/graphql-query-runner/constants/aggregate-operations.constant'; @@ -12,6 +11,7 @@ import { PAGE_LAYOUT_TAB_SEEDS } from 'src/engine/workspace-manager/dev-seeder/c import { PAGE_LAYOUT_WIDGET_SEEDS } from 'src/engine/workspace-manager/dev-seeder/core/constants/page-layout-widget-seeds.constant'; import { type SeederFlatPageLayoutWidget } from 'src/engine/workspace-manager/dev-seeder/core/types/seeder-flat-page-layout-widget.type'; import { generateSeedId } from 'src/engine/workspace-manager/dev-seeder/core/utils/generate-seed-id.util'; +import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; const getFieldId = ( object: ObjectMetadataEntity | undefined, @@ -25,13 +25,17 @@ export const getPageLayoutWidgetDataSeedsV2 = ( objectMetadataItems: ObjectMetadataEntity[], ): SeederFlatPageLayoutWidget[] => { const opportunityObject = objectMetadataItems.find( - (obj) => obj.standardId === STANDARD_OBJECT_IDS.opportunity, + (obj) => + obj.universalIdentifier === + STANDARD_OBJECTS.opportunity.universalIdentifier, ); const companyObject = objectMetadataItems.find( - (obj) => obj.standardId === STANDARD_OBJECT_IDS.company, + (obj) => + obj.universalIdentifier === STANDARD_OBJECTS.company.universalIdentifier, ); const personObject = objectMetadataItems.find( - (obj) => obj.standardId === STANDARD_OBJECT_IDS.person, + (obj) => + obj.universalIdentifier === STANDARD_OBJECTS.person.universalIdentifier, ); const opportunityAmountFieldId = getFieldId(opportunityObject, 'amount'); diff --git a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/get-page-layout-widget-data-seeds.util.ts b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/get-page-layout-widget-data-seeds.util.ts index 3485e300fc..7bceab0eac 100644 --- a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/get-page-layout-widget-data-seeds.util.ts +++ b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/get-page-layout-widget-data-seeds.util.ts @@ -1,5 +1,4 @@ import { CalendarStartDay } from 'twenty-shared/constants'; -import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; import { isDefined } from 'twenty-shared/utils'; import { AggregateOperations } from 'src/engine/api/graphql/graphql-query-runner/constants/aggregate-operations.constant'; @@ -15,6 +14,7 @@ import { PAGE_LAYOUT_WIDGET_SEEDS } from 'src/engine/workspace-manager/dev-seede import { type SeederFlatPageLayoutWidget } from 'src/engine/workspace-manager/dev-seeder/core/types/seeder-flat-page-layout-widget.type'; import { generateSeedId } from 'src/engine/workspace-manager/dev-seeder/core/utils/generate-seed-id.util'; import { getPageLayoutWidgetDataSeedsV2 } from 'src/engine/workspace-manager/dev-seeder/core/utils/get-page-layout-widget-data-seeds-v2.util'; +import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; const getFieldId = ( object: ObjectMetadataEntity | undefined, @@ -29,16 +29,21 @@ export const getPageLayoutWidgetDataSeeds = ( isDashboardV2Enabled: boolean, ): SeederFlatPageLayoutWidget[] => { const opportunityObject = objectMetadataItems.find( - (obj) => obj.standardId === STANDARD_OBJECT_IDS.opportunity, + (obj) => + obj.universalIdentifier === + STANDARD_OBJECTS.opportunity.universalIdentifier, ); const companyObject = objectMetadataItems.find( - (obj) => obj.standardId === STANDARD_OBJECT_IDS.company, + (obj) => + obj.universalIdentifier === STANDARD_OBJECTS.company.universalIdentifier, ); const personObject = objectMetadataItems.find( - (obj) => obj.standardId === STANDARD_OBJECT_IDS.person, + (obj) => + obj.universalIdentifier === STANDARD_OBJECTS.person.universalIdentifier, ); const taskObject = objectMetadataItems.find( - (obj) => obj.standardId === STANDARD_OBJECT_IDS.task, + (obj) => + obj.universalIdentifier === STANDARD_OBJECTS.task.universalIdentifier, ); const rocketObject = objectMetadataItems.find( (obj) => obj.nameSingular === 'rocket', diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant.ts index 268f3e00da..59f2303a70 100644 --- a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant.ts +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant.ts @@ -1,5 +1,3 @@ -import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; - import { ATTACHMENT_STANDARD_FIELD_IDS, BLOCKLIST_STANDARD_FIELD_IDS, @@ -34,7 +32,7 @@ import { export const STANDARD_OBJECTS = { attachment: { - universalIdentifier: STANDARD_OBJECT_IDS.attachment, + universalIdentifier: '20202020-bd3d-4c60-8dca-571c71d4447a', fields: { id: { universalIdentifier: '20202020-a01a-4001-8a01-1d5f8e3c7b2a' }, createdAt: { @@ -104,7 +102,7 @@ export const STANDARD_OBJECTS = { }, }, blocklist: { - universalIdentifier: STANDARD_OBJECT_IDS.blocklist, + universalIdentifier: '20202020-0408-4f38-b8a8-4d5e3e26e24d', fields: { id: { universalIdentifier: '20202020-b01a-4011-8b11-5a9fc27fbf6e' }, createdAt: { @@ -128,7 +126,7 @@ export const STANDARD_OBJECTS = { }, }, calendarChannelEventAssociation: { - universalIdentifier: STANDARD_OBJECT_IDS.calendarChannelEventAssociation, + universalIdentifier: '20202020-491b-4aaa-9825-afd1bae6ae00', fields: { id: { universalIdentifier: '20202020-c01a-4021-8a21-9edf06bfef0a', @@ -169,7 +167,7 @@ export const STANDARD_OBJECTS = { }, }, calendarChannel: { - universalIdentifier: STANDARD_OBJECT_IDS.calendarChannel, + universalIdentifier: '20202020-e8f2-40e1-a39c-c0e0039c5034', fields: { id: { universalIdentifier: '20202020-c02a-4031-8a31-1a2f3b4c5d6e' }, createdAt: { @@ -234,7 +232,7 @@ export const STANDARD_OBJECTS = { }, }, calendarEventParticipant: { - universalIdentifier: STANDARD_OBJECT_IDS.calendarEventParticipant, + universalIdentifier: '20202020-a1c3-47a6-9732-27e5b1e8436d', fields: { id: { universalIdentifier: '20202020-c03a-4041-8a41-5e6f7a8b9cad', @@ -290,7 +288,7 @@ export const STANDARD_OBJECTS = { }, }, calendarEvent: { - universalIdentifier: STANDARD_OBJECT_IDS.calendarEvent, + universalIdentifier: '20202020-8f1d-4eef-9f85-0d1965e27221', fields: { id: { universalIdentifier: '20202020-c04a-4051-8a51-9cadbe0f1e2d' }, createdAt: { @@ -380,7 +378,7 @@ export const STANDARD_OBJECTS = { }, }, company: { - universalIdentifier: STANDARD_OBJECT_IDS.company, + universalIdentifier: '20202020-b374-4779-a561-80086cb2e17f', fields: { id: { universalIdentifier: '20202020-c05a-4061-8a61-1e2f3a4b5c6d' }, createdAt: { @@ -479,7 +477,7 @@ export const STANDARD_OBJECTS = { }, }, connectedAccount: { - universalIdentifier: STANDARD_OBJECT_IDS.connectedAccount, + universalIdentifier: '20202020-977e-46b2-890b-c3002ddfd5c5', fields: { id: { universalIdentifier: '20202020-c06a-4071-8a71-5c6d7e8f9aab' }, createdAt: { @@ -543,7 +541,7 @@ export const STANDARD_OBJECTS = { }, }, dashboard: { - universalIdentifier: STANDARD_OBJECT_IDS.dashboard, + universalIdentifier: '20202020-3840-4b6d-9425-0c5188b05ca8', fields: { id: { universalIdentifier: '20202020-da1a-41d1-8ad1-abcdefabcdef' }, createdAt: { @@ -605,7 +603,7 @@ export const STANDARD_OBJECTS = { }, }, favorite: { - universalIdentifier: STANDARD_OBJECT_IDS.favorite, + universalIdentifier: '20202020-ab56-4e05-92a3-e2414a499860', fields: { id: { universalIdentifier: '20202020-f01a-4091-8a91-ddeeffaabbcc' }, createdAt: { @@ -678,7 +676,7 @@ export const STANDARD_OBJECTS = { }, }, favoriteFolder: { - universalIdentifier: STANDARD_OBJECT_IDS.favoriteFolder, + universalIdentifier: '20202020-7cf8-401f-8211-a9587d27fd2d', fields: { id: { universalIdentifier: '20202020-f02a-40a1-8aa1-1f2e3d4c5b6a' }, createdAt: { @@ -701,7 +699,7 @@ export const STANDARD_OBJECTS = { indexes: {}, }, messageChannelMessageAssociation: { - universalIdentifier: STANDARD_OBJECT_IDS.messageChannelMessageAssociation, + universalIdentifier: '20202020-ad1e-4127-bccb-d83ae04d2ccb', fields: { id: { universalIdentifier: '20202020-b01a-40b1-8ab1-5a6b7c8d9eaf', @@ -752,7 +750,7 @@ export const STANDARD_OBJECTS = { }, }, messageChannel: { - universalIdentifier: STANDARD_OBJECT_IDS.messageChannel, + universalIdentifier: '20202020-fe8c-40bc-a681-b80b771449b7', fields: { id: { universalIdentifier: '20202020-b02a-40c1-8ac1-9eafbacbdced' }, createdAt: { @@ -837,7 +835,7 @@ export const STANDARD_OBJECTS = { }, }, messageFolder: { - universalIdentifier: STANDARD_OBJECT_IDS.messageFolder, + universalIdentifier: '20202020-4955-4fd9-8e59-2dbd373f2a46', fields: { id: { universalIdentifier: '20202020-b03a-40d1-8ad1-dcedfefaabbc' }, createdAt: { @@ -880,7 +878,7 @@ export const STANDARD_OBJECTS = { }, }, messageParticipant: { - universalIdentifier: STANDARD_OBJECT_IDS.messageParticipant, + universalIdentifier: '20202020-a433-4456-aa2d-fd9cb26b774a', fields: { id: { universalIdentifier: '20202020-b04a-40e1-8ae1-1a2b3c4d5e6f' }, createdAt: { @@ -925,7 +923,7 @@ export const STANDARD_OBJECTS = { }, }, messageThread: { - universalIdentifier: STANDARD_OBJECT_IDS.messageThread, + universalIdentifier: '20202020-849a-4c3e-84f5-a25a7d802271', fields: { id: { universalIdentifier: '20202020-b05a-40f1-8af1-5e6f7a8b9cad' }, createdAt: { @@ -961,7 +959,7 @@ export const STANDARD_OBJECTS = { }, }, message: { - universalIdentifier: STANDARD_OBJECT_IDS.message, + universalIdentifier: '20202020-3f6b-4425-80ab-e468899ab4b2', fields: { id: { universalIdentifier: '20202020-b06a-4101-8a01-9cadbedfaeb1' }, createdAt: { @@ -1030,7 +1028,7 @@ export const STANDARD_OBJECTS = { }, }, note: { - universalIdentifier: STANDARD_OBJECT_IDS.note, + universalIdentifier: '20202020-0b00-45cd-b6f6-6cd806fc6804', fields: { id: { universalIdentifier: '20202020-c01a-4111-8a11-dfabcddeef12' }, createdAt: { @@ -1086,7 +1084,7 @@ export const STANDARD_OBJECTS = { }, }, noteTarget: { - universalIdentifier: STANDARD_OBJECT_IDS.noteTarget, + universalIdentifier: '20202020-fff0-4b44-be82-bda313884400', fields: { id: { universalIdentifier: '20202020-c02a-4121-8a21-cddeef123456' }, createdAt: { @@ -1121,7 +1119,7 @@ export const STANDARD_OBJECTS = { }, }, opportunity: { - universalIdentifier: STANDARD_OBJECT_IDS.opportunity, + universalIdentifier: '20202020-9549-49dd-b2b2-883999db8938', fields: { id: { universalIdentifier: '20202020-d01a-4131-8a31-f123456789ab' }, createdAt: { @@ -1253,7 +1251,7 @@ export const STANDARD_OBJECTS = { }, }, person: { - universalIdentifier: STANDARD_OBJECT_IDS.person, + universalIdentifier: '20202020-e674-48e5-a542-72570eee7213', fields: { id: { universalIdentifier: '20202020-e01a-4141-8a41-456789abcdef' }, createdAt: { @@ -1357,7 +1355,7 @@ export const STANDARD_OBJECTS = { }, }, task: { - universalIdentifier: STANDARD_OBJECT_IDS.task, + universalIdentifier: '20202020-1ba1-48ba-bc83-ef7e5990ed10', fields: { id: { universalIdentifier: '20202020-a02a-4151-8a51-89abcdefabcd' }, createdAt: { @@ -1504,7 +1502,7 @@ export const STANDARD_OBJECTS = { }, }, taskTarget: { - universalIdentifier: STANDARD_OBJECT_IDS.taskTarget, + universalIdentifier: '20202020-5a9a-44e8-95df-771cd06d0fb1', fields: { id: { universalIdentifier: '20202020-a03a-4161-8a61-cdefabcdefab' }, createdAt: { @@ -1539,7 +1537,7 @@ export const STANDARD_OBJECTS = { }, }, timelineActivity: { - universalIdentifier: STANDARD_OBJECT_IDS.timelineActivity, + universalIdentifier: '20202020-6736-4337-b5c4-8b39fae325a5', fields: { id: { universalIdentifier: '20202020-a01a-4081-8a81-9aabbccddeff' }, createdAt: { @@ -1663,7 +1661,7 @@ export const STANDARD_OBJECTS = { }, }, workflow: { - universalIdentifier: STANDARD_OBJECT_IDS.workflow, + universalIdentifier: '20202020-62be-406c-b9ca-8caa50d51392', fields: { id: { universalIdentifier: '20202020-f02a-4181-8a81-efabcdefabcd' }, createdAt: { @@ -1731,7 +1729,7 @@ export const STANDARD_OBJECTS = { }, }, workflowAutomatedTrigger: { - universalIdentifier: STANDARD_OBJECT_IDS.workflowAutomatedTrigger, + universalIdentifier: '20202020-3319-4234-a34c-7f3b9d2e4d1f', fields: { id: { universalIdentifier: '20202020-f01a-4171-8a71-abcdefabcdef', @@ -1764,7 +1762,7 @@ export const STANDARD_OBJECTS = { }, }, workflowRun: { - universalIdentifier: STANDARD_OBJECT_IDS.workflowRun, + universalIdentifier: '20202020-4e28-4e95-a9d7-6c00874f843c', fields: { id: { universalIdentifier: '20202020-f03a-4191-8a91-cdefabcdefab' }, createdAt: { @@ -1851,7 +1849,7 @@ export const STANDARD_OBJECTS = { }, }, workflowVersion: { - universalIdentifier: STANDARD_OBJECT_IDS.workflowVersion, + universalIdentifier: '20202020-d65d-4ab9-9344-d77bfb376a3d', fields: { id: { universalIdentifier: '20202020-f04a-41a1-8aa1-abcdefabcdef' }, createdAt: { @@ -1921,7 +1919,7 @@ export const STANDARD_OBJECTS = { }, }, workspaceMember: { - universalIdentifier: STANDARD_OBJECT_IDS.workspaceMember, + universalIdentifier: '20202020-3319-4234-a34c-82d5c0e881a6', fields: { id: { universalIdentifier: '20202020-fb1a-41b1-8ab1-efabcdefabcd' }, createdAt: { diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/object-metadata/create-standard-object-flat-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/object-metadata/create-standard-object-flat-metadata.util.ts index e63eda1c44..94baff9640 100644 --- a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/object-metadata/create-standard-object-flat-metadata.util.ts +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/object-metadata/create-standard-object-flat-metadata.util.ts @@ -62,7 +62,6 @@ export const createStandardObjectFlatMetadata = < return { universalIdentifier, - standardId: universalIdentifier, applicationId: twentyStandardApplicationId, workspaceId, nameSingular, diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/page-layout-config/standard-company-page-layout.config.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/page-layout-config/standard-company-page-layout.config.ts index 1da1a81ff7..0ad41f88d7 100644 --- a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/page-layout-config/standard-company-page-layout.config.ts +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/page-layout-config/standard-company-page-layout.config.ts @@ -1,6 +1,5 @@ -import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; - import { PageLayoutType } from 'src/engine/metadata-modules/page-layout/enums/page-layout-type.enum'; +import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; import { TAB_PROPS, WIDGET_PROPS, @@ -87,7 +86,7 @@ export const STANDARD_COMPANY_PAGE_LAYOUT_CONFIG = { layoutName: 'companyRecordPage', name: 'Default Company Layout', type: PageLayoutType.RECORD_PAGE, - objectUniversalIdentifier: STANDARD_OBJECT_IDS.company, + objectUniversalIdentifier: STANDARD_OBJECTS.company.universalIdentifier, universalIdentifier: '20202020-a101-4001-8001-c0aba11c0001', defaultTabUniversalIdentifier: COMPANY_PAGE_TABS.home.universalIdentifier, tabs: COMPANY_PAGE_TABS, diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/page-layout-config/standard-note-page-layout.config.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/page-layout-config/standard-note-page-layout.config.ts index 298376ef29..797f7da549 100644 --- a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/page-layout-config/standard-note-page-layout.config.ts +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/page-layout-config/standard-note-page-layout.config.ts @@ -1,6 +1,5 @@ -import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; - import { PageLayoutType } from 'src/engine/metadata-modules/page-layout/enums/page-layout-type.enum'; +import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; import { TAB_PROPS, WIDGET_PROPS, @@ -61,7 +60,7 @@ export const STANDARD_NOTE_PAGE_LAYOUT_CONFIG = { layoutName: 'noteRecordPage', name: 'Default Note Layout', type: PageLayoutType.RECORD_PAGE, - objectUniversalIdentifier: STANDARD_OBJECT_IDS.note, + objectUniversalIdentifier: STANDARD_OBJECTS.note.universalIdentifier, universalIdentifier: '20202020-a104-4004-8004-a0be5a11a004', defaultTabUniversalIdentifier: NOTE_PAGE_TABS.home.universalIdentifier, tabs: NOTE_PAGE_TABS, diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/page-layout-config/standard-opportunity-page-layout.config.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/page-layout-config/standard-opportunity-page-layout.config.ts index bb729088be..4bcae29deb 100644 --- a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/page-layout-config/standard-opportunity-page-layout.config.ts +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/page-layout-config/standard-opportunity-page-layout.config.ts @@ -1,6 +1,5 @@ -import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; - import { PageLayoutType } from 'src/engine/metadata-modules/page-layout/enums/page-layout-type.enum'; +import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; import { TAB_PROPS, WIDGET_PROPS, @@ -87,7 +86,7 @@ export const STANDARD_OPPORTUNITY_PAGE_LAYOUT_CONFIG = { layoutName: 'opportunityRecordPage', name: 'Default Opportunity Layout', type: PageLayoutType.RECORD_PAGE, - objectUniversalIdentifier: STANDARD_OBJECT_IDS.opportunity, + objectUniversalIdentifier: STANDARD_OBJECTS.opportunity.universalIdentifier, universalIdentifier: '20202020-a103-4003-8003-0aa0b1ca1003', defaultTabUniversalIdentifier: OPPORTUNITY_PAGE_TABS.home.universalIdentifier, tabs: OPPORTUNITY_PAGE_TABS, diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/page-layout-config/standard-person-page-layout.config.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/page-layout-config/standard-person-page-layout.config.ts index e99dd7ccdd..b5d040e280 100644 --- a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/page-layout-config/standard-person-page-layout.config.ts +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/page-layout-config/standard-person-page-layout.config.ts @@ -1,6 +1,5 @@ -import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; - import { PageLayoutType } from 'src/engine/metadata-modules/page-layout/enums/page-layout-type.enum'; +import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; import { TAB_PROPS, WIDGET_PROPS, @@ -87,7 +86,7 @@ export const STANDARD_PERSON_PAGE_LAYOUT_CONFIG = { layoutName: 'personRecordPage', name: 'Default Person Layout', type: PageLayoutType.RECORD_PAGE, - objectUniversalIdentifier: STANDARD_OBJECT_IDS.person, + objectUniversalIdentifier: STANDARD_OBJECTS.person.universalIdentifier, universalIdentifier: '20202020-a102-4002-8002-ae0a1ea11002', defaultTabUniversalIdentifier: PERSON_PAGE_TABS.home.universalIdentifier, tabs: PERSON_PAGE_TABS, diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/page-layout-config/standard-task-page-layout.config.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/page-layout-config/standard-task-page-layout.config.ts index c8b16a27bb..b26a201b79 100644 --- a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/page-layout-config/standard-task-page-layout.config.ts +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/page-layout-config/standard-task-page-layout.config.ts @@ -1,6 +1,5 @@ -import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; - import { PageLayoutType } from 'src/engine/metadata-modules/page-layout/enums/page-layout-type.enum'; +import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; import { TAB_PROPS, WIDGET_PROPS, @@ -61,7 +60,7 @@ export const STANDARD_TASK_PAGE_LAYOUT_CONFIG = { layoutName: 'taskRecordPage', name: 'Default Task Layout', type: PageLayoutType.RECORD_PAGE, - objectUniversalIdentifier: STANDARD_OBJECT_IDS.task, + objectUniversalIdentifier: STANDARD_OBJECTS.task.universalIdentifier, universalIdentifier: '20202020-a105-4005-8005-ba5ca11a1005', defaultTabUniversalIdentifier: TASK_PAGE_TABS.home.universalIdentifier, tabs: TASK_PAGE_TABS, diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/page-layout-config/standard-workflow-page-layout.config.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/page-layout-config/standard-workflow-page-layout.config.ts index 86f76a4bc1..a46bc098fe 100644 --- a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/page-layout-config/standard-workflow-page-layout.config.ts +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/page-layout-config/standard-workflow-page-layout.config.ts @@ -1,6 +1,5 @@ -import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; - import { PageLayoutType } from 'src/engine/metadata-modules/page-layout/enums/page-layout-type.enum'; +import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; import { TAB_PROPS, WIDGET_PROPS, @@ -27,7 +26,7 @@ export const STANDARD_WORKFLOW_PAGE_LAYOUT_CONFIG = { layoutName: 'workflowRecordPage', name: 'Default Workflow Layout', type: PageLayoutType.RECORD_PAGE, - objectUniversalIdentifier: STANDARD_OBJECT_IDS.workflow, + objectUniversalIdentifier: STANDARD_OBJECTS.workflow.universalIdentifier, universalIdentifier: '20202020-a106-4006-8006-a0bcf10aa006', defaultTabUniversalIdentifier: WORKFLOW_PAGE_TABS.flow.universalIdentifier, tabs: WORKFLOW_PAGE_TABS, diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/page-layout-config/standard-workflow-run-page-layout.config.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/page-layout-config/standard-workflow-run-page-layout.config.ts index a64d043d1b..57a9c01d8b 100644 --- a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/page-layout-config/standard-workflow-run-page-layout.config.ts +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/page-layout-config/standard-workflow-run-page-layout.config.ts @@ -1,6 +1,5 @@ -import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; - import { PageLayoutType } from 'src/engine/metadata-modules/page-layout/enums/page-layout-type.enum'; +import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; import { TAB_PROPS, WIDGET_PROPS, @@ -37,7 +36,7 @@ export const STANDARD_WORKFLOW_RUN_PAGE_LAYOUT_CONFIG = { layoutName: 'workflowRunRecordPage', name: 'Default Workflow Run Layout', type: PageLayoutType.RECORD_PAGE, - objectUniversalIdentifier: STANDARD_OBJECT_IDS.workflowRun, + objectUniversalIdentifier: STANDARD_OBJECTS.workflowRun.universalIdentifier, universalIdentifier: '20202020-a108-4008-8008-a0bcf10ac008', defaultTabUniversalIdentifier: WORKFLOW_RUN_PAGE_TABS.flow.universalIdentifier, diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/page-layout-config/standard-workflow-version-page-layout.config.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/page-layout-config/standard-workflow-version-page-layout.config.ts index 064289f25c..6db4c1b642 100644 --- a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/page-layout-config/standard-workflow-version-page-layout.config.ts +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/page-layout-config/standard-workflow-version-page-layout.config.ts @@ -1,6 +1,5 @@ -import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; - import { PageLayoutType } from 'src/engine/metadata-modules/page-layout/enums/page-layout-type.enum'; +import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; import { TAB_PROPS, WIDGET_PROPS, @@ -37,7 +36,8 @@ export const STANDARD_WORKFLOW_VERSION_PAGE_LAYOUT_CONFIG = { layoutName: 'workflowVersionRecordPage', name: 'Default Workflow Version Layout', type: PageLayoutType.RECORD_PAGE, - objectUniversalIdentifier: STANDARD_OBJECT_IDS.workflowVersion, + objectUniversalIdentifier: + STANDARD_OBJECTS.workflowVersion.universalIdentifier, universalIdentifier: '20202020-a107-4007-8007-a0bcf10ab007', defaultTabUniversalIdentifier: WORKFLOW_VERSION_PAGE_TABS.flow.universalIdentifier, diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/page-layout/create-standard-page-layout-flat-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/page-layout/create-standard-page-layout-flat-metadata.util.ts index 534293a178..07270f9d3b 100644 --- a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/page-layout/create-standard-page-layout-flat-metadata.util.ts +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/page-layout/create-standard-page-layout-flat-metadata.util.ts @@ -1,8 +1,8 @@ -import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; import { isDefined } from 'twenty-shared/utils'; import { type FlatPageLayout } from 'src/engine/metadata-modules/flat-page-layout/types/flat-page-layout.type'; import { type PageLayoutType } from 'src/engine/metadata-modules/page-layout/enums/page-layout-type.enum'; +import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; import { STANDARD_PAGE_LAYOUTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-page-layout.constant'; import { type StandardObjectMetadataRelatedEntityIds } from 'src/engine/workspace-manager/twenty-standard-application/utils/get-standard-object-metadata-related-entity-ids.util'; import { type StandardPageLayoutMetadataRelatedEntityIds } from 'src/engine/workspace-manager/twenty-standard-application/utils/get-standard-page-layout-metadata-related-entity-ids.util'; @@ -27,8 +27,8 @@ export type CreateStandardPageLayoutArgs = { export const findObjectNameByUniversalIdentifier = ( objectUniversalIdentifier: string, ): string => { - for (const [objectName, objectId] of Object.entries(STANDARD_OBJECT_IDS)) { - if (objectId === objectUniversalIdentifier) { + for (const [objectName, objectConfig] of Object.entries(STANDARD_OBJECTS)) { + if (objectConfig.universalIdentifier === objectUniversalIdentifier) { return objectName; } } diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration/workspace-migration-runner/action-handlers/object/services/utils/from-universal-flat-object-metadata-to-flat-object-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration/workspace-migration-runner/action-handlers/object/services/utils/from-universal-flat-object-metadata-to-flat-object-metadata.util.ts index 6cbbd3abaf..7bdc1289c5 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-migration/workspace-migration-runner/action-handlers/object/services/utils/from-universal-flat-object-metadata-to-flat-object-metadata.util.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration/workspace-migration-runner/action-handlers/object/services/utils/from-universal-flat-object-metadata-to-flat-object-metadata.util.ts @@ -104,7 +104,6 @@ export const fromUniversalFlatObjectMetadataToFlatObjectMetadata = ({ id: generatedId, workspaceId, applicationId, - standardId: null, universalIdentifier, applicationUniversalIdentifier, labelIdentifierFieldMetadataId, diff --git a/packages/twenty-server/src/modules/connected-account/query-hooks/connected-account-delete-one.pre-query.hook.ts b/packages/twenty-server/src/modules/connected-account/query-hooks/connected-account-delete-one.pre-query.hook.ts index cc4c0b96be..6a5db29729 100644 --- a/packages/twenty-server/src/modules/connected-account/query-hooks/connected-account-delete-one.pre-query.hook.ts +++ b/packages/twenty-server/src/modules/connected-account/query-hooks/connected-account-delete-one.pre-query.hook.ts @@ -1,4 +1,3 @@ -import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; import { assertIsDefinedOrThrow } from 'twenty-shared/utils'; import { type WorkspacePreQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface'; @@ -13,6 +12,7 @@ import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadat import { findFlatEntityByUniversalIdentifierOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-universal-identifier-or-throw.util'; import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; import { WorkspaceEventEmitter } from 'src/engine/workspace-event-emitter/workspace-event-emitter'; +import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; import { type MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity'; @WorkspaceQueryHook(`connectedAccount.destroyOne`) @@ -62,7 +62,7 @@ export class ConnectedAccountDeleteOnePreQueryHook const flatObjectMetadata = findFlatEntityByUniversalIdentifierOrThrow({ flatEntityMaps: flatObjectMetadataMaps, - universalIdentifier: STANDARD_OBJECT_IDS.messageChannel, + universalIdentifier: STANDARD_OBJECTS.messageChannel.universalIdentifier, }); // TODO: handle cascade events for delete diff --git a/packages/twenty-server/src/modules/contact-creation-manager/services/__tests__/create-company.service.spec.ts b/packages/twenty-server/src/modules/contact-creation-manager/services/__tests__/create-company.service.spec.ts index 377fc85ba6..b448d58a72 100644 --- a/packages/twenty-server/src/modules/contact-creation-manager/services/__tests__/create-company.service.spec.ts +++ b/packages/twenty-server/src/modules/contact-creation-manager/services/__tests__/create-company.service.spec.ts @@ -2,7 +2,6 @@ import { Test, type TestingModule } from '@nestjs/testing'; import { getRepositoryToken } from '@nestjs/typeorm'; import axios from 'axios'; -import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; import { ConnectedAccountProvider, FieldActorSource, @@ -10,6 +9,7 @@ import { import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; +import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; import { type CompanyToCreate, CreateCompanyService, @@ -128,7 +128,7 @@ describe('CreateCompanyService', () => { useValue: { findOne: jest.fn().mockResolvedValue({ id: 'mock-object-metadata-id', - standardId: STANDARD_OBJECT_IDS.company, + universalIdentifier: STANDARD_OBJECTS.company.universalIdentifier, workspaceId, nameSingular: 'company', namePlural: 'companies', diff --git a/packages/twenty-server/src/utils/__test__/get-object-metadata-entity.mock.ts b/packages/twenty-server/src/utils/__test__/get-object-metadata-entity.mock.ts index 5a48de52c8..0efc214030 100644 --- a/packages/twenty-server/src/utils/__test__/get-object-metadata-entity.mock.ts +++ b/packages/twenty-server/src/utils/__test__/get-object-metadata-entity.mock.ts @@ -43,7 +43,6 @@ export const getMockObjectMetadataEntity = ( labelSingular: 'Default mock plural singular', objectPermissions: [], shortcut: null, - standardId: null, universalIdentifier: faker.string.uuid(), applicationId: faker.string.uuid(), application: {} as ApplicationEntity, diff --git a/packages/twenty-shared/src/metadata/standard-object-ids.ts b/packages/twenty-shared/src/metadata/standard-object-ids.ts index 9b1ed07242..e7ec9b9f3e 100644 --- a/packages/twenty-shared/src/metadata/standard-object-ids.ts +++ b/packages/twenty-shared/src/metadata/standard-object-ids.ts @@ -5,6 +5,7 @@ * For readability keys can be edited but the values should not be changed. */ +// TODO remove once fieldMetadata standard id has been deprecated export const STANDARD_OBJECT_IDS = { // TODO: check if activity, activityTarget and comment can be deleted activityTarget: '20202020-2945-440e-8d1a-f84672d33d5e',