You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by yo...@apache.org on 2022/06/05 13:05:22 UTC
[superset] branch master updated: feat: standardized form_data (#20010)
This is an automated email from the ASF dual-hosted git repository.
yongjiezhao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/superset.git
The following commit(s) were added to refs/heads/master by this push:
new dd4b581fb5 feat: standardized form_data (#20010)
dd4b581fb5 is described below
commit dd4b581fb55d920fc3b709fc044cea5339802ee2
Author: Yongjie Zhao <yo...@gmail.com>
AuthorDate: Sun Jun 5 21:05:01 2022 +0800
feat: standardized form_data (#20010)
---
.../superset-ui-chart-controls/src/types.ts | 17 ++
.../src/BigNumber/BigNumberTotal/controlPanel.ts | 4 +
.../BigNumberWithTrendline/controlPanel.tsx | 4 +
.../plugin-chart-echarts/src/Pie/controlPanel.tsx | 5 +
.../src/Timeseries/Regular/controlPanel.tsx | 4 +
.../src/plugin/controlPanel.tsx | 12 +
.../plugin-chart-table/src/controlPanel.tsx | 5 +
.../src/explore/controlUtils/index.ts | 1 +
.../controlUtils/standardizedFormData.test.tsx | 307 +++++++++++++++++++++
.../explore/controlUtils/standardizedFormData.ts | 182 ++++++++++++
.../src/explore/reducers/exploreReducer.js | 28 +-
11 files changed, 554 insertions(+), 15 deletions(-)
diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/types.ts b/superset-frontend/packages/superset-ui-chart-controls/src/types.ts
index 53e3a198bd..7926ffd759 100644
--- a/superset-frontend/packages/superset-ui-chart-controls/src/types.ts
+++ b/superset-frontend/packages/superset-ui-chart-controls/src/types.ts
@@ -25,6 +25,8 @@ import type {
JsonValue,
Metric,
QueryFormData,
+ QueryFormMetric,
+ QueryFormColumn,
} from '@superset-ui/core';
import { sharedControls } from './shared-controls';
import sharedControlComponents from './shared-controls/components';
@@ -340,11 +342,26 @@ export interface ControlPanelSectionConfig {
controlSetRows: ControlSetRow[];
}
+export interface StandardizedState {
+ metrics: QueryFormMetric[];
+ columns: QueryFormColumn[];
+}
+
+export interface StandardizedFormDataInterface {
+ standardizedState: StandardizedState;
+ memorizedFormData: Map<string, QueryFormData>;
+}
+
export interface ControlPanelConfig {
controlPanelSections: (ControlPanelSectionConfig | null)[];
controlOverrides?: ControlOverrides;
sectionOverrides?: SectionOverrides;
onInit?: (state: ControlStateMapping) => void;
+ denormalizeFormData?: (
+ formData: QueryFormData & {
+ standardizedFormData: StandardizedFormDataInterface;
+ },
+ ) => QueryFormData;
}
export type ControlOverrides = {
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/controlPanel.ts b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/controlPanel.ts
index 8511c3ca56..c715c8f232 100644
--- a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/controlPanel.ts
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberTotal/controlPanel.ts
@@ -96,4 +96,8 @@ export default {
label: t('Number format'),
},
},
+ denormalizeFormData: formData => ({
+ ...formData,
+ metric: formData.standardizedFormData.standardizedState.metrics[0],
+ }),
} as ControlPanelConfig;
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx
index 3ba00f55ea..c61ec6d046 100644
--- a/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberWithTrendline/controlPanel.tsx
@@ -270,6 +270,10 @@ const config: ControlPanelConfig = {
label: t('Number format'),
},
},
+ denormalizeFormData: formData => ({
+ ...formData,
+ metric: formData.standardizedFormData.standardizedState.metrics[0],
+ }),
};
export default config;
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx
index 9056446f9f..6e3a1ba593 100644
--- a/superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx
@@ -253,6 +253,11 @@ const config: ControlPanelConfig = {
default: 100,
},
},
+ denormalizeFormData: formData => ({
+ ...formData,
+ metric: formData.standardizedFormData.standardizedState.metrics[0],
+ groupby: formData.standardizedFormData.standardizedState.columns,
+ }),
};
export default config;
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx
index f234df0c82..eaf3cb2615 100644
--- a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/Regular/controlPanel.tsx
@@ -240,6 +240,10 @@ const config: ControlPanelConfig = {
default: rowLimit,
},
},
+ denormalizeFormData: formData => ({
+ ...formData,
+ metrics: formData.standardizedFormData.standardizedState.metrics,
+ }),
};
export default config;
diff --git a/superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx b/superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx
index 99efb8bbcc..acbdb04bc7 100644
--- a/superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx
+++ b/superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx
@@ -18,6 +18,7 @@
*/
import React from 'react';
import {
+ ensureIsArray,
QueryFormMetric,
smartDateFormatter,
t,
@@ -367,6 +368,17 @@ const config: ControlPanelConfig = {
],
},
],
+ denormalizeFormData: formData => {
+ const groupbyColumns =
+ formData.standardizedFormData.standardizedState.columns.filter(
+ col => !ensureIsArray(formData.groupbyRows).includes(col),
+ );
+ return {
+ ...formData,
+ metrics: formData.standardizedFormData.standardizedState.metrics,
+ groupbyColumns,
+ };
+ },
};
export default config;
diff --git a/superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx b/superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx
index bb855bd7cc..4f5530f6b9 100644
--- a/superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx
+++ b/superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx
@@ -531,6 +531,11 @@ const config: ControlPanelConfig = {
],
},
],
+ denormalizeFormData: formData => ({
+ ...formData,
+ metrics: formData.standardizedFormData.standardizedState.metrics,
+ groupby: formData.standardizedFormData.standardizedState.columns,
+ }),
};
export default config;
diff --git a/superset-frontend/src/explore/controlUtils/index.ts b/superset-frontend/src/explore/controlUtils/index.ts
index d9cb1132f4..b39233422b 100644
--- a/superset-frontend/src/explore/controlUtils/index.ts
+++ b/superset-frontend/src/explore/controlUtils/index.ts
@@ -21,3 +21,4 @@ export * from './getControlConfig';
export * from './getControlState';
export * from './getFormDataFromControls';
export * from './getControlValuesCompatibleWithDatasource';
+export * from './standardizedFormData';
diff --git a/superset-frontend/src/explore/controlUtils/standardizedFormData.test.tsx b/superset-frontend/src/explore/controlUtils/standardizedFormData.test.tsx
new file mode 100644
index 0000000000..e048c04498
--- /dev/null
+++ b/superset-frontend/src/explore/controlUtils/standardizedFormData.test.tsx
@@ -0,0 +1,307 @@
+/**
+ * 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.
+ */
+import { getChartControlPanelRegistry, QueryFormData } from '@superset-ui/core';
+import TableChartPlugin from '@superset-ui/plugin-chart-table';
+import { BigNumberTotalChartPlugin } from '@superset-ui/plugin-chart-echarts';
+import { sections } from '@superset-ui/chart-controls';
+import {
+ StandardizedFormData,
+ sharedControls,
+ publicControls,
+} from './standardizedFormData';
+import { xAxisControl } from '../../../plugins/plugin-chart-echarts/src/controls';
+
+describe('should collect control values and create SFD', () => {
+ const sharedControlsFormData = {};
+ Object.entries(sharedControls).forEach(([, names]) => {
+ names.forEach(name => {
+ sharedControlsFormData[name] = name;
+ });
+ });
+ const publicControlsFormData = Object.fromEntries(
+ publicControls.map((name, idx) => [[name], idx]),
+ );
+ const sourceMockFormData: QueryFormData = {
+ ...sharedControlsFormData,
+ ...publicControlsFormData,
+ datasource: '100__table',
+ viz_type: 'source_viz',
+ };
+ const sourceMockStore = {
+ form_data: sourceMockFormData,
+ controls: Object.fromEntries(
+ Object.entries(sourceMockFormData).map(([key, value]) => [
+ key,
+ { value },
+ ]),
+ ),
+ datasource: {
+ type: 'table',
+ columns: [],
+ },
+ };
+ beforeAll(() => {
+ getChartControlPanelRegistry().registerValue('source_viz', {
+ controlPanelSections: [
+ sections.advancedAnalyticsControls,
+ {
+ label: 'transform controls',
+ controlSetRows: publicControls.map(control => [control]),
+ },
+ {
+ label: 'axis column',
+ controlSetRows: [[xAxisControl]],
+ },
+ ],
+ });
+ getChartControlPanelRegistry().registerValue('target_viz', {
+ controlPanelSections: [
+ sections.advancedAnalyticsControls,
+ {
+ label: 'transform controls',
+ controlSetRows: publicControls.map(control => [control]),
+ },
+ {
+ label: 'axis column',
+ controlSetRows: [[xAxisControl]],
+ },
+ ],
+ denormalizeFormData: (formData: QueryFormData) => ({
+ ...formData,
+ columns: formData.standardizedFormData.standardizedState.columns,
+ metrics: formData.standardizedFormData.standardizedState.metrics,
+ }),
+ });
+ });
+
+ test('collect sharedControls', () => {
+ const sfd = new StandardizedFormData(sourceMockFormData);
+
+ expect(sfd.dumpSFD().standardizedState.metrics).toEqual(
+ sharedControls.metrics.map(controlName => controlName),
+ );
+ expect(sfd.dumpSFD().standardizedState.columns).toEqual(
+ sharedControls.columns.map(controlName => controlName),
+ );
+ });
+
+ test('should transform all publicControls', () => {
+ const sfd = new StandardizedFormData(sourceMockFormData);
+ const { formData } = sfd.transform('target_viz', sourceMockStore);
+ Object.entries(publicControlsFormData).forEach(([key]) => {
+ expect(formData).toHaveProperty(key);
+ });
+ Object.entries(sharedControls).forEach(([key, value]) => {
+ expect(formData[key]).toEqual(value);
+ });
+ });
+
+ test('should inherit standardizedFormData and memorizedFormData is LIFO', () => {
+ // from source_viz to target_viz
+ const sfd = new StandardizedFormData(sourceMockFormData);
+ const { formData, controlsState } = sfd.transform(
+ 'target_viz',
+ sourceMockStore,
+ );
+ expect(
+ formData.standardizedFormData.memorizedFormData.map(
+ (fd: [string, QueryFormData]) => fd[0],
+ ),
+ ).toEqual(['source_viz']);
+
+ // from target_viz to source_viz
+ const sfd2 = new StandardizedFormData(formData);
+ const { formData: fd2, controlsState: cs2 } = sfd2.transform('source_viz', {
+ ...sourceMockStore,
+ form_data: formData,
+ controls: controlsState,
+ });
+ expect(
+ fd2.standardizedFormData.memorizedFormData.map(
+ (fd: [string, QueryFormData]) => fd[0],
+ ),
+ ).toEqual(['source_viz', 'target_viz']);
+
+ // from source_viz to target_viz
+ const sfd3 = new StandardizedFormData(fd2);
+ const { formData: fd3 } = sfd3.transform('target_viz', {
+ ...sourceMockStore,
+ form_data: fd2,
+ controls: cs2,
+ });
+ expect(
+ fd3.standardizedFormData.memorizedFormData.map(
+ (fd: [string, QueryFormData]) => fd[0],
+ ),
+ ).toEqual(['target_viz', 'source_viz']);
+ });
+});
+
+describe('should transform form_data between table and bigNumberTotal', () => {
+ const tableVizFormData = {
+ datasource: '30__table',
+ viz_type: 'table',
+ time_grain_sqla: 'P1D',
+ time_range: 'No filter',
+ query_mode: 'aggregate',
+ groupby: ['name'],
+ metrics: ['count'],
+ all_columns: [],
+ percent_metrics: [],
+ adhoc_filters: [],
+ order_by_cols: [],
+ row_limit: 10000,
+ server_page_length: 10,
+ order_desc: true,
+ table_timestamp_format: 'smart_date',
+ show_cell_bars: true,
+ color_pn: true,
+ applied_time_extras: {},
+ url_params: {
+ form_data_key:
+ 'p3No_sqDW7k-kMTzlBPAPd9vwp1IXTf6stbyzjlrPPa0ninvdYUUiMC6F1iKit3Y',
+ dataset_id: '30',
+ },
+ };
+ const tableVizStore = {
+ form_data: tableVizFormData,
+ controls: {
+ datasource: {
+ value: '30__table',
+ },
+ viz_type: {
+ value: 'table',
+ },
+ slice_id: {},
+ cache_timeout: {},
+ url_params: {
+ value: {
+ form_data_key:
+ 'p3No_sqDW7k-kMTzlBPAPd9vwp1IXTf6stbyzjlrPPa0ninvdYUUiMC6F1iKit3Y',
+ dataset_id: '30',
+ },
+ },
+ granularity_sqla: {},
+ time_grain_sqla: {
+ value: 'P1D',
+ },
+ time_range: {
+ value: 'No filter',
+ },
+ query_mode: {
+ value: 'aggregate',
+ },
+ groupby: {
+ value: ['name'],
+ },
+ metrics: {
+ value: ['count'],
+ },
+ all_columns: {
+ value: [],
+ },
+ percent_metrics: {
+ value: [],
+ },
+ adhoc_filters: {
+ value: [],
+ },
+ timeseries_limit_metric: {},
+ order_by_cols: {
+ value: [],
+ },
+ server_pagination: {},
+ row_limit: {
+ value: 10000,
+ },
+ server_page_length: {
+ value: 10,
+ },
+ include_time: {},
+ order_desc: {
+ value: true,
+ },
+ show_totals: {},
+ emit_filter: {},
+ table_timestamp_format: {
+ value: 'smart_date',
+ },
+ page_length: {},
+ include_search: {},
+ show_cell_bars: {
+ value: true,
+ },
+ align_pn: {},
+ color_pn: {
+ value: true,
+ },
+ column_config: {},
+ conditional_formatting: {},
+ },
+ datasource: {
+ type: 'table',
+ columns: [],
+ },
+ };
+
+ beforeAll(() => {
+ getChartControlPanelRegistry().registerValue(
+ 'big_number_total',
+ new BigNumberTotalChartPlugin().controlPanel,
+ );
+ getChartControlPanelRegistry().registerValue(
+ 'table',
+ new TableChartPlugin().controlPanel,
+ );
+ });
+
+ test('transform', () => {
+ // table -> bigNumberTotal
+ const sfd = new StandardizedFormData(tableVizFormData);
+ const { formData: bntFormData, controlsState: bntControlsState } =
+ sfd.transform('big_number_total', tableVizStore);
+ expect(Object.keys(bntFormData).sort()).toEqual(
+ [...Object.keys(bntControlsState), 'standardizedFormData'].sort(),
+ );
+ expect(bntFormData.viz_type).toBe('big_number_total');
+ expect(bntFormData.metric).toBe('count');
+
+ // change control values
+ bntFormData.metric = 'sum(sales)';
+ bntFormData.time_range = '2021 : 2022';
+ bntControlsState.metric.value = 'sum(sales)';
+ bntControlsState.time_range.value = '2021 : 2022';
+
+ // bigNumberTotal -> table
+ const sfd2 = new StandardizedFormData(bntFormData);
+ const { formData: tblFormData, controlsState: tblControlsState } =
+ sfd2.transform('table', {
+ ...tableVizStore,
+ form_data: bntFormData,
+ controls: bntControlsState,
+ });
+ expect(Object.keys(tblFormData).sort()).toEqual(
+ [...Object.keys(tblControlsState), 'standardizedFormData'].sort(),
+ );
+ expect(tblFormData.viz_type).toBe('table');
+ expect(tblFormData.metrics).toEqual(['sum(sales)']);
+ expect(tblFormData.groupby).toEqual([]);
+ expect(tblFormData.time_range).toBe('2021 : 2022');
+ });
+});
diff --git a/superset-frontend/src/explore/controlUtils/standardizedFormData.ts b/superset-frontend/src/explore/controlUtils/standardizedFormData.ts
new file mode 100644
index 0000000000..c42ef95085
--- /dev/null
+++ b/superset-frontend/src/explore/controlUtils/standardizedFormData.ts
@@ -0,0 +1,182 @@
+/**
+ * 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.
+ */
+import {
+ ensureIsArray,
+ getChartControlPanelRegistry,
+ QueryFormData,
+} from '@superset-ui/core';
+import {
+ ControlStateMapping,
+ StandardizedState,
+ StandardizedFormDataInterface,
+} from '@superset-ui/chart-controls';
+import { getControlsState } from 'src/explore/store';
+import { getFormDataFromControls } from './getFormDataFromControls';
+
+export const sharedControls: Record<keyof StandardizedState, string[]> = {
+ metrics: ['metric', 'metrics', 'metric_2'],
+ columns: ['groupby', 'columns', 'groupbyColumns', 'groupbyRows'],
+};
+export const publicControls = [
+ // time section
+ 'granularity_sqla',
+ 'time_grain_sqla',
+ 'time_range',
+ // filters
+ 'adhoc_filters',
+ // subquery limit(series limit)
+ 'limit',
+ // order by clause
+ 'timeseries_limit_metric',
+ 'series_limit_metric',
+ // desc or asc in order by clause
+ 'order_desc',
+ // outer query limit
+ 'row_limit',
+ // x asxs column
+ 'x_axis',
+ // advanced analytics - rolling window
+ 'rolling_type',
+ 'rolling_periods',
+ 'min_periods',
+ // advanced analytics - time comparison
+ 'time_compare',
+ 'comparison_type',
+ // advanced analytics - resample
+ 'resample_rule',
+ 'resample_method',
+];
+
+export class StandardizedFormData {
+ private sfd: StandardizedFormDataInterface;
+
+ constructor(sourceFormData: QueryFormData) {
+ /*
+ * Support form_data for smooth switching between different viz
+ * */
+ const standardizedState = {
+ metrics: [],
+ columns: [],
+ };
+ const formData = Object.freeze(sourceFormData);
+ const reversedMap = StandardizedFormData.getReversedMap();
+
+ Object.entries(formData).forEach(([key, value]) => {
+ if (reversedMap.has(key)) {
+ standardizedState[reversedMap.get(key)].push(...ensureIsArray(value));
+ }
+ });
+
+ const memorizedFormData = Array.isArray(
+ formData?.standardizedFormData?.memorizedFormData,
+ )
+ ? new Map(formData.standardizedFormData.memorizedFormData)
+ : new Map();
+ const vizType = formData.viz_type;
+ if (memorizedFormData.has(vizType)) {
+ memorizedFormData.delete(vizType);
+ }
+ memorizedFormData.set(vizType, formData);
+ this.sfd = {
+ standardizedState,
+ memorizedFormData,
+ };
+ }
+
+ static getReversedMap() {
+ const reversedMap = new Map();
+ Object.entries(sharedControls).forEach(([key, names]) => {
+ names.forEach(name => {
+ reversedMap.set(name, key);
+ });
+ });
+ return reversedMap;
+ }
+
+ private getLatestFormData(vizType: string): QueryFormData {
+ if (this.sfd.memorizedFormData.has(vizType)) {
+ return this.sfd.memorizedFormData.get(vizType) as QueryFormData;
+ }
+
+ return this.memorizedFormData.slice(-1)[0][1];
+ }
+
+ private get standardizedState() {
+ return this.sfd.standardizedState;
+ }
+
+ private get memorizedFormData() {
+ return Array.from(this.sfd.memorizedFormData.entries());
+ }
+
+ dumpSFD() {
+ return {
+ standardizedState: this.standardizedState,
+ memorizedFormData: this.memorizedFormData,
+ };
+ }
+
+ transform(
+ targetVizType: string,
+ exploreState: Record<string, any>,
+ ): {
+ formData: QueryFormData;
+ controlsState: ControlStateMapping;
+ } {
+ /*
+ * Transfrom form_data between different viz. Return new form_data and controlsState.
+ * 1. get memorized form_data by viz type or get previous form_data
+ * 2. collect public control values
+ * 3. generate initial targetControlsState
+ * 4. attach `standardizedFormData` to the initial form_data
+ * 5. call denormalizeFormData to transform initial form_data if the plugin was defined
+ * 6. use final form_data to generate controlsState
+ * */
+ const latestFormData = this.getLatestFormData(targetVizType);
+ const publicFormData = {};
+ publicControls.forEach(key => {
+ if (key in exploreState.form_data) {
+ publicFormData[key] = exploreState.form_data[key];
+ }
+ });
+ const targetControlsState = getControlsState(exploreState, {
+ ...latestFormData,
+ ...publicFormData,
+ viz_type: targetVizType,
+ });
+ const targetFormData = {
+ ...getFormDataFromControls(targetControlsState),
+ standardizedFormData: this.dumpSFD(),
+ };
+
+ const controlPanel = getChartControlPanelRegistry().get(targetVizType);
+ if (controlPanel?.denormalizeFormData) {
+ const transformed = controlPanel.denormalizeFormData(targetFormData);
+ return {
+ formData: transformed,
+ controlsState: getControlsState(exploreState, transformed),
+ };
+ }
+
+ return {
+ formData: targetFormData,
+ controlsState: targetControlsState,
+ };
+ }
+}
diff --git a/superset-frontend/src/explore/reducers/exploreReducer.js b/superset-frontend/src/explore/reducers/exploreReducer.js
index 2897832ff0..818bb31c8c 100644
--- a/superset-frontend/src/explore/reducers/exploreReducer.js
+++ b/superset-frontend/src/explore/reducers/exploreReducer.js
@@ -23,9 +23,9 @@ import { DEFAULT_TIME_RANGE } from 'src/explore/constants';
import { getControlsState } from 'src/explore/store';
import {
getControlConfig,
- getFormDataFromControls,
getControlStateFromControlConfig,
getControlValuesCompatibleWithDatasource,
+ StandardizedFormData,
} from 'src/explore/controlUtils';
import * as actions from 'src/explore/actions/exploreActions';
@@ -129,11 +129,10 @@ export default function exploreReducer(state = {}, action) {
};
},
[actions.SET_FIELD_VALUE]() {
- const new_form_data = state.form_data;
+ const { controlName, value, validationErrors } = action;
+ let new_form_data = { ...state.form_data, [controlName]: value };
const old_metrics_data = state.form_data.metrics;
const new_column_config = state.form_data.column_config;
- const { controlName, value, validationErrors } = action;
- new_form_data[controlName] = value;
const vizType = new_form_data.viz_type;
@@ -204,18 +203,17 @@ export default function exploreReducer(state = {}, action) {
});
const hasErrors = errors && errors.length > 0;
- const currentControlsState =
+ const isVizSwitch =
action.controlName === 'viz_type' &&
- action.value !== state.controls.viz_type.value
- ? // rebuild the full control state if switching viz type
- getControlsState(
- state,
- getFormDataFromControls({
- ...state.controls,
- viz_type: control,
- }),
- )
- : state.controls;
+ action.value !== state.controls.viz_type.value;
+ let currentControlsState = state.controls;
+ if (isVizSwitch) {
+ // get StandardizedFormData from source form_data
+ const sfd = new StandardizedFormData(state.form_data);
+ const transformed = sfd.transform(action.value, state);
+ new_form_data = transformed.formData;
+ currentControlsState = transformed.controlsState;
+ }
return {
...state,