Skip to content

Commit 3823843

Browse files
committed
1 parent e18cd4c commit 3823843

File tree

3 files changed

+85
-29
lines changed

3 files changed

+85
-29
lines changed

src/components/ui/table.tsx

Lines changed: 56 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import * as React from 'react';
2-
import { useCallback } from 'react';
1+
import { Button } from '@/components/ui/button';
32
import { cn } from '@/lib/cn';
43
import { flexRender, Header, RowData } from '@tanstack/react-table';
5-
import { Button } from '@/components/ui/button';
6-
import { ArrowDown, ArrowUp, ArrowUpDown } from 'lucide-react';
4+
import { ArrowDown, ArrowUp, ArrowUpDown, GripVerticalIcon } from 'lucide-react';
5+
import * as React from 'react';
6+
import { useCallback } from 'react';
77

88
export interface TableProps extends React.ComponentProps<'table'> {
99
containerClassName?: string;
@@ -54,7 +54,11 @@ export function TableHead({ className, ...props }: React.ComponentProps<'th'>) {
5454
);
5555
}
5656

57-
export function TableHeadSortable<TData extends RowData>({ header, onColumnClick, ...props }: React.ComponentProps<'th'> & {
57+
export function TableHeadSortable<TData extends RowData>({
58+
header,
59+
onColumnClick,
60+
...props
61+
}: React.ComponentProps<'th'> & {
5862
header: Header<TData, unknown>;
5963
onColumnClick?: (accessorKey: string, willSortByAscending: boolean) => void;
6064
}) {
@@ -64,26 +68,53 @@ export function TableHeadSortable<TData extends RowData>({ header, onColumnClick
6468
// @ts-expect-error The accessorKey isn't accessible.
6569
onColumnClick?.(header.column.columnDef.accessorKey, willSortByAscending);
6670
}, [header, onColumnClick]);
67-
if (header.column.columnDef.enableSorting) {
68-
return <TableHead {...props} className="px-0">
69-
<Button
70-
type="button"
71-
variant="ghost"
72-
className={cn('rounded-none', !header.column.getIsSorted() || header.column.getIsSorted() === 'asc' ? 'cursor-n-resize' : 'cursor-s-resize')}
73-
onClick={onClickSort}>
74-
{header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())}
75-
{header.column.getIsSorted() === 'asc'
76-
? <ArrowUp />
77-
: header.column.getIsSorted() === 'desc'
78-
? <ArrowDown />
79-
: <ArrowUpDown className="text-gray-600" />}
80-
</Button>
81-
</TableHead>;
82-
} else {
83-
return <TableHead {...props} className="px-2">
84-
{header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())}
85-
</TableHead>;
86-
}
71+
const enableSorting = header.column.columnDef.enableSorting;
72+
const enableResizing = header.column.columnDef.enableResizing;
73+
const content = header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext());
74+
const resetSize = useCallback(() => {
75+
header.column.resetSize();
76+
}, [header]);
77+
return <TableHead
78+
{...props}
79+
style={{ width: `${header.getSize()}px` }}
80+
className={enableSorting ? 'px-0' : 'px-2'}
81+
>
82+
<div className="flex items-center justify-between">
83+
{enableSorting ? (
84+
<Button
85+
type="button"
86+
variant="ghost"
87+
className={cn('rounded-none', !header.column.getIsSorted() || header.column.getIsSorted() === 'asc' ? 'cursor-n-resize' : 'cursor-s-resize')}
88+
onClick={onClickSort}>
89+
{content}
90+
{header.column.getIsSorted() === 'asc'
91+
? <ArrowUp />
92+
: header.column.getIsSorted() === 'desc'
93+
? <ArrowDown />
94+
: <ArrowUpDown className="text-gray-600" />}
95+
</Button>
96+
) : (
97+
content
98+
)}
99+
{enableResizing && (
100+
<Button
101+
type="button"
102+
variant="ghost"
103+
className="cursor-col-resize"
104+
onMouseDown={header.getResizeHandler()} // for desktop
105+
onTouchStart={header.getResizeHandler()} // for mobile
106+
onDoubleClick={resetSize}
107+
style={{
108+
transform: header.column.getIsResizing()
109+
? `translateX(${header.getContext().table.getState().columnSizingInfo.deltaOffset}px)`
110+
: '',
111+
}}
112+
>
113+
<GripVerticalIcon />
114+
</Button>
115+
)}
116+
</div>
117+
</TableHead>;
87118
}
88119

