import React from 'react'; import {Wrench} from '@gravity-ui/icons'; import {Flex, Tab, TabList, TabProvider, Text} from '@gravity-ui/uikit'; import {skipToken} from '@reduxjs/toolkit/query'; import {isNil} from 'lodash'; import {Helmet} from 'react-helmet-async'; import {StickyAutoRefreshControl} from '../../components/AutoRefreshControl/StickyAutoRefreshControl'; import {CopyableValue} from '../../components/CopyableValue/CopyableValue'; import {DiskTypeLabel} from '../../components/DiskStatus/DiskStatus'; import {ResponseError} from '../../components/Errors/ResponseError'; import { EvictVDiskButton, isAllVdiskParamsDefined, } from '../../components/EvictVDiskButton/EvictVDiskButton'; import {InfoViewerSkeleton} from '../../components/InfoViewerSkeleton/InfoViewerSkeleton'; import {InternalLink} from '../../components/InternalLink/InternalLink'; import {LinkWithIcon} from '../../components/LinkWithIcon/LinkWithIcon'; import {VDiskInfo} from '../../components/VDiskInfo/VDiskInfo'; import {vDiskInfoKeyset} from '../../components/VDiskInfo/i18n'; import { VDiskDonorLabel, VDiskReplicationStatus, VDiskStateLabel, } from '../../components/VDiskStatus'; import {useVDiskPagePath} from '../../routes'; import {api} from '../../store/reducers/api'; import {setHeaderBreadcrumbs} from '../../store/reducers/header/header'; import {vDiskApi} from '../../store/reducers/vdisk/vdisk'; import {cn} from '../../utils/cn'; import {EMPTY_DATA_PLACEHOLDER} from '../../utils/constants'; import {parseVdiskId} from '../../utils/dataFormatters/dataFormatters'; import {createVDiskDeveloperUILink, useHasDeveloperUi} from '../../utils/developerUI/developerUI'; import {useAutoRefreshInterval, useTypedDispatch} from '../../utils/hooks'; import {useAppTitle} from '../App/AppTitleContext'; import {PaginatedStorage} from '../Storage/PaginatedStorage'; import {VDiskStorageDetails} from './VDiskStorageDetails'; import {VDiskTablets} from './VDiskTablets'; import {vDiskPageKeyset} from './i18n'; import {useVDiskQueryParams} from './useVDiskQueryParams'; import './VDiskPage.scss'; const vDiskPageCn = cn('ydb-vdisk-page'); export function VDiskPage() { const dispatch = useTypedDispatch(); const getVDiskPagePath = useVDiskPagePath(); const containerRef = React.useRef(null); const {nodeId, vDiskId: vDiskIdParam, database, vDiskTab, vDiskTabs} = useVDiskQueryParams(); const hasDeveloperUi = useHasDeveloperUi(); const [autoRefreshInterval] = useAutoRefreshInterval(); const params = React.useMemo(() => { if (!isNil(vDiskIdParam)) { return {vDiskId: vDiskIdParam, nodeId: nodeId?.toString(), database}; } return skipToken; }, [nodeId, vDiskIdParam, database]); const { currentData: vDiskData, isFetching, error, } = vDiskApi.useGetVDiskDataQuery(params, { pollingInterval: autoRefreshInterval, }); const vDiskSlotId = vDiskData?.VDiskSlotId; React.useEffect(() => { dispatch( setHeaderBreadcrumbs('vDisk', { groupId: vDiskData?.VDiskId?.GroupID, database, vDiskId: vDiskData?.StringifiedId, }), ); }, [dispatch, database, vDiskData?.VDiskId?.GroupID, vDiskData?.StringifiedId]); const loading = isFetching && vDiskData === undefined; const {NodeHost, NodeId, PDiskId, PDiskType, VDiskId, StringifiedId} = vDiskData || {}; const resolvedVDiskId = VDiskId || (!loading && parseVdiskId(vDiskIdParam)) || undefined; const {GroupID} = resolvedVDiskId || {}; const vDiskId = vDiskData?.StringifiedId || (loading ? undefined : vDiskIdParam); const {appTitle} = useAppTitle(); const renderHelmet = () => { const vDiskPagePart = vDiskSlotId ? `${vDiskPageKeyset('vdisk')} ${vDiskSlotId}` : vDiskPageKeyset('vdisk'); const pDiskPagePart = PDiskId ? `${vDiskPageKeyset('pdisk')} ${PDiskId}` : vDiskPageKeyset('pdisk'); const nodePagePart = NodeHost ? NodeHost : vDiskPageKeyset('node'); return ( ); }; const renderTitleMeta = () => { return ( {vDiskData?.DonorMode ? ( ) : ( )} ); }; const renderPageTitle = () => { return ( {vDiskPageKeyset('vdisk')}{' '} {vDiskId || EMPTY_DATA_PLACEHOLDER} {renderTitleMeta()} {vDiskInfoKeyset('pool-name')}: {vDiskData?.StoragePoolName || EMPTY_DATA_PLACEHOLDER} ); }; const handleAfterEvictVDisk = React.useCallback(() => { dispatch( api.util.invalidateTags([ { type: 'VDiskData', id: vDiskId?.toString(), }, 'StorageData', ]), ); }, [dispatch, vDiskId]); const renderControls = () => { const canEvict = isAllVdiskParamsDefined(resolvedVDiskId) && !vDiskData?.DonorMode; const developerUILink = hasDeveloperUi && !isNil(NodeId) && !isNil(PDiskId) && !isNil(vDiskSlotId) ? createVDiskDeveloperUILink({ nodeId: NodeId, pDiskId: PDiskId, vDiskSlotId, }) : undefined; if (!canEvict && !developerUILink) { return null; } return (
{canEvict && isAllVdiskParamsDefined(resolvedVDiskId) && ( )} {developerUILink && ( )}
); }; const renderInfo = () => { return ; }; const renderStorageDetails = () => { return ; }; const renderTabs = () => { return (
{vDiskTabs.map(({id, title}) => { const path = getVDiskPagePath( { nodeId: nodeId?.toString(), vDiskId: vDiskId?.toString(), }, {activeTab: id}, ); return ( {title} ); })}
); }; const renderStorageInfo = () => { if (!isNil(GroupID)) { return ( ); } return null; }; const renderTabsContent = () => { switch (vDiskTab) { case 'storage': { return renderStorageInfo(); } case 'tablets': { return ( ); } default: return null; } }; const renderContent = () => { if (loading) { return ; } return ( {error ? : null} {renderStorageDetails()} {renderInfo()} {renderTabs()} {renderTabsContent()} ); }; return (
{renderHelmet()} {renderPageTitle()} {renderControls()} {renderContent()}
); }