feat: adding XAxis to BigNumberTrend (#21577)

This commit is contained in:
Yongjie Zhao 2022-09-26 20:14:17 +08:00 committed by GitHub
parent 5d51555c46
commit f4646f8edb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 89 additions and 60 deletions

View File

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

View File

@ -20,10 +20,16 @@ import {
FeatureFlag, FeatureFlag,
isFeatureEnabled, isFeatureEnabled,
QueryFormData, QueryFormData,
QueryResponse,
t, t,
validateNonEmpty, validateNonEmpty,
} from '@superset-ui/core'; } from '@superset-ui/core';
import { ControlPanelState, ControlState } from '../types'; import {
BaseControlConfig,
ControlPanelState,
ControlState,
Dataset,
} from '../types';
const getAxisLabel = ( const getAxisLabel = (
formData: QueryFormData, formData: QueryFormData,
@ -32,7 +38,7 @@ const getAxisLabel = (
? { label: t('Y-axis'), description: t('Dimension to use on y-axis.') } ? { label: t('Y-axis'), description: t('Dimension to use on y-axis.') }
: { label: t('X-axis'), description: t('Dimension to use on x-axis.') }; : { label: t('X-axis'), description: t('Dimension to use on x-axis.') };
export const xAxisControlConfig = { export const xAxisMixin = {
label: (state: ControlPanelState) => getAxisLabel(state?.form_data).label, label: (state: ControlPanelState) => getAxisLabel(state?.form_data).label,
multi: false, multi: false,
description: (state: ControlPanelState) => description: (state: ControlPanelState) =>
@ -51,3 +57,28 @@ export const xAxisControlConfig = {
}, },
default: undefined, default: undefined,
}; };
export const temporalColumnMixin: Pick<BaseControlConfig, 'mapStateToProps'> = {
mapStateToProps: ({ datasource }) => {
if (datasource?.columns[0]?.hasOwnProperty('column_name')) {
const temporalColumns =
(datasource as Dataset)?.columns?.filter(c => c.is_dttm) ?? [];
return {
options: temporalColumns,
default:
(datasource as Dataset)?.main_dttm_col ||
temporalColumns[0]?.column_name ||
null,
isTemporal: true,
};
}
const sortedQueryColumns = (datasource as QueryResponse)?.columns?.sort(
query => (query?.is_dttm ? -1 : 1),
);
return {
options: sortedQueryColumns,
default: sortedQueryColumns[0]?.name || null,
isTemporal: true,
};
},
};

View File

@ -22,7 +22,6 @@ import {
FeatureFlag, FeatureFlag,
isFeatureEnabled, isFeatureEnabled,
QueryColumn, QueryColumn,
QueryResponse,
t, t,
validateNonEmpty, validateNonEmpty,
} from '@superset-ui/core'; } from '@superset-ui/core';
@ -39,8 +38,9 @@ import {
ColumnOption, ColumnOption,
ColumnMeta, ColumnMeta,
FilterOption, FilterOption,
temporalColumnMixin,
} from '..'; } from '..';
import { xAxisControlConfig } from './constants'; import { xAxisMixin } from './constants';
type Control = { type Control = {
savedMetrics?: Metric[] | null; savedMetrics?: Metric[] | null;
@ -231,6 +231,7 @@ export const dndSecondaryMetricControl: typeof dndAdhocMetricControl = {
export const dndGranularitySqlaControl: typeof dndSeriesControl = { export const dndGranularitySqlaControl: typeof dndSeriesControl = {
...dndSeriesControl, ...dndSeriesControl,
...temporalColumnMixin,
label: TIME_FILTER_LABELS.granularity_sqla, label: TIME_FILTER_LABELS.granularity_sqla,
description: t( description: t(
'The time column for the visualization. Note that you ' + 'The time column for the visualization. Note that you ' +
@ -247,33 +248,11 @@ export const dndGranularitySqlaControl: typeof dndSeriesControl = {
optionRenderer: (c: ColumnMeta) => <ColumnOption showType column={c} />, optionRenderer: (c: ColumnMeta) => <ColumnOption showType column={c} />,
valueRenderer: (c: ColumnMeta) => <ColumnOption column={c} />, valueRenderer: (c: ColumnMeta) => <ColumnOption column={c} />,
valueKey: 'column_name', valueKey: 'column_name',
mapStateToProps: ({ datasource }) => {
if (datasource?.columns[0]?.hasOwnProperty('column_name')) {
const temporalColumns =
(datasource as Dataset)?.columns?.filter(c => c.is_dttm) ?? [];
return {
options: temporalColumns,
default:
(datasource as Dataset)?.main_dttm_col ||
temporalColumns[0]?.column_name ||
null,
isTemporal: true,
};
}
const sortedQueryColumns = (datasource as QueryResponse)?.columns?.sort(
query => (query?.is_dttm ? -1 : 1),
);
return {
options: sortedQueryColumns,
default: sortedQueryColumns[0]?.name || null,
isTemporal: true,
};
},
}; };
export const dndXAxisControl: typeof dndGroupByControl = { export const dndXAxisControl: typeof dndGroupByControl = {
...dndGroupByControl, ...dndGroupByControl,
...xAxisControlConfig, ...xAxisMixin,
}; };
export function withDndFallback( export function withDndFallback(

View File

@ -18,7 +18,9 @@
*/ */
import { import {
buildQueryContext, buildQueryContext,
DTTM_ALIAS, ensureIsArray,
getXAxis,
isXAxisSet,
QueryFormData, QueryFormData,
} from '@superset-ui/core'; } from '@superset-ui/core';
import { import {
@ -29,25 +31,19 @@ import {
} from '@superset-ui/chart-controls'; } from '@superset-ui/chart-controls';
export default function buildQuery(formData: QueryFormData) { export default function buildQuery(formData: QueryFormData) {
return buildQueryContext(formData, baseQueryObject => { return buildQueryContext(formData, baseQueryObject => [
const { x_axis } = formData; {
const is_timeseries = x_axis === DTTM_ALIAS || !x_axis; ...baseQueryObject,
columns: [
return [ ...(isXAxisSet(formData) ? ensureIsArray(getXAxis(formData)) : []),
{ ],
...baseQueryObject, ...(isXAxisSet(formData) ? {} : { is_timeseries: true }),
is_timeseries: true, post_processing: [
post_processing: [ pivotOperator(formData, baseQueryObject),
pivotOperator(formData, { rollingWindowOperator(formData, baseQueryObject),
...baseQueryObject, resampleOperator(formData, baseQueryObject),
index: x_axis, flattenOperator(formData, baseQueryObject),
is_timeseries, ],
}), },
rollingWindowOperator(formData, baseQueryObject), ]);
resampleOperator(formData, baseQueryObject),
flattenOperator(formData, baseQueryObject),
],
},
];
});
} }

View File

@ -16,7 +16,12 @@
* specific language governing permissions and limitations * specific language governing permissions and limitations
* under the License. * under the License.
*/ */
import { smartDateFormatter, t } from '@superset-ui/core'; import {
FeatureFlag,
isFeatureEnabled,
smartDateFormatter,
t,
} from '@superset-ui/core';
import { import {
ControlPanelConfig, ControlPanelConfig,
D3_FORMAT_DOCS, D3_FORMAT_DOCS,
@ -24,17 +29,27 @@ import {
formatSelectOptions, formatSelectOptions,
getStandardizedControls, getStandardizedControls,
sections, sections,
temporalColumnMixin,
} from '@superset-ui/chart-controls'; } from '@superset-ui/chart-controls';
import React from 'react'; import React from 'react';
import { headerFontSize, subheaderFontSize } from '../sharedControls'; import { headerFontSize, subheaderFontSize } from '../sharedControls';
const config: ControlPanelConfig = { const config: ControlPanelConfig = {
controlPanelSections: [ controlPanelSections: [
sections.legacyTimeseriesTime, sections.genericTime,
{ {
label: t('Query'), label: t('Query'),
expanded: true, expanded: true,
controlSetRows: [['metric'], ['adhoc_filters']], controlSetRows: [
[isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES) ? 'x_axis' : null],
[
isFeatureEnabled(FeatureFlag.GENERIC_CHART_AXES)
? 'time_grain_sqla'
: null,
],
['metric'],
['adhoc_filters'],
],
}, },
{ {
label: t('Options'), label: t('Options'),
@ -270,6 +285,10 @@ const config: ControlPanelConfig = {
y_axis_format: { y_axis_format: {
label: t('Number format'), label: t('Number format'),
}, },
x_axis: {
label: t('TEMPORAL X-AXIS'),
...temporalColumnMixin,
},
}, },
formDataOverrides: formData => ({ formDataOverrides: formData => ({
...formData, ...formData,

View File

@ -17,17 +17,16 @@
* under the License. * under the License.
*/ */
import { import {
DTTM_ALIAS,
extractTimegrain, extractTimegrain,
getNumberFormatter, getNumberFormatter,
NumberFormats, NumberFormats,
QueryFormData,
GenericDataType, GenericDataType,
getMetricLabel, getMetricLabel,
t, t,
smartDateVerboseFormatter, smartDateVerboseFormatter,
NumberFormatter, NumberFormatter,
TimeFormatter, TimeFormatter,
getXAxis,
} from '@superset-ui/core'; } from '@superset-ui/core';
import { EChartsCoreOption, graphic } from 'echarts'; import { EChartsCoreOption, graphic } from 'echarts';
import { import {
@ -88,7 +87,7 @@ export default function transformProps(
yAxisFormat, yAxisFormat,
timeRangeFixed, timeRangeFixed,
} = formData; } = formData;
const granularity = extractTimegrain(rawFormData as QueryFormData); const granularity = extractTimegrain(rawFormData);
const { const {
data = [], data = [],
colnames = [], colnames = [],
@ -103,10 +102,11 @@ export default function transformProps(
const { r, g, b } = colorPicker; const { r, g, b } = colorPicker;
const mainColor = `rgb(${r}, ${g}, ${b})`; const mainColor = `rgb(${r}, ${g}, ${b})`;
const timeColumn = getXAxis(rawFormData) as string;
let trendLineData; let trendLineData;
let percentChange = 0; let percentChange = 0;
let bigNumber = data.length === 0 ? null : data[0][metricName]; let bigNumber = data.length === 0 ? null : data[0][metricName];
let timestamp = data.length === 0 ? null : data[0][DTTM_ALIAS]; let timestamp = data.length === 0 ? null : data[0][timeColumn];
let bigNumberFallback; let bigNumberFallback;
const metricColtypeIndex = colnames.findIndex(name => name === metricName); const metricColtypeIndex = colnames.findIndex(name => name === metricName);
@ -115,7 +115,7 @@ export default function transformProps(
if (data.length > 0) { if (data.length > 0) {
const sortedData = (data as BigNumberDatum[]) const sortedData = (data as BigNumberDatum[])
.map(d => [d[DTTM_ALIAS], parseMetricValue(d[metricName])]) .map(d => [d[timeColumn], parseMetricValue(d[metricName])])
// sort in time descending order // sort in time descending order
.sort((a, b) => (a[0] !== null && b[0] !== null ? b[0] - a[0] : 0)); .sort((a, b) => (a[0] !== null && b[0] !== null ? b[0] - a[0] : 0));

View File

@ -43,7 +43,7 @@ export type BigNumberWithTrendlineFormData = BigNumberTotalFormData & {
compareLag?: string | number; compareLag?: string | number;
}; };
export type BigNumberTotalChartProps = ChartProps & { export type BigNumberTotalChartProps = ChartProps<QueryFormData> & {
formData: BigNumberTotalFormData; formData: BigNumberTotalFormData;
queriesData: (ChartDataResponseResult & { queriesData: (ChartDataResponseResult & {
data?: BigNumberDatum[]; data?: BigNumberDatum[];

View File

@ -36,7 +36,8 @@ const formData = {
a: 1, a: 1,
}, },
compareLag: 1, compareLag: 1,
timeGrainSqla: 'P3M' as TimeGranularity, timeGrainSqla: TimeGranularity.QUARTER,
granularitySqla: 'ds',
compareSuffix: 'over last quarter', compareSuffix: 'over last quarter',
viz_type: 'big_number', viz_type: 'big_number',
yAxisFormat: '.3s', yAxisFormat: '.3s',
@ -44,6 +45,7 @@ const formData = {
}; };
const rawFormData = { const rawFormData = {
datasource: '1__table',
metric: 'value', metric: 'value',
color_picker: { color_picker: {
r: 0, r: 0,
@ -52,7 +54,8 @@ const rawFormData = {
a: 1, a: 1,
}, },
compare_lag: 1, compare_lag: 1,
time_grain_sqla: 'P3M' as TimeGranularity, time_grain_sqla: TimeGranularity.QUARTER,
granularity_sqla: 'ds',
compare_suffix: 'over last quarter', compare_suffix: 'over last quarter',
viz_type: 'big_number', viz_type: 'big_number',
y_axis_format: '.3s', y_axis_format: '.3s',