Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 91 additions & 0 deletions design-qa.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,97 @@

final result: passed

# Wework 工作区标签设计 QA

## 目标

- 参考图与实现对照:`docs/assets/images/wework-workspace-tabs-reference-comparison.png`(左侧为用户提供的设计图,右侧为真实 Tauri 实现)。
- 实现范围:Wework 顶层任务 / 项目空间文档标签、项目名标题、关闭与恢复、新窗口。
- 验证环境:macOS 真实 Tauri 隔离实例,浅色主题;主窗口 1280×720;独立项目窗口 1280×800。
- 测试数据:隔离环境内创建本地项目“产品规划”,不读取或修改用户的个人项目数据。

## 对照结果

- 完整审查链:`docs/assets/images/wework-workspace-tabs-review-chain.png`
- 最小权限独立窗口实机图:`docs/assets/images/wework-workspace-tabs-minimal-capability.png`
- 标题栏高度、文档标签宽度、圆角连接、关闭按钮、加号位置与参考方向一致。
- 标题栏使用稳定浅灰底色,选中标签使用内容表面色;未选中标签留在标题栏层,状态差异清晰。
- 顶层产品名统一为“项目空间”;具体项目打开后标签标题显示项目名,例如“产品规划”。
- 主窗口与独立项目窗口均无裁切、重叠、错误边框或圆角断裂。

## 逐用例 QA 记录

| 用例 | 前置条件与精确步骤 | 预期结果 | 实际结果、负向与恢复验证 | 证据 |
| ---------------- | ----------------------------------------------------------- | ---------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | ------------------------------------- |
| 初始与切换选中态 | 启动隔离实例;同时保留“任务”和项目标签;依次点击两个标签 | 只有活动标签使用白色内容表面、加粗文字与连接圆角,未选中标签停留在灰色标题栏 | 通过;首尾标签的连接圆角均未被滚动容器裁切,切换后 ARIA 选中态同步 | 审查链 01、05 |
| 打开顶层项目空间 | 点击 `+`,再点击“项目空间” | 菜单贴近触发器且不越界;打开的顶层标签标题为“项目空间” | 通过;重复打开会复用现有文档而非生成重复标签 | 审查链 02、03;重复文档单测 |
| 打开具体项目 | 在隔离实例创建“产品规划”,从项目空间进入该项目 | 活动标签立即显示“产品规划”,不继续显示顶层产品名 | 通过;创建结果直接更新活动文档,避免异步列表刷新造成旧标题 | 审查链 04;项目标题单测 |
| 关闭与回退 | 激活“产品规划”,点击其关闭按钮 | 项目标签消失,活动文档稳定回退到“任务” | 通过;E2E 使用轮询等待真实 DOM 移除,覆盖 WebView 延迟更新 | 审查链 06;桌面 E2E |
| 恢复已关闭标签 | 完成上一用例后按 `⌘⇧T` | “产品规划”恢复并成为活动标签 | 通过;若原文档 ID 已被占用,会生成新 ID 后恢复,避免覆盖现有文档 | 审查链 07;恢复冲突单测 |
| 拖动排序 | 拖动项目标签跨过相邻标签 | 标签顺序更新,活动文档不变 | 通过;WebKit `dragover` 无法读取 `dataTransfer` 时使用已提升的拖动状态恢复排序 | 拖动回归单测 |
| 键盘上下文菜单 | 聚焦标签并按 `Shift+F10`,检查菜单项并关闭 | 菜单在视口内显示,可键盘进入;关闭按钮和菜单使用中英文可访问名称 | 通过;同时覆盖 Context Menu 键入口和菜单边界夹取 | 审查链 08;键盘/本地化单测 |
| 独立项目窗口 | 在项目标签菜单选择“在新窗口中打开”,等待新 WebView 完整渲染 | 独立窗口标题与标签均显示“产品规划”,内容完整且窗口控件可用 | 通过;创建失败或等待超时会销毁残留窗口;权限仅保留窗口控制、窗口生命周期事件监听/解绑与日志能力 | 审查链 09;最小权限实机图;Tauri 单测 |
| 多窗口截图确定性 | 同时存在主窗口和项目窗口时执行工作区截图命令 | 优先捕获当前聚焦的工作区窗口;无焦点时捕获最近创建的窗口 | 通过;Rust 排序与回退路径编译、测试通过 | 工作区截图命令测试 |

