Skip to content

Add copy button to stack trace code blocks#16

Open
robobun wants to merge 1 commit intomainfrom
claude/add-copy-button-stacktrace
Open

Add copy button to stack trace code blocks#16
robobun wants to merge 1 commit intomainfrom
claude/add-copy-button-stacktrace

Conversation

@robobun
Copy link
Copy Markdown

@robobun robobun commented Feb 11, 2026

Summary

  • Adds a "Copy" button to the stack trace display on the main remapper UI, the crash-recorded page, and the crash-recorded standalone page
  • On the main remapper UI, clicking copies the panic message + plain text stack trace (using the existing addrsToPlainText formatter)
  • On the crash-recorded pages, clicking copies the rendered markdown stack trace text from the <details> section
  • The button shows "Copied!" feedback for 2 seconds after clicking

Closes oven-sh/bun#26888

Test plan

  • Open the main remapper page, paste a trace string, verify the Copy button appears in the top-right of the stack trace table
  • Click Copy, verify clipboard contains the panic message and plain text stack trace
  • Visit a crash-recorded URL, expand "View Stack Trace", click the Copy button, verify clipboard contains the stack trace text
  • Verify the button shows "Copied!" for 2 seconds then reverts to "Copy"
  • Test in both light and dark mode

🤖 Generated with Claude Code

Adds a copy button to the stack trace display in three places:

1. Main remapper UI - copies the panic message + plain text stack trace
   using the existing addrsToPlainText formatter
2. Crash-recorded page - copies the rendered markdown stack trace text
3. Crash-recorded standalone page - same as above

The button shows "Copied!" feedback for 2 seconds after clicking.

Closes oven-sh/bun#26888

Co-Authored-By: Claude <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 11, 2026

Walkthrough

The PR implements copy-to-clipboard functionality for stack traces across multiple frontend components. Users can now copy stack trace content via new copy buttons with visual feedback indicating successful copy action.

Changes

Cohort / File(s) Summary
Crash Recorded Stack Trace UI
frontend/crash-recorded.html, frontend/crash-recorded-standalone.html, frontend/crash-recorded.css
Added interactive copy button to the "View Stack Trace" summary with inline click handler that copies stacktrace content to clipboard and shows temporary "Copied!" feedback. Includes new .copy-trace-btn CSS class with styling for button appearance, hover states, and icon sizing.
Frontend Stack Trace UI
frontend/frontend.ts, frontend/style.css
Implemented copy-to-clipboard functionality in Fetched UI state using addrsToPlainText for plaintext formatting. Added .copy-btn styled button with "Copied!" feedback mechanism. Introduced .table-wrapper container to wrap stack trace table and reposition copy button at top-right with responsive adjustments.
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: adding a copy button to stack trace code blocks across multiple UI locations.
Description check ✅ Passed The description is related to the changeset and provides clear details about what was implemented across three locations with specific behavior.
Linked Issues check ✅ Passed The PR implements the requested feature from #26888: adds copy buttons to stack trace code blocks to simplify copying traces without manual selection.
Out of Scope Changes check ✅ Passed All changes are directly related to adding copy button functionality to stack traces. CSS and HTML modifications support the core feature across the three specified locations.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🤖 Fix all issues with AI agents
In `@frontend/crash-recorded-standalone.html`:
- Line 54: The inline onclick handler for the copy button uses
navigator.clipboard.writeText(...) without a .catch, so failures are silent;
update the handler attached to elements with class "copy-trace-btn" (the current
inline onclick) to add a .catch handler on the promise returned by
navigator.clipboard.writeText that logs the error (console.error) and provides
UI feedback (e.g., change the button's inner span text to "Copy failed" or
similar, then revert after a timeout), and ensure the success .then still sets
"Copied!" and reverts after 2s; keep using event.stopPropagation() and the
existing element lookup (document.querySelector('.stacktrace')) but handle
rejection paths explicitly.

In `@frontend/crash-recorded.css`:
- Around line 233-253: The CSS blocks for the selectors .copy-trace-btn,
.copy-trace-btn:hover, and .copy-trace-btn svg are missing a blank line before
each rule; update the formatting so there is an empty line preceding each of
these selectors to match the file's established spacing and satisfy Stylelint
(i.e., insert a single blank line immediately above the .copy-trace-btn rule,
above .copy-trace-btn:hover, and above .copy-trace-btn svg).

In `@frontend/crash-recorded.html`:
- Line 63: The inline onclick handler on the button (class "copy-trace-btn")
calls navigator.clipboard.writeText(...) but lacks error handling; update the
handler for navigator.clipboard.writeText (or the function it calls) to add a
.catch() (or try/catch if converted to async) so clipboard errors are handled
and user feedback is given (e.g., change the button's inner span text to
"Failed" or show an error tooltip) and optionally log the error to console;
ensure you reference the same DOM access used now
(document.querySelector('.stacktrace').textContent and
this.querySelector('span')) so success still sets "Copied!" and failure sets a
clear failure state.

