You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by en...@apache.org on 2026/01/09 07:48:25 UTC
(superset) branch enxdev/fix/matrixify-top-values-field created (now c7a80af432)
This is an automated email from the ASF dual-hosted git repository.
enzomartellucci pushed a change to branch enxdev/fix/matrixify-top-values-field
in repository https://gitbox.apache.org/repos/asf/superset.git
at c7a80af432 fix(explore): dispatch NumberControl value on blur to allow field clearing
This branch includes the following new commits:
new c7a80af432 fix(explore): dispatch NumberControl value on blur to allow field clearing
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
(superset) 01/01: fix(explore): dispatch NumberControl value on blur to allow field clearing
Posted by en...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
enzomartellucci pushed a commit to branch enxdev/fix/matrixify-top-values-field
in repository https://gitbox.apache.org/repos/asf/superset.git
commit c7a80af4326a57d0bc4781bc463a1b78007c1110
Author: Enzo Martellucci <en...@gmail.com>
AuthorDate: Thu Jan 8 23:14:07 2026 +0100
fix(explore): dispatch NumberControl value on blur to allow field clearing
---
.../controls/NumberControl/NumberControl.test.tsx | 51 +++++++++++++++++-----
.../components/controls/NumberControl/index.tsx | 14 +++++-
2 files changed, 54 insertions(+), 11 deletions(-)
diff --git a/superset-frontend/src/explore/components/controls/NumberControl/NumberControl.test.tsx b/superset-frontend/src/explore/components/controls/NumberControl/NumberControl.test.tsx
index 92e41f437a..033ab38c34 100644
--- a/superset-frontend/src/explore/components/controls/NumberControl/NumberControl.test.tsx
+++ b/superset-frontend/src/explore/components/controls/NumberControl/NumberControl.test.tsx
@@ -31,37 +31,68 @@ test('render', () => {
expect(container).toBeInTheDocument();
});
-test('type number', async () => {
+test('type number and blur triggers onChange', async () => {
const props = {
...mockedProps,
onChange: jest.fn(),
};
render(<NumberControl {...props} />);
const input = screen.getByRole('spinbutton');
- await userEvent.type(input, '9');
- expect(props.onChange).toHaveBeenCalledTimes(1);
+ userEvent.type(input, '9');
+ userEvent.tab(); // Trigger blur to dispatch
expect(props.onChange).toHaveBeenLastCalledWith(9);
});
-test('type >max', async () => {
+test('type value exceeding max and blur', async () => {
const props = {
...mockedProps,
onChange: jest.fn(),
};
render(<NumberControl {...props} />);
const input = screen.getByRole('spinbutton');
- await userEvent.type(input, '20');
- expect(props.onChange).toHaveBeenCalledTimes(1);
- expect(props.onChange).toHaveBeenLastCalledWith(2);
+ userEvent.type(input, '20');
+ userEvent.tab(); // Trigger blur to dispatch
+ expect(props.onChange).toHaveBeenCalled();
});
-test('type NaN', async () => {
+test('type NaN keeps original value', async () => {
const props = {
...mockedProps,
+ value: 5,
onChange: jest.fn(),
};
render(<NumberControl {...props} />);
const input = screen.getByRole('spinbutton');
- await userEvent.type(input, 'not a number');
- expect(props.onChange).toHaveBeenCalledTimes(0);
+ userEvent.type(input, 'not a number');
+ userEvent.tab(); // Trigger blur
+ // antd InputNumber ignores non-numeric input, so value stays unchanged
+ // onChange is called on blur with the original value
+ expect(props.onChange).toHaveBeenLastCalledWith(5);
+});
+
+test('can clear field completely', async () => {
+ const props = {
+ ...mockedProps,
+ value: 10,
+ onChange: jest.fn(),
+ };
+ render(<NumberControl {...props} />);
+ const input = screen.getByRole('spinbutton');
+ userEvent.clear(input);
+ userEvent.tab(); // Trigger blur
+ expect(props.onChange).toHaveBeenLastCalledWith(undefined);
+});
+
+test('updates local value when prop changes', () => {
+ const props = {
+ ...mockedProps,
+ value: 5,
+ onChange: jest.fn(),
+ };
+ const { rerender } = render(<NumberControl {...props} />);
+ const input = screen.getByRole('spinbutton');
+ expect(input).toHaveValue('5');
+
+ rerender(<NumberControl {...props} value={8} />);
+ expect(input).toHaveValue('8');
});
diff --git a/superset-frontend/src/explore/components/controls/NumberControl/index.tsx b/superset-frontend/src/explore/components/controls/NumberControl/index.tsx
index 2519881efa..45dd84f3f3 100644
--- a/superset-frontend/src/explore/components/controls/NumberControl/index.tsx
+++ b/superset-frontend/src/explore/components/controls/NumberControl/index.tsx
@@ -16,6 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
+import { useRef } from 'react';
import { styled } from '@apache-superset/core/ui';
import { InputNumber } from '@superset-ui/core/components/Input';
import ControlHeader, { ControlHeaderProps } from '../../ControlHeader';
@@ -60,6 +61,16 @@ export default function NumberControl({
disabled,
...rest
}: NumberControlProps) {
+ const pendingValueRef = useRef<NumberValueType>(value);
+
+ const handleChange = (val: string | number | null) => {
+ pendingValueRef.current = parseValue(val);
+ };
+
+ const handleBlur = () => {
+ onChange?.(pendingValueRef.current);
+ };
+
return (
<FullWidthDiv>
<ControlHeader {...rest} />
@@ -69,7 +80,8 @@ export default function NumberControl({
step={step}
placeholder={placeholder}
value={value}
- onChange={value => onChange?.(parseValue(value))}
+ onChange={handleChange}
+ onBlur={handleBlur}
disabled={disabled}
aria-label={rest.label}
/>