## 清理

- 结束验证后停止隔离 Tauri 会话并清理其 Executor 进程组与临时认证链接。
- “产品规划”仅存在于隔离测试数据;运行时原始截图保留在被 Git 忽略的 `wework/test-results/`,仓库只提交对照图和审查联系表。

## 缺陷审查

- P0:选中与未选中标签底色过于接近。已拆分标题栏和活动标签表面色,并重新截图验证。
- P0:新建项目后标签仍显示“项目空间”。已改为直接使用创建结果更新活动标签,真实流程与单测均通过。
- P1:右键菜单只能依赖鼠标。已增加 Shift+F10 / Context Menu 键入口。
- P1:动态项目窗口无法纳入隔离截图链。已增加工作区窗口 WebView 截图命令并验证。
- P2:未发现。

## 最终结论

final result: passed

---

# Workspace Document Tabs Follow-up Review

## Source and implementation evidence

- Repository-accessible source/implementation comparison:
`docs/assets/images/wework-workspace-tabs-reference-comparison.png` (source on the left,
real-Tauri implementation on the right).
- Repository-accessible core-flow review chain:
`docs/assets/images/wework-workspace-tabs-review-chain.png`.
- Repository-accessible real-Tauri project window under the minimal capability:
`docs/assets/images/wework-workspace-tabs-minimal-capability.png`.
- Environment: isolated real Tauri app on macOS in light theme; 1280×720 main window and
1280×800 project window.
- Test data: a local project named “产品规划”, created only inside the isolated verification
environment.

## Case-level verification

| Case | Preconditions and exact steps | Expected | Actual, negative, and recovery coverage | Evidence |
| ----------------------- | ------------------------------------------------------------ | ----------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------- |
| Active/inactive states | Keep Task and project documents open; click each tab in turn | Only the active tab joins the white content surface; inactive tabs remain on the muted titlebar | Passed; ARIA selection followed focus and neither end cap was clipped | Review chain 01, 05 |
| Open project spaces | Click `+`, then “项目空间” | A clamped menu opens and the top-level document is titled “项目空间” | Passed; opening the same document again reuses it | Review chain 02, 03; duplicate-document unit test |
| Open a concrete project | Create and enter “产品规划” | The active title changes immediately to the concrete project name | Passed; the create result updates the document before an asynchronous list refresh | Review chain 04; project-title unit test |
| Close and fallback | Activate “产品规划” and press its close control | The project tab is removed and Task becomes active | Passed; desktop E2E polls for real WebView DOM removal | Review chain 06; desktop E2E |
| Restore | After closing, press `Cmd+Shift+T` | “产品规划” returns as the active document | Passed; an occupied historical ID is replaced with a fresh ID | Review chain 07; collision-recovery unit test |
| Reorder | Drag a project tab across its neighbor | Order changes without changing the active document | Passed; lifted drag state recovers WebKit `dragover` events with empty transfer data | Drag regression unit test |
| Keyboard context menu | Focus a tab and press `Shift+F10` | The menu opens inside the viewport with localized accessible names | Passed; Context Menu key and viewport clamping are also covered | Review chain 08; keyboard/i18n unit tests |
| New window | Choose “Open in new window” and wait for the new WebView | The new window renders “产品规划” completely with working chrome | Passed; create errors and readiness timeouts destroy partial windows; capability is limited to window controls, lifecycle listen/unlisten, and logging | Review chain 09; minimal-capability capture; Tauri tests |
| Deterministic capture | Capture while main and project windows both exist | Capture the focused workspace, or the newest one when none is focused | Passed in Rust sorting/fallback coverage | Workspace capture command test |

