Conversation
- Session Messages 详情页 Content too large 阈值调整为 5MB / 30000 行\n- 下载/复制按钮改为导出完整请求头 + 请求体\n- Content too large 提示框支持直接下载请求体 JSON(request.json)\n- 补齐 CodeDisplay 与 Session Messages 相关单元测试(模块语句覆盖率 >= 80%)
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. 📝 WalkthroughWalkthrough更新了多语言本地化文本以明确“复制/下载请求(含头与体)”,在 CodeDisplay 中引入可配置的内容大小/行数限制并提供超限下载,重构会话消息导出为请求导出,并添加/扩展相关单元测试覆盖。 Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: Organization UI Review profile: CHILL Plan: Pro Cache: Disabled due to Reviews > Disable Cache setting 📒 Files selected for processing (10)
🚧 Files skipped from review as they are similar to previous changes (4)
🧰 Additional context used📓 Path-based instructions (10)**/*.{ts,tsx,js,jsx,json}📄 CodeRabbit inference engine (CLAUDE.md)
Files:
messages/**/*.json📄 CodeRabbit inference engine (CLAUDE.md)
Files:
**/*.{tsx,json}📄 CodeRabbit inference engine (AGENTS.md)
Files:
**/*.{ts,tsx,js,jsx}📄 CodeRabbit inference engine (CLAUDE.md)
Files:
src/components/**/*.{ts,tsx}📄 CodeRabbit inference engine (CLAUDE.md)
Files:
src/**/*.{tsx,jsx}📄 CodeRabbit inference engine (AGENTS.md)
Files:
src/components/ui/**/*.{tsx,jsx}📄 CodeRabbit inference engine (AGENTS.md)
Files:
**/*.{ts,tsx}📄 CodeRabbit inference engine (AGENTS.md)
Files:
src/components/**/*.{tsx,jsx}📄 CodeRabbit inference engine (AGENTS.md)
Files:
**/*.test.{ts,tsx}📄 CodeRabbit inference engine (AGENTS.md)
Files:
🧠 Learnings (9)📓 Common learnings📚 Learning: 2026-01-03T09:08:20.573ZApplied to files:
📚 Learning: 2026-01-03T09:08:20.573ZApplied to files:
📚 Learning: 2026-01-03T09:08:49.019ZApplied to files:
📚 Learning: 2026-01-03T09:08:20.573ZApplied to files:
📚 Learning: 2026-01-03T09:08:49.019ZApplied to files:
📚 Learning: 2026-01-03T09:08:49.019ZApplied to files:
📚 Learning: 2026-01-03T09:08:49.019ZApplied to files:
📚 Learning: 2026-01-03T09:08:49.019ZApplied to files:
🧬 Code graph analysis (1)src/app/[locale]/dashboard/sessions/[sessionId]/messages/_components/session-messages-client-actions.test.tsx (1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
🔇 Additional comments (24)
Comment |
Summary of ChangesHello @ding113, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! 此拉取请求旨在优化 Session Messages 详情页的用户体验,特别是针对大型数据内容的显示和导出。通过提高内容显示阈值、提供完整的请求数据导出功能以及在内容受限时提供便捷的下载选项,用户现在可以更有效地处理和分析会话消息。同时,通过增加单元测试,确保了这些新功能的稳定性和代码质量。 Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
🧪 测试结果
总体结果: ✅ 所有测试通过 |
There was a problem hiding this comment.
Code Review
This pull request introduces significant enhancements to the session message display and export functionality. The 'Copy Messages' and 'Download Messages' actions have been updated across multiple internationalization files (English, Japanese, Russian, Simplified Chinese, Traditional Chinese) to clarify that they now export 'Request (Headers + Body)'.
The CodeDisplay component has been refactored to support configurable content size and line limits (maxContentBytes and maxLines), with new default limits of 5MB and 30,000 lines respectively for session details. It now includes an in-panel download button for hard-limited content, allowing users to download the full content when it exceeds display limits. The component also intelligently switches to 'raw' display mode for very large content to prevent performance issues.
In the SessionMessagesClient, the state management for copying and downloading requests has been updated to handle both headers and body. A new getRequestExportJson function was introduced to format the request data for export, and the download filename now includes the sequence number. New test files (session-messages-client-actions.test.tsx) were added to cover these export actions, including scenarios for sequence overriding, header/body inclusion, and missing data. Existing tests for session-messages-client.test.tsx and code-display.test.tsx were expanded to cover the new hard-limit and download functionalities.
Review comments suggest refactoring duplicated state reset logic in SessionMessagesClient into a helper function, and wrapping getRequestExportJson and the CodeDisplay's handleDownload function with useCallback for performance optimization. Additionally, the handleDownload cleanup in CodeDisplay is advised to be delayed using setTimeout to prevent potential race conditions with browser downloads.
| setMessages(null); | ||
| setRequestBody(null); | ||
| setResponse(null); | ||
| setRequestHeaders(null); | ||
| setResponseHeaders(null); | ||
| setRequestMeta({ clientUrl: null, upstreamUrl: null, method: null }); | ||
| setResponseMeta({ upstreamUrl: null, statusCode: null }); | ||
| setSessionStats(null); | ||
| setCurrentSequence(null); | ||
| setPrevSequence(null); | ||
| setNextSequence(null); | ||
| setError(result.error || t("status.fetchFailed")); | ||
| } | ||
| } catch (err) { | ||
| if (cancelled) return; | ||
| setMessages(null); | ||
| setRequestBody(null); | ||
| setResponse(null); | ||
| setRequestHeaders(null); | ||
| setResponseHeaders(null); | ||
| setRequestMeta({ clientUrl: null, upstreamUrl: null, method: null }); | ||
| setResponseMeta({ upstreamUrl: null, statusCode: null }); | ||
| setSessionStats(null); | ||
| setCurrentSequence(null); | ||
| setPrevSequence(null); | ||
| setNextSequence(null); | ||
| setError(err instanceof Error ? err.message : t("status.unknownError")); |
There was a problem hiding this comment.
在 else 和 catch 代码块中,重置状态的逻辑是重复的。为了提高代码的可维护性和减少重复,建议将这部分逻辑提取到一个单独的辅助函数中。
例如,您可以创建一个函数:
const resetStateOnError = () => {
setMessages(null);
setRequestBody(null);
setResponse(null);
setRequestHeaders(null);
setResponseHeaders(null);
setRequestMeta({ clientUrl: null, upstreamUrl: null, method: null });
setResponseMeta({ upstreamUrl: null, statusCode: null });
setSessionStats(null);
setCurrentSequence(null);
setPrevSequence(null);
setNextSequence(null);
};然后在 else 和 catch 块中调用它:
// ...
} else {
resetStateOnError();
setError(result.error || t("status.fetchFailed"));
}
// ...
} catch (err) {
if (cancelled) return;
resetStateOnError();
setError(err instanceof Error ? err.message : t("status.unknownError"));
}
// ...| const getRequestExportJson = () => { | ||
| return JSON.stringify( | ||
| { | ||
| sessionId, | ||
| sequence: exportSequence, | ||
| meta: requestMeta, | ||
| headers: requestHeaders, | ||
| body: requestBody, | ||
| }, | ||
| null, | ||
| 2 | ||
| ); | ||
| }; |
There was a problem hiding this comment.
此函数在每次组件渲染时都会被重新创建。为了优化性能,建议使用 useCallback 将其包裹起来,并提供正确的依赖项数组。
| const getRequestExportJson = () => { | |
| return JSON.stringify( | |
| { | |
| sessionId, | |
| sequence: exportSequence, | |
| meta: requestMeta, | |
| headers: requestHeaders, | |
| body: requestBody, | |
| }, | |
| null, | |
| 2 | |
| ); | |
| }; | |
| const getRequestExportJson = useCallback(() => { | |
| return JSON.stringify( | |
| { | |
| sessionId, | |
| sequence: exportSequence, | |
| meta: requestMeta, | |
| headers: requestHeaders, | |
| body: requestBody, | |
| }, | |
| null, | |
| 2 | |
| ); | |
| }, [sessionId, exportSequence, requestMeta, requestHeaders, requestBody]); |
| const handleDownload = () => { | ||
| const blob = new Blob([content], { | ||
| type: language === "json" ? "application/json" : "text/plain", | ||
| }); | ||
| const url = URL.createObjectURL(blob); | ||
| const a = document.createElement("a"); | ||
| try { | ||
| a.href = url; | ||
| a.download = downloadFileName; | ||
| document.body.appendChild(a); | ||
| a.click(); | ||
| } finally { | ||
| if (a.isConnected) { | ||
| document.body.removeChild(a); | ||
| } | ||
| URL.revokeObjectURL(url); | ||
| } | ||
| }; |
There was a problem hiding this comment.
handleDownload 函数在每次组件渲染时都会被重新创建,建议使用 useCallback 进行性能优化。
此外,同步调用 URL.revokeObjectURL(url) 和 removeChild(a) 可能会在某些浏览器中导致下载失败的竞态条件。更稳妥的做法是将它们放入 setTimeout 中延迟执行,以确保下载已正常启动。
| const handleDownload = () => { | |
| const blob = new Blob([content], { | |
| type: language === "json" ? "application/json" : "text/plain", | |
| }); | |
| const url = URL.createObjectURL(blob); | |
| const a = document.createElement("a"); | |
| try { | |
| a.href = url; | |
| a.download = downloadFileName; | |
| document.body.appendChild(a); | |
| a.click(); | |
| } finally { | |
| if (a.isConnected) { | |
| document.body.removeChild(a); | |
| } | |
| URL.revokeObjectURL(url); | |
| } | |
| }; | |
| const handleDownload = useCallback(() => { | |
| const blob = new Blob([content], { | |
| type: language === "json" ? "application/json" : "text/plain", | |
| }); | |
| const url = URL.createObjectURL(blob); | |
| const a = document.createElement("a"); | |
| a.href = url; | |
| a.download = downloadFileName; | |
| document.body.appendChild(a); | |
| a.click(); | |
| // Delay cleanup to ensure the download can start. | |
| setTimeout(() => { | |
| if (a.isConnected) { | |
| document.body.removeChild(a); | |
| } | |
| URL.revokeObjectURL(url); | |
| }, 100); | |
| }, [content, downloadFileName, language]); |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (3)
src/app/[locale]/dashboard/sessions/[sessionId]/messages/_components/session-messages-client.tsx (1)
220-221: 建议:考虑 exportSequence 为 0 的边界情况当
exportSequence为0时,由于 JavaScript 的 falsy 判断,seqPart会变成空字符串。虽然实际场景中 sequence 从 1 开始,但显式判断null/undefined会更安全。🔎 可选的防御性改进
- const seqPart = exportSequence ? `-seq-${exportSequence}` : ""; + const seqPart = exportSequence != null ? `-seq-${exportSequence}` : "";src/app/[locale]/dashboard/sessions/[sessionId]/messages/_components/session-messages-client-actions.test.tsx (1)
113-114: 建议:注释使用英文代码中的中文注释(如第 113-114 行和 119-120 行)建议改为英文,以保持代码库的一致性。
🔎 建议的注释修改
async function clickAsync(el: Element) { await act(async () => { el.dispatchEvent(new MouseEvent("mousedown", { bubbles: true })); el.dispatchEvent(new MouseEvent("mouseup", { bubbles: true })); el.dispatchEvent(new MouseEvent("click", { bubbles: true })); - // 让事件处理器内的 await 续体在 act 作用域内完成 + // Let async continuations inside event handlers complete within act scope await Promise.resolve(); }); } async function flushEffects() { - // SessionMessagesClient 内部有异步 useEffect(await getSessionDetails + 多次 setState)。 - // 这里用两轮 tick 来确保状态更新都在 act 范围内落地,避免 act 警告。 + // SessionMessagesClient has async useEffect (await getSessionDetails + multiple setState calls). + // Use two ticks to ensure state updates settle within act scope, avoiding act warnings. await act(async () => {Also applies to: 119-120
src/components/ui/code-display.tsx (1)
252-253: 建议:下载按钮文本国际化下载按钮的文本 "Download" 是硬编码的英文,建议使用
next-intl进行国际化处理,与项目其他部分保持一致。🔎 建议的国际化改进
需要在
messages/{locale}/dashboard.json的codeDisplay部分添加download键,然后修改代码:<Button type="button" variant="outline" size="sm" onClick={handleDownload} data-testid="code-display-hard-limit-download" > <Download className="h-4 w-4 mr-2" /> - Download + {t("codeDisplay.download")} </Button>
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Cache: Disabled due to Reviews > Disable Cache setting
📒 Files selected for processing (11)
messages/en/dashboard.jsonmessages/ja/dashboard.jsonmessages/ru/dashboard.jsonmessages/zh-CN/dashboard.jsonmessages/zh-TW/dashboard.jsonsrc/app/[locale]/dashboard/sessions/[sessionId]/messages/_components/session-details-tabs.tsxsrc/app/[locale]/dashboard/sessions/[sessionId]/messages/_components/session-messages-client-actions.test.tsxsrc/app/[locale]/dashboard/sessions/[sessionId]/messages/_components/session-messages-client.test.tsxsrc/app/[locale]/dashboard/sessions/[sessionId]/messages/_components/session-messages-client.tsxsrc/components/ui/__tests__/code-display.test.tsxsrc/components/ui/code-display.tsx
🧰 Additional context used
📓 Path-based instructions (10)
**/*.{ts,tsx,js,jsx,json}
📄 CodeRabbit inference engine (CLAUDE.md)
Use 2-space indentation in all code files
Files:
messages/zh-CN/dashboard.jsonmessages/zh-TW/dashboard.jsonsrc/app/[locale]/dashboard/sessions/[sessionId]/messages/_components/session-messages-client-actions.test.tsxsrc/app/[locale]/dashboard/sessions/[sessionId]/messages/_components/session-messages-client.test.tsxmessages/ru/dashboard.jsonsrc/app/[locale]/dashboard/sessions/[sessionId]/messages/_components/session-details-tabs.tsxsrc/app/[locale]/dashboard/sessions/[sessionId]/messages/_components/session-messages-client.tsxsrc/components/ui/code-display.tsxmessages/en/dashboard.jsonmessages/ja/dashboard.jsonsrc/components/ui/__tests__/code-display.test.tsx
messages/**/*.json
📄 CodeRabbit inference engine (CLAUDE.md)
Support 5 locales via next-intl: en, ja, ru, zh-CN, zh-TW with messages in
messages/{locale}/*.jsonStore message translations in
messages/{locale}/*.jsonfiles
Files:
messages/zh-CN/dashboard.jsonmessages/zh-TW/dashboard.jsonmessages/ru/dashboard.jsonmessages/en/dashboard.jsonmessages/ja/dashboard.json
**/*.{tsx,json}
📄 CodeRabbit inference engine (AGENTS.md)
Use next-intl for internationalization with 5 locales: en, ja, ru, zh-CN, zh-TW
Files:
messages/zh-CN/dashboard.jsonmessages/zh-TW/dashboard.jsonsrc/app/[locale]/dashboard/sessions/[sessionId]/messages/_components/session-messages-client-actions.test.tsxsrc/app/[locale]/dashboard/sessions/[sessionId]/messages/_components/session-messages-client.test.tsxmessages/ru/dashboard.jsonsrc/app/[locale]/dashboard/sessions/[sessionId]/messages/_components/session-details-tabs.tsxsrc/app/[locale]/dashboard/sessions/[sessionId]/messages/_components/session-messages-client.tsxsrc/components/ui/code-display.tsxmessages/en/dashboard.jsonmessages/ja/dashboard.jsonsrc/components/ui/__tests__/code-display.test.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx,js,jsx}: Use double quotes for strings instead of single quotes
Use trailing commas in multi-line structures
Enforce maximum line length of 100 characters
Use path alias@/*to reference files from./src/*directory
**/*.{ts,tsx,js,jsx}: Use Biome for linting and formatting with 2-space indent, double quotes, trailing commas, and 100 character max line length
Use path alias@/*to reference files in./src/*directory
Files:
src/app/[locale]/dashboard/sessions/[sessionId]/messages/_components/session-messages-client-actions.test.tsxsrc/app/[locale]/dashboard/sessions/[sessionId]/messages/_components/session-messages-client.test.tsxsrc/app/[locale]/dashboard/sessions/[sessionId]/messages/_components/session-details-tabs.tsxsrc/app/[locale]/dashboard/sessions/[sessionId]/messages/_components/session-messages-client.tsxsrc/components/ui/code-display.tsxsrc/components/ui/__tests__/code-display.test.tsx
src/**/*.{tsx,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
src/**/*.{tsx,jsx}: Uselucide-reactfor icons, no custom SVGs
Use React's automatic escaping to prevent XSS vulnerabilities
Files:
src/app/[locale]/dashboard/sessions/[sessionId]/messages/_components/session-messages-client-actions.test.tsxsrc/app/[locale]/dashboard/sessions/[sessionId]/messages/_components/session-messages-client.test.tsxsrc/app/[locale]/dashboard/sessions/[sessionId]/messages/_components/session-details-tabs.tsxsrc/app/[locale]/dashboard/sessions/[sessionId]/messages/_components/session-messages-client.tsxsrc/components/ui/code-display.tsxsrc/components/ui/__tests__/code-display.test.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Use TypeScript strict mode for type safety
Use readonly or const assertions for immutable data structures
Files:
src/app/[locale]/dashboard/sessions/[sessionId]/messages/_components/session-messages-client-actions.test.tsxsrc/app/[locale]/dashboard/sessions/[sessionId]/messages/_components/session-messages-client.test.tsxsrc/app/[locale]/dashboard/sessions/[sessionId]/messages/_components/session-details-tabs.tsxsrc/app/[locale]/dashboard/sessions/[sessionId]/messages/_components/session-messages-client.tsxsrc/components/ui/code-display.tsxsrc/components/ui/__tests__/code-display.test.tsx
**/*.test.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use Vitest for unit testing with Node environment, coverage thresholds: 50% lines/functions, 40% branches
Files:
src/app/[locale]/dashboard/sessions/[sessionId]/messages/_components/session-messages-client-actions.test.tsxsrc/app/[locale]/dashboard/sessions/[sessionId]/messages/_components/session-messages-client.test.tsxsrc/components/ui/__tests__/code-display.test.tsx
src/components/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Use
lucide-reactfor icons instead of custom SVGs
Files:
src/components/ui/code-display.tsxsrc/components/ui/__tests__/code-display.test.tsx
src/components/ui/**/*.{tsx,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Place UI components in
src/components/ui/directory (excluded from typecheck)
Files:
src/components/ui/code-display.tsxsrc/components/ui/__tests__/code-display.test.tsx
src/components/**/*.{tsx,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
src/components/**/*.{tsx,jsx}: Use Tailwind CSS for styling, place utility classes close to JSX
Use shadcn/ui component library for high-quality, accessible UI components
Files:
src/components/ui/code-display.tsxsrc/components/ui/__tests__/code-display.test.tsx
🧠 Learnings (8)
📚 Learning: 2026-01-03T09:08:20.573Z
Learnt from: CR
Repo: ding113/claude-code-hub PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-03T09:08:20.573Z
Learning: Applies to messages/**/*.json : Support 5 locales via next-intl: en, ja, ru, zh-CN, zh-TW with messages in `messages/{locale}/*.json`
Applied to files:
messages/zh-CN/dashboard.jsonmessages/zh-TW/dashboard.jsonsrc/app/[locale]/dashboard/sessions/[sessionId]/messages/_components/session-messages-client-actions.test.tsxsrc/app/[locale]/dashboard/sessions/[sessionId]/messages/_components/session-messages-client.tsxmessages/ja/dashboard.jsonsrc/components/ui/__tests__/code-display.test.tsx
📚 Learning: 2026-01-03T09:08:49.019Z
Learnt from: CR
Repo: ding113/claude-code-hub PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-03T09:08:49.019Z
Learning: Applies to **/*.test.{ts,tsx} : Use Vitest for unit testing with Node environment, coverage thresholds: 50% lines/functions, 40% branches
Applied to files:
src/app/[locale]/dashboard/sessions/[sessionId]/messages/_components/session-messages-client.test.tsxsrc/components/ui/__tests__/code-display.test.tsx
📚 Learning: 2026-01-03T09:08:20.573Z
Learnt from: CR
Repo: ding113/claude-code-hub PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-03T09:08:20.573Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Enforce maximum line length of 100 characters
Applied to files:
src/components/ui/code-display.tsx
📚 Learning: 2026-01-03T09:08:49.019Z
Learnt from: CR
Repo: ding113/claude-code-hub PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-03T09:08:49.019Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Use Biome for linting and formatting with 2-space indent, double quotes, trailing commas, and 100 character max line length
Applied to files:
src/components/ui/code-display.tsx
📚 Learning: 2026-01-03T09:08:20.573Z
Learnt from: CR
Repo: ding113/claude-code-hub PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-03T09:08:20.573Z
Learning: Applies to src/components/**/*.{ts,tsx} : Use `lucide-react` for icons instead of custom SVGs
Applied to files:
src/components/ui/code-display.tsx
📚 Learning: 2026-01-03T09:08:49.019Z
Learnt from: CR
Repo: ding113/claude-code-hub PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-03T09:08:49.019Z
Learning: Applies to src/**/*.{tsx,jsx} : Use `lucide-react` for icons, no custom SVGs
Applied to files:
src/components/ui/code-display.tsx
📚 Learning: 2026-01-03T09:08:49.019Z
Learnt from: CR
Repo: ding113/claude-code-hub PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-03T09:08:49.019Z
Learning: Applies to src/components/**/*.{tsx,jsx} : Use shadcn/ui component library for high-quality, accessible UI components
Applied to files:
src/components/ui/code-display.tsx
📚 Learning: 2026-01-03T09:08:49.019Z
Learnt from: CR
Repo: ding113/claude-code-hub PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-03T09:08:49.019Z
Learning: Applies to **/*.{tsx,json} : Use next-intl for internationalization with 5 locales: en, ja, ru, zh-CN, zh-TW
Applied to files:
src/components/ui/__tests__/code-display.test.tsx
🧬 Code graph analysis (4)
src/app/[locale]/dashboard/sessions/[sessionId]/messages/_components/session-messages-client-actions.test.tsx (1)
src/app/[locale]/dashboard/sessions/[sessionId]/messages/_components/session-messages-client.tsx (1)
SessionMessagesClient(40-661)
src/app/[locale]/dashboard/sessions/[sessionId]/messages/_components/session-messages-client.test.tsx (1)
src/app/[locale]/dashboard/sessions/[sessionId]/messages/_components/session-details-tabs.tsx (1)
SessionMessagesDetailsTabs(42-219)
src/app/[locale]/dashboard/sessions/[sessionId]/messages/_components/session-messages-client.tsx (2)
scripts/sync-settings-keys.js (1)
t(72-72)src/components/ui/button.tsx (1)
Button(58-58)
src/components/ui/code-display.tsx (2)
src/lib/utils/sse.ts (1)
parseSSEDataForDisplay(93-98)src/components/ui/button.tsx (1)
Button(58-58)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
- GitHub Check: Greptile Review
- GitHub Check: pr-review
- GitHub Check: pr-label
- GitHub Check: pr-description
- GitHub Check: check-codex-status
- GitHub Check: Docker Build Test
- GitHub Check: 🌐 API Tests
- GitHub Check: dev-build-deploy
🔇 Additional comments (17)
messages/zh-CN/dashboard.json (1)
396-397: 会话操作文案与新导出行为一致,保持即可这两行准确说明按钮操作是针对“请求头和请求体”,与英文及实际导出内容对齐,键名保持不变,JSON 结构与缩进也正确,无需调整。
messages/en/dashboard.json (1)
396-397: 英文主文案清晰标注 Headers + Body,与功能契合说明文本明确为“Request (Headers + Body)”,与会话消息导出新行为匹配,键名和 JSON 结构均未改变,可直接接受。
messages/ja/dashboard.json (1)
395-396: 日文文案自然且语义与其它语言一致新文案清楚说明操作对象是「リクエスト(ヘッダーとボディ)」,与实际导出内容及其他 locale 保持一致,键名与 JSON 结构均正确。
messages/ru/dashboard.json (1)
395-396: 俄文操作文案准确反映“完整请求”导出文本明确为“запрос (заголовки и тело)”,与新行为和其它 locale 对齐,键名未改动,JSON 格式良好。
messages/zh-TW/dashboard.json (1)
396-397: 繁体中文文案与简体及英文版本语义一致使用「複製/下載請求頭與請求體」清楚描述操作对象,与 PR 中“完整請求(Headers + Body)”的行为相符,键名与 JSON 结构均正常。
src/app/[locale]/dashboard/sessions/[sessionId]/messages/_components/session-details-tabs.tsx (2)
11-13: 常量定义合理新增的
SESSION_DETAILS_MAX_CONTENT_BYTES(5MB) 和SESSION_DETAILS_MAX_LINES(30,000) 常量符合 PR 目标要求,数值设置合理。常量作为模块级定义,便于后续调整阈值。
141-142: CodeDisplay 限制参数传递一致所有
CodeDisplay组件的调用都正确传递了maxContentBytes和maxLines参数,确保了整个 Session Details 页面的内容限制行为一致。Also applies to: 158-159, 175-176, 192-193, 209-210
src/components/ui/__tests__/code-display.test.tsx (1)
296-340: 测试覆盖全面新增的
hard-limited content provides download action测试全面验证了硬限制内容的下载流程,包括:
- Blob URL 创建与回收
- 下载文件名和 href 设置
- Blob 内容验证
- Mock 清理
测试设计合理,符合项目测试规范。
src/app/[locale]/dashboard/sessions/[sessionId]/messages/_components/session-messages-client.test.tsx (2)
190-223: 硬限制阈值验证测试测试正确验证了提升后的阈值行为:10,100 个请求头(约 20,200 行)不会触发 "Content too large" 警告,因为新的上限是 30,000 行。测试逻辑清晰,断言准确。
225-286: 面板内下载功能测试完善测试全面验证了当请求体超过 30,000 行时:
- 显示 "Content too large" 提示
- 下载按钮存在且可点击
- 下载的文件名正确 (
request.json)- Blob 内容与预期 JSON 一致
- URL 资源正确回收
src/app/[locale]/dashboard/sessions/[sessionId]/messages/_components/session-messages-client.tsx (2)
130-140: 错误路径的状态重置逻辑完善在
result.ok === false和catch分支中全面重置了相关状态(messages、response、headers、meta、sequences),避免了旧数据残留导致的 UI 不一致问题。实现严谨。Also applies to: 145-156
171-186: 请求导出逻辑设计合理新增的导出逻辑结构清晰:
hasRequestForExport: 检查是否有可导出的内容canExportRequest: 综合判断导出按钮是否可用getRequestExportJson: 构建标准化的导出 JSON 结构导出的 JSON 包含
sessionId、sequence、meta、headers、body,结构完整,便于后续分析和调试。src/app/[locale]/dashboard/sessions/[sessionId]/messages/_components/session-messages-client-actions.test.tsx (2)
1-137: 测试设置完备测试文件的 Mock 设置全面覆盖了所有外部依赖:
@tanstack/react-query、next-intl、next/navigation等库- 路由和 action 函数
- 子组件
afterEach中正确重置了所有 mock 状态,确保测试隔离性。
139-430: 测试用例覆盖全面测试用例完整覆盖了请求导出功能的各个方面:
- URL
seq参数覆盖currentSequence用于导出- 复制/下载导出内容包含完整的请求信息
- 缺少 headers/body 时不渲染导出按钮
- 错误状态正确显示
- Session 统计视图、导航、复制响应、终止会话流程
测试设计符合项目规范,异步处理和 fake timers 使用正确。
src/components/ui/code-display.tsx (3)
16-18: 可配置限制参数设计良好新增的
DEFAULT_MAX_CONTENT_BYTES、DEFAULT_MAX_LINES、PRETTY_MODE_DEFAULT_MAX_CHARS常量与maxContentBytes、maxLinesprops 提供了灵活的配置能力,同时保持了向后兼容性。Also applies to: 27-28
80-86: Pretty 模式的内容限制处理合理初始化时根据
PRETTY_MODE_DEFAULT_MAX_CHARS判断是否使用 raw 模式,并通过useEffect在内容变化时动态切换,避免了大内容在 pretty 模式下的性能问题。Also applies to: 107-112
190-259: 硬限制 UI 和下载功能实现完善硬限制分支的实现要点:
- 清晰显示内容大小和允许的最大值
- 使用
try/finally确保 URL 资源正确回收isConnected检查增强了代码健壮性data-testid便于测试
There was a problem hiding this comment.
Code Review Summary
This PR enhances session message viewing by raising content limits and improving request export functionality. The implementation is clean, well-tested, and follows project conventions. No significant issues identified.
PR Size: L (Large)
- Lines changed: 764 (721 additions + 43 deletions)
- Files changed: 11
Issues Found
| Category | Critical | High | Medium | Low |
|---|---|---|---|---|
| Logic/Bugs | 0 | 0 | 0 | 0 |
| Security | 0 | 0 | 0 | 0 |
| Error Handling | 0 | 0 | 0 | 0 |
| Types | 0 | 0 | 0 | 0 |
| Comments/Docs | 0 | 0 | 0 | 0 |
| Tests | 0 | 0 | 0 | 0 |
| Simplification | 0 | 0 | 0 | 0 |
Key Observations
Positive Implementation Details:
-
Configurable thresholds:
CodeDisplaynow acceptsmaxContentBytesandmaxLinesprops with sensible defaults (1MB/10k lines), allowing session details to use higher limits (5MB/30k lines) -
Proper resource cleanup: Download handlers correctly revoke blob URLs and clean up anchor elements:
// code-display.tsx:197-213 try { a.href = url; a.download = downloadFileName; document.body.appendChild(a); a.click(); } finally { if (a.isConnected) { document.body.removeChild(a); } URL.revokeObjectURL(url); }
-
Complete state reset on error: Error paths now properly reset all state variables to prevent stale data display
-
Smart export condition:
canExportRequestproperly gates export buttons on loading/error state and data availability -
Accurate byte size calculation: Using
new Blob([content]).sizefor UTF-8 accurate measurement -
Auto-fallback for large content: Pretty mode automatically falls back to raw mode for content > 100k chars to prevent performance issues
Review Coverage
- Logic and correctness - Clean
- Security (OWASP Top 10) - Clean
- Error handling - Clean (errors logged to console)
- Type safety - Clean (no
anyusage) - Documentation accuracy - Clean
- Test coverage - Good (431 lines of new tests)
- Code clarity - Good
Automated review by Claude AI
There was a problem hiding this comment.
Code Review Summary
This PR enhances session message viewing by raising content limits and improving request export functionality. The implementation is clean, well-tested, and follows project conventions. No significant issues identified.
PR Size: L (Large)
- Lines changed: 764 (721 additions + 43 deletions)
- Files changed: 11
Issues Found
| Category | Critical | High | Medium | Low |
|---|---|---|---|---|
| Logic/Bugs | 0 | 0 | 0 | 0 |
| Security | 0 | 0 | 0 | 0 |
| Error Handling | 0 | 0 | 0 | 0 |
| Types | 0 | 0 | 0 | 0 |
| Comments/Docs | 0 | 0 | 0 | 0 |
| Tests | 0 | 0 | 0 | 0 |
| Simplification | 0 | 0 | 0 | 0 |
Key Observations
Positive Implementation Details:
-
Configurable thresholds:
CodeDisplaynow acceptsmaxContentBytesandmaxLinesprops with sensible defaults (1MB/10k lines), allowing session details to use higher limits (5MB/30k lines) -
Proper resource cleanup: Download handlers correctly revoke blob URLs and clean up anchor elements with try/finally pattern
-
Complete state reset on error: Error paths now properly reset all state variables to prevent stale data display
-
Smart export condition:
canExportRequestproperly gates export buttons on loading/error state and data availability -
Accurate byte size calculation: Using
new Blob([content]).sizefor UTF-8 accurate measurement -
Auto-fallback for large content: Pretty mode automatically falls back to raw mode for content > 100k chars to prevent performance issues
Review Coverage
- Logic and correctness - Clean
- Security (OWASP Top 10) - Clean
- Error handling - Clean (errors logged to console)
- Type safety - Clean (no
anyusage) - Documentation accuracy - Clean
- Test coverage - Good (431 lines of new tests)
- Code clarity - Good
Automated review by Claude AI
| const handleCopyMessages = async () => { | ||
| if (!messages) return; | ||
| const hasRequestForExport = requestHeaders !== null || requestBody !== null; | ||
| const canExportRequest = !isLoading && error === null && hasRequestForExport; |
There was a problem hiding this comment.
[HIGH] [LOGIC-BUG] Request export can be enabled without a body
Evidence (src/app/[locale]/dashboard/sessions/[sessionId]/messages/_components/session-messages-client.tsx:171):
const hasRequestForExport = requestHeaders !== null || requestBody !== null;
Why this is a problem: requestBody can legitimately be null (e.g., when request body storage is disabled), but requestHeaders may still be available. This makes the UI show “Copy/Download Request (Headers + Body)” while exporting JSON with "body": null, which is misleading and makes the feature appear broken.
Suggested fix (only enable export when both headers and body are present):
const canExportRequest =
!isLoading &&
error === null &&
requestHeaders !== null &&
requestBody !== null;Test suggestion:
// requestBody: null, requestHeaders: { "content-type": "application/json" } => no export buttonsThere was a problem hiding this comment.
Code Review Summary
PR updates the Session Messages detail UI thresholds and adds request export + in-panel download for hard-limited content, with new tests and i18n string updates. One functional gap remains: request export actions can be enabled even when the request body is unavailable, producing incomplete exports while the UI labels claim “Headers + Body”.
PR Size: L
- Lines changed: 764
- Files changed: 11
- Split suggestion (recommended for L PRs): split into (1)
CodeDisplayhard-limit download + tests, (2) Session Messages request export actions + tests, (3) i18n copy updates + threshold tuning.
Issues Found
| Category | Critical | High | Medium | Low |
|---|---|---|---|---|
| Logic/Bugs | 1 | 0 | 0 | 0 |
| Security | 0 | 0 | 0 | 0 |
| Error Handling | 0 | 0 | 0 | 0 |
| Types | 0 | 0 | 0 | 0 |
| Comments/Docs | 0 | 0 | 0 | 0 |
| Tests | 0 | 0 | 0 | 0 |
| Simplification | 0 | 0 | 0 | 0 |
Critical Issues (Must Fix)
- (Confidence 95)
src/app/[locale]/dashboard/sessions/[sessionId]/messages/_components/session-messages-client.tsx:171: export gating allows missingrequestBody, so “Copy/Download Request (Headers + Body)” can export JSON with"body": null.
High Priority Issues (Should Fix)
- None.
Review Coverage
- Logic and correctness
- Security (OWASP Top 10)
- Error handling
- Type safety
- Documentation accuracy
- Test coverage
- Code clarity
Automated review by Codex AI
There was a problem hiding this comment.
- Reviewed PR
#537and applied labelsize/L. - Left 1 inline review comment on
src/app/[locale]/dashboard/sessions/[sessionId]/messages/_components/session-messages-client.tsx:171about request export being enabled whenrequestBodyisnull, which can produce exports with"body": nulldespite the UI label claiming “Headers + Body”. - Submitted the full review summary via
gh pr review(includes split suggestions since this is a sizeLPR).
- 修复导出按钮在缺失请求体时仍可用的问题(避免导出 body:null 误导)\n- 提取错误态重置逻辑,减少重复\n- CodeDisplay 超限提示文案与下载按钮改为 i18n(5 语言补齐)\n- 补充单元测试覆盖缺失请求体场景
🧪 测试结果
总体结果: ✅ 所有测试通过 |
Summary
Enhance the Session Messages details page by raising the content display threshold and improving the request export functionality to include complete request headers and body.
Problem
Related PRs:
The previous implementation had limitations:
messagesfield, missing valuable debugging context like request headers and full request bodySolution
1. Increased Content Threshold
maxContentBytesandmaxLinesprops)2. Complete Request Export
sessionId- Session identifiersequence- Request sequence numbermeta- Request metadata (clientUrl, upstreamUrl, method)headers- Complete request headersbody- Full request bodysession-{id}-seq-{n}-request.json3. In-Panel Download for Hard-Limited Content
4. UI/UX Improvements
Changes
Core Changes
session-details-tabs.tsxsession-messages-client.tsxcode-display.tsxSupporting Changes
messages/*/dashboard.jsonsession-messages-client-actions.test.tsxsession-messages-client.test.tsxcode-display.test.tsxTechnical Details
CodeDisplaynow accepts optionalmaxContentBytesandmaxLinespropsDEFAULT_MAX_CONTENT_BYTES,DEFAULT_MAX_LINES) preserved for backward compatibilitynew Blob([content]).sizefor accurate UTF-8 measurementTesting
Automated Tests
session-messages-client-actions.test.tsxwith comprehensive export flow testssession-messages-client.test.tsxfor threshold validationcode-display.test.tsxfor download functionalityVerification Commands
Manual Testing
Breaking Changes
None. Changes are backward compatible:
Checklist
Description enhanced by Claude AI
Greptile Summary
This PR increases content handling thresholds and improves request export functionality for session messages.
Key Changes
CodeDisplaythresholds configurable via props, improved state cleanup in error paths, added auto-fallback from pretty to raw mode for very large JSONCode Quality
Confidence Score: 5/5
Important Files Changed
Sequence Diagram
sequenceDiagram participant User participant SessionMessagesClient participant getSessionDetails participant CodeDisplay participant Browser User->>SessionMessagesClient: Load session page SessionMessagesClient->>getSessionDetails: Fetch session data (sessionId, selectedSeq) getSessionDetails-->>SessionMessagesClient: Return requestBody, headers, messages, response, meta alt Export Request User->>SessionMessagesClient: Click Copy/Download Request button SessionMessagesClient->>SessionMessagesClient: Build request JSON (headers + body + meta + sequence) alt Copy SessionMessagesClient->>Browser: navigator.clipboard.writeText(JSON) Browser-->>User: Request copied to clipboard else Download SessionMessagesClient->>Browser: Create blob & trigger download Browser-->>User: Download request.json file end end alt View Content SessionMessagesClient->>CodeDisplay: Render content (maxContentBytes: 5MB, maxLines: 30000) alt Content within limits CodeDisplay->>CodeDisplay: Show pretty/raw mode with search CodeDisplay-->>User: Display formatted content else Content exceeds limits CodeDisplay->>CodeDisplay: Show "Content too large" message CodeDisplay-->>User: Display error with download button User->>CodeDisplay: Click download button CodeDisplay->>Browser: Create blob & trigger download Browser-->>User: Download content file end end