RICH_TEXT_V2 frontend (#10083)
Adds task and note support for the new `bodyV2` field. (Field metadata type of `bodyV2` is `RICH_TEXT_V2`.) Related to issue https://github.com/twentyhq/twenty/issues/7613 Upgrade commands will be in separate PRs. Fixes https://github.com/twentyhq/twenty/issues/10084 --------- Co-authored-by: ad-elias <elias@autodiligence.com> Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
This commit is contained in:
@ -4,6 +4,7 @@ import {
|
||||
Fields,
|
||||
SpreadsheetImportDialogOptions,
|
||||
} from '@/spreadsheet-import/types';
|
||||
import { FieldMetadataType } from 'twenty-shared';
|
||||
import { sleep } from '~/utils/sleep';
|
||||
|
||||
const fields = [
|
||||
@ -22,6 +23,7 @@ const fields = [
|
||||
errorMessage: 'Name is required',
|
||||
},
|
||||
],
|
||||
fieldMetadataType: FieldMetadataType.TEXT,
|
||||
},
|
||||
{
|
||||
icon: null,
|
||||
|
||||
@ -4,6 +4,9 @@ import { IconForbid } from 'twenty-ui';
|
||||
import { MatchColumnSelect } from '@/spreadsheet-import/components/MatchColumnSelect';
|
||||
import { useSpreadsheetImportInternal } from '@/spreadsheet-import/hooks/useSpreadsheetImportInternal';
|
||||
|
||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||
import { FieldMetadataType } from 'twenty-shared';
|
||||
import { FeatureFlagKey } from '~/generated-metadata/graphql';
|
||||
import { Columns, ColumnType } from '../MatchColumnsStep';
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
@ -24,26 +27,35 @@ export const TemplateColumn = <T extends string>({
|
||||
columnIndex,
|
||||
onChange,
|
||||
}: TemplateColumnProps<T>) => {
|
||||
const isRichTextV2Enabled = useIsFeatureEnabled(
|
||||
FeatureFlagKey.IsRichTextV2Enabled,
|
||||
);
|
||||
const { fields } = useSpreadsheetImportInternal<T>();
|
||||
const column = columns[columnIndex];
|
||||
const isIgnored = column.type === ColumnType.ignored;
|
||||
|
||||
const fieldOptions = fields.map(({ icon, label, key }) => {
|
||||
const isSelected =
|
||||
columns.findIndex((column) => {
|
||||
if ('value' in column) {
|
||||
return column.value === key;
|
||||
}
|
||||
return false;
|
||||
}) !== -1;
|
||||
const fieldOptions = fields
|
||||
.filter((field) =>
|
||||
isRichTextV2Enabled
|
||||
? field.fieldMetadataType !== FieldMetadataType.RICH_TEXT
|
||||
: true,
|
||||
)
|
||||
.map(({ icon, label, key }) => {
|
||||
const isSelected =
|
||||
columns.findIndex((column) => {
|
||||
if ('value' in column) {
|
||||
return column.value === key;
|
||||
}
|
||||
return false;
|
||||
}) !== -1;
|
||||
|
||||
return {
|
||||
icon: icon,
|
||||
value: key,
|
||||
label: label,
|
||||
disabled: isSelected,
|
||||
} as const;
|
||||
});
|
||||
return {
|
||||
icon: icon,
|
||||
value: key,
|
||||
label: label,
|
||||
disabled: isSelected,
|
||||
} as const;
|
||||
});
|
||||
|
||||
const selectOptions = [
|
||||
{
|
||||
|
||||
@ -4,6 +4,7 @@ import { ReadonlyDeep } from 'type-fest';
|
||||
import { Columns } from '@/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep';
|
||||
import { ImportedStructuredRowMetadata } from '@/spreadsheet-import/steps/components/ValidationStep/types';
|
||||
import { SpreadsheetImportStep } from '@/spreadsheet-import/steps/types/SpreadsheetImportStep';
|
||||
import { FieldMetadataType } from 'twenty-shared';
|
||||
|
||||
export type SpreadsheetImportDialogOptions<FieldNames extends string> = {
|
||||
// Is modal visible.
|
||||
@ -122,6 +123,8 @@ export type Field<T extends string> = {
|
||||
fieldValidationDefinitions?: FieldValidationDefinition[];
|
||||
// Field entry component, default: Input
|
||||
fieldType: SpreadsheetImportFieldType;
|
||||
// Field metadata type
|
||||
fieldMetadataType: FieldMetadataType;
|
||||
// UI-facing values shown to user as field examples pre-upload phase
|
||||
example?: string;
|
||||
};
|
||||
|
||||
@ -6,6 +6,7 @@ import {
|
||||
TableHook,
|
||||
} from '@/spreadsheet-import/types';
|
||||
import { addErrorsAndRunHooks } from '@/spreadsheet-import/utils/dataMutations';
|
||||
import { FieldMetadataType } from 'twenty-shared';
|
||||
|
||||
describe('addErrorsAndRunHooks', () => {
|
||||
type FullData = ImportedStructuredRow<'name' | 'age' | 'country'>;
|
||||
@ -15,6 +16,7 @@ describe('addErrorsAndRunHooks', () => {
|
||||
fieldValidationDefinitions: [{ rule: 'required' }],
|
||||
icon: null,
|
||||
fieldType: { type: 'input' },
|
||||
fieldMetadataType: FieldMetadataType.TEXT,
|
||||
};
|
||||
|
||||
const regexField: Field<'age'> = {
|
||||
@ -25,6 +27,7 @@ describe('addErrorsAndRunHooks', () => {
|
||||
],
|
||||
icon: null,
|
||||
fieldType: { type: 'input' },
|
||||
fieldMetadataType: FieldMetadataType.NUMBER,
|
||||
};
|
||||
|
||||
const uniqueField: Field<'country'> = {
|
||||
@ -33,6 +36,7 @@ describe('addErrorsAndRunHooks', () => {
|
||||
fieldValidationDefinitions: [{ rule: 'unique' }],
|
||||
icon: null,
|
||||
fieldType: { type: 'input' },
|
||||
fieldMetadataType: FieldMetadataType.SELECT,
|
||||
};
|
||||
|
||||
const functionValidationFieldTrue: Field<'email'> = {
|
||||
@ -47,6 +51,7 @@ describe('addErrorsAndRunHooks', () => {
|
||||
],
|
||||
icon: null,
|
||||
fieldType: { type: 'input' },
|
||||
fieldMetadataType: FieldMetadataType.EMAILS,
|
||||
};
|
||||
|
||||
const functionValidationFieldFalse: Field<'email'> = {
|
||||
@ -61,6 +66,7 @@ describe('addErrorsAndRunHooks', () => {
|
||||
],
|
||||
icon: null,
|
||||
fieldType: { type: 'input' },
|
||||
fieldMetadataType: FieldMetadataType.EMAILS,
|
||||
};
|
||||
|
||||
const validData: ImportedStructuredRow<'name' | 'age'> = {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { Field } from '@/spreadsheet-import/types';
|
||||
import { findMatch } from '@/spreadsheet-import/utils/findMatch';
|
||||
|
||||
import { FieldMetadataType } from 'twenty-shared';
|
||||
describe('findMatch', () => {
|
||||
const defaultField: Field<'defaultField'> = {
|
||||
key: 'defaultField',
|
||||
@ -9,6 +9,7 @@ describe('findMatch', () => {
|
||||
fieldType: {
|
||||
type: 'input',
|
||||
},
|
||||
fieldMetadataType: FieldMetadataType.TEXT,
|
||||
alternateMatches: ['Full Name', 'First Name'],
|
||||
};
|
||||
|
||||
@ -19,6 +20,7 @@ describe('findMatch', () => {
|
||||
fieldType: {
|
||||
type: 'input',
|
||||
},
|
||||
fieldMetadataType: FieldMetadataType.TEXT,
|
||||
};
|
||||
|
||||
const fields = [defaultField, secondaryField];
|
||||
|
||||
@ -4,6 +4,7 @@ import {
|
||||
} from '@/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep';
|
||||
import { Field, FieldValidationDefinition } from '@/spreadsheet-import/types';
|
||||
import { findUnmatchedRequiredFields } from '@/spreadsheet-import/utils/findUnmatchedRequiredFields';
|
||||
import { FieldMetadataType } from 'twenty-shared';
|
||||
|
||||
const nameField: Field<'Name'> = {
|
||||
key: 'Name',
|
||||
@ -12,6 +13,7 @@ const nameField: Field<'Name'> = {
|
||||
fieldType: {
|
||||
type: 'input',
|
||||
},
|
||||
fieldMetadataType: FieldMetadataType.TEXT,
|
||||
};
|
||||
|
||||
const ageField: Field<'Age'> = {
|
||||
@ -21,7 +23,9 @@ const ageField: Field<'Age'> = {
|
||||
fieldType: {
|
||||
type: 'input',
|
||||
},
|
||||
fieldMetadataType: FieldMetadataType.NUMBER,
|
||||
};
|
||||
|
||||
const validations: FieldValidationDefinition[] = [{ rule: 'required' }];
|
||||
const nameFieldWithValidations: Field<'Name'> = {
|
||||
...nameField,
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { Field } from '@/spreadsheet-import/types';
|
||||
import { generateExampleRow } from '@/spreadsheet-import/utils/generateExampleRow';
|
||||
import { FieldMetadataType } from 'twenty-shared';
|
||||
|
||||
describe('generateExampleRow', () => {
|
||||
const defaultField: Field<'defaultField'> = {
|
||||
@ -9,6 +10,7 @@ describe('generateExampleRow', () => {
|
||||
fieldType: {
|
||||
type: 'input',
|
||||
},
|
||||
fieldMetadataType: FieldMetadataType.TEXT,
|
||||
};
|
||||
|
||||
it('should generate an example row from input field type', () => {
|
||||
@ -24,6 +26,7 @@ describe('generateExampleRow', () => {
|
||||
{
|
||||
...defaultField,
|
||||
fieldType: { type: 'checkbox' },
|
||||
fieldMetadataType: FieldMetadataType.BOOLEAN,
|
||||
},
|
||||
];
|
||||
|
||||
@ -37,6 +40,7 @@ describe('generateExampleRow', () => {
|
||||
{
|
||||
...defaultField,
|
||||
fieldType: { type: 'select', options: [] },
|
||||
fieldMetadataType: FieldMetadataType.SELECT,
|
||||
},
|
||||
];
|
||||
|
||||
@ -50,6 +54,7 @@ describe('generateExampleRow', () => {
|
||||
{
|
||||
...defaultField,
|
||||
example: 'Example',
|
||||
fieldMetadataType: FieldMetadataType.TEXT,
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { Field } from '@/spreadsheet-import/types';
|
||||
import { getFieldOptions } from '@/spreadsheet-import/utils/getFieldOptions';
|
||||
import { FieldMetadataType } from 'twenty-shared';
|
||||
|
||||
describe('getFieldOptions', () => {
|
||||
const optionsArray = [
|
||||
@ -25,6 +26,7 @@ describe('getFieldOptions', () => {
|
||||
type: 'select',
|
||||
options: optionsArray,
|
||||
},
|
||||
fieldMetadataType: FieldMetadataType.SELECT,
|
||||
},
|
||||
{
|
||||
key: 'Name',
|
||||
@ -33,6 +35,7 @@ describe('getFieldOptions', () => {
|
||||
fieldType: {
|
||||
type: 'input',
|
||||
},
|
||||
fieldMetadataType: FieldMetadataType.TEXT,
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
@ -4,6 +4,7 @@ import {
|
||||
} from '@/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep';
|
||||
import { Field } from '@/spreadsheet-import/types';
|
||||
import { getMatchedColumns } from '@/spreadsheet-import/utils/getMatchedColumns';
|
||||
import { FieldMetadataType } from 'twenty-shared';
|
||||
|
||||
describe('getMatchedColumns', () => {
|
||||
const columns: Column<string>[] = [
|
||||
@ -27,15 +28,23 @@ describe('getMatchedColumns', () => {
|
||||
key: 'Name',
|
||||
label: 'Name',
|
||||
fieldType: { type: 'input' },
|
||||
fieldMetadataType: FieldMetadataType.TEXT,
|
||||
icon: null,
|
||||
},
|
||||
{
|
||||
key: 'Location',
|
||||
label: 'Location',
|
||||
fieldType: { type: 'select', options: [] },
|
||||
fieldMetadataType: FieldMetadataType.POSITION,
|
||||
icon: null,
|
||||
},
|
||||
{
|
||||
key: 'Age',
|
||||
label: 'Age',
|
||||
fieldType: { type: 'input' },
|
||||
fieldMetadataType: FieldMetadataType.NUMBER,
|
||||
icon: null,
|
||||
},
|
||||
{ key: 'Age', label: 'Age', fieldType: { type: 'input' }, icon: null },
|
||||
];
|
||||
|
||||
const data = [
|
||||
@ -110,12 +119,14 @@ describe('getMatchedColumns', () => {
|
||||
key: 'Hobby',
|
||||
label: 'Hobby',
|
||||
fieldType: { type: 'input' },
|
||||
fieldMetadataType: FieldMetadataType.TEXT,
|
||||
icon: null,
|
||||
},
|
||||
{
|
||||
key: 'Interest',
|
||||
label: 'Interest',
|
||||
fieldType: { type: 'input' },
|
||||
fieldMetadataType: FieldMetadataType.TEXT,
|
||||
icon: null,
|
||||
},
|
||||
];
|
||||
|
||||
@ -4,6 +4,7 @@ import {
|
||||
} from '@/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep';
|
||||
import { Field } from '@/spreadsheet-import/types';
|
||||
import { normalizeTableData } from '@/spreadsheet-import/utils/normalizeTableData';
|
||||
import { FieldMetadataType } from 'twenty-shared';
|
||||
|
||||
describe('normalizeTableData', () => {
|
||||
const columns: Column<string>[] = [
|
||||
@ -18,14 +19,27 @@ describe('normalizeTableData', () => {
|
||||
];
|
||||
|
||||
const fields: Field<string>[] = [
|
||||
{ key: 'name', label: 'Name', fieldType: { type: 'input' }, icon: null },
|
||||
{ key: 'age', label: 'Age', fieldType: { type: 'input' }, icon: null },
|
||||
{
|
||||
key: 'name',
|
||||
label: 'Name',
|
||||
fieldType: { type: 'input' },
|
||||
fieldMetadataType: FieldMetadataType.TEXT,
|
||||
icon: null,
|
||||
},
|
||||
{
|
||||
key: 'age',
|
||||
label: 'Age',
|
||||
fieldType: { type: 'input' },
|
||||
fieldMetadataType: FieldMetadataType.NUMBER,
|
||||
icon: null,
|
||||
},
|
||||
{
|
||||
key: 'active',
|
||||
label: 'Active',
|
||||
fieldType: {
|
||||
type: 'checkbox',
|
||||
},
|
||||
fieldMetadataType: FieldMetadataType.BOOLEAN,
|
||||
icon: null,
|
||||
},
|
||||
];
|
||||
@ -64,6 +78,7 @@ describe('normalizeTableData', () => {
|
||||
type: 'checkbox',
|
||||
booleanMatches: { yes: true, no: false },
|
||||
},
|
||||
fieldMetadataType: FieldMetadataType.BOOLEAN,
|
||||
icon: null,
|
||||
},
|
||||
];
|
||||
@ -100,6 +115,7 @@ describe('normalizeTableData', () => {
|
||||
{ label: 'Two', value: '2' },
|
||||
],
|
||||
},
|
||||
fieldMetadataType: FieldMetadataType.SELECT,
|
||||
icon: null,
|
||||
},
|
||||
];
|
||||
|
||||
@ -4,6 +4,7 @@ import {
|
||||
} from '@/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep';
|
||||
import { Field } from '@/spreadsheet-import/types';
|
||||
import { setColumn } from '@/spreadsheet-import/utils/setColumn';
|
||||
import { FieldMetadataType } from 'twenty-shared';
|
||||
|
||||
describe('setColumn', () => {
|
||||
const defaultField: Field<'Name'> = {
|
||||
@ -11,6 +12,7 @@ describe('setColumn', () => {
|
||||
label: 'label',
|
||||
key: 'Name',
|
||||
fieldType: { type: 'input' },
|
||||
fieldMetadataType: FieldMetadataType.TEXT,
|
||||
};
|
||||
|
||||
const oldColumn: Column<'oldValue'> = {
|
||||
|
||||
Reference in New Issue
Block a user