feat(ux): toast 智能行动按钮 + 拓展 ⓘ 到 gateway/agents + sidebar 加术语表入口

延续上一轮小白 UX 改造的尾声三连:

## 1. toast 智能行动按钮(U2 收尾)
- humanizeError 输出新增 action 字段:{ label, route?, handler?, kind }
- 自动按错误 kind 给默认按钮:
  · gatewayDown → [去启动 Gateway] → /services
  · cmdMissing / permission → [打开设置] → /settings
  · auth → [检查 API Key] → /models
  · network / timeout / rateLimit / generic → 不给(重试由用户控制)
- toast 结构化分支渲染 .toast-action-btn 按钮,点击后用 navigate(route) 或调 handler,并自动关闭 toast
- common.js 加 errorAction.* 三个按钮文案 i18n(11 语言)

## 2. ⓘ 拓展到 gateway / agents
- gateway.js: token label 后加 ⓘ(apikey 术语),renderConfig 末尾 attachTermTooltips
- agents.js: addAgent 弹窗 workspace 字段 label 加 ⓘ,setTimeout 扫 document.body 绑定
- term-tooltip.js 精简表新增 4 个术语:workspace / provider / baseurl + scope(已有)

## 3. sidebar 加术语表入口
- 在两个引擎(OpenClaw + Hermes)的最后一个 section 加「术语」条目
- sidebar.js i18n 新增 glossary 键(11 语言)
- 之前只能从 dashboard quick-actions 进入,现在 sidebar 永久可达

## 4. 顺手 bug 修复
- gateway.js 文件末尾历史残留的多余 `}` (line 348) syntax 错误,删除
- 与之前 hermes/cron.js 同类问题,本次改 ⓘ 时被 node --check 暴露

## 累计变动
- 10 个文件修改
- 7 个新 i18n 键(11 语言)
- Build OK
This commit is contained in:
晴天
2026-05-14 03:47:25 +08:00
parent e710db6ffb
commit 7eababad4a
10 changed files with 73 additions and 6 deletions

View File

@@ -88,10 +88,19 @@ function toRawString(e) {
return String(e)
}
// 不同错误类型默认对应的行动按钮label 走 i18nroute 直接跳转)
const DEFAULT_ACTIONS = {
gatewayDown: { labelKey: 'common.errorAction.startGateway', route: '/services' },
cmdMissing: { labelKey: 'common.errorAction.openSettings', route: '/settings' },
permission: { labelKey: 'common.errorAction.openSettings', route: '/settings' },
auth: { labelKey: 'common.errorAction.checkApiKey', route: '/models' },
// network / timeout / busy / rateLimit / notFound / generic不给默认 action重试由用户自己控制
}
/**
* @param {unknown} e - 原始错误Error / string / Tauri Result
* @param {string} [context] - 操作上下文文案(如 t('channels.saveFailed')
* @returns {{ message: string, hint: string, raw: string }}
* @returns {{ message: string, hint: string, raw: string, action?: { label, route?, handler? } }}
*/
export function humanizeError(e, context) {
const raw = toRawString(e).trim()
@@ -111,8 +120,14 @@ export function humanizeError(e, context) {
const message = ctx || t(`common.error.${kind}`)
const hint = t(`common.errorHint.${kind}`)
const result = { message, hint, raw: rawTruncated, kind }
return { message, hint, raw: rawTruncated }
const defaultAction = DEFAULT_ACTIONS[kind]
if (defaultAction) {
result.action = { label: t(defaultAction.labelKey), route: defaultAction.route }
}
return result
}
/**

View File

@@ -59,6 +59,21 @@ const TERMS = {
en: { name: 'Scope (Permissions)', desc: 'A whitelist of what the bot is allowed to do — read messages, send messages, manage members, etc. Too few = missing features; too many = security risk.' },
zhTW: { name: '權限範圍Scope', desc: '機器人能做什麼的「白名單」—— 例如讀訊息、發訊息、改群成員等。Scope 給少了功能不足,給多了有安全風險。' },
},
workspace: {
zhCN: { name: 'Workspace工作目录', desc: 'Agent 用来读写文件的「文件夹」。每个 Agent 可以指定独立的工作目录,互不干扰,避免误删别的 Agent 的资料。' },
en: { name: 'Workspace', desc: 'The "folder" the Agent reads/writes files in. Each Agent can have its own workspace so they don\'t accidentally touch each other\'s files.' },
zhTW: { name: 'Workspace工作目錄', desc: 'Agent 用來讀寫檔案的「資料夾」。每個 Agent 可以指定獨立的工作目錄,互不干擾,避免誤刪別的 Agent 的資料。' },
},
provider: {
zhCN: { name: 'Provider服务商', desc: '给你提供 AI 模型的厂商 —— 比如 OpenAI、Anthropic、DeepSeek、Qwen 等。每个 Provider 通常对应一个 API key。' },
en: { name: 'Provider', desc: 'A company that supplies AI models — OpenAI, Anthropic, DeepSeek, Qwen, etc. Each provider usually maps to one API key.' },
zhTW: { name: 'Provider服務商', desc: '給你提供 AI 模型的廠商 —— 例如 OpenAI、Anthropic、DeepSeek、Qwen 等。每個 Provider 通常對應一個 API key。' },
},
baseurl: {
zhCN: { name: 'Base URL接口地址', desc: '服务商 API 的「门牌号」—— 比如 `https://api.openai.com/v1`。换 Provider 时通常要改这个地址。' },
en: { name: 'Base URL', desc: 'The "address" of the provider\'s API — e.g. `https://api.openai.com/v1`. You change this when switching providers.' },
zhTW: { name: 'Base URL介面位址', desc: '服務商 API 的「門牌號」—— 例如 `https://api.openai.com/v1`。換 Provider 時通常要改這個位址。' },
},
}
function pickLang(item) {