1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-08-05 05:45:22 +02:00

fix(app/edge-configs): high numbers UI overlap (#931)

This commit is contained in:
LP B 2025-07-24 16:37:07 +02:00 committed by GitHub
parent 1afae99345
commit e7d97d7a2b
2 changed files with 120 additions and 0 deletions

View file

@ -0,0 +1,75 @@
/* eslint-disable @typescript-eslint/no-loss-of-precision */
import { abbreviateNumber } from './numbers';
describe('abbreviateNumber', () => {
test('errors', () => {
expect(() => abbreviateNumber(Number.NaN)).toThrowError();
expect(() => abbreviateNumber(1, -1)).toThrowError();
expect(() => abbreviateNumber(1, 21)).toThrowError();
});
test('zero', () => {
expect(abbreviateNumber(0)).toBe('0');
expect(abbreviateNumber(-0)).toBe('0');
});
test('decimals=0', () => {
const cases: [number, string][] = [
[123, '123'],
[123_123, '123k'],
[123_123_123, '123M'],
[123_123_123_123, '123G'],
[123_123_123_123_123, '123T'],
[123_123_123_123_123_123, '123P'],
[123_123_123_123_123_123_123, '123E'],
[123_123_123_123_123_123_123_123, '123Z'],
[123_123_123_123_123_123_123_123_123, '123Y'],
[123_123_123_123_123_123_123_123_123_123, '123123Y'],
];
cases.forEach(([num, str]) => {
expect(abbreviateNumber(num, 0)).toBe(str);
expect(abbreviateNumber(-num, 0)).toBe(`-${str}`);
});
});
test('decimals=1 (default)', () => {
const cases: [number, string][] = [
[123, '123'],
[123_123, '123.1k'],
[123_123_123, '123.1M'],
[123_123_123_123, '123.1G'],
[123_123_123_123_123, '123.1T'],
[123_123_123_123_123_123, '123.1P'],
[123_123_123_123_123_123_123, '123.1E'],
[123_123_123_123_123_123_123_123, '123.1Z'],
[123_123_123_123_123_123_123_123_123, '123.1Y'],
[123_123_123_123_123_123_123_123_123_123, '123123.1Y'],
];
cases.forEach(([num, str]) => {
expect(abbreviateNumber(num)).toBe(str);
expect(abbreviateNumber(-num)).toBe(`-${str}`);
});
});
test('decimals=10', () => {
const cases: [number, string][] = [
[123, '123'],
[123_123, '123.123k'],
[123_123_123, '123.123123M'],
[123_123_123_123, '123.123123123G'],
[123_123_123_123_123, '123.1231231231T'],
[123_123_123_123_123_123, '123.1231231231P'],
[123_123_123_123_123_123_123, '123.1231231231E'],
[123_123_123_123_123_123_123_123, '123.1231231231Z'],
[123_123_123_123_123_123_123_123_123, '123.1231231231Y'],
[123_123_123_123_123_123_123_123_123_123, '123123.1231231231Y'],
];
cases.forEach(([num, str]) => {
expect(abbreviateNumber(num, 10)).toBe(str);
expect(abbreviateNumber(-num, 10)).toBe(`-${str}`);
});
});
});
/* eslint-enable @typescript-eslint/no-loss-of-precision */

View file

@ -0,0 +1,45 @@
const suffixes = ['', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'];
/**
* Converts a number to a human-readable abbreviated format
* Uses base 10 and standard SI prefixes
*
* @param num - The number to abbreviate
* @param decimals - Number of decimal places (default: 1)
* @returns Abbreviated number as string (e.g., "90k", "123M")
*/
export function abbreviateNumber(num: number, decimals: number = 1): string {
if (Number.isNaN(num)) {
throw new Error('Invalid number');
}
if (decimals < 0 || decimals > 20) {
throw new Error('Invalid decimals. Must be in [0;20] range');
}
const isNegative = num < 0;
const absNum = Math.abs(num);
if (absNum === 0) {
return '0';
}
let exponent = Math.floor(Math.log10(absNum) / 3);
if (exponent > suffixes.length - 1) {
exponent = suffixes.length - 1;
}
if (exponent < 0) {
exponent = 0;
}
const value = absNum / 1000 ** exponent;
const roundedValue =
exponent > 0 ? Number(value.toFixed(decimals)) : Math.floor(value);
const finalValue = isNegative ? -roundedValue : roundedValue;
return `${finalValue}${suffixes[exponent]}`;
}