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

asoare 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 880cab58c33 fix(bug): Error when adding a filter using custom sql 
(#38246)
880cab58c33 is described below

commit 880cab58c33c6320b3f7e387a41a9b1f0d04843e
Author: Alexandru Soare <[email protected]>
AuthorDate: Thu Mar 5 11:39:21 2026 +0200

    fix(bug): Error when adding a filter using custom sql (#38246)
---
 .../packages/superset-core/src/api/editors.ts      | 12 ++++
 .../src/core/editors/AceEditorProvider.tsx         |  4 ++
 .../AdhocFilterEditPopoverSqlTabContent.test.tsx   | 84 ++++++++++++++++++----
 .../AdhocFilterEditPopoverSqlTabContent/index.tsx  |  8 +--
 .../MetricControl/AdhocMetricEditPopover/index.tsx | 21 ++----
 5 files changed, 99 insertions(+), 30 deletions(-)

diff --git a/superset-frontend/packages/superset-core/src/api/editors.ts 
b/superset-frontend/packages/superset-core/src/api/editors.ts
index 1113bc8d729..cb151be75fa 100644
--- a/superset-frontend/packages/superset-core/src/api/editors.ts
+++ b/superset-frontend/packages/superset-core/src/api/editors.ts
@@ -480,6 +480,18 @@ export interface EditorHandle {
    * @returns A Disposable that removes the provider when disposed
    */
   registerCompletionProvider(provider: CompletionProvider): Disposable;
+
+  /**
+   * Force the editor to recalculate its dimensions.
+   * Called when the container size changes or when the editor becomes
+   * visible after being hidden (e.g., in a tab).
+   *
+   * Each editor implementation maps this to their equivalent:
+   * - Ace: editor.resize()
+   * - Monaco: editor.layout()
+   * - CodeMirror: editor.requestMeasure()
+   */
+  resize(): void;
 }
 
 /**
diff --git a/superset-frontend/src/core/editors/AceEditorProvider.tsx 
b/superset-frontend/src/core/editors/AceEditorProvider.tsx
index 9236403a3b3..abdf76d14f1 100644
--- a/superset-frontend/src/core/editors/AceEditorProvider.tsx
+++ b/superset-frontend/src/core/editors/AceEditorProvider.tsx
@@ -182,6 +182,10 @@ const createAceEditorHandle = (
       completionProviders.current.delete(provider.id);
     });
   },
+
+  resize: () => {
+    aceEditorRef.current?.editor?.resize();
+  },
 });
 
 /**
diff --git 
a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSqlTabContent/AdhocFilterEditPopoverSqlTabContent.test.tsx
 
b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSqlTabContent/AdhocFilterEditPopoverSqlTabContent.test.tsx
index 2a29116e118..f5b1eee033f 100644
--- 
a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSqlTabContent/AdhocFilterEditPopoverSqlTabContent.test.tsx
+++ 
b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSqlTabContent/AdhocFilterEditPopoverSqlTabContent.test.tsx
@@ -22,30 +22,52 @@ import {
   screen,
   selectOption,
   userEvent,
+  waitFor,
 } from 'spec/helpers/testing-library';
 import AdhocFilter from '../AdhocFilter';
 import { Clauses, ExpressionTypes } from '../types';
 import AdhocFilterEditPopoverSqlTabContent from '.';
 
+// Track resize calls for testing
+const mockResize = jest.fn();
+
+// Mock EditorHost with ref support for resize
+jest.mock('src/core/editors', () => {
+  const React = require('react');
+  return {
+    EditorHost: React.forwardRef(
+      (
+        {
+          value,
+          onChange,
+        }: {
+          value: string;
+          onChange: (v: string) => void;
+        },
+        ref: React.Ref<{ resize: () => void }>,
+      ) => {
+        React.useImperativeHandle(ref, () => ({
+          resize: mockResize,
+        }));
+        return (
+          <textarea
+            defaultValue={value}
+            onChange={e => onChange?.(e.target.value)}
+          />
+        );
+      },
+    ),
+  };
+});
+
 // Add cleanup after each test
 afterEach(async () => {
   cleanup();
+  mockResize.mockClear();
   // Wait for any pending effects to complete
   await new Promise(resolve => setTimeout(resolve, 0));
 });
 
-jest.mock('src/core/editors', () => ({
-  EditorHost: ({
-    value,
-    onChange,
-  }: {
-    value: string;
-    onChange: (v: string) => void;
-  }) => (
-    <textarea defaultValue={value} onChange={e => onChange?.(e.target.value)} 
/>
-  ),
-}));
-
 const adhocFilter = new AdhocFilter({
   expressionType: ExpressionTypes.Sql,
   sqlExpression: 'value > 10',
@@ -89,3 +111,41 @@ test('calls onChange when the SQL expression changes', 
async () => {
     expect.objectContaining({ sqlExpression: input }),
   );
 });
+
+test('calls editor resize when adhocFilter changes', async () => {
+  const onChange = jest.fn();
+  const { rerender } = render(
+    <AdhocFilterEditPopoverSqlTabContent
+      adhocFilter={adhocFilter}
+      onChange={onChange}
+      options={[]}
+      height={100}
+    />,
+  );
+
+  // Initial render should call resize
+  await waitFor(() => {
+    expect(mockResize).toHaveBeenCalled();
+  });
+  mockResize.mockClear();
+
+  // Create a new filter to trigger the useEffect
+  const newFilter = new AdhocFilter({
+    expressionType: ExpressionTypes.Sql,
+    sqlExpression: 'value > 20',
+    clause: Clauses.Where,
+  });
+
+  rerender(
+    <AdhocFilterEditPopoverSqlTabContent
+      adhocFilter={newFilter}
+      onChange={onChange}
+      options={[]}
+      height={100}
+    />,
+  );
+
+  await waitFor(() => {
+    expect(mockResize).toHaveBeenCalled();
+  });
+});
diff --git 
a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSqlTabContent/index.tsx
 
b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSqlTabContent/index.tsx
index 9ba11c617e0..00032523033 100644
--- 
a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSqlTabContent/index.tsx
+++ 
b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSqlTabContent/index.tsx
@@ -17,6 +17,7 @@
  * under the License.
  */
 import { useEffect, useRef, useMemo } from 'react';
+import type { editors } from '@apache-superset/core';
 import { Select } from '@superset-ui/core/components';
 import { t } from '@apache-superset/core';
 import { css, styled, useTheme } from '@apache-superset/core/ui';
@@ -49,12 +50,11 @@ export default function 
AdhocFilterEditPopoverSqlTabContent({
   height: number;
   datasource?: any;
 }) {
-  const aceEditorRef = useRef(null);
+  const editorRef = useRef<editors.EditorHandle>(null);
   const theme = useTheme();
 
   useEffect(() => {
-    // @ts-expect-error - AceEditor ref type doesn't expose editor.resize()
-    aceEditorRef?.current?.editor.resize();
+    editorRef.current?.resize();
   }, [adhocFilter]);
 
   const onSqlExpressionClauseChange = (clause: string) => {
@@ -125,7 +125,7 @@ export default function 
AdhocFilterEditPopoverSqlTabContent({
         `}
       >
         <SQLEditorWithValidation
-          ref={aceEditorRef}
+          ref={editorRef}
           keywords={keywords}
           height={`${height - 130}px`}
           onChange={onSqlExpressionChange}
diff --git 
a/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.tsx
 
b/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.tsx
index 0f435dfa5b7..28f50d73dea 100644
--- 
a/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.tsx
+++ 
b/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.tsx
@@ -130,7 +130,7 @@ export default class AdhocMetricEditPopover extends 
PureComponent<
   // "Saved" is a default tab unless there are no saved metrics for dataset
   defaultActiveTabKey = this.getDefaultTab();
 
-  aceEditorRef: RefObject<editors.EditorHandle>;
+  editorRef: RefObject<editors.EditorHandle>;
 
   dragStartX = 0;
 
@@ -152,8 +152,8 @@ export default class AdhocMetricEditPopover extends 
PureComponent<
     this.onMouseMove = this.onMouseMove.bind(this);
     this.onMouseUp = this.onMouseUp.bind(this);
     this.onTabChange = this.onTabChange.bind(this);
-    this.aceEditorRef = createRef();
-    this.refreshAceEditor = this.refreshAceEditor.bind(this);
+    this.editorRef = createRef();
+    this.refreshEditor = this.refreshEditor.bind(this);
     this.getDefaultTab = this.getDefaultTab.bind(this);
 
     this.state = {
@@ -313,20 +313,13 @@ export default class AdhocMetricEditPopover extends 
PureComponent<
   }
 
   onTabChange(tab: string): void {
-    this.refreshAceEditor();
+    this.refreshEditor();
     this.props.getCurrentTab?.(tab);
   }
 
-  refreshAceEditor(): void {
+  refreshEditor(): void {
     setTimeout(() => {
-      if (this.aceEditorRef.current) {
-        // Cast to access ace editor API
-        (
-          this.aceEditorRef.current as unknown as {
-            editor?: { resize?: () => void };
-          }
-        ).editor?.resize?.();
-      }
+      this.editorRef.current?.resize();
     }, 0);
   }
 
@@ -549,7 +542,7 @@ export default class AdhocMetricEditPopover extends 
PureComponent<
               children: (
                 <SQLEditorWithValidation
                   data-test="sql-editor"
-                  ref={this.aceEditorRef}
+                  ref={this.editorRef}
                   keywords={keywords}
                   height={`${this.state.height - 120}px`}
                   onChange={this.onSqlExpressionChange}

Reply via email to