fix(tasks-ui): postmodern chrome, working clicks, adaptive layout, lean cards

Review feedback from the live 3384 install, fixed at the root:

- COLORS: the new stylesheet used var(--dsw-alias-accent) in 17 places — a
  token the DSH theme does NOT define, so every declaration was dropped
  (older files only survived because they carry fallbacks); container edges
  used border-l1 (4% black, invisible). Accent now rides
  --dsw-alias-state-business-primary, container edges --dsw-alias-border-l4.
- CLICKS: the canvas called setPointerCapture on pointerdown, which
  retargets the derived click to the container and killed every node (and
  ⓘ) interaction; jsdom cannot see this, a real browser can. Capture is
  gone and panning only starts from the background.
- LAYOUT: fit gave up silently at zero container size and never retried,
  centered only horizontally, and capped at 100% while a five-child level
  scaled to 35%. Now: ResizeObserver + first non-zero fit, both axes
  centered, a 0.78 readability floor, and layoutTasksGraphForWidth picks
  the flattest sibling arrangement that still meets that floor.
- CARDS: title (one line) + mono meta + live line only; display title,
  team role, full model id and latest text moved into the ⓘ popover.
- PANEL: metrics follow the approved 360x660 mockup (132x46 cards, 112 row
  stride), explicit line-heights, user-select:none, horizontal control
  cluster with a labelled mode button, always-visible team board strip.
- Tokens for two new popover headings across all 20 dictionaries.

Tests: 3 new page-interaction specs (click after background pointerdown,
node gestures never pan, team board visible without a click) and a
rewritten 9-case layout suite (band wrap, row reservation, width solver,
reserved live row). Full suite 1400 passed / 133 files.
This commit is contained in:
Menghuan1918
2026-09-27 22:18:19 +08:00
parent 9b6628602e
commit 490e96080a
33 changed files with 1744 additions and 1046 deletions
+13 -24
View File
@@ -47,7 +47,8 @@ import { TasksGraph } from './TasksGraph.tsx'
import { TasksTree } from './TasksTree.tsx'
import { JobsDrawer, JobOutputPopoverContent } from './JobsDrawer.tsx'
import { AnchoredPopover } from './AnchoredPopover.tsx'
import { AgentNodePopover, TeamBoardPopover, WorkflowNodePopover } from './TasksPopovers.tsx'
import { AgentNodePopover, WorkflowNodePopover } from './TasksPopovers.tsx'
import { TeamBoard } from './TeamBoard.tsx'
import type { SidebarStore } from './state.ts'
import type { WorkflowRunView } from '../workflow-runs.ts'
import legacy from './SubagentView.module.css'
@@ -130,7 +131,6 @@ type PagePopover =
| { kind: 'node'; nodeId: string; anchor: HTMLElement }
| { kind: 'workflow'; nodeId: string; anchor: HTMLElement }
| { kind: 'job'; jobId: string; anchor: HTMLElement }
| { kind: 'team'; anchor: HTMLElement }
/**
* The sidebar's Tasks page.
@@ -182,6 +182,7 @@ export function SubagentView(props: {
const mode = modeOverride ?? prefsMode
const [folded, setFolded] = useState(true)
const [teamBoardCollapsed, setTeamBoardCollapsed] = useState(false)
const [popover, setPopover] = useState<PagePopover | null>(null)
const model = useMemo(
@@ -347,22 +348,11 @@ export function SubagentView(props: {
/** The current popover's resolved content (subjects re-resolve live). */
const popoverContent = ((): ReactNode => {
if (popover === null) return null
if (popover.kind === 'team' && teamView?.available === true && teamView.team !== null && rootId !== undefined) {
return (
<TeamBoardPopover
rootId={rootId}
members={teamView.team.members}
tasks={teamView.team.tasks}
onChanged={team.refresh}
/>
)
}
if (popover.kind === 'job') {
const row = jobRows.find(candidate => candidate.job.id === popover.jobId)
if (row === undefined) return null
return <JobOutputPopoverContent ownerSessionId={row.ownerSessionId} job={row.job} active={active} />
}
if (popover.kind === 'team') return null
const node = model.find(candidate => candidate.id === popover.nodeId)
if (node === undefined) return null
if (popover.kind === 'workflow' && node.kind === 'workflow') {
@@ -398,17 +388,6 @@ export function SubagentView(props: {
: ''}
</span>
{countLabel !== undefined && <span className={legacy.subagentCount}>{countLabel}</span>}
{teamView?.available === true && teamView.team !== null && (
<button
type="button"
className={css.teamChip}
onClick={(event) => {
setPopover(popover?.kind === 'team' ? null : { kind: 'team', anchor: event.currentTarget })
}}
>
{t('teamChip', { members: teamView.team.members.length, tasks: teamView.team.tasks.length })}
</button>
)}
<button
type="button"
className={legacy.subagentRefresh}
@@ -423,6 +402,16 @@ export function SubagentView(props: {
<IconRefreshOutline14 />
</button>
</div>
{rootId !== undefined && teamView?.available === true && teamView.team !== null && (
<TeamBoard
rootId={rootId}
members={teamView.team.members}
tasks={teamView.team.tasks}
onChanged={team.refresh}
collapsed={teamBoardCollapsed}
onToggleCollapsed={() => { setTeamBoardCollapsed(current => !current) }}
/>
)}
{failedParents.length > 0 && (
<div className={legacy.subagentError}>
<span>{t('catalogLoadFailed', { count: failedParents.length })}</span>