fix: remove sort values on stacked totals (#31333)
This commit is contained in:
parent
5867b87680
commit
15fbb195e9
|
|
@ -19,17 +19,23 @@
|
|||
|
||||
import { QueryFormMetric, isSavedMetric, isAdhocMetricSimple } from './types';
|
||||
|
||||
export default function getMetricLabel(metric: QueryFormMetric): string {
|
||||
export default function getMetricLabel(
|
||||
metric: QueryFormMetric,
|
||||
index?: number,
|
||||
queryFormMetrics?: QueryFormMetric[],
|
||||
verboseMap?: Record<string, string>,
|
||||
): string {
|
||||
let label = '';
|
||||
if (isSavedMetric(metric)) {
|
||||
return metric;
|
||||
}
|
||||
if (metric.label) {
|
||||
return metric.label;
|
||||
}
|
||||
if (isAdhocMetricSimple(metric)) {
|
||||
return `${metric.aggregate}(${
|
||||
label = metric;
|
||||
} else if (metric.label) {
|
||||
({ label } = metric);
|
||||
} else if (isAdhocMetricSimple(metric)) {
|
||||
label = `${metric.aggregate}(${
|
||||
metric.column.columnName || metric.column.column_name
|
||||
})`;
|
||||
} else {
|
||||
label = metric.sqlExpression;
|
||||
}
|
||||
return metric.sqlExpression;
|
||||
return verboseMap?.[label] || label;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import {
|
|||
ensureIsArray,
|
||||
GenericDataType,
|
||||
getCustomFormatter,
|
||||
getMetricLabel,
|
||||
getNumberFormatter,
|
||||
getXAxisLabel,
|
||||
isDefined,
|
||||
|
|
@ -291,12 +292,20 @@ export default function transformProps(
|
|||
const showValueIndexesB = extractShowValueIndexes(rawSeriesB, {
|
||||
stack,
|
||||
});
|
||||
|
||||
const metricsLabels = metrics
|
||||
.map(metric => getMetricLabel(metric, undefined, undefined, verboseMap))
|
||||
.filter((label): label is string => label !== undefined);
|
||||
const metricsLabelsB = metricsB.map((metric: QueryFormMetric) =>
|
||||
getMetricLabel(metric, undefined, undefined, verboseMap),
|
||||
);
|
||||
|
||||
const { totalStackedValues, thresholdValues } = extractDataTotalValues(
|
||||
rebasedDataA,
|
||||
{
|
||||
stack,
|
||||
percentageThreshold,
|
||||
xAxisCol: xAxisLabel,
|
||||
metricsLabels,
|
||||
},
|
||||
);
|
||||
const {
|
||||
|
|
@ -305,7 +314,7 @@ export default function transformProps(
|
|||
} = extractDataTotalValues(rebasedDataB, {
|
||||
stack: Boolean(stackB),
|
||||
percentageThreshold,
|
||||
xAxisCol: xAxisLabel,
|
||||
metricsLabels: metricsLabelsB,
|
||||
});
|
||||
|
||||
annotationLayers
|
||||
|
|
|
|||
|
|
@ -215,14 +215,18 @@ export default function transformProps(
|
|||
) {
|
||||
xAxisLabel = verboseMap[xAxisLabel];
|
||||
}
|
||||
const metricsLabels = metrics
|
||||
.map(metric => getMetricLabel(metric, undefined, undefined, verboseMap))
|
||||
.filter((label): label is string => label !== undefined);
|
||||
const isHorizontal = orientation === OrientationType.Horizontal;
|
||||
|
||||
const { totalStackedValues, thresholdValues } = extractDataTotalValues(
|
||||
rebasedData,
|
||||
{
|
||||
stack,
|
||||
percentageThreshold,
|
||||
xAxisCol: xAxisLabel,
|
||||
legendState,
|
||||
metricsLabels,
|
||||
},
|
||||
);
|
||||
const extraMetricLabels = extractExtraMetrics(chartProps.rawFormData).map(
|
||||
|
|
@ -296,7 +300,6 @@ export default function transformProps(
|
|||
const entryName = String(entry.name || '');
|
||||
const seriesName = inverted[entryName] || entryName;
|
||||
const colorScaleKey = getOriginalSeries(seriesName, array);
|
||||
|
||||
const transformedSeries = transformSeries(
|
||||
entry,
|
||||
colorScale,
|
||||
|
|
|
|||
|
|
@ -60,8 +60,8 @@ export function extractDataTotalValues(
|
|||
opts: {
|
||||
stack: StackType;
|
||||
percentageThreshold: number;
|
||||
xAxisCol: string;
|
||||
legendState?: LegendState;
|
||||
metricsLabels: string[];
|
||||
},
|
||||
): {
|
||||
totalStackedValues: number[];
|
||||
|
|
@ -69,11 +69,11 @@ export function extractDataTotalValues(
|
|||
} {
|
||||
const totalStackedValues: number[] = [];
|
||||
const thresholdValues: number[] = [];
|
||||
const { stack, percentageThreshold, xAxisCol, legendState } = opts;
|
||||
const { stack, percentageThreshold, legendState, metricsLabels } = opts;
|
||||
if (stack) {
|
||||
data.forEach(datum => {
|
||||
const values = Object.keys(datum).reduce((prev, curr) => {
|
||||
if (curr === xAxisCol) {
|
||||
if (!metricsLabels.includes(curr)) {
|
||||
return prev;
|
||||
}
|
||||
if (legendState && !legendState[curr]) {
|
||||
|
|
|
|||
|
|
@ -36,15 +36,25 @@ describe('EchartsTimeseries transformProps', () => {
|
|||
colorScheme: 'bnbColors',
|
||||
datasource: '3__table',
|
||||
granularity_sqla: 'ds',
|
||||
metric: 'sum__num',
|
||||
metrics: ['sum__num'],
|
||||
groupby: ['foo', 'bar'],
|
||||
viz_type: 'my_viz',
|
||||
};
|
||||
const queriesData = [
|
||||
{
|
||||
data: [
|
||||
{ 'San Francisco': 1, 'New York': 2, __timestamp: 599616000000 },
|
||||
{ 'San Francisco': 3, 'New York': 4, __timestamp: 599916000000 },
|
||||
{
|
||||
'San Francisco': 1,
|
||||
'New York': 2,
|
||||
__timestamp: 599616000000,
|
||||
sum__num: 4,
|
||||
},
|
||||
{
|
||||
'San Francisco': 3,
|
||||
'New York': 4,
|
||||
__timestamp: 599916000000,
|
||||
sum__num: 8,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
|
@ -64,7 +74,7 @@ describe('EchartsTimeseries transformProps', () => {
|
|||
height: 600,
|
||||
echartOptions: expect.objectContaining({
|
||||
legend: expect.objectContaining({
|
||||
data: ['San Francisco', 'New York'],
|
||||
data: ['sum__num', 'San Francisco', 'New York'],
|
||||
}),
|
||||
series: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
|
|
@ -101,7 +111,7 @@ describe('EchartsTimeseries transformProps', () => {
|
|||
height: 600,
|
||||
echartOptions: expect.objectContaining({
|
||||
legend: expect.objectContaining({
|
||||
data: ['San Francisco', 'New York'],
|
||||
data: ['sum__num', 'San Francisco', 'New York'],
|
||||
}),
|
||||
series: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
|
|
@ -146,7 +156,7 @@ describe('EchartsTimeseries transformProps', () => {
|
|||
height: 600,
|
||||
echartOptions: expect.objectContaining({
|
||||
legend: expect.objectContaining({
|
||||
data: ['San Francisco', 'New York', 'My Formula'],
|
||||
data: ['sum__num', 'San Francisco', 'New York', 'My Formula'],
|
||||
}),
|
||||
series: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
|
|
@ -274,7 +284,7 @@ describe('EchartsTimeseries transformProps', () => {
|
|||
expect.objectContaining({
|
||||
echartOptions: expect.objectContaining({
|
||||
legend: expect.objectContaining({
|
||||
data: ['San Francisco', 'New York', 'My Line'],
|
||||
data: ['sum__num', 'San Francisco', 'New York', 'My Line'],
|
||||
}),
|
||||
series: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
|
|
@ -420,7 +430,7 @@ describe('Does transformProps transform series correctly', () => {
|
|||
colorScheme: 'bnbColors',
|
||||
datasource: '3__table',
|
||||
granularity_sqla: 'ds',
|
||||
metric: 'sum__num',
|
||||
metrics: ['sum__num'],
|
||||
groupby: ['foo', 'bar'],
|
||||
showValue: true,
|
||||
stack: true,
|
||||
|
|
@ -435,24 +445,28 @@ describe('Does transformProps transform series correctly', () => {
|
|||
'New York': 2,
|
||||
Boston: 1,
|
||||
__timestamp: 599616000000,
|
||||
sum__num: 4,
|
||||
},
|
||||
{
|
||||
'San Francisco': 3,
|
||||
'New York': 4,
|
||||
Boston: 1,
|
||||
__timestamp: 599916000000,
|
||||
sum__num: 8,
|
||||
},
|
||||
{
|
||||
'San Francisco': 5,
|
||||
'New York': 8,
|
||||
Boston: 6,
|
||||
__timestamp: 600216000000,
|
||||
sum__num: 19,
|
||||
},
|
||||
{
|
||||
'San Francisco': 2,
|
||||
'New York': 7,
|
||||
Boston: 2,
|
||||
__timestamp: 600516000000,
|
||||
sum__num: 11,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
@ -468,7 +482,7 @@ describe('Does transformProps transform series correctly', () => {
|
|||
const totalStackedValues = queriesData[0].data.reduce(
|
||||
(totals, currentStack) => {
|
||||
const total = Object.keys(currentStack).reduce((stackSum, key) => {
|
||||
if (key === '__timestamp') return stackSum;
|
||||
if (key === '__timestamp' || key === 'sum__num') return stackSum;
|
||||
return stackSum + currentStack[key as keyof typeof currentStack];
|
||||
}, 0);
|
||||
totals.push(total);
|
||||
|
|
@ -561,7 +575,6 @@ describe('Does transformProps transform series correctly', () => {
|
|||
const expectedThresholds = totalStackedValues.map(
|
||||
total => ((formData.percentageThreshold || 0) / 100) * total,
|
||||
);
|
||||
|
||||
transformedSeries.forEach((series, seriesIndex) => {
|
||||
expect(series.label.show).toBe(true);
|
||||
series.data.forEach((value, dataIndex) => {
|
||||
|
|
@ -576,7 +589,6 @@ describe('Does transformProps transform series correctly', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should not apply percentage threshold when showValue is true and stack is false', () => {
|
||||
const updatedChartPropsConfig = {
|
||||
...chartPropsConfig,
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import {
|
|||
calculateLowerLogTick,
|
||||
dedupSeries,
|
||||
extractGroupbyLabel,
|
||||
extractDataTotalValues,
|
||||
extractSeries,
|
||||
extractShowValueIndexes,
|
||||
extractTooltipKeys,
|
||||
|
|
@ -1085,6 +1086,123 @@ const forecastValue = [
|
|||
},
|
||||
];
|
||||
|
||||
describe('extractDataTotalValues', () => {
|
||||
it('test_extractDataTotalValues_withStack', () => {
|
||||
const data: DataRecord[] = [
|
||||
{ metric1: 10, metric2: 20, xAxisCol: '2021-01-01' },
|
||||
{ metric1: 15, metric2: 25, xAxisCol: '2021-01-02' },
|
||||
];
|
||||
const metricsLabels = ['metric1', 'metric2'];
|
||||
const opts = {
|
||||
stack: true,
|
||||
percentageThreshold: 10,
|
||||
metricsLabels,
|
||||
};
|
||||
const result = extractDataTotalValues(data, opts);
|
||||
expect(result.totalStackedValues).toEqual([30, 40]);
|
||||
expect(result.thresholdValues).toEqual([3, 4]);
|
||||
});
|
||||
|
||||
it('should calculate total and threshold values with stack option enabled', () => {
|
||||
const data: DataRecord[] = [
|
||||
{ metric1: 10, metric2: 20, xAxisCol: '2021-01-01' },
|
||||
{ metric1: 15, metric2: 25, xAxisCol: '2021-01-02' },
|
||||
];
|
||||
const metricsLabels = ['metric1', 'metric2'];
|
||||
const opts = {
|
||||
stack: true,
|
||||
percentageThreshold: 10,
|
||||
metricsLabels,
|
||||
};
|
||||
const result = extractDataTotalValues(data, opts);
|
||||
expect(result.totalStackedValues).toEqual([30, 40]);
|
||||
expect(result.thresholdValues).toEqual([3, 4]);
|
||||
});
|
||||
|
||||
it('should handle empty data array', () => {
|
||||
const data: DataRecord[] = [];
|
||||
const metricsLabels: string[] = [];
|
||||
const opts = {
|
||||
stack: true,
|
||||
percentageThreshold: 10,
|
||||
metricsLabels,
|
||||
};
|
||||
const result = extractDataTotalValues(data, opts);
|
||||
expect(result.totalStackedValues).toEqual([]);
|
||||
expect(result.thresholdValues).toEqual([]);
|
||||
});
|
||||
|
||||
it('should calculate total and threshold values with stack option disabled', () => {
|
||||
const data: DataRecord[] = [
|
||||
{ metric1: 10, metric2: 20, xAxisCol: '2021-01-01' },
|
||||
{ metric1: 15, metric2: 25, xAxisCol: '2021-01-02' },
|
||||
];
|
||||
const metricsLabels = ['metric1', 'metric2'];
|
||||
const opts = {
|
||||
stack: false,
|
||||
percentageThreshold: 10,
|
||||
metricsLabels,
|
||||
};
|
||||
const result = extractDataTotalValues(data, opts);
|
||||
expect(result.totalStackedValues).toEqual([]);
|
||||
expect(result.thresholdValues).toEqual([]);
|
||||
});
|
||||
|
||||
it('should handle data with null or undefined values', () => {
|
||||
const data: DataRecord[] = [
|
||||
{ my_x_axis: 'abc', x: 1, y: 0, z: 2 },
|
||||
{ my_x_axis: 'foo', x: null, y: 10, z: 5 },
|
||||
{ my_x_axis: null, x: 4, y: 3, z: 7 },
|
||||
];
|
||||
const metricsLabels = ['x', 'y', 'z'];
|
||||
const opts = {
|
||||
stack: true,
|
||||
percentageThreshold: 10,
|
||||
metricsLabels,
|
||||
};
|
||||
const result = extractDataTotalValues(data, opts);
|
||||
expect(result.totalStackedValues).toEqual([3, 15, 14]);
|
||||
expect(result.thresholdValues).toEqual([
|
||||
0.30000000000000004, 1.5, 1.4000000000000001,
|
||||
]);
|
||||
});
|
||||
|
||||
it('should handle different percentage thresholds', () => {
|
||||
const data: DataRecord[] = [
|
||||
{ metric1: 10, metric2: 20, xAxisCol: '2021-01-01' },
|
||||
{ metric1: 15, metric2: 25, xAxisCol: '2021-01-02' },
|
||||
];
|
||||
const metricsLabels = ['metric1', 'metric2'];
|
||||
const opts = {
|
||||
stack: true,
|
||||
percentageThreshold: 50,
|
||||
metricsLabels,
|
||||
};
|
||||
const result = extractDataTotalValues(data, opts);
|
||||
expect(result.totalStackedValues).toEqual([30, 40]);
|
||||
expect(result.thresholdValues).toEqual([15, 20]);
|
||||
});
|
||||
it('should not add datum not in metrics to the total value when stacked', () => {
|
||||
const data: DataRecord[] = [
|
||||
{ xAxisCol: 'foo', xAxisSort: 10, val: 345 },
|
||||
{ xAxisCol: 'bar', xAxisSort: 20, val: 2432 },
|
||||
{ xAxisCol: 'baz', xAxisSort: 30, val: 4543 },
|
||||
];
|
||||
const metricsLabels = ['val'];
|
||||
const opts = {
|
||||
stack: true,
|
||||
percentageThreshold: 50,
|
||||
metricsLabels,
|
||||
};
|
||||
|
||||
const result = extractDataTotalValues(data, opts);
|
||||
|
||||
// Assuming extractDataTotalValues returns the total value
|
||||
// without including the 'xAxisCol' category
|
||||
expect(result.totalStackedValues).toEqual([345, 2432, 4543]); // 10 + 20, excluding the 'xAxisCol' category
|
||||
});
|
||||
});
|
||||
|
||||
test('extractTooltipKeys with rich tooltip', () => {
|
||||
const result = extractTooltipKeys(forecastValue, 1, true, false);
|
||||
expect(result).toEqual(['foo', 'bar']);
|
||||
|
|
|
|||
Loading…
Reference in New Issue