korbit-ai[bot] commented on code in PR #35986:
URL: https://github.com/apache/superset/pull/35986#discussion_r2511309199


##########
superset-frontend/packages/superset-ui-core/src/components/AsyncAceEditor/index.tsx:
##########
@@ -207,6 +208,49 @@ export function AsyncAceEditor(
           }
         }, [keywords, setCompleters]);
 
+        // Move autocomplete popup to the nearest parent container with 
data-ace-container
+        useEffect(() => {
+          const editorInstance = (ref as React.RefObject<AceEditor>)?.current
+            ?.editor;
+          if (!editorInstance) return;
+
+          const moveAutocompleteToContainer = () => {
+            const editorContainer = editorInstance.container;
+            const autocompletePopup =
+              (editorContainer?.querySelector(
+                '.ace_autocomplete',
+              ) as HTMLElement) ||
+              (document.querySelector('.ace_autocomplete') as HTMLElement);
+            if (autocompletePopup) {
+              const targetContainer =
+                editorContainer?.closest('#ace-editor') ||
+                editorContainer?.parentElement;
+              if (targetContainer && targetContainer !== document.body) {
+                targetContainer.appendChild(autocompletePopup);
+                autocompletePopup.setAttribute('data-ace-autocomplete', 
'true');
+              }
+            }
+          };
+
+          // Hook into Ace's command execution to detect when autocomplete 
starts
+          const handleAfterExec = (e: Ace.Operation) => {
+            if (
+              e.command.name &&
+              ['insertstring', 'startAutocomplete'].includes(e.command.name)
+            ) {
+              moveAutocompleteToContainer();
+            }
+          };

Review Comment:
   ### Missing validation for Ace operation structure <sub>![category 
Functionality](https://img.shields.io/badge/Functionality-0284c7)</sub>
   
   <details>
     <summary>Tell me more</summary>
   
   ###### What is the issue?
   The event handler doesn't validate the structure of the Ace.Operation 
object, which could cause runtime errors if the expected properties don't exist.
   
   
   ###### Why this matters
   If the Ace.Operation object doesn't have the expected command structure, 
accessing e.command.name could throw a TypeError, breaking the autocomplete 
functionality.
   
   ###### Suggested change ∙ *Feature Preview*
   Add proper validation for the operation object:
   
   ```typescript
   const handleAfterExec = (e: Ace.Operation) => {
     if (
       e?.command?.name &&
       ['insertstring', 'startAutocomplete'].includes(e.command.name)
     ) {
       moveAutocompleteToContainer();
     }
   };
   ```
   
   
   ###### Provide feedback to improve future suggestions
   [![Nice 
Catch](https://img.shields.io/badge/👍%20Nice%20Catch-71BC78)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/05c11c70-a9be-4e88-b04e-8424580f9baf/upvote)
 
[![Incorrect](https://img.shields.io/badge/👎%20Incorrect-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/05c11c70-a9be-4e88-b04e-8424580f9baf?what_not_true=true)
  [![Not in 
Scope](https://img.shields.io/badge/👎%20Out%20of%20PR%20scope-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/05c11c70-a9be-4e88-b04e-8424580f9baf?what_out_of_scope=true)
 [![Not in coding 
standard](https://img.shields.io/badge/👎%20Not%20in%20our%20standards-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/05c11c70-a9be-4e88-b04e-8424580f9baf?what_not_in_standard=true)
 
[![Other](https://img.shields.io/badge/👎%20Other-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/05c11c70-a9be-4e88-b04e-8424580f9baf)
   </details>
   
   <sub>
   
   💬 Looking for more details? Reply to this comment to chat with Korbit.
   </sub>
   
   <!--- korbi internal id:cd1c1e40-7797-48c5-9057-cab9e893756d -->
   
   
   [](cd1c1e40-7797-48c5-9057-cab9e893756d)



##########
superset-frontend/packages/superset-ui-core/src/components/AsyncAceEditor/index.tsx:
##########
@@ -207,6 +208,49 @@ export function AsyncAceEditor(
           }
         }, [keywords, setCompleters]);
 
+        // Move autocomplete popup to the nearest parent container with 
data-ace-container
+        useEffect(() => {
+          const editorInstance = (ref as React.RefObject<AceEditor>)?.current
+            ?.editor;
+          if (!editorInstance) return;
+
+          const moveAutocompleteToContainer = () => {
+            const editorContainer = editorInstance.container;
+            const autocompletePopup =
+              (editorContainer?.querySelector(
+                '.ace_autocomplete',
+              ) as HTMLElement) ||
+              (document.querySelector('.ace_autocomplete') as HTMLElement);

Review Comment:
   ### Unsafe type assertions on nullable DOM queries <sub>![category 
Functionality](https://img.shields.io/badge/Functionality-0284c7)</sub>
   
   <details>
     <summary>Tell me more</summary>
   
   ###### What is the issue?
   The code uses unsafe type assertions that could cause runtime crashes when 
the querySelector returns null.
   
   
   ###### Why this matters
   If neither querySelector finds the autocomplete popup element, the code will 
attempt to call methods on null, leading to TypeError crashes at runtime.
   
   ###### Suggested change ∙ *Feature Preview*
   Add proper null checks before type assertions:
   
   ```typescript
   const autocompletePopup =
     editorContainer?.querySelector('.ace_autocomplete') ||
     document.querySelector('.ace_autocomplete');
   if (!autocompletePopup) return;
   const popup = autocompletePopup as HTMLElement;
   ```
   
   
   ###### Provide feedback to improve future suggestions
   [![Nice 
Catch](https://img.shields.io/badge/👍%20Nice%20Catch-71BC78)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/5fbf4c93-2750-4fd6-9a03-a5eaa4c9d61a/upvote)
 
[![Incorrect](https://img.shields.io/badge/👎%20Incorrect-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/5fbf4c93-2750-4fd6-9a03-a5eaa4c9d61a?what_not_true=true)
  [![Not in 
Scope](https://img.shields.io/badge/👎%20Out%20of%20PR%20scope-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/5fbf4c93-2750-4fd6-9a03-a5eaa4c9d61a?what_out_of_scope=true)
 [![Not in coding 
standard](https://img.shields.io/badge/👎%20Not%20in%20our%20standards-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/5fbf4c93-2750-4fd6-9a03-a5eaa4c9d61a?what_not_in_standard=true)
 
[![Other](https://img.shields.io/badge/👎%20Other-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/5fbf4c93-2750-4fd6-9a03-a5eaa4c9d61a)
   </details>
   
   <sub>
   
   💬 Looking for more details? Reply to this comment to chat with Korbit.
   </sub>
   
   <!--- korbi internal id:a08cd591-d5cf-4acf-bd7d-d5751c9e9841 -->
   
   
   [](a08cd591-d5cf-4acf-bd7d-d5751c9e9841)



##########
superset-frontend/packages/superset-ui-core/src/components/AsyncAceEditor/index.tsx:
##########
@@ -207,6 +208,49 @@ export function AsyncAceEditor(
           }
         }, [keywords, setCompleters]);
 
+        // Move autocomplete popup to the nearest parent container with 
data-ace-container
+        useEffect(() => {
+          const editorInstance = (ref as React.RefObject<AceEditor>)?.current
+            ?.editor;
+          if (!editorInstance) return;
+
+          const moveAutocompleteToContainer = () => {
+            const editorContainer = editorInstance.container;
+            const autocompletePopup =
+              (editorContainer?.querySelector(
+                '.ace_autocomplete',
+              ) as HTMLElement) ||
+              (document.querySelector('.ace_autocomplete') as HTMLElement);
+            if (autocompletePopup) {
+              const targetContainer =
+                editorContainer?.closest('#ace-editor') ||
+                editorContainer?.parentElement;
+              if (targetContainer && targetContainer !== document.body) {
+                targetContainer.appendChild(autocompletePopup);
+                autocompletePopup.setAttribute('data-ace-autocomplete', 
'true');
+              }
+            }
+          };

Review Comment:
   ### Uncached DOM queries in command handler <sub>![category 
Performance](https://img.shields.io/badge/Performance-4f46e5)</sub>
   
   <details>
     <summary>Tell me more</summary>
   
   ###### What is the issue?
   DOM queries are performed on every command execution without caching, 
causing unnecessary performance overhead.
   
   
   ###### Why this matters
   Multiple DOM queries (querySelector, closest, parentElement) execute 
repeatedly for each 'insertstring' or 'startAutocomplete' command, creating 
performance bottlenecks especially during rapid typing or frequent autocomplete 
triggers.
   
   ###### Suggested change ∙ *Feature Preview*
   Cache DOM elements outside the handler function and only re-query when 
necessary:
   
   ```typescript
   let cachedAutocompletePopup: HTMLElement | null = null;
   let cachedTargetContainer: Element | null = null;
   
   const moveAutocompleteToContainer = () => {
     if (!cachedAutocompletePopup) {
       cachedAutocompletePopup = 
editorContainer?.querySelector('.ace_autocomplete') as HTMLElement ||
                                 document.querySelector('.ace_autocomplete') as 
HTMLElement;
     }
     if (cachedAutocompletePopup && !cachedTargetContainer) {
       cachedTargetContainer = editorContainer?.closest('#ace-editor') ||
                              editorContainer?.parentElement;
     }
     // ... rest of logic
   };
   ```
   
   
   ###### Provide feedback to improve future suggestions
   [![Nice 
Catch](https://img.shields.io/badge/👍%20Nice%20Catch-71BC78)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/eeb0626a-9b7c-4a0d-af58-59e6ee16f3e0/upvote)
 
[![Incorrect](https://img.shields.io/badge/👎%20Incorrect-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/eeb0626a-9b7c-4a0d-af58-59e6ee16f3e0?what_not_true=true)
  [![Not in 
Scope](https://img.shields.io/badge/👎%20Out%20of%20PR%20scope-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/eeb0626a-9b7c-4a0d-af58-59e6ee16f3e0?what_out_of_scope=true)
 [![Not in coding 
standard](https://img.shields.io/badge/👎%20Not%20in%20our%20standards-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/eeb0626a-9b7c-4a0d-af58-59e6ee16f3e0?what_not_in_standard=true)
 
[![Other](https://img.shields.io/badge/👎%20Other-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/eeb0626a-9b7c-4a0d-af58-59e6ee16f3e0)
   </details>
   
   <sub>
   
   💬 Looking for more details? Reply to this comment to chat with Korbit.
   </sub>
   
   <!--- korbi internal id:0abf76dd-e38e-4c6f-8176-47b9191670aa -->
   
   
   [](0abf76dd-e38e-4c6f-8176-47b9191670aa)



##########
superset-frontend/packages/superset-ui-core/src/components/AsyncAceEditor/index.tsx:
##########
@@ -207,6 +208,49 @@ export function AsyncAceEditor(
           }
         }, [keywords, setCompleters]);
 
+        // Move autocomplete popup to the nearest parent container with 
data-ace-container
+        useEffect(() => {
+          const editorInstance = (ref as React.RefObject<AceEditor>)?.current
+            ?.editor;
+          if (!editorInstance) return;
+
+          const moveAutocompleteToContainer = () => {
+            const editorContainer = editorInstance.container;
+            const autocompletePopup =
+              (editorContainer?.querySelector(
+                '.ace_autocomplete',
+              ) as HTMLElement) ||
+              (document.querySelector('.ace_autocomplete') as HTMLElement);
+            if (autocompletePopup) {
+              const targetContainer =
+                editorContainer?.closest('#ace-editor') ||
+                editorContainer?.parentElement;
+              if (targetContainer && targetContainer !== document.body) {
+                targetContainer.appendChild(autocompletePopup);
+                autocompletePopup.setAttribute('data-ace-autocomplete', 
'true');
+              }
+            }
+          };
+
+          // Hook into Ace's command execution to detect when autocomplete 
starts
+          const handleAfterExec = (e: Ace.Operation) => {
+            if (
+              e.command.name &&
+              ['insertstring', 'startAutocomplete'].includes(e.command.name)
+            ) {
+              moveAutocompleteToContainer();
+            }
+          };

Review Comment:
   ### Inefficient command name checking <sub>![category 
Performance](https://img.shields.io/badge/Performance-4f46e5)</sub>
   
   <details>
     <summary>Tell me more</summary>
   
   ###### What is the issue?
   Array.includes() is called on every command execution for a small, static 
array.
   
   
   ###### Why this matters
   Using includes() for a small set of known values creates unnecessary array 
iteration overhead when called frequently during typing, especially when a 
simple equality check or Set lookup would be more efficient.
   
   ###### Suggested change ∙ *Feature Preview*
   Use a Set for O(1) lookup or direct equality comparison:
   
   ```typescript
   const AUTOCOMPLETE_COMMANDS = new Set(['insertstring', 'startAutocomplete']);
   
   const handleAfterExec = (e: Ace.Operation) => {
     if (e.command.name && AUTOCOMPLETE_COMMANDS.has(e.command.name)) {
       moveAutocompleteToContainer();
     }
   };
   ```
   
   
   ###### Provide feedback to improve future suggestions
   [![Nice 
Catch](https://img.shields.io/badge/👍%20Nice%20Catch-71BC78)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/2ff82daf-6bdd-48fd-a26b-46c49ad8eadd/upvote)
 
[![Incorrect](https://img.shields.io/badge/👎%20Incorrect-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/2ff82daf-6bdd-48fd-a26b-46c49ad8eadd?what_not_true=true)
  [![Not in 
Scope](https://img.shields.io/badge/👎%20Out%20of%20PR%20scope-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/2ff82daf-6bdd-48fd-a26b-46c49ad8eadd?what_out_of_scope=true)
 [![Not in coding 
standard](https://img.shields.io/badge/👎%20Not%20in%20our%20standards-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/2ff82daf-6bdd-48fd-a26b-46c49ad8eadd?what_not_in_standard=true)
 
[![Other](https://img.shields.io/badge/👎%20Other-white)](https://app.korbit.ai/feedback/aa91ff46-6083-4491-9416-b83dd1994b51/2ff82daf-6bdd-48fd-a26b-46c49ad8eadd)
   </details>
   
   <sub>
   
   💬 Looking for more details? Reply to this comment to chat with Korbit.
   </sub>
   
   <!--- korbi internal id:93062c6a-749c-4405-8e90-312d70c1d8b2 -->
   
   
   [](93062c6a-749c-4405-8e90-312d70c1d8b2)



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to