feat: support mulitple temporal filters in AdhocFilter and move the Time Section away (#21767)

This commit is contained in:
Yongjie Zhao
2022-11-02 08:21:17 +08:00
committed by GitHub
parent 25be9ab4bc
commit a9b229dd1d
59 changed files with 1276 additions and 237 deletions

View File

@@ -22,6 +22,7 @@ import { DndItemType } from 'src/explore/components/DndItemType';
import AdhocFilterPopoverTrigger from 'src/explore/components/controls/FilterControl/AdhocFilterPopoverTrigger';
import AdhocFilter from 'src/explore/components/controls/FilterControl/AdhocFilter';
import { OptionSortType } from 'src/explore/types';
import { useGetTimeRangeLabel } from 'src/explore/components/controls/FilterControl/utils';
import OptionWrapper from './OptionWrapper';
export interface DndAdhocFilterOptionProps {
@@ -45,6 +46,8 @@ export default function DndAdhocFilterOption({
partitionColumn,
index,
}: DndAdhocFilterOptionProps) {
const { actualTimeRange, title } = useGetTimeRangeLabel(adhocFilter);
return (
<AdhocFilterPopoverTrigger
key={index}
@@ -57,8 +60,8 @@ export default function DndAdhocFilterOption({
<OptionWrapper
key={index}
index={index}
label={adhocFilter.getDefaultLabel()}
tooltipTitle={adhocFilter.getTooltipTitle()}
label={actualTimeRange ?? adhocFilter.getDefaultLabel()}
tooltipTitle={title ?? adhocFilter.getTooltipTitle()}
clickClose={onClickClose}
onShiftOptions={onShiftOptions}
type={DndItemType.FilterOption}

View File

@@ -17,7 +17,19 @@
* under the License.
*/
import React from 'react';
import { FeatureFlag, GenericDataType } from '@superset-ui/core';
import thunk from 'redux-thunk';
import { Provider } from 'react-redux';
import configureStore from 'redux-mock-store';
import {
ensureIsArray,
FeatureFlag,
GenericDataType,
QueryFormData,
} from '@superset-ui/core';
import { ColumnMeta } from '@superset-ui/chart-controls';
import { TimeseriesDefaultFormData } from '@superset-ui/plugin-chart-echarts';
import { render, screen } from 'spec/helpers/testing-library';
import AdhocMetric from 'src/explore/components/controls/MetricControl/AdhocMetric';
import AdhocFilter, {
@@ -28,7 +40,6 @@ import {
DndFilterSelectProps,
} from 'src/explore/components/controls/DndColumnSelectControl/DndFilterSelect';
import { PLACEHOLDER_DATASOURCE } from 'src/dashboard/constants';
import { TimeseriesDefaultFormData } from '@superset-ui/plugin-chart-echarts';
const defaultProps: DndFilterSelectProps = {
type: 'DndFilterSelect',
@@ -56,8 +67,32 @@ afterAll(() => {
window.featureFlags = {};
});
const mockStore = configureStore([thunk]);
const store = mockStore({});
function setup({
value = undefined,
formData = baseFormData,
columns = [],
}: {
value?: AdhocFilter;
formData?: QueryFormData;
columns?: ColumnMeta[];
} = {}) {
return (
<Provider store={store}>
<DndFilterSelect
{...defaultProps}
value={ensureIsArray(value)}
formData={formData}
columns={columns}
/>
</Provider>
);
}
test('renders with default props', async () => {
render(<DndFilterSelect {...defaultProps} />, { useDnd: true });
render(setup(), { useDnd: true });
expect(
await screen.findByText('Drop columns or metrics here'),
).toBeInTheDocument();
@@ -68,7 +103,7 @@ test('renders with value', async () => {
sqlExpression: 'COUNT(*)',
expressionType: EXPRESSION_TYPES.SQL,
});
render(<DndFilterSelect {...defaultProps} value={[value]} />, {
render(setup({ value }), {
useDnd: true,
});
expect(await screen.findByText('COUNT(*)')).toBeInTheDocument();
@@ -76,14 +111,13 @@ test('renders with value', async () => {
test('renders options with saved metric', async () => {
render(
<DndFilterSelect
{...defaultProps}
formData={{
setup({
formData: {
...baseFormData,
...TimeseriesDefaultFormData,
metrics: ['saved_metric'],
}}
/>,
},
}),
{
useDnd: true,
},
@@ -95,17 +129,16 @@ test('renders options with saved metric', async () => {
test('renders options with column', async () => {
render(
<DndFilterSelect
{...defaultProps}
columns={[
setup({
columns: [
{
id: 1,
type: 'VARCHAR',
type_generic: GenericDataType.STRING,
column_name: 'Column',
},
]}
/>,
],
}),
{
useDnd: true,
},
@@ -121,14 +154,13 @@ test('renders options with adhoc metric', async () => {
metric_name: 'avg__num',
});
render(
<DndFilterSelect
{...defaultProps}
formData={{
setup({
formData: {
...baseFormData,
...TimeseriesDefaultFormData,
metrics: [adhocMetric],
}}
/>,
},
}),
{
useDnd: true,
},

View File

@@ -19,6 +19,7 @@
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import {
FeatureFlag,
hasGenericChartAxes,
isFeatureEnabled,
logging,
Metric,
@@ -27,7 +28,12 @@ import {
SupersetClient,
t,
} from '@superset-ui/core';
import { ColumnMeta, withDndFallback } from '@superset-ui/chart-controls';
import {
ColumnMeta,
isColumnMeta,
isTemporalColumn,
withDndFallback,
} from '@superset-ui/chart-controls';
import {
OPERATOR_ENUM_TO_OPERATOR_TYPE,
Operators,
@@ -50,6 +56,7 @@ import { DndItemType } from 'src/explore/components/DndItemType';
import { ControlComponentProps } from 'src/explore/components/Control';
import AdhocFilterControl from '../FilterControl/AdhocFilterControl';
import DndAdhocFilterOption from './DndAdhocFilterOption';
import { useDefaultTimeFilter } from '../DateFilterControl/utils';
const EMPTY_OBJECT = {};
const DND_ACCEPTED_TYPES = [
@@ -324,6 +331,7 @@ const DndFilterSelect = (props: DndFilterSelectProps) => {
togglePopover(true);
}, [togglePopover]);
const defaultTimeFilter = useDefaultTimeFilter();
const adhocFilter = useMemo(() => {
if (isSavedMetric(droppedItem)) {
return new AdhocFilter({
@@ -346,6 +354,15 @@ const DndFilterSelect = (props: DndFilterSelectProps) => {
config.operator = OPERATOR_ENUM_TO_OPERATOR_TYPE[Operators.IN].operation;
config.operatorId = Operators.IN;
}
if (
hasGenericChartAxes &&
isColumnMeta(droppedItem) &&
isTemporalColumn(droppedItem?.column_name, props.datasource)
) {
config.operator = Operators.TEMPORAL_RANGE;
config.operatorId = Operators.TEMPORAL_RANGE;
config.comparator = defaultTimeFilter;
}
return new AdhocFilter(config);
}, [droppedItem]);