fix(Gauge): clearing previously set min and max values in a gauge chart sets the data labels to 0 (#36425)

Co-authored-by: Diego Pucci <diegopucci.me@gmail.com>
This commit is contained in:
Enzo Martellucci
2025-12-05 18:16:43 +01:00
committed by GitHub
parent 8c603a6f8b
commit 236e000398
2 changed files with 419 additions and 2 deletions

View File

@@ -281,6 +281,411 @@ describe('Echarts Gauge transformProps', () => {
});
});
describe('Min/Max calculation and axis labels', () => {
const baseFormData: SqlaFormData = {
datasource: '26__table',
viz_type: VizType.Gauge,
metric: 'count',
adhocFilters: [],
rowLimit: 10,
startAngle: 225,
endAngle: -45,
colorScheme: 'SUPERSET_DEFAULT',
fontSize: 14,
numberFormat: 'SMART_NUMBER',
valueFormatter: '{value}',
showPointer: true,
animation: true,
showAxisTick: false,
showSplitLine: false,
splitNumber: 10,
showProgress: true,
overlap: true,
roundCap: false,
groupby: [],
};
it('should use provided minVal and maxVal when valid numbers', () => {
const formData: SqlaFormData = {
...baseFormData,
minVal: 10,
maxVal: 100,
};
const queriesData = [
{
colnames: ['count'],
data: [{ count: 50 }, { count: 75 }],
},
];
const chartProps = new ChartProps({
formData,
width: 800,
height: 600,
queriesData,
theme: supersetTheme,
});
const result = transformProps(chartProps as EchartsGaugeChartProps);
const series = (result.echartOptions as any).series[0];
expect(series.min).toBe(10);
expect(series.max).toBe(100);
});
it('should calculate min/max from data when minVal is null', () => {
const formData: SqlaFormData = {
...baseFormData,
minVal: null,
maxVal: 100,
};
const queriesData = [
{
colnames: ['count'],
data: [{ count: 20 }, { count: 80 }],
},
];
const chartProps = new ChartProps({
formData,
width: 800,
height: 600,
queriesData,
theme: supersetTheme,
});
const result = transformProps(chartProps as EchartsGaugeChartProps);
const series = (result.echartOptions as any).series[0];
expect(series.min).toBe(0);
expect(series.max).toBe(100);
});
it('should calculate min/max from data when maxVal is null', () => {
const formData: SqlaFormData = {
...baseFormData,
minVal: 0,
maxVal: null,
};
const queriesData = [
{
colnames: ['count'],
data: [{ count: 20 }, { count: 80 }],
},
];
const chartProps = new ChartProps({
formData,
width: 800,
height: 600,
queriesData,
theme: supersetTheme,
});
const result = transformProps(chartProps as EchartsGaugeChartProps);
const series = (result.echartOptions as any).series[0];
expect(series.min).toBe(0);
expect(series.max).toBe(160);
});
it('should calculate min/max from data when both are null', () => {
const formData: SqlaFormData = {
...baseFormData,
minVal: null,
maxVal: null,
};
const queriesData = [
{
colnames: ['count'],
data: [{ count: 15 }, { count: 45 }],
},
];
const chartProps = new ChartProps({
formData,
width: 800,
height: 600,
queriesData,
theme: supersetTheme,
});
const result = transformProps(chartProps as EchartsGaugeChartProps);
const series = (result.echartOptions as any).series[0];
expect(series.min).toBe(0);
expect(series.max).toBe(90);
});
it('should calculate min/max from data when minVal is empty string', () => {
const formData: SqlaFormData = {
...baseFormData,
minVal: '' as any,
maxVal: 200,
};
const queriesData = [
{
colnames: ['count'],
data: [{ count: 30 }, { count: 60 }],
},
];
const chartProps = new ChartProps({
formData,
width: 800,
height: 600,
queriesData,
theme: supersetTheme,
});
const result = transformProps(chartProps as EchartsGaugeChartProps);
const series = (result.echartOptions as any).series[0];
expect(series.min).toBe(0);
expect(series.max).toBe(200);
});
it('should calculate min/max from data when maxVal is invalid string', () => {
const formData: SqlaFormData = {
...baseFormData,
minVal: 0,
maxVal: 'invalid' as any,
};
const queriesData = [
{
colnames: ['count'],
data: [{ count: 25 }, { count: 75 }],
},
];
const chartProps = new ChartProps({
formData,
width: 800,
height: 600,
queriesData,
theme: supersetTheme,
});
const result = transformProps(chartProps as EchartsGaugeChartProps);
const series = (result.echartOptions as any).series[0];
expect(series.min).toBe(0);
expect(series.max).toBe(150);
});
it('should handle negative values in min/max calculation', () => {
const formData: SqlaFormData = {
...baseFormData,
minVal: null,
maxVal: null,
};
const queriesData = [
{
colnames: ['count'],
data: [{ count: -20 }, { count: 40 }],
},
];
const chartProps = new ChartProps({
formData,
width: 800,
height: 600,
queriesData,
theme: supersetTheme,
});
const result = transformProps(chartProps as EchartsGaugeChartProps);
const series = (result.echartOptions as any).series[0];
expect(series.min).toBe(-40);
expect(series.max).toBe(80);
});
it('should generate axis labels correctly based on min, max, and splitNumber', () => {
const formData: SqlaFormData = {
...baseFormData,
minVal: 0,
maxVal: 100,
splitNumber: 5,
};
const queriesData = [
{
colnames: ['count'],
data: [{ count: 50 }],
},
];
const chartProps = new ChartProps({
formData,
width: 800,
height: 600,
queriesData,
theme: supersetTheme,
});
const result = transformProps(chartProps as EchartsGaugeChartProps);
const series = (result.echartOptions as any).series[0];
expect(series.min).toBe(0);
expect(series.max).toBe(100);
expect(series.splitNumber).toBe(5);
expect(series.axisLabel).toBeDefined();
expect(series.axisLabel.formatter).toBeDefined();
});
it('should calculate axis label length correctly for different number formats', () => {
const formData: SqlaFormData = {
...baseFormData,
minVal: 0,
maxVal: 1000,
splitNumber: 10,
numberFormat: ',d',
};
const queriesData = [
{
colnames: ['count'],
data: [{ count: 500 }],
},
];
const chartProps = new ChartProps({
formData,
width: 800,
height: 600,
queriesData,
theme: supersetTheme,
});
const result = transformProps(chartProps as EchartsGaugeChartProps);
const series = (result.echartOptions as any).series[0];
expect(series.axisLabel).toBeDefined();
expect(series.axisLabel.formatter).toBeDefined();
expect(typeof series.axisLabel.formatter).toBe('function');
});
it('should integrate interval bounds and colors with calculated min/max', () => {
const formData: SqlaFormData = {
...baseFormData,
minVal: null,
maxVal: null,
intervals: '20,60',
intervalColorIndices: '1,2',
};
const queriesData = [
{
colnames: ['count'],
data: [{ count: 10 }, { count: 50 }],
},
];
const chartProps = new ChartProps({
formData,
width: 800,
height: 600,
queriesData,
theme: supersetTheme,
});
const result = transformProps(chartProps as EchartsGaugeChartProps);
const series = (result.echartOptions as any).series[0];
expect(series.min).toBe(0);
expect(series.max).toBe(100);
const { axisLine } = series;
expect(axisLine.lineStyle.color).toEqual(
expect.arrayContaining([
expect.arrayContaining([expect.any(Number), expect.any(String)]),
]),
);
});
it('should handle zero values in data correctly', () => {
const formData: SqlaFormData = {
...baseFormData,
minVal: null,
maxVal: null,
};
const queriesData = [
{
colnames: ['count'],
data: [{ count: 0 }, { count: 0 }],
},
];
const chartProps = new ChartProps({
formData,
width: 800,
height: 600,
queriesData,
theme: supersetTheme,
});
const result = transformProps(chartProps as EchartsGaugeChartProps);
const series = (result.echartOptions as any).series[0];
expect(series.min).toBe(0);
expect(series.max).toBe(0);
});
it('should handle string minVal/maxVal that can be converted to numbers', () => {
const formData: SqlaFormData = {
...baseFormData,
minVal: '10' as any,
maxVal: '200' as any,
};
const queriesData = [
{
colnames: ['count'],
data: [{ count: 50 }],
},
];
const chartProps = new ChartProps({
formData,
width: 800,
height: 600,
queriesData,
theme: supersetTheme,
});
const result = transformProps(chartProps as EchartsGaugeChartProps);
const series = (result.echartOptions as any).series[0];
expect(series.min).toBe(10);
expect(series.max).toBe(200);
});
it('should handle different splitNumber values', () => {
const formData: SqlaFormData = {
...baseFormData,
minVal: 0,
maxVal: 100,
splitNumber: 20,
};
const queriesData = [
{
colnames: ['count'],
data: [{ count: 50 }],
},
];
const chartProps = new ChartProps({
formData,
width: 800,
height: 600,
queriesData,
theme: supersetTheme,
});
const result = transformProps(chartProps as EchartsGaugeChartProps);
const series = (result.echartOptions as any).series[0];
expect(series.splitNumber).toBe(20);
});
});
describe('getIntervalBoundsAndColors', () => {
it('should generate correct interval bounds and colors', () => {
const colorFn = CategoricalColorNamespace.getScale(