diff --git a/packages/superset-ui-core/src/chart/components/SuperChart.tsx b/packages/superset-ui-core/src/chart/components/SuperChart.tsx index c4fb355759..4cccc5ec58 100644 --- a/packages/superset-ui-core/src/chart/components/SuperChart.tsx +++ b/packages/superset-ui-core/src/chart/components/SuperChart.tsx @@ -12,6 +12,7 @@ const defaultProps = { FallbackComponent: DefaultFallbackComponent, height: 400 as string | number, width: '100%' as string | number, + enableNoResults: true, }; export type FallbackPropsWithDimension = FallbackProps & Partial; @@ -30,6 +31,8 @@ export type Props = Omit & disableErrorBoundary?: boolean; /** debounceTime to check for container resize */ debounceTime?: number; + /** enable "No Results" message if empty result set */ + enableNoResults?: boolean; /** Component to render when there are unexpected errors */ FallbackComponent?: React.ComponentType; /** Event listener for unexpected errors from chart */ @@ -112,6 +115,7 @@ export default class SuperChart extends React.PureComponent { onErrorBoundary, Wrapper, queriesData, + enableNoResults, ...rest } = this.props as PropsWithDefault; @@ -125,8 +129,9 @@ export default class SuperChart extends React.PureComponent { let chart; // Render the no results component if the query data is null or empty const noResultQueries = - !queriesData || - queriesData.every(({ data }) => !data || (Array.isArray(data) && data.length === 0)); + enableNoResults && + (!queriesData || + queriesData.every(({ data }) => !data || (Array.isArray(data) && data.length === 0))); if (noResultQueries) { chart = ; } else { diff --git a/packages/superset-ui-core/src/chart/models/ChartMetadata.ts b/packages/superset-ui-core/src/chart/models/ChartMetadata.ts index 99ff5a9aad..736139850c 100644 --- a/packages/superset-ui-core/src/chart/models/ChartMetadata.ts +++ b/packages/superset-ui-core/src/chart/models/ChartMetadata.ts @@ -10,6 +10,7 @@ export interface ChartMetadataConfig { credits?: string[]; description?: string; datasourceCount?: number; + enableNoResults?: boolean; show?: boolean; supportedAnnotationTypes?: string[]; thumbnail: string; @@ -40,6 +41,8 @@ export default class ChartMetadata { datasourceCount: number; + enableNoResults: boolean; + constructor(config: ChartMetadataConfig) { const { name, @@ -52,6 +55,7 @@ export default class ChartMetadata { useLegacyApi = false, behaviors = [], datasourceCount = 1, + enableNoResults = true, } = config; this.name = name; @@ -73,6 +77,7 @@ export default class ChartMetadata { this.useLegacyApi = useLegacyApi; this.behaviors = behaviors; this.datasourceCount = datasourceCount; + this.enableNoResults = enableNoResults; } canBeAnnotationType(type: string): boolean { @@ -91,6 +96,7 @@ export default class ChartMetadata { useLegacyApi: this.useLegacyApi, behaviors: this.behaviors, datasourceCount: this.datasourceCount, + enableNoResults: this.enableNoResults, }); } } diff --git a/packages/superset-ui-core/src/chart/models/ChartProps.ts b/packages/superset-ui-core/src/chart/models/ChartProps.ts index 23cf0a062b..3c0cf5a5b8 100644 --- a/packages/superset-ui-core/src/chart/models/ChartProps.ts +++ b/packages/superset-ui-core/src/chart/models/ChartProps.ts @@ -1,3 +1,6 @@ +/** Type checking is disabled for this file due to reselect only supporting + * TS declarations for selectors with up to 12 arguments. */ +// @ts-nocheck import { createSelector } from 'reselect'; import { AppSection, @@ -66,6 +69,8 @@ export interface ChartPropsConfig { behaviors?: Behavior[]; /** Application section of the chart on the screen (in what components/screen it placed) */ appSection?: AppSection; + /** is the chart refreshing its contents */ + isRefreshing?: boolean; } const DEFAULT_WIDTH = 800; @@ -102,6 +107,8 @@ export default class ChartProps { appSection?: AppSection; + isRefreshing?: boolean; + constructor(config: ChartPropsConfig & { formData?: FormData } = {}) { const { annotationData = {}, @@ -116,6 +123,7 @@ export default class ChartProps { width = DEFAULT_WIDTH, height = DEFAULT_HEIGHT, appSection, + isRefreshing, } = config; this.width = width; this.height = height; @@ -131,6 +139,7 @@ export default class ChartProps { this.filterState = filterState; this.behaviors = behaviors; this.appSection = appSection; + this.isRefreshing = isRefreshing; } } @@ -149,6 +158,7 @@ ChartProps.createSelector = function create(): ChartPropsSelector { input => input.filterState, input => input.behaviors, input => input.appSection, + input => input.isRefreshing, ( annotationData, datasource, @@ -162,6 +172,7 @@ ChartProps.createSelector = function create(): ChartPropsSelector { filterState, behaviors, appSection, + isRefreshing, ) => new ChartProps({ annotationData, @@ -176,6 +187,7 @@ ChartProps.createSelector = function create(): ChartPropsSelector { width, behaviors, appSection, + isRefreshing, }), ); }; diff --git a/packages/superset-ui-core/test/chart/models/ChartProps.test.ts b/packages/superset-ui-core/test/chart/models/ChartProps.test.ts index b5f9b4fdcf..d62216ea31 100644 --- a/packages/superset-ui-core/test/chart/models/ChartProps.test.ts +++ b/packages/superset-ui-core/test/chart/models/ChartProps.test.ts @@ -1,4 +1,4 @@ -import { ChartProps } from '@superset-ui/core/src'; +import { Behavior, ChartProps } from '@superset-ui/core/src'; const RAW_FORM_DATA = { some_field: 1, @@ -10,6 +10,7 @@ const RAW_DATASOURCE = { const QUERY_DATA = { data: {} }; const QUERIES_DATA = [QUERY_DATA]; +const BEHAVIORS = [Behavior.NATIVE_FILTER, Behavior.INTERACTIVE_CHART]; describe('ChartProps', () => { it('exists', () => { @@ -51,6 +52,8 @@ describe('ChartProps', () => { datasource: RAW_DATASOURCE, formData: RAW_FORM_DATA, queriesData: QUERIES_DATA, + behaviors: BEHAVIORS, + isRefreshing: false, }); const props2 = selector({ width: 800, @@ -58,9 +61,37 @@ describe('ChartProps', () => { datasource: RAW_DATASOURCE, formData: RAW_FORM_DATA, queriesData: QUERIES_DATA, + behaviors: BEHAVIORS, + isRefreshing: false, }); expect(props1).toBe(props2); }); + it('selector returns a new chartProps if the 13th field changes', () => { + /** this test is here to test for selectors that exceed 12 arguments ( + * isRefreshing is the 13th argument, which is missing TS declarations). + * See: https://github.com/reduxjs/reselect/issues/378 + */ + + const props1 = selector({ + width: 800, + height: 600, + datasource: RAW_DATASOURCE, + formData: RAW_FORM_DATA, + queriesData: QUERIES_DATA, + behaviors: BEHAVIORS, + isRefreshing: false, + }); + const props2 = selector({ + width: 800, + height: 600, + datasource: RAW_DATASOURCE, + formData: RAW_FORM_DATA, + queriesData: QUERIES_DATA, + behaviors: BEHAVIORS, + isRefreshing: true, + }); + expect(props1).not.toBe(props2); + }); it('selector returns a new chartProps if some input fields change', () => { const props1 = selector({ width: 800,