diff --git a/superset-frontend/src/components/Select/Select.tsx b/superset-frontend/src/components/Select/Select.tsx index ca0d28dd7f57..12b481bcc0f7 100644 --- a/superset-frontend/src/components/Select/Select.tsx +++ b/superset-frontend/src/components/Select/Select.tsx @@ -40,7 +40,7 @@ import { Spin } from 'antd'; import Icons from 'src/components/Icons'; import { getClientErrorObject } from 'src/utils/getClientErrorObject'; import { SLOW_DEBOUNCE } from 'src/constants'; -import { hasOption } from './utils'; +import { hasOption, hasOptionIgnoreCase } from './utils'; const { Option } = AntdSelect; @@ -57,6 +57,8 @@ type PickedSelectProps = Pick< | 'notFoundContent' | 'onChange' | 'onClear' + | 'onFocus' + | 'onBlur' | 'placeholder' | 'showSearch' | 'value' @@ -519,7 +521,7 @@ const Select = ({ const debouncedHandleSearch = useMemo( () => debounce((search: string) => { - // async search will triggered in handlePaginatedFetch + // async search will be triggered in handlePaginatedFetch setSearchedValue(search); }, SLOW_DEBOUNCE), [], @@ -529,12 +531,14 @@ const Select = ({ const searchValue = search.trim(); if (allowNewOptions && isSingleMode) { const newOption = searchValue && - !hasOption(searchValue, selectOptions) && { + !hasOptionIgnoreCase(searchValue, selectOptions) && { label: searchValue, value: searchValue, isNewOption: true, }; - const cleanSelectOptions = selectOptions.filter(opt => !opt.isNewOption); + const cleanSelectOptions = selectOptions.filter( + opt => !opt.isNewOption || hasOption(opt.value, selectValue), + ); const newOptions = newOption ? [newOption, ...cleanSelectOptions] : cleanSelectOptions; diff --git a/superset-frontend/src/components/Select/utils.ts b/superset-frontend/src/components/Select/utils.ts index 71a904520591..1a3e3ca3b340 100644 --- a/superset-frontend/src/components/Select/utils.ts +++ b/superset-frontend/src/components/Select/utils.ts @@ -1,3 +1,4 @@ +import { ensureIsArray } from '@superset-ui/core'; /** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -60,7 +61,19 @@ export function findValue( return (Array.isArray(value) ? value : [value]).map(find); } -export function hasOption(search: string, options: AntdOptionsType) { +export function hasOption( + value: VT, + options?: VT | VT[] | { value: VT } | { value: VT }[], +) { + const optionsArray = ensureIsArray(options); + return ( + optionsArray.find(x => + typeof x === 'object' ? x.value === value : x === value, + ) !== undefined + ); +} + +export function hasOptionIgnoreCase(search: string, options: AntdOptionsType) { const searchOption = search.trim().toLowerCase(); return options.find(opt => { const { label, value } = opt;