This is an automated email from the ASF dual-hosted git repository.

alexandrusoare pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/superset.git


The following commit(s) were added to refs/heads/master by this push:
     new 6a801ff94f6 fix(explore): sync FilterInput value with parent filter 
state (#42342)
6a801ff94f6 is described below

commit 6a801ff94f6216c8e6f1de0df2b8422c437cec95
Author: Alexandru Soare <[email protected]>
AuthorDate: Wed Jul 29 13:26:49 2026 +0300

    fix(explore): sync FilterInput value with parent filter state (#42342)
---
 .../DataTableControl/FilterInput.test.tsx          | 30 +++++++++++++++++---
 .../explore/components/DataTableControl/index.tsx  | 33 +++++++++++++++++++---
 .../components/DataTableControls.tsx               |  7 ++++-
 .../DataTablesPane/components/SamplesPane.tsx      |  2 ++
 .../components/SingleQueryResultPane.tsx           |  1 +
 .../src/explore/components/DataTablesPane/types.ts |  1 +
 6 files changed, 65 insertions(+), 9 deletions(-)

diff --git 
a/superset-frontend/src/explore/components/DataTableControl/FilterInput.test.tsx
 
b/superset-frontend/src/explore/components/DataTableControl/FilterInput.test.tsx
index 8d4d6188dd8..b65c39e6349 100755
--- 
a/superset-frontend/src/explore/components/DataTableControl/FilterInput.test.tsx
+++ 
b/superset-frontend/src/explore/components/DataTableControl/FilterInput.test.tsx
@@ -19,10 +19,19 @@
 import { render, screen, userEvent } from 'spec/helpers/testing-library';
 import { FilterInput } from '.';
 
-jest.mock('lodash', () => ({
-  ...jest.requireActual('lodash'),
-  debounce: (fuc: Function) => fuc,
-}));
+jest.mock('lodash', () => {
+  const debounce = <T extends (...args: never[]) => unknown>(func: T) => {
+    const debounced = (...args: Parameters<T>) => func(...args);
+    debounced.flush = jest.fn();
+    return debounced;
+  };
+
+  return {
+    __esModule: true,
+    ...jest.requireActual('lodash'),
+    debounce,
+  };
+});
 
 test('Render a FilterInput', async () => {
   const onChangeHandler = jest.fn();
@@ -53,6 +62,19 @@ test('FilterInput auto-focuses when a non-editable element 
(e.g. a tab) has focu
   }
 });
 
+test('FilterInput preserves value after unmount and remount', () => {
+  const onChangeHandler = jest.fn();
+  const { unmount } = render(
+    <FilterInput onChangeHandler={onChangeHandler} value="abc" />,
+  );
+  expect((screen.getByRole('textbox') as HTMLInputElement).value).toBe('abc');
+
+  unmount();
+
+  render(<FilterInput onChangeHandler={onChangeHandler} value="abc" />);
+  expect((screen.getByRole('textbox') as HTMLInputElement).value).toBe('abc');
+});
+
 test('FilterInput does not steal focus when another input already has focus', 
() => {
   const onChangeHandler = jest.fn();
   const otherInput = document.createElement('input');
diff --git 
a/superset-frontend/src/explore/components/DataTableControl/index.tsx 
b/superset-frontend/src/explore/components/DataTableControl/index.tsx
index c4bfda8c852..041104bc93b 100755
--- a/superset-frontend/src/explore/components/DataTableControl/index.tsx
+++ b/superset-frontend/src/explore/components/DataTableControl/index.tsx
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-import { useMemo, useEffect, useRef, RefObject } from 'react';
+import { useMemo, useState, useEffect, useRef, RefObject } from 'react';
 import { t } from '@apache-superset/core/translation';
 import { css, styled, useTheme } from '@apache-superset/core/theme';
 
@@ -100,11 +100,24 @@ export const CopyToClipboardButton = ({
 export const FilterInput = ({
   onChangeHandler,
   shouldFocus = false,
+  value: externalValue = '',
 }: {
   onChangeHandler(filterText: string): void;
   shouldFocus?: boolean;
+  value?: string;
 }) => {
   const inputRef: RefObject<any> = useRef(null);
+  const [internalValue, setInternalValue] = useState(externalValue);
+  const lastEmittedValue = useRef(externalValue);
+  const onChangeRef = useRef(onChangeHandler);
+  onChangeRef.current = onChangeHandler;
+
+  useEffect(() => {
+    if (externalValue !== lastEmittedValue.current) {
+      setInternalValue(externalValue);
+    }
+    lastEmittedValue.current = externalValue;
+  }, [externalValue]);
 
   useEffect(() => {
     if (inputRef.current && shouldFocus) {
@@ -125,16 +138,28 @@ export const FilterInput = ({
   }, []);
 
   const theme = useTheme();
-  const debouncedChangeHandler = debounce(
-    onChangeHandler,
-    Constants.SLOW_DEBOUNCE,
+  const debouncedChangeHandler = useMemo(
+    () =>
+      debounce((value: string) => {
+        lastEmittedValue.current = value;
+        onChangeRef.current(value);
+      }, Constants.SLOW_DEBOUNCE),
+    [],
   );
+
+  useEffect(
+    () => () => debouncedChangeHandler.flush(),
+    [debouncedChangeHandler],
+  );
+
   return (
     <Input
       prefix={<Icons.SearchOutlined iconSize="l" />}
       placeholder={t('Search')}
+      value={internalValue}
       onChange={(event: any) => {
         const filterText = event.target.value;
+        setInternalValue(filterText);
         debouncedChangeHandler(filterText);
       }}
       css={css`
diff --git 
a/superset-frontend/src/explore/components/DataTablesPane/components/DataTableControls.tsx
 
b/superset-frontend/src/explore/components/DataTablesPane/components/DataTableControls.tsx
index 3ab00c9dcb1..092a9cf134f 100644
--- 
a/superset-frontend/src/explore/components/DataTablesPane/components/DataTableControls.tsx
+++ 
b/superset-frontend/src/explore/components/DataTablesPane/components/DataTableControls.tsx
@@ -60,6 +60,7 @@ export const TableControls = ({
   data,
   datasourceId,
   onInputChange,
+  filterText,
   columnNames,
   columnTypes,
   rowcount,
@@ -93,7 +94,11 @@ export const TableControls = ({
   const { canCopyClipboard: copyEnabled } = usePermissions();
   return (
     <TableControlsWrapper>
-      <FilterInput onChangeHandler={onInputChange} shouldFocus />
+      <FilterInput
+        onChangeHandler={onInputChange}
+        shouldFocus
+        value={filterText}
+      />
       <div
         css={css`
           display: flex;
diff --git 
a/superset-frontend/src/explore/components/DataTablesPane/components/SamplesPane.tsx
 
b/superset-frontend/src/explore/components/DataTablesPane/components/SamplesPane.tsx
index e743ad6844a..9e2fa986164 100644
--- 
a/superset-frontend/src/explore/components/DataTablesPane/components/SamplesPane.tsx
+++ 
b/superset-frontend/src/explore/components/DataTablesPane/components/SamplesPane.tsx
@@ -148,6 +148,7 @@ export const SamplesPane = ({
           rowcount={rowcount}
           datasourceId={datasourceId}
           onInputChange={handleInputChange}
+          filterText={filterText}
           isLoading={isLoading}
           canDownload={canDownload}
           rowLimit={rowLimit}
@@ -176,6 +177,7 @@ export const SamplesPane = ({
         rowcount={rowcount}
         datasourceId={datasourceId}
         onInputChange={handleInputChange}
+        filterText={filterText}
         isLoading={isLoading}
         canDownload={canDownload}
         rowLimit={rowLimit}
diff --git 
a/superset-frontend/src/explore/components/DataTablesPane/components/SingleQueryResultPane.tsx
 
b/superset-frontend/src/explore/components/DataTablesPane/components/SingleQueryResultPane.tsx
index 8cd279f4164..0c2cb0a4e5d 100644
--- 
a/superset-frontend/src/explore/components/DataTablesPane/components/SingleQueryResultPane.tsx
+++ 
b/superset-frontend/src/explore/components/DataTablesPane/components/SingleQueryResultPane.tsx
@@ -81,6 +81,7 @@ export const SingleQueryResultPane = ({
         rowcount={rowcount}
         datasourceId={datasourceId}
         onInputChange={handleInputChange}
+        filterText={filterText}
         isLoading={false}
         canDownload={canDownload}
         rowLimit={rowLimit}
diff --git a/superset-frontend/src/explore/components/DataTablesPane/types.ts 
b/superset-frontend/src/explore/components/DataTablesPane/types.ts
index 411e0ef3bff..e7db8500638 100644
--- a/superset-frontend/src/explore/components/DataTablesPane/types.ts
+++ b/superset-frontend/src/explore/components/DataTablesPane/types.ts
@@ -76,6 +76,7 @@ export interface TableControlsProps extends 
DrillControlsProps {
   // {datasource.id}__{datasource.type}, eg: 1__table
   datasourceId?: string;
   onInputChange: (input: string) => void;
+  filterText?: string;
   columnNames: string[];
   columnTypes: GenericDataType[];
   isLoading: boolean;

Reply via email to