fix(client): drop the task board's header completion bar and the rows' occupancy pct

This commit is contained in:
bowenliang123 committed 2026-10-15 00:19:39 +08:00
1 parent adac598ed3
commit 99cb1f3706
7 files changed
+11 -60

No files matched your search

+4 -5
View File
@@ -47,19 +47,18 @@ export function memberStyle(hue: string): CSSProperties {
return { '--lc-member-hue': hue } as CSSProperties
}
/** The run's activity figures a surface carries: consumption, duration, then steps — with the
* occupancy figure beside them for the task rows that show it. */
export function runMetaOf(node: AgentNode, t: ViewKit['t'], fmt: ViewKit['fmt']): { bits: string[]; pct: number | null } {
/** The run's activity figures a surface carries: consumption, duration, then steps. */
export function runMetaOf(node: AgentNode, t: ViewKit['t'], fmt: ViewKit['fmt']): string[] {
const bits: string[] = []
if (node.head !== null && node.head.tokens > 0) bits.push(fmt(node.head.tokens))
if (node.durationMs !== null) bits.push(fmtDurationCompact(node.durationMs))
if (node.requests > 0) bits.push(t('agents.steps', { n: node.requests }))
return { bits, pct: node.head !== null ? node.head.pct : null }
return bits
}
/** The run's activity line above a card's foot — the graph cards' own meta readout. */
function memberMeta(node: AgentNode, t: ViewKit['t'], fmt: ViewKit['fmt']): ReactElement | null {
const { bits } = runMetaOf(node, t, fmt)
const bits = runMetaOf(node, t, fmt)
if (bits.length === 0) return null
return (
<div className="lc-member-meta">
+3 -18
View File
@@ -13,7 +13,7 @@
import { memo, useEffect, useMemo, useRef, useState, type KeyboardEvent as ReactKeyboardEvent, type MouseEvent, type ReactElement } from 'react'
import { IconChecklistOutlineRegular, IconUserOutlineRegular, IconUsersOutlineRegular, StateDot } from '@deepseek-ai/dsh-client-ui-primitives'
import type { AgentForest, AgentNode } from '../agentTree'
import { familyHue, pressureColorOf } from '../agentTree'
import { familyHue } from '../agentTree'
import { fmtTime } from '../format'
import { familyOthersOf, memberIdByName, type FleetTeam, type FleetTeamTask } from '../fleetTeam'
import type { FleetDetail } from '../../shared/types'
@@ -252,8 +252,6 @@ export function TaskBoard(props: TaskBoardProps): ReactElement {
return out
}, [team, agentNodes, ownerVisible, needle, status, props.ownerFilter])
const doneCount = rows.filter(row => row.status === 'completed').length
const activeCount = rows.filter(row => row.status === 'in_progress').length
const visibleCount = groups.reduce((n, group) => n + group.rows.length, 0)
const toggleOpen = (id: string): void => {
@@ -355,7 +353,7 @@ export function TaskBoard(props: TaskBoardProps): ReactElement {
const renderAgentRow = (row: WorkRow, hue: string): ReactElement => {
const node = row.node as AgentNode
const { bits, pct } = runMetaOf(node, t, fmt)
const bits = runMetaOf(node, t, fmt)
// The delegation's briefing prompt is the task's description; the opened row adds the
// subagent's final report-back. Both render as Markdown, clamped to two lines when closed.
const prompt = props.detailOf(node.id)?.detail?.initialPrompt
@@ -391,10 +389,9 @@ export function TaskBoard(props: TaskBoardProps): ReactElement {
<MarkdownBody rich={rich} text={prompt} />
</div>
) : null}
{bits.length > 0 || pct !== null ? (
{bits.length > 0 ? (
<div className="lc-team-task-run">
<span className="lc-team-task-run-text" title={bits.join(' · ')}>{bits.join(' · ')}</span>
{pct !== null ? <span className="lc-team-task-run-pct" style={{ color: pressureColorOf(pct) }}>{pct}%</span> : null}
</div>
) : null}
</li>
@@ -536,18 +533,6 @@ export function TaskBoard(props: TaskBoardProps): ReactElement {
) : null}
</div>
{rows.length > 0 ? (
<div className="lc-tasks-progress">
<span className="lc-tasks-progress-track">
<i style={{ width: `${Math.round((doneCount / rows.length) * 100)}%` }} />
</span>
<span className="lc-tasks-progress-text">
{t('fleet.tasks.progress', { done: doneCount, total: rows.length })}
{activeCount > 0 ? ` · ${t('fleet.tasks.active', { n: activeCount })}` : ''}
</span>
</div>
) : null}
{showToolbar ? (
<div className="lc-fleet-toolbar">
<input
-2
View File
@@ -285,8 +285,6 @@ export const DICT_EN = {
'fleet.tasks.reply': 'Final reply',
'fleet.tasks.desc': 'Task brief',
'fleet.tasks.agent': 'Agent',
'fleet.tasks.progress': '{done}/{total} done',
'fleet.tasks.active': '{n} in progress',
'fleet.tasks.noTeam': 'No tasks yet — team tasks and subagent delegations land here',
'fleet.taskCol.pending': 'Pending',
'fleet.taskCol.in_progress': 'In progress',
-2
View File
@@ -283,8 +283,6 @@ export const DICT_ZH = {
'fleet.tasks.reply': '最终回报',
'fleet.tasks.desc': '任务描述',
'fleet.tasks.agent': '智能体',
'fleet.tasks.progress': '已完成 {done}/{total}',
'fleet.tasks.active': '{n} 进行中',
'fleet.tasks.noTeam': '暂无任务 — 团队任务与子 Agent 委派会在这里出现',
'fleet.taskCol.pending': '待处理',
'fleet.taskCol.in_progress': '进行中',
+4 -9
View File
@@ -17,12 +17,9 @@
.lc-summary-progress-label { color: var(--dsw-alias-label-primary); font-weight: 600; }
.lc-summary-progress-n { font-weight: 600; }
/* The shared progress track: the strip's wide variant and the task board's header line. */
/* The overview strip's progress track. */
.lc-tasks-progress-track { display: inline-block; width: 140px; height: 6px; border-radius: 4px; overflow: hidden; background: color-mix(in srgb, var(--dsw-alias-label-secondary) 16%, transparent); }
.lc-tasks-progress-track i { display: block; height: 100%; border-radius: 4px; background: var(--dsw-alias-brand-primary, var(--color-blue-500)); transition: width var(--ds-transition-duration, 0.2s) var(--ds-ease-in-out, ease-in-out); }
.lc-tasks-progress { display: flex; align-items: center; gap: 8px; margin-top: 6px; }
.lc-tasks-progress .lc-tasks-progress-track { flex: 1; }
.lc-tasks-progress-text { flex: none; font-size: 11px; color: var(--dsw-alias-label-secondary); font-variant-numeric: tabular-nums; }
/* Section heads inside the members board (team cards / other agents). */
.lc-board-section-head { display: flex; align-items: center; gap: 6px; font-size: 11px; font-weight: 650; letter-spacing: 0.02em; color: var(--dsw-alias-label-secondary); margin: 10px 0 6px; padding-bottom: 4px; border-bottom: 1px dashed var(--dsw-alias-border-l2); }
@@ -92,8 +89,7 @@
/* The task card folds at a default height and grows with the network card beside it: the cap is
the larger of its own default and the graph's measured natural height minus the members card
and its 7px bottom margin (--lc-*-h, measured by fleetView's observer), so the two columns'
bottom edges keep meeting. The toolbar and progress pin while the rows fold into their own
scroll region. */
bottom edges keep meeting. The toolbar pins while the rows fold into their own scroll region. */
.lc-tasks { position: relative; display: flex; flex-direction: column; overflow: hidden; max-height: max(560px, calc(var(--lc-graph-h, 0px) - var(--lc-members-h, 0px) - 7px)); }
.lc-tasks-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; scrollbar-width: thin; }
/* The task rows are opaque cards, so the cut-off hint is a sticky overlay fade at the region's
@@ -146,10 +142,9 @@
/* A subagent's prompt title runs long: the head label ellipsizes rather than wrapping the band. */
.lc-tasks-group-head .lc-team-task-owner { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: left; }
/* A delegation row's live readout: the run's figures left, the occupancy figure right. */
.lc-team-task-run { display: flex; align-items: baseline; justify-content: space-between; gap: 6px; margin-top: 6px; font-size: 10.5px; line-height: 1.3; color: var(--dsw-alias-label-tertiary, var(--dsw-alias-label-secondary)); font-variant-numeric: tabular-nums; }
/* A delegation row's live readout: the run's figures. */
.lc-team-task-run { display: flex; align-items: baseline; gap: 6px; margin-top: 6px; font-size: 10.5px; line-height: 1.3; color: var(--dsw-alias-label-tertiary, var(--dsw-alias-label-secondary)); font-variant-numeric: tabular-nums; }
.lc-team-task-run-text { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lc-team-task-run-pct { flex: none; font-weight: 600; }
/* ---- Comms timeline ---- */
/* The comms card folds at its own static cap: the toolbar pins, the rows scroll under the same
@@ -142,8 +142,6 @@ describe('FleetView — the panels over one family', () => {
assert.ok(text(board).includes(DICT_EN['fleet.board.others']))
assert.equal(queryAll(board, '.lc-member-card').length, 4)
assert.ok(text(query(m.container, '.lc-tasks')).includes('schema parsing'))
// The task board's completion bar: team task-1 in flight, the w2 delegation settled.
assert.ok(text(query(m.container, '.lc-tasks-progress')).includes('1/2 done'))
// The comms panel opens collapsed.
assert.ok(text(query(m.container, '.lc-comms')).includes('Scan 3 sessions'))
// The network card stands alone: the boards beside it carry the agent detail.
-22
View File
@@ -104,7 +104,6 @@ describe('TaskBoard — the owner-grouped board', () => {
const scout = query(m.container, '[data-task="s1"]')
assert.ok(text(scout).includes('in progress'))
assert.ok(text(scout).includes('800 · 42s · 5 steps'))
assert.ok(text(scout).includes('80%'))
assert.ok(query(scout, '.lc-team-task-subject').className.includes('lc-team-task-subject-clamp'))
assert.ok(query(scout, '.lc-team-task-head .lc-member-icon') !== null, 'the row wears the agent hue')
// The settled delegation reads done; the idler reads pending without a meta line.
@@ -349,25 +348,6 @@ describe('TaskBoard — the team task DAG', () => {
})
describe('TaskBoard — the toolbar and guidance states', () => {
test('the head carries the completion bar over every row', async () => {
const m = await mount(h(TaskBoard, propsOf()))
const progress = query(m.container, '.lc-tasks-progress')
// Team task-1 plus the settled s2 are done, of eight rows.
assert.ok(text(progress).includes('2/8 done'))
assert.ok(text(progress).includes('2 in progress'))
assert.equal(query(progress, '.lc-tasks-progress-track i')?.style.width, '25%')
await m.unmount()
// No in-flight work: the active count drops out of the text.
const calm = teamOf()
calm.tasks[1] = { ...calm.tasks[1], status: 'completed' }
const calmForest: AgentForest = { ...FOREST, nodes: [FOREST.nodes[0], { ...FOREST.nodes[1], running: false, completed: true }, FOREST.nodes[2], FOREST.nodes[3]] }
const m2 = await mount(h(TaskBoard, propsOf({ team: calm, forest: calmForest })))
assert.ok(text(query(m2.container, '.lc-tasks-progress')).includes('4/8 done'))
assert.ok(!text(query(m2.container, '.lc-tasks-progress')).includes('in progress'))
await m2.unmount()
})
test('the status filter counts and narrows across both kinds', async () => {
const m = await mount(h(TaskBoard, propsOf()))
const filters = queryAll(m.container, '.lc-fleet-filters .lc-gran-btn')
@@ -401,12 +381,10 @@ describe('TaskBoard — the toolbar and guidance states', () => {
const m = await mount(h(TaskBoard, propsOf({ team: null, forest: { nodes: [nodeOf('root', { isCurrent: true, depth: 0 })], edges: [], overflow: 0, solo: true } })))
assert.ok(text(m.container).includes(DICT_EN['fleet.tasks.noTeam']))
assert.equal(queryAll(m.container, '.lc-team-task').length, 0)
assert.equal(queryAll(m.container, '.lc-tasks-progress').length, 0)
await m.unmount()
const empty = await mount(h(TaskBoard, propsOf({ team: teamOf({ tasks: [] }), forest: null })))
assert.ok(text(empty.container).includes(DICT_EN['fleet.team.empty']))
assert.equal(queryAll(empty.container, '.lc-tasks-progress').length, 0, 'no bar without tasks')
await empty.unmount()
})
})