Files
multica/docs/ui-consistency-audit.md
Jiayuan Zhang 5541819f98 refactor(ui): unify collection page patterns (#5258)
* refactor(ui): unify collection page patterns

* refactor(agents): redesign agent detail workbench (#5263)

* refactor(agents): redesign agent detail workbench

* refactor(agents): refine capability and settings surfaces

* refactor(agents): rebuild general settings form

* refactor(agents): refine overview and settings

* refactor(agents): redesign custom args editor

* docs(ui): record consistency audit
2026-07-11 21:12:04 +08:00

18 KiB
Raw Permalink Blame History

Multica UI 一致性问题与页面模式层治理

Status: Draft Owner: TBD Last updated: 2026-07-11 Related implementation: PR #5263

TL;DR

Multica 当前的主要 UI 问题不是缺少颜色 token、Button 或 Card而是缺少一层被明确命名、文档化和持续执行的 Page Pattern Layer页面模式层

现有基础大致分成三层:

  1. packages/ui/styles/ 已经提供颜色、surface、间距等设计 token。
  2. packages/ui/components/ 已经提供 Button、Input、Card、Tabs、Empty 等基础组件。
  3. packages/views/ 中也已经出现 CollectionPageHeaderCollectionPageStateSettingsTabSettingsSectionSettingsCardSettingsRow 等页面模式的早期实现。

但第三层仍然是局部的、未完成的:没有覆盖所有主要页面类型,没有清晰的使用边界,也没有 review checklist 或迁移计划。因此业务页面仍然会自行决定标题、导航、卡片、分割线、表单、空状态和保存反馈,最终形成“基础组件相同,但页面体验不同”的局面。

Agent 详情页重构是页面模式层的一次试点,不应停留在单页优化。下一步应该把其中可复用的结构提炼为明确的页面模式,再逐步迁移其他页面。


1. 文档目的

本文档用于:

  • 记录本轮 UI review 中发现的问题,避免问题只存在于对话和截图中。
  • 明确 UI 不一致的架构根因,而不是继续逐页修补 CSS。
  • 区分 Design Token、基础组件、页面模式和业务页面各自的职责。
  • 记录 Agent 详情页试点中已经处理或仍需验证的事项。
  • 给出下一阶段 UI 治理的优先级、验收标准和开放问题。

本文档不是新的视觉规范。颜色、字体、surface、间距和基础交互仍以 docs/design.md 为准。


2. 核心判断:缺失的是页面模式层

2.1 当前 UI 分层

层级 回答的问题 当前载体 当前状态
Design Token 颜色、间距、圆角、阴影应该是什么 packages/ui/styles/docs/design.md 基本完整
UI Primitive Button、Input、Card、Tabs 如何表现 packages/ui/components/ 基本完整
Page Pattern 页面标题、分区、导航、列表、设置表单、状态页如何组合 packages/views/layout/packages/views/settings/components/settings-layout.tsx 局部存在,但未固化
Business Page Agent、Issue、Runtime 等具体业务如何呈现 packages/views/<domain>/ 大量自行组合

Token 和 Primitive 只能保证局部视觉相似,不能自动保证页面一致。它们不会回答以下问题:

  • 列表页标题、数量、描述和主操作应该放在哪里?
  • 设置页应该用卡片还是平铺?一行可以放几个设置?
  • 二级导航应该横向还是纵向?什么时候需要 URL 深链?
  • Detail 页面如何区分状态概览、工作记录和配置?
  • Empty、Loading、Error、Not Found 是否共享尺寸和文案结构?
  • 可编辑列表是持续显示多个 Input还是列表 + 单个 composer
  • 保存状态、未保存提醒和离开保护如何统一?

如果这些问题没有标准答案,每个业务页面就会重新设计一次。

2.2 根因

当前问题可以概括为:

底层 token 和基础组件已经比较完整,但中间的“页面模式层”没有被明确固化,也没有被持续执行。

具体表现为:

  1. 模式没有被命名。 开发者知道有 Card、Tabs 和 Empty但不知道当前页面属于 Collection、Settings 还是 Workbench Detail。
  2. 模式没有完整覆盖。 Collection 和 Settings 已经有早期抽象Detail、Editable List、Inspector、Split Pane 等仍主要由页面自行实现。
  3. 模式没有使用边界。 什么时候用 Card、什么时候只用 spacing、什么时候允许 divider仍依赖个人判断。
  4. 模式没有持续执行。 缺少新页面 checklist、视觉回归样例和跨页面 review局部 PR 很容易重新引入平行实现。
  5. 复用多停留在 JSX。 相似页面会复制布局 class而不是复用带语义的页面组件一旦规范变化需要逐页修改。

3. 已发现的问题

3.1 全局问题

类别 当前问题 影响
页面 Header 标题高度、左右 padding、数量、描述和操作区组合不一致 页面切换时节奏跳变
二级导航 同类配置有的横向、有的纵向,有的只存在本地 state 信息架构和深链行为不稳定
Section 分组 Card、divider、背景色和纯 spacing 混用,缺少明确优先级 页面过重或分组不清
表单布局 单行单项、双列设置、label/value 比例和保存区位置不一致 扫读和操作成本增加
列表编辑 有的持续显示 Input有的用 dialog有的就地编辑 同类操作需要重新学习
状态页面 Empty、Loading、Error、Not Found 各自实现 图标、留白、文案和操作不一致
保存反馈 Toast、inline status、disabled button、dirty guard 组合不统一 用户无法稳定判断是否已保存
内容约束 长描述、代码、ID 和用户输入的换行/截断策略不统一 容易溢出或出现密集文本墙
响应式与无障碍 icon-only action、focus、移动端折叠依赖页面自行处理 容易产生不可访问或小屏失效的页面

3.2 Agent 详情页问题记录

状态说明:

  • 已实现:当前 Agent 详情页重构分支已有对应实现。
  • 试点中:已在 Agent 页面采用,但尚未抽象或推广为全局模式。
  • 待验证:需要在合并前进行完整视觉或交互回归。
  • 开放:仍需要产品或架构决策。
区域 问题 处理方向 状态
整体信息架构 原详情页更像后端字段检查器,观察、工作和配置混在一起 重组为 Overview、Work、Capabilities、Settings 试点中
二级导航 Capabilities 与 Settings 的二级选项使用横向菜单,扩展后拥挤 桌面端采用稳定的纵向 section nav并保持 URL 深链 已实现
Integrations 本地 feature flag 默认关闭Capabilities 中缺少 Integrations 根据系统配置显示 Integrations并纳入 Capabilities 已实现
Overview / Attention “Tasks Need Attention”价值不明确、优先级过高 无明确干预价值时移除,不制造伪告警 已实现
Overview / Recent Work 条目过少Issue 维度还是 Session 维度没有明确 增加可见条目;产品语义见开放问题 §8.1 试点中
Overview / Skills 多个 skill 时 divider 与下方横线粘连 优先用 spacing 分组,避免连续 divider 待验证
Instructions System Prompt 被设计成单行 Input 使用支持长文本、Markdown 和合理高度的 Textarea 已实现
MCP 描述过长,缺少换行和信息层级,呈现为密集文本墙 缩短主文案,把说明拆成辅助信息并约束宽度 已实现
General 信息展示感强不像配置页Visibility 等交互不顺手 使用标准 Settings section/row明确 label、description、control 试点中
Settings 分组 页面缺少稳定分组,或使用不符合 surface 规范的 Card 独立设置组使用白色 SettingsCard组间使用 section spacing 已实现
Settings 行布局 一行放两个 setting扫读和响应式表现差 默认单行单项;除非字段天然组成一个原子输入 已实现
Access Shared 等权限不是简单 toggle现有交互不能表达复杂规则 Access 独立为 Settings 子 Tab使用专门权限模型 试点中
Details Owner、Created、Updated 等只读元数据被放进 Settings 从可编辑设置中移出,放到 Overview 或 inspector 已实现
Environment 当前结构可暂时保留 后续迁移到统一 editable key-value pattern 开放
Custom Args 横线过多;每个参数永久显示为 Input新增一项就增加一个输入框和 divider 改为有序 token 列表;只有新增/编辑项进入 composer独立命令预览 已实现

3.3 Custom Args 暴露出的通用模式问题

Custom Args 并不只是一个局部样式问题,它暴露了 “Editable List” 页面模式缺失:

  • 数据在静止状态下应该首先是列表,不是表单。
  • 编辑态应该是临时状态,不应该让所有条目永久显示为 Input。
  • 新增操作应该把内容加入列表,而不是无限扩张表单结构。
  • 参数顺序有语义,应明确显示顺序。
  • 每个列表项对应一个 argv token包含空格的 token 不应被前端自行拆分。
  • 命令预览属于结果反馈,应和编辑列表分开呈现。

这个模式未来可以复用于Custom Args、Environment Variables、Webhook Headers、Repository Rules、Token/Secret 列表等,但不同数据类型需要保留各自的验证和敏感信息策略。


4. 建议固化的页面模式

4.1 Collection Page

适用于 Agents、Projects、Skills、Runtimes、Squads、Autopilots 等实体集合。

应统一:

  • Header 的 icon、title、count、description 和 actions。
  • 列表/网格容器的 page padding 和滚动策略。
  • Empty、Loading、Error、No Results 状态。
  • 主操作在小屏下的收缩方式。
  • 筛选、搜索和视图切换的位置。

现有基础:

  • packages/views/layout/collection-page.tsx
  • CollectionPageHeader
  • CollectionPageHeaderAction
  • CollectionPageState

下一步不是再造一套组件,而是补齐使用文档、样例和迁移覆盖。

4.2 Settings Page

适用于 Workspace Settings、Account Settings、Agent Settings 和其他配置型页面。

应统一:

  • SettingsTab → SettingsSection → SettingsCard → SettingsRow 的层级。
  • 默认单行单项;复杂 compound control 必须说明原因。
  • label、description 和 control 的宽度与对齐。
  • auto-save 与 explicit save 两种模式的反馈。
  • dirty state、离开保护、error 和 success 状态。
  • 权限不足时的只读表现。

现有基础:

  • packages/views/settings/components/settings-layout.tsx
  • SettingsTab
  • SettingsSection
  • SettingsCard
  • SettingsRow
  • SettingsSaveState

需要决定这些组件是否继续归属于 Settings domain还是迁移到更通用的 packages/views/layout/

4.3 Workbench Detail Page

适用于 Agent、Runtime、Squad、Member 等同时包含身份、状态、历史和配置的详情页。

应统一:

  • Identity header名称、状态、关键 metadata 和主操作。
  • 一级导航Overview、Work/Activity、Capabilities、Settings。
  • 二级导航:当选项超过 23 个或文案较长时使用纵向 section nav。
  • Overview 只呈现判断和行动所需的信息,不复制全部字段。
  • Settings 只放可编辑配置;只读 metadata 不混入设置。
  • URL 必须反映 tab/section 状态,支持刷新和分享。
  • 不为不存在的健康度或进度制造伪指标。

Agent 详情页是此模式的第一个试点,但不能直接把 Agent 业务组件当作全局抽象。应先识别 Runtime、Squad、Member 的共同结构,再定义最小公共 API。

4.4 Editable List

适用于用户维护一个有序或无序的小型配置集合。

默认交互:

  1. 静止状态显示列表项。
  2. 点击 Add 后只出现一个 composer。
  3. 点击 Edit 后只让目标项进入编辑态。
  4. Enter 提交Escape 取消;新增/编辑时焦点进入输入区。
  5. 删除先更新本地 draft外部持久化由统一 Save 或 auto-save 策略负责。
  6. 空状态仍保留清晰的主操作。
  7. 长值必须支持截断、换行或展开查看。

不应把所有 Editable List 都抽成一个万能业务组件。可以共享布局、状态和 action slot但验证、字段结构和安全策略留在 domain 层。

4.5 Page State

所有页面至少需要明确以下状态:

  • Initial loading
  • Background refreshing
  • Empty
  • No search results
  • Permission denied
  • Not found
  • Recoverable error
  • Fatal error

这些状态应复用一致的尺寸、语气和 action 位置,但不能用同一条空状态文案覆盖不同原因。


5. 组件归属原则

内容 推荐位置 约束
无业务语义的原子组件 packages/ui/ 不得依赖 @multica/core
跨 domain 的页面模式 packages/views/layout/ 只定义布局、slot 和交互契约
某类页面的共享模式 packages/views/<domain-or-pattern>/ 允许有限业务语义,但不得绑定平台路由
具体业务页面 packages/views/<domain>/ 组合模式并负责数据、权限和文案
Next.js / Electron 接线 app platform layer 不进入 shared views

判断一个结构是否应该抽取时,优先问:

  1. 它表达的是视觉细节,还是稳定的页面语义?
  2. 第二个真实使用者是谁?
  3. 抽取后能否减少业务页面对 spacing、divider、responsive class 的重复决策?
  4. 是否能通过 slot 保持业务差异,而不是制造大量 boolean prop

6. 下一步实施计划

Phase 0建立基线

  • 为 Collection、Settings、Workbench Detail、Editable List、Page State 各补一个 canonical example。
  • 建立页面清单,标记每个页面当前采用的模式和偏差。
  • docs/design.md 增加本文件入口。
  • 确认 Agent 详情页试点的视觉和交互验收结果。

Phase 1固化现有模式

  • 补齐 Collection Page 的 loading、filter toolbar 和 responsive 规范。
  • 明确 Settings explicit-save / auto-save 两套状态契约。
  • 从 Agent 详情页提炼最小 Workbench Detail shell而不是复制整页。
  • 提炼 Editable List 的布局契约,并用第二个真实页面验证抽象。
  • 为 pattern components 增加结构和无障碍测试。

Phase 2迁移高频页面

建议优先级:

  1. Agents / Skills / Runtimes / Projects 等 collection 页面。
  2. Workspace Settings 与 Agent Settings。
  3. Runtime / Squad / Member detail 页面。
  4. Environment、Custom Args 和其他 editable configuration lists。

每次迁移应是小 PR不在同一 PR 中同时改变业务行为和全局视觉规范。

Phase 3持续执行

  • 在 PR template 中加入 Page Pattern checklist。
  • 新页面必须声明采用的 page pattern偏离时说明原因。
  • 给 canonical examples 增加 light/dark、中文/英文和窄屏视觉回归。
  • 定期删除迁移后遗留的平行组件和重复 class 组合。
  • 将审计从一次性项目变成每个季度的 UI consistency review。

7. 验收标准

页面模式层达到可用状态,需要同时满足:

  1. 新页面可以先选择页面模式,再填充业务内容,而不是从空白 <div> 开始。
  2. 同类页面的 header、导航、section、empty/error 和 action 位置一致。
  3. 业务页面不再重复决定基础 padding、divider、card 和保存反馈。
  4. 模式组件支持 keyboard、focus、overflow、responsive 和 i18n 长文案。
  5. light/dark、中文/英文、desktop/web 至少有 canonical visual coverage。
  6. 模式允许业务差异,但偏差是显式决定,不是无意复制。
  7. 新抽象至少由两个真实页面验证,避免只为单页包装 JSX。

8. 开放问题

8.1 Agent Recent Work 使用 Issue 还是 Session 维度

需要先确认该区块回答的问题:

  • 如果回答“这个 Agent 最近交付了什么”Issue/Task 是更接近用户心智的单位。
  • 如果回答“这个 Agent 最近每次执行发生了什么”Session 是更准确的诊断单位。

建议不要在同一个平铺列表中混合两个粒度。可以默认使用 Issue/Task 维度,把最新 Session 状态作为行内 metadata完整 Session 历史留在 Work 页面。

8.2 Settings pattern 的归属

当前实现位于 packages/views/settings/components/settings-layout.tsx,但 Agent Settings 已经复用它。需要决定:

  • 保持当前位置,把 Settings 当作共享 pattern package
  • 迁移到 packages/views/layout/settings-*,让归属与实际用途一致。

在迁移前不要再创建第二套 Settings layout。

8.3 Card 与 flat section 的边界

默认遵循 docs/design.md 的容器优先级spacing → 单条 divider → 背景变化 → Card。

建议补充的判断是:

  • 独立设置组、可整体操作的信息块可以使用 Card。
  • 连续阅读内容、元数据清单和普通列表不应每项一张 Card。
  • Card 内不要再通过多层 border 制造“卡片套卡片”。

8.4 Detail pattern 的最小公共部分

Agent、Runtime、Squad 和 Member 的详情页并不完全相同。抽象前需要确认真正共享的是 shell、header、navigation 和 section layout还是还包括 inspector。原则上优先抽取稳定外壳业务内容通过 slot 注入。


9. 新页面 Review Checklist

  • 这个页面属于哪一种 page pattern
  • 是否复用了现有 Header、Section、State 和 Action 模式?
  • 是否出现了业务页面自定义的 Card、divider 或 empty state为什么
  • 设置是否默认单行单项?复合字段是否真的是一个原子输入?
  • URL 是否反映 tab、filter、pagination 或 section 等可分享状态?
  • Loading、Empty、Error、Permission 和 Not Found 是否被分别处理?
  • 长文案、长 ID、用户输入和窄屏是否不会溢出
  • icon-only button 是否有 accessible name键盘 focus 是否可见?
  • light/dark 和至少一种 CJK locale 是否完成视觉检查?
  • 是否新增了一个只服务当前页面、但其实表达通用模式的本地组件?

10. 相关文件

  • docs/design.md
  • packages/ui/styles/tokens.css
  • packages/ui/components/
  • packages/views/layout/collection-page.tsx
  • packages/views/layout/page-header.tsx
  • packages/views/settings/components/settings-layout.tsx
  • packages/views/agents/components/agent-detail-page.tsx
  • packages/views/agents/components/agent-overview-pane.tsx
  • packages/views/agents/components/tabs/custom-args-tab.tsx