Skip to main content
Glama
orneryd

M.I.M.I.R - Multi-agent Intelligent Memory & Insight Repository

by orneryd
ParallelGroupContainer.tsx5.27 kB
import { useDrop } from 'react-dnd'; import { usePlanStore } from '../store/planStore'; import { ParallelGroup, Task, AgentTemplate, AgentTask } from '../types/task'; import { TaskCard } from './TaskCard'; import { Trash2, Edit2 } from 'lucide-react'; import { useState } from 'react'; interface ParallelGroupContainerProps { group: ParallelGroup; isExecuting?: boolean; } export function ParallelGroupContainer({ group, isExecuting = false }: ParallelGroupContainerProps) { const { tasks, assignTaskToGroup, deleteParallelGroup, updateParallelGroup, addTask } = usePlanStore(); const [isEditing, setIsEditing] = useState(false); const [groupName, setGroupName] = useState(group.name); const [{ isOverTask, isOverAgent }, drop] = useDrop(() => ({ accept: ['task', 'reorderable-task', 'agent'], drop: (item: Task | AgentTemplate | { task: Task }, monitor) => { // Only handle drop if it's directly on this zone (not a child zone) if (monitor.didDrop()) { return; // Already handled by a nested drop zone } const itemType = monitor.getItemType(); if (itemType === 'task') { // Existing task being moved to this group const task = item as Task; if (task.parallelGroup !== group.id) { assignTaskToGroup(task.id, group.id); } } else if (itemType === 'reorderable-task') { // Reorderable task from ungrouped section const { task } = item as { task: Task }; if (task.parallelGroup !== group.id) { assignTaskToGroup(task.id, group.id); } } else if (itemType === 'agent') { // Agent being dropped to create new task in this group const agent = item as AgentTemplate; const newTask: AgentTask = { id: `task-${Date.now()}`, taskType: 'agent', title: `New ${agent.name} Task`, agentRoleDescription: agent.agentType === 'worker' ? agent.role : '', workerPreambleId: agent.agentType === 'worker' ? agent.id : undefined, recommendedModel: 'gpt-4.1', prompt: '', successCriteria: [], dependencies: [], estimatedDuration: '30 minutes', estimatedToolCalls: 20, parallelGroup: group.id, qcRole: agent.agentType === 'qc' ? agent.role : '', qcPreambleId: agent.agentType === 'qc' ? agent.id : undefined, verificationCriteria: [], maxRetries: 3, }; addTask(newTask); } }, collect: (monitor) => ({ isOverTask: monitor.isOver({ shallow: true }) && (monitor.getItemType() === 'task' || monitor.getItemType() === 'reorderable-task'), isOverAgent: monitor.isOver({ shallow: true }) && monitor.getItemType() === 'agent', }), })); const groupTasks = tasks.filter((t) => t.parallelGroup === group.id); const handleSaveName = () => { updateParallelGroup(group.id, { name: groupName }); setIsEditing(false); }; return ( <div ref={drop} style={{ borderColor: group.color }} className={`border-2 rounded-lg p-4 transition-colors ${ isOverAgent ? 'bg-valhalla-gold bg-opacity-10 border-valhalla-gold' : isOverTask ? 'bg-opacity-10' : 'bg-norse-shadow' }`} > <div className="flex items-center justify-between mb-4"> <div className="flex items-center space-x-3 flex-1"> <div style={{ backgroundColor: group.color }} className="w-3 h-3 rounded-full" /> {isEditing ? ( <input type="text" value={groupName} onChange={(e) => setGroupName(e.target.value)} onBlur={handleSaveName} onKeyDown={(e) => e.key === 'Enter' && handleSaveName()} className="flex-1 px-2 py-1 border border-gray-300 rounded focus:ring-2 focus:ring-primary-500 focus:border-primary-500" /> ) : ( <> <h3 className="font-semibold text-gray-100">{group.name}</h3> <button type="button" onClick={() => setIsEditing(true)} className="text-gray-400 hover:text-gray-600" > <Edit2 className="w-4 h-4" /> </button> </> )} </div> <div className="flex items-center space-x-2"> <span className="text-sm text-gray-400">{groupTasks.length} tasks</span> <button type="button" onClick={() => deleteParallelGroup(group.id)} className="text-red-400 hover:text-red-600" > <Trash2 className="w-4 h-4" /> </button> </div> </div> {groupTasks.length > 0 ? ( <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-3"> {groupTasks.map((task) => ( <TaskCard key={task.id} task={task} isExecuting={isExecuting} /> ))} </div> ) : ( <div className="text-center py-8 text-gray-400 border-2 border-dashed border-gray-200 rounded-lg"> Drop tasks here to add them to this group </div> )} </div> ); }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/orneryd/Mimir'

If you have feedback or need assistance with the MCP directory API, please join our Discord server