Skip to content

Comments

fix(chatui): add copy rollback path and error message.#5352

Merged
Soulter merged 3 commits intoAstrBotDevs:masterfrom
hanbings:fix/copy-button
Feb 23, 2026
Merged

fix(chatui): add copy rollback path and error message.#5352
Soulter merged 3 commits intoAstrBotDevs:masterfrom
hanbings:fix/copy-button

Conversation

@hanbings
Copy link
Contributor

@hanbings hanbings commented Feb 22, 2026

fixes: #5351

ChatUI 里“复制消息/代码块”在部分浏览器/HTTP 场景下会因剪贴板权限或用户手势限制导致复制失败,但之前失败时缺少用户可见提示(仅有 console 输出),用户无法感知结果。本改动为复制失败补齐 toast 提示与按钮失败状态反馈。

Modifications / 改动点

  • This is NOT a breaking change. / 这不是一个破坏性变更。

dashboard/src/components/chat/MessageList.vue 中调整了复制功能的执行路径,优先使用同步方法避免过早消耗用户手势上下文;并添加了错误 toast 和错误消息 i18n。

Screenshots or Test Results / 运行截图或测试结果

复制成功:

image

复制失败:

image

通过在 chrome console 中使用 document.execCommand = () => false 阻止使用 document.execCommand 且 chrome 设置禁用 Clipboard API 即可复现失败分支


Checklist / 检查清单

  • 😊 如果 PR 中有新加入的功能,已经通过 Issue / 邮件等方式和作者讨论过。/ If there are new features added in the PR, I have discussed it with the authors through issues/emails, etc.
  • 👀 我的更改经过了良好的测试,并已在上方提供了“验证步骤”和“运行截图”。/ My changes have been well-tested, and "Verification Steps" and "Screenshots" have been provided above.
  • 🤓 我确保没有引入新依赖库,或者引入了新依赖库的同时将其添加到了 requirements.txtpyproject.toml 文件相应位置。/ I have ensured that no new dependencies are introduced, OR if new dependencies are introduced, they have been added to the appropriate locations in requirements.txt and pyproject.toml.
  • 😮 我的更改没有引入恶意代码。/ My changes do not introduce malicious code.

Summary by Sourcery

改进 ChatUI 中对消息和代码块的复制到剪贴板行为,提供更健壮的回退方案,并向用户清晰展示复制成功/失败的反馈。

Bug 修复:

  • 通过添加更可靠的复制执行路径,修复在受限剪贴板环境中 ChatUI 消息和代码复制失败的问题。

增强功能:

  • 为 ChatUI 复制按钮添加可视化的成功/失败状态和本地化工具提示,并通过 toast 通知展示复制结果。
  • 优化在复制复合机器人消息时的文本提取,以更好地处理纯文本、媒体标记以及各种边缘情况。
Original summary in English

Summary by Sourcery

Improve ChatUI copy-to-clipboard behavior for messages and code blocks with robust fallbacks and user-visible success/failure feedback.

Bug Fixes:

  • Fix ChatUI message and code copy failures in restricted clipboard environments by adding a more reliable copy execution path.

Enhancements:

  • Add visual success/failure states and localized tooltips for ChatUI copy buttons and surface copy results via toast notifications.
  • Refine text extraction when copying composite bot messages to better handle plain text, media markers, and edge cases.

@dosubot dosubot bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Feb 22, 2026
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @hanbings, 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!

此拉取请求解决了 ChatUI 中复制消息或代码块因浏览器权限或用户手势限制而失败时,用户无法收到通知的问题。本次更改引入了带有回退机制的健壮剪贴板处理、成功和失败复制操作的视觉反馈(包括 Toast 提示和动态按钮图标/标题),并改进了这些消息的国际化。这通过清晰地传达复制操作的结果,显著提升了用户体验。

