Skip to content

Commit d3b3d9b

Browse files
feat(PDiskPage): add pdisk attributes, display in 2 columns (#1069)
1 parent 3305cdb commit d3b3d9b

File tree

6 files changed

+209
-70
lines changed

6 files changed

+209
-70
lines changed

src/components/PDiskInfo/PDiskInfo.scss

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,18 @@
11
.ydb-pdisk-info {
2+
&__wrapper {
3+
display: flex;
4+
flex-flow: row wrap;
5+
gap: 7px;
6+
}
7+
8+
&__col {
9+
display: flex;
10+
flex-direction: column;
11+
gap: 7px;
12+
13+
width: 500px;
14+
}
15+
216
&__links {
317
display: flex;
418
flex-flow: row wrap;
Lines changed: 133 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import {getPDiskPagePath} from '../../routes';
22
import {valueIsDefined} from '../../utils';
3+
import {formatBytes} from '../../utils/bytesParsers';
34
import {cn} from '../../utils/cn';
4-
import {EMPTY_DATA_PLACEHOLDER} from '../../utils/constants';
55
import {formatStorageValuesToGb} from '../../utils/dataFormatters/dataFormatters';
66
import {createPDiskDeveloperUILink} from '../../utils/developerUI/developerUI';
77
import type {PreparedPDisk} from '../../utils/disks/types';
8+
import {useTypedSelector} from '../../utils/hooks';
89
import {EntityStatus} from '../EntityStatus/EntityStatus';
910
import type {InfoViewerItem} from '../InfoViewer';
1011
import {InfoViewer} from '../InfoViewer/InfoViewer';
11-
import type {InfoViewerProps} from '../InfoViewer/InfoViewer';
1212
import {LinkWithIcon} from '../LinkWithIcon/LinkWithIcon';
1313
import {ProgressViewer} from '../ProgressViewer/ProgressViewer';
1414

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

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

21-
interface PDiskInfoProps<T extends PreparedPDisk> extends Omit<InfoViewerProps, 'info'> {
21+
interface GetPDiskInfoOptions<T extends PreparedPDisk> {
2222
pDisk?: T;
2323
nodeId?: number | string | null;
2424
isPDiskPage?: boolean;
25+
isUserAllowedToMakeChanges?: boolean;
2526
}
2627

27-
export function PDiskInfo<T extends PreparedPDisk>({
28+
// eslint-disable-next-line complexity
29+
function getPDiskInfo<T extends PreparedPDisk>({
2830
pDisk,
2931
nodeId,
3032
isPDiskPage = false,
31-
...infoViewerProps
32-
}: PDiskInfoProps<T>) {
33+
isUserAllowedToMakeChanges,
34+
}: GetPDiskInfoOptions<T>) {
3335
const {
3436
PDiskId,
3537
Path,
@@ -42,22 +44,72 @@ export function PDiskInfo<T extends PreparedPDisk>({
4244
SerialNumber,
4345
TotalSize,
4446
AllocatedSize,
47+
DecommitStatus,
48+
StatusV2,
49+
NumActiveSlots,
50+
ExpectedSlotCount,
51+
LogUsedSize,
52+
LogTotalSize,
53+
SystemSize,
54+
SharedWithOs,
4555
} = pDisk || {};
4656

47-
const pdiskInfo: InfoViewerItem[] = [];
57+
const generalInfo: InfoViewerItem[] = [];
4858

59+
if (valueIsDefined(DecommitStatus)) {
60+
generalInfo.push({
61+
label: pDiskInfoKeyset('decomission-status'),
62+
value: DecommitStatus.replace('DECOMMIT_', ''),
63+
});
64+
}
65+
if (valueIsDefined(Category)) {
66+
generalInfo.push({label: pDiskInfoKeyset('type'), value: Type});
67+
}
4968
if (valueIsDefined(Path)) {
50-
pdiskInfo.push({label: pDiskInfoKeyset('path'), value: Path});
69+
generalInfo.push({label: pDiskInfoKeyset('path'), value: Path});
5170
}
5271
if (valueIsDefined(Guid)) {
53-
pdiskInfo.push({label: pDiskInfoKeyset('guid'), value: Guid});
72+
generalInfo.push({label: pDiskInfoKeyset('guid'), value: Guid});
5473
}
55-
if (valueIsDefined(Category)) {
56-
pdiskInfo.push({label: pDiskInfoKeyset('category'), value: Category});
57-
pdiskInfo.push({label: pDiskInfoKeyset('type'), value: Type});
74+
// SerialNumber could be an empty string ""
75+
if (SerialNumber) {
76+
generalInfo.push({
77+
label: pDiskInfoKeyset('serial-number'),
78+
value: SerialNumber,
79+
});
80+
}
81+
if (valueIsDefined(SharedWithOs)) {
82+
generalInfo.push({
83+
label: pDiskInfoKeyset('shared-with-os'),
84+
value: pDiskInfoKeyset('yes'),
85+
});
86+
}
87+
88+
const statusInfo: InfoViewerItem[] = [];
89+
90+
if (valueIsDefined(StatusV2)) {
91+
statusInfo.push({label: pDiskInfoKeyset('drive-status'), value: StatusV2});
5892
}
59-
pdiskInfo.push({
60-
label: pDiskInfoKeyset('size'),
93+
if (valueIsDefined(State)) {
94+
statusInfo.push({label: pDiskInfoKeyset('state'), value: State});
95+
}
96+
if (valueIsDefined(Device)) {
97+
statusInfo.push({
98+
label: pDiskInfoKeyset('device'),
99+
value: <EntityStatus status={Device} />,
100+
});
101+
}
102+
if (valueIsDefined(Realtime)) {
103+
statusInfo.push({
104+
label: pDiskInfoKeyset('realtime'),
105+
value: <EntityStatus status={Realtime} />,
106+
});
107+
}
108+
109+
const spaceInfo: InfoViewerItem[] = [];
110+
111+
spaceInfo.push({
112+
label: pDiskInfoKeyset('space'),
61113
value: (
62114
<ProgressViewer
63115
value={AllocatedSize}
@@ -67,36 +119,46 @@ export function PDiskInfo<T extends PreparedPDisk>({
67119
/>
68120
),
69121
});
70-
if (valueIsDefined(State)) {
71-
pdiskInfo.push({label: pDiskInfoKeyset('state'), value: State});
72-
}
73-
if (valueIsDefined(Device)) {
74-
pdiskInfo.push({
75-
label: pDiskInfoKeyset('device'),
76-
value: <EntityStatus status={Device} />,
122+
if (valueIsDefined(NumActiveSlots) && valueIsDefined(ExpectedSlotCount)) {
123+
spaceInfo.push({
124+
label: pDiskInfoKeyset('slots'),
125+
value: <ProgressViewer value={NumActiveSlots} capacity={ExpectedSlotCount} />,
77126
});
78127
}
79-
if (valueIsDefined(Realtime)) {
80-
pdiskInfo.push({
81-
label: pDiskInfoKeyset('realtime'),
82-
value: <EntityStatus status={Realtime} />,
128+
if (valueIsDefined(LogUsedSize) && valueIsDefined(LogTotalSize)) {
129+
spaceInfo.push({
130+
label: pDiskInfoKeyset('log-size'),
131+
value: (
132+
<ProgressViewer
133+
value={LogUsedSize}
134+
capacity={LogTotalSize}
135+
formatValues={formatStorageValuesToGb}
136+
/>
137+
),
83138
});
84139
}
85-
if (valueIsDefined(SerialNumber)) {
86-
pdiskInfo.push({
87-
label: pDiskInfoKeyset('serial-number'),
88-
value: SerialNumber || EMPTY_DATA_PLACEHOLDER,
140+
if (valueIsDefined(SystemSize)) {
141+
spaceInfo.push({
142+
label: pDiskInfoKeyset('system-size'),
143+
value: formatBytes({value: SystemSize}),
89144
});
90145
}
91146

92-
if (valueIsDefined(PDiskId) && valueIsDefined(nodeId)) {
147+
const additionalInfo: InfoViewerItem[] = [];
148+
149+
const shouldDisplayLinks =
150+
(!isPDiskPage || isUserAllowedToMakeChanges) &&
151+
valueIsDefined(PDiskId) &&
152+
valueIsDefined(nodeId);
153+
154+
if (shouldDisplayLinks) {
93155
const pDiskPagePath = getPDiskPagePath(PDiskId, nodeId);
94156
const pDiskInternalViewerPath = createPDiskDeveloperUILink({
95157
nodeId,
96158
pDiskId: PDiskId,
97159
});
98160

99-
pdiskInfo.push({
161+
additionalInfo.push({
100162
label: pDiskInfoKeyset('links'),
101163
value: (
102164
<span className={b('links')}>
@@ -107,14 +169,49 @@ export function PDiskInfo<T extends PreparedPDisk>({
107169
external={false}
108170
/>
109171
)}
110-
<LinkWithIcon
111-
title={pDiskInfoKeyset('developer-ui')}
112-
url={pDiskInternalViewerPath}
113-
/>
172+
{isUserAllowedToMakeChanges && (
173+
<LinkWithIcon
174+
title={pDiskInfoKeyset('developer-ui')}
175+
url={pDiskInternalViewerPath}
176+
/>
177+
)}
114178
</span>
115179
),
116180
});
117181
}
118182

119-
return <InfoViewer info={pdiskInfo} {...infoViewerProps} />;
183+
return [generalInfo, statusInfo, spaceInfo, additionalInfo];
184+
}
185+
186+
interface PDiskInfoProps<T extends PreparedPDisk> extends GetPDiskInfoOptions<T> {
187+
className?: string;
188+
}
189+
190+
export function PDiskInfo<T extends PreparedPDisk>({
191+
pDisk,
192+
nodeId,
193+
isPDiskPage = false,
194+
className,
195+
}: PDiskInfoProps<T>) {
196+
const {isUserAllowedToMakeChanges} = useTypedSelector((state) => state.authentication);
197+
198+
const [generalInfo, statusInfo, spaceInfo, additionalInfo] = getPDiskInfo({
199+
pDisk,
200+
nodeId,
201+
isPDiskPage,
202+
isUserAllowedToMakeChanges,
203+
});
204+
205+
return (
206+
<div className={b('wrapper', className)}>
207+
<div className={b('col')}>
208+
<InfoViewer info={generalInfo} renderEmptyState={() => null} />
209+
<InfoViewer info={spaceInfo} renderEmptyState={() => null} />
210+
</div>
211+
<div className={b('col')}>
212+
<InfoViewer info={statusInfo} renderEmptyState={() => null} />
213+
<InfoViewer info={additionalInfo} renderEmptyState={() => null} />
214+
</div>
215+
</div>
216+
);
120217
}

src/components/PDiskInfo/i18n/en.json

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,25 @@
11
{
2+
"decomission-status": "Decomission Status",
3+
"type": "Type",
24
"path": "Path",
35
"guid": "GUID",
4-
"category": "Category",
5-
"type": "Type",
6-
"size": "Size",
6+
"serial-number": "Serial Number",
7+
"shared-with-os": "SharedWithOs",
8+
9+
"drive-status": "Drive Status",
710
"state": "State",
811
"device": "Device",
912
"realtime": "Realtime",
10-
"serial-number": "SerialNumber",
13+
14+
"space": "Space",
15+
"slots": "Slots",
16+
"log-size": "Log Size",
17+
"system-size": "System Size",
18+
1119
"links": "Links",
1220

1321
"developer-ui": "Developer UI",
14-
"pdisk-page": "PDisk page"
22+
"pdisk-page": "PDisk page",
23+
24+
"yes": "Yes"
1525
}

src/store/reducers/pdisk/utils.ts

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type {TPDiskInfoResponse} from '../../../types/api/pdisk';
22
import type {TStorageInfo} from '../../../types/api/storage';
33
import type {TEvSystemStateResponse} from '../../../types/api/systemState';
4-
import {getArray} from '../../../utils';
4+
import {getArray, valueIsDefined} from '../../../utils';
55
import {preparePDiskData, prepareVDiskData} from '../../../utils/disks/prepareDisks';
66
import {prepareNodeSystemState} from '../../../utils/nodes';
77
import type {PreparedStorageGroup} from '../storage/types';
@@ -18,24 +18,33 @@ export function preparePDiskDataResponse([pdiskResponse = {}, nodeResponse]: [
1818
const {PDisk: WhiteboardPDiskData = {}, VDisks: WhiteboardVDisksData = []} = Whiteboard;
1919
const {PDisk: BSCPDiskData = {}} = BSC;
2020

21-
const {ExpectedSlotCount, EnforcedDynamicSlotSize} = BSCPDiskData;
22-
23-
const preparedPDisk = preparePDiskData(WhiteboardPDiskData);
24-
25-
const {LogUsedSize, LogTotalSize, TotalSize: PDiskTotalSize, SystemSize} = preparedPDisk;
26-
27-
const logSlot: SlotItem<'log'> = {
28-
SlotType: 'log',
29-
Used: Number(LogUsedSize),
30-
Total: Number(LogTotalSize),
31-
UsagePercent: (Number(LogUsedSize) * 100) / Number(LogTotalSize),
32-
Severity: 1,
33-
SlotData: {
34-
LogUsedSize,
35-
LogTotalSize,
36-
SystemSize,
37-
},
38-
};
21+
const preparedPDisk = preparePDiskData(WhiteboardPDiskData, BSCPDiskData);
22+
23+
const {
24+
LogUsedSize,
25+
LogTotalSize,
26+
TotalSize: PDiskTotalSize,
27+
SystemSize,
28+
ExpectedSlotCount,
29+
EnforcedDynamicSlotSize,
30+
} = preparedPDisk;
31+
32+
let logSlot: SlotItem<'log'> | undefined;
33+
34+
if (valueIsDefined(LogTotalSize)) {
35+
logSlot = {
36+
SlotType: 'log',
37+
Used: Number(LogUsedSize),
38+
Total: Number(LogTotalSize),
39+
UsagePercent: (Number(LogUsedSize) * 100) / Number(LogTotalSize),
40+
Severity: 1,
41+
SlotData: {
42+
LogUsedSize,
43+
LogTotalSize,
44+
SystemSize,
45+
},
46+
};
47+
}
3948

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

85-
const diskSlots = [logSlot, ...vdisksSlots, ...emptySlots];
94+
const diskSlots: PDiskData['SlotItems'] = [...vdisksSlots, ...emptySlots];
95+
96+
if (logSlot) {
97+
diskSlots.unshift(logSlot);
98+
}
8699

87100
const rawNode = nodeResponse.SystemStateInfo?.[0];
88101
const preparedNode = prepareNodeSystemState(rawNode);

src/utils/disks/prepareDisks.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type {TPDiskStateInfo} from '../../types/api/pdisk';
1+
import type {TPDiskInfo, TPDiskStateInfo} from '../../types/api/pdisk';
22
import type {TVDiskStateInfo} from '../../types/api/vdisk';
33

44
import {calculatePDiskSeverity} from './calculatePDiskSeverity';
@@ -35,7 +35,10 @@ export function prepareVDiskData(vdiskState: TVDiskStateInfo = {}): PreparedVDis
3535
};
3636
}
3737

38-
export function preparePDiskData(pdiskState: TPDiskStateInfo = {}): PreparedPDisk {
38+
export function preparePDiskData(
39+
pdiskState: TPDiskStateInfo = {},
40+
bscPDiskInfo: TPDiskInfo = {},
41+
): PreparedPDisk {
3942
const {AvailableSize, TotalSize, Category} = pdiskState;
4043

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

5053
return {
54+
...bscPDiskInfo,
5155
...pdiskState,
5256
Type,
5357
Severity,

0 commit comments

Comments
 (0)