From 6d560b6c495b1fc83281a283bb05267a0e66c916 Mon Sep 17 00:00:00 2001 From: zenchantlive Date: Sun, 1 Mar 2026 17:18:13 -0800 Subject: [PATCH] feat(8ij.2): add inline assign affordance to SocialCard Co-Authored-By: Oz --- src/components/shared/unified-shell.tsx | 21 +++++++++++++-- src/components/social/social-card.tsx | 34 ++++++++++++++++++++++++- src/components/social/social-page.tsx | 5 ++++ 3 files changed, 57 insertions(+), 3 deletions(-) diff --git a/src/components/shared/unified-shell.tsx b/src/components/shared/unified-shell.tsx index 212b921..95052c3 100644 --- a/src/components/shared/unified-shell.tsx +++ b/src/components/shared/unified-shell.tsx @@ -1,6 +1,6 @@ 'use client'; -import { useMemo, useState } from 'react'; +import { useCallback, useEffect, useMemo, useState } from 'react'; import { useRouter } from 'next/navigation'; import type { BeadIssue } from '../../lib/types'; import type { ProjectScopeOption } from '../../lib/project-scope'; @@ -48,6 +48,19 @@ export function UnifiedShell({ hideClosed: true, }); + const [actor, setActor] = useState(''); + + // Read from localStorage after hydration to avoid SSR/client mismatch + useEffect(() => { + const stored = window.localStorage.getItem('bb.humanActor'); + if (stored) setActor(stored); + }, []); + + const handleActorChange = useCallback((name: string) => { + setActor(name); + window.localStorage.setItem('bb.humanActor', name); + }, []); + const [customRightPanel, setCustomRightPanel] = useState(null); // Assign mode state for graph view @@ -138,6 +151,7 @@ export function UnifiedShell({ onSelect={handleCardSelect} projectScopeOptions={projectScopeOptions} blockedOnly={blockedOnly} + projectRoot={projectRoot} /> ); } @@ -165,7 +179,7 @@ export function UnifiedShell({ } // Default: ContextualRightPanel - return ; + return ; }; return ( @@ -176,6 +190,8 @@ export function UnifiedShell({ criticalAlerts={issues.filter(i => i.status === 'blocked').length} busyCount={issues.filter(i => i.status === 'in_progress').length} idleCount={0} + actor={actor} + onActorChange={handleActorChange} /> {!bdHealth.loading && !bdHealth.healthy ? (
@@ -231,6 +247,7 @@ export function UnifiedShell({ embedded={true} issue={selectedItem} projectRoot={projectRoot} + actor={actor} onIssueUpdated={async () => { router.refresh(); }} diff --git a/src/components/social/social-card.tsx b/src/components/social/social-card.tsx index 24211e3..9ca0d35 100644 --- a/src/components/social/social-card.tsx +++ b/src/components/social/social-card.tsx @@ -1,11 +1,13 @@ import type { KeyboardEvent, MouseEventHandler } from 'react'; -import { Activity, Clock3, GitBranch, Link2, MessageCircle, Orbit } from 'lucide-react'; +import { Activity, Clock3, GitBranch, Link2, MessageCircle, Orbit, UserPlus } from 'lucide-react'; import { Badge } from '@/components/ui/badge'; import { cn } from '@/lib/utils'; import type { SocialCard as SocialCardData, AgentStatus } from '../../lib/social-cards'; import { AgentAvatar } from '../shared/agent-avatar'; +import { useArchetypePicker } from '../../hooks/use-archetype-picker'; +import type { AgentArchetype } from '../../lib/types-swarm'; interface SocialCardProps { data: SocialCardData; @@ -22,6 +24,7 @@ interface SocialCardProps { unreadCount?: number; blockedByDetails?: Array<{ id: string; title: string; epic?: string }>; unblocksDetails?: Array<{ id: string; title: string; epic?: string }>; + archetypes?: AgentArchetype[]; } function handleCardKeyDown(event: KeyboardEvent, onClick?: MouseEventHandler) { @@ -116,8 +119,11 @@ export function SocialCard({ unreadCount = 0, blockedByDetails = [], unblocksDetails = [], + archetypes = [], }: SocialCardProps) { const status = statusVisual(data.status); + const { selectedArchetype, setSelectedArchetype, isAssigning, assignSuccess, handleAssign } = useArchetypePicker(); + const showAssign = (data.status === 'blocked' || data.agents.length === 0) && archetypes.length > 0; return (
No crew : null}
+ {showAssign && ( +
e.stopPropagation()}> + + +
+ )} +
diff --git a/src/components/social/social-page.tsx b/src/components/social/social-page.tsx index 6444f5e..147c88d 100644 --- a/src/components/social/social-page.tsx +++ b/src/components/social/social-page.tsx @@ -7,6 +7,7 @@ import type { BeadIssue } from '../../lib/types'; import type { ProjectScopeOption } from '../../lib/project-scope'; import { buildSocialCards } from '../../lib/social-cards'; import { SocialCard } from './social-card'; +import { useArchetypes } from '../../hooks/use-archetypes'; interface SocialPageProps { issues: BeadIssue[]; @@ -14,6 +15,7 @@ interface SocialPageProps { onSelect: (id: string) => void; projectScopeOptions?: ProjectScopeOption[]; blockedOnly?: boolean; + projectRoot: string; } type SectionKey = 'ready' | 'in_progress' | 'blocked' | 'deferred' | 'done'; @@ -63,10 +65,12 @@ export function SocialPage({ onSelect, projectScopeOptions = [], blockedOnly = false, + projectRoot, }: SocialPageProps) { const router = useRouter(); const searchParams = useSearchParams(); const cards = useMemo(() => buildSocialCards(issues), [issues]); + const { archetypes } = useArchetypes(projectRoot); const navigateWithParams = (updates: Record) => { const next = new URLSearchParams(searchParams.toString()); @@ -233,6 +237,7 @@ export function SocialPage({ unreadCount={unreadCount} blockedByDetails={toDependencyDetails(card.unblocks)} unblocksDetails={toDependencyDetails(card.blocks)} + archetypes={archetypes} /> ); })}