122 lines
4.2 KiB
TypeScript
122 lines
4.2 KiB
TypeScript
"use client";
|
|
|
|
/**
|
|
* 프로시저/함수 호출 액션 노드
|
|
* 내부 또는 외부 DB의 프로시저/함수를 호출하는 노드
|
|
*/
|
|
|
|
import { memo } from "react";
|
|
import { Handle, Position, NodeProps } from "reactflow";
|
|
import { Database, Workflow } from "lucide-react";
|
|
import type { ProcedureCallActionNodeData } from "@/types/node-editor";
|
|
|
|
export const ProcedureCallActionNode = memo(
|
|
({ data, selected }: NodeProps<ProcedureCallActionNodeData>) => {
|
|
const hasProcedure = !!data.procedureName;
|
|
const inParams = data.parameters?.filter((p) => p.mode === "IN" || p.mode === "INOUT") ?? [];
|
|
const outParams = data.parameters?.filter((p) => p.mode === "OUT" || p.mode === "INOUT") ?? [];
|
|
|
|
return (
|
|
<div
|
|
className={`min-w-[250px] rounded-lg border-2 bg-white shadow-md transition-all ${
|
|
selected ? "border-violet-500 shadow-lg" : "border-gray-200"
|
|
}`}
|
|
>
|
|
{/* 입력 핸들 */}
|
|
<Handle
|
|
type="target"
|
|
position={Position.Left}
|
|
className="!h-3 !w-3 !border-2 !border-white !bg-violet-500"
|
|
/>
|
|
|
|
{/* 헤더 */}
|
|
<div className="flex items-center gap-2 rounded-t-lg bg-violet-500 px-3 py-2 text-white">
|
|
<Workflow className="h-4 w-4" />
|
|
<div className="flex-1">
|
|
<div className="text-sm font-semibold">
|
|
{data.displayName || "프로시저 호출"}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* 본문 */}
|
|
<div className="space-y-2 p-3">
|
|
{/* DB 소스 */}
|
|
<div className="flex items-center gap-2">
|
|
<Database className="h-3 w-3 text-gray-400" />
|
|
<span className="text-xs text-gray-600">
|
|
{data.dbSource === "external" ? (
|
|
<span className="rounded bg-amber-100 px-2 py-0.5 text-amber-700">
|
|
{data.connectionName || "외부 DB"}
|
|
</span>
|
|
) : (
|
|
<span className="rounded bg-blue-100 px-2 py-0.5 text-blue-700">
|
|
내부 DB
|
|
</span>
|
|
)}
|
|
</span>
|
|
<span
|
|
className={`ml-auto rounded px-2 py-0.5 text-xs font-medium ${
|
|
data.callType === "function"
|
|
? "bg-cyan-100 text-cyan-700"
|
|
: "bg-violet-100 text-violet-700"
|
|
}`}
|
|
>
|
|
{data.callType === "function" ? "FUNCTION" : "PROCEDURE"}
|
|
</span>
|
|
</div>
|
|
|
|
{/* 프로시저명 */}
|
|
<div className="flex items-center gap-2 text-xs">
|
|
<Workflow className="h-3 w-3 text-gray-400" />
|
|
{hasProcedure ? (
|
|
<span className="font-mono text-green-600 truncate">
|
|
{data.procedureSchema && data.procedureSchema !== "public"
|
|
? `${data.procedureSchema}.`
|
|
: ""}
|
|
{data.procedureName}()
|
|
</span>
|
|
) : (
|
|
<span className="text-orange-500">프로시저 선택 필요</span>
|
|
)}
|
|
</div>
|
|
|
|
{/* 파라미터 수 */}
|
|
{hasProcedure && inParams.length > 0 && (
|
|
<div className="text-xs text-gray-500">
|
|
입력 파라미터: {inParams.length}개
|
|
</div>
|
|
)}
|
|
|
|
{/* 반환 필드 */}
|
|
{hasProcedure && outParams.length > 0 && (
|
|
<div className="mt-1 space-y-1 border-t border-gray-100 pt-1">
|
|
<div className="text-[10px] font-medium text-green-600">
|
|
반환 필드:
|
|
</div>
|
|
{outParams.map((p) => (
|
|
<div
|
|
key={p.name}
|
|
className="flex items-center justify-between rounded bg-green-50 px-2 py-0.5 text-[10px]"
|
|
>
|
|
<span className="font-mono text-green-700">{p.name}</span>
|
|
<span className="text-gray-400">{p.dataType}</span>
|
|
</div>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* 출력 핸들 */}
|
|
<Handle
|
|
type="source"
|
|
position={Position.Right}
|
|
className="!h-3 !w-3 !border-2 !border-white !bg-violet-500"
|
|
/>
|
|
</div>
|
|
);
|
|
}
|
|
);
|
|
|
|
ProcedureCallActionNode.displayName = "ProcedureCallActionNode";
|