Skip to content

Codex/feature/dialog message list optimization - #1254

Merged
qdaxb merged 1 commit into
wecode-ai:mainfrom
FicoHu:codex/feature/dialog-message-list-optimization
Jun 3, 2026
Merged

qdaxb merged 1 commit into
wecode-ai:mainfrom
FicoHu:codex/feature/dialog-message-list-optimization

Conversation

@FicoHu

@FicoHu FicoHu commented Jun 3, 2026 •

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • New Features

    • Added conversation queue panel for managing queued and guidance messages with pause/resume, send-as-guidance, edit, and cancel controls.
    • Added empty state UI for new conversations.
    • Enhanced message rendering with attachment previews and time display.
    • Improved streaming response handling with pause button during active streams.
  • Improvements

    • Removed file type restrictions; all file types can now be uploaded.
    • Added copy-to-clipboard functionality for message content.

@coderabbitai

coderabbitai Bot commented Jun 3, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR extends the workbench chat experience with queued and guidance message state, streaming response pause controls, broader file attachment handling, and corresponding UI updates. The changes add new type contracts for queue/guidance lifecycle, refactor the provider to manage queued sends and guidance messages with automatic queue processing, wire these through layouts and composers, render a new queue panel above chat inputs, remove file type restrictions, add streaming pause buttons, and enhance message rendering with attachments and improved styling.

Changes

Workbench Chat Queue and Attachment Flow

Layer / File(s) Summary
Chat contracts and attachment primitives
wework/src/types/api.ts, wework/src/types/workbench.ts, wework/src/api/attachments.ts, wework/src/features/workbench/messageReducer.ts, wework/src/stream/chatStream.ts, wework/src/lib/attachments.ts
New message contracts for QueuedWorkbenchMessage, GuidanceWorkbenchMessage, and API payload types for guidance send/cancel and guidance lifecycle events (queued/applied/expired). Subtask now includes optional attachments, and WorkbenchMessage adds shellType and attachments fields. Stream API gains sendGuidance and cancelStream methods with handler callbacks. Attachment module exports helpers for image detection, URL generation, and type labeling.
Workbench queue and guidance runtime
wework/src/features/workbench/WorkbenchProvider.tsx, wework/src/features/workbench/WorkbenchProvider.test.tsx
Implements queuedMessages and guidanceMessages state in the provider, derives attachments from subtask contexts, handles stream lifecycle with guidance event subscription, clears queues on context navigation, and refactors send logic to enqueue during active streams or send immediately. Auto-sends queued items when appropriate, and exposes pause/cancel/edit/send-as-guidance callbacks. Provider tests verify attachment history rendering and guidance race semantics.
Workbench page and layout wiring
wework/src/pages/WorkbenchPage.tsx, wework/src/components/layout/DesktopWorkbenchLayout.tsx, wework/src/components/layout/DesktopWorkbenchMain.tsx, wework/src/components/layout/MobileWorkbenchLayout.tsx, wework/src/components/layout/DesktopWorkbenchLayout.test.tsx
Extracts queued/guidance messages and response streaming state from useWorkbench and threads them through desktop and mobile layouts to ChatInput. Desktop layout adjusts chat area padding when queued rows are present. Both layouts pass the state and handlers to ChatInput in active and empty chat entry paths.
Queue panel and chat input integration
wework/src/components/chat/ConversationQueuePanel.tsx, wework/src/components/chat/ChatInput.tsx, wework/src/components/chat/ChatInput.test.tsx, wework/src/components/common/ActionMenu.tsx
New ConversationQueuePanel component renders queued and guidance message rows with status labels and action buttons (send-as-guidance, edit, cancel). ChatInput renders the queue panel above both desktop and compact composers, extends props to accept queue/guidance messages and control handlers, and defaults empty arrays. Tests verify pause-response button rendering during streaming and queue action callback invocation. ActionMenu gains optional triggerClassName prop.
Composer streaming controls and unrestricted file uploads
wework/src/components/chat/composer/CompactChatComposer.tsx, wework/src/components/chat/composer/ComposerTextarea.tsx, wework/src/components/chat/composer/ComposerToolbar.tsx, wework/src/components/chat/composer/ProjectChatComposer.tsx, wework/src/components/chat/composer/AddContextMenu.tsx, wework/src/features/workbench/useWorkbenchAttachments.ts, wework/src/features/workbench/workbenchProjectChatHooks.test.tsx, wework/src/i18n/locales/en/common.json, wework/src/i18n/locales/zh-CN/common.json
Replaces onImageSelect prop with onFileSelect across composers to support arbitrary file uploads without type filtering. Adds isStreaming and onPause props; streaming pause button replaces send button when active. ComposerTextarea gains onPasteFiles handler to support clipboard file paste. Removes SUPPORTED_EXTENSIONS import and extension validation from API and hooks. Updates upload label from "image" to "file". Tests verify unrestricted file selection and paste handling.
Message rendering and empty conversation display
wework/src/components/chat/MessageList.tsx, wework/src/components/chat/MessageList.test.tsx, wework/src/components/chat/ScrollableMessageArea.tsx, wework/src/components/chat/ScrollableMessageArea.test.tsx, wework/src/components/chat/composer/AttachmentBadges.tsx
Refactors UserMessage to accept full message object and render image and document attachment previews alongside markdown. Adds helpers for timestamp formatting and clipboard copy with Clipboard API fallback. Updates assistant message hover and markdown styling, and adjusts hover action visibility to exclude streaming messages. ScrollableMessageArea renders empty-state UI when no messages exist. Moves attachment badge helpers to shared library. Tests cover attachment rendering, hover interactions, and empty state.
Dialog focus and button sizing
wework/src/components/common/TextInputDialog.tsx, wework/src/components/common/TextInputDialog.test.tsx
Updates text input dialog to autofocus the input and uses taller height/min-width on close, cancel, and confirm buttons for improved touch targets. Test verifies focus and button sizing classes.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • wecode-ai/Wegent#1116: Implements the backend guidance feature end-to-end—socket events (chat:guide, chat:guidance_queued/applied/expired) and guidance queue mechanics that drive the frontend queued/guidance message state updates in this PR.

  • wecode-ai/Wegent#1177: Touches the same chat composer and attachment handling surfaces, including updates to ChatInput/ProjectChatComposer wiring and removal of file extension restrictions in wework/src/api/attachments.ts.

Suggested reviewers

  • qdaxb

Poem

🐰 Queues build in whispers, guidance flows so free,
Attachments flow unfiltered, as they should be,
Pause buttons bloom when responses take flight,
Messages dance in their queue, shining bright! ✨

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning The PR title 'Codex/feature/dialog message list optimization' is misleading. The changeset introduces comprehensive features for message queuing, guidance streaming, attachment handling, and UI improvements—far beyond just message list optimization. Revise the title to accurately reflect the main changes, such as 'Add message queue panel and guidance streaming support' or 'Implement conversation queue and response streaming controls'.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@FicoHu
FicoHu force-pushed the codex/feature/dialog-message-list-optimization branch from 9db46b9 to 6feac8b Compare June 3, 2026 12:23

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
wework/src/components/chat/ConversationQueuePanel.tsx (1)

1-156: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

File naming convention violation.

Per coding guidelines, "Component names should use PascalCase, and component files should use kebab-case naming in React/TypeScript." This file should be renamed from ConversationQueuePanel.tsx to conversation-queue-panel.tsx.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@wework/src/components/chat/ConversationQueuePanel.tsx` around lines 1 - 156,
Rename the file from ConversationQueuePanel.tsx to conversation-queue-panel.tsx
to follow kebab-case file naming while keeping the exported React component
names (ConversationQueuePanel and QueueRow) in PascalCase; then update any
imports throughout the codebase that reference the old filename to import from
"conversation-queue-panel" (e.g., import { ConversationQueuePanel } from '...'),
and run a quick search to ensure no remaining references to
ConversationQueuePanel.tsx remain.
🧹 Nitpick comments (4)
wework/src/components/common/TextInputDialog.test.tsx (1)

23-24: ⚡ Quick win

Assert full touch-target sizing, not only height.

The new test checks h-11, but the component change also depends on min-w-[44px] for the 44×44 touch target contract. Add class assertions for min-w-[44px] (and ideally the close button too) to prevent regressions.

As per coding guidelines: "All interactive elements on mobile must be at least 44px × 44px - use h-11 min-w-[44px] for buttons".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@wework/src/components/common/TextInputDialog.test.tsx` around lines 23 - 24,
The test currently only asserts height for the rename dialog buttons; update the
assertions for the elements identified by
getByTestId('confirm-rename-project-button') and
getByTestId('rename-project-input-cancel-button') to also assert the min-width
class 'min-w-[44px]' so the 44×44 touch-target contract is enforced (i.e., check
both 'h-11' and 'min-w-[44px]' on each relevant button).
wework/src/features/workbench/WorkbenchProvider.tsx (1)

