feat(bf-3t8): worker card shows beadsCompleted + currentBead, removes eventCount

Phase 9 UI change 2. Updated WorkerGrid component to display bead progress
instead of raw event count. Shows current bead when WORKING state.

- Added beadsCompleted and currentBead fields to frontend WorkerInfo type
- Worker card now shows "bead: bf-5r22 / 31 completed" when WORKING
- Shows "31 completed" when not WORKING or no current bead
- Removed eventCount display from worker card UI
- Updated tests to cover new display format

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
jedarden 2026-05-22 15:50:08 -04:00
parent 072f9c71f4
commit 58c1187794
3 changed files with 81 additions and 8 deletions

View file

@ -153,7 +153,11 @@ const WorkerGrid: React.FC<WorkerGridProps> = ({
</div>
</div>
<div className="worker-stats">
<span>{worker.eventCount} events</span>
<span>
{worker.needleState === 'WORKING' && worker.currentBead
? `bead: ${worker.currentBead} / ${worker.beadsCompleted} completed`
: `${worker.beadsCompleted} completed`}
</span>
<span>{formatLastSeen(worker.lastSeen)}</span>
</div>
{worker.hasCollision && worker.activeFiles && worker.activeFiles.length > 0 && (

View file

@ -49,6 +49,8 @@ export interface WorkerInfo {
id: string;
lastSeen: string;
eventCount: number;
beadsCompleted: number;
currentBead: string | null;
status: 'active' | 'idle' | 'error';
needleState?: NeedleState;
currentTool?: string;

View file

@ -13,6 +13,8 @@ describe('WorkerGrid', () => {
id: 'worker-alpha',
lastSeen: new Date().toISOString(),
eventCount: 10,
beadsCompleted: 5,
currentBead: null,
status: 'active',
recentEvents: [],
...overrides,
@ -133,10 +135,10 @@ describe('WorkerGrid', () => {
});
});
describe('event count display', () => {
it('should display event count', () => {
describe('beads completed display', () => {
it('should display beads completed count', () => {
const workers = [
createMockWorker({ id: 'worker-1', eventCount: 42 }),
createMockWorker({ id: 'worker-1', beadsCompleted: 31 }),
];
render(
@ -147,12 +149,12 @@ describe('WorkerGrid', () => {
/>
);
expect(screen.getByText(/42 events/)).toBeInTheDocument();
expect(screen.getByText(/31 completed/)).toBeInTheDocument();
});
it('should display zero events', () => {
it('should display zero beads completed', () => {
const workers = [
createMockWorker({ id: 'worker-1', eventCount: 0 }),
createMockWorker({ id: 'worker-1', beadsCompleted: 0 }),
];
render(
@ -163,7 +165,72 @@ describe('WorkerGrid', () => {
/>
);
expect(screen.getByText(/0 events/)).toBeInTheDocument();
expect(screen.getByText(/0 completed/)).toBeInTheDocument();
});
it('should display current bead when WORKING', () => {
const workers = [
createMockWorker({
id: 'worker-1',
beadsCompleted: 31,
currentBead: 'bf-5r22',
needleState: 'WORKING',
}),
];
render(
<WorkerGrid
workers={workers}
selectedWorker={null}
onSelectWorker={mockOnSelectWorker}
/>
);
expect(screen.getByText(/bead: bf-5r22 \/ 31 completed/)).toBeInTheDocument();
});
it('should not display current bead when not WORKING', () => {
const workers = [
createMockWorker({
id: 'worker-1',
beadsCompleted: 31,
currentBead: 'bf-5r22',
needleState: 'STOPPED',
}),
];
render(
<WorkerGrid
workers={workers}
selectedWorker={null}
onSelectWorker={mockOnSelectWorker}
/>
);
expect(screen.getByText(/31 completed/)).toBeInTheDocument();
expect(screen.queryByText(/bead: bf-5r22/)).not.toBeInTheDocument();
});
it('should not display bead prefix when WORKING but no currentBead', () => {
const workers = [
createMockWorker({
id: 'worker-1',
beadsCompleted: 15,
currentBead: null,
needleState: 'WORKING',
}),
];
render(
<WorkerGrid
workers={workers}
selectedWorker={null}
onSelectWorker={mockOnSelectWorker}
/>
);
expect(screen.getByText(/15 completed/)).toBeInTheDocument();
expect(screen.queryByText(/bead:/)).not.toBeInTheDocument();
});
});