diff --git a/superset-frontend/spec/fixtures/mockNativeFilters.ts b/superset-frontend/spec/fixtures/mockNativeFilters.ts index 6d475e3b0955e..5b18ce4bff9f7 100644 --- a/superset-frontend/spec/fixtures/mockNativeFilters.ts +++ b/superset-frontend/spec/fixtures/mockNativeFilters.ts @@ -77,7 +77,7 @@ export const nativeFilters: NativeFiltersState = { export const dataMaskWith2Filters: DataMaskStateWithId = { crossFilters: {}, - ownFilters: {}, + ownState: {}, nativeFilters: { 'NATIVE_FILTER-e7Q8zKixx': { id: 'NATIVE_FILTER-e7Q8zKixx', diff --git a/superset-frontend/spec/javascripts/dashboard/fixtures/mockNativeFilters.ts b/superset-frontend/spec/javascripts/dashboard/fixtures/mockNativeFilters.ts index aaef255674f62..97aad0d4323bb 100644 --- a/superset-frontend/spec/javascripts/dashboard/fixtures/mockNativeFilters.ts +++ b/superset-frontend/spec/javascripts/dashboard/fixtures/mockNativeFilters.ts @@ -52,7 +52,7 @@ export const nativeFiltersInfo: NativeFiltersState = { export const mockDataMaskInfo: DataMaskStateWithId = { [DataMaskType.CrossFilters]: {}, - [DataMaskType.OwnFilters]: {}, + [DataMaskType.OwnState]: {}, [DataMaskType.NativeFilters]: { DefaultsID: { id: 'DefaultId', diff --git a/superset-frontend/spec/javascripts/dashboard/util/getFormDataWithExtraFilters_spec.ts b/superset-frontend/spec/javascripts/dashboard/util/getFormDataWithExtraFilters_spec.ts index e30ef3f128f7f..8602953338ff5 100644 --- a/superset-frontend/spec/javascripts/dashboard/util/getFormDataWithExtraFilters_spec.ts +++ b/superset-frontend/spec/javascripts/dashboard/util/getFormDataWithExtraFilters_spec.ts @@ -65,7 +65,7 @@ describe('getFormDataWithExtraFilters', () => { }, dataMask: { crossFilters: {}, - ownFilters: {}, + ownState: {}, nativeFilters: { [filterId]: { id: filterId, diff --git a/superset-frontend/src/chart/ChartRenderer.jsx b/superset-frontend/src/chart/ChartRenderer.jsx index bb9857861346c..d7358f4bf6efc 100644 --- a/superset-frontend/src/chart/ChartRenderer.jsx +++ b/superset-frontend/src/chart/ChartRenderer.jsx @@ -45,7 +45,7 @@ const propTypes = { setDataMask: PropTypes.func, onFilterMenuOpen: PropTypes.func, onFilterMenuClose: PropTypes.func, - ownCurrentState: PropTypes.object, + ownState: PropTypes.object, }; const BLANK = {}; @@ -94,7 +94,7 @@ class ChartRenderer extends React.Component { return ( this.hasQueryResponseChange || nextProps.annotationData !== this.props.annotationData || - nextProps.ownCurrentState !== this.props.ownCurrentState || + nextProps.ownState !== this.props.ownState || nextProps.height !== this.props.height || nextProps.width !== this.props.width || nextProps.triggerRender || @@ -184,7 +184,7 @@ class ChartRenderer extends React.Component { annotationData, datasource, initialValues, - ownCurrentState, + ownState, formData, queriesResponse, } = this.props; @@ -224,7 +224,7 @@ class ChartRenderer extends React.Component { datasource={datasource} initialValues={initialValues} formData={formData} - ownCurrentState={ownCurrentState} + ownState={ownState} hooks={this.hooks} behaviors={[Behavior.CROSS_FILTER]} queriesData={queriesResponse} diff --git a/superset-frontend/src/dashboard/components/gridComponents/Chart.jsx b/superset-frontend/src/dashboard/components/gridComponents/Chart.jsx index 18cec534189dd..bf026319ba52e 100644 --- a/superset-frontend/src/dashboard/components/gridComponents/Chart.jsx +++ b/superset-frontend/src/dashboard/components/gridComponents/Chart.jsx @@ -69,7 +69,7 @@ const propTypes = { sliceCanEdit: PropTypes.bool.isRequired, addSuccessToast: PropTypes.func.isRequired, addDangerToast: PropTypes.func.isRequired, - ownCurrentState: PropTypes.object, + ownState: PropTypes.object, }; const defaultProps = { @@ -260,7 +260,7 @@ export default class Chart extends React.Component { sliceCanEdit, addSuccessToast, addDangerToast, - ownCurrentState, + ownState, handleToggleFullSize, isFullSize, } = this.props; @@ -368,7 +368,7 @@ export default class Chart extends React.Component { dashboardId={dashboardId} initialValues={initialValues} formData={formData} - ownCurrentState={ownCurrentState} + ownState={ownState} queriesResponse={chart.queriesResponse} timeout={timeout} triggerQuery={chart.triggerQuery} diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/CascadeFilters/CascadePopover.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/CascadeFilters/CascadePopover.tsx index dfd0a67ef22fa..168ea8d8cf401 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/CascadeFilters/CascadePopover.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/CascadeFilters/CascadePopover.tsx @@ -22,7 +22,7 @@ import Popover from 'src/components/Popover'; import Icon from 'src/components/Icon'; import { Pill } from 'src/dashboard/components/FiltersBadge/Styles'; import { useSelector } from 'react-redux'; -import { getInitialMask } from 'src/dataMask/reducer'; +import { getInitialFiltersMask } from 'src/dataMask/reducer'; import { MaskWithId } from 'src/dataMask/types'; import FilterControl from '../FilterControls/FilterControl'; import CascadeFilterControl from './CascadeFilterControl'; @@ -84,7 +84,8 @@ const CascadePopover: React.FC = ({ const [currentPathToChild, setCurrentPathToChild] = useState(); const dataMask = useSelector( state => - state.dataMask.nativeFilters[filter.id] ?? getInitialMask(filter.id), + state.dataMask.nativeFilters[filter.id] ?? + getInitialFiltersMask(filter.id), ); useEffect(() => { diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Header.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Header.tsx index 0f2282a99a94b..36ce52705eeb2 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Header.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Header.tsx @@ -22,7 +22,7 @@ import React, { FC } from 'react'; import Icon from 'src/components/Icon'; import Button from 'src/components/Button'; import { useSelector } from 'react-redux'; -import { getInitialMask } from 'src/dataMask/reducer'; +import { getInitialFiltersMask } from 'src/dataMask/reducer'; import { DataMaskUnit, DataMaskUnitWithId } from 'src/dataMask/types'; import FilterConfigurationLink from './FilterConfigurationLink'; import { useFilters } from './state'; @@ -81,7 +81,7 @@ const Header: FC = ({ const handleClearAll = () => { filterValues.forEach(filter => { setDataMaskSelected(draft => { - draft[filter.id] = getInitialMask(filter.id); + draft[filter.id] = getInitialFiltersMask(filter.id); }); }); }; diff --git a/superset-frontend/src/dashboard/components/nativeFilters/utils.ts b/superset-frontend/src/dashboard/components/nativeFilters/utils.ts index 48193ba53ae3a..224de22278678 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/utils.ts +++ b/superset-frontend/src/dashboard/components/nativeFilters/utils.ts @@ -72,7 +72,7 @@ export const getFormData = ({ export function mergeExtraFormData( originalExtra: ExtraFormData = {}, - newExtra: ExtraFormData, + newExtra: ExtraFormData = {}, ): ExtraFormData { const { override_form_data: originalOverride = {}, @@ -82,6 +82,7 @@ export function mergeExtraFormData( override_form_data: newOverride = {}, append_form_data: newAppend = {}, custom_form_data: newCustom = {}, + own_state: newOwnState = {}, } = newExtra; const appendKeys = new Set([ @@ -100,6 +101,7 @@ export function mergeExtraFormData( return { custom_form_data: newCustom, + own_state: newOwnState, override_form_data: { ...originalOverride, ...newOverride, diff --git a/superset-frontend/src/dashboard/containers/Chart.jsx b/superset-frontend/src/dashboard/containers/Chart.jsx index 94f88d3a9ef7f..39b5fb71f1121 100644 --- a/superset-frontend/src/dashboard/containers/Chart.jsx +++ b/superset-frontend/src/dashboard/containers/Chart.jsx @@ -86,7 +86,7 @@ function mapStateToProps( supersetCanExplore: !!dashboardInfo.superset_can_explore, supersetCanCSV: !!dashboardInfo.superset_can_csv, sliceCanEdit: !!dashboardInfo.slice_can_edit, - ownCurrentState: dataMask.ownFilters?.[id]?.currentState, + ownState: dataMask.ownState?.[id], crossFilterCurrentState: dataMask.crossFilters?.[id]?.currentState, }; } diff --git a/superset-frontend/src/dashboard/containers/Dashboard.jsx b/superset-frontend/src/dashboard/containers/Dashboard.jsx index 53acf6ae9501e..62e00e2923767 100644 --- a/superset-frontend/src/dashboard/containers/Dashboard.jsx +++ b/superset-frontend/src/dashboard/containers/Dashboard.jsx @@ -66,7 +66,7 @@ function mapStateToProps(state) { layout: dashboardLayout.present, }), }, - ownDataCharts: dataMask.ownFilters ?? {}, + ownDataCharts: dataMask.ownState ?? {}, slices: sliceEntities.slices, layout: dashboardLayout.present, impressionId, diff --git a/superset-frontend/src/dashboard/util/charts/getFormDataWithExtraFilters.ts b/superset-frontend/src/dashboard/util/charts/getFormDataWithExtraFilters.ts index 2b85d396d97e8..e831edede7499 100644 --- a/superset-frontend/src/dashboard/util/charts/getFormDataWithExtraFilters.ts +++ b/superset-frontend/src/dashboard/util/charts/getFormDataWithExtraFilters.ts @@ -102,12 +102,9 @@ export default function getFormDataWithExtraFilters({ }; } - const { extraFormData: newExtra = {} } = - dataMask?.ownFilters?.[chart.id] ?? {}; - extraData.extra_form_data = mergeExtraFormData( - extraData?.extra_form_data, - newExtra, - ); + extraData.extra_form_data = mergeExtraFormData(extraData?.extra_form_data, { + own_state: dataMask?.ownState?.[chart.id], + }); const formData = { ...chart.formData, diff --git a/superset-frontend/src/dashboard/util/charts/getOwnDataCharts.ts b/superset-frontend/src/dashboard/util/charts/getOwnDataCharts.ts index 096f18af4f3ba..813917af59ffc 100644 --- a/superset-frontend/src/dashboard/util/charts/getOwnDataCharts.ts +++ b/superset-frontend/src/dashboard/util/charts/getOwnDataCharts.ts @@ -31,17 +31,12 @@ export const getAffectedOwnDataCharts = ( const chartIds = Object.keys(ownDataCharts); const appliedChartIds = Object.keys(appliedOwnDataCharts); const affectedIds: string[] = arrayDiff(chartIds, appliedChartIds).filter( - id => - ownDataCharts[id]?.extraFormData || - appliedOwnDataCharts[id]?.extraFormData, + id => ownDataCharts[id] || appliedOwnDataCharts[id], ); const checkForUpdateIds = new Set([...chartIds, ...appliedChartIds]); checkForUpdateIds.forEach(chartId => { if ( - !areObjectsEqual( - ownDataCharts[chartId]?.extraFormData, - appliedOwnDataCharts[chartId]?.extraFormData, - ) + !areObjectsEqual(ownDataCharts[chartId], appliedOwnDataCharts[chartId]) ) { affectedIds.push(chartId); } diff --git a/superset-frontend/src/dataMask/actions.ts b/superset-frontend/src/dataMask/actions.ts index 331be07a540c5..316520882e735 100644 --- a/superset-frontend/src/dataMask/actions.ts +++ b/superset-frontend/src/dataMask/actions.ts @@ -19,6 +19,7 @@ import { DataMaskType, MaskWithId } from './types'; import { FilterConfiguration } from '../dashboard/components/nativeFilters/types'; import { FeatureFlag, isFeatureEnabled } from '../featureFlags'; +import { JsonObject } from '../../cypress-base/cypress/utils'; export const UPDATE_DATA_MASK = 'UPDATE_DATA_MASK'; export interface UpdateDataMask { @@ -26,7 +27,7 @@ export interface UpdateDataMask { filterId: string; [DataMaskType.NativeFilters]?: Omit; [DataMaskType.CrossFilters]?: Omit; - [DataMaskType.OwnFilters]?: Omit; + [DataMaskType.OwnState]?: JsonObject; } export const SET_DATA_MASK_FOR_FILTER_CONFIG_COMPLETE = @@ -48,15 +49,15 @@ export function updateDataMask( dataMask: { nativeFilters?: Omit; crossFilters?: Omit; - ownFilters?: Omit; + ownState?: JsonObject; }, ): UpdateDataMask { - const { nativeFilters, crossFilters, ownFilters } = dataMask; + const { nativeFilters, crossFilters, ownState } = dataMask; const filteredDataMask: { nativeFilters?: Omit; crossFilters?: Omit; - ownFilters?: Omit; - } = { ownFilters }; + ownState?: JsonObject; + } = { ownState }; if (isFeatureEnabled(FeatureFlag.DASHBOARD_NATIVE_FILTERS) && nativeFilters) { filteredDataMask.nativeFilters = nativeFilters; } diff --git a/superset-frontend/src/dataMask/reducer.ts b/superset-frontend/src/dataMask/reducer.ts index 387f81179b71c..3b7120b5bd81e 100644 --- a/superset-frontend/src/dataMask/reducer.ts +++ b/superset-frontend/src/dataMask/reducer.ts @@ -20,7 +20,7 @@ /* eslint-disable no-param-reassign */ // <- When we work with Immer, we need reassign, so disabling lint import produce from 'immer'; -import { MaskWithId, DataMaskType, DataMaskStateWithId, Mask } from './types'; +import { DataMaskStateWithId, DataMaskType, Mask, MaskWithId } from './types'; import { AnyDataMaskAction, SET_DATA_MASK_FOR_FILTER_CONFIG_COMPLETE, @@ -28,7 +28,7 @@ import { UpdateDataMask, } from './actions'; -export function getInitialMask(id: string): MaskWithId { +export function getInitialFiltersMask(id: string): MaskWithId { return { id, extraFormData: {}, @@ -42,9 +42,13 @@ const setUnitDataMask = ( dataMaskState: DataMaskStateWithId, ) => { if (action[unitName]) { + const otherProps: Partial = {}; + if (unitName !== DataMaskType.OwnState) { + otherProps.id = action.filterId; + } dataMaskState[unitName][action.filterId] = { ...(action[unitName] as Mask), - id: action.filterId, + ...otherProps, }; } }; @@ -63,7 +67,8 @@ const dataMaskReducer = produce( draft[action.unitName] = {}; (action.filterConfig ?? []).forEach(filter => { draft[action.unitName][filter.id] = - oldData[action.unitName][filter.id] ?? getInitialMask(filter.id); + oldData[action.unitName][filter.id] ?? + getInitialFiltersMask(filter.id); }); break; @@ -73,7 +78,7 @@ const dataMaskReducer = produce( { [DataMaskType.NativeFilters]: {}, [DataMaskType.CrossFilters]: {}, - [DataMaskType.OwnFilters]: {}, + [DataMaskType.OwnState]: {}, }, ); diff --git a/superset-frontend/src/dataMask/types.ts b/superset-frontend/src/dataMask/types.ts index e73077aa79c11..50fb6098577ee 100644 --- a/superset-frontend/src/dataMask/types.ts +++ b/superset-frontend/src/dataMask/types.ts @@ -17,11 +17,12 @@ * under the License. */ import { ExtraFormData, DataMaskCurrentState } from '@superset-ui/core'; +import { JsonObject } from '../../cypress-base/cypress/utils'; export enum DataMaskType { NativeFilters = 'nativeFilters', CrossFilters = 'crossFilters', - OwnFilters = 'ownFilters', + OwnState = 'ownState', } export type Mask = { @@ -32,7 +33,7 @@ export type DataMaskUnit = { [filterId: string]: Mask }; export type DataMaskState = { [DataMaskType.NativeFilters]: Mask; [DataMaskType.CrossFilters]: Mask; - [DataMaskType.OwnFilters]: Mask; + [DataMaskType.OwnState]: JsonObject; }; export type MaskWithId = Mask & { id: string }; @@ -40,5 +41,5 @@ export type DataMaskUnitWithId = { [filterId: string]: MaskWithId }; export type DataMaskStateWithId = { [DataMaskType.NativeFilters]: DataMaskUnitWithId; [DataMaskType.CrossFilters]: DataMaskUnitWithId; - [DataMaskType.OwnFilters]: DataMaskUnitWithId; + [DataMaskType.OwnState]: JsonObject; }; diff --git a/superset-frontend/src/explore/components/ExploreChartPanel.jsx b/superset-frontend/src/explore/components/ExploreChartPanel.jsx index 779f515ab1d0f..a51b7ca886a7f 100644 --- a/superset-frontend/src/explore/components/ExploreChartPanel.jsx +++ b/superset-frontend/src/explore/components/ExploreChartPanel.jsx @@ -47,7 +47,7 @@ const propTypes = { table_name: PropTypes.string, vizType: PropTypes.string.isRequired, form_data: PropTypes.object, - ownCurrentState: PropTypes.object, + ownState: PropTypes.object, standalone: PropTypes.number, timeout: PropTypes.number, refreshOverlayVisible: PropTypes.bool, @@ -190,7 +190,7 @@ const ExploreChartPanel = props => { { if (previousControls) { @@ -356,11 +356,11 @@ function ExploreViewContainer(props) { }, [previousControls, props.controls]); useEffect(() => { - if (props.ownCurrentState !== undefined) { + if (props.ownState !== undefined) { onQuery(); reRenderChart(); } - }, [props.ownCurrentState]); + }, [props.ownState]); if (chartIsStale) { props.actions.logEvent(LOG_ACTIONS_CHANGE_EXPLORE_CONTROLS); @@ -557,7 +557,9 @@ function mapStateToProps(state) { form_data.extra_form_data = mergeExtraFormData( { ...form_data.extra_form_data }, { - ...dataMask?.ownFilters?.[form_data.slice_id]?.extraFormData, + own_state: { + ...dataMask?.ownState?.[form_data.slice_id], + }, }, ); const chartKey = Object.keys(charts)[0]; @@ -589,7 +591,7 @@ function mapStateToProps(state) { forcedHeight: explore.forced_height, chart, timeout: explore.common.conf.SUPERSET_WEBSERVER_TIMEOUT, - ownCurrentState: dataMask?.ownFilters?.[form_data.slice_id]?.currentState, + ownState: dataMask?.ownState?.[form_data.slice_id], impressionId, }; } diff --git a/superset-frontend/src/explore/exploreUtils.js b/superset-frontend/src/explore/exploreUtils.js index efd67acf31286..3172726156318 100644 --- a/superset-frontend/src/explore/exploreUtils.js +++ b/superset-frontend/src/explore/exploreUtils.js @@ -209,6 +209,7 @@ export const buildV1ChartDataPayload = ({ resultFormat, resultType, setDataMask, + ownState, }) => { const buildQuery = getChartBuildQueryRegistry().get(formData.viz_type) ?? @@ -226,6 +227,7 @@ export const buildV1ChartDataPayload = ({ result_type: resultType, }, { + ownState, hooks: { setDataMask, }, diff --git a/superset-frontend/src/filters/components/Time/TimeFilterPlugin.tsx b/superset-frontend/src/filters/components/Time/TimeFilterPlugin.tsx index 469d3e7535464..7d5cd825b3cf9 100644 --- a/superset-frontend/src/filters/components/Time/TimeFilterPlugin.tsx +++ b/superset-frontend/src/filters/components/Time/TimeFilterPlugin.tsx @@ -16,11 +16,12 @@ * specific language governing permissions and limitations * under the License. */ -import { styled, DataMask, Behavior } from '@superset-ui/core'; +import { styled, Behavior, DataMask } from '@superset-ui/core'; import React, { useState, useEffect } from 'react'; import DateFilterControl from 'src/explore/components/controls/DateFilterControl'; import { PluginFilterTimeProps } from './types'; import { Styles } from '../common'; +import { Mask } from '../../../dataMask/types'; const DEFAULT_VALUE = 'Last week'; @@ -36,7 +37,7 @@ export default function TimeFilterPlugin(props: PluginFilterTimeProps) { const handleTimeRangeChange = (timeRange: string): void => { setValue(timeRange); - const dataMask = { + const dataMask: Mask = { extraFormData: { override_form_data: { time_range: timeRange, diff --git a/superset-frontend/src/filters/utils.ts b/superset-frontend/src/filters/utils.ts index 186cd8aec8171..301da94ba2f70 100644 --- a/superset-frontend/src/filters/utils.ts +++ b/superset-frontend/src/filters/utils.ts @@ -22,6 +22,7 @@ import { NumberFormatter, QueryObjectFilterClause, TimeFormatter, + ExtraFormData, } from '@superset-ui/core'; import { FALSE_STRING, NULL_STRING, TRUE_STRING } from 'src/utils/common'; @@ -30,7 +31,7 @@ export const getSelectExtraFormData = ( value?: null | (string | number)[], emptyFilter = false, inverseSelection = false, -) => ({ +): ExtraFormData => ({ append_form_data: emptyFilter ? { adhoc_filters: [