1-1406: ⚡ Quick win

Consider splitting this file into smaller sub-modules.

The file has grown to ~1406 lines, exceeding the 1000-line guideline. Consider extracting concerns into separate modules:

  • Queue/guidance orchestration (buildSendPayload, sendPreparedMessage, sendNextQueuedMessage, etc.)
  • Message/attachment helpers (getSubtaskAttachments, normalizeAttachmentStatus, subtaskToMessage)
  • Navigation/lifecycle (selectProject, openTask, createProject, etc.)

As per coding guidelines: "File size limit: If a file exceeds 1000 lines, split it into multiple sub-modules"

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@wework/src/features/workbench/WorkbenchProvider.tsx` around lines 1 - 1406,
This file is too large—split responsibilities into focused modules: extract
queue/guidance orchestration (move buildSendPayload, sendPreparedMessage,
sendNextQueuedMessage, sendQueuedAsGuidance, sendPreparedMessage helpers,
queuedSends state and related hooks like sendCurrentInput,
sendNextQueuedMessage, cancelQueuedMessage, editQueuedMessage,
guidanceSendInFlightRef) into a workbench-sender module; extract
message/attachment helpers (getSubtaskAttachments, normalizeAttachmentStatus,
getPersistedToolBlocks, getSubtaskResult, subtaskToMessage,
sortSubtasksForDisplay, normalizeBlockStatus usage) into a
workbench-message-utils module; extract navigation/lifecycle operations
(selectProject, selectStandaloneDevice, startNewChat, startStandaloneChat,
startNewProjectChat, openTask, createProject, updateProjectName, removeProject,
archive*/rename*/list*/delete* task/project functions, refreshWorkLists,
refreshDevices) into a workbench-navigation module; keep WorkbenchProvider only
orchestrating imported hooks and wiring context value (state, dispatch, and
small glue logic), and update imports/exports accordingly so functions like
listLocalSkills, rememberExecutionDevice, and useEffect subscribers still call
into the new modules.
wework/src/components/chat/MessageList.tsx (2)

135-205: ⚖️ Poor tradeoff

Extract the shared image-preview logic to avoid duplication.

MessageImageAttachmentPreview is nearly identical to ImageAttachmentPreview in AttachmentBadges.tsx (same auth fetch, blob type check, object-URL lifecycle, mounted guard). Only the styling and data-testid differ. Consider extracting a shared hook (e.g. useAttachmentImagePreview(attachmentId)) returning { previewUrl, hasError }, leaving each component to render its own markup. This also keeps the function under the 50-line preference.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@wework/src/components/chat/MessageList.tsx` around lines 135 - 205, Extract
the duplicated image-preview logic from MessageImageAttachmentPreview and
ImageAttachmentPreview into a new hook
useAttachmentImagePreview(attachmentId:string) that returns { previewUrl,
hasError }; move fetch(getAttachmentImageUrl(attachmentId)) with auth header,
blob type check, URL.createObjectURL/URL.revokeObjectURL lifecycle and the
isMounted guard into that hook and call it from both
MessageImageAttachmentPreview and ImageAttachmentPreview, keeping each
component's rendering, data-testid and styling intact and ensuring the hook
accepts attachment.id (or string) and cleans up objectUrl on unmount.

