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())