All files / src/components/WorkflowBuilder NodePalette.tsx

0% Statements 0/60
0% Branches 0/1
0% Functions 0/1
0% Lines 0/60

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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                                                                                                                                                                                         
/**
 * Node Palette Component
 *
 * Draggable palette of available node types.
 */
 
import { DragEvent } from 'react';
import type { NodePaletteItem, NodeCategory } from '../../lib/workflow-builder/types';
 
interface NodePaletteProps {
  categories: Record<NodeCategory, NodePaletteItem[]>;
  onDragStart: (type: string) => void;
  onDragEnd: () => void;
}
 
const categoryLabels: Record<NodeCategory, { label: string; color: string }> = {
  input: { label: 'Input', color: 'emerald' },
  ai: { label: 'AI & Skills', color: 'violet' },
  action: { label: 'Actions', color: 'amber' },
  control: { label: 'Control Flow', color: 'orange' },
  output: { label: 'Output', color: 'blue' },
};
 
export function NodePalette({ categories, onDragStart, onDragEnd }: NodePaletteProps) {
  const handleDragStart = (event: DragEvent, type: string) => {
    event.dataTransfer.setData('application/reactflow', type);
    event.dataTransfer.effectAllowed = 'move';
    onDragStart(type);
  };
 
  const handleDragEnd = () => {
    onDragEnd();
  };
 
  return (
    <div className="w-64 bg-white border-r border-gray-200 overflow-y-auto">
      <div className="p-4 border-b border-gray-200">
        <h2 className="font-semibold text-gray-800">Nodes</h2>
        <p className="text-sm text-gray-500">Drag nodes to canvas</p>
      </div>
 
      <div className="p-2">
        {(Object.keys(categories) as NodeCategory[]).map((category) => {
          const items = categories[category];
          if (items.length === 0) return null;
 
          const { label, color } = categoryLabels[category];
 
          return (
            <div key={category} className="mb-4">
              <h3
                className={`text-sm font-medium text-${color}-700 mb-2 px-2`}
              >
                {label}
              </h3>
 
              <div className="space-y-1">
                {items.map((item) => (
                  <div
                    key={item.type}
                    draggable
                    onDragStart={(e) => handleDragStart(e, item.type)}
                    onDragEnd={handleDragEnd}
                    className={`
                      flex items-center gap-3 px-3 py-2 rounded-lg
                      bg-gray-50 hover:bg-gray-100 cursor-grab
                      border border-transparent hover:border-gray-200
                      transition-all duration-150
                      active:cursor-grabbing
                    `}
                  >
                    <span className="text-lg">{item.icon}</span>
                    <div className="flex-1 min-w-0">
                      <div className="font-medium text-gray-700 text-sm">
                        {item.label}
                      </div>
                      <div className="text-xs text-gray-500 truncate">
                        {item.description}
                      </div>
                    </div>
                  </div>
                ))}
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
}
 
export default NodePalette;