diff --git a/desktop/src/components/TeamList.tsx b/desktop/src/components/TeamList.tsx index 0c308d8..613ecd4 100644 --- a/desktop/src/components/TeamList.tsx +++ b/desktop/src/components/TeamList.tsx @@ -6,9 +6,12 @@ * @module components/TeamList */ -import { useEffect } from 'react'; +import { useEffect, useState } from 'react'; import { useTeamStore } from '../store/teamStore'; -import { Users, Plus, Activity, CheckCircle, AlertTriangle } from 'lucide-react'; +import { useGatewayStore } from '../store/gatewayStore'; +import { useChatStore } from '../store/chatStore'; +import { Users, Plus, Activity, CheckCircle, AlertTriangle, X, Bot } from 'lucide-react'; +import type { TeamMemberRole } from '../types/team'; interface TeamListProps { onSelectTeam?: (teamId: string) => void; @@ -16,7 +19,15 @@ interface TeamListProps { } export function TeamList({ onSelectTeam, selectedTeamId }: TeamListProps) { - const { teams, loadTeams, setActiveTeam, isLoading } = useTeamStore(); + const { teams, loadTeams, setActiveTeam, createTeam, isLoading } = useTeamStore(); + const { clones } = useGatewayStore(); + const { agents } = useChatStore(); + const [showCreateModal, setShowCreateModal] = useState(false); + const [teamName, setTeamName] = useState(''); + const [teamDescription, setTeamDescription] = useState(''); + const [teamPattern, setTeamPattern] = useState<'sequential' | 'parallel' | 'pipeline'>('sequential'); + const [selectedAgents, setSelectedAgents] = useState([]); + const [isCreating, setIsCreating] = useState(false); useEffect(() => { loadTeams(); @@ -30,6 +41,45 @@ export function TeamList({ onSelectTeam, selectedTeamId }: TeamListProps) { } }; + const handleCreateTeam = async () => { + if (!teamName.trim() || selectedAgents.length === 0) return; + + setIsCreating(true); + try { + const roleAssignments: { agentId: string; role: TeamMemberRole }[] = selectedAgents.map((agentId, index) => ({ + agentId, + role: (index === 0 ? 'orchestrator' : index === 1 ? 'reviewer' : 'worker') as TeamMemberRole, + })); + + const team = await createTeam({ + name: teamName.trim(), + description: teamDescription.trim() || undefined, + pattern: teamPattern, + memberAgents: roleAssignments, + }); + + if (team) { + setShowCreateModal(false); + setTeamName(''); + setTeamDescription(''); + setSelectedAgents([]); + setTeamPattern('sequential'); + setActiveTeam(team); + onSelectTeam?.(team.id); + } + } finally { + setIsCreating(false); + } + }; + + const toggleAgentSelection = (agentId: string) => { + setSelectedAgents(prev => + prev.includes(agentId) + ? prev.filter(id => id !== agentId) + : [...prev, agentId] + ); + }; + const getStatusIcon = (status: string) => { switch (status) { case 'active': @@ -43,6 +93,13 @@ export function TeamList({ onSelectTeam, selectedTeamId }: TeamListProps) { } }; + // Merge clones and agents for display + const availableAgents = clones.length > 0 ? clones : agents.map(a => ({ + id: a.id, + name: a.name, + role: '默认助手', + })); + return (
{/* Header */} @@ -52,14 +109,130 @@ export function TeamList({ onSelectTeam, selectedTeamId }: TeamListProps) { Teams
+ {/* Create Team Modal */} + {showCreateModal && ( +
+
+
+
+

Create Team

+ +
+
+ +
+ {/* Team Name */} +
+ + setTeamName(e.target.value)} + placeholder="e.g., Dev Team Alpha" + className="w-full px-3 py-2 text-sm border border-gray-200 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:outline-none focus:ring-2 focus:ring-blue-500" + /> +
+ + {/* Team Description */} +
+ +