diff --git a/packages/client/ui-subagent/src/client/SubagentCatalogAction.module.css b/packages/client/ui-subagent/src/client/SubagentCatalogAction.module.css index 043e149e67..6d788bba1c 100644 --- a/packages/client/ui-subagent/src/client/SubagentCatalogAction.module.css +++ b/packages/client/ui-subagent/src/client/SubagentCatalogAction.module.css @@ -55,6 +55,9 @@ position: relative; min-width: 0; } +.menu > .node { + margin-left: -8px; +} .row { position: relative; @@ -64,7 +67,7 @@ box-sizing: border-box; width: 100%; min-height: 50px; - padding: 7px 8px 7px 3px; + padding: 7px 8px 7px 11px; border: 0; border-radius: 8px; background: transparent; @@ -76,12 +79,26 @@ outline: none; } -.row:hover, -.row:focus-visible { +.row:hover > .clickarea, +.row:focus-visible > .clickarea { background: var(--dsw-alias-interactive-bg-hover); } -.row > :global([data-state]) { +.clickarea { + box-sizing: border-box; + display: flex; + flex: 1; + align-self: stretch; + align-items: flex-start; + gap: 8px; + min-width: 0; + margin: -7px -8px -7px; + padding: 7px 8px; + border-radius: 8px; +} + +.row > :global([data-state]), +.clickarea > :global([data-state]) { margin-top: 4px; } @@ -154,7 +171,7 @@ .children { position: relative; - margin-left: 10px; + margin-left: 18px; padding-left: 4px; } @@ -171,6 +188,10 @@ height: 26px; } +.children[aria-busy='true']::before { + content: none; +} + .children > .node::before { top: 0; bottom: 0; @@ -179,15 +200,15 @@ .children > .node:last-child::before { bottom: auto; - height: 25px; + height: 17px; } .children > .node > .row::before { content: ''; position: absolute; - top: 24px; + top: 16px; left: -4px; - width: 7px; + width: 14px; border-top: 1px solid var(--dsw-alias-border-l2); } diff --git a/packages/client/ui-subagent/src/client/SubagentCatalogAction.tsx b/packages/client/ui-subagent/src/client/SubagentCatalogAction.tsx index 6c5ad91b9a..ed08856156 100644 --- a/packages/client/ui-subagent/src/client/SubagentCatalogAction.tsx +++ b/packages/client/ui-subagent/src/client/SubagentCatalogAction.tsx @@ -118,6 +118,7 @@ function CatalogRows({ const childCatalog = catalogs[entry.id] const isExpanded = expanded.has(entry.id) const knownLeaf = !entry.hasChildren + const emptyLoading = childCatalog?.state === 'loading' && childCatalog.entries.length === 0 const summary = summaries[entry.id] const label = entry.label ?? entry.id const mode = entry.mode === 'one-shot' ? '一次性' : '可继续' @@ -176,15 +177,21 @@ function CatalogRows({ )} - - - {label} - {secondary} - - {time !== undefined && {time}} +
+ + + {label} + {secondary} + + {time !== undefined && {time}} +
{isExpanded && childCatalog !== undefined && !knownLeaf && ( -
+
{ expect(input.setCatalogOpen).toHaveBeenCalledWith(CHILD, false) }) + it('shows initial descendant loading status without drawing its branch', () => { + const loading = props(catalog(), { + [CHILD]: catalog({ entries: [], state: 'loading' }), + }) + const view = render() + fireEvent.click(screen.getByRole('button', { name: /2 个子代理/ })) + fireEvent.click(screen.getByRole('button', { name: '展开 worker 的下级子代理' })) + + expect(loading.setCatalogOpen).toHaveBeenCalledWith(CHILD, true) + expect(screen.getByRole('group').getAttribute('aria-busy')).toBe('true') + expect(screen.getByText('正在加载子代理…')).toBeTruthy() + + const ready = props(catalog(), { + [CHILD]: catalog({ + entries: [{ + kind: 'child', id: GRANDCHILD, mode: 'continuable', + label: 'indexer', activity: 'inactive', hasChildren: false, + }], + }), + }) + view.rerender() + expect(screen.getByRole('group').getAttribute('aria-busy')).toBeNull() + expect(screen.getByRole('treeitem', { name: /indexer/ })).toBeTruthy() + }) + it('uses ArrowRight and ArrowLeft for branch disclosure', async () => { const input = props(catalog(), { [CHILD]: catalog({