From 0b7e524f027e2005afc1a2f32d942892a6462747 Mon Sep 17 00:00:00 2001 From: "Michael S. Molina" <70410625+michael-s-molina@users.noreply.github.com> Date: Mon, 28 Jun 2021 15:29:58 -0300 Subject: [PATCH] fix: Select item when allowNewOptions is true and the Enter is pressed (#15429) --- .../src/components/Select/Select.tsx | 67 ++++++++++++------- 1 file changed, 42 insertions(+), 25 deletions(-) diff --git a/superset-frontend/src/components/Select/Select.tsx b/superset-frontend/src/components/Select/Select.tsx index cc02ae8bf..d0b83f33d 100644 --- a/superset-frontend/src/components/Select/Select.tsx +++ b/superset-frontend/src/components/Select/Select.tsx @@ -25,6 +25,7 @@ import React, { useMemo, useState, useRef, + useCallback, } from 'react'; import { styled, t } from '@superset-ui/core'; import { Select as AntdSelect } from 'antd'; @@ -36,6 +37,7 @@ import { } from 'antd/lib/select'; import debounce from 'lodash/debounce'; import { getClientErrorObject } from 'src/utils/getClientErrorObject'; +import { isEqual } from 'lodash'; import { hasOption } from './utils'; type AntdSelectAllProps = AntdSelectProps; @@ -165,37 +167,44 @@ const Select = ({ ? 'tags' : 'multiple'; - const handleTopOptions = (selectedValue: AntdSelectValue | undefined) => { - // bringing selected options to the top of the list - if (selectedValue) { - const currentValue = selectedValue as string[] | string; - const topOptions = selectOptions.filter(opt => - currentValue?.includes(opt.value), - ); - const otherOptions = selectOptions.filter( - opt => !topOptions.find(tOpt => tOpt.value === opt.value), - ); - // fallback for custom options in tags mode as they - // do not appear in the selectOptions state - if (!isSingleMode && Array.isArray(currentValue)) { - // eslint-disable-next-line no-restricted-syntax - for (const val of currentValue) { - if (!topOptions.find(tOpt => tOpt.value === val)) { - topOptions.push({ label: val, value: val }); + const handleTopOptions = useCallback( + (selectedValue: AntdSelectValue | undefined) => { + // bringing selected options to the top of the list + if (selectedValue) { + const currentValue = selectedValue as string[] | string; + const topOptions = selectOptions.filter(opt => + Array.isArray(currentValue) + ? currentValue.includes(opt.value) + : currentValue === opt.value, + ); + const otherOptions = selectOptions.filter( + opt => !topOptions.find(tOpt => tOpt.value === opt.value), + ); + // fallback for custom options in tags mode as they + // do not appear in the selectOptions state + if (!isSingleMode && Array.isArray(currentValue)) { + // eslint-disable-next-line no-restricted-syntax + for (const val of currentValue) { + if (!topOptions.find(tOpt => tOpt.value === val)) { + topOptions.push({ label: val, value: val }); + } } } + + const sortedOptions = [...topOptions, ...otherOptions]; + if (!isEqual(sortedOptions, selectOptions)) { + setOptions(sortedOptions); + } } - setOptions([...topOptions, ...otherOptions]); - } - }; + }, + [isSingleMode, selectOptions], + ); const handleOnSelect = ( selectedValue: string | number | AntdLabeledValue, ) => { if (isSingleMode) { setSelectValue(selectedValue); - // in single mode the sorting must happen on selection - handleTopOptions(selectedValue); } else { const currentSelected = Array.isArray(selectValue) ? selectValue : []; if ( @@ -287,14 +296,15 @@ const Select = ({ const searchValue = search.trim(); // enables option creation if (allowNewOptions && isSingleMode) { - const lastOption = selectOptions[selectOptions.length - 1].value; + const firstOption = selectOptions.length > 0 && selectOptions[0].value; // replaces the last search value entered with the new one // only when the value wasn't part of the original options if ( - lastOption === searchedValue && + searchValue && + firstOption === searchedValue && !initialOptions.find(o => o.value === searchedValue) ) { - selectOptions.pop(); + selectOptions.shift(); setOptions(selectOptions); } if (searchValue && !hasOption(searchValue, selectOptions)) { @@ -305,6 +315,7 @@ const Select = ({ // adds a custom option const newOptions = [...selectOptions, newOption]; setOptions(newOptions); + setSelectValue(searchValue); } } setSearchedValue(searchValue); @@ -376,6 +387,12 @@ const Select = ({ handlePaginatedFetch, ]); + useEffect(() => { + if (isSingleMode) { + handleTopOptions(selectValue); + } + }, [handleTopOptions, isSingleMode, selectValue]); + const dropdownRender = ( originNode: ReactElement & { ref?: RefObject }, ) => {