Skip to content

Commit bb5d1fa

Browse files
committed
feat(Storage): display vdisks over pdisks
1 parent 08e9fe0 commit bb5d1fa

File tree

11 files changed

+103
-10
lines changed

11 files changed

+103
-10
lines changed

src/containers/Storage/DiskStateProgressBar/DiskStateProgressBar.scss

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
.storage-disk-progress-bar {
22
$block: &;
33

4-
$border-width: 2px;
4+
$border-width: 1px;
55
$outer-border-radius: 4px;
66
$inner-border-radius: $outer-border-radius - $border-width;
77

@@ -10,7 +10,7 @@
1010
display: block;
1111

1212
min-width: 50px;
13-
height: var(--yc-text-body-2-line-height);
13+
height: var(--yc-text-body-3-line-height);
1414

1515
text-align: center;
1616

@@ -19,6 +19,17 @@
1919
border-radius: $outer-border-radius;
2020
background-color: var(--yc-color-infographics-misc-light);
2121

22+
&_compact {
23+
min-width: 0;
24+
height: 12px;
25+
26+
border-radius: 2px;
27+
28+
#{$block}__filled {
29+
border-radius: 1px;
30+
}
31+
}
32+
2233
#{$block}__filled {
2334
background-color: var(--yc-color-infographics-misc-medium);
2435
}
@@ -89,7 +100,7 @@
89100

90101
font-size: var(--yc-text-body-1-font-size);
91102
// bar height minus borders
92-
line-height: calc(var(--yc-text-body-2-line-height) - #{$border-width * 2});
103+
line-height: calc(var(--yc-text-body-3-line-height) - #{$border-width * 2});
93104

94105
color: inherit;
95106
}

src/containers/Storage/DiskStateProgressBar/DiskStateProgressBar.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,21 @@ const severityToColor = Object.entries(EDiskStateSeverity).reduce(
2727
interface DiskStateProgressBarProps {
2828
diskAllocatedPercent?: number;
2929
severity?: EDiskStateSeverity;
30+
compact?: boolean;
3031
}
3132

3233
export function DiskStateProgressBar({
3334
diskAllocatedPercent = -1,
3435
severity,
36+
compact,
3537
}: DiskStateProgressBarProps) {
3638
const inverted = useSelector((state) => JSON.parse(getSettingValue(state, INVERTED_DISKS_KEY)));
3739

3840
const renderAllocatedPercent = () => {
41+
if (compact) {
42+
return <div className={b('filled')} style={{width: '100%'}} />;
43+
}
44+
3945
return (
4046
diskAllocatedPercent >= 0 && (
4147
<React.Fragment>
@@ -55,7 +61,7 @@ export function DiskStateProgressBar({
5561
);
5662
};
5763

58-
const mods: Record<string, boolean | undefined> = {inverted};
64+
const mods: Record<string, boolean | undefined> = {inverted, compact};
5965

6066
const color = severity !== undefined && severityToColor[severity];
6167
if (color) {

src/containers/Storage/PDisk/PDisk.scss

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,33 @@
33

44
width: 120px;
55

6-
border-radius: 4px; // to match interactive area with disk shape
7-
86
&__content {
7+
position: relative;
8+
99
border-radius: 4px; // to match interactive area with disk shape
1010
}
1111

12+
&__vdisks {
13+
display: flex;
14+
// this breaks disks relative sizes, but disks rarely exceed one line
15+
flex-wrap: wrap;
16+
gap: 2px;
17+
18+
margin-bottom: 4px;
19+
}
20+
21+
&__vdisks-item {
22+
flex-basis: 5px;
23+
flex-shrink: 0;
24+
}
25+
1226
&__media-type {
1327
position: absolute;
1428
top: 0;
1529
right: 4px;
1630

1731
font-size: var(--yc-text-body-1-font-size);
32+
line-height: var(--yc-text-body-3-line-height);
1833

1934
color: var(--yc-color-text-secondary);
2035
}

src/containers/Storage/PDisk/PDisk.tsx

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,18 @@ import cn from 'bem-cn-lite';
44
import {InternalLink} from '../../../components/InternalLink';
55

66
import routes, {createHref} from '../../../routes';
7+
import {getVDisksForPDisk} from '../../../store/reducers/storage';
78
import {TPDiskStateInfo, TPDiskState} from '../../../types/api/pdisk';
9+
import {TVDiskStateInfo} from '../../../types/api/vdisk';
10+
import {stringifyVdiskId} from '../../../utils';
11+
import {useTypedSelector} from '../../../utils/hooks';
812
import {getPDiskType} from '../../../utils/pdisk';
913

1014
import {STRUCTURE} from '../../Node/NodePages';
1115

1216
import {DiskStateProgressBar, EDiskStateSeverity} from '../DiskStateProgressBar';
1317
import {PDiskPopup} from '../PDiskPopup';
18+
import {VDisk} from '../VDisk';
1419

1520
import {NOT_AVAILABLE_SEVERITY} from '../utils';
1621

@@ -51,6 +56,12 @@ export const PDisk = ({nodeId, data: rawData = {}}: PDiskProps) => {
5156
// NodeId in data is required for the popup
5257
const data = useMemo(() => ({...rawData, NodeId: nodeId}), [rawData, nodeId]);
5358

59+
const vdisks: TVDiskStateInfo[] | undefined = useTypedSelector((state) =>
60+
// @ts-expect-error selector is correct, but js infers broken type
61+
// unignore after rewriting reducer in ts
62+
getVDisksForPDisk(state, nodeId, data.PDiskId),
63+
);
64+
5465
const [severity, setSeverity] = useState(getStateSeverity(data.State));
5566
const [isPopupVisible, setIsPopupVisible] = useState(false);
5667

@@ -83,17 +94,44 @@ export const PDisk = ({nodeId, data: rawData = {}}: PDiskProps) => {
8394
: undefined;
8495
}, [data]);
8596

97+
const renderVDisks = () => {
98+
if (!vdisks?.length) {
99+
return null;
100+
}
101+
102+
return (
103+
<div className={b('vdisks')}>
104+
{vdisks.map((vdisk) => (
105+
<div
106+
key={stringifyVdiskId(vdisk.VDiskId)}
107+
className={b('vdisks-item')}
108+
style={{
109+
// 1 is small enough for empty disks to be of the minimum width
110+
// but if all of them are empty, `flex-grow: 1` would size them evenly
111+
flexGrow: (Number(vdisk.AllocatedSize) || 1),
112+
}}
113+
>
114+
<VDisk data={vdisk} compact />
115+
</div>
116+
))}
117+
</div>
118+
);
119+
};
120+
86121
return (
87122
<React.Fragment>
88123
<PDiskPopup data={data} anchorRef={anchor} open={isPopupVisible} />
89-
<div className={b()} ref={anchor} onMouseEnter={showPopup} onMouseLeave={hidePopup}>
124+
<div className={b()} ref={anchor}>
125+
{renderVDisks()}
90126
<InternalLink
91127
to={createHref(
92128
routes.node,
93129
{id: nodeId, activeTab: STRUCTURE},
94130
{pdiskId: data.PDiskId || ''},
95131
)}
96132
className={b('content')}
133+
onMouseEnter={showPopup}
134+
onMouseLeave={hidePopup}
97135
>
98136
<DiskStateProgressBar
99137
diskAllocatedPercent={pdiskAllocatedPercent}

src/containers/Storage/StorageNodes/StorageNodes.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
overflow-x: auto;
55
overflow-y: hidden;
66
justify-content: left;
7+
align-items: flex-end;
78

89
width: max-content;
910
}

src/containers/Storage/StorageNodes/StorageNodes.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,10 @@ function StorageNodes({
183183
theme="yandex-cloud"
184184
data={data}
185185
columns={columns}
186-
settings={tableSettings}
186+
settings={{
187+
...tableSettings,
188+
dynamicRenderType: 'variable',
189+
}}
187190
initialSortOrder={setSortOrder(visibleEntities)}
188191
emptyDataMessage={i18n('empty.default')}
189192
/>

src/containers/Storage/VDisk/VDisk.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,10 @@ interface VDiskProps {
4949
data?: TVDiskStateInfo;
5050
poolName?: string;
5151
nodes?: NodesHosts;
52+
compact?: boolean;
5253
}
5354

54-
export const VDisk = ({data = {}, poolName, nodes}: VDiskProps) => {
55+
export const VDisk = ({data = {}, poolName, nodes, compact}: VDiskProps) => {
5556
const [severity, setSeverity] = useState(getStateSeverity(data.VDiskState));
5657
const [isPopupVisible, setIsPopupVisible] = useState(false);
5758

@@ -131,12 +132,14 @@ export const VDisk = ({data = {}, poolName, nodes}: VDiskProps) => {
131132
<DiskStateProgressBar
132133
diskAllocatedPercent={vdiskAllocatedPercent}
133134
severity={severity}
135+
compact={compact}
134136
/>
135137
</InternalLink>
136138
) : (
137139
<DiskStateProgressBar
138140
diskAllocatedPercent={vdiskAllocatedPercent}
139141
severity={severity}
142+
compact={compact}
140143
/>
141144
)}
142145
</div>

src/containers/Storage/VDiskPopup/VDiskPopup.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ export const VDiskPopup = ({data, poolName, nodes, ...props}: VDiskPopupProps) =
128128
>
129129
{data.DonorMode && <Label className={b('donor-label')}>Donor</Label>}
130130
<InfoViewer title="VDisk" info={vdiskInfo} size="s" />
131-
<InfoViewer title="PDisk" info={pdiskInfo} size="s" />
131+
{pdiskInfo && <InfoViewer title="PDisk" info={pdiskInfo} size="s" />}
132132
</Popup>
133133
);
134134
};

src/store/reducers/storage.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,19 @@ export const getFlatListStorageNodes = createSelector([getStorageNodes], (storag
317317
});
318318
});
319319

320+
export const getVDisksForPDisk = createSelector(
321+
getStorageNodes,
322+
(_state, nodeId) => nodeId,
323+
(_state, _nodeId, pdiskId) => pdiskId,
324+
(storageNodes, nodeId, pdiskId) => {
325+
const targetNode = storageNodes?.find((node) => node.NodeId === nodeId);
326+
return targetNode?.VDisks?.filter((vdisk) => vdisk.PDiskId === pdiskId).map((data) => ({
327+
...data,
328+
NodeId: nodeId,
329+
}));
330+
},
331+
);
332+
320333
export const getFlatListStorage = createSelector(
321334
[getStorageType, getFlatListStorageGroups, getFlatListStorageNodes],
322335
(storageType, groupsList, nodesList) => {

src/types/api/nodes.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {EFlag} from './enums';
22
import {TPDiskStateInfo} from './pdisk';
33
import {TTabletStateInfo} from './tablet';
4+
import {TVDiskStateInfo} from './vdisk';
45

56
// endpoint: /viewer/json/nodes
67
// source: https://github.com/ydb-platform/ydb/blob/main/ydb/core/viewer/protos/viewer.proto
@@ -19,6 +20,7 @@ export interface TNodeInfo {
1920
NodeId: number;
2021
SystemState: TSystemStateInfo;
2122
PDisks?: TPDiskStateInfo[];
23+
VDisks?: TVDiskStateInfo[];
2224
Tablets?: TTabletStateInfo[];
2325
}
2426

0 commit comments

Comments
 (0)