fix(tasks): 逐节点折叠按钮在聚合规则下失效(手动折叠不再共用自动折叠的守卫)
用户反馈「怎么折叠和怎么自动合并功能没了?我点击没反应」。
根因是折叠入口把两个触发条件塞进了同一组守卫:
if ((folded || foldedIds?.has(child.id)) && isLeaf && !child.current
&& child.team === undefined && (done || error))
`child.team === undefined` 是给**页面级自动聚合**准备的(teammate 是真实可续接
的工作者,不该被自动扫走),但它同样卡住了 `foldedIds` 这条**手动**路径。而卡片小条
的折叠 chevron 是按「已结算」画出来的——于是出现「按钮画出来了,点了没反应」这种
最差的失效形态:既没有折叠,也没有任何反馈。
改为按触发源分别守卫(`isAutoFoldable` = leaf + 非成员;`nodeFoldable` = 已结算 +
非当前会话),手动折叠只需后者;workflow run 成员两个触发都走 `nodeFoldable`。
测试:新增 4 例——手动折叠把「出错」的成员收进聚合、自动规则不动它、
运行中的成员即使用手动折叠也不被收起;pnpm test 1279 passed / 9 skipped,
typecheck / lint 通过。
(cherry picked from commit 3a47ddafe3c2d57f8997dc97f0118eb0530b114a)
This commit is contained in:
@@ -155,6 +155,46 @@ describe('buildTasksModel', () => {
|
||||
expect(agents(model).find(node => node.id === 'w')?.state).toBe('running')
|
||||
})
|
||||
|
||||
it('folds a settled team member when the READER folds it by hand', () => {
|
||||
// The card's chevron is drawn whenever a node is settled, and a teammate
|
||||
// can settle as 出错 (a failed roster row). Auto-fold keeps team members
|
||||
// out of the aggregate — a roster row is a real, resumable worker, not a
|
||||
// settled subagent to sweep away — but a manual fold is the reader's
|
||||
// explicit request for THAT node and must not be silently dropped.
|
||||
const model = buildTasksModel(input({
|
||||
catalogs: { root: catalog([child('mate'), child('sub')]), sub: catalog([]) },
|
||||
byId: { root: summary('root'), mate: summary('mate'), sub: summary('sub') },
|
||||
teamMembers: [member({ id: 'mate', phase: 'failed', status: 'failed' })],
|
||||
folded: false,
|
||||
foldedIds: new Set(['mate', 'sub']),
|
||||
}))
|
||||
expect(model.map(node => node.id)).toEqual(['root', 'fold:root'])
|
||||
expect(model.find(node => node.kind === 'fold')).toMatchObject({
|
||||
count: 2, memberIds: ['mate', 'sub'],
|
||||
})
|
||||
})
|
||||
|
||||
it('leaves a failed teammate alone under the AUTO rule (only a manual fold takes it)', () => {
|
||||
const model = buildTasksModel(input({
|
||||
catalogs: { root: catalog([child('mate'), child('sub')]), sub: catalog([]) },
|
||||
byId: { root: summary('root'), mate: summary('mate'), sub: summary('sub') },
|
||||
teamMembers: [member({ id: 'mate', phase: 'failed', status: 'failed' })],
|
||||
folded: true,
|
||||
}))
|
||||
expect(model.map(node => node.id)).toEqual(['root', 'mate', 'fold:root'])
|
||||
})
|
||||
|
||||
it('never folds a RUNNING team member, even when the reader clicks its chevron', () => {
|
||||
const model = buildTasksModel(input({
|
||||
catalogs: { root: catalog([child('mate')]) },
|
||||
byId: { root: summary('root'), mate: summary('mate') },
|
||||
teamMembers: [member({ id: 'mate', phase: 'active', status: 'running' })],
|
||||
folded: false,
|
||||
foldedIds: new Set(['mate']),
|
||||
}))
|
||||
expect(model.map(node => node.id)).toEqual(['root', 'mate'])
|
||||
})
|
||||
|
||||
it('folds settled leaves per parent and keeps running/teammate/current rows', () => {
|
||||
const model = buildTasksModel(input({
|
||||
catalogs: {
|
||||
|
||||
Reference in New Issue
Block a user