"use client"; import React, { useState, useMemo, useEffect } from "react"; import { Label } from "@/components/ui/label"; import { Input } from "@/components/ui/input"; import { Switch } from "@/components/ui/switch"; import { Checkbox } from "@/components/ui/checkbox"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Slider } from "@/components/ui/slider"; import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "@/components/ui/command"; import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; import { Button } from "@/components/ui/button"; // Accordion 제거 - 단순 섹션으로 변경 import { Check, ChevronsUpDown, X, Database, GripVertical } from "lucide-react"; import { cn } from "@/lib/utils"; import { SplitPanelLayoutConfig } from "./types"; import { TableInfo, ColumnInfo } from "@/types/screen"; import { tableTypeApi } from "@/lib/api/screen"; import { DataFilterConfigPanel } from "@/components/screen/config-panels/DataFilterConfigPanel"; interface SplitPanelLayoutConfigPanelProps { config: SplitPanelLayoutConfig; onChange: (config: SplitPanelLayoutConfig) => void; tables?: TableInfo[]; // 전체 테이블 목록 (선택적) screenTableName?: string; // 현재 화면의 테이블명 (좌측 패널에서 사용) menuObjid?: number; // 🆕 메뉴 OBJID (카테고리 값 조회 시 필요) } /** * 그룹핑 기준 컬럼 선택 컴포넌트 */ const GroupByColumnsSelector: React.FC<{ tableName?: string; selectedColumns: string[]; onChange: (columns: string[]) => void; }> = ({ tableName, selectedColumns, onChange }) => { const [columns, setColumns] = useState([]); // ColumnTypeInfo 타입 const [loading, setLoading] = useState(false); useEffect(() => { if (!tableName) { setColumns([]); return; } const loadColumns = async () => { setLoading(true); try { const { tableManagementApi } = await import("@/lib/api/tableManagement"); const response = await tableManagementApi.getColumnList(tableName); if (response.success && response.data && response.data.columns) { setColumns(response.data.columns); } } catch (error) { console.error("컬럼 정보 로드 실패:", error); } finally { setLoading(false); } }; loadColumns(); }, [tableName]); const toggleColumn = (columnName: string) => { const newSelection = selectedColumns.includes(columnName) ? selectedColumns.filter((c) => c !== columnName) : [...selectedColumns, columnName]; onChange(newSelection); }; if (!tableName) { return (

먼저 우측 패널의 테이블을 선택하세요

); } return (
{loading ? (

로딩 중...

) : columns.length === 0 ? (

컬럼을 찾을 수 없습니다

) : (
{columns.map((col) => (
toggleColumn(col.columnName)} />
))}
)}

