From 1defcf7e6d4c93aef85e17d4952c793587462edd Mon Sep 17 00:00:00 2001 From: mufazalov Date: Wed, 24 Sep 2025 13:54:26 +0300 Subject: [PATCH 1/3] feat(Nodes,Storage): enable both tablets and pdisks columns --- src/components/NetworkTable/columns.tsx | 6 +- src/components/nodesColumns/types.ts | 9 +++ src/containers/Nodes/Nodes.tsx | 20 ++++-- src/containers/Nodes/NodesTable.tsx | 12 +++- .../PaginatedNodes/GroupedNodesComponent.tsx | 21 ++++--- .../Nodes/PaginatedNodes/NodesComponent.tsx | 10 ++- .../Nodes/PaginatedNodes/PaginatedNodes.tsx | 8 ++- src/containers/Nodes/columns/columns.tsx | 38 ++++++------ src/containers/Nodes/columns/hooks.ts | 30 +++++++++ src/containers/Nodes/getNodes.ts | 17 ++--- src/containers/Nodes/shared.tsx | 4 +- .../PaginatedStorageNodesTable.tsx | 4 +- .../columns/columns.tsx | 48 +++++++------- .../columns/types.ts | 5 +- .../TenantCpu/TopNodesByCpu.tsx | 23 ++++--- .../TenantCpu/TopNodesByLoad.tsx | 24 +++---- .../TenantMemory/TopNodesByMemory.tsx | 28 ++++----- .../TenantNetwork/TopNodesByPing.tsx | 2 +- .../TenantNetwork/TopNodesBySkew.tsx | 2 +- .../TenantOverview/TenantNetwork/columns.ts | 11 ++-- .../GroupedNodesTree/GroupedNodesTree.tsx | 4 +- .../Versions/NodesTable/NodesTable.tsx | 24 ++++--- src/containers/Versions/Versions.tsx | 6 +- src/containers/Versions/groupNodes.test.ts | 4 +- src/containers/Versions/groupNodes.ts | 12 ++-- src/containers/Versions/types.ts | 4 +- src/containers/Versions/utils.ts | 6 +- src/services/api/viewer.ts | 4 ++ src/store/reducers/nodes/nodes.ts | 5 +- src/store/reducers/nodes/types.ts | 62 +------------------ src/store/reducers/nodes/utils.ts | 34 ---------- src/store/reducers/storage/types.ts | 19 +++--- src/store/reducers/storage/utils.ts | 15 ++--- .../versions/parseNodesToVersionsValues.ts | 4 +- 34 files changed, 245 insertions(+), 280 deletions(-) create mode 100644 src/containers/Nodes/columns/hooks.ts delete mode 100644 src/store/reducers/nodes/utils.ts diff --git a/src/components/NetworkTable/columns.tsx b/src/components/NetworkTable/columns.tsx index 648577ac4e..9dc1939131 100644 --- a/src/components/NetworkTable/columns.tsx +++ b/src/components/NetworkTable/columns.tsx @@ -1,5 +1,3 @@ -import type {NodesPreparedEntity} from '../../store/reducers/nodes/types'; -import type {Column} from '../../utils/tableUtils/types'; import { getClockSkewColumn, getConnectionsColumn, @@ -16,10 +14,10 @@ import { getUptimeColumn, } from '../nodesColumns/columns'; import {isSortableNodesColumn} from '../nodesColumns/constants'; -import type {GetNodesColumnsParams} from '../nodesColumns/types'; +import type {GetNodesColumnsParams, NodesColumn} from '../nodesColumns/types'; export function getNetworkTableNodesColumns(params: GetNodesColumnsParams) { - const columns: Column[] = [ + const columns: NodesColumn[] = [ getNodeIdColumn(), getNetworkHostColumn(params), getDataCenterColumn(), diff --git a/src/components/nodesColumns/types.ts b/src/components/nodesColumns/types.ts index f09990a207..1d56be9648 100644 --- a/src/components/nodesColumns/types.ts +++ b/src/components/nodesColumns/types.ts @@ -1,6 +1,15 @@ +import type {StorageNodesColumnsSettings} from '../../containers/Storage/PaginatedStorageNodesTable/columns/types'; +import type {StorageViewContext} from '../../containers/Storage/types'; +import type {PreparedStorageNode} from '../../store/reducers/storage/types'; import type {GetNodeRefFunc} from '../../types/additionalProps'; +import type {Column} from '../../utils/tableUtils/types'; export interface GetNodesColumnsParams { getNodeRef?: GetNodeRefFunc; database?: string; + + viewContext?: StorageViewContext; + columnsSettings?: StorageNodesColumnsSettings; } + +export type NodesColumn = Column; diff --git a/src/containers/Nodes/Nodes.tsx b/src/containers/Nodes/Nodes.tsx index b514bd585f..ecc1a279ab 100644 --- a/src/containers/Nodes/Nodes.tsx +++ b/src/containers/Nodes/Nodes.tsx @@ -1,29 +1,29 @@ import React from 'react'; -import type {Column} from '../../components/PaginatedTable'; import { NODES_COLUMNS_IDS, isMonitoringUserNodesColumn, isViewerUserNodesColumn, } from '../../components/nodesColumns/constants'; import type {NodesColumnId} from '../../components/nodesColumns/constants'; +import type {NodesColumn} from '../../components/nodesColumns/types'; import {useBridgeModeEnabled} from '../../store/reducers/capabilities/hooks'; -import type {NodesPreparedEntity} from '../../store/reducers/nodes/types'; import type {AdditionalNodesProps} from '../../types/additionalProps'; import type {NodesGroupByField} from '../../types/api/nodes'; import { useIsUserAllowedToMakeChanges, useIsViewerUser, } from '../../utils/hooks/useIsUserAllowedToMakeChanges'; +import {useStorageColumnsSettings} from '../Storage/utils'; import {PaginatedNodes} from './PaginatedNodes'; -import {getNodesColumns} from './columns/columns'; import { ALL_NODES_GROUP_BY_PARAMS, DEFAULT_NODES_COLUMNS, NODES_TABLE_SELECTED_COLUMNS_LS_KEY, REQUIRED_NODES_COLUMNS, } from './columns/constants'; +import {useGetNodesColumns} from './columns/hooks'; import './Nodes.scss'; @@ -34,7 +34,7 @@ export interface NodesProps { scrollContainerRef: React.RefObject; additionalNodesProps?: AdditionalNodesProps; withPeerRoleFilter?: boolean; - columns?: Column[]; + columns?: NodesColumn[]; defaultColumnsIds?: NodesColumnId[]; requiredColumnsIds?: NodesColumnId[]; selectedColumnsKey?: string; @@ -48,12 +48,21 @@ export function Nodes({ scrollContainerRef, additionalNodesProps, withPeerRoleFilter, - columns = getNodesColumns({database, getNodeRef: additionalNodesProps?.getNodeRef}), + columns: externalColumns, defaultColumnsIds = DEFAULT_NODES_COLUMNS, requiredColumnsIds = REQUIRED_NODES_COLUMNS, selectedColumnsKey = NODES_TABLE_SELECTED_COLUMNS_LS_KEY, groupByParams = ALL_NODES_GROUP_BY_PARAMS, }: NodesProps) { + const {handleDataFetched, columnsSettings} = useStorageColumnsSettings(); + + const columns = useGetNodesColumns({ + columns: externalColumns, + database, + getNodeRef: additionalNodesProps?.getNodeRef, + columnsSettings, + }); + const bridgeModeEnabled = useBridgeModeEnabled(); const columnsWithPile = React.useMemo(() => { @@ -107,6 +116,7 @@ export function Nodes({ requiredColumnsIds={requiredColumnsIds} selectedColumnsKey={selectedColumnsKey} groupByParams={effectiveGroupByParams} + onDataFetched={handleDataFetched} /> ); } diff --git a/src/containers/Nodes/NodesTable.tsx b/src/containers/Nodes/NodesTable.tsx index bdd5b907b9..37c96d847a 100644 --- a/src/containers/Nodes/NodesTable.tsx +++ b/src/containers/Nodes/NodesTable.tsx @@ -1,14 +1,16 @@ import React from 'react'; import {Illustration} from '../../components/Illustration'; +import type {PaginatedTableData} from '../../components/PaginatedTable'; import {ResizeablePaginatedTable} from '../../components/PaginatedTable'; import {NODES_COLUMNS_WIDTH_LS_KEY} from '../../components/nodesColumns/constants'; -import type {NodesFilters, NodesPreparedEntity} from '../../store/reducers/nodes/types'; +import type {NodesColumn} from '../../components/nodesColumns/types'; +import type {NodesFilters} from '../../store/reducers/nodes/types'; import type {ProblemFilterValue} from '../../store/reducers/settings/types'; +import type {PreparedStorageNode} from '../../store/reducers/storage/types'; import type {NodesGroupByField, NodesPeerRole} from '../../types/api/nodes'; import {NodesUptimeFilterValues} from '../../utils/nodes'; import {renderPaginatedTableErrorMessage} from '../../utils/renderPaginatedTableErrorMessage'; -import type {Column} from '../../utils/tableUtils/types'; import {getNodes} from './getNodes'; import i18n from './i18n'; @@ -27,10 +29,12 @@ interface NodesTableProps { filterGroup?: string; filterGroupBy?: NodesGroupByField; - columns: Column[]; + columns: NodesColumn[]; scrollContainerRef: React.RefObject; initialEntitiesCount?: number; + + onDataFetched?: (data: PaginatedTableData) => void; } export function NodesTable({ @@ -46,6 +50,7 @@ export function NodesTable({ columns, scrollContainerRef, initialEntitiesCount, + onDataFetched, }: NodesTableProps) { const tableFilters: NodesFilters = React.useMemo(() => { return { @@ -91,6 +96,7 @@ export function NodesTable({ getRowClassName={getRowClassName} filters={tableFilters} tableName="nodes" + onDataFetched={onDataFetched} /> ); } diff --git a/src/containers/Nodes/PaginatedNodes/GroupedNodesComponent.tsx b/src/containers/Nodes/PaginatedNodes/GroupedNodesComponent.tsx index a8da11a5b9..fc7c6a0ec3 100644 --- a/src/containers/Nodes/PaginatedNodes/GroupedNodesComponent.tsx +++ b/src/containers/Nodes/PaginatedNodes/GroupedNodesComponent.tsx @@ -3,13 +3,14 @@ import React from 'react'; import {isNil} from 'lodash'; import {ResponseError} from '../../../components/Errors/ResponseError'; -import type {Column} from '../../../components/PaginatedTable'; +import type {PaginatedTableData} from '../../../components/PaginatedTable'; import {PaginatedTableWithLayout} from '../../../components/PaginatedTable/PaginatedTableWithLayout'; import {TableColumnSetup} from '../../../components/TableColumnSetup/TableColumnSetup'; import {NODES_COLUMNS_TITLES} from '../../../components/nodesColumns/constants'; import type {NodesColumnId} from '../../../components/nodesColumns/constants'; +import type {NodesColumn} from '../../../components/nodesColumns/types'; import {nodesApi} from '../../../store/reducers/nodes/nodes'; -import type {NodesPreparedEntity} from '../../../store/reducers/nodes/types'; +import type {PreparedStorageNode} from '../../../store/reducers/storage/types'; import type {NodesGroupByField, NodesPeerRole} from '../../../types/api/nodes'; import {useAutoRefreshInterval} from '../../../utils/hooks'; import {useSelectedColumns} from '../../../utils/hooks/useSelectedColumns'; @@ -32,9 +33,10 @@ interface NodeGroupProps { searchValue: string; peerRoleFilter?: NodesPeerRole; groupByParam?: NodesGroupByField; - columns: Column[]; + columns: NodesColumn[]; scrollContainerRef: React.RefObject; onIsExpandedChange: (name: string, isExpanded: boolean) => void; + onDataFetched?: (data: PaginatedTableData) => void; } const NodeGroup = React.memo(function NodeGroup({ @@ -50,6 +52,7 @@ const NodeGroup = React.memo(function NodeGroup({ columns, scrollContainerRef, onIsExpandedChange, + onDataFetched, }: NodeGroupProps) { return ( } tableWrapperProps={{ @@ -92,11 +96,12 @@ interface GroupedNodesComponentProps { databaseFullPath?: string; scrollContainerRef: React.RefObject; withPeerRoleFilter?: boolean; - columns: Column[]; + columns: NodesColumn[]; defaultColumnsIds: NodesColumnId[]; requiredColumnsIds: NodesColumnId[]; selectedColumnsKey: string; groupByParams: NodesGroupByField[]; + onDataFetched?: (data: PaginatedTableData) => void; } export function GroupedNodesComponent({ @@ -110,6 +115,7 @@ export function GroupedNodesComponent({ requiredColumnsIds, selectedColumnsKey, groupByParams, + onDataFetched, }: GroupedNodesComponentProps) { const {searchValue, peerRoleFilter, groupByParam} = useNodesPageQueryParams( groupByParams, @@ -147,11 +153,7 @@ export function GroupedNodesComponent({ ); const isLoading = currentData === undefined && isFetching; - const { - NodeGroups: tableGroups, - FoundNodes: found = 0, - TotalNodes: total = 0, - } = currentData || {}; + const {tableGroups, found = 0, total = 0} = currentData || {}; const {expandedGroups, setIsGroupExpanded} = useExpandedGroups(tableGroups); @@ -186,6 +188,7 @@ export function GroupedNodesComponent({ columns={columnsToShow} scrollContainerRef={scrollContainerRef} onIsExpandedChange={setIsGroupExpanded} + onDataFetched={onDataFetched} /> ); }); diff --git a/src/containers/Nodes/PaginatedNodes/NodesComponent.tsx b/src/containers/Nodes/PaginatedNodes/NodesComponent.tsx index f2b63a8939..d0c6993761 100644 --- a/src/containers/Nodes/PaginatedNodes/NodesComponent.tsx +++ b/src/containers/Nodes/PaginatedNodes/NodesComponent.tsx @@ -1,13 +1,14 @@ import React from 'react'; -import type {Column} from '../../../components/PaginatedTable'; +import type {PaginatedTableData} from '../../../components/PaginatedTable'; import {PaginatedTableWithLayout} from '../../../components/PaginatedTable/PaginatedTableWithLayout'; import {TableColumnSetup} from '../../../components/TableColumnSetup/TableColumnSetup'; import {NODES_COLUMNS_TITLES} from '../../../components/nodesColumns/constants'; import type {NodesColumnId} from '../../../components/nodesColumns/constants'; +import type {NodesColumn} from '../../../components/nodesColumns/types'; import {useViewerNodesHandlerHasGrouping} from '../../../store/reducers/capabilities/hooks'; -import type {NodesPreparedEntity} from '../../../store/reducers/nodes/types'; import {useProblemFilter} from '../../../store/reducers/settings/hooks'; +import type {PreparedStorageNode} from '../../../store/reducers/storage/types'; import type {NodesGroupByField} from '../../../types/api/nodes'; import {useSelectedColumns} from '../../../utils/hooks/useSelectedColumns'; import {NodesTable} from '../NodesTable'; @@ -21,11 +22,12 @@ interface NodesComponentProps { databaseFullPath?: string; scrollContainerRef: React.RefObject; withPeerRoleFilter?: boolean; - columns: Column[]; + columns: NodesColumn[]; defaultColumnsIds: NodesColumnId[]; requiredColumnsIds: NodesColumnId[]; selectedColumnsKey: string; groupByParams: NodesGroupByField[]; + onDataFetched?: (data: PaginatedTableData) => void; } export function NodesComponent({ @@ -39,6 +41,7 @@ export function NodesComponent({ requiredColumnsIds, selectedColumnsKey, groupByParams, + onDataFetched, }: NodesComponentProps) { const {searchValue, uptimeFilter, peerRoleFilter} = useNodesPageQueryParams( groupByParams, @@ -83,6 +86,7 @@ export function NodesComponent({ peerRoleFilter={peerRoleFilter} columns={columnsToShow} scrollContainerRef={scrollContainerRef} + onDataFetched={onDataFetched} /> } tableWrapperProps={{ diff --git a/src/containers/Nodes/PaginatedNodes/PaginatedNodes.tsx b/src/containers/Nodes/PaginatedNodes/PaginatedNodes.tsx index 5264be356e..c47eefdccd 100644 --- a/src/containers/Nodes/PaginatedNodes/PaginatedNodes.tsx +++ b/src/containers/Nodes/PaginatedNodes/PaginatedNodes.tsx @@ -1,14 +1,15 @@ import React from 'react'; import {LoaderWrapper} from '../../../components/LoaderWrapper/LoaderWrapper'; -import type {Column} from '../../../components/PaginatedTable'; +import type {PaginatedTableData} from '../../../components/PaginatedTable'; import type {NodesColumnId} from '../../../components/nodesColumns/constants'; +import type {NodesColumn} from '../../../components/nodesColumns/types'; import { useCapabilitiesLoaded, useViewerNodesHandlerHasGrouping, } from '../../../store/reducers/capabilities/hooks'; -import type {NodesPreparedEntity} from '../../../store/reducers/nodes/types'; import {useProblemFilter} from '../../../store/reducers/settings/hooks'; +import type {PreparedStorageNode} from '../../../store/reducers/storage/types'; import type {NodesGroupByField} from '../../../types/api/nodes'; import {NodesUptimeFilterValues} from '../../../utils/nodes'; import {useNodesPageQueryParams} from '../useNodesPageQueryParams'; @@ -24,11 +25,12 @@ export interface PaginatedNodesProps { database?: string; scrollContainerRef: React.RefObject; withPeerRoleFilter?: boolean; - columns: Column[]; + columns: NodesColumn[]; defaultColumnsIds: NodesColumnId[]; requiredColumnsIds: NodesColumnId[]; selectedColumnsKey: string; groupByParams: NodesGroupByField[]; + onDataFetched?: (data: PaginatedTableData) => void; } export function PaginatedNodes(props: PaginatedNodesProps) { diff --git a/src/containers/Nodes/columns/columns.tsx b/src/containers/Nodes/columns/columns.tsx index 3f2d67ee3d..1e8e49e227 100644 --- a/src/containers/Nodes/columns/columns.tsx +++ b/src/containers/Nodes/columns/columns.tsx @@ -15,26 +15,26 @@ import { getVersionColumn, } from '../../../components/nodesColumns/columns'; import {isSortableNodesColumn} from '../../../components/nodesColumns/constants'; -import type {GetNodesColumnsParams} from '../../../components/nodesColumns/types'; -import type {NodesPreparedEntity} from '../../../store/reducers/nodes/types'; -import type {Column} from '../../../utils/tableUtils/types'; +import type {GetNodesColumnsParams, NodesColumn} from '../../../components/nodesColumns/types'; +import {getPDisksColumn} from '../../Storage/PaginatedStorageNodesTable/columns/columns'; -export function getNodesColumns(params: GetNodesColumnsParams): Column[] { - const columns = [ - getNodeIdColumn(), - getHostColumn(params), - getNodeNameColumn(), - getDataCenterColumn(), - getPileNameColumn(), - getRackColumn(), - getUptimeColumn(), - getCpuColumn(), - getPoolsColumn(), - getRAMColumn(), - getMemoryColumn(), - getLoadAverageColumn(), - getVersionColumn(), - getTabletsColumn(params), +export function getNodesColumns(params: GetNodesColumnsParams): NodesColumn[] { + const columns: NodesColumn[] = [ + getNodeIdColumn(), + getHostColumn(params), + getNodeNameColumn(), + getDataCenterColumn(), + getPileNameColumn(), + getRackColumn(), + getUptimeColumn(), + getCpuColumn(), + getPoolsColumn(), + getRAMColumn(), + getMemoryColumn(), + getLoadAverageColumn(), + getVersionColumn(), + getPDisksColumn(params), + getTabletsColumn(params), ]; return columns.map((column) => { diff --git a/src/containers/Nodes/columns/hooks.ts b/src/containers/Nodes/columns/hooks.ts new file mode 100644 index 0000000000..21606d183c --- /dev/null +++ b/src/containers/Nodes/columns/hooks.ts @@ -0,0 +1,30 @@ +import React from 'react'; + +import type {GetNodesColumnsParams, NodesColumn} from '../../../components/nodesColumns/types'; + +import {getNodesColumns} from './columns'; + +export function useGetNodesColumns({ + columns: externalColumns, + database, + getNodeRef, + viewContext, + columnsSettings, +}: GetNodesColumnsParams & {columns?: NodesColumn[]}) { + return React.useMemo(() => { + let columns: NodesColumn[]; + + if (externalColumns) { + columns = externalColumns; + } else { + columns = getNodesColumns({ + database, + getNodeRef, + viewContext, + columnsSettings, + }); + } + + return columns; + }, [externalColumns, database, getNodeRef, viewContext, columnsSettings]); +} diff --git a/src/containers/Nodes/getNodes.ts b/src/containers/Nodes/getNodes.ts index 16e0d01db7..7bdbc71803 100644 --- a/src/containers/Nodes/getNodes.ts +++ b/src/containers/Nodes/getNodes.ts @@ -5,19 +5,20 @@ import { NODES_COLUMNS_TO_DATA_FIELDS, getNodesColumnSortField, } from '../../components/nodesColumns/constants'; -import type {NodesFilters, NodesPreparedEntity} from '../../store/reducers/nodes/types'; -import {prepareNodesData} from '../../store/reducers/nodes/utils'; +import type {NodesFilters} from '../../store/reducers/nodes/types'; +import type {PreparedStorageNode} from '../../store/reducers/storage/types'; +import {prepareStorageNodesResponse} from '../../store/reducers/storage/utils'; import type {NodesRequestParams} from '../../types/api/nodes'; import {prepareSortValue} from '../../utils/filters'; import {getProblemParamValue, getUptimeParamValue} from '../../utils/nodes'; import {getRequiredDataFields} from '../../utils/tableUtils/getRequiredDataFields'; export const getNodes: FetchData< - NodesPreparedEntity, + PreparedStorageNode, NodesFilters, Pick > = async (params) => { - const {type = 'any', storage = false, limit, offset, sortParams, filters, columnsIds} = params; + const {type = 'any', storage, limit, offset, sortParams, filters, columnsIds} = params; const {sortOrder, columnId} = sortParams ?? {}; const { @@ -56,11 +57,11 @@ export const getNodes: FetchData< filter_group_by: filterGroupBy, fieldsRequired: dataFieldsRequired, }); - const preparedResponse = prepareNodesData(response); + const preparedResponse = prepareStorageNodesResponse(response); return { - data: preparedResponse.Nodes || [], - found: preparedResponse.FoundNodes || 0, - total: preparedResponse.TotalNodes || 0, + data: preparedResponse.nodes || [], + found: preparedResponse.found || 0, + total: preparedResponse.total || 0, }; }; diff --git a/src/containers/Nodes/shared.tsx b/src/containers/Nodes/shared.tsx index bef440a057..8e3cfea4e7 100644 --- a/src/containers/Nodes/shared.tsx +++ b/src/containers/Nodes/shared.tsx @@ -1,10 +1,10 @@ import type {GetRowClassName} from '../../components/PaginatedTable'; -import type {NodesPreparedEntity} from '../../store/reducers/nodes/types'; +import type {PreparedStorageNode} from '../../store/reducers/storage/types'; import {cn} from '../../utils/cn'; import {isUnavailableNode} from '../../utils/nodes'; export const b = cn('ydb-nodes'); -export const getRowClassName: GetRowClassName = (row) => { +export const getRowClassName: GetRowClassName = (row) => { return b('node', {unavailable: isUnavailableNode(row)}); }; diff --git a/src/containers/Storage/PaginatedStorageNodesTable/PaginatedStorageNodesTable.tsx b/src/containers/Storage/PaginatedStorageNodesTable/PaginatedStorageNodesTable.tsx index 29e48fa1b6..13650bc36a 100644 --- a/src/containers/Storage/PaginatedStorageNodesTable/PaginatedStorageNodesTable.tsx +++ b/src/containers/Storage/PaginatedStorageNodesTable/PaginatedStorageNodesTable.tsx @@ -2,6 +2,7 @@ import React from 'react'; import type {PaginatedTableData, RenderErrorMessage} from '../../../components/PaginatedTable'; import {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'; import type {NodesGroupByField} from '../../../types/api/nodes'; @@ -10,7 +11,6 @@ import {NodesUptimeFilterValues, isUnavailableNode} from '../../../utils/nodes'; import {StorageNodesEmptyDataMessage} from './StorageNodesEmptyDataMessage'; import {STORAGE_NODES_COLUMNS_WIDTH_LS_KEY} from './columns/constants'; -import type {StorageNodesColumn} from './columns/types'; import {getStorageNodes} from './getNodes'; import i18n from './i18n'; @@ -22,7 +22,7 @@ const getRowUnavailableClassName = (row: PreparedStorageNode) => b('node', {unavailable: isUnavailableNode(row)}); interface PaginatedStorageNodesTableProps { - columns: StorageNodesColumn[]; + columns: NodesColumn[]; database?: string; nodeId?: string | number; diff --git a/src/containers/Storage/PaginatedStorageNodesTable/columns/columns.tsx b/src/containers/Storage/PaginatedStorageNodesTable/columns/columns.tsx index 12fef84e9d..58d9493f83 100644 --- a/src/containers/Storage/PaginatedStorageNodesTable/columns/columns.tsx +++ b/src/containers/Storage/PaginatedStorageNodesTable/columns/columns.tsx @@ -13,6 +13,7 @@ import { getPoolsColumn, getRAMColumn, getRackColumn, + getTabletsColumn, getUptimeColumn, getVersionColumn, } from '../../../../components/nodesColumns/columns'; @@ -21,26 +22,20 @@ import { NODES_COLUMNS_TITLES, isSortableNodesColumn, } from '../../../../components/nodesColumns/constants'; -import type {PreparedStorageNode} from '../../../../store/reducers/storage/types'; +import type {NodesColumn} from '../../../../components/nodesColumns/types'; import {cn} from '../../../../utils/cn'; import {PDisk} from '../../PDisk/PDisk'; -import type { - GetStorageNodesColumnsParams, - StorageNodesColumn, - StorageNodesColumnsSettings, -} from './types'; +import type {GetStorageNodesColumnsParams} from './types'; import './StorageNodesColumns.scss'; const b = cn('ydb-storage-nodes-columns'); -const getPDisksColumn = ({ +export const getPDisksColumn = ({ viewContext, columnsSettings, -}: GetStorageNodesColumnsParams & { - columnsSettings?: StorageNodesColumnsSettings; -}): StorageNodesColumn => { +}: GetStorageNodesColumnsParams): NodesColumn => { return { name: NODES_COLUMNS_IDS.PDisks, header: NODES_COLUMNS_TITLES.PDisks, @@ -79,25 +74,26 @@ export const getStorageNodesColumns = ({ additionalNodesProps, viewContext, columnsSettings, -}: GetStorageNodesColumnsParams): StorageNodesColumn[] => { +}: GetStorageNodesColumnsParams): NodesColumn[] => { const getNodeRef = additionalNodesProps?.getNodeRef; - const columns = [ - getNodeIdColumn(), - getHostColumn({getNodeRef, database}), - getNodeNameColumn(), - getDataCenterColumn(), - getPileNameColumn(), - getRackColumn(), - getUptimeColumn(), - getCpuColumn(), - getPoolsColumn(), - getRAMColumn(), - getMemoryColumn(), - getDiskSpaceUsageColumn(), - getVersionColumn(), - getMissingDisksColumn(), + const columns: NodesColumn[] = [ + getNodeIdColumn(), + getHostColumn({getNodeRef, database}), + getNodeNameColumn(), + getDataCenterColumn(), + getPileNameColumn(), + getRackColumn(), + getUptimeColumn(), + getCpuColumn(), + getPoolsColumn(), + getRAMColumn(), + getMemoryColumn(), + getDiskSpaceUsageColumn(), + getVersionColumn(), + getMissingDisksColumn(), getPDisksColumn({viewContext, columnsSettings}), + getTabletsColumn({database}), ]; const sortableColumns = columns.map((column) => ({ diff --git a/src/containers/Storage/PaginatedStorageNodesTable/columns/types.ts b/src/containers/Storage/PaginatedStorageNodesTable/columns/types.ts index 9e9053a2dc..3579d2359a 100644 --- a/src/containers/Storage/PaginatedStorageNodesTable/columns/types.ts +++ b/src/containers/Storage/PaginatedStorageNodesTable/columns/types.ts @@ -1,10 +1,7 @@ -import type {PreparedStorageNode, VisibleEntities} from '../../../../store/reducers/storage/types'; +import type {VisibleEntities} from '../../../../store/reducers/storage/types'; import type {AdditionalNodesProps} from '../../../../types/additionalProps'; -import type {Column} from '../../../../utils/tableUtils/types'; import type {StorageViewContext} from '../../types'; -export type StorageNodesColumn = Column; - export interface StorageNodesColumnsSettings { pDiskWidth?: number; pDiskContainerWidth?: number; diff --git a/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopNodesByCpu.tsx b/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopNodesByCpu.tsx index fd621c52e6..908b7a1705 100644 --- a/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopNodesByCpu.tsx +++ b/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopNodesByCpu.tsx @@ -1,5 +1,3 @@ -import type {Column} from '@gravity-ui/react-data-table'; - import {ResizeableDataTable} from '../../../../../components/ResizeableDataTable/ResizeableDataTable'; import { getHostColumn, @@ -10,9 +8,11 @@ import { NODES_COLUMNS_TO_DATA_FIELDS, NODES_COLUMNS_WIDTH_LS_KEY, } from '../../../../../components/nodesColumns/constants'; -import type {GetNodesColumnsParams} from '../../../../../components/nodesColumns/types'; +import type { + GetNodesColumnsParams, + NodesColumn, +} from '../../../../../components/nodesColumns/types'; import {nodesApi} from '../../../../../store/reducers/nodes/nodes'; -import type {NodesPreparedEntity} from '../../../../../store/reducers/nodes/types'; import type {AdditionalNodesProps} from '../../../../../types/additionalProps'; import type {NodesRequiredField} from '../../../../../types/api/nodes'; import { @@ -26,14 +26,13 @@ import i18n from '../i18n'; function getTopNodesByCpuColumns( params: GetNodesColumnsParams, -): [Column[], NodesRequiredField[]] { - const hostColumn = {...getHostColumn(params), width: undefined}; +): [NodesColumn[], NodesRequiredField[]] { + const hostColumn: NodesColumn = { + ...getHostColumn(params), + width: undefined, + }; - const columns = [ - getPoolsColumn(), - getNodeIdColumn(), - hostColumn, - ]; + const columns: NodesColumn[] = [getPoolsColumn(), getNodeIdColumn(), hostColumn]; const columnsIds = columns.map((column) => column.name); const dataFieldsRequired = getRequiredDataFields(columnsIds, NODES_COLUMNS_TO_DATA_FIELDS); @@ -67,7 +66,7 @@ export function TopNodesByCpu({database, additionalNodesProps}: TopNodesByCpuPro const loading = isFetching && currentData === undefined; - const topNodes = currentData?.Nodes || []; + const topNodes = currentData?.nodes || []; return ( diff --git a/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopNodesByLoad.tsx b/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopNodesByLoad.tsx index a59345c327..9aa8f2b378 100644 --- a/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopNodesByLoad.tsx +++ b/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopNodesByLoad.tsx @@ -1,5 +1,3 @@ -import type {Column} from '@gravity-ui/react-data-table'; - import {ResizeableDataTable} from '../../../../../components/ResizeableDataTable/ResizeableDataTable'; import { getHostColumn, @@ -11,9 +9,11 @@ import { NODES_COLUMNS_TO_DATA_FIELDS, NODES_COLUMNS_WIDTH_LS_KEY, } from '../../../../../components/nodesColumns/constants'; -import type {GetNodesColumnsParams} from '../../../../../components/nodesColumns/types'; +import type { + GetNodesColumnsParams, + NodesColumn, +} from '../../../../../components/nodesColumns/types'; import {nodesApi} from '../../../../../store/reducers/nodes/nodes'; -import type {NodesPreparedEntity} from '../../../../../store/reducers/nodes/types'; import type {AdditionalNodesProps} from '../../../../../types/additionalProps'; import type {NodesRequiredField} from '../../../../../types/api/nodes'; import { @@ -27,17 +27,17 @@ import i18n from '../i18n'; function getTopNodesByLoadColumns( params: GetNodesColumnsParams, -): [Column[], NodesRequiredField[]] { - const hostColumn = { - ...getHostColumn(params), +): [NodesColumn[], NodesRequiredField[]] { + const hostColumn: NodesColumn = { + ...getHostColumn(params), width: undefined, }; - const columns = [ - getLoadColumn(), - getNodeIdColumn(), + const columns: NodesColumn[] = [ + getLoadColumn(), + getNodeIdColumn(), hostColumn, - getVersionColumn(), + getVersionColumn(), ]; const columnsIds = columns.map((column) => column.name); @@ -72,7 +72,7 @@ export function TopNodesByLoad({database, additionalNodesProps}: TopNodesByLoadP const loading = isFetching && currentData === undefined; - const topNodes = currentData?.Nodes || []; + const topNodes = currentData?.nodes || []; return ( diff --git a/src/containers/Tenant/Diagnostics/TenantOverview/TenantMemory/TopNodesByMemory.tsx b/src/containers/Tenant/Diagnostics/TenantOverview/TenantMemory/TopNodesByMemory.tsx index 1f95e9b98c..6640fefae8 100644 --- a/src/containers/Tenant/Diagnostics/TenantOverview/TenantMemory/TopNodesByMemory.tsx +++ b/src/containers/Tenant/Diagnostics/TenantOverview/TenantMemory/TopNodesByMemory.tsx @@ -1,5 +1,3 @@ -import type {Column} from '@gravity-ui/react-data-table'; - import {ResizeableDataTable} from '../../../../../components/ResizeableDataTable/ResizeableDataTable'; import { getHostColumn, @@ -14,9 +12,11 @@ import { NODES_COLUMNS_TO_DATA_FIELDS, NODES_COLUMNS_WIDTH_LS_KEY, } from '../../../../../components/nodesColumns/constants'; -import type {GetNodesColumnsParams} from '../../../../../components/nodesColumns/types'; +import type { + GetNodesColumnsParams, + NodesColumn, +} from '../../../../../components/nodesColumns/types'; import {nodesApi} from '../../../../../store/reducers/nodes/nodes'; -import type {NodesPreparedEntity} from '../../../../../store/reducers/nodes/types'; import type {AdditionalNodesProps} from '../../../../../types/additionalProps'; import type {NodesRequiredField} from '../../../../../types/api/nodes'; import { @@ -30,15 +30,15 @@ import i18n from '../i18n'; function getTopNodesByMemoryColumns( params: GetNodesColumnsParams, -): [Column[], NodesRequiredField[]] { - const columns = [ - getNodeIdColumn(), - getHostColumn(params), - getUptimeColumn(), - getLoadColumn(), - getMemoryColumn(), - getSessionsColumn(), - getTabletsColumn(params), +): [NodesColumn[], NodesRequiredField[]] { + const columns: NodesColumn[] = [ + getNodeIdColumn(), + getHostColumn(params), + getUptimeColumn(), + getLoadColumn(), + getMemoryColumn(), + getSessionsColumn(), + getTabletsColumn(params), ]; const columnsIds = columns.map((column) => column.name); @@ -73,7 +73,7 @@ export function TopNodesByMemory({database, additionalNodesProps}: TopNodesByMem const loading = isFetching && currentData === undefined; - const topNodes = currentData?.Nodes || []; + const topNodes = currentData?.nodes || []; return ( diff --git a/src/containers/Tenant/Diagnostics/TenantOverview/TenantNetwork/TopNodesByPing.tsx b/src/containers/Tenant/Diagnostics/TenantOverview/TenantNetwork/TopNodesByPing.tsx index 5fd9739410..23543871f6 100644 --- a/src/containers/Tenant/Diagnostics/TenantOverview/TenantNetwork/TopNodesByPing.tsx +++ b/src/containers/Tenant/Diagnostics/TenantOverview/TenantNetwork/TopNodesByPing.tsx @@ -37,7 +37,7 @@ export function TopNodesByPing({database, additionalNodesProps}: TopNodesByPingP ); const loading = isFetching && currentData === undefined; - const topNodes = currentData?.Nodes || []; + const topNodes = currentData?.nodes || []; return ( diff --git a/src/containers/Tenant/Diagnostics/TenantOverview/TenantNetwork/TopNodesBySkew.tsx b/src/containers/Tenant/Diagnostics/TenantOverview/TenantNetwork/TopNodesBySkew.tsx index de8d0e14d2..f427c3bd4a 100644 --- a/src/containers/Tenant/Diagnostics/TenantOverview/TenantNetwork/TopNodesBySkew.tsx +++ b/src/containers/Tenant/Diagnostics/TenantOverview/TenantNetwork/TopNodesBySkew.tsx @@ -37,7 +37,7 @@ export function TopNodesBySkew({database, additionalNodesProps}: TopNodesBySkewP ); const loading = isFetching && currentData === undefined; - const topNodes = currentData?.Nodes || []; + const topNodes = currentData?.nodes || []; return ( diff --git a/src/containers/Tenant/Diagnostics/TenantOverview/TenantNetwork/columns.ts b/src/containers/Tenant/Diagnostics/TenantOverview/TenantNetwork/columns.ts index 6057d47145..155b26453c 100644 --- a/src/containers/Tenant/Diagnostics/TenantOverview/TenantNetwork/columns.ts +++ b/src/containers/Tenant/Diagnostics/TenantOverview/TenantNetwork/columns.ts @@ -6,13 +6,14 @@ import { getUptimeColumn, } from '../../../../../components/nodesColumns/columns'; import {NODES_COLUMNS_TO_DATA_FIELDS} from '../../../../../components/nodesColumns/constants'; -import type {GetNodesColumnsParams} from '../../../../../components/nodesColumns/types'; -import type {NodesPreparedEntity} from '../../../../../store/reducers/nodes/types'; +import type { + GetNodesColumnsParams, + NodesColumn, +} from '../../../../../components/nodesColumns/types'; import {getRequiredDataFields} from '../../../../../utils/tableUtils/getRequiredDataFields'; -import type {Column} from '../../../../../utils/tableUtils/types'; export function getTopNodesByPingColumns(params: GetNodesColumnsParams) { - const columns: Column[] = [ + const columns: NodesColumn[] = [ getNodeIdColumn(), getNetworkHostColumn(params), getUptimeColumn(), @@ -32,7 +33,7 @@ export function getTopNodesByPingColumns(params: GetNodesColumnsParams) { } export function getTopNodesBySkewColumns(params: GetNodesColumnsParams) { - const columns: Column[] = [ + const columns: NodesColumn[] = [ getNodeIdColumn(), getNetworkHostColumn(params), getUptimeColumn(), diff --git a/src/containers/Versions/GroupedNodesTree/GroupedNodesTree.tsx b/src/containers/Versions/GroupedNodesTree/GroupedNodesTree.tsx index cc76ebe172..73839f7e31 100644 --- a/src/containers/Versions/GroupedNodesTree/GroupedNodesTree.tsx +++ b/src/containers/Versions/GroupedNodesTree/GroupedNodesTree.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import type {NodesPreparedEntity} from '../../../store/reducers/nodes/types'; +import type {PreparedStorageNode} from '../../../store/reducers/storage/types'; import {cn} from '../../../utils/cn'; import type {PreparedVersion} from '../../../utils/versions/types'; import {NodesTable} from '../NodesTable/NodesTable'; @@ -15,7 +15,7 @@ const b = cn('ydb-versions-grouped-node-tree'); interface GroupedNodesTreeProps { title?: string; isDatabase?: boolean; - nodes?: NodesPreparedEntity[]; + nodes?: PreparedStorageNode[]; items?: GroupedNodesItem[]; expanded?: boolean; versionColor?: string; diff --git a/src/containers/Versions/NodesTable/NodesTable.tsx b/src/containers/Versions/NodesTable/NodesTable.tsx index 63718f3b34..e658f494a8 100644 --- a/src/containers/Versions/NodesTable/NodesTable.tsx +++ b/src/containers/Versions/NodesTable/NodesTable.tsx @@ -1,5 +1,3 @@ -import type {Column} from '@gravity-ui/react-data-table'; - import {ResizeableDataTable} from '../../../components/ResizeableDataTable/ResizeableDataTable'; import { getCpuColumn, @@ -11,28 +9,28 @@ import { getUptimeColumn, } from '../../../components/nodesColumns/columns'; import {NODES_COLUMNS_IDS} from '../../../components/nodesColumns/constants'; -import type {GetNodesColumnsParams} from '../../../components/nodesColumns/types'; +import type {GetNodesColumnsParams, NodesColumn} from '../../../components/nodesColumns/types'; import {useBridgeModeEnabled} from '../../../store/reducers/capabilities/hooks'; -import type {NodesPreparedEntity} from '../../../store/reducers/nodes/types'; +import type {PreparedStorageNode} from '../../../store/reducers/storage/types'; import {DEFAULT_TABLE_SETTINGS} from '../../../utils/constants'; import {useAdditionalNodesProps} from '../../../utils/hooks/useAdditionalNodesProps'; const VERSIONS_COLUMNS_WIDTH_LS_KEY = 'versionsTableColumnsWidth'; -function getColumns(params: GetNodesColumnsParams): Column[] { +function getColumns(params: GetNodesColumnsParams): NodesColumn[] { return [ - getNodeIdColumn(), - getHostColumn(params), - getPileNameColumn(), - getUptimeColumn(), - getRAMColumn(), - getCpuColumn(), - getLoadAverageColumn(), + getNodeIdColumn(), + getHostColumn(params), + getPileNameColumn(), + getUptimeColumn(), + getRAMColumn(), + getCpuColumn(), + getLoadAverageColumn(), ]; } interface NodesTableProps { - nodes: NodesPreparedEntity[]; + nodes: PreparedStorageNode[]; } export const NodesTable = ({nodes}: NodesTableProps) => { diff --git a/src/containers/Versions/Versions.tsx b/src/containers/Versions/Versions.tsx index f72460b015..6204de37a2 100644 --- a/src/containers/Versions/Versions.tsx +++ b/src/containers/Versions/Versions.tsx @@ -8,7 +8,7 @@ import {z} from 'zod'; import {LoaderWrapper} from '../../components/LoaderWrapper/LoaderWrapper'; import {VersionsBar} from '../../components/VersionsBar/VersionsBar'; import {nodesApi} from '../../store/reducers/nodes/nodes'; -import type {NodesPreparedEntity} from '../../store/reducers/nodes/types'; +import type {PreparedStorageNode} from '../../store/reducers/storage/types'; import type {TClusterInfo} from '../../types/api/cluster'; import {cn} from '../../utils/cn'; import {useAutoRefreshInterval} from '../../utils/hooks'; @@ -48,7 +48,7 @@ export function VersionsContainer({cluster, loading}: VersionsContainerProps) { @@ -56,7 +56,7 @@ export function VersionsContainer({cluster, loading}: VersionsContainerProps) { } interface VersionsProps { - nodes?: NodesPreparedEntity[]; + nodes?: PreparedStorageNode[]; preparedVersions: PreparedVersion[]; versionsDataMap?: VersionsDataMap; } diff --git a/src/containers/Versions/groupNodes.test.ts b/src/containers/Versions/groupNodes.test.ts index edd63d4e83..eb083cbc5e 100644 --- a/src/containers/Versions/groupNodes.test.ts +++ b/src/containers/Versions/groupNodes.test.ts @@ -1,10 +1,10 @@ -import type {NodesPreparedEntity} from '../../store/reducers/nodes/types'; +import type {PreparedStorageNode} from '../../store/reducers/storage/types'; import {getGroupedStorageNodes, getGroupedTenantNodes, getOtherNodes} from './groupNodes'; import {GroupByValue} from './types'; // Only needed for tests values are present -const nodes: NodesPreparedEntity[] = [ +const nodes: PreparedStorageNode[] = [ { // Storage node with many roles NodeId: 1, diff --git a/src/containers/Versions/groupNodes.ts b/src/containers/Versions/groupNodes.ts index 432583bf75..a2e9e9b9e1 100644 --- a/src/containers/Versions/groupNodes.ts +++ b/src/containers/Versions/groupNodes.ts @@ -1,6 +1,6 @@ import groupBy from 'lodash/groupBy'; -import type {NodesPreparedEntity} from '../../store/reducers/nodes/types'; +import type {PreparedStorageNode} from '../../store/reducers/storage/types'; import {getColorFromVersionsData, parseNodesToPreparedVersions} from '../../utils/versions'; import type {VersionsDataMap} from '../../utils/versions/types'; @@ -11,7 +11,7 @@ const sortByTitle = (a: GroupedNodesItem, b: GroupedNodesItem) => a.title?.localeCompare(b.title || '') || -1; export const getGroupedTenantNodes = ( - nodes: NodesPreparedEntity[] | undefined, + nodes: PreparedStorageNode[] | undefined, versionsDataMap: VersionsDataMap | undefined, groupByValue: GroupByValue, ): GroupedNodesItem[] | undefined => { @@ -85,7 +85,7 @@ export const getGroupedTenantNodes = ( }; export const getGroupedStorageNodes = ( - nodes: NodesPreparedEntity[] | undefined, + nodes: PreparedStorageNode[] | undefined, versionsDataMap: VersionsDataMap | undefined, ): GroupedNodesItem[] | undefined => { if (!nodes || !nodes.length) { @@ -105,7 +105,7 @@ export const getGroupedStorageNodes = ( }; export const getOtherNodes = ( - nodes: NodesPreparedEntity[] | undefined, + nodes: PreparedStorageNode[] | undefined, versionsDataMap: VersionsDataMap | undefined, ): GroupedNodesItem[] | undefined => { if (!nodes || !nodes.length) { @@ -127,10 +127,10 @@ export const getOtherNodes = ( }); }; -function isStorageNode(node: NodesPreparedEntity) { +function isStorageNode(node: PreparedStorageNode) { return Boolean(node.Roles?.includes('Storage')); } -function isTenantNode(node: NodesPreparedEntity) { +function isTenantNode(node: PreparedStorageNode) { return Boolean(node.Tenants); } diff --git a/src/containers/Versions/types.ts b/src/containers/Versions/types.ts index 4586776f5f..9305bfe44c 100644 --- a/src/containers/Versions/types.ts +++ b/src/containers/Versions/types.ts @@ -1,10 +1,10 @@ -import type {NodesPreparedEntity} from '../../store/reducers/nodes/types'; +import type {PreparedStorageNode} from '../../store/reducers/storage/types'; import type {PreparedVersion} from '../../utils/versions/types'; export interface GroupedNodesItem { title?: string; isDatabase?: boolean; - nodes?: NodesPreparedEntity[]; + nodes?: PreparedStorageNode[]; items?: GroupedNodesItem[]; versionColor?: string; preparedVersions?: PreparedVersion[]; diff --git a/src/containers/Versions/utils.ts b/src/containers/Versions/utils.ts index 11c8900d66..eda0902021 100644 --- a/src/containers/Versions/utils.ts +++ b/src/containers/Versions/utils.ts @@ -48,10 +48,10 @@ export function useGetPreparedVersions({ if (!currentData) { return []; } - if (Array.isArray(currentData.NodeGroups)) { - return parseNodeGroupsToPreparedVersions(currentData.NodeGroups, versionsDataMap); + if (Array.isArray(currentData.tableGroups)) { + return parseNodeGroupsToPreparedVersions(currentData.tableGroups, versionsDataMap); } - return parseNodesToPreparedVersions(currentData.Nodes, versionsDataMap); + return parseNodesToPreparedVersions(currentData.nodes, versionsDataMap); }, [currentData, versionsDataMap, cluster]); return preparedVersions; diff --git a/src/services/api/viewer.ts b/src/services/api/viewer.ts index 1826d51ee5..f7e8f72599 100644 --- a/src/services/api/viewer.ts +++ b/src/services/api/viewer.ts @@ -111,10 +111,13 @@ export class ViewerAPI extends BaseYdbAPI { fieldsRequired, filter, path, + storage, ...params }: NodesRequestParams, {concurrentId, signal}: AxiosOptions = {}, ) { + const isStorage = storage ?? fieldsRequired?.includes('PDisks'); + const preparedFieldsRequired = Array.isArray(fieldsRequired) ? this.prepareArrayRequestParam(fieldsRequired) : fieldsRequired; @@ -131,6 +134,7 @@ export class ViewerAPI extends BaseYdbAPI { database: database || tenant, fields_required: preparedFieldsRequired, path: this.getSchemaPath(path), + storage: isStorage, ...params, }, {concurrentId, requestConfig: {signal}}, diff --git a/src/store/reducers/nodes/nodes.ts b/src/store/reducers/nodes/nodes.ts index 16034cd62c..58023e0b63 100644 --- a/src/store/reducers/nodes/nodes.ts +++ b/src/store/reducers/nodes/nodes.ts @@ -1,7 +1,6 @@ import type {NodesRequestParams} from '../../../types/api/nodes'; import {api} from '../api'; - -import {prepareNodesData} from './utils'; +import {prepareStorageNodesResponse} from '../storage/utils'; export const nodesApi = api.injectEndpoints({ endpoints: (builder) => ({ @@ -17,7 +16,7 @@ export const nodesApi = api.injectEndpoints({ }, {signal}, ); - return {data: prepareNodesData(data)}; + return {data: prepareStorageNodesResponse(data)}; } catch (error) { return {error}; } diff --git a/src/store/reducers/nodes/types.ts b/src/store/reducers/nodes/types.ts index ece5888ee6..5ca4d071b4 100644 --- a/src/store/reducers/nodes/types.ts +++ b/src/store/reducers/nodes/types.ts @@ -1,53 +1,7 @@ -import type {EFlag} from '../../../types/api/enums'; -import type { - NodesGroupByField, - NodesPeerRole, - TEndpoint, - TPoolStats, -} from '../../../types/api/nodes'; -import type {TTabletStateInfo as TFullTabletStateInfo} from '../../../types/api/tablet'; -import type {NodesUptimeFilterValues, PreparedNodeSystemState} from '../../../utils/nodes'; +import type {NodesGroupByField, NodesPeerRole} from '../../../types/api/nodes'; +import type {NodesUptimeFilterValues} from '../../../utils/nodes'; import type {ProblemFilterValue} from '../settings/types'; -export interface NodesPreparedEntity extends PreparedNodeSystemState { - NodeId: number; - Host?: string; - NodeName?: string; - SystemState?: EFlag; - Version?: string; - // Bridge mode - PileName?: string; - - StartTime?: string; - DisconnectTime?: string; - - MemoryUsed?: string; - MemoryUsedInAlloc?: string; - MemoryLimit?: string; - - PoolStats?: TPoolStats[]; - LoadAverage?: number[]; - LoadAveragePercents?: number[]; - Tablets?: TFullTabletStateInfo[]; - Endpoints?: TEndpoint[]; - - TotalSessions?: number; - - Connections?: number; - ConnectStatus?: EFlag; - ReceiveThroughput?: string; - SendThroughput?: string; - NetworkUtilization?: number; - NetworkUtilizationMin?: number; - NetworkUtilizationMax?: number; - ClockSkewUs?: string; - ClockSkewMinUs?: string; - ClockSkewMaxUs?: string; - PingTimeUs?: string; - PingTimeMinUs?: string; - PingTimeMaxUs?: string; -} - export interface NodesFilters { searchValue: string; problemFilter: ProblemFilterValue; @@ -61,15 +15,3 @@ export interface NodesFilters { filterGroup?: string; filterGroupBy?: NodesGroupByField; } - -export interface NodesGroup { - name: string; - count: number; -} - -export interface NodesHandledResponse { - Nodes?: NodesPreparedEntity[]; - NodeGroups?: NodesGroup[]; - TotalNodes: number; - FoundNodes?: number; -} diff --git a/src/store/reducers/nodes/utils.ts b/src/store/reducers/nodes/utils.ts deleted file mode 100644 index 56c62aa51b..0000000000 --- a/src/store/reducers/nodes/utils.ts +++ /dev/null @@ -1,34 +0,0 @@ -import type {TNodesInfo} from '../../../types/api/nodes'; -import {prepareNodeSystemState} from '../../../utils/nodes'; - -import type {NodesGroup, NodesHandledResponse} from './types'; - -export const prepareNodesData = (data: TNodesInfo): NodesHandledResponse => { - const rawNodes = data.Nodes || []; - - const preparedNodes = rawNodes.map((node) => { - const {SystemState, ...restNodeParams} = node; - - return { - ...restNodeParams, - ...prepareNodeSystemState(SystemState), - }; - }); - - const preparedGroups = data.NodeGroups?.map(({GroupName, NodeCount}) => { - if (GroupName && NodeCount) { - return { - name: GroupName, - count: Number(NodeCount), - }; - } - return undefined; - }).filter((group): group is NodesGroup => Boolean(group)); - - return { - Nodes: preparedNodes, - NodeGroups: preparedGroups, - TotalNodes: Number(data.TotalNodes) || preparedNodes.length, - FoundNodes: Number(data.FoundNodes), - }; -}; diff --git a/src/store/reducers/storage/types.ts b/src/store/reducers/storage/types.ts index dcdd033e96..81b6d47344 100644 --- a/src/store/reducers/storage/types.ts +++ b/src/store/reducers/storage/types.ts @@ -1,8 +1,9 @@ import {z} from 'zod'; import type {EFlag} from '../../../types/api/enums'; -import type {NodesGroupByField} from '../../../types/api/nodes'; +import type {NodesGroupByField, TNodeInfo} from '../../../types/api/nodes'; import type {Erasure, GroupsGroupByField} from '../../../types/api/storage'; +import type {TTabletStateInfo} from '../../../types/api/tablet'; import type {PreparedPDisk, PreparedVDisk} from '../../../utils/disks/types'; import type {NodesUptimeFilterValues, PreparedNodeSystemState} from '../../../utils/nodes'; @@ -26,20 +27,18 @@ export interface PreparedStorageNodeFilters { filterGroupBy?: NodesGroupByField; } -export interface PreparedStorageNode extends PreparedNodeSystemState { +export interface PreparedStorageNode + extends PreparedNodeSystemState, + Omit { NodeId: number; - DiskSpaceUsage?: number; - PDisks?: PreparedPDisk[]; VDisks?: PreparedVDisk[]; + Tablets?: TTabletStateInfo[]; - Missing: number; - MaximumSlotsPerDisk: number; - MaximumDisksPerNode: number; - - // Bridge mode - PileName?: string; + Missing?: number; + MaximumSlotsPerDisk?: number; + MaximumDisksPerNode?: number; } export interface PreparedStorageGroupFilters { diff --git a/src/store/reducers/storage/utils.ts b/src/store/reducers/storage/utils.ts index 6cda694057..9118322df1 100644 --- a/src/store/reducers/storage/utils.ts +++ b/src/store/reducers/storage/utils.ts @@ -197,18 +197,20 @@ const prepareStorageNodeData = ( maximumSlotsPerDisk: number, maximumDisksPerNode: number, ): PreparedStorageNode => { + const {SystemState, NodeId, PDisks, VDisks, ...restNodeParams} = node; + const missing = - node.PDisks?.filter((pDisk) => { + PDisks?.filter((pDisk) => { return pDisk.State !== TPDiskState.Normal; }).length || 0; - const pDisks = node.PDisks?.map((pDisk) => { + const pDisks = PDisks?.map((pDisk) => { return { ...prepareWhiteboardPDiskData(pDisk), NodeId: node.NodeId, }; }); - const vDisks = node.VDisks?.map((vDisk) => { + const vDisks = VDisks?.map((vDisk) => { return { ...prepareWhiteboardVDiskData(vDisk), NodeId: node.NodeId, @@ -216,10 +218,9 @@ const prepareStorageNodeData = ( }); return { - ...prepareNodeSystemState(node.SystemState), - NodeId: node.NodeId, - DiskSpaceUsage: node.DiskSpaceUsage, - PileName: node.PileName, + ...restNodeParams, + ...prepareNodeSystemState(SystemState), + NodeId: NodeId, PDisks: pDisks, VDisks: vDisks, Missing: missing, diff --git a/src/utils/versions/parseNodesToVersionsValues.ts b/src/utils/versions/parseNodesToVersionsValues.ts index d172509962..9c6267b19e 100644 --- a/src/utils/versions/parseNodesToVersionsValues.ts +++ b/src/utils/versions/parseNodesToVersionsValues.ts @@ -1,4 +1,4 @@ -import type {NodesGroup} from '../../store/reducers/nodes/types'; +import type {TableGroup} from '../../store/reducers/storage/types'; import type {TSystemStateInfo} from '../../types/api/nodes'; import {getMinorVersion} from './parseVersion'; @@ -36,7 +36,7 @@ export const parseNodesToPreparedVersions = ( }; export function parseNodeGroupsToPreparedVersions( - groups: NodesGroup[], + groups: TableGroup[], versionsDataMap?: VersionsDataMap, ): PreparedVersion[] { const preparedVersions = groups.map((group) => { From b3d38aeff9f1f42d8f2b1d2ada30a7b02c48bf9a Mon Sep 17 00:00:00 2001 From: mufazalov Date: Thu, 25 Sep 2025 12:50:39 +0300 Subject: [PATCH 2/3] fix: copilot review --- src/containers/Versions/groupNodes.test.ts | 24 ++++++++++++++++++++++ src/store/reducers/storage/types.ts | 6 +++--- src/store/reducers/storage/utils.ts | 6 +++--- 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/containers/Versions/groupNodes.test.ts b/src/containers/Versions/groupNodes.test.ts index eb083cbc5e..4fa7689658 100644 --- a/src/containers/Versions/groupNodes.test.ts +++ b/src/containers/Versions/groupNodes.test.ts @@ -10,18 +10,27 @@ const nodes: PreparedStorageNode[] = [ NodeId: 1, Version: '25-1-1', Roles: ['StateStorageBoard', 'SchemeBoard', 'Bootstrapper', 'StateStorage', 'Storage'], + Missing: 0, + MaximumSlotsPerDisk: 0, + MaximumDisksPerNode: 0, }, { // Storage node NodeId: 2, Version: '25-1-2', Roles: ['Storage'], + Missing: 0, + MaximumSlotsPerDisk: 0, + MaximumDisksPerNode: 0, }, { // Storage node NodeId: 3, Version: '25-1-3', Roles: ['Storage'], + Missing: 0, + MaximumSlotsPerDisk: 0, + MaximumDisksPerNode: 0, }, { // Tenant node @@ -29,6 +38,9 @@ const nodes: PreparedStorageNode[] = [ Version: '25-1-1', Roles: ['Tenant'], Tenants: ['/Root/db1'], + Missing: 0, + MaximumSlotsPerDisk: 0, + MaximumDisksPerNode: 0, }, { // Tenant node @@ -36,24 +48,36 @@ const nodes: PreparedStorageNode[] = [ Version: '25-1-2', Roles: ['Tenant'], Tenants: ['/Root/db2'], + Missing: 0, + MaximumSlotsPerDisk: 0, + MaximumDisksPerNode: 0, }, { // Tenant node without Roles NodeId: 6, Version: '25-1-3', Tenants: ['/Root/db3'], + Missing: 0, + MaximumSlotsPerDisk: 0, + MaximumDisksPerNode: 0, }, { // Node with some other role NodeId: 7, Version: '25-1-1', Roles: ['Bootstrapper'], + Missing: 0, + MaximumSlotsPerDisk: 0, + MaximumDisksPerNode: 0, }, { // Node without roles NodeId: 8, Version: '25-1-1', Roles: [], + Missing: 0, + MaximumSlotsPerDisk: 0, + MaximumDisksPerNode: 0, }, ]; diff --git a/src/store/reducers/storage/types.ts b/src/store/reducers/storage/types.ts index 81b6d47344..b41db84b6d 100644 --- a/src/store/reducers/storage/types.ts +++ b/src/store/reducers/storage/types.ts @@ -36,9 +36,9 @@ export interface PreparedStorageNode VDisks?: PreparedVDisk[]; Tablets?: TTabletStateInfo[]; - Missing?: number; - MaximumSlotsPerDisk?: number; - MaximumDisksPerNode?: number; + Missing: number; + MaximumSlotsPerDisk: number; + MaximumDisksPerNode: number; } export interface PreparedStorageGroupFilters { diff --git a/src/store/reducers/storage/utils.ts b/src/store/reducers/storage/utils.ts index 9118322df1..5624dfb02b 100644 --- a/src/store/reducers/storage/utils.ts +++ b/src/store/reducers/storage/utils.ts @@ -207,20 +207,20 @@ const prepareStorageNodeData = ( const pDisks = PDisks?.map((pDisk) => { return { ...prepareWhiteboardPDiskData(pDisk), - NodeId: node.NodeId, + NodeId, }; }); const vDisks = VDisks?.map((vDisk) => { return { ...prepareWhiteboardVDiskData(vDisk), - NodeId: node.NodeId, + NodeId, }; }); return { ...restNodeParams, ...prepareNodeSystemState(SystemState), - NodeId: NodeId, + NodeId, PDisks: pDisks, VDisks: vDisks, Missing: missing, From 54c1e6dce14dcb5dd1c4ef8b77a6d81a1c21ce48 Mon Sep 17 00:00:00 2001 From: mufazalov Date: Thu, 25 Sep 2025 13:29:44 +0300 Subject: [PATCH 3/3] chore: add comment --- src/services/api/viewer.ts | 2 ++ src/store/reducers/storage/utils.ts | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/services/api/viewer.ts b/src/services/api/viewer.ts index f7e8f72599..f47efa27bd 100644 --- a/src/services/api/viewer.ts +++ b/src/services/api/viewer.ts @@ -116,6 +116,8 @@ export class ViewerAPI extends BaseYdbAPI { }: NodesRequestParams, {concurrentId, signal}: AxiosOptions = {}, ) { + // This param determines whether we need VDisks to be returned + // We need them only together with PDisks const isStorage = storage ?? fieldsRequired?.includes('PDisks'); const preparedFieldsRequired = Array.isArray(fieldsRequired) diff --git a/src/store/reducers/storage/utils.ts b/src/store/reducers/storage/utils.ts index 5624dfb02b..339f95e832 100644 --- a/src/store/reducers/storage/utils.ts +++ b/src/store/reducers/storage/utils.ts @@ -220,6 +220,8 @@ const prepareStorageNodeData = ( return { ...restNodeParams, ...prepareNodeSystemState(SystemState), + // There is NodeId both in node and its system state + // We should use only NodeId from node, since it's always present (there may be no SystemState) NodeId, PDisks: pDisks, VDisks: vDisks,