You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by gr...@apache.org on 2020/03/09 02:51:31 UTC

[incubator-superset] branch master updated: [log] Add dashboard_id param to explore_json request (#9243)

This is an automated email from the ASF dual-hosted git repository.

graceguo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-superset.git


The following commit(s) were added to refs/heads/master by this push:
     new 8bc30da  [log] Add dashboard_id param to explore_json request (#9243)
8bc30da is described below

commit 8bc30da6211df67ee8bec21e160ce587817ba85b
Author: Grace Guo <gr...@airbnb.com>
AuthorDate: Sun Mar 8 19:51:08 2020 -0700

    [log] Add dashboard_id param to explore_json request (#9243)
    
    * [log] Add dashboard_id param to explore_json request
    
    * fix cypress test
---
 .../cypress/integration/dashboard/edit_mode.js     |  3 +-
 .../cypress/integration/dashboard/filter.js        |  6 ++--
 .../cypress/integration/dashboard/load.js          |  8 ++++--
 .../cypress/integration/dashboard/save.js          |  4 +--
 .../cypress/integration/dashboard/tabs.js          | 10 ++++---
 .../cypress/integration/dashboard/url_params.js    |  4 ++-
 superset-frontend/src/chart/Chart.jsx              |  5 ++++
 superset-frontend/src/chart/chartAction.js         | 32 ++++++++++++++++++----
 .../src/dashboard/actions/dashboardState.js        | 16 +++++++++--
 .../src/dashboard/components/Header.jsx            | 15 ++++++++--
 .../src/dashboard/components/SliceHeader.jsx       |  3 ++
 .../dashboard/components/SliceHeaderControls.jsx   |  6 +++-
 .../dashboard/components/gridComponents/Chart.jsx  | 10 ++++++-
 .../components/gridComponents/ChartHolder.jsx      |  3 ++
 .../dashboard/containers/DashboardComponent.jsx    |  4 ++-
 15 files changed, 101 insertions(+), 28 deletions(-)

diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/edit_mode.js b/superset-frontend/cypress-base/cypress/integration/dashboard/edit_mode.js
index c279cc5..913609c 100644
--- a/superset-frontend/cypress-base/cypress/integration/dashboard/edit_mode.js
+++ b/superset-frontend/cypress-base/cypress/integration/dashboard/edit_mode.js
@@ -28,11 +28,12 @@ export default () =>
       cy.get('#app').then(data => {
         const bootstrapData = JSON.parse(data[0].dataset.bootstrap);
         const dashboard = bootstrapData.dashboard_data;
+        const dashboardId = dashboard.id;
         const boxplotChartId = dashboard.slices.find(
           slice => slice.form_data.viz_type === 'box_plot',
         ).slice_id;
         const formData = `{"slice_id":${boxplotChartId}}`;
-        const boxplotRequest = `/superset/explore_json/?form_data=${formData}`;
+        const boxplotRequest = `/superset/explore_json/?form_data=${formData}&dashboard_id=${dashboardId}`;
         cy.route('POST', boxplotRequest).as('boxplotRequest');
       });
 
diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/filter.js b/superset-frontend/cypress-base/cypress/integration/dashboard/filter.js
index 6da7de2..c219796 100644
--- a/superset-frontend/cypress-base/cypress/integration/dashboard/filter.js
+++ b/superset-frontend/cypress-base/cypress/integration/dashboard/filter.js
@@ -22,6 +22,7 @@ export default () =>
   describe('dashboard filter', () => {
     let sliceIds = [];
     let filterId;
+    let dashboardId;
 
     beforeEach(() => {
       cy.server();
@@ -32,6 +33,7 @@ export default () =>
       cy.get('#app').then(data => {
         const bootstrapData = JSON.parse(data[0].dataset.bootstrap);
         const dashboard = bootstrapData.dashboard_data;
+        dashboardId = dashboard.id;
         sliceIds = dashboard.slices.map(slice => slice.slice_id);
         filterId = dashboard.slices.find(
           slice => slice.form_data.viz_type === 'filter_box',
@@ -43,7 +45,7 @@ export default () =>
       const aliases = [];
 
       const formData = `{"slice_id":${filterId}}`;
-      const filterRoute = `/superset/explore_json/?form_data=${formData}`;
+      const filterRoute = `/superset/explore_json/?form_data=${formData}&dashboard_id=${dashboardId}`;
       cy.route('POST', filterRoute).as('fetchFilter');
       cy.wait('@fetchFilter');
       sliceIds
@@ -54,7 +56,7 @@ export default () =>
 
           cy.route(
             'POST',
-            `/superset/explore_json/?form_data={"slice_id":${id}}`,
+            `/superset/explore_json/?form_data={"slice_id":${id}}&dashboard_id=${dashboardId}`,
           ).as(alias);
         });
 
diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/load.js b/superset-frontend/cypress-base/cypress/integration/dashboard/load.js
index 6050cbf..5cb64fe 100644
--- a/superset-frontend/cypress-base/cypress/integration/dashboard/load.js
+++ b/superset-frontend/cypress-base/cypress/integration/dashboard/load.js
@@ -31,14 +31,16 @@ export default () =>
 
       cy.get('#app').then(data => {
         const bootstrapData = JSON.parse(data[0].dataset.bootstrap);
+        const dashboardId = bootstrapData.dashboard_data.id;
         const slices = bootstrapData.dashboard_data.slices;
         // then define routes and create alias for each requests
         slices.forEach(slice => {
           const alias = `getJson_${slice.slice_id}`;
           const formData = `{"slice_id":${slice.slice_id}}`;
-          cy.route('POST', `/superset/explore_json/?form_data=${formData}`).as(
-            alias,
-          );
+          cy.route(
+            'POST',
+            `/superset/explore_json/?form_data=${formData}&dashboard_id=${dashboardId}`,
+          ).as(alias);
           aliases.push(`@${alias}`);
         });
       });
diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/save.js b/superset-frontend/cypress-base/cypress/integration/dashboard/save.js
index 263fd8a..03dec46 100644
--- a/superset-frontend/cypress-base/cypress/integration/dashboard/save.js
+++ b/superset-frontend/cypress-base/cypress/integration/dashboard/save.js
@@ -60,11 +60,9 @@ export default () =>
     });
 
     it('should save/overwrite dashboard', () => {
-      cy.wait('@copyRequest');
-
       // should have box_plot chart
       const formData = `{"slice_id":${boxplotChartId}}`;
-      const boxplotRequest = `/superset/explore_json/?form_data=${formData}`;
+      const boxplotRequest = `/superset/explore_json/?form_data=${formData}&dashboard_id=${dashboardId}`;
       cy.route('POST', boxplotRequest).as('boxplotRequest');
       cy.wait('@boxplotRequest');
       cy.get('.grid-container .box_plot').should('be.exist');
diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/tabs.js b/superset-frontend/cypress-base/cypress/integration/dashboard/tabs.js
index 4a86d3c..51dfa54 100644
--- a/superset-frontend/cypress-base/cypress/integration/dashboard/tabs.js
+++ b/superset-frontend/cypress-base/cypress/integration/dashboard/tabs.js
@@ -24,6 +24,7 @@ export default () =>
     let treemapId;
     let linechartId;
     let boxplotId;
+    let dashboardId;
 
     // cypress can not handle window.scrollTo
     // https://github.com/cypress-io/cypress/issues/2761
@@ -43,6 +44,7 @@ export default () =>
       cy.get('#app').then(data => {
         const bootstrapData = JSON.parse(data[0].dataset.bootstrap);
         const dashboard = bootstrapData.dashboard_data;
+        dashboardId = dashboard.id;
         filterId = dashboard.slices.find(
           slice => slice.form_data.viz_type === 'filter_box',
         ).slice_id;
@@ -61,7 +63,7 @@ export default () =>
         };
         const filterRequest = `/superset/explore_json/?form_data=${JSON.stringify(
           filterFormdata,
-        )}`;
+        )}&dashboard_id=${dashboardId}`;
         cy.route('POST', filterRequest).as('filterRequest');
 
         const treemapFormdata = {
@@ -69,7 +71,7 @@ export default () =>
         };
         const treemapRequest = `/superset/explore_json/?form_data=${JSON.stringify(
           treemapFormdata,
-        )}`;
+        )}&dashboard_id=${dashboardId}`;
         cy.route('POST', treemapRequest).as('treemapRequest');
 
         const linechartFormdata = {
@@ -77,7 +79,7 @@ export default () =>
         };
         const linechartRequest = `/superset/explore_json/?form_data=${JSON.stringify(
           linechartFormdata,
-        )}`;
+        )}&dashboard_id=${dashboardId}`;
         cy.route('POST', linechartRequest).as('linechartRequest');
 
         const boxplotFormdata = {
@@ -85,7 +87,7 @@ export default () =>
         };
         const boxplotRequest = `/superset/explore_json/?form_data=${JSON.stringify(
           boxplotFormdata,
-        )}`;
+        )}&dashboard_id=${dashboardId}`;
         cy.route('POST', boxplotRequest).as('boxplotRequest');
       });
     });
diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/url_params.js b/superset-frontend/cypress-base/cypress/integration/dashboard/url_params.js
index d7f983e..54b74a6 100644
--- a/superset-frontend/cypress-base/cypress/integration/dashboard/url_params.js
+++ b/superset-frontend/cypress-base/cypress/integration/dashboard/url_params.js
@@ -22,6 +22,7 @@ export default () =>
   describe('dashboard url params', () => {
     const urlParams = { param1: '123', param2: 'abc' };
     let sliceIds = [];
+    let dashboardId;
 
     beforeEach(() => {
       cy.server();
@@ -32,6 +33,7 @@ export default () =>
       cy.get('#app').then(data => {
         const bootstrapData = JSON.parse(data[0].dataset.bootstrap);
         const dashboard = bootstrapData.dashboard_data;
+        dashboardId = dashboard.id;
         sliceIds = dashboard.slices.map(slice => slice.slice_id);
       });
     });
@@ -43,7 +45,7 @@ export default () =>
         aliases.push(`@${alias}`);
         cy.route(
           'POST',
-          `/superset/explore_json/?form_data={"slice_id":${id}}`,
+          `/superset/explore_json/?form_data={"slice_id":${id}}&dashboard_id=${dashboardId}`,
         ).as(alias);
       });
 
diff --git a/superset-frontend/src/chart/Chart.jsx b/superset-frontend/src/chart/Chart.jsx
index 7a4679c..227b7af 100644
--- a/superset-frontend/src/chart/Chart.jsx
+++ b/superset-frontend/src/chart/Chart.jsx
@@ -34,6 +34,8 @@ const propTypes = {
   actions: PropTypes.object,
   chartId: PropTypes.number.isRequired,
   datasource: PropTypes.object.isRequired,
+  // current chart is included by dashboard
+  dashboardId: PropTypes.number,
   // original selected values for FilterBox viz
   // so that FilterBox can pre-populate selected values
   // only affect UI control
@@ -71,6 +73,7 @@ const defaultProps = {
   initialValues: BLANK,
   setControlValue() {},
   triggerRender: false,
+  dashboardId: null,
 };
 
 class Chart extends React.PureComponent {
@@ -101,6 +104,7 @@ class Chart extends React.PureComponent {
         false,
         this.props.timeout,
         this.props.chartId,
+        this.props.dashboardId,
       );
     } else {
       // Create chart with POST request
@@ -109,6 +113,7 @@ class Chart extends React.PureComponent {
         false,
         this.props.timeout,
         this.props.chartId,
+        this.props.dashboardId,
       );
     }
   }
diff --git a/superset-frontend/src/chart/chartAction.js b/superset-frontend/src/chart/chartAction.js
index 657d0be..c7a125f 100644
--- a/superset-frontend/src/chart/chartAction.js
+++ b/superset-frontend/src/chart/chartAction.js
@@ -207,6 +207,7 @@ export function exploreJSON(
   timeout = 60,
   key,
   method,
+  dashboardId,
 ) {
   return dispatch => {
     const { url, payload } = getExploreUrlAndPayload({
@@ -215,6 +216,7 @@ export function exploreJSON(
       force,
       allowDomainSharding,
       method,
+      requestParams: dashboardId ? { dashboard_id: dashboardId } : {},
     });
     const logStart = Logger.getTimestamp();
     const controller = new AbortController();
@@ -308,7 +310,13 @@ export function exploreJSON(
 }
 
 export const GET_SAVED_CHART = 'GET_SAVED_CHART';
-export function getSavedChart(formData, force = false, timeout = 60, key) {
+export function getSavedChart(
+  formData,
+  force = false,
+  timeout = 60,
+  key,
+  dashboardId,
+) {
   /*
    * Perform a GET request to `/explore_json`.
    *
@@ -319,18 +327,24 @@ export function getSavedChart(formData, force = false, timeout = 60, key) {
    *  GET  /explore_json?{"chart_id":1,"extra_filters":"..."}
    *
    */
-  return exploreJSON(formData, force, timeout, key, 'GET');
+  return exploreJSON(formData, force, timeout, key, 'GET', dashboardId);
 }
 
 export const POST_CHART_FORM_DATA = 'POST_CHART_FORM_DATA';
-export function postChartFormData(formData, force = false, timeout = 60, key) {
+export function postChartFormData(
+  formData,
+  force = false,
+  timeout = 60,
+  key,
+  dashboardId,
+) {
   /*
    * Perform a POST request to `/explore_json`.
    *
    * This will post the form data to the endpoint, returning a new chart.
    *
    */
-  return exploreJSON(formData, force, timeout, key, 'POST');
+  return exploreJSON(formData, force, timeout, key, 'POST', dashboardId);
 }
 
 export function redirectSQLLab(formData) {
@@ -359,7 +373,7 @@ export function redirectSQLLab(formData) {
   };
 }
 
-export function refreshChart(chartKey, force) {
+export function refreshChart(chartKey, force, dashboardId) {
   return (dispatch, getState) => {
     const chart = (getState().charts || {})[chartKey];
     const timeout = getState().dashboardInfo.common.conf
@@ -372,7 +386,13 @@ export function refreshChart(chartKey, force) {
       return;
     }
     dispatch(
-      postChartFormData(chart.latestQueryFormData, force, timeout, chart.id),
+      postChartFormData(
+        chart.latestQueryFormData,
+        force,
+        timeout,
+        chart.id,
+        dashboardId,
+      ),
     );
   };
 }
diff --git a/superset-frontend/src/dashboard/actions/dashboardState.js b/superset-frontend/src/dashboard/actions/dashboardState.js
index 20bb35d..33737f8 100644
--- a/superset-frontend/src/dashboard/actions/dashboardState.js
+++ b/superset-frontend/src/dashboard/actions/dashboardState.js
@@ -218,10 +218,17 @@ export function saveDashboardRequest(data, id, saveType) {
   };
 }
 
-export function fetchCharts(chartList = [], force = false, interval = 0) {
+export function fetchCharts(
+  chartList = [],
+  force = false,
+  interval = 0,
+  dashboardId,
+) {
   return (dispatch, getState) => {
     if (!interval) {
-      chartList.forEach(chartKey => dispatch(refreshChart(chartKey, force)));
+      chartList.forEach(chartKey =>
+        dispatch(refreshChart(chartKey, force, dashboardId)),
+      );
       return;
     }
 
@@ -237,7 +244,10 @@ export function fetchCharts(chartList = [], force = false, interval = 0) {
       ? refreshTime / (chartList.length - 1)
       : 0;
     chartList.forEach((chartKey, i) => {
-      setTimeout(() => dispatch(refreshChart(chartKey, force)), delay * i);
+      setTimeout(
+        () => dispatch(refreshChart(chartKey, force, dashboardId)),
+        delay * i,
+      );
     });
   };
 }
diff --git a/superset-frontend/src/dashboard/components/Header.jsx b/superset-frontend/src/dashboard/components/Header.jsx
index 4c8d014..c889d06 100644
--- a/superset-frontend/src/dashboard/components/Header.jsx
+++ b/superset-frontend/src/dashboard/components/Header.jsx
@@ -194,7 +194,13 @@ class Header extends React.PureComponent {
         interval: 0,
         chartCount: chartList.length,
       });
-      return this.props.fetchCharts(chartList, true);
+
+      return this.props.fetchCharts(
+        chartList,
+        true,
+        0,
+        this.props.dashboardInfo.id,
+      );
     }
     return false;
   }
@@ -212,7 +218,12 @@ class Header extends React.PureComponent {
         interval,
         chartCount: affectedCharts.length,
       });
-      return fetchCharts(affectedCharts, true, interval * 0.2);
+      return fetchCharts(
+        affectedCharts,
+        true,
+        interval * 0.2,
+        dashboardInfo.id,
+      );
     };
 
     this.refreshTimer = setPeriodicRunner({
diff --git a/superset-frontend/src/dashboard/components/SliceHeader.jsx b/superset-frontend/src/dashboard/components/SliceHeader.jsx
index 3d36a51..a1fb9f3 100644
--- a/superset-frontend/src/dashboard/components/SliceHeader.jsx
+++ b/superset-frontend/src/dashboard/components/SliceHeader.jsx
@@ -44,6 +44,7 @@ const propTypes = {
   supersetCanCSV: PropTypes.bool,
   sliceCanEdit: PropTypes.bool,
   componentId: PropTypes.string.isRequired,
+  dashboardId: PropTypes.number.isRequired,
   filters: PropTypes.object.isRequired,
   addDangerToast: PropTypes.func.isRequired,
 };
@@ -94,6 +95,7 @@ class SliceHeader extends React.PureComponent {
       annotationQuery,
       annotationError,
       componentId,
+      dashboardId,
       addDangerToast,
     } = this.props;
 
@@ -145,6 +147,7 @@ class SliceHeader extends React.PureComponent {
               supersetCanCSV={supersetCanCSV}
               sliceCanEdit={sliceCanEdit}
               componentId={componentId}
+              dashboardId={dashboardId}
               addDangerToast={addDangerToast}
             />
           )}
diff --git a/superset-frontend/src/dashboard/components/SliceHeaderControls.jsx b/superset-frontend/src/dashboard/components/SliceHeaderControls.jsx
index 779609d..6bd5061 100644
--- a/superset-frontend/src/dashboard/components/SliceHeaderControls.jsx
+++ b/superset-frontend/src/dashboard/components/SliceHeaderControls.jsx
@@ -28,6 +28,7 @@ import { getActiveFilters } from '../util/activeDashboardFilters';
 const propTypes = {
   slice: PropTypes.object.isRequired,
   componentId: PropTypes.string.isRequired,
+  dashboardId: PropTypes.number.isRequired,
   addDangerToast: PropTypes.func.isRequired,
   isCached: PropTypes.bool,
   isExpanded: PropTypes.bool,
@@ -91,7 +92,10 @@ class SliceHeaderControls extends React.PureComponent {
 
   refreshChart() {
     if (this.props.updatedDttm) {
-      this.props.forceRefresh(this.props.slice.slice_id);
+      this.props.forceRefresh(
+        this.props.slice.slice_id,
+        this.props.dashboardId,
+      );
     }
   }
 
diff --git a/superset-frontend/src/dashboard/components/gridComponents/Chart.jsx b/superset-frontend/src/dashboard/components/gridComponents/Chart.jsx
index 02932ca..b399528 100644
--- a/superset-frontend/src/dashboard/components/gridComponents/Chart.jsx
+++ b/superset-frontend/src/dashboard/components/gridComponents/Chart.jsx
@@ -36,6 +36,7 @@ import getFilterValuesByFilterId from '../../util/getFilterValuesByFilterId';
 const propTypes = {
   id: PropTypes.number.isRequired,
   componentId: PropTypes.string.isRequired,
+  dashboardId: PropTypes.number.isRequired,
   width: PropTypes.number.isRequired,
   height: PropTypes.number.isRequired,
   updateSliceName: PropTypes.func.isRequired,
@@ -205,13 +206,18 @@ class Chart extends React.Component {
       slice_id: this.props.slice.slice_id,
       is_cached: this.props.isCached,
     });
-    return this.props.refreshChart(this.props.chart.id, true);
+    return this.props.refreshChart(
+      this.props.chart.id,
+      true,
+      this.props.dashboardId,
+    );
   }
 
   render() {
     const {
       id,
       componentId,
+      dashboardId,
       chart,
       slice,
       datasource,
@@ -269,6 +275,7 @@ class Chart extends React.Component {
           supersetCanCSV={supersetCanCSV}
           sliceCanEdit={sliceCanEdit}
           componentId={componentId}
+          dashboardId={dashboardId}
           filters={filters}
           addDangerToast={addDangerToast}
         />
@@ -306,6 +313,7 @@ class Chart extends React.Component {
             chartId={id}
             chartStatus={chart.chartStatus}
             datasource={datasource}
+            dashboardId={dashboardId}
             initialValues={initialValues}
             formData={formData}
             queryResponse={chart.queryResponse}
diff --git a/superset-frontend/src/dashboard/components/gridComponents/ChartHolder.jsx b/superset-frontend/src/dashboard/components/gridComponents/ChartHolder.jsx
index a3cf5c1..85d5fdf 100644
--- a/superset-frontend/src/dashboard/components/gridComponents/ChartHolder.jsx
+++ b/superset-frontend/src/dashboard/components/gridComponents/ChartHolder.jsx
@@ -42,6 +42,7 @@ const CHART_MARGIN = 32;
 const propTypes = {
   id: PropTypes.string.isRequired,
   parentId: PropTypes.string.isRequired,
+  dashboardId: PropTypes.number.isRequired,
   component: componentShape.isRequired,
   parentComponent: componentShape.isRequired,
   index: PropTypes.number.isRequired,
@@ -175,6 +176,7 @@ class ChartHolder extends React.Component {
       handleComponentDrop,
       editMode,
       isComponentVisible,
+      dashboardId,
     } = this.props;
 
     // inherit the size of parent columns
@@ -228,6 +230,7 @@ class ChartHolder extends React.Component {
               <Chart
                 componentId={component.id}
                 id={component.meta.chartId}
+                dashboardId={dashboardId}
                 width={Math.floor(
                   widthMultiple * columnWidth +
                     (widthMultiple - 1) * GRID_GUTTER_SIZE -
diff --git a/superset-frontend/src/dashboard/containers/DashboardComponent.jsx b/superset-frontend/src/dashboard/containers/DashboardComponent.jsx
index d1e2b8d..dd2c188 100644
--- a/superset-frontend/src/dashboard/containers/DashboardComponent.jsx
+++ b/superset-frontend/src/dashboard/containers/DashboardComponent.jsx
@@ -46,6 +46,7 @@ const propTypes = {
   logEvent: PropTypes.func.isRequired,
   directPathToChild: PropTypes.arrayOf(PropTypes.string),
   directPathLastUpdated: PropTypes.number,
+  dashboardId: PropTypes.number.isRequired,
 };
 
 const defaultProps = {
@@ -55,7 +56,7 @@ const defaultProps = {
 };
 
 function mapStateToProps(
-  { dashboardLayout: undoableLayout, dashboardState },
+  { dashboardLayout: undoableLayout, dashboardState, dashboardInfo },
   ownProps,
 ) {
   const dashboardLayout = undoableLayout.present;
@@ -68,6 +69,7 @@ function mapStateToProps(
     filters: getActiveFilters(),
     directPathToChild: dashboardState.directPathToChild,
     directPathLastUpdated: dashboardState.directPathLastUpdated,
+    dashboardId: dashboardInfo.id,
     filterFieldOnFocus:
       dashboardState.focusedFilterField.length === 0
         ? {}