"use client";
/**
* TableColumnPalette — 테이블 데이터 연결 탭의 컬럼 팔레트
*
* 2단계 플로우:
* 1. 체크박스로 사용할 컬럼을 중복 선택
* 2. 선택된 컬럼만 드래그 가능한 칩으로 표시 → 드롭 존에 배치
*/
import React, { useState, useMemo, useEffect } from "react";
import { useDrag } from "react-dnd";
import { Columns, Loader2, ChevronDown, ChevronUp, X } from "lucide-react";
export const TABLE_COLUMN_DND_TYPE = "table-column";
export interface SchemaColumn {
column_name: string;
data_type: string;
is_nullable: string;
}
// ─── 드래그 가능한 선택된 컬럼 칩 ────────────────────────────────────────────
interface DraggableColumnProps {
column: SchemaColumn;
placed?: boolean;
onRemove?: () => void;
}
function DraggableColumn({ column, placed = false, onRemove }: DraggableColumnProps) {
const [{ isDragging }, drag] = useDrag(() => ({
type: TABLE_COLUMN_DND_TYPE,
item: { columnName: column.column_name, dataType: column.data_type },
canDrag: () => !placed,
collect: (monitor) => ({
isDragging: monitor.isDragging(),
}),
}), [column, placed]);
return (
{column.column_name}
{placed ? (
배치됨
) : (
{column.data_type}
)}
{onRemove && (
)}
);
}
// ─── 메인 팔레트 ──────────────────────────────────────────────────────────────
interface TableColumnPaletteProps {
columns: SchemaColumn[];
loading?: boolean;
maxSelectable?: number;
placedColumns?: Set;
onColumnRemove?: (columnName: string) => void;
}
export function TableColumnPalette({ columns, loading, maxSelectable = 0, placedColumns, onColumnRemove }: TableColumnPaletteProps) {
const [selectedNames, setSelectedNames] = useState>(new Set());
const [listExpanded, setListExpanded] = useState(false);
// 이미 배치된 컬럼을 선택 목록에 자동 포함
useEffect(() => {
if (!placedColumns || placedColumns.size === 0) return;
setSelectedNames((prev) => {
const next = new Set(prev);
let changed = false;
placedColumns.forEach((name) => {
if (!next.has(name)) {
next.add(name);
changed = true;
}
});
return changed ? next : prev;
});
}, [placedColumns]);
const isLimitReached = maxSelectable > 0 && selectedNames.size >= maxSelectable;
const selectedColumns = useMemo(
() => columns.filter((c) => selectedNames.has(c.column_name)),
[columns, selectedNames],
);
const toggleColumn = (name: string) => {
setSelectedNames((prev) => {
const next = new Set(prev);
if (next.has(name)) {
next.delete(name);
} else {
if (maxSelectable > 0 && next.size >= maxSelectable) return prev;
next.add(name);
}
return next;
});
};
return (
{/* Step 1: 컬럼 선택 */}
{listExpanded && (
{loading ? (
컬럼 로딩 중...
) : columns.length === 0 ? (
레이아웃 탭에서 데이터 소스를 먼저 선택하세요.
) : (
<>
{maxSelectable > 0 && (
배치 가능 열 수: {maxSelectable}개
)}
{columns.map((col) => {
const checked = selectedNames.has(col.column_name);
const disabled = !checked && isLimitReached;
return (
);
})}
>
)}
)}
{/* Step 2: 선택된 컬럼 드래그 영역 */}
{selectedColumns.length > 0 && (
선택된 열
드래그하여 아래 표에 배치 ({selectedColumns.length}개)
{selectedColumns.map((col) => (
{
setSelectedNames((prev) => {
const next = new Set(prev);
next.delete(col.column_name);
return next;
});
onColumnRemove?.(col.column_name);
}}
/>
))}
)}
);
}