Skip to content

Commit 8de75b2

Browse files
committed
fix(ClusterMetricsCores): format value and capacity same way
1 parent 96411ee commit 8de75b2

File tree

13 files changed

+276
-72
lines changed

13 files changed

+276
-72
lines changed

src/components/FormattedBytes/FormattedBytes.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import type {FormatBytesArgs} from '../../utils/bytesParsers';
1+
import type {BytesSizes} from '../../utils/bytesParsers';
22
import {formatBytes} from '../../utils/bytesParsers';
3+
import type {FormatValuesArgs} from '../../utils/bytesParsers/common';
34

4-
type FormattedBytesProps = FormatBytesArgs;
5+
type FormattedBytesProps = FormatValuesArgs<BytesSizes>;
56

67
export const FormattedBytes = ({value, withSpeedLabel, ...params}: FormattedBytesProps) => {
78
const formatted = formatBytes({value, withSpeedLabel, ...params});

src/components/FormattedBytes/utils.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
import type {FormatBytesArgs} from '../../utils/bytesParsers';
1+
import type {BytesSizes} from '../../utils/bytesParsers';
2+
import type {FormatValuesArgs} from '../../utils/bytesParsers/common';
23

34
import {FormattedBytes} from './FormattedBytes';
45

56
export const toFormattedSize = (
67
value: number | string | undefined,
7-
params?: Omit<FormatBytesArgs, 'value'>,
8+
params?: Omit<FormatValuesArgs<BytesSizes>, 'value'>,
89
) => {
910
if (!value) {
1011
return null;

src/containers/Cluster/ClusterDashboard/ClusterDashboard.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,11 @@ function ClusterDoughnuts({cluster, loading}: ClusterDashboardProps) {
7070
}
7171
const metricsCards = [];
7272
if (isClusterInfoV2(cluster)) {
73-
const {CoresUsed, NumberOfCpus} = cluster;
74-
if (valueIsDefined(CoresUsed) && valueIsDefined(NumberOfCpus)) {
73+
const {CoresUsed, NumberOfCpus, CoresTotal} = cluster;
74+
const total = CoresTotal ?? NumberOfCpus;
75+
if (valueIsDefined(CoresUsed) && valueIsDefined(total)) {
7576
metricsCards.push(
76-
<ClusterMetricsCores value={CoresUsed} capacity={NumberOfCpus} key="cores" />,
77+
<ClusterMetricsCores value={CoresUsed} capacity={total} key="cores" />,
7778
);
7879
}
7980
}

src/containers/Cluster/ClusterDashboard/components/ClusterMetricsCores.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {DoughnutMetrics} from '../../../../components/DoughnutMetrics/DoughnutMetrics';
2-
import {formatNumberCustom} from '../../../../utils/dataFormatters/dataFormatters';
2+
import {formatNumber, formatNumericValues} from '../../../../utils/dataFormatters/dataFormatters';
33
import i18n from '../../i18n';
44
import type {ClusterMetricsCommonProps} from '../shared';
55
import {useDiagramValues} from '../utils';
@@ -9,7 +9,13 @@ import {ClusterMetricsCardDoughnut} from './ClusterMetricsCard';
99
interface ClusterMetricsCoresProps extends ClusterMetricsCommonProps {}
1010

1111
function formatCoresLegend({value, capacity}: {value: number; capacity: number}) {
12-
return `${formatNumberCustom(value)} / ${formatNumberCustom(capacity)}\n${i18n('context_cores')}`;
12+
let formatted = [];
13+
if (capacity < 10_000) {
14+
formatted = [formatNumber(value), formatNumber(capacity)];
15+
} else {
16+
formatted = formatNumericValues(value, capacity, undefined, '', true);
17+
}
18+
return `${formatted[0]} / ${formatted[1]}\n${i18n('context_cores')}`;
1319
}
1420

1521
export function ClusterMetricsCores({value, capacity, ...rest}: ClusterMetricsCoresProps) {

src/types/api/cluster.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ export interface TClusterInfoV2 extends TClusterInfoV1 {
7777
Version?: number;
7878
/** value is uint64 */
7979
CoresUsed?: string;
80+
CoresTotal?: number;
8081
}
8182

8283
export type TClusterInfo = TClusterInfoV1 | TClusterInfoV2;

src/utils/bytesParsers/common.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import {isNumeric} from '../utils';
2+
3+
export interface FormatToSizeArgs<T> {
4+
value: number;
5+
size?: T;
6+
precision?: number;
7+
}
8+
9+
export type FormatValuesArgs<T> = Omit<FormatToSizeArgs<T>, 'value'> & {
10+
value: number | string | undefined | null;
11+
withSpeedLabel?: boolean;
12+
withSizeLabel?: boolean;
13+
significantDigits?: number;
14+
delimiter?: string;
15+
};
16+
17+
export function formatValues<T>(
18+
formatter: (args: FormatValuesArgs<T>) => string,
19+
sizeGetter: (value: number, significantDigits: number) => T,
20+
value?: number,
21+
total?: number,
22+
size?: T,
23+
delimiter?: string,
24+
withValueLabel = false,
25+
) {
26+
let calculatedSize = sizeGetter(Number(value), 0);
27+
let valueWithSizeLabel = true;
28+
let valuePrecision = 0;
29+
30+
if (isNumeric(total)) {
31+
calculatedSize = sizeGetter(Number(total), 0);
32+
valueWithSizeLabel = withValueLabel;
33+
valuePrecision = 1;
34+
}
35+
36+
let formattedValue = formatter({
37+
value,
38+
withSizeLabel: valueWithSizeLabel,
39+
size: size || calculatedSize,
40+
precision: valuePrecision,
41+
delimiter,
42+
});
43+
if (value && value > 0) {
44+
while (parseFloat(formattedValue) === 0) {
45+
valuePrecision += 1;
46+
formattedValue = formatter({
47+
value,
48+
withSizeLabel: valueWithSizeLabel,
49+
size: size || calculatedSize,
50+
precision: valuePrecision,
51+
delimiter,
52+
});
53+
}
54+
}
55+
const formattedTotal = formatter({
56+
value: total,
57+
size: size || calculatedSize,
58+
delimiter,
59+
});
60+
61+
return [formattedValue, formattedTotal];
62+
}

src/utils/bytesParsers/formatBytes.ts

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {GIGABYTE, KILOBYTE, MEGABYTE, TERABYTE} from '../constants';
22
import {formatNumber, roundToPrecision} from '../dataFormatters/dataFormatters';
33
import {UNBREAKABLE_GAP, isNumeric} from '../utils';
44

5+
import type {FormatToSizeArgs, FormatValuesArgs} from './common';
56
import i18n from './i18n';
67

78
const sizes = {
@@ -72,13 +73,7 @@ export const getSizeWithSignificantDigits = (value: number, significantDigits: n
7273
return size;
7374
};
7475

75-
interface FormatToSizeArgs {
76-
value: number;
77-
size?: BytesSizes;
78-
precision?: number;
79-
}
80-
81-
const formatToSize = ({value, size = 'mb', precision = 0}: FormatToSizeArgs) => {
76+
const formatToSize = ({value, size = 'mb', precision = 0}: FormatToSizeArgs<BytesSizes>) => {
8277
const result = roundToPrecision(Number(value) / sizes[size].value, precision);
8378

8479
return formatNumber(result);
@@ -92,14 +87,6 @@ const addSpeedLabel = (result: string, size: BytesSizes) => {
9287
return addSizeLabel(result, size) + i18n('perSecond');
9388
};
9489

95-
export type FormatBytesArgs = Omit<FormatToSizeArgs, 'value'> & {
96-
value: number | string | undefined | null;
97-
withSpeedLabel?: boolean;
98-
withSizeLabel?: boolean;
99-
significantDigits?: number;
100-
delimiter?: string;
101-
};
102-
10390
/**
10491
* @param significantDigits - number of digits above 3
10592
*/
@@ -111,7 +98,7 @@ export const formatBytes = ({
11198
significantDigits = 0,
11299
delimiter,
113100
...params
114-
}: FormatBytesArgs) => {
101+
}: FormatValuesArgs<BytesSizes>) => {
115102
if (!isNumeric(value)) {
116103
return '';
117104
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import {formatNumber, roundToPrecision} from '../dataFormatters/dataFormatters';
2+
import {UNBREAKABLE_GAP, isNumeric} from '../utils';
3+
4+
import type {FormatToSizeArgs, FormatValuesArgs} from './common';
5+
import i18n from './i18n';
6+
7+
const sizes = {
8+
thousand: {
9+
value: 1_000,
10+
label: i18n('label_thousand'),
11+
},
12+
million: {
13+
value: 1_000_000,
14+
label: i18n('label_million'),
15+
},
16+
billion: {
17+
value: 1_000_000_000,
18+
label: i18n('label_billion'),
19+
},
20+
trillion: {
21+
value: 1_000_000_000_000,
22+
label: i18n('label_trillion'),
23+
},
24+
};
25+
26+
export type Digits = keyof typeof sizes;
27+
28+
/**
29+
* This function is needed to keep more than 3 digits of the same size.
30+
*
31+
* @param significantDigits - number of digits above 3
32+
* @returns size to format value to get required number of digits
33+
*
34+
* By default value converted to the next size when it's above 1000,
35+
* so we have 900mb and 1gb. To extend it additional significantDigits could be set
36+
*
37+
* significantDigits value added above default 3
38+
*
39+
* significantDigits = 1 - 9 000k and 10m
40+
*
41+
* significantDigits = 2 - 90 000m and 100b
42+
*
43+
* significantDigits = 3 - 900 000b and 1000t
44+
*/
45+
export const getNumberWithSignificantDigits = (value: number, significantDigits: number) => {
46+
const multiplier = 10 ** significantDigits;
47+
48+
const thousandLevel = sizes.million.value * multiplier;
49+
const millionLevel = sizes.million.value * multiplier;
50+
const billionLevel = sizes.billion.value * multiplier;
51+
const trillionLevel = sizes.trillion.value * multiplier;
52+
53+
let size: Digits = 'thousand';
54+
55+
if (value > thousandLevel) {
56+
size = 'thousand';
57+
}
58+
if (value >= millionLevel) {
59+
size = 'million';
60+
}
61+
if (value >= billionLevel) {
62+
size = 'billion';
63+
}
64+
if (value >= trillionLevel) {
65+
size = 'trillion';
66+
}
67+
68+
return size;
69+
};
70+
71+
const formatToSize = ({value, size = 'thousand', precision = 0}: FormatToSizeArgs<Digits>) => {
72+
const result = roundToPrecision(Number(value) / sizes[size].value, precision);
73+
74+
return formatNumber(result);
75+
};
76+
77+
const addSizeLabel = (result: string, size: Digits, delimiter = UNBREAKABLE_GAP) => {
78+
return result + delimiter + sizes[size].label;
79+
};
80+
81+
/**
82+
* @param significantDigits - number of digits above 3
83+
*/
84+
export const formatNumberWithDigits = ({
85+
value,
86+
size,
87+
withSizeLabel = true,
88+
significantDigits = 0,
89+
delimiter,
90+
...params
91+
}: FormatValuesArgs<Digits>) => {
92+
if (!isNumeric(value)) {
93+
return '';
94+
}
95+
96+
const numValue = Number(value);
97+
98+
const sizeToConvert = size ?? getNumberWithSignificantDigits(numValue, significantDigits);
99+
100+
const result = formatToSize({value: numValue, size: sizeToConvert, ...params});
101+
102+
if (withSizeLabel) {
103+
return addSizeLabel(result, sizeToConvert, delimiter);
104+
}
105+
106+
return result;
107+
};

src/utils/bytesParsers/i18n/en.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,9 @@
44
"mb": "MB",
55
"gb": "GB",
66
"tb": "TB",
7+
"label_thousand": "k",
8+
"label_million": "m",
9+
"label_billion": "b",
10+
"label_trillion": "t",
711
"perSecond": "/s"
812
}

src/utils/bytesParsers/i18n/index.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import {registerKeysets} from '../../i18n';
22

33
import en from './en.json';
4-
import ru from './ru.json';
54

65
const COMPONENT = 'ydb-bytes-parsers';
76

8-
export default registerKeysets(COMPONENT, {ru, en});
7+
export default registerKeysets(COMPONENT, {en});

0 commit comments

Comments
 (0)