fix(frontend): починить сортировку DataGrid и стиль колонки actions
Клик по заголовку снова сортирует напрямую; убран pin последней колонки, из-за которого actions выглядел отрезанным от строки. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -238,7 +238,12 @@ export function createErrorsColumns(opts: {
|
||||
enableSorting: false,
|
||||
enableHiding: false,
|
||||
enableResizing: false,
|
||||
meta: { skeleton: <Skeleton className="size-7 rounded-md" /> },
|
||||
enablePinning: false,
|
||||
meta: {
|
||||
skeleton: <Skeleton className="size-7 rounded-md" />,
|
||||
cellClassName: 'bg-transparent!',
|
||||
headerClassName: 'bg-transparent!',
|
||||
},
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
@@ -157,7 +157,6 @@ export function ErrorsGridView() {
|
||||
}
|
||||
getFilterFieldValue={getFilterFieldValue}
|
||||
onRowClick={handleOpen}
|
||||
pinLastColumn
|
||||
pageSize={10}
|
||||
initialSorting={[{ id: 'total', desc: true }]}
|
||||
enableColumnVisibility
|
||||
@@ -177,8 +176,10 @@ export function ErrorsGridView() {
|
||||
columnsResizable: true,
|
||||
columnsMovable: true,
|
||||
columnsVisibility: true,
|
||||
columnsPinnable: false,
|
||||
rowsPinnable: false,
|
||||
}}
|
||||
pinLastColumn={false}
|
||||
/>
|
||||
|
||||
<ResourcePage
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
useReactTable,
|
||||
type ColumnDef,
|
||||
type ColumnOrderState,
|
||||
type ColumnPinningState,
|
||||
type OnChangeFn,
|
||||
type PaginationState,
|
||||
type RowPinningState,
|
||||
@@ -172,7 +173,7 @@ const DEFAULT_FILTERED_LAYOUT: TableLayoutConfig = {
|
||||
dense: true,
|
||||
columnsVisibility: true,
|
||||
columnsResizable: true,
|
||||
columnsPinnable: true,
|
||||
columnsPinnable: false,
|
||||
columnsMovable: true,
|
||||
rowsPinnable: false,
|
||||
}
|
||||
@@ -404,6 +405,20 @@ function ResourcePageFiltered<T extends object>({
|
||||
? (columns[columns.length - 1]?.id ?? '')
|
||||
: ''
|
||||
|
||||
const [columnPinning, setColumnPinning] = useState<ColumnPinningState>(() =>
|
||||
pinLastColumn && lastColId
|
||||
? { left: [], right: [lastColId] }
|
||||
: { left: [], right: [] },
|
||||
)
|
||||
|
||||
const handleSortingChange = useCallback<OnChangeFn<SortingState>>(
|
||||
(updater) => {
|
||||
setSorting(updater)
|
||||
resetPagination()
|
||||
},
|
||||
[resetPagination],
|
||||
)
|
||||
|
||||
const table = useReactTable({
|
||||
data: filteredData,
|
||||
columns,
|
||||
@@ -414,6 +429,7 @@ function ResourcePageFiltered<T extends object>({
|
||||
pagination,
|
||||
columnVisibility,
|
||||
columnOrder,
|
||||
columnPinning,
|
||||
...(enableRowPinning ? { rowPinning: resolvedRowPinning } : {}),
|
||||
},
|
||||
enableRowSelection,
|
||||
@@ -421,20 +437,18 @@ function ResourcePageFiltered<T extends object>({
|
||||
keepPinnedRows: enableRowPinning,
|
||||
enableColumnPinning: Boolean(pinLastColumn || layout.columnsPinnable),
|
||||
enableHiding: enableColumnVisibility,
|
||||
onSortingChange: setSorting,
|
||||
enableSorting: true,
|
||||
manualSorting: false,
|
||||
onSortingChange: handleSortingChange,
|
||||
onRowSelectionChange: setRowSelection,
|
||||
onPaginationChange: setPagination,
|
||||
onColumnVisibilityChange: setColumnVisibility,
|
||||
onColumnOrderChange: setColumnOrder,
|
||||
onColumnPinningChange: setColumnPinning,
|
||||
onRowPinningChange: enableRowPinning ? setRowPinning : undefined,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
getSortedRowModel: getSortedRowModel(),
|
||||
getPaginationRowModel: getPaginationRowModel(),
|
||||
initialState: {
|
||||
...(pinLastColumn && lastColId
|
||||
? { columnPinning: { right: [lastColId] } }
|
||||
: {}),
|
||||
},
|
||||
})
|
||||
|
||||
const handleTabChange = useCallback(
|
||||
|
||||
@@ -289,26 +289,44 @@ function DataGridColumnHeaderInner<TData, TValue>({
|
||||
|
||||
if (hasControls) {
|
||||
return (
|
||||
<div className="-ms-2 flex h-full items-center justify-between gap-1.5">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger
|
||||
render={
|
||||
<div className="-ms-2 flex h-full items-center gap-0.5">
|
||||
{canSort ? (
|
||||
<Button
|
||||
variant="ghost"
|
||||
className={headerButtonClassName}
|
||||
disabled={isLoading}
|
||||
onClick={handleSort}
|
||||
aria-label={`Сортировать: ${resolvedTitle}`}
|
||||
>
|
||||
{icon && icon}
|
||||
{resolvedTitle}
|
||||
{sortIcon}
|
||||
</Button>
|
||||
) : (
|
||||
<span className={cn(headerLabelClassName, "px-2")}>
|
||||
{icon && icon}
|
||||
{resolvedTitle}
|
||||
</span>
|
||||
)}
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger
|
||||
render={
|
||||
<Button
|
||||
size="icon-sm"
|
||||
variant="ghost"
|
||||
className="rounded-lg size-7"
|
||||
disabled={isLoading}
|
||||
aria-label={`Параметры колонки: ${resolvedTitle}`}
|
||||
>
|
||||
<Settings2Icon className="size-3.5 opacity-60" aria-hidden="true" />
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
<DropdownMenuContent className="w-40" align="start">
|
||||
{menuItems}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
{props.tableLayout?.columnsPinnable && canPin && isPinned && (
|
||||
{props.tableLayout?.columnsPinnable && canPin && isPinned ? (
|
||||
<Button
|
||||
size="icon-sm"
|
||||
variant="ghost"
|
||||
@@ -319,7 +337,7 @@ function DataGridColumnHeaderInner<TData, TValue>({
|
||||
>
|
||||
<PinOffIcon className="size-3.5! opacity-50!" aria-hidden="true" />
|
||||
</Button>
|
||||
)}
|
||||
) : null}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -349,7 +349,7 @@ export function createUsersColumns(opts: {
|
||||
},
|
||||
{
|
||||
id: 'current_connections',
|
||||
accessorKey: 'current_connections',
|
||||
accessorFn: (row) => Number(row.current_connections ?? 0),
|
||||
header: ({ column }) => (
|
||||
<DataGridColumnHeader
|
||||
title="Соединения"
|
||||
@@ -362,6 +362,7 @@ export function createUsersColumns(opts: {
|
||||
enableSorting: true,
|
||||
enableHiding: true,
|
||||
enableResizing: true,
|
||||
sortingFn: 'basic',
|
||||
meta: {
|
||||
skeleton: (
|
||||
<div className="flex min-w-0 items-center gap-2">
|
||||
@@ -442,7 +443,12 @@ export function createUsersColumns(opts: {
|
||||
},
|
||||
{
|
||||
id: 'data_quota_bytes',
|
||||
accessorKey: 'data_quota_bytes',
|
||||
accessorFn: (row) => {
|
||||
const quota = row.data_quota_bytes
|
||||
if (typeof quota === 'number' && quota > 0) return quota
|
||||
// «Без квоты» в UI показывает usage — сортируем по тому же смыслу
|
||||
return Number(row.total_octets ?? 0)
|
||||
},
|
||||
header: ({ column }) => (
|
||||
<DataGridColumnHeader title="Квота" visibility={true} column={column} />
|
||||
),
|
||||
@@ -451,6 +457,7 @@ export function createUsersColumns(opts: {
|
||||
enableSorting: true,
|
||||
enableHiding: true,
|
||||
enableResizing: true,
|
||||
sortingFn: 'basic',
|
||||
meta: {
|
||||
skeleton: (
|
||||
<div className="flex min-w-0 flex-col gap-1">
|
||||
@@ -534,9 +541,12 @@ export function createUsersColumns(opts: {
|
||||
enableSorting: false,
|
||||
enableHiding: false,
|
||||
enableResizing: false,
|
||||
enablePinning: false,
|
||||
size: 52,
|
||||
meta: {
|
||||
skeleton: <Skeleton className="size-7 rounded-md" />,
|
||||
cellClassName: 'bg-transparent!',
|
||||
headerClassName: 'bg-transparent!',
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
@@ -276,9 +276,17 @@ export function UsersGridView() {
|
||||
enableColumnVisibility
|
||||
columnVisibility={columnVisibility}
|
||||
onColumnVisibilityChange={setColumnVisibility}
|
||||
pinLastColumn
|
||||
pageSize={5}
|
||||
initialSorting={[{ id: 'username', desc: false }]}
|
||||
tableLayout={{
|
||||
dense: true,
|
||||
columnsResizable: true,
|
||||
columnsMovable: true,
|
||||
columnsVisibility: true,
|
||||
columnsPinnable: false,
|
||||
rowsPinnable: true,
|
||||
}}
|
||||
pinLastColumn={false}
|
||||
emptyState={{
|
||||
title: 'Нет пользователей',
|
||||
description: 'Создайте первый аккаунт Telemt.',
|
||||
|
||||
Reference in New Issue
Block a user