feat(cross-filters): add cross filters (#12662)

* feat: add cross filters

* refactor: fix CR notes

* lint: fix lint

* lint: fix lint

* chore: pre-commit

* refactor: under chage

* refactor: move to behaviors

* lint: fix lint

Co-authored-by: amitmiran137 <amit.miran@nielsen.com>
This commit is contained in:
simcha90 2021-02-12 09:58:19 +02:00 committed by GitHub
parent 85d02620b7
commit 956f276e70
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 66 additions and 18 deletions

View File

@ -27,19 +27,24 @@ import { sliceId as chartId } from '../../../fixtures/mockChartQueries';
describe('getFormDataWithExtraFilters', () => {
const filterId = 'native-filter-1';
const mockArgs: GetFormDataWithExtraFiltersArguments = {
chart: {
id: chartId,
formData: {
filters: [
{
col: 'country_name',
op: 'IN',
val: ['United States'],
},
],
},
const mockChart = {
id: chartId,
formData: {
viz_type: 'filter_select',
filters: [
{
col: 'country_name',
op: 'IN',
val: ['United States'],
},
],
},
};
const mockArgs: GetFormDataWithExtraFiltersArguments = {
charts: {
[chartId]: mockChart,
},
chart: mockChart,
filters: {
region: ['Spain'],
color: ['pink', 'purple'],

View File

@ -22,12 +22,14 @@ import { bindActionCreators } from 'redux';
import * as actions from './chartAction';
import { logEvent } from '../logger/actions';
import Chart from './Chart';
import { setExtraFormData } from '../dashboard/actions/nativeFilters';
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(
{
...actions,
setExtraFormData,
logEvent,
},
dispatch,

View File

@ -42,6 +42,7 @@ const propTypes = {
refreshOverlayVisible: PropTypes.bool,
// dashboard callbacks
addFilter: PropTypes.func,
setExtraFormData: PropTypes.func,
onFilterMenuOpen: PropTypes.func,
onFilterMenuClose: PropTypes.func,
};
@ -73,6 +74,8 @@ class ChartRenderer extends React.Component {
setControlValue: this.handleSetControlValue,
onFilterMenuOpen: this.props.onFilterMenuOpen,
onFilterMenuClose: this.props.onFilterMenuClose,
setExtraFormData: extraFormData =>
this.props.actions?.setExtraFormData(this.props.chartId, extraFormData),
};
}

View File

@ -16,8 +16,16 @@
* specific language governing permissions and limitations
* under the License.
*/
import { ExtraFormData, QueryFormData, QueryObject } from '@superset-ui/core';
import {
ExtraFormData,
QueryFormData,
getChartMetadataRegistry,
QueryObject,
Behavior,
} from '@superset-ui/core';
import { Charts } from 'src/dashboard/types';
import { RefObject } from 'react';
import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags';
import { Filter } from './types';
import { NativeFiltersState } from '../../reducers/types';
@ -93,8 +101,16 @@ export function mergeExtraFormData(
};
}
export function isCrossFilter(vizType: string) {
// @ts-ignore need export from superset-ui `ItemWithValue`
return getChartMetadataRegistry().items[vizType]?.value.behaviors?.includes(
Behavior.CROSS_FILTER,
);
}
export function getExtraFormData(
nativeFilters: NativeFiltersState,
charts: Charts,
): ExtraFormData {
let extraFormData: ExtraFormData = {};
Object.keys(nativeFilters.filters).forEach(key => {
@ -102,5 +118,14 @@ export function getExtraFormData(
const { extraFormData: newExtra = {} } = filterState;
extraFormData = mergeExtraFormData(extraFormData, newExtra);
});
if (isFeatureEnabled(FeatureFlag.DASHBOARD_CROSS_FILTERS)) {
Object.entries(charts).forEach(([key, chart]) => {
if (isCrossFilter(chart?.formData?.viz_type)) {
const filterState = nativeFilters.filtersState[key] || {};
const { extraFormData: newExtra = {} } = filterState;
extraFormData = mergeExtraFormData(extraFormData, newExtra);
}
});
}
return extraFormData;
}

View File

@ -60,6 +60,7 @@ function mapStateToProps(
const formData = getFormDataWithExtraFilters({
layout: dashboardLayout.present,
chart,
charts: chartQueries,
filters: getAppliedFilterValues(id),
colorScheme,
colorNamespace,

View File

@ -21,7 +21,7 @@ import {
CategoricalColorNamespace,
DataRecordFilters,
} from '@superset-ui/core';
import { ChartQueryPayload, LayoutItem } from 'src/dashboard/types';
import { ChartQueryPayload, Charts, LayoutItem } from 'src/dashboard/types';
import { getExtraFormData } from 'src/dashboard/components/nativeFilters/utils';
import getEffectiveExtraFilters from './getEffectiveExtraFilters';
import { getActiveNativeFilters } from '../activeDashboardNativeFilters';
@ -34,6 +34,7 @@ const cachedFormdataByChart = {};
export interface GetFormDataWithExtraFiltersArguments {
chart: ChartQueryPayload;
charts: Charts;
filters: DataRecordFilters;
layout: { [key: string]: LayoutItem };
colorScheme?: string;
@ -47,6 +48,7 @@ export interface GetFormDataWithExtraFiltersArguments {
// filters param only contains those applicable to this chart.
export default function getFormDataWithExtraFilters({
chart,
charts,
filters,
colorScheme,
colorNamespace,
@ -78,7 +80,7 @@ export default function getFormDataWithExtraFilters({
);
if (isAffectedChart) {
extraData = {
extra_form_data: getExtraFormData(nativeFilters),
extra_form_data: getExtraFormData(nativeFilters, charts),
};
}

View File

@ -24,9 +24,9 @@ import { useDynamicPluginContext } from 'src/components/DynamicPlugins';
import { Tooltip } from 'src/common/components/Tooltip';
import Modal from 'src/common/components/Modal';
import Label from 'src/components/Label';
import ControlHeader from '../ControlHeader';
import './VizTypeControl.less';
import { FeatureFlag, isFeatureEnabled } from '../../../featureFlags';
const propTypes = {
description: PropTypes.string,
@ -168,7 +168,11 @@ const VizTypeControl = props => {
const filteredTypes = DEFAULT_ORDER.filter(type => registry.has(type))
.filter(type => {
const behaviors = registry.get(type)?.behaviors || [];
return behaviors.includes(Behavior.CROSS_FILTER) || !behaviors.length;
return (
(isFeatureEnabled(FeatureFlag.DASHBOARD_CROSS_FILTERS) &&
behaviors.includes(Behavior.CROSS_FILTER)) ||
!behaviors.length
);
})
.map(type => ({
key: type,
@ -179,7 +183,11 @@ const VizTypeControl = props => {
.entries()
.filter(entry => {
const behaviors = entry.value?.behaviors || [];
return behaviors.includes(Behavior.CROSS_FILTER) || !behaviors.length;
return (
(isFeatureEnabled(FeatureFlag.DASHBOARD_CROSS_FILTERS) &&
behaviors.includes(Behavior.CROSS_FILTER)) ||
!behaviors.length
);
})
.filter(({ key }) => !typesWithDefaultOrder.has(key)),
)

View File

@ -35,6 +35,7 @@ export enum FeatureFlag {
DISPLAY_MARKDOWN_HTML = 'DISPLAY_MARKDOWN_HTML',
ESCAPE_MARKDOWN_HTML = 'ESCAPE_MARKDOWN_HTML',
DASHBOARD_NATIVE_FILTERS = 'DASHBOARD_NATIVE_FILTERS',
DASHBOARD_CROSS_FILTERS = 'DASHBOARD_CROSS_FILTERS',
VERSIONED_EXPORT = 'VERSIONED_EXPORT',
GLOBAL_ASYNC_QUERIES = 'GLOBAL_ASYNC_QUERIES',
ENABLE_TEMPLATE_PROCESSING = 'ENABLE_TEMPLATE_PROCESSING',

View File

@ -328,6 +328,7 @@ DEFAULT_FEATURE_FLAGS: Dict[str, bool] = {
# When True, this escapes HTML (rather than rendering it) in Markdown components
"ESCAPE_MARKDOWN_HTML": False,
"DASHBOARD_NATIVE_FILTERS": False,
"DASHBOARD_CROSS_FILTERS": False,
"GLOBAL_ASYNC_QUERIES": False,
"VERSIONED_EXPORT": False,
# Note that: RowLevelSecurityFilter is only given by default to the Admin role