+
+ {overallContent}
{storageNodesContent}
{tenantNodesContent}
{otherNodesContent}
diff --git a/src/containers/Versions/i18n/en.json b/src/containers/Versions/i18n/en.json
new file mode 100644
index 0000000000..9d0c096a85
--- /dev/null
+++ b/src/containers/Versions/i18n/en.json
@@ -0,0 +1,6 @@
+{
+ "title_overall": "Overall",
+ "title_storage": "Storage nodes",
+ "title_database": "Database nodes",
+ "title_other": "Other nodes"
+}
diff --git a/src/containers/Versions/i18n/index.ts b/src/containers/Versions/i18n/index.ts
new file mode 100644
index 0000000000..493da67aca
--- /dev/null
+++ b/src/containers/Versions/i18n/index.ts
@@ -0,0 +1,7 @@
+import {registerKeysets} from '../../../utils/i18n';
+
+import en from './en.json';
+
+const COMPONENT = 'ydb-versions';
+
+export default registerKeysets(COMPONENT, {en});
diff --git a/src/containers/Versions/utils.ts b/src/containers/Versions/utils.ts
new file mode 100644
index 0000000000..cac2feab99
--- /dev/null
+++ b/src/containers/Versions/utils.ts
@@ -0,0 +1,43 @@
+import React from 'react';
+
+import {skipToken} from '@reduxjs/toolkit/query';
+
+import {nodesApi} from '../../store/reducers/nodes/nodes';
+import {isClusterInfoV2} from '../../types/api/cluster';
+import type {TClusterInfo} from '../../types/api/cluster';
+import type {VersionToColorMap} from '../../types/versions';
+import {parseNodeGroupsToVersionsValues, parseNodesToVersionsValues} from '../../utils/versions';
+
+export const useGetVersionValues = (cluster?: TClusterInfo, versionToColor?: VersionToColorMap) => {
+ const {currentData} = nodesApi.useGetNodesQuery(
+ isClusterInfoV2(cluster)
+ ? skipToken
+ : {
+ tablets: false,
+ group: 'Version',
+ },
+ );
+
+ const versionsValues = React.useMemo(() => {
+ if (isClusterInfoV2(cluster) && cluster.MapVersions) {
+ const groups = Object.entries(cluster.MapVersions).map(([version, count]) => ({
+ name: version,
+ count,
+ }));
+ return parseNodeGroupsToVersionsValues(groups, versionToColor, cluster.NodesTotal);
+ }
+ if (!currentData) {
+ return [];
+ }
+ if (Array.isArray(currentData.NodeGroups)) {
+ return parseNodeGroupsToVersionsValues(
+ currentData.NodeGroups,
+ versionToColor,
+ cluster?.NodesTotal,
+ );
+ }
+ return parseNodesToVersionsValues(currentData.Nodes, versionToColor);
+ }, [currentData, versionToColor, cluster]);
+
+ return versionsValues;
+};
diff --git a/src/utils/clusterVersionColors.ts b/src/utils/clusterVersionColors.ts
index c45a1e246d..a97c173798 100644
--- a/src/utils/clusterVersionColors.ts
+++ b/src/utils/clusterVersionColors.ts
@@ -3,7 +3,7 @@ import uniqBy from 'lodash/uniqBy';
import type {MetaClusterVersion} from '../types/api/meta';
import type {VersionToColorMap} from '../types/versions';
-import {COLORS, GREY_COLOR, getMinorVersion, hashCode} from './versions';
+import {COLORS, DEFAULT_COLOR, getMinorVersion, hashCode} from './versions';
const UNDEFINED_COLOR_INDEX = '__no_color__';
@@ -35,7 +35,7 @@ export const getVersionColors = (versionMap: VersionsMap) => {
.sort((a, b) => hashCode(b) - hashCode(a))
.forEach((minor, minorIndex) => {
if (baseColorIndex === UNDEFINED_COLOR_INDEX) {
- versionToColor.set(minor, GREY_COLOR);
+ versionToColor.set(minor, DEFAULT_COLOR);
} else {
// baseColorIndex is numeric as we check if it is UNDEFINED_COLOR_INDEX before
const currentColorIndex = Number(baseColorIndex) % COLORS.length;
diff --git a/src/utils/versions/getVersionsColors.ts b/src/utils/versions/getVersionsColors.ts
index ff19d1d652..0835d1aa1d 100644
--- a/src/utils/versions/getVersionsColors.ts
+++ b/src/utils/versions/getVersionsColors.ts
@@ -12,7 +12,6 @@ export const hashCode = (s: string) => {
// TODO: colors used in charts as well, need to move to constants
// 11 distinct colors from https://mokole.com/palette.html
export const COLORS = [
- '#008000', // green
'#4169e1', // royalblue
'#ffd700', // gold
'#ff8c00', // darkorange
@@ -25,7 +24,7 @@ export const COLORS = [
'#b22222', // firebrick
];
-export const GREY_COLOR = '#bfbfbf';
+export const DEFAULT_COLOR = '#008000'; // green
export const getVersionsMap = (versions: string[], initialMap: VersionsMap = new Map()) => {
versions.forEach((version) => {
@@ -88,7 +87,7 @@ export const getVersionToColorMap = (versionsMap: VersionsMap) => {
versionToColor.set(minor.version, versionColor);
});
} else {
- versionToColor.set(item.version, GREY_COLOR);
+ versionToColor.set(item.version, DEFAULT_COLOR);
}
});
return versionToColor;
diff --git a/src/utils/versions/parseNodesToVersionsValues.ts b/src/utils/versions/parseNodesToVersionsValues.ts
index e33eb208d7..37f43f8b71 100644
--- a/src/utils/versions/parseNodesToVersionsValues.ts
+++ b/src/utils/versions/parseNodesToVersionsValues.ts
@@ -4,6 +4,8 @@ import type {VersionToColorMap, VersionValue} from '../../types/versions';
import {getMinorVersion} from './parseVersion';
+const MIN_VALUE = 0.5;
+
export const parseNodesToVersionsValues = (
nodes: TSystemStateInfo[] = [],
versionsToColor?: VersionToColorMap,
@@ -18,15 +20,16 @@ export const parseNodesToVersionsValues = (
}
return acc;
}, {});
-
- return Object.keys(versionsCount).map((version) => {
+ const result = Object.keys(versionsCount).map((version) => {
+ const value = (versionsCount[version] / nodes.length) * 100;
return {
title: version,
version: version,
color: versionsToColor?.get(getMinorVersion(version)),
- value: (versionsCount[version] / nodes.length) * 100,
+ value: value < MIN_VALUE ? MIN_VALUE : value,
};
});
+ return normalizeResult(result);
};
export function parseNodeGroupsToVersionsValues(
@@ -35,12 +38,32 @@ export function parseNodeGroupsToVersionsValues(
total?: number,
) {
const normalizedTotal = total ?? groups.reduce((acc, group) => acc + group.count, 0);
- return groups.map((group) => {
+ const result = groups.map((group) => {
+ const value = (group.count / normalizedTotal) * 100;
return {
title: group.name,
version: group.name,
color: versionsToColor?.get(group.name),
- value: (group.count / normalizedTotal) * 100,
+ value: value < MIN_VALUE ? MIN_VALUE : value,
};
});
+ const normalized = normalizeResult(result);
+ return normalized;
+}
+
+function normalizeResult(data: VersionValue[]) {
+ let maximum = data[0].value;
+ let maximumIndex = 0;
+ let total = 0;
+ data.forEach((item, index) => {
+ total += item.value;
+ if (item.value > maximum) {
+ maximum = item.value;
+ maximumIndex = index;
+ }
+ });
+ const result = [...data];
+ //Progress breakes if sum of values more than 100, so we need to subtrackt difference appeared because of MIN_VALUE from the biggest value in set
+ result[maximumIndex] = {...data[maximumIndex], value: maximum + 100 - total};
+ return result;
}