## Cleanup and result

- The isolated Tauri session, Executor process group, and temporary authentication link were
removed after verification.
- Runtime screenshots remain under ignored `wework/test-results/`; only the comparison and review
contact sheet are committed for reviewer and CI access.
- No actionable P0, P1, or P2 visual mismatch remains.

final result: passed

## Dropdown alignment follow-up

- Source visual truth: `/Users/axb-mac/.wegent-executor/workspace/attachments/draft/1785311314363/image.png`
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions docs/en/wework/workbench.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ sidebar_position: 5

# Coding workbench

## Use top-level tabs

The Wework desktop app uses top-level tabs for tasks, project spaces, agents, and other product pages. Sidebar links navigate within the active tab. A new tab is created only when you select the top-bar **+** or another explicit new-tab action from a tab menu.

When many tabs are open, the tab list scrolls horizontally while the **+** and the rightmost feedback button remain visible. A project-space tab can also be opened in a separate window from its context menu.

## Files and terminals

The right workspace displays project files, previews, and change reviews. Multi-root projects show a folder selector in the Files tab. Switching folders changes only the file-tree and preview root; it does not change the execution directory used by the task, terminal, or conversation.

Local file and directory links in an AI response open in the Files tab. File links can jump to referenced lines, while directory links make that directory the file-tree root. In the macOS desktop app, the Files tab's **Open** and **Open location** actions support both files and directories.
Expand Down
6 changes: 6 additions & 0 deletions docs/zh/wework/workbench.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ sidebar_position: 5

# 代码工作台

## 使用顶部标签页

Wework 桌面版使用顶部标签页承载任务、项目空间、智能体和其他功能页面。点击侧边栏链接时,页面会在当前标签页内切换;只有点击顶部 **+** 或使用标签页菜单中的明确新建操作时,才会创建新的标签页。

标签页较多时,标签列表会水平滚动,顶部 **+** 和最右侧的反馈按钮始终保持可见。项目空间标签页也可以通过右键菜单在独立窗口中打开。

## 文件与终端

右侧工作区用于浏览项目文件、预览内容和审核变更。多目录项目会在文件标签中显示文件夹选择器;切换文件夹只改变文件树和预览根目录,不会改变任务、终端或对话使用的执行目录。
Expand Down
45 changes: 45 additions & 0 deletions wework/e2e/desktop/task-flow.e2e.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3184,6 +3184,48 @@ async function captureVerificationScreenshot(control, name, selector = 'body') {
return screenshotPath
}

async function verifyWorkspaceDocumentTabs(control) {
await control.command('waitFor', '[data-testid="workspace-tab-strip"]', {
timeoutMs: DEFAULT_STEP_TIMEOUT_MS,
})
await control.command('waitFor', '[data-tab-kind="task"][aria-selected="true"]', {
text: '任务',
timeoutMs: DEFAULT_STEP_TIMEOUT_MS,
})

await control.command('click', '[data-testid="workspace-tab-add"]')
await control.command('waitFor', '[data-testid="workspace-tab-add-menu"]', {
timeoutMs: DEFAULT_STEP_TIMEOUT_MS,
})
await control.command('click', '[data-testid="workspace-tab-add-board"]')
await control.command('waitFor', '[data-tab-kind="board"][aria-selected="true"]', {
timeoutMs: DEFAULT_STEP_TIMEOUT_MS,
})
await control.command('waitFor', '[data-testid="cloud-todo-workspace"]', {
timeoutMs: DEFAULT_STEP_TIMEOUT_MS,
})
await captureVerificationScreenshot(control, 'workspace-tabs-01-project-spaces-active.png')

await control.command(
'click',
'[data-testid^="workspace-tab-select-task-"]'
)
await control.command('waitFor', '[data-tab-kind="task"][aria-selected="true"]', {
text: '任务',
timeoutMs: DEFAULT_STEP_TIMEOUT_MS,
})
await control.command(
'click',
'[data-testid^="workspace-tab-close-board-"]'
)
await waitForSnapshot(
control,
snapshot => !snapshot.testIds.some(testId => testId.startsWith('workspace-tab-board-')),
'Closing the project-space document tab did not remove it from the titlebar'
)
await captureVerificationScreenshot(control, 'workspace-tabs-02-task-restored.png')
}

