fix(ui): accessibility and cleanup for IssueWorkspaceCard copy button - #1832
Merged
commitperclip[bot] merged 1 commit intoJul 31, 2026
Merged
commitperclip[bot] merged 1 commit into
commitperclip[bot] merged 1 commit into
Conversation
…button The new CopyableInline component in IssueWorkspaceCard had two small issues: 1. The copy button only had a title attribute but no aria-label. Screen reader users cannot tell what the button does because title is not reliably announced. Added aria-label that change between "Copy <label>" and "Copied to clipboard" depending on state. 2. The setTimeout for resetting the copied state was not cleaned up on component unmount. If user navigate away quickly after clicking copy, the timer would fire on unmounted component. Added useEffect cleanup to clear the timeout.
Contributor
Greptile SummaryAdds an accessible name to the workspace copy control and clears its copied-state timeout when the component unmounts.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains.
|
| Filename | Overview |
|---|---|
| ui/src/components/IssueWorkspaceCard.tsx | Adds a dynamic copy-button aria-label and unmount cleanup for the copied-state timer. |
Reviews (2): Last reviewed commit: "fix(ui): add aria-label and timer cleanu..." | Re-trigger Greptile
JAYHUANG0109
pushed a commit
to JAYHUANG0109/paperclip
that referenced
this pull request
Aug 13, 2026
…paperclipai#1832) ## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The board UI shows the workspace attached to an issue in `ui/src/components/IssueWorkspaceCard.tsx` > - That card renders values such as the branch name and the workspace path through a small `CopyableInline` component, each with an icon-only copy button > - The button has a `title` attribute only. Screen readers do not announce `title` reliably. A screen reader user hears no useful name for the button, because the button contains an icon and no text > - The button also starts a 1.5 second `setTimeout` to reset its "copied" state. Nothing clears that timer. If the card unmounts first, the callback sets state on an unmounted component > - This pull request adds a dynamic `aria-label` to the button and clears the timer in a `useEffect` cleanup > - The benefit is a copy control that assistive technology can announce, and no stray timer after the card unmounts ## Linked Issues or Issue Description No existing GitHub issue covers this. The problem is described below with the fields from [`bug_report.yml`](.github/ISSUE_TEMPLATE/bug_report.yml). **What happened?** Open an issue that has a workspace attached. Tab to the copy button next to the branch or the workspace path in the workspace card. The screen reader announces an unlabeled button, because the button holds only a lucide `Copy` icon and a `title` attribute. Separately, copy a value and navigate away within 1.5 seconds. The pending `setTimeout` then calls `setCopied(false)` on an unmounted component. **Expected behavior** The copy button has an accessible name that says what it copies, and the name changes to confirm the copy. The reset timer is cleared when the component unmounts. **Steps to reproduce** 1. Run the app locally with `pnpm dev`. 2. Open an issue that has a workspace attached, so `IssueWorkspaceCard` renders. 3. Turn on a screen reader (VoiceOver, NVDA). 4. Tab to the copy button next to the workspace path or the branch name. The button has no useful accessible name. 5. Click the copy button, then navigate away from the issue in under 1.5 seconds. The reset timer is still pending. **Paperclip version or commit** Reproducible on `master` at this pull request's base commit. **Deployment mode** Local dev (pnpm dev). Related pull request, not a duplicate: paperclipai#3531 makes copy-to-clipboard buttons work in non-secure contexts. That pull request changes the clipboard write path. This one changes the button label and the timer cleanup, so the two do not overlap. ## What Changed - Added an `aria-label` to the `CopyableInline` copy button in `ui/src/components/IssueWorkspaceCard.tsx`. The label reads `Copy <label>` (for example "Copy branch"), falls back to `Copy value` when the component gets no `label` prop, and changes to `Copied to clipboard` after a copy. - Added a `useEffect` cleanup that calls `clearTimeout(timerRef.current)` on unmount, so the 1.5 second reset timer cannot fire after the component unmounts. ## Verification - CI is green on this pull request. - Static check: `pnpm -r typecheck`. - Test suite: `pnpm test`. - Manual, screen reader: open an issue with a workspace, tab to the copy button next to the path or the branch, and confirm the announcement is "Copy path" or "Copy branch". Activate the button and confirm the announcement changes to "Copied to clipboard". - Manual, timer: click the copy button and navigate away from the issue immediately. Confirm the console shows no unmounted-component state update. ## Risks Low risk. The change adds one ARIA attribute and one unmount cleanup in a single presentational component. No behavior changes for mouse users, no API or schema change. `clearTimeout(undefined)` is a no-op, so the cleanup is safe when the user never copied. ## Model Used - Anthropic Claude Opus, model ID `claude-opus-4-6`, 200K context window, extended thinking enabled, with tool use for file edits. - Recorded by a maintainer while bringing this description up to the current template. The original description predates the Model Used requirement, so the author did not state a model. Author: please correct this line if the model was different. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [ ] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge Notes on the checklist: no test or documentation change applies to a two-line ARIA and cleanup fix in one component. The Greptile box stays unchecked until the current review round closes. (cherry picked from commit 54e2031)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Thinking Path
Linked Issues or Issue Description
No existing GitHub issue covers this. The problem is described below with the fields from
bug_report.yml.What happened?
Open an issue that has a workspace attached. Tab to the copy button next to the branch or the workspace path in the workspace card. The screen reader announces an unlabeled button, because the button holds only a lucide
Copyicon and atitleattribute. Separately, copy a value and navigate away within 1.5 seconds. The pendingsetTimeoutthen callssetCopied(false)on an unmounted component.Expected behavior
The copy button has an accessible name that says what it copies, and the name changes to confirm the copy. The reset timer is cleared when the component unmounts.
Steps to reproduce
pnpm dev.IssueWorkspaceCardrenders.Paperclip version or commit
Reproducible on
masterat this pull request's base commit.Deployment mode
Local dev (pnpm dev).
Related pull request, not a duplicate: #3531 makes copy-to-clipboard buttons work in non-secure contexts. That pull request changes the clipboard write path. This one changes the button label and the timer cleanup, so the two do not overlap.
What Changed
aria-labelto theCopyableInlinecopy button inui/src/components/IssueWorkspaceCard.tsx. The label readsCopy <label>(for example "Copy branch"), falls back toCopy valuewhen the component gets nolabelprop, and changes toCopied to clipboardafter a copy.useEffectcleanup that callsclearTimeout(timerRef.current)on unmount, so the 1.5 second reset timer cannot fire after the component unmounts.Verification
pnpm -r typecheck.pnpm test.Risks
Low risk. The change adds one ARIA attribute and one unmount cleanup in a single presentational component. No behavior changes for mouse users, no API or schema change.
clearTimeout(undefined)is a no-op, so the cleanup is safe when the user never copied.Model Used
claude-opus-4-6, 200K context window, extended thinking enabled, with tool use for file edits.Checklist
Fixes: #/Closes #/Refs #OR (b) described the issue in-PR following the relevant issue template#NNN/github.com/paperclipai/paperclipURLs)docs/...,fix/...) and contains no internal Paperclip ticket id or instance-derived detailsNotes on the checklist: no test or documentation change applies to a two-line ARIA and cleanup fix in one component. The Greptile box stays unchecked until the current review round closes.