ERP-node/frontend/components/admin/dashboard/data-sources/DatabaseConfig.tsx

176 lines
6.6 KiB
TypeScript
Raw Normal View History

2025-10-14 13:59:54 +09:00
"use client";
import React, { useState, useEffect } from "react";
2025-10-22 12:48:17 +09:00
import { useRouter } from "next/navigation";
2025-10-14 14:10:49 +09:00
import { ChartDataSource } from "../types";
import { ExternalDbConnectionAPI, ExternalDbConnection } from "@/lib/api/externalDbConnection";
2025-10-14 13:59:54 +09:00
import { Label } from "@/components/ui/label";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { ExternalLink, Database, Server } from "lucide-react";
interface DatabaseConfigProps {
dataSource: ChartDataSource;
onChange: (updates: Partial<ChartDataSource>) => void;
}
/**
*
* - DB / DB
* -
*/
export function DatabaseConfig({ dataSource, onChange }: DatabaseConfigProps) {
2025-10-22 12:48:17 +09:00
const router = useRouter();
2025-10-14 14:10:49 +09:00
const [connections, setConnections] = useState<ExternalDbConnection[]>([]);
2025-10-14 13:59:54 +09:00
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
// 외부 커넥션 목록 불러오기
useEffect(() => {
if (dataSource.connectionType === "external") {
loadExternalConnections();
}
}, [dataSource.connectionType]);
const loadExternalConnections = async () => {
setLoading(true);
setError(null);
try {
2025-10-14 14:10:49 +09:00
const activeConnections = await ExternalDbConnectionAPI.getConnections({ is_active: "Y" });
setConnections(activeConnections);
2025-10-14 13:59:54 +09:00
} catch (err) {
const errorMessage = err instanceof Error ? err.message : "알 수 없는 오류가 발생했습니다";
setError(errorMessage);
} finally {
setLoading(false);
}
};
// 현재 선택된 커넥션 찾기
2025-10-14 14:10:49 +09:00
const selectedConnection = connections.find((conn) => String(conn.id) === dataSource.externalConnectionId);
2025-10-14 13:59:54 +09:00
return (
2025-10-22 12:48:17 +09:00
<div className="space-y-3">
2025-10-14 13:59:54 +09:00
{/* 현재 DB vs 외부 DB 선택 */}
2025-10-22 12:48:17 +09:00
<div>
2025-10-30 18:05:45 +09:00
<Label className="text-foreground mb-2 block text-xs font-medium"> </Label>
2025-10-22 12:48:17 +09:00
<div className="flex gap-2">
<button
2025-10-14 13:59:54 +09:00
onClick={() => {
onChange({ connectionType: "current", externalConnectionId: undefined });
}}
2025-10-22 12:48:17 +09:00
className={`flex flex-1 items-center gap-1.5 rounded border px-2 py-1.5 text-xs transition-colors ${
dataSource.connectionType === "current"
? "bg-primary border-primary text-white"
2025-10-29 17:53:03 +09:00
: "border-border bg-background hover:bg-muted"
2025-10-22 12:48:17 +09:00
}`}
2025-10-14 13:59:54 +09:00
>
2025-10-22 12:48:17 +09:00
<Database className="h-3 w-3" />
DB
</button>
2025-10-14 13:59:54 +09:00
2025-10-22 12:48:17 +09:00
<button
2025-10-14 13:59:54 +09:00
onClick={() => {
onChange({ connectionType: "external" });
}}
2025-10-22 12:48:17 +09:00
className={`flex flex-1 items-center gap-1.5 rounded border px-2 py-1.5 text-xs transition-colors ${
dataSource.connectionType === "external"
? "bg-primary border-primary text-white"
2025-10-29 17:53:03 +09:00
: "border-border bg-background hover:bg-muted"
2025-10-22 12:48:17 +09:00
}`}
2025-10-14 13:59:54 +09:00
>
2025-10-22 12:48:17 +09:00
<Server className="h-3 w-3" />
DB
</button>
2025-10-14 13:59:54 +09:00
</div>
2025-10-22 12:48:17 +09:00
</div>
2025-10-14 13:59:54 +09:00
{/* 외부 DB 선택 시 커넥션 목록 */}
{dataSource.connectionType === "external" && (
2025-10-22 12:48:17 +09:00
<div className="space-y-2">
2025-10-14 13:59:54 +09:00
<div className="flex items-center justify-between">
2025-10-30 18:05:45 +09:00
<Label className="text-foreground text-xs font-medium"> </Label>
2025-10-22 12:48:17 +09:00
<button
2025-10-14 13:59:54 +09:00
onClick={() => {
2025-10-22 12:48:17 +09:00
router.push("/admin/external-connections");
2025-10-14 13:59:54 +09:00
}}
2025-10-30 18:05:45 +09:00
className="text-primary hover:text-primary flex items-center gap-1 text-[11px] transition-colors"
2025-10-14 13:59:54 +09:00
>
2025-10-22 12:48:17 +09:00
<ExternalLink className="h-3 w-3" />
2025-10-14 13:59:54 +09:00
2025-10-22 12:48:17 +09:00
</button>
2025-10-14 13:59:54 +09:00
</div>
{loading && (
2025-10-22 12:48:17 +09:00
<div className="flex items-center justify-center py-3">
2025-10-30 18:05:45 +09:00
<div className="border-border h-4 w-4 animate-spin rounded-full border-2 border-t-blue-600" />
<span className="text-foreground ml-2 text-xs"> ...</span>
2025-10-14 13:59:54 +09:00
</div>
)}
{error && (
2025-10-30 18:05:45 +09:00
<div className="bg-destructive/10 rounded px-2 py-1.5">
<div className="text-destructive text-xs">{error}</div>
2025-10-22 12:48:17 +09:00
<button
onClick={loadExternalConnections}
2025-10-30 18:05:45 +09:00
className="text-destructive mt-1 text-[11px] underline hover:no-underline"
2025-10-22 12:48:17 +09:00
>
2025-10-14 13:59:54 +09:00
2025-10-22 12:48:17 +09:00
</button>
2025-10-14 13:59:54 +09:00
</div>
)}
{!loading && !error && connections.length === 0 && (
2025-10-30 18:05:45 +09:00
<div className="bg-warning/10 rounded px-2 py-2 text-center">
<div className="text-warning mb-1 text-xs"> </div>
2025-10-22 12:48:17 +09:00
<button
2025-10-14 13:59:54 +09:00
onClick={() => {
2025-10-22 12:48:17 +09:00
router.push("/admin/external-connections");
2025-10-14 13:59:54 +09:00
}}
2025-10-30 18:05:45 +09:00
className="text-warning text-[11px] underline hover:no-underline"
2025-10-14 13:59:54 +09:00
>
2025-10-22 12:48:17 +09:00
</button>
2025-10-14 13:59:54 +09:00
</div>
)}
{!loading && !error && connections.length > 0 && (
<>
<Select
value={dataSource.externalConnectionId || undefined}
2025-10-14 13:59:54 +09:00
onValueChange={(value) => {
onChange({ externalConnectionId: value });
}}
>
2025-10-22 12:48:17 +09:00
<SelectTrigger className="h-8 w-full text-xs">
<SelectValue placeholder="커넥션 선택" />
2025-10-14 13:59:54 +09:00
</SelectTrigger>
<SelectContent className="z-[9999]">
2025-10-14 13:59:54 +09:00
{connections.map((conn) => (
2025-10-22 12:48:17 +09:00
<SelectItem key={conn.id} value={String(conn.id)} className="text-xs">
<div className="flex items-center gap-1.5">
2025-10-14 14:10:49 +09:00
<span className="font-medium">{conn.connection_name}</span>
2025-10-30 18:05:45 +09:00
<span className="text-muted-foreground text-[10px]">({conn.db_type.toUpperCase()})</span>
2025-10-14 13:59:54 +09:00
</div>
</SelectItem>
))}
</SelectContent>
</Select>
{selectedConnection && (
2025-10-30 18:05:45 +09:00
<div className="bg-muted text-foreground space-y-0.5 rounded px-2 py-1.5 text-[11px]">
2025-10-22 12:48:17 +09:00
<div>
<span className="font-medium">:</span> {selectedConnection.connection_name}
</div>
<div>
<span className="font-medium">:</span> {selectedConnection.db_type.toUpperCase()}
2025-10-14 13:59:54 +09:00
</div>
</div>
)}
</>
)}
</div>
)}
</div>
);
}