From 5b98819191d2e9ebc3434a65e9351e8f628e3808 Mon Sep 17 00:00:00 2001 From: dohyeons Date: Thu, 27 Nov 2025 12:08:18 +0900 Subject: [PATCH] =?UTF-8?q?=ED=86=A0=ED=81=B0=20=EB=B0=B0=EC=B9=98=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20=ED=99=94=EB=A9=B4=EC=97=90=EC=84=9C=20API?= =?UTF-8?q?=20=EC=9D=91=EB=8B=B5=20=EB=AF=B8=EB=A6=AC=EB=B3=B4=EA=B8=B0=20?= =?UTF-8?q?=EB=B0=8F=20access=5Ftoken=20=EB=A7=A4=ED=95=91=20=ED=8E=B8?= =?UTF-8?q?=EC=A7=91=20=EA=B0=80=EB=8A=A5=ED=95=98=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../(main)/admin/batchmng/edit/[id]/page.tsx | 201 +++++++++++++++++- 1 file changed, 193 insertions(+), 8 deletions(-) diff --git a/frontend/app/(main)/admin/batchmng/edit/[id]/page.tsx b/frontend/app/(main)/admin/batchmng/edit/[id]/page.tsx index 5f87e0d0..4c1d9fba 100644 --- a/frontend/app/(main)/admin/batchmng/edit/[id]/page.tsx +++ b/frontend/app/(main)/admin/batchmng/edit/[id]/page.tsx @@ -7,12 +7,24 @@ import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Textarea } from "@/components/ui/textarea"; -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; import { Badge } from "@/components/ui/badge"; import { Checkbox } from "@/components/ui/checkbox"; import { RefreshCw, Save, ArrowLeft, Plus, Trash2 } from "lucide-react"; import { toast } from "sonner"; -import { BatchAPI, BatchConfig, BatchMapping, ConnectionInfo } from "@/lib/api/batch"; +import { + BatchAPI, + BatchConfig, + BatchMapping, + ConnectionInfo, +} from "@/lib/api/batch"; +import { BatchManagementAPI } from "@/lib/api/batchManagement"; interface BatchColumnInfo { column_name: string; @@ -66,6 +78,9 @@ export default function BatchEditPage() { // 배치 타입 감지 const [batchType, setBatchType] = useState<'db-to-db' | 'restapi-to-db' | 'db-to-restapi' | null>(null); + // REST API 미리보기 상태 + const [apiPreviewData, setApiPreviewData] = useState([]); + // 페이지 로드 시 배치 정보 조회 useEffect(() => { @@ -335,6 +350,86 @@ export default function BatchEditPage() { setMappings([...mappings, newMapping]); }; + // REST API → DB 매핑 추가 + const addRestapiToDbMapping = () => { + if (!batchConfig || !batchConfig.batch_mappings || batchConfig.batch_mappings.length === 0) { + return; + } + + const first = batchConfig.batch_mappings[0] as any; + + const newMapping: BatchMapping = { + // FROM: REST API (기존 설정 그대로 복사) + from_connection_type: "restapi" as any, + from_connection_id: first.from_connection_id, + from_table_name: first.from_table_name, + from_column_name: "", + from_column_type: "", + // TO: DB (기존 설정 그대로 복사) + to_connection_type: first.to_connection_type as any, + to_connection_id: first.to_connection_id, + to_table_name: first.to_table_name, + to_column_name: "", + to_column_type: "", + mapping_type: (first.mapping_type as any) || "direct", + mapping_order: mappings.length + 1, + }; + + setMappings((prev) => [...prev, newMapping]); + }; + + // REST API 데이터 미리보기 (수정 화면용) + const previewRestApiData = async () => { + if (!mappings || mappings.length === 0) { + toast.error("미리보기할 REST API 매핑이 없습니다."); + return; + } + + const first: any = mappings[0]; + + if (!first.from_api_url || !first.from_table_name) { + toast.error("API URL과 엔드포인트 정보가 없습니다."); + return; + } + + try { + const method = + (first.from_api_method as "GET" | "POST" | "PUT" | "DELETE") || "GET"; + + const paramInfo = + first.from_api_param_type && + first.from_api_param_name && + first.from_api_param_value + ? { + paramType: first.from_api_param_type as "url" | "query", + paramName: first.from_api_param_name as string, + paramValue: first.from_api_param_value as string, + paramSource: + (first.from_api_param_source as "static" | "dynamic") || + "static", + } + : undefined; + + const result = await BatchManagementAPI.previewRestApiData( + first.from_api_url, + first.from_api_key || "", + first.from_table_name, + method, + paramInfo, + first.from_api_body || undefined + ); + + setApiPreviewData(result.samples || []); + + toast.success( + `API 데이터 미리보기 완료! ${result.fields.length}개 필드, ${result.samples.length}개 레코드` + ); + } catch (error) { + console.error("REST API 미리보기 오류:", error); + toast.error("API 데이터 미리보기에 실패했습니다."); + } + }; + // 매핑 삭제 const removeMapping = (index: number) => { const updatedMappings = mappings.filter((_, i) => i !== index); @@ -637,6 +732,37 @@ export default function BatchEditPage() { 배치가 실행될 때 이 내용이 그대로 전송됩니다.

+ + {/* API 데이터 미리보기 */} +
+ + + {apiPreviewData.length > 0 && ( +
+

+ 샘플 데이터 (최대 3개) +

+
+ {apiPreviewData.slice(0, 3).map((item, index) => ( +
+                              {JSON.stringify(item, null, 2)}
+                            
+ ))} +
+
+ )} +
)} @@ -687,6 +813,12 @@ export default function BatchEditPage() { 매핑 추가 )} + {batchType === 'restapi-to-db' && ( + + )} @@ -791,20 +923,73 @@ export default function BatchEditPage() {

매핑 #{index + 1}

-

- API 필드: {mapping.from_column_name} → DB 컬럼: {mapping.to_column_name} -

+ {mapping.from_column_name && mapping.to_column_name && ( +

+ API 필드: {mapping.from_column_name} → DB 컬럼: {mapping.to_column_name} +

+ )}
+
- - + + + updateMapping( + index, + "from_column_name", + e.target.value + ) + } + placeholder="response.access_token" + />
- + + {toColumns.length === 0 && ( +

+ 대상 테이블을 선택하면 컬럼 목록이 표시됩니다. +

+ )}