return async function(dispatch, getState) { // If the dataset_query was filtered then we don't have permisison to view this card, so // shortcircuit and return a fake 403 if (!card.dataset_query) { return { dashcard_id: dashcard.id, card_id: card.id, result: { error: { status: 403 }} }; } const isPublicLink = Utils.isUUID(dashcard.dashboard_id); const { dashboardId, dashboards, parameterValues, dashcardData } = getState().dashboard; const dashboard = dashboards[dashboardId]; // if we have a parameter, apply it to the card query before we execute const datasetQuery = applyParameters(card, dashboard.parameters, parameterValues, dashcard && dashcard.parameter_mappings); if (!reload) { // if reload not set, check to see if the last result has the same query dict and return that const lastResult = getIn(dashcardData, [dashcard.id, card.id]); // "constraints" is added by the backend, remove it when comparing if (lastResult && Utils.equals(_.omit(lastResult.json_query, "constraints"), datasetQuery)) { return { dashcard_id: dashcard.id, card_id: card.id, result: lastResult }; } } if (clear) { // clears the card data to indicate the card is reloading dispatch(clearCardData(card.id, dashcard.id)); } let result = null; // start a timer that will fetch the expected card duration if the query takes too long let slowCardTimer = setTimeout(() => { if (result === null) { dispatch(fetchCardDuration(card, datasetQuery)); } }, DATASET_SLOW_TIMEOUT); // make the actual request if (isPublicLink) { result = await fetchDataOrError(PublicApi.dashboardCardQuery({ uuid: dashcard.dashboard_id, cardId: card.id, parameters: datasetQuery.parameters ? JSON.stringify(datasetQuery.parameters) : undefined })); } else { result = await fetchDataOrError(CardApi.query({cardId: card.id, parameters: datasetQuery.parameters})); } clearTimeout(slowCardTimer); return { dashcard_id: dashcard.id, card_id: card.id, result: result }; };