refactor: preparation for time section migration (#21766)

This commit is contained in:
Yongjie Zhao 2022-10-12 08:38:30 +08:00 committed by GitHub
parent bd3166b603
commit 8f61e3c5d9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
43 changed files with 416 additions and 377 deletions

View File

@ -37,4 +37,4 @@ export { legacySortBy } from './shared-controls/legacySortBy';
export * from './shared-controls/emitFilterControl';
export * from './shared-controls/components';
export * from './types';
export { xAxisMixin, temporalColumnMixin } from './shared-controls/mixins';
export * from './shared-controls/mixins';

View File

@ -16,12 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
import {
ContributionType,
FeatureFlag,
isFeatureEnabled,
t,
} from '@superset-ui/core';
import { ContributionType, hasGenericChartAxes, t } from '@superset-ui/core';
import { ControlPanelSectionConfig } from '../types';
import { emitFilterControl } from '../shared-controls/emitFilterControl';
@ -29,12 +24,8 @@ export const echartsTimeSeriesQuery: ControlPanelSectionConfig = {
label: t('Query'),
expanded: true,
controlSetRows: [
[isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES) ? 'x_axis' : null],
[
isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES)
? 'time_grain_sqla'
: null,
],
[hasGenericChartAxes ? 'x_axis' : null],
[hasGenericChartAxes ? 'time_grain_sqla' : null],
['metrics'],
['groupby'],
[

View File

@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
import { FeatureFlag, isFeatureEnabled, t } from '@superset-ui/core';
import { hasGenericChartAxes, t } from '@superset-ui/core';
import { ControlPanelSectionConfig } from '../types';
// A few standard controls sections that are used internally.
@ -42,11 +42,7 @@ export const genericTime: ControlPanelSectionConfig = {
...baseTimeSection,
controlSetRows: [
['granularity_sqla'],
[
isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES)
? null
: 'time_grain_sqla',
],
[hasGenericChartAxes ? null : 'time_grain_sqla'],
['time_range'],
],
};

View File

@ -30,6 +30,7 @@ import {
SharedControlConfig,
Dataset,
Metric,
isDataset,
} from '../types';
import { DATASET_TIME_COLUMN_OPTION, TIME_FILTER_LABELS } from '../constants';
import {
@ -138,8 +139,8 @@ export const dndAdhocFilterControl: SharedControlConfig<
default: [],
description: '',
mapStateToProps: ({ datasource, form_data }) => ({
columns: datasource?.columns[0]?.hasOwnProperty('filterable')
? (datasource as Dataset)?.columns.filter(c => c.filterable)
columns: isDataset(datasource)
? datasource.columns.filter(c => c.filterable)
: datasource?.columns || [],
savedMetrics: defineSavedMetrics(datasource),
// current active adhoc metrics

View File

@ -35,11 +35,9 @@
*/
import { isEmpty } from 'lodash';
import {
FeatureFlag,
t,
getCategoricalSchemeRegistry,
getSequentialSchemeRegistry,
isFeatureEnabled,
SequentialScheme,
legacyValidateInteger,
ComparisionType,
@ -47,6 +45,8 @@ import {
isPhysicalColumn,
ensureIsArray,
isDefined,
hasGenericChartAxes,
NO_TIME_RANGE,
} from '@superset-ui/core';
import {
@ -205,7 +205,7 @@ const time_grain_sqla: SharedControlConfig<'SelectControl'> = {
choices: (datasource as Dataset)?.time_grain_sqla || [],
}),
visibility: ({ controls }) => {
if (!isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES)) {
if (!hasGenericChartAxes) {
return true;
}
@ -227,7 +227,7 @@ const time_range: SharedControlConfig<'DateFilterControl'> = {
type: 'DateFilterControl',
freeForm: true,
label: TIME_FILTER_LABELS.time_range,
default: t('No filter'), // this value is translated, but the backend wouldn't understand a translated value?
default: NO_TIME_RANGE, // this value is an empty filter constant so shouldn't translate it.
description: t(
'The time range for the visualization. All relative times, e.g. "Last month", ' +
'"Last 7 days", "now", etc. are evaluated on the server using the server\'s ' +
@ -236,9 +236,6 @@ const time_range: SharedControlConfig<'DateFilterControl'> = {
"using the engine's local timezone. Note one can explicitly set the timezone " +
'per the ISO 8601 format if specifying either the start and/or end time.',
),
mapStateToProps: ({ datasource }) => ({
datasource,
}),
};
const row_limit: SharedControlConfig<'SelectControl'> = {

View File

@ -17,8 +17,7 @@
* under the License.
*/
import {
FeatureFlag,
isFeatureEnabled,
hasGenericChartAxes,
QueryFormData,
t,
validateNonEmpty,
@ -41,7 +40,7 @@ export const xAxisMixin = {
validators: [validateNonEmpty],
initialValue: (control: ControlState, state: ControlPanelState | null) => {
if (
isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES) &&
hasGenericChartAxes &&
state?.form_data?.granularity_sqla &&
!state.form_data?.x_axis &&
!control?.value

View File

@ -23,7 +23,7 @@ export const TestDataset: Dataset = {
column_format: {},
columns: [
{
advanced_data_type: null,
advanced_data_type: undefined,
certification_details: null,
certified_by: null,
column_name: 'num',
@ -41,7 +41,7 @@ export const TestDataset: Dataset = {
warning_markdown: null,
},
{
advanced_data_type: null,
advanced_data_type: undefined,
certification_details: null,
certified_by: null,
column_name: 'gender',
@ -59,7 +59,7 @@ export const TestDataset: Dataset = {
warning_markdown: null,
},
{
advanced_data_type: null,
advanced_data_type: undefined,
certification_details: null,
certified_by: null,
column_name: 'state',
@ -77,7 +77,7 @@ export const TestDataset: Dataset = {
warning_markdown: null,
},
{
advanced_data_type: null,
advanced_data_type: undefined,
certification_details: null,
certified_by: null,
column_name: 'ds',
@ -95,7 +95,7 @@ export const TestDataset: Dataset = {
warning_markdown: null,
},
{
advanced_data_type: null,
advanced_data_type: undefined,
certification_details: null,
certified_by: null,
column_name: 'name',

View File

@ -24,7 +24,7 @@ test('get temporal columns from a Dataset', () => {
expect(getTemporalColumns(TestDataset)).toEqual({
temporalColumns: [
{
advanced_data_type: null,
advanced_data_type: undefined,
certification_details: null,
certified_by: null,
column_name: 'ds',

View File

@ -1,11 +1,3 @@
import {
ExtraFormDataAppend,
ExtraFormDataOverrideExtras,
ExtraFormDataOverrideRegular,
ExtraFormDataOverride,
QueryObject,
} from './types';
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
@ -24,7 +16,17 @@ import {
* specific language governing permissions and limitations
* under the License.
*/
import {
ExtraFormDataAppend,
ExtraFormDataOverrideExtras,
ExtraFormDataOverrideRegular,
ExtraFormDataOverride,
QueryObject,
} from './types';
export const DTTM_ALIAS = '__timestamp';
export const DEFAULT_TIME_RANGE = 'No filter'; // TODO: make this configurable per Superset installation
export const NO_TIME_RANGE = 'No filter';
export const EXTRA_FORM_DATA_OVERRIDE_EXTRA_KEYS: (keyof ExtraFormDataOverrideExtras)[] =
['relative_start', 'relative_end', 'time_grain_sqla'];

View File

@ -18,6 +18,8 @@
*/
import {
DTTM_ALIAS,
FeatureFlag,
isFeatureEnabled,
getColumnLabel,
isQueryFormColumn,
QueryFormData,
@ -26,6 +28,10 @@ import {
export const isXAxisSet = (formData: QueryFormData) =>
isQueryFormColumn(formData.x_axis);
export const hasGenericChartAxes = isFeatureEnabled(
FeatureFlag.GENERIC_CHART_AXES,
);
export const getXAxis = (formData: QueryFormData): string | undefined => {
// The formData should be "raw form_data" -- the snake_case version of formData rather than camelCase.
if (!(formData.granularity_sqla || formData.x_axis)) {

View File

@ -29,7 +29,7 @@ export { default as getMetricLabel } from './getMetricLabel';
export { default as DatasourceKey } from './DatasourceKey';
export { default as normalizeOrderBy } from './normalizeOrderBy';
export { normalizeTimeColumn } from './normalizeTimeColumn';
export { getXAxis, isXAxisSet } from './getXAxis';
export { getXAxis, isXAxisSet, hasGenericChartAxes } from './getXAxis';
export * from './types/AnnotationLayer';
export * from './types/QueryFormData';

View File

@ -52,6 +52,12 @@ export interface Column {
expression?: string | null;
database_expression?: string | null;
python_date_format?: string | null;
// used for advanced_data_type
optionName?: string;
filterBy?: string;
value?: string;
advanced_data_type?: string;
}
export function isPhysicalColumn(column?: any): column is PhysicalColumn {

View File

@ -16,12 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
import {
FeatureFlag,
isFeatureEnabled,
smartDateFormatter,
t,
} from '@superset-ui/core';
import { hasGenericChartAxes, smartDateFormatter, t } from '@superset-ui/core';
import {
ControlPanelConfig,
D3_FORMAT_DOCS,
@ -41,12 +36,8 @@ const config: ControlPanelConfig = {
label: t('Query'),
expanded: true,
controlSetRows: [
[isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES) ? 'x_axis' : null],
[
isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES)
? 'time_grain_sqla'
: null,
],
[hasGenericChartAxes ? 'x_axis' : null],
[hasGenericChartAxes ? 'time_grain_sqla' : null],
['metric'],
['adhoc_filters'],
],

View File

@ -17,12 +17,7 @@
* under the License.
*/
import React from 'react';
import {
ensureIsArray,
FeatureFlag,
isFeatureEnabled,
t,
} from '@superset-ui/core';
import { ensureIsArray, hasGenericChartAxes, t } from '@superset-ui/core';
import { cloneDeep } from 'lodash';
import {
ControlPanelConfig,
@ -292,7 +287,7 @@ function createAdvancedAnalyticsSection(
const config: ControlPanelConfig = {
controlPanelSections: [
sections.genericTime,
isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES)
hasGenericChartAxes
? {
label: t('Shared query fields'),
expanded: true,

View File

@ -21,8 +21,7 @@ import {
Behavior,
ChartMetadata,
ChartPlugin,
FeatureFlag,
isFeatureEnabled,
hasGenericChartAxes,
t,
} from '@superset-ui/core';
import buildQuery from './buildQuery';
@ -57,7 +56,7 @@ export default class EchartsTimeseriesChartPlugin extends ChartPlugin<
behaviors: [Behavior.INTERACTIVE_CHART],
category: t('Evolution'),
credits: ['https://echarts.apache.org'],
description: isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES)
description: hasGenericChartAxes
? t(
'Visualize two different series using the same x-axis. Note that both series can be visualized with a different chart type (e.g. 1 using bars and 1 using a line).',
)
@ -70,9 +69,7 @@ export default class EchartsTimeseriesChartPlugin extends ChartPlugin<
AnnotationType.Interval,
AnnotationType.Timeseries,
],
name: isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES)
? t('Mixed Chart')
: t('Mixed Time-Series'),
name: hasGenericChartAxes ? t('Mixed Chart') : t('Mixed Time-Series'),
thumbnail,
tags: [
t('Advanced-Analytics'),

View File

@ -22,8 +22,7 @@ import {
ChartPlugin,
AnnotationType,
Behavior,
isFeatureEnabled,
FeatureFlag,
hasGenericChartAxes,
} from '@superset-ui/core';
import buildQuery from '../buildQuery';
import controlPanel from './controlPanel';
@ -54,7 +53,7 @@ export default class EchartsAreaChartPlugin extends ChartPlugin<
behaviors: [Behavior.INTERACTIVE_CHART],
category: t('Evolution'),
credits: ['https://echarts.apache.org'],
description: isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES)
description: hasGenericChartAxes
? t(
'Area charts are similar to line charts in that they represent variables with the same scale, but area charts stack the metrics on top of each other.',
)
@ -68,7 +67,7 @@ export default class EchartsAreaChartPlugin extends ChartPlugin<
AnnotationType.Interval,
AnnotationType.Timeseries,
],
name: isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES)
name: hasGenericChartAxes
? t('Area Chart v2')
: t('Time-series Area Chart'),
tags: [

View File

@ -21,8 +21,7 @@ import {
Behavior,
ChartMetadata,
ChartPlugin,
FeatureFlag,
isFeatureEnabled,
hasGenericChartAxes,
t,
} from '@superset-ui/core';
import {
@ -60,7 +59,7 @@ export default class EchartsTimeseriesBarChartPlugin extends ChartPlugin<
behaviors: [Behavior.INTERACTIVE_CHART],
category: t('Evolution'),
credits: ['https://echarts.apache.org'],
description: isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES)
description: hasGenericChartAxes
? t('Bar Charts are used to show metrics as a series of bars.')
: t(
'Time-series Bar Charts are used to show the changes in a metric over time as a series of bars.',
@ -76,7 +75,7 @@ export default class EchartsTimeseriesBarChartPlugin extends ChartPlugin<
AnnotationType.Interval,
AnnotationType.Timeseries,
],
name: isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES)
name: hasGenericChartAxes
? t('Bar Chart v2')
: t('Time-series Bar Chart v2'),
tags: [

View File

@ -21,8 +21,7 @@ import {
Behavior,
ChartMetadata,
ChartPlugin,
FeatureFlag,
isFeatureEnabled,
hasGenericChartAxes,
t,
} from '@superset-ui/core';
import {
@ -59,7 +58,7 @@ export default class EchartsTimeseriesLineChartPlugin extends ChartPlugin<
behaviors: [Behavior.INTERACTIVE_CHART],
category: t('Evolution'),
credits: ['https://echarts.apache.org'],
description: isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES)
description: hasGenericChartAxes
? t(
'Line chart is used to visualize measurements taken over a given category. Line chart is a type of chart which displays information as a series of data points connected by straight line segments. It is a basic type of chart common in many fields.',
)
@ -73,7 +72,7 @@ export default class EchartsTimeseriesLineChartPlugin extends ChartPlugin<
AnnotationType.Interval,
AnnotationType.Timeseries,
],
name: isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES)
name: hasGenericChartAxes
? t('Line Chart v2')
: t('Time-series Line Chart'),
tags: [

View File

@ -21,8 +21,7 @@ import {
Behavior,
ChartMetadata,
ChartPlugin,
FeatureFlag,
isFeatureEnabled,
hasGenericChartAxes,
t,
} from '@superset-ui/core';
import {
@ -58,7 +57,7 @@ export default class EchartsTimeseriesScatterChartPlugin extends ChartPlugin<
behaviors: [Behavior.INTERACTIVE_CHART],
category: t('Evolution'),
credits: ['https://echarts.apache.org'],
description: isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES)
description: hasGenericChartAxes
? t(
'Scatter Plot has the horizontal axis in linear units, and the points are connected in order. It shows a statistical relationship between two variables.',
)
@ -72,7 +71,7 @@ export default class EchartsTimeseriesScatterChartPlugin extends ChartPlugin<
AnnotationType.Interval,
AnnotationType.Timeseries,
],
name: isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES)
name: hasGenericChartAxes
? t('Scatter Plot')
: t('Time-series Scatter Plot'),
tags: [

View File

@ -21,8 +21,7 @@ import {
Behavior,
ChartMetadata,
ChartPlugin,
FeatureFlag,
isFeatureEnabled,
hasGenericChartAxes,
t,
} from '@superset-ui/core';
import {
@ -58,7 +57,7 @@ export default class EchartsTimeseriesSmoothLineChartPlugin extends ChartPlugin<
behaviors: [Behavior.INTERACTIVE_CHART],
category: t('Evolution'),
credits: ['https://echarts.apache.org'],
description: isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES)
description: hasGenericChartAxes
? t(
'Smooth-line is a variation of the line chart. Without angles and hard edges, Smooth-line sometimes looks smarter and more professional.',
)
@ -72,7 +71,7 @@ export default class EchartsTimeseriesSmoothLineChartPlugin extends ChartPlugin<
AnnotationType.Interval,
AnnotationType.Timeseries,
],
name: isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES)
name: hasGenericChartAxes
? t('Smooth Line')
: t('Time-series Smooth Line'),
tags: [

View File

@ -21,8 +21,7 @@ import {
Behavior,
ChartMetadata,
ChartPlugin,
FeatureFlag,
isFeatureEnabled,
hasGenericChartAxes,
t,
} from '@superset-ui/core';
import {
@ -49,7 +48,7 @@ export default class EchartsTimeseriesStepChartPlugin extends ChartPlugin<
behaviors: [Behavior.INTERACTIVE_CHART],
category: t('Evolution'),
credits: ['https://echarts.apache.org'],
description: isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES)
description: hasGenericChartAxes
? t(
'Stepped-line graph (also called step chart) is a variation of line chart but with the line forming a series of steps between data points. A step chart can be useful when you want to show the changes that occur at irregular intervals.',
)
@ -63,7 +62,7 @@ export default class EchartsTimeseriesStepChartPlugin extends ChartPlugin<
AnnotationType.Interval,
AnnotationType.Timeseries,
],
name: isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES)
name: hasGenericChartAxes
? t('Stepped Line')
: t('Time-series Stepped Line'),
tags: [

View File

@ -21,8 +21,7 @@ import {
Behavior,
ChartMetadata,
ChartPlugin,
FeatureFlag,
isFeatureEnabled,
hasGenericChartAxes,
t,
} from '@superset-ui/core';
import buildQuery from './buildQuery';
@ -48,7 +47,7 @@ export default class EchartsTimeseriesChartPlugin extends ChartPlugin<
behaviors: [Behavior.INTERACTIVE_CHART],
category: t('Evolution'),
credits: ['https://echarts.apache.org'],
description: isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES)
description: hasGenericChartAxes
? t(
'Swiss army knife for visualizing data. Choose between step, line, scatter, and bar charts. This viz type has many customization options as well.',
)
@ -62,9 +61,7 @@ export default class EchartsTimeseriesChartPlugin extends ChartPlugin<
AnnotationType.Interval,
AnnotationType.Timeseries,
],
name: isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES)
? t('Generic Chart')
: t('Time-series Chart'),
name: hasGenericChartAxes ? t('Generic Chart') : t('Time-series Chart'),
tags: [
t('Advanced-Analytics'),
t('Aesthetic'),

View File

@ -22,8 +22,7 @@ import {
AdhocColumn,
buildQueryContext,
ensureIsArray,
FeatureFlag,
isFeatureEnabled,
hasGenericChartAxes,
isPhysicalColumn,
QueryFormColumn,
QueryFormOrderBy,
@ -42,7 +41,7 @@ export default function buildQuery(formData: PivotTableQueryFormData) {
if (
isPhysicalColumn(col) &&
formData.time_grain_sqla &&
isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES) &&
hasGenericChartAxes &&
formData?.datetime_columns_lookup?.[col]
) {
return {
@ -66,7 +65,7 @@ export default function buildQuery(formData: PivotTableQueryFormData) {
}
return [
{
...(isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES)
...(hasGenericChartAxes
? omit(baseQueryObject, ['extras.time_grain_sqla'])
: baseQueryObject),
orderby: orderBy,

View File

@ -19,9 +19,8 @@
import React from 'react';
import {
ensureIsArray,
FeatureFlag,
hasGenericChartAxes,
isAdhocColumn,
isFeatureEnabled,
isPhysicalColumn,
QueryFormMetric,
smartDateFormatter,
@ -68,7 +67,7 @@ const config: ControlPanelConfig = {
},
],
[
isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES)
hasGenericChartAxes
? {
name: 'time_grain_sqla',
config: {
@ -98,9 +97,7 @@ const config: ControlPanelConfig = {
},
}
: null,
isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES)
? 'datetime_columns_lookup'
: null,
hasGenericChartAxes ? 'datetime_columns_lookup' : null,
],
[
{

View File

@ -20,9 +20,8 @@ import {
AdhocColumn,
buildQueryContext,
ensureIsArray,
FeatureFlag,
getMetricLabel,
isFeatureEnabled,
hasGenericChartAxes,
isPhysicalColumn,
QueryMode,
QueryObject,
@ -104,7 +103,7 @@ const buildQuery: BuildQuery<TableChartFormData> = (
if (
isPhysicalColumn(col) &&
formData.time_grain_sqla &&
isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES) &&
hasGenericChartAxes &&
formData?.datetime_columns_lookup?.[col]
) {
return {

View File

@ -23,6 +23,7 @@ import {
ensureIsArray,
FeatureFlag,
GenericDataType,
hasGenericChartAxes,
isAdhocColumn,
isFeatureEnabled,
isPhysicalColumn,
@ -189,7 +190,7 @@ const config: ControlPanelConfig = {
},
],
[
isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES) && isAggMode
hasGenericChartAxes && isAggMode
? {
name: 'time_grain_sqla',
config: {
@ -217,9 +218,7 @@ const config: ControlPanelConfig = {
},
}
: null,
isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES) && isAggMode
? 'datetime_columns_lookup'
: null,
hasGenericChartAxes && isAggMode ? 'datetime_columns_lookup' : null,
],
[
{

View File

@ -25,8 +25,9 @@ import {
FilterState,
isFeatureEnabled,
NativeFilterType,
NO_TIME_RANGE,
} from '@superset-ui/core';
import { NO_TIME_RANGE, TIME_FILTER_MAP } from 'src/explore/constants';
import { TIME_FILTER_MAP } from 'src/explore/constants';
import { getChartIdsInFilterBoxScope } from 'src/dashboard/util/activeDashboardFilters';
import { ChartConfiguration } from 'src/dashboard/reducers/types';
import { Layout } from 'src/dashboard/types';

View File

@ -26,7 +26,7 @@ import { testWithId } from 'src/utils/testUtils';
import { FeatureFlag } from 'src/featureFlags';
import { Preset } from '@superset-ui/core';
import { TimeFilterPlugin, SelectFilterPlugin } from 'src/filters/components';
import { DATE_FILTER_CONTROL_TEST_ID } from 'src/explore/components/controls/DateFilterControl/DateFilterLabel';
import { DATE_FILTER_CONTROL_TEST_ID } from 'src/explore/components/controls/DateFilterControl';
import fetchMock from 'fetch-mock';
import { waitFor } from '@testing-library/react';
import FilterBar, { FILTER_BAR_TEST_ID } from '.';

View File

@ -17,17 +17,14 @@
* under the License.
*/
import React, { useState, useEffect, useMemo } from 'react';
import rison from 'rison';
import { css, SupersetClient, styled, t, useTheme } from '@superset-ui/core';
import {
buildTimeRangeString,
formatTimeRange,
COMMON_RANGE_VALUES_SET,
CALENDAR_RANGE_VALUES_SET,
FRAME_OPTIONS,
customTimeRangeDecode,
} from 'src/explore/components/controls/DateFilterControl/utils';
import { getClientErrorObject } from 'src/utils/getClientErrorObject';
css,
styled,
t,
useTheme,
DEFAULT_TIME_RANGE,
NO_TIME_RANGE,
} from '@superset-ui/core';
import Button from 'src/components/Button';
import ControlHeader from 'src/explore/components/ControlHeader';
import Label, { Type } from 'src/components/Label';
@ -35,14 +32,18 @@ import { Divider } from 'src/components';
import Icons from 'src/components/Icons';
import Select from 'src/components/Select/Select';
import { Tooltip } from 'src/components/Tooltip';
import { DEFAULT_TIME_RANGE } from 'src/explore/constants';
import { useDebouncedEffect } from 'src/explore/exploreUtils';
import { SLOW_DEBOUNCE } from 'src/constants';
import { testWithId } from 'src/utils/testUtils';
import { noOp } from 'src/utils/common';
import { FrameType } from './types';
import ControlPopover from '../ControlPopover/ControlPopover';
import { DateFilterControlProps, FrameType } from './types';
import {
fetchTimeRange,
FRAME_OPTIONS,
getDateFilterControlTestId,
guessFrame,
} from './utils';
import {
CommonFrame,
CalendarFrame,
@ -50,42 +51,6 @@ import {
AdvancedFrame,
} from './components';
const guessFrame = (timeRange: string): FrameType => {
if (COMMON_RANGE_VALUES_SET.has(timeRange)) {
return 'Common';
}
if (CALENDAR_RANGE_VALUES_SET.has(timeRange)) {
return 'Calendar';
}
if (timeRange === 'No filter') {
return 'No filter';
}
if (customTimeRangeDecode(timeRange).matchedFlag) {
return 'Custom';
}
return 'Advanced';
};
const fetchTimeRange = async (timeRange: string) => {
const query = rison.encode_uri(timeRange);
const endpoint = `/api/v1/time_range/?q=${query}`;
try {
const response = await SupersetClient.get({ endpoint });
const timeRangeString = buildTimeRangeString(
response?.json?.result?.since || '',
response?.json?.result?.until || '',
);
return {
value: formatTimeRange(timeRangeString),
};
} catch (response) {
const clientError = await getClientErrorObject(response);
return {
error: clientError.message || clientError.error,
};
}
};
const StyledPopover = styled(ControlPopover)``;
const StyledRangeType = styled(Select)`
width: 272px;
@ -161,20 +126,6 @@ const IconWrapper = styled.span`
}
`;
interface DateFilterControlProps {
name: string;
onChange: (timeRange: string) => void;
value?: string;
type?: Type;
onOpenPopover?: () => void;
onClosePopover?: () => void;
}
export const DATE_FILTER_CONTROL_TEST_ID = 'date-filter-control';
export const getDateFilterControlTestId = testWithId(
DATE_FILTER_CONTROL_TEST_ID,
);
export default function DateFilterLabel(props: DateFilterControlProps) {
const {
value = DEFAULT_TIME_RANGE,
@ -195,6 +146,12 @@ export default function DateFilterLabel(props: DateFilterControlProps) {
const [tooltipTitle, setTooltipTitle] = useState<string>(value);
useEffect(() => {
if (value === NO_TIME_RANGE) {
setActualTimeRange(NO_TIME_RANGE);
setTooltipTitle(NO_TIME_RANGE);
setValidTimeRange(true);
return;
}
fetchTimeRange(value).then(({ value: actualRange, error }) => {
if (error) {
setEvalResponse(error || '');
@ -235,6 +192,12 @@ export default function DateFilterLabel(props: DateFilterControlProps) {
useDebouncedEffect(
() => {
if (timeRangeValue === NO_TIME_RANGE) {
setEvalResponse(NO_TIME_RANGE);
setLastFetchedTimeRange(NO_TIME_RANGE);
setValidTimeRange(true);
return;
}
if (lastFetchedTimeRange !== timeRangeValue) {
fetchTimeRange(timeRangeValue).then(({ value: actualRange, error }) => {
if (error) {
@ -279,11 +242,11 @@ export default function DateFilterLabel(props: DateFilterControlProps) {
}
};
function onChangeFrame(value: string) {
if (value === 'No filter') {
setTimeRangeValue('No filter');
function onChangeFrame(value: FrameType) {
if (value === NO_TIME_RANGE) {
setTimeRangeValue(NO_TIME_RANGE);
}
setFrame(value as FrameType);
setFrame(value);
}
const theme = useTheme();
@ -354,10 +317,6 @@ export default function DateFilterLabel(props: DateFilterControlProps) {
</IconWrapper>
);
const overlayStyle = {
width: '600px',
};
return (
<>
<ControlHeader {...props} />
@ -369,7 +328,7 @@ export default function DateFilterLabel(props: DateFilterControlProps) {
defaultVisible={show}
visible={show}
onVisibleChange={togglePopover}
overlayStyle={overlayStyle}
overlayStyle={{ width: '600px' }}
>
<Tooltip placement="top" title={tooltipTitle}>
<Label className="pointer" data-test="time-range-trigger">

View File

@ -24,20 +24,20 @@ import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls';
import { FrameComponentProps } from 'src/explore/components/controls/DateFilterControl/types';
import DateFunctionTooltip from './DateFunctionTooltip';
export function AdvancedFrame(props: FrameComponentProps) {
function getAdvancedRange(value: string): string {
if (value.includes(SEPARATOR)) {
return value;
}
if (value.startsWith('Last')) {
return [value, ''].join(SEPARATOR);
}
if (value.startsWith('Next')) {
return ['', value].join(SEPARATOR);
}
return SEPARATOR;
function getAdvancedRange(value: string): string {
if (value.includes(SEPARATOR)) {
return value;
}
if (value.startsWith('Last')) {
return [value, ''].join(SEPARATOR);
}
if (value.startsWith('Next')) {
return ['', value].join(SEPARATOR);
}
return SEPARATOR;
}
export function AdvancedFrame(props: FrameComponentProps) {
const advancedRange = getAdvancedRange(props.value || '');
const [since, until] = advancedRange.split(SEPARATOR);
if (advancedRange !== props.value) {

View File

@ -17,3 +17,8 @@
* under the License.
*/
export { default } from './DateFilterLabel';
export {
DATE_FILTER_CONTROL_TEST_ID,
fetchTimeRange,
guessFrame,
} from './utils';

View File

@ -16,6 +16,8 @@
* specific language governing permissions and limitations
* under the License.
*/
import { Type } from 'src/components/Label';
export type SelectOptionType = {
value: string;
label: string;
@ -89,3 +91,12 @@ export type FrameComponentProps = {
onChange: (timeRange: string) => void;
value: string;
};
export interface DateFilterControlProps {
name: string;
onChange: (timeRange: string) => void;
value?: string;
type?: Type;
onOpenPopover?: () => void;
onClosePopover?: () => void;
}

View File

@ -26,6 +26,7 @@ import {
CommonRangeType,
CalendarRangeType,
} from 'src/explore/components/controls/DateFilterControl/types';
import { testWithId } from 'src/utils/testUtils';
export const FRAME_OPTIONS: SelectOptionType[] = [
{ value: 'Common', label: t('Last') },
@ -131,3 +132,8 @@ export const LOCALE_MAPPING = {
sl: 'sl_SI',
nl: 'nl_NL',
};
export const DATE_FILTER_CONTROL_TEST_ID = 'date-filter-control';
export const getDateFilterControlTestId = testWithId(
DATE_FILTER_CONTROL_TEST_ID,
);

View File

@ -16,6 +16,16 @@
* specific language governing permissions and limitations
* under the License.
*/
import rison from 'rison';
import { SupersetClient, NO_TIME_RANGE } from '@superset-ui/core';
import { getClientErrorObject } from 'src/utils/getClientErrorObject';
import {
COMMON_RANGE_VALUES_SET,
CALENDAR_RANGE_VALUES_SET,
customTimeRangeDecode,
} from '.';
import { FrameType } from '../types';
export const SEPARATOR = ' : ';
export const buildTimeRangeString = (since: string, until: string): string =>
@ -24,11 +34,53 @@ export const buildTimeRangeString = (since: string, until: string): string =>
const formatDateEndpoint = (dttm: string, isStart?: boolean): string =>
dttm.replace('T00:00:00', '') || (isStart ? '-∞' : '∞');
export const formatTimeRange = (timeRange: string) => {
export const formatTimeRange = (
timeRange: string,
columnPlaceholder = 'col',
) => {
const splitDateRange = timeRange.split(SEPARATOR);
if (splitDateRange.length === 1) return timeRange;
return `${formatDateEndpoint(
splitDateRange[0],
true,
)} col < ${formatDateEndpoint(splitDateRange[1])}`;
)} ${columnPlaceholder} < ${formatDateEndpoint(splitDateRange[1])}`;
};
export const guessFrame = (timeRange: string): FrameType => {
if (COMMON_RANGE_VALUES_SET.has(timeRange)) {
return 'Common';
}
if (CALENDAR_RANGE_VALUES_SET.has(timeRange)) {
return 'Calendar';
}
if (timeRange === NO_TIME_RANGE) {
return 'No filter';
}
if (customTimeRangeDecode(timeRange).matchedFlag) {
return 'Custom';
}
return 'Advanced';
};
export const fetchTimeRange = async (
timeRange: string,
columnPlaceholder = 'col',
) => {
const query = rison.encode_uri(timeRange);
const endpoint = `/api/v1/time_range/?q=${query}`;
try {
const response = await SupersetClient.get({ endpoint });
const timeRangeString = buildTimeRangeString(
response?.json?.result?.since || '',
response?.json?.result?.until || '',
);
return {
value: formatTimeRange(timeRangeString, columnPlaceholder),
};
} catch (response) {
const clientError = await getClientErrorObject(response);
return {
error: clientError.message || clientError.error || response.statusText,
};
}
};

View File

@ -0,0 +1,69 @@
/**
* 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 React from 'react';
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 OptionWrapper from './OptionWrapper';
export interface DndAdhocFilterOptionProps {
adhocFilter: AdhocFilter;
onFilterEdit: (changedFilter: AdhocFilter) => void;
onClickClose: (index: number) => void;
onShiftOptions: (dragIndex: number, hoverIndex: number) => void;
options: OptionSortType[];
datasource: Record<string, any>;
partitionColumn?: string;
index: number;
}
export default function DndAdhocFilterOption({
adhocFilter,
options,
datasource,
onFilterEdit,
onShiftOptions,
onClickClose,
partitionColumn,
index,
}: DndAdhocFilterOptionProps) {
return (
<AdhocFilterPopoverTrigger
key={index}
adhocFilter={adhocFilter}
options={options}
datasource={datasource}
onFilterEdit={onFilterEdit}
partitionColumn={partitionColumn}
>
<OptionWrapper
key={index}
index={index}
label={adhocFilter.getDefaultLabel()}
tooltipTitle={adhocFilter.getTooltipTitle()}
clickClose={onClickClose}
onShiftOptions={onShiftOptions}
type={DndItemType.FilterOption}
withCaret
isExtra={adhocFilter.isExtra}
/>
</AdhocFilterPopoverTrigger>
);
}

View File

@ -35,7 +35,6 @@ import {
import { Datasource, OptionSortType } from 'src/explore/types';
import { OptionValueType } from 'src/explore/components/controls/DndColumnSelectControl/types';
import AdhocFilterPopoverTrigger from 'src/explore/components/controls/FilterControl/AdhocFilterPopoverTrigger';
import OptionWrapper from 'src/explore/components/controls/DndColumnSelectControl/OptionWrapper';
import DndSelectLabel from 'src/explore/components/controls/DndColumnSelectControl/DndSelectLabel';
import AdhocFilter, {
CLAUSES,
@ -50,6 +49,7 @@ import {
import { DndItemType } from 'src/explore/components/DndItemType';
import { ControlComponentProps } from 'src/explore/components/Control';
import AdhocFilterControl from '../FilterControl/AdhocFilterControl';
import DndAdhocFilterOption from './DndAdhocFilterOption';
const EMPTY_OBJECT = {};
const DND_ACCEPTED_TYPES = [
@ -296,32 +296,18 @@ const DndFilterSelect = (props: DndFilterSelectProps) => {
const valuesRenderer = useCallback(
() =>
values.map((adhocFilter: AdhocFilter, index: number) => {
const label = adhocFilter.getDefaultLabel();
const tooltipTitle = adhocFilter.getTooltipTitle();
return (
<AdhocFilterPopoverTrigger
key={index}
adhocFilter={adhocFilter}
options={options}
datasource={datasource}
onFilterEdit={onFilterEdit}
partitionColumn={partitionColumn}
>
<OptionWrapper
key={index}
index={index}
label={label}
tooltipTitle={tooltipTitle}
clickClose={onClickClose}
onShiftOptions={onShiftOptions}
type={DndItemType.FilterOption}
withCaret
isExtra={adhocFilter.isExtra}
/>
</AdhocFilterPopoverTrigger>
);
}),
values.map((adhocFilter: AdhocFilter, index: number) => (
<DndAdhocFilterOption
index={index}
adhocFilter={adhocFilter}
options={options}
datasource={datasource}
onFilterEdit={onFilterEdit}
partitionColumn={partitionColumn}
onClickClose={onClickClose}
onShiftOptions={onShiftOptions}
/>
)),
[
onClickClose,
onFilterEdit,
@ -401,9 +387,7 @@ const DndFilterSelect = (props: DndFilterSelectProps) => {
visible={newFilterPopoverVisible}
togglePopover={togglePopover}
closePopover={closePopover}
>
<div />
</AdhocFilterPopoverTrigger>
/>
</>
);
};

View File

@ -39,6 +39,7 @@ import { Tooltip } from 'src/components/Tooltip';
import { Input } from 'src/components/Input';
import { optionLabel } from 'src/utils/common';
import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags';
import { ColumnMeta } from '@superset-ui/chart-controls';
import useAdvancedDataTypes from './useAdvancedDataTypes';
const StyledInput = styled(Input)`
@ -61,20 +62,9 @@ const SelectWithLabel = styled(Select)<{ labelText: string }>`
}
`;
export interface SimpleColumnType {
id: number;
column_name: string;
expression?: string;
type: string;
optionName?: string;
filterBy?: string;
value?: string;
advanced_data_type?: string;
}
export interface SimpleExpressionType {
expressionType: keyof typeof EXPRESSION_TYPES;
column: SimpleColumnType;
column: ColumnMeta;
aggregate: keyof typeof AGGREGATES;
label: string;
}
@ -89,7 +79,7 @@ export interface MetricColumnType {
}
export type ColumnType =
| SimpleColumnType
| ColumnMeta
| SimpleExpressionType
| SQLExpressionType
| MetricColumnType;
@ -100,7 +90,7 @@ export interface Props {
options: ColumnType[];
datasource: {
id: string;
columns: SimpleColumnType[];
columns: ColumnMeta[];
type: string;
filter_select: boolean;
};
@ -410,31 +400,35 @@ const AdhocFilterEditPopoverSimpleTabContent: React.FC<Props> = props => {
}
}, [props.adhocFilter.comparator]);
return (
// another name for columns, just for following previous naming.
const subjectComponent = (
<Select
css={(theme: SupersetTheme) => ({
marginTop: theme.gridUnit * 4,
marginBottom: theme.gridUnit * 4,
})}
data-test="select-element"
options={columns.map(column => ({
value:
('column_name' in column && column.column_name) ||
('optionName' in column && column.optionName) ||
'',
label:
('saved_metric_name' in column && column.saved_metric_name) ||
('column_name' in column && column.column_name) ||
('label' in column && column.label),
key:
('id' in column && column.id) ||
('optionName' in column && column.optionName) ||
undefined,
customLabel: renderSubjectOptionLabel(column),
}))}
{...subjectSelectProps}
/>
);
const operatorsAndOperandComponent = (
<>
<Select
css={(theme: SupersetTheme) => ({
marginTop: theme.gridUnit * 4,
marginBottom: theme.gridUnit * 4,
})}
data-test="select-element"
options={columns.map(column => ({
value:
('column_name' in column && column.column_name) ||
('optionName' in column && column.optionName) ||
'',
label:
('saved_metric_name' in column && column.saved_metric_name) ||
('column_name' in column && column.column_name) ||
('label' in column && column.label),
key:
('id' in column && column.id) ||
('optionName' in column && column.optionName) ||
undefined,
customLabel: renderSubjectOptionLabel(column),
}))}
{...subjectSelectProps}
/>
<Select
css={(theme: SupersetTheme) => ({ marginBottom: theme.gridUnit * 4 })}
options={(props.operators ?? OPERATORS_OPTIONS)
@ -484,6 +478,12 @@ const AdhocFilterEditPopoverSimpleTabContent: React.FC<Props> = props => {
)}
</>
);
return (
<>
{subjectComponent}
{operatorsAndOperandComponent}
</>
);
};
export default AdhocFilterEditPopoverSimpleTabContent;

View File

@ -25,7 +25,7 @@ import AdhocFilter, {
EXPRESSION_TYPES,
CLAUSES,
} from 'src/explore/components/controls/FilterControl/AdhocFilter';
import AdhocFilterOption from '.';
import AdhocFilterOption, { AdhocFilterOptionProps } from '.';
const simpleAdhocFilter = new AdhocFilter({
expressionType: EXPRESSION_TYPES.SIMPLE,
@ -44,18 +44,18 @@ const options = [
const mockedProps = {
adhocFilter: simpleAdhocFilter,
onFilterEdit: jest.fn(),
onRemoveFilter: jest.fn(),
options,
sections: [],
operators: [],
datasource: {},
partitionColumn: '',
onMoveLabel: jest.fn(),
onDropLabel: jest.fn(),
index: 1,
};
const setup = (props: {
adhocFilter: typeof simpleAdhocFilter;
onFilterEdit: () => void;
options: {
type: string;
column_name: string;
id: number;
}[];
}) => (
const setup = (props: AdhocFilterOptionProps) => (
<DndProvider backend={HTML5Backend}>
<AdhocFilterOption {...props} />
</DndProvider>

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 React from 'react';
import PropTypes from 'prop-types';
import adhocMetricType from 'src/explore/components/controls/MetricControl/adhocMetricType';
import { OptionControlLabel } from 'src/explore/components/controls/OptionControls';
import { DndItemType } from 'src/explore/components/DndItemType';
import columnType from 'src/explore/components/controls/FilterControl/columnType';
import AdhocFilterPopoverTrigger from 'src/explore/components/controls/FilterControl/AdhocFilterPopoverTrigger';
import AdhocFilter from 'src/explore/components/controls/FilterControl/AdhocFilter';
const propTypes = {
adhocFilter: PropTypes.instanceOf(AdhocFilter).isRequired,
onFilterEdit: PropTypes.func.isRequired,
onRemoveFilter: PropTypes.func,
options: PropTypes.arrayOf(
PropTypes.oneOfType([
columnType,
PropTypes.shape({ saved_metric_name: PropTypes.string.isRequired }),
adhocMetricType,
]),
).isRequired,
sections: PropTypes.arrayOf(PropTypes.string),
operators: PropTypes.arrayOf(PropTypes.string),
datasource: PropTypes.object,
partitionColumn: PropTypes.string,
onMoveLabel: PropTypes.func,
onDropLabel: PropTypes.func,
index: PropTypes.number,
};
const AdhocFilterOption = ({
adhocFilter,
options,
datasource,
onFilterEdit,
onRemoveFilter,
partitionColumn,
onMoveLabel,
onDropLabel,
index,
sections,
operators,
}) => (
<AdhocFilterPopoverTrigger
sections={sections}
operators={operators}
adhocFilter={adhocFilter}
options={options}
datasource={datasource}
onFilterEdit={onFilterEdit}
partitionColumn={partitionColumn}
>
<OptionControlLabel
label={adhocFilter.getDefaultLabel()}
tooltipTitle={adhocFilter.getTooltipTitle()}
onRemove={onRemoveFilter}
onMoveLabel={onMoveLabel}
onDropLabel={onDropLabel}
index={index}
type={DndItemType.FilterOption}
withCaret
isExtra={adhocFilter.isExtra}
/>
</AdhocFilterPopoverTrigger>
);
export default AdhocFilterOption;
AdhocFilterOption.propTypes = propTypes;

View File

@ -0,0 +1,77 @@
/**
* 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 React from 'react';
import { OptionControlLabel } from 'src/explore/components/controls/OptionControls';
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 { Operators } from 'src/explore/constants';
export interface AdhocFilterOptionProps {
adhocFilter: AdhocFilter;
onFilterEdit: () => void;
onRemoveFilter: () => void;
options: OptionSortType[];
sections: string[];
operators: Operators[];
datasource: Record<string, any>;
partitionColumn: string;
onMoveLabel: () => void;
onDropLabel: () => void;
index: number;
}
export default function AdhocFilterOption({
adhocFilter,
options,
datasource,
onFilterEdit,
onRemoveFilter,
partitionColumn,
onMoveLabel,
onDropLabel,
index,
sections,
operators,
}: AdhocFilterOptionProps) {
return (
<AdhocFilterPopoverTrigger
sections={sections}
operators={operators}
adhocFilter={adhocFilter}
options={options}
datasource={datasource}
onFilterEdit={onFilterEdit}
partitionColumn={partitionColumn}
>
<OptionControlLabel
label={adhocFilter.getDefaultLabel()}
tooltipTitle={adhocFilter.getTooltipTitle()}
onRemove={onRemoveFilter}
onMoveLabel={onMoveLabel}
onDropLabel={onDropLabel}
index={index}
type={DndItemType.FilterOption}
withCaret
isExtra={adhocFilter.isExtra}
/>
</AdhocFilterPopoverTrigger>
);
}

View File

@ -142,10 +142,6 @@ export const TIME_FILTER_MAP = {
granularity: '__granularity',
};
// TODO: make this configurable per Superset installation
export const DEFAULT_TIME_RANGE = 'No filter';
export const NO_TIME_RANGE = 'No filter';
export enum FILTER_BOX_MIGRATION_STATES {
CONVERTED = 'CONVERTED',
NOOP = 'NOOP',

View File

@ -29,8 +29,8 @@ import {
AdhocFilter,
isFreeFormAdhocFilter,
isSimpleAdhocFilter,
NO_TIME_RANGE,
} from '@superset-ui/core';
import { NO_TIME_RANGE } from '../constants';
const simpleFilterToAdhoc = (
filterClause: QueryObjectFilterClause,

View File

@ -16,10 +16,9 @@
* specific language governing permissions and limitations
* under the License.
*/
import { styled } from '@superset-ui/core';
import { styled, NO_TIME_RANGE } from '@superset-ui/core';
import React, { useCallback, useEffect } from 'react';
import DateFilterControl from 'src/explore/components/controls/DateFilterControl';
import { NO_TIME_RANGE } from 'src/explore/constants';
import { PluginFilterTimeProps } from './types';
import { FilterPluginStyle } from '../common';