diff --git a/superset/assets/cypress/integration/dashboard/controls.js b/superset/assets/cypress/integration/dashboard/controls.js index fe5581590c..77974a0b8c 100644 --- a/superset/assets/cypress/integration/dashboard/controls.js +++ b/superset/assets/cypress/integration/dashboard/controls.js @@ -38,8 +38,8 @@ export default () => describe('top-level controls', () => { .forEach((slice) => { const sliceRequest = `getJson_${slice.slice_id}`; sliceRequests.push(`@${sliceRequest}`); - const formData = `{"slice_id":${slice.slice_id},"viz_type":"${slice.form_data.viz_type}"}`; - cy.route('GET', `/superset/explore_json/?form_data=${formData}`).as(sliceRequest); + const formData = `{"slice_id":${slice.slice_id}}`; + cy.route('POST', `/superset/explore_json/?form_data=${formData}`).as(sliceRequest); const forceRefresh = `postJson_${slice.slice_id}_force`; forceRefreshRequests.push(`@${forceRefresh}`); diff --git a/superset/assets/cypress/integration/dashboard/edit_mode.js b/superset/assets/cypress/integration/dashboard/edit_mode.js index 280b6aae41..79198e60af 100644 --- a/superset/assets/cypress/integration/dashboard/edit_mode.js +++ b/superset/assets/cypress/integration/dashboard/edit_mode.js @@ -28,9 +28,9 @@ export default () => describe('edit mode', () => { const bootstrapData = JSON.parse(data[0].dataset.bootstrap); const dashboard = bootstrapData.dashboard_data; const boxplotChartId = dashboard.slices.find(slice => (slice.form_data.viz_type === 'box_plot')).slice_id; - const formData = `{"slice_id":${boxplotChartId},"viz_type":"box_plot"}`; + const formData = `{"slice_id":${boxplotChartId}}`; const boxplotRequest = `/superset/explore_json/?form_data=${formData}`; - cy.route('GET', boxplotRequest).as('boxplotRequest'); + cy.route('POST', boxplotRequest).as('boxplotRequest'); }); cy.get('.dashboard-header').contains('Edit dashboard').click(); diff --git a/superset/assets/cypress/integration/dashboard/filter.js b/superset/assets/cypress/integration/dashboard/filter.js index f37c8c849e..97b40a4150 100644 --- a/superset/assets/cypress/integration/dashboard/filter.js +++ b/superset/assets/cypress/integration/dashboard/filter.js @@ -39,9 +39,9 @@ export default () => describe('dashboard filter', () => { it('should apply filter', () => { const aliases = []; - const formData = `{"slice_id":${filterId},"viz_type":"filter_box"}`; + const formData = `{"slice_id":${filterId}}`; const filterRoute = `/superset/explore_json/?form_data=${formData}`; - cy.route('GET', filterRoute).as('fetchFilter'); + cy.route('POST', filterRoute).as('fetchFilter'); cy.wait('@fetchFilter'); sliceIds .filter(id => (parseInt(id, 10) !== filterId)) diff --git a/superset/assets/cypress/integration/dashboard/load.js b/superset/assets/cypress/integration/dashboard/load.js index 79daa30422..c6427c7320 100644 --- a/superset/assets/cypress/integration/dashboard/load.js +++ b/superset/assets/cypress/integration/dashboard/load.js @@ -34,8 +34,8 @@ export default () => describe('load', () => { // 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},"viz_type":"${slice.form_data.viz_type}"}`; - cy.route('GET', `/superset/explore_json/?form_data=${formData}`).as(alias); + const formData = `{"slice_id":${slice.slice_id}}`; + cy.route('POST', `/superset/explore_json/?form_data=${formData}`).as(alias); aliases.push(`@${alias}`); }); }); diff --git a/superset/assets/cypress/integration/dashboard/save.js b/superset/assets/cypress/integration/dashboard/save.js index 1d26ac219a..772862d5b8 100644 --- a/superset/assets/cypress/integration/dashboard/save.js +++ b/superset/assets/cypress/integration/dashboard/save.js @@ -56,9 +56,9 @@ export default () => describe('save', () => { cy.wait('@copyRequest'); // should have box_plot chart - const formData = `{"slice_id":${boxplotChartId},"viz_type":"box_plot"}`; + const formData = `{"slice_id":${boxplotChartId}}`; const boxplotRequest = `/superset/explore_json/?form_data=${formData}`; - cy.route('GET', boxplotRequest).as('boxplotRequest'); + cy.route('POST', boxplotRequest).as('boxplotRequest'); cy.wait('@boxplotRequest'); cy.get('.grid-container .box_plot').should('be.exist'); diff --git a/superset/assets/src/chart/Chart.jsx b/superset/assets/src/chart/Chart.jsx index c0d391673f..cfc6ce8a97 100644 --- a/superset/assets/src/chart/Chart.jsx +++ b/superset/assets/src/chart/Chart.jsx @@ -20,6 +20,7 @@ import PropTypes from 'prop-types'; import React from 'react'; import { Alert } from 'react-bootstrap'; +import { isFeatureEnabled, FeatureFlag } from 'src/featureFlags'; import { Logger, LOG_ACTIONS_RENDER_CHART_CONTAINER } from '../logger/LogUtils'; import Loading from '../components/Loading'; import RefreshChartOverlay from '../components/RefreshChartOverlay'; @@ -70,7 +71,7 @@ class Chart extends React.PureComponent { } componentDidMount() { if (this.props.triggerQuery) { - if (this.props.chartId > 0) { + if (this.props.chartId > 0 && isFeatureEnabled(FeatureFlag.CLIENT_CACHE)) { // Load saved chart with a GET request this.props.actions.getSavedChart( this.props.formData, diff --git a/superset/assets/src/chart/chartAction.js b/superset/assets/src/chart/chartAction.js index 3909dadd85..dc9eb322d4 100644 --- a/superset/assets/src/chart/chartAction.js +++ b/superset/assets/src/chart/chartAction.js @@ -21,6 +21,7 @@ /* eslint no-param-reassign: ["error", { "props": false }] */ import { t } from '@superset-ui/translation'; import { SupersetClient } from '@superset-ui/connection'; +import { isFeatureEnabled, FeatureFlag } from 'src/featureFlags'; import { getExploreUrlAndPayload, getAnnotationJsonUrl } from '../explore/exploreUtils'; import { requiresQuery, ANNOTATION_SOURCE_TYPES } from '../modules/AnnotationTypes'; import { addDangerToast } from '../messageToasts/actions'; @@ -194,7 +195,9 @@ export function exploreJSON(formData, force = false, timeout = 60, key, method) }; } - const clientMethod = method === 'GET' ? SupersetClient.get : SupersetClient.post; + const clientMethod = method === 'GET' && isFeatureEnabled(FeatureFlag.CLIENT_CACHE) + ? SupersetClient.get + : SupersetClient.post; const queryPromise = clientMethod(querySettings) .then(({ json }) => { dispatch(logEvent(LOG_ACTIONS_LOAD_CHART, { diff --git a/superset/assets/src/featureFlags.ts b/superset/assets/src/featureFlags.ts index 54eee94829..8638a5471f 100644 --- a/superset/assets/src/featureFlags.ts +++ b/superset/assets/src/featureFlags.ts @@ -21,6 +21,7 @@ export enum FeatureFlag { SCOPED_FILTER = 'SCOPED_FILTER', OMNIBAR = 'OMNIBAR', + CLIENT_CACHE = 'CLIENT_CACHE', } export type FeatureFlagMap = { diff --git a/superset/config.py b/superset/config.py index b402fec9aa..df14b0f2c1 100644 --- a/superset/config.py +++ b/superset/config.py @@ -200,7 +200,10 @@ LANGUAGES = { # For example, DEFAULT_FEATURE_FLAGS = { 'FOO': True, 'BAR': False } here # and FEATURE_FLAGS = { 'BAR': True, 'BAZ': True } in superset_config.py # will result in combined feature flags of { 'FOO': True, 'BAR': True, 'BAZ': True } -DEFAULT_FEATURE_FLAGS = {} +DEFAULT_FEATURE_FLAGS = { + # Experimental feature introducing a client (browser) cache + 'CLIENT_CACHE': False, +} # A function that receives a dict of all feature flags # (DEFAULT_FEATURE_FLAGS merged with FEATURE_FLAGS)