fix(client): drop the task board's header completion bar and the rows' occupancy pct
This commit is contained in:
1 parent
adac598ed3
commit
99cb1f3706
7 files changed
+11
-60
No files matched your search
@@ -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">
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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': '进行中',
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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()
|
||||
})
|
||||
})
|
||||
Reference in new issue
Block a user