From 5ebc09b33923eb16bcaf4f4c6663e768fa2c970f Mon Sep 17 00:00:00 2001 From: Kamil Gabryjelski Date: Mon, 30 Nov 2020 18:16:38 +0100 Subject: [PATCH] fix: Download as image not working on Dashboard view (#11778) * Fix download as image not working on Dashboard view * Fix menu not closing before making a screenshot * Move hardcoded selectors to variables * Fix linting issue * Add comments * Close menu before taking a screenshot on Explore view * Use style.visibility instead of timeout to hide menu for screenshot * Change const name to uppercase * Move variable declarations to case --- .../src/common/components/index.tsx | 1 + .../components/HeaderActionsDropdown.jsx | 26 ++++++++++++++++--- .../components/SliceHeaderControls.jsx | 20 +++++++++++--- .../explore/components/DisplayQueryButton.jsx | 4 +++ 4 files changed, 45 insertions(+), 6 deletions(-) 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 && [