Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/components/FormattedBytes/FormattedBytes.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import type {FormatBytesArgs} from '../../utils/bytesParsers';
import type {BytesSizes} from '../../utils/bytesParsers';
import {formatBytes} from '../../utils/bytesParsers';
import type {FormatValuesArgs} from '../../utils/dataFormatters/common';

type FormattedBytesProps = FormatBytesArgs;
type FormattedBytesProps = FormatValuesArgs<BytesSizes>;

export const FormattedBytes = ({value, withSpeedLabel, ...params}: FormattedBytesProps) => {
const formatted = formatBytes({value, withSpeedLabel, ...params});
Expand Down
5 changes: 3 additions & 2 deletions src/components/FormattedBytes/utils.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import type {FormatBytesArgs} from '../../utils/bytesParsers';
import type {BytesSizes} from '../../utils/bytesParsers';
import type {FormatValuesArgs} from '../../utils/dataFormatters/common';

import {FormattedBytes} from './FormattedBytes';

export const toFormattedSize = (
value: number | string | undefined,
params?: Omit<FormatBytesArgs, 'value'>,
params?: Omit<FormatValuesArgs<BytesSizes>, 'value'>,
) => {
if (!value) {
return null;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {DoughnutMetrics} from '../../../../components/DoughnutMetrics/DoughnutMetrics';
import {formatNumberCustom} from '../../../../utils/dataFormatters/dataFormatters';
import {formatNumber, formatNumericValues} from '../../../../utils/dataFormatters/dataFormatters';
import i18n from '../../i18n';
import type {ClusterMetricsCommonProps} from '../shared';
import {useDiagramValues} from '../utils';
Expand All @@ -9,7 +9,13 @@ import {ClusterMetricsCardDoughnut} from './ClusterMetricsCard';
interface ClusterMetricsCoresProps extends ClusterMetricsCommonProps {}

function formatCoresLegend({value, capacity}: {value: number; capacity: number}) {
return `${formatNumberCustom(value)} / ${formatNumberCustom(capacity)}\n${i18n('context_cores')}`;
let formatted = [];
if (capacity < 10_000) {
formatted = [formatNumber(Math.round(value)), formatNumber(Math.round(capacity))];
} else {
formatted = formatNumericValues(value, capacity, undefined, '', true);
}
return `${formatted[0]} / ${formatted[1]}\n${i18n('context_cores')}`;
}

export function ClusterMetricsCores({value, capacity, ...rest}: ClusterMetricsCoresProps) {
Expand Down
19 changes: 3 additions & 16 deletions src/utils/bytesParsers/formatBytes.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {GIGABYTE, KILOBYTE, MEGABYTE, TERABYTE} from '../constants';
import type {FormatToSizeArgs, FormatValuesArgs} from '../dataFormatters/common';
import {formatNumber, roundToPrecision} from '../dataFormatters/dataFormatters';
import {UNBREAKABLE_GAP, isNumeric} from '../utils';

Expand Down Expand Up @@ -72,13 +73,7 @@ export const getSizeWithSignificantDigits = (value: number, significantDigits: n
return size;
};

interface FormatToSizeArgs {
value: number;
size?: BytesSizes;
precision?: number;
}

const formatToSize = ({value, size = 'mb', precision = 0}: FormatToSizeArgs) => {
const formatToSize = ({value, size = 'mb', precision = 0}: FormatToSizeArgs<BytesSizes>) => {
const result = roundToPrecision(Number(value) / sizes[size].value, precision);

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

export type FormatBytesArgs = Omit<FormatToSizeArgs, 'value'> & {
value: number | string | undefined | null;
withSpeedLabel?: boolean;
withSizeLabel?: boolean;
significantDigits?: number;
delimiter?: string;
};

/**
* @param significantDigits - number of digits above 3
*/
Expand All @@ -111,7 +98,7 @@ export const formatBytes = ({
significantDigits = 0,
delimiter,
...params
}: FormatBytesArgs) => {
}: FormatValuesArgs<BytesSizes>) => {
if (!isNumeric(value)) {
return '';
}
Expand Down
4 changes: 4 additions & 0 deletions src/utils/bytesParsers/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,9 @@
"mb": "MB",
"gb": "GB",
"tb": "TB",
"label_thousand": "k",
"label_million": "m",
"label_billion": "b",
"label_trillion": "t",
"perSecond": "/s"
}
3 changes: 1 addition & 2 deletions src/utils/bytesParsers/i18n/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import {registerKeysets} from '../../i18n';

import en from './en.json';
import ru from './ru.json';

const COMPONENT = 'ydb-bytes-parsers';

export default registerKeysets(COMPONENT, {ru, en});
export default registerKeysets(COMPONENT, {en});
8 changes: 0 additions & 8 deletions src/utils/bytesParsers/i18n/ru.json

This file was deleted.

43 changes: 43 additions & 0 deletions src/utils/dataFormatters/__test__/formatNumbers.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import {UNBREAKABLE_GAP} from '../../utils';
import {formatNumericValues} from '../dataFormatters';

describe('formatNumericValues', () => {
it('should return ["", ""] when both value and total are undefined', () => {
const result = formatNumericValues();
expect(result).toEqual(['', '']);
});

it('should format value correctly when total is undefined', () => {
const result = formatNumericValues(1000);
expect(result).toEqual([`1${UNBREAKABLE_GAP}k`, '']);
});

it('should format total correctly when value is undefined', () => {
const result = formatNumericValues(undefined, 1_000_000);
expect(result).toEqual(['', `1${UNBREAKABLE_GAP}m`]);
});

it('should format both value and total correctly', () => {
const result = formatNumericValues(1024, 2048);
expect(result).toEqual(['1', `2${UNBREAKABLE_GAP}k`]);
});
it('should format value with label if set', () => {
const result = formatNumericValues(1024, 2048, undefined, undefined, true);
expect(result).toEqual([`1${UNBREAKABLE_GAP}k`, `2${UNBREAKABLE_GAP}k`]);
});

it('should return ["0", formattedTotal] when value is 0', () => {
const result = formatNumericValues(0, 2048);
expect(result).toEqual(['0', `2${UNBREAKABLE_GAP}k`]);
});

it('should use provided size and delimiter', () => {
const result = formatNumericValues(5120, 10240, 'billion', '/');
expect(result).toEqual(['0', '0/b']);
});

it('should handle non-numeric total gracefully', () => {
const result = formatNumericValues(2048, 'Not a number' as any);
expect(result).toEqual([`2${UNBREAKABLE_GAP}k`, '']);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,14 @@ describe('formatStorageValues', () => {
expect(result).toEqual(['1', `2${UNBREAKABLE_GAP}KB`]);
});

it('should handle small value compared to total and increase precision', () => {
const result = formatStorageValues(1, 1024);
expect(result).toEqual(['0.001', `1${UNBREAKABLE_GAP}KB`]);
});

it('should return ["0", formattedTotal] when value is 0', () => {
const result = formatStorageValues(0, 2048);
expect(result).toEqual(['0', `2${UNBREAKABLE_GAP}KB`]);
});

it('should use provided size and delimiter', () => {
const result = formatStorageValues(5120, 10240, 'mb', '/');
expect(result).toEqual(['0.01', '0/MB']);
expect(result).toEqual(['0', '0/MB']);
});

it('should handle non-numeric total gracefully', () => {
Expand Down
50 changes: 50 additions & 0 deletions src/utils/dataFormatters/common.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import {isNumeric} from '../utils';

export interface FormatToSizeArgs<T> {
value: number;
size?: T;
precision?: number;
}

export type FormatValuesArgs<T> = Omit<FormatToSizeArgs<T>, 'value'> & {
value: number | string | undefined | null;
withSpeedLabel?: boolean;
withSizeLabel?: boolean;
significantDigits?: number;
delimiter?: string;
};

export function formatValues<T>(
formatter: (args: FormatValuesArgs<T>) => string,
sizeGetter: (value: number, significantDigits: number) => T,
value?: number,
total?: number,
size?: T,
delimiter?: string,
withValueLabel = false,
) {
let calculatedSize = sizeGetter(Number(value), 0);
let valueWithSizeLabel = true;
let valuePrecision = 0;

if (isNumeric(total)) {
calculatedSize = sizeGetter(Number(total), 0);
valueWithSizeLabel = withValueLabel;
valuePrecision = 1;
}

const formattedValue = formatter({
value,
withSizeLabel: valueWithSizeLabel,
size: size || calculatedSize,
precision: valuePrecision,
delimiter,
});
const formattedTotal = formatter({
value: total,
size: size || calculatedSize,
delimiter,
});

return [formattedValue, formattedTotal];
}
75 changes: 33 additions & 42 deletions src/utils/dataFormatters/dataFormatters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ import {DAY_IN_SECONDS, HOUR_IN_SECONDS} from '../constants';
import {configuredNumeral} from '../numeral';
import {isNumeric} from '../utils';

import {formatValues} from './common';
import {formatNumberWithDigits, getNumberWithSignificantDigits} from './formatNumber';
import type {Digits} from './formatNumber';
import i18n from './i18n';

// Here you can't control displayed size and precision
Expand Down Expand Up @@ -52,47 +55,41 @@ export const formatMsToUptime = (ms?: number) => {
return ms && formatUptime(ms / 1000);
};

export const formatStorageValues = (
export function formatStorageValues(
value?: number,
total?: number,
size?: BytesSizes,
delimiter?: string,
) => {
let calculatedSize = getSizeWithSignificantDigits(Number(value), 0);
let valueWithSizeLabel = true;
let valuePrecision = 0;

if (isNumeric(total)) {
calculatedSize = getSizeWithSignificantDigits(Number(total), 0);
valueWithSizeLabel = false;
valuePrecision = 1;
}

let formattedValue = formatBytesCustom({
withValueLabel?: boolean,
) {
return formatValues<BytesSizes>(
formatBytesCustom,
getSizeWithSignificantDigits,
value,
withSizeLabel: valueWithSizeLabel,
size: size || calculatedSize,
precision: valuePrecision,
});
if (value && value > 0) {
while (formattedValue === '0') {
valuePrecision += 1;
formattedValue = formatBytesCustom({
value,
withSizeLabel: valueWithSizeLabel,
size: size || calculatedSize,
precision: valuePrecision,
});
}
}
const formattedTotal = formatBytesCustom({
value: total,
size: size || calculatedSize,
total,
size,
delimiter,
});
withValueLabel,
);
}

return [formattedValue, formattedTotal];
};
export function formatNumericValues(
value?: number,
total?: number,
size?: Digits,
delimiter?: string,
withValueLabel?: boolean,
) {
return formatValues<Digits>(
formatNumberWithDigits,
getNumberWithSignificantDigits,
value,
total,
size,
delimiter,
withValueLabel,
);
}

export const formatStorageValuesToGb = (value?: number, total?: number) => {
return formatStorageValues(value, total, 'gb');
Expand All @@ -110,19 +107,13 @@ export const formatNumber = (number?: unknown) => {
// "," in format is delimiter sign, not delimiter itself
return configuredNumeral(number).format('0,0.[00000]');
};
export const formatNumberCustom = (number?: number) => {
return configuredNumeral(number).format('0.[0]a');
};

export const formatPercent = (number?: unknown) => {
if (!isNumeric(number)) {
return '';
}
const configuredNumber = configuredNumeral(number);
const numberValue = configuredNumber.value();
let format = '0.[0]%';
if (numberValue && numberValue < 0.001) {
format = '0.[00]%';
}
const format = '0%';
return configuredNumber.format(format);
};

Expand Down
Loading
Loading