CSV importing and exporting fixes (#8824)
Fixes issue https://github.com/twentyhq/twenty/issues/5793 (and duplicate https://github.com/twentyhq/twenty/issues/8822) - Fix importing multi-select and array fields. - Fix exporting and importing RAW_JSON fields. --------- Co-authored-by: ad-elias <elias@autodiligence.com>
This commit is contained in:
@ -3,6 +3,7 @@ import { Field, Fields } from '@/spreadsheet-import/types';
|
||||
const titleMap: Record<Field<string>['fieldType']['type'], string> = {
|
||||
checkbox: 'Boolean',
|
||||
select: 'Options',
|
||||
multiSelect: 'Options',
|
||||
input: 'Text',
|
||||
};
|
||||
|
||||
|
||||
@ -8,5 +8,8 @@ export const getFieldOptions = <T extends string>(
|
||||
if (!field) {
|
||||
return [];
|
||||
}
|
||||
return field.fieldType.type === 'select' ? field.fieldType.options : [];
|
||||
return field.fieldType.type === 'select' ||
|
||||
field.fieldType.type === 'multiSelect'
|
||||
? field.fieldType.options
|
||||
: [];
|
||||
};
|
||||
|
||||
@ -8,6 +8,8 @@ import {
|
||||
ImportedStructuredRow,
|
||||
} from '@/spreadsheet-import/types';
|
||||
|
||||
import { isDefined } from '@ui/utilities/isDefined';
|
||||
import { z } from 'zod';
|
||||
import { normalizeCheckboxValue } from './normalizeCheckboxValue';
|
||||
|
||||
export const normalizeTableData = <T extends string>(
|
||||
@ -54,10 +56,45 @@ export const normalizeTableData = <T extends string>(
|
||||
}
|
||||
case ColumnType.matchedSelect:
|
||||
case ColumnType.matchedSelectOptions: {
|
||||
const matchedOption = column.matchedOptions.find(
|
||||
({ entry }) => entry === curr,
|
||||
);
|
||||
acc[column.value] = matchedOption?.value || undefined;
|
||||
const field = fields.find((field) => field.key === column.value);
|
||||
|
||||
if (!field) {
|
||||
return acc;
|
||||
}
|
||||
|
||||
if (field.fieldType.type === 'multiSelect' && isDefined(curr)) {
|
||||
const currentOptionsSchema = z.preprocess(
|
||||
(value) => JSON.parse(z.string().parse(value)),
|
||||
z.array(z.unknown()),
|
||||
);
|
||||
|
||||
const rawCurrentOptions = currentOptionsSchema.safeParse(curr).data;
|
||||
|
||||
const matchedOptionValues = [
|
||||
...new Set(
|
||||
rawCurrentOptions
|
||||
?.map(
|
||||
(option) =>
|
||||
column.matchedOptions.find(
|
||||
(matchedOption) => matchedOption.entry === option,
|
||||
)?.value,
|
||||
)
|
||||
.filter(isDefined),
|
||||
),
|
||||
];
|
||||
|
||||
const fieldValue =
|
||||
matchedOptionValues && matchedOptionValues.length > 0
|
||||
? JSON.stringify(matchedOptionValues)
|
||||
: undefined;
|
||||
|
||||
acc[column.value] = fieldValue;
|
||||
} else {
|
||||
const matchedOption = column.matchedOptions.find(
|
||||
({ entry }) => entry === curr,
|
||||
);
|
||||
acc[column.value] = matchedOption?.value || undefined;
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
case ColumnType.empty:
|
||||
|
||||
@ -6,6 +6,7 @@ import {
|
||||
} from '@/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep';
|
||||
import { Field } from '@/spreadsheet-import/types';
|
||||
|
||||
import { z } from 'zod';
|
||||
import { uniqueEntries } from './uniqueEntries';
|
||||
|
||||
export const setColumn = <T extends string>(
|
||||
@ -19,6 +20,7 @@ export const setColumn = <T extends string>(
|
||||
data || [],
|
||||
oldColumn.index,
|
||||
) as MatchedOptions<T>[];
|
||||
|
||||
const matchedOptions = uniqueData.map((record) => {
|
||||
const value = fieldOptions.find(
|
||||
(fieldOption) =>
|
||||
@ -42,6 +44,48 @@ export const setColumn = <T extends string>(
|
||||
};
|
||||
}
|
||||
|
||||
if (field?.fieldType.type === 'multiSelect') {
|
||||
const fieldOptions = field.fieldType.options;
|
||||
|
||||
const entries = [
|
||||
...new Set(
|
||||
data
|
||||
?.flatMap((row) => {
|
||||
try {
|
||||
const value = row[oldColumn.index];
|
||||
const options = JSON.parse(z.string().parse(value));
|
||||
return z.array(z.string()).parse(options);
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
})
|
||||
.filter((entry) => typeof entry === 'string'),
|
||||
),
|
||||
];
|
||||
|
||||
const matchedOptions = entries.map((entry) => {
|
||||
const value = fieldOptions.find(
|
||||
(fieldOption) =>
|
||||
fieldOption.value === entry || fieldOption.label === entry,
|
||||
)?.value;
|
||||
return value
|
||||
? ({ entry, value } as MatchedOptions<T>)
|
||||
: ({ entry } as MatchedOptions<T>);
|
||||
});
|
||||
const areAllMatched =
|
||||
matchedOptions.filter((option) => option.value).length ===
|
||||
entries?.length;
|
||||
|
||||
return {
|
||||
...oldColumn,
|
||||
type: areAllMatched
|
||||
? ColumnType.matchedSelectOptions
|
||||
: ColumnType.matchedSelect,
|
||||
value: field.key,
|
||||
matchedOptions,
|
||||
};
|
||||
}
|
||||
|
||||
if (field?.fieldType.type === 'checkbox') {
|
||||
return {
|
||||
index: oldColumn.index,
|
||||
|
||||
Reference in New Issue
Block a user