Skip to content

Commit

Permalink
feat(explore): Implement chart empty states (#18678)
Browse files Browse the repository at this point in the history
* feat(explore): Implement chart empty states

* Fix test

* Remove unused import

* Fix tests
  • Loading branch information
kgabryje authored Feb 14, 2022
1 parent c1205b5 commit 167e18e
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ describe('No Results', () => {

cy.visitChartByParams(JSON.stringify(formData));
cy.wait('@getJson').its('response.statusCode').should('eq', 200);
cy.get('div.chart-container').contains('No Results');
cy.get('div.chart-container').contains(
'No results were returned for this query',
);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,17 @@ describe('Visualization > Line', () => {
it('should show validator error when no metric', () => {
const formData = { ...LINE_CHART_DEFAULTS, metrics: [] };
cy.visitChartByParams(JSON.stringify(formData));
cy.get('.ant-alert-warning').contains(`Metrics: cannot be empty`);
cy.get('.panel-body').contains(
`Add required control values to preview chart`,
);
});

it('should not show validator error when metric added', () => {
const formData = { ...LINE_CHART_DEFAULTS, metrics: [] };
cy.visitChartByParams(JSON.stringify(formData));
cy.get('.ant-alert-warning').contains(`Metrics: cannot be empty`);
cy.get('.panel-body').contains(
`Add required control values to preview chart`,
);
cy.get('.text-danger').contains('Metrics');

cy.get('[data-test=metrics]')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ export type Props = Omit<SuperChartCoreProps, 'chartProps'> &
* because it will clash with auto-sizing.
*/
Wrapper?: React.ComponentType<WrapperProps>;
/**
* Component to display when query returns no results.
* If not defined, NoResultsComponent is used
*/
noResults?: ReactNode;
};

type PropsWithDefault = Props & Readonly<typeof defaultProps>;
Expand Down Expand Up @@ -148,6 +153,7 @@ export default class SuperChart extends React.PureComponent<Props, {}> {
Wrapper,
queriesData,
enableNoResults,
noResults,
...rest
} = this.props as PropsWithDefault;

Expand All @@ -167,7 +173,7 @@ export default class SuperChart extends React.PureComponent<Props, {}> {
({ data }) => !data || (Array.isArray(data) && data.length === 0),
));
if (noResultQueries) {
chart = (
chart = noResults || (
<NoResultsComponent
id={id}
className={className}
Expand Down
27 changes: 20 additions & 7 deletions superset-frontend/src/chart/Chart.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,17 @@
*/
import PropTypes from 'prop-types';
import React from 'react';
import Alert from 'src/components/Alert';
import { styled, logging, t } from '@superset-ui/core';

import { isFeatureEnabled, FeatureFlag } from 'src/featureFlags';
import { PLACEHOLDER_DATASOURCE } from 'src/dashboard/constants';
import Button from 'src/components/Button';
import Loading from 'src/components/Loading';
import ErrorBoundary from '../components/ErrorBoundary';
import { EmptyStateBig } from 'src/components/EmptyState';
import ErrorBoundary from 'src/components/ErrorBoundary';
import { Logger, LOG_ACTIONS_RENDER_CHART } from 'src/logger/LogUtils';
import ChartRenderer from './ChartRenderer';
import { ChartErrorMessage } from './ChartErrorMessage';
import { Logger, LOG_ACTIONS_RENDER_CHART } from '../logger/LogUtils';

const propTypes = {
annotationData: PropTypes.object,
Expand Down Expand Up @@ -96,6 +96,10 @@ const Styles = styled.div`
opacity: 0.75;
font-size: ${({ theme }) => theme.typography.sizes.s}px;
}
.slice_container {
height: ${p => p.height}px;
}
`;

const RefreshOverlayWrapper = styled.div`
Expand Down Expand Up @@ -248,11 +252,20 @@ class Chart extends React.PureComponent {
}

if (errorMessage) {
const description = isFeatureEnabled(
FeatureFlag.ENABLE_EXPLORE_DRAG_AND_DROP,
)
? t(
'Drag and drop values into highlighted field(s) on the left control panel and run query',
)
: t(
'Select values in highlighted field(s) on the left control panel and run query',
);
return (
<Alert
data-test="alert-warning"
message={errorMessage}
type="warning"
<EmptyStateBig
title={t('Add required control values to preview chart')}
description={description}
image="chart.svg"
/>
);
}
Expand Down
12 changes: 11 additions & 1 deletion superset-frontend/src/chart/ChartRenderer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@
import { snakeCase, isEqual } from 'lodash';
import PropTypes from 'prop-types';
import React from 'react';
import { SuperChart, logging, Behavior } from '@superset-ui/core';
import { SuperChart, logging, Behavior, t } from '@superset-ui/core';
import { Logger, LOG_ACTIONS_RENDER_CHART } from 'src/logger/LogUtils';
import { EmptyStateBig } from 'src/components/EmptyState';

const propTypes = {
annotationData: PropTypes.object,
Expand Down Expand Up @@ -231,6 +232,15 @@ class ChartRenderer extends React.Component {
queriesData={queriesResponse}
onRenderSuccess={this.handleRenderSuccess}
onRenderFailure={this.handleRenderFailure}
noResults={
<EmptyStateBig
title={t('No results were returned for this query')}
description={t(
'Make sure that the controls are configured properly and the datasource contains data for the selected time range',
)}
image="chart.svg"
/>
}
/>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
*/

import React from 'react';
import { waitFor } from '@testing-library/react';
import { sliceId as chartId } from 'spec/fixtures/mockChartQueries';
import { nativeFiltersInfo } from 'src/dashboard/fixtures/mockNativeFilters';
import newComponentFactory from 'src/dashboard/util/newComponentFactory';
Expand Down Expand Up @@ -80,14 +79,17 @@ describe('ChartHolder', () => {
</Provider>,
);

it('should render full size', async () => {
it('should render empty state', async () => {
renderWrapper();

const chart = (
screen.getByTestId('slice-container').firstChild as HTMLElement
).style;

await waitFor(() => expect(chart?.width).toBe('992px'));
expect(chart?.height).toBe('714px');
expect(
screen.getByText('No results were returned for this query'),
).toBeVisible();
expect(
screen.getByText(
'Make sure that the controls are configured properly and the datasource contains data for the selected time range',
),
).toBeVisible();
expect(screen.getByAltText('empty')).toBeVisible();
});
});

0 comments on commit 167e18e

Please sign in to comment.