"use client"; import React from "react"; import { Handle, Position } from "@xyflow/react"; import { Monitor, Database, FormInput, Table2, LayoutDashboard, MousePointer2, Key, Link2, Columns3, } from "lucide-react"; import { ScreenLayoutSummary } from "@/lib/api/screenGroup"; // ========== 타입 정의 ========== // 화면 노드 데이터 인터페이스 export interface ScreenNodeData { label: string; subLabel?: string; type: "screen" | "table" | "action"; tableName?: string; isMain?: boolean; // 레이아웃 요약 정보 (미리보기용) layoutSummary?: ScreenLayoutSummary; // 그룹 내 포커스 관련 속성 isInGroup?: boolean; // 그룹 모드인지 isFocused?: boolean; // 포커스된 화면인지 isFaded?: boolean; // 흑백 처리할지 screenRole?: string; // 화면 역할 (메인그리드, 등록폼 등) } // 테이블 노드 데이터 인터페이스 export interface TableNodeData { label: string; subLabel?: string; isMain?: boolean; columns?: Array<{ name: string; type: string; isPrimaryKey?: boolean; isForeignKey?: boolean; }>; } // ========== 유틸리티 함수 ========== // 화면 타입별 아이콘 const getScreenTypeIcon = (screenType?: string) => { switch (screenType) { case "grid": return ; case "dashboard": return ; case "action": return ; default: return ; } }; // 화면 타입별 색상 (헤더) const getScreenTypeColor = (screenType?: string, isMain?: boolean) => { if (!isMain) return "bg-slate-400"; switch (screenType) { case "grid": return "bg-violet-500"; case "dashboard": return "bg-amber-500"; case "action": return "bg-rose-500"; default: return "bg-blue-500"; } }; // 화면 역할(screenRole)에 따른 색상 const getScreenRoleColor = (screenRole?: string) => { if (!screenRole) return "bg-slate-400"; // 역할명에 포함된 키워드로 색상 결정 const role = screenRole.toLowerCase(); if (role.includes("그리드") || role.includes("grid") || role.includes("메인") || role.includes("main") || role.includes("list")) { return "bg-violet-500"; // 보라색 - 메인 그리드 } if (role.includes("등록") || role.includes("폼") || role.includes("form") || role.includes("register") || role.includes("input")) { return "bg-blue-500"; // 파란색 - 등록 폼 } if (role.includes("액션") || role.includes("action") || role.includes("이벤트") || role.includes("event") || role.includes("클릭")) { return "bg-rose-500"; // 빨간색 - 액션/이벤트 } if (role.includes("상세") || role.includes("detail") || role.includes("popup") || role.includes("팝업")) { return "bg-amber-500"; // 주황색 - 상세/팝업 } return "bg-slate-400"; // 기본 회색 }; // 화면 타입별 라벨 const getScreenTypeLabel = (screenType?: string) => { switch (screenType) { case "grid": return "그리드"; case "dashboard": return "대시보드"; case "action": return "액션"; default: return "폼"; } }; // ========== 화면 노드 (상단) - 미리보기 표시 ========== export const ScreenNode: React.FC<{ data: ScreenNodeData }> = ({ data }) => { const { label, subLabel, isMain, tableName, layoutSummary, isInGroup, isFocused, isFaded, screenRole } = data; const screenType = layoutSummary?.screenType || "form"; // 그룹 모드에서는 screenRole 기반 색상, 그렇지 않으면 screenType 기반 색상 // isFocused일 때 색상 활성화, isFaded일 때 회색 let headerColor: string; if (isInGroup) { if (isFaded) { headerColor = "bg-gray-300"; // 흑백 처리 - 더 확실한 회색 } else { // 포커스되었거나 아직 아무것도 선택 안됐을 때: 역할별 색상 headerColor = getScreenRoleColor(screenRole); } } else { headerColor = getScreenTypeColor(screenType, isMain); } return (
{/* Handles */} {/* 헤더 (컬러) */}
{label} {(isMain || isFocused) && }
{/* 화면 미리보기 영역 (컴팩트) */}
{layoutSummary ? ( ) : (
{getScreenTypeIcon(screenType)} 화면: {label}
)}
{/* 필드 매핑 영역 */}
필드 매핑 {layoutSummary?.layoutItems?.filter(i => i.label && !i.componentKind?.includes('button')).length || 0}개
{layoutSummary?.layoutItems ?.filter(item => item.label && !item.componentKind?.includes('button')) ?.slice(0, 6) ?.map((item, idx) => (
{item.label} {item.componentKind?.split('-')[0] || 'field'}
)) || (
필드 정보 없음
)}
{/* 푸터 (테이블 정보) */}
{tableName || "No Table"}
{getScreenTypeLabel(screenType)}
); }; // ========== 컴포넌트 종류별 미니어처 색상 ========== // componentKind는 더 정확한 컴포넌트 타입 (table-list, button-primary 등) const getComponentColor = (componentKind: string) => { // 테이블/그리드 관련 if (componentKind === "table-list" || componentKind === "data-grid") { return "bg-violet-200 border-violet-400"; } // 검색 필터 if (componentKind === "table-search-widget" || componentKind === "search-filter") { return "bg-pink-200 border-pink-400"; } // 버튼 관련 if (componentKind?.includes("button")) { return "bg-blue-300 border-blue-500"; } // 입력 필드 if (componentKind?.includes("input") || componentKind?.includes("text")) { return "bg-slate-200 border-slate-400"; } // 셀렉트/드롭다운 if (componentKind?.includes("select") || componentKind?.includes("dropdown")) { return "bg-amber-200 border-amber-400"; } // 차트 if (componentKind?.includes("chart")) { return "bg-emerald-200 border-emerald-400"; } // 커스텀 위젯 if (componentKind === "custom") { return "bg-pink-200 border-pink-400"; } return "bg-slate-100 border-slate-300"; }; // ========== 화면 미리보기 컴포넌트 - 화면 타입별 간단한 일러스트 ========== const ScreenPreview: React.FC<{ layoutSummary: ScreenLayoutSummary; screenType: string }> = ({ layoutSummary, screenType, }) => { const { totalComponents, widgetCounts } = layoutSummary; // 그리드 화면 일러스트 if (screenType === "grid") { return (
{/* 상단 툴바 */}
{/* 테이블 헤더 */}
{[...Array(5)].map((_, i) => (
))}
{/* 테이블 행들 */}
{[...Array(7)].map((_, i) => (
{[...Array(5)].map((_, j) => (
))}
))}
{/* 페이지네이션 */}
{/* 컴포넌트 수 */}
{totalComponents}개
); } // 폼 화면 일러스트 if (screenType === "form") { return (
{/* 폼 필드들 */} {[...Array(6)].map((_, i) => (
))} {/* 버튼 영역 */}
{/* 컴포넌트 수 */}
{totalComponents}개
); } // 대시보드 화면 일러스트 if (screenType === "dashboard") { return (
{/* 카드/차트들 */}
{[...Array(10)].map((_, i) => (
))}
{/* 컴포넌트 수 */}
{totalComponents}개
); } // 액션 화면 일러스트 (버튼 중심) if (screenType === "action") { return (
액션 화면
{/* 컴포넌트 수 */}
{totalComponents}개
); } // 기본 (알 수 없는 타입) return (
{getScreenTypeIcon(screenType)}
{totalComponents}개 컴포넌트
); }; // ========== 테이블 노드 (하단) - 컬럼 목록 표시 (컴팩트) ========== export const TableNode: React.FC<{ data: TableNodeData }> = ({ data }) => { const { label, subLabel, isMain, columns } = data; // 최대 5개 컬럼만 표시 const displayColumns = columns?.slice(0, 5) || []; const remainingCount = (columns?.length || 0) - 5; return (
{/* Handles */} {/* 헤더 (초록색, 컴팩트) */}
{label}
{subLabel &&
{subLabel}
}
{/* 컬럼 목록 (컴팩트) */}
{displayColumns.length > 0 ? (
{displayColumns.map((col, idx) => (
{/* PK/FK 아이콘 */} {col.isPrimaryKey && } {col.isForeignKey && !col.isPrimaryKey && } {!col.isPrimaryKey && !col.isForeignKey &&
} {/* 컬럼명 */} {col.name} {/* 타입 */} {col.type}
))} {remainingCount > 0 && (
+ {remainingCount}개 더
)}
) : (
컬럼 정보 없음
)}
{/* 푸터 (컴팩트) */}
PostgreSQL {columns && ( {columns.length}개 컬럼 )}
); }; // ========== 기존 호환성 유지용 ========== export const LegacyScreenNode = ScreenNode; export const AggregateNode: React.FC<{ data: any }> = ({ data }) => { return (
{data.label || "Aggregate"}
); };