From 0a9b508493fd90343e56767336f9482c2281422d Mon Sep 17 00:00:00 2001 From: Stephanie Anderson Date: Thu, 19 Feb 2026 16:16:42 +0100 Subject: [PATCH 1/4] docs(sdk): Add issue saved replies and simplify CopyableCard Add 10 saved replies for GitHub issues covering common scenarios: closing (inactivity, no response, can't reproduce, outdated, duplicate, working as intended, wrong repo), requesting information, and redirecting to support channels. Simplify CopyableCard by removing the description prop and reading copyable text directly from rendered children via a ref, eliminating content duplication in MDX files. Co-Authored-By: Claude --- .../templates/saved-replies/index.mdx | 127 +++++++++++++++--- src/components/copyableCard.tsx | 26 ++-- 2 files changed, 128 insertions(+), 25 deletions(-) diff --git a/develop-docs/sdk/getting-started/templates/saved-replies/index.mdx b/develop-docs/sdk/getting-started/templates/saved-replies/index.mdx index 7d1c51852cad3..74eb4063e62f2 100644 --- a/develop-docs/sdk/getting-started/templates/saved-replies/index.mdx +++ b/develop-docs/sdk/getting-started/templates/saved-replies/index.mdx @@ -10,11 +10,11 @@ Using these replies is encouraged - they give everyone permission to politely up To set up saved replies go to [GitHub > Settings > Saved replies](https://github.com/settings/replies), and add all of the replies below. ---- +## Pull Requests - + Thanks for the contribution! We ask that behavioral changes and refactors have a linked issue so we can discuss the approach before a PR is opened. Could you open an issue describing the problem you're solving and your proposed approach? Closing this for now - happy to revisit once there's an issue to reference. @@ -22,9 +22,7 @@ Please also have a look at our CONTRIBUTING.md for more PR guidelines. - + This is an interesting idea! We'd like to align on the approach before reviewing code - could you open an issue describing the problem and your proposed solution? That way we can agree on direction first. Closing this PR for now. @@ -32,16 +30,9 @@ Please also have a look at our CONTRIBUTING.md for more PR guidelines. - + Thanks for the contribution! This PR needs some updates before we can review: @@ -55,3 +46,109 @@ We marked it as draft for now. Please update and we'll take another look. Please also have a look at our CONTRIBUTING.md for more PR guidelines. + + +## Issues + +### Closing Issues + + + +Closing this issue due to inactivity. If this is still relevant for you, please feel free to reopen or create a new issue with up-to-date information and we'll be happy to take another look. + +Thank you for taking the time to report this! + + + + + +We haven't heard back on this, so we're closing it for now. If you're able to provide the requested information, please feel free to comment and we'll reopen and take another look. + +Thank you for taking the time to report this! + + + + + +We weren't able to reproduce this on our end. If you're still experiencing this issue and can share a minimal reproduction or additional details on how to trigger it, please feel free to comment and we'll reopen. + +Thank you for taking the time to report this! + + + + + +Closing this as it has been superseded by newer SDK or platform versions, or by other issues that cover this topic. If you believe this is still relevant with a current SDK version, please feel free to comment with updated information and we'll reopen. + +Thank you for taking the time to report this! + + + + + +This appears to be a duplicate of #ISSUE_NUMBER, so we're closing this to keep the discussion in one place. Please follow that issue for updates and feel free to add any additional context there. + +Thank you for taking the time to report this! + + + + + +After looking into this, we believe the current behavior is working as intended. EXPLAIN_REASON_HERE + +If you have a use case that isn't covered or think we've misunderstood the issue, please feel free to comment and we can revisit. + +Thank you for taking the time to report this! + + + + + +It looks like this issue belongs in a different repository. Could you please open it in REPO_LINK instead? That team will be better equipped to help. + +Closing this for now. Thank you for taking the time to report this! + + + +### Requesting Information + + + +Thanks for reporting this! To help us investigate, could you provide a few more details? + +- **SDK version**: (e.g. 1.2.3) +- **Platform/OS version**: (e.g. iOS 17, Android 14, Node 20) +- **Steps to reproduce**: What were you doing when this occurred? +- **Expected behavior**: What did you expect to happen? +- **Actual behavior**: What happened instead? +- **Logs or stack traces**: If available + +This will help us narrow things down. Thank you! + + + + + +Thanks for reporting this! We'd love to look into it further, but we need a minimal reproduction to investigate effectively. Could you provide a small, self-contained project or code snippet that demonstrates the issue? + +A good minimal reproduction: +- Uses the latest SDK version +- Contains only the code necessary to trigger the issue +- Includes steps to run and observe the behavior + +This helps us rule out project-specific factors and get to the root cause faster. Thank you! + + + +### Redirecting to Support + + + +Thanks for reaching out! This looks like a usage or configuration question rather than a bug report or feature request. For the fastest help, we'd recommend reaching out through one of our support channels: + +- [Sentry Discord](https://discord.gg/sentry) +- [Sentry Support](https://help.sentry.io/) + +Our support team and community are well-equipped to help with setup and usage questions. If it turns out there is a bug, please feel free to open a new issue with reproduction steps and we'll investigate. + + diff --git a/src/components/copyableCard.tsx b/src/components/copyableCard.tsx index 45112bd6c27e2..fda23bf70d9fd 100644 --- a/src/components/copyableCard.tsx +++ b/src/components/copyableCard.tsx @@ -8,16 +8,16 @@ import Chevron from 'sentry-docs/icons/Chevron'; interface CopyableCardProps { children: React.ReactNode; - description: string; title: string; } -export function CopyableCard({title, description, children}: CopyableCardProps) { - const [copiedItem, setCopiedItem] = useState<'title' | 'description' | null>(null); +export function CopyableCard({title, children}: CopyableCardProps) { + const [copiedItem, setCopiedItem] = useState<'title' | 'body' | null>(null); const [isOpen, setIsOpen] = useState(false); const [isMounted, setIsMounted] = useState(false); const buttonRef = useRef(null); const dropdownRef = useRef(null); + const contentRef = useRef(null); useEffect(() => { setIsMounted(true); @@ -39,7 +39,7 @@ export function CopyableCard({title, description, children}: CopyableCardProps) }; }, []); - async function copyText(text: string, item: 'title' | 'description') { + async function copyText(text: string, item: 'title' | 'body') { try { await navigator.clipboard.writeText(text.trim()); setCopiedItem(item); @@ -67,12 +67,16 @@ export function CopyableCard({title, description, children}: CopyableCardProps) const dropdownItemClass = 'w-full p-2 px-3 text-left text-sm bg-transparent border-none rounded-md transition-colors hover:bg-gray-100 dark:hover:bg-[var(--gray-a4)] font-sans text-gray-900 dark:text-[var(--foreground)] cursor-pointer'; + function getBodyText(): string { + return contentRef.current?.innerText?.trim() ?? ''; + } + const getButtonLabel = () => { if (copiedItem === 'title') { return 'Reply title copied!'; } - if (copiedItem === 'description') { - return 'Reply description copied!'; + if (copiedItem === 'body') { + return 'Reply body copied!'; } return 'Copy'; }; @@ -89,7 +93,7 @@ export function CopyableCard({title, description, children}: CopyableCardProps)
, @@ -142,7 +146,9 @@ export function CopyableCard({title, description, children}: CopyableCardProps) )}
-
{children}
+
+ {children} +
); From 9a1c8756a4fc1b72ac812ae34092f042e0a5a4e3 Mon Sep 17 00:00:00 2001 From: Stephanie Anderson Date: Thu, 19 Feb 2026 16:26:07 +0100 Subject: [PATCH 2/4] fix(copyableCard): preserve markdown formatting when copying reply body Replace innerText with a DOM-to-markdown converter so that copied saved replies retain checkboxes, bold, links, and list formatting when pasted into GitHub's markdown editor. Fixes bugbot comment on #16459. Co-Authored-By: Claude --- src/components/copyableCard.tsx | 62 ++++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/src/components/copyableCard.tsx b/src/components/copyableCard.tsx index fda23bf70d9fd..bdb2ef87f6313 100644 --- a/src/components/copyableCard.tsx +++ b/src/components/copyableCard.tsx @@ -6,6 +6,63 @@ import {Clipboard} from 'react-feather'; import Chevron from 'sentry-docs/icons/Chevron'; +/** + * Converts a DOM tree back to markdown so that copied saved replies + * preserve formatting (checkboxes, bold, links, lists) when pasted + * into GitHub's markdown editor. + */ +function domToMarkdown(node: Node): string { + if (node.nodeType === Node.TEXT_NODE) { + return node.textContent ?? ''; + } + + if (node.nodeType !== Node.ELEMENT_NODE) { + return ''; + } + + const el = node as HTMLElement; + const tag = el.tagName.toLowerCase(); + + // Self-closing / special elements + if (tag === 'br') { + return '\n'; + } + if (tag === 'input' && el.getAttribute('type') === 'checkbox') { + return (el as HTMLInputElement).checked ? '[x] ' : '[ ] '; + } + + const childText = Array.from(el.childNodes).map(domToMarkdown).join(''); + + switch (tag) { + case 'strong': + case 'b': + return `**${childText}**`; + case 'em': + case 'i': + return `*${childText}*`; + case 'a': + return `[${childText}](${el.getAttribute('href') ?? ''})`; + case 'p': + return `${childText}\n\n`; + case 'li': { + const parent = el.parentElement; + if (parent?.tagName.toLowerCase() === 'ol') { + const index = + Array.from(parent.children).indexOf(el as HTMLLIElement) + 1; + return `${index}. ${childText}\n`; + } + return `- ${childText}\n`; + } + case 'ul': + case 'ol': + return `${childText}\n`; + case 'code': + return `\`${childText}\``; + default: + return childText; + } +} + interface CopyableCardProps { children: React.ReactNode; title: string; @@ -68,7 +125,10 @@ export function CopyableCard({title, children}: CopyableCardProps) { 'w-full p-2 px-3 text-left text-sm bg-transparent border-none rounded-md transition-colors hover:bg-gray-100 dark:hover:bg-[var(--gray-a4)] font-sans text-gray-900 dark:text-[var(--foreground)] cursor-pointer'; function getBodyText(): string { - return contentRef.current?.innerText?.trim() ?? ''; + if (!contentRef.current) { + return ''; + } + return domToMarkdown(contentRef.current).trim(); } const getButtonLabel = () => { From 22ca8e50f2ad7a6f2b022636c66d270db11cc9d6 Mon Sep 17 00:00:00 2001 From: "getsantry[bot]" <66042841+getsantry[bot]@users.noreply.github.com> Date: Thu, 19 Feb 2026 15:27:14 +0000 Subject: [PATCH 3/4] [getsentry/action-github-commit] Auto commit --- src/components/copyableCard.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/copyableCard.tsx b/src/components/copyableCard.tsx index bdb2ef87f6313..9c77bc6728334 100644 --- a/src/components/copyableCard.tsx +++ b/src/components/copyableCard.tsx @@ -47,8 +47,7 @@ function domToMarkdown(node: Node): string { case 'li': { const parent = el.parentElement; if (parent?.tagName.toLowerCase() === 'ol') { - const index = - Array.from(parent.children).indexOf(el as HTMLLIElement) + 1; + const index = Array.from(parent.children).indexOf(el as HTMLLIElement) + 1; return `${index}. ${childText}\n`; } return `- ${childText}\n`; From a09893eb06e002d1f2825c1b4b5f2de46423a27a Mon Sep 17 00:00:00 2001 From: "getsantry[bot]" <66042841+getsantry[bot]@users.noreply.github.com> Date: Thu, 19 Feb 2026 15:27:55 +0000 Subject: [PATCH 4/4] [getsentry/action-github-commit] Auto commit