선택된 컬럼: {selectedColumns.length > 0 ? selectedColumns.join(", ") : "없음"}
같은 값을 가진 모든 레코드를 함께 불러옵니다

); }; /** * 화면 선택 Combobox 컴포넌트 */ const ScreenSelector: React.FC<{ value?: number; onChange: (screenId?: number) => void; }> = ({ value, onChange }) => { const [open, setOpen] = useState(false); const [screens, setScreens] = useState>([]); const [loading, setLoading] = useState(false); useEffect(() => { const loadScreens = async () => { setLoading(true); try { const { screenApi } = await import("@/lib/api/screen"); const response = await screenApi.getScreens({ page: 1, size: 1000 }); setScreens( response.data.map((s) => ({ screenId: s.screenId, screenName: s.screenName, screenCode: s.screenCode })), ); } catch (error) { console.error("화면 목록 로드 실패:", error); } finally { setLoading(false); } }; loadScreens(); }, []); const selectedScreen = screens.find((s) => s.screenId === value); return ( 화면을 찾을 수 없습니다. {screens.map((screen) => ( { onChange(screen.screenId === value ? undefined : screen.screenId); setOpen(false); }} className="text-xs" >
{screen.screenName} {screen.screenCode}
))}
); }; /** * SplitPanelLayout 설정 패널 */ export const SplitPanelLayoutConfigPanel: React.FC = ({ config, onChange, tables = [], // 기본값 빈 배열 (현재 화면 테이블만) screenTableName, // 현재 화면의 테이블명 menuObjid, // 🆕 메뉴 OBJID }) => { const [rightTableOpen, setRightTableOpen] = useState(false); const [loadedTableColumns, setLoadedTableColumns] = useState>({}); const [loadingColumns, setLoadingColumns] = useState>({}); const [allTables, setAllTables] = useState([]); // 조인 모드용 전체 테이블 목록 // 엔티티 참조 테이블 컬럼 type EntityRefTable = { tableName: string; columns: ColumnInfo[] }; const [entityReferenceTables, setEntityReferenceTables] = useState>({}); // 🆕 입력 필드용 로컬 상태 const [isUserEditing, setIsUserEditing] = useState(false); const [localTitles, setLocalTitles] = useState({ left: config.leftPanel?.title || "", right: config.rightPanel?.title || "", }); // 관계 타입 const relationshipType = config.rightPanel?.relation?.type || "detail"; // config 변경 시 로컬 타이틀 동기화 (사용자가 입력 중이 아닐 때만) useEffect(() => { if (!isUserEditing) { setLocalTitles({ left: config.leftPanel?.title || "", right: config.rightPanel?.title || "", }); } }, [config.leftPanel?.title, config.rightPanel?.title, isUserEditing]); // 조인 모드일 때만 전체 테이블 목록 로드 useEffect(() => { if (relationshipType === "join") { const loadAllTables = async () => { try { const { tableManagementApi } = await import("@/lib/api/tableManagement"); const response = await tableManagementApi.getTableList(); if (response.success && response.data) { console.log("✅ 분할패널 조인 모드: 전체 테이블 목록 로드", response.data.length, "개"); setAllTables(response.data); } } catch (error) { console.error("❌ 전체 테이블 목록 로드 실패:", error); } }; loadAllTables(); } else { // 상세 모드일 때는 기본 테이블만 사용 setAllTables([]); } }, [relationshipType]); // screenTableName이 변경되면 좌측 패널 테이블을 항상 화면 테이블로 설정 useEffect(() => { if (screenTableName) { // 좌측 패널은 항상 현재 화면의 테이블 사용 if (config.leftPanel?.tableName !== screenTableName) { updateLeftPanel({ tableName: screenTableName }); } } // eslint-disable-next-line react-hooks/exhaustive-deps }, [screenTableName]); // 테이블 컬럼 로드 함수 const loadTableColumns = async (tableName: string) => { if (loadedTableColumns[tableName] || loadingColumns[tableName]) { return; // 이미 로드되었거나 로딩 중 } setLoadingColumns((prev) => ({ ...prev, [tableName]: true })); try { const columnsResponse = await tableTypeApi.getColumns(tableName); console.log(`📊 테이블 ${tableName} 컬럼 응답:`, columnsResponse); const columns: ColumnInfo[] = (columnsResponse || []).map((col: any) => ({ tableName: col.tableName || tableName, columnName: col.columnName || col.column_name, columnLabel: col.displayName || col.columnLabel || col.column_label || col.columnName || col.column_name, dataType: col.dataType || col.data_type || col.dbType, webType: col.webType || col.web_type, input_type: col.inputType || col.input_type, widgetType: col.widgetType || col.widget_type || col.webType || col.web_type, isNullable: col.isNullable || col.is_nullable, required: col.required !== undefined ? col.required : col.isNullable === "NO" || col.is_nullable === "NO", columnDefault: col.columnDefault || col.column_default, characterMaximumLength: col.characterMaximumLength || col.character_maximum_length, isPrimaryKey: col.isPrimaryKey || false, // PK 여부 추가 codeCategory: col.codeCategory || col.code_category, codeValue: col.codeValue || col.code_value, referenceTable: col.referenceTable || col.reference_table, // 🆕 참조 테이블 referenceColumn: col.referenceColumn || col.reference_column, // 🆕 참조 컬럼 displayColumn: col.displayColumn || col.display_column, // 🆕 표시 컬럼 })); console.log(`✅ 테이블 ${tableName} 컬럼 ${columns.length}개 로드됨:`, columns); setLoadedTableColumns((prev) => ({ ...prev, [tableName]: columns })); // 🆕 엔티티 타입 컬럼의 참조 테이블 컬럼도 로드 await loadEntityReferenceColumns(tableName, columns); } catch (error) { console.error(`테이블 ${tableName} 컬럼 로드 실패:`, error); setLoadedTableColumns((prev) => ({ ...prev, [tableName]: [] })); } finally { setLoadingColumns((prev) => ({ ...prev, [tableName]: false })); } }; // 🆕 엔티티 참조 테이블의 컬럼 로드 const loadEntityReferenceColumns = async (sourceTableName: string, columns: ColumnInfo[]) => { const entityColumns = columns.filter( (col) => (col.input_type === "entity" || col.webType === "entity") && col.referenceTable, ); if (entityColumns.length === 0) { return; } console.log( `🔗 테이블 ${sourceTableName}의 엔티티 참조 ${entityColumns.length}개 발견:`, entityColumns.map((c) => `${c.columnName} -> ${c.referenceTable}`), ); const referenceTableData: Array<{ tableName: string; columns: ColumnInfo[] }> = []; // 각 참조 테이블의 컬럼 로드 for (const entityCol of entityColumns) { const refTableName = entityCol.referenceTable!; // 이미 로드했으면 스킵 if (referenceTableData.some((t) => t.tableName === refTableName)) continue; try { const refColumnsResponse = await tableTypeApi.getColumns(refTableName); const refColumns: ColumnInfo[] = (refColumnsResponse || []).map((col: any) => ({ tableName: col.tableName || refTableName, columnName: col.columnName || col.column_name, columnLabel: col.displayName || col.columnLabel || col.column_label || col.columnName || col.column_name, dataType: col.dataType || col.data_type || col.dbType, input_type: col.inputType || col.input_type, })); referenceTableData.push({ tableName: refTableName, columns: refColumns }); console.log(` ✅ 참조 테이블 ${refTableName} 컬럼 ${refColumns.length}개 로드됨`); } catch (error) { console.error(` ❌ 참조 테이블 ${refTableName} 컬럼 로드 실패:`, error); } } // 참조 테이블 정보 저장 setEntityReferenceTables((prev) => ({ ...prev, [sourceTableName]: referenceTableData, })); console.log(`✅ [엔티티 참조] ${sourceTableName}의 참조 테이블 저장 완료:`, { sourceTableName, referenceTableCount: referenceTableData.length, referenceTables: referenceTableData.map((t) => `${t.tableName}(${t.columns.length}개)`), }); }; // 좌측/우측 테이블이 변경되면 해당 테이블의 컬럼 로드 useEffect(() => { if (config.leftPanel?.tableName) { loadTableColumns(config.leftPanel.tableName); } }, [config.leftPanel?.tableName]); useEffect(() => { if (config.rightPanel?.tableName) { loadTableColumns(config.rightPanel.tableName); } }, [config.rightPanel?.tableName]); console.log("🔧 SplitPanelLayoutConfigPanel 렌더링"); console.log(" - config:", config); console.log(" - tables:", tables); console.log(" - tablesCount:", tables.length); console.log(" - screenTableName:", screenTableName); console.log(" - leftTable:", config.leftPanel?.tableName); console.log(" - rightTable:", config.rightPanel?.tableName); const updateConfig = (updates: Partial) => { const newConfig = { ...config, ...updates }; console.log("🔄 Config 업데이트:", newConfig); onChange(newConfig); }; const updateLeftPanel = (updates: Partial) => { const newConfig = { ...config, leftPanel: { ...config.leftPanel, ...updates }, }; console.log("🔄 Left Panel 업데이트:", newConfig); onChange(newConfig); }; const updateRightPanel = (updates: Partial) => { const newConfig = { ...config, rightPanel: { ...config.rightPanel, ...updates }, }; console.log("🔄 Right Panel 업데이트:", newConfig); onChange(newConfig); }; // 좌측 테이블명 const leftTableName = config.leftPanel?.tableName || screenTableName || ""; // 좌측 테이블 컬럼 (로드된 컬럼 사용) const leftTableColumns = useMemo(() => { return leftTableName ? loadedTableColumns[leftTableName] || [] : []; }, [loadedTableColumns, leftTableName]); // 우측 테이블명 const rightTableName = config.rightPanel?.tableName || ""; // 우측 테이블 컬럼 (로드된 컬럼 사용) const rightTableColumns = useMemo(() => { return rightTableName ? loadedTableColumns[rightTableName] || [] : []; }, [loadedTableColumns, rightTableName]); // 테이블 데이터 로딩 상태 확인 if (!tables || tables.length === 0) { return (

테이블 데이터를 불러올 수 없습니다.

화면에 테이블이 연결되지 않았거나 테이블 목록이 로드되지 않았습니다.

); } // 조인 모드에서 우측 테이블 선택 시 사용할 테이블 목록 const availableRightTables = relationshipType === "join" ? allTables : tables; console.log("📊 분할패널 테이블 목록 상태:"); console.log(" - relationshipType:", relationshipType); console.log(" - allTables:", allTables.length, "개"); console.log(" - availableRightTables:", availableRightTables.length, "개"); return (
{/* 관계 타입 선택 */}

패널 관계 타입

{/* 좌측 패널 설정 */}

좌측 패널 설정 (마스터)

{ setIsUserEditing(true); setLocalTitles((prev) => ({ ...prev, left: e.target.value })); }} onBlur={() => { setIsUserEditing(false); updateLeftPanel({ title: localTitles.left }); }} placeholder="좌측 패널 제목" />
{/* 헤더 높이 설정 - 숨김 처리 */} {/*
updateLeftPanel({ panelHeaderHeight: parseInt(e.target.value) || 48 })} placeholder="48" min={32} max={120} />

패널 상단 헤더의 높이 (기본: 48px)

*/}
{/* 좌측 패널 표시 컬럼 설정 - 체크박스 방식 */}
{/* 컬럼 체크박스 목록 */}
{leftTableColumns.length === 0 ? (

컬럼 로딩 중...

) : ( leftTableColumns .filter((column) => !["company_code", "company_name"].includes(column.columnName)) .map((column) => { const isSelected = (config.leftPanel?.columns || []).some((c) => c.name === column.columnName); return (
{ const currentColumns = config.leftPanel?.columns || []; if (isSelected) { // 제거 const newColumns = currentColumns.filter((c) => c.name !== column.columnName); updateLeftPanel({ columns: newColumns }); } else { // 추가 const newColumn = { name: column.columnName, label: column.columnLabel || column.columnName, width: 100, }; updateLeftPanel({ columns: [...currentColumns, newColumn] }); } }} > { const currentColumns = config.leftPanel?.columns || []; if (isSelected) { const newColumns = currentColumns.filter((c) => c.name !== column.columnName); updateLeftPanel({ columns: newColumns }); } else { const newColumn = { name: column.columnName, label: column.columnLabel || column.columnName, width: 100, }; updateLeftPanel({ columns: [...currentColumns, newColumn] }); } }} className="pointer-events-none h-3.5 w-3.5 shrink-0" /> {column.columnLabel || column.columnName}
); }) )}
{/* 선택된 컬럼 상세 설정 */} {(config.leftPanel?.columns || []).length > 0 && (
{(config.leftPanel?.columns || []).map((col, index) => { const column = leftTableColumns.find((c) => c.columnName === col.name); const isTableMode = config.leftPanel?.displayMode === "table"; // 숫자 타입 판별 const dbNumericTypes = [ "numeric", "decimal", "integer", "bigint", "double precision", "real", "smallint", "int4", "int8", "float4", "float8", ]; const inputNumericTypes = ["number", "decimal", "currency", "integer"]; const isNumeric = column && (dbNumericTypes.includes(column.dataType?.toLowerCase() || "") || inputNumericTypes.includes(column.input_type?.toLowerCase() || "") || inputNumericTypes.includes(column.webType?.toLowerCase() || "")); return (
{ const newColumns = [...(config.leftPanel?.columns || [])]; newColumns[index] = { ...newColumns[index], label: e.target.value }; updateLeftPanel({ columns: newColumns }); }} placeholder="제목" className="h-6 flex-1 text-xs" /> { const newColumns = [...(config.leftPanel?.columns || [])]; newColumns[index] = { ...newColumns[index], width: parseInt(e.target.value) || 100 }; updateLeftPanel({ columns: newColumns }); }} placeholder="너비" className="h-6 w-14 text-xs" /> {/* 숫자 타입: 천단위 구분자 체크박스 */} {isNumeric && ( )}
); })}
)}
{/* 좌측 패널 데이터 필터링 */}

