mirror of
https://github.com/apache/superset.git
synced 2026-04-07 10:31:50 +00:00
feat: Support multiple queries per request (#11880)
* refactor: add queriesData fields for multiple queries * feat: support multi queries request * lint: fix lint * lint: fix lint * lint: fix lint * fix: fix CR notes * fix: fix CR notes * fix: fix CR notes * fix: fix error case for multi queries * feat: change queryResponse to queriesResponse * fix: revert webpack * test: fix tests * chore: lint * chore: adjust asyncEvent to multiple results * fix: lint * fix: eslint * fix: another eslint rule Co-authored-by: Amit Miran <47772523+amitmiran137@users.noreply.github.com> Co-authored-by: amitmiran137 <amit.miran@nielsen.com>
This commit is contained in:
@@ -189,7 +189,7 @@ describe('chart actions', () => {
|
||||
expect(dispatch.callCount).toBe(5);
|
||||
const updateFailedAction = dispatch.args[4][0];
|
||||
expect(updateFailedAction.type).toBe(actions.CHART_UPDATE_FAILED);
|
||||
expect(updateFailedAction.queryResponse.error).toBe('misc error');
|
||||
expect(updateFailedAction.queriesResponse[0].error).toBe('misc error');
|
||||
|
||||
setupDefaultFetchMock();
|
||||
});
|
||||
|
||||
@@ -51,11 +51,13 @@ describe('FiltersBadge', () => {
|
||||
store.dispatch({
|
||||
type: CHART_UPDATE_SUCCEEDED,
|
||||
key: sliceId,
|
||||
queryResponse: {
|
||||
status: 'success',
|
||||
applied_filters: [],
|
||||
rejected_filters: [],
|
||||
},
|
||||
queriesResponse: [
|
||||
{
|
||||
status: 'success',
|
||||
applied_filters: [],
|
||||
rejected_filters: [],
|
||||
},
|
||||
],
|
||||
dashboardFilters,
|
||||
});
|
||||
const wrapper = shallow(
|
||||
@@ -74,11 +76,13 @@ describe('FiltersBadge', () => {
|
||||
store.dispatch({
|
||||
type: CHART_UPDATE_SUCCEEDED,
|
||||
key: sliceId,
|
||||
queryResponse: {
|
||||
status: 'success',
|
||||
applied_filters: [{ column: 'region' }],
|
||||
rejected_filters: [],
|
||||
},
|
||||
queriesResponse: [
|
||||
{
|
||||
status: 'success',
|
||||
applied_filters: [{ column: 'region' }],
|
||||
rejected_filters: [],
|
||||
},
|
||||
],
|
||||
dashboardFilters,
|
||||
});
|
||||
const wrapper = shallow(
|
||||
@@ -97,11 +101,13 @@ describe('FiltersBadge', () => {
|
||||
store.dispatch({
|
||||
type: CHART_UPDATE_SUCCEEDED,
|
||||
key: sliceId,
|
||||
queryResponse: {
|
||||
status: 'success',
|
||||
applied_filters: [],
|
||||
rejected_filters: [{ column: 'region', reason: 'not_in_datasource' }],
|
||||
},
|
||||
queriesResponse: [
|
||||
{
|
||||
status: 'success',
|
||||
applied_filters: [],
|
||||
rejected_filters: [{ column: 'region', reason: 'not_in_datasource' }],
|
||||
},
|
||||
],
|
||||
dashboardFilters,
|
||||
});
|
||||
const wrapper = shallow(
|
||||
|
||||
@@ -56,7 +56,7 @@ const propTypes = {
|
||||
chartAlert: PropTypes.string,
|
||||
chartStatus: PropTypes.string,
|
||||
chartStackTrace: PropTypes.string,
|
||||
queryResponse: PropTypes.object,
|
||||
queriesResponse: PropTypes.arrayOf(PropTypes.object),
|
||||
triggerQuery: PropTypes.bool,
|
||||
refreshOverlayVisible: PropTypes.bool,
|
||||
errorMessage: PropTypes.node,
|
||||
@@ -150,14 +150,8 @@ class Chart extends React.PureComponent {
|
||||
});
|
||||
}
|
||||
|
||||
renderErrorMessage() {
|
||||
const {
|
||||
chartAlert,
|
||||
chartStackTrace,
|
||||
dashboardId,
|
||||
owners,
|
||||
queryResponse,
|
||||
} = this.props;
|
||||
renderErrorMessage(queryResponse) {
|
||||
const { chartAlert, chartStackTrace, dashboardId, owners } = this.props;
|
||||
|
||||
const error = queryResponse?.errors?.[0];
|
||||
if (error) {
|
||||
@@ -187,14 +181,14 @@ class Chart extends React.PureComponent {
|
||||
errorMessage,
|
||||
onQuery,
|
||||
refreshOverlayVisible,
|
||||
queriesResponse = [],
|
||||
} = this.props;
|
||||
|
||||
const isLoading = chartStatus === 'loading';
|
||||
|
||||
const isFaded = refreshOverlayVisible && !errorMessage;
|
||||
this.renderContainerStartTime = Logger.getTimestamp();
|
||||
if (chartStatus === 'failed') {
|
||||
return this.renderErrorMessage();
|
||||
return queriesResponse.map(item => this.renderErrorMessage(item));
|
||||
}
|
||||
if (errorMessage) {
|
||||
return (
|
||||
|
||||
@@ -37,7 +37,7 @@ const propTypes = {
|
||||
// state
|
||||
chartAlert: PropTypes.string,
|
||||
chartStatus: PropTypes.string,
|
||||
queryResponse: PropTypes.object,
|
||||
queriesResponse: PropTypes.arrayOf(PropTypes.object),
|
||||
triggerQuery: PropTypes.bool,
|
||||
refreshOverlayVisible: PropTypes.bool,
|
||||
// dashboard callbacks
|
||||
@@ -78,14 +78,14 @@ class ChartRenderer extends React.Component {
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
const resultsReady =
|
||||
nextProps.queryResponse &&
|
||||
nextProps.queriesResponse &&
|
||||
['success', 'rendered'].indexOf(nextProps.chartStatus) > -1 &&
|
||||
!nextProps.queryResponse.error &&
|
||||
!nextProps.queriesResponse?.[0]?.error &&
|
||||
!nextProps.refreshOverlayVisible;
|
||||
|
||||
if (resultsReady) {
|
||||
this.hasQueryResponseChange =
|
||||
nextProps.queryResponse !== this.props.queryResponse;
|
||||
nextProps.queriesResponse !== this.props.queriesResponse;
|
||||
return (
|
||||
this.hasQueryResponseChange ||
|
||||
nextProps.annotationData !== this.props.annotationData ||
|
||||
@@ -179,7 +179,7 @@ class ChartRenderer extends React.Component {
|
||||
datasource,
|
||||
initialValues,
|
||||
formData,
|
||||
queryResponse,
|
||||
queriesResponse,
|
||||
} = this.props;
|
||||
|
||||
// It's bad practice to use unprefixed `vizType` as classnames for chart
|
||||
@@ -218,7 +218,8 @@ class ChartRenderer extends React.Component {
|
||||
initialValues={initialValues}
|
||||
formData={formData}
|
||||
hooks={this.hooks}
|
||||
queryData={queryResponse}
|
||||
queryData={queriesResponse?.[0]} // deprecated
|
||||
queriesData={queriesResponse}
|
||||
onRenderSuccess={this.handleRenderSuccess}
|
||||
onRenderFailure={this.handleRenderFailure}
|
||||
/>
|
||||
|
||||
@@ -52,8 +52,8 @@ export function chartUpdateStarted(queryController, latestQueryFormData, key) {
|
||||
}
|
||||
|
||||
export const CHART_UPDATE_SUCCEEDED = 'CHART_UPDATE_SUCCEEDED';
|
||||
export function chartUpdateSucceeded(queryResponse, key) {
|
||||
return { type: CHART_UPDATE_SUCCEEDED, queryResponse, key };
|
||||
export function chartUpdateSucceeded(queriesResponse, key) {
|
||||
return { type: CHART_UPDATE_SUCCEEDED, queriesResponse, key };
|
||||
}
|
||||
|
||||
export const CHART_UPDATE_STOPPED = 'CHART_UPDATE_STOPPED';
|
||||
@@ -62,8 +62,8 @@ export function chartUpdateStopped(key) {
|
||||
}
|
||||
|
||||
export const CHART_UPDATE_FAILED = 'CHART_UPDATE_FAILED';
|
||||
export function chartUpdateFailed(queryResponse, key) {
|
||||
return { type: CHART_UPDATE_FAILED, queryResponse, key };
|
||||
export function chartUpdateFailed(queriesResponse, key) {
|
||||
return { type: CHART_UPDATE_FAILED, queriesResponse, key };
|
||||
}
|
||||
|
||||
export const CHART_UPDATE_QUEUED = 'CHART_UPDATE_QUEUED';
|
||||
@@ -361,38 +361,35 @@ export function exploreJSON(
|
||||
|
||||
const chartDataRequestCaught = chartDataRequest
|
||||
.then(response => {
|
||||
const queriesResponse = response.result;
|
||||
if (isFeatureEnabled(FeatureFlag.GLOBAL_ASYNC_QUERIES)) {
|
||||
// deal with getChartDataRequest transforming the response data
|
||||
const result = 'result' in response ? response.result[0] : response;
|
||||
return dispatch(chartUpdateQueued(result, key));
|
||||
}
|
||||
|
||||
// new API returns an object with an array of restults
|
||||
// problem: response holds a list of results, when before we were just getting one result.
|
||||
// How to make the entire app compatible with multiple results?
|
||||
// For now just use the first result.
|
||||
const result = response.result[0];
|
||||
|
||||
dispatch(
|
||||
logEvent(LOG_ACTIONS_LOAD_CHART, {
|
||||
slice_id: key,
|
||||
applied_filters: result.applied_filters,
|
||||
is_cached: result.is_cached,
|
||||
force_refresh: force,
|
||||
row_count: result.rowcount,
|
||||
datasource: formData.datasource,
|
||||
start_offset: logStart,
|
||||
ts: new Date().getTime(),
|
||||
duration: Logger.getTimestamp() - logStart,
|
||||
has_extra_filters:
|
||||
formData.extra_filters && formData.extra_filters.length > 0,
|
||||
viz_type: formData.viz_type,
|
||||
data_age: result.is_cached
|
||||
? moment(new Date()).diff(moment.utc(result.cached_dttm))
|
||||
: null,
|
||||
}),
|
||||
queriesResponse.forEach(resultItem =>
|
||||
dispatch(
|
||||
logEvent(LOG_ACTIONS_LOAD_CHART, {
|
||||
slice_id: key,
|
||||
applied_filters: resultItem.applied_filters,
|
||||
is_cached: resultItem.is_cached,
|
||||
force_refresh: force,
|
||||
row_count: resultItem.rowcount,
|
||||
datasource: formData.datasource,
|
||||
start_offset: logStart,
|
||||
ts: new Date().getTime(),
|
||||
duration: Logger.getTimestamp() - logStart,
|
||||
has_extra_filters:
|
||||
formData.extra_filters && formData.extra_filters.length > 0,
|
||||
viz_type: formData.viz_type,
|
||||
data_age: resultItem.is_cached
|
||||
? moment(new Date()).diff(moment.utc(resultItem.cached_dttm))
|
||||
: null,
|
||||
}),
|
||||
),
|
||||
);
|
||||
return dispatch(chartUpdateSucceeded(result, key));
|
||||
return dispatch(chartUpdateSucceeded(queriesResponse, key));
|
||||
})
|
||||
.catch(response => {
|
||||
const appendErrorLog = (errorDetails, isCached) => {
|
||||
@@ -419,7 +416,7 @@ export function exploreJSON(
|
||||
} else {
|
||||
appendErrorLog(parsedResponse.error, parsedResponse.is_cached);
|
||||
}
|
||||
return dispatch(chartUpdateFailed(parsedResponse, key));
|
||||
return dispatch(chartUpdateFailed([parsedResponse], key));
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ export const chart = {
|
||||
chartUpdateStartTime: 0,
|
||||
latestQueryFormData: {},
|
||||
queryController: null,
|
||||
queryResponse: null,
|
||||
queriesResponse: null,
|
||||
triggerQuery: true,
|
||||
lastRendered: 0,
|
||||
};
|
||||
@@ -47,8 +47,8 @@ export default function chartReducer(charts = {}, action) {
|
||||
return {
|
||||
...state,
|
||||
chartStatus: 'success',
|
||||
queryResponse: action.queryResponse,
|
||||
chartAlert: null,
|
||||
queriesResponse: action.queriesResponse,
|
||||
chartUpdateEndTime: now(),
|
||||
};
|
||||
},
|
||||
@@ -97,13 +97,13 @@ export default function chartReducer(charts = {}, action) {
|
||||
return {
|
||||
...state,
|
||||
chartStatus: 'failed',
|
||||
chartAlert: action.queryResponse
|
||||
? action.queryResponse.error
|
||||
chartAlert: action.queriesResponse
|
||||
? action.queriesResponse?.[0]?.error
|
||||
: t('Network error.'),
|
||||
chartUpdateEndTime: now(),
|
||||
queryResponse: action.queryResponse,
|
||||
chartStackTrace: action.queryResponse
|
||||
? action.queryResponse.stacktrace
|
||||
queriesResponse: action.queriesResponse,
|
||||
chartStackTrace: action.queriesResponse
|
||||
? action.queriesResponse?.[0]?.stacktrace
|
||||
: null,
|
||||
};
|
||||
},
|
||||
|
||||
@@ -132,12 +132,12 @@ export const selectIndicatorsForChart = (
|
||||
// for now we only need to know which columns are compatible/incompatible,
|
||||
// so grab the columns from the applied/rejected filters
|
||||
const appliedColumns: Set<string> = new Set(
|
||||
(chart?.queryResponse?.applied_filters || []).map(
|
||||
(chart?.queriesResponse?.[0]?.applied_filters || []).map(
|
||||
(filter: any) => filter.column,
|
||||
),
|
||||
);
|
||||
const rejectedColumns: Set<string> = new Set(
|
||||
(chart?.queryResponse?.rejected_filters || []).map(
|
||||
(chart?.queriesResponse?.[0]?.rejected_filters || []).map(
|
||||
(filter: any) => filter.column,
|
||||
),
|
||||
);
|
||||
|
||||
@@ -29,8 +29,8 @@ const propTypes = {
|
||||
innerRef: PropTypes.func,
|
||||
slice: PropTypes.object.isRequired,
|
||||
isExpanded: PropTypes.bool,
|
||||
isCached: PropTypes.bool,
|
||||
cachedDttm: PropTypes.string,
|
||||
isCached: PropTypes.arrayOf(PropTypes.bool),
|
||||
cachedDttm: PropTypes.arrayOf(PropTypes.string),
|
||||
updatedDttm: PropTypes.number,
|
||||
updateSliceName: PropTypes.func,
|
||||
toggleExpandSlice: PropTypes.func,
|
||||
@@ -64,8 +64,8 @@ const defaultProps = {
|
||||
annotationError: {},
|
||||
cachedDttm: null,
|
||||
updatedDttm: null,
|
||||
isCached: false,
|
||||
isExpanded: false,
|
||||
isCached: [],
|
||||
isExpanded: [],
|
||||
sliceName: '',
|
||||
supersetCanExplore: false,
|
||||
supersetCanCSV: false,
|
||||
|
||||
@@ -31,9 +31,9 @@ const propTypes = {
|
||||
componentId: PropTypes.string.isRequired,
|
||||
dashboardId: PropTypes.number.isRequired,
|
||||
addDangerToast: PropTypes.func.isRequired,
|
||||
isCached: PropTypes.bool,
|
||||
isCached: PropTypes.arrayOf(PropTypes.bool),
|
||||
cachedDttm: PropTypes.arrayOf(PropTypes.string),
|
||||
isExpanded: PropTypes.bool,
|
||||
cachedDttm: PropTypes.string,
|
||||
updatedDttm: PropTypes.number,
|
||||
supersetCanExplore: PropTypes.bool,
|
||||
supersetCanCSV: PropTypes.bool,
|
||||
@@ -49,9 +49,9 @@ const defaultProps = {
|
||||
toggleExpandSlice: () => ({}),
|
||||
exploreChart: () => ({}),
|
||||
exportCSV: () => ({}),
|
||||
cachedDttm: null,
|
||||
cachedDttm: [],
|
||||
updatedDttm: null,
|
||||
isCached: false,
|
||||
isCached: [],
|
||||
isExpanded: false,
|
||||
supersetCanExplore: false,
|
||||
supersetCanCSV: false,
|
||||
@@ -82,9 +82,14 @@ const VerticalDotsContainer = styled.div`
|
||||
`;
|
||||
|
||||
const RefreshTooltip = styled.div`
|
||||
height: ${({ theme }) => theme.gridUnit * 4}px;
|
||||
height: auto;
|
||||
margin: ${({ theme }) => theme.gridUnit}px 0;
|
||||
color: ${({ theme }) => theme.colors.grayscale.base};
|
||||
line-height: ${({ theme }) => theme.typography.sizes.m * 1.5}px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
justify-content: flex-start;
|
||||
`;
|
||||
|
||||
const SCREENSHOT_NODE_SELECTOR = '.dashboard-component-chart-holder';
|
||||
@@ -171,13 +176,26 @@ class SliceHeaderControls extends React.PureComponent {
|
||||
addDangerToast,
|
||||
isFullSize,
|
||||
} = this.props;
|
||||
const cachedWhen = moment.utc(cachedDttm).fromNow();
|
||||
const cachedWhen = cachedDttm.map(itemCachedDttm =>
|
||||
moment.utc(itemCachedDttm).fromNow(),
|
||||
);
|
||||
const updatedWhen = updatedDttm ? moment.utc(updatedDttm).fromNow() : '';
|
||||
const refreshTooltip = isCached
|
||||
? t('Cached %s', cachedWhen)
|
||||
: (updatedWhen && t('Fetched %s', updatedWhen)) || '';
|
||||
const getCachedTitle = itemCached => {
|
||||
return itemCached
|
||||
? t('Cached %s', cachedWhen)
|
||||
: updatedWhen && t('Fetched %s', updatedWhen);
|
||||
};
|
||||
const refreshTooltipData = isCached.map(getCachedTitle) || '';
|
||||
// If all queries have same cache time we can unit them to one
|
||||
let refreshTooltip = [...new Set(refreshTooltipData)];
|
||||
refreshTooltip = refreshTooltip.map((item, index) => (
|
||||
<div>
|
||||
{refreshTooltip.length > 1
|
||||
? `${t('Query')} ${index + 1}: ${item}`
|
||||
: item}
|
||||
</div>
|
||||
));
|
||||
const resizeLabel = isFullSize ? t('Minimize Chart') : t('Maximize Chart');
|
||||
|
||||
const menu = (
|
||||
<Menu
|
||||
onClick={this.handleMenuClick}
|
||||
|
||||
@@ -266,10 +266,13 @@ export default class Chart extends React.Component {
|
||||
return <MissingChart height={this.getChartHeight()} />;
|
||||
}
|
||||
|
||||
const { queryResponse, chartUpdateEndTime, chartStatus } = chart;
|
||||
const { queriesResponse, chartUpdateEndTime, chartStatus } = chart;
|
||||
const isLoading = chartStatus === 'loading';
|
||||
const isCached = queryResponse && queryResponse.is_cached;
|
||||
const cachedDttm = queryResponse && queryResponse.cached_dttm;
|
||||
// eslint-disable-next-line camelcase
|
||||
const isCached = queriesResponse?.map(({ is_cached }) => is_cached) || [];
|
||||
const cachedDttm =
|
||||
// eslint-disable-next-line camelcase
|
||||
queriesResponse?.map(({ cached_dttm }) => cached_dttm) || [];
|
||||
const isOverflowable = OVERFLOWABLE_VIZ_TYPES.has(slice.viz_type);
|
||||
const initialValues = isFilterBox(id)
|
||||
? getFilterValuesByFilterId({
|
||||
@@ -277,7 +280,6 @@ export default class Chart extends React.Component {
|
||||
filterId: id,
|
||||
})
|
||||
: {};
|
||||
|
||||
return (
|
||||
<div className="chart-slice">
|
||||
<SliceHeader
|
||||
@@ -352,7 +354,7 @@ export default class Chart extends React.Component {
|
||||
dashboardId={dashboardId}
|
||||
initialValues={initialValues}
|
||||
formData={formData}
|
||||
queryResponse={chart.queryResponse}
|
||||
queriesResponse={chart.queriesResponse}
|
||||
timeout={timeout}
|
||||
triggerQuery={chart.triggerQuery}
|
||||
vizType={slice.viz_type}
|
||||
|
||||
@@ -50,7 +50,7 @@ export const chartPropShape = PropTypes.shape({
|
||||
chartUpdateStartTime: PropTypes.number,
|
||||
latestQueryFormData: PropTypes.object,
|
||||
queryController: PropTypes.shape({ abort: PropTypes.func }),
|
||||
queryResponse: PropTypes.object,
|
||||
queriesResponse: PropTypes.arrayOf(PropTypes.object),
|
||||
triggerQuery: PropTypes.bool,
|
||||
lastRendered: PropTypes.number,
|
||||
});
|
||||
|
||||
@@ -47,7 +47,6 @@ SyntaxHighlighter.registerLanguage('json', jsonSyntax);
|
||||
const propTypes = {
|
||||
onOpenPropertiesModal: PropTypes.func,
|
||||
onOpenInEditor: PropTypes.func,
|
||||
queryResponse: PropTypes.object,
|
||||
chartStatus: PropTypes.string,
|
||||
chartHeight: PropTypes.string.isRequired,
|
||||
latestQueryFormData: PropTypes.object.isRequired,
|
||||
|
||||
@@ -33,7 +33,7 @@ const propTypes = {
|
||||
chartStatus: PropTypes.string,
|
||||
chartHeight: PropTypes.string.isRequired,
|
||||
latestQueryFormData: PropTypes.object,
|
||||
queryResponse: PropTypes.object,
|
||||
queriesResponse: PropTypes.arrayOf(PropTypes.object),
|
||||
slice: PropTypes.object,
|
||||
};
|
||||
|
||||
@@ -43,7 +43,7 @@ export default function ExploreActionButtons({
|
||||
chartHeight,
|
||||
chartStatus,
|
||||
latestQueryFormData,
|
||||
queryResponse,
|
||||
queriesResponse,
|
||||
slice,
|
||||
}) {
|
||||
const exportToCSVClasses = cx('btn btn-default btn-sm', {
|
||||
@@ -106,7 +106,7 @@ export default function ExploreActionButtons({
|
||||
)}
|
||||
<ConnectedDisplayQueryButton
|
||||
chartHeight={chartHeight}
|
||||
queryResponse={queryResponse}
|
||||
queryResponse={queriesResponse?.[0]}
|
||||
latestQueryFormData={latestQueryFormData}
|
||||
chartStatus={chartStatus}
|
||||
onOpenInEditor={actions.redirectSQLLab}
|
||||
|
||||
@@ -130,8 +130,10 @@ export class ExploreChartHeader extends React.PureComponent {
|
||||
chartUpdateEndTime,
|
||||
chartUpdateStartTime,
|
||||
latestQueryFormData,
|
||||
queryResponse,
|
||||
queriesResponse,
|
||||
} = this.props.chart;
|
||||
// TODO: when will get appropriate design for multi queries use all results and not first only
|
||||
const queryResponse = queriesResponse?.[0];
|
||||
const chartFinished = ['failed', 'rendered', 'success'].includes(
|
||||
this.props.chart.chartStatus,
|
||||
);
|
||||
|
||||
@@ -189,7 +189,7 @@ const ExploreChartPanel = props => {
|
||||
formData={props.form_data}
|
||||
onQuery={props.onQuery}
|
||||
owners={props?.slice?.owners}
|
||||
queryResponse={chart.queryResponse}
|
||||
queriesResponse={chart.queriesResponse}
|
||||
refreshOverlayVisible={props.refreshOverlayVisible}
|
||||
setControlValue={props.actions.setControlValue}
|
||||
timeout={props.timeout}
|
||||
|
||||
@@ -72,7 +72,7 @@ export default function getInitialState(bootstrapData) {
|
||||
latestQueryFormData: getFormDataFromControls(controls),
|
||||
sliceFormData,
|
||||
queryController: null,
|
||||
queryResponse: null,
|
||||
queriesResponse: null,
|
||||
triggerQuery: false,
|
||||
lastRendered: 0,
|
||||
},
|
||||
|
||||
@@ -16,10 +16,10 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { Middleware, MiddlewareAPI, Dispatch } from 'redux';
|
||||
import { Dispatch, Middleware, MiddlewareAPI } from 'redux';
|
||||
import { makeApi, SupersetClient } from '@superset-ui/core';
|
||||
import { SupersetError } from 'src/components/ErrorMessage/types';
|
||||
import { isFeatureEnabled, FeatureFlag } from '../featureFlags';
|
||||
import { FeatureFlag, isFeatureEnabled } from '../featureFlags';
|
||||
import {
|
||||
getClientErrorObject,
|
||||
parseErrorJson,
|
||||
@@ -100,7 +100,7 @@ const initAsyncEvents = (options: AsyncEventOptions) => {
|
||||
const { json } = await SupersetClient.get({
|
||||
endpoint: asyncEvent.result_url,
|
||||
});
|
||||
data = 'result' in json ? json.result[0] : json;
|
||||
data = 'result' in json ? json.result : json;
|
||||
} catch (response) {
|
||||
status = 'error';
|
||||
data = await getClientErrorObject(response);
|
||||
@@ -152,7 +152,7 @@ const initAsyncEvents = (options: AsyncEventOptions) => {
|
||||
break;
|
||||
case JOB_STATUS.ERROR:
|
||||
store.dispatch(
|
||||
errorAction(componentId, parseErrorJson(asyncEvent)),
|
||||
errorAction(componentId, [parseErrorJson(asyncEvent)]),
|
||||
);
|
||||
break;
|
||||
default:
|
||||
@@ -164,10 +164,13 @@ const initAsyncEvents = (options: AsyncEventOptions) => {
|
||||
|
||||
const fetchResults = await Promise.all(fetchDataEvents);
|
||||
fetchResults.forEach(result => {
|
||||
const data = Array.isArray(result.data)
|
||||
? result.data
|
||||
: [result.data];
|
||||
if (result.status === 'success') {
|
||||
store.dispatch(successAction(result.componentId, result.data));
|
||||
store.dispatch(successAction(result.componentId, data));
|
||||
} else {
|
||||
store.dispatch(errorAction(result.componentId, result.data));
|
||||
store.dispatch(errorAction(result.componentId, data));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user