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


##########
superset-frontend/src/SqlLab/components/ResultSet/ResultSet.test.tsx:
##########
@@ -760,6 +772,197 @@ describe('ResultSet', () => {
     },
   );
 
+  test('should show CSV button with granular can_export_data permission when 
flag is ON', async () => {
+    mockIsFeatureEnabled.mockImplementation(
+      (flag: FeatureFlag) => flag === FeatureFlag.GranularExportControls,
+    );
+    const { queryByTestId } = setup(
+      mockedProps,
+      mockStore({
+        ...initialState,
+        user: {
+          ...user,
+          roles: {
+            sql_lab: [['can_export_data', 'Superset']],
+          },
+        },
+        sqlLab: {
+          ...initialState.sqlLab,
+          queries: {
+            [queries[0].id]: queries[0],
+          },
+        },
+      }),
+    );
+    const csvButton = queryByTestId('export-csv-button');
+    expect(csvButton).toBeInTheDocument();
+    expect(csvButton).toBeEnabled();
+    mockIsFeatureEnabled.mockReset();
+  });
+
+  test('should disable CSV button when granular flag is ON and user lacks 
can_export_data', async () => {
+    mockIsFeatureEnabled.mockImplementation(
+      (flag: FeatureFlag) => flag === FeatureFlag.GranularExportControls,
+    );
+    const { queryByTestId } = setup(
+      mockedProps,
+      mockStore({
+        ...initialState,
+        user: {
+          ...user,
+          roles: {
+            sql_lab: [],
+          },
+        },
+        sqlLab: {
+          ...initialState.sqlLab,
+          queries: {
+            [queries[0].id]: queries[0],
+          },
+        },
+      }),
+    );
+    const csvButton = queryByTestId('export-csv-button');
+    expect(csvButton).toBeInTheDocument();
+    expect(csvButton).toBeDisabled();
+    mockIsFeatureEnabled.mockReset();
+  });
+
+  test('should show clipboard button with granular can_copy_clipboard 
permission when flag is ON', async () => {
+    mockIsFeatureEnabled.mockImplementation(
+      (flag: FeatureFlag) => flag === FeatureFlag.GranularExportControls,
+    );
+    const { queryByTestId } = setup(
+      mockedProps,
+      mockStore({
+        ...initialState,
+        user: {
+          ...user,
+          roles: {
+            sql_lab: [['can_copy_clipboard', 'Superset']],
+          },
+        },
+        sqlLab: {
+          ...initialState.sqlLab,
+          queries: {
+            [queries[0].id]: queries[0],
+          },
+        },
+      }),
+    );
+    expect(queryByTestId('copy-to-clipboard-button')).toBeInTheDocument();
+    mockIsFeatureEnabled.mockReset();
+  });
+
+  test('should disable clipboard button when granular flag is ON and user 
lacks can_copy_clipboard', async () => {
+    mockIsFeatureEnabled.mockImplementation(
+      (flag: FeatureFlag) => flag === FeatureFlag.GranularExportControls,
+    );
+    const { queryByTestId } = setup(
+      mockedProps,
+      mockStore({
+        ...initialState,
+        user: {
+          ...user,
+          roles: {
+            sql_lab: [['can_export_data', 'Superset']],
+          },
+        },
+        sqlLab: {
+          ...initialState.sqlLab,
+          queries: {
+            [queries[0].id]: queries[0],
+          },
+        },
+      }),
+    );
+    const clipboardButton = queryByTestId('copy-to-clipboard-button');
+    expect(clipboardButton).toBeInTheDocument();
+    expect(clipboardButton).toBeDisabled();
+    mockIsFeatureEnabled.mockReset();
+  });
+
+  test('should use legacy can_export_csv for both CSV and clipboard when 
granular flag is OFF', async () => {
+    mockIsFeatureEnabled.mockReturnValue(false);
+    const { queryByTestId } = setup(
+      mockedProps,
+      mockStore({
+        ...initialState,
+        user: {
+          ...user,
+          roles: {
+            sql_lab: [['can_export_csv', 'SQLLab']],
+          },
+        },
+        sqlLab: {
+          ...initialState.sqlLab,
+          queries: {
+            [queries[0].id]: queries[0],
+          },
+        },
+      }),
+    );
+    expect(queryByTestId('export-csv-button')).toBeInTheDocument();
+    expect(queryByTestId('copy-to-clipboard-button')).toBeInTheDocument();

Review Comment:
   **Suggestion:** This legacy fallback test only checks that both controls are 
rendered, but both controls are rendered even when disabled. That means 
regressions in legacy `can_export_csv` permission behavior would go undetected. 
Assert enabled state for both controls. [logic error]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   - ⚠️ Legacy can_export_csv mapping for SQL Lab unvalidated enablement.
   - ⚠️ CSV and clipboard actions could silently disable for admins.
   ```
   </details>
   
   ```suggestion
       const csvButton = queryByTestId('export-csv-button');
       const clipboardButton = queryByTestId('copy-to-clipboard-button');
       expect(csvButton).toBeInTheDocument();
       expect(csvButton).toBeEnabled();
       expect(clipboardButton).toBeInTheDocument();
       expect(clipboardButton).toBeEnabled();
   ```
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. In `superset-frontend/src/hooks/usePermissions.ts` at lines 37–60, note 
that when
   `GranularExportControls` is disabled, both `canExportDataSqlLab` and
   `canCopyClipboardSqlLab` fall back to the legacy SQL Lab permission 
`can_export_csv` via
   `canExportCsvSqlLab`.
   
   2. In `superset-frontend/src/SqlLab/components/ResultSet/index.tsx` lines 
388–455, the CSV
   and clipboard buttons use `disabled={!canExportData}` and 
`disabled={!canCopyClipboard}`
   respectively, so with the feature flag off and `can_export_csv` granted, 
both buttons
   should be enabled for SQL Lab users.
   
   3. Find the test `"should use legacy can_export_csv for both CSV and 
clipboard when
   granular flag is OFF"` in `ResultSet.test.tsx` at lines 885–908; it forces
   `mockIsFeatureEnabled.mockReturnValue(false)` (line 886) and configures the 
Redux store so
   `user.roles.sql_lab = [['can_export_csv', 'SQLLab']]` (lines 892–895).
   
   4. The test currently only asserts that both buttons are present in the DOM 
(lines
   905–906) and then resets the feature flag mock (907); if a regression caused
   `canExportDataSqlLab` or `canCopyClipboardSqlLab` to be computed as `false` 
under the
   legacy path, resulting in disabled buttons for authorized users, this test 
would still
   pass because it never validates that either control is enabled.
   ```
   </details>
   <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/ResultSet/ResultSet.test.tsx
   **Line:** 905:906
   **Comment:**
        *Logic Error: This legacy fallback test only checks that both controls 
are rendered, but both controls are rendered even when disabled. That means 
regressions in legacy `can_export_csv` permission behavior would go undetected. 
Assert enabled state for both controls.
   
   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.
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38581&comment_hash=737af7ebfe9a4eb774178e487c61a5ef47eeaa84dc1f8d6ae1736c91b5e4569a&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38581&comment_hash=737af7ebfe9a4eb774178e487c61a5ef47eeaa84dc1f8d6ae1736c91b5e4569a&reaction=dislike'>👎</a>



##########
superset-frontend/src/SqlLab/components/ResultSet/ResultSet.test.tsx:
##########
@@ -760,6 +772,197 @@ describe('ResultSet', () => {
     },
   );
 
+  test('should show CSV button with granular can_export_data permission when 
flag is ON', async () => {
+    mockIsFeatureEnabled.mockImplementation(
+      (flag: FeatureFlag) => flag === FeatureFlag.GranularExportControls,
+    );
+    const { queryByTestId } = setup(
+      mockedProps,
+      mockStore({
+        ...initialState,
+        user: {
+          ...user,
+          roles: {
+            sql_lab: [['can_export_data', 'Superset']],
+          },
+        },
+        sqlLab: {
+          ...initialState.sqlLab,
+          queries: {
+            [queries[0].id]: queries[0],
+          },
+        },
+      }),
+    );
+    const csvButton = queryByTestId('export-csv-button');
+    expect(csvButton).toBeInTheDocument();
+    expect(csvButton).toBeEnabled();
+    mockIsFeatureEnabled.mockReset();
+  });
+
+  test('should disable CSV button when granular flag is ON and user lacks 
can_export_data', async () => {
+    mockIsFeatureEnabled.mockImplementation(
+      (flag: FeatureFlag) => flag === FeatureFlag.GranularExportControls,
+    );
+    const { queryByTestId } = setup(
+      mockedProps,
+      mockStore({
+        ...initialState,
+        user: {
+          ...user,
+          roles: {
+            sql_lab: [],
+          },
+        },
+        sqlLab: {
+          ...initialState.sqlLab,
+          queries: {
+            [queries[0].id]: queries[0],
+          },
+        },
+      }),
+    );
+    const csvButton = queryByTestId('export-csv-button');
+    expect(csvButton).toBeInTheDocument();
+    expect(csvButton).toBeDisabled();
+    mockIsFeatureEnabled.mockReset();
+  });
+
+  test('should show clipboard button with granular can_copy_clipboard 
permission when flag is ON', async () => {
+    mockIsFeatureEnabled.mockImplementation(
+      (flag: FeatureFlag) => flag === FeatureFlag.GranularExportControls,
+    );
+    const { queryByTestId } = setup(
+      mockedProps,
+      mockStore({
+        ...initialState,
+        user: {
+          ...user,
+          roles: {
+            sql_lab: [['can_copy_clipboard', 'Superset']],
+          },
+        },
+        sqlLab: {
+          ...initialState.sqlLab,
+          queries: {
+            [queries[0].id]: queries[0],
+          },
+        },
+      }),
+    );
+    expect(queryByTestId('copy-to-clipboard-button')).toBeInTheDocument();

Review Comment:
   **Suggestion:** This test only verifies that the clipboard button exists, 
but the button is always rendered and can still be disabled. As written, it can 
pass even when `can_copy_clipboard` permission handling is broken. Assert 
enabled state to validate the permission contract. [logic error]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   - ⚠️ SQL Lab clipboard permission regressions may escape unit tests.
   - ⚠️ Granular export controls less validated for clipboard behavior.
   ```
   </details>
   
   ```suggestion
       const clipboardButton = queryByTestId('copy-to-clipboard-button');
       expect(clipboardButton).toBeInTheDocument();
       expect(clipboardButton).toBeEnabled();
   ```
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Open `superset-frontend/src/SqlLab/components/ResultSet/index.tsx` and 
locate the
   copy-to-clipboard button in `renderControls()` at lines 434–454, where
   `disabled={!canCopyClipboard}` determines whether the button is enabled.
   
   2. Inspect `superset-frontend/src/hooks/usePermissions.ts` at lines 24–60: 
when the
   `GranularExportControls` feature flag is enabled
   (`isFeatureEnabled(FeatureFlag.GranularExportControls)`), 
`canCopyClipboardSqlLab` is
   derived from the `can_copy_clipboard` permission and returned as 
`canCopyClipboardSqlLab`
   (aliased to `canCopyClipboard` in `ResultSet`).
   
   3. In the test file
   `superset-frontend/src/SqlLab/components/ResultSet/ResultSet.test.tsx`, find 
the test
   `"should show clipboard button with granular can_copy_clipboard permission 
when flag is
   ON"` at lines 831–855; it enables the `GranularExportControls` flag and sets
   `user.roles.sql_lab = [['can_copy_clipboard', 'Superset']]` (lines 831–852), 
then only
   asserts 
`expect(queryByTestId('copy-to-clipboard-button')).toBeInTheDocument();` (line
   853).
   
   4. Because this test never asserts `expect(clipboardButton).toBeEnabled()`, 
a regression
   that incorrectly sets `canCopyClipboardSqlLab` to `false` (making the button 
disabled
   despite the permission) would still leave this test passing, allowing a real 
SQL Lab
   clipboard permission bug to slip through CI.
   ```
   </details>
   <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/ResultSet/ResultSet.test.tsx
   **Line:** 853:853
   **Comment:**
        *Logic Error: This test only verifies that the clipboard button exists, 
but the button is always rendered and can still be disabled. As written, it can 
pass even when `can_copy_clipboard` permission handling is broken. Assert 
enabled state to validate the permission contract.
   
   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.
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38581&comment_hash=011ace98ffa4b71a811d8d1e5a3ee74299305a6fc46e3bfc10739861f1463465&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38581&comment_hash=011ace98ffa4b71a811d8d1e5a3ee74299305a6fc46e3bfc10739861f1463465&reaction=dislike'>👎</a>



##########
superset-frontend/src/SqlLab/components/ResultSet/index.tsx:
##########
@@ -427,30 +431,33 @@ const ResultSet = ({
               }}
             />
           )}
-          {canExportData && (
-            <CopyToClipboard
-              text={prepareCopyToClipboardTabularData(
-                data,
-                columns.map(c => c.column_name),
-              )}
-              wrapped={false}
-              copyNode={
-                <Button
-                  buttonSize="small"
-                  variant="text"
-                  color="primary"
-                  icon={<Icons.CopyOutlined iconSize="m" />}
-                  tooltip={t('Copy to Clipboard')}
-                  aria-label={t('Copy to Clipboard')}
-                  data-test="copy-to-clipboard-button"
-                />
-              }
-              hideTooltip
-              onCopyEnd={() =>
-                logAction(LOG_ACTIONS_SQLLAB_COPY_RESULT_TO_CLIPBOARD, {})
-              }
-            />
-          )}
+          <CopyToClipboard
+            text={prepareCopyToClipboardTabularData(
+              data,
+              columns.map(c => c.column_name),
+            )}

Review Comment:
   **Suggestion:** The clipboard payload is always materialized even when the 
user cannot copy, which can serialize very large result sets unnecessarily and 
cause avoidable UI slowdowns. Only build the clipboard text when copy 
permission is granted. [performance]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   - ⚠️ SQL Lab result header recomputes huge clipboard strings unnecessarily.
   - ⚠️ Extra CPU and memory for users without clipboard permission.
   - ⚠️ Potential UI lag on large result sets in SQL Lab.
   ```
   </details>
   
   ```suggestion
               text={
                       canCopyClipboard
                         ? prepareCopyToClipboardTabularData(
                             data,
                             columns.map(c => c.column_name),
                           )
                         : ''
                     }
   ```
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Enable the `GRANULAR_EXPORT_CONTROLS` feature flag so that SQL Lab uses 
granular
   clipboard permissions, as wired in `usePermissions`
   (`superset-frontend/src/hooks/usePermissions.ts:49-60`, where 
`granularExport` toggles
   `canCopyClipboardSqlLab` based on `can_copy_clipboard`).
   
   2. Create or use a role that has SQL Lab access and export permissions 
(`can_export_csv`
   on `SQLLab` or `can_export_data` on `Superset`) but explicitly lacks 
`can_copy_clipboard`
   on `Superset`, so `canCopyClipboardSqlLab` resolves to `false` for that user
   (`usePermissions.ts:46-60`).
   
   3. Log in as that restricted user, open SQL Lab, and run a query that 
returns a large
   result set (e.g. tens of thousands of rows with many columns) so that 
`query.results.data`
   and `query.results.columns` are large when `ResultSet` renders
   (`superset-frontend/src/SqlLab/components/ResultSet/index.tsx`, 
`renderControls` function
   around hunk lines 343-383 where `data` and `columns` are derived from 
`query.results`).
   
   4. Observe that on every render of `renderControls` (e.g. initial render, 
typing in the
   filter input, or other state changes), the `CopyToClipboard` component at
   `ResultSet/index.tsx` hunk lines 435-441 calls 
`prepareCopyToClipboardTabularData(data,
   columns.map(...))` to eagerly build a full tab-delimited string for the 
entire result set,
   even though `canCopyClipboard` is `false` and the underlying button is 
disabled. This
   unnecessary O(rows × columns) loop and large string allocation can be seen in
   `prepareCopyToClipboardTabularData` 
(`superset-frontend/src/utils/common.ts:106-127`) and
   can cause noticeable main-thread work and UI slowness for large results, 
despite the user
   not being allowed to copy.
   ```
   </details>
   <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/ResultSet/index.tsx
   **Line:** 435:438
   **Comment:**
        *Performance: The clipboard payload is always materialized even when 
the user cannot copy, which can serialize very large result sets unnecessarily 
and cause avoidable UI slowdowns. Only build the clipboard text when copy 
permission is granted.
   
   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.
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38581&comment_hash=1489118a5e665d3c709deb4c11fb79cbf941a03032bd7ccf54f04bcdbce918b3&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38581&comment_hash=1489118a5e665d3c709deb4c11fb79cbf941a03032bd7ccf54f04bcdbce918b3&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