"use client"; import React from "react"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Checkbox } from "@/components/ui/checkbox"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { ColumnConfig } from "../types"; import { Database, Link2, GripVertical, X, Check, ChevronsUpDown, Lock, Unlock } from "lucide-react"; import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "@/components/ui/command"; import { cn } from "@/lib/utils"; import { DndContext, closestCenter, type DragEndEvent } from "@dnd-kit/core"; import { SortableContext, useSortable, verticalListSortingStrategy, arrayMove } from "@dnd-kit/sortable"; import { CSS } from "@dnd-kit/utilities"; function SortableColumnRow({ id, col, index, isEntityJoin, onLabelChange, onWidthChange, onRemove, }: { id: string; col: ColumnConfig; index: number; isEntityJoin?: boolean; onLabelChange: (value: string) => void; onWidthChange: (value: number) => void; onRemove: () => void; }) { const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ id }); const style = { transform: CSS.Transform.toString(transform), transition }; return (
{isEntityJoin ? ( ) : ( #{index + 1} )} onLabelChange(e.target.value)} placeholder="표시명" className="h-6 min-w-0 flex-1 text-xs" /> onWidthChange(parseInt(e.target.value) || 100)} placeholder="너비" className="h-6 w-14 shrink-0 text-xs" />
); } export interface ColumnsConfigPanelProps { config: any; onChange: (key: string, value: any) => void; screenTableName?: string; targetTableName: string | undefined; availableColumns: Array<{ columnName: string; dataType: string; label?: string; input_type?: string }>; tableColumns?: any[]; entityJoinColumns: { availableColumns: Array<{ tableName: string; columnName: string; columnLabel: string; dataType: string; joinAlias: string; suggestedLabel: string; }>; joinTables: Array<{ tableName: string; currentDisplayColumn: string; availableColumns: Array<{ columnName: string; columnLabel: string; dataType: string; description?: string; }>; }>; }; entityDisplayConfigs: Record< string, { sourceColumns: Array<{ columnName: string; displayName: string; dataType: string }>; joinColumns: Array<{ columnName: string; displayName: string; dataType: string }>; selectedColumns: string[]; separator: string; } >; onAddColumn: (columnName: string) => void; onAddEntityColumn: (joinColumn: { tableName: string; columnName: string; columnLabel: string; dataType: string; joinAlias: string; suggestedLabel: string; }) => void; onRemoveColumn: (columnName: string) => void; onUpdateColumn: (columnName: string, updates: Partial) => void; onToggleEntityDisplayColumn: (columnName: string, selectedColumn: string) => void; onUpdateEntityDisplaySeparator: (columnName: string, separator: string) => void; } /** * 컬럼 설정 패널: 컬럼 선택, Entity 조인, DnD 순서 변경 */ export const ColumnsConfigPanel: React.FC = ({ config, onChange, screenTableName, targetTableName, availableColumns, tableColumns, entityJoinColumns, entityDisplayConfigs, onAddColumn, onAddEntityColumn, onRemoveColumn, onUpdateColumn, onToggleEntityDisplayColumn, onUpdateEntityDisplaySeparator, }) => { const handleChange = (key: string, value: any) => { onChange(key, value); }; return (
{/* 엔티티 컬럼 표시 설정 섹션 */} {config.columns?.some((col: ColumnConfig) => col.isEntityJoin) && (
{config.columns ?.filter((col: ColumnConfig) => col.isEntityJoin && col.entityDisplayConfig) .map((column: ColumnConfig) => (
{column.displayName || column.columnName}
{entityDisplayConfigs[column.columnName] ? (
onUpdateEntityDisplaySeparator(column.columnName, e.target.value)} className="h-6 w-full text-xs" style={{ fontSize: "12px" }} placeholder=" - " />
{entityDisplayConfigs[column.columnName].sourceColumns.length === 0 && entityDisplayConfigs[column.columnName].joinColumns.length === 0 ? (
표시 가능한 컬럼이 없습니다. {!column.entityDisplayConfig?.joinTable && (

테이블 타입 관리에서 참조 테이블을 설정하면 더 많은 컬럼을 선택할 수 있습니다.

)}
) : ( 컬럼을 찾을 수 없습니다. {entityDisplayConfigs[column.columnName].sourceColumns.length > 0 && ( {entityDisplayConfigs[column.columnName].sourceColumns.map((col) => ( onToggleEntityDisplayColumn(column.columnName, col.columnName)} className="text-xs" > {col.displayName} ))} )} {entityDisplayConfigs[column.columnName].joinColumns.length > 0 && ( {entityDisplayConfigs[column.columnName].joinColumns.map((col) => ( onToggleEntityDisplayColumn(column.columnName, col.columnName)} className="text-xs" > {col.displayName} ))} )} )}
{!column.entityDisplayConfig?.joinTable && entityDisplayConfigs[column.columnName].sourceColumns.length > 0 && (
현재 기본 테이블 컬럼만 표시됩니다. 테이블 타입 관리에서 참조 테이블을 설정하면 조인된 테이블의 컬럼도 선택할 수 있습니다.
)} {entityDisplayConfigs[column.columnName].selectedColumns.length > 0 && (
{entityDisplayConfigs[column.columnName].selectedColumns.map((colName, idx) => ( {colName} {idx < entityDisplayConfigs[column.columnName].selectedColumns.length - 1 && ( {entityDisplayConfigs[column.columnName].separator} )} ))}
)}
) : (
컬럼 정보 로딩 중...
)}
))}
)} {!targetTableName ? (

테이블이 선택되지 않았습니다.

기본 설정 탭에서 테이블을 선택하세요.

) : availableColumns.length === 0 ? (

컬럼을 추가하려면 먼저 컴포넌트에 테이블을 명시적으로 선택하거나

기본 설정 탭에서 테이블을 설정해주세요.

현재 화면 테이블: {screenTableName}

) : ( <>

컬럼 선택

표시할 컬럼을 선택하세요


{availableColumns.map((column) => { const isAdded = config.columns?.some((c: ColumnConfig) => c.columnName === column.columnName); return (
{ if (isAdded) { handleChange( "columns", config.columns?.filter((c: ColumnConfig) => c.columnName !== column.columnName) || [], ); } else { onAddColumn(column.columnName); } }} > { if (isAdded) { handleChange( "columns", config.columns?.filter((c: ColumnConfig) => c.columnName !== column.columnName) || [], ); } else { onAddColumn(column.columnName); } }} className="pointer-events-none h-3.5 w-3.5" /> {column.label || column.columnName} {isAdded && ( )} {column.input_type || column.dataType}
); })}
{entityJoinColumns.joinTables.length > 0 && (

Entity 조인 컬럼

연관 테이블의 컬럼을 선택하세요


{entityJoinColumns.joinTables.map((joinTable, tableIndex) => (
{joinTable.tableName} {joinTable.currentDisplayColumn}
{joinTable.availableColumns.map((column, colIndex) => { const matchingJoinColumn = entityJoinColumns.availableColumns.find( (jc) => jc.tableName === joinTable.tableName && jc.columnName === column.columnName, ); const isAlreadyAdded = config.columns?.some( (col: ColumnConfig) => col.columnName === matchingJoinColumn?.joinAlias, ); if (!matchingJoinColumn) return null; return (
{ if (isAlreadyAdded) { handleChange( "columns", config.columns?.filter( (c: ColumnConfig) => c.columnName !== matchingJoinColumn.joinAlias, ) || [], ); } else { onAddEntityColumn(matchingJoinColumn); } }} > { if (isAlreadyAdded) { handleChange( "columns", config.columns?.filter( (c: ColumnConfig) => c.columnName !== matchingJoinColumn.joinAlias, ) || [], ); } else { onAddEntityColumn(matchingJoinColumn); } }} className="pointer-events-none h-3.5 w-3.5" /> {column.columnLabel} {column.inputType || column.dataType}
); })}
))}
)} )} {config.columns && config.columns.length > 0 && (

표시할 컬럼 ({config.columns.length}개 선택)

드래그하여 순서를 변경하거나 표시명/너비를 수정할 수 있습니다


{ const { active, over } = event; if (!over || active.id === over.id) return; const columns = [...(config.columns || [])]; const oldIndex = columns.findIndex((c: ColumnConfig) => c.columnName === active.id); const newIndex = columns.findIndex((c: ColumnConfig) => c.columnName === over.id); if (oldIndex !== -1 && newIndex !== -1) { const reordered = arrayMove(columns, oldIndex, newIndex); reordered.forEach((col: ColumnConfig, idx: number) => { col.order = idx; }); handleChange("columns", reordered); } }} > c.columnName)} strategy={verticalListSortingStrategy} >
{(config.columns || []).map((column: ColumnConfig, idx: number) => { const resolvedLabel = column.displayName && column.displayName !== column.columnName ? column.displayName : availableColumns.find((c) => c.columnName === column.columnName)?.label || column.displayName || column.columnName; const colWithLabel = { ...column, displayName: resolvedLabel }; return ( onUpdateColumn(column.columnName, { displayName: value })} onWidthChange={(value) => onUpdateColumn(column.columnName, { width: value })} onRemove={() => onRemoveColumn(column.columnName)} /> ); })}
)}
); };