mirror of https://github.com/apache/superset.git
chore(native-filters): introduce experimental feature flag (#14814)
* chore(native-filters): introduce experimental feature flag * break out util and add tests * fix import
This commit is contained in:
parent
6bdbd2bf50
commit
e466066229
|
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -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 = ({
|
||||
|
@ -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))
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
@ -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('');
|
||||
|
|
|
@ -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,
|
||||
Filters,
|
||||
SelectOption,
|
||||
FilterOperator,
|
||||
Filters,
|
||||
ListViewProps,
|
||||
SelectOption,
|
||||
} from 'src/components/ListView';
|
||||
import { getFromLocalStorage } from 'src/utils/localStorageHelpers';
|
||||
import withToasts from 'src/messageToasts/enhancers/withToasts';
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import { Preset } from '@superset-ui/core';
|
||||
import { isFeatureEnabled, Preset } from '@superset-ui/core';
|
||||
import {
|
||||
BigNumberChartPlugin,
|
||||
BigNumberTotalChartPlugin,
|
||||
|
@ -76,9 +76,16 @@ import {
|
|||
import { PivotTableChartPlugin as PivotTableChartPluginV2 } from '@superset-ui/plugin-chart-pivot-table';
|
||||
import FilterBoxChartPlugin from '../FilterBox/FilterBoxChartPlugin';
|
||||
import TimeTableChartPlugin from '../TimeTable/TimeTableChartPlugin';
|
||||
import { FeatureFlag } from '../../featureFlags';
|
||||
|
||||
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()],
|
||||
|
@ -135,8 +142,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,
|
||||
],
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue