"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 { Link, Key, Save, Globe, Plus, Zap, Trash2 } from "lucide-react"; import { DataFlowAPI, TableRelationship, TableInfo, ColumnInfo, ConditionNode } 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; connectionType: string; settings?: Record; }; } // 연결 설정 타입 interface ConnectionConfig { relationshipName: string; connectionType: "simple-key" | "data-save" | "external-call"; fromColumnName: string; toColumnName: string; settings?: Record; } // 단순 키값 연결 설정 interface SimpleKeySettings { notes: string; } // 데이터 저장 설정 interface DataSaveSettings { actions: Array<{ id: string; name: string; actionType: "insert" | "update" | "delete" | "upsert"; conditions?: ConditionNode[]; fieldMappings: Array<{ sourceTable?: string; sourceField: string; targetTable?: string; targetField: string; defaultValue?: string; transformFunction?: string; }>; splitConfig?: { sourceField: string; // 분할할 소스 필드 delimiter: string; // 구분자 (예: ",") targetField: 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; onConfirm: (relationship: TableRelationship) => void; onCancel: () => void; } export const ConnectionSetupModal: React.FC = ({ isOpen, connection, companyCode, onConfirm, onCancel, }) => { const [config, setConfig] = useState({ relationshipName: "", connectionType: "simple-key", fromColumnName: "", toColumnName: "", settings: {}, }); // 연결 종류별 설정 상태 const [simpleKeySettings, setSimpleKeySettings] = useState({ notes: "", }); const [dataSaveSettings, setDataSaveSettings] = useState({ actions: [], }); 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([]); // 필요시 로드하는 테이블 컬럼 캐시 const [tableColumnsCache, setTableColumnsCache] = useState<{ [tableName: string]: ColumnInfo[] }>({}); // 조건부 연결을 위한 새로운 상태들 const [conditions, setConditions] = 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; const connectionType = (existingRel?.connectionType as "simple-key" | "data-save" | "external-call") || "simple-key"; setConfig({ relationshipName: existingRel?.relationshipName || `${fromDisplayName} → ${toDisplayName}`, connectionType, fromColumnName: "", toColumnName: "", settings: existingRel?.settings || {}, }); // 🔥 기존 설정 데이터 로드 if (existingRel?.settings) { const settings = existingRel.settings; if (connectionType === "simple-key" && settings.notes) { setSimpleKeySettings({ notes: settings.notes as string, }); } else if (connectionType === "data-save" && settings.actions) { // data-save 설정 로드 - 안전하게 처리 const actionsData = Array.isArray(settings.actions) ? settings.actions : []; setDataSaveSettings({ actions: actionsData.map((action: Record) => ({ id: (action.id as string) || `action-${Date.now()}`, name: (action.name as string) || "새 액션", actionType: (action.actionType as "insert" | "update" | "delete" | "upsert") || "insert", conditions: Array.isArray(action.conditions) ? action.conditions.map( (condition: Record) => ({ ...condition, operator: condition.operator || "=", // 기본값 보장 }) as ConditionNode, ) : [], fieldMappings: Array.isArray(action.fieldMappings) ? action.fieldMappings.map((mapping: Record) => ({ sourceTable: (mapping.sourceTable as string) || "", sourceField: (mapping.sourceField as string) || "", targetTable: (mapping.targetTable as string) || "", targetField: (mapping.targetField as string) || "", defaultValue: (mapping.defaultValue as string) || "", transformFunction: (mapping.transformFunction as string) || "", })) : [], splitConfig: action.splitConfig ? { sourceField: ((action.splitConfig as Record).sourceField as string) || "", delimiter: ((action.splitConfig as Record).delimiter as string) || ",", targetField: ((action.splitConfig as Record).targetField as string) || "", } : undefined, })), }); // 전체 실행 조건 로드 - 안전하게 처리 if (settings.control) { const controlSettings = settings.control as { conditionTree?: ConditionNode[] }; if (Array.isArray(controlSettings.conditionTree)) { // 기존 조건이 없을 때만 로드 (사용자가 추가한 조건 보존) setConditions((prevConditions) => { if (prevConditions.length === 0) { return controlSettings.conditionTree || []; } return prevConditions; }); } else { // 기존 조건이 없을 때만 초기화 setConditions((prevConditions) => (prevConditions.length === 0 ? [] : prevConditions)); } } else { // 기존 조건이 없을 때만 초기화 setConditions((prevConditions) => (prevConditions.length === 0 ? [] : prevConditions)); } } else if (connectionType === "external-call") { setExternalCallSettings({ callType: (settings.callType as "rest-api" | "webhook") || "rest-api", apiUrl: (settings.apiUrl as string) || "", httpMethod: (settings.httpMethod as "GET" | "POST" | "PUT" | "DELETE") || "POST", headers: (settings.headers as string) || "{}", bodyTemplate: (settings.bodyTemplate as string) || "{}", }); } } else { // 기본값 설정 setSimpleKeySettings({ notes: `${fromDisplayName}과 ${toDisplayName} 간의 키값 연결`, }); setDataSaveSettings({ actions: [], }); } // 🔥 필드 선택 상태 초기화 setSelectedFromColumns([]); setSelectedToColumns([]); // 외부 호출 기본값 설정 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 loadTableColumns = async (tableName: string): Promise => { if (tableColumnsCache[tableName]) { return tableColumnsCache[tableName]; } try { const columns = await DataFlowAPI.getTableColumns(tableName); setTableColumnsCache((prev) => ({ ...prev, [tableName]: columns, })); return columns; } catch (error) { console.error(`${tableName} 컬럼 로드 실패:`, error); return []; } }; // 테이블 선택 시 컬럼 로드 useEffect(() => { const loadColumns = async () => { const tablesToLoad = new Set(); // 필드 매핑에서 사용되는 모든 테이블 수집 (dataSaveSettings.actions || []).forEach((action) => { (action.fieldMappings || []).forEach((mapping) => { if (mapping.sourceTable && !tableColumnsCache[mapping.sourceTable]) { tablesToLoad.add(mapping.sourceTable); } if (mapping.targetTable && !tableColumnsCache[mapping.targetTable]) { tablesToLoad.add(mapping.targetTable); } }); }); // 필요한 테이블들의 컬럼만 로드 for (const tableName of tablesToLoad) { await loadTableColumns(tableName); } }; loadColumns(); }, [dataSaveSettings.actions, tableColumnsCache]); // eslint-disable-line react-hooks/exhaustive-deps 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 (config.connectionType === "simple-key") { 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 conditionalSettings = isConditionalConnection() ? { control: { triggerType: "insert", conditionTree: conditions.length > 0 ? conditions : null, }, category: { type: config.connectionType, }, plan: { sourceTable: fromTableName, targetActions: config.connectionType === "data-save" ? dataSaveSettings.actions.map((action) => ({ id: action.id, actionType: action.actionType, enabled: true, conditions: action.conditions?.map((condition) => { // 모든 조건 타입에 대해 operator 필드 보장 const baseCondition = { ...condition }; if (condition.type === "condition") { baseCondition.operator = condition.operator || "="; } return baseCondition; }) || [], fieldMappings: action.fieldMappings.map((mapping) => ({ sourceTable: mapping.sourceTable, sourceField: mapping.sourceField, targetTable: mapping.targetTable, targetField: mapping.targetField, defaultValue: mapping.defaultValue, transformFunction: mapping.transformFunction, })), splitConfig: action.splitConfig, })) : [], }, } : {}; // 컬럼 정보는 단순 키값 연결일 때만 사용 const finalFromColumns = config.connectionType === "simple-key" ? selectedFromColumns : []; const finalToColumns = config.connectionType === "simple-key" ? selectedToColumns : []; // 메모리 기반 시스템: 관계 데이터만 생성하여 부모로 전달 const relationshipData: TableRelationship = { relationship_name: config.relationshipName, from_table_name: fromTableName, to_table_name: toTableName, from_column_name: finalFromColumns.join(","), // 여러 컬럼을 콤마로 구분 to_column_name: finalToColumns.join(","), // 여러 컬럼을 콤마로 구분 connection_type: config.connectionType, company_code: companyCode, settings: { ...settings, ...conditionalSettings, // 조건부 연결 설정 추가 // 중복 제거: multiColumnMapping, isMultiColumn, columnCount, description 제거 // 필요시 from_column_name, to_column_name에서 split으로 추출 가능 }, }; toast.success("관계가 생성되었습니다!"); // 부모 컴포넌트로 관계 데이터 전달 (DB 저장 없이) onConfirm(relationshipData); handleCancel(); // 모달 닫기 }; const handleCancel = () => { setConfig({ relationshipName: "", connectionType: "simple-key", fromColumnName: "", toColumnName: "", }); onCancel(); }; if (!connection) return null; // 선택된 컬럼 데이터 가져오기 (현재 사용되지 않음 - 향후 확장을 위해 유지) // const selectedColumnsData = connection.selectedColumnsData || {}; // 조건부 연결인지 확인하는 헬퍼 함수 const isConditionalConnection = () => { return config.connectionType === "data-save" || config.connectionType === "external-call"; }; // 고유 ID 생성 헬퍼 const generateId = () => `cond_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; // 조건 관리 헬퍼 함수들 const addCondition = () => { const newCondition: ConditionNode = { id: generateId(), type: "condition" as const, field: "", operator: "=", value: "", dataType: "string", // 첫 번째 조건이 아니고, 바로 앞이 group-start가 아니면 logicalOperator 추가 ...(conditions.length > 0 && conditions[conditions.length - 1]?.type !== "group-start" && { logicalOperator: "AND" as const }), }; setConditions([...conditions, newCondition]); }; // 그룹 시작 추가 const addGroupStart = () => { const groupId = `group_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; const groupLevel = getNextGroupLevel(); const groupStart: ConditionNode = { id: generateId(), type: "group-start" as const, groupId, groupLevel, // 첫 번째 그룹이 아니면 logicalOperator 추가 ...(conditions.length > 0 && { logicalOperator: "AND" as const }), }; setConditions([...conditions, groupStart]); }; // 그룹 끝 추가 const addGroupEnd = () => { // 가장 최근에 열린 그룹 찾기 const openGroups = findOpenGroups(); if (openGroups.length === 0) { toast.error("닫을 그룹이 없습니다."); return; } const lastOpenGroup = openGroups[openGroups.length - 1]; const groupEnd: ConditionNode = { id: generateId(), type: "group-end" as const, groupId: lastOpenGroup.groupId, groupLevel: lastOpenGroup.groupLevel, }; setConditions([...conditions, groupEnd]); }; // 다음 그룹 레벨 계산 const getNextGroupLevel = (): number => { const openGroups = findOpenGroups(); return openGroups.length; }; // 열린 그룹 찾기 const findOpenGroups = () => { const openGroups: Array<{ groupId: string; groupLevel: number }> = []; for (const condition of conditions) { if (condition.type === "group-start") { openGroups.push({ groupId: condition.groupId!, groupLevel: condition.groupLevel!, }); } else if (condition.type === "group-end") { // 해당 그룹 제거 const groupIndex = openGroups.findIndex((g) => g.groupId === condition.groupId); if (groupIndex !== -1) { openGroups.splice(groupIndex, 1); } } } return openGroups; }; const updateCondition = (index: number, field: keyof ConditionNode, value: string) => { const updatedConditions = [...conditions]; updatedConditions[index] = { ...updatedConditions[index], [field]: value }; setConditions(updatedConditions); }; const removeCondition = (index: number) => { const conditionToRemove = conditions[index]; // 그룹 시작/끝을 삭제하는 경우 해당 그룹 전체 삭제 if (conditionToRemove.type === "group-start" || conditionToRemove.type === "group-end") { removeGroup(conditionToRemove.groupId!); } else { const updatedConditions = conditions.filter((_, i) => i !== index); setConditions(updatedConditions); } }; // 그룹 전체 삭제 const removeGroup = (groupId: string) => { const updatedConditions = conditions.filter((c) => c.groupId !== groupId); setConditions(updatedConditions); }; // 현재 조건의 그룹 레벨 계산 const getCurrentGroupLevel = (conditionIndex: number): number => { let level = 0; for (let i = 0; i < conditionIndex; i++) { const condition = conditions[i]; if (condition.type === "group-start") { level++; } else if (condition.type === "group-end") { level--; } } return level; }; // 액션별 조건 그룹 관리 함수들 const addActionGroupStart = (actionIndex: number) => { const groupId = `action_group_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; const currentConditions = dataSaveSettings.actions[actionIndex].conditions || []; const groupLevel = getActionNextGroupLevel(currentConditions); const groupStart: ConditionNode = { id: generateId(), type: "group-start" as const, groupId, groupLevel, // 첫 번째 그룹이 아니면 logicalOperator 추가 ...(currentConditions.length > 0 && { logicalOperator: "AND" as const }), }; const newActions = [...dataSaveSettings.actions]; newActions[actionIndex].conditions = [...currentConditions, groupStart]; setDataSaveSettings({ ...dataSaveSettings, actions: newActions }); }; const addActionGroupEnd = (actionIndex: number) => { const currentConditions = dataSaveSettings.actions[actionIndex].conditions || []; const openGroups = findActionOpenGroups(currentConditions); if (openGroups.length === 0) { toast.error("닫을 그룹이 없습니다."); return; } const lastOpenGroup = openGroups[openGroups.length - 1]; const groupEnd: ConditionNode = { id: generateId(), type: "group-end" as const, groupId: lastOpenGroup.groupId, groupLevel: lastOpenGroup.groupLevel, }; const newActions = [...dataSaveSettings.actions]; newActions[actionIndex].conditions = [...currentConditions, groupEnd]; setDataSaveSettings({ ...dataSaveSettings, actions: newActions }); }; // 액션별 다음 그룹 레벨 계산 const getActionNextGroupLevel = (conditions: ConditionNode[]): number => { const openGroups = findActionOpenGroups(conditions); return openGroups.length; }; // 액션별 열린 그룹 찾기 const findActionOpenGroups = (conditions: ConditionNode[]) => { const openGroups: Array<{ groupId: string; groupLevel: number }> = []; for (const condition of conditions) { if (condition.type === "group-start") { openGroups.push({ groupId: condition.groupId!, groupLevel: condition.groupLevel!, }); } else if (condition.type === "group-end") { const groupIndex = openGroups.findIndex((g) => g.groupId === condition.groupId); if (groupIndex !== -1) { openGroups.splice(groupIndex, 1); } } } return openGroups; }; // 액션별 현재 조건의 그룹 레벨 계산 const getActionCurrentGroupLevel = (conditions: ConditionNode[], conditionIndex: number): number => { let level = 0; for (let i = 0; i < conditionIndex; i++) { const condition = conditions[i]; if (condition.type === "group-start") { level++; } else if (condition.type === "group-end") { level--; } } return level; }; // 액션별 조건 렌더링 함수 const renderActionCondition = (condition: ConditionNode, condIndex: number, actionIndex: number) => { // 그룹 시작 렌더링 if (condition.type === "group-start") { return (
{/* 그룹 시작 앞의 논리 연산자 */} {condIndex > 0 && ( )}
( 그룹 시작
); } // 그룹 끝 렌더링 if (condition.type === "group-end") { return (
) 그룹 끝
); } // 일반 조건 렌더링 (기존 로직 간소화) return (
{/* 그룹 내 첫 번째 조건이 아닐 때만 논리 연산자 표시 */} {condIndex > 0 && dataSaveSettings.actions[actionIndex].conditions![condIndex - 1]?.type !== "group-start" && ( )}
{/* 데이터 타입에 따른 동적 입력 컴포넌트 */} {(() => { const selectedColumn = fromTableColumns.find((col) => col.columnName === condition.field); const dataType = selectedColumn?.dataType?.toLowerCase() || "string"; if (dataType.includes("timestamp") || dataType.includes("datetime") || dataType.includes("date")) { return ( { const newActions = [...dataSaveSettings.actions]; newActions[actionIndex].conditions![condIndex].value = e.target.value; setDataSaveSettings({ ...dataSaveSettings, actions: newActions }); }} className="h-6 flex-1 text-xs" /> ); } else if (dataType.includes("time")) { return ( { const newActions = [...dataSaveSettings.actions]; newActions[actionIndex].conditions![condIndex].value = e.target.value; setDataSaveSettings({ ...dataSaveSettings, actions: newActions }); }} className="h-6 flex-1 text-xs" /> ); } else if (dataType.includes("date")) { return ( { const newActions = [...dataSaveSettings.actions]; newActions[actionIndex].conditions![condIndex].value = e.target.value; setDataSaveSettings({ ...dataSaveSettings, actions: newActions }); }} className="h-6 flex-1 text-xs" /> ); } else if ( dataType.includes("int") || dataType.includes("numeric") || dataType.includes("decimal") || dataType.includes("float") || dataType.includes("double") ) { return ( { const newActions = [...dataSaveSettings.actions]; newActions[actionIndex].conditions![condIndex].value = e.target.value; setDataSaveSettings({ ...dataSaveSettings, actions: newActions }); }} className="h-6 flex-1 text-xs" /> ); } else if (dataType.includes("bool")) { return ( ); } else { return ( { const newActions = [...dataSaveSettings.actions]; newActions[actionIndex].conditions![condIndex].value = e.target.value; setDataSaveSettings({ ...dataSaveSettings, actions: newActions }); }} className="h-6 flex-1 text-xs" /> ); } })()}
); }; // 조건부 연결 설정 UI 렌더링 const renderConditionalSettings = () => { return (
전체 실행 조건 (언제 이 연결이 동작할지)
{/* 실행 조건 설정 */}
{/* 조건 목록 */}
{conditions.length === 0 ? (
조건을 추가하면 해당 조건을 만족할 때만 실행됩니다.
조건이 없으면 항상 실행됩니다.
) : ( {conditions.map((condition, index) => { // 그룹 시작 렌더링 if (condition.type === "group-start") { return (
{/* 그룹 시작 앞의 논리 연산자 - 이전 요소가 group-end가 아닌 경우에만 표시 */} {index > 0 && conditions[index - 1]?.type !== "group-end" && ( )} {/* 그룹 레벨에 따른 들여쓰기 */}
( 그룹 시작
); } // 그룹 끝 렌더링 if (condition.type === "group-end") { return (
) 그룹 끝
{/* 그룹 끝 다음에 다른 조건이나 그룹이 있으면 논리 연산자 표시 */} {index < conditions.length - 1 && ( )}
); } // 일반 조건 렌더링 return (
{/* 일반 조건 앞의 논리 연산자 - 이전 요소가 group-end가 아닌 경우에만 표시 */} {index > 0 && conditions[index - 1]?.type !== "group-start" && conditions[index - 1]?.type !== "group-end" && ( )} {/* 그룹 레벨에 따른 들여쓰기와 조건 필드들 */}
{/* 조건 필드 선택 */} {/* 연산자 선택 */} {/* 데이터 타입에 따른 동적 입력 컴포넌트 */} {(() => { const selectedColumn = fromTableColumns.find((col) => col.columnName === condition.field); const dataType = selectedColumn?.dataType?.toLowerCase() || "string"; if ( dataType.includes("timestamp") || dataType.includes("datetime") || dataType.includes("date") ) { return ( updateCondition(index, "value", e.target.value)} className="h-8 flex-1 text-xs" /> ); } else if (dataType.includes("time")) { return ( updateCondition(index, "value", e.target.value)} className="h-8 flex-1 text-xs" /> ); } else if (dataType.includes("date")) { return ( updateCondition(index, "value", e.target.value)} className="h-8 flex-1 text-xs" /> ); } else if ( dataType.includes("int") || dataType.includes("numeric") || dataType.includes("decimal") || dataType.includes("float") || dataType.includes("double") ) { return ( updateCondition(index, "value", e.target.value)} className="h-8 flex-1 text-xs" /> ); } else if (dataType.includes("bool")) { return ( ); } else { return ( updateCondition(index, "value", e.target.value)} className="h-8 flex-1 text-xs" /> ); } })()} {/* 삭제 버튼 */}
); })}
)}
); }; // 연결 종류별 설정 패널 렌더링 const renderConnectionTypeSettings = () => { switch (config.connectionType) { case "simple-key": return (
{/* 테이블 및 컬럼 선택 */}
테이블 및 컬럼 선택
{/* 현재 선택된 테이블 표시 */}
{availableTables.find((t) => t.tableName === selectedFromTable)?.displayName || selectedFromTable} ({selectedFromTable})
{availableTables.find((t) => t.tableName === selectedToTable)?.displayName || selectedToTable} ({selectedToTable})
{/* 컬럼 선택 */}
{fromTableColumns.map((column) => ( ))} {fromTableColumns.length === 0 && (
{selectedFromTable ? "컬럼을 불러오는 중..." : "테이블을 먼저 선택해주세요"}
)}
{toTableColumns.map((column) => ( ))} {toTableColumns.length === 0 && (
{selectedToTable ? "컬럼을 불러오는 중..." : "테이블을 먼저 선택해주세요"}
)}
{/* 선택된 컬럼 미리보기 */} {(selectedFromColumns.length > 0 || selectedToColumns.length > 0) && (
{selectedFromColumns.length > 0 ? ( selectedFromColumns.map((column) => ( {column} )) ) : ( 선택된 컬럼 없음 )}
{selectedToColumns.length > 0 ? ( selectedToColumns.map((column) => ( {column} )) ) : ( 선택된 컬럼 없음 )}
)}
{/* 단순 키값 연결 설정 */}
단순 키값 연결 설정