Skip to content

Commit

Permalink
feat(PDiskPage): add pdisk attributes, display in 2 columns (#1069)
Browse files Browse the repository at this point in the history
  • Loading branch information
artemmufazalov authored Jul 26, 2024
1 parent 3305cdb commit d3b3d9b
Show file tree
Hide file tree
Showing 6 changed files with 209 additions and 70 deletions.
14 changes: 14 additions & 0 deletions src/components/PDiskInfo/PDiskInfo.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,18 @@
.ydb-pdisk-info {
&__wrapper {
display: flex;
flex-flow: row wrap;
gap: 7px;
}

&__col {
display: flex;
flex-direction: column;
gap: 7px;

width: 500px;
}

&__links {
display: flex;
flex-flow: row wrap;
Expand Down
169 changes: 133 additions & 36 deletions src/components/PDiskInfo/PDiskInfo.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import {getPDiskPagePath} from '../../routes';
import {valueIsDefined} from '../../utils';
import {formatBytes} from '../../utils/bytesParsers';
import {cn} from '../../utils/cn';
import {EMPTY_DATA_PLACEHOLDER} from '../../utils/constants';
import {formatStorageValuesToGb} from '../../utils/dataFormatters/dataFormatters';
import {createPDiskDeveloperUILink} from '../../utils/developerUI/developerUI';
import type {PreparedPDisk} from '../../utils/disks/types';
import {useTypedSelector} from '../../utils/hooks';
import {EntityStatus} from '../EntityStatus/EntityStatus';
import type {InfoViewerItem} from '../InfoViewer';
import {InfoViewer} from '../InfoViewer/InfoViewer';
import type {InfoViewerProps} from '../InfoViewer/InfoViewer';
import {LinkWithIcon} from '../LinkWithIcon/LinkWithIcon';
import {ProgressViewer} from '../ProgressViewer/ProgressViewer';

Expand All @@ -18,18 +18,20 @@ import './PDiskInfo.scss';

const b = cn('ydb-pdisk-info');

interface PDiskInfoProps<T extends PreparedPDisk> extends Omit<InfoViewerProps, 'info'> {
interface GetPDiskInfoOptions<T extends PreparedPDisk> {
pDisk?: T;
nodeId?: number | string | null;
isPDiskPage?: boolean;
isUserAllowedToMakeChanges?: boolean;
}

export function PDiskInfo<T extends PreparedPDisk>({
// eslint-disable-next-line complexity
function getPDiskInfo<T extends PreparedPDisk>({
pDisk,
nodeId,
isPDiskPage = false,
...infoViewerProps
}: PDiskInfoProps<T>) {
isUserAllowedToMakeChanges,
}: GetPDiskInfoOptions<T>) {
const {
PDiskId,
Path,
Expand All @@ -42,22 +44,72 @@ export function PDiskInfo<T extends PreparedPDisk>({
SerialNumber,
TotalSize,
AllocatedSize,
DecommitStatus,
StatusV2,
NumActiveSlots,
ExpectedSlotCount,
LogUsedSize,
LogTotalSize,
SystemSize,
SharedWithOs,
} = pDisk || {};

const pdiskInfo: InfoViewerItem[] = [];
const generalInfo: InfoViewerItem[] = [];

if (valueIsDefined(DecommitStatus)) {
generalInfo.push({
label: pDiskInfoKeyset('decomission-status'),
value: DecommitStatus.replace('DECOMMIT_', ''),
});
}
if (valueIsDefined(Category)) {
generalInfo.push({label: pDiskInfoKeyset('type'), value: Type});
}
if (valueIsDefined(Path)) {
pdiskInfo.push({label: pDiskInfoKeyset('path'), value: Path});
generalInfo.push({label: pDiskInfoKeyset('path'), value: Path});
}
if (valueIsDefined(Guid)) {
pdiskInfo.push({label: pDiskInfoKeyset('guid'), value: Guid});
generalInfo.push({label: pDiskInfoKeyset('guid'), value: Guid});
}
if (valueIsDefined(Category)) {
pdiskInfo.push({label: pDiskInfoKeyset('category'), value: Category});
pdiskInfo.push({label: pDiskInfoKeyset('type'), value: Type});
// SerialNumber could be an empty string ""
if (SerialNumber) {
generalInfo.push({
label: pDiskInfoKeyset('serial-number'),
value: SerialNumber,
});
}
if (valueIsDefined(SharedWithOs)) {
generalInfo.push({
label: pDiskInfoKeyset('shared-with-os'),
value: pDiskInfoKeyset('yes'),
});
}

const statusInfo: InfoViewerItem[] = [];

if (valueIsDefined(StatusV2)) {
statusInfo.push({label: pDiskInfoKeyset('drive-status'), value: StatusV2});
}
pdiskInfo.push({
label: pDiskInfoKeyset('size'),
if (valueIsDefined(State)) {
statusInfo.push({label: pDiskInfoKeyset('state'), value: State});
}
if (valueIsDefined(Device)) {
statusInfo.push({
label: pDiskInfoKeyset('device'),
value: <EntityStatus status={Device} />,
});
}
if (valueIsDefined(Realtime)) {
statusInfo.push({
label: pDiskInfoKeyset('realtime'),
value: <EntityStatus status={Realtime} />,
});
}

const spaceInfo: InfoViewerItem[] = [];

spaceInfo.push({
label: pDiskInfoKeyset('space'),
value: (
<ProgressViewer
value={AllocatedSize}
Expand All @@ -67,36 +119,46 @@ export function PDiskInfo<T extends PreparedPDisk>({
/>
),
});
if (valueIsDefined(State)) {
pdiskInfo.push({label: pDiskInfoKeyset('state'), value: State});
}
if (valueIsDefined(Device)) {
pdiskInfo.push({
label: pDiskInfoKeyset('device'),
value: <EntityStatus status={Device} />,
if (valueIsDefined(NumActiveSlots) && valueIsDefined(ExpectedSlotCount)) {
spaceInfo.push({
label: pDiskInfoKeyset('slots'),
value: <ProgressViewer value={NumActiveSlots} capacity={ExpectedSlotCount} />,
});
}
if (valueIsDefined(Realtime)) {
pdiskInfo.push({
label: pDiskInfoKeyset('realtime'),
value: <EntityStatus status={Realtime} />,
if (valueIsDefined(LogUsedSize) && valueIsDefined(LogTotalSize)) {
spaceInfo.push({
label: pDiskInfoKeyset('log-size'),
value: (
<ProgressViewer
value={LogUsedSize}
capacity={LogTotalSize}
formatValues={formatStorageValuesToGb}
/>
),
});
}
if (valueIsDefined(SerialNumber)) {
pdiskInfo.push({
label: pDiskInfoKeyset('serial-number'),
value: SerialNumber || EMPTY_DATA_PLACEHOLDER,
if (valueIsDefined(SystemSize)) {
spaceInfo.push({
label: pDiskInfoKeyset('system-size'),
value: formatBytes({value: SystemSize}),
});
}

if (valueIsDefined(PDiskId) && valueIsDefined(nodeId)) {
const additionalInfo: InfoViewerItem[] = [];

const shouldDisplayLinks =
(!isPDiskPage || isUserAllowedToMakeChanges) &&
valueIsDefined(PDiskId) &&
valueIsDefined(nodeId);

if (shouldDisplayLinks) {
const pDiskPagePath = getPDiskPagePath(PDiskId, nodeId);
const pDiskInternalViewerPath = createPDiskDeveloperUILink({
nodeId,
pDiskId: PDiskId,
});

pdiskInfo.push({
additionalInfo.push({
label: pDiskInfoKeyset('links'),
value: (
<span className={b('links')}>
Expand All @@ -107,14 +169,49 @@ export function PDiskInfo<T extends PreparedPDisk>({
external={false}
/>
)}
<LinkWithIcon
title={pDiskInfoKeyset('developer-ui')}
url={pDiskInternalViewerPath}
/>
{isUserAllowedToMakeChanges && (
<LinkWithIcon
title={pDiskInfoKeyset('developer-ui')}
url={pDiskInternalViewerPath}
/>
)}
</span>
),
});
}

return <InfoViewer info={pdiskInfo} {...infoViewerProps} />;
return [generalInfo, statusInfo, spaceInfo, additionalInfo];
}

interface PDiskInfoProps<T extends PreparedPDisk> extends GetPDiskInfoOptions<T> {
className?: string;
}

export function PDiskInfo<T extends PreparedPDisk>({
pDisk,
nodeId,
isPDiskPage = false,
className,
}: PDiskInfoProps<T>) {
const {isUserAllowedToMakeChanges} = useTypedSelector((state) => state.authentication);

const [generalInfo, statusInfo, spaceInfo, additionalInfo] = getPDiskInfo({
pDisk,
nodeId,
isPDiskPage,
isUserAllowedToMakeChanges,
});

return (
<div className={b('wrapper', className)}>
<div className={b('col')}>
<InfoViewer info={generalInfo} renderEmptyState={() => null} />
<InfoViewer info={spaceInfo} renderEmptyState={() => null} />
</div>
<div className={b('col')}>
<InfoViewer info={statusInfo} renderEmptyState={() => null} />
<InfoViewer info={additionalInfo} renderEmptyState={() => null} />
</div>
</div>
);
}
20 changes: 15 additions & 5 deletions src/components/PDiskInfo/i18n/en.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,25 @@
{
"decomission-status": "Decomission Status",
"type": "Type",
"path": "Path",
"guid": "GUID",
"category": "Category",
"type": "Type",
"size": "Size",
"serial-number": "Serial Number",
"shared-with-os": "SharedWithOs",

"drive-status": "Drive Status",
"state": "State",
"device": "Device",
"realtime": "Realtime",
"serial-number": "SerialNumber",

"space": "Space",
"slots": "Slots",
"log-size": "Log Size",
"system-size": "System Size",

"links": "Links",

"developer-ui": "Developer UI",
"pdisk-page": "PDisk page"
"pdisk-page": "PDisk page",

"yes": "Yes"
}
53 changes: 33 additions & 20 deletions src/store/reducers/pdisk/utils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type {TPDiskInfoResponse} from '../../../types/api/pdisk';
import type {TStorageInfo} from '../../../types/api/storage';
import type {TEvSystemStateResponse} from '../../../types/api/systemState';
import {getArray} from '../../../utils';
import {getArray, valueIsDefined} from '../../../utils';
import {preparePDiskData, prepareVDiskData} from '../../../utils/disks/prepareDisks';
import {prepareNodeSystemState} from '../../../utils/nodes';
import type {PreparedStorageGroup} from '../storage/types';
Expand All @@ -18,24 +18,33 @@ export function preparePDiskDataResponse([pdiskResponse = {}, nodeResponse]: [
const {PDisk: WhiteboardPDiskData = {}, VDisks: WhiteboardVDisksData = []} = Whiteboard;
const {PDisk: BSCPDiskData = {}} = BSC;

const {ExpectedSlotCount, EnforcedDynamicSlotSize} = BSCPDiskData;

const preparedPDisk = preparePDiskData(WhiteboardPDiskData);

const {LogUsedSize, LogTotalSize, TotalSize: PDiskTotalSize, SystemSize} = preparedPDisk;

const logSlot: SlotItem<'log'> = {
SlotType: 'log',
Used: Number(LogUsedSize),
Total: Number(LogTotalSize),
UsagePercent: (Number(LogUsedSize) * 100) / Number(LogTotalSize),
Severity: 1,
SlotData: {
LogUsedSize,
LogTotalSize,
SystemSize,
},
};
const preparedPDisk = preparePDiskData(WhiteboardPDiskData, BSCPDiskData);

const {
LogUsedSize,
LogTotalSize,
TotalSize: PDiskTotalSize,
SystemSize,
ExpectedSlotCount,
EnforcedDynamicSlotSize,
} = preparedPDisk;

let logSlot: SlotItem<'log'> | undefined;

if (valueIsDefined(LogTotalSize)) {
logSlot = {
SlotType: 'log',
Used: Number(LogUsedSize),
Total: Number(LogTotalSize),
UsagePercent: (Number(LogUsedSize) * 100) / Number(LogTotalSize),
Severity: 1,
SlotData: {
LogUsedSize,
LogTotalSize,
SystemSize,
},
};
}

const preparedVDisks = WhiteboardVDisksData.map(prepareVDiskData).sort(
(disk1, disk2) => Number(disk2.VDiskSlotId) - Number(disk1.VDiskSlotId),
Expand Down Expand Up @@ -82,7 +91,11 @@ export function preparePDiskDataResponse([pdiskResponse = {}, nodeResponse]: [
});
}

const diskSlots = [logSlot, ...vdisksSlots, ...emptySlots];
const diskSlots: PDiskData['SlotItems'] = [...vdisksSlots, ...emptySlots];

if (logSlot) {
diskSlots.unshift(logSlot);
}

const rawNode = nodeResponse.SystemStateInfo?.[0];
const preparedNode = prepareNodeSystemState(rawNode);
Expand Down
8 changes: 6 additions & 2 deletions src/utils/disks/prepareDisks.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type {TPDiskStateInfo} from '../../types/api/pdisk';
import type {TPDiskInfo, TPDiskStateInfo} from '../../types/api/pdisk';
import type {TVDiskStateInfo} from '../../types/api/vdisk';

import {calculatePDiskSeverity} from './calculatePDiskSeverity';
Expand Down Expand Up @@ -35,7 +35,10 @@ export function prepareVDiskData(vdiskState: TVDiskStateInfo = {}): PreparedVDis
};
}

export function preparePDiskData(pdiskState: TPDiskStateInfo = {}): PreparedPDisk {
export function preparePDiskData(
pdiskState: TPDiskStateInfo = {},
bscPDiskInfo: TPDiskInfo = {},
): PreparedPDisk {
const {AvailableSize, TotalSize, Category} = pdiskState;

const Type = getPDiskType(Category);
Expand All @@ -48,6 +51,7 @@ export function preparePDiskData(pdiskState: TPDiskStateInfo = {}): PreparedPDis
const Severity = calculatePDiskSeverity(pdiskState, allocatedPercent);

return {
...bscPDiskInfo,
...pdiskState,
Type,
Severity,
Expand Down
Loading

0 comments on commit d3b3d9b

Please sign in to comment.