feat(apess): surface real board activity on the instructor dashboard
Extend the collective feed to consume node:status / node:activity: the reducer now tracks per-team board online state and a bounded, most-recent-first activity feed (preserved across snapshots). Admin gains a "Boards live" stat and a "Board activity" panel (new BoardActivity component) showing real generate/compile/flash events across teams. Tests: front-end 177, typecheck clean, prod build passes. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
f21bbdf31e
commit
28a0965108
@@ -0,0 +1,47 @@
|
||||
import type { NodeActivityEntry } from '@/lib/useCollective'
|
||||
import type { NodeActivityKind } from '@/types'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const KIND_DOT: Record<NodeActivityKind, string> = {
|
||||
thinking: 'bg-muted-foreground',
|
||||
tool: 'bg-amber',
|
||||
flash: 'bg-primary',
|
||||
error: 'bg-destructive',
|
||||
response: 'bg-teal',
|
||||
}
|
||||
|
||||
export interface BoardActivityProps {
|
||||
activity: NodeActivityEntry[]
|
||||
/** Resolve a teamId to a display name (falls back to the id). */
|
||||
nameFor?: (teamId: string) => string
|
||||
}
|
||||
|
||||
/** Instructor-facing rolling feed of real on-device agent activity across boards. */
|
||||
export function BoardActivity({ activity, nameFor }: BoardActivityProps) {
|
||||
if (activity.length === 0) {
|
||||
return (
|
||||
<p data-testid="board-activity-empty" className="font-mono text-[11px] text-muted-foreground">
|
||||
No board activity yet — boards report generate / compile / flash here as teams work.
|
||||
</p>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<ul data-testid="board-activity" className="space-y-1.5">
|
||||
{activity.map((e, i) => (
|
||||
<li key={i} className="flex items-center gap-2 font-mono text-[11px]">
|
||||
<span className={cn('w-1.5 h-1.5 rounded-full shrink-0', KIND_DOT[e.kind])} />
|
||||
<span className="text-muted-foreground shrink-0">{nameFor ? nameFor(e.teamId) : e.teamId}</span>
|
||||
<span
|
||||
className={cn(
|
||||
'truncate',
|
||||
e.kind === 'error' && 'text-destructive',
|
||||
e.kind === 'flash' && 'text-foreground font-medium',
|
||||
)}
|
||||
>
|
||||
{e.label}
|
||||
</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user