Deprecate legacy RICH_TEXT field metadata type (#18623)
## Summary - Removes the deprecated `RICH_TEXT` (V1) field metadata type from the codebase entirely - Adds a 1.20 upgrade command that migrates existing `RICH_TEXT` fields to `TEXT` in `core.fieldMetadata` - Cleans up ~70 files across `twenty-shared`, `twenty-server`, `twenty-front`, `twenty-sdk`, and `twenty-zapier` ## Context `RICH_TEXT` was a legacy field type that stored rich text as a single `text` column. It was already **read-only** — writes threw errors directing users to `RICH_TEXT_V2` instead. `RICH_TEXT_V2` is the current approach: a composite type with `blocknote` (editor JSON) and `markdown` subfields. Keeping the deprecated type added maintenance burden without any value. Since the underlying database column type for `RICH_TEXT` was already `text` (same as `TEXT`), the migration only needs to update the metadata — no data migration or column changes required. ## Changes ### Upgrade command (new) - `1-20-migrate-rich-text-to-text.command.ts` — runs `UPDATE core."fieldMetadata" SET "type" = 'TEXT' WHERE "type" = 'RICH_TEXT'` per workspace, with cache invalidation ### Enum & shared types - Removed `RICH_TEXT` from `FieldMetadataType` enum - Removed from `FieldMetadataDefaultValueMapping`, `isFieldMetadataTextKind` ### Server (~30 files) - Removed from type mapper (scalar, filter, order-by), data processors, input transformer, filter operators, zod schemas, column type mapping, searchable fields, RLS matching, OpenAPI schema, fake value generators - Removed from field creation flow and field metadata type validator - Updated dev seeder Pet `bio` field to `TEXT` - Cleaned up mocks, snapshots, integration tests ### Frontend (~25 files) - Deleted: `RichTextFieldDisplay`, `isFieldRichText`, `isFieldRichTextValue`, `useRichTextFieldDisplay` - Removed from `FieldDisplay`, `usePersistField`, `isFieldValueEmpty`, `isRecordMatchingFilter`, `generateEmptyFieldValue`, `isFieldCellSupported`, spreadsheet import, workflow fake values - Removed from settings types, field type configs, and field creation exclusion list - Updated tests, mocks, and stories ### SDK & Zapier - Removed from generated GraphQL schema and TypeScript types - Removed from Zapier `computeInputFields`
This commit is contained in:
+114
@@ -0,0 +1,114 @@
|
||||
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';
|
||||
|
||||
@Command({
|
||||
name: 'upgrade:1-20:migrate-rich-text-to-text',
|
||||
description:
|
||||
'Migrate deprecated RICH_TEXT field metadata type to TEXT. The underlying column type is already text, so only the metadata needs updating.',
|
||||
})
|
||||
export class MigrateRichTextToTextCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner {
|
||||
constructor(
|
||||
@InjectRepository(WorkspaceEntity)
|
||||
protected readonly workspaceRepository: Repository<WorkspaceEntity>,
|
||||
@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<void> {
|
||||
const dryRun = options?.dryRun ?? false;
|
||||
|
||||
this.logger.log(
|
||||
`${dryRun ? '[DRY RUN] ' : ''}Migrating RICH_TEXT fields to TEXT in workspace ${workspaceId}`,
|
||||
);
|
||||
|
||||
if (dryRun) {
|
||||
this.logger.log(
|
||||
`[DRY RUN] Would update RICH_TEXT -> TEXT in core.fieldMetadata for workspace ${workspaceId}. Skipping.`,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const queryRunner = this.coreDataSource.createQueryRunner();
|
||||
|
||||
await queryRunner.connect();
|
||||
|
||||
try {
|
||||
const result = await queryRunner.query(
|
||||
`UPDATE core."fieldMetadata"
|
||||
SET "type" = 'TEXT'
|
||||
WHERE "workspaceId" = $1
|
||||
AND "type" = 'RICH_TEXT'
|
||||
RETURNING "id"`,
|
||||
[workspaceId],
|
||||
);
|
||||
|
||||
const updatedCount = result.length;
|
||||
|
||||
if (updatedCount > 0) {
|
||||
this.logger.log(
|
||||
`Migrated ${updatedCount} RICH_TEXT field(s) to TEXT in workspace ${workspaceId}`,
|
||||
);
|
||||
await this.invalidateCaches(workspaceId);
|
||||
} else {
|
||||
this.logger.log(
|
||||
`No RICH_TEXT fields found in workspace ${workspaceId}`,
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
await queryRunner.release();
|
||||
}
|
||||
}
|
||||
|
||||
private async invalidateCaches(workspaceId: string): Promise<void> {
|
||||
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}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
+11
-2
@@ -3,6 +3,7 @@ import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
|
||||
import { BackfillCommandMenuItemsCommand } from 'src/database/commands/upgrade-version-command/1-20/1-20-backfill-command-menu-items.command';
|
||||
import { BackfillPageLayoutsCommand } from 'src/database/commands/upgrade-version-command/1-20/1-20-backfill-page-layouts.command';
|
||||
import { MigrateRichTextToTextCommand } from 'src/database/commands/upgrade-version-command/1-20/1-20-migrate-rich-text-to-text.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';
|
||||
@@ -25,7 +26,15 @@ import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace
|
||||
WorkspaceMigrationModule,
|
||||
FeatureFlagModule,
|
||||
],
|
||||
providers: [BackfillCommandMenuItemsCommand, BackfillPageLayoutsCommand],
|
||||
exports: [BackfillCommandMenuItemsCommand, BackfillPageLayoutsCommand],
|
||||
providers: [
|
||||
BackfillCommandMenuItemsCommand,
|
||||
BackfillPageLayoutsCommand,
|
||||
MigrateRichTextToTextCommand,
|
||||
],
|
||||
exports: [
|
||||
BackfillCommandMenuItemsCommand,
|
||||
BackfillPageLayoutsCommand,
|
||||
MigrateRichTextToTextCommand,
|
||||
],
|
||||
})
|
||||
export class V1_20_UpgradeVersionCommandModule {}
|
||||
|
||||
+3
@@ -35,6 +35,7 @@ import { BackfillMissingStandardViewsCommand } from 'src/database/commands/upgra
|
||||
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 { BackfillPageLayoutsCommand } from 'src/database/commands/upgrade-version-command/1-20/1-20-backfill-page-layouts.command';
|
||||
import { MigrateRichTextToTextCommand } from 'src/database/commands/upgrade-version-command/1-20/1-20-migrate-rich-text-to-text.command';
|
||||
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';
|
||||
@@ -87,6 +88,7 @@ export class UpgradeCommand extends UpgradeCommandRunner {
|
||||
// 1.20 Commands
|
||||
protected readonly backfillCommandMenuItemsCommand: BackfillCommandMenuItemsCommand,
|
||||
protected readonly backfillPageLayoutsCommand: BackfillPageLayoutsCommand,
|
||||
protected readonly migrateRichTextToTextCommand: MigrateRichTextToTextCommand,
|
||||
) {
|
||||
super(
|
||||
workspaceRepository,
|
||||
@@ -133,6 +135,7 @@ export class UpgradeCommand extends UpgradeCommandRunner {
|
||||
];
|
||||
|
||||
const commands_1200: VersionCommands = [
|
||||
this.migrateRichTextToTextCommand,
|
||||
this.backfillCommandMenuItemsCommand,
|
||||
this.backfillPageLayoutsCommand,
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user