Skip to content

Commit

Permalink
chore(native-filters): introduce experimental feature flag (apache#14814
Browse files Browse the repository at this point in the history
)

* chore(native-filters): introduce experimental feature flag

* break out util and add tests

* fix import
  • Loading branch information
villebro authored and cccs-RyanS committed Dec 17, 2021
1 parent 69a91de commit 380af47
Show file tree
Hide file tree
Showing 5 changed files with 161 additions and 18 deletions.
126 changes: 126 additions & 0 deletions superset-frontend/src/dashboard/components/nativeFilters/utils.test.ts
@@ -0,0 +1,126 @@
/**
* 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 { Behavior, FeatureFlag } from '@superset-ui/core';
import * as featureFlags from 'src/featureFlags';
import { nativeFilterGate } from './utils';

let isFeatureEnabledMock: jest.MockInstance<boolean, [feature: FeatureFlag]>;

describe('nativeFilterGate', () => {
describe('with all feature flags disabled', () => {
beforeAll(() => {
isFeatureEnabledMock = jest
.spyOn(featureFlags, 'isFeatureEnabled')
.mockImplementation(() => false);
});

afterAll(() => {
// @ts-ignore
isFeatureEnabledMock.restore();
});

it('should return true for regular chart', () => {
expect(nativeFilterGate([])).toEqual(true);
});

it('should return true for cross filter chart', () => {
expect(nativeFilterGate([Behavior.INTERACTIVE_CHART])).toEqual(true);
});

it('should return false for native filter chart with cross filter support', () => {
expect(
nativeFilterGate([Behavior.NATIVE_FILTER, Behavior.INTERACTIVE_CHART]),
).toEqual(false);
});

it('should return false for native filter behavior', () => {
expect(nativeFilterGate([Behavior.NATIVE_FILTER])).toEqual(false);
});
});

describe('with only native filters feature flag enabled', () => {
beforeAll(() => {
isFeatureEnabledMock = jest
.spyOn(featureFlags, 'isFeatureEnabled')
.mockImplementation(
(featureFlag: FeatureFlag) =>
featureFlag === FeatureFlag.DASHBOARD_NATIVE_FILTERS,
);
});

afterAll(() => {
// @ts-ignore
isFeatureEnabledMock.restore();
});

it('should return true for regular chart', () => {
expect(nativeFilterGate([])).toEqual(true);
});

it('should return true for cross filter chart', () => {
expect(nativeFilterGate([Behavior.INTERACTIVE_CHART])).toEqual(true);
});

it('should return false for native filter chart with cross filter support', () => {
expect(
nativeFilterGate([Behavior.NATIVE_FILTER, Behavior.INTERACTIVE_CHART]),
).toEqual(false);
});

it('should return false for native filter behavior', () => {
expect(nativeFilterGate([Behavior.NATIVE_FILTER])).toEqual(false);
});
});

describe('with native filters and experimental feature flag enabled', () => {
beforeAll(() => {
isFeatureEnabledMock = jest
.spyOn(featureFlags, 'isFeatureEnabled')
.mockImplementation((featureFlag: FeatureFlag) =>
[
FeatureFlag.DASHBOARD_CROSS_FILTERS,
FeatureFlag.DASHBOARD_FILTERS_EXPERIMENTAL,
].includes(featureFlag),
);
});

afterAll(() => {
// @ts-ignore
isFeatureEnabledMock.restore();
});

it('should return true for regular chart', () => {
expect(nativeFilterGate([])).toEqual(true);
});

it('should return true for cross filter chart', () => {
expect(nativeFilterGate([Behavior.INTERACTIVE_CHART])).toEqual(true);
});

it('should return true for native filter chart with cross filter support', () => {
expect(
nativeFilterGate([Behavior.NATIVE_FILTER, Behavior.INTERACTIVE_CHART]),
).toEqual(true);
});

it('should return false for native filter behavior', () => {
expect(nativeFilterGate([Behavior.NATIVE_FILTER])).toEqual(false);
});
});
});
11 changes: 11 additions & 0 deletions superset-frontend/src/dashboard/components/nativeFilters/utils.ts
Expand Up @@ -24,11 +24,13 @@ import {
EXTRA_FORM_DATA_APPEND_KEYS,
EXTRA_FORM_DATA_OVERRIDE_KEYS,
AdhocFilter,
FeatureFlag,
} from '@superset-ui/core';
import { Charts } from 'src/dashboard/types';
import { RefObject } from 'react';
import { DataMaskStateWithId } from 'src/dataMask/types';
import extractUrlParams from 'src/dashboard/util/extractUrlParams';
import { isFeatureEnabled } from 'src/featureFlags';
import { Filter } from './types';

export const getFormData = ({
Expand Down Expand Up @@ -131,3 +133,12 @@ export function getExtraFormData(
});
return extraFormData;
}

export function nativeFilterGate(behaviors: Behavior[]): boolean {
return (
!behaviors.includes(Behavior.NATIVE_FILTER) ||
(isFeatureEnabled(FeatureFlag.DASHBOARD_FILTERS_EXPERIMENTAL) &&
isFeatureEnabled(FeatureFlag.DASHBOARD_CROSS_FILTERS) &&
behaviors.includes(Behavior.INTERACTIVE_CHART))
);
}
Expand Up @@ -19,14 +19,14 @@
import React, { useEffect, useRef, useState } from 'react';
import PropTypes from 'prop-types';
import { Input, Row, Col } from 'src/common/components';
import { Behavior, t, getChartMetadataRegistry } from '@superset-ui/core';
import { t, getChartMetadataRegistry } from '@superset-ui/core';
import { useDynamicPluginContext } from 'src/components/DynamicPlugins';
import Modal from 'src/components/Modal';
import { Tooltip } from 'src/components/Tooltip';
import Label from 'src/components/Label';
import ControlHeader from 'src/explore/components/ControlHeader';
import { nativeFilterGate } from 'src/dashboard/components/nativeFilters/utils';
import './VizTypeControl.less';
import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags';

const propTypes = {
description: PropTypes.string,
Expand Down Expand Up @@ -108,11 +108,6 @@ function VizSupportValidation({ vizType }) {
);
}

const nativeFilterGate = behaviors =>
!behaviors.includes(Behavior.NATIVE_FILTER) ||
(isFeatureEnabled(FeatureFlag.DASHBOARD_CROSS_FILTERS) &&
behaviors.includes(Behavior.INTERACTIVE_CHART));

const VizTypeControl = props => {
const [showModal, setShowModal] = useState(false);
const [filter, setFilter] = useState('');
Expand Down
18 changes: 10 additions & 8 deletions superset-frontend/src/views/CRUD/chart/ChartList.tsx
Expand Up @@ -17,35 +17,35 @@
* under the License.
*/
import {
SupersetClient,
getChartMetadataRegistry,
t,
styled,
SupersetClient,
t,
} from '@superset-ui/core';
import React, { useMemo, useState } from 'react';
import rison from 'rison';
import { uniqBy } from 'lodash';
import { isFeatureEnabled, FeatureFlag } from 'src/featureFlags';
import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags';
import {
createFetchRelated,
createErrorHandler,
createFetchRelated,
handleBulkChartExport,
handleChartDelete,
} from 'src/views/CRUD/utils';
import {
useListViewResource,
useFavoriteStatus,
useChartEditModal,
useFavoriteStatus,
useListViewResource,
} from 'src/views/CRUD/hooks';
import ConfirmStatusChange from 'src/components/ConfirmStatusChange';
import SubMenu, { SubMenuProps } from 'src/components/Menu/SubMenu';
import FaveStar from 'src/components/FaveStar';
import ListView, {
ListViewProps,
Filter,
FilterOperator,
Filters,
ListViewProps,
SelectOption,
FilterOperator,
} from 'src/components/ListView';
import { getFromLocalStorage } from 'src/utils/localStorageHelpers';
import withToasts from 'src/messageToasts/enhancers/withToasts';
Expand All @@ -54,6 +54,7 @@ import ImportModelsModal from 'src/components/ImportModal/index';
import Chart from 'src/types/Chart';
import { Tooltip } from 'src/components/Tooltip';
import Icons from 'src/components/Icons';
import { nativeFilterGate } from 'src/dashboard/components/nativeFilters/utils';
import ChartCard from './ChartCard';

