feat(explore): Implement chart empty states (#18678)
* feat(explore): Implement chart empty states * Fix test * Remove unused import * Fix tests
This commit is contained in:
parent
c1205b5279
commit
167e18e806
|
|
@ -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',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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]')
|
||||
|
|
|
|||
|
|
@ -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>;
|
||||
|
|
@ -148,6 +153,7 @@ export default class SuperChart extends React.PureComponent<Props, {}> {
|
|||
Wrapper,
|
||||
queriesData,
|
||||
enableNoResults,
|
||||
noResults,
|
||||
...rest
|
||||
} = this.props as PropsWithDefault;
|
||||
|
||||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
@ -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`
|
||||
|
|
@ -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"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
@ -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"
|
||||
/>
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
@ -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();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue