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
This commit is contained in:
Kamil Gabryjelski 2020-11-30 18:16:38 +01:00 committed by GitHub
parent 9dd33d5566
commit 5ebc09b339
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 45 additions and 6 deletions

View File

@ -61,6 +61,7 @@ export const MenuItem = styled(AntdMenu.Item)`
display: inline-block; display: inline-block;
width: 100%; width: 100%;
} }
transition-duration: 0s;
} }
`; `;

View File

@ -87,6 +87,8 @@ const DropdownButton = styled.div`
margin-left: ${({ theme }) => theme.gridUnit * 2.5}px; margin-left: ${({ theme }) => theme.gridUnit * 2.5}px;
`; `;
const SCREENSHOT_NODE_SELECTOR = '.dashboard';
class HeaderActionsDropdown extends React.PureComponent { class HeaderActionsDropdown extends React.PureComponent {
static discardChanges() { static discardChanges() {
window.location.reload(); window.location.reload();
@ -144,9 +146,21 @@ class HeaderActionsDropdown extends React.PureComponent {
case MENU_KEYS.EDIT_PROPERTIES: case MENU_KEYS.EDIT_PROPERTIES:
this.props.showPropertiesModal(); this.props.showPropertiesModal();
break; break;
case MENU_KEYS.DOWNLOAD_AS_IMAGE: case MENU_KEYS.DOWNLOAD_AS_IMAGE: {
downloadAsImage('.dashboard', this.props.dashboardTitle)(domEvent); // 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; break;
}
case MENU_KEYS.TOGGLE_FULLSCREEN: { case MENU_KEYS.TOGGLE_FULLSCREEN: {
const hasStandalone = window.location.search.includes( const hasStandalone = window.location.search.includes(
'standalone=true', 'standalone=true',
@ -294,7 +308,13 @@ class HeaderActionsDropdown extends React.PureComponent {
</Menu> </Menu>
); );
return ( return (
<NoAnimationDropdown overlay={menu} trigger={['click']}> <NoAnimationDropdown
overlay={menu}
trigger={['click']}
getPopupContainer={triggerNode =>
triggerNode.closest(SCREENSHOT_NODE_SELECTOR)
}
>
<DropdownButton id="save-dash-split-button" role="button"> <DropdownButton id="save-dash-split-button" role="button">
<Icon name="more-horiz" /> <Icon name="more-horiz" />
</DropdownButton> </DropdownButton>

View File

@ -87,6 +87,8 @@ const RefreshTooltip = styled.div`
color: ${({ theme }) => theme.colors.grayscale.base}; color: ${({ theme }) => theme.colors.grayscale.base};
`; `;
const SCREENSHOT_NODE_SELECTOR = '.dashboard-component-chart-holder';
const VerticalDotsTrigger = () => ( const VerticalDotsTrigger = () => (
<VerticalDotsContainer> <VerticalDotsContainer>
<span className="dot" /> <span className="dot" />
@ -139,12 +141,21 @@ class SliceHeaderControls extends React.PureComponent {
case MENU_KEYS.RESIZE_LABEL: case MENU_KEYS.RESIZE_LABEL:
this.props.handleToggleFullSize(); this.props.handleToggleFullSize();
break; 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( downloadAsImage(
'.dashboard-component-chart-holder', SCREENSHOT_NODE_SELECTOR,
this.props.slice.slice_name, this.props.slice.slice_name,
)(domEvent); )(domEvent).then(() => {
menu.style.visibility = 'visible';
});
break; break;
}
default: default:
break; break;
} }
@ -232,6 +243,9 @@ class SliceHeaderControls extends React.PureComponent {
dropdownAlign={{ dropdownAlign={{
offset: [-40, 4], offset: [-40, 4],
}} }}
getPopupContainer={triggerNode =>
triggerNode.closest(SCREENSHOT_NODE_SELECTOR)
}
> >
<a id={`slice_${slice.slice_id}-controls`} role="button"> <a id={`slice_${slice.slice_id}-controls`} role="button">
<VerticalDotsTrigger /> <VerticalDotsTrigger />

View File

@ -90,6 +90,7 @@ export const DisplayQueryButton = props => {
datasource && datasource.split('__')[1] === 'table', datasource && datasource.split('__')[1] === 'table',
); );
const [isPropertiesModalOpen, setIsPropertiesModalOpen] = useState(false); const [isPropertiesModalOpen, setIsPropertiesModalOpen] = useState(false);
const [menuVisible, setMenuVisible] = useState(false);
const tableData = useMemo(() => { const tableData = useMemo(() => {
if (!data?.length) { if (!data?.length) {
@ -150,6 +151,7 @@ export const DisplayQueryButton = props => {
const handleMenuClick = ({ key, domEvent }) => { const handleMenuClick = ({ key, domEvent }) => {
const { chartHeight, slice, onOpenInEditor, latestQueryFormData } = props; const { chartHeight, slice, onOpenInEditor, latestQueryFormData } = props;
setMenuVisible(false);
switch (key) { switch (key) {
case MENU_KEYS.EDIT_PROPERTIES: case MENU_KEYS.EDIT_PROPERTIES:
openPropertiesModal(); openPropertiesModal();
@ -273,6 +275,7 @@ export const DisplayQueryButton = props => {
const { slice } = props; const { slice } = props;
return ( return (
<DropdownButton <DropdownButton
open={menuVisible}
noCaret noCaret
data-test="query-dropdown" data-test="query-dropdown"
title={ title={
@ -284,6 +287,7 @@ export const DisplayQueryButton = props => {
bsSize="sm" bsSize="sm"
pullRight pullRight
id="query" id="query"
onToggle={setMenuVisible}
> >
<Menu onClick={handleMenuClick} selectable={false}> <Menu onClick={handleMenuClick} selectable={false}>
{slice && [ {slice && [