diff --git a/packages/twenty-client-sdk/src/metadata/generated/schema.graphql b/packages/twenty-client-sdk/src/metadata/generated/schema.graphql index e88d30e421..df6d8f2b91 100644 --- a/packages/twenty-client-sdk/src/metadata/generated/schema.graphql +++ b/packages/twenty-client-sdk/src/metadata/generated/schema.graphql @@ -1726,8 +1726,6 @@ enum FeatureFlagKey { IS_EMAILING_DOMAIN_ENABLED IS_JUNCTION_RELATIONS_ENABLED IS_COMMAND_MENU_ITEM_ENABLED - IS_NAVIGATION_MENU_ITEM_ENABLED - IS_NAVIGATION_MENU_ITEM_EDITING_ENABLED IS_DRAFT_EMAIL_ENABLED IS_USAGE_ANALYTICS_ENABLED IS_RICH_TEXT_V1_MIGRATED diff --git a/packages/twenty-client-sdk/src/metadata/generated/schema.ts b/packages/twenty-client-sdk/src/metadata/generated/schema.ts index c8f4c2bf22..5f7795deac 100644 --- a/packages/twenty-client-sdk/src/metadata/generated/schema.ts +++ b/packages/twenty-client-sdk/src/metadata/generated/schema.ts @@ -1422,7 +1422,7 @@ export interface PublicFeatureFlag { __typename: 'PublicFeatureFlag' } -export type FeatureFlagKey = 'IS_UNIQUE_INDEXES_ENABLED' | 'IS_JSON_FILTER_ENABLED' | 'IS_AI_ENABLED' | 'IS_MARKETPLACE_ENABLED' | 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED' | 'IS_PUBLIC_DOMAIN_ENABLED' | 'IS_EMAILING_DOMAIN_ENABLED' | 'IS_JUNCTION_RELATIONS_ENABLED' | 'IS_COMMAND_MENU_ITEM_ENABLED' | 'IS_NAVIGATION_MENU_ITEM_ENABLED' | 'IS_NAVIGATION_MENU_ITEM_EDITING_ENABLED' | 'IS_DRAFT_EMAIL_ENABLED' | 'IS_USAGE_ANALYTICS_ENABLED' | 'IS_RICH_TEXT_V1_MIGRATED' | 'IS_DIRECT_GRAPHQL_EXECUTION_ENABLED' | 'IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED' | 'IS_CONNECTED_ACCOUNT_MIGRATED' | 'IS_GRAPHQL_QUERY_TIMING_ENABLED' | 'IS_RECORD_TABLE_WIDGET_ENABLED' | 'IS_DATASOURCE_MIGRATED' +export type FeatureFlagKey = 'IS_UNIQUE_INDEXES_ENABLED' | 'IS_JSON_FILTER_ENABLED' | 'IS_AI_ENABLED' | 'IS_MARKETPLACE_ENABLED' | 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED' | 'IS_PUBLIC_DOMAIN_ENABLED' | 'IS_EMAILING_DOMAIN_ENABLED' | 'IS_JUNCTION_RELATIONS_ENABLED' | 'IS_COMMAND_MENU_ITEM_ENABLED' | 'IS_DRAFT_EMAIL_ENABLED' | 'IS_USAGE_ANALYTICS_ENABLED' | 'IS_RICH_TEXT_V1_MIGRATED' | 'IS_DIRECT_GRAPHQL_EXECUTION_ENABLED' | 'IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED' | 'IS_CONNECTED_ACCOUNT_MIGRATED' | 'IS_GRAPHQL_QUERY_TIMING_ENABLED' | 'IS_RECORD_TABLE_WIDGET_ENABLED' | 'IS_DATASOURCE_MIGRATED' export interface ClientConfig { appVersion?: Scalars['String'] @@ -8953,8 +8953,6 @@ export const enumFeatureFlagKey = { IS_EMAILING_DOMAIN_ENABLED: 'IS_EMAILING_DOMAIN_ENABLED' as const, IS_JUNCTION_RELATIONS_ENABLED: 'IS_JUNCTION_RELATIONS_ENABLED' as const, IS_COMMAND_MENU_ITEM_ENABLED: 'IS_COMMAND_MENU_ITEM_ENABLED' as const, - IS_NAVIGATION_MENU_ITEM_ENABLED: 'IS_NAVIGATION_MENU_ITEM_ENABLED' as const, - IS_NAVIGATION_MENU_ITEM_EDITING_ENABLED: 'IS_NAVIGATION_MENU_ITEM_EDITING_ENABLED' as const, IS_DRAFT_EMAIL_ENABLED: 'IS_DRAFT_EMAIL_ENABLED' as const, IS_USAGE_ANALYTICS_ENABLED: 'IS_USAGE_ANALYTICS_ENABLED' as const, IS_RICH_TEXT_V1_MIGRATED: 'IS_RICH_TEXT_V1_MIGRATED' as const, diff --git a/packages/twenty-front/src/generated-metadata/graphql.ts b/packages/twenty-front/src/generated-metadata/graphql.ts index ce50e1be32..7a837a1758 100644 --- a/packages/twenty-front/src/generated-metadata/graphql.ts +++ b/packages/twenty-front/src/generated-metadata/graphql.ts @@ -1702,8 +1702,6 @@ export enum FeatureFlagKey { IS_JSON_FILTER_ENABLED = 'IS_JSON_FILTER_ENABLED', IS_JUNCTION_RELATIONS_ENABLED = 'IS_JUNCTION_RELATIONS_ENABLED', IS_MARKETPLACE_ENABLED = 'IS_MARKETPLACE_ENABLED', - IS_NAVIGATION_MENU_ITEM_EDITING_ENABLED = 'IS_NAVIGATION_MENU_ITEM_EDITING_ENABLED', - IS_NAVIGATION_MENU_ITEM_ENABLED = 'IS_NAVIGATION_MENU_ITEM_ENABLED', IS_PUBLIC_DOMAIN_ENABLED = 'IS_PUBLIC_DOMAIN_ENABLED', IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED = 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED', IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED = 'IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED', diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-19/1-19-add-missing-system-fields-to-standard-objects.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-19/1-19-add-missing-system-fields-to-standard-objects.command.ts deleted file mode 100644 index f9c2533b1b..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-19/1-19-add-missing-system-fields-to-standard-objects.command.ts +++ /dev/null @@ -1,241 +0,0 @@ -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 { ADD_MISSING_SYSTEM_FIELDS_TO_STANDARD_OBJECTS_1771420702241 } from 'src/database/commands/upgrade-version-command/workspace-migrations/1771420702241-add-missing-system-fields-to-standard-objects'; -import { WorkspaceMigrationRunnerException } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/exceptions/workspace-migration-runner.exception'; -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'; -import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service'; -import { type WorkspaceMigration } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/workspace-migration.type'; -import { WorkspaceMigrationRunnerService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/services/workspace-migration-runner.service'; - -const { applicationUniversalIdentifier, actions: allActions } = - ADD_MISSING_SYSTEM_FIELDS_TO_STANDARD_OBJECTS_1771420702241; - -const NON_TS_VECTOR_MIGRATION: WorkspaceMigration = { - applicationUniversalIdentifier, - actions: allActions.filter( - (action) => action.flatEntity.type !== FieldMetadataType.TS_VECTOR, - ), -}; - -const TS_VECTOR_INDIVIDUAL_MIGRATIONS = allActions - .filter((action) => action.flatEntity.type === FieldMetadataType.TS_VECTOR) - .map((action) => ({ - universalIdentifier: action.flatEntity.universalIdentifier, - fieldName: action.flatEntity.name, - objectIdentifier: action.flatEntity.objectMetadataUniversalIdentifier, - migration: { - applicationUniversalIdentifier, - actions: [action], - } satisfies WorkspaceMigration, - })); - -const NON_TS_VECTOR_INDIVIDUAL_MIGRATIONS = allActions - .filter((action) => action.flatEntity.type !== FieldMetadataType.TS_VECTOR) - .map((action) => ({ - universalIdentifier: action.flatEntity.universalIdentifier, - fieldName: action.flatEntity.name, - objectIdentifier: action.flatEntity.objectMetadataUniversalIdentifier, - migration: { - applicationUniversalIdentifier, - actions: [action], - } satisfies WorkspaceMigration, - })); - -const FIRST_NON_TS_VECTOR_UNIVERSAL_IDENTIFIER = - allActions[0].flatEntity.universalIdentifier; - -const DUPLICATE_KEY_MESSAGE = 'duplicate key value violates unique constraint'; - -const getNestedErrorMessages = ( - error: WorkspaceMigrationRunnerException, -): string | undefined => { - const nestedErrors = error.errors; - - if (!isDefined(nestedErrors)) { - return undefined; - } - - const details = [ - nestedErrors.metadata && `metadata: ${nestedErrors.metadata.message}`, - nestedErrors.workspaceSchema && - `workspaceSchema: ${nestedErrors.workspaceSchema.message}`, - nestedErrors.actionTranspilation && - `actionTranspilation: ${nestedErrors.actionTranspilation.message}`, - ] - .filter(isDefined) - .join('; '); - - return details || undefined; -}; - -const isUniqueViolationError = (error: Error): boolean => { - if (error.message.includes(DUPLICATE_KEY_MESSAGE)) { - return true; - } - - if (error instanceof WorkspaceMigrationRunnerException) { - const nestedMessages = getNestedErrorMessages(error); - - return nestedMessages?.includes(DUPLICATE_KEY_MESSAGE) === true; - } - - return false; -}; - -const enrichErrorMessage = (error: Error): Error => { - if (!(error instanceof WorkspaceMigrationRunnerException)) { - return error; - } - - const details = getNestedErrorMessages(error); - - if (isDefined(details)) { - error.message = `${error.message} (${details})`; - } - - return error; -}; - -@Command({ - name: 'upgrade:1-19:add-missing-system-fields-to-standard-objects', - description: - 'Add missing system fields (position, searchVector, createdBy, updatedBy) to standard objects', -}) -export class AddMissingSystemFieldsToStandardObjectsCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner { - constructor( - @InjectRepository(WorkspaceEntity) - protected readonly workspaceRepository: Repository, - protected readonly twentyORMGlobalManager: GlobalWorkspaceOrmManager, - protected readonly dataSourceService: DataSourceService, - private readonly workspaceCacheService: WorkspaceCacheService, - private readonly workspaceMigrationRunnerService: WorkspaceMigrationRunnerService, - ) { - super(workspaceRepository, twentyORMGlobalManager, dataSourceService); - } - - private async runIndividualMigrations( - workspaceId: string, - migrations: { - universalIdentifier: string; - fieldName: string; - objectIdentifier: string; - migration: WorkspaceMigration; - }[], - ): Promise { - for (const entry of migrations) { - const alreadyCreated = await this.hasFieldBeenCreated( - workspaceId, - entry.universalIdentifier, - ); - - if (alreadyCreated) { - continue; - } - - this.logger.log( - `Adding field ${entry.fieldName} on object ${entry.objectIdentifier} in workspace ${workspaceId}`, - ); - - try { - await this.workspaceMigrationRunnerService.run({ - workspaceId, - workspaceMigration: entry.migration, - }); - } catch (error) { - if (!isUniqueViolationError(error)) { - throw enrichErrorMessage(error); - } - - this.logger.warn( - `Field ${entry.fieldName} on object ${entry.objectIdentifier} already exists in workspace ${workspaceId}, skipping`, - ); - } - } - } - - private async hasFieldBeenCreated( - workspaceId: string, - universalIdentifier: string, - ): Promise { - const { flatFieldMetadataMaps } = - await this.workspaceCacheService.getOrRecompute(workspaceId, [ - 'flatFieldMetadataMaps', - ]); - - return isDefined( - flatFieldMetadataMaps.byUniversalIdentifier[universalIdentifier], - ); - } - - override async runOnWorkspace({ - workspaceId, - options, - }: RunOnWorkspaceArgs): Promise { - const dryRun = options?.dryRun ?? false; - - this.logger.log( - `${dryRun ? '[DRY RUN] ' : ''}Adding missing system fields to standard objects in workspace ${workspaceId}`, - ); - - if (dryRun) { - this.logger.log( - `[DRY RUN] Would add ${NON_TS_VECTOR_MIGRATION.actions.length} non-tsVector fields and ${TS_VECTOR_INDIVIDUAL_MIGRATIONS.length} tsVector fields to standard objects in workspace ${workspaceId}. Skipping.`, - ); - - return; - } - - const nonTsVectorAlreadyRan = await this.hasFieldBeenCreated( - workspaceId, - FIRST_NON_TS_VECTOR_UNIVERSAL_IDENTIFIER, - ); - - if (!nonTsVectorAlreadyRan) { - this.logger.log( - `Adding ${NON_TS_VECTOR_MIGRATION.actions.length} non-tsVector fields (position, createdBy, updatedBy) in workspace ${workspaceId}`, - ); - - try { - await this.workspaceMigrationRunnerService.run({ - workspaceId, - workspaceMigration: NON_TS_VECTOR_MIGRATION, - }); - } catch (error) { - if (!isUniqueViolationError(error)) { - throw enrichErrorMessage(error); - } - - this.logger.warn( - `Batch non-tsVector migration hit a duplicate field in workspace ${workspaceId}, falling back to individual field migrations`, - ); - - await this.runIndividualMigrations( - workspaceId, - NON_TS_VECTOR_INDIVIDUAL_MIGRATIONS, - ); - } - } else { - this.logger.log( - `Non-tsVector fields already exist in workspace ${workspaceId}, skipping.`, - ); - } - - await this.runIndividualMigrations( - workspaceId, - TS_VECTOR_INDIVIDUAL_MIGRATIONS, - ); - - this.logger.log( - `Successfully added missing system fields to standard objects in workspace ${workspaceId}`, - ); - } -} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-19/1-19-backfill-message-channel-message-association-message-folder.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-19/1-19-backfill-message-channel-message-association-message-folder.command.ts deleted file mode 100644 index a042376711..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-19/1-19-backfill-message-channel-message-association-message-folder.command.ts +++ /dev/null @@ -1,157 +0,0 @@ -import { InjectRepository } from '@nestjs/typeorm'; - -import { Command } from 'nest-commander'; -import { STANDARD_OBJECTS } from 'twenty-shared/metadata'; -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/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 { findFlatEntityByUniversalIdentifierOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-universal-identifier-or-throw.util'; -import { findFlatEntityByUniversalIdentifier } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-universal-identifier.util'; -import { findManyFlatEntityByUniversalIdentifierInUniversalFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-many-flat-entity-by-universal-identifier-in-universal-flat-entity-maps-or-throw.util'; -import { isMorphOrRelationUniversalFlatFieldMetadata } 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 { 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'; - -const OBJECT_UNIVERSAL_IDENTIFIER_TO_CREATE = - STANDARD_OBJECTS.messageChannelMessageAssociationMessageFolder - .universalIdentifier; -const FIELD_UNIVERSAL_IDENTIFIERS_TO_CREATE = Object.values( - STANDARD_OBJECTS.messageChannelMessageAssociationMessageFolder.fields, -).map((el) => el.universalIdentifier); - -@Command({ - name: 'upgrade:1-19:backfill-message-channel-message-association-message-folder', - description: - 'Backfill messageChannelMessageAssociationMessageFolder standard object and its relation fields', -}) -export class BackfillMessageChannelMessageAssociationMessageFolderCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner { - constructor( - @InjectRepository(WorkspaceEntity) - protected readonly workspaceRepository: Repository, - protected readonly twentyORMGlobalManager: GlobalWorkspaceOrmManager, - protected readonly dataSourceService: DataSourceService, - private readonly applicationService: ApplicationService, - private readonly workspaceCacheService: WorkspaceCacheService, - private readonly workspaceMigrationValidateBuildAndRunService: WorkspaceMigrationValidateBuildAndRunService, - ) { - super(workspaceRepository, twentyORMGlobalManager, dataSourceService); - } - - override async runOnWorkspace({ - workspaceId, - options, - }: RunOnWorkspaceArgs): Promise { - const isDryRun = options.dryRun ?? false; - - this.logger.log( - `${isDryRun ? '[DRY RUN] ' : ''}Starting backfill of messageChannelMessageAssociationMessageFolder for workspace ${workspaceId}`, - ); - - const { flatObjectMetadataMaps } = - await this.workspaceCacheService.getOrRecompute(workspaceId, [ - 'flatObjectMetadataMaps', - ]); - - const existingObject = findFlatEntityByUniversalIdentifier({ - flatEntityMaps: flatObjectMetadataMaps, - universalIdentifier: OBJECT_UNIVERSAL_IDENTIFIER_TO_CREATE, - }); - - if (existingObject) { - this.logger.log( - `messageChannelMessageAssociationMessageFolder object already exists for workspace ${workspaceId}, skipping`, - ); - - return; - } - - if (isDryRun) { - this.logger.log( - `[DRY RUN] Would create messageChannelMessageAssociationMessageFolder object and relation fields for workspace ${workspaceId}`, - ); - - return; - } - - const { twentyStandardFlatApplication } = - await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow( - { workspaceId }, - ); - - const { allFlatEntityMaps: standardAllFlatEntityMaps } = - computeTwentyStandardApplicationAllFlatEntityMaps({ - now: new Date().toISOString(), - workspaceId, - twentyStandardApplicationId: twentyStandardFlatApplication.id, - }); - - const flatObjectMetadataToCreate = - findFlatEntityByUniversalIdentifierOrThrow({ - flatEntityMaps: standardAllFlatEntityMaps.flatObjectMetadataMaps, - universalIdentifier: OBJECT_UNIVERSAL_IDENTIFIER_TO_CREATE, - }); - - const flatFieldMetadataToCreateOnObject = - findManyFlatEntityByUniversalIdentifierInUniversalFlatEntityMapsOrThrow({ - flatEntityMaps: standardAllFlatEntityMaps.flatFieldMetadataMaps, - universalIdentifiers: FIELD_UNIVERSAL_IDENTIFIERS_TO_CREATE, - }); - const relatedFlatFieldMetadataToCreate = flatFieldMetadataToCreateOnObject - .map((flatFieldMetadata) => { - if (!isMorphOrRelationUniversalFlatFieldMetadata(flatFieldMetadata)) { - return undefined; - } - - return findFlatEntityByUniversalIdentifierOrThrow({ - flatEntityMaps: standardAllFlatEntityMaps.flatFieldMetadataMaps, - universalIdentifier: - flatFieldMetadata.relationTargetFieldMetadataUniversalIdentifier, - }); - }) - .filter(isDefined); - - const validateAndBuildResult = - await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration( - { - allFlatEntityOperationByMetadataName: { - objectMetadata: { - flatEntityToCreate: [flatObjectMetadataToCreate], - flatEntityToDelete: [], - flatEntityToUpdate: [], - }, - fieldMetadata: { - flatEntityToCreate: [ - ...flatFieldMetadataToCreateOnObject, - ...relatedFlatFieldMetadataToCreate, - ], - flatEntityToDelete: [], - flatEntityToUpdate: [], - }, - }, - workspaceId, - applicationUniversalIdentifier: - twentyStandardFlatApplication.universalIdentifier, - }, - ); - - if (validateAndBuildResult.status === 'fail') { - this.logger.error( - `Failed to create messageChannelMessageAssociationMessageFolder:\n${JSON.stringify(validateAndBuildResult, null, 2)}`, - ); - throw new Error( - `Failed to create messageChannelMessageAssociationMessageFolder for workspace ${workspaceId}`, - ); - } - - this.logger.log( - `Successfully created messageChannelMessageAssociationMessageFolder for workspace ${workspaceId}`, - ); - } -} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-19/1-19-backfill-missing-standard-views.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-19/1-19-backfill-missing-standard-views.command.ts deleted file mode 100644 index 5542f04348..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-19/1-19-backfill-missing-standard-views.command.ts +++ /dev/null @@ -1,185 +0,0 @@ -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 { ApplicationService } from 'src/engine/core-modules/application/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 { 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 { 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'; - -@Command({ - name: 'upgrade:1-19:backfill-missing-standard-views', - description: - 'Backfill missing standard views and their child entities (fields, groups, filters, field groups) for workspaces', -}) -export class BackfillMissingStandardViewsCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner { - constructor( - @InjectRepository(WorkspaceEntity) - protected readonly workspaceRepository: Repository, - protected readonly twentyORMGlobalManager: GlobalWorkspaceOrmManager, - protected readonly dataSourceService: DataSourceService, - private readonly applicationService: ApplicationService, - private readonly workspaceMigrationValidateBuildAndRunService: WorkspaceMigrationValidateBuildAndRunService, - private readonly workspaceCacheService: WorkspaceCacheService, - ) { - super(workspaceRepository, twentyORMGlobalManager, dataSourceService); - } - - override async runOnWorkspace({ - workspaceId, - options, - }: RunOnWorkspaceArgs): Promise { - const isDryRun = options.dryRun ?? false; - - this.logger.log( - `${isDryRun ? '[DRY RUN] ' : ''}Starting backfill of missing standard views for workspace ${workspaceId}`, - ); - - const { twentyStandardFlatApplication } = - await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow( - { workspaceId }, - ); - - const { allFlatEntityMaps: standardAllFlatEntityMaps } = - computeTwentyStandardApplicationAllFlatEntityMaps({ - shouldIncludeRecordPageLayouts: true, - now: new Date().toISOString(), - workspaceId, - twentyStandardApplicationId: twentyStandardFlatApplication.id, - }); - - const { flatViewMaps: existingFlatViewMaps } = - await this.workspaceCacheService.getOrRecompute(workspaceId, [ - 'flatViewMaps', - ]); - - const missingViewUniversalIdentifiers = new Set(); - - const viewsToCreate = Object.values( - standardAllFlatEntityMaps.flatViewMaps.byUniversalIdentifier, - ) - .filter(isDefined) - .filter((view) => { - const alreadyExists = isDefined( - existingFlatViewMaps.byUniversalIdentifier[view.universalIdentifier], - ); - - if (alreadyExists) { - return false; - } - - missingViewUniversalIdentifiers.add(view.universalIdentifier); - - return true; - }); - - if (viewsToCreate.length === 0) { - this.logger.log( - `No missing standard views for workspace ${workspaceId}, skipping`, - ); - - return; - } - - this.logger.log( - `Found ${viewsToCreate.length} missing standard view(s) for workspace ${workspaceId}`, - ); - - if (isDryRun) { - this.logger.log( - `[DRY RUN] Would create ${viewsToCreate.length} view(s) for workspace ${workspaceId}`, - ); - - return; - } - - const viewFieldsToCreate = Object.values( - standardAllFlatEntityMaps.flatViewFieldMaps.byUniversalIdentifier, - ) - .filter(isDefined) - .filter((viewField) => - missingViewUniversalIdentifiers.has(viewField.viewUniversalIdentifier), - ); - - const viewGroupsToCreate = Object.values( - standardAllFlatEntityMaps.flatViewGroupMaps.byUniversalIdentifier, - ) - .filter(isDefined) - .filter((viewGroup) => - missingViewUniversalIdentifiers.has(viewGroup.viewUniversalIdentifier), - ); - - const viewFiltersToCreate = Object.values( - standardAllFlatEntityMaps.flatViewFilterMaps.byUniversalIdentifier, - ) - .filter(isDefined) - .filter((viewFilter) => - missingViewUniversalIdentifiers.has(viewFilter.viewUniversalIdentifier), - ); - - const viewFieldGroupsToCreate = Object.values( - standardAllFlatEntityMaps.flatViewFieldGroupMaps.byUniversalIdentifier, - ) - .filter(isDefined) - .filter((viewFieldGroup) => - missingViewUniversalIdentifiers.has( - viewFieldGroup.viewUniversalIdentifier, - ), - ); - - const validateAndBuildResult = - await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration( - { - allFlatEntityOperationByMetadataName: { - view: { - flatEntityToCreate: viewsToCreate, - flatEntityToDelete: [], - flatEntityToUpdate: [], - }, - viewField: { - flatEntityToCreate: viewFieldsToCreate, - flatEntityToDelete: [], - flatEntityToUpdate: [], - }, - viewGroup: { - flatEntityToCreate: viewGroupsToCreate, - flatEntityToDelete: [], - flatEntityToUpdate: [], - }, - viewFilter: { - flatEntityToCreate: viewFiltersToCreate, - flatEntityToDelete: [], - flatEntityToUpdate: [], - }, - viewFieldGroup: { - flatEntityToCreate: viewFieldGroupsToCreate, - flatEntityToDelete: [], - flatEntityToUpdate: [], - }, - }, - workspaceId, - applicationUniversalIdentifier: - twentyStandardFlatApplication.universalIdentifier, - }, - ); - - if (validateAndBuildResult.status === 'fail') { - this.logger.warn( - `Failed to backfill missing standard views for workspace ${workspaceId}, skipping:\n${JSON.stringify(validateAndBuildResult)}`, - ); - - return; - } - - this.logger.log( - `Successfully backfilled ${viewsToCreate.length} standard view(s) for workspace ${workspaceId}`, - ); - } -} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-19/1-19-backfill-system-fields-is-system.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-19/1-19-backfill-system-fields-is-system.command.ts deleted file mode 100644 index 9ceb9acf89..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-19/1-19-backfill-system-fields-is-system.command.ts +++ /dev/null @@ -1,176 +0,0 @@ -import { InjectDataSource, InjectRepository } from '@nestjs/typeorm'; - -import { Command } from 'nest-commander'; -import { STANDARD_OBJECTS } from 'twenty-shared/metadata'; -import { FieldMetadataType } from 'twenty-shared/types'; -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 { 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 { PARTIAL_SYSTEM_FLAT_FIELD_METADATAS } from 'src/engine/metadata-modules/object-metadata/constants/partial-system-flat-field-metadatas.constant'; -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 { type WorkspaceCacheKeyName } from 'src/engine/workspace-cache/types/workspace-cache-key.type'; - -const SYSTEM_FIELD_NAMES = Object.keys(PARTIAL_SYSTEM_FLAT_FIELD_METADATAS); - -const POSITION_FIELDS_TO_FIX_TYPE = [ - STANDARD_OBJECTS.favorite.fields.position.universalIdentifier, - STANDARD_OBJECTS.favoriteFolder.fields.position.universalIdentifier, -]; - -const RELATION_FIELD_TYPES = [ - FieldMetadataType.RELATION, - FieldMetadataType.MORPH_RELATION, -]; - -@Command({ - name: 'upgrade:1-19:backfill-system-fields-is-system', - description: - 'Set isSystem to true for system field names, set isSystem to false for relation/morph_relation fields, and fix position field type for favorite/favoriteFolder', -}) -export class BackfillSystemFieldsIsSystemCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner { - constructor( - @InjectRepository(WorkspaceEntity) - protected readonly workspaceRepository: Repository, - @InjectDataSource() - private readonly coreDataSource: DataSource, - protected readonly twentyORMGlobalManager: GlobalWorkspaceOrmManager, - protected readonly dataSourceService: DataSourceService, - private readonly workspaceCacheService: WorkspaceCacheService, - private readonly workspaceCacheStorageService: WorkspaceCacheStorageService, - private readonly workspaceMetadataVersionService: WorkspaceMetadataVersionService, - ) { - super(workspaceRepository, twentyORMGlobalManager, dataSourceService); - } - - override async runOnWorkspace({ - workspaceId, - options, - }: RunOnWorkspaceArgs): Promise { - const dryRun = options?.dryRun ?? false; - - this.logger.log( - `${dryRun ? '[DRY RUN] ' : ''}Backfilling isSystem for system fields in workspace ${workspaceId}`, - ); - - if (dryRun) { - this.logger.log( - `[DRY RUN] Would set isSystem=true for fields named [${SYSTEM_FIELD_NAMES.join(', ')}], set isSystem=false for relation fields, and fix position field types in workspace ${workspaceId}. Skipping.`, - ); - - return; - } - - const queryRunner = this.coreDataSource.createQueryRunner(); - - await queryRunner.connect(); - - try { - let needsCacheInvalidation = false; - - const isSystemResult = await queryRunner.query( - `UPDATE core."fieldMetadata" - SET "isSystem" = true - WHERE "workspaceId" = $1 - AND "name" = ANY($2) - AND "isSystem" = false`, - [workspaceId, SYSTEM_FIELD_NAMES], - ); - - const isSystemUpdatedCount = isSystemResult?.[1] ?? 0; - - if (isSystemUpdatedCount > 0) { - this.logger.log( - `Set isSystem=true for ${isSystemUpdatedCount} field(s) in workspace ${workspaceId}`, - ); - needsCacheInvalidation = true; - } - - const relationIsSystemResult = await queryRunner.query( - `UPDATE core."fieldMetadata" - SET "isSystem" = false - WHERE "workspaceId" = $1 - AND "type" = ANY($2) - AND "isSystem" = true`, - [workspaceId, RELATION_FIELD_TYPES], - ); - - const relationIsSystemUpdatedCount = relationIsSystemResult?.[1] ?? 0; - - if (relationIsSystemUpdatedCount > 0) { - this.logger.log( - `Set isSystem=false for ${relationIsSystemUpdatedCount} relation field(s) in workspace ${workspaceId}`, - ); - needsCacheInvalidation = true; - } - - const positionTypeResult = await queryRunner.query( - `UPDATE core."fieldMetadata" - SET "type" = $1 - WHERE "workspaceId" = $2 - AND "universalIdentifier" = ANY($3) - AND "type" = $4`, - [ - FieldMetadataType.POSITION, - workspaceId, - POSITION_FIELDS_TO_FIX_TYPE, - FieldMetadataType.NUMBER, - ], - ); - - const positionTypeUpdatedCount = positionTypeResult?.[1] ?? 0; - - if (positionTypeUpdatedCount > 0) { - this.logger.log( - `Fixed type from NUMBER to POSITION for ${positionTypeUpdatedCount} field(s) in workspace ${workspaceId}`, - ); - needsCacheInvalidation = true; - } - - if (needsCacheInvalidation) { - await this.invalidateCaches(workspaceId); - } else { - this.logger.log( - `No fields needed updating in workspace ${workspaceId}`, - ); - } - } finally { - await queryRunner.release(); - } - } - - private async invalidateCaches(workspaceId: string): Promise { - const modifiedMetadataNames = ['fieldMetadata'] as const; - - const cacheKeysToInvalidate: WorkspaceCacheKeyName[] = [ - ...new Set( - modifiedMetadataNames - .flatMap((name) => [name, ...getMetadataRelatedMetadataNames(name)]) - .map(getMetadataFlatEntityMapsKey), - ), - 'ORMEntityMetadatas', - ]; - - await this.workspaceCacheService.invalidateAndRecompute( - workspaceId, - cacheKeysToInvalidate, - ); - - await this.workspaceMetadataVersionService.incrementMetadataVersion( - workspaceId, - ); - - await this.workspaceCacheStorageService.flush(workspaceId); - - this.logger.log( - `Cache invalidated and metadata version incremented for workspace ${workspaceId}`, - ); - } -} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-19/1-19-fix-invalid-standard-universal-identifiers.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-19/1-19-fix-invalid-standard-universal-identifiers.command.ts deleted file mode 100644 index 63893edc6e..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-19/1-19-fix-invalid-standard-universal-identifiers.command.ts +++ /dev/null @@ -1,677 +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 { 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 { 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 { type WorkspaceCacheKeyName } from 'src/engine/workspace-cache/types/workspace-cache-key.type'; -import { STANDARD_AGENT } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-agent.constant'; -import { STANDARD_ROLE } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-role.constant'; -import { STANDARD_SKILL } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-skill.constant'; - -const OLD_ROLE_ADMIN_UNIVERSAL_IDENTIFIER = - '20202020-0001-0001-0001-000000000001'; -const OLD_AGENT_HELPER_UNIVERSAL_IDENTIFIER = - '20202020-0002-0001-0001-000000000004'; - -const STANDARD_OBJECT_MISMATCHES = [ - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: 'c9e5a0b4-1d36-4f8c-0a7b-3e4f5d6c7a81', - newValue: '9d31ea73-13b6-4e06-84ee-c66c72bf7787', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: 'd0f6b1c5-2e47-4a9d-1b8c-4f5a6e7d8b92', - newValue: '55637a5a-1edc-4351-8d76-d40020bf8944', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: 'e1a7c2d6-3f58-4b0e-2c9d-5a6b7f8e9c03', - newValue: '4137ba06-184d-438f-b484-080f02a97659', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: 'f2b8d3e7-4a69-4c1f-3d0e-6b7c8a9f0d14', - newValue: '8cc162d1-c127-4981-878d-f78622f8f12d', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '03c9e4f8-5b70-4d2a-4e1f-7c8d9b0a1e25', - newValue: 'c10eba2d-ff1a-4eab-9285-50481c12a003', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '14d0f5a9-6c81-4e3b-5f2a-8d9e0c1b2f36', - newValue: 'fadeab4b-79ee-4173-af79-72c51fbad888', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '25e1a6b0-7d92-4f4c-6a3b-9e0f1d2c3a47', - newValue: '4daf320e-74d0-4f24-a45a-af3a09d741cb', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '36f2b7c1-8e03-4a5d-7b4c-0f1a2e3d4b58', - newValue: 'ff6b86c1-3112-4dfa-b734-c4789111a716', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '69c5e0f4-1b36-4d8a-0e7f-3c4d5b6a7e81', - newValue: 'c458ad97-8b95-43de-9003-88eb68576049', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '70d6f1a5-2c47-4e9b-1f8a-4d5e6c7b8f92', - newValue: '30e9b75a-881f-4a85-aaf1-f2d2464be1cf', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '81e7a2b6-3d58-4f0c-2a9b-5e6f7d8c9003', - newValue: '898aa202-428f-4a7a-a3b3-8f0a17a6658e', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '92f8b3c7-4e69-4a1d-3b0c-6f7a8e9d0114', - newValue: 'ec2ebfc9-0c9b-4597-a87d-aa295e2d8bfe', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: 'a3a9c4d8-5f70-4b2e-4c1d-7a8b9f0e1225', - newValue: 'dd300c61-f422-467a-91f4-de4f83c4175b', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: 'b4b0d5e9-6a81-4c3f-5d2e-8b9c0a1f2336', - newValue: 'c3eb62df-2cc1-4cc3-b7aa-e96a4d65c633', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: 'c5c1e6f0-7b92-4d4a-6e3f-9c0d1b2a3447', - newValue: '8e7ca28e-6002-4304-9dcc-0a8da93ca198', - }, - { - table: 'core."fieldMetadata"', - column: '"universalIdentifier"', - oldValue: '20202020-9b0c-5d6e-7f8a-9b0c1d2e3f4a', - newValue: '99c330c0-5b7d-4276-a764-aed84499dfb5', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: 'd6d2f7a1-8c03-4e5b-7f4a-0d1e2c3b4558', - newValue: 'e69f71aa-de0f-4b70-845f-7a8369c47928', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '0905c0d4-1f36-4b8e-0c7d-3a4b5f6e788b', - newValue: '1f360393-a336-435d-966d-8ec2645f875c', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '1016d1e5-2a47-4c9f-1d8e-4b5c6a7f899c', - newValue: 'c0369a13-49bd-48b0-a9f0-6ed0ee8e1b09', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '2127e2f6-3b58-4d0a-2e9f-5c6d7b80900d', - newValue: 'b8e9f696-5be4-48cb-815c-7c0bb8b69d38', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '3238f3a7-4c69-4e1b-3f0a-6d7e8c91011e', - newValue: 'd4f3ef9f-ae24-4cef-9d7a-684a24d4968b', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '4349a4b8-5d70-4f2c-4a1b-7e8f9d02122f', - newValue: 'a257158e-3a89-4715-970c-7fc38ac22370', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '5450b5c9-6e81-4a3d-5b2c-8f90ae132340', - newValue: 'd55711a3-3297-4fef-beab-48d733712a33', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '6561c6d0-7f92-4b4e-6c3d-90a1bf243451', - newValue: 'f30c9a75-a563-45a2-93b8-84f59004de8f', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '7672d7e1-8003-4c5f-7d4e-01b2c0354562', - newValue: 'dca73027-adbe-4078-ae47-8d17850b9f2b', - }, - { - table: 'core."fieldMetadata"', - column: '"universalIdentifier"', - oldValue: '20202020-c3d4-e5f6-a7b8-901234567890', - newValue: '9bfc9da7-ae2d-44fd-9563-ede90c5d6222', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '0905a0b4-1336-4f8c-0a7b-34e5f3687895', - newValue: '9bb24d40-60dd-4beb-8c64-a74e8c67f9ee', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '1a16b1c5-2447-4a9d-1b8c-45f6a47989a6', - newValue: '1b86ece8-7ce3-4df3-8771-fd4b5d45b2f2', - }, - { - table: 'core."fieldMetadata"', - column: '"universalIdentifier"', - oldValue: '20202020-d4e5-f6a7-b8c9-012345678901', - newValue: '7411cfa3-4fd9-4b90-a636-940015fd7243', - }, - { - table: 'core."fieldMetadata"', - column: '"universalIdentifier"', - oldValue: '20202020-e5f6-a7b8-c9d0-123456789012', - newValue: 'b3369d31-3856-4a7a-b007-ee353918127c', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '2b38d3e7-5779-4c1f-4e0f-78c9d70d1de9', - newValue: '8e6038aa-1f79-4a84-87b5-f33caa172e98', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '3c49e4f8-6880-4d2a-5f1a-89d0e81e2ef0', - newValue: '905299c3-ca81-435d-901c-f68b87562516', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '4d50f5a9-7991-4e3b-6a2b-90e1f92f3f01', - newValue: 'a3de1788-5dff-4849-ac5a-0dabe5fab216', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '2b27c2d6-3558-4b0e-2c9d-56a7b58a9ab7', - newValue: 'ab09a386-4dcc-41f7-8dc6-a6071e9c64b7', - }, - { - table: 'core."fieldMetadata"', - column: '"universalIdentifier"', - oldValue: '20202020-f6a7-b8c9-d0e1-234567890123', - newValue: 'cce5ce1e-31d0-42e6-83cd-90059244a484', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '3c38d3e7-4669-4c1f-3d0e-67b8c69b0bc8', - newValue: '6217f2a5-28ac-4b88-8a2a-45eee4580e57', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '4d49e4f8-5770-4d2a-4e1f-78c9d70c1cd9', - newValue: 'ab0863ba-f95e-493c-b86c-56e1bc7e5bc2', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '5e50f5a9-6881-4e3b-5f2a-89d0e81d2de0', - newValue: 'df805c2e-3bfe-4d51-8309-75e5eb4052fe', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '6f61a6b0-7992-4f4c-6a3b-90e1f92e3ef1', - newValue: 'ce1e3a9e-afe9-439d-abb7-6cc98a6fa405', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '7072b7c1-8003-4a5d-7b4c-01f2a03f4f02', - newValue: '7a05b45e-7aa6-4a7e-9bbc-299cbed53c96', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '0305e0f4-1336-4d8a-0e7f-34c5d36c7c35', - newValue: '7c069dc0-e83b-4cd5-aaa2-cac7f3e00d80', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '1416f1a5-2447-4e9b-1f8a-45d6e47d8d46', - newValue: '2d83909a-a383-4e82-b00a-8b7739f3f906', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '2527a2b6-3558-4f0c-2a9b-56e7f58e9e57', - newValue: '0d1a59b4-cc87-4b7d-804a-656e8504f371', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '3638b3c7-4669-4a1d-3b0c-67f8a69f0f68', - newValue: 'b8c2a673-a981-4357-a43d-313a358e4daa', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '4749c4d8-5770-4b2e-4c1d-78a9b70a1a79', - newValue: 'e161072d-37b1-477a-b944-ef0d65289574', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '5850d5e9-6881-4c3f-5d2e-89b0c81b2b80', - newValue: 'ae60d580-b562-44f2-a24d-7b8040063f83', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '6961e6f0-7992-4d4a-6e3f-90c1d92c3c91', - newValue: 'f53fdd28-a26b-47ba-81b5-6813ad622720', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '7072f7a1-8003-4e5b-7f4a-01d2e03d4d02', - newValue: '8a265a5c-d3ae-47dc-bdf9-b42cfa2ba639', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '0305c0d4-1336-4b8e-0c7d-34a5b36a7a35', - newValue: 'f48fa3b1-0cec-44da-a9e5-f8a5e766637e', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '1416d1e5-2447-4c9f-1d8e-45b6c47b8b46', - newValue: 'a86b32b3-01d3-4302-a152-8b7f247db7b4', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '2527e2f6-3558-4d0a-2e9f-56c7d58c9c57', - newValue: 'c882f7a4-b025-4d32-aa26-5ef2595bdbf9', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '3638f3a7-4669-4e1b-3f0a-67d8e69d0d68', - newValue: 'b7d305d1-6fae-4ed6-9bdc-354fe9032c0e', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '4749a4b8-5770-4f2c-4a1b-78e9f70e1e79', - newValue: 'c0af54c7-751b-4bb2-b102-677cc4e47402', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '5850b5c9-6881-4a3d-5b2c-89f0a81f2f80', - newValue: '6942e0ba-90f6-4c33-bf40-7f00b1ec35ab', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '6961c6d0-7992-4b4e-6c3d-90a1b92a3a91', - newValue: '5e0b2391-85ca-4a66-aef4-52d74245bec2', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '7072d7e1-8003-4c5f-7d4e-01b2c03b4b02', - newValue: '3e89a914-7bec-47bd-9cf9-743c6b83d001', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '0305a0b4-1336-4f8c-0a7b-34e5f36e7e35', - newValue: '995db1d8-0d3e-40f7-b0eb-5e6897bc9966', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '1416b1c5-2447-4a9d-1b8c-45f6a47f8f46', - newValue: '609cf622-86ef-48d1-812b-e1cab610a46c', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '2527c2d6-3558-4b0e-2c9d-56a7b58a9a57', - newValue: 'd6059ec2-92b0-4cfc-9fd8-78050f03108f', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '3638d3e7-4669-4c1f-3d0e-67b8c69b0b68', - newValue: 'd94329b3-5dc8-4141-ae28-31afe28f7135', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '4749e4f8-5770-4d2a-4e1f-78c9d70c1c79', - newValue: '1a2bd046-7c23-4e0a-9f8a-c3ca3a16d3b9', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '5850f5a9-6881-4e3b-5f2a-89d0e81d2d80', - newValue: 'e8821da9-728d-470a-bf5b-5a981fff7880', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '6961a6b0-7992-4f4c-6a3b-90e1f92e3e91', - newValue: 'c7e64c55-eb0c-4b93-b076-5cfcf2e2e042', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '7072b7c1-8003-4a5d-7b4c-01f2a03f4f03', - newValue: '7331ff89-a3f9-4ac0-9fa9-0de5663ae7b2', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '0305e0f4-1336-4d8a-0e7f-34c5d36c7c36', - newValue: 'e0ac5ad2-d0c8-4f72-b710-8e53b9dc18d9', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '1416f1a5-2447-4e9b-1f8a-45d6e47d8d47', - newValue: '8138c3b3-0b14-4ee1-be0e-debdde6b3219', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '2527a2b6-3558-4f0c-2a9b-56e7f58e9e58', - newValue: '6f3a65eb-2aee-4108-b8a0-c62da419d1dc', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '3638b3c7-4669-4a1d-3b0c-67f8a69f0f69', - newValue: '76da5f27-523c-44b6-ad06-12954f6b949f', - }, - { - table: 'core."indexMetadata"', - column: '"universalIdentifier"', - oldValue: '4749c4d8-5770-4b2e-4c1d-78a9b70a1a7a', - newValue: '8678dde9-a804-4a9e-80e3-9af35e471ec5', - }, - { - table: 'core."fieldMetadata"', - column: '"universalIdentifier"', - oldValue: '20202020-92d0-1d7f-a126-25ededa6b142', - newValue: '20202020-1ecc-4562-84c9-ff3a2f6cce85', - }, - { - table: 'core."skill"', - column: '"universalIdentifier"', - oldValue: '20202020-6155-838a-b64e-44a791fbdc13', - newValue: STANDARD_SKILL['workflow-building'].universalIdentifier, - }, - { - table: 'core."skill"', - column: '"universalIdentifier"', - oldValue: '20202020-e225-f5c7-3d56-45feaa36f2e6', - newValue: STANDARD_SKILL['data-manipulation'].universalIdentifier, - }, - { - table: 'core."skill"', - column: '"universalIdentifier"', - oldValue: '20202020-398f-0d7a-82db-4f43bc7e7044', - newValue: STANDARD_SKILL['dashboard-building'].universalIdentifier, - }, - { - table: 'core."skill"', - column: '"universalIdentifier"', - oldValue: '20202020-c66a-5fed-4a74-46e0b42a6332', - newValue: STANDARD_SKILL['metadata-building'].universalIdentifier, - }, - { - table: 'core."skill"', - column: '"universalIdentifier"', - oldValue: '20202020-db75-4fca-6813-4c7db0f964a0', - newValue: STANDARD_SKILL.research.universalIdentifier, - }, - { - table: 'core."skill"', - column: '"universalIdentifier"', - oldValue: '20202020-5eb9-e775-cf4e-4f22be7be362', - newValue: STANDARD_SKILL['code-interpreter'].universalIdentifier, - }, - { - table: 'core."skill"', - column: '"universalIdentifier"', - oldValue: '20202020-2c7f-5b77-dfa4-494b84752ab7', - newValue: STANDARD_SKILL.xlsx.universalIdentifier, - }, - { - table: 'core."skill"', - column: '"universalIdentifier"', - oldValue: '20202020-c3d1-e0c9-2f93-45648b8bbd26', - newValue: STANDARD_SKILL.pdf.universalIdentifier, - }, - { - table: 'core."skill"', - column: '"universalIdentifier"', - oldValue: '20202020-6f15-2432-0537-4e23a2efd1cb', - newValue: STANDARD_SKILL.docx.universalIdentifier, - }, - { - table: 'core."skill"', - column: '"universalIdentifier"', - oldValue: '20202020-c81b-baf8-5255-4c34bd0eac9b', - newValue: STANDARD_SKILL.pptx.universalIdentifier, - }, -]; - -@Command({ - name: 'upgrade:1-19:fix-invalid-standard-universal-identifiers', - description: - 'Fix invalid universalIdentifier values in core tables to comply with UUID v4 format', -}) -export class FixInvalidStandardUniversalIdentifiersCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner { - constructor( - @InjectRepository(WorkspaceEntity) - protected readonly workspaceRepository: Repository, - @InjectDataSource() - private readonly coreDataSource: DataSource, - protected readonly twentyORMGlobalManager: GlobalWorkspaceOrmManager, - protected readonly dataSourceService: DataSourceService, - private readonly workspaceCacheService: WorkspaceCacheService, - private readonly workspaceCacheStorageService: WorkspaceCacheStorageService, - private readonly workspaceMetadataVersionService: WorkspaceMetadataVersionService, - ) { - super(workspaceRepository, twentyORMGlobalManager, dataSourceService); - } - - override async runOnWorkspace({ - workspaceId, - options, - }: RunOnWorkspaceArgs): Promise { - const isDryRun = options?.dryRun ?? false; - - this.logger.log( - `${isDryRun ? '[DRY RUN] ' : ''}Fixing universal identifiers for workspace ${workspaceId}`, - ); - - if (isDryRun) { - this.logger.log( - `[DRY RUN] Would fix role, agent, skill, and ${STANDARD_OBJECT_MISMATCHES.length} standard object universal identifier mismatches in workspace ${workspaceId}. Skipping.`, - ); - - return; - } - - const queryRunner = this.coreDataSource.createQueryRunner(); - - await queryRunner.connect(); - - try { - let totalUpdated = 0; - - const roleResult = await queryRunner.query( - `UPDATE core."role" - SET "universalIdentifier" = $1 - WHERE "workspaceId" = $2 - AND "universalIdentifier" = $3`, - [ - STANDARD_ROLE.admin.universalIdentifier, - workspaceId, - OLD_ROLE_ADMIN_UNIVERSAL_IDENTIFIER, - ], - ); - - const roleUpdatedCount = roleResult?.[1] ?? 0; - - if (roleUpdatedCount > 0) { - this.logger.log( - `Updated ${roleUpdatedCount} role universalIdentifier in workspace ${workspaceId}`, - ); - totalUpdated += roleUpdatedCount; - } - - const agentResult = await queryRunner.query( - `UPDATE core."agent" - SET "universalIdentifier" = $1 - WHERE "workspaceId" = $2 - AND "universalIdentifier" = $3`, - [ - STANDARD_AGENT.helper.universalIdentifier, - workspaceId, - OLD_AGENT_HELPER_UNIVERSAL_IDENTIFIER, - ], - ); - - const agentUpdatedCount = agentResult?.[1] ?? 0; - - if (agentUpdatedCount > 0) { - this.logger.log( - `Updated ${agentUpdatedCount} agent universalIdentifier in workspace ${workspaceId}`, - ); - totalUpdated += agentUpdatedCount; - } - - const updateCountsByTable: Record = {}; - - for (const mismatch of STANDARD_OBJECT_MISMATCHES) { - const result = await queryRunner.query( - `UPDATE ${mismatch.table} - SET ${mismatch.column} = $1 - WHERE "workspaceId" = $2 - AND ${mismatch.column} = $3`, - [mismatch.newValue, workspaceId, mismatch.oldValue], - ); - - const updatedCount = result?.[1] ?? 0; - - if (updatedCount > 0) { - const tableKey = `${mismatch.table}.${mismatch.column}`; - - updateCountsByTable[tableKey] = - (updateCountsByTable[tableKey] ?? 0) + updatedCount; - totalUpdated += updatedCount; - } - } - - for (const [tableKey, count] of Object.entries(updateCountsByTable)) { - this.logger.log( - `Updated ${count} rows in ${tableKey} for workspace ${workspaceId}`, - ); - } - - if (totalUpdated === 0) { - this.logger.log( - `No universal identifiers needed updating in workspace ${workspaceId}`, - ); - } else { - this.logger.log( - `Updated ${totalUpdated} total universal identifiers in workspace ${workspaceId}`, - ); - - await this.invalidateCaches(workspaceId); - } - } finally { - await queryRunner.release(); - } - } - - private async invalidateCaches(workspaceId: string): Promise { - const modifiedMetadataNames = [ - 'fieldMetadata', - 'index', - 'role', - 'agent', - 'skill', - ] as const; - - const cacheKeysToInvalidate: WorkspaceCacheKeyName[] = [ - ...new Set( - modifiedMetadataNames - .flatMap((name) => [name, ...getMetadataRelatedMetadataNames(name)]) - .map(getMetadataFlatEntityMapsKey), - ), - 'ORMEntityMetadatas', - 'rolesPermissions', - 'userWorkspaceRoleMap', - 'apiKeyRoleMap', - 'flatRoleTargetByAgentIdMaps', - ]; - - await this.workspaceCacheService.invalidateAndRecompute( - workspaceId, - cacheKeysToInvalidate, - ); - - await this.workspaceMetadataVersionService.incrementMetadataVersion( - workspaceId, - ); - - await this.workspaceCacheStorageService.flush(workspaceId); - - this.logger.log( - `Cache invalidated and metadata version incremented for workspace ${workspaceId}`, - ); - } -} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-19/1-19-seed-server-id.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-19/1-19-seed-server-id.command.ts deleted file mode 100644 index cc81c1f0e4..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-19/1-19-seed-server-id.command.ts +++ /dev/null @@ -1,46 +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 { 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'; -import { seedServerId } from 'src/engine/workspace-manager/dev-seeder/core/utils/seed-server-id.util'; - -@Command({ - name: 'upgrade:1-19:seed-server-id', - description: - 'Seed a unique SERVER_ID (UUID v4) into the keyValuePair table as a CONFIG_VARIABLE', -}) -export class SeedServerIdCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner { - private hasRun = false; - - constructor( - @InjectRepository(WorkspaceEntity) - protected readonly workspaceRepository: Repository, - @InjectDataSource() - private readonly coreDataSource: DataSource, - protected readonly twentyORMGlobalManager: GlobalWorkspaceOrmManager, - protected readonly dataSourceService: DataSourceService, - ) { - super(workspaceRepository, twentyORMGlobalManager, dataSourceService); - } - - override async runOnWorkspace(): Promise { - if (this.hasRun) { - return; - } - - const queryRunner = this.coreDataSource.createQueryRunner(); - - await seedServerId({ queryRunner, schemaName: 'core' }); - - this.hasRun = true; - - await queryRunner.release(); - - this.logger.log(`SERVER_ID seeded successfully`); - } -} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-19/1-19-upgrade-version-command.module.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-19/1-19-upgrade-version-command.module.ts deleted file mode 100644 index 5e51e2b97d..0000000000 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-19/1-19-upgrade-version-command.module.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { Module } from '@nestjs/common'; -import { TypeOrmModule } from '@nestjs/typeorm'; - -import { AddMissingSystemFieldsToStandardObjectsCommand } from 'src/database/commands/upgrade-version-command/1-19/1-19-add-missing-system-fields-to-standard-objects.command'; -import { BackfillMessageChannelMessageAssociationMessageFolderCommand } from 'src/database/commands/upgrade-version-command/1-19/1-19-backfill-message-channel-message-association-message-folder.command'; -import { BackfillMissingStandardViewsCommand } from 'src/database/commands/upgrade-version-command/1-19/1-19-backfill-missing-standard-views.command'; -import { BackfillSystemFieldsIsSystemCommand } from 'src/database/commands/upgrade-version-command/1-19/1-19-backfill-system-fields-is-system.command'; -import { FixInvalidStandardUniversalIdentifiersCommand } from 'src/database/commands/upgrade-version-command/1-19/1-19-fix-invalid-standard-universal-identifiers.command'; -import { SeedServerIdCommand } from 'src/database/commands/upgrade-version-command/1-19/1-19-seed-server-id.command'; -import { ApplicationModule } from 'src/engine/core-modules/application/application.module'; -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 { WorkspaceMetadataVersionModule } from 'src/engine/metadata-modules/workspace-metadata-version/workspace-metadata-version.module'; -import { WorkspaceCacheStorageModule } from 'src/engine/workspace-cache-storage/workspace-cache-storage.module'; -import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache.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]), - DataSourceModule, - WorkspaceCacheModule, - WorkspaceCacheStorageModule, - WorkspaceMetadataVersionModule, - WorkspaceMigrationRunnerModule, - ApplicationModule, - WorkspaceMigrationModule, - FeatureFlagModule, - ], - providers: [ - BackfillSystemFieldsIsSystemCommand, - AddMissingSystemFieldsToStandardObjectsCommand, - BackfillMessageChannelMessageAssociationMessageFolderCommand, - BackfillMissingStandardViewsCommand, - FixInvalidStandardUniversalIdentifiersCommand, - SeedServerIdCommand, - ], - exports: [ - BackfillSystemFieldsIsSystemCommand, - AddMissingSystemFieldsToStandardObjectsCommand, - BackfillMessageChannelMessageAssociationMessageFolderCommand, - BackfillMissingStandardViewsCommand, - FixInvalidStandardUniversalIdentifiersCommand, - SeedServerIdCommand, - ], -}) -export class V1_19_UpgradeVersionCommandModule {} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/upgrade-version-command.module.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/upgrade-version-command.module.ts index 8cc3fcc2a3..ba38815670 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,7 +1,6 @@ import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; -import { V1_19_UpgradeVersionCommandModule } from 'src/database/commands/upgrade-version-command/1-19/1-19-upgrade-version-command.module'; import { V1_20_UpgradeVersionCommandModule } from 'src/database/commands/upgrade-version-command/1-20/1-20-upgrade-version-command.module'; import { UpgradeCommand } from 'src/database/commands/upgrade-version-command/upgrade.command'; import { CoreEngineVersionModule } from 'src/engine/core-engine-version/core-engine-version.module'; @@ -13,7 +12,6 @@ import { WorkspaceVersionModule } from 'src/engine/workspace-manager/workspace-v @Module({ imports: [ TypeOrmModule.forFeature([WorkspaceEntity]), - V1_19_UpgradeVersionCommandModule, V1_20_UpgradeVersionCommandModule, DataSourceModule, CoreEngineVersionModule, 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 acaa29b58e..528d9ce06c 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 @@ -10,12 +10,6 @@ import { type VersionCommands, } from 'src/database/commands/command-runners/upgrade.command-runner'; import { CoreMigrationRunnerService } from 'src/database/commands/core-migration-runner/services/core-migration-runner.service'; -import { AddMissingSystemFieldsToStandardObjectsCommand } from 'src/database/commands/upgrade-version-command/1-19/1-19-add-missing-system-fields-to-standard-objects.command'; -import { BackfillMessageChannelMessageAssociationMessageFolderCommand } from 'src/database/commands/upgrade-version-command/1-19/1-19-backfill-message-channel-message-association-message-folder.command'; -import { BackfillMissingStandardViewsCommand } from 'src/database/commands/upgrade-version-command/1-19/1-19-backfill-missing-standard-views.command'; -import { BackfillSystemFieldsIsSystemCommand } from 'src/database/commands/upgrade-version-command/1-19/1-19-backfill-system-fields-is-system.command'; -import { FixInvalidStandardUniversalIdentifiersCommand } from 'src/database/commands/upgrade-version-command/1-19/1-19-fix-invalid-standard-universal-identifiers.command'; -import { SeedServerIdCommand } from 'src/database/commands/upgrade-version-command/1-19/1-19-seed-server-id.command'; import { BackfillCommandMenuItemsCommand } from 'src/database/commands/upgrade-version-command/1-20/1-20-backfill-command-menu-items.command'; import { BackfillNavigationMenuItemTypeCommand } from 'src/database/commands/upgrade-version-command/1-20/1-20-backfill-navigation-menu-item-type.command'; import { BackfillPageLayoutsAndFieldsWidgetViewFieldsCommand } from 'src/database/commands/upgrade-version-command/1-20/1-20-backfill-page-layouts-and-fields-widget-view-fields.command'; @@ -56,14 +50,6 @@ export class UpgradeCommand extends UpgradeCommandRunner { protected readonly workspaceVersionService: WorkspaceVersionService, protected readonly coreMigrationRunnerService: CoreMigrationRunnerService, - // 1.19 Commands - protected readonly backfillSystemFieldsIsSystemCommand: BackfillSystemFieldsIsSystemCommand, - protected readonly addMissingSystemFieldsToStandardObjectsCommand: AddMissingSystemFieldsToStandardObjectsCommand, - protected readonly backfillMessageChannelMessageAssociationMessageFolderCommand: BackfillMessageChannelMessageAssociationMessageFolderCommand, - protected readonly backfillMissingStandardViewsCommand: BackfillMissingStandardViewsCommand, - protected readonly fixRoleAndAgentUniversalIdentifiersCommand: FixInvalidStandardUniversalIdentifiersCommand, - protected readonly seedServerIdCommand: SeedServerIdCommand, - // 1.20 Commands protected readonly identifyPermissionFlagMetadataCommand: IdentifyPermissionFlagMetadataCommand, protected readonly makePermissionFlagUniversalIdentifierAndApplicationIdNotNullableMigrationCommand: MakePermissionFlagUniversalIdentifierAndApplicationIdNotNullableMigrationCommand, @@ -92,16 +78,6 @@ export class UpgradeCommand extends UpgradeCommandRunner { coreMigrationRunnerService, ); - const commands_1190: VersionCommands = [ - this.fixRoleAndAgentUniversalIdentifiersCommand, - this.backfillSystemFieldsIsSystemCommand, - this.addMissingSystemFieldsToStandardObjectsCommand, - this.backfillMessageChannelMessageAssociationMessageFolderCommand, - this.backfillMissingStandardViewsCommand, - this.fixRoleAndAgentUniversalIdentifiersCommand, - this.seedServerIdCommand, - ]; - const commands_1200: VersionCommands = [ this.identifyPermissionFlagMetadataCommand, this @@ -125,7 +101,7 @@ export class UpgradeCommand extends UpgradeCommandRunner { ]; this.allCommands = { - '1.19.0': commands_1190, + '1.19.0': [], '1.20.0': commands_1200, }; } diff --git a/packages/twenty-server/src/engine/core-modules/cache-lock/cache-lock.service.ts b/packages/twenty-server/src/engine/core-modules/cache-lock/cache-lock.service.ts index 2a775415ca..8e2123481f 100644 --- a/packages/twenty-server/src/engine/core-modules/cache-lock/cache-lock.service.ts +++ b/packages/twenty-server/src/engine/core-modules/cache-lock/cache-lock.service.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@nestjs/common'; +import { Injectable, Logger } from '@nestjs/common'; import { InjectCacheStorage } from 'src/engine/core-modules/cache-storage/decorators/cache-storage.decorator'; import { CacheStorageNamespace } from 'src/engine/core-modules/cache-storage/types/cache-storage-namespace.enum'; @@ -12,6 +12,8 @@ export type CacheLockOptions = { @Injectable() export class CacheLockService { + private readonly logger = new Logger(CacheLockService.name); + constructor( @InjectCacheStorage(CacheStorageNamespace.EngineLock) private readonly cacheStorageService: CacheStorageService, @@ -35,7 +37,13 @@ export class CacheLockService { try { return await fn(); } finally { - await this.cacheStorageService.releaseLock(key); + try { + await this.cacheStorageService.releaseLock(key); + } catch (releaseError) { + this.logger.warn( + `Failed to release lock for key "${key}": ${releaseError}`, + ); + } } } diff --git a/packages/twenty-server/src/engine/core-modules/metrics/metrics.service.ts b/packages/twenty-server/src/engine/core-modules/metrics/metrics.service.ts index 76a6d3bfc3..16657e8ce7 100644 --- a/packages/twenty-server/src/engine/core-modules/metrics/metrics.service.ts +++ b/packages/twenty-server/src/engine/core-modules/metrics/metrics.service.ts @@ -98,7 +98,7 @@ export class MetricsService { counter.add(1, attributes); if (shouldStoreInCache && eventId) { - this.metricsCacheService.updateCounter(key, [eventId]); + await this.metricsCacheService.updateCounter(key, [eventId]); } if (isDefined(debugLog)) { @@ -122,7 +122,7 @@ export class MetricsService { counter.add(eventIds.length, attributes); if (shouldStoreInCache) { - this.metricsCacheService.updateCounter(key, eventIds); + await this.metricsCacheService.updateCounter(key, eventIds); } } 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 65cb39c0d2..2bd4af3cae 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 @@ -239,8 +239,6 @@ describe('WorkspaceEntityManager', () => { IS_EMAILING_DOMAIN_ENABLED: false, IS_JUNCTION_RELATIONS_ENABLED: false, IS_COMMAND_MENU_ITEM_ENABLED: false, - IS_NAVIGATION_MENU_ITEM_ENABLED: false, - IS_NAVIGATION_MENU_ITEM_EDITING_ENABLED: false, IS_DRAFT_EMAIL_ENABLED: false, IS_USAGE_ANALYTICS_ENABLED: false, IS_RICH_TEXT_V1_MIGRATED: false, diff --git a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/seed-feature-flags.util.ts b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/seed-feature-flags.util.ts index 54ba630135..817de9dd80 100644 --- a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/seed-feature-flags.util.ts +++ b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/seed-feature-flags.util.ts @@ -45,16 +45,6 @@ export const seedFeatureFlags = async ({ workspaceId: workspaceId, value: true, }, - { - key: FeatureFlagKey.IS_NAVIGATION_MENU_ITEM_ENABLED, - workspaceId: workspaceId, - value: true, - }, - { - key: FeatureFlagKey.IS_NAVIGATION_MENU_ITEM_EDITING_ENABLED, - workspaceId: workspaceId, - value: true, - }, { key: FeatureFlagKey.IS_MARKETPLACE_ENABLED, workspaceId: workspaceId, diff --git a/packages/twenty-server/src/modules/workflow/workflow-runner/workflow-run-queue/workspace-services/workflow-run-enqueue.workspace-service.ts b/packages/twenty-server/src/modules/workflow/workflow-runner/workflow-run-queue/workspace-services/workflow-run-enqueue.workspace-service.ts index 04d906f8e6..8b89e4d92c 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-runner/workflow-run-queue/workspace-services/workflow-run-enqueue.workspace-service.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-runner/workflow-run-queue/workspace-services/workflow-run-enqueue.workspace-service.ts @@ -153,19 +153,30 @@ export class WorkflowRunEnqueueWorkspaceService { authContext, ); } catch (error) { - this.metricsService.incrementCounter({ - key: MetricsKeys.WorkflowRunFailedToEnqueue, - eventId: workspaceId, - }); + try { + await this.metricsService.incrementCounter({ + key: MetricsKeys.WorkflowRunFailedToEnqueue, + eventId: workspaceId, + }); + } catch { + // Metrics may fail if Redis is shutting down — safe to ignore + } this.logger.error( `Failed to enqueue workflow runs for workspace: ${workspaceId}`, error, ); } finally { - await this.workflowThrottlingWorkspaceService.releaseWorkflowEnqueueLock( - workspaceId, - ); + try { + await this.workflowThrottlingWorkspaceService.releaseWorkflowEnqueueLock( + workspaceId, + ); + } catch (releaseError) { + this.logger.warn( + `Failed to release workflow enqueue lock for workspace: ${workspaceId}`, + releaseError, + ); + } } } } diff --git a/packages/twenty-shared/src/types/FeatureFlagKey.ts b/packages/twenty-shared/src/types/FeatureFlagKey.ts index 57a716d172..337ef6588f 100644 --- a/packages/twenty-shared/src/types/FeatureFlagKey.ts +++ b/packages/twenty-shared/src/types/FeatureFlagKey.ts @@ -8,8 +8,6 @@ export enum FeatureFlagKey { IS_EMAILING_DOMAIN_ENABLED = 'IS_EMAILING_DOMAIN_ENABLED', IS_JUNCTION_RELATIONS_ENABLED = 'IS_JUNCTION_RELATIONS_ENABLED', IS_COMMAND_MENU_ITEM_ENABLED = 'IS_COMMAND_MENU_ITEM_ENABLED', - IS_NAVIGATION_MENU_ITEM_ENABLED = 'IS_NAVIGATION_MENU_ITEM_ENABLED', - IS_NAVIGATION_MENU_ITEM_EDITING_ENABLED = 'IS_NAVIGATION_MENU_ITEM_EDITING_ENABLED', IS_DRAFT_EMAIL_ENABLED = 'IS_DRAFT_EMAIL_ENABLED', IS_USAGE_ANALYTICS_ENABLED = 'IS_USAGE_ANALYTICS_ENABLED', IS_RICH_TEXT_V1_MIGRATED = 'IS_RICH_TEXT_V1_MIGRATED',