diff --git a/src/components/ResizeableDataTable/ResizeableDataTable.tsx b/src/components/ResizeableDataTable/ResizeableDataTable.tsx index 9eefb505d3..dccd55c2d4 100644 --- a/src/components/ResizeableDataTable/ResizeableDataTable.tsx +++ b/src/components/ResizeableDataTable/ResizeableDataTable.tsx @@ -1,11 +1,12 @@ import React from 'react'; -import type {Column, DataTableProps, Settings, SortOrder} from '@gravity-ui/react-data-table'; +import type {Column, DataTableProps, SortOrder} from '@gravity-ui/react-data-table'; import DataTable, {updateColumnsWidth} from '@gravity-ui/react-data-table'; import {Skeleton} from '@gravity-ui/uikit'; import {cn} from '../../utils/cn'; import {useTableResize} from '../../utils/hooks/useTableResize'; +import {TableSkeleton} from '../TableSkeleton/TableSkeleton'; import './ResizeableDataTable.scss'; @@ -14,7 +15,19 @@ const b = cn('ydb-resizeable-data-table'); export interface ResizeableDataTableProps extends Omit, 'theme' | 'onResize'> { columnsWidthLSKey?: string; wrapperClassName?: string; - loading?: boolean; + + /** + * Not enough meta data (settings, sizes, features, etc.) to properly render table columns + * Use case: initial load + */ + isLoading?: boolean; + /** + * No table data, but columns data is loaded and they could be rendered + * Use case: you need to preserve table headers on sort change when backend sort + */ + isFetching?: boolean; + loadingSkeletonRowsCount?: number; + onSortChange?: (params: SortOrder | SortOrder[] | undefined) => void; } @@ -23,9 +36,12 @@ export function ResizeableDataTable({ columns, settings, wrapperClassName, - loading, + isLoading, + isFetching, + loadingSkeletonRowsCount = 2, onSort, onSortChange, + data, ...props }: ResizeableDataTableProps) { const [tableColumnsWidth, setTableColumnsWidth] = useTableResize(columnsWidthLSKey); @@ -39,19 +55,36 @@ export function ResizeableDataTable({ ); // If loading is true, override the render method of each column to display a Skeleton - const processedColumns = loading - ? columns.map((column: Column) => ({ - ...column, - render: () => , - })) - : columns; + const processedColumns = React.useMemo(() => { + if (isFetching) { + return columns.map((column: Column) => ({ + ...column, + render: () => , + })); + } + return columns; + }, [isFetching, columns]); const updatedColumns = updateColumnsWidth(processedColumns, tableColumnsWidth); - const newSettings: Settings = { - ...settings, - defaultResizeable: true, - }; + const processedData = React.useMemo(() => { + if (isFetching && !data?.length) { + // We do not use data in render method when loading, so we can return an array of empty objects + return Array.from({length: loadingSkeletonRowsCount}, () => ({}) as T); + } + return data; + }, [isFetching, data, loadingSkeletonRowsCount]); + + const newSettings = React.useMemo(() => { + return { + ...settings, + defaultResizeable: true, + }; + }, [settings]); + + if (isLoading) { + return ; + } return (
@@ -61,6 +94,7 @@ export function ResizeableDataTable({ onResize={setTableColumnsWidth} onSort={handleSort} settings={newSettings} + data={processedData} {...props} />
diff --git a/src/containers/Node/Threads/Threads.tsx b/src/containers/Node/Threads/Threads.tsx index 859dad6d74..867feda453 100644 --- a/src/containers/Node/Threads/Threads.tsx +++ b/src/containers/Node/Threads/Threads.tsx @@ -37,7 +37,7 @@ export function Threads({nodeId, className, scrollContainerRef}: ThreadsProps) { columns={columns} settings={DEFAULT_TABLE_SETTINGS} emptyDataMessage={i18n('alert_no-thread-data')} - loading={isLoading} + isLoading={isLoading} /> diff --git a/src/containers/Tenant/Diagnostics/Partitions/Partitions.tsx b/src/containers/Tenant/Diagnostics/Partitions/Partitions.tsx index 9e754eca77..0f544f94f6 100644 --- a/src/containers/Tenant/Diagnostics/Partitions/Partitions.tsx +++ b/src/containers/Tenant/Diagnostics/Partitions/Partitions.tsx @@ -5,7 +5,6 @@ import {skipToken} from '@reduxjs/toolkit/query'; import {ResponseError} from '../../../../components/Errors/ResponseError'; import {ResizeableDataTable} from '../../../../components/ResizeableDataTable/ResizeableDataTable'; import {TableColumnSetup} from '../../../../components/TableColumnSetup/TableColumnSetup'; -import {TableSkeleton} from '../../../../components/TableSkeleton/TableSkeleton'; import {TableWithControlsLayout} from '../../../../components/TableWithControlsLayout/TableWithControlsLayout'; import {nodesListApi, selectNodesMap} from '../../../../store/reducers/nodesList'; import {partitionsApi, setSelectedConsumer} from '../../../../store/reducers/partitions/partitions'; @@ -112,16 +111,13 @@ export const Partitions = ({path, database, databaseFullPath}: PartitionsProps) }; const renderContent = () => { - if (loading) { - return ; - } - return ( diff --git a/src/containers/Tenant/Diagnostics/TopQueries/QueriesTableWithDrawer.tsx b/src/containers/Tenant/Diagnostics/TopQueries/QueriesTableWithDrawer.tsx index 6916cee1d3..f1ef2fb474 100644 --- a/src/containers/Tenant/Diagnostics/TopQueries/QueriesTableWithDrawer.tsx +++ b/src/containers/Tenant/Diagnostics/TopQueries/QueriesTableWithDrawer.tsx @@ -104,7 +104,7 @@ export function QueriesTableWithDrawer({ columnsWidthLSKey={columnsWidthLSKey} columns={columns} data={data} - loading={loading} + isFetching={loading} settings={tableSettings} onRowClick={handleRowClick} rowClassName={(row) => b('row', {active: isEqual(row, selectedRow)})}