Skip to content

UI Audit: 添加 .NET 仓库(friendly duplicate toast / add-flow detect copy / add-button busy) - #99

Closed
sperictao wants to merge 2 commits into
mainfrom
ui/add-dotnet-repo-audit
Closed

sperictao wants to merge 2 commits into
mainfrom
ui/add-dotnet-repo-audit

Conversation

@sperictao

Copy link
Copy Markdown
Owner

UI/UX Audit — 添加 .NET 仓库

Draft stacked PR,禁止自动 merge。审计报告全文本地见 docs/agent/ui-audit-add-dotnet-repo/AUDIT_REPORT.mddocs/agent/ 按仓库约定不入库);Before/After GIF/PNG 由 ui-audit-add-dotnet-repo workflow 以 artifact 形式上传。

范围

  • 本轮:主页(仓库面板)→ 添加仓库(+)→ 目录选择 → dotnet 自动检测 → 入库 → 列表/选中/发布面板验证
  • 不处理:EditRepositoryDialog、移除仓库、排序、发布配置编辑

用户操作路径(Before/After 完全一致)

+ 按钮(title=添加仓库) → 目录选择(mock) → detect_repository_provider → 扫描分支/项目候选 → add_repository → 验证列表/选中/toast。四个场景:A 成功添加、B 检测失败、A2 注入 1.4s 检测延迟、C 重复路径。

Baseline 已确认缺陷(产品)

  1. C 重复路径:toast 直接显示序列化错误对象 Error: {"code":"repository_exists",...}(真实 Tauri 下为 String(err),更不可读)。
  2. B 检测失败:toast 引导「可手动选择 Provider」,但全 UI 无任何手动选择入口(恢复入口计数 0);且文案含 pom.xml/Java/Gradle,与 .NET 添加场景错位(与编辑对话框共享 key 所致)。
  3. A2 慢检测:1.4s 检测期间 + 按钮无 disabled/aria-busy/spinner,用户会认为点击无效。

正确业务语义(保持):添加成功自动选中新仓库、发布面板切换、成功 toast 含名称、无乐观更新、重复路径数据无损、取消目录静默返回。

修复(最小范围)

  • useRepositoryActions.runtime.tsextractInvokeErrorCode 识别 repository_exists → 「仓库已存在」+ 路径;其余错误用 extractInvokeErrorMessage;添加流程检测失败改用专用 key(不再引导不存在的入口;编辑对话框原 key 保留)。
  • RepositoryList.tsx:+ 按钮添加期间 disabled + aria-busy + Loader 图标,完成恢复;补 aria-labelonAddRepo 允许 Promise。
  • i18n zh/en:app.repositoryAlreadyExistsapp.addRepoProviderDetectUnsupported(Desc)repositoryList.addRepositoryInProgress
  • 测试基建(非产品):mock-tauri 与真实契约对齐(plugin:dialog|open、detect 返回字符串/path 参数、branches 按 path、candidates 按 startPath、add_repository 返回 AppState + repository_exists reject 对象);新增 capture spec(默认 skip)与 workflow。

Focused Test

  • 单测 useRepositoryActions.runtime.test.ts:6/6(新增 repository_exists 友好提示、专用检测文案 2 例)
  • e2e specs/11-add-repository.spec.ts:4/4(成功+自动选中、重复路径不泄漏原始错误、失败文案无误导入口、busy 状态出现与恢复)

After(同路径强断言,全绿)

A:新行 + aria-pressed="true";B:toast 含「未添加仓库…」不含「可手动选择 Provider」且恢复入口 0;A2:检测中 disabled=true + aria-busy="true",完成恢复;C:toast「仓库已存在 / 路径」无 JSON。

Quality

  • tsc --noEmit ✓ | Vitest 467/467 ✓ | check:i18n 100% ✓ | lint 0 errors ✓ | format:check
  • e2e 全量:67 passed + 4 skipped(capture-only);4 个失败(09-geist-prototype ×2、publish-config-floating-drift、10-provider-operations 发布后打包)在 main@2e03d3f8 干基线同样失败,属既有失败,非本轮回归
  • Rust:clippy ✓;cargo test 1 个既有失败(automation::tests::bindings_keep_their_revision…,本轮零 Rust 改动,main 同样失败)
  • UI Audit workflow:PR paths 触发 + workflow_dispatch 按 baseline/after 上传录制 artifact

