From 006f56f0307fba91f2f86814039e7de9d613bd4c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 21 Jul 2025 08:26:52 +0000 Subject: [PATCH 01/12] Initial plan From 02709c3aaddbd059dd7c476bf1dbadf17801df8e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 21 Jul 2025 08:43:29 +0000 Subject: [PATCH 02/12] Add replication progress, remaining time, and donors info to VDisk page Co-authored-by: antonkovalenko <692649+antonkovalenko@users.noreply.github.com> --- src/components/VDiskInfo/VDiskInfo.tsx | 52 +++++++++++++++++++++++++- src/components/VDiskInfo/i18n/en.json | 3 ++ 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/src/components/VDiskInfo/VDiskInfo.tsx b/src/components/VDiskInfo/VDiskInfo.tsx index 3013b521bb..653283b53f 100644 --- a/src/components/VDiskInfo/VDiskInfo.tsx +++ b/src/components/VDiskInfo/VDiskInfo.tsx @@ -5,9 +5,13 @@ import {Flex} from '@gravity-ui/uikit'; import {getVDiskPagePath} from '../../routes'; import {valueIsDefined} from '../../utils'; import {cn} from '../../utils/cn'; -import {formatStorageValuesToGb} from '../../utils/dataFormatters/dataFormatters'; +import { + formatStorageValuesToGb, + formatUptimeInSeconds, + stringifyVdiskId, +} from '../../utils/dataFormatters/dataFormatters'; import {createVDiskDeveloperUILink} from '../../utils/developerUI/developerUI'; -import {getSeverityColor} from '../../utils/disks/helpers'; +import {getSeverityColor, isFullVDiskData} from '../../utils/disks/helpers'; import type {PreparedVDisk} from '../../utils/disks/types'; import {useIsUserAllowedToMakeChanges} from '../../utils/hooks/useIsUserAllowedToMakeChanges'; import {bytesToSpeed} from '../../utils/utils'; @@ -46,6 +50,9 @@ export function VDiskInfo({ FrontQueues, Guid, Replicated, + ReplicationProgress, + ReplicationSecondsRemaining, + Donors, VDiskState, VDiskSlotId, Kind, @@ -130,6 +137,31 @@ export function VDiskInfo({ value: Replicated ? vDiskInfoKeyset('yes') : vDiskInfoKeyset('no'), }); } + if (valueIsDefined(ReplicationProgress)) { + rightColumn.push({ + label: vDiskInfoKeyset('replication-progress'), + value: ( + [ + `${Math.round((value || 0) * 100)}%`, + `${Math.round((capacity || 1) * 100)}%`, + ]} + colorizeProgress={true} + /> + ), + }); + } + if (valueIsDefined(ReplicationSecondsRemaining)) { + const timeRemaining = formatUptimeInSeconds(ReplicationSecondsRemaining); + if (timeRemaining) { + rightColumn.push({ + label: vDiskInfoKeyset('replication-time-remaining'), + value: timeRemaining, + }); + } + } if (valueIsDefined(VDiskSlotId)) { rightColumn.push({label: vDiskInfoKeyset('slot-id'), value: VDiskSlotId}); } @@ -152,6 +184,22 @@ export function VDiskInfo({ value: HasUnreadableBlobs ? vDiskInfoKeyset('yes') : vDiskInfoKeyset('no'), }); } + if (Donors && Donors.length > 0) { + const donorsList = Donors.map((donor) => { + const isFullData = isFullVDiskData(donor); + const donorId = stringifyVdiskId(isFullData ? donor.VDiskId : donor); + return donorId; + }) + .filter(Boolean) + .join(', '); + + if (donorsList) { + rightColumn.push({ + label: vDiskInfoKeyset('donors'), + value: donorsList, + }); + } + } const diskParamsDefined = valueIsDefined(PDiskId) && valueIsDefined(NodeId) && valueIsDefined(VDiskSlotId); diff --git a/src/components/VDiskInfo/i18n/en.json b/src/components/VDiskInfo/i18n/en.json index e87bf2694b..6062b3736d 100644 --- a/src/components/VDiskInfo/i18n/en.json +++ b/src/components/VDiskInfo/i18n/en.json @@ -8,6 +8,9 @@ "instance-guid": "Instance GUID", "replication-status": "Replicated", + "replication-progress": "Replication Progress", + "replication-time-remaining": "Time Remaining", + "donors": "Donors", "state-status": "VDisk State", "space-status": "Disk Space", From 8c89486da0ace0ba52288302d6e7d42de251f77e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 21 Jul 2025 08:47:12 +0000 Subject: [PATCH 03/12] Add replication progress and time remaining to VDisk tooltip Co-authored-by: antonkovalenko <692649+antonkovalenko@users.noreply.github.com> --- src/components/VDiskPopup/VDiskPopup.tsx | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/components/VDiskPopup/VDiskPopup.tsx b/src/components/VDiskPopup/VDiskPopup.tsx index 84199c3426..0ad1052c1e 100644 --- a/src/components/VDiskPopup/VDiskPopup.tsx +++ b/src/components/VDiskPopup/VDiskPopup.tsx @@ -7,6 +7,7 @@ import {EFlag} from '../../types/api/enums'; import {valueIsDefined} from '../../utils'; import {cn} from '../../utils/cn'; import {EMPTY_DATA_PLACEHOLDER} from '../../utils/constants'; +import {formatUptimeInSeconds} from '../../utils/dataFormatters/dataFormatters'; import {createVDiskDeveloperUILink} from '../../utils/developerUI/developerUI'; import {isFullVDiskData} from '../../utils/disks/helpers'; import type {PreparedVDisk, UnavailableDonor} from '../../utils/disks/types'; @@ -73,6 +74,8 @@ const prepareVDiskData = (data: PreparedVDisk, withDeveloperUILink?: boolean) => DiskSpace, FrontQueues, Replicated, + ReplicationProgress, + ReplicationSecondsRemaining, UnsyncedVDisks, AllocatedSize, ReadThroughput, @@ -129,6 +132,24 @@ const prepareVDiskData = (data: PreparedVDisk, withDeveloperUILink?: boolean) => vdiskData.push({label: 'Replicated', value: 'NO'}); } + if (valueIsDefined(ReplicationProgress)) { + const progressPercent = Math.round(ReplicationProgress * 100); + vdiskData.push({ + label: 'Replication Progress', + value: `${progressPercent}%`, + }); + } + + if (valueIsDefined(ReplicationSecondsRemaining)) { + const timeRemaining = formatUptimeInSeconds(ReplicationSecondsRemaining); + if (timeRemaining) { + vdiskData.push({ + label: 'Time Remaining', + value: timeRemaining, + }); + } + } + if (UnsyncedVDisks) { vdiskData.push({label: 'UnsyncVDisks', value: UnsyncedVDisks}); } From 3740536d700269ed22a4394c9b5f937591418adf Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 22 Jul 2025 05:45:46 +0000 Subject: [PATCH 04/12] Fix replication fields visibility and color handling - Only show replication progress and time remaining when disk is not replicated (Replicated=false) - Add inverseColorize=true to make 100% progress show as green instead of red - Update both VDiskInfo and VDiskPopup components to respect replication status Co-authored-by: adameat <34044711+adameat@users.noreply.github.com> --- src/components/VDiskInfo/VDiskInfo.tsx | 46 +++++++++++++----------- src/components/VDiskPopup/VDiskPopup.tsx | 29 +++++++-------- 2 files changed, 40 insertions(+), 35 deletions(-) diff --git a/src/components/VDiskInfo/VDiskInfo.tsx b/src/components/VDiskInfo/VDiskInfo.tsx index 653283b53f..1b50828cab 100644 --- a/src/components/VDiskInfo/VDiskInfo.tsx +++ b/src/components/VDiskInfo/VDiskInfo.tsx @@ -137,30 +137,34 @@ export function VDiskInfo({ value: Replicated ? vDiskInfoKeyset('yes') : vDiskInfoKeyset('no'), }); } - if (valueIsDefined(ReplicationProgress)) { - rightColumn.push({ - label: vDiskInfoKeyset('replication-progress'), - value: ( - [ - `${Math.round((value || 0) * 100)}%`, - `${Math.round((capacity || 1) * 100)}%`, - ]} - colorizeProgress={true} - /> - ), - }); - } - if (valueIsDefined(ReplicationSecondsRemaining)) { - const timeRemaining = formatUptimeInSeconds(ReplicationSecondsRemaining); - if (timeRemaining) { + // Only show replication progress and time remaining when disk is not replicated + if (Replicated === false) { + if (valueIsDefined(ReplicationProgress)) { rightColumn.push({ - label: vDiskInfoKeyset('replication-time-remaining'), - value: timeRemaining, + label: vDiskInfoKeyset('replication-progress'), + value: ( + [ + `${Math.round((value || 0) * 100)}%`, + `${Math.round((capacity || 1) * 100)}%`, + ]} + colorizeProgress={true} + inverseColorize={true} + /> + ), }); } + if (valueIsDefined(ReplicationSecondsRemaining)) { + const timeRemaining = formatUptimeInSeconds(ReplicationSecondsRemaining); + if (timeRemaining) { + rightColumn.push({ + label: vDiskInfoKeyset('replication-time-remaining'), + value: timeRemaining, + }); + } + } } if (valueIsDefined(VDiskSlotId)) { rightColumn.push({label: vDiskInfoKeyset('slot-id'), value: VDiskSlotId}); diff --git a/src/components/VDiskPopup/VDiskPopup.tsx b/src/components/VDiskPopup/VDiskPopup.tsx index 0ad1052c1e..5e5e0fba99 100644 --- a/src/components/VDiskPopup/VDiskPopup.tsx +++ b/src/components/VDiskPopup/VDiskPopup.tsx @@ -130,24 +130,25 @@ const prepareVDiskData = (data: PreparedVDisk, withDeveloperUILink?: boolean) => if (Replicated === false) { vdiskData.push({label: 'Replicated', value: 'NO'}); - } - if (valueIsDefined(ReplicationProgress)) { - const progressPercent = Math.round(ReplicationProgress * 100); - vdiskData.push({ - label: 'Replication Progress', - value: `${progressPercent}%`, - }); - } - - if (valueIsDefined(ReplicationSecondsRemaining)) { - const timeRemaining = formatUptimeInSeconds(ReplicationSecondsRemaining); - if (timeRemaining) { + // Only show replication progress and time remaining when disk is not replicated + if (valueIsDefined(ReplicationProgress)) { + const progressPercent = Math.round(ReplicationProgress * 100); vdiskData.push({ - label: 'Time Remaining', - value: timeRemaining, + label: 'Replication Progress', + value: `${progressPercent}%`, }); } + + if (valueIsDefined(ReplicationSecondsRemaining)) { + const timeRemaining = formatUptimeInSeconds(ReplicationSecondsRemaining); + if (timeRemaining) { + vdiskData.push({ + label: 'Time Remaining', + value: timeRemaining, + }); + } + } } if (UnsyncedVDisks) { From 763bb573143531495fec853da3aa2d442dd9b198 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 22 Jul 2025 10:12:09 +0000 Subject: [PATCH 05/12] Fix VDisk replication UI issues: state condition, progress color, duplicate donors Co-authored-by: adameat <34044711+adameat@users.noreply.github.com> --- src/components/VDiskInfo/VDiskInfo.tsx | 27 ++++++------------------ src/components/VDiskPopup/VDiskPopup.tsx | 5 +++-- 2 files changed, 9 insertions(+), 23 deletions(-) diff --git a/src/components/VDiskInfo/VDiskInfo.tsx b/src/components/VDiskInfo/VDiskInfo.tsx index 1b50828cab..e57adc163e 100644 --- a/src/components/VDiskInfo/VDiskInfo.tsx +++ b/src/components/VDiskInfo/VDiskInfo.tsx @@ -3,15 +3,15 @@ import React from 'react'; import {Flex} from '@gravity-ui/uikit'; import {getVDiskPagePath} from '../../routes'; +import {EVDiskState} from '../../types/api/vdisk'; import {valueIsDefined} from '../../utils'; import {cn} from '../../utils/cn'; import { formatStorageValuesToGb, formatUptimeInSeconds, - stringifyVdiskId, } from '../../utils/dataFormatters/dataFormatters'; import {createVDiskDeveloperUILink} from '../../utils/developerUI/developerUI'; -import {getSeverityColor, isFullVDiskData} from '../../utils/disks/helpers'; +import {getSeverityColor} from '../../utils/disks/helpers'; import type {PreparedVDisk} from '../../utils/disks/types'; import {useIsUserAllowedToMakeChanges} from '../../utils/hooks/useIsUserAllowedToMakeChanges'; import {bytesToSpeed} from '../../utils/utils'; @@ -52,7 +52,6 @@ export function VDiskInfo({ Replicated, ReplicationProgress, ReplicationSecondsRemaining, - Donors, VDiskState, VDiskSlotId, Kind, @@ -137,8 +136,8 @@ export function VDiskInfo({ value: Replicated ? vDiskInfoKeyset('yes') : vDiskInfoKeyset('no'), }); } - // Only show replication progress and time remaining when disk is not replicated - if (Replicated === false) { + // Only show replication progress and time remaining when disk is not replicated and state is OK + if (Replicated === false && VDiskState === EVDiskState.OK) { if (valueIsDefined(ReplicationProgress)) { rightColumn.push({ label: vDiskInfoKeyset('replication-progress'), @@ -152,6 +151,8 @@ export function VDiskInfo({ ]} colorizeProgress={true} inverseColorize={true} + dangerThreshold={0} + warningThreshold={0} /> ), }); @@ -188,22 +189,6 @@ export function VDiskInfo({ value: HasUnreadableBlobs ? vDiskInfoKeyset('yes') : vDiskInfoKeyset('no'), }); } - if (Donors && Donors.length > 0) { - const donorsList = Donors.map((donor) => { - const isFullData = isFullVDiskData(donor); - const donorId = stringifyVdiskId(isFullData ? donor.VDiskId : donor); - return donorId; - }) - .filter(Boolean) - .join(', '); - - if (donorsList) { - rightColumn.push({ - label: vDiskInfoKeyset('donors'), - value: donorsList, - }); - } - } const diskParamsDefined = valueIsDefined(PDiskId) && valueIsDefined(NodeId) && valueIsDefined(VDiskSlotId); diff --git a/src/components/VDiskPopup/VDiskPopup.tsx b/src/components/VDiskPopup/VDiskPopup.tsx index 5e5e0fba99..c9e308f532 100644 --- a/src/components/VDiskPopup/VDiskPopup.tsx +++ b/src/components/VDiskPopup/VDiskPopup.tsx @@ -4,6 +4,7 @@ import {Flex, Label} from '@gravity-ui/uikit'; import {selectNodesMap} from '../../store/reducers/nodesList'; import {EFlag} from '../../types/api/enums'; +import {EVDiskState} from '../../types/api/vdisk'; import {valueIsDefined} from '../../utils'; import {cn} from '../../utils/cn'; import {EMPTY_DATA_PLACEHOLDER} from '../../utils/constants'; @@ -128,10 +129,10 @@ const prepareVDiskData = (data: PreparedVDisk, withDeveloperUILink?: boolean) => vdiskData.push({label: 'FrontQueues', value: FrontQueues}); } - if (Replicated === false) { + if (Replicated === false && VDiskState === EVDiskState.OK) { vdiskData.push({label: 'Replicated', value: 'NO'}); - // Only show replication progress and time remaining when disk is not replicated + // Only show replication progress and time remaining when disk is not replicated and state is OK if (valueIsDefined(ReplicationProgress)) { const progressPercent = Math.round(ReplicationProgress * 100); vdiskData.push({ From a7d356cd41781e2098e5b7d099e8b43863cdc945 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 22 Jul 2025 10:46:25 +0000 Subject: [PATCH 06/12] Fix replication UI issues: remove "/ 100%" format and improve tooltip alignment Co-authored-by: adameat <34044711+adameat@users.noreply.github.com> --- src/components/VDiskInfo/VDiskInfo.tsx | 6 ++---- src/components/VDiskPopup/VDiskPopup.tsx | 4 ++-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/components/VDiskInfo/VDiskInfo.tsx b/src/components/VDiskInfo/VDiskInfo.tsx index e57adc163e..edc6f85992 100644 --- a/src/components/VDiskInfo/VDiskInfo.tsx +++ b/src/components/VDiskInfo/VDiskInfo.tsx @@ -145,14 +145,12 @@ export function VDiskInfo({ [ - `${Math.round((value || 0) * 100)}%`, - `${Math.round((capacity || 1) * 100)}%`, - ]} + formatValues={(value) => [`${Math.round((value || 0) * 100)}%`]} colorizeProgress={true} inverseColorize={true} dangerThreshold={0} warningThreshold={0} + hideCapacity={true} /> ), }); diff --git a/src/components/VDiskPopup/VDiskPopup.tsx b/src/components/VDiskPopup/VDiskPopup.tsx index c9e308f532..ace30002ec 100644 --- a/src/components/VDiskPopup/VDiskPopup.tsx +++ b/src/components/VDiskPopup/VDiskPopup.tsx @@ -136,7 +136,7 @@ const prepareVDiskData = (data: PreparedVDisk, withDeveloperUILink?: boolean) => if (valueIsDefined(ReplicationProgress)) { const progressPercent = Math.round(ReplicationProgress * 100); vdiskData.push({ - label: 'Replication Progress', + label: 'Progress', value: `${progressPercent}%`, }); } @@ -145,7 +145,7 @@ const prepareVDiskData = (data: PreparedVDisk, withDeveloperUILink?: boolean) => const timeRemaining = formatUptimeInSeconds(ReplicationSecondsRemaining); if (timeRemaining) { vdiskData.push({ - label: 'Time Remaining', + label: 'Remaining', value: timeRemaining, }); } From 1b181ee15cc6bdd997bf0622d175c1815c8ef1fa Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 22 Jul 2025 11:09:13 +0000 Subject: [PATCH 07/12] Fix donors display: add back to main UI and improve TVSlotId processing Co-authored-by: adameat <34044711+adameat@users.noreply.github.com> --- src/components/VDiskInfo/VDiskInfo.tsx | 30 +++++++++++++++++++++++++- src/utils/disks/prepareDisks.ts | 23 ++++++++++++++++++-- 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/src/components/VDiskInfo/VDiskInfo.tsx b/src/components/VDiskInfo/VDiskInfo.tsx index edc6f85992..9761e330a9 100644 --- a/src/components/VDiskInfo/VDiskInfo.tsx +++ b/src/components/VDiskInfo/VDiskInfo.tsx @@ -9,9 +9,10 @@ import {cn} from '../../utils/cn'; import { formatStorageValuesToGb, formatUptimeInSeconds, + stringifyVdiskId, } from '../../utils/dataFormatters/dataFormatters'; import {createVDiskDeveloperUILink} from '../../utils/developerUI/developerUI'; -import {getSeverityColor} from '../../utils/disks/helpers'; +import {getSeverityColor, isFullVDiskData} from '../../utils/disks/helpers'; import type {PreparedVDisk} from '../../utils/disks/types'; import {useIsUserAllowedToMakeChanges} from '../../utils/hooks/useIsUserAllowedToMakeChanges'; import {bytesToSpeed} from '../../utils/utils'; @@ -52,6 +53,7 @@ export function VDiskInfo({ Replicated, ReplicationProgress, ReplicationSecondsRemaining, + Donors, VDiskState, VDiskSlotId, Kind, @@ -188,6 +190,32 @@ export function VDiskInfo({ }); } + // Show donors list when replication is in progress + if (Replicated === false && VDiskState === EVDiskState.OK && Donors && Donors.length > 0) { + const donorsList = Donors.map((donor) => { + if (isFullVDiskData(donor)) { + // Full VDisk data - use VDiskId if available + return stringifyVdiskId(donor.VDiskId); + } else { + // TVSlotId data - construct from NodeId-PDiskId-VSlotId + const {NodeId: dNodeId, PDiskId: dPDiskId, VSlotId} = donor; + if (valueIsDefined(dNodeId) && valueIsDefined(dPDiskId) && valueIsDefined(VSlotId)) { + return `${dNodeId}-${dPDiskId}-${VSlotId}`; + } + return null; + } + }) + .filter(Boolean) + .join(', '); + + if (donorsList) { + rightColumn.push({ + label: vDiskInfoKeyset('donors'), + value: donorsList, + }); + } + } + const diskParamsDefined = valueIsDefined(PDiskId) && valueIsDefined(NodeId) && valueIsDefined(VDiskSlotId); diff --git a/src/utils/disks/prepareDisks.ts b/src/utils/disks/prepareDisks.ts index f77bc75555..6a0d8b7567 100644 --- a/src/utils/disks/prepareDisks.ts +++ b/src/utils/disks/prepareDisks.ts @@ -63,8 +63,27 @@ export function prepareWhiteboardVDiskData( const StringifiedId = stringifyVdiskId(VDiskId); const preparedDonors = Donors?.map((donor) => { - return prepareWhiteboardVDiskData({...donor, DonorMode: true}); - }); + // Handle both TVDiskStateInfo and TVSlotId donor types + if (isFullVDiskData(donor)) { + // Full VDisk data + return prepareWhiteboardVDiskData({...donor, DonorMode: true}); + } else { + // TVSlotId data - create a minimal PreparedVDisk + const {NodeId: dNodeId, PDiskId: dPDiskId, VSlotId} = donor; + const StringifiedId = + valueIsDefined(dNodeId) && valueIsDefined(dPDiskId) && valueIsDefined(VSlotId) + ? `${dNodeId}-${dPDiskId}-${VSlotId}` + : ''; + + return { + NodeId: dNodeId, + PDiskId: dPDiskId, + VDiskSlotId: VSlotId, + StringifiedId, + DonorMode: true, + } as PreparedVDisk; + } + }).filter((donor) => donor.StringifiedId); return { ...restVDiskFields, From 2ae6ca8e303a3b9b415527c851f054d0cd9faad7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 22 Jul 2025 11:40:13 +0000 Subject: [PATCH 08/12] Fix donors list display in VDisk main page by simplifying data access Co-authored-by: adameat <34044711+adameat@users.noreply.github.com> --- src/components/VDiskInfo/VDiskInfo.tsx | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/src/components/VDiskInfo/VDiskInfo.tsx b/src/components/VDiskInfo/VDiskInfo.tsx index 9761e330a9..c5af964fb0 100644 --- a/src/components/VDiskInfo/VDiskInfo.tsx +++ b/src/components/VDiskInfo/VDiskInfo.tsx @@ -9,10 +9,9 @@ import {cn} from '../../utils/cn'; import { formatStorageValuesToGb, formatUptimeInSeconds, - stringifyVdiskId, } from '../../utils/dataFormatters/dataFormatters'; import {createVDiskDeveloperUILink} from '../../utils/developerUI/developerUI'; -import {getSeverityColor, isFullVDiskData} from '../../utils/disks/helpers'; +import {getSeverityColor} from '../../utils/disks/helpers'; import type {PreparedVDisk} from '../../utils/disks/types'; import {useIsUserAllowedToMakeChanges} from '../../utils/hooks/useIsUserAllowedToMakeChanges'; import {bytesToSpeed} from '../../utils/utils'; @@ -190,21 +189,9 @@ export function VDiskInfo({ }); } - // Show donors list when replication is in progress + // Show donors list when replication is in progress if (Replicated === false && VDiskState === EVDiskState.OK && Donors && Donors.length > 0) { - const donorsList = Donors.map((donor) => { - if (isFullVDiskData(donor)) { - // Full VDisk data - use VDiskId if available - return stringifyVdiskId(donor.VDiskId); - } else { - // TVSlotId data - construct from NodeId-PDiskId-VSlotId - const {NodeId: dNodeId, PDiskId: dPDiskId, VSlotId} = donor; - if (valueIsDefined(dNodeId) && valueIsDefined(dPDiskId) && valueIsDefined(VSlotId)) { - return `${dNodeId}-${dPDiskId}-${VSlotId}`; - } - return null; - } - }) + const donorsList = Donors.map((donor) => donor.StringifiedId) .filter(Boolean) .join(', '); From 2ebbecb3de418cbb6b3d46d3ba516efa9239dce1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 22 Jul 2025 12:20:01 +0000 Subject: [PATCH 09/12] Convert donors list to clickable links to VDisk pages Co-authored-by: adameat <34044711+adameat@users.noreply.github.com> --- src/components/VDiskInfo/VDiskInfo.tsx | 33 ++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/src/components/VDiskInfo/VDiskInfo.tsx b/src/components/VDiskInfo/VDiskInfo.tsx index c5af964fb0..d2aebf23bf 100644 --- a/src/components/VDiskInfo/VDiskInfo.tsx +++ b/src/components/VDiskInfo/VDiskInfo.tsx @@ -16,6 +16,7 @@ import type {PreparedVDisk} from '../../utils/disks/types'; import {useIsUserAllowedToMakeChanges} from '../../utils/hooks/useIsUserAllowedToMakeChanges'; import {bytesToSpeed} from '../../utils/utils'; import {InfoViewer} from '../InfoViewer'; +import {InternalLink} from '../InternalLink'; import {LinkWithIcon} from '../LinkWithIcon/LinkWithIcon'; import {ProgressViewer} from '../ProgressViewer/ProgressViewer'; import {StatusIcon} from '../StatusIcon/StatusIcon'; @@ -191,14 +192,36 @@ export function VDiskInfo({ // Show donors list when replication is in progress if (Replicated === false && VDiskState === EVDiskState.OK && Donors && Donors.length > 0) { - const donorsList = Donors.map((donor) => donor.StringifiedId) - .filter(Boolean) - .join(', '); + const donorLinks = Donors.map((donor, index) => { + if (!donor.StringifiedId) { + return null; + } + + // Parse StringifiedId format: "nodeId-pDiskId-vDiskSlotId" + const parts = donor.StringifiedId.split('-'); + if (parts.length !== 3) { + return donor.StringifiedId; + } + + const [nodeId, pDiskId, vDiskSlotId] = parts; + const vDiskPath = getVDiskPagePath({ + nodeId: parseInt(nodeId), + pDiskId: parseInt(pDiskId), + vDiskSlotId: parseInt(vDiskSlotId), + }); + + return ( + + {index > 0 && ', '} + {donor.StringifiedId} + + ); + }).filter(Boolean); - if (donorsList) { + if (donorLinks.length > 0) { rightColumn.push({ label: vDiskInfoKeyset('donors'), - value: donorsList, + value: <>{donorLinks}, }); } } From 85191b071d4cf0da28c773ad10ef2c7268149fbf Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 22 Jul 2025 12:36:38 +0000 Subject: [PATCH 10/12] Change donors list to vertical layout instead of horizontal Co-authored-by: adameat <34044711+adameat@users.noreply.github.com> --- src/components/VDiskInfo/VDiskInfo.tsx | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/components/VDiskInfo/VDiskInfo.tsx b/src/components/VDiskInfo/VDiskInfo.tsx index d2aebf23bf..e8335c9093 100644 --- a/src/components/VDiskInfo/VDiskInfo.tsx +++ b/src/components/VDiskInfo/VDiskInfo.tsx @@ -211,17 +211,20 @@ export function VDiskInfo({ }); return ( - - {index > 0 && ', '} - {donor.StringifiedId} - + + {donor.StringifiedId} + ); }).filter(Boolean); if (donorLinks.length > 0) { rightColumn.push({ label: vDiskInfoKeyset('donors'), - value: <>{donorLinks}, + value: ( + + {donorLinks} + + ), }); } } From 4fbf95b4bf6e49328f4495c4ccbd3f2e68c576a6 Mon Sep 17 00:00:00 2001 From: Elena Makarova Date: Wed, 23 Jul 2025 09:28:13 +0300 Subject: [PATCH 11/12] fix: review --- src/components/VDiskInfo/VDiskInfo.tsx | 36 ++++++++++++-------------- src/utils/disks/prepareDisks.ts | 22 +++++++++------- 2 files changed, 28 insertions(+), 30 deletions(-) diff --git a/src/components/VDiskInfo/VDiskInfo.tsx b/src/components/VDiskInfo/VDiskInfo.tsx index e8335c9093..2eeceb63d4 100644 --- a/src/components/VDiskInfo/VDiskInfo.tsx +++ b/src/components/VDiskInfo/VDiskInfo.tsx @@ -145,14 +145,10 @@ export function VDiskInfo({ label: vDiskInfoKeyset('replication-progress'), value: ( [`${Math.round((value || 0) * 100)}%`]} + value={Math.round(ReplicationProgress * 100)} + percents colorizeProgress={true} - inverseColorize={true} - dangerThreshold={0} - warningThreshold={0} - hideCapacity={true} + capacity={100} /> ), }); @@ -191,28 +187,28 @@ export function VDiskInfo({ } // Show donors list when replication is in progress - if (Replicated === false && VDiskState === EVDiskState.OK && Donors && Donors.length > 0) { + if (Replicated === false && VDiskState === EVDiskState.OK && Donors?.length) { const donorLinks = Donors.map((donor, index) => { - if (!donor.StringifiedId) { - return null; - } + const { + StringifiedId: id, + NodeId: dNodeId, + PDiskId: dPDiskId, + VDiskSlotId: dVSlotId, + } = donor; - // Parse StringifiedId format: "nodeId-pDiskId-vDiskSlotId" - const parts = donor.StringifiedId.split('-'); - if (parts.length !== 3) { - return donor.StringifiedId; + if (!id || !dVSlotId || !dNodeId || !dPDiskId) { + return null; } - const [nodeId, pDiskId, vDiskSlotId] = parts; const vDiskPath = getVDiskPagePath({ - nodeId: parseInt(nodeId), - pDiskId: parseInt(pDiskId), - vDiskSlotId: parseInt(vDiskSlotId), + nodeId: dNodeId, + pDiskId: dPDiskId, + vDiskSlotId: dVSlotId, }); return ( - {donor.StringifiedId} + {id} ); }).filter(Boolean); diff --git a/src/utils/disks/prepareDisks.ts b/src/utils/disks/prepareDisks.ts index 6a0d8b7567..efe4d24ccc 100644 --- a/src/utils/disks/prepareDisks.ts +++ b/src/utils/disks/prepareDisks.ts @@ -1,3 +1,5 @@ +import {isNil} from 'lodash'; + import {valueIsDefined} from '..'; import type {TPDiskStateInfo} from '../../types/api/pdisk'; import type {TVDiskStateInfo, TVSlotId} from '../../types/api/vdisk'; @@ -69,21 +71,21 @@ export function prepareWhiteboardVDiskData( return prepareWhiteboardVDiskData({...donor, DonorMode: true}); } else { // TVSlotId data - create a minimal PreparedVDisk - const {NodeId: dNodeId, PDiskId: dPDiskId, VSlotId} = donor; - const StringifiedId = - valueIsDefined(dNodeId) && valueIsDefined(dPDiskId) && valueIsDefined(VSlotId) - ? `${dNodeId}-${dPDiskId}-${VSlotId}` + const {NodeId: dNodeId, PDiskId: dPDiskId, VSlotId: vSlotId} = donor; + const stringifiedId = + !isNil(dNodeId) && !isNil(dPDiskId) && !isNil(vSlotId) + ? `${dNodeId}-${dPDiskId}-${vSlotId}` : ''; - + return { NodeId: dNodeId, - PDiskId: dPDiskId, - VDiskSlotId: VSlotId, - StringifiedId, + PDiskId: dPDiskId, + VDiskSlotId: vSlotId, + StringifiedId: stringifiedId, DonorMode: true, - } as PreparedVDisk; + }; } - }).filter((donor) => donor.StringifiedId); + }); return { ...restVDiskFields, From 55413db427c3606a256a994859462eccd5eb91ca Mon Sep 17 00:00:00 2001 From: Elena Makarova Date: Wed, 23 Jul 2025 09:29:37 +0300 Subject: [PATCH 12/12] fix --- src/components/VDiskInfo/VDiskInfo.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/VDiskInfo/VDiskInfo.tsx b/src/components/VDiskInfo/VDiskInfo.tsx index 2eeceb63d4..9af4110136 100644 --- a/src/components/VDiskInfo/VDiskInfo.tsx +++ b/src/components/VDiskInfo/VDiskInfo.tsx @@ -213,7 +213,7 @@ export function VDiskInfo({ ); }).filter(Boolean); - if (donorLinks.length > 0) { + if (donorLinks.length) { rightColumn.push({ label: vDiskInfoKeyset('donors'), value: (