"use client"; import React, { useState, useEffect } from "react"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Badge } from "@/components/ui/badge"; import { Textarea } from "@/components/ui/textarea"; import { ArrowRight, Link, Key, Save, Globe, Plus } from "lucide-react"; import { DataFlowAPI, TableRelationship, TableInfo, ColumnInfo } from "@/lib/api/dataflow"; import toast from "react-hot-toast"; // 연결 정보 타입 interface ConnectionInfo { fromNode: { id: string; tableName: string; displayName: string; }; toNode: { id: string; tableName: string; displayName: string; }; fromColumn?: string; toColumn?: string; selectedColumnsData?: { [tableName: string]: { displayName: string; columns: string[]; }; }; existingRelationship?: { relationshipName: string; relationshipType: string; connectionType: string; settings?: any; }; } // 연결 설정 타입 interface ConnectionConfig { relationshipName: string; relationshipType: "one-to-one" | "one-to-many" | "many-to-one" | "many-to-many"; connectionType: "simple-key" | "data-save" | "external-call"; fromColumnName: string; toColumnName: string; settings?: Record; description?: string; } // 단순 키값 연결 설정 interface SimpleKeySettings { notes: string; } // 데이터 저장 설정 interface DataSaveSettings { sourceField: string; targetField: string; saveConditions: string; } // 외부 호출 설정 interface ExternalCallSettings { callType: "rest-api" | "email" | "webhook" | "ftp" | "queue"; apiUrl?: string; httpMethod?: "GET" | "POST" | "PUT" | "DELETE"; headers?: string; bodyTemplate?: string; } interface ConnectionSetupModalProps { isOpen: boolean; connection: ConnectionInfo | null; companyCode: string; diagramId?: number; onConfirm: (relationship: TableRelationship) => void; onCancel: () => void; } export const ConnectionSetupModal: React.FC = ({ isOpen, connection, companyCode, diagramId, onConfirm, onCancel, }) => { const [config, setConfig] = useState({ relationshipName: "", relationshipType: "one-to-one", connectionType: "simple-key", fromColumnName: "", toColumnName: "", description: "", settings: {}, }); // 연결 종류별 설정 상태 const [simpleKeySettings, setSimpleKeySettings] = useState({ notes: "", }); const [dataSaveSettings, setDataSaveSettings] = useState({ sourceField: "", targetField: "", saveConditions: "", }); const [externalCallSettings, setExternalCallSettings] = useState({ callType: "rest-api", apiUrl: "", httpMethod: "POST", headers: "{}", bodyTemplate: "{}", }); // 테이블 및 컬럼 선택을 위한 새로운 상태들 const [availableTables, setAvailableTables] = useState([]); const [selectedFromTable, setSelectedFromTable] = useState(""); const [selectedToTable, setSelectedToTable] = useState(""); const [fromTableColumns, setFromTableColumns] = useState([]); const [toTableColumns, setToTableColumns] = useState([]); const [selectedFromColumns, setSelectedFromColumns] = useState([]); const [selectedToColumns, setSelectedToColumns] = useState([]); // 테이블 목록 로드 useEffect(() => { const loadTables = async () => { try { const tables = await DataFlowAPI.getTables(); setAvailableTables(tables); } catch (error) { console.error("테이블 목록 로드 실패:", error); toast.error("테이블 목록을 불러오는데 실패했습니다."); } }; if (isOpen) { loadTables(); } }, [isOpen]); // 모달이 열릴 때 기본값 설정 useEffect(() => { if (isOpen && connection) { const fromTableName = connection.fromNode.tableName; const toTableName = connection.toNode.tableName; const fromDisplayName = connection.fromNode.displayName; const toDisplayName = connection.toNode.displayName; // 테이블 선택 설정 setSelectedFromTable(fromTableName); setSelectedToTable(toTableName); // 기존 관계 정보가 있으면 사용, 없으면 기본값 설정 const existingRel = connection.existingRelationship; setConfig({ relationshipName: existingRel?.relationshipName || `${fromDisplayName} → ${toDisplayName}`, relationshipType: (existingRel?.relationshipType as "one-to-one" | "one-to-many" | "many-to-one" | "many-to-many") || "one-to-one", connectionType: (existingRel?.connectionType as "simple-key" | "data-save" | "external-call") || "simple-key", fromColumnName: "", toColumnName: "", description: existingRel?.settings?.description || `${fromDisplayName}과 ${toDisplayName} 간의 데이터 관계`, settings: existingRel?.settings || {}, }); // 단순 키값 연결 기본값 설정 setSimpleKeySettings({ notes: `${fromDisplayName}과 ${toDisplayName} 간의 키값 연결`, }); // 데이터 저장 기본값 설정 setDataSaveSettings({ sourceField: "", targetField: "", saveConditions: "데이터 저장 조건을 입력하세요", }); // 외부 호출 기본값 설정 setExternalCallSettings({ callType: "rest-api", apiUrl: "https://api.example.com/webhook", httpMethod: "POST", headers: "{}", bodyTemplate: "{}", }); // 선택된 컬럼 정보가 있다면 설정 if (connection.selectedColumnsData) { const fromColumns = connection.selectedColumnsData[fromTableName]?.columns || []; const toColumns = connection.selectedColumnsData[toTableName]?.columns || []; setSelectedFromColumns(fromColumns); setSelectedToColumns(toColumns); setConfig((prev) => ({ ...prev, fromColumnName: fromColumns.join(", "), toColumnName: toColumns.join(", "), })); } } }, [isOpen, connection]); // From 테이블 선택 시 컬럼 로드 useEffect(() => { const loadFromColumns = async () => { if (selectedFromTable) { try { const columns = await DataFlowAPI.getTableColumns(selectedFromTable); setFromTableColumns(columns); } catch (error) { console.error("From 테이블 컬럼 로드 실패:", error); toast.error("From 테이블 컬럼을 불러오는데 실패했습니다."); } } }; loadFromColumns(); }, [selectedFromTable]); // To 테이블 선택 시 컬럼 로드 useEffect(() => { const loadToColumns = async () => { if (selectedToTable) { try { const columns = await DataFlowAPI.getTableColumns(selectedToTable); setToTableColumns(columns); } catch (error) { console.error("To 테이블 컬럼 로드 실패:", error); toast.error("To 테이블 컬럼을 불러오는데 실패했습니다."); } } }; loadToColumns(); }, [selectedToTable]); // 선택된 컬럼들이 변경될 때 config 업데이트 useEffect(() => { setConfig((prev) => ({ ...prev, fromColumnName: selectedFromColumns.join(", "), toColumnName: selectedToColumns.join(", "), })); }, [selectedFromColumns, selectedToColumns]); const handleConfirm = () => { if (!config.relationshipName || !connection) { toast.error("필수 정보를 모두 입력해주세요."); return; } // 연결 종류별 설정을 준비 let settings = {}; switch (config.connectionType) { case "simple-key": settings = simpleKeySettings; break; case "data-save": settings = dataSaveSettings; break; case "external-call": settings = externalCallSettings; break; } // 선택된 컬럼들 검증 if (selectedFromColumns.length === 0 || selectedToColumns.length === 0) { toast.error("선택된 컬럼이 없습니다. From과 To 테이블에서 각각 최소 1개 이상의 컬럼을 선택해주세요."); return; } // 선택된 테이블과 컬럼 정보 사용 const fromTableName = selectedFromTable || connection.fromNode.tableName; const toTableName = selectedToTable || connection.toNode.tableName; // 메모리 기반 시스템: 관계 데이터만 생성하여 부모로 전달 const relationshipData: TableRelationship = { relationship_name: config.relationshipName, from_table_name: fromTableName, to_table_name: toTableName, from_column_name: selectedFromColumns.join(","), // 여러 컬럼을 콤마로 구분 to_column_name: selectedToColumns.join(","), // 여러 컬럼을 콤마로 구분 relationship_type: config.relationshipType as any, connection_type: config.connectionType as any, company_code: companyCode, settings: { ...settings, description: config.description, multiColumnMapping: { fromColumns: selectedFromColumns, toColumns: selectedToColumns, fromTable: fromTableName, toTable: toTableName, }, isMultiColumn: selectedFromColumns.length > 1 || selectedToColumns.length > 1, columnCount: { from: selectedFromColumns.length, to: selectedToColumns.length, }, }, }; toast.success("관계가 생성되었습니다!"); // 부모 컴포넌트로 관계 데이터 전달 (DB 저장 없이) onConfirm(relationshipData); handleCancel(); // 모달 닫기 }; const handleCancel = () => { setConfig({ relationshipName: "", relationshipType: "one-to-one", connectionType: "simple-key", fromColumnName: "", toColumnName: "", description: "", }); onCancel(); }; if (!connection) return null; // 선택된 컬럼 데이터 가져오기 const selectedColumnsData = connection.selectedColumnsData || {}; const tableNames = Object.keys(selectedColumnsData); const fromTable = tableNames[0]; const toTable = tableNames[1]; const fromTableData = selectedColumnsData[fromTable]; const toTableData = selectedColumnsData[toTable]; // 연결 종류별 설정 패널 렌더링 const renderConnectionTypeSettings = () => { switch (config.connectionType) { case "simple-key": return (
단순 키값 연결 설정