Refactor spreadsheet import (#11250)
Mostly renaming objects to avoid conflicts (it was painful because names were too generic so you could cmd+replace easily) Also refactoring `useBuildAvailableFieldsForImport`
This commit is contained in:
@ -1,45 +1,45 @@
|
||||
import {
|
||||
Field,
|
||||
ImportedStructuredRow,
|
||||
Info,
|
||||
RowHook,
|
||||
TableHook,
|
||||
SpreadsheetImportField,
|
||||
SpreadsheetImportInfo,
|
||||
SpreadsheetImportRowHook,
|
||||
SpreadsheetImportTableHook,
|
||||
} from '@/spreadsheet-import/types';
|
||||
import { addErrorsAndRunHooks } from '@/spreadsheet-import/utils/dataMutations';
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
|
||||
describe('addErrorsAndRunHooks', () => {
|
||||
type FullData = ImportedStructuredRow<'name' | 'age' | 'country'>;
|
||||
const requiredField: Field<'name'> = {
|
||||
const requiredField: SpreadsheetImportField<'name'> = {
|
||||
key: 'name',
|
||||
label: 'Name',
|
||||
fieldValidationDefinitions: [{ rule: 'required' }],
|
||||
icon: null,
|
||||
Icon: null,
|
||||
fieldType: { type: 'input' },
|
||||
fieldMetadataType: FieldMetadataType.TEXT,
|
||||
};
|
||||
|
||||
const regexField: Field<'age'> = {
|
||||
const regexField: SpreadsheetImportField<'age'> = {
|
||||
key: 'age',
|
||||
label: 'Age',
|
||||
fieldValidationDefinitions: [
|
||||
{ rule: 'regex', value: '\\d+', errorMessage: 'Regex error' },
|
||||
],
|
||||
icon: null,
|
||||
Icon: null,
|
||||
fieldType: { type: 'input' },
|
||||
fieldMetadataType: FieldMetadataType.NUMBER,
|
||||
};
|
||||
|
||||
const uniqueField: Field<'country'> = {
|
||||
const uniqueField: SpreadsheetImportField<'country'> = {
|
||||
key: 'country',
|
||||
label: 'Country',
|
||||
fieldValidationDefinitions: [{ rule: 'unique' }],
|
||||
icon: null,
|
||||
Icon: null,
|
||||
fieldType: { type: 'input' },
|
||||
fieldMetadataType: FieldMetadataType.SELECT,
|
||||
};
|
||||
|
||||
const functionValidationFieldTrue: Field<'email'> = {
|
||||
const functionValidationFieldTrue: SpreadsheetImportField<'email'> = {
|
||||
key: 'email',
|
||||
label: 'Email',
|
||||
fieldValidationDefinitions: [
|
||||
@ -49,12 +49,12 @@ describe('addErrorsAndRunHooks', () => {
|
||||
errorMessage: 'Field is invalid',
|
||||
},
|
||||
],
|
||||
icon: null,
|
||||
Icon: null,
|
||||
fieldType: { type: 'input' },
|
||||
fieldMetadataType: FieldMetadataType.EMAILS,
|
||||
};
|
||||
|
||||
const functionValidationFieldFalse: Field<'email'> = {
|
||||
const functionValidationFieldFalse: SpreadsheetImportField<'email'> = {
|
||||
key: 'email',
|
||||
label: 'Email',
|
||||
fieldValidationDefinitions: [
|
||||
@ -64,7 +64,7 @@ describe('addErrorsAndRunHooks', () => {
|
||||
errorMessage: 'Field is invalid',
|
||||
},
|
||||
],
|
||||
icon: null,
|
||||
Icon: null,
|
||||
fieldType: { type: 'input' },
|
||||
fieldMetadataType: FieldMetadataType.EMAILS,
|
||||
};
|
||||
@ -88,24 +88,43 @@ describe('addErrorsAndRunHooks', () => {
|
||||
dataWithoutNameAndInvalidAge,
|
||||
];
|
||||
|
||||
const basicError: Info = { message: 'Field is invalid', level: 'error' };
|
||||
const nameError: Info = { message: 'Name Error', level: 'error' };
|
||||
const ageError: Info = { message: 'Age Error', level: 'error' };
|
||||
const regexError: Info = { message: 'Regex error', level: 'error' };
|
||||
const requiredError: Info = { message: 'Field is required', level: 'error' };
|
||||
const duplicatedError: Info = {
|
||||
const basicError: SpreadsheetImportInfo = {
|
||||
message: 'Field is invalid',
|
||||
level: 'error',
|
||||
};
|
||||
const nameError: SpreadsheetImportInfo = {
|
||||
message: 'Name Error',
|
||||
level: 'error',
|
||||
};
|
||||
const ageError: SpreadsheetImportInfo = {
|
||||
message: 'Age Error',
|
||||
level: 'error',
|
||||
};
|
||||
const regexError: SpreadsheetImportInfo = {
|
||||
message: 'Regex error',
|
||||
level: 'error',
|
||||
};
|
||||
const requiredError: SpreadsheetImportInfo = {
|
||||
message: 'Field is required',
|
||||
level: 'error',
|
||||
};
|
||||
const duplicatedError: SpreadsheetImportInfo = {
|
||||
message: 'Field must be unique',
|
||||
level: 'error',
|
||||
};
|
||||
|
||||
const rowHook: RowHook<'name' | 'age'> = jest.fn((row, addError) => {
|
||||
addError('name', nameError);
|
||||
return row;
|
||||
});
|
||||
const tableHook: TableHook<'name' | 'age'> = jest.fn((table, addError) => {
|
||||
addError(0, 'age', ageError);
|
||||
return table;
|
||||
});
|
||||
const rowHook: SpreadsheetImportRowHook<'name' | 'age'> = jest.fn(
|
||||
(row, addError) => {
|
||||
addError('name', nameError);
|
||||
return row;
|
||||
},
|
||||
);
|
||||
const tableHook: SpreadsheetImportTableHook<'name' | 'age'> = jest.fn(
|
||||
(table, addError) => {
|
||||
addError(0, 'age', ageError);
|
||||
return table;
|
||||
},
|
||||
);
|
||||
|
||||
it('should correctly call rowHook and tableHook and add errors', () => {
|
||||
const result = addErrorsAndRunHooks(
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import { Field } from '@/spreadsheet-import/types';
|
||||
import { SpreadsheetImportField } from '@/spreadsheet-import/types';
|
||||
import { findMatch } from '@/spreadsheet-import/utils/findMatch';
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
|
||||
describe('findMatch', () => {
|
||||
const defaultField: Field<'defaultField'> = {
|
||||
const defaultField: SpreadsheetImportField<'defaultField'> = {
|
||||
key: 'defaultField',
|
||||
icon: null,
|
||||
Icon: null,
|
||||
label: 'label',
|
||||
fieldType: {
|
||||
type: 'input',
|
||||
@ -14,9 +14,9 @@ describe('findMatch', () => {
|
||||
alternateMatches: ['Full Name', 'First Name'],
|
||||
};
|
||||
|
||||
const secondaryField: Field<'secondaryField'> = {
|
||||
const secondaryField: SpreadsheetImportField<'secondaryField'> = {
|
||||
key: 'secondaryField',
|
||||
icon: null,
|
||||
Icon: null,
|
||||
label: 'label',
|
||||
fieldType: {
|
||||
type: 'input',
|
||||
|
||||
@ -1,59 +1,62 @@
|
||||
import {
|
||||
Column,
|
||||
ColumnType,
|
||||
} from '@/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep';
|
||||
import { Field, FieldValidationDefinition } from '@/spreadsheet-import/types';
|
||||
SpreadsheetImportField,
|
||||
SpreadsheetImportFieldValidationDefinition,
|
||||
} from '@/spreadsheet-import/types';
|
||||
import { SpreadsheetColumn } from '@/spreadsheet-import/types/SpreadsheetColumn';
|
||||
import { SpreadsheetColumnType } from '@/spreadsheet-import/types/SpreadsheetColumnType';
|
||||
import { findUnmatchedRequiredFields } from '@/spreadsheet-import/utils/findUnmatchedRequiredFields';
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
|
||||
const nameField: Field<'Name'> = {
|
||||
const nameField: SpreadsheetImportField<'Name'> = {
|
||||
key: 'Name',
|
||||
label: 'Name',
|
||||
icon: null,
|
||||
Icon: null,
|
||||
fieldType: {
|
||||
type: 'input',
|
||||
},
|
||||
fieldMetadataType: FieldMetadataType.TEXT,
|
||||
};
|
||||
|
||||
const ageField: Field<'Age'> = {
|
||||
const ageField: SpreadsheetImportField<'Age'> = {
|
||||
key: 'Age',
|
||||
label: 'Age',
|
||||
icon: null,
|
||||
Icon: null,
|
||||
fieldType: {
|
||||
type: 'input',
|
||||
},
|
||||
fieldMetadataType: FieldMetadataType.NUMBER,
|
||||
};
|
||||
|
||||
const validations: FieldValidationDefinition[] = [{ rule: 'required' }];
|
||||
const nameFieldWithValidations: Field<'Name'> = {
|
||||
const validations: SpreadsheetImportFieldValidationDefinition[] = [
|
||||
{ rule: 'required' },
|
||||
];
|
||||
const nameFieldWithValidations: SpreadsheetImportField<'Name'> = {
|
||||
...nameField,
|
||||
fieldValidationDefinitions: validations,
|
||||
};
|
||||
const ageFieldWithValidations: Field<'Age'> = {
|
||||
const ageFieldWithValidations: SpreadsheetImportField<'Age'> = {
|
||||
...ageField,
|
||||
fieldValidationDefinitions: validations,
|
||||
};
|
||||
|
||||
type ColumnValues = 'Name' | 'Age';
|
||||
|
||||
const nameColumn: Column<ColumnValues> = {
|
||||
type: ColumnType.matched,
|
||||
const nameColumn: SpreadsheetColumn<ColumnValues> = {
|
||||
type: SpreadsheetColumnType.matched,
|
||||
index: 0,
|
||||
header: '',
|
||||
value: 'Name',
|
||||
};
|
||||
|
||||
const ageColumn: Column<ColumnValues> = {
|
||||
type: ColumnType.matched,
|
||||
const ageColumn: SpreadsheetColumn<ColumnValues> = {
|
||||
type: SpreadsheetColumnType.matched,
|
||||
index: 0,
|
||||
header: '',
|
||||
value: 'Age',
|
||||
};
|
||||
|
||||
const extraColumn: Column<ColumnValues> = {
|
||||
type: ColumnType.matched,
|
||||
const extraColumn: SpreadsheetColumn<ColumnValues> = {
|
||||
type: SpreadsheetColumnType.matched,
|
||||
index: 0,
|
||||
header: '',
|
||||
value: 'Age',
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import { Field } from '@/spreadsheet-import/types';
|
||||
import { SpreadsheetImportField } from '@/spreadsheet-import/types';
|
||||
import { generateExampleRow } from '@/spreadsheet-import/utils/generateExampleRow';
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
|
||||
describe('generateExampleRow', () => {
|
||||
const defaultField: Field<'defaultField'> = {
|
||||
const defaultField: SpreadsheetImportField<'defaultField'> = {
|
||||
key: 'defaultField',
|
||||
icon: null,
|
||||
Icon: null,
|
||||
label: 'label',
|
||||
fieldType: {
|
||||
type: 'input',
|
||||
@ -14,7 +14,7 @@ describe('generateExampleRow', () => {
|
||||
};
|
||||
|
||||
it('should generate an example row from input field type', () => {
|
||||
const fields: Field<'defaultField'>[] = [defaultField];
|
||||
const fields: SpreadsheetImportField<'defaultField'>[] = [defaultField];
|
||||
|
||||
const result = generateExampleRow(fields);
|
||||
|
||||
@ -22,7 +22,7 @@ describe('generateExampleRow', () => {
|
||||
});
|
||||
|
||||
it('should generate an example row from checkbox field type', () => {
|
||||
const fields: Field<'defaultField'>[] = [
|
||||
const fields: SpreadsheetImportField<'defaultField'>[] = [
|
||||
{
|
||||
...defaultField,
|
||||
fieldType: { type: 'checkbox' },
|
||||
@ -36,7 +36,7 @@ describe('generateExampleRow', () => {
|
||||
});
|
||||
|
||||
it('should generate an example row from select field type', () => {
|
||||
const fields: Field<'defaultField'>[] = [
|
||||
const fields: SpreadsheetImportField<'defaultField'>[] = [
|
||||
{
|
||||
...defaultField,
|
||||
fieldType: { type: 'select', options: [] },
|
||||
@ -50,7 +50,7 @@ describe('generateExampleRow', () => {
|
||||
});
|
||||
|
||||
it('should generate an example row with provided example values for fields', () => {
|
||||
const fields: Field<'defaultField'>[] = [
|
||||
const fields: SpreadsheetImportField<'defaultField'>[] = [
|
||||
{
|
||||
...defaultField,
|
||||
example: 'Example',
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { Field } from '@/spreadsheet-import/types';
|
||||
import { SpreadsheetImportField } from '@/spreadsheet-import/types';
|
||||
import { getFieldOptions } from '@/spreadsheet-import/utils/getFieldOptions';
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
|
||||
@ -17,10 +17,10 @@ describe('getFieldOptions', () => {
|
||||
value: 'Three',
|
||||
},
|
||||
];
|
||||
const fields: Field<'Options' | 'Name'>[] = [
|
||||
const fields: SpreadsheetImportField<'Options' | 'Name'>[] = [
|
||||
{
|
||||
key: 'Options',
|
||||
icon: null,
|
||||
Icon: null,
|
||||
label: 'options',
|
||||
fieldType: {
|
||||
type: 'select',
|
||||
@ -30,7 +30,7 @@ describe('getFieldOptions', () => {
|
||||
},
|
||||
{
|
||||
key: 'Name',
|
||||
icon: null,
|
||||
Icon: null,
|
||||
label: 'name',
|
||||
fieldType: {
|
||||
type: 'input',
|
||||
|
||||
@ -1,49 +1,52 @@
|
||||
import {
|
||||
Column,
|
||||
ColumnType,
|
||||
} from '@/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep';
|
||||
import { Field } from '@/spreadsheet-import/types';
|
||||
import { SpreadsheetImportField } from '@/spreadsheet-import/types';
|
||||
import { SpreadsheetColumn } from '@/spreadsheet-import/types/SpreadsheetColumn';
|
||||
import { SpreadsheetColumnType } from '@/spreadsheet-import/types/SpreadsheetColumnType';
|
||||
import { getMatchedColumns } from '@/spreadsheet-import/utils/getMatchedColumns';
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
|
||||
describe('getMatchedColumns', () => {
|
||||
const columns: Column<string>[] = [
|
||||
{ index: 0, header: 'Name', type: ColumnType.matched, value: 'Name' },
|
||||
const columns: SpreadsheetColumn<string>[] = [
|
||||
{
|
||||
index: 0,
|
||||
header: 'Name',
|
||||
type: SpreadsheetColumnType.matched,
|
||||
value: 'Name',
|
||||
},
|
||||
{
|
||||
index: 1,
|
||||
header: 'Location',
|
||||
type: ColumnType.matched,
|
||||
type: SpreadsheetColumnType.matched,
|
||||
value: 'Location',
|
||||
},
|
||||
{
|
||||
index: 2,
|
||||
header: 'Age',
|
||||
type: ColumnType.matched,
|
||||
type: SpreadsheetColumnType.matched,
|
||||
value: 'Age',
|
||||
},
|
||||
];
|
||||
|
||||
const fields: Field<string>[] = [
|
||||
const fields: SpreadsheetImportField<string>[] = [
|
||||
{
|
||||
key: 'Name',
|
||||
label: 'Name',
|
||||
fieldType: { type: 'input' },
|
||||
fieldMetadataType: FieldMetadataType.TEXT,
|
||||
icon: null,
|
||||
Icon: null,
|
||||
},
|
||||
{
|
||||
key: 'Location',
|
||||
label: 'Location',
|
||||
fieldType: { type: 'select', options: [] },
|
||||
fieldMetadataType: FieldMetadataType.POSITION,
|
||||
icon: null,
|
||||
Icon: null,
|
||||
},
|
||||
{
|
||||
key: 'Age',
|
||||
label: 'Age',
|
||||
fieldType: { type: 'input' },
|
||||
fieldMetadataType: FieldMetadataType.NUMBER,
|
||||
icon: null,
|
||||
Icon: null,
|
||||
},
|
||||
];
|
||||
|
||||
@ -57,11 +60,16 @@ describe('getMatchedColumns', () => {
|
||||
it('should return matched columns for each field', () => {
|
||||
const result = getMatchedColumns(columns, fields, data, autoMapDistance);
|
||||
expect(result).toEqual([
|
||||
{ index: 0, header: 'Name', type: ColumnType.matched, value: 'Name' },
|
||||
{
|
||||
index: 0,
|
||||
header: 'Name',
|
||||
type: SpreadsheetColumnType.matched,
|
||||
value: 'Name',
|
||||
},
|
||||
{
|
||||
index: 1,
|
||||
header: 'Location',
|
||||
type: ColumnType.matchedSelect,
|
||||
type: SpreadsheetColumnType.matchedSelect,
|
||||
value: 'Location',
|
||||
matchedOptions: [
|
||||
{
|
||||
@ -72,18 +80,33 @@ describe('getMatchedColumns', () => {
|
||||
},
|
||||
],
|
||||
},
|
||||
{ index: 2, header: 'Age', type: ColumnType.matched, value: 'Age' },
|
||||
{
|
||||
index: 2,
|
||||
header: 'Age',
|
||||
type: SpreadsheetColumnType.matched,
|
||||
value: 'Age',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should handle columns with duplicate values by choosing the closest match', () => {
|
||||
const columnsWithDuplicates: Column<string>[] = [
|
||||
{ index: 0, header: 'Name', type: ColumnType.matched, value: 'Name' },
|
||||
{ index: 1, header: 'Name', type: ColumnType.matched, value: 'Name' },
|
||||
const columnsWithDuplicates: SpreadsheetColumn<string>[] = [
|
||||
{
|
||||
index: 0,
|
||||
header: 'Name',
|
||||
type: SpreadsheetColumnType.matched,
|
||||
value: 'Name',
|
||||
},
|
||||
{
|
||||
index: 1,
|
||||
header: 'Name',
|
||||
type: SpreadsheetColumnType.matched,
|
||||
value: 'Name',
|
||||
},
|
||||
{
|
||||
index: 2,
|
||||
header: 'Location',
|
||||
type: ColumnType.matched,
|
||||
type: SpreadsheetColumnType.matched,
|
||||
value: 'Location',
|
||||
},
|
||||
];
|
||||
@ -98,12 +121,12 @@ describe('getMatchedColumns', () => {
|
||||
expect(result[0]).toEqual({
|
||||
index: 0,
|
||||
header: 'Name',
|
||||
type: ColumnType.empty,
|
||||
type: SpreadsheetColumnType.empty,
|
||||
});
|
||||
expect(result[1]).toEqual({
|
||||
index: 1,
|
||||
header: 'Name',
|
||||
type: ColumnType.matched,
|
||||
type: SpreadsheetColumnType.matched,
|
||||
value: 'Name',
|
||||
});
|
||||
});
|
||||
@ -114,20 +137,20 @@ describe('getMatchedColumns', () => {
|
||||
['Alice', 'Los Angeles', '25'],
|
||||
];
|
||||
|
||||
const unmatchedFields: Field<string>[] = [
|
||||
const unmatchedFields: SpreadsheetImportField<string>[] = [
|
||||
{
|
||||
key: 'Hobby',
|
||||
label: 'Hobby',
|
||||
fieldType: { type: 'input' },
|
||||
fieldMetadataType: FieldMetadataType.TEXT,
|
||||
icon: null,
|
||||
Icon: null,
|
||||
},
|
||||
{
|
||||
key: 'Interest',
|
||||
label: 'Interest',
|
||||
fieldType: { type: 'input' },
|
||||
fieldMetadataType: FieldMetadataType.TEXT,
|
||||
icon: null,
|
||||
Icon: null,
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
@ -1,37 +1,46 @@
|
||||
import {
|
||||
Column,
|
||||
ColumnType,
|
||||
} from '@/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep';
|
||||
import { Field } from '@/spreadsheet-import/types';
|
||||
import { SpreadsheetImportField } from '@/spreadsheet-import/types';
|
||||
import { SpreadsheetColumn } from '@/spreadsheet-import/types/SpreadsheetColumn';
|
||||
import { SpreadsheetColumns } from '@/spreadsheet-import/types/SpreadsheetColumns';
|
||||
import { SpreadsheetColumnType } from '@/spreadsheet-import/types/SpreadsheetColumnType';
|
||||
import { normalizeTableData } from '@/spreadsheet-import/utils/normalizeTableData';
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
|
||||
describe('normalizeTableData', () => {
|
||||
const columns: Column<string>[] = [
|
||||
{ index: 0, header: 'Name', type: ColumnType.matched, value: 'name' },
|
||||
{ index: 1, header: 'Age', type: ColumnType.matched, value: 'age' },
|
||||
const columns: SpreadsheetColumn<string>[] = [
|
||||
{
|
||||
index: 0,
|
||||
header: 'Name',
|
||||
type: SpreadsheetColumnType.matched,
|
||||
value: 'name',
|
||||
},
|
||||
{
|
||||
index: 1,
|
||||
header: 'Age',
|
||||
type: SpreadsheetColumnType.matched,
|
||||
value: 'age',
|
||||
},
|
||||
{
|
||||
index: 2,
|
||||
header: 'Active',
|
||||
type: ColumnType.matchedCheckbox,
|
||||
type: SpreadsheetColumnType.matchedCheckbox,
|
||||
value: 'active',
|
||||
},
|
||||
];
|
||||
|
||||
const fields: Field<string>[] = [
|
||||
const fields: SpreadsheetImportField<string>[] = [
|
||||
{
|
||||
key: 'name',
|
||||
label: 'Name',
|
||||
fieldType: { type: 'input' },
|
||||
fieldMetadataType: FieldMetadataType.TEXT,
|
||||
icon: null,
|
||||
Icon: null,
|
||||
},
|
||||
{
|
||||
key: 'age',
|
||||
label: 'Age',
|
||||
fieldType: { type: 'input' },
|
||||
fieldMetadataType: FieldMetadataType.NUMBER,
|
||||
icon: null,
|
||||
Icon: null,
|
||||
},
|
||||
{
|
||||
key: 'active',
|
||||
@ -40,7 +49,7 @@ describe('normalizeTableData', () => {
|
||||
type: 'checkbox',
|
||||
},
|
||||
fieldMetadataType: FieldMetadataType.BOOLEAN,
|
||||
icon: null,
|
||||
Icon: null,
|
||||
},
|
||||
];
|
||||
|
||||
@ -61,16 +70,16 @@ describe('normalizeTableData', () => {
|
||||
});
|
||||
|
||||
it('should normalize matchedCheckbox values and handle booleanMatches', () => {
|
||||
const columns: Column<string>[] = [
|
||||
const columns: SpreadsheetColumn<string>[] = [
|
||||
{
|
||||
index: 0,
|
||||
header: 'Active',
|
||||
type: ColumnType.matchedCheckbox,
|
||||
type: SpreadsheetColumnType.matchedCheckbox,
|
||||
value: 'active',
|
||||
},
|
||||
];
|
||||
|
||||
const fields: Field<string>[] = [
|
||||
const fields: SpreadsheetImportField<string>[] = [
|
||||
{
|
||||
key: 'active',
|
||||
label: 'Active',
|
||||
@ -79,7 +88,7 @@ describe('normalizeTableData', () => {
|
||||
booleanMatches: { yes: true, no: false },
|
||||
},
|
||||
fieldMetadataType: FieldMetadataType.BOOLEAN,
|
||||
icon: null,
|
||||
Icon: null,
|
||||
},
|
||||
];
|
||||
|
||||
@ -91,11 +100,11 @@ describe('normalizeTableData', () => {
|
||||
});
|
||||
|
||||
it('should map matchedSelect and matchedSelectOptions values correctly', () => {
|
||||
const columns: Column<string>[] = [
|
||||
const columns: SpreadsheetColumn<string>[] = [
|
||||
{
|
||||
index: 0,
|
||||
header: 'Number',
|
||||
type: ColumnType.matchedSelect,
|
||||
type: SpreadsheetColumnType.matchedSelect,
|
||||
value: 'number',
|
||||
matchedOptions: [
|
||||
{ entry: 'One', value: '1' },
|
||||
@ -104,7 +113,7 @@ describe('normalizeTableData', () => {
|
||||
},
|
||||
];
|
||||
|
||||
const fields: Field<string>[] = [
|
||||
const fields: SpreadsheetImportField<string>[] = [
|
||||
{
|
||||
key: 'number',
|
||||
label: 'Number',
|
||||
@ -116,7 +125,7 @@ describe('normalizeTableData', () => {
|
||||
],
|
||||
},
|
||||
fieldMetadataType: FieldMetadataType.SELECT,
|
||||
icon: null,
|
||||
Icon: null,
|
||||
},
|
||||
];
|
||||
|
||||
@ -132,9 +141,9 @@ describe('normalizeTableData', () => {
|
||||
});
|
||||
|
||||
it('should handle empty and ignored columns', () => {
|
||||
const columns: Column<string>[] = [
|
||||
{ index: 0, header: 'Empty', type: ColumnType.empty },
|
||||
{ index: 1, header: 'Ignored', type: ColumnType.ignored },
|
||||
const columns: SpreadsheetColumn<string>[] = [
|
||||
{ index: 0, header: 'Empty', type: SpreadsheetColumnType.empty },
|
||||
{ index: 1, header: 'Ignored', type: SpreadsheetColumnType.ignored },
|
||||
];
|
||||
|
||||
const rawData = [['Value1', 'Value2']];
|
||||
@ -145,11 +154,11 @@ describe('normalizeTableData', () => {
|
||||
});
|
||||
|
||||
it('should handle unrecognized column types and return empty object', () => {
|
||||
const columns: Column<string>[] = [
|
||||
const columns: SpreadsheetColumns<string> = [
|
||||
{
|
||||
index: 0,
|
||||
header: 'Unrecognized',
|
||||
type: 'Unknown' as unknown as ColumnType.matched,
|
||||
type: 'Unknown' as unknown as SpreadsheetColumnType.matched,
|
||||
value: '',
|
||||
},
|
||||
];
|
||||
|
||||
@ -1,24 +1,22 @@
|
||||
import {
|
||||
Column,
|
||||
ColumnType,
|
||||
} from '@/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep';
|
||||
import { Field } from '@/spreadsheet-import/types';
|
||||
import { SpreadsheetImportField } from '@/spreadsheet-import/types';
|
||||
import { SpreadsheetColumn } from '@/spreadsheet-import/types/SpreadsheetColumn';
|
||||
import { SpreadsheetColumnType } from '@/spreadsheet-import/types/SpreadsheetColumnType';
|
||||
import { setColumn } from '@/spreadsheet-import/utils/setColumn';
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
|
||||
describe('setColumn', () => {
|
||||
const defaultField: Field<'Name'> = {
|
||||
icon: null,
|
||||
const defaultField: SpreadsheetImportField<'Name'> = {
|
||||
Icon: null,
|
||||
label: 'label',
|
||||
key: 'Name',
|
||||
fieldType: { type: 'input' },
|
||||
fieldMetadataType: FieldMetadataType.TEXT,
|
||||
};
|
||||
|
||||
const oldColumn: Column<'oldValue'> = {
|
||||
const oldColumn: SpreadsheetColumn<'oldValue'> = {
|
||||
index: 0,
|
||||
header: 'Name',
|
||||
type: ColumnType.matched,
|
||||
type: SpreadsheetColumnType.matched,
|
||||
value: 'oldValue',
|
||||
};
|
||||
|
||||
@ -29,7 +27,7 @@ describe('setColumn', () => {
|
||||
type: 'select',
|
||||
options: [{ value: 'John' }, { value: 'Alice' }],
|
||||
},
|
||||
} as Field<'Name'>;
|
||||
} as SpreadsheetImportField<'Name'>;
|
||||
|
||||
const data = [['John'], ['Alice']];
|
||||
const result = setColumn(oldColumn, field, data);
|
||||
@ -37,7 +35,7 @@ describe('setColumn', () => {
|
||||
expect(result).toEqual({
|
||||
index: 0,
|
||||
header: 'Name',
|
||||
type: ColumnType.matchedSelectOptions,
|
||||
type: SpreadsheetColumnType.matchedSelectOptions,
|
||||
value: 'Name',
|
||||
matchedOptions: [
|
||||
{
|
||||
@ -56,14 +54,14 @@ describe('setColumn', () => {
|
||||
const field = {
|
||||
...defaultField,
|
||||
fieldType: { type: 'checkbox' },
|
||||
} as Field<'Name'>;
|
||||
} as SpreadsheetImportField<'Name'>;
|
||||
|
||||
const result = setColumn(oldColumn, field);
|
||||
|
||||
expect(result).toEqual({
|
||||
index: 0,
|
||||
header: 'Name',
|
||||
type: ColumnType.matchedCheckbox,
|
||||
type: SpreadsheetColumnType.matchedCheckbox,
|
||||
value: 'Name',
|
||||
});
|
||||
});
|
||||
@ -72,14 +70,14 @@ describe('setColumn', () => {
|
||||
const field = {
|
||||
...defaultField,
|
||||
fieldType: { type: 'input' },
|
||||
} as Field<'Name'>;
|
||||
} as SpreadsheetImportField<'Name'>;
|
||||
|
||||
const result = setColumn(oldColumn, field);
|
||||
|
||||
expect(result).toEqual({
|
||||
index: 0,
|
||||
header: 'Name',
|
||||
type: ColumnType.matched,
|
||||
type: SpreadsheetColumnType.matched,
|
||||
value: 'Name',
|
||||
});
|
||||
});
|
||||
@ -88,14 +86,14 @@ describe('setColumn', () => {
|
||||
const field = {
|
||||
...defaultField,
|
||||
fieldType: { type: 'unknown' },
|
||||
} as unknown as Field<'Name'>;
|
||||
} as unknown as SpreadsheetImportField<'Name'>;
|
||||
|
||||
const result = setColumn(oldColumn, field);
|
||||
|
||||
expect(result).toEqual({
|
||||
index: 0,
|
||||
header: 'Name',
|
||||
type: ColumnType.empty,
|
||||
type: SpreadsheetColumnType.empty,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,22 +1,20 @@
|
||||
import {
|
||||
Column,
|
||||
ColumnType,
|
||||
} from '@/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep';
|
||||
import { SpreadsheetColumn } from '@/spreadsheet-import/types/SpreadsheetColumn';
|
||||
import { SpreadsheetColumnType } from '@/spreadsheet-import/types/SpreadsheetColumnType';
|
||||
import { setIgnoreColumn } from '@/spreadsheet-import/utils/setIgnoreColumn';
|
||||
|
||||
describe('setIgnoreColumn', () => {
|
||||
it('should return a column with type "ignored"', () => {
|
||||
const column: Column<'John'> = {
|
||||
const column: SpreadsheetColumn<'John'> = {
|
||||
index: 0,
|
||||
header: 'Name',
|
||||
type: ColumnType.matched,
|
||||
type: SpreadsheetColumnType.matched,
|
||||
value: 'John',
|
||||
};
|
||||
const result = setIgnoreColumn(column);
|
||||
expect(result).toEqual({
|
||||
index: 0,
|
||||
header: 'Name',
|
||||
type: ColumnType.ignored,
|
||||
type: SpreadsheetColumnType.ignored,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,15 +1,13 @@
|
||||
import {
|
||||
Column,
|
||||
ColumnType,
|
||||
} from '@/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep';
|
||||
import { SpreadsheetColumn } from '@/spreadsheet-import/types/SpreadsheetColumn';
|
||||
import { SpreadsheetColumnType } from '@/spreadsheet-import/types/SpreadsheetColumnType';
|
||||
import { setSubColumn } from '@/spreadsheet-import/utils/setSubColumn';
|
||||
|
||||
describe('setSubColumn', () => {
|
||||
it('should return a matchedSelectColumn with updated matchedOptions', () => {
|
||||
const oldColumn: Column<'John' | ''> = {
|
||||
const oldColumn: SpreadsheetColumn<'John' | ''> = {
|
||||
index: 0,
|
||||
header: 'Name',
|
||||
type: ColumnType.matchedSelect,
|
||||
type: SpreadsheetColumnType.matchedSelect,
|
||||
matchedOptions: [
|
||||
{ entry: 'Name1', value: 'John' },
|
||||
{ entry: 'Name2', value: '' },
|
||||
@ -24,7 +22,7 @@ describe('setSubColumn', () => {
|
||||
expect(result).toEqual({
|
||||
index: 0,
|
||||
header: 'Name',
|
||||
type: ColumnType.matchedSelect,
|
||||
type: SpreadsheetColumnType.matchedSelect,
|
||||
matchedOptions: [
|
||||
{ entry: 'Name1', value: 'John Doe' },
|
||||
{ entry: 'Name2', value: '' },
|
||||
@ -34,10 +32,10 @@ describe('setSubColumn', () => {
|
||||
});
|
||||
|
||||
it('should return a matchedSelectOptionsColumn with updated matchedOptions', () => {
|
||||
const oldColumn: Column<'John' | 'Jane'> = {
|
||||
const oldColumn: SpreadsheetColumn<'John' | 'Jane'> = {
|
||||
index: 0,
|
||||
header: 'Name',
|
||||
type: ColumnType.matchedSelectOptions,
|
||||
type: SpreadsheetColumnType.matchedSelectOptions,
|
||||
matchedOptions: [
|
||||
{ entry: 'Name1', value: 'John' },
|
||||
{ entry: 'Name2', value: 'Jane' },
|
||||
@ -52,7 +50,7 @@ describe('setSubColumn', () => {
|
||||
expect(result).toEqual({
|
||||
index: 0,
|
||||
header: 'Name',
|
||||
type: ColumnType.matchedSelectOptions,
|
||||
type: SpreadsheetColumnType.matchedSelectOptions,
|
||||
matchedOptions: [
|
||||
{ entry: 'Name1', value: 'John Doe' },
|
||||
{ entry: 'Name2', value: 'Jane' },
|
||||
|
||||
@ -6,24 +6,28 @@ import {
|
||||
ImportedStructuredRowMetadata,
|
||||
} from '@/spreadsheet-import/steps/components/ValidationStep/types';
|
||||
import {
|
||||
Fields,
|
||||
ImportedStructuredRow,
|
||||
Info,
|
||||
RowHook,
|
||||
TableHook,
|
||||
SpreadsheetImportFields,
|
||||
SpreadsheetImportInfo,
|
||||
SpreadsheetImportRowHook,
|
||||
SpreadsheetImportTableHook,
|
||||
} from '@/spreadsheet-import/types';
|
||||
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
|
||||
|
||||
export const addErrorsAndRunHooks = <T extends string>(
|
||||
data: (ImportedStructuredRow<T> & Partial<ImportedStructuredRowMetadata>)[],
|
||||
fields: Fields<T>,
|
||||
rowHook?: RowHook<T>,
|
||||
tableHook?: TableHook<T>,
|
||||
fields: SpreadsheetImportFields<T>,
|
||||
rowHook?: SpreadsheetImportRowHook<T>,
|
||||
tableHook?: SpreadsheetImportTableHook<T>,
|
||||
): (ImportedStructuredRow<T> & ImportedStructuredRowMetadata)[] => {
|
||||
const errors: Errors = {};
|
||||
|
||||
const addHookError = (rowIndex: number, fieldKey: T, error: Info) => {
|
||||
const addHookError = (
|
||||
rowIndex: number,
|
||||
fieldKey: T,
|
||||
error: SpreadsheetImportInfo,
|
||||
) => {
|
||||
errors[rowIndex] = {
|
||||
...errors[rowIndex],
|
||||
[fieldKey]: error,
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import { SpreadsheetImportFields } from '@/spreadsheet-import/types';
|
||||
import lavenstein from 'js-levenshtein';
|
||||
|
||||
import { Fields } from '@/spreadsheet-import/types';
|
||||
|
||||
type AutoMatchAccumulator<T> = {
|
||||
distance: number;
|
||||
value: T;
|
||||
@ -9,7 +8,7 @@ type AutoMatchAccumulator<T> = {
|
||||
|
||||
export const findMatch = <T extends string>(
|
||||
header: string,
|
||||
fields: Fields<T>,
|
||||
fields: SpreadsheetImportFields<T>,
|
||||
autoMapDistance: number,
|
||||
): T | undefined => {
|
||||
const smallestValue = fields.reduce<AutoMatchAccumulator<T>>((acc, field) => {
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { Columns } from '@/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep';
|
||||
import { Fields } from '@/spreadsheet-import/types';
|
||||
import { SpreadsheetImportFields } from '@/spreadsheet-import/types';
|
||||
import { SpreadsheetColumns } from '@/spreadsheet-import/types/SpreadsheetColumns';
|
||||
|
||||
export const findUnmatchedRequiredFields = <T extends string>(
|
||||
fields: Fields<T>,
|
||||
columns: Columns<T>,
|
||||
fields: SpreadsheetImportFields<T>,
|
||||
columns: SpreadsheetColumns<T>,
|
||||
) =>
|
||||
fields
|
||||
.filter((field) =>
|
||||
|
||||
@ -1,13 +1,21 @@
|
||||
import { Field, Fields } from '@/spreadsheet-import/types';
|
||||
import {
|
||||
SpreadsheetImportField,
|
||||
SpreadsheetImportFields,
|
||||
} from '@/spreadsheet-import/types';
|
||||
|
||||
const titleMap: Record<Field<string>['fieldType']['type'], string> = {
|
||||
const titleMap: Record<
|
||||
SpreadsheetImportField<string>['fieldType']['type'],
|
||||
string
|
||||
> = {
|
||||
checkbox: 'Boolean',
|
||||
select: 'Options',
|
||||
multiSelect: 'Options',
|
||||
input: 'Text',
|
||||
};
|
||||
|
||||
export const generateExampleRow = <T extends string>(fields: Fields<T>) => [
|
||||
export const generateExampleRow = <T extends string>(
|
||||
fields: SpreadsheetImportFields<T>,
|
||||
) => [
|
||||
fields.reduce(
|
||||
(acc, field) => {
|
||||
acc[field.key as T] = field.example || titleMap[field.fieldType.type];
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { Fields } from '@/spreadsheet-import/types';
|
||||
import { SpreadsheetImportFields } from '@/spreadsheet-import/types';
|
||||
|
||||
export const getFieldOptions = <T extends string>(
|
||||
fields: Fields<T>,
|
||||
fields: SpreadsheetImportFields<T>,
|
||||
fieldKey: string,
|
||||
) => {
|
||||
const field = fields.find(({ key }) => fieldKey === key);
|
||||
|
||||
@ -1,26 +1,29 @@
|
||||
import lavenstein from 'js-levenshtein';
|
||||
|
||||
import {
|
||||
Column,
|
||||
Columns,
|
||||
MatchColumnsStepProps,
|
||||
} from '@/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep';
|
||||
import { Field, Fields } from '@/spreadsheet-import/types';
|
||||
import { MatchColumnsStepProps } from '@/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep';
|
||||
|
||||
import {
|
||||
SpreadsheetImportField,
|
||||
SpreadsheetImportFields,
|
||||
} from '@/spreadsheet-import/types';
|
||||
import { SpreadsheetColumn } from '@/spreadsheet-import/types/SpreadsheetColumn';
|
||||
import { SpreadsheetColumns } from '@/spreadsheet-import/types/SpreadsheetColumns';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { findMatch } from './findMatch';
|
||||
import { setColumn } from './setColumn';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export const getMatchedColumns = <T extends string>(
|
||||
columns: Columns<T>,
|
||||
fields: Fields<T>,
|
||||
columns: SpreadsheetColumns<T>,
|
||||
fields: SpreadsheetImportFields<T>,
|
||||
data: MatchColumnsStepProps['data'],
|
||||
autoMapDistance: number,
|
||||
) =>
|
||||
columns.reduce<Column<T>[]>((arr, column) => {
|
||||
columns.reduce<SpreadsheetColumn<T>[]>((arr, column) => {
|
||||
const autoMatch = findMatch(column.header, fields, autoMapDistance);
|
||||
if (isDefined(autoMatch)) {
|
||||
const field = fields.find((field) => field.key === autoMatch) as Field<T>;
|
||||
const field = fields.find(
|
||||
(field) => field.key === autoMatch,
|
||||
) as SpreadsheetImportField<T>;
|
||||
const duplicateIndex = arr.findIndex(
|
||||
(column) => 'value' in column && column.value === field.key,
|
||||
);
|
||||
|
||||
@ -1,26 +1,24 @@
|
||||
import {
|
||||
Columns,
|
||||
ColumnType,
|
||||
} from '@/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep';
|
||||
import {
|
||||
Fields,
|
||||
ImportedRow,
|
||||
ImportedStructuredRow,
|
||||
SpreadsheetImportFields,
|
||||
} from '@/spreadsheet-import/types';
|
||||
import { SpreadsheetColumns } from '@/spreadsheet-import/types/SpreadsheetColumns';
|
||||
import { SpreadsheetColumnType } from '@/spreadsheet-import/types/SpreadsheetColumnType';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { z } from 'zod';
|
||||
import { normalizeCheckboxValue } from './normalizeCheckboxValue';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export const normalizeTableData = <T extends string>(
|
||||
columns: Columns<T>,
|
||||
columns: SpreadsheetColumns<T>,
|
||||
data: ImportedRow[],
|
||||
fields: Fields<T>,
|
||||
fields: SpreadsheetImportFields<T>,
|
||||
) =>
|
||||
data.map((row) =>
|
||||
columns.reduce((acc, column, index) => {
|
||||
const curr = row[index];
|
||||
switch (column.type) {
|
||||
case ColumnType.matchedCheckbox: {
|
||||
case SpreadsheetColumnType.matchedCheckbox: {
|
||||
const field = fields.find((field) => field.key === column.value);
|
||||
|
||||
if (!field) {
|
||||
@ -49,12 +47,12 @@ export const normalizeTableData = <T extends string>(
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
case ColumnType.matched: {
|
||||
case SpreadsheetColumnType.matched: {
|
||||
acc[column.value] = curr === '' ? undefined : curr;
|
||||
return acc;
|
||||
}
|
||||
case ColumnType.matchedSelect:
|
||||
case ColumnType.matchedSelectOptions: {
|
||||
case SpreadsheetColumnType.matchedSelect:
|
||||
case SpreadsheetColumnType.matchedSelectOptions: {
|
||||
const field = fields.find((field) => field.key === column.value);
|
||||
|
||||
if (!field) {
|
||||
@ -96,8 +94,8 @@ export const normalizeTableData = <T extends string>(
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
case ColumnType.empty:
|
||||
case ColumnType.ignored: {
|
||||
case SpreadsheetColumnType.empty:
|
||||
case SpreadsheetColumnType.ignored: {
|
||||
return acc;
|
||||
}
|
||||
default:
|
||||
|
||||
@ -1,25 +1,23 @@
|
||||
import {
|
||||
Column,
|
||||
ColumnType,
|
||||
MatchColumnsStepProps,
|
||||
MatchedOptions,
|
||||
} from '@/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep';
|
||||
import { Field } from '@/spreadsheet-import/types';
|
||||
import { MatchColumnsStepProps } from '@/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep';
|
||||
|
||||
import { SpreadsheetImportField } from '@/spreadsheet-import/types';
|
||||
import { SpreadsheetColumn } from '@/spreadsheet-import/types/SpreadsheetColumn';
|
||||
import { SpreadsheetColumnType } from '@/spreadsheet-import/types/SpreadsheetColumnType';
|
||||
import { SpreadsheetMatchedOptions } from '@/spreadsheet-import/types/SpreadsheetMatchedOptions';
|
||||
import { z } from 'zod';
|
||||
import { uniqueEntries } from './uniqueEntries';
|
||||
|
||||
export const setColumn = <T extends string>(
|
||||
oldColumn: Column<T>,
|
||||
field?: Field<T>,
|
||||
oldColumn: SpreadsheetColumn<T>,
|
||||
field?: SpreadsheetImportField<T>,
|
||||
data?: MatchColumnsStepProps['data'],
|
||||
): Column<T> => {
|
||||
): SpreadsheetColumn<T> => {
|
||||
if (field?.fieldType.type === 'select') {
|
||||
const fieldOptions = field.fieldType.options;
|
||||
const uniqueData = uniqueEntries(
|
||||
data || [],
|
||||
oldColumn.index,
|
||||
) as MatchedOptions<T>[];
|
||||
) as SpreadsheetMatchedOptions<T>[];
|
||||
|
||||
const matchedOptions = uniqueData.map((record) => {
|
||||
const value = fieldOptions.find(
|
||||
@ -28,8 +26,8 @@ export const setColumn = <T extends string>(
|
||||
fieldOption.label === record.entry,
|
||||
)?.value;
|
||||
return value
|
||||
? ({ ...record, value } as MatchedOptions<T>)
|
||||
: (record as MatchedOptions<T>);
|
||||
? ({ ...record, value } as SpreadsheetMatchedOptions<T>)
|
||||
: (record as SpreadsheetMatchedOptions<T>);
|
||||
});
|
||||
const allMatched =
|
||||
matchedOptions.filter((o) => o.value).length === uniqueData?.length;
|
||||
@ -37,8 +35,8 @@ export const setColumn = <T extends string>(
|
||||
return {
|
||||
...oldColumn,
|
||||
type: allMatched
|
||||
? ColumnType.matchedSelectOptions
|
||||
: ColumnType.matchedSelect,
|
||||
? SpreadsheetColumnType.matchedSelectOptions
|
||||
: SpreadsheetColumnType.matchedSelect,
|
||||
value: field.key,
|
||||
matchedOptions,
|
||||
};
|
||||
@ -69,8 +67,8 @@ export const setColumn = <T extends string>(
|
||||
fieldOption.value === entry || fieldOption.label === entry,
|
||||
)?.value;
|
||||
return value
|
||||
? ({ entry, value } as MatchedOptions<T>)
|
||||
: ({ entry } as MatchedOptions<T>);
|
||||
? ({ entry, value } as SpreadsheetMatchedOptions<T>)
|
||||
: ({ entry } as SpreadsheetMatchedOptions<T>);
|
||||
});
|
||||
const areAllMatched =
|
||||
matchedOptions.filter((option) => option.value).length ===
|
||||
@ -79,8 +77,8 @@ export const setColumn = <T extends string>(
|
||||
return {
|
||||
...oldColumn,
|
||||
type: areAllMatched
|
||||
? ColumnType.matchedSelectOptions
|
||||
: ColumnType.matchedSelect,
|
||||
? SpreadsheetColumnType.matchedSelectOptions
|
||||
: SpreadsheetColumnType.matchedSelect,
|
||||
value: field.key,
|
||||
matchedOptions,
|
||||
};
|
||||
@ -89,7 +87,7 @@ export const setColumn = <T extends string>(
|
||||
if (field?.fieldType.type === 'checkbox') {
|
||||
return {
|
||||
index: oldColumn.index,
|
||||
type: ColumnType.matchedCheckbox,
|
||||
type: SpreadsheetColumnType.matchedCheckbox,
|
||||
value: field.key,
|
||||
header: oldColumn.header,
|
||||
};
|
||||
@ -98,7 +96,7 @@ export const setColumn = <T extends string>(
|
||||
if (field?.fieldType.type === 'input') {
|
||||
return {
|
||||
index: oldColumn.index,
|
||||
type: ColumnType.matched,
|
||||
type: SpreadsheetColumnType.matched,
|
||||
value: field.key,
|
||||
header: oldColumn.header,
|
||||
};
|
||||
@ -107,6 +105,6 @@ export const setColumn = <T extends string>(
|
||||
return {
|
||||
index: oldColumn.index,
|
||||
header: oldColumn.header,
|
||||
type: ColumnType.empty,
|
||||
type: SpreadsheetColumnType.empty,
|
||||
};
|
||||
};
|
||||
|
||||
@ -1,13 +1,11 @@
|
||||
import {
|
||||
Column,
|
||||
ColumnType,
|
||||
} from '@/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep';
|
||||
import { SpreadsheetColumn } from '@/spreadsheet-import/types/SpreadsheetColumn';
|
||||
import { SpreadsheetColumnType } from '@/spreadsheet-import/types/SpreadsheetColumnType';
|
||||
|
||||
export const setIgnoreColumn = <T extends string>({
|
||||
header,
|
||||
index,
|
||||
}: Column<T>): Column<T> => ({
|
||||
}: SpreadsheetColumn<T>): SpreadsheetColumn<T> => ({
|
||||
header,
|
||||
index,
|
||||
type: ColumnType.ignored,
|
||||
type: SpreadsheetColumnType.ignored,
|
||||
});
|
||||
|
||||
@ -1,30 +1,34 @@
|
||||
import {
|
||||
ColumnType,
|
||||
MatchedOptions,
|
||||
MatchedSelectColumn,
|
||||
MatchedSelectOptionsColumn,
|
||||
} from '@/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep';
|
||||
SpreadsheetMatchedSelectColumn,
|
||||
SpreadsheetMatchedSelectOptionsColumn,
|
||||
} from '@/spreadsheet-import/types/SpreadsheetColumn';
|
||||
import { SpreadsheetColumnType } from '@/spreadsheet-import/types/SpreadsheetColumnType';
|
||||
import { SpreadsheetMatchedOptions } from '@/spreadsheet-import/types/SpreadsheetMatchedOptions';
|
||||
|
||||
export const setSubColumn = <T>(
|
||||
oldColumn: MatchedSelectColumn<T> | MatchedSelectOptionsColumn<T>,
|
||||
oldColumn:
|
||||
| SpreadsheetMatchedSelectColumn<T>
|
||||
| SpreadsheetMatchedSelectOptionsColumn<T>,
|
||||
entry: string,
|
||||
value: string,
|
||||
): MatchedSelectColumn<T> | MatchedSelectOptionsColumn<T> => {
|
||||
):
|
||||
| SpreadsheetMatchedSelectColumn<T>
|
||||
| SpreadsheetMatchedSelectOptionsColumn<T> => {
|
||||
const options = oldColumn.matchedOptions.map((option) =>
|
||||
option.entry === entry ? { ...option, value } : option,
|
||||
);
|
||||
const allMathced = options.every(({ value }) => !!value);
|
||||
if (allMathced) {
|
||||
const allMatched = options.every(({ value }) => !!value);
|
||||
if (allMatched) {
|
||||
return {
|
||||
...oldColumn,
|
||||
matchedOptions: options as MatchedOptions<T>[],
|
||||
type: ColumnType.matchedSelectOptions,
|
||||
matchedOptions: options as SpreadsheetMatchedOptions<T>[],
|
||||
type: SpreadsheetColumnType.matchedSelectOptions,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
...oldColumn,
|
||||
matchedOptions: options as MatchedOptions<T>[],
|
||||
type: ColumnType.matchedSelect,
|
||||
matchedOptions: options as SpreadsheetMatchedOptions<T>[],
|
||||
type: SpreadsheetColumnType.matchedSelect,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
@ -1,14 +1,12 @@
|
||||
import uniqBy from 'lodash.uniqby';
|
||||
|
||||
import {
|
||||
MatchColumnsStepProps,
|
||||
MatchedOptions,
|
||||
} from '@/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep';
|
||||
import { MatchColumnsStepProps } from '@/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep';
|
||||
import { SpreadsheetMatchedOptions } from '@/spreadsheet-import/types/SpreadsheetMatchedOptions';
|
||||
|
||||
export const uniqueEntries = <T extends string>(
|
||||
data: MatchColumnsStepProps['data'],
|
||||
index: number,
|
||||
): Partial<MatchedOptions<T>>[] =>
|
||||
): Partial<SpreadsheetMatchedOptions<T>>[] =>
|
||||
uniqBy(
|
||||
data.map((row) => ({ entry: row[index] })),
|
||||
'entry',
|
||||
|
||||
Reference in New Issue
Block a user