const PAGE_SIZE = 25;
Expand Down Expand Up @@ -454,6 +455,7 @@ function ChartList(props: ChartListProps) {
unfilteredLabel: t('All'),
selects: registry
.keys()
.filter(k => nativeFilterGate(registry.get(k)?.behaviors || []))
.map(k => ({ label: registry.get(k)?.name || k, value: k }))
.sort((a, b) => {
if (!a.label || !b.label) {
Expand Down
15 changes: 12 additions & 3 deletions superset-frontend/src/visualizations/presets/MainPreset.js
Expand Up @@ -16,8 +16,11 @@
* specific language governing permissions and limitations
* under the License.
*/
import { Preset } from '@superset-ui/core';
import { BigNumberTotalChartPlugin } from '@superset-ui/legacy-preset-chart-big-number';
import { isFeatureEnabled, Preset } from '@superset-ui/core';
import {
BigNumberChartPlugin,
BigNumberTotalChartPlugin,
} from '@superset-ui/legacy-preset-chart-big-number';
import CalendarChartPlugin from '@superset-ui/legacy-plugin-chart-calendar';
import ChordChartPlugin from '@superset-ui/legacy-plugin-chart-chord';
import CountryMapChartPlugin from '@superset-ui/legacy-plugin-chart-country-map';
Expand Down Expand Up @@ -86,6 +89,12 @@ import {

export default class MainPreset extends Preset {
constructor() {
const experimentalplugins = isFeatureEnabled(
FeatureFlag.DASHBOARD_FILTERS_EXPERIMENTAL,
)
? [new GroupByFilterPlugin().configure({ key: 'filter_groupby' })]
: [];

super({
name: 'Legacy charts',
presets: [new DeckGLChartPreset()],
Expand Down Expand Up @@ -148,8 +157,8 @@ export default class MainPreset extends Preset {
new TimeFilterPlugin().configure({ key: 'filter_time' }),
new TimeColumnFilterPlugin().configure({ key: 'filter_timecolumn' }),
new TimeGrainFilterPlugin().configure({ key: 'filter_timegrain' }),
new GroupByFilterPlugin().configure({ key: 'filter_groupby' }),
new EchartsTreeChartPlugin().configure({ key: 'tree_chart' }),
...experimentalplugins,
],
});
}
Expand Down

0 comments on commit 380af47

Please sign in to comment.