mirror of
https://github.com/apache/superset.git
synced 2026-04-28 20:44:24 +00:00
Compare commits
4 Commits
fix-explor
...
issue34737
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
256bf5a4ba | ||
|
|
49dc8b557f | ||
|
|
d76e5ab529 | ||
|
|
fd1265e9e4 |
@@ -320,4 +320,127 @@ describe('RangeFilterPlugin', () => {
|
||||
expect(sliders.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Decimal value handling', () => {
|
||||
test('should handle decimal ranges correctly (0.03 to 1.08)', () => {
|
||||
const decimalProps = {
|
||||
queriesData: [
|
||||
{
|
||||
rowcount: 1,
|
||||
colnames: ['min', 'max'],
|
||||
coltypes: [GenericDataType.Numeric, GenericDataType.Numeric],
|
||||
data: [{ min: 0.03, max: 1.08 }],
|
||||
applied_filters: [],
|
||||
rejected_filters: [],
|
||||
},
|
||||
],
|
||||
filterState: { value: [0.5, 0.8] },
|
||||
};
|
||||
getWrapper(decimalProps);
|
||||
|
||||
const inputs = screen.getAllByRole('spinbutton');
|
||||
expect(inputs).toHaveLength(2);
|
||||
expect(inputs[0]).toHaveValue('0.5');
|
||||
expect(inputs[1]).toHaveValue('0.8');
|
||||
|
||||
// Verify the slider exists and can handle decimal values
|
||||
const sliders = screen.getAllByRole('slider');
|
||||
expect(sliders.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
test('should calculate appropriate step size for small decimal ranges', () => {
|
||||
const smallRangeProps = {
|
||||
queriesData: [
|
||||
{
|
||||
rowcount: 1,
|
||||
colnames: ['min', 'max'],
|
||||
coltypes: [GenericDataType.Numeric, GenericDataType.Numeric],
|
||||
data: [{ min: 0.001, max: 0.01 }],
|
||||
applied_filters: [],
|
||||
rejected_filters: [],
|
||||
},
|
||||
],
|
||||
filterState: { value: [0.005, 0.008] },
|
||||
};
|
||||
getWrapper(smallRangeProps);
|
||||
|
||||
const inputs = screen.getAllByRole('spinbutton');
|
||||
expect(inputs[0]).toHaveValue('0.005');
|
||||
expect(inputs[1]).toHaveValue('0.008');
|
||||
});
|
||||
|
||||
test('should handle very large ranges with appropriate step size', () => {
|
||||
const largeRangeProps = {
|
||||
queriesData: [
|
||||
{
|
||||
rowcount: 1,
|
||||
colnames: ['min', 'max'],
|
||||
coltypes: [GenericDataType.Numeric, GenericDataType.Numeric],
|
||||
data: [{ min: 0, max: 1000000 }],
|
||||
applied_filters: [],
|
||||
rejected_filters: [],
|
||||
},
|
||||
],
|
||||
filterState: { value: [100000, 500000] },
|
||||
};
|
||||
getWrapper(largeRangeProps);
|
||||
|
||||
const inputs = screen.getAllByRole('spinbutton');
|
||||
expect(inputs[0]).toHaveValue('100000');
|
||||
expect(inputs[1]).toHaveValue('500000');
|
||||
});
|
||||
|
||||
test('should handle negative decimal ranges', () => {
|
||||
const negativeDecimalProps = {
|
||||
queriesData: [
|
||||
{
|
||||
rowcount: 1,
|
||||
colnames: ['min', 'max'],
|
||||
coltypes: [GenericDataType.Numeric, GenericDataType.Numeric],
|
||||
data: [{ min: -1.5, max: 2.5 }],
|
||||
applied_filters: [],
|
||||
rejected_filters: [],
|
||||
},
|
||||
],
|
||||
filterState: { value: [-0.5, 1.5] },
|
||||
};
|
||||
getWrapper(negativeDecimalProps);
|
||||
|
||||
const inputs = screen.getAllByRole('spinbutton');
|
||||
expect(inputs[0]).toHaveValue('-0.5');
|
||||
expect(inputs[1]).toHaveValue('1.5');
|
||||
});
|
||||
|
||||
test('should allow decimal input via keyboard', async () => {
|
||||
const decimalProps = {
|
||||
queriesData: [
|
||||
{
|
||||
rowcount: 1,
|
||||
colnames: ['min', 'max'],
|
||||
coltypes: [GenericDataType.Numeric, GenericDataType.Numeric],
|
||||
data: [{ min: 0, max: 10 }],
|
||||
applied_filters: [],
|
||||
rejected_filters: [],
|
||||
},
|
||||
],
|
||||
filterState: { value: [null, null] },
|
||||
};
|
||||
getWrapper(decimalProps);
|
||||
|
||||
const inputs = screen.getAllByRole('spinbutton');
|
||||
const fromInput = inputs[0];
|
||||
|
||||
await userEvent.clear(fromInput);
|
||||
await userEvent.type(fromInput, '2.5');
|
||||
await userEvent.tab();
|
||||
|
||||
expect(setDataMask).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
filterState: expect.objectContaining({
|
||||
value: [2.5, null],
|
||||
}),
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -234,6 +234,30 @@ export default function RangeFilterPlugin(props: PluginFilterRangeProps) {
|
||||
const [row] = data;
|
||||
// @ts-expect-error
|
||||
const { min, max }: { min: number; max: number } = row;
|
||||
|
||||
// Calculate appropriate step size for decimal values
|
||||
// Uses a consistent approach for all ranges to avoid floating-point string parsing issues
|
||||
const calculateStep = useCallback((minValue: number, maxValue: number) => {
|
||||
const range = maxValue - minValue;
|
||||
if (range <= 0) return 0.01;
|
||||
|
||||
// Calculate step to give approximately 100 steps across the range
|
||||
const idealSteps = 100;
|
||||
let step = range / idealSteps;
|
||||
|
||||
// Round step to a nice value (0.0001, 0.001, 0.01, 0.1, 1, 10, etc.)
|
||||
const magnitude = Math.pow(10, Math.floor(Math.log10(step)));
|
||||
step = Math.round(step / magnitude) * magnitude;
|
||||
|
||||
// Ensure we don't return 0 for very small ranges
|
||||
return step || 0.0001;
|
||||
}, []);
|
||||
|
||||
const sliderStep = useMemo(
|
||||
() =>
|
||||
min !== undefined && max !== undefined ? calculateStep(min, max) : 0.01,
|
||||
[min, max, calculateStep],
|
||||
);
|
||||
const { groupby, enableSingleValue, enableEmptyFilter, defaultValue } =
|
||||
formData;
|
||||
|
||||
@@ -548,6 +572,7 @@ export default function RangeFilterPlugin(props: PluginFilterRangeProps) {
|
||||
<Slider
|
||||
min={min}
|
||||
max={max}
|
||||
step={sliderStep}
|
||||
value={Array.isArray(sliderValue) ? sliderValue[0] : sliderValue}
|
||||
onChange={handleSliderChange}
|
||||
tooltip={{
|
||||
@@ -562,6 +587,7 @@ export default function RangeFilterPlugin(props: PluginFilterRangeProps) {
|
||||
<Slider
|
||||
min={min}
|
||||
max={max}
|
||||
step={sliderStep}
|
||||
range
|
||||
value={Array.isArray(sliderValue) ? sliderValue : [min, sliderValue]}
|
||||
onChange={handleSliderChange}
|
||||
|
||||
Reference in New Issue
Block a user