diff --git a/src/components/PaginatedTable/PaginatedTable.tsx b/src/components/PaginatedTable/PaginatedTable.tsx index 04395ab6e..263ce586e 100644 --- a/src/components/PaginatedTable/PaginatedTable.tsx +++ b/src/components/PaginatedTable/PaginatedTable.tsx @@ -11,6 +11,7 @@ import type { FetchData, GetRowClassName, HandleTableColumnsResize, + PaginatedTableData, RenderControls, RenderEmptyDataMessage, RenderErrorMessage, @@ -36,6 +37,7 @@ export interface PaginatedTableProps { renderEmptyDataMessage?: RenderEmptyDataMessage; renderErrorMessage?: RenderErrorMessage; containerClassName?: string; + onDataFetched?: (data: PaginatedTableData) => void; } const DEFAULT_PAGINATION_LIMIT = 20; @@ -56,6 +58,7 @@ export const PaginatedTable = ({ renderErrorMessage, renderEmptyDataMessage, containerClassName, + onDataFetched, }: PaginatedTableProps) => { const initialTotal = initialEntitiesCount || 0; const initialFound = initialEntitiesCount || 1; @@ -84,11 +87,17 @@ export const PaginatedTable = ({ return foundEntities % chunkSize || chunkSize; }, [foundEntities, chunkSize]); - const handleDataFetched = React.useCallback((total: number, found: number) => { - setTotalEntities(total); - setFoundEntities(found); - setIsInitialLoad(false); - }, []); + const handleDataFetched = React.useCallback( + (data?: PaginatedTableData) => { + if (data) { + setTotalEntities(data.total); + setFoundEntities(data.found); + setIsInitialLoad(false); + onDataFetched?.(data); + } + }, + [onDataFetched], + ); // reset table on filters change React.useLayoutEffect(() => { diff --git a/src/components/PaginatedTable/TableChunk.tsx b/src/components/PaginatedTable/TableChunk.tsx index 56620bc20..df01ee4d4 100644 --- a/src/components/PaginatedTable/TableChunk.tsx +++ b/src/components/PaginatedTable/TableChunk.tsx @@ -12,6 +12,7 @@ import type { Column, FetchData, GetRowClassName, + PaginatedTableData, RenderEmptyDataMessage, RenderErrorMessage, SortParams, @@ -35,7 +36,7 @@ interface TableChunkProps { getRowClassName?: GetRowClassName; renderErrorMessage?: RenderErrorMessage; renderEmptyDataMessage?: RenderEmptyDataMessage; - onDataFetched: (total: number, found: number) => void; + onDataFetched: (data?: PaginatedTableData) => void; } // Memoisation prevents chunks rerenders that could cause perfomance issues on big tables @@ -93,8 +94,12 @@ export const TableChunk = typedMemo(function TableChunk({ React.useEffect(() => { if (currentData && isActive) { - const {total = 0, found = 0} = currentData; - onDataFetched(total, found); + onDataFetched({ + ...currentData, + data: currentData.data as T[], + found: currentData.found || 0, + total: currentData.total || 0, + }); } }, [currentData, isActive, onDataFetched]); diff --git a/src/components/nodesColumns/columns.tsx b/src/components/nodesColumns/columns.tsx index afe910147..5e8b92829 100644 --- a/src/components/nodesColumns/columns.tsx +++ b/src/components/nodesColumns/columns.tsx @@ -370,6 +370,7 @@ export function getMissingDisksColumn(): Column render: ({row}) => row.Missing, align: DataTable.CENTER, defaultOrder: DataTable.DESCENDING, + width: 100, }; } diff --git a/src/containers/Storage/PDisk/PDisk.scss b/src/containers/Storage/PDisk/PDisk.scss index d615a278f..1e4560563 100644 --- a/src/containers/Storage/PDisk/PDisk.scss +++ b/src/containers/Storage/PDisk/PDisk.scss @@ -1,11 +1,15 @@ +@import '../../../styles/mixins.scss'; + .pdisk-storage { + --pdisk-vdisk-width: 3px; + --pdisk-gap-width: 2px; + position: relative; display: flex; flex-direction: column; justify-content: flex-end; - width: var(--pdisk-width); min-width: var(--pdisk-min-width); &__content { diff --git a/src/containers/Storage/PDisk/PDisk.tsx b/src/containers/Storage/PDisk/PDisk.tsx index 1c09dbe9c..d4e9d9203 100644 --- a/src/containers/Storage/PDisk/PDisk.tsx +++ b/src/containers/Storage/PDisk/PDisk.tsx @@ -25,6 +25,7 @@ interface PDiskProps { className?: string; progressBarClassName?: string; viewContext?: StorageViewContext; + width?: number; } export const PDisk = ({ @@ -36,6 +37,7 @@ export const PDisk = ({ className, progressBarClassName, viewContext, + width, }: PDiskProps) => { const {NodeId, PDiskId} = data; const pDiskIdsDefined = valueIsDefined(NodeId) && valueIsDefined(PDiskId); @@ -79,7 +81,7 @@ export const PDisk = ({ } return ( -
+
{renderVDisks()} { @@ -101,6 +107,7 @@ function StorageNodesComponent({ renderErrorMessage={renderPaginatedTableErrorMessage} columns={columnsToShow} initialEntitiesCount={initialEntitiesCount} + onDataFetched={handleDataFetched} /> ); } @@ -116,7 +123,7 @@ function GroupedStorageNodesComponent({ const {searchValue, storageNodesGroupByParam, handleShowAllNodes} = useStorageQueryParams(); - const {columnsToShow, columnsToSelect, setColumns} = useStorageNodesColumnsToSelect({ + const {columnsToSelect, setColumns} = useStorageNodesColumnsToSelect({ database, viewContext, }); @@ -168,19 +175,15 @@ function GroupedStorageNodesComponent({ expanded={isExpanded} onIsExpandedChange={setIsGroupExpanded} > - @@ -206,12 +209,66 @@ function GroupedStorageNodesComponent({ ); } +interface StorageNodesTableGroupContentProps { + database?: string; + parentRef: React.RefObject; + nodeId?: string | number; + groupId?: string | number; + searchValue: string; + handleShowAllNodes: VoidFunction; + filterGroup: string; + filterGroupBy?: NodesGroupByField; + viewContext?: StorageViewContext; + initialEntitiesCount: number; +} + +function StorageNodesTableGroupContent({ + database, + parentRef, + nodeId, + groupId, + searchValue, + handleShowAllNodes, + filterGroup, + filterGroupBy, + viewContext, + initialEntitiesCount, +}: StorageNodesTableGroupContentProps) { + const {handleDataFetched, columnsSettings} = useStorageColumnsSettings(); + const {columnsToShow} = useStorageNodesColumnsToSelect({ + database, + viewContext, + columnsSettings, + }); + + return ( + + ); +} + function useStorageNodesColumnsToSelect({ database, viewContext, + columnsSettings, }: { database?: string; viewContext?: StorageViewContext; + columnsSettings?: StorageNodesColumnsSettings; }) { const additionalNodesProps = useAdditionalNodesProps(); const {visibleEntities} = useStorageQueryParams(); @@ -221,5 +278,6 @@ function useStorageNodesColumnsToSelect({ visibleEntities, database, viewContext, + columnsSettings, }); } diff --git a/src/containers/Storage/StorageNodes/PaginatedStorageNodesTable.tsx b/src/containers/Storage/StorageNodes/PaginatedStorageNodesTable.tsx index 2b1d7b3c5..248b2f108 100644 --- a/src/containers/Storage/StorageNodes/PaginatedStorageNodesTable.tsx +++ b/src/containers/Storage/StorageNodes/PaginatedStorageNodesTable.tsx @@ -1,6 +1,10 @@ import React from 'react'; -import type {RenderControls, RenderErrorMessage} from '../../../components/PaginatedTable'; +import type { + PaginatedTableData, + RenderControls, + RenderErrorMessage, +} from '../../../components/PaginatedTable'; import {ResizeablePaginatedTable} from '../../../components/PaginatedTable'; import {VISIBLE_ENTITIES} from '../../../store/reducers/storage/constants'; import type {PreparedStorageNode, VisibleEntities} from '../../../store/reducers/storage/types'; @@ -40,6 +44,7 @@ interface PaginatedStorageNodesTableProps { renderControls?: RenderControls; renderErrorMessage: RenderErrorMessage; initialEntitiesCount?: number; + onDataFetched?: (data: PaginatedTableData) => void; } export const PaginatedStorageNodesTable = ({ @@ -57,6 +62,7 @@ export const PaginatedStorageNodesTable = ({ renderControls, renderErrorMessage, initialEntitiesCount, + onDataFetched, }: PaginatedStorageNodesTableProps) => { const tableFilters = React.useMemo(() => { return { @@ -111,6 +117,7 @@ export const PaginatedStorageNodesTable = ({ getRowClassName={getRowUnavailableClassName} filters={tableFilters} tableName="storage-nodes" + onDataFetched={onDataFetched} /> ); }; diff --git a/src/containers/Storage/StorageNodes/columns/StorageNodesColumns.scss b/src/containers/Storage/StorageNodes/columns/StorageNodesColumns.scss index 1ff35f2e2..16e429a71 100644 --- a/src/containers/Storage/StorageNodes/columns/StorageNodesColumns.scss +++ b/src/containers/Storage/StorageNodes/columns/StorageNodesColumns.scss @@ -7,12 +7,9 @@ &__pdisks-wrapper { display: flex; - gap: var(--pdisk-margin); + gap: 10px; - width: var(--pdisks-container-width); height: 40px; - - @include calculate-storage-nodes-pdisk-variables(); } &__pdisks-item { diff --git a/src/containers/Storage/StorageNodes/columns/columns.tsx b/src/containers/Storage/StorageNodes/columns/columns.tsx index 6200092e3..4aa9624e3 100644 --- a/src/containers/Storage/StorageNodes/columns/columns.tsx +++ b/src/containers/Storage/StorageNodes/columns/columns.tsx @@ -24,28 +24,30 @@ import type {PreparedStorageNode} from '../../../../store/reducers/storage/types import {cn} from '../../../../utils/cn'; import {PDisk} from '../../PDisk/PDisk'; -import type {GetStorageNodesColumnsParams, StorageNodesColumn} from './types'; +import type { + GetStorageNodesColumnsParams, + StorageNodesColumn, + StorageNodesColumnsSettings, +} from './types'; import './StorageNodesColumns.scss'; const b = cn('ydb-storage-nodes-columns'); -const MAX_SLOTS_CSS_VAR = '--maximum-slots'; -const MAX_DISKS_CSS_VAR = '--maximum-disks'; - -const getPDisksColumn = ({viewContext}: GetStorageNodesColumnsParams): StorageNodesColumn => { +const getPDisksColumn = ({ + viewContext, + columnsSettings, +}: GetStorageNodesColumnsParams & { + columnsSettings?: StorageNodesColumnsSettings; +}): StorageNodesColumn => { return { name: NODES_COLUMNS_IDS.PDisks, header: NODES_COLUMNS_TITLES.PDisks, className: b('pdisks-column'), + width: columnsSettings?.pDiskContainerWidth, render: ({row}) => { - const pDiskStyles = { - [MAX_SLOTS_CSS_VAR]: row.MaximumSlotsPerDisk, - [MAX_DISKS_CSS_VAR]: row.MaximumDisksPerNode, - } as React.CSSProperties; - return ( -
+
{row.PDisks?.map((pDisk) => { const vDisks = row.VDisks?.filter( (vdisk) => vdisk.PDiskId === pDisk.PDiskId, @@ -53,7 +55,12 @@ const getPDisksColumn = ({viewContext}: GetStorageNodesColumnsParams): StorageNo return (
- +
); })} @@ -70,6 +77,7 @@ export const getStorageNodesColumns = ({ database, additionalNodesProps, viewContext, + columnsSettings, }: GetStorageNodesColumnsParams): StorageNodesColumn[] => { const getNodeRef = additionalNodesProps?.getNodeRef; @@ -87,7 +95,7 @@ export const getStorageNodesColumns = ({ getDiskSpaceUsageColumn(), getVersionColumn(), getMissingDisksColumn(), - getPDisksColumn({viewContext}), + getPDisksColumn({viewContext, columnsSettings}), ]; const sortableColumns = columns.map((column) => ({ diff --git a/src/containers/Storage/StorageNodes/columns/hooks.ts b/src/containers/Storage/StorageNodes/columns/hooks.ts index 9f05a4aa3..0f33c2b57 100644 --- a/src/containers/Storage/StorageNodes/columns/hooks.ts +++ b/src/containers/Storage/StorageNodes/columns/hooks.ts @@ -20,10 +20,16 @@ export function useStorageNodesSelectedColumns({ database, additionalNodesProps, viewContext, + columnsSettings, }: GetStorageNodesColumnsParams) { const columns = React.useMemo(() => { - return getStorageNodesColumns({database, additionalNodesProps, viewContext}); - }, [database, additionalNodesProps, viewContext]); + return getStorageNodesColumns({ + database, + additionalNodesProps, + viewContext, + columnsSettings, + }); + }, [database, additionalNodesProps, viewContext, columnsSettings]); const requiredColumns = React.useMemo(() => { if (visibleEntities === VISIBLE_ENTITIES.missing) { diff --git a/src/containers/Storage/StorageNodes/columns/types.ts b/src/containers/Storage/StorageNodes/columns/types.ts index e144c5957..9e9053a2d 100644 --- a/src/containers/Storage/StorageNodes/columns/types.ts +++ b/src/containers/Storage/StorageNodes/columns/types.ts @@ -5,9 +5,15 @@ import type {StorageViewContext} from '../../types'; export type StorageNodesColumn = Column; +export interface StorageNodesColumnsSettings { + pDiskWidth?: number; + pDiskContainerWidth?: number; +} + export interface GetStorageNodesColumnsParams { additionalNodesProps?: AdditionalNodesProps | undefined; visibleEntities?: VisibleEntities; database?: string; viewContext?: StorageViewContext; + columnsSettings?: StorageNodesColumnsSettings; } diff --git a/src/containers/Storage/StorageNodes/getNodes.ts b/src/containers/Storage/StorageNodes/getNodes.ts index be9a0714e..c8cc7d7f5 100644 --- a/src/containers/Storage/StorageNodes/getNodes.ts +++ b/src/containers/Storage/StorageNodes/getNodes.ts @@ -65,5 +65,6 @@ export const getStorageNodes: FetchData< data: preparedResponse.nodes || [], found: preparedResponse.found || 0, total: preparedResponse.total || 0, + columnsSettings: preparedResponse.columnsSettings, }; }; diff --git a/src/containers/Storage/types.ts b/src/containers/Storage/types.ts index 9e9942c40..8199d4021 100644 --- a/src/containers/Storage/types.ts +++ b/src/containers/Storage/types.ts @@ -1,6 +1,16 @@ +import type {PaginatedTableData} from '../../components/PaginatedTable'; +import type {PreparedStorageNode} from '../../store/reducers/storage/types'; + export type StorageViewContext = { groupId?: string; nodeId?: string; pDiskId?: string; vDiskSlotId?: string; }; + +export type StorageNodesPaginatedTableData = PaginatedTableData & { + columnsSettings?: { + maxSlotsPerDisk: number; + maxDisksPerNode: number; + }; +}; diff --git a/src/containers/Storage/utils/index.ts b/src/containers/Storage/utils/index.ts index 331e86475..45b4c5170 100644 --- a/src/containers/Storage/utils/index.ts +++ b/src/containers/Storage/utils/index.ts @@ -114,3 +114,5 @@ export function useVDisksWithDCMargins(vDisks: PreparedVDisk[] = [], erasure?: E return disksWithMargins; }, [erasure, vDisks, nodesMap]); } + +export {useStorageColumnsSettings} from './useStorageColumnsSettings'; diff --git a/src/containers/Storage/utils/useStorageColumnsSettings.ts b/src/containers/Storage/utils/useStorageColumnsSettings.ts new file mode 100644 index 000000000..f5f31ac74 --- /dev/null +++ b/src/containers/Storage/utils/useStorageColumnsSettings.ts @@ -0,0 +1,51 @@ +import React from 'react'; + +import type {StorageNodesColumnsSettings} from '../StorageNodes/columns/types'; +import type {StorageNodesPaginatedTableData} from '../types'; + +const PDISK_VDISK_WIDTH = 3; +const PDISK_GAP_WIDTH = 2; +const PDISK_MIN_WIDTH = 120; +const PDISK_MARGIN = 10; +const MAX_SLOTS_DEFAULT = 1; +const PAGNATED_TABLE_CELL_HORIZONTAL_PADDING = 10; + +export function useStorageColumnsSettings() { + const [pDiskWidth, setPDiskWidth] = React.useState(undefined); + const [pDiskContainerWidth, setPDiskContainerWidth] = React.useState( + undefined, + ); + + const handleDataFetched = React.useCallback( + (data: StorageNodesPaginatedTableData) => { + if (data?.columnsSettings && !pDiskWidth) { + const {maxSlotsPerDisk, maxDisksPerNode} = data.columnsSettings; + const maxSlots = maxSlotsPerDisk || MAX_SLOTS_DEFAULT; + const maxDisks = maxDisksPerNode || MAX_SLOTS_DEFAULT; + + const calculatedPDiskWidth = + maxSlots * PDISK_VDISK_WIDTH + (maxSlots - 1) * PDISK_GAP_WIDTH; + const calculatedPDiskContainerWidth = + maxDisks * calculatedPDiskWidth + + (maxDisks - 1) * PDISK_MARGIN + + 2 * PAGNATED_TABLE_CELL_HORIZONTAL_PADDING; + + setPDiskWidth(calculatedPDiskWidth); + setPDiskContainerWidth(calculatedPDiskContainerWidth); + } + }, + [pDiskWidth], + ); + + const columnsSettings: StorageNodesColumnsSettings = React.useMemo(() => { + return { + pDiskWidth: pDiskWidth || PDISK_MIN_WIDTH, + pDiskContainerWidth: pDiskContainerWidth, + }; + }, [pDiskContainerWidth, pDiskWidth]); + + return { + handleDataFetched, + columnsSettings, + }; +} diff --git a/src/store/reducers/storage/__tests__/calculateMaximumDisksPerNode.test.ts b/src/store/reducers/storage/__tests__/calculateMaximumDisksPerNode.test.ts index 5e20367ee..a2da9ab55 100644 --- a/src/store/reducers/storage/__tests__/calculateMaximumDisksPerNode.test.ts +++ b/src/store/reducers/storage/__tests__/calculateMaximumDisksPerNode.test.ts @@ -7,17 +7,17 @@ describe('calculateMaximumDisksPerNode', () => { const nodes: TNodeInfo[] = []; const providedMaximumDisksPerNode = '5'; - expect(calculateMaximumDisksPerNode(nodes, providedMaximumDisksPerNode)).toBe('5'); + expect(calculateMaximumDisksPerNode(nodes, providedMaximumDisksPerNode)).toBe(5); }); test('should return "1" for empty nodes array', () => { const nodes: TNodeInfo[] = []; - expect(calculateMaximumDisksPerNode(nodes)).toBe('1'); + expect(calculateMaximumDisksPerNode(nodes)).toBe(1); }); test('should return "1" for undefined nodes', () => { - expect(calculateMaximumDisksPerNode(undefined)).toBe('1'); + expect(calculateMaximumDisksPerNode(undefined)).toBe(1); }); test('should return "1" for nodes without PDisks', () => { @@ -28,7 +28,7 @@ describe('calculateMaximumDisksPerNode', () => { }, ]; - expect(calculateMaximumDisksPerNode(nodes)).toBe('1'); + expect(calculateMaximumDisksPerNode(nodes)).toBe(1); }); test('should calculate maximum disks correctly for single node with multiple PDisks', () => { @@ -53,7 +53,7 @@ describe('calculateMaximumDisksPerNode', () => { }, ]; - expect(calculateMaximumDisksPerNode(nodes)).toBe('3'); + expect(calculateMaximumDisksPerNode(nodes)).toBe(3); }); test('should calculate maximum disks across multiple nodes', () => { @@ -106,7 +106,7 @@ describe('calculateMaximumDisksPerNode', () => { }, ]; - expect(calculateMaximumDisksPerNode(nodes)).toBe('4'); + expect(calculateMaximumDisksPerNode(nodes)).toBe(4); }); test('should handle nodes with empty PDisks array', () => { @@ -132,6 +132,6 @@ describe('calculateMaximumDisksPerNode', () => { }, ]; - expect(calculateMaximumDisksPerNode(nodes)).toBe('2'); + expect(calculateMaximumDisksPerNode(nodes)).toBe(2); }); }); diff --git a/src/store/reducers/storage/__tests__/calculateMaximumSlotsPerDisk.test.ts b/src/store/reducers/storage/__tests__/calculateMaximumSlotsPerDisk.test.ts index cfb256a03..772c7da2e 100644 --- a/src/store/reducers/storage/__tests__/calculateMaximumSlotsPerDisk.test.ts +++ b/src/store/reducers/storage/__tests__/calculateMaximumSlotsPerDisk.test.ts @@ -17,17 +17,17 @@ describe('calculateMaximumSlotsPerDisk', () => { const nodes: TNodeInfo[] = []; const providedMaximumSlotsPerDisk = '5'; - expect(calculateMaximumSlotsPerDisk(nodes, providedMaximumSlotsPerDisk)).toBe('5'); + expect(calculateMaximumSlotsPerDisk(nodes, providedMaximumSlotsPerDisk)).toBe(5); }); test('should return "1" for empty nodes array', () => { const nodes: TNodeInfo[] = []; - expect(calculateMaximumSlotsPerDisk(nodes)).toBe('1'); + expect(calculateMaximumSlotsPerDisk(nodes)).toBe(1); }); test('should return "1" for undefined nodes', () => { - expect(calculateMaximumSlotsPerDisk(undefined)).toBe('1'); + expect(calculateMaximumSlotsPerDisk(undefined)).toBe(1); }); test('should return "1" for nodes without PDisks or VDisks', () => { @@ -38,7 +38,7 @@ describe('calculateMaximumSlotsPerDisk', () => { }, ]; - expect(calculateMaximumSlotsPerDisk(nodes)).toBe('1'); + expect(calculateMaximumSlotsPerDisk(nodes)).toBe(1); }); test('should calculate maximum slots correctly for single node with one PDisk and multiple VDisks', () => { @@ -67,7 +67,7 @@ describe('calculateMaximumSlotsPerDisk', () => { }, ]; - expect(calculateMaximumSlotsPerDisk(nodes)).toBe('2'); + expect(calculateMaximumSlotsPerDisk(nodes)).toBe(2); }); test('should calculate maximum slots across multiple nodes', () => { @@ -118,7 +118,7 @@ describe('calculateMaximumSlotsPerDisk', () => { }, ]; - expect(calculateMaximumSlotsPerDisk(nodes)).toBe('3'); + expect(calculateMaximumSlotsPerDisk(nodes)).toBe(3); }); test('should handle nodes with multiple PDisks', () => { @@ -156,7 +156,7 @@ describe('calculateMaximumSlotsPerDisk', () => { }, ]; - expect(calculateMaximumSlotsPerDisk(nodes)).toBe('2'); + expect(calculateMaximumSlotsPerDisk(nodes)).toBe(2); }); test('should ignore VDisks with non-matching PDiskId', () => { @@ -185,6 +185,6 @@ describe('calculateMaximumSlotsPerDisk', () => { }, ]; - expect(calculateMaximumSlotsPerDisk(nodes)).toBe('1'); + expect(calculateMaximumSlotsPerDisk(nodes)).toBe(1); }); }); diff --git a/src/store/reducers/storage/types.ts b/src/store/reducers/storage/types.ts index 28522207c..1103b85b2 100644 --- a/src/store/reducers/storage/types.ts +++ b/src/store/reducers/storage/types.ts @@ -35,8 +35,8 @@ export interface PreparedStorageNode extends PreparedNodeSystemState { VDisks?: PreparedVDisk[]; Missing: number; - MaximumSlotsPerDisk: string; - MaximumDisksPerNode: string; + MaximumSlotsPerDisk: number; + MaximumDisksPerNode: number; } export interface PreparedStorageGroupFilters { @@ -107,4 +107,8 @@ export interface PreparedStorageResponse { found: number | undefined; total: number | undefined; tableGroups?: TableGroup[]; + columnsSettings?: { + maxSlotsPerDisk: number; + maxDisksPerNode: number; + }; } diff --git a/src/store/reducers/storage/utils.ts b/src/store/reducers/storage/utils.ts index 78dfc4ac9..c80272541 100644 --- a/src/store/reducers/storage/utils.ts +++ b/src/store/reducers/storage/utils.ts @@ -194,8 +194,8 @@ const prepareStorageGroups = ( const prepareStorageNodeData = ( node: TNodeInfo, - maximumSlotsPerDisk: string, - maximumDisksPerNode: string, + maximumSlotsPerDisk: number, + maximumDisksPerNode: number, ): PreparedStorageNode => { const missing = node.PDisks?.filter((pDisk) => { @@ -234,9 +234,9 @@ const prepareStorageNodeData = ( export const calculateMaximumSlotsPerDisk = ( nodes: TNodeInfo[] | undefined, providedMaximumSlotsPerDisk?: string, -): string => { - if (providedMaximumSlotsPerDisk) { - return providedMaximumSlotsPerDisk; +): number => { + if (providedMaximumSlotsPerDisk && !isNaN(Number(providedMaximumSlotsPerDisk))) { + return Number(providedMaximumSlotsPerDisk); } const safeNodes = nodes || []; @@ -251,7 +251,7 @@ export const calculateMaximumSlotsPerDisk = ( }); const maxSlots = Math.max(1, ...slotsPerDiskCounts); - return String(maxSlots); + return maxSlots; }; /** @@ -260,15 +260,15 @@ export const calculateMaximumSlotsPerDisk = ( export const calculateMaximumDisksPerNode = ( nodes: TNodeInfo[] | undefined, providedMaximumDisksPerNode?: string, -): string => { - if (providedMaximumDisksPerNode) { - return providedMaximumDisksPerNode; +): number => { + if (providedMaximumDisksPerNode && !isNaN(Number(providedMaximumDisksPerNode))) { + return Number(providedMaximumDisksPerNode); } const safeNodes = nodes || []; const disksPerNodeCounts = safeNodes.map((node) => node.PDisks?.length || 0); const maxDisks = Math.max(1, ...disksPerNodeCounts); - return String(maxDisks); + return maxDisks; }; // ==== Prepare responses ==== @@ -287,10 +287,10 @@ export const prepareStorageNodesResponse = (data: TNodesInfo): PreparedStorageRe return undefined; }).filter((group): group is TableGroup => Boolean(group)); - const maximumSlots = calculateMaximumSlotsPerDisk(Nodes, MaximumSlotsPerDisk); - const maximumDisks = calculateMaximumDisksPerNode(Nodes, MaximumDisksPerNode); + const maxSlotsPerDisk = calculateMaximumSlotsPerDisk(Nodes, MaximumSlotsPerDisk); + const maxDisksPerNode = calculateMaximumDisksPerNode(Nodes, MaximumDisksPerNode); const preparedNodes = Nodes?.map((node) => - prepareStorageNodeData(node, maximumSlots, maximumDisks), + prepareStorageNodeData(node, maxSlotsPerDisk, maxDisksPerNode), ); return { @@ -298,6 +298,7 @@ export const prepareStorageNodesResponse = (data: TNodesInfo): PreparedStorageRe total: Number(TotalNodes) || preparedNodes?.length, found: Number(FoundNodes), tableGroups, + columnsSettings: {maxSlotsPerDisk, maxDisksPerNode}, }; }; diff --git a/src/styles/mixins.scss b/src/styles/mixins.scss index ea0bb7d13..b044c429b 100644 --- a/src/styles/mixins.scss +++ b/src/styles/mixins.scss @@ -304,23 +304,3 @@ background-color: unset; } } - -@mixin calculate-storage-nodes-pdisk-variables() { - --pdisk-vdisk-width: 3px; - --pdisk-gap-width: 2px; - --pdisk-min-width: 120px; - --pdisk-margin: 10px; - - --pdisk-width: max( - calc( - var(--maximum-slots, 1) * var(--pdisk-vdisk-width) + (var(--maximum-slots, 1) - 1) * - var(--pdisk-gap-width) - ), - var(--pdisk-min-width) - ); - - --pdisks-container-width: calc( - var(--maximum-disks, 1) * var(--pdisk-width) + (var(--maximum-disks, 1) - 1) * - var(--pdisk-margin) - ); -}