From 8e6f8d2a27fdac008f2b553a01670faeeb8fe00f Mon Sep 17 00:00:00 2001 From: hyeonsu Date: Fri, 12 Sep 2025 16:15:36 +0900 Subject: [PATCH] =?UTF-8?q?UI=20=EA=B0=9C=EC=84=A0=20-=20=EC=A0=80?= =?UTF-8?q?=EC=9E=A5=20=EB=B0=A9=EC=8B=9D=EB=B3=84=20=EC=B0=A8=EB=B3=84?= =?UTF-8?q?=ED=99=94=20=EB=B0=8F=20=EC=A4=91=EB=B3=B5=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dataflow/ConnectionSetupModal.tsx | 626 ++++++++++++++++-- 1 file changed, 572 insertions(+), 54 deletions(-) diff --git a/frontend/components/dataflow/ConnectionSetupModal.tsx b/frontend/components/dataflow/ConnectionSetupModal.tsx index d8deba54..036688af 100644 --- a/frontend/components/dataflow/ConnectionSetupModal.tsx +++ b/frontend/components/dataflow/ConnectionSetupModal.tsx @@ -58,9 +58,30 @@ interface SimpleKeySettings { // 데이터 저장 설정 interface DataSaveSettings { - sourceField: string; - targetField: string; - saveConditions: string; + saveMode: "simple" | "conditional" | "split"; // 저장 방식 + actions: Array<{ + id: string; + name: string; + actionType: "insert" | "update" | "delete" | "upsert"; + conditions?: Array<{ + field: string; + operator: "=" | "!=" | ">" | "<" | ">=" | "<=" | "LIKE"; + value: string; + }>; + fieldMappings: Array<{ + sourceTable?: string; + sourceField: string; + targetTable?: string; + targetField: string; + defaultValue?: string; + transformFunction?: string; + }>; + splitConfig?: { + sourceField: string; // 분할할 소스 필드 + delimiter: string; // 구분자 (예: ",") + targetField: string; // 분할된 값이 들어갈 필드 + }; + }>; } // 외부 호출 설정 @@ -103,9 +124,8 @@ export const ConnectionSetupModal: React.FC = ({ }); const [dataSaveSettings, setDataSaveSettings] = useState({ - sourceField: "", - targetField: "", - saveConditions: "", + saveMode: "simple", + actions: [], }); const [externalCallSettings, setExternalCallSettings] = useState({ @@ -124,6 +144,8 @@ export const ConnectionSetupModal: React.FC = ({ const [toTableColumns, setToTableColumns] = useState([]); const [selectedFromColumns, setSelectedFromColumns] = useState([]); const [selectedToColumns, setSelectedToColumns] = useState([]); + // 필요시 로드하는 테이블 컬럼 캐시 + const [tableColumnsCache, setTableColumnsCache] = useState<{ [tableName: string]: ColumnInfo[] }>({}); // 조건부 연결을 위한 새로운 상태들 const [conditions, setConditions] = useState([]); @@ -179,9 +201,15 @@ export const ConnectionSetupModal: React.FC = ({ // 데이터 저장 기본값 설정 setDataSaveSettings({ - sourceField: "", - targetField: "", - saveConditions: "데이터 저장 조건을 입력하세요", + saveMode: "simple", + actions: [ + { + id: "action_1", + name: `${fromDisplayName}에서 ${toDisplayName}로 데이터 저장`, + actionType: "insert", + fieldMappings: [], + }, + ], }); // 외부 호출 기본값 설정 @@ -253,6 +281,51 @@ export const ConnectionSetupModal: React.FC = ({ })); }, [selectedFromColumns, selectedToColumns]); + // 테이블 컬럼 로드 함수 (캐시 활용) + const loadTableColumns = async (tableName: string): Promise => { + if (tableColumnsCache[tableName]) { + return tableColumnsCache[tableName]; + } + + try { + const columns = await DataFlowAPI.getTableColumns(tableName); + setTableColumnsCache((prev) => ({ + ...prev, + [tableName]: columns, + })); + return columns; + } catch (error) { + console.error(`${tableName} 컬럼 로드 실패:`, error); + return []; + } + }; + + // 테이블 선택 시 컬럼 로드 + useEffect(() => { + const loadColumns = async () => { + const tablesToLoad = new Set(); + + // 필드 매핑에서 사용되는 모든 테이블 수집 + dataSaveSettings.actions.forEach((action) => { + action.fieldMappings.forEach((mapping) => { + if (mapping.sourceTable && !tableColumnsCache[mapping.sourceTable]) { + tablesToLoad.add(mapping.sourceTable); + } + if (mapping.targetTable && !tableColumnsCache[mapping.targetTable]) { + tablesToLoad.add(mapping.targetTable); + } + }); + }); + + // 필요한 테이블들의 컬럼만 로드 + for (const tableName of tablesToLoad) { + await loadTableColumns(tableName); + } + }; + + loadColumns(); + }, [dataSaveSettings.actions, tableColumnsCache]); // eslint-disable-line react-hooks/exhaustive-deps + const handleConfirm = () => { if (!config.relationshipName || !connection) { toast.error("필수 정보를 모두 입력해주세요."); @@ -303,7 +376,24 @@ export const ConnectionSetupModal: React.FC = ({ }, plan: { sourceTable: fromTableName, - targetActions: [], // 나중에 액션 설정 UI에서 채울 예정 + targetActions: + config.connectionType === "data-save" + ? dataSaveSettings.actions.map((action) => ({ + id: action.id, + actionType: action.actionType, + enabled: true, + conditions: action.conditions, + fieldMappings: action.fieldMappings.map((mapping) => ({ + sourceTable: mapping.sourceTable, + sourceField: mapping.sourceField, + targetTable: mapping.targetTable, + targetField: mapping.targetField, + defaultValue: mapping.defaultValue, + transformFunction: mapping.transformFunction, + })), + splitConfig: action.splitConfig, + })) + : [], }, } : {}; @@ -395,7 +485,7 @@ export const ConnectionSetupModal: React.FC = ({
- 실행 조건 설정 + 전체 실행 조건 (언제 이 연결이 동작할지)
{/* 실행 조건 설정 */} @@ -528,50 +618,478 @@ export const ConnectionSetupModal: React.FC = ({ 데이터 저장 설정
-
-
-
- - setDataSaveSettings({ ...dataSaveSettings, sourceField: e.target.value })} - placeholder="소스 필드" - className="text-sm" - /> -
-
- -
- setDataSaveSettings({ ...dataSaveSettings, targetField: e.target.value })} - placeholder="대상 필드" - className="text-sm" - /> - -
-
-
+
+ {/* 저장 방식 선택 */}
- -