import React from 'react';
import {Wrench} from '@gravity-ui/icons';
import {Divider, Flex} from '@gravity-ui/uikit';
import {isNil} from 'lodash';
import {useVDiskPagePath} from '../../routes';
import {api} from '../../store/reducers/api';
import {useBlobStorageCapacityMetricsEnabled} from '../../store/reducers/capabilities/hooks';
import type {TVDiskID} from '../../types/api/vdisk';
import type {NodeMetadata} from '../../types/store/nodesList';
import {cn} from '../../utils/cn';
import {BRAND_BUTTON_CLASS, EMPTY_DATA_PLACEHOLDER} from '../../utils/constants';
import {parseVdiskId} from '../../utils/dataFormatters/dataFormatters';
import {createVDiskDeveloperUILink, useHasDeveloperUi} from '../../utils/developerUI/developerUI';
import {isFullVDiskData} from '../../utils/disks/helpers';
import type {PreparedVDisk, UnavailableDonor} from '../../utils/disks/types';
import {useTypedDispatch} from '../../utils/hooks';
import {useIsViewerUser} from '../../utils/hooks/useIsUserAllowedToMakeChanges';
import {useNodeMetadata} from '../../utils/hooks/useNodeMetadata';
import {getVDiskCapacityItems} from '../DiskCapacityInfo/DiskCapacityInfo';
import {
DiskPopup,
DiskPopupHeader,
DiskPopupLocation,
DiskPopupPanel,
DiskPopupText,
} from '../DiskPopup/DiskPopup';
import {EvictVDiskButton, isAllVdiskParamsDefined} from '../EvictVDiskButton/EvictVDiskButton';
import {InternalLinkButton} from '../InternalLinkButton';
import {LinkWithIcon} from '../LinkWithIcon/LinkWithIcon';
import {PDiskPopupContent} from '../PDiskPopup/PDiskPopup';
import {
getVDiskIdentityItems,
getVDiskLocationItems,
getVDiskThroughputItems,
} from '../VDiskInfo/getVDiskDetails';
import {vDiskInfoKeyset} from '../VDiskInfo/i18n';
import {
VDiskCompactionRankLabel,
VDiskDonorLabel,
VDiskFrontQueuesLabel,
VDiskReplicationStatus,
VDiskStateLabel,
} from '../VDiskStatus';
import type {YDBDefinitionListItem} from '../YDBDefinitionList/YDBDefinitionList';
import {YDBDefinitionList} from '../YDBDefinitionList/YDBDefinitionList';
import {vDiskPopupKeyset} from './i18n';
import './VDiskPopup.scss';
const b = cn('ydb-vdisk-popup');
function buildUnavailableVDiskFooter(
data: UnavailableDonor,
withDeveloperUILink: boolean,
): React.ReactNode | null {
const {NodeId, PDiskId, VDiskSlotId} = data;
if (!withDeveloperUILink || isNil(NodeId) || isNil(PDiskId) || isNil(VDiskSlotId)) {
return null;
}
const vDiskInternalViewerPath = createVDiskDeveloperUILink({
nodeId: NodeId,
pDiskId: PDiskId,
vDiskSlotId: VDiskSlotId,
});
return (
);
}
function getRuntimeItems(
data: PreparedVDisk,
withUnreadableBlobs: boolean,
): YDBDefinitionListItem[] {
const items: YDBDefinitionListItem[] = [
{
name: vDiskPopupKeyset('label_front-queues'),
content: ,
},
{
name: vDiskPopupKeyset('label_compaction'),
content: (
),
},
];
items.push(...getVDiskThroughputItems(data));
if (withUnreadableBlobs) {
items.push({
name: vDiskInfoKeyset('has-unreadable-blobs'),
content: isNil(data.HasUnreadableBlobs)
? EMPTY_DATA_PLACEHOLDER
: vDiskInfoKeyset(data.HasUnreadableBlobs ? 'yes' : 'no'),
});
}
return items;
}
function getStorageItems(
data: PreparedVDisk,
capacityMetricsEnabled: boolean,
): YDBDefinitionListItem[] {
const items: YDBDefinitionListItem[] = [
{
name: vDiskPopupKeyset('label_storage-pool'),
content: ,
copyText: data.StoragePoolName,
},
];
return isFullVDiskData(data)
? [...items, ...getVDiskCapacityItems(data, {capacityMetricsEnabled})]
: items;
}
function getLocationItems(data: PreparedVDisk, nodeData: NodeMetadata, withPDiskPanel: boolean) {
const items = getVDiskLocationItems(data, nodeData);
if (!withPDiskPanel) {
return items;
}
return items.filter(({id}) => id !== 'pdisk-id' && id !== 'pdisk-path');
}
function DiskHeader({
data = {},
donorMode,
withPDiskType = true,
}: {
data?: PreparedVDisk;
donorMode?: boolean;
withPDiskType?: boolean;
}) {
return (
}
/>
);
}
/**
* Resolve VDiskId from PreparedVDisk data.
* Prefers the structured VDiskId when all fields are present,
* falls back to parsing StringifiedId (e.g. "123-1-0-0-0").
*/
const resolveVDiskId = (data: PreparedVDisk): Required | undefined => {
if (isAllVdiskParamsDefined(data.VDiskId)) {
return data.VDiskId;
}
const parsed = parseVdiskId(data.StringifiedId);
return isAllVdiskParamsDefined(parsed) ? parsed : undefined;
};
function buildVDiskFooter(
data: PreparedVDisk,
withDeveloperUILink: boolean,
getVDiskLinkFn: ReturnType,
onSuccess: (isDialogOpen: boolean) => void,
withActions: boolean,
onDialogOpen?: () => VoidFunction,
): React.ReactNode | null {
const {NodeId, PDiskId, VDiskSlotId, StringifiedId, DonorMode} = data;
const vDiskInternalViewerPath =
withDeveloperUILink && !isNil(NodeId) && !isNil(PDiskId) && !isNil(VDiskSlotId)
? createVDiskDeveloperUILink({
nodeId: NodeId,
pDiskId: PDiskId,
vDiskSlotId: VDiskSlotId,
})
: undefined;
const vDiskPagePath =
withActions && withDeveloperUILink && !isNil(NodeId) && StringifiedId
? getVDiskLinkFn({nodeId: NodeId, vDiskId: StringifiedId})
: undefined;
const resolvedVDiskId = withActions ? resolveVDiskId(data) : undefined;
if (!vDiskInternalViewerPath && !vDiskPagePath && !resolvedVDiskId) {
return null;
}
return (
{vDiskInternalViewerPath && (
)}
{(vDiskPagePath || resolvedVDiskId) && (
{vDiskPagePath && (
{vDiskPopupKeyset('action_go-to-vdisk')}
)}
{resolvedVDiskId && (
)}
)}
);
}
interface VDiskPopupProps {
data: PreparedVDisk;
nodeData?: NodeMetadata;
onClose?: VoidFunction;
onDialogOpen?: () => VoidFunction;
view?: 'default' | 'space-distribution';
}
export function VDiskPopup({
data,
nodeData: parentNodeData,
onClose,
onDialogOpen,
view = 'default',
}: VDiskPopupProps) {
const dispatch = useTypedDispatch();
const nodeData = useNodeMetadata(data.NodeId, parentNodeData);
const isViewerUser = useIsViewerUser();
const capacityMetricsEnabled = useBlobStorageCapacityMetricsEnabled();
const hasDeveloperUi = useHasDeveloperUi();
const getVDiskLink = useVDiskPagePath();
const fullData = isFullVDiskData(data) ? data : undefined;
const vdiskId = fullData?.StringifiedId;
const handleAfterEvictVDisk = (isDialogOpen: boolean) => {
dispatch(
api.util.invalidateTags([
'TableData',
'StorageData',
'PDiskData',
{type: 'VDiskData', id: vdiskId},
]),
);
if (isDialogOpen) {
onClose?.();
}
};
const isSpaceDistribution = view === 'space-distribution';
const runtimeItems = fullData ? getRuntimeItems(fullData, isSpaceDistribution) : [];
const identityItems = isSpaceDistribution ? getVDiskIdentityItems(fullData) : [];
const storageItems = getStorageItems(data, capacityMetricsEnabled);
const pdisk = !isSpaceDistribution && isViewerUser ? fullData?.PDisk : undefined;
const vdiskFooter = isFullVDiskData(data)
? buildVDiskFooter(
data,
hasDeveloperUi,
getVDiskLink,
handleAfterEvictVDisk,
!isSpaceDistribution,
onDialogOpen,
)
: buildUnavailableVDiskFooter(data, hasDeveloperUi);
const locationItems = getLocationItems(data, nodeData, Boolean(pdisk));
return (
{pdisk && }
{runtimeItems.length > 0 && (
)}
{runtimeItems.length > 0 && storageItems.length > 0 && }
{storageItems.length > 0 && (
)}
{identityItems.length > 0 && (
)}
);
}