-
Notifications
You must be signed in to change notification settings - Fork 66
refactor: 拆分和优化 ChatPage 组件 #38
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
base: master
Are you sure you want to change the base?
refactor: 拆分和优化 ChatPage 组件 #38
Conversation
Reviewer's GuideRefactors the monolithic ChatPage into a smaller index.vue container plus reusable header, message list, and icon button components, while preserving behavior, fixing header layout overlap, and slightly cleaning up surrounding app wiring and metadata. Sequence diagram for sending a message and auto-scrolling in refactored ChatPagesequenceDiagram
actor User
participant ChatInputBox
participant ChatPage_index as ChatPage_index
participant Session
participant ChatMessageList
User->>ChatInputBox: type message and press enter
ChatInputBox->>ChatPage_index: submit(content)
ChatPage_index->>ChatPage_index: handleSubmit(content)
ChatPage_index->>Session: send(trimmedContent, attachments)
Session-->>ChatPage_index: send resolved
ChatPage_index->>ChatPage_index: clear attachments
ChatPage_index->>ChatPage_index: messages length changes
ChatPage_index->>ChatPage_index: watch(messages.length)
ChatPage_index->>ChatPage_index: nextTick()
ChatPage_index->>ChatMessageList: scrollToBottom()
ChatMessageList->>ChatMessageList: scrollIntoView(endEl)
Class diagram for refactored ChatPage container and child componentsclassDiagram
class ChatPage_index {
+runtime
+toolContext
+session
+title
+messages
+isBusy
+permissionMode
+permissionRequests
+permissionRequestsLen
+pendingPermission
+platform
+progressPercentage
+messageListRef
+attachments
+newChat() Promise~void~
+handleSubmit(content string) Promise~void~
+handleToggleThinking() Promise~void~
+handleModeSelect(mode PermissionMode) Promise~void~
+togglePermissionMode() void
+handleModelSelect(modelId string) Promise~void~
+handleStop() void
+handleAddAttachment(files FileList) Promise~void~
+handleRemoveAttachment(id string) void
+handleResolvePermission(request PermissionRequest, allow boolean) void
+scrollToBottom() void
}
class ChatHeader {
+title string
+menuClick()
+newChat()
}
class ChatMessageList {
+messages any[]
+isBusy boolean
+permissionRequestsLen number
+platform string
+toolContext ToolContext
+permissionMode PermissionMode
+scrollToBottom() void
}
class IconButton {
+icon string
+title string
+size number
+buttonSize number
+iconSize number
+click()
}
class ChatInputBox {
+showProgress boolean
+progressPercentage number
+conversationWorking boolean
+attachments AttachmentItem[]
+thinkingLevel string
+permissionMode PermissionMode
+selectedModel any
+submit(content string)
+stop()
+addAttachment(files FileList)
+removeAttachment(id string)
+thinkingToggle()
+modeSelect(mode PermissionMode)
+modelSelect(modelId string)
}
class PermissionRequestModal {
+request PermissionRequest
+context ToolContext
+onResolve(request PermissionRequest, allow boolean)
}
class Session {
+summary
+messages
+busy
+permissionMode
+permissionRequests
+usageData
+thinkingLevel
+modelSelection
+send(content string, attachments AttachmentItem[]) Promise~void~
+setThinkingLevel(level string) Promise~void~
+setPermissionMode(mode PermissionMode) Promise~void~
+setModel(model any) Promise~void~
+interrupt() Promise~void~
}
class RuntimeAppContext {
+fileOpener
+platform string
+startNewConversationTab() boolean
+commandRegistry
}
class CommandRegistry {
+registerAction(config any, group string, handler function) function
}
class Runtime {
+appContext RuntimeAppContext
+sessionStore
}
class SessionStore {
+activeSession
+createSession(options any) Promise~void~
}
ChatPage_index --> ChatHeader : uses
ChatPage_index --> ChatMessageList : uses
ChatPage_index --> ChatInputBox : uses
ChatPage_index --> PermissionRequestModal : uses
ChatPage_index --> Session : wraps via useSession
ChatPage_index --> Runtime : injected RuntimeKey
Runtime --> RuntimeAppContext : has
Runtime --> SessionStore : has
RuntimeAppContext --> CommandRegistry : has
ChatHeader --> IconButton : uses
ChatMessageList --> ClaudeWordmark : uses
ChatMessageList --> RandomTip : uses
ChatMessageList --> MessageRenderer : uses
ChatMessageList --> Spinner : uses
ChatPage_index --> ChatMessageList : calls scrollToBottom()
ChatPage_index --> CommandRegistry : registers permissionMode_toggle
ChatInputBox --> ChatPage_index : emits submit stop addAttachment removeAttachment thinkingToggle modeSelect modelSelect
ChatHeader --> ChatPage_index : emits menuClick newChat
Flow diagram for ChatPage component composition after refactorflowchart TD
App[App_main]
App --> ChatPage_index[ChatPage_index]
ChatPage_index --> ChatHeader[ChatHeader]
ChatPage_index --> MainArea[Main area]
MainArea --> ChatMessageList[ChatMessageList]
MainArea --> InputContainer[Input container]
InputContainer --> PermissionRequestModal[PermissionRequestModal]
InputContainer --> ChatInputBox[ChatInputBox]
ChatHeader --> HeaderLeft[Header left]
HeaderLeft --> MenuButton[IconButton menu]
HeaderLeft --> Title[Chat title]
ChatHeader --> NewChatButton[IconButton plus]
ChatMessageList --> EmptyState[Empty state]
EmptyState --> ClaudeWordmark[ClaudeWordmark]
EmptyState --> RandomTip[RandomTip]
ChatMessageList --> MessageRenderer[MessageRenderer]
ChatMessageList --> Spinner[Spinner]
ChatInputBox --> UserActions[submit/stop/attachments/thinking/mode/model events]
UserActions --> ChatPage_index
ChatPage_index --> Runtime[Runtime]
Runtime --> SessionStore[SessionStore]
SessionStore --> Session[Session]
ChatPage_index --> MessageListRef[messageListRef scrollToBottom]
MessageListRef --> ChatMessageList
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
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 there - I've reviewed your changes - here's some feedback:
- In
ChatMessageList.vuethemessagesprop is typed asany[]; since these are core to the chat flow it would be helpful to introduce a strongly-typedMessageinterface (e.g., from the existing domain types) and use that instead ofanyto catch render-time issues earlier. - The new
IconButtoncomponent only exposes a customclickevent and does not pass through standard button attributes (e.g.,type,disabled,aria-label); consider supportingv-bind="$attrs"and mappingtitle/aria-labelexplicitly so the component is accessible and behaves correctly in more contexts. - In
ChatMessageList.vuethe scroll logic relies onscrollIntoViewon a hidden anchor; if you expect very long message lists, consider usingscrollTop = scrollHeighton the container instead to avoid layout thrashing and ensure consistent behavior across browsers.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `ChatMessageList.vue` the `messages` prop is typed as `any[]`; since these are core to the chat flow it would be helpful to introduce a strongly-typed `Message` interface (e.g., from the existing domain types) and use that instead of `any` to catch render-time issues earlier.
- The new `IconButton` component only exposes a custom `click` event and does not pass through standard button attributes (e.g., `type`, `disabled`, `aria-label`); consider supporting `v-bind="$attrs"` and mapping `title`/`aria-label` explicitly so the component is accessible and behaves correctly in more contexts.
- In `ChatMessageList.vue` the scroll logic relies on `scrollIntoView` on a hidden anchor; if you expect very long message lists, consider using `scrollTop = scrollHeight` on the container instead to avoid layout thrashing and ensure consistent behavior across browsers.
## Individual Comments
### Comment 1
<location> `src/webview/src/pages/ChatPage/index.vue:267` </location>
<code_context>
+
+<template>
+ <div class="chat-page">
+ <ChatHeader :title="title" @newChat="newChat" @menuClick="$emit('switchToSessions')" />
+ <!-- 主体:消息容器 -->
+ <div class="main">
</code_context>
<issue_to_address>
**suggestion:** Declare the `switchToSessions` emit for better type-safety and consistency.
`switchToSessions` is emitted via `menuClick`, but there’s no `defineEmits` declaration, so the event isn’t type-checked in `<script setup lang="ts">`. Please add something like `const emit = defineEmits<{ (e: 'switchToSessions'): void }>();` and use `emit('switchToSessions')` so the event contract is explicit and typed.
Suggested implementation:
```
} catch (e) {
console.error('[ChatPage] permission resolve failed', e);
}
}
const emit = defineEmits<{ (e: 'switchToSessions'): void }>();
</script>
```
```
<div class="chat-page">
<ChatHeader :title="title" @newChat="newChat" @menuClick="emit('switchToSessions')" />
```
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
|
|
||
| <template> | ||
| <div class="chat-page"> | ||
| <ChatHeader :title="title" @newChat="newChat" @menuClick="$emit('switchToSessions')" /> |
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: Declare the switchToSessions emit for better type-safety and consistency.
switchToSessions is emitted via menuClick, but there’s no defineEmits declaration, so the event isn’t type-checked in <script setup lang="ts">. Please add something like const emit = defineEmits<{ (e: 'switchToSessions'): void }>(); and use emit('switchToSessions') so the event contract is explicit and typed.
Suggested implementation:
} catch (e) {
console.error('[ChatPage] permission resolve failed', e);
}
}
const emit = defineEmits<{ (e: 'switchToSessions'): void }>();
</script>
<div class="chat-page">
<ChatHeader :title="title" @newChat="newChat" @menuClick="emit('switchToSessions')" />
本 PR 对 ChatPage 组件进行了重构与拆分,将原本的大型单体组件拆分为多个小型、可复用的组件,提高了代码的可维护性和可读性。
主要改动
组件拆分
新增组件
IconButton.vue (41行)
ChatHeader.vue (51行)
ChatMessageList.vue (97行)
其他优化
文件变更统计
Summary by Sourcery
Refactor the chat page into a modular structure with dedicated header, message list, and shared icon button components, improving layout and session handling without changing core behavior.
New Features:
Enhancements: