Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
62 changes: 34 additions & 28 deletions apps/desktop/e2e/accessibility-coverage.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,18 +142,21 @@ test('module pages and global overlays expose named actionable controls', async
await page.keyboard.press('Escape');
});

test('data-backed conversation exposes ordered todos and keyboard access to tools, models, and Graph', async ({
test('data-backed conversation exposes an open workbar face and keyboard access to tools, models, and Graph', async ({
accessibilityNarrativeWindow: page,
}) => {
const cdp = await page.context().newCDPSession(page);
await expect(page.getByRole('region', { name: /对话:/ })).toBeVisible();
const todoRegion = page.getByRole('region', { name: '任务待办' });
await expect(todoRegion).toBeVisible();
await expect(todoRegion.getByRole('listitem')).toHaveText([
'补齐桌面端无障碍覆盖',
'核对模型选择器的键盘路径',
'确认工具结果可以展开阅读',
]);
// The scenario opens a face beside the transcript so the AX sweep below sees
// the workbar's own tree, not an empty column. Which face is incidental — it
// was the Task face until that face was retired — so this asserts the strip
// reports one, rather than reaching into the face's contents.
const workbar = page.getByRole('complementary', { name: '任务工作栏' });
await expect(workbar).toBeVisible();
await expect(workbar.getByRole('tab', { name: '变更' })).toHaveAttribute(
'aria-selected',
'true',
);
await assertAxHealth(cdp, 'conversation/data-backed');

await expect(page.getByRole('main')).toHaveCount(1);
Expand Down Expand Up @@ -277,35 +280,38 @@ test('composer and workbar entry points expose named actionable controls', async
await expect(page.getByRole('list', { name: '打开工具' })).toBeVisible();
await assertAxHealth(cdp, 'workbar/launcher');

const workbarPanels = [
'侧边对话',
'变更',
'终端',
'浏览器',
'生成文件',
'待办',
'追踪',
] as const;
for (const panel of workbarPanels) {
await page
.getByRole('list', { name: '打开工具' })
.getByRole('button', { name: new RegExp(`^${panel}(?: |$)`) })
.click();
// Registry order, minus the Task face this shell retired. The launcher is
// the empty state, so it opens the first face and then goes away; every face
// after it is opened from the [+] menu, which is the only entry point once a
// face is on screen. The faces stay open behind one another — the strip is a
// `tablist` now, so each one has to keep reporting its own tab.
const workbarPanels = ['侧边对话', '变更', '终端', '浏览器', '生成文件', '追踪'] as const;
for (const [index, panel] of workbarPanels.entries()) {
if (index === 0) {
await page
.getByRole('list', { name: '打开工具' })
.getByRole('button', { name: new RegExp(`^${panel}(?: |$)`) })
.click();
} else {
await page.getByRole('button', { name: '打开或关闭工作栏的面' }).first().click();
const faceMenu = page.getByRole('menu');
await expect(faceMenu).toBeVisible();
await assertAxHealth(cdp, `workbar/face-menu/${panel}`);
await faceMenu.getByRole('menuitem', { name: panel, exact: true }).click();
// The menu stays open on select, so that one pick can close a face as
// well as open one. Dismiss it before reading the panel underneath.
await page.keyboard.press('Escape');
await expect(faceMenu).toBeHidden();
}
const activeTab = page.getByRole('tab', { name: new RegExp(panel) });
await expect(activeTab).toBeVisible();
await expect(activeTab).toHaveAttribute('aria-selected', 'true');
if (panel === '终端') {
await expect(page.getByRole('region', { name: '任务终端' })).toBeVisible();
} else if (panel === '浏览器') {
await expect(page.getByRole('region', { name: '嵌入式浏览器' })).toBeVisible();
} else if (panel === '待办') {
await expect(page.getByRole('region', { name: '任务待办' })).toBeVisible();
}
await assertAxHealth(cdp, `workbar/${panel}`);
if (panel !== workbarPanels.at(-1)) {
await page.getByRole('button', { name: '打开工作栏标签' }).first().click();
await expect(page.getByRole('list', { name: '打开工具' })).toBeVisible();
}
}
});

Expand Down
4 changes: 2 additions & 2 deletions apps/desktop/e2e/fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -799,8 +799,8 @@ export const test = base.extend<E2eTestFixtures, E2eWorkerFixtures>({
showWindow: true,
}, use);
},
// A data-backed conversation with settled tool evidence and a populated
// task ledger. Shown because the accessibility journey follows real native
// A data-backed conversation with settled tool evidence and the workbar open
// beside it. Shown because the accessibility journey follows real native
// focus order through the transcript into the composer controls.
accessibilityNarrativeWindow: async ({}, use) => {
await withE2eWindow({
Expand Down
30 changes: 20 additions & 10 deletions apps/desktop/e2e/session-workbar.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -324,9 +324,16 @@ test('titlebar workbar action restores an existing tool instead of the picker',
const safeAreaToggleBox = await collapseButton.boundingBox();
expect(safeAreaToggleBox).not.toBeNull();

await page.getByRole('button', { name: '打开工作栏标签' }).click();
// [+] is a menu over the panel now, not a swap to the launcher: the face you
// are reading stays on screen while you pick another one.
await page.getByRole('button', { name: '打开或关闭工作栏的面' }).click();
const faceMenu = page.getByRole('menu');
await expect(faceMenu).toBeVisible();
await expect(panel).toBeVisible();
await page.keyboard.press('Escape');
await expect(faceMenu).toBeHidden();
const picker = page.getByRole('list', { name: '打开工具' });
await expect(picker).toBeVisible();
await expect(picker).not.toBeVisible();

await collapseButton.click();
const expandButton = workspaceActions.getByRole('button', { name: '展开任务工作栏' });
Expand Down Expand Up @@ -440,19 +447,22 @@ test('Side Chat survives collapse, confirms close, and cleans up on source switc
await page.getByRole('button', { name: '展开任务工作栏' }).click();
await expect(companion).toBeVisible();

const workbarToolbar = page.getByRole('toolbar', { name: '任务工作栏标签' }).first();
const closeActiveSideChat = () =>
workbarToolbar
.getByRole('tab', { selected: true })
.locator('..')
.getByRole('button', { name: /^关闭/ });
await closeActiveSideChat().click();
// Closing is the same [+] menu that opens: the face already on screen carries
// a checkmark, and picking it again asks to close it.
const closeActiveSideChat = async () => {
await page.getByRole('button', { name: '打开或关闭工作栏的面' }).first().click();
await page
.getByRole('menu')
.getByRole('menuitem', { name: '侧边对话', exact: true })
.click();
};
await closeActiveSideChat();
const confirmation = page.getByRole('dialog');
await expect(confirmation).toContainText('这个临时侧边对话会被永久删除');
await confirmation.getByRole('button', { name: '取消' }).click();
await expect(companion).toBeVisible();

await closeActiveSideChat().click();
await closeActiveSideChat();
await confirmation.getByRole('button', { name: '关闭侧边对话' }).click();
await expect(companion).toHaveCount(0);
await expect
Expand Down
12 changes: 7 additions & 5 deletions apps/desktop/e2e/settings.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,13 +123,15 @@ test('settings hides expanded workbar chrome and restores it on close', async ({
const workbar = page.locator('.maka-session-workbar[data-placement="right"]');
const workbarToolbar = workbar.getByRole('toolbar', { name: '任务工作栏标签' });
await expect(workbarToolbar).toBeVisible();
await expect(workbarToolbar.getByRole('button', { name: '打开工作栏标签' })).toBeVisible();
await expect(
workbarToolbar.getByRole('button', { name: '打开或关闭工作栏的面' }),
).toBeVisible();
await expect(workbarToolbar.getByRole('button', { name: '收起任务工作栏' })).toBeVisible();
await page
.getByRole('button', { name: /待办.*查看和维护这个任务的待办台账/ })
.getByRole('button', { name: /变更.*查看当前 Git 工作区变化/ })
.click();
const taskTab = workbarToolbar.getByRole('tab', { name: '待办' });
await expect(taskTab).toBeVisible();
const openFaceTab = workbarToolbar.getByRole('tab', { name: '变更' });
await expect(openFaceTab).toBeVisible();

await ensureSidebarExpanded(page);
await page.getByRole('button', { name: '设置' }).click();
Expand All @@ -138,7 +140,7 @@ test('settings hides expanded workbar chrome and restores it on close', async ({

await page.keyboard.press('Escape');
await expect(workbarToolbar).toBeVisible();
await expect(taskTab).toBeVisible();
await expect(openFaceTab).toBeVisible();
});

test('wide settings gutters scroll the whole main pane', async ({ window: page }) => {
Expand Down
4 changes: 0 additions & 4 deletions apps/desktop/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,6 @@
"@astryxdesign/core": "0.5.2",
"@astryxdesign/theme-neutral": "0.5.2",
"@babel/parser": "7.29.7",
"@dnd-kit/core": "^6.3.1",
"@dnd-kit/sortable": "^10.0.0",
"@fontsource-variable/geist": "^5.3.0",
"@fontsource-variable/geist-mono": "^5.3.0",
"@maka/ui": "0.1.0",
Expand Down Expand Up @@ -102,8 +100,6 @@
"@ant-design/icons-svg",
"@astryxdesign/core",
"@astryxdesign/theme-neutral",
"@dnd-kit/core",
"@dnd-kit/sortable",
"@fontsource-variable/geist",
"@fontsource-variable/geist-mono",
"@maka/ui",
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/renderer-architecture.json
Original file line number Diff line number Diff line change
Expand Up @@ -450,7 +450,7 @@
"./theme": 1
},
"importSpecifiers": 1,
"nonTriviaTokens": 672
"nonTriviaTokens": 666
},
"src/renderer/app-shell-effects.ts": {
"importDeclarations": 12,
Expand Down
141 changes: 0 additions & 141 deletions apps/desktop/resources/licenses/npm/THIRD_PARTY_NOTICES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -813,126 +813,6 @@ THE SOFTWARE.

================================================================================

Package: @dnd-kit/accessibility@3.1.1
Declared license: MIT
Selected license: MIT
Repository: git+https://github.com/clauderic/dnd-kit.git#packages/accessibility

--- LICENSE ---
MIT License

Copyright (c) 2021, Claudéric Demers

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

================================================================================

Package: @dnd-kit/core@6.3.1
Declared license: MIT
Selected license: MIT
Repository: git+https://github.com/clauderic/dnd-kit.git#packages/core

--- LICENSE ---
MIT License

Copyright (c) 2021, Claudéric Demers

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

================================================================================

Package: @dnd-kit/sortable@10.0.0
Declared license: MIT
Selected license: MIT
Repository: git+https://github.com/clauderic/dnd-kit.git#packages/sortable

--- LICENSE ---
MIT License

Copyright (c) 2021, Claudéric Demers

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

================================================================================

Package: @dnd-kit/utilities@3.2.2
Declared license: MIT
Selected license: MIT
Repository: git+https://github.com/clauderic/dnd-kit.git#packages/utilities

--- LICENSE ---
MIT License

Copyright (c) 2021, Claudéric Demers

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

================================================================================

Package: @formatjs/fast-memoize@3.1.7
Declared license: MIT
Selected license: MIT
Expand Down Expand Up @@ -13739,27 +13619,6 @@ SOFTWARE.

================================================================================

Package: tslib@2.8.1
Declared license: 0BSD
Selected license: 0BSD
Repository: https://github.com/Microsoft/tslib.git

--- LICENSE.txt ---
Copyright (c) Microsoft Corporation.

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.

================================================================================

Package: tuf-js@6.0.0
Declared license: MIT
Selected license: MIT
Expand Down
Loading
Loading