From 566fec9f56a8fcdcb72eb9f2fd58f400bbae8804 Mon Sep 17 00:00:00 2001 From: weichen Date: Sun, 11 Oct 2026 17:52:27 +0000 Subject: [PATCH] Register the audit workspace builtin so its entry is reachable Why: buildWorkspaceEntries pushed only BUILTINS[0] (agents); the U4 rdm-audit workspace was declared but never ranked, so no user could open the trace/audit workspace from the sidebar. Evidence: vitest workspaces.test.ts 4/4 (updated expectations plus a new overflow-truncation case); full browser run in scripts/e2e.sh. Impact: sidebar gains the second builtin tool; server-declared workspaces keep their shortcut precedence. Refs: U4 (Dev #368) regression; task feature/rdm-e2e-acceptance. --- e2e/rdm-audit.playwright.ts | 9 ++++----- src/workspaces.ts | 1 + test/workspaces.test.ts | 22 ++++++++++++++++------ 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/e2e/rdm-audit.playwright.ts b/e2e/rdm-audit.playwright.ts index 172795c..fe0a4c0 100644 --- a/e2e/rdm-audit.playwright.ts +++ b/e2e/rdm-audit.playwright.ts @@ -36,14 +36,13 @@ async function login(page: Page) { await page.getByPlaceholder('初始密码或常用密码').fill(PASSWORD2) await page.getByRole('button', { name: '登录', exact: true }).click() } - // 登录成功后左侧体系工具栏出现「追溯审计」入口。 - await expect(page.locator('button[title^="追溯审计"]')).toBeVisible({ timeout: 15_000 }) + // 登录成功后侧栏体系工具出现「追溯审计」入口。 + await expect(page.locator('.tsb-tool', { hasText: '追溯审计' })).toBeVisible({ timeout: 15_000 }) } async function openAudit(page: Page) { - // 左栏默认展开且展开态无体系工具入口:先收起(⌘B 按钮进入 icon 轨)。 - await page.locator('button[title="收起侧栏(⌘B)"]').click() - await page.locator('button[title^="追溯审计"]').click() + // 展开态侧栏底部的体系工具条(tsb-tool,name=标题)。 + await page.locator('.tsb-tool', { hasText: '追溯审计' }).click() await expect(page.getByText('追溯审计').first()).toBeVisible() await expect(page.locator('.rdm-audit-project')).toBeVisible() } diff --git a/src/workspaces.ts b/src/workspaces.ts index 3735611..92631d0 100644 --- a/src/workspaces.ts +++ b/src/workspaces.ts @@ -57,6 +57,7 @@ export function buildWorkspaceEntries(server: WorkspaceSource[]): WorkspaceEntry return 99 } ranked.push({ rank: takeFree(1), entry: BUILTINS[0] }) + ranked.push({ rank: takeFree(2), entry: BUILTINS[1] }) for (const entry of unranked) ranked.push({ rank: takeFree(9), entry }) return ranked .filter(item => item.rank <= 9) diff --git a/test/workspaces.test.ts b/test/workspaces.test.ts index 2c7423a..34472fd 100644 --- a/test/workspaces.test.ts +++ b/test/workspaces.test.ts @@ -1,19 +1,20 @@ import { describe, expect, it } from 'vitest' import { buildWorkspaceEntries } from '../src/workspaces' -// 三栏工作台(2026-10-11):文件浏览并入第三栏「文件」入口,体系工具只补「代理」。 +// 三栏工作台(2026-10-11):文件浏览并入第三栏「文件」入口;体系工具内置 +// 「代理」与「追溯审计」(U4 修复:第二个 builtin 此前未入列,入口不可达)。 describe('buildWorkspaceEntries', () => { - it('没有领域插件时,代理补在 ⌘1', () => { + it('没有领域插件时,代理补 ⌘1、追溯审计补 ⌘2', () => { const entries = buildWorkspaceEntries([]) - expect(entries.map(e => `${e.shortcut} ${e.title}`)).toEqual(['⌘1 代理']) + expect(entries.map(e => `${e.shortcut} ${e.title}`)).toEqual(['⌘1 代理', '⌘2 追溯审计']) }) it('声明了 shortcut 的工作区占住该位,内置工具让位', () => { const entries = buildWorkspaceEntries([ { id: 'trace', title: '追溯网', shortcut: '1' }, ]) - expect(entries.map(e => e.title)).toEqual(['追溯网', '代理']) - expect(entries.map(e => e.shortcut)).toEqual(['⌘1', '⌘2']) + expect(entries.map(e => e.title)).toEqual(['追溯网', '代理', '追溯审计']) + expect(entries.map(e => e.shortcut)).toEqual(['⌘1', '⌘2', '⌘3']) expect(entries[0].key).toBe('ws:trace') }) @@ -21,6 +22,15 @@ describe('buildWorkspaceEntries', () => { const entries = buildWorkspaceEntries([ { id: 'mem', title: '记忆库' }, ]) - expect(entries.map(e => e.title)).toEqual(['代理', '记忆库']) + expect(entries.map(e => e.title)).toEqual(['代理', '追溯审计', '记忆库']) + }) + + it('九位占满时低序内置保留,溢出项截断', () => { + const server = Array.from({ length: 8 }, (_, i) => ({ id: `w${i}`, title: `w${i}`, shortcut: String(i + 1) })) + const entries = buildWorkspaceEntries(server) + // ⌘1–8 被声明占住;代理取 ⌘9;追溯审计溢出截断(slice 0,9)。 + expect(entries.filter(e => e.key.startsWith('ws:'))).toHaveLength(8) + expect(entries.map(e => e.title)).toContain('代理') + expect(entries.map(e => e.title)).not.toContain('追溯审计') }) })