update import auto matching (#12552)
<img width="800" alt="Screenshot 2025-06-11 at 17 45 13" src="https://github.com/user-attachments/assets/ecc04d41-d74a-424a-9f83-14a793cf4268" /> closes https://github.com/twentyhq/core-team-issues/issues/905
This commit is contained in:
+46
-10
@@ -1,32 +1,68 @@
|
||||
import { MatchColumnsStepProps } from '@/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep';
|
||||
|
||||
import { SpreadsheetImportFields } from '@/spreadsheet-import/types';
|
||||
import {
|
||||
SpreadsheetImportField,
|
||||
SpreadsheetImportFields,
|
||||
} 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 { setColumn } from '@/spreadsheet-import/utils/setColumn';
|
||||
import Fuse from 'fuse.js';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export const getMatchedColumnsWithFuse = <T extends string>(
|
||||
columns: SpreadsheetColumns<T>,
|
||||
fields: SpreadsheetImportFields<T>,
|
||||
data: MatchColumnsStepProps['data'],
|
||||
) => {
|
||||
export const getMatchedColumnsWithFuse = <T extends string>({
|
||||
columns,
|
||||
fields,
|
||||
data,
|
||||
}: {
|
||||
columns: SpreadsheetColumns<T>;
|
||||
fields: SpreadsheetImportFields<T>;
|
||||
data: MatchColumnsStepProps['data'];
|
||||
}) => {
|
||||
const matchedColumns: SpreadsheetColumn<T>[] = [];
|
||||
|
||||
const fieldsToSearch = new Fuse(fields, {
|
||||
keys: ['label'],
|
||||
includeScore: true,
|
||||
ignoreLocation: true,
|
||||
threshold: 0.3,
|
||||
});
|
||||
|
||||
const suggestedFieldsByColumnHeader: Record<
|
||||
SpreadsheetColumn<T>['header'],
|
||||
SpreadsheetImportField<T>[]
|
||||
> = {};
|
||||
|
||||
for (const column of columns) {
|
||||
const fieldsThatMatch = fieldsToSearch.search(column.header);
|
||||
|
||||
const firstMatch = fieldsThatMatch[0]?.item ?? null;
|
||||
const firstMatch = fieldsThatMatch[0] || null;
|
||||
const secondMatch = fieldsThatMatch[1] || null;
|
||||
|
||||
if (isDefined(firstMatch)) {
|
||||
const newColumn = setColumn(column, firstMatch as any, data);
|
||||
const isFirstMatchValid =
|
||||
isDefined(firstMatch?.item) &&
|
||||
isDefined(firstMatch?.score) &&
|
||||
firstMatch.score < 0.4 &&
|
||||
((isDefined(secondMatch?.score) &&
|
||||
secondMatch.score !== firstMatch.score) ||
|
||||
!isDefined(secondMatch));
|
||||
|
||||
const isFieldStillUnmatched = !matchedColumns.some(
|
||||
(matchedColumn) =>
|
||||
(matchedColumn.type === SpreadsheetColumnType.matched ||
|
||||
matchedColumn.type === SpreadsheetColumnType.matchedCheckbox ||
|
||||
matchedColumn.type === SpreadsheetColumnType.matchedSelect ||
|
||||
matchedColumn.type === SpreadsheetColumnType.matchedSelectOptions) &&
|
||||
matchedColumn?.value === firstMatch?.item?.key,
|
||||
);
|
||||
|
||||
suggestedFieldsByColumnHeader[column.header] = fieldsThatMatch.map(
|
||||
(match) => match.item as SpreadsheetImportField<T>,
|
||||
);
|
||||
|
||||
if (isFirstMatchValid && isFieldStillUnmatched) {
|
||||
const newColumn = setColumn(column, firstMatch.item as any, data);
|
||||
|
||||
matchedColumns.push(newColumn);
|
||||
} else {
|
||||
@@ -34,5 +70,5 @@ export const getMatchedColumnsWithFuse = <T extends string>(
|
||||
}
|
||||
}
|
||||
|
||||
return { matchedColumns };
|
||||
return { matchedColumns, suggestedFieldsByColumnHeader };
|
||||
};
|
||||
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
import { getFieldMetadataTypeLabel } from '@/object-record/object-filter-dropdown/utils/getFieldMetadataTypeLabel';
|
||||
import { SpreadsheetImportFields } from '@/spreadsheet-import/types';
|
||||
import { SpreadsheetColumns } from '@/spreadsheet-import/types/SpreadsheetColumns';
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
|
||||
export const spreadsheetBuildFieldOptions = <T extends string>(
|
||||
fields: SpreadsheetImportFields<T>,
|
||||
columns: SpreadsheetColumns<string>,
|
||||
) => {
|
||||
return fields
|
||||
.filter((field) => field.fieldMetadataType !== FieldMetadataType.RICH_TEXT)
|
||||
.map(({ Icon, label, key, fieldMetadataType }) => {
|
||||
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,
|
||||
fieldMetadataTypeLabel: getFieldMetadataTypeLabel(fieldMetadataType),
|
||||
} as const;
|
||||
});
|
||||
};
|
||||
Reference in New Issue
Block a user