feat: dashboard page xlsx export (#24005)

Co-authored-by: Vitali Logvin <vitali.logvin@noogadev.com>
This commit is contained in:
Vitali Logvin 2023-05-19 13:18:16 +03:00 committed by GitHub
parent d583ca9ef5
commit d0687d04eb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 67 additions and 6 deletions

View File

@ -135,6 +135,7 @@ const SliceHeader: FC<SliceHeaderProps> = ({
logExploreChart = () => ({}),
logEvent,
exportCSV = () => ({}),
exportXLSX = () => ({}),
editMode = false,
annotationQuery = {},
annotationError = {},
@ -264,6 +265,7 @@ const SliceHeader: FC<SliceHeaderProps> = ({
logEvent={logEvent}
exportCSV={exportCSV}
exportFullCSV={exportFullCSV}
exportXLSX={exportXLSX}
supersetCanExplore={supersetCanExplore}
supersetCanShare={supersetCanShare}
supersetCanCSV={supersetCanCSV}

View File

@ -44,6 +44,7 @@ const createProps = (viz_type = 'sunburst') =>
exploreChart: jest.fn(),
exportCSV: jest.fn(),
exportFullCSV: jest.fn(),
exportXLSX: jest.fn(),
forceRefresh: jest.fn(),
handleToggleFullSize: jest.fn(),
toggleExpandSlice: jest.fn(),
@ -126,6 +127,8 @@ test('Should render default props', () => {
// @ts-ignore
delete props.exportCSV;
// @ts-ignore
delete props.exportXLSX;
// @ts-ignore
delete props.cachedDttm;
// @ts-ignore
delete props.updatedDttm;
@ -170,6 +173,16 @@ test('Should "export to CSV"', async () => {
expect(props.exportCSV).toBeCalledWith(371);
});
test('Should "export to Excel"', async () => {
const props = createProps();
renderWrapper(props);
expect(props.exportXLSX).toBeCalledTimes(0);
userEvent.hover(screen.getByText('Download'));
userEvent.click(await screen.findByText('Export to Excel'));
expect(props.exportXLSX).toBeCalledTimes(1);
expect(props.exportXLSX).toBeCalledWith(371);
});
test('Should not show "Download" if slice is filter box', () => {
const props = createProps('filter_box');
renderWrapper(props);

View File

@ -64,6 +64,7 @@ const MENU_KEYS = {
EXPLORE_CHART: 'explore_chart',
EXPORT_CSV: 'export_csv',
EXPORT_FULL_CSV: 'export_full_csv',
EXPORT_XLSX: 'export_xlsx',
FORCE_REFRESH: 'force_refresh',
FULLSCREEN: 'fullscreen',
TOGGLE_CHART_DESCRIPTION: 'toggle_chart_description',
@ -144,6 +145,7 @@ export interface SliceHeaderControlsProps {
toggleExpandSlice?: (sliceId: number) => void;
exportCSV?: (sliceId: number) => void;
exportFullCSV?: (sliceId: number) => void;
exportXLSX?: (sliceId: number) => void;
handleToggleFullSize: () => void;
addDangerToast: (message: string) => void;
@ -294,6 +296,10 @@ const SliceHeaderControls = (props: SliceHeaderControlsPropsWithRouter) => {
// eslint-disable-next-line no-unused-expressions
props.exportFullCSV?.(props.slice.slice_id);
break;
case MENU_KEYS.EXPORT_XLSX:
// eslint-disable-next-line no-unused-expressions
props.exportXLSX?.(props.slice.slice_id);
break;
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
@ -493,6 +499,12 @@ const SliceHeaderControls = (props: SliceHeaderControlsPropsWithRouter) => {
</Menu.Item>
)}
<Menu.Item
key={MENU_KEYS.EXPORT_XLSX}
icon={<Icons.FileOutlined css={dropdownIconsStyles} />}
>
{t('Export to Excel')}
</Menu.Item>
<Menu.Item
key={MENU_KEYS.DOWNLOAD_AS_IMAGE}
icon={<Icons.FileImageOutlined css={dropdownIconsStyles} />}

View File

@ -29,6 +29,7 @@ import {
LOG_ACTIONS_CHANGE_DASHBOARD_FILTER,
LOG_ACTIONS_EXPLORE_DASHBOARD_CHART,
LOG_ACTIONS_EXPORT_CSV_DASHBOARD_CHART,
LOG_ACTIONS_EXPORT_XLSX_DASHBOARD_CHART,
LOG_ACTIONS_FORCE_REFRESH_CHART,
} from 'src/logger/LogUtils';
import { areObjectsEqual } from 'src/reduxUtils';
@ -139,6 +140,7 @@ class Chart extends React.Component {
this.handleFilterMenuClose = this.handleFilterMenuClose.bind(this);
this.exportCSV = this.exportCSV.bind(this);
this.exportFullCSV = this.exportFullCSV.bind(this);
this.exportXLSX = this.exportXLSX.bind(this);
this.forceRefresh = this.forceRefresh.bind(this);
this.resize = this.resize.bind(this);
this.setDescriptionRef = this.setDescriptionRef.bind(this);
@ -324,8 +326,24 @@ class Chart extends React.Component {
}
};
exportFullCSV() {
this.exportCSV(true);
}
exportCSV(isFullCSV = false) {
this.props.logEvent(LOG_ACTIONS_EXPORT_CSV_DASHBOARD_CHART, {
this.exportTable('csv', isFullCSV);
}
exportXLSX() {
this.exportTable('xlsx', false);
}
exportTable(format, isFullCSV) {
const logAction =
format === 'csv'
? LOG_ACTIONS_EXPORT_CSV_DASHBOARD_CHART
: LOG_ACTIONS_EXPORT_XLSX_DASHBOARD_CHART;
this.props.logEvent(logAction, {
slice_id: this.props.slice.slice_id,
is_cached: this.props.isCached,
});
@ -334,16 +352,12 @@ class Chart extends React.Component {
? { ...this.props.formData, row_limit: this.props.maxRows }
: this.props.formData,
resultType: 'full',
resultFormat: 'csv',
resultFormat: format,
force: true,
ownState: this.props.ownState,
});
}
exportFullCSV() {
this.exportCSV(true);
}
forceRefresh() {
this.props.logEvent(LOG_ACTIONS_FORCE_REFRESH_CHART, {
slice_id: this.props.slice.slice_id,
@ -437,6 +451,7 @@ class Chart extends React.Component {
logEvent={logEvent}
onExploreChart={this.onExploreChart}
exportCSV={this.exportCSV}
exportXLSX={this.exportXLSX}
exportFullCSV={this.exportFullCSV}
updateSliceName={updateSliceName}
sliceName={sliceName}

View File

@ -62,6 +62,7 @@ describe('Chart', () => {
addDangerToast() {},
exportCSV() {},
exportFullCSV() {},
exportXLSX() {},
componentId: 'test',
dashboardId: 111,
editMode: false,
@ -145,4 +146,20 @@ describe('Chart', () => {
expect(stubbedExportCSV.lastCall.args[0].formData.row_limit).toEqual(666);
exploreUtils.exportChart.restore();
});
it('should call exportChart when exportXLSX is clicked', () => {
const stubbedExportXLSX = sinon
.stub(exploreUtils, 'exportChart')
.returns(() => {});
const wrapper = setup();
wrapper.instance().exportXLSX(props.slice.sliceId);
expect(stubbedExportXLSX.calledOnce).toBe(true);
expect(stubbedExportXLSX.lastCall.args[0]).toEqual(
expect.objectContaining({
formData: expect.anything(),
resultType: 'full',
resultFormat: 'xlsx',
}),
);
exploreUtils.exportChart.restore();
});
});

View File

@ -34,6 +34,8 @@ export const LOG_ACTIONS_PERIODIC_RENDER_DASHBOARD =
export const LOG_ACTIONS_EXPLORE_DASHBOARD_CHART = 'explore_dashboard_chart';
export const LOG_ACTIONS_EXPORT_CSV_DASHBOARD_CHART =
'export_csv_dashboard_chart';
export const LOG_ACTIONS_EXPORT_XLSX_DASHBOARD_CHART =
'export_csv_dashboard_chart';
export const LOG_ACTIONS_CHANGE_DASHBOARD_FILTER = 'change_dashboard_filter';
export const LOG_ACTIONS_DATASET_CREATION_EMPTY_CANCELLATION =
'dataset_creation_empty_cancellation';