Skip to content

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

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

feat(ui): Add copy button for code blocks in mothership#4033
TheodoreSpeaks merged 5 commits into
stagingfrom
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

vercelBot commented Apr 8, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
ProjectDeploymentActionsUpdated (UTC)
docsSkippedSkippedApr 8, 2026 3:25am

Request Review

@TheodoreSpeaks

Copy link
Copy Markdown
CollaboratorAuthor

@BugBot review

@cursor

cursorBot commented Apr 8, 2026

Copy link
Copy Markdown

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.

@cursorcursorBot left a comment

Copy link
Copy Markdown

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.

Comment threadapps/sim/app/chat/components/message/components/markdown-renderer.tsx Outdated
Comment threadapps/sim/app/chat/components/message/components/markdown-renderer.tsx Outdated
@TheodoreSpeaks
TheodoreSpeaks marked this pull request as ready for review April 8, 2026 03:01
@greptile-apps

Copy link
Copy Markdown
Contributor

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

FilenameOverview
apps/sim/components/ui/copy-code-button.tsxNew 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.tsxAdds 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.tsxAdds 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

Comment threadapps/sim/components/ui/copy-code-button.tsx Outdated
Comment threadapps/sim/app/chat/components/message/components/markdown-renderer.tsx Outdated
Comment threadapps/sim/components/ui/copy-code-button.tsx Outdated
- 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) <noreply@anthropic.com>
@TheodoreSpeaks
TheodoreSpeaks merged commit 6f9f336 into stagingApr 8, 2026
12 checks passed
@TheodoreSpeaks
TheodoreSpeaks deleted the feat/copy-button branch April 8, 2026 03:33
Sign up for freeto 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

@TheodoreSpeaks