Skip to content

feat(permissions): add copy-to-clipboard button for plan content#3102

Closed
MattPua wants to merge 1 commit into
mainfrom
posthog-code/add-copy-plan-to-clipboard-button
Closed

feat(permissions): add copy-to-clipboard button for plan content#3102
MattPua wants to merge 1 commit into
mainfrom
posthog-code/add-copy-plan-to-clipboard-button

Conversation

@MattPua

@MattPua MattPua commented Jul 2, 2026

Copy link
Copy Markdown
Member

TL;DR

Added a copy-to-clipboard button to the plan content display that allows users to easily copy the full plan text. The button shows a confirmation state ("Copied!") after clicking and appears in both normal and fullscreen views.

Problem

Users viewing plan content had limited options for interacting with it. Adding a copy-to-clipboard button makes it easier to share or work with plan text without manual selection and copying.

Changes

  • Added Copy and Check icons from @phosphor-icons/react for the copy button and confirmation state
  • Imported Tooltip component for better UX on icon buttons
  • Added copied state to track clipboard action confirmation
  • Implemented handleCopy() function that copies plan text to clipboard and temporarily shows "Copied!" confirmation (1.5 second duration)
  • Added copy button with tooltip ("Copy plan to clipboard") in the fullscreen modal header
  • Added matching copy button with tooltip in the normal plan view (sticky top-right position)
  • Wrapped both header buttons in a Flex container for consistent spacing and alignment
  • Added tooltips to existing buttons ("Exit fullscreen" and "Expand to fullscreen") for consistency

How did you test this?

  • Visual verification of button placement in both normal and fullscreen views
  • Tested copy functionality and confirmation state display
  • Verified tooltip content displays correctly

Automatic notifications

  • Publish to changelog?
  • Alert Sales and Marketing teams?

Created with PostHog Code

@trunk-io

trunk-io Bot commented Jul 2, 2026

Copy link
Copy Markdown

Merging to main in this repository is managed by Trunk.

  • To merge this pull request, check the box to the left or comment /trunk merge below.

After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here

@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown

React Doctor found no issues in the changed files. 🎉

Reviewed by React Doctor for commit e6632e6.

@MattPua MattPua closed this Jul 2, 2026
@MattPua MattPua deleted the posthog-code/add-copy-plan-to-clipboard-button branch July 2, 2026 17:14
@greptile-apps

greptile-apps Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Reviews (1): Last reviewed commit: "feat(permissions): add copy-to-clipboard..." | Re-trigger Greptile

Comment on lines +28 to +32
const handleCopy = () => {
navigator.clipboard.writeText(plan);
setCopied(true);
setTimeout(() => setCopied(false), 1500);
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 navigator.clipboard.writeText returns a Promise that can be rejected — for example when the Permissions Policy blocks clipboard access, the page is not focused, or the user denies the permission. Because the return value is never awaited, setCopied(true) is called unconditionally even when the write silently failed, so users see "Copied!" while nothing was placed on the clipboard. Per the project's async/await convention and the rule to wrap async calls in try/catch, this should be awaited inside a try/catch.

Suggested change
const handleCopy = () => {
navigator.clipboard.writeText(plan);
setCopied(true);
setTimeout(() => setCopied(false), 1500);
};
const handleCopy = async () => {
try {
await navigator.clipboard.writeText(plan);
setCopied(true);
setTimeout(() => setCopied(false), 1500);
} catch {
// clipboard write failed; do not show confirmation
}
};

Rule Used: Always wrap asynchronous calls that may fail, such... (source)

Learned From
PostHog/posthog#32098

const handleCopy = () => {
navigator.clipboard.writeText(plan);
setCopied(true);
setTimeout(() => setCopied(false), 1500);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Timeout not cleaned up on unmount

The setTimeout handle is never stored or cleared. If the component unmounts within 1.5 seconds of the click, the callback fires on a stale closure. Consider storing the ID in a useRef and clearing it in a useEffect cleanup — or at minimum clearing any outstanding timer when handleCopy is called again in quick succession, to avoid racing timeouts resetting the state at unexpected times.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

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