- 8 node types (Model, Solver, DesignVar, Extractor, Objective, Constraint, Algorithm, Surrogate) - Drag-drop from palette to canvas - Node configuration panels - Graph validation with error/warning display - Intent JSON serialization - Zustand state management Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
73 lines
1.8 KiB
TypeScript
73 lines
1.8 KiB
TypeScript
import { memo, ReactNode } from 'react';
|
|
import { Handle, Position, NodeProps } from 'reactflow';
|
|
import { BaseNodeData } from '../../../lib/canvas/schema';
|
|
|
|
interface BaseNodeProps extends NodeProps<BaseNodeData> {
|
|
icon: ReactNode;
|
|
color: string;
|
|
children?: ReactNode;
|
|
inputs?: number;
|
|
outputs?: number;
|
|
}
|
|
|
|
function BaseNodeComponent({
|
|
data,
|
|
selected,
|
|
icon,
|
|
color,
|
|
children,
|
|
inputs = 1,
|
|
outputs = 1,
|
|
}: BaseNodeProps) {
|
|
return (
|
|
<div
|
|
className={`
|
|
px-4 py-3 rounded-lg border-2 min-w-[180px] bg-white shadow-sm
|
|
transition-all duration-200
|
|
${selected ? 'border-blue-500 shadow-lg' : 'border-gray-200'}
|
|
${!data.configured ? 'border-dashed' : ''}
|
|
${data.errors?.length ? 'border-red-400' : ''}
|
|
`}
|
|
>
|
|
{/* Input handles */}
|
|
{inputs > 0 && (
|
|
<Handle
|
|
type="target"
|
|
position={Position.Left}
|
|
className="w-3 h-3 !bg-gray-400"
|
|
/>
|
|
)}
|
|
|
|
{/* Header */}
|
|
<div className="flex items-center gap-2 mb-2">
|
|
<span className={`text-lg ${color}`}>{icon}</span>
|
|
<span className="font-medium text-gray-800">{data.label}</span>
|
|
{!data.configured && (
|
|
<span className="text-xs text-orange-500">!</span>
|
|
)}
|
|
</div>
|
|
|
|
{/* Content */}
|
|
{children && <div className="text-sm text-gray-600">{children}</div>}
|
|
|
|
{/* Errors */}
|
|
{data.errors?.length ? (
|
|
<div className="mt-2 text-xs text-red-500">
|
|
{data.errors[0]}
|
|
</div>
|
|
) : null}
|
|
|
|
{/* Output handles */}
|
|
{outputs > 0 && (
|
|
<Handle
|
|
type="source"
|
|
position={Position.Right}
|
|
className="w-3 h-3 !bg-gray-400"
|
|
/>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export const BaseNode = memo(BaseNodeComponent);
|