From 7c894fe87096d3cc0b02814c9247f209ce604ed0 Mon Sep 17 00:00:00 2001 From: "gitstart-app[bot]" <57568882+gitstart-app[bot]@users.noreply.github.com> Date: Wed, 28 Aug 2024 17:33:39 +0200 Subject: [PATCH] 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 Co-authored-by: gitstart-twenty --- .../input/components/SelectFieldInput.tsx | 1 + .../MatchColumnsStep/MatchColumnsStep.tsx | 26 +++++++++++-------- .../components/SubMatchingSelect.tsx | 11 +++++++- .../states/initialComputedColumnsState.ts | 4 +-- .../SelectHeaderStep/SelectHeaderStep.tsx | 18 ++++++------- .../SelectSheetStep/SelectSheetStep.tsx | 16 ++++++------ .../components/SpreadsheetImportStepper.tsx | 22 +++++++--------- .../components/UploadStep/UploadStep.tsx | 18 ++++++------- .../__stories__/MatchColumns.stories.tsx | 2 +- .../__stories__/SelectHeader.stories.tsx | 2 +- .../__stories__/SelectSheet.stories.tsx | 2 +- .../components/__stories__/Upload.stories.tsx | 2 +- .../ui/input/components/SelectInput.tsx | 12 +++------ 13 files changed, 70 insertions(+), 66 deletions(-) diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/SelectFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/SelectFieldInput.tsx index 2d9b4072e..d9082b850 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/SelectFieldInput.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/SelectFieldInput.tsx @@ -89,6 +89,7 @@ export const SelectFieldInput = ({ fieldDefinition.metadata.isNullable ? handleClearField : undefined } clearLabel={fieldDefinition.label} + hotkeyScope={hotkeyScope} /> diff --git a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep.tsx b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep.tsx index 20b0051c9..c0a7e52c2 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep.tsx +++ b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep.tsx @@ -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 = ({ setPreviousStepState, currentStepState, nextStep, - errorToast, + onError, }: MatchColumnsStepProps) => { const { enqueueDialog } = useDialogManager(); const { enqueueSnackBar } = useSnackBar(); @@ -145,7 +145,7 @@ export const MatchColumnsStep = ({ useSpreadsheetImportInternal(); const [isLoading, setIsLoading] = useState(false); const [columns, setColumns] = useRecoilState( - initialComputedColumnsState(headerValues), + initialComputedColumnsSelector(headerValues), ); const { matchColumnsStepHook } = useSpreadsheetImportInternal(); @@ -215,7 +215,7 @@ export const MatchColumnsStep = ({ ], ); - const onContinue = useCallback( + const handleContinue = useCallback( async ( values: ImportedStructuredRow[], rawData: ImportedRow[], @@ -231,11 +231,11 @@ export const MatchColumnsStep = ({ 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 = ({ 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 = ({ }); } else { setIsLoading(true); - await onContinue( + await handleContinue( normalizeTableData(columns, data, fields), data, columns, @@ -304,7 +308,7 @@ export const MatchColumnsStep = ({ unmatchedRequiredFields, enqueueDialog, handleAlertOnContinue, - onContinue, + handleContinue, columns, data, fields, diff --git a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/SubMatchingSelect.tsx b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/SubMatchingSelect.tsx index 9a7e7e5f5..27aa269d8 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/SubMatchingSelect.tsx +++ b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/SubMatchingSelect.tsx @@ -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 = ({ setIsOpen(false); }; + const setHotkeyScope = useSetHotkeyScope(); + + useEffect(() => { + setHotkeyScope(SelectFieldHotkeyScope.SelectField); + }, [setHotkeyScope]); + return ( @@ -113,6 +121,7 @@ export const SubMatchingSelect = ({ options={options} onOptionSelected={handleSelect} onCancel={() => setIsOpen(false)} + hotkeyScope={SelectFieldHotkeyScope.SelectField} /> )} diff --git a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/states/initialComputedColumnsState.ts b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/states/initialComputedColumnsState.ts index ed147aadd..9b41943cd 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/states/initialComputedColumnsState.ts +++ b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/states/initialComputedColumnsState.ts @@ -10,11 +10,11 @@ export const matchColumnsState = atom({ default: [] as Columns, }); -export const initialComputedColumnsState = selectorFamily< +export const initialComputedColumnsSelector = selectorFamily< Columns, ImportedRow >({ - key: 'InitialComputedColumnsState', + key: 'initialComputedColumnsSelector', get: (headerValues: ImportedRow) => ({ get }) => { diff --git a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/SelectHeaderStep/SelectHeaderStep.tsx b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/SelectHeaderStep/SelectHeaderStep.tsx index 55c46e433..f92dcee6c 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/SelectHeaderStep/SelectHeaderStep.tsx +++ b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/SelectHeaderStep/SelectHeaderStep.tsx @@ -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) => { 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 = ({ 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 ( diff --git a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/SpreadsheetImportStepper.tsx b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/SpreadsheetImportStepper.tsx index 7b85b17cd..c3bdf3a5d 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/SpreadsheetImportStepper.tsx +++ b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/SpreadsheetImportStepper.tsx @@ -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 }, ); diff --git a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/UploadStep/UploadStep.tsx b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/UploadStep/UploadStep.tsx index 9d3109601..6119bb189 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/UploadStep/UploadStep.tsx +++ b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/UploadStep/UploadStep.tsx @@ -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 ( diff --git a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/__stories__/MatchColumns.stories.tsx b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/__stories__/MatchColumns.stories.tsx index e3a849964..47cb4e54d 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/__stories__/MatchColumns.stories.tsx +++ b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/__stories__/MatchColumns.stories.tsx @@ -72,7 +72,7 @@ export const Default = () => ( setPreviousStepState={() => null} currentStepState={{} as SpreadsheetImportStep} nextStep={() => null} - errorToast={() => null} + onError={() => null} /> diff --git a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/__stories__/SelectHeader.stories.tsx b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/__stories__/SelectHeader.stories.tsx index d6de08e0d..a87f0ce42 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/__stories__/SelectHeader.stories.tsx +++ b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/__stories__/SelectHeader.stories.tsx @@ -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, diff --git a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/__stories__/SelectSheet.stories.tsx b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/__stories__/SelectSheet.stories.tsx index 3c37538e4..e48542f1a 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/__stories__/SelectSheet.stories.tsx +++ b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/__stories__/SelectSheet.stories.tsx @@ -50,7 +50,7 @@ export const Default = () => ( }, }, }} - errorToast={() => null} + onError={() => null} onBack={() => Promise.resolve()} /> diff --git a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/__stories__/Upload.stories.tsx b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/__stories__/Upload.stories.tsx index fb7e9d78d..7f2b295fb 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/__stories__/Upload.stories.tsx +++ b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/__stories__/Upload.stories.tsx @@ -26,7 +26,7 @@ export const Default = () => ( null} setCurrentStepState={() => null} - errorToast={() => null} + onError={() => null} nextStep={() => null} setPreviousStepState={() => null} currentStepState={{ diff --git a/packages/twenty-front/src/modules/ui/input/components/SelectInput.tsx b/packages/twenty-front/src/modules/ui/input/components/SelectInput.tsx index e08131d9a..67c9ffa03 100644 --- a/packages/twenty-front/src/modules/ui/input/components/SelectInput.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/SelectInput.tsx @@ -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(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], );