mirror of
https://github.com/apache/superset.git
synced 2026-04-19 08:04:53 +00:00
feat: add download as image button to explore (#10297)
This commit is contained in:
@@ -20,6 +20,7 @@ import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import ModalTrigger from 'src/components/ModalTrigger';
|
||||
import { DisplayQueryButton } from 'src/explore/components/DisplayQueryButton';
|
||||
import { MenuItem } from 'react-bootstrap';
|
||||
|
||||
describe('DisplayQueryButton', () => {
|
||||
const defaultProps = {
|
||||
@@ -43,5 +44,6 @@ describe('DisplayQueryButton', () => {
|
||||
it('renders a dropdown', () => {
|
||||
const wrapper = mount(<DisplayQueryButton {...defaultProps} />);
|
||||
expect(wrapper.find(ModalTrigger)).toHaveLength(3);
|
||||
expect(wrapper.find(MenuItem)).toHaveLength(5);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -28,7 +28,7 @@ import SaveModal from './SaveModal';
|
||||
import injectCustomCss from '../util/injectCustomCss';
|
||||
import { SAVE_TYPE_NEWDASHBOARD } from '../util/constants';
|
||||
import URLShortLinkModal from '../../components/URLShortLinkModal';
|
||||
import downloadAsImage from '../util/downloadAsImage';
|
||||
import downloadAsImage from '../../utils/downloadAsImage';
|
||||
import getDashboardUrl from '../util/getDashboardUrl';
|
||||
import { getActiveFilters } from '../util/activeDashboardFilters';
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ import moment from 'moment';
|
||||
import { Dropdown, MenuItem } from 'react-bootstrap';
|
||||
import { t } from '@superset-ui/translation';
|
||||
import URLShortLinkModal from '../../components/URLShortLinkModal';
|
||||
import downloadAsImage from '../util/downloadAsImage';
|
||||
import downloadAsImage from '../../utils/downloadAsImage';
|
||||
import getDashboardUrl from '../util/getDashboardUrl';
|
||||
import { getActiveFilters } from '../util/activeDashboardFilters';
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ import { t } from '@superset-ui/translation';
|
||||
import getClientErrorObject from '../../utils/getClientErrorObject';
|
||||
import CopyToClipboard from './../../components/CopyToClipboard';
|
||||
import { getChartDataRequest } from '../../chart/chartAction';
|
||||
|
||||
import downloadAsImage from '../../utils/downloadAsImage';
|
||||
import Loading from '../../components/Loading';
|
||||
import ModalTrigger from './../../components/ModalTrigger';
|
||||
import Button from '../../components/Button';
|
||||
@@ -63,6 +63,7 @@ const propTypes = {
|
||||
animation: PropTypes.bool,
|
||||
queryResponse: PropTypes.object,
|
||||
chartStatus: PropTypes.string,
|
||||
chartHeight: PropTypes.string.isRequired,
|
||||
latestQueryFormData: PropTypes.object.isRequired,
|
||||
slice: PropTypes.object,
|
||||
};
|
||||
@@ -219,7 +220,7 @@ export class DisplayQueryButton extends React.PureComponent {
|
||||
return null;
|
||||
}
|
||||
render() {
|
||||
const { animation, slice } = this.props;
|
||||
const { animation, chartHeight, slice } = this.props;
|
||||
return (
|
||||
<DropdownButton
|
||||
noCaret
|
||||
@@ -279,6 +280,18 @@ export class DisplayQueryButton extends React.PureComponent {
|
||||
{t('Run in SQL Lab')}
|
||||
</MenuItem>
|
||||
)}
|
||||
<MenuItem
|
||||
onClick={downloadAsImage(
|
||||
'.chart-container',
|
||||
// eslint-disable-next-line camelcase
|
||||
slice?.slice_name ?? t('New chart'),
|
||||
{
|
||||
height: parseInt(chartHeight, 10),
|
||||
},
|
||||
)}
|
||||
>
|
||||
{t('Download as image')}
|
||||
</MenuItem>
|
||||
</DropdownButton>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ const propTypes = {
|
||||
canDownload: PropTypes.oneOfType([PropTypes.string, PropTypes.bool])
|
||||
.isRequired,
|
||||
chartStatus: PropTypes.string,
|
||||
chartHeight: PropTypes.string.isRequired,
|
||||
latestQueryFormData: PropTypes.object,
|
||||
queryResponse: PropTypes.object,
|
||||
slice: PropTypes.object,
|
||||
@@ -39,6 +40,7 @@ const propTypes = {
|
||||
export default function ExploreActionButtons({
|
||||
actions,
|
||||
canDownload,
|
||||
chartHeight,
|
||||
chartStatus,
|
||||
latestQueryFormData,
|
||||
queryResponse,
|
||||
@@ -95,6 +97,7 @@ export default function ExploreActionButtons({
|
||||
</a>
|
||||
)}
|
||||
<DisplayQueryButton
|
||||
chartHeight={chartHeight}
|
||||
queryResponse={queryResponse}
|
||||
latestQueryFormData={latestQueryFormData}
|
||||
chartStatus={chartStatus}
|
||||
|
||||
@@ -45,6 +45,7 @@ const propTypes = {
|
||||
addHistory: PropTypes.func,
|
||||
can_overwrite: PropTypes.bool.isRequired,
|
||||
can_download: PropTypes.bool.isRequired,
|
||||
chartHeight: PropTypes.string.isRequired,
|
||||
isStarred: PropTypes.bool.isRequired,
|
||||
slice: PropTypes.object,
|
||||
sliceName: PropTypes.string,
|
||||
@@ -169,6 +170,7 @@ export class ExploreChartHeader extends React.PureComponent {
|
||||
slice={this.props.slice}
|
||||
canDownload={this.props.can_download}
|
||||
chartStatus={chartStatus}
|
||||
chartHeight={this.props.chartHeight}
|
||||
latestQueryFormData={latestQueryFormData}
|
||||
queryResponse={queryResponse}
|
||||
/>
|
||||
|
||||
@@ -102,6 +102,7 @@ class ExploreChartPanel extends React.PureComponent {
|
||||
addHistory={this.props.addHistory}
|
||||
can_overwrite={this.props.can_overwrite}
|
||||
can_download={this.props.can_download}
|
||||
chartHeight={this.props.height}
|
||||
isStarred={this.props.isStarred}
|
||||
slice={this.props.slice}
|
||||
sliceName={this.props.sliceName}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* under the License.
|
||||
*/
|
||||
import { SyntheticEvent } from 'react';
|
||||
import domToImage from 'dom-to-image';
|
||||
import domToImage, { Options } from 'dom-to-image';
|
||||
import kebabCase from 'lodash/kebabCase';
|
||||
import { t } from '@superset-ui/translation';
|
||||
import { addWarningToast } from 'src/messageToasts/actions';
|
||||
@@ -52,7 +52,7 @@ const generateFileStem = (description: string, date = new Date()) => {
|
||||
export default function downloadAsImage(
|
||||
selector: string,
|
||||
description: string,
|
||||
backgroundColor = GRAY_BACKGROUND_COLOR,
|
||||
domToImageOptions: Options = {},
|
||||
) {
|
||||
return (event: SyntheticEvent) => {
|
||||
const elementToPrint = event.currentTarget.closest(selector);
|
||||
@@ -63,7 +63,11 @@ export default function downloadAsImage(
|
||||
);
|
||||
|
||||
return domToImage
|
||||
.toJpeg(elementToPrint, { quality: 0.95, bgcolor: backgroundColor })
|
||||
.toJpeg(elementToPrint, {
|
||||
quality: 0.95,
|
||||
bgcolor: GRAY_BACKGROUND_COLOR,
|
||||
...domToImageOptions,
|
||||
})
|
||||
.then(dataUrl => {
|
||||
const link = document.createElement('a');
|
||||
link.download = `${generateFileStem(description)}.jpg`;
|
||||
Reference in New Issue
Block a user