File size: 3,915 Bytes
98d5416
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import React from 'react'
import Node from './Node'

export default function NodeCanvas({ 
  nodes, 
  connections, 
  selectedNode, 
  onSelectNode, 
  onEditNode, 
  onDeleteNode,
  onAddConnection,
  onNodeDragStart
}) {
  const getNodeColor = (type) => {
    switch (type) {
      case 'ceo': return 'from-yellow-500 to-amber-600'
      case 'claude': return 'from-violet-500 to-purple-600'
      case 'gemini': return 'from-blue-500 to-cyan-600'
      case 'openai': return 'from-emerald-500 to-teal-600'
      case 'llama': return 'from-orange-500 to-red-600'
      default: return 'from-slate-500 to-slate-600'
    }
  }

  const renderConnections = () => {
    return connections.map(conn => {
      const fromNode = nodes.find(n => n.id === conn.from)
      const toNode = nodes.find(n => n.id === conn.to)
      if (!fromNode || !toNode) return null

      const fromX = fromNode.position.x + 140
      const fromY = fromNode.position.y + 60
      const toX = toNode.position.x + 140
      const toY = toNode.position.y + 60

      const midX = (fromX + toX) / 2
      const controlOffset = Math.abs(toX - fromX) / 3

      return (
        <g key={conn.id}>
          <path
            d={`M ${fromX} ${fromY} C ${fromX + controlOffset} ${fromY}, ${toX - controlOffset} ${toY}, ${toX} ${toY}`}
            className={`node-connection ${conn.active ? 'active' : ''}`}
            markerEnd="url(#arrowhead)"
          />
          <circle
            cx={toX}
            cy={toY}
            r={6}
            fill={conn.active ? '#22c55e' : '#64748b'}
            className="cursor-pointer hover:fill-red-500 transition-colors"
            onClick={() => {
              if (confirm('Delete this connection?')) {
                onDeleteNode(conn.id)
              }

          />
        </g>
      )
    })
  }

  return (
    <div id="node-canvas" className="w-full h-full canvas-grid overflow-auto relative">
      <svg className="absolute inset-0 w-full h-full pointer-events-none" style={{ minWidth: '100%', minHeight: '100%' }}>
        <defs>
          <marker
            id="arrowhead"
            markerWidth="10"
            markerHeight="7"
            refX="9"
            refY="3.5"
            orient="auto"
          >
            <polygon points="0 0, 10 3.5, 0 7" fill="#64748b" />
          </marker>
        </defs>
        <g className="pointer-events-auto">
          {renderConnections()}
        </g>
      </svg>

      {nodes.map(node => (
        <Node
          key={node.id}
          node={node}
          isSelected={selectedNode?.id === node.id}
          color={getNodeColor(node.type)}
          onSelect={() => onSelectNode(node)}
          onEdit={() => onEditNode(node)}
          onDelete={() => onDeleteNode(node.id)}
          onAddConnection={() => onAddConnection(node.id)}
          onDragStart={(e) => onNodeDragStart(e, node)}
        />
      ))}

      {nodes.length === 0 && (
        <div className="absolute inset-0 flex items-center justify-center">
          <div className="text-center">
            <div className="w-20 h-20 mx-auto mb-4 bg-slate-700/50 rounded-2xl flex items-center justify-center">
              <svg className="w-10 h-10 text-slate-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M19.428 15.428a2 2 0 00-1.022-.547l-2.387-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z" />
              </svg>
            </div>
            <h3 className="text-lg font-medium text-slate-400">No agents yet</h3>
            <p className="text-sm text-slate-500 mt-1">Click "Add Node" to create your first agent</p>
          </div>
        </div>
      )}
    </div>
  )
}