"use client"; import React, { useState, useEffect } from "react"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Textarea } from "@/components/ui/textarea"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Badge } from "@/components/ui/badge"; import { Trash2, Plus, ArrowRight, Save, RefreshCw } from "lucide-react"; import { toast } from "sonner"; import { BatchManagementAPI, BatchConnectionInfo, BatchColumnInfo, } from "@/lib/api/batchManagement"; interface MappingState { from: { connection: BatchConnectionInfo | null; table: string; column: BatchColumnInfo | null; } | null; to: { connection: BatchConnectionInfo | null; table: string; column: BatchColumnInfo | null; } | null; } export default function BatchManagementNewPage() { // 기본 상태 const [batchName, setBatchName] = useState(""); const [cronSchedule, setCronSchedule] = useState("0 12 * * *"); const [description, setDescription] = useState(""); // 커넥션 및 테이블 데이터 const [connections, setConnections] = useState([]); const [fromTables, setFromTables] = useState([]); const [toTables, setToTables] = useState([]); const [fromColumns, setFromColumns] = useState([]); const [toColumns, setToColumns] = useState([]); // 선택된 상태 const [fromConnection, setFromConnection] = useState(null); const [toConnection, setToConnection] = useState(null); const [fromTable, setFromTable] = useState(""); const [toTable, setToTable] = useState(""); const [selectedFromColumn, setSelectedFromColumn] = useState(null); // 매핑 상태 const [mappings, setMappings] = useState([]); // 초기 데이터 로드 useEffect(() => { loadConnections(); }, []); // 커넥션 목록 로드 const loadConnections = async () => { try { const data = await BatchManagementAPI.getAvailableConnections(); setConnections(Array.isArray(data) ? data : []); } catch (error) { console.error("커넥션 목록 로드 오류:", error); toast.error("커넥션 목록을 불러오는데 실패했습니다."); setConnections([]); // 오류 시 빈 배열로 설정 } }; // FROM 커넥션 변경 시 테이블 로드 const handleFromConnectionChange = async (connectionId: string) => { if (connectionId === 'unknown') return; const connection = connections.find((c: BatchConnectionInfo) => c.type === 'internal' ? c.type === connectionId : c.id?.toString() === connectionId ); if (!connection) return; setFromConnection(connection); setFromTable(""); setFromColumns([]); setSelectedFromColumn(null); try { const tables = await BatchManagementAPI.getTablesFromConnection( connection.type, connection.id ); setFromTables(Array.isArray(tables) ? tables : []); } catch (error) { console.error("FROM 테이블 목록 로드 오류:", error); toast.error("테이블 목록을 불러오는데 실패했습니다."); setFromTables([]); // 오류 시 빈 배열로 설정 } }; // TO 커넥션 변경 시 테이블 로드 const handleToConnectionChange = async (connectionId: string) => { if (connectionId === 'unknown') return; const connection = connections.find((c: BatchConnectionInfo) => c.type === 'internal' ? c.type === connectionId : c.id?.toString() === connectionId ); if (!connection) return; setToConnection(connection); setToTable(""); setToColumns([]); try { const tables = await BatchManagementAPI.getTablesFromConnection( connection.type, connection.id ); setToTables(Array.isArray(tables) ? tables : []); } catch (error) { console.error("TO 테이블 목록 로드 오류:", error); toast.error("테이블 목록을 불러오는데 실패했습니다."); setToTables([]); // 오류 시 빈 배열로 설정 } }; // FROM 테이블 변경 시 컬럼 로드 const handleFromTableChange = async (tableName: string) => { if (!fromConnection) return; setFromTable(tableName); setSelectedFromColumn(null); try { const columns = await BatchManagementAPI.getTableColumns( fromConnection.type, tableName, fromConnection.id ); setFromColumns(Array.isArray(columns) ? columns : []); } catch (error) { console.error("FROM 컬럼 목록 로드 오류:", error); toast.error("컬럼 목록을 불러오는데 실패했습니다."); setFromColumns([]); // 오류 시 빈 배열로 설정 } }; // TO 테이블 변경 시 컬럼 로드 const handleToTableChange = async (tableName: string) => { if (!toConnection) return; console.log("TO 테이블 변경:", { tableName, connectionType: toConnection.type, connectionId: toConnection.id }); setToTable(tableName); try { const columns = await BatchManagementAPI.getTableColumns( toConnection.type, tableName, toConnection.id ); console.log("TO 컬럼 목록 로드 성공:", columns); setToColumns(Array.isArray(columns) ? columns : []); } catch (error) { console.error("TO 컬럼 목록 로드 오류:", error); toast.error("컬럼 목록을 불러오는데 실패했습니다."); setToColumns([]); // 오류 시 빈 배열로 설정 } }; // FROM 컬럼 클릭 const handleFromColumnClick = (column: BatchColumnInfo) => { setSelectedFromColumn(column); }; // TO 컬럼 클릭 (매핑 생성) const handleToColumnClick = (column: BatchColumnInfo) => { if (!selectedFromColumn || !fromConnection || !toConnection) { toast.error("FROM 컬럼을 먼저 선택해주세요."); return; } // N:1 매핑 방지 (여러 FROM 컬럼이 같은 TO 컬럼에 매핑되는 것 방지) const isAlreadyMapped = mappings.some(mapping => mapping.to?.connection?.type === toConnection.type && mapping.to?.connection?.id === toConnection.id && mapping.to?.table === toTable && mapping.to?.column?.column_name === column.column_name ); if (isAlreadyMapped) { toast.error("이미 매핑된 TO 컬럼입니다. N:1 매핑은 허용되지 않습니다."); return; } // 새 매핑 추가 const newMapping: MappingState = { from: { connection: fromConnection, table: fromTable, column: selectedFromColumn }, to: { connection: toConnection, table: toTable, column: column } }; setMappings([...mappings, newMapping]); setSelectedFromColumn(null); toast.success("매핑이 추가되었습니다."); }; // 매핑 삭제 const removeMapping = (index: number) => { setMappings(mappings.filter((_, i) => i !== index)); toast.success("매핑이 삭제되었습니다."); }; // 컬럼이 이미 매핑되었는지 확인 const isColumnMapped = ( connectionType: 'internal' | 'external', connectionId: number | undefined, tableName: string, columnName: string ): boolean => { return mappings.some(mapping => mapping.to?.connection?.type === connectionType && mapping.to?.connection?.id === connectionId && mapping.to?.table === tableName && mapping.to?.column?.column_name === columnName ); }; // 배치 설정 저장 const handleSave = () => { if (!batchName.trim()) { toast.error("배치명을 입력해주세요."); return; } if (mappings.length === 0) { toast.error("최소 하나의 매핑을 설정해주세요."); return; } // TODO: 실제 저장 로직 구현 console.log("배치 설정 저장:", { batchName, cronSchedule, description, mappings }); toast.success("배치 설정이 저장되었습니다."); }; return (

배치관리 시스템 (새 버전)

{/* 기본 정보 */} 기본 정보
setBatchName(e.target.value)} placeholder="배치명을 입력하세요" />
setCronSchedule(e.target.value)} placeholder="0 12 * * *" />