Skip to content

feat(ui): Add copy button for code blocks in mothership#4033

Merged
TheodoreSpeaks merged 5 commits intostagingfrom
feat/copy-button
Apr 8, 2026
Merged

feat(ui): Add copy button for code blocks in mothership#4033
TheodoreSpeaks merged 5 commits intostagingfrom
feat/copy-button

Conversation

@TheodoreSpeaks
Copy link
Copy Markdown
Collaborator

Summary

Add copy button for any code blocks in mothership. Makes it easier to copy code blocks.

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation
  • Other: ___________

Testing

Tested locally with different code block types.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

Screenshots/Videos

image

@vercel
Copy link
Copy Markdown

vercel bot commented Apr 8, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Apr 8, 2026 3:25am

Request Review

@TheodoreSpeaks
Copy link
Copy Markdown
Collaborator Author

@BugBot review

@cursor
Copy link
Copy Markdown

cursor bot commented Apr 8, 2026

PR Summary

Low Risk
Low risk UI-only change that adds client-side clipboard copying to rendered markdown code blocks; main risk is minor UX issues if navigator.clipboard is unavailable or denied.

Overview
Adds a reusable CopyCodeButton that copies code to the clipboard and shows a temporary success state.

Updates both chat markdown renderers (markdown-renderer.tsx and chat-content.tsx) to display this button in code block headers, and introduces a shared extractTextContent utility to reliably derive plain text from React node code content.

Reviewed by Cursor Bugbot for commit 6ed3bcc. Bugbot is set up for automated code reviews on this repo. Configure here.

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit e079c82. Configure here.

@TheodoreSpeaks TheodoreSpeaks marked this pull request as ready for review April 8, 2026 03:01
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Apr 8, 2026

Greptile Summary

This PR adds a reusable CopyCodeButton component and wires it into both the public chat markdown renderer (markdown-renderer.tsx) and the workspace chat content renderer (chat-content.tsx), giving users a one-click way to copy fenced code blocks.

Key findings:

  • P1 — Unhandled clipboard Promise (copy-code-button.tsx): navigator.clipboard.writeText(code) is not awaited. setCopied(true) fires unconditionally, so the "✓ Copied" indicator appears even when the write fails (e.g. browser permissions denied, page not focused).
  • P2 — Invisible hover state (chat-content.tsx): The CopyCodeButton receives hover:bg-[var(--surface-4)], which is the same token used by its parent container, so the hover effect produces no visible change.
  • P2 — extractTextContent duplicated across two files: An identical helper is now defined independently in both markdown-renderer.tsx and chat-content.tsx. Per project guidelines, shared helpers needed by 2+ files should be extracted into a shared utils.ts.
  • P2 — setTimeout not cleaned up on unmount: The timer handle is discarded; clearing it in a useEffect cleanup would prevent the state update from firing after the component unmounts.

Confidence Score: 4/5

Safe to merge after fixing the unhandled clipboard Promise, which causes a misleading success indicator on write failure.

One P1 issue: the clipboard write is not awaited, so the copy-success UI fires regardless of whether the write actually succeeded. This is a real, reproducible behaviour defect on the primary user path of the feature. The remaining findings are P2 quality/style items that do not block correctness.

apps/sim/components/ui/copy-code-button.tsx — fix async clipboard handling before merging.

Vulnerabilities

No security concerns identified. The clipboard write uses the standard navigator.clipboard.writeText API with user-supplied code content that is already rendered on-screen. No injection vectors, credential exposure, or auth-boundary issues were found.

Important Files Changed

Filename Overview
apps/sim/components/ui/copy-code-button.tsx New shared copy-button component; clipboard write is not awaited causing the success indicator to fire even on failure, and the setTimeout is not cleaned up on unmount.
apps/sim/app/chat/components/message/components/markdown-renderer.tsx Adds CopyCodeButton to chat code blocks and introduces extractTextContent helper, which is now duplicated with the identical function in chat-content.tsx.
apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/chat-content/chat-content.tsx Adds CopyCodeButton to workspace chat code blocks; hover background token matches container background, making hover feedback invisible.

Sequence Diagram

sequenceDiagram
    participant User
    participant CopyCodeButton
    participant Clipboard as navigator.clipboard
    participant Timer as setTimeout

    User->>CopyCodeButton: click
    CopyCodeButton->>Clipboard: writeText(code) [Promise, not awaited]
    CopyCodeButton->>CopyCodeButton: setCopied(true) [fires immediately, regardless of result]
    CopyCodeButton->>Timer: setTimeout(setCopied(false), 2000)
    Note over Clipboard: Write may succeed or fail silently
    Timer-->>CopyCodeButton: setCopied(false) after 2s
    Note over CopyCodeButton: If component unmounts before 2s,<br/>timer fires on unmounted component
Loading

Reviews (1): Last reviewed commit: "Handle react node case for copy" | Re-trigger Greptile

- Await clipboard write and clear timeout on unmount in CopyCodeButton
- Fix hover bg color matching container bg (surface-4 -> surface-5)
- Extract extractTextContent to shared util at lib/core/utils/react-node-text.ts

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
@TheodoreSpeaks TheodoreSpeaks merged commit 6f9f336 into staging Apr 8, 2026
12 checks passed
@TheodoreSpeaks TheodoreSpeaks deleted the feat/copy-button branch April 8, 2026 03:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant