Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Select item when allowNewOptions is true and Enter is pressed #15429

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
67 changes: 42 additions & 25 deletions superset-frontend/src/components/Select/Select.tsx
Expand Up @@ -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';
Expand All @@ -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<AntdSelectValue>;
Expand Down Expand Up @@ -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 (
Expand Down Expand Up @@ -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)) {
Expand All @@ -305,6 +315,7 @@ const Select = ({
// adds a custom option
const newOptions = [...selectOptions, newOption];
setOptions(newOptions);
setSelectValue(searchValue);
}
}
setSearchedValue(searchValue);
Expand Down Expand Up @@ -376,6 +387,12 @@ const Select = ({
handlePaginatedFetch,
]);

useEffect(() => {
if (isSingleMode) {
handleTopOptions(selectValue);
}
}, [handleTopOptions, isSingleMode, selectValue]);

const dropdownRender = (
originNode: ReactElement & { ref?: RefObject<HTMLElement> },
) => {
Expand Down