mirror of
https://github.com/apache/superset.git
synced 2024-09-06 22:07:34 -04:00
feat: adding XAxis to BigNumberTrend (#21577)
This commit is contained in:
parent
5d51555c46
commit
f4646f8edb
@ -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';
|
||||||
|
@ -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,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
@ -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(
|
||||||
|
@ -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;
|
|
||||||
|
|
||||||
return [
|
|
||||||
{
|
{
|
||||||
...baseQueryObject,
|
...baseQueryObject,
|
||||||
is_timeseries: true,
|
columns: [
|
||||||
|
...(isXAxisSet(formData) ? ensureIsArray(getXAxis(formData)) : []),
|
||||||
|
],
|
||||||
|
...(isXAxisSet(formData) ? {} : { is_timeseries: true }),
|
||||||
post_processing: [
|
post_processing: [
|
||||||
pivotOperator(formData, {
|
pivotOperator(formData, baseQueryObject),
|
||||||
...baseQueryObject,
|
|
||||||
index: x_axis,
|
|
||||||
is_timeseries,
|
|
||||||
}),
|
|
||||||
rollingWindowOperator(formData, baseQueryObject),
|
rollingWindowOperator(formData, baseQueryObject),
|
||||||
resampleOperator(formData, baseQueryObject),
|
resampleOperator(formData, baseQueryObject),
|
||||||
flattenOperator(formData, baseQueryObject),
|
flattenOperator(formData, baseQueryObject),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
]);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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));
|
||||||
|
|
||||||
|
@ -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[];
|
||||||
|
@ -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',
|
||||||
|
Loading…
Reference in New Issue
Block a user