Spaces:
Build error
Build error
| import React, { useState } from 'react' | |
| export default function NodeEditor({ node, modelOptions, onSave, onClose, onDelete }) { | |
| const [formData, setFormData] = useState({ | |
| name: node.name, | |
| type: node.type, | |
| model: node.model, | |
| apiKey: node.apiKey, | |
| brief: node.brief, | |
| }) | |
| const typeOptions = [ | |
| { value: 'ceo', label: 'CEO (Coordinator)', icon: '👑' }, | |
| { value: 'agent', label: 'Agent', icon: '🤖' }, | |
| { value: 'claude', label: 'Claude', icon: '🧠' }, | |
| { value: 'gemini', label: 'Gemini', icon: '💎' }, | |
| { value: 'openai', label: 'OpenAI', icon: '🤖' }, | |
| { value: 'llama', label: 'Llama', icon: '🦙' }, | |
| ] | |
| const allModels = [ | |
| ...modelOptions.claude, | |
| ...modelOptions.gemini, | |
| ...modelOptions.openai, | |
| ...modelOptions.llama, | |
| ] | |
| return ( | |
| <div className="fixed inset-0 bg-black/50 backdrop-blur-sm z-50 flex items-center justify-center p-4"> | |
| <div className="bg-slate-800 rounded-2xl border border-slate-700 w-full max-w-lg max-h-[90vh] overflow-hidden"> | |
| {/* Header */} | |
| <div className="p-4 border-b border-slate-700 flex items-center justify-between"> | |
| <h2 className="text-lg font-bold text-white">Edit Node: {node.name}</h2> | |
| <button | |
| onClick={onClose} | |
| className="w-8 h-8 bg-slate-700 hover:bg-slate-600 rounded-lg flex items-center justify-center text-slate-400 hover:text-white transition-colors" | |
| > | |
| ✕ | |
| </button> | |
| </div> | |
| {/* Content */} | |
| <div className="p-4 space-y-4 overflow-y-auto max-h-[calc(90vh-140px)]"> | |
| {/* Name */} | |
| <div> | |
| <label className="block text-sm font-medium text-slate-300 mb-1">Node Name</label> | |
| <input | |
| type="text" | |
| value={formData.name} | |
| onChange={(e) => setFormData({ ...formData, name: e.target.value })} | |
| className="w-full px-3 py-2 bg-slate-700 border border-slate-600 rounded-lg text-white focus:outline-none focus:ring-2 focus:ring-violet-500 focus:border-transparent" | |
| placeholder="Enter node name" | |
| /> | |
| </div> | |
| {/* Type */} | |
| <div> | |
| <label className="block text-sm font-medium text-slate-300 mb-1">Node Type</label> | |
| <div className="grid grid-cols-3 gap-2"> | |
| {typeOptions.map((type) => ( | |
| <button | |
| key={type.value} | |
| onClick={() => setFormData({ ...formData, type: type.value })} | |
| className={`px-3 py-2 rounded-lg text-sm font-medium transition-all ${ | |
| formData.type === type.value | |
| ? 'bg-violet-600 text-white' | |
| : 'bg-slate-700 text-slate-300 hover:bg-slate-600' | |
| }`} | |
| > | |
| {type.icon} {type.label} | |
| </button> | |
| ))} | |
| </div> | |
| </div> | |
| {/* Model */} | |
| <div> | |
| <label className="block text-sm font-medium text-slate-300 mb-1">Model</label> | |
| <select | |
| value={formData.model} | |
| onChange={(e) => setFormData({ ...formData, model: e.target.value })} | |
| className="w-full px-3 py-2 bg-slate-700 border border-slate-600 rounded-lg text-white focus:outline-none focus:ring-2 focus:ring-violet-500 focus:border-transparent" | |
| > | |
| {allModels.map((model) => ( | |
| <option key={model} value={model}>{model}</option> | |
| ))} | |
| </select> | |
| </div> | |
| {/* API Key */} | |
| <div> | |
| <label className="block text-sm font-medium text-slate-300 mb-1">API Key</label> | |
| <input | |
| type="password" | |
| value={formData.apiKey} | |
| onChange={(e) => setFormData({ ...formData, apiKey: e.target.value })} | |
| className="w-full px-3 py-2 bg-slate-700 border border-slate-600 rounded-lg text-white focus:outline-none focus:ring-2 focus:ring-violet-500 focus:border-transparent" | |
| placeholder="Enter API key" | |
| /> | |
| <p className="text-xs text-slate-500 mt-1">Your API key is stored locally and never shared</p> | |
| </div> | |
| {/* Brief */} | |
| <div> | |
| <label className="block text-sm font-medium text-slate-300 mb-1">Agent Brief</label> | |
| <textarea | |
| value={formData.brief} | |
| onChange={(e) => setFormData({ ...formData, brief: e.target.value })} | |
| rows={4} | |
| className="w-full px-3 py-2 bg-slate-700 border border-slate-600 rounded-lg text-white focus:outline-none focus:ring-2 focus:ring-violet-500 focus:border-transparent resize-none" | |
| placeholder="Describe the agent's role and behavior..." | |
| /> | |
| </div> | |
| </div> | |
| {/* Footer */} | |
| <div className="p-4 border-t border-slate-700 flex justify-between"> | |
| {node.type !== 'ceo' ? ( | |
| <button | |
| onClick={onDelete} | |
| className="px-4 py-2 bg-red-900/30 hover:bg-red-900/50 text-red-400 rounded-lg font-medium transition-colors" | |
| > | |
| Delete Node | |
| </button> | |
| ) : ( | |
| <div></div> | |
| )} | |
| <div className="flex gap-2"> | |
| <button | |
| onClick={onClose} | |
| className="px-4 py-2 bg-slate-700 hover:bg-slate-600 text-slate-300 rounded-lg font-medium transition-colors" | |
| > | |
| Cancel | |
| </button> | |
| <button | |
| onClick={() => onSave(formData)} | |
| className="px-4 py-2 bg-gradient-to-r from-violet-600 to-fuchsia-600 hover:from-violet-500 hover:to-fuchsia-500 text-white rounded-lg font-medium transition-all" | |
| > | |
| Save Changes | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| ) | |
| } |