You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by vi...@apache.org on 2021/03/17 12:01:43 UTC

[superset] branch master updated: feat(cross-filters): Add scoping for cross filters (#13625)

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

villebro 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 0e0c99b  feat(cross-filters): Add scoping for cross filters (#13625)
0e0c99b is described below

commit 0e0c99b2fb4cb275b65cc1293bafafe4f91ba33a
Author: simcha90 <56...@users.noreply.github.com>
AuthorDate: Wed Mar 17 14:00:32 2021 +0200

    feat(cross-filters): Add scoping for cross filters (#13625)
    
    * feat: cross filter modal
    
    * refactor: add charts metadata
    
    * refactor: add charts metadata
    
    * feat: cross filters scoping
    
    * fix: fix CR notes
    
    * test: fix test
    
    * lint: fix lint
---
 .../dashboard/components/Dashboard_spec.jsx        |  6 +-
 .../util/getFormDataWithExtraFilters_spec.ts       |  1 +
 .../src/dashboard/actions/dashboardInfo.ts         | 81 ++++++++++++++++++
 .../src/dashboard/actions/nativeFilters.ts         |  9 +-
 .../CrossFilterScopingForm.tsx                     | 54 ++++++++++++
 .../CrossFilterScopingModal.tsx                    | 97 ++++++++++++++++++++++
 .../CrossFilterScopingModal/types.ts}              |  9 +-
 .../CrossFilterScopingModal/utils.ts}              | 16 ++--
 .../src/dashboard/components/Dashboard.jsx         |  5 +-
 .../dashboard/components/SliceHeaderControls.jsx   | 65 +++++++++++----
 .../FiltersConfigForm/ControlItems.tsx             |  4 +-
 .../FiltersConfigForm/DefaultValue.tsx             |  4 +-
 .../FiltersConfigForm/FilterScope/FilterScope.tsx  | 71 +++++++++-------
 .../FiltersConfigForm/FilterScope/ScopingTree.tsx  | 24 +++---
 .../FiltersConfigForm/FiltersConfigForm.tsx        | 17 ++--
 .../FiltersConfigModal/FiltersConfigForm/state.ts  |  6 +-
 .../FiltersConfigModal/FiltersConfigForm/utils.ts  |  2 +-
 .../dashboard/components/nativeFilters/state.ts    |  2 +-
 .../dashboard/components/nativeFilters/utils.ts    | 15 +---
 .../src/dashboard/containers/Chart.jsx             |  2 +
 .../src/dashboard/containers/Dashboard.jsx         |  8 +-
 .../src/dashboard/reducers/getInitialState.js      |  2 +-
 superset-frontend/src/dashboard/reducers/types.ts  | 19 ++++-
 ...tiveFilters.ts => activeAllDashboardFilters.ts} | 45 +++++-----
 .../util/charts/getFormDataWithExtraFilters.ts     | 13 +--
 superset/dashboards/schemas.py                     |  6 +-
 26 files changed, 438 insertions(+), 145 deletions(-)

diff --git a/superset-frontend/spec/javascripts/dashboard/components/Dashboard_spec.jsx b/superset-frontend/spec/javascripts/dashboard/components/Dashboard_spec.jsx
index 733f824..c9c13b1 100644
--- a/superset-frontend/spec/javascripts/dashboard/components/Dashboard_spec.jsx
+++ b/superset-frontend/spec/javascripts/dashboard/components/Dashboard_spec.jsx
@@ -39,7 +39,7 @@ import dashboardInfo from 'spec/fixtures/mockDashboardInfo';
 import { dashboardLayout } from 'spec/fixtures/mockDashboardLayout';
 import dashboardState from 'spec/fixtures/mockDashboardState';
 import { sliceEntitiesForChart as sliceEntities } from 'spec/fixtures/mockSliceEntities';
