diff --git a/superset-frontend/src/common/components/index.tsx b/superset-frontend/src/common/components/index.tsx index a9bad8e2f4..cb11a6f1cf 100644 --- a/superset-frontend/src/common/components/index.tsx +++ b/superset-frontend/src/common/components/index.tsx @@ -61,6 +61,7 @@ export const MenuItem = styled(AntdMenu.Item)` display: inline-block; width: 100%; } + transition-duration: 0s; } `; diff --git a/superset-frontend/src/dashboard/components/HeaderActionsDropdown.jsx b/superset-frontend/src/dashboard/components/HeaderActionsDropdown.jsx index ac592afce9..b18056d1d7 100644 --- a/superset-frontend/src/dashboard/components/HeaderActionsDropdown.jsx +++ b/superset-frontend/src/dashboard/components/HeaderActionsDropdown.jsx @@ -87,6 +87,8 @@ const DropdownButton = styled.div` margin-left: ${({ theme }) => theme.gridUnit * 2.5}px; `; +const SCREENSHOT_NODE_SELECTOR = '.dashboard'; + class HeaderActionsDropdown extends React.PureComponent { static discardChanges() { window.location.reload(); @@ -144,9 +146,21 @@ class HeaderActionsDropdown extends React.PureComponent { case MENU_KEYS.EDIT_PROPERTIES: this.props.showPropertiesModal(); break; - case MENU_KEYS.DOWNLOAD_AS_IMAGE: - downloadAsImage('.dashboard', this.props.dashboardTitle)(domEvent); + case MENU_KEYS.DOWNLOAD_AS_IMAGE: { + // menu closes with a delay, we need to hide it manually, + // so that we don't capture it on the screenshot + const menu = document.querySelector( + '.ant-dropdown:not(.ant-dropdown-hidden)', + ); + menu.style.visibility = 'hidden'; + downloadAsImage( + SCREENSHOT_NODE_SELECTOR, + this.props.dashboardTitle, + )(domEvent).then(() => { + menu.style.visibility = 'visible'; + }); break; + } case MENU_KEYS.TOGGLE_FULLSCREEN: { const hasStandalone = window.location.search.includes( 'standalone=true', @@ -294,7 +308,13 @@ class HeaderActionsDropdown extends React.PureComponent { ); return ( - + + triggerNode.closest(SCREENSHOT_NODE_SELECTOR) + } + > diff --git a/superset-frontend/src/dashboard/components/SliceHeaderControls.jsx b/superset-frontend/src/dashboard/components/SliceHeaderControls.jsx index ec94ab3ebd..673f2baf6e 100644 --- a/superset-frontend/src/dashboard/components/SliceHeaderControls.jsx +++ b/superset-frontend/src/dashboard/components/SliceHeaderControls.jsx @@ -87,6 +87,8 @@ const RefreshTooltip = styled.div` color: ${({ theme }) => theme.colors.grayscale.base}; `; +const SCREENSHOT_NODE_SELECTOR = '.dashboard-component-chart-holder'; + const VerticalDotsTrigger = () => ( @@ -139,12 +141,21 @@ class SliceHeaderControls extends React.PureComponent { case MENU_KEYS.RESIZE_LABEL: this.props.handleToggleFullSize(); break; - case MENU_KEYS.DOWNLOAD_AS_IMAGE: + case MENU_KEYS.DOWNLOAD_AS_IMAGE: { + // menu closes with a delay, we need to hide it manually, + // so that we don't capture it on the screenshot + const menu = document.querySelector( + '.ant-dropdown:not(.ant-dropdown-hidden)', + ); + menu.style.visibility = 'hidden'; downloadAsImage( - '.dashboard-component-chart-holder', + SCREENSHOT_NODE_SELECTOR, this.props.slice.slice_name, - )(domEvent); + )(domEvent).then(() => { + menu.style.visibility = 'visible'; + }); break; + } default: break; } @@ -232,6 +243,9 @@ class SliceHeaderControls extends React.PureComponent { dropdownAlign={{ offset: [-40, 4], }} + getPopupContainer={triggerNode => + triggerNode.closest(SCREENSHOT_NODE_SELECTOR) + } > diff --git a/superset-frontend/src/explore/components/DisplayQueryButton.jsx b/superset-frontend/src/explore/components/DisplayQueryButton.jsx index 285d8ac4e8..ab19c5fb49 100644 --- a/superset-frontend/src/explore/components/DisplayQueryButton.jsx +++ b/superset-frontend/src/explore/components/DisplayQueryButton.jsx @@ -90,6 +90,7 @@ export const DisplayQueryButton = props => { datasource && datasource.split('__')[1] === 'table', ); const [isPropertiesModalOpen, setIsPropertiesModalOpen] = useState(false); + const [menuVisible, setMenuVisible] = useState(false); const tableData = useMemo(() => { if (!data?.length) { @@ -150,6 +151,7 @@ export const DisplayQueryButton = props => { const handleMenuClick = ({ key, domEvent }) => { const { chartHeight, slice, onOpenInEditor, latestQueryFormData } = props; + setMenuVisible(false); switch (key) { case MENU_KEYS.EDIT_PROPERTIES: openPropertiesModal(); @@ -273,6 +275,7 @@ export const DisplayQueryButton = props => { const { slice } = props; return ( { bsSize="sm" pullRight id="query" + onToggle={setMenuVisible} > {slice && [