관계도 조회 구현
This commit is contained in:
@@ -62,7 +62,7 @@ export const DataFlowDesigner: React.FC<DataFlowDesignerProps> = ({
|
||||
companyCode,
|
||||
onSave,
|
||||
selectedDiagram,
|
||||
onBackToList,
|
||||
onBackToList, // eslint-disable-line @typescript-eslint/no-unused-vars
|
||||
}) => {
|
||||
const [nodes, setNodes, onNodesChange] = useNodesState<Node<TableNodeData>>([]);
|
||||
const [edges, setEdges, onEdgesChange] = useEdgesState<Edge>([]);
|
||||
@@ -84,7 +84,7 @@ export const DataFlowDesigner: React.FC<DataFlowDesignerProps> = ({
|
||||
};
|
||||
} | null>(null);
|
||||
const [relationships, setRelationships] = useState<TableRelationship[]>([]); // eslint-disable-line @typescript-eslint/no-unused-vars
|
||||
const toastShownRef = useRef(false);
|
||||
const toastShownRef = useRef(false); // eslint-disable-line @typescript-eslint/no-unused-vars
|
||||
|
||||
// 키보드 이벤트 핸들러 (Del 키로 선택된 노드 삭제)
|
||||
useEffect(() => {
|
||||
@@ -212,6 +212,38 @@ export const DataFlowDesigner: React.FC<DataFlowDesignerProps> = ({
|
||||
}
|
||||
}
|
||||
|
||||
// 연결된 컬럼 정보 계산
|
||||
const connectedColumnsInfo: {
|
||||
[tableName: string]: { [columnName: string]: { direction: "source" | "target" | "both" } };
|
||||
} = {};
|
||||
|
||||
diagramRelationships.forEach((rel) => {
|
||||
const fromTable = rel.from_table_name;
|
||||
const toTable = rel.to_table_name;
|
||||
const fromColumns = rel.from_column_name.split(",").map((col) => col.trim());
|
||||
const toColumns = rel.to_column_name.split(",").map((col) => col.trim());
|
||||
|
||||
// 소스 테이블의 컬럼들을 source로 표시
|
||||
if (!connectedColumnsInfo[fromTable]) connectedColumnsInfo[fromTable] = {};
|
||||
fromColumns.forEach((col) => {
|
||||
if (connectedColumnsInfo[fromTable][col]) {
|
||||
connectedColumnsInfo[fromTable][col].direction = "both";
|
||||
} else {
|
||||
connectedColumnsInfo[fromTable][col] = { direction: "source" };
|
||||
}
|
||||
});
|
||||
|
||||
// 타겟 테이블의 컬럼들을 target으로 표시
|
||||
if (!connectedColumnsInfo[toTable]) connectedColumnsInfo[toTable] = {};
|
||||
toColumns.forEach((col) => {
|
||||
if (connectedColumnsInfo[toTable][col]) {
|
||||
connectedColumnsInfo[toTable][col].direction = "both";
|
||||
} else {
|
||||
connectedColumnsInfo[toTable][col] = { direction: "target" };
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 테이블을 노드로 변환 (자동 레이아웃)
|
||||
const tableNodes = tableDefinitions.map((table, index) => {
|
||||
const x = (index % 3) * 400 + 100; // 3열 배치
|
||||
@@ -234,6 +266,7 @@ export const DataFlowDesigner: React.FC<DataFlowDesignerProps> = ({
|
||||
},
|
||||
onColumnClick: handleColumnClick,
|
||||
selectedColumns: selectedColumns[table.tableName] || [],
|
||||
connectedColumns: connectedColumnsInfo[table.tableName] || {},
|
||||
} as TableNodeData,
|
||||
};
|
||||
});
|
||||
@@ -242,23 +275,47 @@ export const DataFlowDesigner: React.FC<DataFlowDesignerProps> = ({
|
||||
console.log("📍 테이블 노드 상세:", tableNodes);
|
||||
setNodes(tableNodes);
|
||||
|
||||
// 관계를 엣지로 변환하여 표시
|
||||
const relationshipEdges = diagramRelationships.map((rel) => ({
|
||||
id: generateUniqueId("edge", rel.relationship_id),
|
||||
source: `table-${rel.from_table_name}`,
|
||||
target: `table-${rel.to_table_name}`,
|
||||
sourceHandle: "right",
|
||||
targetHandle: "left",
|
||||
type: "default",
|
||||
data: {
|
||||
relationshipId: rel.relationship_id,
|
||||
relationshipType: rel.relationship_type,
|
||||
connectionType: rel.connection_type,
|
||||
label: rel.relationship_name,
|
||||
fromColumn: rel.from_column_name,
|
||||
toColumn: rel.to_column_name,
|
||||
},
|
||||
}));
|
||||
// 관계를 엣지로 변환하여 표시 (컬럼별 연결)
|
||||
const relationshipEdges: Edge[] = [];
|
||||
|
||||
diagramRelationships.forEach((rel) => {
|
||||
const fromTable = rel.from_table_name;
|
||||
const toTable = rel.to_table_name;
|
||||
const fromColumns = rel.from_column_name.split(",").map((col) => col.trim());
|
||||
const toColumns = rel.to_column_name.split(",").map((col) => col.trim());
|
||||
|
||||
// 각 from 컬럼을 각 to 컬럼에 연결 (1:1 매핑이거나 many:many인 경우)
|
||||
const maxConnections = Math.max(fromColumns.length, toColumns.length);
|
||||
|
||||
for (let i = 0; i < maxConnections; i++) {
|
||||
const fromColumn = fromColumns[i] || fromColumns[0]; // 컬럼이 부족하면 첫 번째 컬럼 재사용
|
||||
const toColumn = toColumns[i] || toColumns[0]; // 컬럼이 부족하면 첫 번째 컬럼 재사용
|
||||
|
||||
relationshipEdges.push({
|
||||
id: generateUniqueId("edge", rel.relationship_id),
|
||||
source: `table-${fromTable}`,
|
||||
target: `table-${toTable}`,
|
||||
sourceHandle: `${fromTable}-${fromColumn}-source`,
|
||||
targetHandle: `${toTable}-${toColumn}-target`,
|
||||
type: "smoothstep",
|
||||
animated: false,
|
||||
style: {
|
||||
stroke: "#3b82f6",
|
||||
strokeWidth: 1.5,
|
||||
strokeDasharray: "none",
|
||||
},
|
||||
data: {
|
||||
relationshipId: rel.relationship_id,
|
||||
relationshipType: rel.relationship_type,
|
||||
connectionType: rel.connection_type,
|
||||
fromTable: fromTable,
|
||||
toTable: toTable,
|
||||
fromColumn: fromColumn,
|
||||
toColumn: toColumn,
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
console.log("🔗 생성된 관계 에지 수:", relationshipEdges.length);
|
||||
console.log("📍 관계 에지 상세:", relationshipEdges);
|
||||
@@ -268,7 +325,7 @@ export const DataFlowDesigner: React.FC<DataFlowDesignerProps> = ({
|
||||
console.error("선택된 관계도 로드 실패:", error);
|
||||
toast.error("관계도를 불러오는데 실패했습니다.", { id: "load-diagram" });
|
||||
}
|
||||
}, [selectedDiagram, companyCode, setNodes, setEdges, selectedColumns, handleColumnClick]);
|
||||
}, [selectedDiagram, setNodes, setEdges, selectedColumns, handleColumnClick]);
|
||||
|
||||
// 기존 관계 로드 (새 관계도 생성 시)
|
||||
const loadExistingRelationships = useCallback(async () => {
|
||||
@@ -278,23 +335,47 @@ export const DataFlowDesigner: React.FC<DataFlowDesignerProps> = ({
|
||||
const existingRelationships = await DataFlowAPI.getRelationshipsByCompany(companyCode);
|
||||
setRelationships(existingRelationships);
|
||||
|
||||
// 기존 관계를 엣지로 변환하여 표시
|
||||
const existingEdges = existingRelationships.map((rel) => ({
|
||||
id: generateUniqueId("edge", rel.relationship_id),
|
||||
source: `table-${rel.from_table_name}`,
|
||||
target: `table-${rel.to_table_name}`,
|
||||
sourceHandle: "right",
|
||||
targetHandle: "left",
|
||||
type: "default",
|
||||
data: {
|
||||
relationshipId: rel.relationship_id,
|
||||
relationshipType: rel.relationship_type,
|
||||
connectionType: rel.connection_type,
|
||||
label: rel.relationship_name,
|
||||
fromColumn: rel.from_column_name,
|
||||
toColumn: rel.to_column_name,
|
||||
},
|
||||
}));
|
||||
// 기존 관계를 엣지로 변환하여 표시 (컬럼별 연결)
|
||||
const existingEdges: Edge[] = [];
|
||||
|
||||
existingRelationships.forEach((rel) => {
|
||||
const fromTable = rel.from_table_name;
|
||||
const toTable = rel.to_table_name;
|
||||
const fromColumns = rel.from_column_name.split(",").map((col) => col.trim());
|
||||
const toColumns = rel.to_column_name.split(",").map((col) => col.trim());
|
||||
|
||||
// 각 from 컬럼을 각 to 컬럼에 연결
|
||||
const maxConnections = Math.max(fromColumns.length, toColumns.length);
|
||||
|
||||
for (let i = 0; i < maxConnections; i++) {
|
||||
const fromColumn = fromColumns[i] || fromColumns[0];
|
||||
const toColumn = toColumns[i] || toColumns[0];
|
||||
|
||||
existingEdges.push({
|
||||
id: generateUniqueId("edge", rel.relationship_id),
|
||||
source: `table-${fromTable}`,
|
||||
target: `table-${toTable}`,
|
||||
sourceHandle: `${fromTable}-${fromColumn}-source`,
|
||||
targetHandle: `${toTable}-${toColumn}-target`,
|
||||
type: "smoothstep",
|
||||
animated: false,
|
||||
style: {
|
||||
stroke: "#3b82f6",
|
||||
strokeWidth: 1.5,
|
||||
strokeDasharray: "none",
|
||||
},
|
||||
data: {
|
||||
relationshipId: rel.relationship_id,
|
||||
relationshipType: rel.relationship_type,
|
||||
connectionType: rel.connection_type,
|
||||
fromTable: fromTable,
|
||||
toTable: toTable,
|
||||
fromColumn: fromColumn,
|
||||
toColumn: toColumn,
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
setEdges(existingEdges);
|
||||
} catch (error) {
|
||||
@@ -488,24 +569,45 @@ export const DataFlowDesigner: React.FC<DataFlowDesignerProps> = ({
|
||||
(relationship: TableRelationship) => {
|
||||
if (!pendingConnection) return;
|
||||
|
||||
const newEdge = {
|
||||
id: generateUniqueId("edge", relationship.relationship_id),
|
||||
source: pendingConnection.fromNode.id,
|
||||
target: pendingConnection.toNode.id,
|
||||
sourceHandle: "right",
|
||||
targetHandle: "left",
|
||||
type: "default",
|
||||
data: {
|
||||
relationshipId: relationship.relationship_id,
|
||||
relationshipType: relationship.relationship_type,
|
||||
connectionType: relationship.connection_type,
|
||||
label: relationship.relationship_name,
|
||||
fromColumn: relationship.from_column_name,
|
||||
toColumn: relationship.to_column_name,
|
||||
},
|
||||
};
|
||||
// 컬럼별 에지 생성
|
||||
const newEdges: Edge[] = [];
|
||||
const fromTable = relationship.from_table_name;
|
||||
const toTable = relationship.to_table_name;
|
||||
const fromColumns = relationship.from_column_name.split(",").map((col) => col.trim());
|
||||
const toColumns = relationship.to_column_name.split(",").map((col) => col.trim());
|
||||
|
||||
setEdges((eds) => [...eds, newEdge]);
|
||||
const maxConnections = Math.max(fromColumns.length, toColumns.length);
|
||||
|
||||
for (let i = 0; i < maxConnections; i++) {
|
||||
const fromColumn = fromColumns[i] || fromColumns[0];
|
||||
const toColumn = toColumns[i] || toColumns[0];
|
||||
|
||||
newEdges.push({
|
||||
id: generateUniqueId("edge", relationship.relationship_id),
|
||||
source: pendingConnection.fromNode.id,
|
||||
target: pendingConnection.toNode.id,
|
||||
sourceHandle: `${fromTable}-${fromColumn}-source`,
|
||||
targetHandle: `${toTable}-${toColumn}-target`,
|
||||
type: "smoothstep",
|
||||
animated: false,
|
||||
style: {
|
||||
stroke: "#3b82f6",
|
||||
strokeWidth: 1.5,
|
||||
strokeDasharray: "none",
|
||||
},
|
||||
data: {
|
||||
relationshipId: relationship.relationship_id,
|
||||
relationshipType: relationship.relationship_type,
|
||||
connectionType: relationship.connection_type,
|
||||
fromTable: fromTable,
|
||||
toTable: toTable,
|
||||
fromColumn: fromColumn,
|
||||
toColumn: toColumn,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
setEdges((eds) => [...eds, ...newEdges]);
|
||||
setRelationships((prev) => [...prev, relationship]);
|
||||
setPendingConnection(null);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user