mirror of
https://github.com/apache/superset.git
synced 2026-05-18 22:35:14 +00:00
Compare commits
4 Commits
fix/mcp-ex
...
fix/dropdo
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bf6e779200 | ||
|
|
ce6501c36c | ||
|
|
6ea6b01f4f | ||
|
|
c1376c05a9 |
@@ -51,8 +51,16 @@ test('renders children with custom horizontal spacing', () => {
|
|||||||
expect(screen.getByTestId('container')).toHaveStyle('gap: 20px');
|
expect(screen.getByTestId('container')).toHaveStyle('gap: 20px');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('does not render a dropdown button when not overflowing', () => {
|
test('renders dropdown button when items exist even when not overflowing', () => {
|
||||||
render(<DropdownContainer items={generateItems(3)} />);
|
render(<DropdownContainer items={generateItems(3)} />);
|
||||||
|
// Button should always be visible when items exist to prevent layout shifts
|
||||||
|
expect(screen.getByText('More')).toBeInTheDocument();
|
||||||
|
// Badge should show 0 when nothing is overflowing
|
||||||
|
expect(screen.getByText('0')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('does not render a dropdown button when no items', () => {
|
||||||
|
render(<DropdownContainer items={[]} />);
|
||||||
expect(screen.queryByText('More')).not.toBeInTheDocument();
|
expect(screen.queryByText('More')).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ import { t } from '@apache-superset/core/translation';
|
|||||||
import { usePrevious } from '@superset-ui/core';
|
import { usePrevious } from '@superset-ui/core';
|
||||||
import { css, useTheme } from '@apache-superset/core/theme';
|
import { css, useTheme } from '@apache-superset/core/theme';
|
||||||
import { useResizeDetector } from 'react-resize-detector';
|
import { useResizeDetector } from 'react-resize-detector';
|
||||||
import { Badge, Icons, Button, Tooltip, Popover } from '..';
|
import { Badge, Icons, Button, Popover } from '..';
|
||||||
import { DropdownContainerProps, DropdownItem, DropdownRef } from './types';
|
import { DropdownContainerProps, DropdownItem, DropdownRef } from './types';
|
||||||
|
|
||||||
const MAX_HEIGHT = 500;
|
const MAX_HEIGHT = 500;
|
||||||
@@ -234,6 +234,10 @@ export const DropdownContainer = forwardRef(
|
|||||||
const overflowingCount =
|
const overflowingCount =
|
||||||
overflowingIndex !== -1 ? items.length - overflowingIndex : 0;
|
overflowingIndex !== -1 ? items.length - overflowingIndex : 0;
|
||||||
|
|
||||||
|
// Always show button when items exist to prevent layout shifts
|
||||||
|
// and ensure consistent UI even when no items are overflowing
|
||||||
|
const shouldShowButton = items.length > 0 || !!dropdownContent;
|
||||||
|
|
||||||
const popoverContent = useMemo(
|
const popoverContent = useMemo(
|
||||||
() =>
|
() =>
|
||||||
dropdownContent || overflowingCount ? (
|
dropdownContent || overflowingCount ? (
|
||||||
@@ -293,72 +297,13 @@ export const DropdownContainer = forwardRef(
|
|||||||
};
|
};
|
||||||
}, [popoverVisible]);
|
}, [popoverVisible]);
|
||||||
|
|
||||||
return (
|
const triggerButton = (
|
||||||
<div
|
|
||||||
ref={ref}
|
|
||||||
css={css`
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
css={css`
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: ${theme.sizeUnit * 4}px;
|
|
||||||
margin-right: ${theme.sizeUnit * 4}px;
|
|
||||||
min-width: 0px;
|
|
||||||
`}
|
|
||||||
data-test="container"
|
|
||||||
style={style}
|
|
||||||
>
|
|
||||||
{notOverflowedItems.map(item => item.element)}
|
|
||||||
</div>
|
|
||||||
{popoverContent && (
|
|
||||||
<>
|
|
||||||
<Global
|
|
||||||
styles={css`
|
|
||||||
.ant-popover-inner {
|
|
||||||
// Some OS versions only show the scroll when hovering.
|
|
||||||
// These settings will make the scroll always visible.
|
|
||||||
::-webkit-scrollbar {
|
|
||||||
-webkit-appearance: none;
|
|
||||||
width: 14px;
|
|
||||||
}
|
|
||||||
::-webkit-scrollbar-thumb {
|
|
||||||
border-radius: 9px;
|
|
||||||
background-color: ${theme.colorFillSecondary};
|
|
||||||
border: 3px solid transparent;
|
|
||||||
background-clip: content-box;
|
|
||||||
}
|
|
||||||
::-webkit-scrollbar-track {
|
|
||||||
background-color: ${theme.colorFillQuaternary};
|
|
||||||
border-left: 1px solid ${theme.colorFillTertiary};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Popover
|
|
||||||
styles={{
|
|
||||||
body: {
|
|
||||||
maxHeight: `${MAX_HEIGHT}px`,
|
|
||||||
overflow: showOverflow ? 'auto' : 'visible',
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
content={popoverContent}
|
|
||||||
trigger="click"
|
|
||||||
open={popoverVisible}
|
|
||||||
onOpenChange={visible => setPopoverVisible(visible)}
|
|
||||||
placement="bottom"
|
|
||||||
forceRender={forceRender}
|
|
||||||
fresh // This prop prevents caching and stale data for filter scoping.
|
|
||||||
>
|
|
||||||
<Tooltip title={dropdownTriggerTooltip}>
|
|
||||||
<Button
|
<Button
|
||||||
buttonStyle="secondary"
|
buttonStyle="secondary"
|
||||||
data-test="dropdown-container-btn"
|
data-test="dropdown-container-btn"
|
||||||
icon={dropdownTriggerIcon}
|
icon={dropdownTriggerIcon}
|
||||||
|
disabled={!popoverContent}
|
||||||
|
tooltip={dropdownTriggerTooltip}
|
||||||
css={css`
|
css={css`
|
||||||
padding-left: ${theme.paddingXS}px;
|
padding-left: ${theme.paddingXS}px;
|
||||||
padding-right: ${theme.paddingXXS}px;
|
padding-right: ${theme.paddingXXS}px;
|
||||||
@@ -388,8 +333,75 @@ export const DropdownContainer = forwardRef(
|
|||||||
`}
|
`}
|
||||||
/>
|
/>
|
||||||
</Button>
|
</Button>
|
||||||
</Tooltip>
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
ref={ref}
|
||||||
|
css={css`
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
css={css`
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: ${theme.sizeUnit * 4}px;
|
||||||
|
margin-right: ${theme.sizeUnit * 4}px;
|
||||||
|
min-width: 0px;
|
||||||
|
`}
|
||||||
|
data-test="container"
|
||||||
|
style={style}
|
||||||
|
>
|
||||||
|
{notOverflowedItems.map(item => item.element)}
|
||||||
|
</div>
|
||||||
|
{shouldShowButton && (
|
||||||
|
<>
|
||||||
|
<Global
|
||||||
|
styles={css`
|
||||||
|
.ant-popover-inner {
|
||||||
|
// Some OS versions only show the scroll when hovering.
|
||||||
|
// These settings will make the scroll always visible.
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
width: 14px;
|
||||||
|
}
|
||||||
|
::-webkit-scrollbar-thumb {
|
||||||
|
border-radius: 9px;
|
||||||
|
background-color: ${theme.colorFillSecondary};
|
||||||
|
border: 3px solid transparent;
|
||||||
|
background-clip: content-box;
|
||||||
|
}
|
||||||
|
::-webkit-scrollbar-track {
|
||||||
|
background-color: ${theme.colorFillQuaternary};
|
||||||
|
border-left: 1px solid ${theme.colorFillTertiary};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{popoverContent ? (
|
||||||
|
<Popover
|
||||||
|
styles={{
|
||||||
|
body: {
|
||||||
|
maxHeight: `${MAX_HEIGHT}px`,
|
||||||
|
overflow: showOverflow ? 'auto' : 'visible',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
content={popoverContent}
|
||||||
|
trigger="click"
|
||||||
|
open={popoverVisible}
|
||||||
|
onOpenChange={visible => setPopoverVisible(visible)}
|
||||||
|
placement="bottom"
|
||||||
|
forceRender={forceRender}
|
||||||
|
fresh // This prop prevents caching and stale data for filter scoping.
|
||||||
|
>
|
||||||
|
{triggerButton}
|
||||||
</Popover>
|
</Popover>
|
||||||
|
) : (
|
||||||
|
triggerButton
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user