diff --git a/src/renderer/components/team/TeamDetailView.tsx b/src/renderer/components/team/TeamDetailView.tsx index 878c9565..021305fb 100644 --- a/src/renderer/components/team/TeamDetailView.tsx +++ b/src/renderer/components/team/TeamDetailView.tsx @@ -246,11 +246,26 @@ export const TeamDetailView = ({ teamName }: TeamDetailViewProps): React.JSX.Ele setSendDialogDefaultChip(undefined); setSendDialogOpen(true); }; + const onOpenProfile = (e: Event) => { + const { teamName: tn, memberName } = (e as CustomEvent).detail ?? {}; + if (tn !== teamName || !data) return; + const member = data.members.find((m: { name: string }) => m.name === memberName); + if (member) setSelectedMember(member); + }; + const onCreateTask = (e: Event) => { + const { teamName: tn, owner } = (e as CustomEvent).detail ?? {}; + if (tn !== teamName) return; + openCreateTaskDialog('', '', owner ?? ''); + }; window.addEventListener('graph:open-task', onOpenTask); window.addEventListener('graph:send-message', onSendMsg); + window.addEventListener('graph:open-profile', onOpenProfile); + window.addEventListener('graph:create-task', onCreateTask); return () => { window.removeEventListener('graph:open-task', onOpenTask); window.removeEventListener('graph:send-message', onSendMsg); + window.removeEventListener('graph:open-profile', onOpenProfile); + window.removeEventListener('graph:create-task', onCreateTask); }; }); diff --git a/src/renderer/features/agent-graph/ui/GraphNodePopover.tsx b/src/renderer/features/agent-graph/ui/GraphNodePopover.tsx index 67996ce9..0b124a95 100644 --- a/src/renderer/features/agent-graph/ui/GraphNodePopover.tsx +++ b/src/renderer/features/agent-graph/ui/GraphNodePopover.tsx @@ -7,7 +7,7 @@ import { Badge } from '@renderer/components/ui/badge'; import { Button } from '@renderer/components/ui/button'; import { agentAvatarUrl } from '@renderer/utils/memberHelpers'; -import { MessageSquare, ExternalLink, User } from 'lucide-react'; +import { MessageSquare, ExternalLink, User, Plus } from 'lucide-react'; import type { GraphNode } from '@claude-teams/agent-graph'; @@ -17,6 +17,7 @@ interface GraphNodePopoverProps { onSendMessage?: (memberName: string) => void; onOpenTaskDetail?: (taskId: string) => void; onOpenMemberProfile?: (memberName: string) => void; + onCreateTask?: (owner: string) => void; } export function GraphNodePopover({ @@ -25,6 +26,7 @@ export function GraphNodePopover({ onSendMessage, onOpenTaskDetail, onOpenMemberProfile, + onCreateTask, }: GraphNodePopoverProps): React.JSX.Element { if (node.kind === 'member' || node.kind === 'lead') { return ( @@ -33,6 +35,7 @@ export function GraphNodePopover({ onClose={onClose} onSendMessage={onSendMessage} onOpenProfile={onOpenMemberProfile} + onCreateTask={onCreateTask} /> ); } @@ -66,11 +69,13 @@ function MemberPopoverContent({ onClose, onSendMessage, onOpenProfile, + onCreateTask, }: { node: GraphNode; onClose: () => void; onSendMessage?: (name: string) => void; onOpenProfile?: (name: string) => void; + onCreateTask?: (owner: string) => void; }): React.JSX.Element { const memberName = node.domainRef.kind === 'member' ? node.domainRef.memberName : 'team-lead'; const avatarSrc = node.avatarUrl ?? agentAvatarUrl(memberName, 64); @@ -167,7 +172,7 @@ function MemberPopoverContent({ )} {/* Actions */} -
+
+
); diff --git a/src/renderer/features/agent-graph/ui/TeamGraphTab.tsx b/src/renderer/features/agent-graph/ui/TeamGraphTab.tsx index 8f634922..951d3079 100644 --- a/src/renderer/features/agent-graph/ui/TeamGraphTab.tsx +++ b/src/renderer/features/agent-graph/ui/TeamGraphTab.tsx @@ -37,18 +37,30 @@ export const TeamGraphTab = ({ teamName }: TeamGraphTabProps): React.JSX.Element ), [teamName] ); + const dispatchOpenProfile = useCallback( + (memberName: string) => + window.dispatchEvent( + new CustomEvent('graph:open-profile', { detail: { teamName, memberName } }) + ), + [teamName] + ); + const dispatchCreateTask = useCallback( + (owner: string) => + window.dispatchEvent(new CustomEvent('graph:create-task', { detail: { teamName, owner } })), + [teamName] + ); const events: GraphEventPort = { onNodeDoubleClick: useCallback( (ref: GraphDomainRef) => { if (ref.kind === 'task') dispatchOpenTask(ref.taskId); - else if (ref.kind === 'member') dispatchSendMessage(ref.memberName); + else if (ref.kind === 'member') dispatchOpenProfile(ref.memberName); }, - [dispatchOpenTask, dispatchSendMessage] + [dispatchOpenTask, dispatchOpenProfile] ), onSendMessage: dispatchSendMessage, onOpenTaskDetail: dispatchOpenTask, - onOpenMemberProfile: dispatchSendMessage, + onOpenMemberProfile: dispatchOpenProfile, }; return ( @@ -64,7 +76,8 @@ export const TeamGraphTab = ({ teamName }: TeamGraphTabProps): React.JSX.Element onClose={onClose} onSendMessage={dispatchSendMessage} onOpenTaskDetail={dispatchOpenTask} - onOpenMemberProfile={dispatchSendMessage} + onOpenMemberProfile={dispatchOpenProfile} + onCreateTask={dispatchCreateTask} /> )} />