"use client"; import React, { useState, useEffect } from "react"; import { Plus, Search, Pencil, Trash2, Database, Terminal, Globe } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Card, CardContent } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from "@/components/ui/alert-dialog"; import { useToast } from "@/hooks/use-toast"; import { ExternalDbConnectionAPI, ExternalDbConnection, ExternalDbConnectionFilter, ConnectionTestRequest, } from "@/lib/api/externalDbConnection"; import { ExternalDbConnectionModal } from "@/components/admin/ExternalDbConnectionModal"; import { SqlQueryModal } from "@/components/admin/SqlQueryModal"; import { RestApiConnectionList } from "@/components/admin/RestApiConnectionList"; type ConnectionTabType = "database" | "rest-api"; // DB 타입 매핑 const DB_TYPE_LABELS: Record = { mysql: "MySQL", postgresql: "PostgreSQL", oracle: "Oracle", mssql: "SQL Server", sqlite: "SQLite", }; // 활성 상태 옵션 const ACTIVE_STATUS_OPTIONS = [ { value: "ALL", label: "전체" }, { value: "Y", label: "활성" }, { value: "N", label: "비활성" }, ]; export default function ExternalConnectionsPage() { const { toast } = useToast(); // 탭 상태 const [activeTab, setActiveTab] = useState("database"); // 상태 관리 const [connections, setConnections] = useState([]); const [loading, setLoading] = useState(true); const [searchTerm, setSearchTerm] = useState(""); const [dbTypeFilter, setDbTypeFilter] = useState("ALL"); const [activeStatusFilter, setActiveStatusFilter] = useState("ALL"); const [isModalOpen, setIsModalOpen] = useState(false); const [editingConnection, setEditingConnection] = useState(); const [supportedDbTypes, setSupportedDbTypes] = useState>([]); const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); const [connectionToDelete, setConnectionToDelete] = useState(null); const [testingConnections, setTestingConnections] = useState>(new Set()); const [testResults, setTestResults] = useState>(new Map()); const [sqlModalOpen, setSqlModalOpen] = useState(false); const [selectedConnection, setSelectedConnection] = useState(null); // 데이터 로딩 const loadConnections = async () => { try { setLoading(true); const filter: ExternalDbConnectionFilter = { search: searchTerm.trim() || undefined, db_type: dbTypeFilter === "ALL" ? undefined : dbTypeFilter, is_active: activeStatusFilter === "ALL" ? undefined : activeStatusFilter, }; const data = await ExternalDbConnectionAPI.getConnections(filter); setConnections(data); } catch (error) { console.error("연결 목록 로딩 오류:", error); toast({ title: "오류", description: "연결 목록을 불러오는데 실패했습니다.", variant: "destructive", }); } finally { setLoading(false); } }; // 지원되는 DB 타입 로딩 const loadSupportedDbTypes = async () => { try { const types = await ExternalDbConnectionAPI.getSupportedTypes(); setSupportedDbTypes([{ value: "ALL", label: "전체" }, ...types]); } catch (error) { console.error("지원 DB 타입 로딩 오류:", error); // 실패 시 기본값 사용 setSupportedDbTypes([ { value: "ALL", label: "전체" }, { value: "mysql", label: "MySQL" }, { value: "postgresql", label: "PostgreSQL" }, { value: "oracle", label: "Oracle" }, { value: "mssql", label: "SQL Server" }, { value: "sqlite", label: "SQLite" }, ]); } }; // 초기 데이터 로딩 useEffect(() => { loadConnections(); loadSupportedDbTypes(); }, []); // 필터 변경 시 데이터 재로딩 useEffect(() => { loadConnections(); }, [searchTerm, dbTypeFilter, activeStatusFilter]); // 새 연결 추가 const handleAddConnection = () => { setEditingConnection(undefined); setIsModalOpen(true); }; // 연결 편집 const handleEditConnection = (connection: ExternalDbConnection) => { setEditingConnection(connection); setIsModalOpen(true); }; // 연결 삭제 확인 다이얼로그 열기 const handleDeleteConnection = (connection: ExternalDbConnection) => { setConnectionToDelete(connection); setDeleteDialogOpen(true); }; // 연결 삭제 실행 const confirmDeleteConnection = async () => { if (!connectionToDelete?.id) return; try { await ExternalDbConnectionAPI.deleteConnection(connectionToDelete.id); toast({ title: "성공", description: "연결이 삭제되었습니다.", }); loadConnections(); } catch (error) { console.error("연결 삭제 오류:", error); toast({ title: "오류", description: error instanceof Error ? error.message : "연결 삭제에 실패했습니다.", variant: "destructive", }); } finally { setDeleteDialogOpen(false); setConnectionToDelete(null); } }; // 연결 삭제 취소 const cancelDeleteConnection = () => { setDeleteDialogOpen(false); setConnectionToDelete(null); }; // 연결 테스트 const handleTestConnection = async (connection: ExternalDbConnection) => { if (!connection.id) return; setTestingConnections((prev) => new Set(prev).add(connection.id!)); try { const result = await ExternalDbConnectionAPI.testConnection(connection.id); setTestResults((prev) => new Map(prev).set(connection.id!, result.success)); if (result.success) { toast({ title: "연결 성공", description: `${connection.connection_name} 연결이 성공했습니다.`, }); } else { toast({ title: "연결 실패", description: result.message || `${connection.connection_name} 연결에 실패했습니다.`, variant: "destructive", }); } } catch (error) { console.error("연결 테스트 오류:", error); setTestResults((prev) => new Map(prev).set(connection.id!, false)); toast({ title: "연결 테스트 오류", description: "연결 테스트 중 오류가 발생했습니다.", variant: "destructive", }); } finally { setTestingConnections((prev) => { const newSet = new Set(prev); newSet.delete(connection.id!); return newSet; }); } }; // 모달 저장 처리 const handleModalSave = () => { setIsModalOpen(false); setEditingConnection(undefined); loadConnections(); }; // 모달 취소 처리 const handleModalCancel = () => { setIsModalOpen(false); setEditingConnection(undefined); }; return (
{/* 페이지 헤더 */}

