131 lines
4.6 KiB
TypeScript
131 lines
4.6 KiB
TypeScript
|
|
"use client";
|
|||
|
|
|
|||
|
|
import React from "react";
|
|||
|
|
import { TableNodeData } from "@/types/dataflowTypes";
|
|||
|
|
|
|||
|
|
interface SelectedTablesPanelProps {
|
|||
|
|
selectedNodes: string[];
|
|||
|
|
nodes: Array<{
|
|||
|
|
id: string;
|
|||
|
|
data: TableNodeData;
|
|||
|
|
}>;
|
|||
|
|
onClose: () => void;
|
|||
|
|
onOpenConnectionModal: () => void;
|
|||
|
|
onClear: () => void;
|
|||
|
|
canCreateConnection: boolean;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export const SelectedTablesPanel: React.FC<SelectedTablesPanelProps> = ({
|
|||
|
|
selectedNodes,
|
|||
|
|
nodes,
|
|||
|
|
onClose,
|
|||
|
|
onOpenConnectionModal,
|
|||
|
|
onClear,
|
|||
|
|
canCreateConnection,
|
|||
|
|
}) => {
|
|||
|
|
return (
|
|||
|
|
<div className="pointer-events-auto absolute top-4 left-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="flex h-6 w-6 items-center justify-center rounded-full bg-blue-100">
|
|||
|
|
<span className="text-sm text-blue-600">📋</span>
|
|||
|
|
</div>
|
|||
|
|
<div>
|
|||
|
|
<div className="text-sm font-semibold text-gray-800">선택된 테이블</div>
|
|||
|
|
<div className="text-xs text-gray-500">
|
|||
|
|
{selectedNodes.length === 1
|
|||
|
|
? "FROM 테이블 선택됨"
|
|||
|
|
: selectedNodes.length === 2
|
|||
|
|
? "FROM → TO 연결 준비"
|
|||
|
|
: `${selectedNodes.length}개 테이블`}
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
<button
|
|||
|
|
onClick={onClose}
|
|||
|
|
className="flex h-5 w-5 items-center justify-center rounded-full text-gray-400 hover:bg-gray-100 hover:text-gray-600"
|
|||
|
|
>
|
|||
|
|
✕
|
|||
|
|
</button>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
{/* 컨텐츠 */}
|
|||
|
|
<div className="max-h-80 overflow-y-auto p-3">
|
|||
|
|
<div className="space-y-3">
|
|||
|
|
{selectedNodes.map((nodeId, index) => {
|
|||
|
|
const node = nodes.find((n) => n.id === nodeId);
|
|||
|
|
if (!node) return null;
|
|||
|
|
|
|||
|
|
const { tableName, displayName } = node.data.table;
|
|||
|
|
return (
|
|||
|
|
<div key={`selected-${nodeId}-${index}`}>
|
|||
|
|
{/* 테이블 정보 */}
|
|||
|
|
<div
|
|||
|
|
className={`rounded-lg p-2 ${
|
|||
|
|
index === 0
|
|||
|
|
? "border-l-4 border-emerald-400 bg-emerald-50"
|
|||
|
|
: index === 1
|
|||
|
|
? "border-l-4 border-blue-400 bg-blue-50"
|
|||
|
|
: "bg-gray-50"
|
|||
|
|
}`}
|
|||
|
|
>
|
|||
|
|
<div className="mb-1 flex items-center justify-between">
|
|||
|
|
<div
|
|||
|
|
className={`text-xs font-medium ${
|
|||
|
|
index === 0 ? "text-emerald-700" : index === 1 ? "text-blue-700" : "text-gray-700"
|
|||
|
|
}`}
|
|||
|
|
>
|
|||
|
|
{displayName}
|
|||
|
|
</div>
|
|||
|
|
{selectedNodes.length === 2 && (
|
|||
|
|
<div
|
|||
|
|
className={`rounded-full px-2 py-0.5 text-xs font-bold ${
|
|||
|
|
index === 0 ? "bg-emerald-200 text-emerald-800" : "bg-blue-200 text-blue-800"
|
|||
|
|
}`}
|
|||
|
|
>
|
|||
|
|
{index === 0 ? "FROM" : "TO"}
|
|||
|
|
</div>
|
|||
|
|
)}
|
|||
|
|
</div>
|
|||
|
|
<div className="text-xs text-gray-600">{tableName}</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
{/* 연결 화살표 (마지막이 아닌 경우) */}
|
|||
|
|
{index < selectedNodes.length - 1 && (
|
|||
|
|
<div className="flex justify-center py-1">
|
|||
|
|
<div className="text-gray-400">→</div>
|
|||
|
|
</div>
|
|||
|
|
)}
|
|||
|
|
</div>
|
|||
|
|
);
|
|||
|
|
})}
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
{/* 액션 버튼 */}
|
|||
|
|
<div className="flex gap-2 border-t border-blue-100 p-3">
|
|||
|
|
<button
|
|||
|
|
onClick={onOpenConnectionModal}
|
|||
|
|
disabled={!canCreateConnection}
|
|||
|
|
className={`flex flex-1 items-center justify-center gap-1 rounded-lg px-3 py-2 text-xs font-medium transition-colors ${
|
|||
|
|
canCreateConnection
|
|||
|
|
? "bg-blue-500 text-white hover:bg-blue-600"
|
|||
|
|
: "cursor-not-allowed bg-gray-300 text-gray-500"
|
|||
|
|
}`}
|
|||
|
|
>
|
|||
|
|
<span>🔗</span>
|
|||
|
|
<span>연결 설정</span>
|
|||
|
|
</button>
|
|||
|
|
<button
|
|||
|
|
onClick={onClear}
|
|||
|
|
className="flex flex-1 items-center justify-center gap-1 rounded-lg bg-gray-200 px-3 py-2 text-xs font-medium text-gray-600 hover:bg-gray-300"
|
|||
|
|
>
|
|||
|
|
<span>🗑️</span>
|
|||
|
|
<span>초기화</span>
|
|||
|
|
</button>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
);
|
|||
|
|
};
|