"use client"; /** * 테이블 소스 노드 속성 편집 */ import { useEffect, useState } from "react"; import { Check, ChevronsUpDown, Table, FileText } from "lucide-react"; import { Label } from "@/components/ui/label"; import { Input } from "@/components/ui/input"; import { Button } from "@/components/ui/button"; import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "@/components/ui/command"; import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { ScrollArea } from "@/components/ui/scroll-area"; import { cn } from "@/lib/utils"; import { useFlowEditorStore } from "@/lib/stores/flowEditorStore"; import { tableTypeApi } from "@/lib/api/screen"; import type { TableSourceNodeData } from "@/types/node-editor"; interface TableSourcePropertiesProps { nodeId: string; data: TableSourceNodeData; } interface TableOption { tableName: string; displayName: string; description: string; label: string; // 표시용 (라벨 또는 테이블명) } export function TableSourceProperties({ nodeId, data }: TableSourcePropertiesProps) { const { updateNode } = useFlowEditorStore(); const [displayName, setDisplayName] = useState(data.displayName || data.tableName); const [tableName, setTableName] = useState(data.tableName); // 🆕 데이터 소스 타입 (기본값: context-data) const [dataSourceType, setDataSourceType] = useState<"context-data" | "table-all">( (data as any).dataSourceType || "context-data", ); // 테이블 선택 관련 상태 const [tables, setTables] = useState([]); const [loading, setLoading] = useState(false); const [open, setOpen] = useState(false); // 데이터 변경 시 로컬 상태 업데이트 useEffect(() => { setDisplayName(data.displayName || data.tableName); setTableName(data.tableName); setDataSourceType((data as any).dataSourceType || "context-data"); }, [data.displayName, data.tableName, (data as any).dataSourceType]); // 테이블 목록 로딩 useEffect(() => { loadTables(); }, []); /** * 테이블 목록 로드 */ const loadTables = async () => { try { setLoading(true); console.log("🔍 테이블 목록 로딩 중..."); const tableList = await tableTypeApi.getTables(); // 테이블 목록 변환 (라벨 또는 displayName 우선 표시) const options: TableOption[] = tableList.map((table) => { // tableLabel이 있으면 우선 사용, 없으면 displayName, 그것도 없으면 tableName const label = (table as any).tableLabel || table.displayName || table.tableName || "알 수 없는 테이블"; return { tableName: table.tableName, displayName: table.displayName || table.tableName, description: table.description || "", label, }; }); setTables(options); console.log(`✅ 테이블 ${options.length}개 로딩 완료`); } catch (error) { console.error("❌ 테이블 목록 로딩 실패:", error); setTables([]); } finally { setLoading(false); } }; /** * 테이블 선택 핸들러 (즉시 노드 업데이트 + 컬럼 로드) */ const handleTableSelect = async (selectedTableName: string) => { const selectedTable = tables.find((t) => t.tableName === selectedTableName); if (selectedTable) { const newTableName = selectedTable.tableName; const newDisplayName = selectedTable.label; setTableName(newTableName); setDisplayName(newDisplayName); setOpen(false); // 컬럼 정보 로드 console.log(`🔍 테이블 "${newTableName}" 컬럼 로드 중...`); try { const columns = await tableTypeApi.getColumns(newTableName); console.log("🔍 API에서 받은 컬럼 데이터:", columns); const fields = columns.map((col: any) => ({ name: col.column_name || col.columnName, type: col.data_type || col.dataType || "unknown", nullable: col.is_nullable === "YES" || col.isNullable === true, // displayName이 라벨입니다! label: col.displayName || col.label_ko || col.columnLabel || col.column_label, })); console.log(`✅ ${fields.length}개 컬럼 로드 완료:`, fields); // 필드 정보와 함께 노드 업데이트 updateNode(nodeId, { displayName: newDisplayName, tableName: newTableName, fields, }); } catch (error) { console.error("❌ 컬럼 로드 실패:", error); // 실패해도 테이블 정보는 업데이트 updateNode(nodeId, { displayName: newDisplayName, tableName: newTableName, fields: [], }); } console.log(`✅ 테이블 선택: ${newTableName} (${newDisplayName})`); } }; /** * 표시 이름 변경 핸들러 */ const handleDisplayNameChange = (newDisplayName: string) => { setDisplayName(newDisplayName); updateNode(nodeId, { displayName: newDisplayName, tableName, }); }; /** * 🆕 데이터 소스 타입 변경 핸들러 */ const handleDataSourceTypeChange = (newType: "context-data" | "table-all") => { setDataSourceType(newType); updateNode(nodeId, { dataSourceType: newType, }); console.log(`✅ 데이터 소스 타입 변경: ${newType}`); }; // 현재 선택된 테이블의 라벨 찾기 const selectedTableLabel = tables.find((t) => t.tableName === tableName)?.label || tableName; return (
{/* 기본 정보 */}

기본 정보

handleDisplayNameChange(e.target.value)} className="mt-1" placeholder="노드 표시 이름" />
{/* 테이블 선택 Combobox */}
검색 결과가 없습니다. {tables.map((table) => ( handleTableSelect(table.tableName)} className="cursor-pointer" >
{table.label} {table.label !== table.tableName && ( {table.tableName} )} {table.description && ( {table.description} )}
))}
{tableName && selectedTableLabel !== tableName && (

실제 테이블명: {tableName}

)}
{/* 🆕 데이터 소스 설정 */}

데이터 소스 설정

{/* 설명 텍스트 */}
{dataSourceType === "context-data" ? ( <>

💡 컨텍스트 데이터 모드

버튼 실행 시 전달된 데이터(폼 데이터, 테이블 선택 항목 등)를 사용합니다.

• 폼 데이터: 1개 레코드

• 테이블 선택: N개 레코드

) : ( <>

📊 테이블 전체 데이터 모드

선택한 테이블의 **모든 행**을 직접 조회합니다.

⚠️ 대량 데이터 시 성능 주의

)}
{/* 필드 정보 */}

출력 필드 {data.fields && data.fields.length > 0 && `(${data.fields.length}개)`}

{data.fields && data.fields.length > 0 ? (
{data.fields.map((field) => (
{field.name} {field.type}
))}
) : (
필드 정보가 없습니다
)}
); }