From c240510e152af420c9b3c78ed5b0e900591d1ce3 Mon Sep 17 00:00:00 2001
From: Anton Kulyk <kuliks.anton@gmail.com>
Date: Thu, 23 Feb 2023 11:48:47 +0000
Subject: [PATCH] Fix ace editor popover in action editor (#28525)

* Move `ace` element ID to constants

* Close ace popover before opening the save modal

* Change name

* Workaround type warning
---
 .../ActionCreator/ActionCreator.tsx           | 20 ++++++++++++++++---
 .../ActionCreator/QueryActionEditor.tsx       |  3 +++
 .../components/NativeQueryEditor.jsx          |  8 ++++++--
 .../components/NativeQueryEditor/constants.ts |  1 +
 4 files changed, 27 insertions(+), 5 deletions(-)

diff --git a/frontend/src/metabase/actions/containers/ActionCreator/ActionCreator.tsx b/frontend/src/metabase/actions/containers/ActionCreator/ActionCreator.tsx
index 0cfa4a58c5e..6101b347494 100644
--- a/frontend/src/metabase/actions/containers/ActionCreator/ActionCreator.tsx
+++ b/frontend/src/metabase/actions/containers/ActionCreator/ActionCreator.tsx
@@ -29,6 +29,7 @@ import type Metadata from "metabase-lib/metadata/Metadata";
 import { isSavedAction } from "../../utils";
 import ActionContext, { useActionContext } from "./ActionContext";
 import ActionCreatorView from "./ActionCreatorView";
+import { ACE_ELEMENT_ID } from "./QueryActionEditor";
 import CreateActionForm, {
   FormValues as CreateActionFormValues,
 } from "./CreateActionForm";
@@ -95,7 +96,7 @@ function ActionCreator({
     renderEditorBody,
   } = useActionContext();
 
-  const [showSaveModal, setShowSaveModal] = useState(false);
+  const [isSaveModalShown, setShowSaveModal] = useState(false);
 
   const isEditable = isNew || model.canWriteActions();
 
@@ -131,9 +132,14 @@ function ActionCreator({
     }
   };
 
+  const showSaveModal = () => {
+    ensureAceEditorClosed();
+    setShowSaveModal(true);
+  };
+
   const handleClickSave = () => {
     if (isNew) {
-      setShowSaveModal(true);
+      showSaveModal();
     } else {
       handleUpdate();
       onClose?.();
@@ -158,7 +164,7 @@ function ActionCreator({
       >
         {renderEditorBody({ isEditable })}
       </ActionCreatorView>
-      {showSaveModal && (
+      {isSaveModalShown && (
         <Modal title={t`New Action`} onClose={handleCloseNewActionModal}>
           <CreateActionForm
             initialValues={{
@@ -175,6 +181,14 @@ function ActionCreator({
   );
 }
 
+function ensureAceEditorClosed() {
+  // @ts-expect-error — `ace` isn't typed yet
+  const editor = window.ace?.edit(ACE_ELEMENT_ID);
+  if (editor) {
+    editor.completer.popup.hide();
+  }
+}
+
 function ActionCreatorWithContext({
   initialAction,
   metadata,
diff --git a/frontend/src/metabase/actions/containers/ActionCreator/QueryActionEditor.tsx b/frontend/src/metabase/actions/containers/ActionCreator/QueryActionEditor.tsx
index 58ed3563af7..98e3408beb7 100644
--- a/frontend/src/metabase/actions/containers/ActionCreator/QueryActionEditor.tsx
+++ b/frontend/src/metabase/actions/containers/ActionCreator/QueryActionEditor.tsx
@@ -1,6 +1,7 @@
 import React from "react";
 
 import NativeQueryEditor from "metabase/query_builder/components/NativeQueryEditor";
+import { ACE_ELEMENT_ID } from "metabase/query_builder/components/NativeQueryEditor/constants";
 
 import type NativeQuery from "metabase-lib/queries/NativeQuery";
 
@@ -31,4 +32,6 @@ function QueryActionEditor({
   );
 }
 
+export { ACE_ELEMENT_ID };
+
 export default QueryActionEditor;
diff --git a/frontend/src/metabase/query_builder/components/NativeQueryEditor.jsx b/frontend/src/metabase/query_builder/components/NativeQueryEditor.jsx
index 2ad127bad75..4ea04c00a52 100644
--- a/frontend/src/metabase/query_builder/components/NativeQueryEditor.jsx
+++ b/frontend/src/metabase/query_builder/components/NativeQueryEditor.jsx
@@ -39,7 +39,11 @@ import NativeQueryEditorSidebar from "./NativeQueryEditor/NativeQueryEditorSideb
 import VisibilityToggler from "./NativeQueryEditor/VisibilityToggler";
 import RightClickPopover from "./NativeQueryEditor/RightClickPopover";
 import DataSourceSelectors from "./NativeQueryEditor/DataSourceSelectors";
-import { SCROLL_MARGIN, MIN_HEIGHT_LINES } from "./NativeQueryEditor/constants";
+import {
+  ACE_ELEMENT_ID,
+  SCROLL_MARGIN,
+  MIN_HEIGHT_LINES,
+} from "./NativeQueryEditor/constants";
 import {
   calcInitialEditorHeight,
   getEditorLineHeight,
@@ -578,7 +582,7 @@ class NativeQueryEditor extends Component {
             this._editor.resize();
           }}
         >
-          <div className="flex-full" id="id_sql" ref={this.editor} />
+          <div className="flex-full" id={ACE_ELEMENT_ID} ref={this.editor} />
 
           <RightClickPopover
             isOpen={this.state.isSelectedTextPopoverOpen}
diff --git a/frontend/src/metabase/query_builder/components/NativeQueryEditor/constants.ts b/frontend/src/metabase/query_builder/components/NativeQueryEditor/constants.ts
index 35baede0eb1..6de294b63ad 100644
--- a/frontend/src/metabase/query_builder/components/NativeQueryEditor/constants.ts
+++ b/frontend/src/metabase/query_builder/components/NativeQueryEditor/constants.ts
@@ -1,2 +1,3 @@
 export const SCROLL_MARGIN = 8;
 export const MIN_HEIGHT_LINES = 15;
+export const ACE_ELEMENT_ID = "id_sql";
-- 
GitLab