Skip to content
This repository has been archived by the owner on Nov 3, 2023. It is now read-only.

Commit

Permalink
feat: Drill by open in Explore (apache#23575)
Browse files Browse the repository at this point in the history
  • Loading branch information
kgabryje committed Apr 5, 2023
1 parent 9d2f43d commit 117360c
Show file tree
Hide file tree
Showing 6 changed files with 171 additions and 117 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,17 @@ import {
} from './Operator';
import { TimeGranularity } from '../../time-format';

interface BaseSimpleAdhocFilter {
expressionType: 'SIMPLE';
interface BaseAdhocFilter {
clause: 'WHERE' | 'HAVING';
subject: string;
timeGrain?: TimeGranularity;
isExtra?: boolean;
}

interface BaseSimpleAdhocFilter extends BaseAdhocFilter {
expressionType: 'SIMPLE';
subject: string;
}

export type UnaryAdhocFilter = BaseSimpleAdhocFilter & {
operator: UnaryOperator;
};
Expand All @@ -54,9 +57,8 @@ export type SimpleAdhocFilter =
| BinaryAdhocFilter
| SetAdhocFilter;

export interface FreeFormAdhocFilter {
export interface FreeFormAdhocFilter extends BaseAdhocFilter {
expressionType: 'SQL';
clause: 'WHERE' | 'HAVING';
sqlExpression: string;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,30 +40,10 @@ const fetchWithNoData = () => {
});
};

const setup = (overrides: Record<string, any> = {}) => {
const props = {
column: { column_name: 'state' },
formData: { ...chart.form_data, viz_type: 'pie' },
groupbyFieldName: 'groupby',
...overrides,
};
return render(
<DrillByChart
filters={[
{
col: 'gender',
op: '==',
val: 'boy',
formattedVal: 'boy',
},
]}
{...props}
/>,
{
useRedux: true,
},
);
};
const setup = (overrides: Record<string, any> = {}) =>
render(<DrillByChart formData={{ ...chart.form_data, ...overrides }} />, {
useRedux: true,
});

const waitForRender = (overrides: Record<string, any> = {}) =>
waitFor(() => setup(overrides));
Expand Down
42 changes: 5 additions & 37 deletions superset-frontend/src/components/Chart/DrillBy/DrillByChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,52 +17,20 @@
* under the License.
*/
import React, { useEffect, useState } from 'react';
import {
Behavior,
BinaryQueryObjectFilterClause,
Column,
css,
SuperChart,
} from '@superset-ui/core';
import { simpleFilterToAdhoc } from 'src/utils/simpleFilterToAdhoc';
import { BaseFormData, Behavior, css, SuperChart } from '@superset-ui/core';
import { getChartDataRequest } from 'src/components/Chart/chartAction';
import Loading from 'src/components/Loading';

interface DrillByChartProps {
column?: Column;
filters?: BinaryQueryObjectFilterClause[];
formData: { [key: string]: any; viz_type: string };
groupbyFieldName?: string;
formData: BaseFormData & { [key: string]: any };
}

export default function DrillByChart({
column,
filters,
formData,
groupbyFieldName = 'groupby',
}: DrillByChartProps) {
let updatedFormData = formData;
let groupbyField: any = [];
export default function DrillByChart({ formData }: DrillByChartProps) {
const [chartDataResult, setChartDataResult] = useState();

if (column) {
groupbyField = Array.isArray(formData[groupbyFieldName])
? [column.column_name]
: column.column_name;
}

if (filters) {
const adhocFilters = filters.map(filter => simpleFilterToAdhoc(filter));
updatedFormData = {
...formData,
adhoc_filters: [...formData.adhoc_filters, ...adhocFilters],
[groupbyFieldName]: groupbyField,
};
}

useEffect(() => {
getChartDataRequest({
formData: updatedFormData,
formData,
}).then(({ json }) => {
setChartDataResult(json.result);
});
Expand All @@ -81,7 +49,7 @@ export default function DrillByChart({
behaviors={[Behavior.INTERACTIVE_CHART]}
chartType={formData.viz_type}
enableNoResults
formData={updatedFormData}
formData={formData}
queriesData={chartDataResult}
height="100%"
width="100%"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,30 +18,35 @@
*/

import React, { useState } from 'react';
import fetchMock from 'fetch-mock';
import { omit, isUndefined, omitBy } from 'lodash';
import userEvent from '@testing-library/user-event';
import { waitFor } from '@testing-library/react';
import { render, screen } from 'spec/helpers/testing-library';
import chartQueries, { sliceId } from 'spec/fixtures/mockChartQueries';
import mockState from 'spec/fixtures/mockState';
import fetchMock from 'fetch-mock';
import { DashboardPageIdContext } from 'src/dashboard/containers/DashboardPage';
import DrillByModal from './DrillByModal';

const CHART_DATA_ENDPOINT =
'glob:*api/v1/chart/data?form_data=%7B%22slice_id%22%3A18%7D';

fetchMock.post(CHART_DATA_ENDPOINT, { body: {} }, {});
const CHART_DATA_ENDPOINT = 'glob:*/api/v1/chart/data*';
const FORM_DATA_KEY_ENDPOINT = 'glob:*/api/v1/explore/form_data';

const { form_data: formData } = chartQueries[sliceId];
const { slice_name: chartName } = formData;
const drillByModalState = {
...mockState,
dashboardLayout: {
CHART_ID: {
id: 'CHART_ID',
meta: {
chartId: formData.slice_id,
sliceName: chartName,
past: [],
present: {
CHART_ID: {
id: 'CHART_ID',
meta: {
chartId: formData.slice_id,
sliceName: chartName,
},
},
},
future: [],
},
};
const dataset = {
Expand All @@ -56,12 +61,13 @@ const dataset = {
},
],
};
const renderModal = async (state?: object) => {

const renderModal = async () => {
const DrillByModalWrapper = () => {
const [showModal, setShowModal] = useState(false);

return (
<>
<DashboardPageIdContext.Provider value="1">
<button type="button" onClick={() => setShowModal(true)}>
Show modal
</button>
Expand All @@ -71,23 +77,29 @@ const renderModal = async (state?: object) => {
onHideModal={() => setShowModal(false)}
dataset={dataset}
/>
</>
</DashboardPageIdContext.Provider>
);
};
render(<DrillByModalWrapper />, {
useDnd: true,
useRedux: true,
useRouter: true,
initialState: state,
initialState: drillByModalState,
});

userEvent.click(screen.getByRole('button', { name: 'Show modal' }));
await screen.findByRole('dialog', { name: `Drill by: ${chartName}` });
};

beforeEach(() => {
fetchMock
.post(CHART_DATA_ENDPOINT, { body: {} }, {})
.post(FORM_DATA_KEY_ENDPOINT, { key: '123' });
});
afterEach(fetchMock.restore);

test('should render the title', async () => {
await renderModal(drillByModalState);
await renderModal();
expect(screen.getByText(`Drill by: ${chartName}`)).toBeInTheDocument();
});

Expand All @@ -105,3 +117,30 @@ test('should close the modal', async () => {
userEvent.click(screen.getAllByRole('button', { name: 'Close' })[1]);
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
});

test('should generate Explore url', async () => {
await renderModal();
await waitFor(() => fetchMock.called(FORM_DATA_KEY_ENDPOINT));
const expectedRequestPayload = {
form_data: {
...omitBy(
omit(formData, ['slice_id', 'slice_name', 'dashboards']),
isUndefined,
),
slice_id: 0,
},
datasource_id: Number(formData.datasource.split('__')[0]),
datasource_type: formData.datasource.split('__')[1],
};

const parsedRequestPayload = JSON.parse(
fetchMock.lastCall()?.[1]?.body as string,
);
parsedRequestPayload.form_data = JSON.parse(parsedRequestPayload.form_data);

expect(parsedRequestPayload).toEqual(expectedRequestPayload);

expect(
await screen.findByRole('link', { name: 'Edit chart' }),
).toHaveAttribute('href', '/explore/?form_data_key=123&dashboard_page_id=1');
});
Loading

0 comments on commit 117360c

Please sign in to comment.