Highlights

  • 视觉反馈: 在 ChatUI 中为复制成功和失败操作实现了视觉反馈,包括 Toast 提示和按钮状态变化。
  • 剪贴板逻辑优化: 重构了剪贴板复制逻辑,优先使用同步的 document.execCommand 以提高兼容性和保留用户手势上下文,并回退到 navigator.clipboard.writeText
  • 国际化支持: 为复制相关消息添加了国际化支持,包括新增的“复制失败”消息。
Changelog
  • dashboard/src/components/chat/MessageList.vue
    • 更新了复制按钮以显示成功/失败状态
    • 集成了 Toast 通知系统
    • 引入了 copyFailedMessages 状态来跟踪复制失败尝试
    • 重构了剪贴板复制方法,包括同步回退和更好的错误处理
    • 添加了用于构建复制文本和管理复制状态的新实用函数
    • 根据操作结果实现了复制按钮的动态图标和标题更新
    • 为复制失败按钮状态添加了 CSS 样式
  • dashboard/src/i18n/locales/en-US/core/common.json
    • 添加了“copyFailed”翻译键
  • dashboard/src/i18n/locales/zh-CN/core/common.json
    • 添加了“复制失败”翻译键
Activity
  • 此拉取请求目前没有活动记录。
Using Gemini Code Assist

The 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 /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

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 .gemini/ folder in the base of the repository. Detailed instructions can be found here.

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

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@dosubot
Copy link

dosubot bot commented Feb 22, 2026

Related Documentation

Checked 1 published document(s) in 1 knowledge base(s). No updates required.

How did I do? Any feedback?  Join Discord

@dosubot dosubot bot added the feature:chatui The bug / feature is about astrbot's chatui, webchat label Feb 22, 2026
Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey - 我发现了 1 个问题,并给出了一些整体层面的反馈:

  • tryExecCommandCopy 中,如果在 textarea 已经被追加到文档后 document.execCommand('copy') 抛出异常,那么该元素将不会被移除;可以考虑把 removeChild 调用移到 finally 块中,这样无论成功还是失败都能清理 DOM 节点。
  • 复制成功/失败的处理目前分散在 copyTextToClipboardcopyCodeToClipboardcopyBotMessage 中(包括 toast、状态标志、按钮标题);建议集中到一个单一的辅助函数中,由它返回一个结构化的结果,并在一个地方统一更新 UI/toast,以避免消息复制与代码复制之间的逻辑重复和行为偏差。
给 AI Agent 的提示
Please address the comments from this code review:

## Overall Comments
- In `tryExecCommandCopy`, if `document.execCommand('copy')` throws after the textarea is appended, the element is never removed; consider moving the `removeChild` call into a `finally` block so it always cleans up DOM nodes on both success and failure.
- The copy success/failure handling is now split between `copyTextToClipboard`, `copyCodeToClipboard`, and `copyBotMessage` (toasts, state flags, button titles); consider centralizing this into a single helper that returns a structured result and updates UI/toasts in one place to avoid duplicated logic and drifting behavior between message and code copying.

## Individual Comments