In `@frontend/frontend.ts`:
- Around line 211-216: The clipboard write call using
navigator.clipboard.writeText(text) in the click handler should handle failures;
add a .catch(err => { ... }) after the .then to handle rejection, e.g. set
copyBtn.querySelector("span")!.textContent to an error/fallback message (or
revert to "Copy"), and log the error (console.error or a logger) so failures are
visible; ensure you still restore the button text in a timeout on both success
and failure paths and reference navigator.clipboard.writeText, copyBtn, and the
span querySelector in your changes.

In `@frontend/style.css`:
- Line 314: Replace the legacy comma-separated rgb() value used on the
border-color declaration with the modern space-separated color-function syntax;
locate the border-color: rgb(247, 97, 174) statement and change it to use
rgb(247 97 174) (no commas) so it satisfies Stylelint's modern color-function
rule.

<summary>View Stack Trace</summary>
<summary>
View Stack Trace
<button class="copy-trace-btn" onclick="event.stopPropagation();var t=document.querySelector('.stacktrace').textContent;navigator.clipboard.writeText(t).then(function(){this.querySelector('span').textContent='Copied!';var b=this;setTimeout(function(){b.querySelector('span').textContent='Copy'},2e3)}.bind(this))" title="Copy stack trace">
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add error handling for clipboard API failure.

The navigator.clipboard.writeText() call has no .catch() handler. If clipboard access is denied (e.g., in non-secure contexts or when permissions are blocked), the promise rejects silently and the "Copied!" feedback never appears, leaving users confused.

🛡️ Proposed fix with error handling
-          <button class="copy-trace-btn" onclick="event.stopPropagation();var t=document.querySelector('.stacktrace').textContent;navigator.clipboard.writeText(t).then(function(){this.querySelector('span').textContent='Copied!';var b=this;setTimeout(function(){b.querySelector('span').textContent='Copy'},2e3)}.bind(this))" title="Copy stack trace">
+          <button class="copy-trace-btn" onclick="event.stopPropagation();var t=document.querySelector('.stacktrace').textContent;navigator.clipboard.writeText(t).then(function(){this.querySelector('span').textContent='Copied!';var b=this;setTimeout(function(){b.querySelector('span').textContent='Copy'},2000)}.bind(this)).catch(function(){this.querySelector('span').textContent='Failed';var b=this;setTimeout(function(){b.querySelector('span').textContent='Copy'},2000)}.bind(this))" title="Copy stack trace">
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<button class="copy-trace-btn" onclick="event.stopPropagation();var t=document.querySelector('.stacktrace').textContent;navigator.clipboard.writeText(t).then(function(){this.querySelector('span').textContent='Copied!';var b=this;setTimeout(function(){b.querySelector('span').textContent='Copy'},2e3)}.bind(this))" title="Copy stack trace">
<button class="copy-trace-btn" onclick="event.stopPropagation();var t=document.querySelector('.stacktrace').textContent;navigator.clipboard.writeText(t).then(function(){this.querySelector('span').textContent='Copied!';var b=this;setTimeout(function(){b.querySelector('span').textContent='Copy'},2000)}.bind(this)).catch(function(){this.querySelector('span').textContent='Failed';var b=this;setTimeout(function(){b.querySelector('span').textContent='Copy'},2000)}.bind(this))" title="Copy stack trace">
🤖 Prompt for AI Agents
In `@frontend/crash-recorded-standalone.html` at line 54, The inline onclick
handler for the copy button uses navigator.clipboard.writeText(...) without a
.catch, so failures are silent; update the handler attached to elements with
class "copy-trace-btn" (the current inline onclick) to add a .catch handler on
the promise returned by navigator.clipboard.writeText that logs the error
(console.error) and provides UI feedback (e.g., change the button's inner span
text to "Copy failed" or similar, then revert after a timeout), and ensure the
success .then still sets "Copied!" and reverts after 2s; keep using
event.stopPropagation() and the existing element lookup
(document.querySelector('.stacktrace')) but handle rejection paths explicitly.

