연결 이름 수정 로직 수정

This commit is contained in:
hyeonsu 2025-09-16 16:49:59 +09:00
parent f715b5fa8c
commit 104faf487c
3 changed files with 264 additions and 30 deletions

View File

@ -13,11 +13,17 @@ import { RelationshipListModal } from "./RelationshipListModal";
import { EdgeInfoPanel } from "./EdgeInfoPanel";
import SaveDiagramModal from "./SaveDiagramModal";
import { TableDefinition, DataFlowAPI, JsonRelationship } from "@/lib/api/dataflow";
import {
TableDefinition,
DataFlowAPI,
JsonRelationship,
TableRelationship,
CreateDiagramRequest,
} from "@/lib/api/dataflow";
import { useAuth } from "@/hooks/useAuth";
import { useDataFlowDesigner } from "@/hooks/useDataFlowDesigner";
import { DataFlowDesignerProps, TableNodeData } from "@/types/dataflowTypes";
import { extractTableNames } from "@/utils/dataflowUtils";
import { extractTableNames, extractNodePositions } from "@/utils/dataflowUtils";
// 노드 및 엣지 타입 정의
const nodeTypes = {
@ -30,10 +36,10 @@ export const DataFlowDesigner: React.FC<DataFlowDesignerProps> = ({
companyCode: propCompanyCode = "*",
diagramId,
}) => {
const { user } = useAuth();
const { user: authUser } = useAuth();
// 실제 사용자 회사 코드 사용 (prop보다 사용자 정보 우선)
const companyCode = user?.company_code || user?.companyCode || propCompanyCode;
const companyCode = authUser?.company_code || authUser?.companyCode || propCompanyCode;
// 커스텀 훅 사용
const {
@ -196,11 +202,6 @@ export const DataFlowDesigner: React.FC<DataFlowDesignerProps> = ({
}));
setEdges(loadedEdges);
console.log("✅ 관계도 데이터 로드 완료:", {
relationships: jsonDiagram.relationships?.relationships?.length || 0,
tables: Array.from(new Set(loadedRelationships.flatMap((rel) => [rel.fromTable, rel.toTable]))).length,
});
}
}
} catch (error) {
@ -386,8 +387,6 @@ export const DataFlowDesigner: React.FC<DataFlowDesignerProps> = ({
(rel.fromTable === toTable && rel.toTable === fromTable),
);
console.log(`🔗 ${fromTable}${toTable} 간의 관계:`, tablePairRelationships);
// 관계가 1개든 여러 개든 항상 관계 목록 모달 표시
setSelectedTablePairRelationships(tablePairRelationships);
setShowRelationshipListModal(true);
@ -468,15 +467,102 @@ export const DataFlowDesigner: React.FC<DataFlowDesignerProps> = ({
};
// 연결 설정 확인
const handleConfirmConnection = useCallback(() => {
if (!pendingConnection) return;
const handleConfirmConnection = useCallback(
(relationshipData: TableRelationship) => {
if (!pendingConnection || !relationshipData) return;
// 관계 생성 로직은 여기서 구현...
// 현재는 간단히 성공 메시지만 표시
toast.success("관계가 생성되었습니다.");
setPendingConnection(null);
setHasUnsavedChanges(true);
}, [pendingConnection, setPendingConnection, setHasUnsavedChanges]);
if (editingRelationshipId) {
// 편집 모드: 기존 관계 업데이트
const updatedRelationship = {
id: editingRelationshipId,
fromTable: relationshipData.from_table_name,
toTable: relationshipData.to_table_name,
fromColumns: relationshipData.from_column_name ? relationshipData.from_column_name.split(",") : [],
toColumns: relationshipData.to_column_name ? relationshipData.to_column_name.split(",") : [],
connectionType: relationshipData.connection_type as "simple-key" | "data-save" | "external-call",
relationshipName: relationshipData.relationship_name,
settings: relationshipData.settings || {},
};
// tempRelationships에서 기존 관계 업데이트
setTempRelationships((prev) =>
prev.map((rel) => (rel.id === editingRelationshipId ? updatedRelationship : rel)),
);
// 기존 엣지 업데이트
setEdges((prevEdges) =>
prevEdges.map((edge) =>
edge.data?.relationshipId === editingRelationshipId
? {
...edge,
data: {
...edge.data,
relationshipId: editingRelationshipId,
fromTable: relationshipData.from_table_name,
toTable: relationshipData.to_table_name,
connectionType: relationshipData.connection_type,
relationshipName: relationshipData.relationship_name,
},
}
: edge,
),
);
// 편집 모드 종료
setEditingRelationshipId(null);
} else {
// 새로 생성 모드: 새로운 관계 추가
const newRelationship = {
id: `rel-${Date.now()}`,
fromTable: relationshipData.from_table_name,
toTable: relationshipData.to_table_name,
fromColumns: relationshipData.from_column_name ? relationshipData.from_column_name.split(",") : [],
toColumns: relationshipData.to_column_name ? relationshipData.to_column_name.split(",") : [],
connectionType: relationshipData.connection_type as "simple-key" | "data-save" | "external-call",
relationshipName: relationshipData.relationship_name,
settings: relationshipData.settings || {},
};
// tempRelationships 상태 업데이트
setTempRelationships((prev) => [...prev, newRelationship]);
// 새로운 엣지 생성
const newEdge = {
id: `edge-${relationshipData.from_table_name}-${relationshipData.to_table_name}-${Date.now()}`,
source: `table-${relationshipData.from_table_name}`,
target: `table-${relationshipData.to_table_name}`,
type: "step",
data: {
relationshipId: newRelationship.id,
fromTable: relationshipData.from_table_name,
toTable: relationshipData.to_table_name,
connectionType: relationshipData.connection_type,
relationshipName: relationshipData.relationship_name,
},
style: {
stroke: "#3b82f6",
strokeWidth: 2,
},
animated: false,
};
// 엣지 추가
setEdges((prevEdges) => [...prevEdges, newEdge]);
}
setPendingConnection(null);
setHasUnsavedChanges(true);
},
[
pendingConnection,
setPendingConnection,
setHasUnsavedChanges,
setTempRelationships,
setEdges,
editingRelationshipId,
setEditingRelationshipId,
],
);
// 연결 설정 취소
const handleCancelConnection = useCallback(() => {
@ -499,7 +585,7 @@ export const DataFlowDesigner: React.FC<DataFlowDesignerProps> = ({
}
}, [isSaving, setShowSaveModal]);
// 관계도 저장 함수 (간단한 구현)
// 관계도 저장 함수
const handleSaveDiagram = useCallback(
async (diagramName: string) => {
if (nodes.length === 0) {
@ -509,7 +595,74 @@ export const DataFlowDesigner: React.FC<DataFlowDesignerProps> = ({
setIsSaving(true);
try {
// 여기서 실제 저장 로직 구현
// 노드 위치 정보 추출
const nodePositions = extractNodePositions(nodes);
// 연결된 테이블 목록 추출
const tableNames = extractTableNames(nodes);
// 관계 데이터를 JsonRelationship 형태로 변환
const jsonRelationships: JsonRelationship[] = tempRelationships.map((rel) => ({
id: rel.id,
relationshipName: rel.relationshipName, // 🔥 핵심: 관계 이름 포함
fromTable: rel.fromTable,
toTable: rel.toTable,
fromColumns: rel.fromColumns,
toColumns: rel.toColumns,
connectionType: rel.connectionType,
settings: rel.settings,
}));
// 저장 요청 데이터 구성
const saveRequest: CreateDiagramRequest = {
diagram_name: diagramName,
relationships: {
relationships: jsonRelationships,
tables: tableNames,
},
node_positions: nodePositions,
// 카테고리 정보 추가
category: tempRelationships.map((rel) => ({
id: rel.id,
category: rel.connectionType,
})),
// 조건부 연결 설정이 있는 경우 추가
control: tempRelationships
.filter((rel) => rel.settings?.control)
.map((rel) => ({
id: rel.id,
triggerType: rel.settings?.control?.triggerType || "insert",
conditions: (rel.settings?.control?.conditionTree || []).map((condition: Record<string, unknown>) => ({
...condition,
logicalOperator:
condition.logicalOperator === "AND" || condition.logicalOperator === "OR"
? condition.logicalOperator
: undefined,
})),
})),
// 데이터 저장 액션이 있는 경우 추가
plan: tempRelationships
.filter((rel) => rel.settings?.actions && Array.isArray(rel.settings.actions))
.map((rel) => ({
id: rel.id,
sourceTable: rel.fromTable,
actions: rel.settings?.actions || [],
})),
};
if (diagramId && diagramId > 0) {
// 기존 관계도 수정
await DataFlowAPI.updateJsonDataFlowDiagram(
diagramId,
saveRequest,
companyCode,
authUser?.userId || "SYSTEM",
);
} else {
// 새로운 관계도 생성
await DataFlowAPI.createJsonDataFlowDiagram(saveRequest, companyCode, authUser?.userId || "SYSTEM");
}
toast.success(`관계도 "${diagramName}"가 성공적으로 저장되었습니다.`);
setHasUnsavedChanges(false);
setShowSaveModal(false);
@ -520,7 +673,16 @@ export const DataFlowDesigner: React.FC<DataFlowDesignerProps> = ({
setIsSaving(false);
}
},
[nodes, setIsSaving, setHasUnsavedChanges, setShowSaveModal],
[
nodes,
tempRelationships,
diagramId,
companyCode,
authUser?.userId,
setIsSaving,
setHasUnsavedChanges,
setShowSaveModal,
],
);
// 고립된 노드 제거 함수
@ -608,7 +770,11 @@ export const DataFlowDesigner: React.FC<DataFlowDesignerProps> = ({
{/* 관계 목록 모달 */}
<RelationshipListModal
isOpen={showRelationshipListModal}
relationships={selectedTablePairRelationships}
relationships={selectedTablePairRelationships.map((rel) => {
// 최신 tempRelationships에서 해당 관계 찾기
const updatedRel = tempRelationships.find((tempRel) => tempRel.id === rel.id);
return updatedRel || rel; // 업데이트된 관계가 있으면 사용, 없으면 원본 사용
})}
nodes={nodes}
diagramId={diagramId}
companyCode={companyCode}
@ -682,8 +848,76 @@ export const DataFlowDesigner: React.FC<DataFlowDesignerProps> = ({
setSelectedEdgeForEdit(null);
setSelectedColumns({});
}}
onEdit={() => {}}
onDelete={() => {}}
onEdit={() => {
if (selectedEdgeInfo) {
// 기존 관계 찾기
const existingRelationship = tempRelationships.find((rel) => rel.id === selectedEdgeInfo.relationshipId);
if (existingRelationship) {
// 편집 모드로 설정
setEditingRelationshipId(selectedEdgeInfo.relationshipId);
// 연결 설정 모달 열기
const fromTable = nodes.find((node) => node.data?.table?.tableName === selectedEdgeInfo.fromTable);
const toTable = nodes.find((node) => node.data?.table?.tableName === selectedEdgeInfo.toTable);
if (fromTable && toTable) {
setPendingConnection({
fromNode: {
id: fromTable.id,
tableName: selectedEdgeInfo.fromTable,
displayName: fromTable.data?.table?.displayName || selectedEdgeInfo.fromTable,
},
toNode: {
id: toTable.id,
tableName: selectedEdgeInfo.toTable,
displayName: toTable.data?.table?.displayName || selectedEdgeInfo.toTable,
},
selectedColumnsData: {
[selectedEdgeInfo.fromTable]: {
displayName: fromTable.data?.table?.displayName || selectedEdgeInfo.fromTable,
columns: selectedEdgeInfo.fromColumns || [],
},
[selectedEdgeInfo.toTable]: {
displayName: toTable.data?.table?.displayName || selectedEdgeInfo.toTable,
columns: selectedEdgeInfo.toColumns || [],
},
},
existingRelationship: {
relationshipName: existingRelationship.relationshipName,
connectionType: existingRelationship.connectionType,
settings: existingRelationship.settings,
},
});
// 패널 닫기
setSelectedEdgeInfo(null);
setShowEdgeActions(false);
setSelectedEdgeForEdit(null);
}
}
}
}}
onDelete={() => {
if (selectedEdgeInfo) {
// 관계 삭제
setTempRelationships((prev) => prev.filter((rel) => rel.id !== selectedEdgeInfo.relationshipId));
// 엣지 삭제
setEdges((prev) => prev.filter((edge) => edge.data?.relationshipId !== selectedEdgeInfo.relationshipId));
// 변경사항 표시
setHasUnsavedChanges(true);
// 패널 닫기
setSelectedEdgeInfo(null);
setShowEdgeActions(false);
setSelectedEdgeForEdit(null);
setSelectedColumns({});
toast.success("관계가 삭제되었습니다.");
}
}}
/>
{/* 관계도 저장 모달 */}

View File

@ -156,7 +156,7 @@ export const RelationshipListModal: React.FC<RelationshipListModalProps> = ({
>
<div className="mb-1 flex items-center justify-between">
<h4 className="text-sm font-medium text-gray-900">
{relationship.fromTable} {relationship.toTable}
{relationship.relationshipName || `${relationship.fromTable}${relationship.toTable}`}
</h4>
<div className="flex items-center gap-1">
{/* 편집 버튼 */}

View File

@ -155,11 +155,11 @@ const SaveDiagramModal: React.FC<SaveDiagramModalProps> = ({
<div className="flex-1">
<div className="flex items-center gap-2 text-sm">
<Badge variant="secondary" className="text-xs">
{relationship.relationshipType}
{relationship.connectionType || "simple-key"}
</Badge>
<span className="font-medium">{relationship.fromTable}</span>
<span className="text-gray-500"></span>
<span className="font-medium">{relationship.toTable}</span>
<span className="font-medium">
{relationship.relationshipName || `${relationship.fromTable}${relationship.toTable}`}
</span>
</div>
<div className="mt-1 text-xs text-gray-600">
{relationship.fromColumns.join(", ")} {relationship.toColumns.join(", ")}