refactor: Removes the deprecated DASHBOARD_FILTERS_EXPERIMENTAL feature flag (#26330)

This commit is contained in:
Michael S. Molina 2024-01-18 13:24:25 -03:00 committed by GitHub
parent 8539dfd0ba
commit ae0eb4b8d9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 4 additions and 432 deletions

View File

@ -84,7 +84,6 @@ These features flags currently default to True and **will be removed in a future
[//]: # "PLEASE KEEP THE LIST SORTED ALPHABETICALLY"
- DASHBOARD_CROSS_FILTERS
- DASHBOARD_FILTERS_EXPERIMENTAL
- DASHBOARD_NATIVE_FILTERS
- ENABLE_JAVASCRIPT_CONTROLS
- GENERIC_CHART_AXES

View File

@ -30,6 +30,7 @@ assists people when migrating to a new version.
### Breaking Changes
- [26330](https://github.com/apache/superset/issues/26330): Removes the deprecated `DASHBOARD_FILTERS_EXPERIMENTAL` feature flag. The previous value of the feature flag was `False` and now the feature is permanently removed.
- [26344](https://github.com/apache/superset/issues/26344): Removes the deprecated `ENABLE_EXPLORE_JSON_CSRF_PROTECTION` feature flag. The previous value of the feature flag was `False` and now the feature is permanently removed.
- [26345](https://github.com/apache/superset/issues/26345): Removes the deprecated `ENABLE_TEMPLATE_REMOVE_FILTERS` feature flag. The previous value of the feature flag was `True` and now the feature is permanently enabled.
- [26346](https://github.com/apache/superset/issues/26346): Removes the deprecated `REMOVE_SLICE_LEVEL_LABEL_COLORS` feature flag. The previous value of the feature flag was `False` and now the feature is permanently removed.

View File

@ -29,7 +29,6 @@ export enum FeatureFlag {
CONFIRM_DASHBOARD_DIFF = 'CONFIRM_DASHBOARD_DIFF',
/** @deprecated */
DASHBOARD_CROSS_FILTERS = 'DASHBOARD_CROSS_FILTERS',
DASHBOARD_FILTERS_EXPERIMENTAL = 'DASHBOARD_FILTERS_EXPERIMENTAL',
DASHBOARD_NATIVE_FILTERS = 'DASHBOARD_NATIVE_FILTERS',
DASHBOARD_VIRTUALIZATION = 'DASHBOARD_VIRTUALIZATION',
DASHBOARD_RBAC = 'DASHBOARD_RBAC',

View File

@ -94,10 +94,7 @@ describe('nativeFilterGate', () => {
isFeatureEnabledMock = jest
.spyOn(uiCore, 'isFeatureEnabled')
.mockImplementation((featureFlag: FeatureFlag) =>
[
FeatureFlag.DASHBOARD_CROSS_FILTERS,
FeatureFlag.DASHBOARD_FILTERS_EXPERIMENTAL,
].includes(featureFlag),
[FeatureFlag.DASHBOARD_CROSS_FILTERS].includes(featureFlag),
);
});

View File

@ -151,8 +151,7 @@ export function getExtraFormData(
export function nativeFilterGate(behaviors: Behavior[]): boolean {
return (
!behaviors.includes(Behavior.NATIVE_FILTER) ||
(isFeatureEnabled(FeatureFlag.DASHBOARD_FILTERS_EXPERIMENTAL) &&
isFeatureEnabled(FeatureFlag.DASHBOARD_CROSS_FILTERS) &&
(isFeatureEnabled(FeatureFlag.DASHBOARD_CROSS_FILTERS) &&
behaviors.includes(Behavior.INTERACTIVE_CHART))
);
}

View File

@ -1,130 +0,0 @@
/**
* 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 {
ensureIsArray,
ExtraFormData,
getColumnLabel,
t,
tn,
} from '@superset-ui/core';
import React, { useEffect, useState } from 'react';
import { FormItemProps } from 'antd/lib/form';
import { Select } from 'src/components';
import { FilterPluginStyle, StyledFormItem, StatusMessage } from '../common';
import { PluginFilterGroupByProps } from './types';
export default function PluginFilterGroupBy(props: PluginFilterGroupByProps) {
const {
data,
formData,
height,
width,
setDataMask,
setHoveredFilter,
unsetHoveredFilter,
setFocusedFilter,
unsetFocusedFilter,
setFilterActive,
filterState,
inputRef,
} = props;
const { defaultValue, multiSelect } = formData;
const [value, setValue] = useState<string[]>(defaultValue ?? []);
const handleChange = (value?: string[] | string | null) => {
const resultValue: string[] = ensureIsArray<string>(value);
setValue(resultValue);
const extraFormData: ExtraFormData = {};
if (resultValue.length) {
extraFormData.interactive_groupby = resultValue;
}
setDataMask({
filterState: { value: resultValue.length ? resultValue : null },
extraFormData,
});
};
useEffect(() => {
handleChange(filterState.value);
}, [JSON.stringify(filterState.value), multiSelect]);
useEffect(() => {
handleChange(defaultValue ?? null);
// I think after Config Modal update some filter it re-creates default value for all other filters
// so we can process it like this `JSON.stringify` or start to use `Immer`
}, [JSON.stringify(defaultValue), multiSelect]);
const groupbys = ensureIsArray(formData.groupby).map(getColumnLabel);
const groupby = groupbys[0]?.length ? groupbys[0] : null;
const withData = groupby
? data.filter(row => groupby.includes(row.column_name as string))
: data;
const columns = data ? withData : [];
const placeholderText =
columns.length === 0
? t('No columns')
: tn('%s option', '%s options', columns.length, columns.length);
const formItemData: FormItemProps = {};
if (filterState.validateMessage) {
formItemData.extra = (
<StatusMessage status={filterState.validateStatus}>
{filterState.validateMessage}
</StatusMessage>
);
}
const options = columns.map(
(row: { column_name: string; verbose_name: string | null }) => {
const { column_name: columnName, verbose_name: verboseName } = row;
return {
label: verboseName ?? columnName,
value: columnName,
};
},
);
return (
<FilterPluginStyle height={height} width={width}>
<StyledFormItem
validateStatus={filterState.validateStatus}
{...formItemData}
>
<Select
allowClear
value={value}
placeholder={placeholderText}
mode={multiSelect ? 'multiple' : undefined}
// @ts-ignore
onChange={handleChange}
onBlur={unsetFocusedFilter}
onFocus={setFocusedFilter}
onMouseEnter={setHoveredFilter}
onMouseLeave={unsetHoveredFilter}
ref={inputRef}
options={options}
onDropdownVisibleChange={setFilterActive}
/>
</StyledFormItem>
</FilterPluginStyle>
);
}

View File

@ -1,45 +0,0 @@
/**
* 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 { buildQueryContext, QueryFormData } from '@superset-ui/core';
/**
* The buildQuery function is used to create an instance of QueryContext that's
* sent to the chart data endpoint. In addition to containing information of which
* datasource to use, it specifies the type (e.g. full payload, samples, query) and
* format (e.g. CSV or JSON) of the result and whether or not to force refresh the data from
* the datasource as opposed to using a cached copy of the data, if available.
*
* More importantly though, QueryContext contains a property `queries`, which is an array of
* QueryObjects specifying individual data requests to be made. A QueryObject specifies which
* columns, metrics and filters, among others, to use during the query. Usually it will be enough
* to specify just one query based on the baseQueryObject, but for some more advanced use cases
* it is possible to define post processing operations in the QueryObject, or multiple queries
* if a viz needs multiple different result sets.
*/
export default function buildQuery(formData: QueryFormData) {
return buildQueryContext(formData, baseQueryObject => [
{
...baseQueryObject,
result_type: 'columns',
columns: [],
metrics: [],
orderby: [],
},
]);
}

View File

@ -1,86 +0,0 @@
/**
* 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 {
ControlPanelConfig,
sections,
sharedControls,
} from '@superset-ui/chart-controls';
import { t } from '@superset-ui/core';
import { DEFAULT_FORM_DATA } from './types';
const { multiSelect } = DEFAULT_FORM_DATA;
const config: ControlPanelConfig = {
controlPanelSections: [
// @ts-ignore
sections.legacyRegularTime,
{
label: t('Query'),
expanded: true,
controlSetRows: [
[
{
name: 'groupby',
config: {
...sharedControls.groupby,
label: t('Columns to show'),
multiple: true,
required: false,
},
},
],
],
},
{
label: t('UI Configuration'),
expanded: true,
controlSetRows: [
[
{
name: 'multiSelect',
config: {
type: 'CheckboxControl',
label: t('Can select multiple values'),
default: multiSelect,
affectsDataMask: true,
resetConfig: true,
renderTrigger: true,
},
},
],
[
{
name: 'enableEmptyFilter',
config: {
type: 'CheckboxControl',
label: t('Filter value is required'),
default: false,
renderTrigger: true,
description: t(
'User must select a value before applying the filter',
),
},
},
],
],
},
],
};
export default config;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

View File

@ -1,43 +0,0 @@
/**
* 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, ChartMetadata, ChartPlugin, t } from '@superset-ui/core';
import buildQuery from './buildQuery';
import controlPanel from './controlPanel';
import transformProps from './transformProps';
import thumbnail from './images/thumbnail.png';
export default class FilterGroupByPlugin extends ChartPlugin {
constructor() {
const metadata = new ChartMetadata({
name: t('Group By'),
description: t('Group By filter plugin'),
behaviors: [Behavior.INTERACTIVE_CHART, Behavior.NATIVE_FILTER],
tags: [t('Experimental')],
thumbnail,
});
super({
buildQuery,
controlPanel,
loadChart: () => import('./GroupByFilterPlugin'),
metadata,
transformProps,
});
}
}

View File

@ -1,60 +0,0 @@
/**
* 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 { ChartProps } from '@superset-ui/core';
import { noOp } from 'src/utils/common';
import { DEFAULT_FORM_DATA } from './types';
export default function transformProps(chartProps: ChartProps) {
const {
behaviors,
formData,
height,
hooks,
queriesData,
width,
filterState,
inputRef,
} = chartProps;
const {
setDataMask = noOp,
setHoveredFilter = noOp,
unsetHoveredFilter = noOp,
setFocusedFilter = noOp,
unsetFocusedFilter = noOp,
setFilterActive = noOp,
} = hooks;
const { data } = queriesData[0];
return {
filterState,
behaviors,
width,
height,
data,
formData: { ...DEFAULT_FORM_DATA, ...formData },
setDataMask,
setHoveredFilter,
unsetHoveredFilter,
setFocusedFilter,
unsetFocusedFilter,
setFilterActive,
inputRef,
};
}

View File

@ -1,49 +0,0 @@
/**
* 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,
DataRecord,
FilterState,
QueryFormData,
} from '@superset-ui/core';
import { RefObject } from 'react';
import { PluginFilterHooks, PluginFilterStylesProps } from '../types';
interface PluginFilterGroupByCustomizeProps {
defaultValue?: string[] | null;
inputRef?: RefObject<HTMLInputElement>;
multiSelect: boolean;
}
export type PluginFilterGroupByQueryFormData = QueryFormData &
PluginFilterStylesProps &
PluginFilterGroupByCustomizeProps;
export type PluginFilterGroupByProps = PluginFilterStylesProps & {
behaviors: Behavior[];
data: DataRecord[];
filterState: FilterState;
formData: PluginFilterGroupByQueryFormData;
inputRef: RefObject<HTMLInputElement>;
} & PluginFilterHooks;
export const DEFAULT_FORM_DATA: PluginFilterGroupByCustomizeProps = {
defaultValue: null,
multiSelect: false,
};

View File

@ -20,5 +20,4 @@ export { default as SelectFilterPlugin } from './Select';
export { default as RangeFilterPlugin } from './Range';
export { default as TimeFilterPlugin } from './Time';
export { default as TimeColumnFilterPlugin } from './TimeColumn';
export { default as GroupByFilterPlugin } from './GroupBy';
export { default as TimeGrainFilterPlugin } from './TimeGrain';

View File

@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
import { isFeatureEnabled, Preset, FeatureFlag } from '@superset-ui/core';
import { Preset } from '@superset-ui/core';
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';
@ -73,7 +73,6 @@ import {
TimeFilterPlugin,
TimeColumnFilterPlugin,
TimeGrainFilterPlugin,
GroupByFilterPlugin,
} from 'src/filters/components';
import { PivotTableChartPlugin as PivotTableChartPluginV2 } from '@superset-ui/plugin-chart-pivot-table';
import { HandlebarsChartPlugin } from '@superset-ui/plugin-chart-handlebars';
@ -82,12 +81,6 @@ import TimeTableChartPlugin from '../TimeTable';
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()],
@ -164,7 +157,6 @@ export default class MainPreset extends Preset {
new EchartsSunburstChartPlugin().configure({ key: 'sunburst_v2' }),
new HandlebarsChartPlugin().configure({ key: 'handlebars' }),
new EchartsBubbleChartPlugin().configure({ key: 'bubble_v2' }),
...experimentalplugins,
],
});
}

View File

@ -430,7 +430,6 @@ DEFAULT_FEATURE_FLAGS: dict[str, bool] = {
"ESCAPE_MARKDOWN_HTML": False,
"DASHBOARD_NATIVE_FILTERS": True, # deprecated
"DASHBOARD_CROSS_FILTERS": True, # deprecated
"DASHBOARD_FILTERS_EXPERIMENTAL": False, # deprecated
"DASHBOARD_VIRTUALIZATION": True,
"GLOBAL_ASYNC_QUERIES": False,
"VERSIONED_EXPORT": True, # deprecated