diff --git a/superset-frontend/cypress-base/cypress/integration/explore/chart.test.js b/superset-frontend/cypress-base/cypress/integration/explore/chart.test.js index acb83264f..c9f4a1c9f 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/chart.test.js +++ b/superset-frontend/cypress-base/cypress/integration/explore/chart.test.js @@ -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', + ); }); }); diff --git a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/line.test.ts b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/line.test.ts index 63473a1b9..5dda1abb9 100644 --- a/superset-frontend/cypress-base/cypress/integration/explore/visualizations/line.test.ts +++ b/superset-frontend/cypress-base/cypress/integration/explore/visualizations/line.test.ts @@ -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]') diff --git a/superset-frontend/packages/superset-ui-core/src/chart/components/SuperChart.tsx b/superset-frontend/packages/superset-ui-core/src/chart/components/SuperChart.tsx index ac3f3ede3..a8e559244 100644 --- a/superset-frontend/packages/superset-ui-core/src/chart/components/SuperChart.tsx +++ b/superset-frontend/packages/superset-ui-core/src/chart/components/SuperChart.tsx @@ -77,6 +77,11 @@ export type Props = Omit & * because it will clash with auto-sizing. */ Wrapper?: React.ComponentType; + /** + * Component to display when query returns no results. + * If not defined, NoResultsComponent is used + */ + noResults?: ReactNode; }; type PropsWithDefault = Props & Readonly; @@ -148,6 +153,7 @@ export default class SuperChart extends React.PureComponent { Wrapper, queriesData, enableNoResults, + noResults, ...rest } = this.props as PropsWithDefault; @@ -167,7 +173,7 @@ export default class SuperChart extends React.PureComponent { ({ data }) => !data || (Array.isArray(data) && data.length === 0), )); if (noResultQueries) { - chart = ( + chart = noResults || ( 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 ( - ); } diff --git a/superset-frontend/src/chart/ChartRenderer.jsx b/superset-frontend/src/chart/ChartRenderer.jsx index 03e0b258c..a5a20c616 100644 --- a/superset-frontend/src/chart/ChartRenderer.jsx +++ b/superset-frontend/src/chart/ChartRenderer.jsx @@ -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={ + + } /> ); } diff --git a/superset-frontend/src/dashboard/components/gridComponents/ChartHolder.test.tsx b/superset-frontend/src/dashboard/components/gridComponents/ChartHolder.test.tsx index 6268e96bd..4b2b91041 100644 --- a/superset-frontend/src/dashboard/components/gridComponents/ChartHolder.test.tsx +++ b/superset-frontend/src/dashboard/components/gridComponents/ChartHolder.test.tsx @@ -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', () => { , ); - 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(); }); });