Skip to content

Commit cd22005

Browse files
aliu39claude
andauthored
feat(seer-explorer): Add copy-to-clipboard button to block action bar (#110224)
## Changes Adds a copy-to-clipboard action button to `BlockComponent` in the Seer Explorer, positioned between the thumbs feedback buttons and the restart button. - Copies `block.message.content` to the clipboard via the Clipboard API - Shows a success toast on copy, error toast on failure - Hidden when the block is loading (inherits the existing `showActions` guard which already checks `!block.loading`) --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 4feb45c commit cd22005

File tree

1 file changed

+19
-1
lines changed

1 file changed

+19
-1
lines changed

static/app/views/seerExplorer/blockComponents.tsx

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@ import {Text} from '@sentry/scraps/text';
1010
import {Tooltip} from '@sentry/scraps/tooltip';
1111

1212
import {FlippedReturnIcon} from 'sentry/components/events/autofix/insights/autofixInsightCard';
13-
import {IconChevron, IconLink, IconThumb} from 'sentry/icons';
13+
import {IconChevron, IconCopy, IconLink, IconThumb} from 'sentry/icons';
1414
import {t} from 'sentry/locale';
1515
import {trackAnalytics} from 'sentry/utils/analytics';
1616
import {MarkedText} from 'sentry/utils/marked/markedText';
17+
import useCopyToClipboard from 'sentry/utils/useCopyToClipboard';
1718
import {useNavigate} from 'sentry/utils/useNavigate';
1819
import useOrganization from 'sentry/utils/useOrganization';
1920
import useProjects from 'sentry/utils/useProjects';
@@ -157,6 +158,7 @@ function BlockComponent({
157158
readOnly = false,
158159
ref,
159160
}: BlockProps) {
161+
const {copy} = useCopyToClipboard();
160162
const organization = useOrganization();
161163
const navigate = useNavigate();
162164
const {projects} = useProjects();
@@ -345,6 +347,11 @@ function BlockComponent({
345347
onDelete?.();
346348
};
347349

350+
const handleCopyClick = (e: React.MouseEvent) => {
351+
e.stopPropagation();
352+
copy(block.message.content);
353+
};
354+
348355
const handleNavigateClick = (e: React.MouseEvent, linkIndex: number) => {
349356
e.stopPropagation();
350357
if (sortedToolLinks.length === 0) {
@@ -369,6 +376,7 @@ function BlockComponent({
369376
!isAwaitingQuestion &&
370377
!readOnly;
371378
const showFeedbackButtons = block.message.role === 'assistant';
379+
const showCopyButton = block.message.role !== 'tool_use';
372380

373381
return (
374382
<Block
@@ -489,6 +497,16 @@ function BlockComponent({
489497
<ActionButtonBar gap="xs">
490498
{showFeedbackButtons && thumbsFeedbackButton('positive')}
491499
{showFeedbackButtons && thumbsFeedbackButton('negative')}
500+
{showCopyButton && (
501+
<Button
502+
aria-label={t('Copy block content')}
503+
icon={<IconCopy />}
504+
priority="transparent"
505+
size="xs"
506+
tooltipProps={{title: t('Copy to clipboard')}}
507+
onClick={handleCopyClick}
508+
/>
509+
)}
492510
<Button
493511
size="xs"
494512
priority="transparent"

0 commit comments

Comments
 (0)