You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by di...@apache.org on 2023/01/17 13:57:58 UTC

[superset] branch feat/cross-filters updated: Enable cross-filters by default

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

diegopucci pushed a commit to branch feat/cross-filters
in repository https://gitbox.apache.org/repos/asf/superset.git


The following commit(s) were added to refs/heads/feat/cross-filters by this push:
     new 80a95b0663 Enable cross-filters by default
80a95b0663 is described below

commit 80a95b0663bdffa9ea9402f6865659e870fb0f50
Author: geido <di...@gmail.com>
AuthorDate: Tue Jan 17 14:57:40 2023 +0100

    Enable cross-filters by default
---
 .../integration/dashboard/nativeFilters.test.ts    |  1 +
 .../plugins/plugin-chart-echarts/src/types.ts      |  2 +-
 .../spec/fixtures/mockDashboardState.js            |  2 +-
 .../components/DropdownSelectableIcon/index.tsx    |  6 +-
 .../src/dashboard/actions/dashboardInfo.ts         | 56 ++++++++++++++++
 .../src/dashboard/actions/dashboardState.js        |  4 +-
 superset-frontend/src/dashboard/actions/hydrate.js |  2 +
 .../dashboard/components/gridComponents/Chart.jsx  | 12 +++-
 .../FilterBarSettings/FilterBarSettings.test.tsx   |  1 +
 .../FilterBar/FilterBarSettings/index.tsx          | 75 ++++++++++++++--------
 .../src/dashboard/containers/Chart.jsx             |  1 +
 .../src/dashboard/reducers/dashboardInfo.js        |  6 ++
 superset-frontend/src/dashboard/types.ts           |  1 +
 superset/dashboards/dao.py                         |  1 +
 superset/dashboards/schemas.py                     |  1 +
 tests/integration_tests/dashboards/api_tests.py    |  2 +-
 tests/unit_tests/fixtures/assets_configs.py        |  1 +
 17 files changed, 138 insertions(+), 36 deletions(-)

diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilters.test.ts b/superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilters.test.ts
index 365a7e4ecb..e1d888cdea 100644
--- a/superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilters.test.ts
+++ b/superset-frontend/cypress-base/cypress/integration/dashboard/nativeFilters.test.ts
@@ -128,6 +128,7 @@ function prepareDashboardFilters(
         label_colors: {},
         shared_label_colors: {},
         color_scheme_domain: [],
+        cross_filters_enabled: false,
         positions: {
           DASHBOARD_VERSION_KEY: 'v2',
           ROOT_ID: { type: 'ROOT', id: 'ROOT_ID', children: ['GRID_ID'] },
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/types.ts b/superset-frontend/plugins/plugin-chart-echarts/src/types.ts
index faffb7a565..2f71b21af7 100644
--- a/superset-frontend/plugins/plugin-chart-echarts/src/types.ts
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/types.ts
@@ -134,7 +134,7 @@ export type CrossFilterTransformedProps = {
   setControlValue?: HandlerFunction;
   setDataMask: SetDataMaskHook;
   selectedValues: Record<number, string>;
-  emitCrossFilters: boolean;
+  emitCrossFilters?: boolean;
 };
 
 export type ContextMenuTransformedProps = {
diff --git a/superset-frontend/spec/fixtures/mockDashboardState.js b/superset-frontend/spec/fixtures/mockDashboardState.js
index b605443af6..0895ccf386 100644
--- a/superset-frontend/spec/fixtures/mockDashboardState.js
+++ b/superset-frontend/spec/fixtures/mockDashboardState.js
@@ -113,6 +113,6 @@ export const overwriteConfirmMetadata = {
     slug: null,
     owners: [],
     json_metadata:
-      '{"timed_refresh_immune_slices":[],"expanded_slices":{},"refresh_frequency":0,"default_filters":"{}","color_scheme":"supersetColors","label_colors":{"0":"#FCC700","1":"#A868B7","15":"#3CCCCB","30":"#A38F79","45":"#8FD3E4","age":"#1FA8C9","Yes,":"#1FA8C9","Female":"#454E7C","Prefer":"#5AC189","No,":"#FF7F44","Male":"#666666","Prefer not to say":"#E04355","Ph.D.":"#FCC700","associate\'s degree":"#A868B7","bachelor\'s degree":"#3CCCCB","high school diploma or equivalent (GED)":"#A38F7 [...]
+      '{"timed_refresh_immune_slices":[],"expanded_slices":{},"refresh_frequency":0,"default_filters":"{}","color_scheme":"supersetColors","label_colors":{"0":"#FCC700","1":"#A868B7","15":"#3CCCCB","30":"#A38F79","45":"#8FD3E4","age":"#1FA8C9","Yes,":"#1FA8C9","Female":"#454E7C","Prefer":"#5AC189","No,":"#FF7F44","Male":"#666666","Prefer not to say":"#E04355","Ph.D.":"#FCC700","associate\'s degree":"#A868B7","bachelor\'s degree":"#3CCCCB","high school diploma or equivalent (GED)":"#A38F7 [...]
   },
 };
diff --git a/superset-frontend/src/components/DropdownSelectableIcon/index.tsx b/superset-frontend/src/components/DropdownSelectableIcon/index.tsx
index 8d4926995e..c2488b45c3 100644
--- a/superset-frontend/src/components/DropdownSelectableIcon/index.tsx
+++ b/superset-frontend/src/components/DropdownSelectableIcon/index.tsx
@@ -26,7 +26,7 @@ import { css, Global } from '@emotion/react';
 
 const { SubMenu } = Menu;
 
-type SubMenuItemProps = { key: string; label: React.ReactNode };
+type SubMenuItemProps = { key: string; label: string | React.ReactNode };
 
 export interface DropDownSelectableProps extends Pick<MenuProps, 'onSelect'> {
   ref?: RefObject<HTMLDivElement>;
@@ -34,7 +34,7 @@ export interface DropDownSelectableProps extends Pick<MenuProps, 'onSelect'> {
   info?: string;
   menuItems: {
     key: string;
-    label: React.ReactNode;
+    label: string | React.ReactNode;
     children?: SubMenuItemProps[];
   }[];
   selectedKeys?: string[];
@@ -103,7 +103,7 @@ export default (props: DropDownSelectableProps) => {
         )}
         {menuItems.map(m =>
           m.children?.length ? (
-            <SubMenu title={m.label}>
+            <SubMenu title={m.label} key={m.key}>
               {m.children.map(s => menuItem(s.label, s.key))}
             </SubMenu>
           ) : (
diff --git a/superset-frontend/src/dashboard/actions/dashboardInfo.ts b/superset-frontend/src/dashboard/actions/dashboardInfo.ts
index dbec0cd1cc..3720df2bd5 100644
--- a/superset-frontend/src/dashboard/actions/dashboardInfo.ts
+++ b/superset-frontend/src/dashboard/actions/dashboardInfo.ts
@@ -131,6 +131,17 @@ export function setFilterBarOrientation(
   return { type: SET_FILTER_BAR_ORIENTATION, filterBarOrientation };
 }
 
+export const SET_CROSS_FILTERS_ENABLED = 'SET_CROSS_FILTERS_ENABLED';
+export interface SetCrossFiltersEnabled {
+  type: typeof SET_CROSS_FILTERS_ENABLED;
+  crossFiltersEnabled: boolean;
+}
+export function setCrossFiltersEnabled(
+  crossFiltersEnabled: boolean,
+) {
+  return { type: SET_CROSS_FILTERS_ENABLED, crossFiltersEnabled };
+}
+
 export function saveFilterBarOrientation(orientation: FilterBarOrientation) {
   return async (dispatch: Dispatch, getState: () => RootState) => {
     const { id, metadata } = getState().dashboardInfo;
@@ -177,3 +188,48 @@ export function saveFilterBarOrientation(orientation: FilterBarOrientation) {
     }
   };
 }
+
+export function saveCrossFiltersSetting(crossFiltersEnabled: boolean) {
+  return async (dispatch: Dispatch, getState: () => RootState) => {
+    const { id, metadata } = getState().dashboardInfo;
+    const updateDashboard = makeApi<
+      Partial<DashboardInfo>,
+      { result: Partial<DashboardInfo>; last_modified_time: number }
+    >({
+      method: 'PUT',
+      endpoint: `/api/v1/dashboard/${id}`,
+    });
+    try {
+      const response = await updateDashboard({
+        json_metadata: JSON.stringify({
+          ...metadata,
+          cross_filters_enabled: crossFiltersEnabled,
+        }),
+      });
+      const updatedDashboard = response.result;
+      const lastModifiedTime = response.last_modified_time;
+      if (updatedDashboard.json_metadata) {
+        const metadata = JSON.parse(updatedDashboard.json_metadata);
+        dispatch(setCrossFiltersEnabled(metadata.cross_filters_enabled));
+      }
+      if (lastModifiedTime) {
+        dispatch(onSave(lastModifiedTime));
+      }
+    } catch (errorObject) {
+      const { error, message } = await getClientErrorObject(errorObject);
+      let errorText = t('Sorry, an unknown error occurred.');
+
+      if (error) {
+        errorText = t(
+          'Sorry, there was an error saving this dashboard: %s',
+          error,
+        );
+      }
+      if (typeof message === 'string' && message === 'Forbidden') {
+        errorText = t('You do not have permission to edit this dashboard');
+      }
+      dispatch(addDangerToast(errorText));
+      throw errorObject;
+    }
+  };
+}
\ No newline at end of file
diff --git a/superset-frontend/src/dashboard/actions/dashboardState.js b/superset-frontend/src/dashboard/actions/dashboardState.js
index 518dd7b5dc..3e4cc73650 100644
--- a/superset-frontend/src/dashboard/actions/dashboardState.js
+++ b/superset-frontend/src/dashboard/actions/dashboardState.js
@@ -242,7 +242,7 @@ export function saveDashboardRequest(data, id, saveType) {
     } = data;
 
     const hasId = item => item.id !== undefined;
-
+    const metadataCrossFiltersEnabled = data.metadata?.cross_filters_enabled;
     // making sure the data is what the backend expects
     const cleanedData = {
       ...data,
@@ -267,6 +267,8 @@ export function saveDashboardRequest(data, id, saveType) {
         refresh_frequency: data.metadata?.refresh_frequency || 0,
         timed_refresh_immune_slices:
           data.metadata?.timed_refresh_immune_slices || [],
+          // cross-filters should be enabled by default
+        cross_filters_enabled: metadataCrossFiltersEnabled === undefined ? true : metadataCrossFiltersEnabled,
       },
     };
 
diff --git a/superset-frontend/src/dashboard/actions/hydrate.js b/superset-frontend/src/dashboard/actions/hydrate.js
index ed359a8cee..da6e1eecd2 100644
--- a/superset-frontend/src/dashboard/actions/hydrate.js
+++ b/superset-frontend/src/dashboard/actions/hydrate.js
@@ -433,6 +433,8 @@ export const hydrateDashboard =
             (isFeatureEnabled(FeatureFlag.HORIZONTAL_FILTER_BAR) &&
               metadata.filter_bar_orientation) ||
             FilterBarOrientation.VERTICAL,
+          crossFiltersEnabled: (isFeatureEnabled(FeatureFlag.DASHBOARD_CROSS_FILTERS) &&
+            metadata.cross_filters_enabled === undefined || metadata.cross_filters_enabled) || false,
         },
         dataMask,
         dashboardFilters,
diff --git a/superset-frontend/src/dashboard/components/gridComponents/Chart.jsx b/superset-frontend/src/dashboard/components/gridComponents/Chart.jsx
index 5891b9fa16..9612189f1b 100644
--- a/superset-frontend/src/dashboard/components/gridComponents/Chart.jsx
+++ b/superset-frontend/src/dashboard/components/gridComponents/Chart.jsx
@@ -97,6 +97,7 @@ const propTypes = {
   postTransformProps: PropTypes.func,
   datasetsStatus: PropTypes.oneOf(['loading', 'error', 'complete']),
   isInView: PropTypes.bool,
+  emitCrossFilters: PropTypes.bool,
 };
 
 const defaultProps = {
@@ -175,6 +176,13 @@ class Chart extends React.Component {
       return true;
     }
 
+    // allow chart to update if enable/disable cross-filters.
+    if (
+      this.props?.emitCrossFilters !== nextProps?.emitCrossFilters
+    ) {
+      return true;
+    }
+
     // allow chart update/re-render only if visible:
     // under selected tab or no tab layout
     if (nextProps.isComponentVisible) {
@@ -399,6 +407,7 @@ class Chart extends React.Component {
       postTransformProps,
       datasetsStatus,
       isInView,
+      emitCrossFilters,
     } = this.props;
 
     const { width } = this.state;
@@ -428,6 +437,7 @@ class Chart extends React.Component {
           filterId: id,
         })
       : {};
+
     return (
       <SliceContainer
         className="chart-slice"
@@ -529,7 +539,7 @@ class Chart extends React.Component {
             postTransformProps={postTransformProps}
             datasetsStatus={datasetsStatus}
             isInView={isInView}
-            emitCrossFilters
+            emitCrossFilters={emitCrossFilters}
           />
         </div>
       </SliceContainer>
diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterBarSettings/FilterBarSettings.test.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterBarSettings/FilterBarSettings.test.tsx
index 5f49076385..e003d1dc75 100644
--- a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterBarSettings/FilterBarSettings.test.tsx
+++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterBarSettings/FilterBarSettings.test.tsx
@@ -39,6 +39,7 @@ const initialState: { dashboardInfo: DashboardInfo } = {
       color_scheme_domain: [],
       label_colors: {},
       shared_label_colors: {},
+      cross_filters_enabled: false,
     },
     json_metadata: '',
     dash_edit_perm: true,
diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterBarSettings/index.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterBarSettings/index.tsx
index 2c658442d2..1ea1880f5b 100644
--- a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterBarSettings/index.tsx
+++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterBarSettings/index.tsx
@@ -17,14 +17,14 @@
  * under the License.
  */
 
-import React, { useCallback, useMemo, useState } from 'react';
+import React, { useCallback, useEffect, useMemo, useState } from 'react';
 import { useDispatch, useSelector } from 'react-redux';
-import { styled, t, useTheme } from '@superset-ui/core';
+import { FeatureFlag, isFeatureEnabled, styled, t, useTheme } from '@superset-ui/core';
 import { MenuProps } from 'src/components/Menu';
 import { FilterBarOrientation, RootState } from 'src/dashboard/types';
-import { saveFilterBarOrientation } from 'src/dashboard/actions/dashboardInfo';
+import { saveFilterBarOrientation, saveCrossFiltersSetting } from 'src/dashboard/actions/dashboardInfo';
 import Icons from 'src/components/Icons';
-import DropdownSelectableIcon from 'src/components/DropdownSelectableIcon';
+import DropdownSelectableIcon, { DropDownSelectableProps } from 'src/components/DropdownSelectableIcon';
 import Checkbox from 'src/components/Checkbox';
 
 type SelectedKey = FilterBarOrientation | string | number;
@@ -38,18 +38,33 @@ const StyledMenuLabel = styled.span`
 const FilterBarSettings = () => {
   const dispatch = useDispatch();
   const theme = useTheme();
+  const isCrossFiltersEnabled = useSelector<RootState, boolean>(
+    ({ dashboardInfo }) => dashboardInfo.crossFiltersEnabled,
+  );
   const filterBarOrientation = useSelector<RootState, FilterBarOrientation>(
     ({ dashboardInfo }) => dashboardInfo.filterBarOrientation,
   );
   const [selectedFilterBarOrientation, setSelectedFilterBarOrientation] =
     useState(filterBarOrientation);
+  const isCrossFiltersFeatureEnabled = isFeatureEnabled(
+    FeatureFlag.DASHBOARD_CROSS_FILTERS,
+  );
+  const shouldEnableCrossFilters = !!isCrossFiltersEnabled && isCrossFiltersFeatureEnabled;
   const [crossFiltersEnabled, setCrossFiltersEnabled] =
-    useState<boolean>(false);
+    useState<boolean>(shouldEnableCrossFilters);
   const crossFiltersMenuKey = 'cross-filters-menu-key';
   const isOrientation = (o: SelectedKey): o is FilterBarOrientation =>
     o === FilterBarOrientation.VERTICAL ||
     o === FilterBarOrientation.HORIZONTAL;
-  const toggleFilterBarOrientation = useCallback(
+  const updateCrossFiltersSetting = useCallback(
+    async (isEnabled) => {
+      await dispatch(
+        saveCrossFiltersSetting(isEnabled),
+      );
+    },
+    [dispatch, crossFiltersEnabled],
+  );
+  const changeFilterBarSettings = useCallback(
     async (
       selection: Parameters<
         Required<Pick<MenuProps, 'onSelect'>>['onSelect']
@@ -58,6 +73,7 @@ const FilterBarSettings = () => {
       const selectedKey: SelectedKey = selection.key;
       if (selectedKey === crossFiltersMenuKey) {
         setCrossFiltersEnabled(!crossFiltersEnabled);
+        updateCrossFiltersSetting(!crossFiltersEnabled);
         return;
       }
       if (isOrientation(selectedKey) && selectedKey !== filterBarOrientation) {
@@ -76,7 +92,6 @@ const FilterBarSettings = () => {
     },
     [dispatch, crossFiltersEnabled, filterBarOrientation],
   );
-
   const crossFiltersMenuItem = useMemo(
     () => (
       <StyledMenuLabel>
@@ -90,10 +105,33 @@ const FilterBarSettings = () => {
     ),
     [crossFiltersEnabled],
   );
+  const menuItems: DropDownSelectableProps["menuItems"] = [
+    {
+      key: 'placement',
+      label: t('Placement of the filter bar'),
+      children: [
+        {
+          key: FilterBarOrientation.VERTICAL,
+          label: t('Vertical (Left)'),
+        },
+        {
+          key: FilterBarOrientation.HORIZONTAL,
+          label: t('Horizontal (Top)'),
+        },
+      ],
+    },
+  ];
+
+  if (isCrossFiltersFeatureEnabled) {
+    menuItems.unshift({
+      key: crossFiltersMenuKey,
+      label: crossFiltersMenuItem,
+    });
+  }
 
   return (
     <DropdownSelectableIcon
-      onSelect={toggleFilterBarOrientation}
+      onSelect={changeFilterBarSettings}
       icon={
         <Icons.Gear
           name="gear"
@@ -101,26 +139,7 @@ const FilterBarSettings = () => {
           data-test="filterbar-orientation-icon"
         />
       }
-      menuItems={[
-        {
-          key: crossFiltersMenuKey,
-          label: crossFiltersMenuItem,
-        },
-        {
-          key: 'placement',
-          label: t('Placement of the filter bar'),
-          children: [
-            {
-              key: FilterBarOrientation.VERTICAL,
-              label: t('Vertical (Left)'),
-            },
-            {
-              key: FilterBarOrientation.HORIZONTAL,
-              label: t('Horizontal (Top)'),
-            },
-          ],
-        },
-      ]}
+      menuItems={menuItems}
       selectedKeys={[selectedFilterBarOrientation]}
     />
   );
diff --git a/superset-frontend/src/dashboard/containers/Chart.jsx b/superset-frontend/src/dashboard/containers/Chart.jsx
index 337b5fc017..167ec0a043 100644
--- a/superset-frontend/src/dashboard/containers/Chart.jsx
+++ b/superset-frontend/src/dashboard/containers/Chart.jsx
@@ -102,6 +102,7 @@ function mapStateToProps(
     setControlValue,
     filterboxMigrationState: dashboardState.filterboxMigrationState,
     datasetsStatus,
+    emitCrossFilters: !!dashboardInfo.crossFiltersEnabled,
   };
 }
 
diff --git a/superset-frontend/src/dashboard/reducers/dashboardInfo.js b/superset-frontend/src/dashboard/reducers/dashboardInfo.js
index 030fd60250..166323af25 100644
--- a/superset-frontend/src/dashboard/reducers/dashboardInfo.js
+++ b/superset-frontend/src/dashboard/reducers/dashboardInfo.js
@@ -20,6 +20,7 @@
 import {
   DASHBOARD_INFO_UPDATED,
   SET_FILTER_BAR_ORIENTATION,
+  SET_CROSS_FILTERS_ENABLED,
 } from '../actions/dashboardInfo';
 import { HYDRATE_DASHBOARD } from '../actions/hydrate';
 
@@ -43,6 +44,11 @@ export default function dashboardStateReducer(state = {}, action) {
         ...state,
         filterBarOrientation: action.filterBarOrientation,
       };
+      case SET_CROSS_FILTERS_ENABLED:
+        return {
+          ...state,
+          crossFiltersEnabled: action.crossFiltersEnabled,
+        };
     default:
       return state;
   }
diff --git a/superset-frontend/src/dashboard/types.ts b/superset-frontend/src/dashboard/types.ts
index e24356be61..694372f1f5 100644
--- a/superset-frontend/src/dashboard/types.ts
+++ b/superset-frontend/src/dashboard/types.ts
@@ -109,6 +109,7 @@ export type DashboardInfo = {
     label_colors: JsonObject;
     shared_label_colors: JsonObject;
   };
+  crossFiltersEnabled: boolean;
   filterBarOrientation: FilterBarOrientation;
 };
 
diff --git a/superset/dashboards/dao.py b/superset/dashboards/dao.py
index c6577f1b0e..3f0666266f 100644
--- a/superset/dashboards/dao.py
+++ b/superset/dashboards/dao.py
@@ -279,6 +279,7 @@ class DashboardDAO(BaseDAO):
         md["label_colors"] = data.get("label_colors", {})
         md["shared_label_colors"] = data.get("shared_label_colors", {})
         md["color_scheme_domain"] = data.get("color_scheme_domain", [])
+        md["cross_filters_enabled"] = data.get("cross_filters_enabled", True)
         dashboard.json_metadata = json.dumps(md)
 
         if commit:
diff --git a/superset/dashboards/schemas.py b/superset/dashboards/schemas.py
index d3a9444980..f0d05445aa 100644
--- a/superset/dashboards/schemas.py
+++ b/superset/dashboards/schemas.py
@@ -130,6 +130,7 @@ class DashboardJSONMetadataSchema(Schema):
     label_colors = fields.Dict()
     shared_label_colors = fields.Dict()
     color_scheme_domain = fields.List(fields.Str())
+    cross_filters_enabled = fields.Boolean(default=True)
     # used for v0 import/export
     import_time = fields.Integer()
     remote_id = fields.Integer()
diff --git a/tests/integration_tests/dashboards/api_tests.py b/tests/integration_tests/dashboards/api_tests.py
index 7288889bf1..93dade83ff 100644
--- a/tests/integration_tests/dashboards/api_tests.py
+++ b/tests/integration_tests/dashboards/api_tests.py
@@ -72,7 +72,7 @@ class TestDashboardApi(SupersetTestCase, ApiOwnersTestCaseMixin, InsertChartMixi
         "slug": "slug1_changed",
         "position_json": '{"b": "B"}',
         "css": "css_changed",
-        "json_metadata": '{"refresh_frequency": 30, "timed_refresh_immune_slices": [], "expanded_slices": {}, "color_scheme": "", "label_colors": {}, "shared_label_colors": {}, "color_scheme_domain": []}',
+        "json_metadata": '{"refresh_frequency": 30, "timed_refresh_immune_slices": [], "expanded_slices": {}, "color_scheme": "", "label_colors": {}, "shared_label_colors": {}, "color_scheme_domain": [], "cross_filters_enabled": false}',
         "published": False,
     }
 
diff --git a/tests/unit_tests/fixtures/assets_configs.py b/tests/unit_tests/fixtures/assets_configs.py
index 14ff37cf61..6e78d9e562 100644
--- a/tests/unit_tests/fixtures/assets_configs.py
+++ b/tests/unit_tests/fixtures/assets_configs.py
@@ -177,6 +177,7 @@ dashboards_config_1: Dict[str, Any] = {
             "show_native_filters": True,
             "color_scheme_domain": [],
             "shared_label_colors": {},
+            "cross_filters_enabled": False,
         },
         "version": "1.0.0",
     },