Why: The three-column workbench redesign converges entries and hierarchy: project switching tops the left rail (identity shown once), sessions and search stay centered, files/workspaces/account sink to the bottom. The right column becomes a Work/Files third column that absorbs the preview pane, which is no longer an independent fourth region; the artifacts workspace overlay folds into the Files entry, and stop control consolidates into the input area with a light fast/slow-lane status hint. Evidence: make test-frontend NOT_RUN at commit time; the run and its outcome are recorded in the Dev task card before integration. Impact: App.tsx layout and divider width tiers (work 280-560, files with open preview 420-1100); store UI state rightTab work/files plus filesView with syncFilesEntry replacing syncPreviewRail; Workbench dual entry; PreviewPane gains a back-to-list control; TaskSidebar project switcher; TopBar drops project identity; Conversation drops the header stop button and gains the input status line; workspaces.ts drops the artifacts builtin. Refs: three-column workbench proposal (2026-10-11), DESIGN.md 6/9.3 revision follows in the Dev repo.
66 lines
1.9 KiB
TypeScript
66 lines
1.9 KiB
TypeScript
// 体系工具排位:服务端声明的工作区对所有用户可见,按 shortcut 数字占位;
|
|
// 内置「代理」补进空位。文件浏览在第三栏「文件」入口(方案:入口收敛),不再占体系工具位。
|
|
// 插件管理面板不进这条清单。
|
|
|
|
export interface WorkspaceEntry {
|
|
key: string
|
|
title: string
|
|
icon: string
|
|
shortcut: string
|
|
}
|
|
|
|
export interface WorkspaceSource {
|
|
id: string
|
|
title: string
|
|
icon?: string
|
|
shortcut?: string
|
|
}
|
|
|
|
const BUILTINS: Omit<WorkspaceEntry, 'shortcut'>[] = [
|
|
{ key: 'agents', title: '代理', icon: '🤖' },
|
|
]
|
|
|
|
function shortcutNum(raw?: string): number | null {
|
|
if (!raw) return null
|
|
const m = raw.match(/(\d)/)
|
|
if (!m) return null
|
|
const n = Number(m[1])
|
|
return n >= 1 && n <= 9 ? n : null
|
|
}
|
|
|
|
export function buildWorkspaceEntries(server: WorkspaceSource[]): WorkspaceEntry[] {
|
|
const used = new Set<number>()
|
|
const ranked: { rank: number; entry: Omit<WorkspaceEntry, 'shortcut'> }[] = []
|
|
const unranked: Omit<WorkspaceEntry, 'shortcut'>[] = []
|
|
for (const w of server) {
|
|
const entry = { key: `ws:${w.id}`, title: w.title, icon: w.icon || '🗂' }
|
|
const n = shortcutNum(w.shortcut)
|
|
if (n && !used.has(n)) {
|
|
used.add(n)
|
|
ranked.push({ rank: n, entry })
|
|
} else {
|
|
unranked.push(entry)
|
|
}
|
|
}
|
|
const takeFree = (prefer: number): number => {
|
|
if (!used.has(prefer) && prefer >= 1 && prefer <= 9) {
|
|
used.add(prefer)
|
|
return prefer
|
|
}
|
|
for (let n = 1; n <= 9; n++) {
|
|
if (!used.has(n)) {
|
|
used.add(n)
|
|
return n
|
|
}
|
|
}
|
|
return 99
|
|
}
|
|
ranked.push({ rank: takeFree(1), entry: BUILTINS[0] })
|
|
for (const entry of unranked) ranked.push({ rank: takeFree(9), entry })
|
|
return ranked
|
|
.filter(item => item.rank <= 9)
|
|
.sort((a, b) => a.rank - b.rank)
|
|
.slice(0, 9)
|
|
.map((item, i) => ({ ...item.entry, shortcut: `⌘${i + 1}` }))
|
|
}
|