api관리 구현(대시보드쪽)

This commit is contained in:
dohyeons
2025-10-22 09:45:47 +09:00
parent 7ec60bed6c
commit b62f2ffc10
2 changed files with 208 additions and 21 deletions

View File

@@ -1,12 +1,14 @@
"use client";
import React, { useState } from "react";
import React, { useState, useEffect } from "react";
import { ChartDataSource, QueryResult, KeyValuePair } from "../types";
import { Card } from "@/components/ui/card";
import { Label } from "@/components/ui/label";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { Plus, X, Play, AlertCircle } from "lucide-react";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { ExternalDbConnectionAPI, ExternalApiConnection } from "@/lib/api/externalDbConnection";
interface ApiConfigProps {
dataSource: ChartDataSource;
@@ -24,6 +26,106 @@ export function ApiConfig({ dataSource, onChange, onTestResult }: ApiConfigProps
const [testing, setTesting] = useState(false);
const [testResult, setTestResult] = useState<QueryResult | null>(null);
const [testError, setTestError] = useState<string | null>(null);
const [apiConnections, setApiConnections] = useState<ExternalApiConnection[]>([]);
const [selectedConnectionId, setSelectedConnectionId] = useState<string>("");
// 외부 API 커넥션 목록 로드
useEffect(() => {
const loadApiConnections = async () => {
const connections = await ExternalDbConnectionAPI.getApiConnections({ is_active: "Y" });
setApiConnections(connections);
};
loadApiConnections();
}, []);
// 외부 커넥션 선택 핸들러
const handleConnectionSelect = async (connectionId: string) => {
setSelectedConnectionId(connectionId);
if (!connectionId || connectionId === "manual") return;
const connection = await ExternalDbConnectionAPI.getApiConnectionById(Number(connectionId));
if (!connection) {
console.error("커넥션을 찾을 수 없습니다:", connectionId);
return;
}
console.log("불러온 커넥션:", connection);
// 커넥션 설정을 API 설정에 자동 적용
const updates: Partial<ChartDataSource> = {
endpoint: connection.base_url,
};
const headers: KeyValuePair[] = [];
const queryParams: KeyValuePair[] = [];
// 기본 헤더가 있으면 적용
if (connection.default_headers && Object.keys(connection.default_headers).length > 0) {
Object.entries(connection.default_headers).forEach(([key, value]) => {
headers.push({
id: `header_${Date.now()}_${Math.random()}`,
key,
value,
});
});
console.log("기본 헤더 적용:", headers);
}
// 인증 설정이 있으면 헤더 또는 쿼리 파라미터에 추가
if (connection.auth_type && connection.auth_type !== "none" && connection.auth_config) {
console.log("인증 설정:", connection.auth_type, connection.auth_config);
if (connection.auth_type === "bearer" && connection.auth_config.token) {
headers.push({
id: `header_${Date.now()}_auth`,
key: "Authorization",
value: `Bearer ${connection.auth_config.token}`,
});
console.log("Bearer 토큰 추가");
} else if (connection.auth_type === "api-key") {
console.log("API Key 설정:", connection.auth_config);
if (connection.auth_config.keyName && connection.auth_config.keyValue) {
if (connection.auth_config.keyLocation === "header") {
headers.push({
id: `header_${Date.now()}_apikey`,
key: connection.auth_config.keyName,
value: connection.auth_config.keyValue,
});
console.log(`API Key 헤더 추가: ${connection.auth_config.keyName}=${connection.auth_config.keyValue}`);
} else if (connection.auth_config.keyLocation === "query") {
queryParams.push({
id: `param_${Date.now()}_apikey`,
key: connection.auth_config.keyName,
value: connection.auth_config.keyValue,
});
console.log(
`API Key 쿼리 파라미터 추가: ${connection.auth_config.keyName}=${connection.auth_config.keyValue}`,
);
}
}
} else if (
connection.auth_type === "basic" &&
connection.auth_config.username &&
connection.auth_config.password
) {
const basicAuth = btoa(`${connection.auth_config.username}:${connection.auth_config.password}`);
headers.push({
id: `header_${Date.now()}_basic`,
key: "Authorization",
value: `Basic ${basicAuth}`,
});
console.log("Basic Auth 추가");
}
}
updates.headers = headers;
updates.queryParams = queryParams;
console.log("최종 업데이트:", updates);
onChange(updates);
};
// 헤더를 배열로 정규화 (객체 형식 호환)
const normalizeHeaders = (): KeyValuePair[] => {
@@ -217,6 +319,30 @@ export function ApiConfig({ dataSource, onChange, onTestResult }: ApiConfigProps
<p className="mt-1 text-sm text-gray-600"> API에서 </p>
</div>
{/* 외부 커넥션 선택 */}
{apiConnections.length > 0 && (
<Card className="space-y-4 p-4">
<div>
<Label className="text-sm font-medium text-gray-700"> ()</Label>
<Select value={selectedConnectionId} onValueChange={handleConnectionSelect}>
<SelectTrigger className="mt-2">
<SelectValue placeholder="저장된 커넥션 선택" />
</SelectTrigger>
<SelectContent className="z-[9999]">
<SelectItem value="manual"> </SelectItem>
{apiConnections.map((conn) => (
<SelectItem key={conn.id} value={String(conn.id)}>
{conn.connection_name}
{conn.description && <span className="ml-2 text-xs text-gray-500">({conn.description})</span>}
</SelectItem>
))}
</SelectContent>
</Select>
<p className="mt-1 text-xs text-gray-500"> REST API </p>
</div>
</Card>
)}
{/* API URL */}
<Card className="space-y-4 p-4">
<div>
@@ -230,13 +356,6 @@ export function ApiConfig({ dataSource, onChange, onTestResult }: ApiConfigProps
/>
<p className="mt-1 text-xs text-gray-500">GET API </p>
</div>
{/* HTTP 메서드 (고정) */}
<div>
<Label className="text-sm font-medium text-gray-700">HTTP </Label>
<div className="mt-2 rounded border border-gray-300 bg-gray-100 p-2 text-sm text-gray-700">GET ()</div>
<p className="mt-1 text-xs text-gray-500"> GET </p>
</div>
</Card>
{/* 쿼리 파라미터 */}