style(web): polish subagent and bash chrome
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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({
|
||||
<IconChevronRightOutline14 />
|
||||
</button>
|
||||
)}
|
||||
<StateDot state={entry.activity === 'running' ? 'ongoing' : 'done'} />
|
||||
<span className={css.content}>
|
||||
<span className={css.label}>{label}</span>
|
||||
<span className={css.summary}>{secondary}</span>
|
||||
</span>
|
||||
{time !== undefined && <span className={css.time}>{time}</span>}
|
||||
<div className={css.clickarea}>
|
||||
<StateDot state={entry.activity === 'running' ? 'ongoing' : 'done'} />
|
||||
<span className={css.content}>
|
||||
<span className={css.label}>{label}</span>
|
||||
<span className={css.summary}>{secondary}</span>
|
||||
</span>
|
||||
{time !== undefined && <span className={css.time}>{time}</span>}
|
||||
</div>
|
||||
</div>
|
||||
{isExpanded && childCatalog !== undefined && !knownLeaf && (
|
||||
<div role="group" className={css.children}>
|
||||
<div
|
||||
role="group"
|
||||
className={css.children}
|
||||
aria-busy={emptyLoading || undefined}
|
||||
>
|
||||
<CatalogRows
|
||||
parentSessionId={entry.id}
|
||||
catalog={childCatalog}
|
||||
|
||||
@@ -237,6 +237,31 @@ describe('SubagentCatalogAction', () => {
|
||||
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(<SubagentCatalogAction {...loading} />)
|
||||
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(<SubagentCatalogAction {...ready} />)
|
||||
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({
|
||||
|
||||
Reference in New Issue
Block a user