dev #46

Merged
kjs merged 344 commits from dev into main 2025-09-22 18:17:24 +09:00
1 changed files with 78 additions and 9 deletions
Showing only changes of commit 11b1743f6b - Show all commits

View File

@ -4,7 +4,7 @@ import React, { useState, useEffect } from "react";
import { Plus, Search, Pencil, Trash2, Database } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
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";
@ -23,6 +23,7 @@ import {
ExternalDbConnectionAPI,
ExternalDbConnection,
ExternalDbConnectionFilter,
ConnectionTestRequest,
} from "@/lib/api/externalDbConnection";
import { ExternalDbConnectionModal } from "@/components/admin/ExternalDbConnectionModal";
@ -56,6 +57,8 @@ export default function ExternalConnectionsPage() {
const [supportedDbTypes, setSupportedDbTypes] = useState<Array<{ value: string; label: string }>>([]);
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
const [connectionToDelete, setConnectionToDelete] = useState<ExternalDbConnection | null>(null);
const [testingConnections, setTestingConnections] = useState<Set<number>>(new Set());
const [testResults, setTestResults] = useState<Map<number, boolean>>(new Map());
// 데이터 로딩
const loadConnections = async () => {
@ -160,6 +163,57 @@ export default function ExternalConnectionsPage() {
setConnectionToDelete(null);
};
// 연결 테스트
const handleTestConnection = async (connection: ExternalDbConnection) => {
if (!connection.id) return;
setTestingConnections((prev) => new Set(prev).add(connection.id!));
try {
const testData: ConnectionTestRequest = {
db_type: connection.db_type,
host: connection.host,
port: connection.port,
database_name: connection.database_name,
username: connection.username,
password: connection.password,
connection_timeout: connection.connection_timeout,
ssl_enabled: connection.ssl_enabled,
};
const result = await ExternalDbConnectionAPI.testConnection(testData);
setTestResults((prev) => new Map(prev).set(connection.id!, result.success));
if (result.success) {
toast({
title: "연결 성공",
description: `${connection.connection_name} 연결이 성공했습니다.`,
});
} else {
toast({
title: "연결 실패",
description: `${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);
@ -264,6 +318,7 @@ export default function ExternalConnectionsPage() {
<TableHead className="w-[120px]"></TableHead>
<TableHead className="w-[80px]"></TableHead>
<TableHead className="w-[100px]"></TableHead>
<TableHead className="w-[100px]"> </TableHead>
<TableHead className="w-[120px] text-right"></TableHead>
</TableRow>
</TableHeader>
@ -271,14 +326,7 @@ export default function ExternalConnectionsPage() {
{connections.map((connection) => (
<TableRow key={connection.id} className="hover:bg-gray-50">
<TableCell>
<div>
<div className="font-medium">{connection.connection_name}</div>
{connection.description && (
<div className="max-w-[180px] truncate text-sm text-gray-500" title={connection.description}>
{connection.description}
</div>
)}
</div>
<div className="font-medium">{connection.connection_name}</div>
</TableCell>
<TableCell>
<Badge variant="outline" className="text-xs">
@ -298,6 +346,27 @@ export default function ExternalConnectionsPage() {
<TableCell className="text-sm">
{connection.created_date ? new Date(connection.created_date).toLocaleDateString() : "N/A"}
</TableCell>
<TableCell>
<div className="flex items-center gap-2">
<Button
variant="outline"
size="sm"
onClick={() => handleTestConnection(connection)}
disabled={testingConnections.has(connection.id!)}
className="h-7 px-2 text-xs"
>
{testingConnections.has(connection.id!) ? "테스트 중..." : "테스트"}
</Button>
{testResults.has(connection.id!) && (
<Badge
variant={testResults.get(connection.id!) ? "default" : "destructive"}
className="text-xs text-white"
>
{testResults.get(connection.id!) ? "성공" : "실패"}
</Badge>
)}
</div>
</TableCell>
<TableCell className="text-right">
<div className="flex justify-end gap-1">
<Button