Improve Data Importer Select Matching - Post Merge Updates (#6750)

This PR was created by [GitStart](https://gitstart.com/) to address the
requirements from this ticket:
[TWNTY-6135-1](https://clients.gitstart.com/twenty/5449/tickets/TWNTY-6135-1).

 --- 
### Description
This [PR](https://github.com/twentyhq/twenty/pull/6338) was merged, but
the reviewr asked for some changes in another PR
https://github.com/twentyhq/twenty/pull/6338#pullrequestreview-2255006727


### Refs
https://github.com/twentyhq/twenty/pull/6338

### Demo
<https://jam.dev/c/80336c7a-4536-4a58-b531-981bac81cb26>

Co-authored-by: gitstart-twenty <gitstart-twenty@users.noreply.github.com>
This commit is contained in:
gitstart-app[bot]
2024-08-28 17:33:39 +02:00
committed by GitHub
parent 0531eb5015
commit 7c894fe870
13 changed files with 70 additions and 66 deletions

View File

@ -89,6 +89,7 @@ export const SelectFieldInput = ({
fieldDefinition.metadata.isNullable ? handleClearField : undefined
}
clearLabel={fieldDefinition.label}
hotkeyScope={hotkeyScope}
/>
</SelectableList>
</div>

View File

@ -21,8 +21,8 @@ import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { Modal } from '@/ui/layout/modal/components/Modal';
import { initialComputedColumnsSelector } from '@/spreadsheet-import/steps/components/MatchColumnsStep/components/states/initialComputedColumnsState';
import { UnmatchColumn } from '@/spreadsheet-import/steps/components/MatchColumnsStep/components/UnmatchColumn';
import { initialComputedColumnsState } from '@/spreadsheet-import/steps/components/MatchColumnsStep/components/states/initialComputedColumnsState';
import { SpreadsheetImportStep } from '@/spreadsheet-import/steps/types/SpreadsheetImportStep';
import { SpreadsheetImportStepType } from '@/spreadsheet-import/steps/types/SpreadsheetImportStepType';
import { useRecoilState } from 'recoil';
@ -63,7 +63,7 @@ export type MatchColumnsStepProps = {
setPreviousStepState: (currentStepState: SpreadsheetImportStep) => void;
currentStepState: SpreadsheetImportStep;
nextStep: () => void;
errorToast: (message: string) => void;
onError: (message: string) => void;
};
export enum ColumnType {
@ -136,7 +136,7 @@ export const MatchColumnsStep = <T extends string>({
setPreviousStepState,
currentStepState,
nextStep,
errorToast,
onError,
}: MatchColumnsStepProps) => {
const { enqueueDialog } = useDialogManager();
const { enqueueSnackBar } = useSnackBar();
@ -145,7 +145,7 @@ export const MatchColumnsStep = <T extends string>({
useSpreadsheetImportInternal<T>();
const [isLoading, setIsLoading] = useState(false);
const [columns, setColumns] = useRecoilState(
initialComputedColumnsState(headerValues),
initialComputedColumnsSelector(headerValues),
);
const { matchColumnsStepHook } = useSpreadsheetImportInternal();
@ -215,7 +215,7 @@ export const MatchColumnsStep = <T extends string>({
],
);
const onContinue = useCallback(
const handleContinue = useCallback(
async (
values: ImportedStructuredRow<string>[],
rawData: ImportedRow[],
@ -231,11 +231,11 @@ export const MatchColumnsStep = <T extends string>({
setPreviousStepState(currentStepState);
nextStep();
} catch (e) {
errorToast((e as Error).message);
onError((e as Error).message);
}
},
[
errorToast,
onError,
matchColumnsStepHook,
nextStep,
setPreviousStepState,
@ -263,9 +263,13 @@ export const MatchColumnsStep = <T extends string>({
const handleAlertOnContinue = useCallback(async () => {
setIsLoading(true);
await onContinue(normalizeTableData(columns, data, fields), data, columns);
await handleContinue(
normalizeTableData(columns, data, fields),
data,
columns,
);
setIsLoading(false);
}, [onContinue, columns, data, fields]);
}, [handleContinue, columns, data, fields]);
const handleOnContinue = useCallback(async () => {
if (unmatchedRequiredFields.length > 0) {
@ -293,7 +297,7 @@ export const MatchColumnsStep = <T extends string>({
});
} else {
setIsLoading(true);
await onContinue(
await handleContinue(
normalizeTableData(columns, data, fields),
data,
columns,
@ -304,7 +308,7 @@ export const MatchColumnsStep = <T extends string>({
unmatchedRequiredFields,
enqueueDialog,
handleAlertOnContinue,
onContinue,
handleContinue,
columns,
data,
fields,

View File

@ -6,8 +6,10 @@ import { SelectOption } from '@/spreadsheet-import/types';
import { getFieldOptions } from '@/spreadsheet-import/utils/getFieldOptions';
import { SelectFieldHotkeyScope } from '@/object-record/select/types/SelectFieldHotkeyScope';
import { SelectInput } from '@/ui/input/components/SelectInput';
import { useState } from 'react';
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
import { useEffect, useState } from 'react';
import { IconChevronDown, Tag, TagColor } from 'twenty-ui';
import {
MatchedOptions,
@ -83,6 +85,12 @@ export const SubMatchingSelect = <T extends string>({
setIsOpen(false);
};
const setHotkeyScope = useSetHotkeyScope();
useEffect(() => {
setHotkeyScope(SelectFieldHotkeyScope.SelectField);
}, [setHotkeyScope]);
return (
<StyledContainer>
<StyledControlContainer cursor="default">
@ -113,6 +121,7 @@ export const SubMatchingSelect = <T extends string>({
options={options}
onOptionSelected={handleSelect}
onCancel={() => setIsOpen(false)}
hotkeyScope={SelectFieldHotkeyScope.SelectField}
/>
)}
</StyledControlContainer>

View File

@ -10,11 +10,11 @@ export const matchColumnsState = atom({
default: [] as Columns<string>,
});
export const initialComputedColumnsState = selectorFamily<
export const initialComputedColumnsSelector = selectorFamily<
Columns<string>,
ImportedRow
>({
key: 'InitialComputedColumnsState',
key: 'initialComputedColumnsSelector',
get:
(headerValues: ImportedRow) =>
({ get }) => {

View File

@ -27,7 +27,7 @@ type SelectHeaderStepProps = {
setCurrentStepState: (currentStepState: SpreadsheetImportStep) => void;
nextStep: () => void;
setPreviousStepState: (currentStepState: SpreadsheetImportStep) => void;
errorToast: (message: string) => void;
onError: (message: string) => void;
onBack: () => void;
currentStepState: SpreadsheetImportStep;
};
@ -37,7 +37,7 @@ export const SelectHeaderStep = ({
setCurrentStepState,
nextStep,
setPreviousStepState,
errorToast,
onError,
onBack,
currentStepState,
}: SelectHeaderStepProps) => {
@ -49,7 +49,7 @@ export const SelectHeaderStep = ({
const { selectHeaderStepHook } = useSpreadsheetImportInternal();
const onContinue = useCallback(
const handleContinue = useCallback(
async (...args: Parameters<typeof selectHeaderStepHook>) => {
try {
const { importedRows: data, headerRow: headerValues } =
@ -62,11 +62,11 @@ export const SelectHeaderStep = ({
setPreviousStepState(currentStepState);
nextStep();
} catch (e) {
errorToast((e as Error).message);
onError((e as Error).message);
}
},
[
errorToast,
onError,
nextStep,
selectHeaderStepHook,
setPreviousStepState,
@ -75,17 +75,17 @@ export const SelectHeaderStep = ({
],
);
const handleContinue = useCallback(async () => {
const handleOnContinue = useCallback(async () => {
const [selectedRowIndex] = Array.from(new Set(selectedRowIndexes));
// We consider data above header to be redundant
const trimmedData = importedRows.slice(selectedRowIndex + 1);
setIsLoading(true);
await onContinue(importedRows[selectedRowIndex], trimmedData);
await handleContinue(importedRows[selectedRowIndex], trimmedData);
setIsLoading(false);
}, [onContinue, importedRows, selectedRowIndexes]);
}, [handleContinue, importedRows, selectedRowIndexes]);
return (
<>
@ -100,7 +100,7 @@ export const SelectHeaderStep = ({
</StyledTableContainer>
</Modal.Content>
<StepNavigationButton
onClick={handleContinue}
onClick={handleOnContinue}
onBack={onBack}
title="Continue"
isLoading={isLoading}

View File

@ -35,7 +35,7 @@ type SelectSheetStepProps = {
sheetNames: string[];
onBack: () => void;
setCurrentStepState: (data: SpreadsheetImportStep) => void;
errorToast: (message: string) => void;
onError: (message: string) => void;
setPreviousStepState: (data: SpreadsheetImportStep) => void;
currentStepState: {
type: SpreadsheetImportStepType.selectSheet;
@ -46,7 +46,7 @@ type SelectSheetStepProps = {
export const SelectSheetStep = ({
sheetNames,
setCurrentStepState,
errorToast,
onError,
setPreviousStepState,
onBack,
currentStepState,
@ -57,7 +57,7 @@ export const SelectSheetStep = ({
const { maxRecords, uploadStepHook } = useSpreadsheetImportInternal();
const onContinue = useCallback(
const handleContinue = useCallback(
async (sheetName: string) => {
if (
maxRecords > 0 &&
@ -66,7 +66,7 @@ export const SelectSheetStep = ({
maxRecords,
)
) {
errorToast(`Too many records. Up to ${maxRecords.toString()} allowed`);
onError(`Too many records. Up to ${maxRecords.toString()} allowed`);
return;
}
try {
@ -79,11 +79,11 @@ export const SelectSheetStep = ({
});
setPreviousStepState(currentStepState);
} catch (e) {
errorToast((e as Error).message);
onError((e as Error).message);
}
},
[
errorToast,
onError,
maxRecords,
currentStepState,
setPreviousStepState,
@ -95,10 +95,10 @@ export const SelectSheetStep = ({
const handleOnContinue = useCallback(
async (data: typeof value) => {
setIsLoading(true);
await onContinue(data);
await handleContinue(data);
setIsLoading(false);
},
[onContinue],
[handleContinue],
);
return (

View File

@ -48,7 +48,7 @@ export const SpreadsheetImportStepper = ({
const { enqueueSnackBar } = useSnackBar();
const errorToast = useCallback(
const handleError = useCallback(
(description: string) => {
enqueueSnackBar(description, {
title: 'Error',
@ -58,7 +58,7 @@ export const SpreadsheetImportStepper = ({
[enqueueSnackBar],
);
const onBack = useCallback(() => {
const handleBack = useCallback(() => {
setCurrentStepState(previousStepState);
prevStep();
}, [prevStep, previousStepState]);
@ -71,7 +71,7 @@ export const SpreadsheetImportStepper = ({
currentStepState={currentStepState}
setPreviousStepState={setPreviousStepState}
setCurrentStepState={setCurrentStepState}
errorToast={errorToast}
onError={handleError}
nextStep={nextStep}
/>
);
@ -81,9 +81,9 @@ export const SpreadsheetImportStepper = ({
sheetNames={currentStepState.workbook.SheetNames}
setCurrentStepState={setCurrentStepState}
currentStepState={currentStepState}
errorToast={errorToast}
onError={handleError}
setPreviousStepState={setPreviousStepState}
onBack={onBack}
onBack={handleBack}
/>
);
case SpreadsheetImportStepType.selectHeader:
@ -93,8 +93,8 @@ export const SpreadsheetImportStepper = ({
setCurrentStepState={setCurrentStepState}
nextStep={nextStep}
setPreviousStepState={setPreviousStepState}
errorToast={errorToast}
onBack={onBack}
onError={handleError}
onBack={handleBack}
currentStepState={currentStepState}
/>
);
@ -107,10 +107,8 @@ export const SpreadsheetImportStepper = ({
setPreviousStepState={setPreviousStepState}
currentStepState={currentStepState}
nextStep={nextStep}
onBack={() => {
onBack();
}}
errorToast={errorToast}
onBack={handleBack}
onError={handleError}
/>
);
case SpreadsheetImportStepType.validateData:
@ -124,7 +122,7 @@ export const SpreadsheetImportStepper = ({
file={uploadedFile}
setCurrentStepState={setCurrentStepState}
onBack={() => {
onBack();
handleBack();
setPreviousStepState(
initialStepState || { type: SpreadsheetImportStepType.upload },
);

View File

@ -18,7 +18,7 @@ const StyledContent = styled(Modal.Content)`
type UploadStepProps = {
setUploadedFile: (file: File) => void;
setCurrentStepState: (data: any) => void;
errorToast: (message: string) => void;
onError: (message: string) => void;
nextStep: () => void;
setPreviousStepState: (data: any) => void;
currentStepState: SpreadsheetImportStep;
@ -27,7 +27,7 @@ type UploadStepProps = {
export const UploadStep = ({
setUploadedFile,
setCurrentStepState,
errorToast,
onError,
nextStep,
setPreviousStepState,
currentStepState,
@ -36,7 +36,7 @@ export const UploadStep = ({
const { maxRecords, uploadStepHook, selectHeaderStepHook, selectHeader } =
useSpreadsheetImportInternal();
const onContinue = useCallback(
const handleContinue = useCallback(
async (workbook: WorkBook, file: File) => {
setUploadedFile(file);
const isSingleSheet = workbook.SheetNames.length === 1;
@ -45,9 +45,7 @@ export const UploadStep = ({
maxRecords > 0 &&
exceedsMaxRecords(workbook.Sheets[workbook.SheetNames[0]], maxRecords)
) {
errorToast(
`Too many records. Up to ${maxRecords.toString()} allowed`,
);
onError(`Too many records. Up to ${maxRecords.toString()} allowed`);
return;
}
try {
@ -72,7 +70,7 @@ export const UploadStep = ({
});
}
} catch (e) {
errorToast((e as Error).message);
onError((e as Error).message);
}
} else {
setCurrentStepState({
@ -84,7 +82,7 @@ export const UploadStep = ({
nextStep();
},
[
errorToast,
onError,
maxRecords,
nextStep,
selectHeader,
@ -100,10 +98,10 @@ export const UploadStep = ({
const handleOnContinue = useCallback(
async (data: WorkBook, file: File) => {
setIsLoading(true);
await onContinue(data, file);
await handleContinue(data, file);
setIsLoading(false);
},
[onContinue],
[handleContinue],
);
return (

View File

@ -72,7 +72,7 @@ export const Default = () => (
setPreviousStepState={() => null}
currentStepState={{} as SpreadsheetImportStep}
nextStep={() => null}
errorToast={() => null}
onError={() => null}
/>
</ModalWrapper>
</ReactSpreadsheetImportContextProvider>

View File

@ -29,7 +29,7 @@ export const Default = () => (
setCurrentStepState={() => null}
nextStep={() => Promise.resolve()}
setPreviousStepState={() => null}
errorToast={() => null}
onError={() => null}
onBack={() => Promise.resolve()}
currentStepState={{
type: SpreadsheetImportStepType.selectHeader,

View File

@ -50,7 +50,7 @@ export const Default = () => (
},
},
}}
errorToast={() => null}
onError={() => null}
onBack={() => Promise.resolve()}
/>
</ModalWrapper>

View File

@ -26,7 +26,7 @@ export const Default = () => (
<UploadStep
setUploadedFile={() => null}
setCurrentStepState={() => null}
errorToast={() => null}
onError={() => null}
nextStep={() => null}
setPreviousStepState={() => null}
currentStepState={{

View File

@ -2,14 +2,12 @@ import styled from '@emotion/styled';
import { SelectOption } from '@/spreadsheet-import/types';
import { SelectFieldHotkeyScope } from '@/object-record/select/types/SelectFieldHotkeyScope';
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput';
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
import { MenuItemSelectTag } from '@/ui/navigation/menu-item/components/MenuItemSelectTag';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
import { useTheme } from '@emotion/react';
import {
@ -40,6 +38,7 @@ interface SelectInputProps {
onFilterChange?: (filteredOptions: SelectOption[]) => void;
onClear?: () => void;
clearLabel?: string;
hotkeyScope: string;
}
export const SelectInput = ({
@ -51,6 +50,7 @@ export const SelectInput = ({
defaultOption,
parentRef,
onFilterChange,
hotkeyScope,
}: SelectInputProps) => {
const containerRef = useRef<HTMLDivElement>(null);
@ -97,12 +97,6 @@ export const SelectInput = ({
placement: 'bottom-start',
});
const setHotkeyScope = useSetHotkeyScope();
useEffect(() => {
setHotkeyScope(SelectFieldHotkeyScope.SelectField);
}, [setHotkeyScope]);
useEffect(() => {
onFilterChange?.(optionsInDropDown);
}, [onFilterChange, optionsInDropDown]);
@ -132,7 +126,7 @@ export const SelectInput = ({
handleOptionChange(selectedOption);
}
},
SelectFieldHotkeyScope.SelectField,
hotkeyScope,
[searchFilter, optionsInDropDown],
);