2025-09-16 14:57:47 +09:00
|
|
|
"use client";
|
|
|
|
|
|
|
|
|
|
import React from "react";
|
|
|
|
|
import { ExtendedJsonRelationship, TableNodeData } from "@/types/dataflowTypes";
|
|
|
|
|
import { DataFlowAPI } from "@/lib/api/dataflow";
|
|
|
|
|
|
|
|
|
|
interface RelationshipListModalProps {
|
|
|
|
|
isOpen: boolean;
|
|
|
|
|
relationships: ExtendedJsonRelationship[];
|
|
|
|
|
nodes: Array<{ id: string; data: TableNodeData }>;
|
|
|
|
|
diagramId?: number;
|
|
|
|
|
companyCode: string;
|
|
|
|
|
editingRelationshipId: string | null;
|
|
|
|
|
onClose: () => void;
|
|
|
|
|
onEdit: (relationship: ExtendedJsonRelationship) => void;
|
|
|
|
|
onDelete: (relationshipId: string) => void;
|
|
|
|
|
onSetEditingId: (id: string | null) => void;
|
|
|
|
|
onSetSelectedColumns: (columns: { [tableName: string]: string[] }) => void;
|
|
|
|
|
onSetPendingConnection: (connection: any) => void;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export const RelationshipListModal: React.FC<RelationshipListModalProps> = ({
|
|
|
|
|
isOpen,
|
|
|
|
|
relationships,
|
|
|
|
|
nodes,
|
|
|
|
|
diagramId,
|
|
|
|
|
companyCode,
|
|
|
|
|
editingRelationshipId,
|
|
|
|
|
onClose,
|
|
|
|
|
onEdit,
|
|
|
|
|
onDelete,
|
|
|
|
|
onSetEditingId,
|
|
|
|
|
onSetSelectedColumns,
|
|
|
|
|
onSetPendingConnection,
|
|
|
|
|
}) => {
|
|
|
|
|
if (!isOpen) return null;
|
|
|
|
|
|
|
|
|
|
const handleEdit = async (relationship: ExtendedJsonRelationship) => {
|
|
|
|
|
// 관계 선택 시 수정 모드로 전환
|
|
|
|
|
onSetEditingId(relationship.id);
|
|
|
|
|
|
|
|
|
|
// 관련 컬럼 하이라이트
|
|
|
|
|
const newSelectedColumns: { [tableName: string]: string[] } = {};
|
|
|
|
|
if (relationship.fromTable && relationship.fromColumns) {
|
|
|
|
|
newSelectedColumns[relationship.fromTable] = [...relationship.fromColumns];
|
|
|
|
|
}
|
|
|
|
|
if (relationship.toTable && relationship.toColumns) {
|
|
|
|
|
newSelectedColumns[relationship.toTable] = [...relationship.toColumns];
|
|
|
|
|
}
|
|
|
|
|
onSetSelectedColumns(newSelectedColumns);
|
|
|
|
|
|
2025-09-16 18:22:06 +09:00
|
|
|
// 🔥 수정: 관계 설정 정보 로드 (임시 관계 우선, 없으면 데이터베이스에서)
|
2025-09-16 14:57:47 +09:00
|
|
|
let relationshipSettings = {};
|
2025-09-16 18:22:06 +09:00
|
|
|
|
|
|
|
|
// 1. 먼저 임시 관계의 settings 사용 (메모리에 있는 데이터)
|
|
|
|
|
if (relationship.settings && Object.keys(relationship.settings).length > 0) {
|
|
|
|
|
relationshipSettings = relationship.settings;
|
|
|
|
|
}
|
|
|
|
|
// 2. 임시 settings가 없고 저장된 관계도인 경우 데이터베이스에서 로드
|
|
|
|
|
else if (diagramId && diagramId > 0) {
|
2025-09-16 14:57:47 +09:00
|
|
|
try {
|
|
|
|
|
const jsonDiagram = await DataFlowAPI.getJsonDataFlowDiagramById(diagramId, companyCode);
|
|
|
|
|
if (jsonDiagram && relationship.connectionType === "data-save") {
|
|
|
|
|
const control = jsonDiagram.control?.find((c) => c.id === relationship.id);
|
|
|
|
|
const plan = jsonDiagram.plan?.find((p) => p.id === relationship.id);
|
|
|
|
|
|
|
|
|
|
relationshipSettings = {
|
|
|
|
|
control: control
|
|
|
|
|
? {
|
|
|
|
|
triggerType: control.triggerType,
|
|
|
|
|
conditionTree: control.conditions || [],
|
|
|
|
|
}
|
|
|
|
|
: undefined,
|
|
|
|
|
actions: plan ? plan.actions || [] : [],
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("관계 설정 정보 로드 실패:", error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 연결 설정 모달 열기
|
|
|
|
|
const fromTable = nodes.find((node) => node.data?.table?.tableName === relationship.fromTable);
|
|
|
|
|
const toTable = nodes.find((node) => node.data?.table?.tableName === relationship.toTable);
|
|
|
|
|
|
|
|
|
|
if (fromTable && toTable) {
|
|
|
|
|
onSetPendingConnection({
|
|
|
|
|
fromNode: {
|
|
|
|
|
id: fromTable.id,
|
|
|
|
|
tableName: relationship.fromTable,
|
|
|
|
|
displayName: fromTable.data?.table?.displayName || relationship.fromTable,
|
|
|
|
|
},
|
|
|
|
|
toNode: {
|
|
|
|
|
id: toTable.id,
|
|
|
|
|
tableName: relationship.toTable,
|
|
|
|
|
displayName: toTable.data?.table?.displayName || relationship.toTable,
|
|
|
|
|
},
|
|
|
|
|
selectedColumnsData: {
|
|
|
|
|
[relationship.fromTable]: {
|
|
|
|
|
displayName: fromTable.data?.table?.displayName || relationship.fromTable,
|
|
|
|
|
columns: relationship.fromColumns || [],
|
|
|
|
|
},
|
|
|
|
|
[relationship.toTable]: {
|
|
|
|
|
displayName: toTable.data?.table?.displayName || relationship.toTable,
|
|
|
|
|
columns: relationship.toColumns || [],
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
existingRelationship: {
|
|
|
|
|
relationshipName: relationship.relationshipName,
|
|
|
|
|
connectionType: relationship.connectionType,
|
2025-09-16 18:15:54 +09:00
|
|
|
note: relationship.note, // 🔥 연결 설명 포함
|
2025-09-16 14:57:47 +09:00
|
|
|
settings: relationshipSettings,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 모달 닫기
|
|
|
|
|
onClose();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleDelete = (relationship: ExtendedJsonRelationship) => {
|
|
|
|
|
onDelete(relationship.id);
|
|
|
|
|
|
|
|
|
|
// 선택된 컬럼 초기화
|
|
|
|
|
onSetSelectedColumns({});
|
|
|
|
|
|
|
|
|
|
// 편집 모드 해제
|
|
|
|
|
if (editingRelationshipId === relationship.id) {
|
|
|
|
|
onSetEditingId(null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 모달 닫기
|
|
|
|
|
onClose();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className="pointer-events-auto absolute top-4 right-4 z-40 w-80 rounded-xl border border-blue-200 bg-white shadow-lg">
|
|
|
|
|
{/* 헤더 */}
|
|
|
|
|
<div className="flex items-center justify-between rounded-t-xl border-b border-blue-100 bg-gradient-to-r from-blue-50 to-indigo-50 p-3">
|
|
|
|
|
<div className="flex items-center gap-2">
|
|
|
|
|
<div className="rounded-full bg-blue-100 p-1">
|
|
|
|
|
<span className="text-sm text-blue-600">🔗</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="text-sm font-semibold text-gray-800">테이블 간 관계 목록</div>
|
|
|
|
|
</div>
|
|
|
|
|
<button
|
|
|
|
|
onClick={onClose}
|
|
|
|
|
className="flex h-6 w-6 items-center justify-center rounded-full text-gray-400 transition-colors hover:bg-gray-100 hover:text-gray-600"
|
|
|
|
|
>
|
|
|
|
|
<svg className="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
|
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
|
|
|
|
|
</svg>
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* 관계 목록 */}
|
|
|
|
|
<div className="p-3">
|
|
|
|
|
<div className="max-h-96 space-y-2 overflow-y-auto">
|
|
|
|
|
{relationships.map((relationship) => (
|
|
|
|
|
<div
|
|
|
|
|
key={relationship.id}
|
|
|
|
|
className="rounded-lg border border-gray-200 p-3 transition-all hover:border-blue-300 hover:bg-blue-50"
|
|
|
|
|
>
|
|
|
|
|
<div className="mb-1 flex items-center justify-between">
|
|
|
|
|
<h4 className="text-sm font-medium text-gray-900">
|
2025-09-16 16:49:59 +09:00
|
|
|
{relationship.relationshipName || `${relationship.fromTable} → ${relationship.toTable}`}
|
2025-09-16 14:57:47 +09:00
|
|
|
</h4>
|
|
|
|
|
<div className="flex items-center gap-1">
|
|
|
|
|
{/* 편집 버튼 */}
|
|
|
|
|
<button
|
|
|
|
|
onClick={(e) => {
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
handleEdit(relationship);
|
|
|
|
|
}}
|
|
|
|
|
className="flex h-6 w-6 items-center justify-center rounded text-gray-400 hover:bg-blue-100 hover:text-blue-600"
|
|
|
|
|
title="관계 편집"
|
|
|
|
|
>
|
|
|
|
|
<svg className="h-3 w-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
|
|
|
<path
|
|
|
|
|
strokeLinecap="round"
|
|
|
|
|
strokeLinejoin="round"
|
|
|
|
|
strokeWidth={2}
|
|
|
|
|
d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"
|
|
|
|
|
/>
|
|
|
|
|
</svg>
|
|
|
|
|
</button>
|
|
|
|
|
{/* 삭제 버튼 */}
|
|
|
|
|
<button
|
|
|
|
|
onClick={(e) => {
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
handleDelete(relationship);
|
|
|
|
|
}}
|
|
|
|
|
className="flex h-6 w-6 items-center justify-center rounded text-gray-400 hover:bg-red-100 hover:text-red-600"
|
|
|
|
|
title="관계 삭제"
|
|
|
|
|
>
|
|
|
|
|
<svg className="h-3 w-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
|
|
|
<path
|
|
|
|
|
strokeLinecap="round"
|
|
|
|
|
strokeLinejoin="round"
|
|
|
|
|
strokeWidth={2}
|
|
|
|
|
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
|
|
|
|
|
/>
|
|
|
|
|
</svg>
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="space-y-1 text-xs text-gray-600">
|
|
|
|
|
<p>타입: {relationship.connectionType}</p>
|
|
|
|
|
<p>From: {relationship.fromTable}</p>
|
|
|
|
|
<p>To: {relationship.toTable}</p>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
};
|