diff --git a/src/components/PDiskPopup/PDiskPopup.tsx b/src/components/PDiskPopup/PDiskPopup.tsx
index 30dca66fe0..b8827359f9 100644
--- a/src/components/PDiskPopup/PDiskPopup.tsx
+++ b/src/components/PDiskPopup/PDiskPopup.tsx
@@ -6,10 +6,9 @@ import {EFlag} from '../../types/api/enums';
import {valueIsDefined} from '../../utils';
import {EMPTY_DATA_PLACEHOLDER} from '../../utils/constants';
import {createPDiskDeveloperUILink} from '../../utils/developerUI/developerUI';
-import {getPDiskId} from '../../utils/disks/helpers';
import type {PreparedPDisk} from '../../utils/disks/types';
import {useTypedSelector} from '../../utils/hooks';
-import {bytesToGB} from '../../utils/utils';
+import {bytesToGB, isNumeric} from '../../utils/utils';
import {InfoViewer} from '../InfoViewer';
import type {InfoViewerItem} from '../InfoViewer';
import {LinkWithIcon} from '../LinkWithIcon/LinkWithIcon';
@@ -21,12 +20,23 @@ export const preparePDiskData = (
nodeHost?: string,
withDeveloperUILink?: boolean,
) => {
- const {AvailableSize, TotalSize, State, PDiskId, NodeId, Path, Realtime, Type, Device} = data;
+ const {
+ AvailableSize,
+ TotalSize,
+ State,
+ PDiskId,
+ NodeId,
+ StringifiedId,
+ Path,
+ Realtime,
+ Type,
+ Device,
+ } = data;
const pdiskData: InfoViewerItem[] = [
{
label: 'PDisk',
- value: getPDiskId(NodeId, PDiskId) ?? EMPTY_DATA_PLACEHOLDER,
+ value: StringifiedId ?? EMPTY_DATA_PLACEHOLDER,
},
{label: 'State', value: State || 'not available'},
{label: 'Type', value: Type || 'unknown'},
@@ -44,10 +54,12 @@ export const preparePDiskData = (
pdiskData.push({label: 'Path', value: Path});
}
- pdiskData.push({
- label: 'Available',
- value: `${bytesToGB(AvailableSize)} of ${bytesToGB(TotalSize)}`,
- });
+ if (isNumeric(TotalSize)) {
+ pdiskData.push({
+ label: 'Available',
+ value: `${bytesToGB(AvailableSize)} of ${bytesToGB(TotalSize)}`,
+ });
+ }
if (Realtime && errorColors.includes(Realtime)) {
pdiskData.push({label: 'Realtime', value: Realtime});
diff --git a/src/components/VDiskPopup/VDiskPopup.tsx b/src/components/VDiskPopup/VDiskPopup.tsx
index 74314044cb..8181bf015e 100644
--- a/src/components/VDiskPopup/VDiskPopup.tsx
+++ b/src/components/VDiskPopup/VDiskPopup.tsx
@@ -8,7 +8,6 @@ import {EFlag} from '../../types/api/enums';
import {valueIsDefined} from '../../utils';
import {cn} from '../../utils/cn';
import {EMPTY_DATA_PLACEHOLDER} from '../../utils/constants';
-import {stringifyVdiskId} from '../../utils/dataFormatters/dataFormatters';
import {createVDiskDeveloperUILink} from '../../utils/developerUI/developerUI';
import {isFullVDiskData} from '../../utils/disks/helpers';
import type {PreparedVDisk, UnavailableDonor} from '../../utils/disks/types';
@@ -203,22 +202,9 @@ export const VDiskPopup = ({data}: VDiskPopupProps) => {
if ('Donors' in data && data.Donors) {
const donors = data.Donors;
for (const donor of donors) {
- const isFullDonorData = isFullVDiskData(donor);
donorsInfo.push({
label: 'VDisk',
- value: (
-
- {stringifyVdiskId(
- isFullDonorData
- ? donor.VDiskId
- : {
- NodeId: donor.NodeId,
- PDiskId: donor.PDiskId,
- VSlotId: donor.VSlotId,
- },
- )}
-
- ),
+ value: {donor.StringifiedId},
});
}
}
diff --git a/src/containers/Storage/Disks/Disks.tsx b/src/containers/Storage/Disks/Disks.tsx
index c4e6ce509d..c450fc3ed0 100644
--- a/src/containers/Storage/Disks/Disks.tsx
+++ b/src/containers/Storage/Disks/Disks.tsx
@@ -5,7 +5,6 @@ import {Flex, useLayoutContext} from '@gravity-ui/uikit';
import {VDisk} from '../../../components/VDisk/VDisk';
import {valueIsDefined} from '../../../utils';
import {cn} from '../../../utils/cn';
-import {getPDiskId} from '../../../utils/disks/helpers';
import type {PreparedVDisk} from '../../../utils/disks/types';
import {PDisk} from '../PDisk';
import type {StorageViewContext} from '../types';
@@ -54,7 +53,7 @@ export function Disks({vDisks = [], viewContext}: DisksProps) {
{vDisks?.map((vDisk) => (
{
const vDisks = group.VDisks?.filter((el) => el.NodeId === nodeId).map(
- prepareVDiskData,
+ prepareWhiteboardVDiskData,
);
vDisks?.forEach((vd) => {
const vDiskId = stringifyVdiskId(vd.VDiskId);
- const preparedPDisk = preparePDiskData(vd.PDisk);
- const pDiskId = preparedPDisk.PDiskId;
+ const pDiskId = vd.PDisk?.PDiskId;
if (!structure[String(pDiskId)]) {
- structure[String(pDiskId)] = {vDisks: {}, ...preparedPDisk};
+ structure[String(pDiskId)] = {vDisks: {}, ...vd.PDisk};
}
structure[String(pDiskId)].vDisks[vDiskId] = {
...vd,
diff --git a/src/store/reducers/node/types.ts b/src/store/reducers/node/types.ts
index b2e9cfc232..ef7df529e3 100644
--- a/src/store/reducers/node/types.ts
+++ b/src/store/reducers/node/types.ts
@@ -1,14 +1,13 @@
-import type {TVDiskStateInfo} from '../../../types/api/vdisk';
-import type {PreparedPDisk} from '../../../utils/disks/types';
+import type {PreparedPDisk, PreparedVDisk} from '../../../utils/disks/types';
import type {PreparedNodeSystemState} from '../../../utils/nodes';
interface RawStructurePDisk extends PreparedPDisk {
- vDisks: Record;
+ vDisks: Record;
}
export type RawNodeStructure = Record;
-export interface PreparedStructureVDisk extends TVDiskStateInfo {
+export interface PreparedStructureVDisk extends PreparedVDisk {
id: string;
order: number;
}
diff --git a/src/store/reducers/pdisk/utils.ts b/src/store/reducers/pdisk/utils.ts
index f493a190d1..41e9d8c005 100644
--- a/src/store/reducers/pdisk/utils.ts
+++ b/src/store/reducers/pdisk/utils.ts
@@ -1,7 +1,10 @@
import type {TPDiskInfoResponse} from '../../../types/api/pdisk';
import type {TEvSystemStateResponse} from '../../../types/api/systemState';
import {getArray, valueIsDefined} from '../../../utils';
-import {preparePDiskData, prepareVDiskData} from '../../../utils/disks/prepareDisks';
+import {
+ prepareWhiteboardPDiskData,
+ prepareWhiteboardVDiskData,
+} from '../../../utils/disks/prepareDisks';
import {prepareNodeSystemState} from '../../../utils/nodes';
import type {PDiskData, SlotItem} from './types';
@@ -18,7 +21,10 @@ export function preparePDiskDataResponse([pdiskResponse = {}, nodeResponse]: [
const {PDisk: WhiteboardPDiskData = {}, VDisks: WhiteboardVDisksData = []} = Whiteboard;
const {PDisk: BSCPDiskData = {}} = BSC;
- const preparedPDisk = preparePDiskData(WhiteboardPDiskData, BSCPDiskData);
+ const preparedPDisk = prepareWhiteboardPDiskData({
+ ...BSCPDiskData,
+ ...WhiteboardPDiskData,
+ });
const NodeId = preparedPDisk.NodeId ?? preparedNode.NodeId;
@@ -48,7 +54,9 @@ export function preparePDiskDataResponse([pdiskResponse = {}, nodeResponse]: [
};
}
- const preparedVDisks = WhiteboardVDisksData.map((disk) => prepareVDiskData({...disk, NodeId}));
+ const preparedVDisks = WhiteboardVDisksData.map((disk) =>
+ prepareWhiteboardVDiskData({...disk, NodeId}),
+ );
preparedVDisks.sort((disk1, disk2) => Number(disk2.VDiskSlotId) - Number(disk1.VDiskSlotId));
const vdisksSlots: SlotItem<'vDisk'>[] = preparedVDisks.map((preparedVDisk) => {
diff --git a/src/store/reducers/storage/__test__/prepareGroupsDisks.test.ts b/src/store/reducers/storage/__test__/prepareGroupsDisks.test.ts
new file mode 100644
index 0000000000..b957a0f853
--- /dev/null
+++ b/src/store/reducers/storage/__test__/prepareGroupsDisks.test.ts
@@ -0,0 +1,414 @@
+import type {TStoragePDisk, TStorageVDisk} from '../../../../types/api/storage';
+import {prepareGroupsPDisk, prepareGroupsVDisk} from '../prepareGroupsDisks';
+
+describe('prepareGroupsVDisk', () => {
+ it('Should correctly parse data', () => {
+ const vDiksDataWithoutPDisk = {
+ VDiskId: '2181038134-22-0-0-0',
+ NodeId: 224,
+ AllocatedSize: '30943477760',
+ AvailableSize: '234461593600',
+ Status: 'READY',
+ DiskSpace: 'Green',
+ Whiteboard: {
+ VDiskId: {
+ GroupID: 2181038134,
+ GroupGeneration: 22,
+ Ring: 0,
+ Domain: 0,
+ VDisk: 0,
+ },
+ ChangeTime: '1730273487988',
+ PDiskId: 1001,
+ VDiskSlotId: 1019,
+ Guid: '10619691988133943213',
+ Kind: '0',
+ VDiskState: 'OK',
+ DiskSpace: 'Green',
+ SatisfactionRank: {
+ FreshRank: {
+ Flag: 'Green',
+ },
+ LevelRank: {
+ Flag: 'Green',
+ },
+ },
+ Replicated: true,
+ UnsyncedVDisks: '3',
+ AllocatedSize: '30943477760',
+ AvailableSize: '234461593600',
+ HasUnreadableBlobs: false,
+ IncarnationGuid: '14709186654400312808',
+ InstanceGuid: '18225898175839904663',
+ FrontQueues: 'Green',
+ StoragePoolName: '/storage/pool/name',
+ ReadThroughput: '0',
+ WriteThroughput: '0',
+ },
+ } as const as TStorageVDisk;
+
+ const expectedResult = {
+ VDiskId: {
+ GroupID: 2181038134,
+ GroupGeneration: 22,
+ Ring: 0,
+ Domain: 0,
+ VDisk: 0,
+ },
+ StringifiedId: '2181038134-22-0-0-0',
+ NodeId: 224,
+ PDiskId: 1001,
+ VDiskSlotId: 1019,
+
+ StoragePoolName: '/storage/pool/name',
+
+ Kind: '0',
+ ChangeTime: '1730273487988',
+ Guid: '10619691988133943213',
+ IncarnationGuid: '14709186654400312808',
+ InstanceGuid: '18225898175839904663',
+
+ Severity: 1,
+ VDiskState: 'OK',
+ DiskSpace: 'Green',
+ FrontQueues: 'Green',
+ Status: 'READY',
+ SatisfactionRank: {
+ FreshRank: {
+ Flag: 'Green',
+ },
+ LevelRank: {
+ Flag: 'Green',
+ },
+ },
+ Replicated: true,
+
+ UnsyncedVDisks: '3',
+ HasUnreadableBlobs: false,
+
+ ReadThroughput: '0',
+ WriteThroughput: '0',
+
+ AllocatedSize: 30943477760,
+ AvailableSize: 234461593600,
+ TotalSize: 265405071360,
+ AllocatedPercent: 12,
+
+ Donors: undefined,
+ PDisk: undefined,
+ };
+
+ const preparedData = prepareGroupsVDisk(vDiksDataWithoutPDisk);
+
+ expect(preparedData).toEqual(expectedResult);
+ });
+ it('Should use BSC data when no Whiteboard data', () => {
+ const vDiksDataWithoutPDisk = {
+ VDiskId: '2181038134-22-0-0-0',
+ NodeId: 224,
+ AllocatedSize: '30943477760',
+ AvailableSize: '234461593600',
+ Status: 'READY',
+ DiskSpace: 'Green',
+ } as const as TStorageVDisk;
+
+ const expectedResult = {
+ StringifiedId: '2181038134-22-0-0-0',
+ NodeId: 224,
+
+ Severity: 0,
+ DiskSpace: 'Green',
+ Status: 'READY',
+
+ AllocatedSize: 30943477760,
+ AvailableSize: 234461593600,
+ TotalSize: 265405071360,
+ AllocatedPercent: 12,
+ };
+
+ const preparedData = prepareGroupsVDisk(vDiksDataWithoutPDisk);
+
+ expect(preparedData).toEqual(expectedResult);
+ });
+ it('Should use Whiteboard data when no BSC data', () => {
+ const vDiksDataWithoutPDisk = {
+ Whiteboard: {
+ VDiskId: {
+ GroupID: 2181038134,
+ GroupGeneration: 22,
+ Ring: 0,
+ Domain: 0,
+ VDisk: 0,
+ },
+ ChangeTime: '1730273487988',
+ PDiskId: 1001,
+ VDiskSlotId: 1019,
+ Guid: '10619691988133943213',
+ Kind: '0',
+ VDiskState: 'OK',
+ DiskSpace: 'Green',
+ SatisfactionRank: {
+ FreshRank: {
+ Flag: 'Green',
+ },
+ LevelRank: {
+ Flag: 'Green',
+ },
+ },
+ Replicated: true,
+ UnsyncedVDisks: '3',
+ AllocatedSize: '30943477760',
+ AvailableSize: '234461593600',
+ HasUnreadableBlobs: false,
+ IncarnationGuid: '14709186654400312808',
+ InstanceGuid: '18225898175839904663',
+ FrontQueues: 'Green',
+ StoragePoolName: '/storage/pool/name',
+ ReadThroughput: '0',
+ WriteThroughput: '0',
+ },
+ } as const as TStorageVDisk;
+
+ const expectedResult = {
+ VDiskId: {
+ GroupID: 2181038134,
+ GroupGeneration: 22,
+ Ring: 0,
+ Domain: 0,
+ VDisk: 0,
+ },
+ StringifiedId: '2181038134-22-0-0-0',
+ PDiskId: 1001,
+ VDiskSlotId: 1019,
+
+ StoragePoolName: '/storage/pool/name',
+
+ Kind: '0',
+ ChangeTime: '1730273487988',
+ Guid: '10619691988133943213',
+ IncarnationGuid: '14709186654400312808',
+ InstanceGuid: '18225898175839904663',
+
+ Severity: 1,
+ VDiskState: 'OK',
+ DiskSpace: 'Green',
+ FrontQueues: 'Green',
+ SatisfactionRank: {
+ FreshRank: {
+ Flag: 'Green',
+ },
+ LevelRank: {
+ Flag: 'Green',
+ },
+ },
+ Replicated: true,
+
+ UnsyncedVDisks: '3',
+ HasUnreadableBlobs: false,
+
+ ReadThroughput: '0',
+ WriteThroughput: '0',
+
+ AllocatedSize: 30943477760,
+ AvailableSize: 234461593600,
+ TotalSize: 265405071360,
+ AllocatedPercent: 12,
+
+ Donors: undefined,
+ PDisk: undefined,
+ };
+
+ const preparedData = prepareGroupsVDisk(vDiksDataWithoutPDisk);
+
+ expect(preparedData).toEqual(expectedResult);
+ });
+});
+
+describe('prepareGroupsPDisk', () => {
+ it('Should correctly parse data', () => {
+ const pDiskData = {
+ PDiskId: '224-1001',
+ NodeId: 224,
+ Path: '/dev/disk/by-partlabel/kikimr_nvme_04',
+ Type: 'ssd',
+ Guid: '10619691988133943213',
+ Category: '1',
+ TotalSize: '6400161873920',
+ AvailableSize: '5613855703040',
+ Status: 'ACTIVE',
+ DiskSpace: 'Green',
+ DecommitStatus: 'DECOMMIT_NONE',
+ SlotSize: '265405071360',
+ Whiteboard: {
+ PDiskId: 1001,
+ ChangeTime: '1730273451793',
+ Path: '/dev/disk/by-partlabel/kikimr_nvme_04',
+ Guid: '10619691988133943213',
+ Category: '1',
+ AvailableSize: '5613855703040',
+ TotalSize: '6400161873920',
+ State: 'Normal',
+ Device: 'Green',
+ Realtime: 'Green',
+ SerialNumber: 'PHLN227201336P4CGN',
+ SystemSize: '817889280',
+ LogUsedSize: '3271557120',
+ LogTotalSize: '27262976000',
+ ExpectedSlotCount: 24,
+ EnforcedDynamicSlotSize: '265405071360',
+ NumActiveSlots: 18,
+ },
+ } as const as TStoragePDisk & {
+ NodeId?: number;
+ };
+
+ const expectedResult = {
+ NodeId: 224,
+ PDiskId: 1001,
+ StringifiedId: '224-1001',
+
+ ChangeTime: '1730273451793',
+ Path: '/dev/disk/by-partlabel/kikimr_nvme_04',
+ Guid: '10619691988133943213',
+ SerialNumber: 'PHLN227201336P4CGN',
+
+ Category: '1',
+ Type: 'SSD',
+
+ State: 'Normal',
+ Device: 'Green',
+ Realtime: 'Green',
+ Status: 'ACTIVE',
+ DiskSpace: 'Green',
+ DecommitStatus: 'DECOMMIT_NONE',
+
+ AvailableSize: 5613855703040,
+ TotalSize: 6400161873920,
+ AllocatedPercent: 12,
+ AllocatedSize: 786306170880,
+ Severity: 1,
+
+ SystemSize: '817889280',
+ LogUsedSize: '3271557120',
+ LogTotalSize: '27262976000',
+
+ NumActiveSlots: 18,
+ ExpectedSlotCount: 24,
+ SlotSize: '265405071360',
+ EnforcedDynamicSlotSize: '265405071360',
+ };
+
+ const preparedData = prepareGroupsPDisk(pDiskData);
+
+ expect(preparedData).toEqual(expectedResult);
+ });
+ it('Should use BSC data when no Whiteboard data', () => {
+ const pDiskData = {
+ PDiskId: '224-1001',
+ NodeId: 224,
+ Path: '/dev/disk/by-partlabel/kikimr_nvme_04',
+ Type: 'ssd',
+ Guid: '10619691988133943213',
+ Category: '1',
+ TotalSize: '6400161873920',
+ AvailableSize: '5613855703040',
+ Status: 'ACTIVE',
+ DiskSpace: 'Green',
+ DecommitStatus: 'DECOMMIT_NONE',
+ SlotSize: '265405071360',
+ } as const as TStoragePDisk & {
+ NodeId?: number;
+ };
+
+ const expectedResult = {
+ NodeId: 224,
+ StringifiedId: '224-1001',
+
+ Path: '/dev/disk/by-partlabel/kikimr_nvme_04',
+ Guid: '10619691988133943213',
+
+ Category: '1',
+ Type: 'SSD',
+
+ Severity: 0,
+
+ Status: 'ACTIVE',
+ DiskSpace: 'Green',
+ DecommitStatus: 'DECOMMIT_NONE',
+
+ TotalSize: 6400161873920,
+ AvailableSize: 5613855703040,
+ AllocatedPercent: 12,
+ AllocatedSize: 786306170880,
+
+ SlotSize: '265405071360',
+ };
+
+ const preparedData = prepareGroupsPDisk(pDiskData);
+
+ expect(preparedData).toEqual(expectedResult);
+ });
+ it('Should use Whiteboard data when no BSC data', () => {
+ const pDiskData = {
+ NodeId: 224,
+ Whiteboard: {
+ PDiskId: 1001,
+ ChangeTime: '1730273451793',
+ Path: '/dev/disk/by-partlabel/kikimr_nvme_04',
+ Guid: '10619691988133943213',
+ Category: '1',
+ AvailableSize: '5613855703040',
+ TotalSize: '6400161873920',
+ State: 'Normal',
+ Device: 'Green',
+ Realtime: 'Green',
+ SerialNumber: 'PHLN227201336P4CGN',
+ SystemSize: '817889280',
+ LogUsedSize: '3271557120',
+ LogTotalSize: '27262976000',
+ ExpectedSlotCount: 24,
+ EnforcedDynamicSlotSize: '265405071360',
+ NumActiveSlots: 18,
+ },
+ } as const as TStoragePDisk & {
+ NodeId?: number;
+ };
+
+ const expectedResult = {
+ NodeId: 224,
+ PDiskId: 1001,
+ StringifiedId: '224-1001',
+
+ ChangeTime: '1730273451793',
+ Path: '/dev/disk/by-partlabel/kikimr_nvme_04',
+ Guid: '10619691988133943213',
+ SerialNumber: 'PHLN227201336P4CGN',
+
+ Category: '1',
+ Type: 'SSD',
+
+ State: 'Normal',
+ Device: 'Green',
+ Realtime: 'Green',
+
+ AvailableSize: 5613855703040,
+ TotalSize: 6400161873920,
+ AllocatedPercent: 12,
+ AllocatedSize: 786306170880,
+ Severity: 1,
+
+ SystemSize: '817889280',
+ LogUsedSize: '3271557120',
+ LogTotalSize: '27262976000',
+
+ NumActiveSlots: 18,
+ ExpectedSlotCount: 24,
+ SlotSize: '265405071360',
+ EnforcedDynamicSlotSize: '265405071360',
+ };
+
+ const preparedData = prepareGroupsPDisk(pDiskData);
+
+ expect(preparedData).toEqual(expectedResult);
+ });
+});
diff --git a/src/store/reducers/storage/prepareGroupsDisks.ts b/src/store/reducers/storage/prepareGroupsDisks.ts
new file mode 100644
index 0000000000..1494f1723d
--- /dev/null
+++ b/src/store/reducers/storage/prepareGroupsDisks.ts
@@ -0,0 +1,90 @@
+import type {TStoragePDisk, TStorageVDisk} from '../../../types/api/storage';
+import {stringifyVdiskId} from '../../../utils/dataFormatters/dataFormatters';
+import {calculatePDiskSeverity} from '../../../utils/disks/calculatePDiskSeverity';
+import {calculateVDiskSeverity} from '../../../utils/disks/calculateVDiskSeverity';
+import {getPDiskType} from '../../../utils/disks/getPDiskType';
+import {getPDiskId} from '../../../utils/disks/helpers';
+import {preparePDiskSizeFields, prepareVDiskSizeFields} from '../../../utils/disks/prepareDisks';
+import type {PDiskType, PreparedVDisk} from '../../../utils/disks/types';
+
+export function prepareGroupsVDisk(data: TStorageVDisk = {}): PreparedVDisk {
+ const {Whiteboard: whiteboardVDisk = {}, PDisk, ...bscVDisk} = data;
+
+ const mergedVDiskData = {
+ ...whiteboardVDisk,
+ ...bscVDisk,
+ VDiskId: whiteboardVDisk.VDiskId,
+ };
+
+ const preparedPDisk = PDisk
+ ? prepareGroupsPDisk({...PDisk, NodeId: mergedVDiskData.NodeId})
+ : undefined;
+
+ const PDiskId = preparedPDisk?.PDiskId ?? whiteboardVDisk?.PDiskId;
+
+ const StringifiedId = bscVDisk.VDiskId ?? stringifyVdiskId(whiteboardVDisk.VDiskId);
+
+ const Severity = calculateVDiskSeverity(mergedVDiskData);
+
+ const vDiskSizeFields = prepareVDiskSizeFields({
+ AvailableSize: mergedVDiskData.AvailableSize ?? PDisk?.AvailableSize,
+ AllocatedSize: mergedVDiskData.AllocatedSize,
+ });
+
+ const preparedDonors = bscVDisk.Donors?.map((donor) => {
+ return prepareGroupsVDisk({
+ ...donor,
+ Whiteboard: {...donor.Whiteboard, DonorMode: true},
+ });
+ });
+
+ return {
+ ...mergedVDiskData,
+ ...vDiskSizeFields,
+ PDisk: preparedPDisk,
+ Donors: preparedDonors,
+ PDiskId,
+ StringifiedId,
+ Severity,
+ };
+}
+
+export function prepareGroupsPDisk(data: TStoragePDisk & {NodeId?: number} = {}) {
+ const {Whiteboard: whiteboardPDisk, ...bscPDisk} = data;
+
+ const mergedPDiskData = {
+ ...whiteboardPDisk,
+ ...bscPDisk,
+ PDiskId: whiteboardPDisk?.PDiskId,
+ };
+
+ const StringifiedId =
+ bscPDisk.PDiskId || getPDiskId(mergedPDiskData.NodeId, mergedPDiskData.PDiskId);
+
+ const {AllocatedPercent, AllocatedSize, AvailableSize, TotalSize} = preparePDiskSizeFields({
+ AvailableSize: mergedPDiskData.AvailableSize,
+ TotalSize: mergedPDiskData.TotalSize,
+ });
+
+ const Type =
+ (bscPDisk.Type?.toUpperCase() as PDiskType) ?? getPDiskType(whiteboardPDisk?.Category);
+
+ const Severity = calculatePDiskSeverity({
+ State: whiteboardPDisk?.State,
+ AllocatedPercent,
+ });
+
+ const SlotSize = bscPDisk.SlotSize ?? whiteboardPDisk?.EnforcedDynamicSlotSize;
+
+ return {
+ ...mergedPDiskData,
+ StringifiedId,
+ AllocatedPercent,
+ AllocatedSize,
+ AvailableSize,
+ TotalSize,
+ Type,
+ Severity,
+ SlotSize,
+ };
+}
diff --git a/src/store/reducers/storage/utils.ts b/src/store/reducers/storage/utils.ts
index 9a1d22efb2..e4f3b18988 100644
--- a/src/store/reducers/storage/utils.ts
+++ b/src/store/reducers/storage/utils.ts
@@ -12,11 +12,15 @@ import type {
import {EVDiskState} from '../../../types/api/vdisk';
import type {TVDiskStateInfo} from '../../../types/api/vdisk';
import {getColorSeverity, getSeverityColor} from '../../../utils/disks/helpers';
-import {preparePDiskData, prepareVDiskData} from '../../../utils/disks/prepareDisks';
+import {
+ prepareWhiteboardPDiskData,
+ prepareWhiteboardVDiskData,
+} from '../../../utils/disks/prepareDisks';
import {prepareNodeSystemState} from '../../../utils/nodes';
import {getUsage} from '../../../utils/storage';
import {parseUsToMs} from '../../../utils/timeParsers';
+import {prepareGroupsVDisk} from './prepareGroupsDisks';
import type {
PreparedStorageGroup,
PreparedStorageNode,
@@ -36,7 +40,7 @@ function getGroupDiskSpaceStatus(group: TStorageGroupInfo | TGroupsStorageGroupI
}
const prepareVDisk = (vDisk: TVDiskStateInfo, poolName: string | undefined) => {
- const preparedVDisk = prepareVDiskData(vDisk);
+ const preparedVDisk = prepareWhiteboardVDiskData(vDisk);
// VDisk doesn't have its own StoragePoolName when located inside StoragePool data
return {
@@ -78,7 +82,7 @@ export const prepareStorageGroupData = (
Type: PDiskType,
State: PDiskState,
AvailableSize: PDiskAvailableSize,
- } = preparePDiskData(PDisk);
+ } = prepareWhiteboardPDiskData(PDisk);
if (!Replicated || PDiskState !== TPDiskState.Normal || VDiskState !== EVDiskState.OK) {
missing += 1;
@@ -192,13 +196,13 @@ const prepareStorageNodeData = (node: TNodeInfo): PreparedStorageNode => {
const pDisks = node.PDisks?.map((pDisk) => {
return {
- ...preparePDiskData(pDisk),
+ ...prepareWhiteboardPDiskData(pDisk),
NodeId: node.NodeId,
};
});
const vDisks = node.VDisks?.map((vDisk) => {
return {
- ...prepareVDiskData(vDisk),
+ ...prepareWhiteboardVDiskData(vDisk),
NodeId: node.NodeId,
};
});
@@ -268,42 +272,7 @@ export function prepareGroupsResponse(data: StorageGroupsResponse): PreparedStor
LatencyGetFast,
} = group;
- const vDisks = VDisks.map((disk) => {
- const {
- Whiteboard: whiteboardVDisk,
- PDisk,
- VDiskId,
- NodeId,
- AllocatedSize,
- AvailableSize,
- DiskSpace,
- Status,
- } = disk;
- const whiteboardPDisk = PDisk?.Whiteboard;
-
- const PDiskId = whiteboardPDisk?.PDiskId;
-
- const whiteboardVDiskData = {
- ...whiteboardVDisk,
- PDiskId,
- NodeId,
- AllocatedSize,
- AvailableSize,
- DiskSpace,
- Status,
- PDisk: {...whiteboardPDisk, NodeId},
- };
-
- const preparedVDiskData = prepareVDiskData(whiteboardVDiskData);
-
- return {
- ...preparedVDiskData,
- // There might be no Whiteboard data if cluster is not healthy
- // StringifiedId is formed from Whiteboard.VDiskId object
- // Use VDiskId string from backend in such case
- StringifiedId: preparedVDiskData.StringifiedId || VDiskId,
- };
- });
+ const vDisks = VDisks.map(prepareGroupsVDisk);
const diskSpaceStatus = getGroupDiskSpaceStatus(group);
diff --git a/src/store/reducers/vdisk/utils.ts b/src/store/reducers/vdisk/utils.ts
index 9726e5a71d..e2168bc3aa 100644
--- a/src/store/reducers/vdisk/utils.ts
+++ b/src/store/reducers/vdisk/utils.ts
@@ -1,7 +1,10 @@
import type {TEvPDiskStateResponse} from '../../../types/api/pdisk';
import type {TEvSystemStateResponse} from '../../../types/api/systemState';
import type {TEvVDiskStateResponse} from '../../../types/api/vdisk';
-import {preparePDiskData, prepareVDiskData} from '../../../utils/disks/prepareDisks';
+import {
+ prepareWhiteboardPDiskData,
+ prepareWhiteboardVDiskData,
+} from '../../../utils/disks/prepareDisks';
import {prepareNodeSystemState} from '../../../utils/nodes';
import type {VDiskData} from './types';
@@ -12,10 +15,10 @@ export function prepareVDiskDataResponse([vDiskResponse, pDiskResponse, nodeResp
TEvSystemStateResponse,
]): VDiskData {
const rawVDisk = vDiskResponse.VDiskStateInfo?.[0];
- const preparedVDisk = prepareVDiskData(rawVDisk);
+ const preparedVDisk = prepareWhiteboardVDiskData(rawVDisk);
const rawPDisk = pDiskResponse.PDiskStateInfo?.[0];
- const preparedPDisk = preparePDiskData(rawPDisk);
+ const preparedPDisk = prepareWhiteboardPDiskData(rawPDisk);
const rawNode = nodeResponse.SystemStateInfo?.[0];
const preparedNode = prepareNodeSystemState(rawNode);
diff --git a/src/types/api/pdisk.ts b/src/types/api/pdisk.ts
index dae9506c01..5d6aea2743 100644
--- a/src/types/api/pdisk.ts
+++ b/src/types/api/pdisk.ts
@@ -88,7 +88,7 @@ interface TPDiskInfoWhiteboard {
interface TPDiskInfoBSC {
PDisk?: TPDiskInfo;
- VDisks?: TVSlotEntry;
+ VDisks?: TVSlotEntry[];
}
/**
diff --git a/src/types/api/storage.ts b/src/types/api/storage.ts
index 87e095163a..094e447f1d 100644
--- a/src/types/api/storage.ts
+++ b/src/types/api/storage.ts
@@ -193,7 +193,7 @@ export interface TStorageVDisk {
AvailableSize?: string;
Status?: EVDiskStatus;
DiskSpace?: EFlag;
- Donors?: Omit;
+ Donors?: TStorageVDisk[];
PDisk?: TStoragePDisk;
Whiteboard?: TVDiskStateInfo;
}
@@ -201,7 +201,7 @@ export interface TStorageVDisk {
/**
* PDisk data from storage/groups handler
*/
-interface TStoragePDisk {
+export interface TStoragePDisk {
PDiskId?: string;
Path?: string;
Type?: 'hdd' | 'ssd' | 'nvme';
diff --git a/src/utils/disks/__test__/calculatePDiskSeverity.test.ts b/src/utils/disks/__test__/calculatePDiskSeverity.test.ts
index 726384b42e..2a9671f429 100644
--- a/src/utils/disks/__test__/calculatePDiskSeverity.test.ts
+++ b/src/utils/disks/__test__/calculatePDiskSeverity.test.ts
@@ -11,9 +11,9 @@ describe('PDisk state', () => {
});
it('Should determine severity based on space utilization if state severity is OK', () => {
- const severity1 = calculatePDiskSeverity({State: TPDiskState.Normal}, 0);
- const severity2 = calculatePDiskSeverity({State: TPDiskState.Normal}, 86);
- const severity3 = calculatePDiskSeverity({State: TPDiskState.Normal}, 96);
+ const severity1 = calculatePDiskSeverity({State: TPDiskState.Normal, AllocatedPercent: 0});
+ const severity2 = calculatePDiskSeverity({State: TPDiskState.Normal, AllocatedPercent: 86});
+ const severity3 = calculatePDiskSeverity({State: TPDiskState.Normal, AllocatedPercent: 96});
expect(severity1).toEqual(DISK_COLOR_STATE_TO_NUMERIC_SEVERITY.Green);
expect(severity2).toEqual(DISK_COLOR_STATE_TO_NUMERIC_SEVERITY.Yellow);
@@ -21,8 +21,11 @@ describe('PDisk state', () => {
});
it('Should determine severity based on max severity of state and space utilization ', () => {
- const severity1 = calculatePDiskSeverity({State: TPDiskState.ChunkQuotaError}, 0);
- const severity2 = calculatePDiskSeverity({State: TPDiskState.Normal}, 96);
+ const severity1 = calculatePDiskSeverity({
+ State: TPDiskState.ChunkQuotaError,
+ AllocatedPercent: 0,
+ });
+ const severity2 = calculatePDiskSeverity({State: TPDiskState.Normal, AllocatedPercent: 96});
expect(severity1).toEqual(DISK_COLOR_STATE_TO_NUMERIC_SEVERITY.Red);
expect(severity2).toEqual(DISK_COLOR_STATE_TO_NUMERIC_SEVERITY.Red);
@@ -37,8 +40,8 @@ describe('PDisk state', () => {
});
it('Should display as unavailabe when no State is provided event if space severity is not OK', () => {
- const severity1 = calculatePDiskSeverity({}, 86);
- const severity2 = calculatePDiskSeverity({}, 96);
+ const severity1 = calculatePDiskSeverity({AllocatedPercent: 86});
+ const severity2 = calculatePDiskSeverity({AllocatedPercent: 96});
expect(severity1).toEqual(DISK_COLOR_STATE_TO_NUMERIC_SEVERITY.Grey);
expect(severity2).toEqual(DISK_COLOR_STATE_TO_NUMERIC_SEVERITY.Grey);
diff --git a/src/utils/disks/__test__/calculateVDiskSeverity.test.ts b/src/utils/disks/__test__/calculateVDiskSeverity.test.ts
index 3dddca95d0..fe48e0b0b5 100644
--- a/src/utils/disks/__test__/calculateVDiskSeverity.test.ts
+++ b/src/utils/disks/__test__/calculateVDiskSeverity.test.ts
@@ -6,19 +6,16 @@ import {DISK_COLOR_STATE_TO_NUMERIC_SEVERITY} from '../constants';
describe('VDisk state', () => {
it('Should determine severity based on the highest value among VDiskState, DiskSpace and FrontQueues', () => {
const severity1 = calculateVDiskSeverity({
- VDiskId: {Domain: 1},
VDiskState: EVDiskState.OK, // severity 1, green
DiskSpace: EFlag.Yellow, // severity 3, yellow
FrontQueues: EFlag.Green, // severity 1, green
});
const severity2 = calculateVDiskSeverity({
- VDiskId: {Domain: 2},
VDiskState: EVDiskState.PDiskError, // severity 5, red
DiskSpace: EFlag.Yellow, // severity 3, yellow
FrontQueues: EFlag.Green, // severity 1, green
});
const severity3 = calculateVDiskSeverity({
- VDiskId: {Domain: 3},
VDiskState: EVDiskState.OK, // severity 1, green
DiskSpace: EFlag.Yellow, // severity 3, yellow
FrontQueues: EFlag.Orange, // severity 4, orange
@@ -31,13 +28,11 @@ describe('VDisk state', () => {
it('Should not pick the highest severity based on FrontQueues value', () => {
const severity1 = calculateVDiskSeverity({
- VDiskId: {Domain: 1},
VDiskState: EVDiskState.OK, // severity 1, green
DiskSpace: EFlag.Green, // severity 1, green
FrontQueues: EFlag.Red, // severity 5, red
});
const severity2 = calculateVDiskSeverity({
- VDiskId: {Domain: 2},
VDiskState: EVDiskState.OK, // severity 1, green
DiskSpace: EFlag.Red, // severity 5, red
FrontQueues: EFlag.Red, // severity 5, red
@@ -49,29 +44,27 @@ describe('VDisk state', () => {
// prettier-ignore
it('Should display as unavailable when no VDiskState is provided', () => {
- const severity1 = calculateVDiskSeverity({
- VDiskId: {Domain: 1}
- });
+ const severity1 = calculateVDiskSeverity({});
const severity2 = calculateVDiskSeverity({
- VDiskId: {Domain: 2}, VDiskState: EVDiskState.OK
+ VDiskState: EVDiskState.OK
});
const severity3 = calculateVDiskSeverity({
- VDiskId: {Domain: 3}, DiskSpace: EFlag.Green
+ DiskSpace: EFlag.Green
});
const severity4 = calculateVDiskSeverity({
- VDiskId: {Domain: 4}, FrontQueues: EFlag.Green
+ FrontQueues: EFlag.Green
});
const severity5 = calculateVDiskSeverity({
- VDiskId: {Domain: 5}, VDiskState: EVDiskState.OK, DiskSpace: EFlag.Green
+ VDiskState: EVDiskState.OK, DiskSpace: EFlag.Green
});
const severity6 = calculateVDiskSeverity({
- VDiskId: {Domain: 6}, VDiskState: EVDiskState.OK, FrontQueues: EFlag.Green
+ VDiskState: EVDiskState.OK, FrontQueues: EFlag.Green
});
const severity7 = calculateVDiskSeverity({
- VDiskId: {Domain: 7}, DiskSpace: EFlag.Green, FrontQueues: EFlag.Green
+ DiskSpace: EFlag.Green, FrontQueues: EFlag.Green
});
const severity8 = calculateVDiskSeverity({
- VDiskId: {Domain: 8}, VDiskState: EVDiskState.OK, DiskSpace: EFlag.Green, FrontQueues: EFlag.Green
+ VDiskState: EVDiskState.OK, DiskSpace: EFlag.Green, FrontQueues: EFlag.Green
});
// unavailable disks display with the grey color
@@ -87,7 +80,6 @@ describe('VDisk state', () => {
it('Should display as unavailable when no VDiskState is provided even if DiskSpace or FrontQueues flags are not green', () => {
const severity1 = calculateVDiskSeverity({
- VDiskId: {Domain: 1},
DiskSpace: EFlag.Red,
FrontQueues: EFlag.Yellow,
});
@@ -98,12 +90,10 @@ describe('VDisk state', () => {
it('Should display replicating VDisks in OK state with a distinct color', () => {
const severity1 = calculateVDiskSeverity({
- VDiskId: {Domain: 1},
VDiskState: EVDiskState.OK, // severity 1, green
Replicated: false,
});
const severity2 = calculateVDiskSeverity({
- VDiskId: {Domain: 2},
VDiskState: EVDiskState.OK, // severity 1, green
Replicated: true,
});
@@ -114,12 +104,10 @@ describe('VDisk state', () => {
it('Should display replicating VDisks in a not-OK state with a regular color', () => {
const severity1 = calculateVDiskSeverity({
- VDiskId: {Domain: 1},
VDiskState: EVDiskState.Initial, // severity 3, yellow
Replicated: false,
});
const severity2 = calculateVDiskSeverity({
- VDiskId: {Domain: 2},
VDiskState: EVDiskState.PDiskError, // severity 5, red
Replicated: false,
});
@@ -130,19 +118,16 @@ describe('VDisk state', () => {
it('Should always display donor VDisks with a regular color', () => {
const severity1 = calculateVDiskSeverity({
- VDiskId: {Domain: 1},
VDiskState: EVDiskState.OK, // severity 1, green
Replicated: false, // donors are always in the not replicated state since they are leftovers
DonorMode: true,
});
const severity2 = calculateVDiskSeverity({
- VDiskId: {Domain: 2},
VDiskState: EVDiskState.Initial, // severity 3, yellow
Replicated: false,
DonorMode: true,
});
const severity3 = calculateVDiskSeverity({
- VDiskId: {Domain: 3},
VDiskState: EVDiskState.PDiskError, // severity 5, red
Replicated: false,
DonorMode: true,
diff --git a/src/utils/disks/__test__/prepareDisks.test.ts b/src/utils/disks/__test__/prepareDisks.test.ts
new file mode 100644
index 0000000000..1d9272f785
--- /dev/null
+++ b/src/utils/disks/__test__/prepareDisks.test.ts
@@ -0,0 +1,238 @@
+import type {TPDiskStateInfo} from '../../../types/api/pdisk';
+import type {TVDiskStateInfo, TVSlotId} from '../../../types/api/vdisk';
+import {
+ preparePDiskSizeFields,
+ prepareVDiskSizeFields,
+ prepareWhiteboardPDiskData,
+ prepareWhiteboardVDiskData,
+} from '../prepareDisks';
+
+describe('prepareWhiteboardVDiskData', () => {
+ it('Should correctly parse data', () => {
+ const data = {
+ VDiskId: {
+ GroupID: 0,
+ GroupGeneration: 1,
+ Ring: 0,
+ Domain: 0,
+ VDisk: 0,
+ },
+ ChangeTime: '1730384311105',
+ PDiskId: 1,
+ VDiskSlotId: 0,
+ Guid: '3910585916831022250',
+ Kind: '0',
+ NodeId: 1,
+ VDiskState: 'OK',
+ DiskSpace: 'Green',
+ SatisfactionRank: {
+ FreshRank: {
+ Flag: 'Green',
+ },
+ LevelRank: {
+ Flag: 'Green',
+ },
+ },
+ Replicated: true,
+ ReplicationProgress: 1,
+ ReplicationSecondsRemaining: 0,
+ AllocatedSize: '8996782080',
+ AvailableSize: '188523479040',
+ HasUnreadableBlobs: false,
+ IncarnationGuid: '719472956608975753',
+ InstanceGuid: '11219959563151194061',
+ FrontQueues: 'Green',
+ StoragePoolName: 'static',
+ ReadThroughput: '0',
+ WriteThroughput: '447',
+ } as const as TVDiskStateInfo;
+
+ const expectedResult = {
+ StringifiedId: '0-1-0-0-0',
+ VDiskId: {
+ GroupID: 0,
+ GroupGeneration: 1,
+ Ring: 0,
+ Domain: 0,
+ VDisk: 0,
+ },
+ NodeId: 1,
+ PDiskId: 1,
+ VDiskSlotId: 0,
+ StoragePoolName: 'static',
+
+ ChangeTime: '1730384311105',
+
+ Guid: '3910585916831022250',
+ Kind: '0',
+ IncarnationGuid: '719472956608975753',
+ InstanceGuid: '11219959563151194061',
+
+ Severity: 1,
+ VDiskState: 'OK',
+ DiskSpace: 'Green',
+ FrontQueues: 'Green',
+ SatisfactionRank: {
+ FreshRank: {
+ Flag: 'Green',
+ },
+ LevelRank: {
+ Flag: 'Green',
+ },
+ },
+ Replicated: true,
+ ReplicationProgress: 1,
+ ReplicationSecondsRemaining: 0,
+ HasUnreadableBlobs: false,
+
+ ReadThroughput: '0',
+ WriteThroughput: '447',
+
+ AvailableSize: 188523479040,
+ AllocatedSize: 8996782080,
+ TotalSize: 197520261120,
+ AllocatedPercent: 5,
+ };
+
+ const preparedData = prepareWhiteboardVDiskData(data);
+
+ expect(preparedData).toEqual(expectedResult);
+ });
+ it('Should parse unavailable donors', () => {
+ const data = {
+ NodeId: 1,
+ PDiskId: 2,
+ VSlotId: 3,
+ } as const as TVSlotId;
+
+ const expectedResult = {
+ NodeId: 1,
+ PDiskId: 2,
+ VDiskSlotId: 3,
+ StringifiedId: '1-2-3',
+ };
+
+ const preparedData = prepareWhiteboardVDiskData(data);
+
+ expect(preparedData).toEqual(expectedResult);
+ });
+});
+
+describe('prepareWhiteboardPDiskData', () => {
+ it('Should correctly parse data', () => {
+ const data = {
+ PDiskId: 1,
+ ChangeTime: '1730383540716',
+ Path: '/dev/disk/by-partlabel/kikimr_nvme_01',
+ Guid: '3910585916831022250',
+ Category: '1',
+ AvailableSize: '3107979264000',
+ TotalSize: '3199556648960',
+ State: 'Normal',
+ NodeId: 1,
+ Device: 'Green',
+ Realtime: 'Green',
+ SerialNumber: '',
+ SystemSize: '817889280',
+ LogUsedSize: '1772093440',
+ LogTotalSize: '36805017600',
+ ExpectedSlotCount: 16,
+ EnforcedDynamicSlotSize: '197520261120',
+ NumActiveSlots: 10,
+ } as const as TPDiskStateInfo;
+
+ const expectedResult = {
+ PDiskId: 1,
+ NodeId: 1,
+ StringifiedId: '1-1',
+
+ Type: 'SSD',
+ Category: '1',
+ Path: '/dev/disk/by-partlabel/kikimr_nvme_01',
+ Guid: '3910585916831022250',
+ SerialNumber: '',
+
+ ChangeTime: '1730383540716',
+
+ Severity: 1,
+ Device: 'Green',
+ Realtime: 'Green',
+ State: 'Normal',
+
+ AvailableSize: 3107979264000,
+ TotalSize: 3199556648960,
+ AllocatedSize: 91577384960,
+ AllocatedPercent: 3,
+
+ ExpectedSlotCount: 16,
+ NumActiveSlots: 10,
+ SlotSize: '197520261120',
+
+ SystemSize: '817889280',
+ LogUsedSize: '1772093440',
+ LogTotalSize: '36805017600',
+ };
+
+ const preparedData = prepareWhiteboardPDiskData(data);
+
+ expect(preparedData).toEqual(expectedResult);
+ });
+});
+
+describe('prepareVDiskSizeFields', () => {
+ it('Should prepare VDisk size fields', () => {
+ expect(
+ prepareVDiskSizeFields({
+ AvailableSize: '400',
+ AllocatedSize: '100',
+ }),
+ ).toEqual({
+ AvailableSize: 400,
+ AllocatedSize: 100,
+ TotalSize: 500,
+ AllocatedPercent: 20,
+ });
+ });
+ it('Returns NaN if on undefined data', () => {
+ expect(
+ prepareVDiskSizeFields({
+ AvailableSize: undefined,
+ AllocatedSize: undefined,
+ }),
+ ).toEqual({
+ AvailableSize: NaN,
+ AllocatedSize: NaN,
+ TotalSize: NaN,
+ AllocatedPercent: NaN,
+ });
+ });
+});
+
+describe('preparePDiskSizeFields', () => {
+ it('Should prepare PDisk size fields', () => {
+ expect(
+ preparePDiskSizeFields({
+ AvailableSize: '400',
+ TotalSize: '500',
+ }),
+ ).toEqual({
+ AvailableSize: 400,
+ AllocatedSize: 100,
+ TotalSize: 500,
+ AllocatedPercent: 20,
+ });
+ });
+ it('Returns NaN if on undefined data', () => {
+ expect(
+ preparePDiskSizeFields({
+ AvailableSize: undefined,
+ TotalSize: undefined,
+ }),
+ ).toEqual({
+ AvailableSize: NaN,
+ AllocatedSize: NaN,
+ TotalSize: NaN,
+ AllocatedPercent: NaN,
+ });
+ });
+});
diff --git a/src/utils/disks/calculatePDiskSeverity.ts b/src/utils/disks/calculatePDiskSeverity.ts
index de4ddcd298..21f54a62c8 100644
--- a/src/utils/disks/calculatePDiskSeverity.ts
+++ b/src/utils/disks/calculatePDiskSeverity.ts
@@ -1,5 +1,5 @@
import {EFlag} from '../../types/api/enums';
-import type {TPDiskState, TPDiskStateInfo} from '../../types/api/pdisk';
+import type {TPDiskState} from '../../types/api/pdisk';
import {generateEvaluator} from '../generateEvaluator';
import {
@@ -10,9 +10,14 @@ import {
const getUsageSeverityForPDisk = generateEvaluator(85, 95, [EFlag.Green, EFlag.Yellow, EFlag.Red]);
-export function calculatePDiskSeverity(pDisk: TPDiskStateInfo, allocatedPercent = 0) {
+export function calculatePDiskSeverity<
+ T extends {
+ State?: TPDiskState;
+ AllocatedPercent?: number;
+ },
+>(pDisk: T) {
const stateSeverity = getStateSeverity(pDisk.State);
- const spaceSeverityFlag = getUsageSeverityForPDisk(allocatedPercent);
+ const spaceSeverityFlag = getUsageSeverityForPDisk(pDisk.AllocatedPercent || 0);
if (stateSeverity === NOT_AVAILABLE_SEVERITY || !spaceSeverityFlag) {
return stateSeverity;
diff --git a/src/utils/disks/calculateVDiskSeverity.ts b/src/utils/disks/calculateVDiskSeverity.ts
index 54d71b89f8..06808dd111 100644
--- a/src/utils/disks/calculateVDiskSeverity.ts
+++ b/src/utils/disks/calculateVDiskSeverity.ts
@@ -1,18 +1,20 @@
import type {EFlag} from '../../types/api/enums';
-import type {EVDiskState, TVDiskStateInfo} from '../../types/api/vdisk';
+import type {EVDiskState} from '../../types/api/vdisk';
import {
DISK_COLOR_STATE_TO_NUMERIC_SEVERITY,
NOT_AVAILABLE_SEVERITY,
VDISK_STATE_SEVERITY,
} from './constants';
-import {isFullVDiskData} from './helpers';
-
-export function calculateVDiskSeverity(vDisk: TVDiskStateInfo) {
- if (!isFullVDiskData(vDisk)) {
- return NOT_AVAILABLE_SEVERITY;
- }
+export function calculateVDiskSeverity<
+ T extends {
+ DiskSpace?: EFlag;
+ VDiskState?: EVDiskState;
+ FrontQueues?: EFlag;
+ Replicated?: boolean;
+ },
+>(vDisk: T) {
const {DiskSpace, VDiskState, FrontQueues, Replicated} = vDisk;
// if the disk is not available, this determines its status severity regardless of other features
diff --git a/src/utils/disks/helpers.ts b/src/utils/disks/helpers.ts
index 51719e481b..8528e4cb6d 100644
--- a/src/utils/disks/helpers.ts
+++ b/src/utils/disks/helpers.ts
@@ -7,8 +7,11 @@ import {
DISK_NUMERIC_SEVERITY_TO_STATE_COLOR,
NOT_AVAILABLE_SEVERITY_COLOR,
} from './constants';
+import type {PreparedVDisk} from './types';
-export function isFullVDiskData(disk: TVDiskStateInfo | TVSlotId): disk is TVDiskStateInfo {
+export function isFullVDiskData(
+ disk: PreparedVDisk | TVDiskStateInfo | TVSlotId,
+): disk is PreparedVDisk | TVDiskStateInfo {
return 'VDiskId' in disk;
}
diff --git a/src/utils/disks/prepareDisks.ts b/src/utils/disks/prepareDisks.ts
index 745a0a981a..dbd6f486b6 100644
--- a/src/utils/disks/prepareDisks.ts
+++ b/src/utils/disks/prepareDisks.ts
@@ -1,70 +1,155 @@
-import type {TPDiskInfo, TPDiskStateInfo} from '../../types/api/pdisk';
-import type {TVDiskStateInfo} from '../../types/api/vdisk';
+import type {TPDiskStateInfo} from '../../types/api/pdisk';
+import type {TVDiskStateInfo, TVSlotId} from '../../types/api/vdisk';
import {stringifyVdiskId} from '../dataFormatters/dataFormatters';
import {calculatePDiskSeverity} from './calculatePDiskSeverity';
import {calculateVDiskSeverity} from './calculateVDiskSeverity';
import {getPDiskType} from './getPDiskType';
+import {getPDiskId, isFullVDiskData} from './helpers';
import type {PreparedPDisk, PreparedVDisk} from './types';
-export function prepareVDiskData(vdiskState: TVDiskStateInfo = {}): PreparedVDisk {
+export function prepareWhiteboardVDiskData(
+ vDiskState: TVDiskStateInfo | TVSlotId = {},
+): PreparedVDisk {
+ if (!isFullVDiskData(vDiskState)) {
+ const {NodeId, PDiskId, VSlotId} = vDiskState;
+
+ const StringifiedId = stringifyVdiskId({
+ NodeId,
+ PDiskId,
+ VSlotId,
+ });
+
+ return {
+ StringifiedId,
+ NodeId,
+ PDiskId,
+ // Replace VSlotId with VDiskSlotId to match with PreparedVDisk type
+ VDiskSlotId: VSlotId,
+ };
+ }
+
+ const {
+ PDisk,
+ PDiskId,
+ VDiskId,
+ NodeId,
+ Donors,
+ AvailableSize,
+ AllocatedSize,
+ ...restVDiskFields
+ } = vDiskState;
+
// Prepare PDisk only if it is present
- const PDisk = vdiskState.PDisk
- ? preparePDiskData({
- ...vdiskState.PDisk,
- NodeId: vdiskState.PDisk.NodeId ?? vdiskState.NodeId,
- })
+ const preparedPDisk = PDisk
+ ? prepareWhiteboardPDiskData({...PDisk, NodeId: PDisk?.NodeId ?? NodeId})
: undefined;
- const PDiskId = vdiskState.PDiskId ?? PDisk?.PDiskId;
+ const actualPDiskId = PDiskId ?? preparedPDisk?.PDiskId;
- const available = Number(vdiskState.AvailableSize ?? PDisk?.AvailableSize);
- const allocated = Number(vdiskState.AllocatedSize);
- const total = allocated + available;
- const allocatedPercent = Math.round((allocated * 100) / total);
+ const vDiskSizeFields = prepareVDiskSizeFields({
+ AvailableSize: AvailableSize ?? PDisk?.AvailableSize,
+ AllocatedSize: AllocatedSize,
+ });
+
+ const Severity = calculateVDiskSeverity(vDiskState);
+
+ const StringifiedId = stringifyVdiskId(VDiskId);
- const Donors = vdiskState.Donors?.map((donor) => {
- return prepareVDiskData({...donor, DonorMode: true});
+ const preparedDonors = Donors?.map((donor) => {
+ return prepareWhiteboardVDiskData({...donor, DonorMode: true});
});
- const Severity = calculateVDiskSeverity(vdiskState);
+ return {
+ ...restVDiskFields,
+ ...vDiskSizeFields,
+
+ VDiskId,
+ NodeId,
+ PDiskId: actualPDiskId,
+ PDisk: preparedPDisk,
+ Donors: preparedDonors,
+
+ Severity,
+ StringifiedId,
+ };
+}
+
+export function prepareWhiteboardPDiskData(pdiskState: TPDiskStateInfo = {}): PreparedPDisk {
+ const {
+ AvailableSize,
+ TotalSize,
+ Category,
+ State,
+ PDiskId,
+ NodeId,
+ EnforcedDynamicSlotSize,
+ ...restPDiskFields
+ } = pdiskState;
+
+ const StringifiedId = getPDiskId(PDiskId, NodeId);
+
+ const Type = getPDiskType(Category);
+
+ const pdiskPreparedSizeFields = preparePDiskSizeFields({
+ AvailableSize,
+ TotalSize,
+ });
- const StringifiedId = stringifyVdiskId(vdiskState.VDiskId);
+ const Severity = calculatePDiskSeverity({
+ State,
+ AllocatedPercent: pdiskPreparedSizeFields.AllocatedPercent,
+ });
return {
- ...vdiskState,
- PDisk,
+ ...restPDiskFields,
+ ...pdiskPreparedSizeFields,
PDiskId,
- Donors,
- Severity,
+ NodeId,
StringifiedId,
+ Type,
+ Category,
+ State,
+ Severity,
+ SlotSize: EnforcedDynamicSlotSize,
+ };
+}
+
+export function prepareVDiskSizeFields({
+ AvailableSize,
+ AllocatedSize,
+}: {
+ AvailableSize: string | number | undefined;
+ AllocatedSize: string | number | undefined;
+}) {
+ const available = Number(AvailableSize);
+ const allocated = Number(AllocatedSize);
+ const total = allocated + available;
+ const allocatedPercent = Math.round((allocated * 100) / total);
+ return {
+ AvailableSize: available,
+ AllocatedSize: allocated,
TotalSize: total,
AllocatedPercent: allocatedPercent,
};
}
-export function preparePDiskData(
- pdiskState: TPDiskStateInfo = {},
- bscPDiskInfo: TPDiskInfo = {},
-): PreparedPDisk {
- const {AvailableSize, TotalSize, Category} = pdiskState;
-
- const Type = getPDiskType(Category);
-
+export function preparePDiskSizeFields({
+ AvailableSize,
+ TotalSize,
+}: {
+ AvailableSize: string | number | undefined;
+ TotalSize: string | number | undefined;
+}) {
const available = Number(AvailableSize);
const total = Number(TotalSize);
const allocated = total - available;
const allocatedPercent = Math.round((allocated * 100) / total);
- const Severity = calculatePDiskSeverity(pdiskState, allocatedPercent);
-
return {
- ...bscPDiskInfo,
- ...pdiskState,
- Type,
- Severity,
-
+ AvailableSize: available,
+ TotalSize: total,
AllocatedSize: allocated,
AllocatedPercent: allocatedPercent,
};
diff --git a/src/utils/disks/types.ts b/src/utils/disks/types.ts
index ad7e93d262..45371819fd 100644
--- a/src/utils/disks/types.ts
+++ b/src/utils/disks/types.ts
@@ -4,22 +4,35 @@ import type {ValueOf} from '../../types/common';
import type {PDISK_TYPES} from './getPDiskType';
-export type PreparedPDisk = TPDiskStateInfo &
- Omit, 'Type'> & {
+export type PreparedPDisk = Omit<
+ TPDiskStateInfo,
+ 'AvailableSize' | 'TotalSize' | 'EnforcedDynamicSlotSize'
+> &
+ Omit, 'Type' | 'AvailableSize' | 'TotalSize'> & {
Type?: PDiskType;
Severity?: number;
+ StringifiedId?: string;
+ AvailableSize?: number;
+ TotalSize?: number;
AllocatedSize?: number;
AllocatedPercent?: number;
+
+ SlotSize?: string;
};
-export interface PreparedVDisk extends TVDiskStateInfo {
+export interface PreparedVDisk
+ extends Omit {
PDisk?: PreparedPDisk;
Severity?: number;
StringifiedId?: string;
+ AvailableSize?: number;
TotalSize?: number;
+ AllocatedSize?: number;
AllocatedPercent?: number;
+
+ Donors?: PreparedVDisk[];
}
export type PDiskType = ValueOf;