Comment on lines +233 to +253
.copy-trace-btn {
margin-left: auto;
display: inline-flex;
align-items: center;
gap: 0.35rem;
padding: 0.25rem 0.5rem;
font-size: 0.75rem;
background: #262626;
border: 1px solid #383838;
border-radius: 4px;
color: #a3a3a3;
cursor: pointer;
transition: color 0.15s, background 0.15s;
}
.copy-trace-btn:hover {
background: #333;
color: #f472b6;
}
.copy-trace-btn svg {
flex-shrink: 0;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Add empty lines before CSS rules for consistency.

Stylelint flags missing empty lines before .copy-trace-btn, .copy-trace-btn:hover, and .copy-trace-btn svg rules. Adding empty lines improves readability and matches the formatting pattern used elsewhere in this file.

🧹 Proposed formatting fix
 .hidden {
   display: none;
 }
+
 .copy-trace-btn {
   margin-left: auto;
   display: inline-flex;
   align-items: center;
   gap: 0.35rem;
   padding: 0.25rem 0.5rem;
   font-size: 0.75rem;
   background: `#262626`;
   border: 1px solid `#383838`;
   border-radius: 4px;
   color: `#a3a3a3`;
   cursor: pointer;
   transition: color 0.15s, background 0.15s;
 }
+
 .copy-trace-btn:hover {
   background: `#333`;
   color: `#f472b6`;
 }
+
 .copy-trace-btn svg {
   flex-shrink: 0;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
.copy-trace-btn {
margin-left: auto;
display: inline-flex;
align-items: center;
gap: 0.35rem;
padding: 0.25rem 0.5rem;
font-size: 0.75rem;
background: #262626;
border: 1px solid #383838;
border-radius: 4px;
color: #a3a3a3;
cursor: pointer;
transition: color 0.15s, background 0.15s;
}
.copy-trace-btn:hover {
background: #333;
color: #f472b6;
}
.copy-trace-btn svg {
flex-shrink: 0;
}
.hidden {
display: none;
}
.copy-trace-btn {
margin-left: auto;
display: inline-flex;
align-items: center;
gap: 0.35rem;
padding: 0.25rem 0.5rem;
font-size: 0.75rem;
background: `#262626`;
border: 1px solid `#383838`;
border-radius: 4px;
color: `#a3a3a3`;
cursor: pointer;
transition: color 0.15s, background 0.15s;
}
.copy-trace-btn:hover {
background: `#333`;
color: `#f472b6`;
}
.copy-trace-btn svg {
flex-shrink: 0;
}
🧰 Tools
🪛 Stylelint (17.2.0)

[error] 233-246: Expected empty line before rule (rule-empty-line-before)

(rule-empty-line-before)


[error] 247-250: Expected empty line before rule (rule-empty-line-before)

(rule-empty-line-before)


[error] 251-253: Expected empty line before rule (rule-empty-line-before)

(rule-empty-line-before)

🤖 Prompt for AI Agents
In `@frontend/crash-recorded.css` around lines 233 - 253, The CSS blocks for the
selectors .copy-trace-btn, .copy-trace-btn:hover, and .copy-trace-btn svg are
missing a blank line before each rule; update the formatting so there is an
empty line preceding each of these selectors to match the file's established
spacing and satisfy Stylelint (i.e., insert a single blank line immediately
above the .copy-trace-btn rule, above .copy-trace-btn:hover, and above
.copy-trace-btn svg).

<summary>View Stack Trace</summary>
<summary>
View Stack Trace
<button class="copy-trace-btn" onclick="event.stopPropagation();var t=document.querySelector('.stacktrace').textContent;navigator.clipboard.writeText(t).then(function(){this.querySelector('span').textContent='Copied!';var b=this;setTimeout(function(){b.querySelector('span').textContent='Copy'},2e3)}.bind(this))" title="Copy stack trace">
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add error handling for clipboard API failure.

Same issue as the standalone version—no .catch() handler for navigator.clipboard.writeText(). If clipboard access fails, users get no feedback.

🛡️ Proposed fix with error handling
-          <button class="copy-trace-btn" onclick="event.stopPropagation();var t=document.querySelector('.stacktrace').textContent;navigator.clipboard.writeText(t).then(function(){this.querySelector('span').textContent='Copied!';var b=this;setTimeout(function(){b.querySelector('span').textContent='Copy'},2e3)}.bind(this))" title="Copy stack trace">
+          <button class="copy-trace-btn" onclick="event.stopPropagation();var t=document.querySelector('.stacktrace').textContent;navigator.clipboard.writeText(t).then(function(){this.querySelector('span').textContent='Copied!';var b=this;setTimeout(function(){b.querySelector('span').textContent='Copy'},2000)}.bind(this)).catch(function(){this.querySelector('span').textContent='Failed';var b=this;setTimeout(function(){b.querySelector('span').textContent='Copy'},2000)}.bind(this))" title="Copy stack trace">
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<button class="copy-trace-btn" onclick="event.stopPropagation();var t=document.querySelector('.stacktrace').textContent;navigator.clipboard.writeText(t).then(function(){this.querySelector('span').textContent='Copied!';var b=this;setTimeout(function(){b.querySelector('span').textContent='Copy'},2e3)}.bind(this))" title="Copy stack trace">
<button class="copy-trace-btn" onclick="event.stopPropagation();var t=document.querySelector('.stacktrace').textContent;navigator.clipboard.writeText(t).then(function(){this.querySelector('span').textContent='Copied!';var b=this;setTimeout(function(){b.querySelector('span').textContent='Copy'},2000)}.bind(this)).catch(function(){this.querySelector('span').textContent='Failed';var b=this;setTimeout(function(){b.querySelector('span').textContent='Copy'},2000)}.bind(this))" title="Copy stack trace">
🤖 Prompt for AI Agents
In `@frontend/crash-recorded.html` at line 63, The inline onclick handler on the
button (class "copy-trace-btn") calls navigator.clipboard.writeText(...) but
lacks error handling; update the handler for navigator.clipboard.writeText (or
the function it calls) to add a .catch() (or try/catch if converted to async) so
clipboard errors are handled and user feedback is given (e.g., change the
button's inner span text to "Failed" or show an error tooltip) and optionally
log the error to console; ensure you reference the same DOM access used now
(document.querySelector('.stacktrace').textContent and
this.querySelector('span')) so success still sets "Copied!" and failure sets a
clear failure state.

Comment thread frontend/frontend.ts
Comment on lines +211 to +216
navigator.clipboard.writeText(text).then(() => {
copyBtn.querySelector("span")!.textContent = "Copied!";
setTimeout(() => {
copyBtn.querySelector("span")!.textContent = "Copy";
}, 2000);
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add error handling for clipboard API failure.

The navigator.clipboard.writeText() call lacks a .catch() handler. Unlike the HTML templates, TypeScript makes it easy to handle this properly.

🛡️ Proposed fix with error handling
         navigator.clipboard.writeText(text).then(() => {
           copyBtn.querySelector("span")!.textContent = "Copied!";
           setTimeout(() => {
             copyBtn.querySelector("span")!.textContent = "Copy";
           }, 2000);
+        }).catch(() => {
+          copyBtn.querySelector("span")!.textContent = "Failed";
+          setTimeout(() => {
+            copyBtn.querySelector("span")!.textContent = "Copy";
+          }, 2000);
         });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
navigator.clipboard.writeText(text).then(() => {
copyBtn.querySelector("span")!.textContent = "Copied!";
setTimeout(() => {
copyBtn.querySelector("span")!.textContent = "Copy";
}, 2000);
});
navigator.clipboard.writeText(text).then(() => {
copyBtn.querySelector("span")!.textContent = "Copied!";
setTimeout(() => {
copyBtn.querySelector("span")!.textContent = "Copy";
}, 2000);
}).catch(() => {
copyBtn.querySelector("span")!.textContent = "Failed";
setTimeout(() => {
copyBtn.querySelector("span")!.textContent = "Copy";
}, 2000);
});
🤖 Prompt for AI Agents
In `@frontend/frontend.ts` around lines 211 - 216, The clipboard write call using
navigator.clipboard.writeText(text) in the click handler should handle failures;
add a .catch(err => { ... }) after the .then to handle rejection, e.g. set
copyBtn.querySelector("span")!.textContent to an error/fallback message (or
revert to "Copy"), and log the error (console.error or a logger) so failures are
visible; ensure you still restore the button text in a timeout on both success
and failure paths and reference navigator.clipboard.writeText, copyBtn, and the
span querySelector in your changes.

Comment thread frontend/style.css
.copy-btn:hover {
opacity: 1;
background-color: var(--pink);
border-color: rgb(247, 97, 174);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Use modern color-function notation.

Stylelint flags rgb(247, 97, 174) as using legacy syntax. Modern CSS uses space-separated values without commas.

🧹 Proposed fix
 .copy-btn:hover {
   opacity: 1;
   background-color: var(--pink);
-  border-color: rgb(247, 97, 174);
+  border-color: rgb(247 97 174);
   color: black;
 }
🧰 Tools
🪛 Stylelint (17.2.0)

[error] 314-314: Expected modern color-function notation (color-function-notation)

(color-function-notation)

🤖 Prompt for AI Agents
In `@frontend/style.css` at line 314, Replace the legacy comma-separated rgb()
value used on the border-color declaration with the modern space-separated
color-function syntax; locate the border-color: rgb(247, 97, 174) statement and
change it to use rgb(247 97 174) (no commas) so it satisfies Stylelint's modern
color-function rule.

@alii alii self-requested a review February 11, 2026 06:29
@dylan-conway dylan-conway force-pushed the main branch 2 times, most recently from d768a24 to e3f577f Compare February 14, 2026 04:07
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.

Implement Copy Button on Bun.report codeblock / git prefill

1 participant