mirror of
https://github.com/apache/superset.git
synced 2026-05-07 00:44:26 +00:00
Compare commits
4 Commits
feat/toolt
...
issue34737
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
256bf5a4ba | ||
|
|
49dc8b557f | ||
|
|
d76e5ab529 | ||
|
|
fd1265e9e4 |
@@ -320,4 +320,127 @@ describe('RangeFilterPlugin', () => {
|
|||||||
expect(sliders.length).toBeGreaterThan(0);
|
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;
|
const [row] = data;
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
const { min, max }: { min: number; max: number } = row;
|
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 } =
|
const { groupby, enableSingleValue, enableEmptyFilter, defaultValue } =
|
||||||
formData;
|
formData;
|
||||||
|
|
||||||
@@ -548,6 +572,7 @@ export default function RangeFilterPlugin(props: PluginFilterRangeProps) {
|
|||||||
<Slider
|
<Slider
|
||||||
min={min}
|
min={min}
|
||||||
max={max}
|
max={max}
|
||||||
|
step={sliderStep}
|
||||||
value={Array.isArray(sliderValue) ? sliderValue[0] : sliderValue}
|
value={Array.isArray(sliderValue) ? sliderValue[0] : sliderValue}
|
||||||
onChange={handleSliderChange}
|
onChange={handleSliderChange}
|
||||||
tooltip={{
|
tooltip={{
|
||||||
@@ -562,6 +587,7 @@ export default function RangeFilterPlugin(props: PluginFilterRangeProps) {
|
|||||||
<Slider
|
<Slider
|
||||||
min={min}
|
min={min}
|
||||||
max={max}
|
max={max}
|
||||||
|
step={sliderStep}
|
||||||
range
|
range
|
||||||
value={Array.isArray(sliderValue) ? sliderValue : [min, sliderValue]}
|
value={Array.isArray(sliderValue) ? sliderValue : [min, sliderValue]}
|
||||||
onChange={handleSliderChange}
|
onChange={handleSliderChange}
|
||||||
|
|||||||
Reference in New Issue
Block a user