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


##########
superset-frontend/src/components/CopyToClipboard/index.tsx:
##########
@@ -16,126 +16,153 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-import { Component, cloneElement, ReactElement } from 'react';
+import {
+  cloneElement,
+  isValidElement,
+  type KeyboardEvent,
+  ReactElement,
+  useCallback,
+} from 'react';
 import { t } from '@apache-superset/core/translation';
 import { css, SupersetTheme } from '@apache-superset/core/theme';
 import copyTextToClipboard from 'src/utils/copy';
 import { Tooltip } from '@superset-ui/core/components';
 import withToasts from '../MessageToasts/withToasts';
 import type { CopyToClipboardProps } from './types';
 
-const defaultProps: Partial<CopyToClipboardProps> = {
-  copyNode: <span>{t('Copy')}</span>,
-  onCopyEnd: () => {},
-  shouldShowText: true,
-  wrapped: true,
-  tooltipText: t('Copy to clipboard'),
-  hideTooltip: false,
-};
+function CopyToClip({
+  copyNode = <span>{t('Copy')}</span>,
+  onCopyEnd = () => {},
+  shouldShowText = true,
+  wrapped = true,
+  tooltipText = t('Copy to clipboard'),
+  hideTooltip = false,
+  disabled,
+  getText,
+  text,
+  addSuccessToast,
+  addDangerToast,
+}: CopyToClipboardProps) {
+  const copyToClipboard = useCallback(
+    (textToCopy: Promise<string>) => {
+      copyTextToClipboard(() => textToCopy)
+        .then(() => {
+          addSuccessToast(t('Copied to clipboard!'));
+        })
+        .catch(() => {
+          addDangerToast(
+            t(
+              'Sorry, your browser does not support copying. Use Ctrl / Cmd + 
C!',
+            ),
+          );
+        })
+        .finally(() => {
+          if (onCopyEnd) onCopyEnd();
+        });
+    },
+    [addSuccessToast, addDangerToast, onCopyEnd],
+  );
 
-class CopyToClip extends Component<CopyToClipboardProps> {
-  static defaultProps = defaultProps;
-
-  constructor(props: CopyToClipboardProps) {
-    super(props);
-    this.copyToClipboard = this.copyToClipboard.bind(this);
-    this.onClick = this.onClick.bind(this);
-  }
-
-  onClick() {
-    if (this.props.disabled) {
+  const onClick = useCallback(() => {
+    if (disabled) {
       return;
     }
-    if (this.props.getText) {
-      this.props.getText((d: string) => {
-        this.copyToClipboard(Promise.resolve(d));
+    if (getText) {
+      getText((d: string) => {
+        copyToClipboard(Promise.resolve(d));
       });
     } else {
-      this.copyToClipboard(Promise.resolve(this.props.text || ''));
+      copyToClipboard(Promise.resolve(text || ''));
     }
-  }
-
-  getDecoratedCopyNode() {
-    const copyNode = this.props.copyNode as ReactElement;
-    const { disabled } = this.props;
-    return cloneElement(copyNode, {
-      style: {
-        ...copyNode.props.style,
-        cursor: disabled ? 'not-allowed' : 'pointer',
-      },
-      onClick: disabled ? undefined : this.onClick,
-      'aria-disabled': disabled || undefined,
-      tabIndex: disabled ? -1 : copyNode.props.tabIndex,
-    });
-  }
+  }, [disabled, getText, text, copyToClipboard]);
 
-  copyToClipboard(textToCopy: Promise<string>) {
-    copyTextToClipboard(() => textToCopy)
-      .then(() => {
-        this.props.addSuccessToast(t('Copied to clipboard!'));
-      })
-      .catch(() => {
-        this.props.addDangerToast(
-          t(
-            'Sorry, your browser does not support copying. Use Ctrl / Cmd + 
C!',
-          ),
-        );
-      })
-      .finally(() => {
-        if (this.props.onCopyEnd) this.props.onCopyEnd();
+  const getDecoratedCopyNode = useCallback(() => {
+    const cursor = disabled ? 'not-allowed' : 'pointer';
+    if (isValidElement(copyNode)) {
+      const node = copyNode as ReactElement;
+      return cloneElement(node, {
+        style: {
+          ...node.props.style,
+          cursor,
+        },
+        onClick: disabled ? undefined : onClick,

Review Comment:
   **Suggestion:** Replacing the child element's click handler with `onClick` 
drops any existing `copyNode` click behavior, which can break caller logic (for 
example preventing default navigation or custom analytics). Compose with the 
original handler instead of overwriting it. [api mismatch]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   - ⚠️ Future copy buttons lose custom click behavior.
   - ⚠️ Analytics handlers on copyNode would never execute.
   - ⚠️ Affects SqlLab, dashboard, and explore copy interactions.
   ```
   </details>
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Inspect `CopyToClipboard` implementation in
   superset-frontend/src/components/CopyToClipboard/index.tsx:79–92; when 
`copyNode` is a
   ReactElement, `cloneElement(node, { ...style, cursor, onClick: disabled ? 
undefined :
   onClick, 'aria-disabled': ..., tabIndex: ... })` is used, unconditionally 
setting
   `onClick`.
   
   2. Note that several callers already pass custom React elements as 
`copyNode` (e.g.
   URLShortLinkButton at
   
superset-frontend/src/dashboard/components/URLShortLinkButton/index.tsx:11–16,
   TableElement at 
superset-frontend/src/SqlLab/components/TableElement/index.tsx:122–137,
   DataTableControl at
   superset-frontend/src/explore/components/DataTableControl/index.tsx:8–27), 
even though
   they currently omit `onClick`.
   
   3. If any of these callers adds a meaningful `onClick` to `copyNode` (for 
analytics,
   navigation, or side effects), React will still execute 
`getDecoratedCopyNode()`
   (CopyToClipboard:79–114), and `cloneElement` at line 83–89 will overwrite 
the original
   `node.props.onClick` with its own `onClick` handler.
   
   4. At runtime, clicking the rendered copy control calls only 
`CopyToClipboard`'s internal
   `onClick` (lines 66–77, which performs clipboard copy) while the caller's 
original
   `copyNode` click handler is never invoked, silently breaking any caller 
logic attached to
   that handler without errors.
   ```
   </details>
   
   [Fix in 
Cursor](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=d8fe6c0ea86f4019903672c807aabb22&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
 | [Fix in VSCode 
Claude](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=d8fe6c0ea86f4019903672c807aabb22&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/components/CopyToClipboard/index.tsx
   **Line:** 88:88
   **Comment:**
        *Api Mismatch: Replacing the child element's click handler with 
`onClick` drops any existing `copyNode` click behavior, which can break caller 
logic (for example preventing default navigation or custom analytics). Compose 
with the original handler instead of overwriting it.
   
   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%2F39461&comment_hash=15245a6f2eccabd67fa04d57e6515e29ca0b4d1ac03904a2f42b51336b45e250&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F39461&comment_hash=15245a6f2eccabd67fa04d57e6515e29ca0b4d1ac03904a2f42b51336b45e250&reaction=dislike'>👎</a>



##########
superset-frontend/packages/superset-ui-core/src/components/ModalTrigger/index.tsx:
##########
@@ -110,7 +113,9 @@ export const ModalTrigger = forwardRef(
           className={className}
           show={showModal}
           onHide={close}
-          name={modalTitle}
+          // `name` is used for data-test / telemetry and must be a string;
+          // `title` accepts arbitrary ReactNode for rich rendering.
+          name={typeof modalTitle === 'string' ? modalTitle : undefined}

Review Comment:
   **Suggestion:** When `modalTitle` is a React node, `name` becomes 
`undefined`, so the underlying modal falls back to the generic 
`data-test="antd-modal"` and loses the stable per-modal identifier used by 
telemetry/selectors. Add a dedicated string prop (for example `modalName`) and 
pass that to `name` so rich titles do not erase modal identity. [api mismatch]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   - ⚠️ Rich-title modals get generic data-test "antd-modal".
   - ⚠️ Telemetry cannot distinguish individually named modals.
   - ⚠️ End-to-end tests lose stable modal selectors.
   ```
   </details>
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Note that `ModalTrigger`
   
(superset-frontend/packages/superset-ui-core/src/components/ModalTrigger/index.tsx:24–31,
   112–120) declares `modalTitle?: ReactNode` and passes `name={typeof 
modalTitle ===
   'string' ? modalTitle : undefined}` to `Modal`.
   
   2. Observe `Modal` implementation
   
(superset-frontend/packages/superset-ui-core/src/components/Modal/Modal.tsx:228–256,
   87–109) where `wrapProps` is set to `{'data-test': `${name || 
'antd'}-modal`, ...}` so
   when `name` is falsy the data-test falls back to `"antd-modal"`.
   
   3. Use `ModalTrigger` from any caller (for example `renderControls` in
   superset-frontend/src/SqlLab/components/TableElement/index.tsx:58–80) but 
pass a rich
   ReactNode title as encouraged by the new comment (lines 27–30 in 
ModalTrigger), e.g.
   `<ControlHeader title="Keys for table" />` instead of a plain string.
   
   4. When the trigger node is clicked, `open()` in ModalTrigger (lines 84–88) 
sets
   `showModal` to true, rendering `<Modal>` with `name={undefined}`; inside 
`Modal` line 108
   sets `data-test="antd-modal"`, so this modal no longer has a stable, 
specific `data-test`
   identifier for telemetry or automated selectors even though a distinct title 
ReactNode was
   provided.
   ```
   </details>
   
   [Fix in 
Cursor](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=15fca8579efa4d6096d478489e099cdd&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
 | [Fix in VSCode 
Claude](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=15fca8579efa4d6096d478489e099cdd&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/packages/superset-ui-core/src/components/ModalTrigger/index.tsx
   **Line:** 118:118
   **Comment:**
        *Api Mismatch: When `modalTitle` is a React node, `name` becomes 
`undefined`, so the underlying modal falls back to the generic 
`data-test="antd-modal"` and loses the stable per-modal identifier used by 
telemetry/selectors. Add a dedicated string prop (for example `modalName`) and 
pass that to `name` so rich titles do not erase modal identity.
   
   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%2F39461&comment_hash=3719c63cd0433116af8b3e74714be5c58c79c0025ac62a3583d86b312932aeb2&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F39461&comment_hash=3719c63cd0433116af8b3e74714be5c58c79c0025ac62a3583d86b312932aeb2&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