89120
export function TableCell({ className, ...props }: React.ComponentProps<'td'>) {

src/features/instance/databases/components/TableView.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,12 @@ export function TableView<TData, TValue>({
4848
data,
4949
columns,
5050
manualPagination: true,
51+
enableColumnResizing: true,
52+
columnResizeMode: 'onEnd',
5153
pageCount: totalPages,
54+
defaultColumn: {
55+
minSize: 1,
56+
},
5257
rowCount: totalRecords,
5358
getCoreRowModel: getCoreRowModel(),
5459
getPaginationRowModel: getPaginationRowModel(),
@@ -75,6 +80,7 @@ export function TableView<TData, TValue>({
7580
onClick={() => onRowClick?.(row)}
7681
className={cn('hover:bg-muted/10 data-[state=selected]:bg-muted', onRowClick && 'cursor-pointer')}>
7782
{row.getVisibleCells().map((cell) => (<TableCell key={cell.id}
83+
style={{ width: `${cell.column.getSize()}px` }}
7884
className="py-2 px-2 overflow-x-hidden max-w-32 text-ellipsis whitespace-nowrap">
7985
{flexRender(cell.column.columnDef.cell, cell.getContext())}
8086
</TableCell>))}

src/features/instance/databases/functions/formatBrowseDataTableHeader.ts

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { InstanceTable } from '@/lib/api.patch';
1+
import { InstanceAttribute, InstanceTable } from '@/lib/api.patch';
22
import { ColumnDef } from '@tanstack/react-table';
33

4-
function formatBrowseDataTableHeader(instanceTable: InstanceTable): {
4+
export function formatBrowseDataTableHeader(instanceTable: InstanceTable): {
55
dataTableColumns: Array<ColumnDef<Record<string, unknown>>>;
66
hashAttribute: string;
77
} {
@@ -11,12 +11,14 @@ function formatBrowseDataTableHeader(instanceTable: InstanceTable): {
1111
const normalColumns: ColumnDef<Record<string, unknown>>[] = [];
1212
const timeColumns: ColumnDef<Record<string, unknown>>[] = [];
1313
for (let i = attributes.length - 1; i >= 0; i--) {
14-
const { attribute, is_primary_key, indexed } = attributes[i];
14+
const { attribute, type, is_primary_key, indexed } = attributes[i];
1515

1616
const dataTableColumn: ColumnDef<Record<string, unknown>> = {
1717
header: attribute,
1818
accessorKey: attribute,
1919
enableSorting: Boolean(is_primary_key || indexed),
20+
enableResizing: true,
21+
size: sizeByAttributeType(type),
2022
};
2123
if (is_primary_key) {
2224
primaryKeyColumns.push(dataTableColumn);
@@ -34,4 +36,21 @@ function formatBrowseDataTableHeader(instanceTable: InstanceTable): {
3436
};
3537
}
3638

37-
export { formatBrowseDataTableHeader };
39+
function sizeByAttributeType(type: InstanceAttribute['type']) {
40+
switch (type) {
41+
case 'Id':
42+
case 'ID':
43+
return 1;
44+
case 'Boolean':
45+
return 1;
46+
case 'Int':
47+
case 'Long':
48+
case 'Float':
49+
case 'BigInt':
50+
return 1;
51+
case 'Date':
52+
case 'String':
53+
default:
54+
return Math.round(window.innerWidth * 0.1);
55+
}
56+
}

0 commit comments

Comments
 (0)