diff --git a/src/components/PaginatedTable/PaginatedTable.tsx b/src/components/PaginatedTable/PaginatedTable.tsx index 3cd5a3436f..562dbe6c3f 100644 --- a/src/components/PaginatedTable/PaginatedTable.tsx +++ b/src/components/PaginatedTable/PaginatedTable.tsx @@ -3,6 +3,7 @@ import React from 'react'; import {usePaginatedTableState} from './PaginatedTableContext'; import {TableChunksRenderer} from './TableChunksRenderer'; import {TableHead} from './TableHead'; +import type {PaginatedTableId} from './constants'; import {DEFAULT_TABLE_ROW_HEIGHT} from './constants'; import {b} from './shared'; import type { @@ -22,7 +23,7 @@ export interface PaginatedTableProps { initialEntitiesCount?: number; fetchData: FetchData; filters?: F; - tableName: string; + tableName: PaginatedTableId; columns: Column[]; getRowClassName?: GetRowClassName; rowHeight?: number; diff --git a/src/components/PaginatedTable/TableChunk.tsx b/src/components/PaginatedTable/TableChunk.tsx index e19632e5bd..bfe3ae4b4c 100644 --- a/src/components/PaginatedTable/TableChunk.tsx +++ b/src/components/PaginatedTable/TableChunk.tsx @@ -8,6 +8,8 @@ import {ResponseError} from '../Errors/ResponseError'; import {usePaginatedTableState} from './PaginatedTableContext'; import {EmptyTableRow, LoadingTableRow, TableRow} from './TableRow'; +import type {PaginatedTableId} from './constants'; +import {shouldSendColumnIds} from './constants'; import i18n from './i18n'; import type { Column, @@ -32,7 +34,7 @@ interface TableChunkProps { sortParams?: SortParams; shouldFetch: boolean; shouldRender: boolean; - tableName: string; + tableName: PaginatedTableId; fetchData: FetchData; getRowClassName?: GetRowClassName; @@ -66,8 +68,14 @@ export const TableChunk = typedMemo(function TableChunk({ const [autoRefreshInterval] = useAutoRefreshInterval(); const {noBatching} = usePaginatedTableState(); - //sort ids to prevent refetch if only order was changed - const columnsIds = columns.map((column) => column.name).toSorted(); + const hasColumnsIdsInRequest = shouldSendColumnIds(tableName); + + const columnsIds = React.useMemo( + () => + // sort ids to prevent refetch if only order was changed + hasColumnsIdsInRequest ? columns.map((column) => column.name).toSorted() : [], + [columns, hasColumnsIdsInRequest], + ); const queryParams = { offset: id * chunkSize, diff --git a/src/components/PaginatedTable/TableChunksRenderer.tsx b/src/components/PaginatedTable/TableChunksRenderer.tsx index 0a1e7185d5..1f9eccfb60 100644 --- a/src/components/PaginatedTable/TableChunksRenderer.tsx +++ b/src/components/PaginatedTable/TableChunksRenderer.tsx @@ -1,6 +1,7 @@ import React from 'react'; import {TableChunk} from './TableChunk'; +import type {PaginatedTableId} from './constants'; import {b} from './shared'; import type { Column, @@ -22,7 +23,7 @@ export interface TableChunksRendererProps { columns: Column[]; fetchData: FetchData; filters?: F; - tableName: string; + tableName: PaginatedTableId; sortParams?: SortParams; getRowClassName?: GetRowClassName; renderErrorMessage?: RenderErrorMessage; diff --git a/src/components/PaginatedTable/constants.ts b/src/components/PaginatedTable/constants.ts index 355d659333..233a1357ab 100644 --- a/src/components/PaginatedTable/constants.ts +++ b/src/components/PaginatedTable/constants.ts @@ -16,3 +16,25 @@ export const DEFAULT_REQUEST_TIMEOUT = 200; export const DEFAULT_TABLE_ROW_HEIGHT = 41; export const DEFAULT_INTERSECTION_OBSERVER_MARGIN = '100%'; + +export const PAGINATED_TABLE_IDS = { + NODES: 'nodes', + STORAGE_NODES: 'storage-nodes', + STORAGE_GROUPS: 'storage-groups', + TOPIC_DATA: 'topic-data', + NODE_PEERS: 'node-peers', +} as const; + +export type PaginatedTableId = (typeof PAGINATED_TABLE_IDS)[keyof typeof PAGINATED_TABLE_IDS]; + +export const PAGINATED_TABLE_COLUMN_IDS_IN_REQUEST: Record = { + [PAGINATED_TABLE_IDS.NODES]: true, + [PAGINATED_TABLE_IDS.STORAGE_NODES]: true, + [PAGINATED_TABLE_IDS.STORAGE_GROUPS]: true, + [PAGINATED_TABLE_IDS.TOPIC_DATA]: true, + [PAGINATED_TABLE_IDS.NODE_PEERS]: false, +}; + +export function shouldSendColumnIds(tableId: PaginatedTableId): boolean { + return PAGINATED_TABLE_COLUMN_IDS_IN_REQUEST[tableId] ?? false; +} diff --git a/src/components/nodesColumns/__test__/utils.test.ts b/src/components/nodesColumns/__test__/utils.test.ts index b60ee5bfed..c109ba8317 100644 --- a/src/components/nodesColumns/__test__/utils.test.ts +++ b/src/components/nodesColumns/__test__/utils.test.ts @@ -1,4 +1,4 @@ -import {UNBREAKABLE_GAP} from '../../../utils/utils'; +import {UNBREAKABLE_GAP} from '../../../utils/constants'; import {prepareClockSkewValue, preparePingTimeValue} from '../utils'; describe('preparePingTimeValue', () => { diff --git a/src/containers/Node/NodeNetwork/NodeNetworkTable.tsx b/src/containers/Node/NodeNetwork/NodeNetworkTable.tsx index 2d656c63a7..1b28051713 100644 --- a/src/containers/Node/NodeNetwork/NodeNetworkTable.tsx +++ b/src/containers/Node/NodeNetwork/NodeNetworkTable.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import {ResizeablePaginatedTable} from '../../../components/PaginatedTable'; +import {PAGINATED_TABLE_IDS, ResizeablePaginatedTable} from '../../../components/PaginatedTable'; import type {PaginatedTableData} from '../../../components/PaginatedTable'; import {renderPaginatedTableErrorMessage} from '../../../utils/renderPaginatedTableErrorMessage'; import type {Column} from '../../../utils/tableUtils/types'; @@ -42,7 +42,7 @@ export function NodeNetworkTable({ columns={columns} fetchData={getNodePeers} filters={filters} - tableName={i18n('table_node-peers')} + tableName={PAGINATED_TABLE_IDS.NODE_PEERS} renderErrorMessage={renderPaginatedTableErrorMessage} renderEmptyDataMessage={renderEmptyDataMessage} onDataFetched={onDataFetched} diff --git a/src/containers/Node/NodeNetwork/columns.ts b/src/containers/Node/NodeNetwork/columns.ts index 877eeff07d..0948d23cf7 100644 --- a/src/containers/Node/NodeNetwork/columns.ts +++ b/src/containers/Node/NodeNetwork/columns.ts @@ -12,9 +12,9 @@ import { } from '../../../components/nodesColumns/columns'; import type {GetNodesColumnsParams} from '../../../components/nodesColumns/types'; import {EMPTY_DATA_PLACEHOLDER} from '../../../lib'; +import {formatBytes} from '../../../utils/bytesParsers'; import {formatDateTime} from '../../../utils/dataFormatters/dataFormatters'; import type {Column} from '../../../utils/tableUtils/types'; -import {bytesToMB, isNumeric} from '../../../utils/utils'; import { NODE_NETWORK_COLUMNS_IDS, @@ -35,6 +35,14 @@ function getPeerConnectTimeColumn(): Column }; } +function renderBytes(bytes?: number | string) { + return formatBytes({ + value: bytes, + size: 'mb', + withSizeLabel: true, + }); +} + function getPeerSentBytesColumn(): Column { return { name: NODE_NETWORK_COLUMNS_IDS.BytesSend, @@ -42,8 +50,7 @@ function getPeerSentBytesColumn(): Colu align: DataTable.RIGHT, width: 140, resizeMinWidth: 120, - render: ({row}) => - isNumeric(row.BytesSend) ? bytesToMB(row.BytesSend, 0) : EMPTY_DATA_PLACEHOLDER, + render: ({row}) => renderBytes(row.BytesSend) || EMPTY_DATA_PLACEHOLDER, }; } @@ -54,8 +61,7 @@ function getPeerReceivedBytesColumn align: DataTable.RIGHT, width: 160, resizeMinWidth: 130, - render: ({row}) => - isNumeric(row.BytesReceived) ? bytesToMB(row.BytesReceived, 0) : EMPTY_DATA_PLACEHOLDER, + render: ({row}) => renderBytes(row.BytesReceived) || EMPTY_DATA_PLACEHOLDER, }; } diff --git a/src/containers/Node/NodeNetwork/i18n/en.json b/src/containers/Node/NodeNetwork/i18n/en.json index 095e982f0c..57e46872ba 100644 --- a/src/containers/Node/NodeNetwork/i18n/en.json +++ b/src/containers/Node/NodeNetwork/i18n/en.json @@ -4,6 +4,5 @@ "field_received-bytes": "Received Bytes", "alert_no-network-data": "No network data", "search-placeholder": "Search peers", - "field_peers": "Peers", - "table_node-peers": "Node Peers" + "field_peers": "Peers" } diff --git a/src/containers/Nodes/NodesTable.tsx b/src/containers/Nodes/NodesTable.tsx index 8728cb02e3..112b4e219f 100644 --- a/src/containers/Nodes/NodesTable.tsx +++ b/src/containers/Nodes/NodesTable.tsx @@ -2,7 +2,7 @@ import React from 'react'; import {Illustration} from '../../components/Illustration'; import type {PaginatedTableData} from '../../components/PaginatedTable'; -import {ResizeablePaginatedTable} from '../../components/PaginatedTable'; +import {PAGINATED_TABLE_IDS, ResizeablePaginatedTable} from '../../components/PaginatedTable'; import {NODES_COLUMNS_WIDTH_LS_KEY} from '../../components/nodesColumns/constants'; import type {NodesColumn} from '../../components/nodesColumns/types'; import type {NodesFilters} from '../../store/reducers/nodes/types'; @@ -94,7 +94,7 @@ export function NodesTable({ renderEmptyDataMessage={renderEmptyDataMessage} getRowClassName={getRowClassName} filters={tableFilters} - tableName="nodes" + tableName={PAGINATED_TABLE_IDS.NODES} onDataFetched={onDataFetched} /> ); diff --git a/src/containers/Storage/PaginatedStorageGroupsTable/PaginatedStorageGroupsTable.tsx b/src/containers/Storage/PaginatedStorageGroupsTable/PaginatedStorageGroupsTable.tsx index f75db20712..5b54a35ac5 100644 --- a/src/containers/Storage/PaginatedStorageGroupsTable/PaginatedStorageGroupsTable.tsx +++ b/src/containers/Storage/PaginatedStorageGroupsTable/PaginatedStorageGroupsTable.tsx @@ -2,7 +2,7 @@ import React from 'react'; import {LoaderWrapper} from '../../../components/LoaderWrapper/LoaderWrapper'; import type {RenderErrorMessage} from '../../../components/PaginatedTable'; -import {ResizeablePaginatedTable} from '../../../components/PaginatedTable'; +import {PAGINATED_TABLE_IDS, ResizeablePaginatedTable} from '../../../components/PaginatedTable'; import { useCapabilitiesLoaded, useStorageGroupsHandlerAvailable, @@ -103,7 +103,7 @@ export const PaginatedStorageGroupsTable = ({ renderErrorMessage={renderErrorMessage} renderEmptyDataMessage={renderEmptyDataMessage} filters={tableFilters} - tableName="storage-groups" + tableName={PAGINATED_TABLE_IDS.STORAGE_GROUPS} /> ); diff --git a/src/containers/Storage/PaginatedStorageNodesTable/PaginatedStorageNodesTable.tsx b/src/containers/Storage/PaginatedStorageNodesTable/PaginatedStorageNodesTable.tsx index 13650bc36a..eb0f5c9a18 100644 --- a/src/containers/Storage/PaginatedStorageNodesTable/PaginatedStorageNodesTable.tsx +++ b/src/containers/Storage/PaginatedStorageNodesTable/PaginatedStorageNodesTable.tsx @@ -1,7 +1,7 @@ import React from 'react'; import type {PaginatedTableData, RenderErrorMessage} from '../../../components/PaginatedTable'; -import {ResizeablePaginatedTable} from '../../../components/PaginatedTable'; +import {PAGINATED_TABLE_IDS, ResizeablePaginatedTable} from '../../../components/PaginatedTable'; import type {NodesColumn} from '../../../components/nodesColumns/types'; import {VISIBLE_ENTITIES} from '../../../store/reducers/storage/constants'; import type {PreparedStorageNode, VisibleEntities} from '../../../store/reducers/storage/types'; @@ -109,7 +109,7 @@ export const PaginatedStorageNodesTable = ({ renderEmptyDataMessage={renderEmptyDataMessage} getRowClassName={getRowUnavailableClassName} filters={tableFilters} - tableName="storage-nodes" + tableName={PAGINATED_TABLE_IDS.STORAGE_NODES} onDataFetched={onDataFetched} /> ); diff --git a/src/containers/Tenant/Diagnostics/TenantOverview/MetricsTabs/components/PlaceholderTab.tsx b/src/containers/Tenant/Diagnostics/TenantOverview/MetricsTabs/components/PlaceholderTab.tsx index b1b13cc1e1..c5da545eb7 100644 --- a/src/containers/Tenant/Diagnostics/TenantOverview/MetricsTabs/components/PlaceholderTab.tsx +++ b/src/containers/Tenant/Diagnostics/TenantOverview/MetricsTabs/components/PlaceholderTab.tsx @@ -1,5 +1,5 @@ import {cn} from '../../../../../../utils/cn'; -import {NON_BREAKING_SPACE} from '../../../../../../utils/constants'; +import {UNBREAKABLE_GAP} from '../../../../../../utils/constants'; import {ServerlessTabCard} from '../../TabCard/ServerlessTabCard'; import '../MetricsTabs.scss'; @@ -11,10 +11,10 @@ export function PlaceholderTab() {
diff --git a/src/containers/Tenant/Diagnostics/TopicData/TopicData.tsx b/src/containers/Tenant/Diagnostics/TopicData/TopicData.tsx index 1163e5eb5f..86fb8dde5b 100644 --- a/src/containers/Tenant/Diagnostics/TopicData/TopicData.tsx +++ b/src/containers/Tenant/Diagnostics/TopicData/TopicData.tsx @@ -11,6 +11,7 @@ import {PageError} from '../../../../components/Errors/PageError/PageError'; import {Fullscreen} from '../../../../components/Fullscreen/Fullscreen'; import { DEFAULT_TABLE_ROW_HEIGHT, + PAGINATED_TABLE_IDS, ResizeablePaginatedTable, } from '../../../../components/PaginatedTable'; import {PaginatedTableWithLayout} from '../../../../components/PaginatedTable/PaginatedTableWithLayout'; @@ -354,7 +355,7 @@ export function TopicData({scrollContainerRef, path, database, databaseFullPath} renderErrorMessage={renderPaginatedTableErrorMessage} renderEmptyDataMessage={renderEmptyDataMessage} filters={tableFilters} - tableName="topicData" + tableName={PAGINATED_TABLE_IDS.TOPIC_DATA} rowHeight={DEFAULT_TABLE_ROW_HEIGHT} keepCache={false} getRowClassName={(row) => { diff --git a/src/utils/bytesParsers/__test__/formatBytes.test.ts b/src/utils/bytesParsers/__test__/formatBytes.test.ts index 11f6ff1e94..474387e4b3 100644 --- a/src/utils/bytesParsers/__test__/formatBytes.test.ts +++ b/src/utils/bytesParsers/__test__/formatBytes.test.ts @@ -1,4 +1,4 @@ -import {UNBREAKABLE_GAP} from '../../utils'; +import {UNBREAKABLE_GAP} from '../../constants'; import {formatBytes} from '../formatBytes'; describe('formatBytes', () => { diff --git a/src/utils/bytesParsers/formatBytes.ts b/src/utils/bytesParsers/formatBytes.ts index 6c22be3cf4..3be9116bd0 100644 --- a/src/utils/bytesParsers/formatBytes.ts +++ b/src/utils/bytesParsers/formatBytes.ts @@ -1,7 +1,7 @@ -import {GIGABYTE, KILOBYTE, MEGABYTE, TERABYTE} from '../constants'; +import {GIGABYTE, KILOBYTE, MEGABYTE, TERABYTE, UNBREAKABLE_GAP} from '../constants'; import type {FormatToSizeArgs, FormatValuesArgs} from '../dataFormatters/common'; import {formatNumber, roundToPrecision} from '../dataFormatters/dataFormatters'; -import {UNBREAKABLE_GAP, isNumeric} from '../utils'; +import {isNumeric} from '../utils'; import i18n from './i18n'; diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 86d35e3dbf..e1b97ab4a6 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -68,7 +68,7 @@ export const SECTION_IDS = { export const TENANT_OVERVIEW_TABLES_LIMIT = 3; export const EMPTY_DATA_PLACEHOLDER = '—'; -export const NON_BREAKING_SPACE = '\u00A0'; +export const UNBREAKABLE_GAP = '\u00A0'; export const QUERY_TECHNICAL_MARK = '/*UI-QUERY-EXCLUDE*/'; diff --git a/src/utils/dataFormatters/__test__/formatNumbers.test.ts b/src/utils/dataFormatters/__test__/formatNumbers.test.ts index a99bc528d1..d684ccb8a7 100644 --- a/src/utils/dataFormatters/__test__/formatNumbers.test.ts +++ b/src/utils/dataFormatters/__test__/formatNumbers.test.ts @@ -1,4 +1,4 @@ -import {UNBREAKABLE_GAP} from '../../utils'; +import {UNBREAKABLE_GAP} from '../../constants'; import {formatNumericValues} from '../dataFormatters'; describe('formatNumericValues', () => { diff --git a/src/utils/dataFormatters/__test__/formatStorageValues.test.ts b/src/utils/dataFormatters/__test__/formatStorageValues.test.ts index ea54a1d976..04bb4050a6 100644 --- a/src/utils/dataFormatters/__test__/formatStorageValues.test.ts +++ b/src/utils/dataFormatters/__test__/formatStorageValues.test.ts @@ -1,4 +1,4 @@ -import {UNBREAKABLE_GAP} from '../../utils'; +import {UNBREAKABLE_GAP} from '../../constants'; import {formatStorageValues} from '../dataFormatters'; describe('formatStorageValues', () => { diff --git a/src/utils/dataFormatters/__test__/formatUptime.test.ts b/src/utils/dataFormatters/__test__/formatUptime.test.ts index 8ad347c2f8..b1e28063d2 100644 --- a/src/utils/dataFormatters/__test__/formatUptime.test.ts +++ b/src/utils/dataFormatters/__test__/formatUptime.test.ts @@ -1,4 +1,4 @@ -import {UNBREAKABLE_GAP} from '../../utils'; +import {UNBREAKABLE_GAP} from '../../constants'; import { formatUptimeInSeconds, getDowntimeFromDateFormatted, diff --git a/src/utils/dataFormatters/dataFormatters.ts b/src/utils/dataFormatters/dataFormatters.ts index 2ee9adfd3f..856f1f2bed 100644 --- a/src/utils/dataFormatters/dataFormatters.ts +++ b/src/utils/dataFormatters/dataFormatters.ts @@ -3,9 +3,9 @@ import {dateTimeParse, duration} from '@gravity-ui/date-utils'; import type {TVDiskID, TVSlotId} from '../../types/api/vdisk'; import {formatBytes as formatBytesCustom, getBytesSizeUnit} from '../bytesParsers/formatBytes'; import type {BytesSizes} from '../bytesParsers/formatBytes'; -import {HOUR_IN_SECONDS} from '../constants'; +import {HOUR_IN_SECONDS, UNBREAKABLE_GAP} from '../constants'; import {configuredNumeral} from '../numeral'; -import {UNBREAKABLE_GAP, isNumeric} from '../utils'; +import {isNumeric} from '../utils'; import {formatValues} from './common'; import {formatNumberWithDigits, getNumberSizeUnit} from './formatNumber'; diff --git a/src/utils/dataFormatters/formatNumber.ts b/src/utils/dataFormatters/formatNumber.ts index c051a2c44a..9f57746184 100644 --- a/src/utils/dataFormatters/formatNumber.ts +++ b/src/utils/dataFormatters/formatNumber.ts @@ -1,5 +1,6 @@ import i18n from '../bytesParsers/i18n'; -import {UNBREAKABLE_GAP, isNumeric} from '../utils'; +import {UNBREAKABLE_GAP} from '../constants'; +import {isNumeric} from '../utils'; import type {FormatToSizeArgs, FormatValuesArgs} from './common'; import {formatNumber, roundToPrecision} from './dataFormatters'; diff --git a/src/utils/numeral.ts b/src/utils/numeral.ts index 1ae6acc13a..002f7e1430 100644 --- a/src/utils/numeral.ts +++ b/src/utils/numeral.ts @@ -1,8 +1,8 @@ import numeral from 'numeral'; import 'numeral/locales'; // Without this numeral will throw an error when using not 'en' locale +import {UNBREAKABLE_GAP} from './constants'; import {Lang, i18n} from './i18n'; -import {UNBREAKABLE_GAP} from './utils'; // Set space delimiter for all locales possible in project Object.values(Lang).forEach((value) => { diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 4dd942f630..9d9f3d6704 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -107,8 +107,6 @@ export function toExponential(value: number, precision?: number) { return Number(value).toExponential(precision); } -export const UNBREAKABLE_GAP = '\xa0'; - // Numeric values expected, not numeric value should be displayd as 0 export function safeParseNumber(value: unknown, defaultValue = 0): number { if (isNumeric(value)) {