diff --git a/superset-frontend/src/components/Select/AsyncSelect.stories.tsx b/superset-frontend/src/components/Select/AsyncSelect.stories.tsx
index 547fc7fa994e9..0bdaf43f2c06f 100644
--- a/superset-frontend/src/components/Select/AsyncSelect.stories.tsx
+++ b/superset-frontend/src/components/Select/AsyncSelect.stories.tsx
@@ -123,6 +123,15 @@ const ARG_TYPES = {
By default label and value.
`,
},
+ oneLine: {
+ defaultValue: false,
+ description: `Sets maxTagCount to 1. The overflow tag is always displayed in
+ the same line, line wrapping is disabled.
+ When the dropdown is open, sets maxTagCount to 0,
+ displays only the overflow tag.
+ Requires '"mode=multiple"'.
+ `,
+ },
};
const USERS = [
diff --git a/superset-frontend/src/components/Select/AsyncSelect.test.tsx b/superset-frontend/src/components/Select/AsyncSelect.test.tsx
index b11dcde017c48..ac9c78767c4ae 100644
--- a/superset-frontend/src/components/Select/AsyncSelect.test.tsx
+++ b/superset-frontend/src/components/Select/AsyncSelect.test.tsx
@@ -756,6 +756,54 @@ test('finds an element with a numeric value and does not duplicate the options',
expect(await querySelectOption('11')).not.toBeInTheDocument();
});
+test('Renders only 1 tag and an overflow tag in oneLine mode', () => {
+ render(
+ ,
+ );
+ expect(screen.getByText(OPTIONS[0].label)).toBeVisible();
+ expect(screen.queryByText(OPTIONS[1].label)).not.toBeInTheDocument();
+ expect(screen.queryByText(OPTIONS[2].label)).not.toBeInTheDocument();
+ expect(screen.getByText('+ 2 ...')).toBeVisible();
+});
+
+test('Renders only an overflow tag if dropdown is open in oneLine mode', async () => {
+ render(
+ ,
+ );
+ await open();
+
+ const withinSelector = within(getElementByClassName('.ant-select-selector'));
+ await waitFor(() => {
+ expect(
+ withinSelector.queryByText(OPTIONS[0].label),
+ ).not.toBeInTheDocument();
+ expect(
+ withinSelector.queryByText(OPTIONS[1].label),
+ ).not.toBeInTheDocument();
+ expect(
+ withinSelector.queryByText(OPTIONS[2].label),
+ ).not.toBeInTheDocument();
+ expect(withinSelector.getByText('+ 3 ...')).toBeVisible();
+ });
+
+ await type('{esc}');
+
+ expect(await withinSelector.findByText(OPTIONS[0].label)).toBeVisible();
+ expect(withinSelector.queryByText(OPTIONS[1].label)).not.toBeInTheDocument();
+ expect(withinSelector.queryByText(OPTIONS[2].label)).not.toBeInTheDocument();
+ expect(withinSelector.getByText('+ 2 ...')).toBeVisible();
+});
+
/*
TODO: Add tests that require scroll interaction. Needs further investigation.
- Fetches more data when scrolling and more data is available
diff --git a/superset-frontend/src/components/Select/AsyncSelect.tsx b/superset-frontend/src/components/Select/AsyncSelect.tsx
index 71474a341c907..5cbd193c56483 100644
--- a/superset-frontend/src/components/Select/AsyncSelect.tsx
+++ b/superset-frontend/src/components/Select/AsyncSelect.tsx
@@ -71,6 +71,7 @@ import {
TOKEN_SEPARATORS,
DEFAULT_SORT_COMPARATOR,
} from './constants';
+import { oneLineTagRender } from './CustomTag';
const Error = ({ error }: { error: string }) => (
@@ -125,6 +126,8 @@ const AsyncSelect = forwardRef(
tokenSeparators,
value,
getPopupContainer,
+ oneLine,
+ maxTagCount: propsMaxTagCount,
...props
}: AsyncSelectProps,
ref: RefObject,
@@ -148,6 +151,16 @@ const AsyncSelect = forwardRef(
: 'multiple';
const allowFetch = !fetchOnlyOnSearch || inputValue;
+ const [maxTagCount, setMaxTagCount] = useState(
+ propsMaxTagCount ?? MAX_TAG_COUNT,
+ );
+
+ useEffect(() => {
+ if (oneLine) {
+ setMaxTagCount(isDropdownVisible ? 0 : 1);
+ }
+ }, [isDropdownVisible, oneLine]);
+
useEffect(() => {
selectValueRef.current = selectValue;
}, [selectValue]);
@@ -487,7 +500,7 @@ const AsyncSelect = forwardRef(
}
headerPosition={headerPosition}
labelInValue
- maxTagCount={MAX_TAG_COUNT}
+ maxTagCount={maxTagCount}
mode={mappedMode}
notFoundContent={isLoading ? t('Loading...') : notFoundContent}
onDeselect={handleOnDeselect}
@@ -513,6 +526,8 @@ const AsyncSelect = forwardRef(
)
}
+ oneLine={oneLine}
+ tagRender={oneLine ? oneLineTagRender : undefined}
{...props}
ref={ref}
>