feat(conversation): replicate in-place user message editing (TODO 03)

This commit is contained in:
xiaohan.yuan committed 2026-10-17 06:31:37 +08:00
1 parent ed31a7c1b4
commit ee51208931
18 files changed
+992 -67

No files matched your search

+30 -5
View File
@@ -4,6 +4,8 @@ import { ComposerControls } from '../src/renderer/src/workbuddy/composer/Compose
import { encodePcmWav, downsamplePcm, VOICE_MAX_DURATION_MS } from '../src/renderer/src/workbuddy/composer/VoiceInputControl'
import { buildComposerSendPayload, MAX_ATTACHMENT_BYTES, oversizedAttachmentNames, parseResourcePath, readReferenceUris } from '../src/renderer/src/workbuddy/composer/ComposerControls'
import { MessageActionToolbar } from '../src/renderer/src/workbuddy/message-actions/MessageActionToolbar'
import { UserMessageToolbar } from '../src/renderer/src/workbuddy/message-actions/UserMessageToolbar'
import { UserMessageEditor } from '../src/renderer/src/workbuddy/conversation/UserMessageEditor'
import { buildCopyMessagePayload, buildUserMessageClipboard, getSortedRequestMessages, projectSafeMessage, safeStringify, USER_CONTENT_BLOCKS_MIME } from '../src/renderer/src/workbuddy/message-actions/project-safe-message'
import type { ChatMessage } from '../src/shared/types'
@@ -132,11 +134,34 @@ const assistantMarkup = renderToStaticMarkup(<MessageActionToolbar message={assi
assert.match(assistantMarkup, /复制/)
assert.match(assistantMarkup, /重新生成/)
assert.doesNotMatch(assistantMarkup, /编辑/)
const userMarkup = renderToStaticMarkup(<MessageActionToolbar message={{ id: 'user', role: 'user', content: 'hi', createdAt: 1 }} onEdit={() => undefined} onRevert={() => undefined} onResend={() => undefined} />)
assert.match(userMarkup, /编辑/)
assert.match(userMarkup, /重新发送/)
assert.doesNotMatch(userMarkup, /重新生成/)
assert.doesNotMatch(userMarkup, /赞同|不赞同/, 'feedback actions are assistant-only')
// 用户消息工具条已替换为原版 .cr-toolbar(时间 + 复制 + 恢复此版本 + 编辑,不含重新发送)。
const userMarkup = renderToStaticMarkup(<UserMessageToolbar message={{ id: 'user', role: 'user', content: 'hi', createdAt: Date.now() }} canEdit onEdit={() => undefined} onRevert={() => undefined} />)
assert.match(userMarkup, /class="cr-toolbar"/)
assert.match(userMarkup, /cr-toolbar__time/)
assert.match(userMarkup, /data-action="copy"/)
assert.match(userMarkup, /data-action="revert"/)
assert.match(userMarkup, /data-action="edit"/)
assert.match(userMarkup, /cr-icon-button__icon/)
assert.doesNotMatch(userMarkup, /重新发送|重新生成|赞同|不赞同/)
assert.doesNotMatch(userMarkup, /wb-message-action__label/, '工具栏只保留图标,不再渲染文字标签')
const editorMarkup = renderToStaticMarkup(<UserMessageEditor message={{ id: 'user', role: 'user', content: 'hi', createdAt: 1 }} onSubmit={async () => undefined} onCancel={() => undefined} />)
assert.match(editorMarkup, /class="cr-user-message-editor"/)
assert.match(editorMarkup, /cr-input-container-wrapper/)
assert.match(editorMarkup, /cr-input-editor-host/)
assert.match(editorMarkup, /data-slate-editor/)
assert.match(editorMarkup, /cr-user-message-editor__hint-icon/)
assert.match(editorMarkup, /编辑后将从此处重新开始对话,产物也将回退至此信息前版本/)
assert.match(editorMarkup, /cr-user-message-editor__cancel/)
assert.match(editorMarkup, /cr-user-message-editor__send/)
assert.match(editorMarkup, />取消</)
assert.match(editorMarkup, />发送</)
assert.doesNotMatch(editorMarkup, /role="alert"/, '有内容时不显示错误')
const emptyEditorMarkup = renderToStaticMarkup(<UserMessageEditor message={{ id: 'user', role: 'user', content: '', createdAt: 1 }} onSubmit={async () => undefined} onCancel={() => undefined} />)
assert.match(emptyEditorMarkup, /消息内容不能为空/)
assert.match(emptyEditorMarkup, /role="alert"/)
assert.match(emptyEditorMarkup, /cr-user-message-editor__send" disabled/)
const composerMarkup = renderToStaticMarkup(
<ComposerControls value="draft" onChange={() => undefined} onSend={() => undefined} onModeChange={() => undefined} modelSlot={<span>Model slot</span>} workspaceFooter={<span>Workspace slot</span>} sending />