좌측 패널 데이터 필터링

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

({ columnName: col.columnName, columnLabel: col.columnLabel || col.columnName, dataType: col.dataType || "text", input_type: (col as any).input_type, }) as any, )} config={config.leftPanel?.dataFilter} onConfigChange={(dataFilter) => updateLeftPanel({ dataFilter })} menuObjid={menuObjid} // 🆕 메뉴 OBJID 전달 />
{/* 우측 패널 설정 */}

우측 패널 설정 ({relationshipType === "detail" ? "상세" : "조인"})

{ setIsUserEditing(true); setLocalTitles((prev) => ({ ...prev, right: e.target.value })); }} onBlur={() => { setIsUserEditing(false); updateRightPanel({ title: localTitles.right }); }} placeholder="우측 패널 제목" />
{/* 헤더 높이 설정 - 숨김 처리 */} {/*
updateRightPanel({ panelHeaderHeight: parseInt(e.target.value) || 48 })} placeholder="48" min={32} max={120} />

패널 상단 헤더의 높이 (기본: 48px)

*/} {/* 관계 타입에 따라 테이블 선택 UI 변경 */} {relationshipType === "detail" ? ( // 상세 모드: 좌측과 동일한 테이블 (자동 설정)

{config.leftPanel?.tableName || screenTableName || "테이블이 지정되지 않음"}

상세 모드에서는 좌측과 동일한 테이블을 사용합니다

) : ( // 조인 모드: 전체 테이블에서 선택 가능
테이블을 찾을 수 없습니다. {availableRightTables.map((table) => ( { updateRightPanel({ tableName: table.tableName }); setRightTableOpen(false); }} > {table.displayName || table.tableName} {table.displayName && ({table.tableName})} ))}
)}
{/* 요약 표시 설정 (LIST 모드에서만) */} {(config.rightPanel?.displayMode || "list") === "list" && (
{ const value = parseInt(e.target.value) || 3; updateRightPanel({ summaryColumnCount: value }); }} className="bg-white" />

접기 전에 표시할 컬럼 개수 (기본: 3개)

컬럼명 표시 여부

{ updateRightPanel({ summaryShowLabel: checked as boolean }); }} />
)} {/* 엔티티 설정 선택 - 조인 모드에서만 표시 */} {relationshipType !== "detail" && (

우측 테이블에서 좌측 테이블을 참조하는 엔티티 컬럼을 선택하세요

{config.rightPanel?.relation?.foreignKey && (

선택된 컬럼의 엔티티 설정이 자동으로 적용됩니다.

)}
)} {/* 우측 패널 표시 컬럼 설정 - 체크박스 방식 */}
{/* 컬럼 체크박스 목록 */}
{rightTableColumns.length === 0 ? (

테이블을 선택해주세요

) : ( rightTableColumns .filter((column) => !["company_code", "company_name"].includes(column.columnName)) .map((column) => { const isSelected = (config.rightPanel?.columns || []).some((c) => c.name === column.columnName); return (
{ const currentColumns = config.rightPanel?.columns || []; if (isSelected) { const newColumns = currentColumns.filter((c) => c.name !== column.columnName); updateRightPanel({ columns: newColumns }); } else { const newColumn = { name: column.columnName, label: column.columnLabel || column.columnName, width: 100, }; updateRightPanel({ columns: [...currentColumns, newColumn] }); } }} > { const currentColumns = config.rightPanel?.columns || []; if (isSelected) { const newColumns = currentColumns.filter((c) => c.name !== column.columnName); updateRightPanel({ columns: newColumns }); } else { const newColumn = { name: column.columnName, label: column.columnLabel || column.columnName, width: 100, }; updateRightPanel({ columns: [...currentColumns, newColumn] }); } }} className="pointer-events-none h-3.5 w-3.5 shrink-0" /> {column.columnLabel || column.columnName}
); }) )}
{/* 선택된 컬럼 상세 설정 */} {(config.rightPanel?.columns || []).length > 0 && (
{(config.rightPanel?.columns || []).map((col, index) => { const column = rightTableColumns.find((c) => c.columnName === col.name); // 숫자 타입 판별 const dbNumericTypes = [ "numeric", "decimal", "integer", "bigint", "double precision", "real", "smallint", "int4", "int8", "float4", "float8", ]; const inputNumericTypes = ["number", "decimal", "currency", "integer"]; const isNumeric = column && (dbNumericTypes.includes(column.dataType?.toLowerCase() || "") || inputNumericTypes.includes(column.input_type?.toLowerCase() || "") || inputNumericTypes.includes(column.webType?.toLowerCase() || "")); return (
{ const newColumns = [...(config.rightPanel?.columns || [])]; newColumns[index] = { ...newColumns[index], label: e.target.value }; updateRightPanel({ columns: newColumns }); }} placeholder="제목" className="h-6 flex-1 text-xs" /> { const newColumns = [...(config.rightPanel?.columns || [])]; newColumns[index] = { ...newColumns[index], width: parseInt(e.target.value) || 100 }; updateRightPanel({ columns: newColumns }); }} placeholder="너비" className="h-6 w-14 text-xs" /> {/* 숫자 타입: 천단위 구분자 체크박스 */} {isNumeric && ( )}
); })}
)}
{/* 우측 패널 데이터 필터링 */}

우측 패널 데이터 필터링

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

({ columnName: col.columnName, columnLabel: col.columnLabel || col.columnName, dataType: col.dataType || "text", input_type: (col as any).input_type, }) as any, )} config={config.rightPanel?.dataFilter} onConfigChange={(dataFilter) => updateRightPanel({ dataFilter })} menuObjid={menuObjid} // 🆕 메뉴 OBJID 전달 />
{/* 우측 패널 중복 제거 */}

중복 데이터 제거

같은 값을 가진 데이터를 하나로 통합하여 표시

{ if (checked) { updateRightPanel({ deduplication: { enabled: true, groupByColumn: "", keepStrategy: "latest", sortColumn: "start_date", }, }); } else { updateRightPanel({ deduplication: undefined }); } }} />
{config.rightPanel?.deduplication?.enabled && (
{/* 중복 제거 기준 컬럼 */}

이 컬럼의 값이 같은 데이터들 중 하나만 표시합니다

{/* 유지 전략 */}

{config.rightPanel?.deduplication?.keepStrategy === "latest" && "가장 최근에 추가된 데이터를 표시합니다"} {config.rightPanel?.deduplication?.keepStrategy === "earliest" && "가장 먼저 추가된 데이터를 표시합니다"} {config.rightPanel?.deduplication?.keepStrategy === "current_date" && "오늘 날짜 기준으로 유효한 기간의 데이터를 표시합니다"} {config.rightPanel?.deduplication?.keepStrategy === "base_price" && "기준단가(base_price)로 체크된 데이터를 표시합니다"}

{/* 정렬 기준 컬럼 (latest/earliest만) */} {(config.rightPanel?.deduplication?.keepStrategy === "latest" || config.rightPanel?.deduplication?.keepStrategy === "earliest") && (

이 컬럼의 값으로 최신/최초를 판단합니다 (보통 날짜 컬럼)

)}
)}
{/* 🆕 우측 패널 수정 버튼 설정 */}

수정 버튼 설정

우측 리스트의 수정 버튼 동작 방식 설정

{ updateRightPanel({ editButton: { enabled: checked, mode: config.rightPanel?.editButton?.mode || "auto", buttonLabel: config.rightPanel?.editButton?.buttonLabel, buttonVariant: config.rightPanel?.editButton?.buttonVariant, }, }); }} />
{(config.rightPanel?.editButton?.enabled ?? true) && (
{/* 수정 모드 */}

{config.rightPanel?.editButton?.mode === "modal" ? "지정한 화면을 모달로 열어 데이터를 수정합니다" : "현재 위치에서 직접 데이터를 수정합니다"}

{/* 모달 화면 선택 (modal 모드일 때만) */} {config.rightPanel?.editButton?.mode === "modal" && (
updateRightPanel({ editButton: { ...config.rightPanel?.editButton!, modalScreenId: screenId, }, }) } />

수정 버튼 클릭 시 열릴 화면을 선택하세요

)} {/* 버튼 라벨 */}
updateRightPanel({ editButton: { ...config.rightPanel?.editButton!, buttonLabel: e.target.value, enabled: config.rightPanel?.editButton?.enabled ?? true, mode: config.rightPanel?.editButton?.mode || "auto", }, }) } className="h-8 text-xs" placeholder="수정" />
{/* 버튼 스타일 */}
{/* 🆕 그룹핑 기준 컬럼 설정 (modal 모드일 때만 표시) */} {config.rightPanel?.editButton?.mode === "modal" && ( { updateRightPanel({ editButton: { ...config.rightPanel?.editButton!, groupByColumns: columns, enabled: config.rightPanel?.editButton?.enabled ?? true, mode: config.rightPanel?.editButton?.mode || "auto", }, }); }} /> )}
)}
{/* 🆕 우측 패널 삭제 버튼 설정 */}

삭제 버튼 설정

{ updateRightPanel({ deleteButton: { enabled: checked, buttonLabel: config.rightPanel?.deleteButton?.buttonLabel, buttonVariant: config.rightPanel?.deleteButton?.buttonVariant, }, }); }} />
{(config.rightPanel?.deleteButton?.enabled ?? true) && (
{/* 버튼 라벨 */}
{ updateRightPanel({ deleteButton: { ...config.rightPanel?.deleteButton!, buttonLabel: e.target.value || undefined, enabled: config.rightPanel?.deleteButton?.enabled ?? true, }, }); }} className="h-8 text-xs" />
{/* 버튼 스타일 */}
{/* 삭제 확인 메시지 */}
{ updateRightPanel({ deleteButton: { ...config.rightPanel?.deleteButton!, confirmMessage: e.target.value || undefined, enabled: config.rightPanel?.deleteButton?.enabled ?? true, }, }); }} className="h-8 text-xs" />
)}
{/* 레이아웃 설정 */}
updateConfig({ splitRatio: value[0] })} min={20} max={80} step={5} />
updateConfig({ resizable: checked })} />
updateConfig({ autoLoad: checked })} />
); };