async function verifyCloudWorkPage(control) {
await control.command('navigate', 'body', { value: '/cloud-work' })
await control.command('waitFor', '[data-testid="cloud-work-page"]', {
Expand Down Expand Up @@ -10979,6 +11021,9 @@ last_updated = "2026-07-30T00:00:00Z"`

if (shouldRunDesktopCheckpoint('core-task-flow')) {
if (!GUIDANCE_SCROLL_ONLY) {
phase = 'workspace-document-tabs'
await verifyWorkspaceDocumentTabs(control)

phase = 'automation-lifecycle'
await verifyAutomationLifecycle(control, workspacePath)

Expand Down
6 changes: 4 additions & 2 deletions wework/scripts/ai-verify.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const corsHeaders = {
function usage() {
console.error(`Usage:
pnpm --filter wework ai:verify start
pnpm --filter wework ai:verify <capture|capture-popout|snapshot|debug|click|click-at|click-then-macrotask|seed-local-project|reload|close-to-tray|request-close|dismiss-popout|drag|drop-file|drop-paths|fill|hover|metrics|navigate|paste-paths|pointer-move|press|scroll-into-view|select-text|show-popout|system-drag-drop|wait-for|window-focus-snapshot|text|status|stop> --session PATH [options]
pnpm --filter wework ai:verify <capture|capture-popout|capture-workspace|snapshot|debug|click|click-at|click-then-macrotask|seed-local-project|reload|close-to-tray|request-close|dismiss-popout|drag|drop-file|drop-paths|fill|hover|metrics|navigate|paste-paths|pointer-move|press|scroll-into-view|select-text|show-popout|system-drag-drop|wait-for|window-focus-snapshot|text|status|stop> --session PATH [options]

Options:
--codex-home-initialization true
Expand Down Expand Up @@ -401,6 +401,7 @@ async function main() {
const action = {
capture: 'capture',
'capture-popout': 'capturePopoutWindow',
'capture-workspace': 'captureWorkspaceWindow',
snapshot: 'snapshot',
debug: 'getWorkbenchDebugSnapshot',
click: 'click',
Expand Down Expand Up @@ -438,6 +439,7 @@ async function main() {
options.selector ??
(command === 'capture' ||
command === 'capture-popout' ||
command === 'capture-workspace' ||
command === 'snapshot' ||
command === 'debug' ||
command === 'click-at' ||
Expand Down Expand Up @@ -490,7 +492,7 @@ async function main() {
effectiveTimeoutMs
)
}
if (command === 'capture' || command === 'capture-popout') {
if (command === 'capture' || command === 'capture-popout' || command === 'capture-workspace') {
if (!options.output) throw new Error('--output is required')
const prefix = 'data:image/png;base64,'
if (!value.value?.startsWith(prefix)) throw new Error('Invalid screenshot payload')
Expand Down
23 changes: 23 additions & 0 deletions wework/src-tauri/capabilities/workspace-window.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "workspace-window",
"description": "Allows project-space document windows to manage only their own window chrome.",
"windows": ["workspace-*"],
"permissions": [
"core:event:allow-listen",
"core:event:allow-unlisten",
"core:window:allow-close",
"core:window:allow-destroy",
"core:window:allow-set-focus",
"core:window:allow-show",
"core:window:allow-start-dragging",
"core:window:allow-unminimize",
"core:window:allow-minimize",
"core:window:allow-maximize",
"core:window:allow-unmaximize",
"core:window:allow-toggle-maximize",
"core:window:allow-is-maximized",
"core:window:allow-is-fullscreen",
"log:default"
]
}
Loading
Loading