Skip to content

Commit 6cc07d5

Browse files
authored
feat(Versions): show overall version info in Versions tab (#1442)
1 parent 9daa5a3 commit 6cc07d5

File tree

11 files changed

+150
-19
lines changed

11 files changed

+150
-19
lines changed

src/containers/Cluster/Cluster.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ export function Cluster({
200200
getLocationObjectFromHref(getClusterPath(clusterTabsIds.versions)).pathname
201201
}
202202
>
203-
<Versions versionToColor={versionToColor} />
203+
<Versions versionToColor={versionToColor} cluster={cluster} />
204204
</Route>
205205
<Route
206206
render={() => (

src/containers/Cluster/VersionsBar/VersionsBar.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
display: flex;
33
flex-direction: column;
44

5-
width: 600px;
5+
min-width: 600px;
66

77
& .g-progress {
88
width: 100%;

src/containers/Cluster/VersionsBar/VersionsBar.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type {ProgressProps} from '@gravity-ui/uikit';
12
import {Progress} from '@gravity-ui/uikit';
23

34
import type {VersionValue} from '../../../types/versions';
@@ -9,12 +10,18 @@ const b = cn('ydb-cluster-versions-bar');
910

1011
interface VersionsBarProps {
1112
versionsValues?: VersionValue[];
13+
size?: ProgressProps['size'];
14+
progressClassName?: string;
1215
}
1316

14-
export const VersionsBar = ({versionsValues = []}: VersionsBarProps) => {
17+
export const VersionsBar = ({
18+
versionsValues = [],
19+
size = 's',
20+
progressClassName: className,
21+
}: VersionsBarProps) => {
1522
return (
1623
<div className={b()}>
17-
<Progress value={100} stack={versionsValues} size="s" />
24+
<Progress value={100} stack={versionsValues} size={size} className={className} />
1825
<div className={b('versions')}>
1926
{versionsValues.map((item, index) => (
2027
<div

src/containers/Versions/Versions.scss

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@
33
.ydb-versions {
44
$_: &;
55

6+
--ydb-info-viewer-font-size: var(--g-text-body-2-font-size);
7+
--ydb-info-viewer-line-height: var(--g-text-body-2-line-height);
8+
9+
font-size: var(--ydb-info-viewer-font-size);
10+
line-height: var(--ydb-info-viewer-line-height);
11+
612
&__controls {
713
display: flex;
814
align-items: center;
@@ -25,4 +31,24 @@
2531
margin-right: 25px;
2632
}
2733
}
34+
&__overall-wrapper {
35+
margin-top: 10px;
36+
margin-bottom: 10px;
37+
padding: 20px;
38+
39+
border: 1px solid var(--g-color-line-generic);
40+
border-radius: 10px;
41+
}
42+
&__overall-progress {
43+
height: 20px;
44+
45+
line-height: 20px;
46+
47+
border-radius: 5px;
48+
.g-progress__stack {
49+
height: 20px;
50+
51+
line-height: 20px;
52+
}
53+
}
2854
}

src/containers/Versions/Versions.tsx

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,30 @@ import {Checkbox, RadioButton} from '@gravity-ui/uikit';
44

55
import {Loader} from '../../components/Loader';
66
import {nodesApi} from '../../store/reducers/nodes/nodes';
7+
import type {TClusterInfo} from '../../types/api/cluster';
78
import type {VersionToColorMap} from '../../types/versions';
89
import {cn} from '../../utils/cn';
910
import {useAutoRefreshInterval} from '../../utils/hooks';
11+
import {VersionsBar} from '../Cluster/VersionsBar/VersionsBar';
1012

1113
import {GroupedNodesTree} from './GroupedNodesTree/GroupedNodesTree';
1214
import {getGroupedStorageNodes, getGroupedTenantNodes, getOtherNodes} from './groupNodes';
15+
import i18n from './i18n';
1316
import {GroupByValue} from './types';
17+
import {useGetVersionValues} from './utils';
1418

1519
import './Versions.scss';
1620

1721
const b = cn('ydb-versions');
1822

1923
interface VersionsProps {
2024
versionToColor?: VersionToColorMap;
25+
cluster?: TClusterInfo;
2126
}
2227

23-
export const Versions = ({versionToColor}: VersionsProps) => {
28+
export const Versions = ({versionToColor, cluster}: VersionsProps) => {
2429
const [autoRefreshInterval] = useAutoRefreshInterval();
30+
const versionsValues = useGetVersionValues(cluster, versionToColor);
2531
const {currentData, isLoading: isNodesLoading} = nodesApi.useGetNodesQuery(
2632
{tablets: false},
2733
{pollingInterval: autoRefreshInterval},
@@ -74,7 +80,7 @@ export const Versions = ({versionToColor}: VersionsProps) => {
7480
const otherNodes = getOtherNodes(nodes, versionToColor);
7581
const storageNodesContent = storageNodes?.length ? (
7682
<React.Fragment>
77-
<h3>Storage nodes</h3>
83+
<h4>{i18n('title_storage')}</h4>
7884
{storageNodes.map(({title, nodes: itemNodes, items, versionColor}) => (
7985
<GroupedNodesTree
8086
key={`storage-nodes-${title}`}
@@ -88,7 +94,7 @@ export const Versions = ({versionToColor}: VersionsProps) => {
8894
) : null;
8995
const tenantNodesContent = tenantNodes?.length ? (
9096
<React.Fragment>
91-
<h3>Database nodes</h3>
97+
<h4>{i18n('title_database')}</h4>
9298
{renderControls()}
9399
{tenantNodes.map(({title, nodes: itemNodes, items, versionColor, versionsValues}) => (
94100
<GroupedNodesTree
@@ -105,7 +111,7 @@ export const Versions = ({versionToColor}: VersionsProps) => {
105111
) : null;
106112
const otherNodesContent = otherNodes?.length ? (
107113
<React.Fragment>
108-
<h3>Other nodes</h3>
114+
<h4>{i18n('title_other')}</h4>
109115
{otherNodes.map(({title, nodes: itemNodes, items, versionColor, versionsValues}) => (
110116
<GroupedNodesTree
111117
key={`other-nodes-${title}`}
@@ -119,8 +125,22 @@ export const Versions = ({versionToColor}: VersionsProps) => {
119125
</React.Fragment>
120126
) : null;
121127

128+
const overallContent = (
129+
<React.Fragment>
130+
<h4>{i18n('title_overall')}</h4>
131+
<div className={b('overall-wrapper')}>
132+
<VersionsBar
133+
progressClassName={b('overall-progress')}
134+
versionsValues={versionsValues.filter((el) => el.title !== 'unknown')}
135+
size="m"
136+
/>
137+
</div>
138+
</React.Fragment>
139+
);
140+
122141
return (
123-
<div className={b('versions')}>
142+
<div className={b()}>
143+
{overallContent}
124144
{storageNodesContent}
125145
{tenantNodesContent}
126146
{otherNodesContent}

src/containers/Versions/i18n/en.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"title_overall": "Overall",
3+
"title_storage": "Storage nodes",
4+
"title_database": "Database nodes",
5+
"title_other": "Other nodes"
6+
}

src/containers/Versions/i18n/index.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import {registerKeysets} from '../../../utils/i18n';
2+
3+
import en from './en.json';
4+
5+
const COMPONENT = 'ydb-versions';
6+
7+
export default registerKeysets(COMPONENT, {en});

src/containers/Versions/utils.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import React from 'react';
2+
3+
import {skipToken} from '@reduxjs/toolkit/query';
4+
5+
import {nodesApi} from '../../store/reducers/nodes/nodes';
6+
import {isClusterInfoV2} from '../../types/api/cluster';
7+
import type {TClusterInfo} from '../../types/api/cluster';
8+
import type {VersionToColorMap} from '../../types/versions';
9+
import {parseNodeGroupsToVersionsValues, parseNodesToVersionsValues} from '../../utils/versions';
10+
11+
export const useGetVersionValues = (cluster?: TClusterInfo, versionToColor?: VersionToColorMap) => {
12+
const {currentData} = nodesApi.useGetNodesQuery(
13+
isClusterInfoV2(cluster)
14+
? skipToken
15+
: {
16+
tablets: false,
17+
group: 'Version',
18+
},
19+
);
20+
21+
const versionsValues = React.useMemo(() => {
22+
if (isClusterInfoV2(cluster) && cluster.MapVersions) {
23+
const groups = Object.entries(cluster.MapVersions).map(([version, count]) => ({
24+
name: version,
25+
count,
26+
}));
27+
return parseNodeGroupsToVersionsValues(groups, versionToColor, cluster.NodesTotal);
28+
}
29+
if (!currentData) {
30+
return [];
31+
}
32+
if (Array.isArray(currentData.NodeGroups)) {
33+
return parseNodeGroupsToVersionsValues(
34+
currentData.NodeGroups,
35+
versionToColor,
36+
cluster?.NodesTotal,
37+
);
38+
}
39+
return parseNodesToVersionsValues(currentData.Nodes, versionToColor);
40+
}, [currentData, versionToColor, cluster]);
41+
42+
return versionsValues;
43+
};

src/utils/clusterVersionColors.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import uniqBy from 'lodash/uniqBy';
33
import type {MetaClusterVersion} from '../types/api/meta';
44
import type {VersionToColorMap} from '../types/versions';
55

6-
import {COLORS, GREY_COLOR, getMinorVersion, hashCode} from './versions';
6+
import {COLORS, DEFAULT_COLOR, getMinorVersion, hashCode} from './versions';
77

88
const UNDEFINED_COLOR_INDEX = '__no_color__';
99

@@ -35,7 +35,7 @@ export const getVersionColors = (versionMap: VersionsMap) => {
3535
.sort((a, b) => hashCode(b) - hashCode(a))
3636
.forEach((minor, minorIndex) => {
3737
if (baseColorIndex === UNDEFINED_COLOR_INDEX) {
38-
versionToColor.set(minor, GREY_COLOR);
38+
versionToColor.set(minor, DEFAULT_COLOR);
3939
} else {
4040
// baseColorIndex is numeric as we check if it is UNDEFINED_COLOR_INDEX before
4141
const currentColorIndex = Number(baseColorIndex) % COLORS.length;

src/utils/versions/getVersionsColors.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ export const hashCode = (s: string) => {
1212
// TODO: colors used in charts as well, need to move to constants
1313
// 11 distinct colors from https://mokole.com/palette.html
1414
export const COLORS = [
15-
'#008000', // green
1615
'#4169e1', // royalblue
1716
'#ffd700', // gold
1817
'#ff8c00', // darkorange
@@ -25,7 +24,7 @@ export const COLORS = [
2524
'#b22222', // firebrick
2625
];
2726

28-
export const GREY_COLOR = '#bfbfbf';
27+
export const DEFAULT_COLOR = '#008000'; // green
2928

3029
export const getVersionsMap = (versions: string[], initialMap: VersionsMap = new Map()) => {
3130
versions.forEach((version) => {
@@ -88,7 +87,7 @@ export const getVersionToColorMap = (versionsMap: VersionsMap) => {
8887
versionToColor.set(minor.version, versionColor);
8988
});
9089
} else {
91-
versionToColor.set(item.version, GREY_COLOR);
90+
versionToColor.set(item.version, DEFAULT_COLOR);
9291
}
9392
});
9493
return versionToColor;

0 commit comments

Comments
 (0)