-
Notifications
You must be signed in to change notification settings - Fork 625
fix: stabilize streaming artifact dialog behavior #1005
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
|
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. WalkthroughAdds per-context artifact dismissal to the artifact store (dismissedContexts + makeContextKey), exposes dismissArtifact(), extends showArtifact(...) with optional { force } behavior and updates call sites to pass { force: true }; refactors ArtifactDialog and CodeArtifact for language normalization, preview-state tracking, and Monaco teardown. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant UI as Component (Dialog/Preview/Code/Markdown)
participant Store as ArtifactStore
participant D as DismissedContexts
User->>UI: request show/preview artifact
UI->>Store: showArtifact(artifact, messageId, threadId, { force? })
alt options.force == true
Store->>D: remove(contextKey)
Store-->>UI: show artifact
else
Store->>D: has(contextKey)?
alt dismissed
Store-->>UI: skip show
else
Store-->>UI: show artifact
end
end
User->>UI: close/back
UI->>Store: dismissArtifact()
Store->>D: add(contextKey)
Store-->>UI: hide artifact
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
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.
💡 Codex Review
Here are some automated review suggestions for this pull request.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting
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.
Actionable comments posted: 0
🧹 Nitpick comments (3)
src/renderer/src/stores/artifact.ts (2)
16-18: Prefer type alias over interface for small option bagsUse a type alias to follow the repo guideline (prefer types over interfaces).
As per coding guidelines
-interface ShowArtifactOptions { - force?: boolean -} +type ShowArtifactOptions = { force?: boolean }
56-67: Consider a small API to clear old dismissed contextsThe Set can grow over long sessions. Expose a reset helper (global or per-thread) and add it to the store return.
const dismissArtifact = () => { if (currentArtifact.value && currentMessageId.value && currentThreadId.value) { const contextKey = makeContextKey( currentArtifact.value.id, currentMessageId.value, currentThreadId.value ) dismissedContexts.value.add(contextKey) } hideArtifact() } + +const resetDismissedContexts = (scope?: { threadId?: string }) => { + // Clear all by default + if (!scope?.threadId) { + dismissedContexts.value.clear() + return + } + // Or clear only entries for a specific thread + dismissedContexts.value = new Set( + [...dismissedContexts.value].filter((k) => !k.startsWith(`${scope.threadId}:`)) + ) +}Add to return:
hideArtifact, dismissArtifact, + resetDismissedContexts, validateContext,Also applies to: 82-92
src/renderer/src/components/artifacts/ArtifactDialog.vue (1)
255-255: Preview-state logic matches spec; consider simplifying watchers
- Defaults to code view until preview-only types are loaded; preserves user toggle via userHasSetPreview. Looks right.
- Small simplification opportunity: compute isPreview from (artifact, status, userHasSetPreview, userSelection) to reduce two watchers and duplication.
Example direction:
- Track userSelection: 'preview' | 'code' | null
- isPreview = computed(() => userSelection != null ? userSelection === 'preview' : getDefaultPreviewState(artifact))
Optional, defer if out of scope.
Also applies to: 349-359, 362-362, 372-384, 391-403
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
src/renderer/src/components/artifacts/ArtifactDialog.vue(6 hunks)src/renderer/src/components/artifacts/ArtifactPreview.vue(1 hunks)src/renderer/src/components/artifacts/CodeArtifact.vue(1 hunks)src/renderer/src/components/markdown/MarkdownRenderer.vue(1 hunks)src/renderer/src/stores/artifact.ts(3 hunks)
🧰 Additional context used
📓 Path-based instructions (20)
src/renderer/src/**/*
📄 CodeRabbit inference engine (.cursor/rules/i18n.mdc)
src/renderer/src/**/*: All user-facing strings must use i18n keys (avoid hardcoded user-visible text in code)
Use the 'vue-i18n' framework for all internationalization in the renderer
Ensure all user-visible text in the renderer uses the translation system
Files:
src/renderer/src/components/markdown/MarkdownRenderer.vuesrc/renderer/src/stores/artifact.tssrc/renderer/src/components/artifacts/CodeArtifact.vuesrc/renderer/src/components/artifacts/ArtifactDialog.vuesrc/renderer/src/components/artifacts/ArtifactPreview.vue
src/renderer/**/*.{vue,ts,js,tsx,jsx}
📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)
渲染进程代码放在
src/renderer
Files:
src/renderer/src/components/markdown/MarkdownRenderer.vuesrc/renderer/src/stores/artifact.tssrc/renderer/src/components/artifacts/CodeArtifact.vuesrc/renderer/src/components/artifacts/ArtifactDialog.vuesrc/renderer/src/components/artifacts/ArtifactPreview.vue
src/renderer/src/**/*.{vue,ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/vue-best-practices.mdc)
src/renderer/src/**/*.{vue,ts,tsx,js,jsx}: Use the Composition API for better code organization and reusability
Implement proper state management with Pinia
Utilize Vue Router for navigation and route management
Leverage Vue's built-in reactivity system for efficient data handling
Files:
src/renderer/src/components/markdown/MarkdownRenderer.vuesrc/renderer/src/stores/artifact.tssrc/renderer/src/components/artifacts/CodeArtifact.vuesrc/renderer/src/components/artifacts/ArtifactDialog.vuesrc/renderer/src/components/artifacts/ArtifactPreview.vue
src/renderer/src/**/*.vue
📄 CodeRabbit inference engine (.cursor/rules/vue-best-practices.mdc)
Use scoped styles to prevent CSS conflicts between components
Files:
src/renderer/src/components/markdown/MarkdownRenderer.vuesrc/renderer/src/components/artifacts/CodeArtifact.vuesrc/renderer/src/components/artifacts/ArtifactDialog.vuesrc/renderer/src/components/artifacts/ArtifactPreview.vue
src/renderer/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (.cursor/rules/vue-shadcn.mdc)
src/renderer/**/*.{ts,tsx,vue}: Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError).
Use TypeScript for all code; prefer types over interfaces.
Avoid enums; use const objects instead.
Use arrow functions for methods and computed properties.
Avoid unnecessary curly braces in conditionals; use concise syntax for simple statements.
Files:
src/renderer/src/components/markdown/MarkdownRenderer.vuesrc/renderer/src/stores/artifact.tssrc/renderer/src/components/artifacts/CodeArtifact.vuesrc/renderer/src/components/artifacts/ArtifactDialog.vuesrc/renderer/src/components/artifacts/ArtifactPreview.vue
src/renderer/**/*.{vue,ts}
📄 CodeRabbit inference engine (.cursor/rules/vue-shadcn.mdc)
Implement lazy loading for routes and components.
Files:
src/renderer/src/components/markdown/MarkdownRenderer.vuesrc/renderer/src/stores/artifact.tssrc/renderer/src/components/artifacts/CodeArtifact.vuesrc/renderer/src/components/artifacts/ArtifactDialog.vuesrc/renderer/src/components/artifacts/ArtifactPreview.vue
src/renderer/**/*.{ts,vue}
📄 CodeRabbit inference engine (.cursor/rules/vue-shadcn.mdc)
src/renderer/**/*.{ts,vue}: Use useFetch and useAsyncData for data fetching.
Implement SEO best practices using Nuxt's useHead and useSeoMeta.Use Pinia for frontend state management (do not introduce alternative state libraries)
Files:
src/renderer/src/components/markdown/MarkdownRenderer.vuesrc/renderer/src/stores/artifact.tssrc/renderer/src/components/artifacts/CodeArtifact.vuesrc/renderer/src/components/artifacts/ArtifactDialog.vuesrc/renderer/src/components/artifacts/ArtifactPreview.vue
**/*.{ts,tsx,js,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Use English for all logs and comments
Files:
src/renderer/src/components/markdown/MarkdownRenderer.vuesrc/renderer/src/stores/artifact.tssrc/renderer/src/components/artifacts/CodeArtifact.vuesrc/renderer/src/components/artifacts/ArtifactDialog.vuesrc/renderer/src/components/artifacts/ArtifactPreview.vue
**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Enable and adhere to strict TypeScript typing (avoid implicit any, prefer precise types)
Use PascalCase for TypeScript types and classes
Files:
src/renderer/src/components/markdown/MarkdownRenderer.vuesrc/renderer/src/stores/artifact.tssrc/renderer/src/components/artifacts/CodeArtifact.vuesrc/renderer/src/components/artifacts/ArtifactDialog.vuesrc/renderer/src/components/artifacts/ArtifactPreview.vue
src/renderer/{src,shell,floating}/**/*.vue
📄 CodeRabbit inference engine (CLAUDE.md)
src/renderer/{src,shell,floating}/**/*.vue: Use Vue 3 Composition API for all components
All user-facing strings must use i18n keys via vue-i18n (no hard-coded UI strings)
Use Tailwind CSS utilities and ensure styles are scoped in Vue components
Files:
src/renderer/src/components/markdown/MarkdownRenderer.vuesrc/renderer/src/components/artifacts/CodeArtifact.vuesrc/renderer/src/components/artifacts/ArtifactDialog.vuesrc/renderer/src/components/artifacts/ArtifactPreview.vue
src/renderer/src/components/**/*
📄 CodeRabbit inference engine (CLAUDE.md)
Organize UI components by feature within src/renderer/src/
Files:
src/renderer/src/components/markdown/MarkdownRenderer.vuesrc/renderer/src/components/artifacts/CodeArtifact.vuesrc/renderer/src/components/artifacts/ArtifactDialog.vuesrc/renderer/src/components/artifacts/ArtifactPreview.vue
src/renderer/src/**
📄 CodeRabbit inference engine (AGENTS.md)
Place Vue 3 app source under src/renderer/src (components, stores, views, i18n, lib)
Files:
src/renderer/src/components/markdown/MarkdownRenderer.vuesrc/renderer/src/stores/artifact.tssrc/renderer/src/components/artifacts/CodeArtifact.vuesrc/renderer/src/components/artifacts/ArtifactDialog.vuesrc/renderer/src/components/artifacts/ArtifactPreview.vue
src/renderer/src/**/*.{vue,ts}
📄 CodeRabbit inference engine (AGENTS.md)
All user-facing strings must use vue-i18n ($t/keys) rather than hardcoded literals
Files:
src/renderer/src/components/markdown/MarkdownRenderer.vuesrc/renderer/src/stores/artifact.tssrc/renderer/src/components/artifacts/CodeArtifact.vuesrc/renderer/src/components/artifacts/ArtifactDialog.vuesrc/renderer/src/components/artifacts/ArtifactPreview.vue
**/*.{ts,tsx,js,jsx,vue,css,scss,md,json,yml,yaml}
📄 CodeRabbit inference engine (AGENTS.md)
Prettier style: single quotes, no semicolons, print width 100; run pnpm run format
Files:
src/renderer/src/components/markdown/MarkdownRenderer.vuesrc/renderer/src/stores/artifact.tssrc/renderer/src/components/artifacts/CodeArtifact.vuesrc/renderer/src/components/artifacts/ArtifactDialog.vuesrc/renderer/src/components/artifacts/ArtifactPreview.vue
**/*.{ts,tsx,js,jsx,vue}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,js,jsx,vue}: Use OxLint for JS/TS code; keep lint clean
Use camelCase for variables and functions
Use SCREAMING_SNAKE_CASE for constants
Files:
src/renderer/src/components/markdown/MarkdownRenderer.vuesrc/renderer/src/stores/artifact.tssrc/renderer/src/components/artifacts/CodeArtifact.vuesrc/renderer/src/components/artifacts/ArtifactDialog.vuesrc/renderer/src/components/artifacts/ArtifactPreview.vue
src/renderer/**/*.vue
📄 CodeRabbit inference engine (AGENTS.md)
Name Vue component files in PascalCase (e.g., ChatInput.vue)
Files:
src/renderer/src/components/markdown/MarkdownRenderer.vuesrc/renderer/src/components/artifacts/CodeArtifact.vuesrc/renderer/src/components/artifacts/ArtifactDialog.vuesrc/renderer/src/components/artifacts/ArtifactPreview.vue
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/development-setup.mdc)
**/*.{js,jsx,ts,tsx}: 使用 OxLint 进行代码检查
Log和注释使用英文书写
Files:
src/renderer/src/stores/artifact.ts
src/{main,renderer}/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/electron-best-practices.mdc)
src/{main,renderer}/**/*.ts: Use context isolation for improved security
Implement proper inter-process communication (IPC) patterns
Optimize application startup time with lazy loading
Implement proper error handling and logging for debugging
Files:
src/renderer/src/stores/artifact.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/error-logging.mdc)
**/*.{ts,tsx}: 始终使用 try-catch 处理可能的错误
提供有意义的错误信息
记录详细的错误日志
优雅降级处理
日志应包含时间戳、日志级别、错误代码、错误描述、堆栈跟踪(如适用)、相关上下文信息
日志级别应包括 ERROR、WARN、INFO、DEBUG
不要吞掉错误
提供用户友好的错误信息
实现错误重试机制
避免记录敏感信息
使用结构化日志
设置适当的日志级别
Files:
src/renderer/src/stores/artifact.ts
src/renderer/src/stores/**/*.{vue,ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/pinia-best-practices.mdc)
src/renderer/src/stores/**/*.{vue,ts,tsx,js,jsx}: Use modules to organize related state and actions
Implement proper state persistence for maintaining data across sessions
Use getters for computed state properties
Utilize actions for side effects and asynchronous operations
Keep the store focused on global state, not component-specific data
Files:
src/renderer/src/stores/artifact.ts
⏰ 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). (1)
- GitHub Check: build-check (x64)
🔇 Additional comments (6)
src/renderer/src/stores/artifact.ts (1)
27-42: Per-context dismissal guard + force override look correctRespects previously dismissed contexts and allows user-triggered force to show. Matches the PR intent.
src/renderer/src/components/markdown/MarkdownRenderer.vue (1)
80-82: LGTM: user-triggered preview bypasses dismissalPassing { force: true } aligns with the new store API and UX.
src/renderer/src/components/artifacts/ArtifactPreview.vue (1)
316-318: LGTM: explicit force when opening from preview cardEnsures previews open even if the context was previously dismissed via the dialog.
Confirm that using hideArtifact (Line 304) on second click (toggle-close) is intentional vs dismissArtifact. If toggling should suppress auto-reopen during streaming, switch to dismissArtifact.
src/renderer/src/components/artifacts/CodeArtifact.vue (1)
190-192: LGTM: forced display for HTML/SVG previewMatches the store’s new options and intended behavior.
src/renderer/src/components/artifacts/ArtifactDialog.vue (2)
19-21: Use dismissArtifact on back/closeCorrectly records a manual dismissal and hides the dialog, matching the per-context guard.
233-234: Typed import for ArtifactStateGood addition; keeps helpers strongly typed.
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.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/renderer/src/components/artifacts/CodeArtifact.vue (2)
130-168: Replace hardcoded language display names with i18n keys.All language display names are hardcoded strings, which violates the coding guidelines requiring all user-facing text to use i18n translation keys via
vue-i18n. As per coding guidelines.Refactor to use i18n keys. For example:
const displayLanguage = computed(() => { const lang = codeLanguage.value - const displayNames: Record<string, string> = { - javascript: 'JavaScript', - typescript: 'TypeScript', - python: 'Python', + const displayNames: Record<string, string> = { + javascript: t('languages.javascript'), + typescript: t('languages.typescript'), + python: t('languages.python'), // ... rest of mappings }Then add corresponding keys to your i18n locale files:
{ "languages": { "javascript": "JavaScript", "typescript": "TypeScript", "python": "Python", // ... etc } }
202-202: Remove or sanitize the language fallback.The fallback
lowerLang || props.block.artifact?.languageintroduces inconsistency. SincelowerLangcomes from the already-sanitizedcodeLanguage.value, falling back to the unsanitizedprops.block.artifact?.languagedefeats the purpose of sanitization. IflowerLangis empty, the fallback should also be sanitized or simply removed (empty string is valid).Apply this diff to sanitize the fallback:
- language: lowerLang || props.block.artifact?.language, + language: lowerLang || sanitizeLanguage(props.block.artifact?.language),Or remove the fallback entirely if empty language is acceptable:
- language: lowerLang || props.block.artifact?.language, + language: lowerLang,
🧹 Nitpick comments (3)
src/renderer/src/components/artifacts/CodeArtifact.vue (3)
74-89: Add explicit return type annotation.For better type safety and clarity, explicitly annotate the return type as
string.Apply this diff:
-const sanitizeLanguage = (language?: string | null) => { +const sanitizeLanguage = (language?: string | null): string => { if (!language) return '' const normalized = language.trim().toLowerCase()
78-88: Expand language alias mappings for better coverage.The current alias list is limited. Consider adding common aliases like
js→javascript,ts→typescript,py→python,sh→shell,yml→yaml, etc., to improve normalization consistency across different language identifiers.Apply this diff to add common aliases:
switch (normalized) { + case 'js': + return 'javascript' + case 'ts': + return 'typescript' + case 'py': + return 'python' case 'md': return 'markdown' case 'plain': case 'text': return 'plaintext' case 'htm': return 'html' + case 'sh': + return 'shell' + case 'yml': + return 'yaml' default: return normalized }
74-89: Consider extractingsanitizeLanguageto a shared utility module.Since multiple artifact-related components might need language normalization (ArtifactDialog, ArtifactPreview, etc.), consider extracting this helper to a shared utility file like
src/renderer/src/lib/language-utils.tsfor better reusability and maintainability.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/renderer/src/components/artifacts/ArtifactDialog.vue(6 hunks)src/renderer/src/components/artifacts/CodeArtifact.vue(3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- src/renderer/src/components/artifacts/ArtifactDialog.vue
🧰 Additional context used
📓 Path-based instructions (16)
src/renderer/src/**/*
📄 CodeRabbit inference engine (.cursor/rules/i18n.mdc)
src/renderer/src/**/*: All user-facing strings must use i18n keys (avoid hardcoded user-visible text in code)
Use the 'vue-i18n' framework for all internationalization in the renderer
Ensure all user-visible text in the renderer uses the translation system
Files:
src/renderer/src/components/artifacts/CodeArtifact.vue
src/renderer/**/*.{vue,ts,js,tsx,jsx}
📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)
渲染进程代码放在
src/renderer
Files:
src/renderer/src/components/artifacts/CodeArtifact.vue
src/renderer/src/**/*.{vue,ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/vue-best-practices.mdc)
src/renderer/src/**/*.{vue,ts,tsx,js,jsx}: Use the Composition API for better code organization and reusability
Implement proper state management with Pinia
Utilize Vue Router for navigation and route management
Leverage Vue's built-in reactivity system for efficient data handling
Files:
src/renderer/src/components/artifacts/CodeArtifact.vue
src/renderer/src/**/*.vue
📄 CodeRabbit inference engine (.cursor/rules/vue-best-practices.mdc)
Use scoped styles to prevent CSS conflicts between components
Files:
src/renderer/src/components/artifacts/CodeArtifact.vue
src/renderer/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (.cursor/rules/vue-shadcn.mdc)
src/renderer/**/*.{ts,tsx,vue}: Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError).
Use TypeScript for all code; prefer types over interfaces.
Avoid enums; use const objects instead.
Use arrow functions for methods and computed properties.
Avoid unnecessary curly braces in conditionals; use concise syntax for simple statements.
Files:
src/renderer/src/components/artifacts/CodeArtifact.vue
src/renderer/**/*.{vue,ts}
📄 CodeRabbit inference engine (.cursor/rules/vue-shadcn.mdc)
Implement lazy loading for routes and components.
Files:
src/renderer/src/components/artifacts/CodeArtifact.vue
src/renderer/**/*.{ts,vue}
📄 CodeRabbit inference engine (.cursor/rules/vue-shadcn.mdc)
src/renderer/**/*.{ts,vue}: Use useFetch and useAsyncData for data fetching.
Implement SEO best practices using Nuxt's useHead and useSeoMeta.Use Pinia for frontend state management (do not introduce alternative state libraries)
Files:
src/renderer/src/components/artifacts/CodeArtifact.vue
**/*.{ts,tsx,js,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Use English for all logs and comments
Files:
src/renderer/src/components/artifacts/CodeArtifact.vue
**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Enable and adhere to strict TypeScript typing (avoid implicit any, prefer precise types)
Use PascalCase for TypeScript types and classes
Files:
src/renderer/src/components/artifacts/CodeArtifact.vue
src/renderer/{src,shell,floating}/**/*.vue
📄 CodeRabbit inference engine (CLAUDE.md)
src/renderer/{src,shell,floating}/**/*.vue: Use Vue 3 Composition API for all components
All user-facing strings must use i18n keys via vue-i18n (no hard-coded UI strings)
Use Tailwind CSS utilities and ensure styles are scoped in Vue components
Files:
src/renderer/src/components/artifacts/CodeArtifact.vue
src/renderer/src/components/**/*
📄 CodeRabbit inference engine (CLAUDE.md)
Organize UI components by feature within src/renderer/src/
Files:
src/renderer/src/components/artifacts/CodeArtifact.vue
src/renderer/src/**
📄 CodeRabbit inference engine (AGENTS.md)
Place Vue 3 app source under src/renderer/src (components, stores, views, i18n, lib)
Files:
src/renderer/src/components/artifacts/CodeArtifact.vue
src/renderer/src/**/*.{vue,ts}
📄 CodeRabbit inference engine (AGENTS.md)
All user-facing strings must use vue-i18n ($t/keys) rather than hardcoded literals
Files:
src/renderer/src/components/artifacts/CodeArtifact.vue
**/*.{ts,tsx,js,jsx,vue,css,scss,md,json,yml,yaml}
📄 CodeRabbit inference engine (AGENTS.md)
Prettier style: single quotes, no semicolons, print width 100; run pnpm run format
Files:
src/renderer/src/components/artifacts/CodeArtifact.vue
**/*.{ts,tsx,js,jsx,vue}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,js,jsx,vue}: Use OxLint for JS/TS code; keep lint clean
Use camelCase for variables and functions
Use SCREAMING_SNAKE_CASE for constants
Files:
src/renderer/src/components/artifacts/CodeArtifact.vue
src/renderer/**/*.vue
📄 CodeRabbit inference engine (AGENTS.md)
Name Vue component files in PascalCase (e.g., ChatInput.vue)
Files:
src/renderer/src/components/artifacts/CodeArtifact.vue
🔇 Additional comments (2)
src/renderer/src/components/artifacts/CodeArtifact.vue (2)
207-209: LGTM! User-triggered preview bypasses dismissal guard.The
{ force: true }option correctly implements the PR objective of allowing user-triggered artifact previews to bypass the dismissal guard.
91-91: LGTM! Consistent sanitization across language handling.The
sanitizeLanguagehelper is correctly applied in initialization (line 91), detection (line 96), and watch logic (line 237), ensuring consistent language normalization throughout the component lifecycle.Also applies to: 96-96, 237-237
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.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (14)
src/renderer/src/components/artifacts/ArtifactDialog.vue (14)
1-1: Fix Prettier formatting to pass CI checks.The pipeline reports a Prettier formatting failure. Run the following command to fix:
pnpm run format
14-14: Replace Chinese comment with English.The coding guidelines require all comments to be in English.
Apply this diff:
- <!-- 顶部导航栏 --> + <!-- Top navigation bar -->As per coding guidelines.
314-314: Replaceanytype with proper HTMLElement type.Using
anyviolates the strict TypeScript guidelines.Apply this diff:
-const codeEditor = ref<any>(null) +const codeEditor = ref<HTMLDivElement | null>(null)As per coding guidelines.
26-27: Replace Chinese comment with English.Apply this diff:
- <!-- 预览/代码切换按钮组 --> + <!-- Preview/Code toggle button group -->As per coding guidelines.
52-53: Replace Chinese comment with English.Apply this diff:
- <!-- 设备尺寸切换按钮组 (仅在HTML预览时显示) --> + <!-- Device size toggle buttons (shown only in HTML preview) -->As per coding guidelines.
95-96: Replace Chinese comment with English.Apply this diff:
- <!-- 尺寸微调输入框 (仅在平板和手机模式下显示) --> + <!-- Size adjustment inputs (shown only in tablet and mobile modes) -->As per coding guidelines.
143-144: Replace Chinese comment with English.Apply this diff:
- <!-- 导出按钮 --> + <!-- Export buttons -->As per coding guidelines.
195-196: Replace Chinese comment with English.Apply this diff:
- <!-- 内容区域 --> + <!-- Content area -->As per coding guidelines.
258-259: Replace Chinese comment with English.Apply this diff:
-const tabletHeight = ref(1024) // 4:3 比例 -const mobileHeight = ref(667) // 16:9 比例 +const tabletHeight = ref(1024) // 4:3 aspect ratio +const mobileHeight = ref(667) // 16:9 aspect ratioAs per coding guidelines.
529-530: Replace Chinese comment with English.Apply this diff:
- // 如果是 Mermaid 图表,需要先渲染成 SVG + // If it's a Mermaid diagram, render it to SVG firstAs per coding guidelines.
537-538: Replace Chinese comment with English.Apply this diff:
- // 确保 SVG 内容是有效的 + // Ensure SVG content is validAs per coding guidelines.
579-579: Replace Chinese string with i18n key.The error log contains a hardcoded Chinese string. According to coding guidelines, all user-facing strings must use i18n keys, and logs should be in English.
Apply this diff:
- console.error('复制失败', e) + console.error('Copy failed', e)As per coding guidelines.
592-596: Replace Chinese comment with English.Apply this diff:
- // 检查是否是 iframe 类型的 artifact (HTML 或 React) + // Check if this is an iframe-type artifact (HTML or React)As per coding guidelines.
600-608: Replace Chinese comments with English.Apply this diff:
if (isIframeArtifact) { - // 对于 iframe 类型,我们使用 iframe 元素作为滚动容器 + // For iframe types, use the iframe element as the scroll container containerSelector = '.html-iframe-wrapper' targetSelector = '.html-iframe-wrapper' } else { - // 非 iframe 类型使用默认配置 + // Non-iframe types use default configuration containerSelector = '.artifact-scroll-container' targetSelector = '.artifact-dialog-content' }As per coding guidelines.
🧹 Nitpick comments (2)
src/renderer/src/components/artifacts/ArtifactDialog.vue (2)
282-306: LGTM! Consider extracting type mapping.The
normalizeLanguagefunction correctly derives language from artifact properties with appropriate fallbacks.For maintainability, consider extracting the type-to-language mapping:
const ARTIFACT_TYPE_TO_LANGUAGE = { 'application/vnd.ant.code': 'plaintext', 'text/markdown': 'markdown', 'text/html': 'html', 'image/svg+xml': 'svg', 'application/vnd.ant.mermaid': 'mermaid', 'application/vnd.ant.react': 'jsx' } as const const normalizeLanguage = (artifact: ArtifactState | null) => { if (!artifact) return '' const explicit = sanitizeLanguage(artifact.language) if (explicit) return explicit return ARTIFACT_TYPE_TO_LANGUAGE[artifact.type] || sanitizeLanguage(artifact.type) }
425-484: Consider consolidating editor cleanup.Both the
isOpenwatcher (lines 425-432) andonBeforeUnmount(lines 482-484) callcleanupEditor(). While defensive, this may be redundant. Consider whether cleanup on dialog close is needed ifonBeforeUnmountalways runs before component destruction.If the dialog can be closed without unmounting the component, the current dual-cleanup approach is correct. Otherwise,
onBeforeUnmountalone would suffice.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/renderer/src/components/artifacts/ArtifactDialog.vue(6 hunks)
🧰 Additional context used
📓 Path-based instructions (16)
src/renderer/src/**/*
📄 CodeRabbit inference engine (.cursor/rules/i18n.mdc)
src/renderer/src/**/*: All user-facing strings must use i18n keys (avoid hardcoded user-visible text in code)
Use the 'vue-i18n' framework for all internationalization in the renderer
Ensure all user-visible text in the renderer uses the translation system
Files:
src/renderer/src/components/artifacts/ArtifactDialog.vue
src/renderer/**/*.{vue,ts,js,tsx,jsx}
📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)
渲染进程代码放在
src/renderer
Files:
src/renderer/src/components/artifacts/ArtifactDialog.vue
src/renderer/src/**/*.{vue,ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/vue-best-practices.mdc)
src/renderer/src/**/*.{vue,ts,tsx,js,jsx}: Use the Composition API for better code organization and reusability
Implement proper state management with Pinia
Utilize Vue Router for navigation and route management
Leverage Vue's built-in reactivity system for efficient data handling
Files:
src/renderer/src/components/artifacts/ArtifactDialog.vue
src/renderer/src/**/*.vue
📄 CodeRabbit inference engine (.cursor/rules/vue-best-practices.mdc)
Use scoped styles to prevent CSS conflicts between components
Files:
src/renderer/src/components/artifacts/ArtifactDialog.vue
src/renderer/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (.cursor/rules/vue-shadcn.mdc)
src/renderer/**/*.{ts,tsx,vue}: Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError).
Use TypeScript for all code; prefer types over interfaces.
Avoid enums; use const objects instead.
Use arrow functions for methods and computed properties.
Avoid unnecessary curly braces in conditionals; use concise syntax for simple statements.
Files:
src/renderer/src/components/artifacts/ArtifactDialog.vue
src/renderer/**/*.{vue,ts}
📄 CodeRabbit inference engine (.cursor/rules/vue-shadcn.mdc)
Implement lazy loading for routes and components.
Files:
src/renderer/src/components/artifacts/ArtifactDialog.vue
src/renderer/**/*.{ts,vue}
📄 CodeRabbit inference engine (.cursor/rules/vue-shadcn.mdc)
src/renderer/**/*.{ts,vue}: Use useFetch and useAsyncData for data fetching.
Implement SEO best practices using Nuxt's useHead and useSeoMeta.Use Pinia for frontend state management (do not introduce alternative state libraries)
Files:
src/renderer/src/components/artifacts/ArtifactDialog.vue
**/*.{ts,tsx,js,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Use English for all logs and comments
Files:
src/renderer/src/components/artifacts/ArtifactDialog.vue
**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Enable and adhere to strict TypeScript typing (avoid implicit any, prefer precise types)
Use PascalCase for TypeScript types and classes
Files:
src/renderer/src/components/artifacts/ArtifactDialog.vue
src/renderer/{src,shell,floating}/**/*.vue
📄 CodeRabbit inference engine (CLAUDE.md)
src/renderer/{src,shell,floating}/**/*.vue: Use Vue 3 Composition API for all components
All user-facing strings must use i18n keys via vue-i18n (no hard-coded UI strings)
Use Tailwind CSS utilities and ensure styles are scoped in Vue components
Files:
src/renderer/src/components/artifacts/ArtifactDialog.vue
src/renderer/src/components/**/*
📄 CodeRabbit inference engine (CLAUDE.md)
Organize UI components by feature within src/renderer/src/
Files:
src/renderer/src/components/artifacts/ArtifactDialog.vue
src/renderer/src/**
📄 CodeRabbit inference engine (AGENTS.md)
Place Vue 3 app source under src/renderer/src (components, stores, views, i18n, lib)
Files:
src/renderer/src/components/artifacts/ArtifactDialog.vue
src/renderer/src/**/*.{vue,ts}
📄 CodeRabbit inference engine (AGENTS.md)
All user-facing strings must use vue-i18n ($t/keys) rather than hardcoded literals
Files:
src/renderer/src/components/artifacts/ArtifactDialog.vue
**/*.{ts,tsx,js,jsx,vue,css,scss,md,json,yml,yaml}
📄 CodeRabbit inference engine (AGENTS.md)
Prettier style: single quotes, no semicolons, print width 100; run pnpm run format
Files:
src/renderer/src/components/artifacts/ArtifactDialog.vue
**/*.{ts,tsx,js,jsx,vue}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,js,jsx,vue}: Use OxLint for JS/TS code; keep lint clean
Use camelCase for variables and functions
Use SCREAMING_SNAKE_CASE for constants
Files:
src/renderer/src/components/artifacts/ArtifactDialog.vue
src/renderer/**/*.vue
📄 CodeRabbit inference engine (AGENTS.md)
Name Vue component files in PascalCase (e.g., ChatInput.vue)
Files:
src/renderer/src/components/artifacts/ArtifactDialog.vue
🪛 GitHub Actions: PR Check
src/renderer/src/components/artifacts/ArtifactDialog.vue
[error] 1-1: Prettier formatting check failed (exit code 1) for ArtifactDialog.vue. Run 'prettier --write' to fix formatting.
🔇 Additional comments (9)
src/renderer/src/components/artifacts/ArtifactDialog.vue (9)
265-280: LGTM! Clean language normalization.The
sanitizeLanguagefunction properly handles common language aliases with good defensive null/undefined checks.
325-331: LGTM! Stable context key generation.The
getArtifactContextKeyfunction properly creates stable context identifiers for dismissal tracking, aligning with the PR objectives.
368-370: Verify language detection is still needed.Since
codeLanguageis now initialized withnormalizeLanguage(artifactStore.currentArtifact)at line 308, the condition!codeLanguage.valueat line 368 may rarely (or never) be true, preventing auto-detection from running. If auto-detection is still needed as a fallback for unrecognized types, consider checking for'plaintext'or empty string instead:- if (!codeLanguage.value) { + if (!codeLanguage.value || codeLanguage.value === 'plaintext') { throttledDetectLanguage(newCode) }Alternatively, if explicit language from
normalizeLanguageshould always take precedence, the current logic is correct and this check serves as a safety net.
405-423: LGTM! Proper editor lifecycle management.The watcher correctly initializes the Monaco editor only when all conditions are met (dialog open, code view active, element available). The
flush: 'post'option ensures the DOM is ready.
437-447: Excellent! Aligns perfectly with PR objectives.The
AUTO_PREVIEW_TYPESset combined with thestatus !== 'loaded'check (line 445) ensures the dialog defaults to code view during streaming and only switches to preview for specific types after content has fully loaded. This directly implements the PR objective: "Default the streaming artifact dialog to the code view unless preview-only types have finished loading."
449-452: LGTM! Tracks explicit user preview toggles.Setting
userHasSetPreviewwhen the user explicitly changes the preview mode is essential for preserving their choice during streaming updates.
458-475: LGTM! Respects user choice and loading state.The status watcher properly respects
userHasSetPreview(line 466) and defers togetDefaultPreviewStateonly when the user hasn't explicitly set a preference. This ensures user actions persist while still providing sensible defaults for loaded artifacts.
337-378: Consider removingdeep: trueto avoid performance issues
The deep watcher may fire on every property change during streaming. No existing performance-streaming tests were found—manually validate streaming performance or removedeep: trueand rely on the separate content watcher for granular updates.
19-19: artifactStore.dismissArtifact is defined in the artifact store
ThedismissArtifactmethod is declared (lines 56–63) and exported (line 89) insrc/renderer/src/stores/artifact.ts, so this call is valid.
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.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/renderer/src/components/artifacts/ArtifactDialog.vue (1)
571-575: Use English in logs- console.error('复制失败', e) + console.error('Copy failed', e)As per coding guidelines.
♻️ Duplicate comments (2)
src/renderer/src/components/artifacts/ArtifactDialog.vue (2)
427-427: Replace Chinese comment with English-// 截图相关功能 +// Screenshot functionalityAs per coding guidelines.
471-473: Replace Chinese comment with English- // 获取应用版本 + // Get application versionAs per coding guidelines.
🧹 Nitpick comments (5)
src/renderer/src/components/artifacts/ArtifactDialog.vue (5)
265-281: Normalize languages for Monaco; drop mermaid early-return so code view updates
- Monaco doesn’t register mermaid or svg; map to markdown/xml for highlighting.
- Remove the mermaid early return to keep code view in sync.
Apply:
@@ - case 'image/svg+xml': - return 'svg' + case 'image/svg+xml': + return 'xml' @@ - case 'application/vnd.ant.mermaid': - return 'mermaid' + case 'application/vnd.ant.mermaid': + return 'markdown'And:
- if (codeLanguage.value === 'mermaid') { - return - }Also applies to: 282-306, 363-365
337-362: Don’t remount preview on every streaming updatecomponentKey.value++ runs on each currentArtifact change; this remounts preview components repeatedly. Only bump when the artifact context actually changes.
- componentKey.value++ @@ - if (isNewArtifact) { + if (isNewArtifact) { + componentKey.value++ activeArtifactContext.value = newContextKey userHasSetPreview.value = false isPreview.value = getDefaultPreviewState(newArtifact) }
367-375: Reduce duplicate code updates; rely on dedicated watchersupdateCode is executed in this deep watcher and also in the content and language watchers, causing redundant updates. Make this watcher shallow and drop the inline update.
@@ - const newCode = newArtifact.content || '' - - if (!codeLanguage.value) { - throttledDetectLanguage(newCode) - } - - updateCode(newCode, codeLanguage.value) + const newCode = newArtifact.content || '' + if (!codeLanguage.value) throttledDetectLanguage(newCode) @@ - deep: true // Add deep watching to catch property changes + // Shallow watch; content and language updates handled by dedicated watchersAlso applies to: 376-379, 393-404
406-417: Guard Monaco initialization to avoid duplicate editors; type the refAdd a readiness flag to prevent re-creating the editor on every toggle/open.
@@ -const codeEditor = ref<any>(null) +const codeEditor = ref<HTMLDivElement | null>(null) +const editorReady = ref(false) @@ - ([editorEl, previewActive, open]) => { + ([editorEl, previewActive, open]) => { if (!open || previewActive || !editorEl) return - void createEditor(editorEl, artifactStore.currentArtifact?.content || '', codeLanguage.value) + if (editorReady.value) { + updateCode(artifactStore.currentArtifact?.content || '', codeLanguage.value) + return + } + void createEditor(editorEl, artifactStore.currentArtifact?.content || '', codeLanguage.value) + editorReady.value = true }, @@ (open) => { if (!open) { cleanupEditor() + editorReady.value = false } } ) @@ onBeforeUnmount(() => { cleanupEditor() + editorReady.value = false })Also applies to: 418-425, 475-477, 314-315
325-334: Reuse artifact store’s makeContextKeyExport
makeContextKeyfromsrc/renderer/src/stores/artifact.ts, import it inArtifactDialog.vue, and replace the manual${threadId}:${messageId}:${artifact.id}logic withmakeContextKey(artifact.id, messageId, threadId)to ensure consistency.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/renderer/src/components/artifacts/ArtifactDialog.vue(6 hunks)
🧰 Additional context used
📓 Path-based instructions (16)
src/renderer/src/**/*
📄 CodeRabbit inference engine (.cursor/rules/i18n.mdc)
src/renderer/src/**/*: All user-facing strings must use i18n keys (avoid hardcoded user-visible text in code)
Use the 'vue-i18n' framework for all internationalization in the renderer
Ensure all user-visible text in the renderer uses the translation system
Files:
src/renderer/src/components/artifacts/ArtifactDialog.vue
src/renderer/**/*.{vue,ts,js,tsx,jsx}
📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)
渲染进程代码放在
src/renderer
Files:
src/renderer/src/components/artifacts/ArtifactDialog.vue
src/renderer/src/**/*.{vue,ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/vue-best-practices.mdc)
src/renderer/src/**/*.{vue,ts,tsx,js,jsx}: Use the Composition API for better code organization and reusability
Implement proper state management with Pinia
Utilize Vue Router for navigation and route management
Leverage Vue's built-in reactivity system for efficient data handling
Files:
src/renderer/src/components/artifacts/ArtifactDialog.vue
src/renderer/src/**/*.vue
📄 CodeRabbit inference engine (.cursor/rules/vue-best-practices.mdc)
Use scoped styles to prevent CSS conflicts between components
Files:
src/renderer/src/components/artifacts/ArtifactDialog.vue
src/renderer/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (.cursor/rules/vue-shadcn.mdc)
src/renderer/**/*.{ts,tsx,vue}: Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError).
Use TypeScript for all code; prefer types over interfaces.
Avoid enums; use const objects instead.
Use arrow functions for methods and computed properties.
Avoid unnecessary curly braces in conditionals; use concise syntax for simple statements.
Files:
src/renderer/src/components/artifacts/ArtifactDialog.vue
src/renderer/**/*.{vue,ts}
📄 CodeRabbit inference engine (.cursor/rules/vue-shadcn.mdc)
Implement lazy loading for routes and components.
Files:
src/renderer/src/components/artifacts/ArtifactDialog.vue
src/renderer/**/*.{ts,vue}
📄 CodeRabbit inference engine (.cursor/rules/vue-shadcn.mdc)
src/renderer/**/*.{ts,vue}: Use useFetch and useAsyncData for data fetching.
Implement SEO best practices using Nuxt's useHead and useSeoMeta.Use Pinia for frontend state management (do not introduce alternative state libraries)
Files:
src/renderer/src/components/artifacts/ArtifactDialog.vue
**/*.{ts,tsx,js,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Use English for all logs and comments
Files:
src/renderer/src/components/artifacts/ArtifactDialog.vue
**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Enable and adhere to strict TypeScript typing (avoid implicit any, prefer precise types)
Use PascalCase for TypeScript types and classes
Files:
src/renderer/src/components/artifacts/ArtifactDialog.vue
src/renderer/{src,shell,floating}/**/*.vue
📄 CodeRabbit inference engine (CLAUDE.md)
src/renderer/{src,shell,floating}/**/*.vue: Use Vue 3 Composition API for all components
All user-facing strings must use i18n keys via vue-i18n (no hard-coded UI strings)
Use Tailwind CSS utilities and ensure styles are scoped in Vue components
Files:
src/renderer/src/components/artifacts/ArtifactDialog.vue
src/renderer/src/components/**/*
📄 CodeRabbit inference engine (CLAUDE.md)
Organize UI components by feature within src/renderer/src/
Files:
src/renderer/src/components/artifacts/ArtifactDialog.vue
src/renderer/src/**
📄 CodeRabbit inference engine (AGENTS.md)
Place Vue 3 app source under src/renderer/src (components, stores, views, i18n, lib)
Files:
src/renderer/src/components/artifacts/ArtifactDialog.vue
src/renderer/src/**/*.{vue,ts}
📄 CodeRabbit inference engine (AGENTS.md)
All user-facing strings must use vue-i18n ($t/keys) rather than hardcoded literals
Files:
src/renderer/src/components/artifacts/ArtifactDialog.vue
**/*.{ts,tsx,js,jsx,vue,css,scss,md,json,yml,yaml}
📄 CodeRabbit inference engine (AGENTS.md)
Prettier style: single quotes, no semicolons, print width 100; run pnpm run format
Files:
src/renderer/src/components/artifacts/ArtifactDialog.vue
**/*.{ts,tsx,js,jsx,vue}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,js,jsx,vue}: Use OxLint for JS/TS code; keep lint clean
Use camelCase for variables and functions
Use SCREAMING_SNAKE_CASE for constants
Files:
src/renderer/src/components/artifacts/ArtifactDialog.vue
src/renderer/**/*.vue
📄 CodeRabbit inference engine (AGENTS.md)
Name Vue component files in PascalCase (e.g., ChatInput.vue)
Files:
src/renderer/src/components/artifacts/ArtifactDialog.vue
⏰ 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). (1)
- GitHub Check: build-check (x64)
🔇 Additional comments (3)
src/renderer/src/components/artifacts/ArtifactDialog.vue (3)
19-21: Back button: switch to dismissArtifact looks correctUpdated to artifactStore.dismissArtifact aligns with store API changes.
430-441: Auto-preview defaults match PR intentAUTO_PREVIEW_TYPES and getDefaultPreviewState implement “preview when loaded for preview-only types.” Looks good.
443-446: User choice persists across streaming updatessetPreview marks userHasSetPreview; the status watcher respects it. This fixes the prior reset issue during partial updates.
Please confirm artifact.id remains stable during streaming; otherwise userHasSetPreview could reset unexpectedly on identity changes.
Also applies to: 454-465
Summary
Testing
https://chatgpt.com/codex/tasks/task_e_68ee2f1a78bc832c8749adf13f9428de
Summary by CodeRabbit
New Features
Bug Fixes