"use client"; import React, { useState, useEffect } from "react"; import { Plus, Search, Pencil, Trash2, Globe } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Badge } from "@/components/ui/badge"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from "@/components/ui/alert-dialog"; import { useToast } from "@/hooks/use-toast"; import { ExternalRestApiConnectionAPI, ExternalRestApiConnection, ExternalRestApiConnectionFilter, } from "@/lib/api/externalRestApiConnection"; import { RestApiConnectionModal } from "./RestApiConnectionModal"; // 인증 타입 라벨 const AUTH_TYPE_LABELS: Record = { none: "인증 없음", "api-key": "API Key", bearer: "Bearer", basic: "Basic Auth", oauth2: "OAuth 2.0", "db-token": "DB 토큰", }; // 인증 타입 색상 const AUTH_TYPE_COLORS: Record = { none: "bg-gray-100 text-gray-600 dark:bg-gray-800 dark:text-gray-400", "api-key": "bg-amber-100 text-amber-700 dark:bg-amber-900/30 dark:text-amber-400", bearer: "bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400", basic: "bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400", oauth2: "bg-purple-100 text-purple-700 dark:bg-purple-900/30 dark:text-purple-400", "db-token": "bg-rose-100 text-rose-700 dark:bg-rose-900/30 dark:text-rose-400", }; // 활성 상태 옵션 const ACTIVE_STATUS_OPTIONS = [ { value: "ALL", label: "전체" }, { value: "Y", label: "활성" }, { value: "N", label: "비활성" }, ]; export function RestApiConnectionList() { const { toast } = useToast(); const [connections, setConnections] = useState([]); const [loading, setLoading] = useState(true); const [searchTerm, setSearchTerm] = useState(""); const [authTypeFilter, setAuthTypeFilter] = useState("ALL"); const [activeStatusFilter, setActiveStatusFilter] = useState("ALL"); const [isModalOpen, setIsModalOpen] = useState(false); const [editingConnection, setEditingConnection] = useState(); const [supportedAuthTypes, setSupportedAuthTypes] = useState>([]); const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); const [connectionToDelete, setConnectionToDelete] = useState(null); const [testingConnections, setTestingConnections] = useState>(new Set()); const [testResults, setTestResults] = useState>(new Map()); const loadConnections = async () => { try { setLoading(true); const filter: ExternalRestApiConnectionFilter = { search: searchTerm.trim() || undefined, auth_type: authTypeFilter === "ALL" ? undefined : authTypeFilter, is_active: activeStatusFilter === "ALL" ? undefined : activeStatusFilter, }; const data = await ExternalRestApiConnectionAPI.getConnections(filter); setConnections(data); } catch (error) { toast({ title: "오류", description: "연결 목록을 불러오는데 실패했습니다.", variant: "destructive" }); } finally { setLoading(false); } }; const loadSupportedAuthTypes = () => { const types = ExternalRestApiConnectionAPI.getSupportedAuthTypes(); setSupportedAuthTypes([{ value: "ALL", label: "전체" }, ...types]); }; useEffect(() => { loadConnections(); loadSupportedAuthTypes(); }, []); useEffect(() => { loadConnections(); }, [searchTerm, authTypeFilter, activeStatusFilter]); const handleAddConnection = () => { setEditingConnection(undefined); setIsModalOpen(true); }; const handleEditConnection = (conn: ExternalRestApiConnection) => { setEditingConnection(conn); setIsModalOpen(true); }; const handleDeleteConnection = (conn: ExternalRestApiConnection) => { setConnectionToDelete(conn); setDeleteDialogOpen(true); }; const confirmDeleteConnection = async () => { if (!connectionToDelete?.id) return; try { await ExternalRestApiConnectionAPI.deleteConnection(connectionToDelete.id); toast({ title: "성공", description: "연결이 삭제되었습니다." }); loadConnections(); } catch (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: ExternalRestApiConnection) => { if (!connection.id) return; setTestingConnections((prev) => new Set(prev).add(connection.id!)); try { const result = await ExternalRestApiConnectionAPI.testConnectionById(connection.id); setTestResults((prev) => new Map(prev).set(connection.id!, result.success)); const nowIso = new Date().toISOString(); setConnections((prev) => prev.map((c) => c.id === connection.id ? { ...c, last_test_date: nowIso as any, last_test_result: result.success ? "Y" : "N", last_test_message: result.message } : c ) ); if (result.success) { toast({ title: "연결 성공", description: `${connection.connection_name} 연결이 성공했습니다.` }); } else { toast({ title: "연결 실패", description: result.message || `${connection.connection_name} 연결에 실패했습니다.`, variant: "destructive" }); } } catch (error) { setTestResults((prev) => new Map(prev).set(connection.id!, false)); toast({ title: "연결 테스트 오류", description: "연결 테스트 중 오류가 발생했습니다.", variant: "destructive" }); } finally { setTestingConnections((prev) => { const s = new Set(prev); s.delete(connection.id!); return s; }); } }; const handleModalSave = () => { setIsModalOpen(false); setEditingConnection(undefined); loadConnections(); }; const handleModalCancel = () => { setIsModalOpen(false); setEditingConnection(undefined); }; return ( <> {/* 검색 및 필터 */}
setSearchTerm(e.target.value)} className="h-8 pl-8 text-xs" />
{/* 그리드 카드 목록 */} {loading ? (
{Array.from({ length: 8 }).map((_, i) => (
))}
) : connections.length === 0 ? (

등록된 REST API 연결이 없습니다

) : (
{connections.map((conn) => { const isTesting = testingConnections.has(conn.id!); const testResult = testResults.get(conn.id!); const authColor = AUTH_TYPE_COLORS[conn.auth_type] || "bg-gray-100 text-gray-600 dark:bg-gray-800 dark:text-gray-400"; const headerCount = Object.keys(conn.default_headers || {}).length; return (
{/* 상단: 인증타입 + 상태 */}
{AUTH_TYPE_LABELS[conn.auth_type] || conn.auth_type} {conn.is_active === "Y" ? "활성" : "비활성"}
{/* 연결명 */}

{conn.connection_name}

{/* 회사 */}

{(conn as any).company_name || conn.company_code || "공통"}

{/* URL 정보 */}

{conn.base_url}

{headerCount > 0 && ( 헤더 {headerCount}개 )} {conn.last_test_result && ( {conn.last_test_result === "Y" ? "성공" : "실패"} )}
{/* 하단 버튼 */}
); })}
)} {/* 모달 */} {isModalOpen && ( )} {/* 삭제 확인 */} 연결 삭제 “{connectionToDelete?.connection_name}” 연결을 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다. 취소 삭제 ); }