-
-
Notifications
You must be signed in to change notification settings - Fork 13.8k
feat: 支持在 ChatItem 侧右键快速唤起 ContextMenu & 支持上下文片段引用 #8488
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
Reviewer's GuideImplements a right-click context menu in ChatItem by adding a custom hook and ContextMenu component, wiring menu actions to chat store functions, enhancing the ActionsBar for inline quoting, and cleaning up outdated desktop routes. Sequence diagram for context menu action handling in ChatItemsequenceDiagram
actor User
participant ChatItem
participant useChatItemContextMenu
participant ContextMenu
participant ChatStore
User->>ChatItem: Right-click on message
ChatItem->>useChatItemContextMenu: handleContextMenu(event)
useChatItemContextMenu->>ContextMenu: Show menu at position with selectedText
User->>ContextMenu: Clicks menu item (e.g., Quote)
ContextMenu->>useChatItemContextMenu: handleMenuClick(action)
useChatItemContextMenu->>ChatItem: onActionClick(action)
ChatItem->>ChatStore: Dispatches action (e.g., updateInputMessage, copyMessage, etc.)
Class diagram for new and updated ChatItem context menu components and hooksclassDiagram
class ChatItem {
+handleContextMenuAction(action)
+renderMessage(editableContent)
}
class ContextMenu {
+onMenuClick(action)
+visible
+position
+selectedText
}
class useChatItemContextMenu {
+containerRef
+contextMenuState
+handleContextMenu(event)
+handleMenuClick(action)
+hideContextMenu()
}
ChatItem --|> useChatItemContextMenu : uses
ChatItem --|> ContextMenu : renders
ContextMenu --|> useChatItemContextMenu : uses state/handlers
Class diagram for ActionsBar enhancements (inline quoting)classDiagram
class ActionsBar {
+handleActionClick(action)
}
ActionsBar --|> ChatStore : uses updateInputMessage
File-Level Changes
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
Thank you for raising your pull request and contributing to our Community |
TestGru AssignmentSummary
Tip You can |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @ONLY-yours - I've reviewed your changes and they look great!
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location> `src/features/Conversation/components/ChatItem/ContextMenu.tsx:37` </location>
<code_context>
+ const { t } = useTranslation('common');
+ const { regenerate, edit, copy, del, branching, delAndRegenerate, export: exportAction, share } = useChatListActionsBar();
+
+ const renderIcon = useCallback((IconComponent: any) => {
+ console.log("IconComponent", IconComponent)
+ return <ActionIcon icon={<IconComponent size={16} />} size={'small'} />
+ return <IconComponent size={16} />
+ if (!IconComponent) return null;
</code_context>
<issue_to_address>
The renderIcon function contains unreachable code after the first return statement.
Since the function returns immediately, the remaining code is never executed. Please remove or refactor this code as needed.
</issue_to_address>
### Comment 2
<location> `src/features/Conversation/components/ChatItem/index.tsx:120` </location>
<code_context>
+ const handleContextMenuAction = useCallback(async (action: any) => {
</code_context>
<issue_to_address>
The handleContextMenuAction function uses a broad 'any' type for the action parameter.
Defining a specific type for the action parameter will improve type safety and maintainability.
</issue_to_address>
### Comment 3
<location> `src/features/Conversation/components/ChatItem/ActionsBar.tsx:72` </location>
<code_context>
const handleActionClick = useCallback(
- async (action: ActionIconGroupEvent) => {
+ async (action: ActionIconGroupEvent & { selectedText?: string }) => {
switch (action.key) {
case 'edit': {
</code_context>
<issue_to_address>
The dependency array for handleActionClick omits some dependencies used in the function.
'toggleMessageEditing', 'id', 'virtuosoRef', and 'index' should be added to the dependency array to prevent stale closures.
</issue_to_address>
### Comment 4
<location> `src/features/Conversation/hooks/useChatItemContextMenu.tsx:23` </location>
<code_context>
+
+ const containerRef = useRef<HTMLDivElement>(null);
+
+ const handleContextMenu = useCallback((event: React.MouseEvent) => {
+ event.preventDefault();
+ event.stopPropagation();
+
+ // Get selected text
+ const selection = window.getSelection();
+ const selectedText = selection?.toString().trim() || '';
+
+ setContextMenuState({
+ position: { x: event.clientX, y: event.clientY },
+ selectedText,
</code_context>
<issue_to_address>
Selected text is always taken from window.getSelection(), which may not be scoped to the chat item.
Scoping the selection to the chat item's container will prevent the context menu from using unrelated selections.
</issue_to_address>
<suggested_fix>
<<<<<<< SEARCH
const handleContextMenu = useCallback((event: React.MouseEvent) => {
event.preventDefault();
event.stopPropagation();
// Get selected text
const selection = window.getSelection();
const selectedText = selection?.toString().trim() || '';
setContextMenuState({
position: { x: event.clientX, y: event.clientY },
selectedText,
visible: true,
});
}, []);
=======
const handleContextMenu = useCallback((event: React.MouseEvent) => {
event.preventDefault();
event.stopPropagation();
// Get selected text scoped to the container
let selectedText = '';
const selection = window.getSelection();
if (selection && selection.rangeCount > 0) {
const range = selection.getRangeAt(0);
const container = containerRef.current;
if (container && range && container.contains(range.commonAncestorContainer)) {
selectedText = selection.toString().trim();
}
}
setContextMenuState({
position: { x: event.clientX, y: event.clientY },
selectedText,
visible: true,
});
}, []);
>>>>>>> REPLACE
</suggested_fix>
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
const renderIcon = useCallback((IconComponent: any) => { | ||
console.log("IconComponent", IconComponent) | ||
return <ActionIcon icon={<IconComponent size={16} />} size={'small'} /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue: The renderIcon function contains unreachable code after the first return statement.
Since the function returns immediately, the remaining code is never executed. Please remove or refactor this code as needed.
const handleContextMenuAction = useCallback(async (action: any) => { | ||
switch (action.key) { | ||
case 'quote': { | ||
if (action.selectedText) { | ||
const currentInput = useChatStore.getState().inputMessage; | ||
const quotedText = `> ${action.selectedText.replaceAll('\n', '\n> ')}\n\n`; | ||
updateInputMessage(currentInput + quotedText); | ||
} | ||
break; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion: The handleContextMenuAction function uses a broad 'any' type for the action parameter.
Defining a specific type for the action parameter will improve type safety and maintainability.
translateMessage(id, lang); | ||
} | ||
}, | ||
[item], | ||
[item, updateInputMessage, t, message], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue (bug_risk): The dependency array for handleActionClick omits some dependencies used in the function.
'toggleMessageEditing', 'id', 'virtuosoRef', and 'index' should be added to the dependency array to prevent stale closures.
const handleContextMenu = useCallback((event: React.MouseEvent) => { | ||
event.preventDefault(); | ||
event.stopPropagation(); | ||
|
||
// Get selected text | ||
const selection = window.getSelection(); | ||
const selectedText = selection?.toString().trim() || ''; | ||
|
||
setContextMenuState({ | ||
position: { x: event.clientX, y: event.clientY }, | ||
selectedText, | ||
visible: true, | ||
}); | ||
}, []); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion (bug_risk): Selected text is always taken from window.getSelection(), which may not be scoped to the chat item.
Scoping the selection to the chat item's container will prevent the context menu from using unrelated selections.
const handleContextMenu = useCallback((event: React.MouseEvent) => { | |
event.preventDefault(); | |
event.stopPropagation(); | |
// Get selected text | |
const selection = window.getSelection(); | |
const selectedText = selection?.toString().trim() || ''; | |
setContextMenuState({ | |
position: { x: event.clientX, y: event.clientY }, | |
selectedText, | |
visible: true, | |
}); | |
}, []); | |
const handleContextMenu = useCallback((event: React.MouseEvent) => { | |
event.preventDefault(); | |
event.stopPropagation(); | |
// Get selected text scoped to the container | |
let selectedText = ''; | |
const selection = window.getSelection(); | |
if (selection && selection.rangeCount > 0) { | |
const range = selection.getRangeAt(0); | |
const container = containerRef.current; | |
if (container && range && container.contains(range.commonAncestorContainer)) { | |
selectedText = selection.toString().trim(); | |
} | |
} | |
setContextMenuState({ | |
position: { x: event.clientX, y: event.clientY }, | |
selectedText, | |
visible: true, | |
}); | |
}, []); |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #8488 +/- ##
==========================================
+ Coverage 85.31% 85.55% +0.23%
==========================================
Files 908 912 +4
Lines 68519 69378 +859
Branches 6514 6547 +33
==========================================
+ Hits 58455 59354 +899
+ Misses 10064 10024 -40
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
引用和右键 contextMenu 分成两个 pr 吧
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这里revert
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
revert
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
revert
💻 变更类型 | Change Type
Ref: #8442
🔀 变更说明 | Description of Change
📝 补充信息 | Additional Information