외부 REST API 연결 확장
This commit is contained in:
@@ -6,6 +6,7 @@ import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { Plus, Trash2, Loader2, CheckCircle, XCircle } from "lucide-react";
|
||||
import { ExternalDbConnectionAPI, ExternalApiConnection } from "@/lib/api/externalDbConnection";
|
||||
import { getApiUrl } from "@/lib/utils/apiUrl";
|
||||
@@ -20,7 +21,7 @@ export default function MultiApiConfig({ dataSource, onChange, onTestResult }: M
|
||||
const [testing, setTesting] = useState(false);
|
||||
const [testResult, setTestResult] = useState<{ success: boolean; message: string } | null>(null);
|
||||
const [apiConnections, setApiConnections] = useState<ExternalApiConnection[]>([]);
|
||||
const [selectedConnectionId, setSelectedConnectionId] = useState<string>("");
|
||||
const [selectedConnectionId, setSelectedConnectionId] = useState<string>(dataSource.externalConnectionId || "");
|
||||
const [availableColumns, setAvailableColumns] = useState<string[]>([]); // API 테스트 후 발견된 컬럼 목록
|
||||
const [columnTypes, setColumnTypes] = useState<Record<string, string>>({}); // 컬럼 타입 정보
|
||||
const [sampleData, setSampleData] = useState<any[]>([]); // 샘플 데이터 (최대 3개)
|
||||
@@ -35,6 +36,13 @@ export default function MultiApiConfig({ dataSource, onChange, onTestResult }: M
|
||||
loadApiConnections();
|
||||
}, []);
|
||||
|
||||
// dataSource.externalConnectionId가 변경되면 selectedConnectionId 업데이트
|
||||
useEffect(() => {
|
||||
if (dataSource.externalConnectionId) {
|
||||
setSelectedConnectionId(dataSource.externalConnectionId);
|
||||
}
|
||||
}, [dataSource.externalConnectionId]);
|
||||
|
||||
// 외부 커넥션 선택 핸들러
|
||||
const handleConnectionSelect = async (connectionId: string) => {
|
||||
setSelectedConnectionId(connectionId);
|
||||
@@ -58,11 +66,20 @@ export default function MultiApiConfig({ dataSource, onChange, onTestResult }: M
|
||||
|
||||
const updates: Partial<ChartDataSource> = {
|
||||
endpoint: fullEndpoint,
|
||||
externalConnectionId: connectionId, // 외부 연결 ID 저장
|
||||
};
|
||||
|
||||
const headers: KeyValuePair[] = [];
|
||||
const queryParams: KeyValuePair[] = [];
|
||||
|
||||
// 기본 메서드/바디가 있으면 적용
|
||||
if (connection.default_method) {
|
||||
updates.method = connection.default_method as ChartDataSource["method"];
|
||||
}
|
||||
if (connection.default_body) {
|
||||
updates.body = connection.default_body;
|
||||
}
|
||||
|
||||
// 기본 헤더가 있으면 적용
|
||||
if (connection.default_headers && Object.keys(connection.default_headers).length > 0) {
|
||||
Object.entries(connection.default_headers).forEach(([key, value]) => {
|
||||
@@ -210,6 +227,11 @@ export default function MultiApiConfig({ dataSource, onChange, onTestResult }: M
|
||||
}
|
||||
});
|
||||
|
||||
const bodyPayload =
|
||||
dataSource.body && dataSource.body.trim().length > 0
|
||||
? dataSource.body
|
||||
: undefined;
|
||||
|
||||
const response = await fetch(getApiUrl("/api/dashboards/fetch-external-api"), {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
@@ -219,6 +241,8 @@ export default function MultiApiConfig({ dataSource, onChange, onTestResult }: M
|
||||
method: dataSource.method || "GET",
|
||||
headers,
|
||||
queryParams,
|
||||
body: bodyPayload,
|
||||
externalConnectionId: dataSource.externalConnectionId, // 외부 연결 ID 전달
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -415,6 +439,58 @@ export default function MultiApiConfig({ dataSource, onChange, onTestResult }: M
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* HTTP 메서드 */}
|
||||
<div className="space-y-2">
|
||||
<Label className="text-xs">HTTP 메서드</Label>
|
||||
<Select
|
||||
value={dataSource.method || "GET"}
|
||||
onValueChange={(value) =>
|
||||
onChange({
|
||||
method: value as ChartDataSource["method"],
|
||||
})
|
||||
}
|
||||
>
|
||||
<SelectTrigger className="h-8 text-xs">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="GET" className="text-xs">
|
||||
GET
|
||||
</SelectItem>
|
||||
<SelectItem value="POST" className="text-xs">
|
||||
POST
|
||||
</SelectItem>
|
||||
<SelectItem value="PUT" className="text-xs">
|
||||
PUT
|
||||
</SelectItem>
|
||||
<SelectItem value="DELETE" className="text-xs">
|
||||
DELETE
|
||||
</SelectItem>
|
||||
<SelectItem value="PATCH" className="text-xs">
|
||||
PATCH
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
{/* Request Body (POST/PUT/PATCH 일 때만) */}
|
||||
{(dataSource.method === "POST" ||
|
||||
dataSource.method === "PUT" ||
|
||||
dataSource.method === "PATCH") && (
|
||||
<div className="space-y-2">
|
||||
<Label className="text-xs">Request Body (선택)</Label>
|
||||
<Textarea
|
||||
value={dataSource.body || ""}
|
||||
onChange={(e) => onChange({ body: e.target.value })}
|
||||
placeholder='{"key": "value"} 또는 원시 페이로드를 그대로 입력하세요'
|
||||
className="h-24 text-xs font-mono"
|
||||
/>
|
||||
<p className="text-[10px] text-muted-foreground">
|
||||
이 내용은 그대로 외부 API 요청 Body로 전송됩니다. JSON이 아니어도 됩니다.
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* JSON Path */}
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor={`jsonPath-\${dataSource.id}`} className="text-xs">
|
||||
|
||||
Reference in New Issue
Block a user