twentyhq / twenty

Building a modern alternative to Salesforce, powered by the community.
https://twenty.com
GNU Affero General Public License v3.0
15.97k stars 1.77k forks source link

If CSV imports returns a 400 then we should return to the previous step #5790

Open FelixMalfait opened 3 months ago

FelixMalfait commented 3 months ago

Currently if the CSV import fails (e.g. send a wrong value to a SELECT field), we optimistic-render the result which still appear in the table even though the import failed. Instead, we should stay in the import modal and give explicit feedback on what needs to be fixed.

greptile-apps[bot] commented 3 months ago

Disclaimer: This comment was automatically generated with AI. It can give some useful hints as to where to look for, but sometimes it can also give very inaccurate answers so takes this with a pinch of salt :).

To handle the case where CSV imports return a 400 error, modify the UploadFlow component to catch the error and revert to the previous step. Update the onContinue function in UploadStep and ValidationStep components to handle the error and provide feedback.

  1. Update UploadFlow.tsx:
const onContinue = async (workbook, file) => {
  try {
    setUploadedFile(file);
    const isSingleSheet = workbook.SheetNames.length === 1;
    if (isSingleSheet) {
      if (maxRecords > 0 && exceedsMaxRecords(workbook.Sheets[workbook.SheetNames[0]], maxRecords)) {
        errorToast(`Too many records. Up to ${maxRecords.toString()} allowed`);
        return;
      }
      const mappedWorkbook = await uploadStepHook(mapWorkbook(workbook));
      if (selectHeader) {
        setState({ type: StepType.selectHeader, data: mappedWorkbook });
      } else {
        const trimmedData = mappedWorkbook.slice(1);
        const { data, headerValues } = await selectHeaderStepHook(mappedWorkbook[0], trimmedData);
        setState({ type: StepType.matchColumns, data, headerValues });
      }
    } else {
      setState({ type: StepType.selectSheet, workbook });
    }
    setPreviousState(state);
    nextStep();
  } catch (e) {
    errorToast((e as Error).message);
    setState(previousState); // Revert to previous step on error
  }
};
  1. Update ValidationStep.tsx:
const submitData = async () => {
  try {
    const calculatedData = data.reduce((acc, value) => {
      const { __index, __errors, ...values } = value;
      if (isDefined(__errors)) {
        for (const key in __errors) {
          if (__errors[key].level === 'error') {
            acc.invalidData.push(values as unknown as Data<T>);
            return acc;
          }
        }
      }
      acc.validData.push(values as unknown as Data<T>);
      return acc;
    }, { validData: [] as Data<T>[], invalidData: [] as Data<T>[], all: data });
    onSubmitStart?.();
    await onSubmit(calculatedData, file);
    onClose();
  } catch (e) {
    errorToast((e as Error).message);
    onBack(); // Revert to previous step on error
  }
};
  1. Update UploadStep.tsx:
const handleOnContinue = async (data: WorkBook, file: File) => {
  setIsLoading(true);
  try {
    await onContinue(data, file);
  } catch (e) {
    errorToast((e as Error).message);
  } finally {
    setIsLoading(false);
  }
};

References

/packages/twenty-front/src/modules/spreadsheet-import/steps/components/UploadFlow.tsx /packages/twenty-front/src/modules/spreadsheet-import/steps/components/ValidationStep/ValidationStep.tsx /packages/twenty-front/src/modules/spreadsheet-import/steps/components/UploadStep/UploadStep.tsx

Ask Greptile