Repository navigation
fix: move copy button - #390
Conversation
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThe PR adjusts copy-to-clipboard UI: it removes the header-level CopyButton from AnalysisAnswer and adds a footer-level CopyButton in AnalysisResult that copies the concatenated textual parts of a response. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/ai-core/src/components/AnalysisResult.tsx (1)
60-70: Avoidanyand memoize text aggregation to improve type safety and performance.Line 65's
as anydrops type guarantees. Lines 60–70 recompute text aggregation on every render despite being expensive (multiple iterations over arrays). Both'text'and'reasoning'message parts have a guaranteed.text: stringproperty per the schema, so a type-safeuseMemowrapper is straightforward.♻️ Proposed refactor
-import {useEffect, useRef, useState} from 'react'; +import {useEffect, useMemo, useRef, useState} from 'react'; - const allTextContent = uiMessageParts - .filter((part) => part.type === 'text' || part.type === 'reasoning') - .map((part) => { - if (part.type === 'text' || part.type === 'reasoning') { - return (part as any).text; - } - return ''; - }) - .join('\n\n'); + const allTextContent = useMemo( + () => + uiMessageParts + .flatMap((part) => { + if ( + (part.type === 'text' || part.type === 'reasoning') && + 'text' in part && + typeof part.text === 'string' + ) { + return [part.text]; + } + return []; + }) + .join('\n\n'), + [uiMessageParts], + );🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/ai-core/src/components/AnalysisResult.tsx` around lines 60 - 70, Replace the untyped cast and repeated computation by memoizing the text aggregation with React's useMemo and using the proper part type narrowing: compute allTextContent via useMemo(() => uiMessageParts.filter(p => p.type === 'text' || p.type === 'reasoning').map(p => p.text).join('\n\n'), [uiMessageParts]) (no "as any"), then derive hasTextContent from that memoized value; update references to allTextContent and hasTextContent in AnalysisResult.tsx accordingly so the code preserves type safety and avoids recomputing on every render.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@packages/ai-core/src/components/AnalysisResult.tsx`:
- Around line 60-70: Replace the untyped cast and repeated computation by
memoizing the text aggregation with React's useMemo and using the proper part
type narrowing: compute allTextContent via useMemo(() => uiMessageParts.filter(p
=> p.type === 'text' || p.type === 'reasoning').map(p => p.text).join('\n\n'),
[uiMessageParts]) (no "as any"), then derive hasTextContent from that memoized
value; update references to allTextContent and hasTextContent in
AnalysisResult.tsx accordingly so the code preserves type safety and avoids
recomputing on every render.
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
packages/ai-core/src/components/AnalysisAnswer.tsxpackages/ai-core/src/components/AnalysisResult.tsx
💤 Files with no reviewable changes (1)
- packages/ai-core/src/components/AnalysisAnswer.tsx
There was a problem hiding this comment.
Pull request overview
This PR refactors the copy button functionality for AI analysis results by moving it from individual answer components to a single copy button at the analysis result level. The change consolidates the copy functionality to provide a single "Copy entire response" button that collects all text and reasoning content from message parts, rather than having individual copy buttons for each answer segment.
Changes:
- Moved copy button from AnalysisAnswer component to AnalysisResult component
- Added logic to collect all text and reasoning content from message parts for a unified copy operation
- Removed headerActions prop usage from MessageContainer in AnalysisAnswer
- Added bottom margin (mb-4) to AnalysisResult container for improved spacing
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| packages/ai-core/src/components/AnalysisResult.tsx | Added text content collection logic and placed copy button at the end of the analysis result, added mb-4 margin to container |
| packages/ai-core/src/components/AnalysisAnswer.tsx | Removed headerActions variable and prop that previously contained the copy button |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Moved the copy button in the ai assistant

Summary by CodeRabbit