"use client"; import React, { useState, useEffect } 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 { TableListConfig, ColumnConfig } from "./types"; import { entityJoinApi } from "@/lib/api/entityJoin"; import { tableTypeApi } from "@/lib/api/screen"; import { tableManagementApi } from "@/lib/api/tableManagement"; import { Plus, Trash2, ArrowUp, ArrowDown, ChevronsUpDown, Check, Lock, Unlock, Database, Table2, Link2 } 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 { DataFilterConfigPanel } from "@/components/screen/config-panels/DataFilterConfigPanel"; export interface TableListConfigPanelProps { config: TableListConfig; onChange: (config: Partial) => void; screenTableName?: string; // 화면에 연결된 테이블명 tableColumns?: any[]; // 테이블 컬럼 정보 } /** * TableList 설정 패널 * 컴포넌트의 설정값들을 편집할 수 있는 UI 제공 */ export const TableListConfigPanel: React.FC = ({ config, onChange, screenTableName, tableColumns, }) => { // console.log("🔍 TableListConfigPanel props:", { // config, // configType: typeof config, // configSelectedTable: config?.selectedTable, // configPagination: config?.pagination, // paginationEnabled: config?.pagination?.enabled, // paginationPageSize: config?.pagination?.pageSize, // configKeys: typeof config === 'object' ? Object.keys(config || {}) : 'not object', // screenTableName, // tableColumns: tableColumns?.length, // tableColumnsSample: tableColumns?.[0], // }); const [availableTables, setAvailableTables] = useState>([]); const [loadingTables, setLoadingTables] = useState(false); const [tableComboboxOpen, setTableComboboxOpen] = useState(false); // 테이블 Combobox 열림 상태 const [availableColumns, setAvailableColumns] = useState< Array<{ columnName: string; dataType: string; label?: string; input_type?: string }> >([]); const [entityJoinColumns, setEntityJoinColumns] = useState<{ 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; }>; }>; }>({ availableColumns: [], joinTables: [] }); const [loadingEntityJoins, setLoadingEntityJoins] = useState(false); // 🆕 제외 필터용 참조 테이블 컬럼 목록 const [referenceTableColumns, setReferenceTableColumns] = useState< Array<{ columnName: string; dataType: string; label?: string }> >([]); const [loadingReferenceColumns, setLoadingReferenceColumns] = useState(false); // 🔄 외부에서 config가 변경될 때 내부 상태 동기화 (표의 페이지네이션 변경 감지) useEffect(() => { // console.log("🔄 TableListConfigPanel - 외부 config 변경 감지:", { // configPagination: config?.pagination, // configPageSize: config?.pagination?.pageSize, // }); // 현재는 별도 내부 상태가 없어서 자동으로 UI가 업데이트됨 // 만약 내부 상태가 있다면 여기서 동기화 처리 }, [config]); // 🎯 엔티티 컬럼 표시 설정을 위한 상태 const [entityDisplayConfigs, setEntityDisplayConfigs] = useState< Record< string, { sourceColumns: Array<{ columnName: string; displayName: string; dataType: string }>; joinColumns: Array<{ columnName: string; displayName: string; dataType: string }>; selectedColumns: string[]; separator: string; } > >({}); // 화면 테이블명이 있으면 자동으로 설정 (초기 한 번만) useEffect(() => { if (screenTableName && !config.selectedTable) { // 기존 config의 모든 속성을 유지하면서 selectedTable만 추가/업데이트 const updatedConfig = { ...config, selectedTable: screenTableName, // 컬럼이 있으면 유지, 없으면 빈 배열 columns: config.columns || [], }; onChange(updatedConfig); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [screenTableName]); // config.selectedTable이 없을 때만 실행되도록 의존성 최소화 // 테이블 목록 가져오기 useEffect(() => { const fetchTables = async () => { setLoadingTables(true); try { // API 클라이언트를 사용하여 올바른 포트로 호출 const response = await tableTypeApi.getTables(); setAvailableTables( response.map((table: any) => ({ tableName: table.tableName, displayName: table.displayName || table.tableName, })), ); } catch (error) { console.error("테이블 목록 가져오기 실패:", error); } finally { setLoadingTables(false); } }; fetchTables(); }, []); // 🆕 실제 사용할 테이블 이름 계산 (customTableName 우선) const targetTableName = React.useMemo(() => { if (config.useCustomTable && config.customTableName) { return config.customTableName; } return config.selectedTable || screenTableName; }, [config.useCustomTable, config.customTableName, config.selectedTable, screenTableName]); // 선택된 테이블의 컬럼 목록 설정 useEffect(() => { console.log( "🔍 useEffect 실행됨 - targetTableName:", targetTableName, "config.useCustomTable:", config.useCustomTable, "config.customTableName:", config.customTableName, "config.selectedTable:", config.selectedTable, "screenTableName:", screenTableName, ); if (!targetTableName) { console.log("🔧 컬럼 목록 숨김 - 테이블이 선택되지 않음"); setAvailableColumns([]); return; } // 🆕 customTableName이 설정된 경우 반드시 API에서 가져오기 // tableColumns prop은 화면의 기본 테이블 컬럼이므로, customTableName 사용 시 무시 const shouldUseTableColumnsProp = !config.useCustomTable && tableColumns && tableColumns.length > 0; if (shouldUseTableColumnsProp) { const mappedColumns = tableColumns.map((column: any) => ({ columnName: column.columnName || column.name, dataType: column.dataType || column.type || "text", label: column.label || column.displayName || column.columnLabel || column.columnName || column.name, input_type: column.input_type || column.inputType, })); setAvailableColumns(mappedColumns); // selectedTable이 없으면 screenTableName으로 설정 if (!config.selectedTable && screenTableName) { onChange({ ...config, selectedTable: screenTableName, columns: config.columns || [], }); } } else { // API에서 컬럼 정보 가져오기 - tableManagementApi 사용 const fetchColumns = async () => { console.log("🔧 API에서 컬럼 정보 가져오기 (tableManagementApi):", targetTableName); try { const result = await tableManagementApi.getColumnList(targetTableName); console.log("🔧 tableManagementApi 응답:", result); if (result.success && result.data) { // API 응답 구조: { columns: [...], total, page, ... } const columns = Array.isArray(result.data) ? result.data : result.data.columns; console.log("🔧 컬럼 배열:", columns); if (columns && Array.isArray(columns)) { setAvailableColumns( columns.map((col: any) => ({ columnName: col.columnName, dataType: col.dataType, label: col.displayName || col.columnLabel || col.columnName, input_type: col.input_type || col.inputType, })), ); } else { console.error("🔧 컬럼 배열을 찾을 수 없음:", result.data); setAvailableColumns([]); } } else { console.error("🔧 컬럼 조회 실패:", result.message); setAvailableColumns([]); } } catch (error) { console.error("컬럼 목록 가져오기 실패:", error); setAvailableColumns([]); } }; fetchColumns(); } }, [targetTableName, config.useCustomTable, tableColumns]); // Entity 조인 컬럼 정보 가져오기 - targetTableName 사용 useEffect(() => { const fetchEntityJoinColumns = async () => { if (!targetTableName) { setEntityJoinColumns({ availableColumns: [], joinTables: [] }); return; } setLoadingEntityJoins(true); try { console.log("🔗 Entity 조인 컬럼 정보 가져오기:", targetTableName); const result = await entityJoinApi.getEntityJoinColumns(targetTableName); console.log("✅ Entity 조인 컬럼 응답:", result); setEntityJoinColumns({ availableColumns: result.availableColumns || [], joinTables: result.joinTables || [], }); } catch (error) { console.error("❌ Entity 조인 컬럼 조회 오류:", error); setEntityJoinColumns({ availableColumns: [], joinTables: [] }); } finally { setLoadingEntityJoins(false); } }; fetchEntityJoinColumns(); }, [targetTableName]); // 🆕 제외 필터용 참조 테이블 컬럼 가져오기 useEffect(() => { const fetchReferenceColumns = async () => { const refTable = config.excludeFilter?.referenceTable; if (!refTable) { setReferenceTableColumns([]); return; } setLoadingReferenceColumns(true); try { console.log("🔗 참조 테이블 컬럼 정보 가져오기:", refTable); const result = await tableManagementApi.getColumnList(refTable); if (result.success && result.data) { // result.data는 { columns: [], total, page, size, totalPages } 형태 const columns = result.data.columns || []; setReferenceTableColumns( columns.map((col: any) => ({ columnName: col.columnName || col.column_name, dataType: col.dataType || col.data_type || "text", label: col.displayName || col.columnLabel || col.column_label || col.columnName || col.column_name, })), ); console.log("✅ 참조 테이블 컬럼 로드 완료:", columns.length, "개"); } } catch (error) { console.error("❌ 참조 테이블 컬럼 조회 오류:", error); setReferenceTableColumns([]); } finally { setLoadingReferenceColumns(false); } }; fetchReferenceColumns(); }, [config.excludeFilter?.referenceTable]); // 🎯 엔티티 컬럼 자동 로드 useEffect(() => { const entityColumns = config.columns?.filter((col) => col.isEntityJoin && col.entityDisplayConfig); if (!entityColumns || entityColumns.length === 0) return; // 각 엔티티 컬럼에 대해 자동으로 loadEntityDisplayConfig 호출 entityColumns.forEach((column) => { // 이미 로드된 경우 스킵 if (entityDisplayConfigs[column.columnName]) { return; } loadEntityDisplayConfig(column); }); }, [config.columns]); const handleChange = (key: keyof TableListConfig, value: any) => { // 기존 config와 병합하여 전달 (다른 속성 손실 방지) onChange({ ...config, [key]: value }); }; const handleNestedChange = (parentKey: keyof TableListConfig, childKey: string, value: any) => { // console.log("🔧 TableListConfigPanel handleNestedChange:", { // parentKey, // childKey, // value, // parentValue: config[parentKey], // hasOnChange: !!onChange, // onChangeType: typeof onChange, // }); const parentValue = config[parentKey] as any; // 전체 config와 병합하여 다른 속성 유지 const newConfig = { ...config, [parentKey]: { ...parentValue, [childKey]: value, }, }; // console.log("📤 TableListConfigPanel onChange 호출:", newConfig); onChange(newConfig); }; // 컬럼 추가 const addColumn = (columnName: string) => { const existingColumn = config.columns?.find((col) => col.columnName === columnName); if (existingColumn) return; // tableColumns에서 해당 컬럼의 라벨 정보 찾기 const columnInfo = tableColumns?.find((col: any) => (col.columnName || col.name) === columnName); // 라벨명 우선 사용, 없으면 컬럼명 사용 const displayName = columnInfo?.label || columnInfo?.displayName || columnName; const newColumn: ColumnConfig = { columnName, displayName, visible: true, sortable: true, searchable: true, align: "left", format: "text", order: config.columns?.length || 0, }; handleChange("columns", [...(config.columns || []), newColumn]); }; // 🎯 조인 컬럼 추가 (조인 탭에서 추가하는 컬럼들은 일반 컬럼으로 처리) const addEntityColumn = (joinColumn: (typeof entityJoinColumns.availableColumns)[0]) => { console.log("🔗 조인 컬럼 추가 요청:", { joinColumn, joinAlias: joinColumn.joinAlias, columnLabel: joinColumn.columnLabel, tableName: joinColumn.tableName, columnName: joinColumn.columnName, }); const existingColumn = config.columns?.find((col) => col.columnName === joinColumn.joinAlias); if (existingColumn) { console.warn("⚠️ 이미 존재하는 컬럼:", joinColumn.joinAlias); return; } // 🎯 joinTables에서 sourceColumn 찾기 const joinTableInfo = entityJoinColumns.joinTables?.find((jt: any) => jt.tableName === joinColumn.tableName); const sourceColumn = joinTableInfo?.joinConfig?.sourceColumn || ""; console.log("🔍 조인 정보 추출:", { tableName: joinColumn.tableName, foundJoinTable: !!joinTableInfo, sourceColumn, joinConfig: joinTableInfo?.joinConfig, }); // 조인 탭에서 추가하는 컬럼들은 일반 컬럼으로 처리 (isEntityJoin: false) const newColumn: ColumnConfig = { columnName: joinColumn.joinAlias, displayName: joinColumn.columnLabel, visible: true, sortable: true, searchable: true, align: "left", format: "text", order: config.columns?.length || 0, isEntityJoin: false, // 조인 탭에서 추가하는 컬럼은 엔티티 타입이 아님 // 🎯 추가 조인 정보 저장 additionalJoinInfo: { sourceTable: config.selectedTable || screenTableName || "", // 기준 테이블 (예: user_info) sourceColumn: sourceColumn, // 기준 컬럼 (예: dept_code) - joinTables에서 추출 referenceTable: joinColumn.tableName, // 참조 테이블 (예: dept_info) joinAlias: joinColumn.joinAlias, // 조인 별칭 (예: dept_code_company_name) }, }; handleChange("columns", [...(config.columns || []), newColumn]); console.log("✅ 조인 컬럼 추가 완료:", { columnName: newColumn.columnName, displayName: newColumn.displayName, totalColumns: (config.columns?.length || 0) + 1, }); }; // 컬럼 제거 const removeColumn = (columnName: string) => { const updatedColumns = config.columns?.filter((col) => col.columnName !== columnName) || []; handleChange("columns", updatedColumns); }; // 컬럼 업데이트 const updateColumn = (columnName: string, updates: Partial) => { const updatedColumns = config.columns?.map((col) => (col.columnName === columnName ? { ...col, ...updates } : col)) || []; handleChange("columns", updatedColumns); }; // 🎯 기존 컬럼들을 체크하여 엔티티 타입인 경우 isEntityJoin 플래그 설정 // useRef로 이전 컬럼 개수를 추적하여 새 컬럼 추가 시에만 실행 const prevColumnsLengthRef = React.useRef(0); useEffect(() => { const currentLength = config.columns?.length || 0; const prevLength = prevColumnsLengthRef.current; console.log("🔍 엔티티 컬럼 감지 useEffect 실행:", { hasColumns: !!config.columns, columnsCount: currentLength, prevColumnsCount: prevLength, hasTableColumns: !!tableColumns, tableColumnsCount: tableColumns?.length || 0, selectedTable: config.selectedTable, }); if (!config.columns || !tableColumns || config.columns.length === 0) { console.log("⚠️ 컬럼 또는 테이블 컬럼 정보가 없어서 엔티티 감지 스킵"); prevColumnsLengthRef.current = currentLength; return; } // 컬럼 개수가 변경되지 않았고, 이미 체크한 적이 있으면 스킵 if (currentLength === prevLength && prevLength > 0) { console.log("ℹ️ 컬럼 개수 변경 없음, 엔티티 감지 스킵"); return; } const updatedColumns = config.columns.map((column) => { // 이미 isEntityJoin이 설정된 경우 스킵 if (column.isEntityJoin) { console.log("✅ 이미 엔티티 플래그 설정됨:", column.columnName); return column; } // 테이블 컬럼 정보에서 해당 컬럼 찾기 const tableColumn = tableColumns.find((tc) => tc.columnName === column.columnName); console.log("🔍 컬럼 검색:", { columnName: column.columnName, found: !!tableColumn, inputType: tableColumn?.input_type, webType: tableColumn?.web_type, }); // 엔티티 타입인 경우 isEntityJoin 플래그 설정 (input_type 또는 web_type 확인) if (tableColumn && (tableColumn.input_type === "entity" || tableColumn.web_type === "entity")) { console.log("🎯 엔티티 컬럼 감지 및 플래그 설정:", { columnName: column.columnName, referenceTable: tableColumn.reference_table, referenceTableAlt: tableColumn.referenceTable, allTableColumnKeys: Object.keys(tableColumn), }); return { ...column, isEntityJoin: true, entityJoinInfo: { sourceTable: config.selectedTable || screenTableName || "", sourceColumn: column.columnName, joinAlias: column.columnName, }, entityDisplayConfig: { displayColumns: [], // 빈 배열로 초기화 separator: " - ", sourceTable: config.selectedTable || screenTableName || "", joinTable: tableColumn.reference_table || tableColumn.referenceTable || "", }, }; } return column; }); // 변경사항이 있는 경우에만 업데이트 const hasChanges = updatedColumns.some((col, index) => col.isEntityJoin !== config.columns![index].isEntityJoin); if (hasChanges) { console.log("🎯 엔티티 컬럼 플래그 업데이트:", updatedColumns); handleChange("columns", updatedColumns); } else { console.log("ℹ️ 엔티티 컬럼 변경사항 없음"); } // 현재 컬럼 개수를 저장 prevColumnsLengthRef.current = currentLength; // eslint-disable-next-line react-hooks/exhaustive-deps }, [config.columns?.length, tableColumns, config.selectedTable]); // 컬럼 개수 변경 시에만 실행 // 🎯 엔티티 컬럼의 표시 컬럼 정보 로드 const loadEntityDisplayConfig = async (column: ColumnConfig) => { const configKey = `${column.columnName}`; // 이미 로드된 경우 스킵 if (entityDisplayConfigs[configKey]) return; if (!column.isEntityJoin) { // 엔티티 컬럼이 아니면 빈 상태로 설정하여 로딩 상태 해제 setEntityDisplayConfigs((prev) => ({ ...prev, [configKey]: { sourceColumns: [], joinColumns: [], selectedColumns: [], separator: " - ", }, })); return; } // sourceTable 결정 우선순위: // 1. entityDisplayConfig.sourceTable // 2. entityJoinInfo.sourceTable // 3. config.selectedTable // 4. screenTableName const sourceTable = column.entityDisplayConfig?.sourceTable || column.entityJoinInfo?.sourceTable || config.selectedTable || screenTableName; // sourceTable이 비어있으면 빈 상태로 설정 if (!sourceTable) { console.warn("⚠️ sourceTable을 찾을 수 없음:", column.columnName); setEntityDisplayConfigs((prev) => ({ ...prev, [configKey]: { sourceColumns: [], joinColumns: [], selectedColumns: column.entityDisplayConfig?.displayColumns || [], separator: column.entityDisplayConfig?.separator || " - ", }, })); return; } let joinTable = column.entityDisplayConfig?.joinTable; // joinTable이 없으면 tableTypeApi로 조회해서 설정 if (!joinTable) { try { console.log("🔍 tableTypeApi로 컬럼 정보 조회:", { tableName: sourceTable, columnName: column.columnName, }); const columnList = await tableTypeApi.getColumns(sourceTable); const columnInfo = columnList.find((col: any) => (col.column_name || col.columnName) === column.columnName); console.log("🔍 컬럼 정보 조회 결과:", { columnInfo: columnInfo, referenceTable: columnInfo?.reference_table || columnInfo?.referenceTable, referenceColumn: columnInfo?.reference_column || columnInfo?.referenceColumn, }); if (columnInfo?.reference_table || columnInfo?.referenceTable) { joinTable = columnInfo.reference_table || columnInfo.referenceTable; console.log("✅ tableTypeApi에서 조인 테이블 정보 찾음:", joinTable); // entityDisplayConfig 업데이트 const updatedConfig = { ...column.entityDisplayConfig, sourceTable: sourceTable, joinTable: joinTable, displayColumns: column.entityDisplayConfig?.displayColumns || [], separator: column.entityDisplayConfig?.separator || " - ", }; // 컬럼 설정 업데이트 const updatedColumns = config.columns?.map((col) => col.columnName === column.columnName ? { ...col, entityDisplayConfig: updatedConfig } : col, ); if (updatedColumns) { handleChange("columns", updatedColumns); } } else { console.warn("⚠️ tableTypeApi에서 조인 테이블 정보를 찾지 못함:", column.columnName); } } catch (error) { console.error("tableTypeApi 컬럼 정보 조회 실패:", error); } } console.log("🔍 최종 추출한 값:", { sourceTable, joinTable }); try { // 기본 테이블 컬럼 정보는 항상 로드 const sourceResult = await entityJoinApi.getReferenceTableColumns(sourceTable); const sourceColumns = sourceResult.columns || []; // joinTable이 있으면 조인 테이블 컬럼도 로드 let joinColumns: Array<{ columnName: string; displayName: string; dataType: string }> = []; if (joinTable) { try { const joinResult = await entityJoinApi.getReferenceTableColumns(joinTable); joinColumns = joinResult.columns || []; } catch (joinError) { console.warn("⚠️ 조인 테이블 컬럼 로드 실패:", joinTable, joinError); // 조인 테이블 로드 실패해도 소스 테이블 컬럼은 표시 } } setEntityDisplayConfigs((prev) => ({ ...prev, [configKey]: { sourceColumns, joinColumns, selectedColumns: column.entityDisplayConfig?.displayColumns || [], separator: column.entityDisplayConfig?.separator || " - ", }, })); } catch (error) { console.error("엔티티 표시 컬럼 정보 로드 실패:", error); // 에러 발생 시에도 빈 상태로 설정하여 로딩 상태 해제 setEntityDisplayConfigs((prev) => ({ ...prev, [configKey]: { sourceColumns: [], joinColumns: [], selectedColumns: column.entityDisplayConfig?.displayColumns || [], separator: column.entityDisplayConfig?.separator || " - ", }, })); } }; // 🎯 엔티티 표시 컬럼 선택 토글 const toggleEntityDisplayColumn = (columnName: string, selectedColumn: string) => { const configKey = `${columnName}`; const localConfig = entityDisplayConfigs[configKey]; if (!localConfig) return; const newSelectedColumns = localConfig.selectedColumns.includes(selectedColumn) ? localConfig.selectedColumns.filter((col) => col !== selectedColumn) : [...localConfig.selectedColumns, selectedColumn]; // 로컬 상태 업데이트 setEntityDisplayConfigs((prev) => ({ ...prev, [configKey]: { ...prev[configKey], selectedColumns: newSelectedColumns, }, })); // 실제 컬럼 설정도 업데이트 const updatedColumns = config.columns?.map((col) => { if (col.columnName === columnName && col.entityDisplayConfig) { return { ...col, entityDisplayConfig: { ...col.entityDisplayConfig, displayColumns: newSelectedColumns, }, }; } return col; }); if (updatedColumns) { handleChange("columns", updatedColumns); } }; // 🎯 엔티티 표시 구분자 업데이트 const updateEntityDisplaySeparator = (columnName: string, separator: string) => { const configKey = `${columnName}`; const localConfig = entityDisplayConfigs[configKey]; if (!localConfig) return; // 로컬 상태 업데이트 setEntityDisplayConfigs((prev) => ({ ...prev, [configKey]: { ...prev[configKey], separator, }, })); // 실제 컬럼 설정도 업데이트 const updatedColumns = config.columns?.map((col) => { if (col.columnName === columnName && col.entityDisplayConfig) { return { ...col, entityDisplayConfig: { ...col.entityDisplayConfig, separator, }, }; } return col; }); if (updatedColumns) { handleChange("columns", updatedColumns); } }; // 컬럼 순서 변경 const moveColumn = (columnName: string, direction: "up" | "down") => { const columns = [...(config.columns || [])]; const index = columns.findIndex((col) => col.columnName === columnName); if (index === -1) return; const targetIndex = direction === "up" ? index - 1 : index + 1; if (targetIndex < 0 || targetIndex >= columns.length) return; [columns[index], columns[targetIndex]] = [columns[targetIndex], columns[index]]; // order 값 재정렬 columns.forEach((col, idx) => { col.order = idx; }); handleChange("columns", columns); }; return (
테이블 리스트 설정
{/* 툴바 버튼 설정 */}

툴바 버튼 설정

테이블 상단에 표시할 버튼을 선택합니다


handleNestedChange("toolbar", "showEditMode", checked)} />
handleNestedChange("toolbar", "showExcel", checked)} />
handleNestedChange("toolbar", "showPdf", checked)} />
handleNestedChange("toolbar", "showCopy", checked)} />
handleNestedChange("toolbar", "showSearch", checked)} />
handleNestedChange("toolbar", "showFilter", checked)} />
handleNestedChange("toolbar", "showRefresh", checked)} />
handleNestedChange("toolbar", "showPaginationRefresh", checked)} />
{/* 체크박스 설정 */}