-import { getActiveNativeFilters } from 'src/dashboard/util/activeDashboardNativeFilters';
+import { getAllActiveFilters } from 'src/dashboard/util/activeAllDashboardFilters';
 
 describe('Dashboard', () => {
   const props = {
@@ -154,9 +154,9 @@ describe('Dashboard', () => {
       wrapper.setProps({
         activeFilters: {
           ...OVERRIDE_FILTERS,
-          ...getActiveNativeFilters({
+          ...getAllActiveFilters({
             dataMask: dataMaskWith1Filter,
-            filters: singleNativeFiltersState.filters,
+            nativeFilters: singleNativeFiltersState.filters,
             layout: layoutForSingleNativeFilter,
           }),
         },
diff --git a/superset-frontend/spec/javascripts/dashboard/util/getFormDataWithExtraFilters_spec.ts b/superset-frontend/spec/javascripts/dashboard/util/getFormDataWithExtraFilters_spec.ts
index 18242e3..e30ef3f 100644
--- a/superset-frontend/spec/javascripts/dashboard/util/getFormDataWithExtraFilters_spec.ts
+++ b/superset-frontend/spec/javascripts/dashboard/util/getFormDataWithExtraFilters_spec.ts
@@ -41,6 +41,7 @@ describe('getFormDataWithExtraFilters', () => {
     },
   };
   const mockArgs: GetFormDataWithExtraFiltersArguments = {
+    chartConfiguration: {},
     charts: {
       [chartId]: mockChart,
     },
diff --git a/superset-frontend/src/dashboard/actions/dashboardInfo.ts b/superset-frontend/src/dashboard/actions/dashboardInfo.ts
new file mode 100644
index 0000000..3aa3093
--- /dev/null
+++ b/superset-frontend/src/dashboard/actions/dashboardInfo.ts
@@ -0,0 +1,81 @@
+/**
+ * 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 { Dispatch } from 'redux';
+import { makeApi } from '@superset-ui/core';
+import { ChartConfiguration, DashboardInfo } from '../reducers/types';
+
+export const DASHBOARD_INFO_UPDATED = 'DASHBOARD_INFO_UPDATED';
+
+// updates partially changed dashboard info
+export function dashboardInfoChanged(newInfo: { metadata: any }) {
+  return { type: DASHBOARD_INFO_UPDATED, newInfo };
+}
+export const SET_CHART_CONFIG_BEGIN = 'SET_CHART_CONFIG_BEGIN';
+export interface SetChartConfigBegin {
+  type: typeof SET_CHART_CONFIG_BEGIN;
+  chartConfiguration: ChartConfiguration;
+}
+export const SET_CHART_CONFIG_COMPLETE = 'SET_CHART_CONFIG_COMPLETE';
+export interface SetChartConfigComplete {
+  type: typeof SET_CHART_CONFIG_COMPLETE;
+  chartConfiguration: ChartConfiguration;
+}
+export const SET_CHART_CONFIG_FAIL = 'SET_CHART_CONFIG_FAIL';
+export interface SetChartConfigFail {
+  type: typeof SET_CHART_CONFIG_FAIL;
+  chartConfiguration: ChartConfiguration;
+}
+export const setChartConfiguration = (
+  chartConfiguration: ChartConfiguration,
+) => async (dispatch: Dispatch, getState: () => any) => {
+  dispatch({
+    type: SET_CHART_CONFIG_BEGIN,
+    chartConfiguration,
+  });
+  const { id, metadata } = getState().dashboardInfo;
+
+  // TODO extract this out when makeApi supports url parameters
+  const updateDashboard = makeApi<
+    Partial<DashboardInfo>,
+    { result: DashboardInfo }
+  >({
+    method: 'PUT',
+    endpoint: `/api/v1/dashboard/${id}`,
+  });
+
+  try {
+    const response = await updateDashboard({
+      json_metadata: JSON.stringify({
+        ...metadata,
+        chart_configuration: chartConfiguration,
+      }),
+    });
+    dispatch(
+      dashboardInfoChanged({
+        metadata: JSON.parse(response.result.json_metadata),
+      }),
+    );
+    dispatch({
+      type: SET_CHART_CONFIG_COMPLETE,
+      chartConfiguration,
+    });
+  } catch (err) {
+    dispatch({ type: SET_CHART_CONFIG_FAIL, chartConfiguration });
+  }
+};
diff --git a/superset-frontend/src/dashboard/actions/nativeFilters.ts b/superset-frontend/src/dashboard/actions/nativeFilters.ts
index 2e1c7e7..8d18327 100644
--- a/superset-frontend/src/dashboard/actions/nativeFilters.ts
+++ b/superset-frontend/src/dashboard/actions/nativeFilters.ts
@@ -26,7 +26,7 @@ import {
   SET_DATA_MASK_FOR_FILTER_CONFIG_FAIL,
 } from 'src/dataMask/actions';
 import { dashboardInfoChanged } from './dashboardInfo';
-import { FilterSet } from '../reducers/types';
+import { DashboardInfo, FilterSet } from '../reducers/types';
 
 export const SET_FILTER_CONFIG_BEGIN = 'SET_FILTER_CONFIG_BEGIN';
 export interface SetFilterConfigBegin {
@@ -60,11 +60,6 @@ export interface SetFilterSetsConfigFail {
   filterSetsConfig: FilterSet[];
 }
 
-interface DashboardInfo {
-  id: number;
-  json_metadata: string;
-}
-
 export const setFilterConfiguration = (
   filterConfig: FilterConfiguration,
 ) => async (dispatch: Dispatch, getState: () => any) => {
@@ -87,7 +82,7 @@ export const setFilterConfiguration = (
     const response = await updateDashboard({
       json_metadata: JSON.stringify({
         ...metadata,
-        filter_configuration: filterConfig,
+        native_filter_configuration: filterConfig,
       }),
     });
     dispatch(
diff --git a/superset-frontend/src/dashboard/components/CrossFilterScopingModal/CrossFilterScopingForm.tsx b/superset-frontend/src/dashboard/components/CrossFilterScopingModal/CrossFilterScopingForm.tsx
new file mode 100644
index 0000000..7e98ee0
--- /dev/null
+++ b/superset-frontend/src/dashboard/components/CrossFilterScopingModal/CrossFilterScopingForm.tsx
@@ -0,0 +1,54 @@
+/**
+ * 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 React, { FC } from 'react';
+import { FormInstance } from 'antd/lib/form';
+import FilterScope from '../nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/FilterScope';
+import { setCrossFilterFieldValues } from './utils';
+import { Scope } from '../nativeFilters/types';
+import { useForceUpdate } from '../nativeFilters/FiltersConfigModal/FiltersConfigForm/utils';
+import { CrossFilterScopingFormType } from './types';
+
+type CrossFilterScopingFormProps = {
+  scope: Scope;
+  form: FormInstance<CrossFilterScopingFormType>;
+};
+
+const CrossFilterScopingForm: FC<CrossFilterScopingFormProps> = ({
+  form,
+  scope,
+}) => {
+  const forceUpdate = useForceUpdate();
+  const formScope = form.getFieldValue('scope');
+  const formScoping = form.getFieldValue('scoping');
+  return (
+    <FilterScope
+      updateFormValues={(values: any) => {
+        setCrossFilterFieldValues(form, {
+          ...values,
+        });
+      }}
+      scope={scope}
+      formScope={formScope}
+      forceUpdate={forceUpdate}
+      formScoping={formScoping}
+    />
+  );
+};
+
+export default CrossFilterScopingForm;
diff --git a/superset-frontend/src/dashboard/components/CrossFilterScopingModal/CrossFilterScopingModal.tsx b/superset-frontend/src/dashboard/components/CrossFilterScopingModal/CrossFilterScopingModal.tsx
new file mode 100644
index 0000000..765ff2b
--- /dev/null
+++ b/superset-frontend/src/dashboard/components/CrossFilterScopingModal/CrossFilterScopingModal.tsx
@@ -0,0 +1,97 @@
+/**
+ * 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 { t } from '@superset-ui/core';
+import React, { FC } from 'react';
+import { useDispatch, useSelector } from 'react-redux';
+import { StyledModal } from 'src/common/components/Modal';
+import Button from 'src/components/Button';
+import { Form } from 'src/common/components';
+import { setChartConfiguration } from 'src/dashboard/actions/dashboardInfo';
+import { ChartConfiguration } from 'src/dashboard/reducers/types';
+import CrossFilterScopingForm from './CrossFilterScopingForm';
+import { CrossFilterScopingFormType } from './types';
+import { StyledForm } from '../nativeFilters/FiltersConfigModal/FiltersConfigModal';
+
+type CrossFilterScopingModalProps = {
+  chartId: number;
+  isOpen: boolean;
+  onClose: () => void;
+};
+
+const CrossFilterScopingModal: FC<CrossFilterScopingModalProps> = ({
+  isOpen,
+  chartId,
+  onClose,
+}) => {
+  const dispatch = useDispatch();
+  const [form] = Form.useForm<CrossFilterScopingFormType>();
+  const chartConfig = useSelector<any, ChartConfiguration>(
+    ({ dashboardInfo }) => dashboardInfo?.metadata?.chart_configuration,
+  );
+  const scope = chartConfig?.[chartId]?.crossFilters?.scope;
+  const handleSave = () => {
+    dispatch(
+      setChartConfiguration({
+        ...chartConfig,
+        [chartId]: { crossFilters: { scope: form.getFieldValue('scope') } },
+      }),
+    );
+    onClose();
+  };
+
+  return (
+    <StyledModal
+      visible={isOpen}
+      maskClosable={false}
+      title={t('Cross Filter Scoping')}
+      width="55%"
+      destroyOnClose
+      onCancel={onClose}
+      onOk={handleSave}
+      centered
+      data-test="cross-filter-scoping-modal"
+      footer={
+        <>
+          <Button
+            key="cancel"
+            buttonStyle="secondary"
+            data-test="cross-filter-scoping-modal-cancel-button"
+            onClick={onClose}
+          >
+            {t('Cancel')}
+          </Button>
+          <Button
+            key="submit"
+            buttonStyle="primary"
+            onClick={handleSave}
+            data-test="cross-filter-scoping-modal-save-button"
+          >
+            {t('Save')}
+          </Button>
+        </>
+      }
+    >
+      <StyledForm preserve={false} form={form} layout="vertical">
+        <CrossFilterScopingForm form={form} scope={scope} />
+      </StyledForm>
+    </StyledModal>
+  );
+};
+
+export default CrossFilterScopingModal;
diff --git a/superset-frontend/src/dashboard/actions/dashboardInfo.js b/superset-frontend/src/dashboard/components/CrossFilterScopingModal/types.ts
similarity index 79%
copy from superset-frontend/src/dashboard/actions/dashboardInfo.js
copy to superset-frontend/src/dashboard/components/CrossFilterScopingModal/types.ts
index 10b6f21..b56ffc0 100644
--- a/superset-frontend/src/dashboard/actions/dashboardInfo.js
+++ b/superset-frontend/src/dashboard/components/CrossFilterScopingModal/types.ts
@@ -17,9 +17,8 @@
  * under the License.
  */
 
-export const DASHBOARD_INFO_UPDATED = 'DASHBOARD_INFO_UPDATED';
+import { Scope } from '../nativeFilters/types';
 
-// updates partially changed dashboard info
-export function dashboardInfoChanged(newInfo) {
-  return { type: DASHBOARD_INFO_UPDATED, newInfo };
-}
+export type CrossFilterScopingFormType = {
+  scope: Scope;
+};
diff --git a/superset-frontend/src/dashboard/actions/dashboardInfo.js b/superset-frontend/src/dashboard/components/CrossFilterScopingModal/utils.ts
similarity index 77%
rename from superset-frontend/src/dashboard/actions/dashboardInfo.js
rename to superset-frontend/src/dashboard/components/CrossFilterScopingModal/utils.ts
index 10b6f21..27e6945 100644
--- a/superset-frontend/src/dashboard/actions/dashboardInfo.js
+++ b/superset-frontend/src/dashboard/components/CrossFilterScopingModal/utils.ts
@@ -16,10 +16,14 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+import { FormInstance } from 'antd/lib/form';
 
-export const DASHBOARD_INFO_UPDATED = 'DASHBOARD_INFO_UPDATED';
-
-// updates partially changed dashboard info
-export function dashboardInfoChanged(newInfo) {
-  return { type: DASHBOARD_INFO_UPDATED, newInfo };
-}
+// eslint-disable-next-line import/prefer-default-export
+export const setCrossFilterFieldValues = (
+  form: FormInstance,
+  values: object,
+) => {
+  form.setFieldsValue({
+    ...values,
+  });
+};
diff --git a/superset-frontend/src/dashboard/components/Dashboard.jsx b/superset-frontend/src/dashboard/components/Dashboard.jsx
index 859b560..a373d33 100644
--- a/superset-frontend/src/dashboard/components/Dashboard.jsx
+++ b/superset-frontend/src/dashboard/components/Dashboard.jsx
@@ -207,7 +207,10 @@ class Dashboard extends React.PureComponent {
       this.appliedOwnDataCharts,
     );
     [...allKeys].forEach(filterKey => {
-      if (!currFilterKeys.includes(filterKey)) {
+      if (
+        !currFilterKeys.includes(filterKey) &&
+        appliedFilterKeys.includes(filterKey)
+      ) {
         // filterKey is removed?
         affectedChartIds.push(...appliedFilters[filterKey].scope);
       } else if (!appliedFilterKeys.includes(filterKey)) {
diff --git a/superset-frontend/src/dashboard/components/SliceHeaderControls.jsx b/superset-frontend/src/dashboard/components/SliceHeaderControls.jsx
index aeb94b9..8963b56 100644
--- a/superset-frontend/src/dashboard/components/SliceHeaderControls.jsx
+++ b/superset-frontend/src/dashboard/components/SliceHeaderControls.jsx
@@ -19,12 +19,19 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import moment from 'moment';
-import { styled, t } from '@superset-ui/core';
+import {
+  Behavior,
+  getChartMetadataRegistry,
+  styled,
+  t,
+} from '@superset-ui/core';
 import { Menu, NoAnimationDropdown } from 'src/common/components';
 import ShareMenuItems from 'src/dashboard/components/menu/ShareMenuItems';
 import downloadAsImage from '../../utils/downloadAsImage';
 import getDashboardUrl from '../util/getDashboardUrl';
 import { getActiveFilters } from '../util/activeDashboardFilters';
+import { FeatureFlag, isFeatureEnabled } from '../../featureFlags';
+import CrossFilterScopingModal from './CrossFilterScopingModal/CrossFilterScopingModal';
 
 const propTypes = {
   slice: PropTypes.object.isRequired,
@@ -59,6 +66,7 @@ const defaultProps = {
 };
 
 const MENU_KEYS = {
+  CROSS_FILTER_SCOPING: 'cross_filter_scoping',
   FORCE_REFRESH: 'force_refresh',
   TOGGLE_CHART_DESCRIPTION: 'toggle_chart_description',
   EXPLORE_CHART: 'explore_chart',
@@ -111,6 +119,7 @@ class SliceHeaderControls extends React.PureComponent {
 
     this.state = {
       showControls: false,
+      showCrossFilterScopingModal: false,
     };
   }
 
@@ -134,6 +143,9 @@ class SliceHeaderControls extends React.PureComponent {
       case MENU_KEYS.FORCE_REFRESH:
         this.refreshChart();
         break;
+      case MENU_KEYS.CROSS_FILTER_SCOPING:
+        this.setState({ showCrossFilterScopingModal: true });
+        break;
       case MENU_KEYS.TOGGLE_CHART_DESCRIPTION:
         this.props.toggleExpandSlice(this.props.slice.slice_id);
         break;
@@ -177,6 +189,14 @@ class SliceHeaderControls extends React.PureComponent {
       addDangerToast,
       isFullSize,
     } = this.props;
+    const crossFilterItems = getChartMetadataRegistry().items;
+    const isCrossFilter = Object.entries(crossFilterItems)
+      // @ts-ignore
+      .filter(([, { value }]) =>
+        value.behaviors?.includes(Behavior.CROSS_FILTER),
+      )
+      .find(([key]) => key === slice.viz_type);
+
     const cachedWhen = cachedDttm.map(itemCachedDttm =>
       moment.utc(itemCachedDttm).fromNow(),
     );
@@ -255,25 +275,38 @@ class SliceHeaderControls extends React.PureComponent {
         {this.props.supersetCanCSV && (
           <Menu.Item key={MENU_KEYS.EXPORT_CSV}>{t('Export CSV')}</Menu.Item>
         )}
+        {isFeatureEnabled(FeatureFlag.DASHBOARD_CROSS_FILTERS) &&
+          isCrossFilter && (
+            <Menu.Item key={MENU_KEYS.CROSS_FILTER_SCOPING}>
+              {t('Cross-filter scoping')}
+            </Menu.Item>
+          )}
       </Menu>
     );
 
     return (
-      <NoAnimationDropdown
-        overlay={menu}
-        trigger={['click']}
-        placement="bottomRight"
-        dropdownAlign={{
-          offset: [-40, 4],
-        }}
-        getPopupContainer={triggerNode =>
-          triggerNode.closest(SCREENSHOT_NODE_SELECTOR)
-        }
-      >
-        <span id={`slice_${slice.slice_id}-controls`} role="button">
-          <VerticalDotsTrigger />
-        </span>
-      </NoAnimationDropdown>
+      <>
+        <CrossFilterScopingModal
+          chartId={slice.slice_id}
+          isOpen={this.state.showCrossFilterScopingModal}
+          onClose={() => this.setState({ showCrossFilterScopingModal: false })}
+        />
+        <NoAnimationDropdown
+          overlay={menu}
+          trigger={['click']}
+          placement="bottomRight"
+          dropdownAlign={{
+            offset: [-40, 4],
+          }}
+          getPopupContainer={triggerNode =>
+            triggerNode.closest(SCREENSHOT_NODE_SELECTOR)
+          }
+        >
+          <span id={`slice_${slice.slice_id}-controls`} role="button">
+            <VerticalDotsTrigger />
+          </span>
+        </NoAnimationDropdown>
+      </>
     );
   }
 }
diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/ControlItems.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/ControlItems.tsx
index 1480225..7deee0d 100644
--- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/ControlItems.tsx
+++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/ControlItems.tsx
@@ -21,7 +21,7 @@ import React, { FC } from 'react';
 import { Checkbox } from 'src/common/components';
 import { FormInstance } from 'antd/lib/form';
 import { getChartControlPanelRegistry } from '@superset-ui/core';
-import { getControlItems, setFilterFieldValues } from './utils';
+import { getControlItems, setNativeFilterFieldValues } from './utils';
 import { NativeFiltersForm, NativeFiltersFormItem } from '../types';
 import { StyledCheckboxFormItem } from './FiltersConfigForm';
 import { Filter } from '../../types';
@@ -71,7 +71,7 @@ const ControlItems: FC<ControlItemsProps> = ({
                 if (!controlItem.config.resetConfig) {
                   return;
                 }
-                setFilterFieldValues(form, filterId, {
+                setNativeFilterFieldValues(form, filterId, {
                   defaultValue: null,
                 });
                 forceUpdate();
diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DefaultValue.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DefaultValue.tsx
index 1019bd6..4d0dcdd 100644
--- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DefaultValue.tsx
+++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/DefaultValue.tsx
@@ -19,7 +19,7 @@
 import React, { FC } from 'react';
 import { t, SuperChart, Behavior } from '@superset-ui/core';
 import { FormInstance } from 'antd/lib/form';
-import { setFilterFieldValues } from './utils';
+import { setNativeFilterFieldValues } from './utils';
 import { StyledFormItem, StyledLabel } from './FiltersConfigForm';
 import { Filter } from '../../types';
 import { NativeFiltersForm } from '../types';
@@ -68,7 +68,7 @@ const DefaultValue: FC<DefaultValueProps> = ({
           chartType={formFilter?.filterType}
           hooks={{
             setDataMask: ({ nativeFilters }) => {
-              setFilterFieldValues(form, filterId, {
+              setNativeFilterFieldValues(form, filterId, {
                 defaultValue: nativeFilters?.currentState?.value,
               });
               forceUpdate();
diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/FilterScope.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/FilterScope.tsx
index e24dafe..09321ca 100644
--- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/FilterScope.tsx
+++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/FilterScope.tsx
@@ -20,52 +20,57 @@
 import React, { FC } from 'react';
 import { t, styled } from '@superset-ui/core';
 import { Radio } from 'src/common/components/Radio';
-import { Form, Typography, Space, FormInstance } from 'src/common/components';
-import { NativeFiltersForm } from '../../types';
-import { Filter } from '../../../types';
+import { Form, Typography } from 'src/common/components';
+import { Scope } from '../../../types';
 import { Scoping } from './types';
 import ScopingTree from './ScopingTree';
-import { setFilterFieldValues, useForceUpdate } from '../utils';
 import { getDefaultScopeValue, isScopingAll } from './utils';
 
 type FilterScopeProps = {
-  filterId: string;
-  filterToEdit?: Filter;
-  form: FormInstance<NativeFiltersForm>;
+  pathToFormValue?: string[];
+  updateFormValues: (values: any) => void;
+  formScope?: Scope;
+  forceUpdate: Function;
+  scope?: Scope;
+  formScoping?: Scoping;
 };
 
+const Wrapper = styled.div`
+  display: flex;
+  flex-direction: column;
+  & > * {
+    margin-bottom: ${({ theme }) => theme.gridUnit}px;
+  }
+`;
+
 const CleanFormItem = styled(Form.Item)`
   margin-bottom: 0;
 `;
 
 const FilterScope: FC<FilterScopeProps> = ({
-  filterId,
-  filterToEdit,
-  form,
+  pathToFormValue = [],
+  formScoping,
+  formScope,
+  forceUpdate,
+  scope,
+  updateFormValues,
 }) => {
-  const formFilter = form.getFieldValue('filters')?.[filterId];
-  const initialScope = filterToEdit?.scope || getDefaultScopeValue();
-
-  const scoping = isScopingAll(initialScope) ? Scoping.all : Scoping.specific;
-
-  const forceUpdate = useForceUpdate();
+  const initialScope = scope || getDefaultScopeValue();
+  const initialScoping = isScopingAll(initialScope)
+    ? Scoping.all
+    : Scoping.specific;
 
   return (
-    <Space direction="vertical">
-      <CleanFormItem
-        name={['filters', filterId, 'scope']}
-        hidden
-        initialValue={initialScope}
-      />
+    <Wrapper>
       <Typography.Title level={5}>{t('Scoping')}</Typography.Title>
       <CleanFormItem
-        name={['filters', filterId, 'scoping']}
-        initialValue={scoping}
+        name={[...pathToFormValue, 'scoping']}
+        initialValue={initialScoping}
       >
         <Radio.Group
           onChange={({ target: { value } }) => {
             if (value === Scoping.all) {
-              setFilterFieldValues(form, filterId, {
+              updateFormValues({
                 scope: getDefaultScopeValue(),
               });
             }
@@ -79,18 +84,24 @@ const FilterScope: FC<FilterScopeProps> = ({
         </Radio.Group>
       </CleanFormItem>
       <Typography.Text type="secondary">
-        {formFilter?.scoping === Scoping.specific
+        {(formScoping ?? initialScoping) === Scoping.specific
           ? t('Only selected panels will be affected by this filter')
           : t('All panels with this column will be affected by this filter')}
       </Typography.Text>
-      {formFilter?.scoping === Scoping.specific && (
+      {(formScoping ?? initialScoping) === Scoping.specific && (
         <ScopingTree
+          updateFormValues={updateFormValues}
           initialScope={initialScope}
-          form={form}
-          filterId={filterId}
+          formScope={formScope}
+          forceUpdate={forceUpdate}
         />
       )}
-    </Space>
+      <CleanFormItem
+        name={[...pathToFormValue, 'scope']}
+        hidden
+        initialValue={initialScope}
+      />
+    </Wrapper>
   );
 };
 
diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/ScopingTree.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/ScopingTree.tsx
index 7c67ade..3c99db9 100644
--- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/ScopingTree.tsx
+++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FilterScope/ScopingTree.tsx
@@ -18,31 +18,29 @@
  */
 
 import React, { FC, useMemo, useState } from 'react';
-import { FormInstance, Tree } from 'src/common/components';
+import { Tree } from 'src/common/components';
 import { DASHBOARD_ROOT_ID } from 'src/dashboard/util/constants';
 import { useFilterScopeTree } from './state';
-import { setFilterFieldValues, useForceUpdate } from '../utils';
 import { findFilterScope, getTreeCheckedItems } from './utils';
-import { NativeFiltersForm } from '../../types';
 import { Scope } from '../../../types';
 
 type ScopingTreeProps = {
-  form: FormInstance<NativeFiltersForm>;
-  filterId: string;
+  forceUpdate: Function;
+  updateFormValues: (values: any) => void;
+  formScope?: Scope;
   initialScope: Scope;
 };
 
 const ScopingTree: FC<ScopingTreeProps> = ({
-  form,
-  filterId,
+  formScope,
   initialScope,
+  forceUpdate,
+  updateFormValues,
 }) => {
   const [expandedKeys, setExpandedKeys] = useState<string[]>([
     DASHBOARD_ROOT_ID,
   ]);
 
-  const formFilter = form.getFieldValue('filters')[filterId];
-
   const { treeData, layout } = useFilterScopeTree();
   const [autoExpandParent, setAutoExpandParent] = useState<boolean>(true);
 
@@ -50,18 +48,16 @@ const ScopingTree: FC<ScopingTreeProps> = ({
     setExpandedKeys(expandedKeys);
     setAutoExpandParent(false);
   };
-  const forceUpdate = useForceUpdate();
   const handleCheck = (checkedKeys: string[]) => {
     forceUpdate();
-    setFilterFieldValues(form, filterId, {
+    updateFormValues({
       scope: findFilterScope(checkedKeys, layout),
     });
   };
 
   const checkedKeys = useMemo(
-    () =>
-      getTreeCheckedItems({ ...(formFilter.scope || initialScope) }, layout),
-    [formFilter.scope, initialScope, layout],
+    () => getTreeCheckedItems({ ...(formScope || initialScope) }, layout),
+    [formScope, initialScope, layout],
   );
 
   return (
diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx
index 8c54a82..4d1a466 100644
--- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx
+++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx
@@ -33,7 +33,7 @@ import { ColumnSelect } from './ColumnSelect';
 import { NativeFiltersForm } from '../types';
 import {
   datasetToSelectOption,
-  setFilterFieldValues,
+  setNativeFilterFieldValues,
   useForceUpdate,
 } from './utils';
 import { useBackendFormUpdate } from './state';
@@ -171,7 +171,7 @@ export const FiltersConfigForm: React.FC<FiltersConfigFormProps> = ({
               label: nativeFilterItems[filterType]?.value.name,
             }))}
             onChange={({ value }: { value: string }) => {
-              setFilterFieldValues(form, filterId, {
+              setNativeFilterFieldValues(form, filterId, {
                 filterType: value,
                 defaultValue: null,
               });
@@ -202,7 +202,7 @@ export const FiltersConfigForm: React.FC<FiltersConfigFormProps> = ({
                 // We need reset column when dataset changed
                 const datasetId = formFilter?.dataset?.value;
                 if (datasetId && e?.value !== datasetId) {
-                  setFilterFieldValues(form, filterId, {
+                  setNativeFilterFieldValues(form, filterId, {
                     column: null,
                   });
                 }
@@ -283,9 +283,14 @@ export const FiltersConfigForm: React.FC<FiltersConfigFormProps> = ({
         forceUpdate={forceUpdate}
       />
       <FilterScope
-        filterId={filterId}
-        filterToEdit={filterToEdit}
-        form={form}
+        updateFormValues={(values: any) =>
+          setNativeFilterFieldValues(form, filterId, values)
+        }
+        pathToFormValue={['filters', filterId]}
+        forceUpdate={forceUpdate}
+        scope={filterToEdit?.scope}
+        formScope={formFilter?.scope}
+        formScoping={formFilter?.scoping}
       />
     </>
   );
diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/state.ts b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/state.ts
index 9d33636..d304422 100644
--- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/state.ts
+++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/state.ts
@@ -20,7 +20,7 @@ import { useEffect } from 'react';
 import { FormInstance } from 'antd/lib/form';
 import { getChartDataRequest } from 'src/chart/chartAction';
 import { NativeFiltersForm } from '../types';
-import { setFilterFieldValues, useForceUpdate } from './utils';
+import { setNativeFilterFieldValues, useForceUpdate } from './utils';
 import { Filter } from '../../types';
 import { getFormData } from '../../utils';
 
@@ -44,7 +44,7 @@ export const useBackendFormUpdate = (
     // No need to check data set change because it cascading update column
     // So check that column exists is enough
     if (hasColumn && !formFilter?.column) {
-      setFilterFieldValues(form, filterId, {
+      setNativeFilterFieldValues(form, filterId, {
         defaultValueQueriesData: [],
         defaultValue: resolvedDefaultValue,
       });
@@ -73,7 +73,7 @@ export const useBackendFormUpdate = (
       ) {
         resolvedDefaultValue = filterToEdit?.defaultValue;
       }
-      setFilterFieldValues(form, filterId, {
+      setNativeFilterFieldValues(form, filterId, {
         defaultValueQueriesData: response.result,
         defaultValue: resolvedDefaultValue,
       });
diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/utils.ts b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/utils.ts
index 8a04a36..015a2f1 100644
--- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/utils.ts
+++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/utils.ts
@@ -26,7 +26,7 @@ export const useForceUpdate = () => {
   return React.useCallback(() => updateState({}), []);
 };
 
-export const setFilterFieldValues = (
+export const setNativeFilterFieldValues = (
   form: FormInstance,
   filterId: string,
   values: object,
diff --git a/superset-frontend/src/dashboard/components/nativeFilters/state.ts b/superset-frontend/src/dashboard/components/nativeFilters/state.ts
index d07b979..83003d6 100644
--- a/superset-frontend/src/dashboard/components/nativeFilters/state.ts
+++ b/superset-frontend/src/dashboard/components/nativeFilters/state.ts
@@ -25,7 +25,7 @@ const defaultFilterConfiguration: Filter[] = [];
 export function useFilterConfiguration() {
   return useSelector<any, FilterConfiguration>(
     state =>
-      state.dashboardInfo?.metadata?.filter_configuration ||
+      state.dashboardInfo?.metadata?.native_filter_configuration ||
       defaultFilterConfiguration,
   );
 }
diff --git a/superset-frontend/src/dashboard/components/nativeFilters/utils.ts b/superset-frontend/src/dashboard/components/nativeFilters/utils.ts
index 1d72de9..48193ba 100644
--- a/superset-frontend/src/dashboard/components/nativeFilters/utils.ts
+++ b/superset-frontend/src/dashboard/components/nativeFilters/utils.ts
@@ -25,9 +25,8 @@ import {
 } from '@superset-ui/core';
 import { Charts } from 'src/dashboard/types';
 import { RefObject } from 'react';
-import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags';
+import { DataMaskStateWithId } from 'src/dataMask/types';
 import { Filter } from './types';
-import { DataMaskStateWithId } from '../../../dataMask/types';
 
 export const getFormData = ({
   datasetId,
@@ -123,18 +122,10 @@ export function getExtraFormData(
 ): ExtraFormData {
   let extraFormData: ExtraFormData = {};
   filterIdsAppliedOnChart.forEach(key => {
-    const singleDataMask = dataMask.nativeFilters[key] || {};
+    const singleDataMask =
+      dataMask.nativeFilters[key] ?? dataMask.crossFilters[key] ?? {};
     const { extraFormData: newExtra = {} } = singleDataMask;
     extraFormData = mergeExtraFormData(extraFormData, newExtra);
   });
-  if (isFeatureEnabled(FeatureFlag.DASHBOARD_CROSS_FILTERS)) {
-    Object.entries(charts).forEach(([key, chart]) => {
-      if (isCrossFilter(chart?.formData?.viz_type)) {
-        const singleDataMask = dataMask.crossFilters[key] || {};
-        const { extraFormData: newExtra = {} } = singleDataMask;
-        extraFormData = mergeExtraFormData(extraFormData, newExtra);
-      }
-    });
-  }
   return extraFormData;
 }
diff --git a/superset-frontend/src/dashboard/containers/Chart.jsx b/superset-frontend/src/dashboard/containers/Chart.jsx
index 8b5efc4..3077e8a 100644
--- a/superset-frontend/src/dashboard/containers/Chart.jsx
+++ b/superset-frontend/src/dashboard/containers/Chart.jsx
@@ -61,6 +61,8 @@ function mapStateToProps(
   const formData = getFormDataWithExtraFilters({
     layout: dashboardLayout.present,
     chart,
+    // eslint-disable-next-line camelcase
+    chartConfiguration: dashboardInfo.metadata?.chart_configuration,
     charts: chartQueries,
     filters: getAppliedFilterValues(id),
     colorScheme,
diff --git a/superset-frontend/src/dashboard/containers/Dashboard.jsx b/superset-frontend/src/dashboard/containers/Dashboard.jsx
index e2bf97b..53acf6a 100644
--- a/superset-frontend/src/dashboard/containers/Dashboard.jsx
+++ b/superset-frontend/src/dashboard/containers/Dashboard.jsx
@@ -28,7 +28,7 @@ import {
 import { triggerQuery } from '../../chart/chartAction';
 import { logEvent } from '../../logger/actions';
 import { getActiveFilters } from '../util/activeDashboardFilters';
-import { getActiveNativeFilters } from '../util/activeDashboardNativeFilters';
+import { getAllActiveFilters } from '../util/activeAllDashboardFilters';
 
 function mapStateToProps(state) {
   const {
@@ -58,8 +58,10 @@ function mapStateToProps(state) {
     // When user start interacting with dashboard, it will be user picked values from all filter_box
     activeFilters: {
       ...getActiveFilters(),
-      ...getActiveNativeFilters({
-        filters: nativeFilters.filters,
+      ...getAllActiveFilters({
+        // eslint-disable-next-line camelcase
+        chartConfiguration: dashboardInfo.metadata?.chart_configuration,
+        nativeFilters: nativeFilters.filters,
         dataMask,
         layout: dashboardLayout.present,
       }),
diff --git a/superset-frontend/src/dashboard/reducers/getInitialState.js b/superset-frontend/src/dashboard/reducers/getInitialState.js
index c44fde2..19ea54e 100644
--- a/superset-frontend/src/dashboard/reducers/getInitialState.js
+++ b/superset-frontend/src/dashboard/reducers/getInitialState.js
@@ -259,7 +259,7 @@ export default function getInitialState(bootstrapData) {
   }
 
   const nativeFilters = getInitialNativeFilterState({
-    filterConfig: dashboard.metadata.filter_configuration || [],
+    filterConfig: dashboard.metadata.native_filter_configuration || [],
     filterSetsConfig: dashboard.metadata.filter_sets_configuration || [],
   });
 
diff --git a/superset-frontend/src/dashboard/reducers/types.ts b/superset-frontend/src/dashboard/reducers/types.ts
index 535d36a..21365f6 100644
--- a/superset-frontend/src/dashboard/reducers/types.ts
+++ b/superset-frontend/src/dashboard/reducers/types.ts
@@ -19,11 +19,24 @@
 
 import componentTypes from 'src/dashboard/util/componentTypes';
 import { DataMaskStateWithId } from 'src/dataMask/types';
-import { Filter } from '../components/nativeFilters/types';
+import { Filter, Scope } from '../components/nativeFilters/types';
 
 export enum Scoping {
-  all,
-  specific,
+  All = 'All',
+  Specific = 'Specific',
+}
+
+export type ChartConfiguration = {
+  [chartId: string]: {
+    crossFilters: {
+      scope: Scope;
+    };
+  };
+};
+
+export interface DashboardInfo {
+  id: number;
+  json_metadata: string;
 }
 
 /** Chart state of redux */
diff --git a/superset-frontend/src/dashboard/util/activeDashboardNativeFilters.ts b/superset-frontend/src/dashboard/util/activeAllDashboardFilters.ts
similarity index 77%
rename from superset-frontend/src/dashboard/util/activeDashboardNativeFilters.ts
rename to superset-frontend/src/dashboard/util/activeAllDashboardFilters.ts
index aba57cf..204791b 100644
--- a/superset-frontend/src/dashboard/util/activeDashboardNativeFilters.ts
+++ b/superset-frontend/src/dashboard/util/activeAllDashboardFilters.ts
@@ -19,7 +19,7 @@
 import { CHART_TYPE } from './componentTypes';
 import { Scope } from '../components/nativeFilters/types';
 import { ActiveFilters, LayoutItem } from '../types';
-import { Filters } from '../reducers/types';
+import { ChartConfiguration, Filters } from '../reducers/types';
 import { DASHBOARD_ROOT_ID } from './constants';
 import { DataMaskStateWithId } from '../../dataMask/types';
 
@@ -28,14 +28,14 @@ export const findAffectedCharts = ({
   child,
   layout,
   scope,
-  activeNativeFilters,
+  activeFilters,
   filterId,
   extraFormData,
 }: {
   child: string;
   layout: { [key: string]: LayoutItem };
   scope: Scope;
-  activeNativeFilters: ActiveFilters;
+  activeFilters: ActiveFilters;
   filterId: string;
   extraFormData: any;
 }) => {
@@ -45,17 +45,17 @@ export const findAffectedCharts = ({
     if (scope.excluded.includes(chartId)) {
       return;
     }
-    if (!activeNativeFilters[filterId]) {
+    if (!activeFilters[filterId]) {
       // Small mutation but simplify logic
       // eslint-disable-next-line no-param-reassign
-      activeNativeFilters[filterId] = {
+      activeFilters[filterId] = {
         scope: [],
         values: [],
       };
     }
     // Add not excluded chart scopes(to know what charts refresh) and values(refresh only if its value changed)
-    activeNativeFilters[filterId].scope.push(chartId);
-    activeNativeFilters[filterId].values.push(extraFormData);
+    activeFilters[filterId].scope.push(chartId);
+    activeFilters[filterId].values.push(extraFormData);
     return;
   }
   // If child is not chart, recursive iterate over its children
@@ -64,35 +64,36 @@ export const findAffectedCharts = ({
       child,
       layout,
       scope,
-      activeNativeFilters,
+      activeFilters,
       filterId,
       extraFormData,
     }),
   );
 };
 
-export const getActiveNativeFilters = ({
-  filters,
+export const getAllActiveFilters = ({
+  chartConfiguration,
+  nativeFilters,
   dataMask,
   layout,
 }: {
+  chartConfiguration: ChartConfiguration;
   dataMask: DataMaskStateWithId;
-  filters: Filters;
+  nativeFilters: Filters;
   layout: { [key: string]: LayoutItem };
 }): ActiveFilters => {
-  const activeNativeFilters = {};
-  if (!dataMask?.nativeFilters) {
-    return activeNativeFilters;
-  }
+  const activeFilters = {};
+
+  // Combine native filters with cross filters, because they have similar logic
   Object.values({
     ...dataMask.nativeFilters,
     ...dataMask.crossFilters,
   }).forEach(({ id: filterId, extraFormData }) => {
-    // TODO: for a case of a cross filters (should be updated will be added scope there)
-    const scope = filters?.[filterId]?.scope ?? {
-      rootPath: [DASHBOARD_ROOT_ID],
-      excluded: [],
-    };
+    const scope = nativeFilters?.[filterId]?.scope ??
+      chartConfiguration?.[filterId]?.crossFilters?.scope ?? {
+        rootPath: [DASHBOARD_ROOT_ID],
+        excluded: [],
+      };
     // Iterate over all roots to find all affected charts
     scope.rootPath.forEach(layoutItemId => {
       layout[layoutItemId].children.forEach((child: string) => {
@@ -101,12 +102,12 @@ export const getActiveNativeFilters = ({
           child,
           layout,
           scope,
-          activeNativeFilters,
+          activeFilters,
           filterId,
           extraFormData,
         });
       });
     });
   });
-  return activeNativeFilters;
+  return activeFilters;
 };
diff --git a/superset-frontend/src/dashboard/util/charts/getFormDataWithExtraFilters.ts b/superset-frontend/src/dashboard/util/charts/getFormDataWithExtraFilters.ts
index 5130a6f..2b85d39 100644
--- a/superset-frontend/src/dashboard/util/charts/getFormDataWithExtraFilters.ts
+++ b/superset-frontend/src/dashboard/util/charts/getFormDataWithExtraFilters.ts
@@ -29,8 +29,8 @@ import {
 } from 'src/dashboard/components/nativeFilters/utils';
 import { DataMaskStateWithId } from 'src/dataMask/types';
 import getEffectiveExtraFilters from './getEffectiveExtraFilters';
-import { getActiveNativeFilters } from '../activeDashboardNativeFilters';
-import { NativeFiltersState } from '../../reducers/types';
+import { ChartConfiguration, NativeFiltersState } from '../../reducers/types';
+import { getAllActiveFilters } from '../activeAllDashboardFilters';
 
 // We cache formData objects so that our connected container components don't always trigger
 // render cascades. we cannot leverage the reselect library because our cache size is >1
@@ -38,6 +38,7 @@ const cachedFiltersByChart = {};
 const cachedFormdataByChart = {};
 
 export interface GetFormDataWithExtraFiltersArguments {
+  chartConfiguration: ChartConfiguration;
   chart: ChartQueryPayload;
   charts: Charts;
   filters: DataRecordFilters;
@@ -57,6 +58,7 @@ export default function getFormDataWithExtraFilters({
   charts,
   filters,
   nativeFilters,
+  chartConfiguration,
   colorScheme,
   colorNamespace,
   sliceId,
@@ -81,12 +83,13 @@ export default function getFormDataWithExtraFilters({
   }
 
   let extraData: { extra_form_data?: JsonObject } = {};
-  const activeNativeFilters = getActiveNativeFilters({
+  const activeFilters = getAllActiveFilters({
+    chartConfiguration,
     dataMask,
     layout,
-    filters: nativeFilters.filters,
+    nativeFilters: nativeFilters.filters,
   });
-  const filterIdsAppliedOnChart = Object.entries(activeNativeFilters)
+  const filterIdsAppliedOnChart = Object.entries(activeFilters)
     .filter(([, { scope }]) => scope.includes(chart.id))
     .map(([filterId]) => filterId);
   if (filterIdsAppliedOnChart.length) {
diff --git a/superset/dashboards/schemas.py b/superset/dashboards/schemas.py
index 552851e..80da0fd 100644
--- a/superset/dashboards/schemas.py
+++ b/superset/dashboards/schemas.py
@@ -106,8 +106,10 @@ def validate_json_metadata(value: Union[bytes, bytearray, str]) -> None:
 
 
 class DashboardJSONMetadataSchema(Schema):
-    # filter_configuration is for dashboard-native filters
-    filter_configuration = fields.List(fields.Dict(), allow_none=True)
+    # native_filter_configuration is for dashboard-native filters
+    native_filter_configuration = fields.List(fields.Dict(), allow_none=True)
+    # chart_configuration is for dashboard-native filters
+    chart_configuration = fields.List(fields.Dict(), allow_none=True)
     # filter_sets_configuration is for dashboard-native filters
     filter_sets_configuration = fields.List(fields.Dict(), allow_none=True)
     timed_refresh_immune_slices = fields.List(fields.Integer())