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:
@@ -335,20 +335,6 @@ export const fieldRawJsonMock = getMockFieldMetadataEntity({
|
||||
updatedAt: new Date(),
|
||||
});
|
||||
|
||||
export const fieldRichTextMock = getMockFieldMetadataEntity({
|
||||
workspaceId,
|
||||
objectMetadataId,
|
||||
id: 'fieldRichTextId',
|
||||
name: 'fieldRichText',
|
||||
type: FieldMetadataType.RICH_TEXT,
|
||||
label: 'Field Rich Text',
|
||||
isNullable: true,
|
||||
defaultValue: null,
|
||||
isLabelSyncedWithName: true,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
});
|
||||
|
||||
export const fieldActorMock = getMockFieldMetadataEntity({
|
||||
workspaceId,
|
||||
objectMetadataId,
|
||||
@@ -436,7 +422,6 @@ const FIELDS_MOCK = [
|
||||
fieldPositionMock,
|
||||
fieldAddressMock,
|
||||
fieldRawJsonMock,
|
||||
fieldRichTextMock,
|
||||
fieldActorMock,
|
||||
fieldArrayMock,
|
||||
];
|
||||
|
||||
-2
@@ -172,8 +172,6 @@ exports[`DataArgProcessorService failing inputs validation RELATION should throw
|
||||
|
||||
exports[`DataArgProcessorService failing inputs validation RELATION should throw for invalid input #5: "non-uuid" 1`] = `"Invalid UUID value 'non-uuid' for field "manyToOneRelationFieldId""`;
|
||||
|
||||
exports[`DataArgProcessorService failing inputs validation RICH_TEXT should throw for invalid input #1: "test" 1`] = `"richTextField RICH_TEXT-typed field does not support write operations"`;
|
||||
|
||||
exports[`DataArgProcessorService failing inputs validation RICH_TEXT_V2 should throw for invalid input #1: "not-a-rich-text" 1`] = `"Invalid rich text v2 value 'not-a-rich-text' for field "richTextV2Field" - Should be an object"`;
|
||||
|
||||
exports[`DataArgProcessorService failing inputs validation RICH_TEXT_V2 should throw for invalid input #2: 1 1`] = `"Invalid rich text v2 value 1 for field "richTextV2Field" - Should be an object"`;
|
||||
|
||||
-1
@@ -96,7 +96,6 @@ export const failingInputsByFieldMetadataType: {
|
||||
{ input: { booleanField: 'string' } },
|
||||
{ input: { booleanField: 1 } },
|
||||
],
|
||||
[FieldMetadataType.RICH_TEXT]: [{ input: { richTextField: 'test' } }],
|
||||
[FieldMetadataType.ADDRESS]: [
|
||||
{ input: { addressField: 'not-an-address' } },
|
||||
{ input: { addressField: 1 } },
|
||||
|
||||
-5
@@ -139,11 +139,6 @@ export const fieldMetadataConfigByFieldName: Record<
|
||||
type: FieldMetadataType.RICH_TEXT_V2,
|
||||
isNullable: true,
|
||||
},
|
||||
richTextField: {
|
||||
name: 'richTextField',
|
||||
type: FieldMetadataType.RICH_TEXT,
|
||||
isNullable: true,
|
||||
},
|
||||
position: {
|
||||
name: 'position',
|
||||
type: FieldMetadataType.POSITION,
|
||||
|
||||
-1
@@ -312,7 +312,6 @@ export class DataArgProcessorService {
|
||||
|
||||
return transformLinksValue(validatedValue);
|
||||
}
|
||||
case FieldMetadataType.RICH_TEXT:
|
||||
case FieldMetadataType.TS_VECTOR:
|
||||
throw new CommonQueryRunnerException(
|
||||
`${key} ${fieldMetadata.type}-typed field does not support write operations`,
|
||||
|
||||
-4
@@ -140,10 +140,6 @@ exports[`FilterArgProcessorService failing filter inputs validation RELATION sho
|
||||
|
||||
exports[`FilterArgProcessorService failing filter inputs validation RELATION should throw for invalid filter #3: {"manyToOneRelationFieldId":{}} 1`] = `"Filter for field "manyToOneRelationFieldId" must have exactly one operator"`;
|
||||
|
||||
exports[`FilterArgProcessorService failing filter inputs validation RICH_TEXT should throw for invalid filter #1: {"richTextField":{"invalidOperator":"test"}} 1`] = `"Operator "invalidOperator" is not valid for field "richTextField" of type RICH_TEXT - Allowed operators: eq, neq, gt, gte, lt, lte, in, is, like, ilike, startsWith, endsWith"`;
|
||||
|
||||
exports[`FilterArgProcessorService failing filter inputs validation RICH_TEXT should throw for invalid filter #2: {"richTextField":{}} 1`] = `"Filter for field "richTextField" must have exactly one operator"`;
|
||||
|
||||
exports[`FilterArgProcessorService failing filter inputs validation RICH_TEXT_V2 should throw for invalid filter #1: {"richTextV2Field":{"invalidOperator":"test"}} 1`] = `"Sub field "invalidOperator" not found for composite type: RICH_TEXT_V2"`;
|
||||
|
||||
exports[`FilterArgProcessorService failing filter inputs validation RICH_TEXT_V2 should throw for invalid filter #2: {"richTextV2Field":{"markdown":{"invalidOperator":"test"}}} 1`] = `"Operator "invalidOperator" is not valid for field "richTextV2Field.markdown" of type TEXT - Allowed operators: eq, neq, gt, gte, lt, lte, in, is, like, ilike, startsWith, endsWith"`;
|
||||
|
||||
-4
@@ -11,10 +11,6 @@ export const failingFilterInputsByFieldMetadataType: {
|
||||
{ filter: { textField: { eq: 'test', neq: 'test' } } },
|
||||
{ filter: { textField: {} } },
|
||||
],
|
||||
[FieldMetadataType.RICH_TEXT]: [
|
||||
{ filter: { richTextField: { invalidOperator: 'test' } } },
|
||||
{ filter: { richTextField: {} } },
|
||||
],
|
||||
[FieldMetadataType.NUMBER]: [
|
||||
{ filter: { numberField: { eq: 'not-a-number' } } },
|
||||
{ filter: { numberField: { eq: {} } } },
|
||||
|
||||
-7
@@ -21,13 +21,6 @@ export const successfulFilterInputsByFieldMetadataType: {
|
||||
{ filter: { textField: { is: 'NOT_NULL' } } },
|
||||
{ filter: { textField: { eq: null } } },
|
||||
],
|
||||
[FieldMetadataType.RICH_TEXT]: [
|
||||
{ filter: { richTextField: { eq: 'test' } } },
|
||||
{ filter: { richTextField: { like: '%test%' } } },
|
||||
{ filter: { richTextField: { ilike: '%test%' } } },
|
||||
{ filter: { richTextField: { is: 'NULL' } } },
|
||||
{ filter: { richTextField: { is: 'NOT_NULL' } } },
|
||||
],
|
||||
[FieldMetadataType.NUMBER]: [
|
||||
{ filter: { numberField: { eq: 1 } } },
|
||||
{ filter: { numberField: { neq: 1 } } },
|
||||
|
||||
-1
@@ -20,7 +20,6 @@ export const getOperatorsForFieldType = (
|
||||
): FilterOperator[] => {
|
||||
switch (fieldType) {
|
||||
case FieldMetadataType.TEXT:
|
||||
case FieldMetadataType.RICH_TEXT:
|
||||
return STRING_FILTER_OPERATORS;
|
||||
|
||||
case FieldMetadataType.NUMBER:
|
||||
|
||||
-3
@@ -74,7 +74,6 @@ export class TypeMapperService {
|
||||
[FieldMetadataType.POSITION, PositionScalarType],
|
||||
[FieldMetadataType.RAW_JSON, GraphQLJSON],
|
||||
[FieldMetadataType.ARRAY, StringArrayScalarType],
|
||||
[FieldMetadataType.RICH_TEXT, GraphQLString],
|
||||
[FieldMetadataType.TS_VECTOR, TSVectorScalarType],
|
||||
]);
|
||||
|
||||
@@ -179,7 +178,6 @@ export class TypeMapperService {
|
||||
[FieldMetadataType.POSITION, FloatFilterType],
|
||||
[FieldMetadataType.FILES, RawJsonFilterType],
|
||||
[FieldMetadataType.RAW_JSON, RawJsonFilterType],
|
||||
[FieldMetadataType.RICH_TEXT, StringFilterType],
|
||||
[FieldMetadataType.RICH_TEXT_V2, RichTextV2FilterType],
|
||||
[FieldMetadataType.ARRAY, ArrayFilterType],
|
||||
[FieldMetadataType.MULTI_SELECT, MultiSelectFilterType],
|
||||
@@ -209,7 +207,6 @@ export class TypeMapperService {
|
||||
[FieldMetadataType.POSITION, OrderByDirectionType],
|
||||
[FieldMetadataType.FILES, OrderByDirectionType],
|
||||
[FieldMetadataType.RAW_JSON, OrderByDirectionType],
|
||||
[FieldMetadataType.RICH_TEXT, OrderByDirectionType],
|
||||
[FieldMetadataType.ARRAY, OrderByDirectionType],
|
||||
[FieldMetadataType.TS_VECTOR, OrderByDirectionType], // TODO: Add TSVectorOrderByType
|
||||
]);
|
||||
|
||||
Reference in New Issue
Block a user