Final head

26be9519(本 PR 全部提交)

人工关键帧结论(After)

spinner 替换 + 图标无布局挤压;toast 文案清晰无 JSON 残留;Focus/Scroll 无跳变;仅影响目标功能。

sperictao added a commit that referenced this pull request Sep 11, 2026
测试基建合并自 ui-audit(add-dotnet-repo)(PR #99),使 e2e 真正能跑通
添加仓库的完整用户路径,此前 mock 与真实契约不符、且缺少目录选择器,
该路径实际无 e2e 覆盖。

- tests/e2e/fixtures/mock-tauri.ts
  - 新增 dialogOpenPath 选项,响应 plugin:dialog|open/ask/message
  - add_repository 对齐 store/commands.rs:重复路径抛 repository_exists,
    成功后自动选中新仓库并返回新 AppState
  - detect_repository_provider 修正为真实契约(path → 裸 provider id 字符串,
    此前是 repoPath → 对象,会让 repo.providerId 变成对象并导致渲染崩溃)
  - scan_repository_branches / scan_project_candidates 对齐前端契约
    (path / startPath)
- 新增 tests/e2e/specs/11-add-repository.spec.ts
  覆盖成功入库并自动选中、重复目录的可读文案、未识别 Provider 时照常
  落库并开放手动选择、慢检测期间按钮 busy 四条回归语义
- 新增 tests/e2e/capture-add-repository.spec.ts 与
  .github/workflows/ui-audit-add-repository.yml
  可复现的录制与证据上传(workflow_dispatch,或相关路径变更的 PR 触发)
@sperictao

Copy link
Copy Markdown
Owner Author

测试基建已并入 #98,关闭本 PR(两者是同一功能的重复实现,不应同时合并)。

已并入 #98 的部分(测试基建)

  • tests/e2e/fixtures/mock-tauri.tsdialogOpenPathplugin:dialog|open/ask/messageadd_repositoryrepository_exists 语义与自动选中、detect_repository_provider 的真实契约、scan_repository_branches(path) / scan_project_candidates(startPath)
  • tests/e2e/specs/11-add-repository.spec.ts:真实覆盖添加仓库的回归用例
  • 录制 spec + ui-audit-add-repository.yml:可复现的证据生成(已泛化为 add-repository,去掉 dotnet 限定)

未并入的部分(产品语义分歧)
本 PR 在 Provider 检测失败时选择「不落库 + 改文案」;#98 选择「照常落库 + 自动打开编辑窗口手动选择 Provider」,因为后者让原本不存在的「手动选择」入口变成真实可用(#98 的 H2)。合并以 #98 的语义为准,因此 spec 11 与 capture 的第 3 条断言按 #98 语义改写。

顺带一提:本 PR 的 CI 与 #98 一样是 quality pass / rust fail,两者互为佐证 —— 那条 Rust 失败是 origin/main 自带的问题,已记录到 #101

@sperictao

Copy link
Copy Markdown
Owner Author

测试基建已并入 #98

@sperictao sperictao closed this Sep 11, 2026
sperictao added a commit that referenced this pull request Sep 11, 2026
* fix(repository): 修复「添加 Java 仓库」审计发现的 15 项交互问题

对「添加仓库」流程做了一轮 UI/UX 审计(3 P0 / 7 P1 / 5 P2),本次按最小改动收敛全部问题,
不改变业务语义。

P0
- H1 慢速检测期间无任何反馈:先把 toast.loading 占位,成功/失败复用同一 toast id 演进;
  按钮进入 disabled + aria-busy + spinner,并用并发守卫避免重复弹目录选择器。
- H2 Maven 项目(provider 检测失败)不再死路:仍落库,并在列表中打开编辑弹窗手动选择 Provider。
- H3 错误提示暴露序列化负载:统一走 extractInvokeErrorMessage / 失败原因分类器;
  重复目录给出「该目录已添加为仓库「xxx」」的可读文案。

P1
- M1 搜索过滤生效时添加仓库后新行不可见:添加成功后清空搜索词。
- M2 provider 徽标显示原始 id:改为展示 provider 显示名(如 Java (Gradle))。
- M3 成功提示信息不完整:描述改为 `Java (Gradle) · main · /path`。
- M4 空态缺少入口:文案修正为「点击上方 + 添加仓库」并补 action 按钮。
- M5 按钮层级混乱:统一 listActionButtonClass,仓库计数降级为纯文本。
- M6 路径归一化缺失:前后端同时按尾部分隔符/空白/大小写(Windows)归一化后判重。
- M7 重复点击无守卫:改用 useRef 并发守卫。

P2
- L1 仓库 id 用时间戳可能碰撞:改用 crypto.randomUUID()。
- L2 detect 仅 unsupported_provider 放行,其余失败按分类给出可读原因。
- L3 目录选择器 IPC 异常未捕获:try/catch 并给出提示。
- L4 providerId 为空时不再发起无效的候选扫描 IPC。
- L5 添加成功后主区空白:刷新态骨架衔接,不再白屏。

顺带
- check-i18n-coverage.mjs 修正块注释内 CJK 被误报为硬编码文案的问题。
- 补齐 configPanel.automation* 缺失的 i18n key,check:i18n 恢复 100%。

验证
- pnpm typecheck / pnpm test(494 passed)/ pnpm check:i18n(100%)/ pnpm check:design 均通过
- cargo test --lib(411 passed)/ cargo clippy 无新增告警
- Playwright After 录制 9/9 passed(与 Baseline 相同用户路径)

* chore: ignore the local .ui-audit/ and .workbuddy/ workspaces

.ui-audit/ 存放 UI/UX 审计的录制脚本、截图与自包含报告(约 12MB),
属于本地证据而非源码;.workbuddy/ 是本地 agent 状态目录,与仓库里已忽略的
.claude/ .codex/ .cursor/ 等属同一类。两者此前悬空未跟踪,容易误提交。

* test(e2e): 补全「添加仓库」的 e2e 基建与回归用例

测试基建合并自 ui-audit(add-dotnet-repo)(PR #99),使 e2e 真正能跑通
添加仓库的完整用户路径,此前 mock 与真实契约不符、且缺少目录选择器,
该路径实际无 e2e 覆盖。

- tests/e2e/fixtures/mock-tauri.ts
  - 新增 dialogOpenPath 选项,响应 plugin:dialog|open/ask/message
  - add_repository 对齐 store/commands.rs:重复路径抛 repository_exists,
    成功后自动选中新仓库并返回新 AppState
  - detect_repository_provider 修正为真实契约(path → 裸 provider id 字符串,
    此前是 repoPath → 对象,会让 repo.providerId 变成对象并导致渲染崩溃)
  - scan_repository_branches / scan_project_candidates 对齐前端契约
    (path / startPath)
- 新增 tests/e2e/specs/11-add-repository.spec.ts
  覆盖成功入库并自动选中、重复目录的可读文案、未识别 Provider 时照常
  落库并开放手动选择、慢检测期间按钮 busy 四条回归语义
- 新增 tests/e2e/capture-add-repository.spec.ts 与
  .github/workflows/ui-audit-add-repository.yml
  可复现的录制与证据上传(workflow_dispatch,或相关路径变更的 PR 触发)

* fix(repository): 编辑窗口自动探测 Provider 失败时不再重复弹错

添加仓库时若未识别到 Provider,会照常落库并自动打开编辑窗口;
而编辑窗口打开后会立即自动探测一次,失败即再弹一条
「未识别到支持的 Provider」,与刚刚给出的「已添加仓库,请手动选择 Provider」
互相矛盾(StrictMode 下会重复成两条)。

给 handleDetectRepoProviderRuntime 增加 silentFailure 选项,仅用于窗口
打开时的首次自动探测——触发它的流程已经把结果告知用户了。
用户手动点击「检测」仍保留错误反馈。
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.

1 participant