외부 커넥션 관리

외부 데이터베이스 및 REST API 연결 정보를 관리합니다

{/* 탭 */} setActiveTab(value as ConnectionTabType)}> 데이터베이스 연결 REST API 연결 {/* 데이터베이스 연결 탭 */} {/* 검색 및 필터 */}
{/* 검색 */}
setSearchTerm(e.target.value)} className="h-10 pl-10 text-sm" />
{/* DB 타입 필터 */} {/* 활성 상태 필터 */}
{/* 추가 버튼 */}
{/* 연결 목록 */} {loading ? (
로딩 중...
) : connections.length === 0 ? (

등록된 연결이 없습니다

) : (
연결명 회사 DB 타입 호스트:포트 데이터베이스 사용자 상태 생성일 연결 테스트 작업 {connections.map((connection) => (
{connection.connection_name}
{(connection as any).company_name || connection.company_code} {DB_TYPE_LABELS[connection.db_type] || connection.db_type} {connection.host}:{connection.port} {connection.database_name} {connection.username} {connection.is_active === "Y" ? "활성" : "비활성"} {connection.created_date ? new Date(connection.created_date).toLocaleDateString() : "N/A"}
{testResults.has(connection.id!) && ( {testResults.get(connection.id!) ? "성공" : "실패"} )}
))}
)} {/* 연결 설정 모달 */} {isModalOpen && ( type.value !== "ALL")} /> )} {/* 삭제 확인 다이얼로그 */} 연결 삭제 확인 "{connectionToDelete?.connection_name}" 연결을 삭제하시겠습니까?
이 작업은 되돌릴 수 없습니다.
취소 삭제
{/* SQL 쿼리 모달 */} {selectedConnection && ( { setSqlModalOpen(false); setSelectedConnection(null); }} connectionId={selectedConnection.id!} connectionName={selectedConnection.connection_name} /> )}
{/* REST API 연결 탭 */}
); }