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:
+13
-24
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user