체크박스 설정


handleNestedChange("checkbox", "enabled", checked)} />
{config.checkbox?.enabled && ( <>
handleNestedChange("checkbox", "selectAll", checked)} />
)}
{/* 가로 스크롤 및 컬럼 고정 */}

가로 스크롤 및 컬럼 고정


handleNestedChange("horizontalScroll", "enabled", checked)} />
{config.horizontalScroll?.enabled && (
handleNestedChange("horizontalScroll", "maxVisibleColumns", parseInt(e.target.value) || 8) } min={3} max={20} placeholder="8" className="h-8" />
이 수를 넘는 컬럼이 있으면 가로 스크롤이 생성됩니다
)}
{/* 컬럼 설정 */} {/* 🎯 엔티티 컬럼 표시 설정 섹션 */} {config.columns?.some((col) => col.isEntityJoin) && (
{config.columns ?.filter((col) => col.isEntityJoin && col.entityDisplayConfig) .map((column) => (
{column.displayName || column.columnName}
{entityDisplayConfigs[column.columnName] ? (
{/* 구분자 설정 */}
updateEntityDisplaySeparator(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) => ( toggleEntityDisplayColumn(column.columnName, col.columnName)} className="text-xs" > {col.displayName} ))} )} {entityDisplayConfigs[column.columnName].joinColumns.length > 0 && ( {entityDisplayConfigs[column.columnName].joinColumns.map((col) => ( toggleEntityDisplayColumn(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} )} ))}
)}
) : (
컬럼 정보 로딩 중...
)}
))}
)} {!screenTableName ? (

테이블이 연결되지 않았습니다.

화면에 테이블을 연결한 후 컬럼을 설정할 수 있습니다.

) : availableColumns.length === 0 ? (

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

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

현재 화면 테이블: {screenTableName}

) : ( <>

컬럼 선택

표시할 컬럼을 선택하세요


{availableColumns.length > 0 ? (
{availableColumns.map((column) => { const isAdded = config.columns?.some((c) => c.columnName === column.columnName); return (
{ if (isAdded) { // 컬럼 제거 handleChange("columns", config.columns?.filter((c) => c.columnName !== column.columnName) || []); } else { // 컬럼 추가 addColumn(column.columnName); } }} > { if (isAdded) { handleChange("columns", config.columns?.filter((c) => c.columnName !== column.columnName) || []); } else { addColumn(column.columnName); } }} className="pointer-events-none h-3.5 w-3.5" /> {column.label || column.columnName} {column.input_type || column.dataType}
); })}
) : (
컬럼 정보를 불러오는 중...
)}
{/* Entity 조인 컬럼 추가 */} {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) => col.columnName === matchingJoinColumn?.joinAlias, ); if (!matchingJoinColumn) return null; return (
{ if (isAlreadyAdded) { // 컬럼 제거 handleChange("columns", config.columns?.filter((c) => c.columnName !== matchingJoinColumn.joinAlias) || []); } else { // 컬럼 추가 addEntityColumn(matchingJoinColumn); } }} > { if (isAlreadyAdded) { handleChange("columns", config.columns?.filter((c) => c.columnName !== matchingJoinColumn.joinAlias) || []); } else { addEntityColumn(matchingJoinColumn); } }} className="pointer-events-none h-3.5 w-3.5" /> {column.columnLabel} {column.inputType || column.dataType}
); })}
))}
)} )} {/* 🆕 데이터 필터링 설정 */}

데이터 필터링

특정 컬럼 값으로 데이터를 필터링합니다


({ columnName: col.columnName, columnLabel: col.label || col.columnName, dataType: col.dataType, input_type: col.input_type, // 🆕 실제 input_type 전달 }) as any, )} config={config.dataFilter} onConfigChange={(dataFilter) => handleChange("dataFilter", dataFilter)} />
); };