feat(chat): add /export slash command for conversation export#1684
feat(chat): add /export slash command for conversation export#1684piorpua merged 9 commits intoiOfficeAI:mainfrom
Conversation
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
e86b2c8 to
3664441
Compare
CI 检查未通过以下 job 在本次自动化 review 时未通过,请修复:
本次自动化 review 暂缓,待 CI 全部通过后将重新处理。 |
3664441 to
fc3da0c
Compare
57b2978 to
506ebae
Compare
|
@piorpua Rebased on latest main and resolved the conflict. CI should be green now. |
CI 检查未通过以下 job 在本次自动化 review 时未通过,请修复:
本次自动化 review 暂缓,待 CI 全部通过后将重新处理。 |
Code Review:feat(chat): add /export slash command for conversation export (#1684)变更概述本 PR 在聊天输入框(sendbox)新增 方案评估结论:✅ 方案合理 状态机设计( 问题清单🟡 MEDIUM —
|
| 未覆盖路径 | 说明 |
|---|---|
handleCopy 流程 |
选择 copy 菜单项 → 复制成功/失败 |
handleKeyDown — menu 步骤的 ArrowUp/ArrowDown/Enter |
键盘导航菜单 |
handleKeyDown — filename 步骤的 Enter |
键盘提交文件名 |
loadTranscript 缓存路径 |
第二次调用应直接返回缓存而不重新 fetch |
submitFilename — baseDirectoryRef.current 为空时的错误路径 |
修复建议:补充以下测试(示例):
it('copies transcript to clipboard when copy action is selected', async () => {
// renderHook + openExportFlow + onSelectMenuItem('copy')
// expect mockCopyText called, success shown, step = 'closed'
});
it('navigates menu items with ArrowDown/ArrowUp and selects with Enter', async () => {
// renderHook + openExportFlow
// act: handleKeyDown({ key: 'ArrowDown' }) → activeIndex = 1
// act: handleKeyDown({ key: 'Enter' }) → triggers save flow
});
it('submits filename with Enter key in filename step', async () => {
// renderHook + openExportFlow + onSelectMenuItem('save')
// act: handleKeyDown({ key: 'Enter' }) → submitFilename called
});🔵 LOW — conversationExport.ts 覆盖率略低于阈值
文件:src/renderer/utils/chat/conversationExport.ts
问题说明:
Codecov 报告 patch 覆盖率为 77.27%(4 Missing + 11 Partials),略低于 80%。缺失的分支主要是:
readMessageContent中content为null/undefined时的JSON.stringify回退路径joinFilePath中路径末尾已有分隔符的情况(dir.endsWith('/')为 true 的分支)
修复建议:在 conversationExport.test.ts 中补充:
it('readMessageContent falls back to JSON.stringify for object content', () => {
// message.content = { type: 'tool_call', callId: '...' }
// expect readMessageContent(message) 返回 JSON 字符串
});
it('joinFilePath handles trailing slash in dir', () => {
expect(joinFilePath('/workspace/', 'file.txt')).toBe('/workspace/file.txt');
});汇总
| # | 严重级别 | 文件 | 问题 |
|---|---|---|---|
| 1 | 🟡 MEDIUM | useConversationExport.tsx |
测试覆盖率 66.66%,低于项目 80% 阈值 |
| 2 | 🔵 LOW | conversationExport.ts |
测试覆盖率 77.27%,略低于项目 80% 阈值 |
结论
useConversationExport.tsx 测试覆盖率(66.66%)明显低于项目 80% 阈值,需补充 copy 流程、键盘导航等测试用例后可合并。
本报告由本地 pr-review skill 生成,包含完整项目上下文,无截断限制。
…shold - Add handleCopy success and failure path tests - Add handleKeyDown ArrowDown/ArrowUp/Enter keyboard navigation tests - Add handleKeyDown Enter in filename step test - Add loadTranscript cache path test (no re-fetch on second call) - Add submitFilename error path when baseDirectory is empty Review follow-up for iOfficeAI#1684
PR Fix 验证报告原始 PR: #1684
总结: ✅ 已修复 1 个 | ❌ 未能修复 0 个
|
Closes #1685
Summary
/exportbuiltin slash command to the chat sendbox for single-conversation export.txtto the workspace directoryMotivation
Users have no quick way to export a single conversation from within the chat. The existing GroupedHistory ZIP export is a different feature for bulk export. This adds a lightweight
/exportcommand accessible directly in the sendbox.Commits
47b6c238feat(chat): add /export slash command for conversation export — core implementation: export hook, shared utilities, sendbox integration, i18n keys (6 locales)fc3da0cbtest(chat): expand export test coverage and fix stale button style — add tests for exportHelpers and useExport, expand coverage for hook/sendbox/utilities, remove hardcoded#000000button color and stale CSS commentDiff
+1850 −96across 18 files (12 modified, 6 new)+825 −96across 13 files+1025 −0across 5 filesFiles changed
sendbox.tsx(+140 / -36) — register/exportbuiltin command, integrate export overlay, remove hardcoded button colorsendbox.css(+0 / -1) — remove stale style commentexportHelpers.ts(+10 / -39) — extract shared functions to new module, deduplicate role-label logic viagetMessageRoleKeyuseExport.ts(+17 / -20) — import shared utilities directly (remove transitional re-exports)conversationExport.ts(+130, new) — shared pure utilities: filename generation, message extraction, transcript buildinguseConversationExport.tsx(+360, new) — state machine hook for export flow (closed → menu → filename)i18n-keys.d.ts(+24) — 24 newmessages.export.*type definitionsmessages.json× 6 locales (+24 each) — en-US, ja-JP, ko-KR, tr-TR, zh-CN, zh-TWconversationExport.test.ts(+137, new) — transcript building, filename generation, edge casesuseConversationExport.dom.test.tsx(+167, new) — hook flow, copy/save paths, error handling, keyboard navigationsendboxExport.dom.test.tsx(+258, new) — end-to-end slash command → export menu → copy/saveexportHelpers.test.ts(+149, new) — markdown builder, zip path normalization, timeout helperuseExport.dom.test.tsx(+314, new) — grouped history export hook: file save, ZIP export, duplicate filename handlingTesting
bunx tsc --noEmit— no type errorsbunx oxlint— 0 errorsbunx oxfmt— passedbunx vitest run tests/unit/chat/— 5 files, 29 tests, all passingnode scripts/check-i18n.js— passedRisks / Side effects