mirror of https://github.com/apache/superset.git
fix: chart empty state & result panel when multiple queries are executed display incorrectly (#20816)
This commit is contained in:
parent
34278c2d56
commit
279ab954b1
|
@ -26,6 +26,7 @@ import { ParentSize } from '@vx/responsive';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import { withTheme } from '@emotion/react';
|
import { withTheme } from '@emotion/react';
|
||||||
import { parseLength, Dimension } from '../../dimension';
|
import { parseLength, Dimension } from '../../dimension';
|
||||||
|
import getChartMetadataRegistry from '../registries/ChartMetadataRegistrySingleton';
|
||||||
import SuperChartCore, { Props as SuperChartCoreProps } from './SuperChartCore';
|
import SuperChartCore, { Props as SuperChartCoreProps } from './SuperChartCore';
|
||||||
import DefaultFallbackComponent from './FallbackComponent';
|
import DefaultFallbackComponent from './FallbackComponent';
|
||||||
import ChartProps, { ChartPropsConfig } from '../models/ChartProps';
|
import ChartProps, { ChartPropsConfig } from '../models/ChartProps';
|
||||||
|
@ -140,6 +141,9 @@ class SuperChart extends React.PureComponent<Props, {}> {
|
||||||
this.core = core;
|
this.core = core;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private getQueryCount = () =>
|
||||||
|
getChartMetadataRegistry().get(this.props.chartType)?.queryObjectCount ?? 1;
|
||||||
|
|
||||||
renderChart(width: number, height: number) {
|
renderChart(width: number, height: number) {
|
||||||
const {
|
const {
|
||||||
id,
|
id,
|
||||||
|
@ -174,9 +178,11 @@ class SuperChart extends React.PureComponent<Props, {}> {
|
||||||
const noResultQueries =
|
const noResultQueries =
|
||||||
enableNoResults &&
|
enableNoResults &&
|
||||||
(!queriesData ||
|
(!queriesData ||
|
||||||
queriesData.every(
|
queriesData
|
||||||
({ data }) => !data || (Array.isArray(data) && data.length === 0),
|
.slice(0, this.getQueryCount())
|
||||||
));
|
.every(
|
||||||
|
({ data }) => !data || (Array.isArray(data) && data.length === 0),
|
||||||
|
));
|
||||||
if (noResultQueries) {
|
if (noResultQueries) {
|
||||||
chart = noResults || (
|
chart = noResults || (
|
||||||
<NoResultsComponent
|
<NoResultsComponent
|
||||||
|
|
|
@ -48,6 +48,7 @@ export interface ChartMetadataConfig {
|
||||||
// label: ChartLabel.DEPRECATED which will display a "deprecated" label on the chart.
|
// label: ChartLabel.DEPRECATED which will display a "deprecated" label on the chart.
|
||||||
label?: ChartLabel | null;
|
label?: ChartLabel | null;
|
||||||
labelExplanation?: string | null;
|
labelExplanation?: string | null;
|
||||||
|
queryObjectCount?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class ChartMetadata {
|
export default class ChartMetadata {
|
||||||
|
@ -87,6 +88,8 @@ export default class ChartMetadata {
|
||||||
|
|
||||||
labelExplanation?: string | null;
|
labelExplanation?: string | null;
|
||||||
|
|
||||||
|
queryObjectCount: number;
|
||||||
|
|
||||||
constructor(config: ChartMetadataConfig) {
|
constructor(config: ChartMetadataConfig) {
|
||||||
const {
|
const {
|
||||||
name,
|
name,
|
||||||
|
@ -106,6 +109,7 @@ export default class ChartMetadata {
|
||||||
deprecated = false,
|
deprecated = false,
|
||||||
label = null,
|
label = null,
|
||||||
labelExplanation = null,
|
labelExplanation = null,
|
||||||
|
queryObjectCount = 1,
|
||||||
} = config;
|
} = config;
|
||||||
|
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
@ -134,6 +138,7 @@ export default class ChartMetadata {
|
||||||
this.deprecated = deprecated;
|
this.deprecated = deprecated;
|
||||||
this.label = label;
|
this.label = label;
|
||||||
this.labelExplanation = labelExplanation;
|
this.labelExplanation = labelExplanation;
|
||||||
|
this.queryObjectCount = queryObjectCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
canBeAnnotationType(type: string): boolean {
|
canBeAnnotationType(type: string): boolean {
|
||||||
|
|
|
@ -84,6 +84,7 @@ export default class EchartsTimeseriesChartPlugin extends ChartPlugin<
|
||||||
t('Time'),
|
t('Time'),
|
||||||
t('Transformable'),
|
t('Transformable'),
|
||||||
],
|
],
|
||||||
|
queryObjectCount: 2,
|
||||||
}),
|
}),
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
transformProps,
|
transformProps,
|
||||||
|
|
|
@ -17,13 +17,17 @@
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { ensureIsArray, styled, t } from '@superset-ui/core';
|
import {
|
||||||
|
ensureIsArray,
|
||||||
|
styled,
|
||||||
|
t,
|
||||||
|
getChartMetadataRegistry,
|
||||||
|
} from '@superset-ui/core';
|
||||||
import Loading from 'src/components/Loading';
|
import Loading from 'src/components/Loading';
|
||||||
import { EmptyStateMedium } from 'src/components/EmptyState';
|
import { EmptyStateMedium } from 'src/components/EmptyState';
|
||||||
import { getChartDataRequest } from 'src/components/Chart/chartAction';
|
import { getChartDataRequest } from 'src/components/Chart/chartAction';
|
||||||
import { getClientErrorObject } from 'src/utils/getClientErrorObject';
|
import { getClientErrorObject } from 'src/utils/getClientErrorObject';
|
||||||
import { ResultsPaneProps, QueryResultInterface } from '../types';
|
import { ResultsPaneProps, QueryResultInterface } from '../types';
|
||||||
import { getQueryCount } from '../utils';
|
|
||||||
import { SingleQueryResultPane } from './SingleQueryResultPane';
|
import { SingleQueryResultPane } from './SingleQueryResultPane';
|
||||||
import { TableControls } from './DataTableControls';
|
import { TableControls } from './DataTableControls';
|
||||||
|
|
||||||
|
@ -43,12 +47,14 @@ export const useResultsPane = ({
|
||||||
isVisible,
|
isVisible,
|
||||||
dataSize = 50,
|
dataSize = 50,
|
||||||
}: ResultsPaneProps): React.ReactElement[] => {
|
}: ResultsPaneProps): React.ReactElement[] => {
|
||||||
|
const metadata = getChartMetadataRegistry().get(
|
||||||
|
queryFormData?.viz_type || queryFormData?.vizType,
|
||||||
|
);
|
||||||
|
|
||||||
const [resultResp, setResultResp] = useState<QueryResultInterface[]>([]);
|
const [resultResp, setResultResp] = useState<QueryResultInterface[]>([]);
|
||||||
const [isLoading, setIsLoading] = useState<boolean>(true);
|
const [isLoading, setIsLoading] = useState<boolean>(true);
|
||||||
const [responseError, setResponseError] = useState<string>('');
|
const [responseError, setResponseError] = useState<string>('');
|
||||||
const queryCount = getQueryCount(
|
const queryCount = metadata?.queryObjectCount ?? 1;
|
||||||
queryFormData?.viz_type || queryFormData?.vizType,
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// it's an invalid formData when gets a errorMessage
|
// it's an invalid formData when gets a errorMessage
|
||||||
|
@ -122,15 +128,17 @@ export const useResultsPane = ({
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return resultResp.map((result, idx) => (
|
return resultResp
|
||||||
<SingleQueryResultPane
|
.slice(0, queryCount)
|
||||||
data={result.data}
|
.map((result, idx) => (
|
||||||
colnames={result.colnames}
|
<SingleQueryResultPane
|
||||||
coltypes={result.coltypes}
|
data={result.data}
|
||||||
dataSize={dataSize}
|
colnames={result.colnames}
|
||||||
datasourceId={queryFormData.datasource}
|
coltypes={result.coltypes}
|
||||||
key={idx}
|
dataSize={dataSize}
|
||||||
isVisible={isVisible}
|
datasourceId={queryFormData.datasource}
|
||||||
/>
|
key={idx}
|
||||||
));
|
isVisible={isVisible}
|
||||||
|
/>
|
||||||
|
));
|
||||||
};
|
};
|
||||||
|
|
|
@ -24,7 +24,7 @@ import {
|
||||||
waitForElementToBeRemoved,
|
waitForElementToBeRemoved,
|
||||||
} from 'spec/helpers/testing-library';
|
} from 'spec/helpers/testing-library';
|
||||||
import { exploreActions } from 'src/explore/actions/exploreActions';
|
import { exploreActions } from 'src/explore/actions/exploreActions';
|
||||||
import { promiseTimeout } from '@superset-ui/core';
|
import { ChartMetadata, ChartPlugin, promiseTimeout } from '@superset-ui/core';
|
||||||
import { ResultsPaneOnDashboard } from '../components';
|
import { ResultsPaneOnDashboard } from '../components';
|
||||||
import { createResultsPaneOnDashboardProps } from './fixture';
|
import { createResultsPaneOnDashboardProps } from './fixture';
|
||||||
|
|
||||||
|
@ -147,6 +147,19 @@ describe('ResultsPaneOnDashboard', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('multiple results pane', async () => {
|
test('multiple results pane', async () => {
|
||||||
|
const FakeChart = () => <span>test</span>;
|
||||||
|
const metadata = new ChartMetadata({
|
||||||
|
name: 'test-chart',
|
||||||
|
thumbnail: '',
|
||||||
|
queryObjectCount: 2,
|
||||||
|
});
|
||||||
|
|
||||||
|
const plugin = new ChartPlugin({
|
||||||
|
metadata,
|
||||||
|
Chart: FakeChart,
|
||||||
|
});
|
||||||
|
plugin.configure({ key: 'mixed_timeseries' }).register();
|
||||||
|
|
||||||
const props = createResultsPaneOnDashboardProps({
|
const props = createResultsPaneOnDashboardProps({
|
||||||
sliceId: 196,
|
sliceId: 196,
|
||||||
vizType: 'mixed_timeseries',
|
vizType: 'mixed_timeseries',
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
/**
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
const queryObjectCount = {
|
|
||||||
mixed_timeseries: 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getQueryCount = (vizType: string): number =>
|
|
||||||
queryObjectCount?.[vizType] || 1;
|
|
Loading…
Reference in New Issue