"use client"; import React, { useState, useEffect } from "react"; import { Plus, Search, Pencil, Trash2, TestTube } 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 { 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 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 = (connection: ExternalRestApiConnection) => { setEditingConnection(connection); setIsModalOpen(true); }; // 연결 삭제 확인 다이얼로그 열기 const handleDeleteConnection = (connection: ExternalRestApiConnection) => { setConnectionToDelete(connection); 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)); // 현재 행의 "마지막 테스트" 정보만 낙관적으로 업데이트하여 // 전체 목록 리로딩 없이도 UI를 즉시 반영한다. 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 newSet = new Set(prev); newSet.delete(connection.id!); return newSet; }); } }; // 모달 저장 처리 const handleModalSave = () => { setIsModalOpen(false); setEditingConnection(undefined); loadConnections(); }; // 모달 취소 처리 const handleModalCancel = () => { setIsModalOpen(false); setEditingConnection(undefined); }; return ( <> {/* 검색 및 필터 */}
{/* 검색 */}
setSearchTerm(e.target.value)} className="h-10 pl-10 text-sm" />
{/* 인증 타입 필터 */} {/* 활성 상태 필터 */}
{/* 추가 버튼 */}
{/* 연결 목록 */} {loading ? (
로딩 중...
) : connections.length === 0 ? (

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

) : (
연결명 기본 URL 인증 타입 헤더 수 상태 마지막 테스트 연결 테스트 작업 {connections.map((connection) => (
{connection.connection_name}
{connection.description && (
{connection.description}
)}
{connection.base_url}
{AUTH_TYPE_LABELS[connection.auth_type] || connection.auth_type} {Object.keys(connection.default_headers || {}).length} {connection.is_active === "Y" ? "활성" : "비활성"} {connection.last_test_date ? (
{new Date(connection.last_test_date).toLocaleDateString()}
{connection.last_test_result === "Y" ? "성공" : "실패"}
) : ( - )}
{testResults.has(connection.id!) && ( {testResults.get(connection.id!) ? "성공" : "실패"} )}
))}
)} {/* 연결 설정 모달 */} {isModalOpen && ( )} {/* 삭제 확인 다이얼로그 */} 연결 삭제 확인 "{connectionToDelete?.connection_name}" 연결을 삭제하시겠습니까?
이 작업은 되돌릴 수 없습니다.
취소 삭제
); }