diff --git a/src/components/PaginatedTable/PaginatedTableWithLayout.tsx b/src/components/PaginatedTable/PaginatedTableWithLayout.tsx index 4525dc72a..e8b49ced0 100644 --- a/src/components/PaginatedTable/PaginatedTableWithLayout.tsx +++ b/src/components/PaginatedTable/PaginatedTableWithLayout.tsx @@ -1,37 +1,79 @@ import React from 'react'; import {TableWithControlsLayout} from '../TableWithControlsLayout/TableWithControlsLayout'; -import type {TableProps} from '../TableWithControlsLayout/TableWithControlsLayout'; +import type {TableWrapperProps} from '../TableWithControlsLayout/TableWithControlsLayout'; -import {PaginatedTableProvider} from './PaginatedTableContext'; +import {PaginatedTableProvider, usePaginatedTableState} from './PaginatedTableContext'; import type {PaginatedTableState} from './types'; export interface PaginatedTableWithLayoutProps { - controls: React.ReactNode; + controls?: React.ReactNode; table: React.ReactNode; - tableProps?: TableProps; + tableWrapperProps?: Omit; error?: React.ReactNode; initialState?: Partial; fullHeight?: boolean; noBatching?: boolean; } +const TableWrapper = ({ + table, + tableWrapperProps, +}: { + table: React.ReactNode; + tableWrapperProps?: Omit; +}) => { + const {tableState} = usePaginatedTableState(); + const {sortParams} = tableState; + + const enhancedTableWrapperProps = React.useMemo(() => { + const existingScrollDependencies = tableWrapperProps?.scrollDependencies || []; + + return { + ...tableWrapperProps, + scrollDependencies: [...existingScrollDependencies, sortParams], + }; + }, [tableWrapperProps, sortParams]); + + return ( + + {table} + + ); +}; + +const ControlsSection = ({controls}: {controls?: React.ReactNode}) => { + if (!controls) { + return null; + } + + return {controls}; +}; + +const ErrorSection = ({error}: {error?: React.ReactNode}) => { + if (!error) { + return null; + } + + return {error}; +}; + export const PaginatedTableWithLayout = ({ controls, table, - tableProps, + tableWrapperProps, error, initialState, noBatching, fullHeight = true, -}: PaginatedTableWithLayoutProps) => ( - - - {controls} - {error} - - {table} - - - -); +}: PaginatedTableWithLayoutProps) => { + return ( + + + + + + + + ); +}; diff --git a/src/components/ResizeableDataTable/ResizeableDataTable.tsx b/src/components/ResizeableDataTable/ResizeableDataTable.tsx index 186b18315..9eefb505d 100644 --- a/src/components/ResizeableDataTable/ResizeableDataTable.tsx +++ b/src/components/ResizeableDataTable/ResizeableDataTable.tsx @@ -1,4 +1,6 @@ -import type {Column, DataTableProps, Settings} from '@gravity-ui/react-data-table'; +import React from 'react'; + +import type {Column, DataTableProps, Settings, SortOrder} from '@gravity-ui/react-data-table'; import DataTable, {updateColumnsWidth} from '@gravity-ui/react-data-table'; import {Skeleton} from '@gravity-ui/uikit'; @@ -13,6 +15,7 @@ export interface ResizeableDataTableProps extends Omit, 'th columnsWidthLSKey?: string; wrapperClassName?: string; loading?: boolean; + onSortChange?: (params: SortOrder | SortOrder[] | undefined) => void; } export function ResizeableDataTable({ @@ -21,10 +24,20 @@ export function ResizeableDataTable({ settings, wrapperClassName, loading, + onSort, + onSortChange, ...props }: ResizeableDataTableProps) { const [tableColumnsWidth, setTableColumnsWidth] = useTableResize(columnsWidthLSKey); + const handleSort = React.useCallback( + (params: SortOrder | SortOrder[] | undefined) => { + onSort?.(params); // Original onSort if provided + onSortChange?.(params); // Expose sort params to parent + }, + [onSort, onSortChange], + ); + // If loading is true, override the render method of each column to display a Skeleton const processedColumns = loading ? columns.map((column: Column) => ({ @@ -46,6 +59,7 @@ export function ResizeableDataTable({ theme="yandex-cloud" columns={updatedColumns} onResize={setTableColumnsWidth} + onSort={handleSort} settings={newSettings} {...props} /> diff --git a/src/components/TableWithControlsLayout/TableWithControlsLayout.tsx b/src/components/TableWithControlsLayout/TableWithControlsLayout.tsx index 6e644bad9..cec3679ac 100644 --- a/src/components/TableWithControlsLayout/TableWithControlsLayout.tsx +++ b/src/components/TableWithControlsLayout/TableWithControlsLayout.tsx @@ -12,16 +12,17 @@ import './TableWithControlsLayout.scss'; const b = cn('ydb-table-with-controls-layout'); interface TableWithControlsLayoutItemProps { - children?: React.ReactNode; + children: React.ReactNode; renderExtraControls?: () => React.ReactNode; className?: string; fullHeight?: boolean; } -export interface TableProps extends TableWithControlsLayoutItemProps { +export interface TableWrapperProps extends Omit { loading?: boolean; scrollContainerRef?: React.RefObject; scrollDependencies?: any[]; + children: React.ReactNode; } export const TableWithControlsLayout = ({ @@ -56,7 +57,7 @@ TableWithControlsLayout.Table = function Table({ className, scrollContainerRef, scrollDependencies = [], -}: TableProps) { +}: TableWrapperProps) { // Create an internal ref for the table container const tableContainerRef = React.useRef(null); diff --git a/src/containers/Nodes/PaginatedNodes/GroupedNodesComponent.tsx b/src/containers/Nodes/PaginatedNodes/GroupedNodesComponent.tsx index 315169757..c65f263bc 100644 --- a/src/containers/Nodes/PaginatedNodes/GroupedNodesComponent.tsx +++ b/src/containers/Nodes/PaginatedNodes/GroupedNodesComponent.tsx @@ -55,18 +55,26 @@ const NodeGroup = React.memo(function NodeGroup({ expanded={isExpanded} onIsExpandedChange={onIsExpandedChange} > - + } + tableWrapperProps={{ + scrollContainerRef: scrollContainerRef, + }} /> ); @@ -184,13 +192,12 @@ export function GroupedNodesComponent({ } error={error ? : null} table={renderGroups()} - tableProps={{ + tableWrapperProps={{ scrollContainerRef, scrollDependencies: [searchValue, groupByParam, tableGroups, peerRoleFilter], loading: isLoading, className: b('groups-wrapper'), }} - fullHeight /> ); } diff --git a/src/containers/Nodes/PaginatedNodes/NodesComponent.tsx b/src/containers/Nodes/PaginatedNodes/NodesComponent.tsx index 34b8bbb87..7f05e879c 100644 --- a/src/containers/Nodes/PaginatedNodes/NodesComponent.tsx +++ b/src/containers/Nodes/PaginatedNodes/NodesComponent.tsx @@ -72,11 +72,10 @@ export function NodesComponent({ scrollContainerRef={scrollContainerRef} /> } - tableProps={{ + tableWrapperProps={{ scrollContainerRef, scrollDependencies: [searchValue, problemFilter, uptimeFilter, peerRoleFilter], }} - fullHeight /> ); } diff --git a/src/containers/Storage/PaginatedStorageGroups/GroupedStorageGroupsComponent.tsx b/src/containers/Storage/PaginatedStorageGroups/GroupedStorageGroupsComponent.tsx index cd748c64f..41c674e89 100644 --- a/src/containers/Storage/PaginatedStorageGroups/GroupedStorageGroupsComponent.tsx +++ b/src/containers/Storage/PaginatedStorageGroups/GroupedStorageGroupsComponent.tsx @@ -59,20 +59,28 @@ export const StorageGroupGroup = React.memo(function StorageGroupGroup({ expanded={isExpanded} onIsExpandedChange={onIsExpandedChange} > - + } + tableWrapperProps={{ + scrollContainerRef: scrollContainerRef, + }} /> ); @@ -173,7 +181,7 @@ export function GroupedStorageGroupsComponent({ error={error ? : null} table={renderGroups()} initialState={initialState} - tableProps={{ + tableWrapperProps={{ scrollContainerRef, scrollDependencies: [searchValue, storageGroupsGroupByParam, tableGroups], loading: isLoading, diff --git a/src/containers/Storage/PaginatedStorageGroups/StorageGroupsComponent.tsx b/src/containers/Storage/PaginatedStorageGroups/StorageGroupsComponent.tsx index 0864a81c6..0ecb6488b 100644 --- a/src/containers/Storage/PaginatedStorageGroups/StorageGroupsComponent.tsx +++ b/src/containers/Storage/PaginatedStorageGroups/StorageGroupsComponent.tsx @@ -51,11 +51,10 @@ export function StorageGroupsComponent({ initialEntitiesCount={initialEntitiesCount} /> } - tableProps={{ + tableWrapperProps={{ scrollContainerRef, scrollDependencies: [searchValue, visibleEntities], }} - fullHeight /> ); } diff --git a/src/containers/Storage/PaginatedStorageNodes/GroupedStorageNodesComponent.tsx b/src/containers/Storage/PaginatedStorageNodes/GroupedStorageNodesComponent.tsx index 20beaa867..320c8cb1b 100644 --- a/src/containers/Storage/PaginatedStorageNodes/GroupedStorageNodesComponent.tsx +++ b/src/containers/Storage/PaginatedStorageNodes/GroupedStorageNodesComponent.tsx @@ -60,21 +60,29 @@ export const StorageNodeGroup = React.memo(function StorageNodeGroup({ expanded={isExpanded} onIsExpandedChange={onIsExpandedChange} > - + } + tableWrapperProps={{ + scrollContainerRef: scrollContainerRef, + }} /> ); @@ -174,7 +182,7 @@ export function GroupedStorageNodesComponent({ error={error ? : null} table={renderGroups()} initialState={initialState} - tableProps={{ + tableWrapperProps={{ scrollContainerRef, scrollDependencies: [searchValue, storageNodesGroupByParam, tableGroups], loading: isLoading, diff --git a/src/containers/Storage/PaginatedStorageNodes/StorageNodesComponent.tsx b/src/containers/Storage/PaginatedStorageNodes/StorageNodesComponent.tsx index d0c155f9c..5869af50d 100644 --- a/src/containers/Storage/PaginatedStorageNodes/StorageNodesComponent.tsx +++ b/src/containers/Storage/PaginatedStorageNodes/StorageNodesComponent.tsx @@ -56,11 +56,10 @@ export function StorageNodesComponent({ onDataFetched={handleDataFetched} /> } - tableProps={{ + tableWrapperProps={{ scrollContainerRef, scrollDependencies: [searchValue, visibleEntities, nodesUptimeFilter], }} - fullHeight /> ); } diff --git a/src/containers/Tablets/TabletsTable.tsx b/src/containers/Tablets/TabletsTable.tsx index aedc46242..3cddfd5d9 100644 --- a/src/containers/Tablets/TabletsTable.tsx +++ b/src/containers/Tablets/TabletsTable.tsx @@ -1,7 +1,7 @@ import React from 'react'; import {ArrowRotateLeft} from '@gravity-ui/icons'; -import type {Column as DataTableColumn} from '@gravity-ui/react-data-table'; +import type {Column as DataTableColumn, SortOrder} from '@gravity-ui/react-data-table'; import {Icon, Text} from '@gravity-ui/uikit'; import {StringParam, useQueryParams} from 'use-query-params'; @@ -183,6 +183,9 @@ export function TabletsTable({ tabletsSearch: StringParam, }); + // Track sort state for scroll dependencies + const [sortParams, setSortParams] = React.useState(); + const columns = React.useMemo(() => getColumns({database}), [database]); const filteredTablets = React.useMemo(() => { @@ -214,7 +217,7 @@ export function TabletsTable({ {error ? : null} diff --git a/src/containers/Tenant/Diagnostics/TopicData/TopicData.tsx b/src/containers/Tenant/Diagnostics/TopicData/TopicData.tsx index 90e372a29..168088b9b 100644 --- a/src/containers/Tenant/Diagnostics/TopicData/TopicData.tsx +++ b/src/containers/Tenant/Diagnostics/TopicData/TopicData.tsx @@ -343,11 +343,10 @@ export function TopicData({scrollContainerRef, path, database}: TopicDataProps) }} /> } - tableProps={{ + tableWrapperProps={{ scrollContainerRef, scrollDependencies: [baseOffset, baseEndOffset, tableFilters], }} - fullHeight noBatching /> diff --git a/src/containers/Tenants/Tenants.tsx b/src/containers/Tenants/Tenants.tsx index 5c80ff820..e9e94e904 100644 --- a/src/containers/Tenants/Tenants.tsx +++ b/src/containers/Tenants/Tenants.tsx @@ -1,7 +1,7 @@ import React from 'react'; import {CirclePlus, Pencil, TrashBin} from '@gravity-ui/icons'; -import type {Column} from '@gravity-ui/react-data-table'; +import type {Column, SortOrder} from '@gravity-ui/react-data-table'; import DataTable from '@gravity-ui/react-data-table'; import type {DropdownMenuItem} from '@gravity-ui/uikit'; import {Button, DropdownMenu, Icon} from '@gravity-ui/uikit'; @@ -70,6 +70,9 @@ export const Tenants = ({additionalTenantsProps, scrollContainerRef}: TenantsPro ); const loading = isFetching && currentData === undefined; + // Track sort state for scroll dependencies + const [sortParams, setSortParams] = React.useState(); + const isCreateDBAvailable = useCreateDatabaseFeatureAvailable() && uiFactory.onCreateDB !== undefined; const isEditDBAvailable = useEditDatabaseFeatureAvailable() && uiFactory.onEditDB !== undefined; @@ -261,6 +264,7 @@ export const Tenants = ({additionalTenantsProps, scrollContainerRef}: TenantsPro columns={columns} settings={DEFAULT_TABLE_SETTINGS} emptyDataMessage="No such tenants" + onSortChange={setSortParams} /> ); }; @@ -275,7 +279,7 @@ export const Tenants = ({additionalTenantsProps, scrollContainerRef}: TenantsPro {currentData ? renderTable() : null}