374-378: 💤 Low value

Reuse copyText for the code-block copy.

copyText was added with a clipboard fallback (textarea + execCommand), but CodeBlock still calls navigator.clipboard.writeText directly, which throws in insecure/unsupported contexts. Consider reusing copyText here for consistent behavior.

♻️ Proposed change
   const handleCopy = () => {
-    void navigator.clipboard.writeText(text)
-    setCopied(true)
-    setTimeout(() => setCopied(false), 1500)
+    void copyText(text).then(() => {
+      setCopied(true)
+      setTimeout(() => setCopied(false), 1500)
+    })
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@wework/src/components/chat/MessageList.tsx` around lines 374 - 378, The
inline handleCopy in MessageList.tsx should use the existing copyText utility
(which implements a clipboard fallback) instead of calling
navigator.clipboard.writeText directly; replace the
navigator.clipboard.writeText call with a call to copyText(text) (await or void
as appropriate), keep the setCopied(true)/setTimeout logic, and ensure copyText
is imported where handleCopy is defined so copying works in insecure/unsupported
contexts.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@wework/src/components/chat/composer/CompactChatComposer.tsx`:
- Line 4: The import of useTranslation in CompactChatComposer.tsx is coming from
'react-i18next' but should use the app wrapper; change the import to pull
useTranslation from '`@/hooks/useTranslation`' instead of 'react-i18next' (update
the import line that currently imports useTranslation to reference the
application hook so the component uses the app-level i18n wrapper).

In `@wework/src/components/chat/ConversationQueuePanel.tsx`:
- Around line 86-91: Replace the hardcoded Chinese fallbacks in the
ConversationQueuePanel by wiring the i18n translation hook (e.g., import and
call useTranslation to get t) at the component level and use
t('common.send_failed') and t('common.expired') (or whatever key names you
choose) instead of '发送失败' and '已过期' when computing statusText; then add the
corresponding keys and translations to wework/src/i18n/locales/zh-CN/common.json
and wework/src/i18n/locales/en/common.json so both locales provide values for
those keys.

In `@wework/src/components/chat/MessageList.tsx`:
- Around line 241-242: The aria-labels in MessageList.tsx are hardcoded Chinese
strings for the copy button (aria-label using the copied boolean), which
bypasses i18n; update the component to use the existing i18n hook
(useTranslation) and replace the literals with translation lookups (e.g.,
t('copied') when copied is true and t('copyMessage') when false), or reuse the
same translation keys used by ScrollableMessageArea to keep labels consistent
for all locales.

In `@wework/src/components/common/TextInputDialog.tsx`:
- Line 92: The confirm button in TextInputDialog.tsx is using a custom-styled
<button> (the element with className="h-11 min-w-[44px] ...") but must use the
shared Button component with variant="primary"; replace the raw <button> with
the project Button component (pass variant="primary" and preserve existing props
like onClick/disabled) and remove the custom className so the dialog's primary
action follows the standardized styling and behavior.

---

Outside diff comments:
In `@wework/src/components/chat/ConversationQueuePanel.tsx`:
- Around line 1-156: Rename the file from ConversationQueuePanel.tsx to
conversation-queue-panel.tsx to follow kebab-case file naming while keeping the
exported React component names (ConversationQueuePanel and QueueRow) in
PascalCase; then update any imports throughout the codebase that reference the
old filename to import from "conversation-queue-panel" (e.g., import {
ConversationQueuePanel } from '...'), and run a quick search to ensure no
remaining references to ConversationQueuePanel.tsx remain.

---

Nitpick comments:
In `@wework/src/components/chat/MessageList.tsx`:
- Around line 135-205: Extract the duplicated image-preview logic from
MessageImageAttachmentPreview and ImageAttachmentPreview into a new hook
useAttachmentImagePreview(attachmentId:string) that returns { previewUrl,
hasError }; move fetch(getAttachmentImageUrl(attachmentId)) with auth header,
blob type check, URL.createObjectURL/URL.revokeObjectURL lifecycle and the
isMounted guard into that hook and call it from both
MessageImageAttachmentPreview and ImageAttachmentPreview, keeping each
component's rendering, data-testid and styling intact and ensuring the hook
accepts attachment.id (or string) and cleans up objectUrl on unmount.
- Around line 374-378: The inline handleCopy in MessageList.tsx should use the
existing copyText utility (which implements a clipboard fallback) instead of
calling navigator.clipboard.writeText directly; replace the
navigator.clipboard.writeText call with a call to copyText(text) (await or void
as appropriate), keep the setCopied(true)/setTimeout logic, and ensure copyText
is imported where handleCopy is defined so copying works in insecure/unsupported
contexts.

In `@wework/src/components/common/TextInputDialog.test.tsx`:
- Around line 23-24: The test currently only asserts height for the rename
dialog buttons; update the assertions for the elements identified by
getByTestId('confirm-rename-project-button') and
getByTestId('rename-project-input-cancel-button') to also assert the min-width
class 'min-w-[44px]' so the 44×44 touch-target contract is enforced (i.e., check
both 'h-11' and 'min-w-[44px]' on each relevant button).

In `@wework/src/features/workbench/WorkbenchProvider.tsx`:
- Around line 1-1406: This file is too large—split responsibilities into focused
modules: extract queue/guidance orchestration (move buildSendPayload,
sendPreparedMessage, sendNextQueuedMessage, sendQueuedAsGuidance,
sendPreparedMessage helpers, queuedSends state and related hooks like
sendCurrentInput, sendNextQueuedMessage, cancelQueuedMessage, editQueuedMessage,
guidanceSendInFlightRef) into a workbench-sender module; extract
message/attachment helpers (getSubtaskAttachments, normalizeAttachmentStatus,
getPersistedToolBlocks, getSubtaskResult, subtaskToMessage,
sortSubtasksForDisplay, normalizeBlockStatus usage) into a
workbench-message-utils module; extract navigation/lifecycle operations
(selectProject, selectStandaloneDevice, startNewChat, startStandaloneChat,
startNewProjectChat, openTask, createProject, updateProjectName, removeProject,
archive*/rename*/list*/delete* task/project functions, refreshWorkLists,
refreshDevices) into a workbench-navigation module; keep WorkbenchProvider only
orchestrating imported hooks and wiring context value (state, dispatch, and
small glue logic), and update imports/exports accordingly so functions like
listLocalSkills, rememberExecutionDevice, and useEffect subscribers still call
into the new modules.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e56c749d-41e5-411b-a8fc-796ff96534f8

📥 Commits

Reviewing files that changed from the base of the PR and between 0b3c124 and 6feac8b.

📒 Files selected for processing (35)
  • wework/src/api/attachments.ts
  • wework/src/components/chat/ChatInput.test.tsx
  • wework/src/components/chat/ChatInput.tsx
  • wework/src/components/chat/ConversationQueuePanel.tsx
  • wework/src/components/chat/MessageList.test.tsx
  • wework/src/components/chat/MessageList.tsx
  • wework/src/components/chat/ScrollableMessageArea.test.tsx
  • wework/src/components/chat/ScrollableMessageArea.tsx
  • wework/src/components/chat/composer/AddContextMenu.tsx
  • wework/src/components/chat/composer/AttachmentBadges.tsx
  • wework/src/components/chat/composer/CompactChatComposer.tsx
  • wework/src/components/chat/composer/ComposerTextarea.tsx
  • wework/src/components/chat/composer/ComposerToolbar.tsx
  • wework/src/components/chat/composer/ProjectChatComposer.tsx
  • wework/src/components/common/ActionMenu.tsx
  • wework/src/components/common/TextInputDialog.test.tsx
  • wework/src/components/common/TextInputDialog.tsx
  • wework/src/components/layout/DesktopWorkbenchLayout.test.tsx
  • wework/src/components/layout/DesktopWorkbenchLayout.tsx
  • wework/src/components/layout/DesktopWorkbenchMain.tsx
  • wework/src/components/layout/MobileWorkbenchLayout.tsx
  • wework/src/features/workbench/WorkbenchProvider.test.tsx
  • wework/src/features/workbench/WorkbenchProvider.tsx
  • wework/src/features/workbench/messageReducer.test.ts
  • wework/src/features/workbench/messageReducer.ts
  • wework/src/features/workbench/useWorkbenchAttachments.ts
  • wework/src/features/workbench/workbenchProjectChatHooks.test.tsx
  • wework/src/i18n/locales/en/common.json
  • wework/src/i18n/locales/zh-CN/common.json
  • wework/src/lib/attachments.ts
  • wework/src/pages/WorkbenchPage.tsx
  • wework/src/stream/chatStream.test.ts
  • wework/src/stream/chatStream.ts
  • wework/src/types/api.ts
  • wework/src/types/workbench.ts
💤 Files with no reviewable changes (2)
  • wework/src/features/workbench/useWorkbenchAttachments.ts
  • wework/src/components/chat/composer/AddContextMenu.tsx

import { ArrowUp, Camera, Image, Maximize2, Mic, Minimize2, Plus, Square } from 'lucide-react'
import type { ChangeEvent, ClipboardEventHandler } from 'react'
import { useEffect, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Import useTranslation from the application hook, not react-i18next.

Line 4 imports useTranslation from react-i18next, but application code must import from @/hooks/useTranslation. Only i18n infrastructure files should import from react-i18next directly.

🔧 Proposed fix
-import { useTranslation } from 'react-i18next'
+import { useTranslation } from '`@/hooks/useTranslation`'

Based on learnings: "Application code MUST import useTranslation from @/hooks/useTranslation, not from react-i18next - only i18n infrastructure files should import from react-i18next directly".

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { useTranslation } from 'react-i18next'
import { useTranslation } from '`@/hooks/useTranslation`'
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@wework/src/components/chat/composer/CompactChatComposer.tsx` at line 4, The
import of useTranslation in CompactChatComposer.tsx is coming from
'react-i18next' but should use the app wrapper; change the import to pull
useTranslation from '`@/hooks/useTranslation`' instead of 'react-i18next' (update
the import line that currently imports useTranslation to reference the
application hook so the component uses the app-level i18n wrapper).

Comment on lines +86 to +91
const statusText =
status === 'failed'
? error ?? '发送失败'
: status === 'expired'
? error ?? '已过期'
: null

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Replace hardcoded Chinese strings with i18n keys.

Lines 88 and 90 use hardcoded Chinese strings '发送失败' and '已过期' as fallback values. These should use translation keys for consistency with the rest of the codebase.

🌐 Proposed fix to use i18n

Add the translation hook at the component level and use keys:

+import { useTranslation } from '`@/hooks/useTranslation`'
+
 export function ConversationQueuePanel({
   queuedMessages,
   guidanceMessages,
   onCancelQueuedMessage,
   onSendQueuedAsGuidance,
   onEditQueuedMessage,
   onCancelGuidanceMessage,
 }: ConversationQueuePanelProps) {
+  const { t } = useTranslation('common')
+
   if (queuedMessages.length === 0 && guidanceMessages.length === 0) {
     return null
   }
 
   return (
     <div
       data-testid="conversation-queue-panel"
       className="mb-2 rounded-[18px] border border-border bg-base px-3 py-2 shadow-[0_12px_32px_rgba(0,0,0,0.06)]"
     >
       <div className="flex flex-col gap-1">
         {queuedMessages.map(message => (
           <QueueRow
             key={message.id}
             id={message.id}
             content={message.content}
             status={message.status}
             error={message.error}
             mode="queue"
+            t={t}
             onGuide={onSendQueuedAsGuidance}
             onEdit={onEditQueuedMessage}
             onCancel={onCancelQueuedMessage}
           />
         ))}
         {guidanceMessages.map(message => (
           <QueueRow
             key={message.id}
             id={message.id}
             content={message.content}
             status={message.status}
             error={message.error}
             mode="guidance"
+            t={t}
             onCancel={onCancelGuidanceMessage}
           />
         ))}
       </div>
     </div>
   )
 }
 
 interface QueueRowProps {
   id: string
   content: string
   status: QueuedWorkbenchMessage['status'] | GuidanceWorkbenchMessage['status']
   error?: string
   mode: 'queue' | 'guidance'
+  t: (key: string, fallback: string) => string
   onGuide?: (id: string) => void
   onEdit?: (id: string) => void
   onCancel?: (id: string) => void
 }
 
 function QueueRow({
   id,
   content,
   status,
   error,
   mode,
+  t,
   onGuide,
   onEdit,
   onCancel,
 }: QueueRowProps) {
   const isBusy = status === 'sending'
   const statusText =
     status === 'failed'
-      ? error ?? '发送失败'
+      ? error ?? t('workbench.queue_send_failed', '发送失败')
       : status === 'expired'
-        ? error ?? '已过期'
+        ? error ?? t('workbench.queue_expired', '已过期')
         : null

Then add the corresponding keys to wework/src/i18n/locales/zh-CN/common.json and wework/src/i18n/locales/en/common.json.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@wework/src/components/chat/ConversationQueuePanel.tsx` around lines 86 - 91,
Replace the hardcoded Chinese fallbacks in the ConversationQueuePanel by wiring
the i18n translation hook (e.g., import and call useTranslation to get t) at the
component level and use t('common.send_failed') and t('common.expired') (or
whatever key names you choose) instead of '发送失败' and '已过期' when computing
statusText; then add the corresponding keys and translations to
wework/src/i18n/locales/zh-CN/common.json and
wework/src/i18n/locales/en/common.json so both locales provide values for those
keys.

Comment on lines +241 to +242
aria-label={copied ? '已复制' : '复制消息'}
>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Hardcoded Chinese aria-labels bypass i18n.

These labels ('已复制' / '复制消息') are hardcoded while the rest of the chat UI resolves copy via useTranslation. Non-Chinese locales will get untranslated screen-reader text. Route these through t(...) like ScrollableMessageArea does for its strings.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@wework/src/components/chat/MessageList.tsx` around lines 241 - 242, The
aria-labels in MessageList.tsx are hardcoded Chinese strings for the copy button
(aria-label using the copied boolean), which bypasses i18n; update the component
to use the existing i18n hook (useTranslation) and replace the literals with
translation lookups (e.g., t('copied') when copied is true and t('copyMessage')
when false), or reuse the same translation keys used by ScrollableMessageArea to
keep labels consistent for all locales.

}
}}
className="h-8 rounded-md bg-[#14b8a6] px-4 text-[13px] font-medium leading-[18px] text-white hover:bg-[#0f9f93] disabled:opacity-50"
className="h-11 min-w-[44px] rounded-md bg-[#14b8a6] px-4 text-[13px] font-medium leading-[18px] text-white hover:bg-[#0f9f93] disabled:opacity-50"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use the dialog primary action variant for the confirm button.

The confirm action is the dialog’s primary action, but it is still implemented as a custom-styled <button> instead of using variant="primary" per the dialog button contract. Please switch this control to the shared button variant path so styling and behavior stay consistent across dialogs.

As per coding guidelines: "Primary action buttons in dialogs MUST use variant="primary" to ensure visual consistency and proper styling".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@wework/src/components/common/TextInputDialog.tsx` at line 92, The confirm
button in TextInputDialog.tsx is using a custom-styled <button> (the element
with className="h-11 min-w-[44px] ...") but must use the shared Button component
with variant="primary"; replace the raw <button> with the project Button
component (pass variant="primary" and preserve existing props like
onClick/disabled) and remove the custom className so the dialog's primary action
follows the standardized styling and behavior.

@qdaxb
qdaxb merged commit d5cd48a into wecode-ai:main Jun 3, 2026
22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants