diff --git a/backend-node/src/controllers/tableManagementController.ts b/backend-node/src/controllers/tableManagementController.ts index 10f76e72..c3192a6f 100644 --- a/backend-node/src/controllers/tableManagementController.ts +++ b/backend-node/src/controllers/tableManagementController.ts @@ -282,15 +282,13 @@ export async function getTableLabels( const tableLabels = await tableManagementService.getTableLabels(tableName); if (!tableLabels) { - const response: ApiResponse = { - success: false, - message: "테이블 라벨 정보를 찾을 수 없습니다.", - error: { - code: "TABLE_LABELS_NOT_FOUND", - details: `테이블 ${tableName}의 라벨 정보가 존재하지 않습니다.`, - }, + // 라벨이 없으면 빈 객체를 성공으로 반환 (404 에러 대신) + const response: ApiResponse<{}> = { + success: true, + message: "테이블 라벨 정보를 조회했습니다.", + data: {}, }; - res.status(404).json(response); + res.status(200).json(response); return; } @@ -350,15 +348,13 @@ export async function getColumnLabels( ); if (!columnLabels) { - const response: ApiResponse = { - success: false, - message: "컬럼 라벨 정보를 찾을 수 없습니다.", - error: { - code: "COLUMN_LABELS_NOT_FOUND", - details: `컬럼 ${tableName}.${columnName}의 라벨 정보가 존재하지 않습니다.`, - }, + // 라벨이 없으면 빈 객체를 성공으로 반환 (404 에러 대신) + const response: ApiResponse<{}> = { + success: true, + message: "컬럼 라벨 정보를 조회했습니다.", + data: {}, }; - res.status(404).json(response); + res.status(200).json(response); return; } diff --git a/frontend/components/dataflow/ConnectionSetupModal.tsx b/frontend/components/dataflow/ConnectionSetupModal.tsx index b0c27fe9..781d7c33 100644 --- a/frontend/components/dataflow/ConnectionSetupModal.tsx +++ b/frontend/components/dataflow/ConnectionSetupModal.tsx @@ -185,6 +185,9 @@ export const ConnectionSetupModal: React.FC = ({ // 모달이 열릴 때 기본값 설정 useEffect(() => { if (isOpen && connection) { + // 모달이 열릴 때마다 캐시 초기화 (라벨 업데이트 반영) + setTableColumnsCache({}); + const fromTableName = connection.fromNode.tableName; const toTableName = connection.toNode.tableName; const fromDisplayName = connection.fromNode.displayName; @@ -283,8 +286,8 @@ export const ConnectionSetupModal: React.FC = ({ }, [selectedFromColumns, selectedToColumns]); // 테이블 컬럼 로드 함수 (캐시 활용) - const loadTableColumns = async (tableName: string): Promise => { - if (tableColumnsCache[tableName]) { + const loadTableColumns = async (tableName: string, forceReload = false): Promise => { + if (tableColumnsCache[tableName] && !forceReload) { return tableColumnsCache[tableName]; } diff --git a/frontend/components/dataflow/DataFlowDesigner.tsx b/frontend/components/dataflow/DataFlowDesigner.tsx index 7ebe19ab..f3a5372f 100644 --- a/frontend/components/dataflow/DataFlowDesigner.tsx +++ b/frontend/components/dataflow/DataFlowDesigner.tsx @@ -284,8 +284,12 @@ export const DataFlowDesigner: React.FC = ({ description: "", // 새로 추가된 노드는 description 없이 통일 columns: Array.isArray(table.columns) ? table.columns.map((col) => ({ - name: col.columnName || "unknown", - type: col.dataType || "varchar", // 기존과 동일한 기본값 사용 + columnName: col.columnName || "unknown", + name: col.columnName || "unknown", // 호환성을 위해 유지 + displayName: col.displayName, // 한국어 라벨 + columnLabel: col.columnLabel, // 한국어 라벨 + type: col.dataType || "varchar", + dataType: col.dataType || "varchar", description: col.description || "", })) : [], diff --git a/frontend/components/dataflow/SaveDiagramModal.tsx b/frontend/components/dataflow/SaveDiagramModal.tsx index 2ed0e13d..a2385efc 100644 --- a/frontend/components/dataflow/SaveDiagramModal.tsx +++ b/frontend/components/dataflow/SaveDiagramModal.tsx @@ -131,7 +131,7 @@ const SaveDiagramModal: React.FC = ({
{connectedTables.map((table) => ( - 📋 {table} + {table} ))}
@@ -162,7 +162,7 @@ const SaveDiagramModal: React.FC = ({
- {relationship.fromColumns.join(", ")} → {relationship.toColumns.join(", ")} + {relationship.fromTable} → {relationship.toTable}
diff --git a/frontend/components/dataflow/TableNode.tsx b/frontend/components/dataflow/TableNode.tsx index bbe7f88b..67fdf8b0 100644 --- a/frontend/components/dataflow/TableNode.tsx +++ b/frontend/components/dataflow/TableNode.tsx @@ -4,9 +4,13 @@ import React from "react"; import { Handle, Position } from "@xyflow/react"; interface TableColumn { - name: string; - type: string; - description: string; + columnName: string; + name?: string; // 호환성을 위해 유지 + columnLabel?: string; + displayName?: string; + dataType?: string; + type?: string; // 호환성을 위해 유지 + description?: string; } interface Table { @@ -43,21 +47,24 @@ export const TableNode: React.FC<{ data: TableNodeData }> = ({ data }) => {
{table.columns.map((column) => { - const isSelected = selectedColumns.includes(column.name); + const columnKey = column.columnName || column.name || ""; + const columnDisplayName = column.displayName || column.columnLabel || column.name || column.columnName; + const columnType = column.dataType || column.type || ""; + const isSelected = selectedColumns.includes(columnKey); return (
onColumnClick(table.tableName, column.name)} + onClick={() => onColumnClick(table.tableName, columnKey)} > {/* 핸들 제거됨 - 컬럼 클릭으로만 연결 생성 */}
- {column.name} - {column.type} + {columnDisplayName} + {columnType}
{column.description &&
{column.description}
}
diff --git a/frontend/components/dataflow/condition/ConditionRenderer.tsx b/frontend/components/dataflow/condition/ConditionRenderer.tsx index 88a1dbff..17c38bf9 100644 --- a/frontend/components/dataflow/condition/ConditionRenderer.tsx +++ b/frontend/components/dataflow/condition/ConditionRenderer.tsx @@ -172,7 +172,7 @@ export const ConditionRenderer: React.FC = ({ {fromTableColumns.map((column) => ( - {column.columnName} + {column.displayName || column.columnLabel || column.columnName} ))} diff --git a/frontend/components/dataflow/connection/ActionConditionRenderer.tsx b/frontend/components/dataflow/connection/ActionConditionRenderer.tsx index fb542ebc..6c0cb933 100644 --- a/frontend/components/dataflow/connection/ActionConditionRenderer.tsx +++ b/frontend/components/dataflow/connection/ActionConditionRenderer.tsx @@ -214,13 +214,13 @@ export const ActionConditionRenderer: React.FC = ( {condition.tableType === "from" && fromTableColumns.map((column) => ( - {column.columnName} + {column.displayName || column.columnLabel || column.columnName} ))} {condition.tableType === "to" && toTableColumns.map((column) => ( - {column.columnName} + {column.displayName || column.columnLabel || column.columnName} ))} diff --git a/frontend/components/dataflow/connection/ActionFieldMappings.tsx b/frontend/components/dataflow/connection/ActionFieldMappings.tsx index dcd56cf6..008b6a32 100644 --- a/frontend/components/dataflow/connection/ActionFieldMappings.tsx +++ b/frontend/components/dataflow/connection/ActionFieldMappings.tsx @@ -154,7 +154,7 @@ export const ActionFieldMappings: React.FC = ({ tableColumnsCache[mapping.sourceTable]?.map((column) => (
- {column.columnName} + {column.displayName || column.columnLabel || column.columnName}
))} @@ -200,7 +200,7 @@ export const ActionFieldMappings: React.FC = ({ tableColumnsCache[mapping.targetTable]?.map((column) => (
- {column.columnName} + {column.displayName || column.columnLabel || column.columnName}
))} diff --git a/frontend/components/dataflow/connection/ActionSplitConfig.tsx b/frontend/components/dataflow/connection/ActionSplitConfig.tsx index 9538a50a..685c85a1 100644 --- a/frontend/components/dataflow/connection/ActionSplitConfig.tsx +++ b/frontend/components/dataflow/connection/ActionSplitConfig.tsx @@ -90,7 +90,7 @@ export const ActionSplitConfig: React.FC = ({ {fromTableColumns.map((column) => ( - {column.columnName} + {column.displayName || column.columnLabel || column.columnName} ))} @@ -117,7 +117,7 @@ export const ActionSplitConfig: React.FC = ({ {toTableColumns.map((column) => ( - {column.columnName} + {column.displayName || column.columnLabel || column.columnName} ))} diff --git a/frontend/components/dataflow/connection/ColumnTableSection.tsx b/frontend/components/dataflow/connection/ColumnTableSection.tsx index 0edbd0a6..eff8ba18 100644 --- a/frontend/components/dataflow/connection/ColumnTableSection.tsx +++ b/frontend/components/dataflow/connection/ColumnTableSection.tsx @@ -198,7 +198,9 @@ export const ColumnTableSection: React.FC = ({
- {column.columnName} + + {column.displayName || column.columnLabel || column.columnName} + {isSelected && } {isMapped && } {oppositeSelectedColumn && !isTypeCompatible && ( @@ -264,7 +266,9 @@ export const ColumnTableSection: React.FC = ({ >
- {column.columnName} + + {column.displayName || column.columnLabel || column.columnName} + {isSelected && } {oppositeSelectedColumn && !isTypeCompatible && ( diff --git a/frontend/components/dataflow/connection/InsertFieldMappingPanel.tsx b/frontend/components/dataflow/connection/InsertFieldMappingPanel.tsx index 8118147c..71892017 100644 --- a/frontend/components/dataflow/connection/InsertFieldMappingPanel.tsx +++ b/frontend/components/dataflow/connection/InsertFieldMappingPanel.tsx @@ -236,14 +236,10 @@ export const InsertFieldMappingPanel: React.FC = ( return (
{/* 헤더 섹션 */} - - -

- 양쪽 테이블의 컬럼을 클릭하여 매핑하거나, 대상 컬럼에 기본값을 입력하세요. 같은 데이터 타입의 컬럼만 매핑 - 가능합니다. 하나의 FROM 컬럼은 하나의 TO 컬럼에만 매핑 가능합니다. -

-
-
+

+ 양쪽 테이블의 컬럼을 클릭하여 매핑하거나, 대상 컬럼에 기본값을 입력하세요. 같은 데이터 타입의 컬럼만 매핑 + 가능합니다. 하나의 FROM 컬럼은 하나의 TO 컬럼에만 매핑 가능합니다. +

= (
{/* 빠른 필터 액션 */} - + 빠른 필터: