diff options
Diffstat (limited to 'components/data-table/data-table-pin-right.tsx')
| -rw-r--r-- | components/data-table/data-table-pin-right.tsx | 150 |
1 files changed, 116 insertions, 34 deletions
diff --git a/components/data-table/data-table-pin-right.tsx b/components/data-table/data-table-pin-right.tsx index 3ed42402..ad52e44d 100644 --- a/components/data-table/data-table-pin-right.tsx +++ b/components/data-table/data-table-pin-right.tsx @@ -68,15 +68,48 @@ function areAllSubColumnsPinned<TData>( } /** + * Helper function to get the display name of a column + */ +function getColumnDisplayName<TData>(column: Column<TData>): string { + // First try to use excelHeader from meta if available + const excelHeader = column.columnDef.meta?.excelHeader + if (excelHeader) { + return excelHeader + } + + // Fall back to converting the column ID to sentence case + return toSentenceCase(column.id) +} + +/** + * Array of column IDs that should be auto-pinned to the right when available + */ +const AUTO_PIN_RIGHT_COLUMNS = ['actions'] + +/** * "Pin Right" Popover. Supports pinning both individual columns and header groups. */ export function PinRightButton<TData>({ table }: { table: Table<TData> }) { const [open, setOpen] = React.useState(false) const triggerRef = React.useRef<HTMLButtonElement>(null) - // Get all columns that can be pinned, including parent columns + // Try to auto-pin actions columns if they exist + React.useEffect(() => { + AUTO_PIN_RIGHT_COLUMNS.forEach((columnId) => { + const column = table.getColumn(columnId) + if (column?.getCanPin?.()) { + column.pin?.("right") + } + }) + }, [table]) + // Get all columns that can be pinned (excluding auto-pinned columns) const pinnableColumns = React.useMemo(() => { return table.getAllColumns().filter((column) => { + // Skip auto-pinned columns + if (AUTO_PIN_RIGHT_COLUMNS.includes(column.id)) { + return false + } + // If it's a leaf column, check if it can be pinned if (!isParentColumn(column)) { return column.getCanPin?.() @@ -93,6 +126,25 @@ export function PinRightButton<TData>({ table }: { table: Table<TData> }) { }) }, [table]) + // Get flat list of all leaf columns for display + const allPinnableLeafColumns = React.useMemo(() => { + const leafColumns: Column<TData>[] = [] + + // Function to recursively collect leaf columns + const collectLeafColumns = (column: Column<TData>) => { + if (isParentColumn(column)) { + column.columns.forEach(collectLeafColumns) + } else if (column.getCanPin?.() && !AUTO_PIN_RIGHT_COLUMNS.includes(column.id)) { + leafColumns.push(column) + } + } + + // Process all columns + table.getAllColumns().forEach(collectLeafColumns) + + return leafColumns + }, [table]) + // Handle column pinning const handleColumnPin = React.useCallback((column: Column<TData>) => { // For parent columns, pin/unpin all subcolumns @@ -127,7 +179,7 @@ export function PinRightButton<TData>({ table }: { table: Table<TData> }) { <MoveRight className="size-4" /> <span className="hidden sm:inline"> - Right + 오른 고정 </span> <ChevronsUpDown className="ml-1 size-4 opacity-50 hidden sm:inline" /> </Button> @@ -140,42 +192,72 @@ export function PinRightButton<TData>({ table }: { table: Table<TData> }) { > <Command> <CommandInput placeholder="Search columns..." /> - <CommandList> + <CommandList className="max-h-[300px]"> <CommandEmpty>No columns found.</CommandEmpty> <CommandGroup> - {/* Header Columns (Parent Columns) */} + {/* Parent Columns with subcolumns */} {pinnableColumns .filter(isParentColumn) - .map((column) => ( - <CommandItem - key={column.id} - onSelect={() => { - handleColumnPin(column) - }} - className="font-medium" - > - <span className="truncate"> - {column.id === "Basic Info" || column.id === "Metadata" - ? column.id // Use column ID directly for common groups - : toSentenceCase(column.id)} - </span> - <Check - className={cn( - "ml-auto size-4 shrink-0", - isColumnPinned(column) ? "opacity-100" : "opacity-0" - )} - /> - </CommandItem> + .map((parentColumn) => ( + <React.Fragment key={parentColumn.id}> + {/* Parent column header - can pin/unpin all children at once */} + <CommandItem + onSelect={() => { + handleColumnPin(parentColumn) + }} + className="font-medium bg-muted/50" + > + <span className="truncate"> + {getColumnDisplayName(parentColumn)} + </span> + <Check + className={cn( + "ml-auto size-4 shrink-0", + isColumnPinned(parentColumn) ? "opacity-100" : "opacity-0" + )} + /> + </CommandItem> + + {/* Individual subcolumns */} + {parentColumn.columns + .filter(col => !isParentColumn(col) && col.getCanPin?.()) + .map(subColumn => ( + <CommandItem + key={subColumn.id} + onSelect={() => { + handleColumnPin(subColumn) + }} + className="pl-6 text-sm" + > + <span className="truncate"> + {getColumnDisplayName(subColumn)} + </span> + <Check + className={cn( + "ml-auto size-4 shrink-0", + isColumnPinned(subColumn) ? "opacity-100" : "opacity-0" + )} + /> + </CommandItem> + ))} + </React.Fragment> ))} - - {pinnableColumns.some(isParentColumn) && - pinnableColumns.some(col => !isParentColumn(col)) && ( - <CommandSeparator /> - )} - - {/* Leaf Columns (individual columns) */} - {pinnableColumns - .filter(col => !isParentColumn(col)) + </CommandGroup> + + {/* Separator if we have both parent columns and standalone leaf columns */} + {pinnableColumns.some(isParentColumn) && + allPinnableLeafColumns.some(col => !pinnableColumns.find(parent => + isParentColumn(parent) && parent.columns.includes(col)) + ) && ( + <CommandSeparator /> + )} + + {/* Standalone leaf columns (not part of any parent column group) */} + <CommandGroup> + {allPinnableLeafColumns + .filter(col => !pinnableColumns.find(parent => + isParentColumn(parent) && parent.columns.includes(col) + )) .map((column) => ( <CommandItem key={column.id} @@ -184,7 +266,7 @@ export function PinRightButton<TData>({ table }: { table: Table<TData> }) { }} > <span className="truncate"> - {toSentenceCase(column.id)} + {getColumnDisplayName(column)} </span> <Check className={cn( |