### Comment 1
<location> `dashboard/src/components/chat/MessageList.vue:503-510` </location>
<code_context>
-            }).catch(err => {
-                console.error('复制失败:', err);
-                // 如果现代API失败,使用传统方法
+        tryExecCommandCopy(text) {
+            try {
                 const textArea = document.createElement('textarea');
-                textArea.value = code;
+                textArea.value = text;
                 document.body.appendChild(textArea);
+                textArea.focus();
                 textArea.select();
+                const ok = document.execCommand('copy');
+                document.body.removeChild(textArea);
+                return ok;
</code_context>

<issue_to_address>
**issue (bug_risk):** The fallback copy implementation can leak the temporary textarea node if `execCommand` throws.

In `tryExecCommandCopy`, the textarea is created and appended inside the `try`, but if `document.execCommand('copy')` throws, control jumps to `catch` and the node is never removed, so failed attempts will accumulate hidden textareas. Move the cleanup to a `finally` block (or equivalent) so the textarea is always removed, regardless of success or failure.
</issue_to_address>

Sourcery 对开源项目免费——如果你觉得我们的代码审查有帮助,欢迎分享 ✨
帮我变得更有用!请在每条评论上点击 👍 或 👎,我会根据你的反馈改进后续的代码审查。
Original comment in English

Hey - I've found 1 issue, and left some high level feedback:

  • In tryExecCommandCopy, if document.execCommand('copy') throws after the textarea is appended, the element is never removed; consider moving the removeChild call into a finally block so it always cleans up DOM nodes on both success and failure.
  • The copy success/failure handling is now split between copyTextToClipboard, copyCodeToClipboard, and copyBotMessage (toasts, state flags, button titles); consider centralizing this into a single helper that returns a structured result and updates UI/toasts in one place to avoid duplicated logic and drifting behavior between message and code copying.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `tryExecCommandCopy`, if `document.execCommand('copy')` throws after the textarea is appended, the element is never removed; consider moving the `removeChild` call into a `finally` block so it always cleans up DOM nodes on both success and failure.
- The copy success/failure handling is now split between `copyTextToClipboard`, `copyCodeToClipboard`, and `copyBotMessage` (toasts, state flags, button titles); consider centralizing this into a single helper that returns a structured result and updates UI/toasts in one place to avoid duplicated logic and drifting behavior between message and code copying.

## Individual Comments

### Comment 1
<location> `dashboard/src/components/chat/MessageList.vue:503-510` </location>
<code_context>
-            }).catch(err => {
-                console.error('复制失败:', err);
-                // 如果现代API失败,使用传统方法
+        tryExecCommandCopy(text) {
+            try {
                 const textArea = document.createElement('textarea');
-                textArea.value = code;
+                textArea.value = text;
                 document.body.appendChild(textArea);
+                textArea.focus();
                 textArea.select();
+                const ok = document.execCommand('copy');
+                document.body.removeChild(textArea);
+                return ok;
</code_context>

<issue_to_address>
**issue (bug_risk):** The fallback copy implementation can leak the temporary textarea node if `execCommand` throws.

In `tryExecCommandCopy`, the textarea is created and appended inside the `try`, but if `document.execCommand('copy')` throws, control jumps to `catch` and the node is never removed, so failed attempts will accumulate hidden textareas. Move the cleanup to a `finally` block (or equivalent) so the textarea is always removed, regardless of success or failure.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

本次 PR 修复了剪贴板复制功能在某些情况下会静默失败的问题,做得很好。新的复制逻辑通过 document.execCommandnavigator.clipboard.writeText 提供了更可靠的回退机制,并且为复制成功和失败都增加了明确的用户反馈(Toast 提示和按钮状态),显著提升了用户体验。代码结构清晰,重构合理。我提出了一些关于颜色值的小建议,主要是为了增强主题一致性,希望对你有帮助。

@dosubot dosubot bot added the lgtm This PR has been approved by a maintainer label Feb 23, 2026
@Soulter Soulter merged commit c1009ad into AstrBotDevs:master Feb 23, 2026
6 checks passed
astrbot-doc-agent bot pushed a commit to AstrBotDevs/AstrBot-docs that referenced this pull request Feb 23, 2026
@astrbot-doc-agent
Copy link

Generated docs update PR (pending manual review):
AstrBotDevs/AstrBot-docs#140
Trigger: PR merged


AI change summary:

  • zh/use/webui.md 新增 "ChatUI" 章节,介绍管理面板内置 ChatUI 的复制功能。
  • 详细说明复制消息特性:支持复制复合消息(含文本、图片/音频占位符),代码块右上角支持一键复制。
  • 补充功能细节:自动适配浏览器环境优先同步复制,以及 Toast 提示和按钮状态反馈。
  • 同步更新英文文档 en/use/webui.md

Experimental bot notice:

  • This output is generated by AstrBot-Doc-Agent for review only.
  • It does not represent the final documentation form.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature:chatui The bug / feature is about astrbot's chatui, webchat lgtm This PR has been approved by a maintainer size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] 局域网 IP 下 Chat UI 中复制按钮复制消息时失败,且无失败提示

2 participants