codeant-ai-for-open-source[bot] commented on code in PR #41285:
URL: https://github.com/apache/superset/pull/41285#discussion_r3488903734


##########
superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.tsx:
##########
@@ -93,6 +96,105 @@ const TabTitle = styled.span`
 // Get the user's OS
 const userOS = detectOS();
 
+const newTabTooltip =
+  userOS === 'Windows' ? t('New tab (Ctrl + q)') : t('New tab (Ctrl + t)');
+
+const PlusIcon = (
+  <Icons.PlusOutlined
+    iconSize="l"
+    css={css`
+      vertical-align: middle;
+    `}
+    data-test="add-tab-icon"
+  />
+);
+
+function NewTabButton({ onAddSqlEditor }: { onAddSqlEditor: () => void }) {
+  const [open, setOpen] = useState(false);
+
+  const dropdownItems = useMemo<MenuItemType[]>(() => {
+    if (!open) return [];
+    const primaryItems =
+      menus.getMenu(ViewLocations.sqllab.newTab)?.primary ?? [];
+    return [
+      {
+        key: 'sql-editor',
+        label: t('SQL Editor'),
+        icon: <Icons.TableOutlined iconSize="m" />,
+        onClick: () => {
+          setOpen(false);
+          onAddSqlEditor();
+        },
+      },
+      ...primaryItems.map(item => {
+        const command = commands.getCommand(item.command);
+        const Icon = command?.icon
+          ? ((Icons as Record<string, typeof Icons.FileOutlined>)[
+              command.icon
+            ] ?? Icons.FileOutlined)
+          : Icons.FileOutlined;
+        return {
+          key: command?.id ?? item.command,
+          label: command?.title ?? item.command,
+          icon: <Icon iconSize="m" />,
+          onClick: () => {
+            setOpen(false);
+            commands.executeCommand(item.command);
+          },
+        } as MenuItemType;

Review Comment:
   **Suggestion:** The menu item handler executes `item.command` even when 
`getCommand` returned `undefined`. If an extension contributes a menu item 
before its command is registered (or the command failed to load), clicking the 
item throws `Command "...\" not found` and breaks the add-tab flow. Filter out 
missing commands or guard execution and show a non-fatal fallback. [api 
mismatch]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   - ❌ SQL Lab new-tab menu crashes when command missing.
   - ⚠️ Extension-provided tab actions fail, reducing usability.
   ```
   </details>
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. An extension contributes a new tab type into the `sqllab.newTab` menu, so 
that
   `menus.getMenu(ViewLocations.sqllab.newTab)?.primary` returns an item with 
`item.command`
   in `NewTabButton`
   
(`superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.tsx:115-121`).
   
   2. At the moment the SQL Lab `TabbedSqlEditors` component renders, assume 
the extension
   has not yet registered its command handler (or registration failed), so
   `commands.getCommand(item.command)` in the dropdown items mapper returns 
`undefined`
   (`TabbedSqlEditors/index.tsx:129-131`), while the label and icon fall back 
to defaults.
   
   3. Despite `command` being `undefined`, the code still builds a 
`MenuItemType` whose
   `onClick` handler calls `commands.executeCommand(item.command)` without any 
guard
   (`TabbedSqlEditors/index.tsx:136-143`).
   
   4. When the user opens the new-tab dropdown and clicks this contributed tab 
type,
   `commands.executeCommand` in 
`superset-frontend/src/core/commands/index.ts:52-59` looks up
   the command in `commandRegistry`, fails to find it, and throws 
`Error('Command "..." not
   found.')`, causing a runtime error that interrupts the add-tab flow for that
   extension-provided tab type.
   ```
   </details>
   
   [![Fix in 
Cursor](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-cursor-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=f72d0080e84c4c798d67c1f14f8d20ed&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
 [![Fix in VSCode 
Claude](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-vscode-claude-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=f72d0080e84c4c798d67c1f14f8d20ed&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
   
   *(Use Cmd/Ctrl + Click for best experience)*
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** superset-frontend/src/SqlLab/components/TabbedSqlEditors/index.tsx
   **Line:** 129:144
   **Comment:**
        *Api Mismatch: The menu item handler executes `item.command` even when 
`getCommand` returned `undefined`. If an extension contributes a menu item 
before its command is registered (or the command failed to load), clicking the 
item throws `Command "...\" not found` and breaks the add-tab flow. Filter out 
missing commands or guard execution and show a non-fatal fallback.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   Once fix is implemented, also check other comments on the same PR, and ask 
user if the user wants to fix the rest of the comments as well. if said yes, 
then fetch all the comments validate the correctness and implement a minimal fix
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41285&comment_hash=af053530bfba6f2755c4362d48fead2dfed34ba8c21865ac591d142aeb651010&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41285&comment_hash=af053530bfba6f2755c4362d48fead2dfed34ba8c21865ac591d142aeb651010&reaction=dislike'>👎</a>



##########
superset-frontend/src/SqlLab/components/SqlEditor/index.tsx:
##########
@@ -271,6 +302,48 @@ const SqlEditor: FC<Props> = ({
 
   const logAction = useLogAction({ queryEditorId: queryEditor.id });
   const isActive = currentQueryEditorId === queryEditor.id;
+
+  // Re-renders when an extension registers a northPane view after async load.
+  const northPaneViews = useViews(ViewLocations.sqllab.northPane) || [];
+
+  // Resolve the per-tab localStorage key the same way every other SQL Lab
+  // consumer does (`tabViewId ?? id`), so the value written, read back, and
+  // observed via the `storage` event all agree once a tab is 
backend-persisted.
+  const northPaneStorageId = queryEditor.tabViewId ?? queryEditor.id;
+
+  // ID of the northPane view active for this tab, or null for the default
+  // SQL editor layout.  Set by an extension via PENDING_NORTH_PANE_VIEW_KEY
+  // before calling createTab(); persisted per-tab in localStorage.
+  const [northPaneViewId, setNorthPaneViewId] = useState<string | null>(() => {
+    const pendingViewId = readNorthPaneStorage(PENDING_NORTH_PANE_VIEW_KEY);
+    if (pendingViewId) {
+      writeNorthPaneStorage(PENDING_NORTH_PANE_VIEW_KEY, null);
+      writeNorthPaneStorage(
+        NORTH_PANE_VIEW_KEY(northPaneStorageId),
+        pendingViewId,
+      );
+      return pendingViewId;
+    }
+    return readNorthPaneStorage(NORTH_PANE_VIEW_KEY(northPaneStorageId));
+  });
+
+  useEffect(() => {
+    writeNorthPaneStorage(
+      NORTH_PANE_VIEW_KEY(northPaneStorageId),
+      northPaneViewId,
+    );
+  }, [northPaneStorageId, northPaneViewId]);

Review Comment:
   **Suggestion:** This effect writes the current mode immediately whenever the 
storage key changes, but `northPaneStorageId` can switch from client `id` to 
backend `tabViewId` after hydration while `northPaneViewId` is still `null`. In 
that transition, the code removes the existing persisted value under the 
backend key before ever reading it, so a previously saved extension pane mode 
is lost on reload. Read/migrate the new key first (or gate writes until 
initialization for the new key completes) before writing/removing. [cache]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   - ❌ NorthPane extension mode lost after backend persistence migration.
   - ⚠️ Extensions cannot rely on consistent northPane mode storage.
   ```
   </details>
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Open SQL Lab and create or use a tab that will be persisted via backend 
tab state
   (FeatureFlag.SqllabBackendPersistence), so that `EditorAutoSync` is active
   (`superset-frontend/src/SqlLab/components/EditorAutoSync/index.tsx:69-184`) 
and will later
   call `syncQueryEditor` for unsaved editors (`lines 161-168`).
   
   2. Install an extension that configures a northPane view by setting
   `PENDING_NORTH_PANE_VIEW_KEY` before creating a new tab, as documented in
   `superset-frontend/src/SqlLab/contributions.ts:60-72`, so that `SqlEditor` 
persists the
   chosen northPane view id into localStorage via
   `writeNorthPaneStorage(NORTH_PANE_VIEW_KEY(northPaneStorageId), 
pendingViewId)` in the
   `useState` initializer
   (`superset-frontend/src/SqlLab/components/SqlEditor/index.tsx:317-325`).
   
   3. Observe that `SqlEditor` derives the per-tab storage key as 
`northPaneStorageId =
   queryEditor.tabViewId ?? queryEditor.id` (`index.tsx:309-312`) and initially 
reads only
   `NORTH_PANE_VIEW_KEY(northPaneStorageId)` in the state initializer 
(`index.tsx:317-328`),
   while `EditorAutoSync` later migrates the same `QueryEditor` to the backend 
by setting
   `tabViewId` in `syncQueryEditor` 
(`superset-frontend/src/SqlLab/actions/sqlLab.ts:24-47`),
   causing `northPaneStorageId` to switch from the temporary `id` to the 
backend `tabViewId`.
   
   4. When `tabViewId` is populated after this migration while 
`northPaneViewId` in React
   state remains `null` for that tab, the effect at 
`SqlEditor/index.tsx:330-335` runs with
   the new `northPaneStorageId` and writes `null` via
   `writeNorthPaneStorage(NORTH_PANE_VIEW_KEY(northPaneStorageId), 
northPaneViewId)`, which
   calls `localStorage.removeItem`, erasing any previously persisted northPane 
view id under
   the backend key so that subsequent reloads cannot restore the 
extension-specific northPane
   layout for that tab.
   ```
   </details>
   
   [![Fix in 
Cursor](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-cursor-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=3c5596c8e0d44f419300a31a0f65f9ea&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
 [![Fix in VSCode 
Claude](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-vscode-claude-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=3c5596c8e0d44f419300a31a0f65f9ea&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
   
   *(Use Cmd/Ctrl + Click for best experience)*
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** superset-frontend/src/SqlLab/components/SqlEditor/index.tsx
   **Line:** 330:335
   **Comment:**
        *Cache: This effect writes the current mode immediately whenever the 
storage key changes, but `northPaneStorageId` can switch from client `id` to 
backend `tabViewId` after hydration while `northPaneViewId` is still `null`. In 
that transition, the code removes the existing persisted value under the 
backend key before ever reading it, so a previously saved extension pane mode 
is lost on reload. Read/migrate the new key first (or gate writes until 
initialization for the new key completes) before writing/removing.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   Once fix is implemented, also check other comments on the same PR, and ask 
user if the user wants to fix the rest of the comments as well. if said yes, 
then fetch all the comments validate the correctness and implement a minimal fix
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41285&comment_hash=103334efa3560374713fb6e40a5ae899629a555f9f0cb6d02be3a91054e964df&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41285&comment_hash=103334efa3560374713fb6e40a5ae899629a555f9f0cb6d02be3a91054e964df&reaction=dislike'>👎</a>



-- 
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