Skip to content

Commit

Permalink
Basic import for select in CSV (#6047)
Browse files Browse the repository at this point in the history
Enables basic support for Select import and field matching in CSV. 
It's not pretty! But it's better than what we had before.
We should iterate on that quickly

<img width="591" alt="Screenshot 2024-06-26 at 18 41 16"
src="https://github.com/twentyhq/twenty/assets/6399865/99f67f39-3f0f-4074-aac6-3200954be08a">
  • Loading branch information
FelixMalfait authored Jun 26, 2024
1 parent 1eb9c58 commit 7b816e5
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 43 deletions.
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { isNonEmptyString } from '@sniptt/guards';
import { IconComponent, useIcons } from 'twenty-ui';
import { useIcons } from 'twenty-ui';

import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { useCreateManyRecords } from '@/object-record/hooks/useCreateManyRecords';
import { getSpreadSheetValidation } from '@/object-record/spreadsheet-import/util/getSpreadSheetValidation';
import { useSpreadsheetImport } from '@/spreadsheet-import/hooks/useSpreadsheetImport';
import { SpreadsheetOptions, Validation } from '@/spreadsheet-import/types';
import { Field, SpreadsheetOptions } from '@/spreadsheet-import/types';
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { FieldMetadataType } from '~/generated-metadata/graphql';
Expand All @@ -32,15 +32,7 @@ export const useSpreadsheetRecordImport = (objectNameSingular: string) => {
)
.sort((a, b) => a.name.localeCompare(b.name));

const templateFields: {
icon: IconComponent;
label: string;
key: string;
fieldType: {
type: 'input' | 'checkbox';
};
validations?: Validation[];
}[] = [];
const templateFields: Field<string>[] = [];
for (const field of fields) {
if (field.type === FieldMetadataType.FullName) {
templateFields.push({
Expand Down Expand Up @@ -80,6 +72,24 @@ export const useSpreadsheetRecordImport = (objectNameSingular: string) => {
field.label + ' (ID)',
),
});
} else if (field.type === FieldMetadataType.Select) {
templateFields.push({
icon: getIcon(field.icon),
label: field.label,
key: field.name,
fieldType: {
type: 'select',
options:
field.options?.map((option) => ({
label: option.label,
value: option.value,
})) || [],
},
validations: getSpreadSheetValidation(
field.type,
field.label + ' (ID)',
),
});
} else {
templateFields.push({
icon: getIcon(field.icon),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ export const MatchColumnSelect = ({
<DropdownMenu
data-select-disable
ref={dropdownContainerRef}
width={refs.domReference.current?.clientWidth}
// width={refs.domReference.current?.clientWidth}
>
<DropdownMenuSearchInput
value={searchFilter}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,10 @@ export const ValidationStep = <T extends string>({
(importColumn) =>
(importColumn.type === ColumnType.matched &&
importColumn.value === column.key) ||
(importColumn.type === ColumnType.matchedSelect &&
importColumn.value === column.key) ||
(importColumn.type === ColumnType.matchedSelectOptions &&
importColumn.value === column.key) ||
column.key === 'select-row',
).length > 0;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,13 @@ describe('setColumn', () => {
value: 'oldValue',
};

it('should return a matchedSelect column if field type is "select"', () => {
it('should return a matchedSelectOptions column if field type is "select"', () => {
const field = {
...defaultField,
fieldType: { type: 'select' },
fieldType: {
type: 'select',
options: [{ value: 'John' }, { value: 'Alice' }],
},
} as Field<'Name'>;

const data = [['John'], ['Alice']];
Expand All @@ -32,14 +35,16 @@ describe('setColumn', () => {
expect(result).toEqual({
index: 0,
header: 'Name',
type: ColumnType.matchedSelect,
type: ColumnType.matchedSelectOptions,
value: 'Name',
matchedOptions: [
{
entry: 'John',
value: 'John',
},
{
entry: 'Alice',
value: 'Alice',
},
],
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
Column,
ColumnType,
MatchColumnsStepProps,
MatchedOptions,
} from '@/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep';
import { Field } from '@/spreadsheet-import/types';

Expand All @@ -12,33 +13,56 @@ export const setColumn = <T extends string>(
field?: Field<T>,
data?: MatchColumnsStepProps<T>['data'],
): Column<T> => {
switch (field?.fieldType.type) {
case 'select':
return {
...oldColumn,
type: ColumnType.matchedSelect,
value: field.key,
matchedOptions: uniqueEntries(data || [], oldColumn.index),
};
case 'checkbox':
return {
index: oldColumn.index,
type: ColumnType.matchedCheckbox,
value: field.key,
header: oldColumn.header,
};
case 'input':
return {
index: oldColumn.index,
type: ColumnType.matched,
value: field.key,
header: oldColumn.header,
};
default:
return {
index: oldColumn.index,
header: oldColumn.header,
type: ColumnType.empty,
};
if (field?.fieldType.type === 'select') {
const fieldOptions = field.fieldType.options;
const uniqueData = uniqueEntries(
data || [],
oldColumn.index,
) as MatchedOptions<T>[];
const matchedOptions = uniqueData.map((record) => {
const value = fieldOptions.find(
(fieldOption) =>
fieldOption.value === record.entry ||
fieldOption.label === record.entry,
)?.value;
return value
? ({ ...record, value } as MatchedOptions<T>)
: (record as MatchedOptions<T>);
});
const allMatched =
matchedOptions.filter((o) => o.value).length === uniqueData?.length;

return {
...oldColumn,
type: allMatched
? ColumnType.matchedSelectOptions
: ColumnType.matchedSelect,
value: field.key,
matchedOptions,
};
}

if (field?.fieldType.type === 'checkbox') {
return {
index: oldColumn.index,
type: ColumnType.matchedCheckbox,
value: field.key,
header: oldColumn.header,
};
}

if (field?.fieldType.type === 'input') {
return {
index: oldColumn.index,
type: ColumnType.matched,
value: field.key,
header: oldColumn.header,
};
}

return {
index: oldColumn.index,
header: oldColumn.header,
type: ColumnType.empty,
};
};

0 comments on commit 7b816e5

Please sign in to comment.