Files
homeutils/docs/superpowers/specs/2026-07-31-public-ui-foundation-design.md
T
2026-07-31 19:08:42 +08:00

179 lines
8.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 公共 UI 基础能力收尾设计
日期:2026-07-31
## 目标
收拢生成、扫描和同步类插件中重复的通知、结果文件操作、任务状态展示与无障碍语义,使窗口只负责组合界面和业务用例。重构后,常见交互具有一致行为,公共代码可以独立测试,AI 修改单个插件时不需要复制或猜测平台相关实现。
本阶段不改变业务流程、输出格式和历史数据格式。
## 范围
### 本阶段实施
- 新增统一通知入口,首批迁移 MyBatis 生成器和 Git 同步。
- 统一 API 文档、Scanner、MyBatis SQL 导出的历史文件操作。
- 核对任务取消能力,只为具有真实协作式取消协议的任务显示停止按钮。
- 加强 `ExportHistoryPane`、`EmptyStatePane`、`OperationStatusPane` 的键盘、焦点和屏幕阅读器语义。
- 为 `ScanProgress`、`SqlExportProgress` 增加输入约束和稳定的展示转换。
- 增加单元测试、组件测试和架构约束测试。
### 明确不实施
- Git 评审的弹窗或窗口重构。
- 手机 UI 自动化窗口的任何重构。
- 系统设置和插件管理窗口迁移到新通知能力。
- 全局视觉主题、配色和窗口布局重做。
- 为进度 DTO 引入统一继承层次或通用事件总线。
- 把 Diff 剪贴板操作并入历史文件操作。
## 设计原则
1. 窗口不直接处理操作系统文件打开、编辑、目录定位或剪贴板细节。
2. 公共服务通过窄接口注入,测试不启动外部程序、不写系统剪贴板。
3. 通知文案由调用方表达业务含义,通知中心只负责展示方式和线程安全。
4. 只有底层任务具有真实取消能力时才展示停止按钮。
5. 不为了“统一”创建不能降低调用复杂度的抽象。
## 组件设计
### 1. NotificationCenter
在 `system.ui.notification` 下新增:
- `NotificationCenter`:窗口可依赖的接口。
- `FxNotificationCenter`:JavaFX 实现,绑定 owner,并集中创建对话框。
- `NotificationMessage`:不可变通知数据,包含级别、标题、正文;构造时拒绝空正文。
接口提供:
- `info(title, message)`
- `warning(title, message)`
- `error(title, message)`
- `confirm(title, header, message)`,返回是否确认
普通通知允许从任意线程调用;实现会调度到 JavaFX Application Thread。确认对话框必须在 JavaFX Application Thread 调用,因为它需要同步返回用户选择;违反约束时立即抛出带说明的异常,避免后台线程静默阻塞或死锁。
`FxNotificationCenter` 负责 owner、默认标题、可复制长文本和一致的关闭行为。长结果仍可使用可调整大小的文本对话框,但由通知中心实现,不再由 MyBatis 窗口自行创建 `Stage`。
首批调用方:
- MyBatis 生成器:查询/生成警告、生成结果、生成前确认。
- Git 同步:缺失远程地址警告、批量重新拉取确认。
Git 同步中“删除目录后重新 clone”的危险说明必须原样保留;本轮只替换展示机制。
### 2. ResultFileActions
在 `system.ui.history` 下新增:
- `FileActionGateway`:`open`、`edit`、`reveal`、`copyPath` 四个操作。
- `SystemFileActionGateway`:使用 `SystemOpenHelper` 和 JavaFX Clipboard 的生产实现。
- `ResultFileActions`:路径校验、异常转换、统一通知和成功反馈。
`ResultFileActions` 可生成现有 `HistoryFileCommands`,因此 `ExportHistoryPane` 不需要知道操作系统能力,也不需要改变对外构造协议。调用方可以传入一个可选的成功消息消费者,将“已复制路径”等信息写入自己的日志区;失败统一交给 `NotificationCenter`。
路径规则:
- 空路径:不调用网关,显示明确错误。
- 打开或编辑:目标必须是存在的普通文件。
- 定位目录:目标文件存在时定位该文件;目标已不存在时不得猜测父目录,显示错误。
- 复制路径:复制规范化绝对路径;目标不存在时仍允许复制,以便排查历史记录,但反馈中说明目标不存在。
API 文档、Scanner、MyBatis SQL 导出删除各自的 `openFile`、`openWithNotepad`、`openFolder` 和剪贴板代码,改为在窗口初始化时创建一次共享命令对象。
### 3. 进度与取消语义
保留领域 DTO,不增加通用进度接口:
- `ScanProgress`:正文不可为空;进度必须是 `-1`(不确定)或 `[0, 1]`。
- `SqlExportProgress`:`current`、`total`、`recordCount` 不得为负,`current` 不得大于 `total`,项目名不可为空;`fraction()` 保持在 `[0, 1]`。
DTO 只表达领域进度,并提供展示所需的稳定 message/fraction。用例把 DTO 值报告给 `OperationContext`,窗口不再重复拼接进度文案;DTO 的边界和展示结果独立测试。
Scanner 没有中断协议,保持不显示停止按钮。MyBatis SQL 导出已经通过 `ExportCallback.isCancelled()` 在项目边界读取 `OperationContext.isCancellationRequested()`,属于真实的协作式取消,因此保留停止按钮。测试必须证明取消请求能传递到回调,且界面只在运行阶段显示停止按钮。
### 4. 公共组件无障碍语义
`ExportHistoryPane`:
- “打开”“目录”按钮设置明确的 accessible text;tooltip 作为补充而非唯一说明。
- 右键菜单保留,同时支持表格行获得焦点后通过键盘打开文件。
- 行为空时清除 tooltip、accessible text 和旧行引用,避免 TableCell 复用泄漏上一个条目。
- 操作失败后焦点留在触发控件,不强制跳转。
`EmptyStatePane`:
- 容器使用可读的无障碍角色描述。
- 标题和说明组合为完整 accessible text。
- 有操作按钮时,按钮进入正常 Tab 顺序;无操作时容器不抢占键盘焦点。
`OperationStatusPane`:
- 进度条和状态文案设置 accessible text。
- 状态变化时同步可读文本,不只依赖颜色表达成功或失败。
- 不可取消时,不创建可聚焦的停止按钮;可取消时只在运行阶段显示并进入 Tab 顺序。
本阶段用代码语义和现有主题常量检查颜色使用,不进行全主题颜色重做。若发现现有公共组件直接使用低对比硬编码颜色,只在该组件内修正。
## 数据与调用流
文件操作流程:
`ExportHistoryPane -> HistoryFileCommands -> ResultFileActions -> FileActionGateway`
其中 `ResultFileActions` 负责验证和错误翻译,网关只执行平台动作。窗口只提供 owner 和可选日志消费者。
通知流程:
`Window / ResultFileActions -> NotificationCenter -> JavaFX dialog`
业务异常在最接近业务语境的调用方转换成用户文案;通知中心不解析异常、不拼接业务名称,也不记录敏感值。
## 错误处理
- 公共服务捕获平台操作的已知运行时异常,展示稳定的中文动作描述,并保留异常消息作为附加信息。
- 不吞掉编程错误:空依赖、非法 DTO 和错误线程上的确认调用立即失败。
- 通知内容不得包含数据源密码、令牌或带凭据的远程 URL。
- Git 重新拉取的删除与 clone 逻辑不移动到通知中心,也不因弹窗重构改变执行顺序。
## 测试策略
### 单元测试
- `ResultFileActionsTest`:四种委托、空路径、文件不存在、网关异常、复制不存在路径及成功反馈。
- `NotificationMessageTest`:字段规范化和非法输入。
- 进度 DTO 测试:边界值、非法值和 fraction。
- 进度展示转换测试:初始、中间、结束及记录数文案。
### JavaFX 组件测试
- `ExportHistoryPane` 的按钮、tooltip、accessible text、键盘触发和 TableCell 复用清理。
- `EmptyStatePane` 的无操作/有操作焦点行为。
- `OperationStatusPane` 的可取消与不可取消结构、状态文字和可见性。
### 架构约束
- API 文档、Scanner、MyBatis SQL 导出不得直接调用 `SystemOpenHelper` 或 JavaFX Clipboard。
- MyBatis 生成器和 Git 同步不得直接创建 `Alert`。
- 排除项不纳入此约束,避免本阶段误改 Git 评审、手机 UI 自动化、系统设置。
### 验收
- 全量 Maven 测试通过。
- Maven compile 通过。
- `git diff --check` 通过。
- 只读 UI 冒烟检查确认三个历史列表、MyBatis 生成确认/结果和 Git 同步确认仍可正常交互。
- 不启动文件、编辑器、资源管理器或危险 Git 重拉操作来完成自动化验证;平台动作由测试替身验证。
## 实施顺序
1. 先以测试定义通知接口及线程约束,再实现并迁移两个窗口。
2. 以测试定义文件动作规则,再迁移三个历史窗口。
3. 补强进度 DTO,修正 SQL 导出取消语义。
4. 补齐三个公共组件的无障碍行为。
5. 运行架构测试、全量验证和只读 UI 验收。
每一步保持可独立编译和回滚,不把未完成的半套公共接口留给后续步骤。