/** * 플로우 노드 컴포넌트 * React Flow 커스텀 노드 */ import { memo } from "react"; import { Handle, Position, NodeProps } from "reactflow"; import { FlowNodeData, FlowCondition, ConditionOperator } from "@/types/flow"; import { Badge } from "@/components/ui/badge"; // 조건을 자연어로 변환하는 헬퍼 함수 const formatCondition = (cond: FlowCondition): string => { const operatorLabels: Record = { equals: "=", not_equals: "≠", greater_than: ">", less_than: "<", greater_than_or_equal: "≥", less_than_or_equal: "≤", in: "IN", not_in: "NOT IN", like: "LIKE", not_like: "NOT LIKE", is_null: "IS NULL", is_not_null: "IS NOT NULL", }; const operatorLabel = operatorLabels[cond.operator] || cond.operator; if (cond.operator === "is_null" || cond.operator === "is_not_null") { return `${cond.column} ${operatorLabel}`; } return `${cond.column} ${operatorLabel} "${cond.value || ""}"`; }; const formatAllConditions = (data: FlowNodeData): string => { if (!data.condition || data.condition.conditions.length === 0) { return "조건 없음"; } const conditions = data.condition.conditions; const type = data.condition.type; // 조건이 많으면 간략하게 표시 if (conditions.length > 2) { return `${conditions.length}개 조건 (${type})`; } const connector = type === "AND" ? " AND " : " OR "; return conditions.map(formatCondition).join(connector); }; export const FlowNodeComponent = memo(({ data }: NodeProps) => { return (
{/* 입력 핸들 */} {/* 노드 내용 */}
단계 {data.stepOrder}
{data.label}
{/* 테이블 정보 */} {data.tableName && (
📊 {data.tableName}
)} {/* 데이터 건수 */} {data.count !== undefined && ( {data.count}건 )} {/* 조건 미리보기 */} {data.condition && data.condition.conditions.length > 0 ? (
조건:
{formatAllConditions(data)}
) : (
조건 없음
)}
{/* 출력 핸들 */}
); }); FlowNodeComponent.displayName = "FlowNodeComponent";