Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: correctly format usage data #2148

Closed
wants to merge 5 commits into from
Closed
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
42 changes: 21 additions & 21 deletions server_manager/www/data_formatting.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,18 @@ describe('formatBytesParts', () => {
expect(korean.unit).toEqual('B');
expect(korean.value).toEqual('2');

const russian = formatting.formatBytesParts(3000, 'ru');
const russian = formatting.formatBytesParts(3 * 1024, 'ru');
expect(russian.unit).toEqual('кБ');
expect(russian.value).toEqual('3');

const simplifiedChinese = formatting.formatBytesParts(
1.5 * 10 ** 9,
'zh-CN'
1.5 * 1024 ** 3,
'zh-CN',
);
expect(simplifiedChinese.unit).toEqual('GB');
expect(simplifiedChinese.value).toEqual('1.5');

const farsi = formatting.formatBytesParts(133.5 * 10 ** 6, 'fa');
const farsi = formatting.formatBytesParts(133.5 * 1024 ** 2, 'fa');
expect(farsi.unit).toEqual('MB');
expect(farsi.value).toEqual('۱۳۳٫۵');
});
Expand All @@ -57,32 +57,32 @@ describe('formatBytes', () => {
} else {
it('Formats data amounts', () => {
expect(formatting.formatBytes(2.1, 'zh-TW')).toEqual('2 byte');
expect(formatting.formatBytes(7.8 * 10 ** 3, 'ar')).toEqual('8 كيلوبايت');
expect(formatting.formatBytes(1.5 * 10 ** 6, 'tr')).toEqual('1,5 MB');
expect(formatting.formatBytes(10 * 10 ** 9, 'jp')).toEqual('10 GB');
expect(formatting.formatBytes(2.35 * 10 ** 12, 'pr')).toEqual('2.35 TB');
expect(formatting.formatBytes(7.8 * 1024, 'ar')).toEqual('8 كيلوبايت');
expect(formatting.formatBytes(1.5 * 1024 ** 2, 'tr')).toEqual('1,5 MB');
expect(formatting.formatBytes(10 * 1024 ** 3, 'jp')).toEqual('10 GB');
expect(formatting.formatBytes(2.35 * 1024 ** 4, 'pr')).toEqual('2.35 TB');
});

it('Omits trailing zero decimal digits', () => {
expect(formatting.formatBytes(10 ** 12, 'en')).toEqual('1 TB');
expect(formatting.formatBytes(1024 ** 4, 'en')).toEqual('1 TB');
});
}
});

function makeDisplayDataAmount(value: number, unit: 'MB' | 'GB') {
return {unit, value};
return { unit, value };
}

describe('displayDataAmountToBytes', () => {
it('correctly converts DisplayDataAmounts to byte values', () => {
expect(
formatting.displayDataAmountToBytes(makeDisplayDataAmount(1, 'MB'))
).toEqual(10 ** 6);
formatting.displayDataAmountToBytes(makeDisplayDataAmount(1, 'MB')),
).toEqual(1024 ** 2);
expect(
formatting.displayDataAmountToBytes(makeDisplayDataAmount(20, 'GB'))
).toEqual(2 * 10 ** 10);
formatting.displayDataAmountToBytes(makeDisplayDataAmount(20, 'GB')),
).toEqual(20 * 1024 ** 3);
expect(
formatting.displayDataAmountToBytes(makeDisplayDataAmount(0, 'MB'))
formatting.displayDataAmountToBytes(makeDisplayDataAmount(0, 'MB')),
).toEqual(0);
});
it('handles null input', () => {
Expand All @@ -92,14 +92,14 @@ describe('displayDataAmountToBytes', () => {

describe('bytesToDisplayDataAmount', () => {
it('correctly converts byte values to DisplayDataAmounts', () => {
expect(formatting.bytesToDisplayDataAmount(10 ** 6)).toEqual(
makeDisplayDataAmount(1, 'MB')
expect(formatting.bytesToDisplayDataAmount(1024 ** 2)).toEqual(
makeDisplayDataAmount(1, 'MB'),
);
expect(formatting.bytesToDisplayDataAmount(3 * 10 ** 9)).toEqual(
makeDisplayDataAmount(3, 'GB')
expect(formatting.bytesToDisplayDataAmount(3 * 1024 ** 3)).toEqual(
makeDisplayDataAmount(3, 'GB'),
);
expect(formatting.bytesToDisplayDataAmount(7 * 10 ** 5)).toEqual(
makeDisplayDataAmount(0, 'MB')
expect(formatting.bytesToDisplayDataAmount(7 * 1024)).toEqual(
makeDisplayDataAmount(0, 'MB'),
);
});
it('handles null and undefined input', () => {
Expand Down
40 changes: 20 additions & 20 deletions server_manager/www/data_formatting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@

// Utility functions for internationalizing numbers and units

const TERABYTE = 10 ** 12;
const GIGABYTE = 10 ** 9;
const MEGABYTE = 10 ** 6;
const KILOBYTE = 10 ** 3;
const KILOBYTE = 1024;
const MEGABYTE = KILOBYTE ** 2;
const GIGABYTE = KILOBYTE ** 3;
const TERABYTE = KILOBYTE ** 4;

const inWebApp =
typeof window !== 'undefined' && typeof window.document !== 'undefined';
Expand All @@ -31,15 +31,15 @@ interface FormatParams {

function getDataFormattingParams(numBytes: number): FormatParams {
if (numBytes >= TERABYTE) {
return {value: numBytes / TERABYTE, unit: 'terabyte', decimalPlaces: 2};
return { value: numBytes / TERABYTE, unit: 'terabyte', decimalPlaces: 2 };
} else if (numBytes >= GIGABYTE) {
return {value: numBytes / GIGABYTE, unit: 'gigabyte', decimalPlaces: 2};
return { value: numBytes / GIGABYTE, unit: 'gigabyte', decimalPlaces: 2 };
} else if (numBytes >= MEGABYTE) {
return {value: numBytes / MEGABYTE, unit: 'megabyte', decimalPlaces: 1};
return { value: numBytes / MEGABYTE, unit: 'megabyte', decimalPlaces: 1 };
} else if (numBytes >= KILOBYTE) {
return {value: numBytes / KILOBYTE, unit: 'kilobyte', decimalPlaces: 0};
return { value: numBytes / KILOBYTE, unit: 'kilobyte', decimalPlaces: 0 };
}
return {value: numBytes, unit: 'byte', decimalPlaces: 0};
return { value: numBytes, unit: 'byte', decimalPlaces: 0 };
}

function makeDataAmountFormatter(language: string, params: FormatParams) {
Expand Down Expand Up @@ -68,20 +68,20 @@ interface DataAmountParts {
*/
export function formatBytesParts(
numBytes: number,
language: string
language: string,
): DataAmountParts {
if (!inWebApp) {
throw new Error(
"formatBytesParts only works in web app code. Node usage isn't supported."
"formatBytesParts only works in web app code. Node usage isn't supported.",
);
}
const params = getDataFormattingParams(numBytes);
const parts = makeDataAmountFormatter(language, params).formatToParts(
params.value
params.value,
);
// Cast away the type since `tsc` mistakenly omits the possibility for a 'unit' part
const isUnit = (part: Intl.NumberFormatPart) =>
(part as {type: string}).type === 'unit';
(part as { type: string }).type === 'unit';
const unitText = parts.find(isUnit).value;
return {
value: parts
Expand All @@ -106,7 +106,7 @@ export function formatBytesParts(
export function formatBytes(numBytes: number, language: string): string {
if (!inWebApp) {
throw new Error(
"formatBytes only works in web app code. Node usage isn't supported."
"formatBytes only works in web app code. Node usage isn't supported.",
);
}
const params = getDataFormattingParams(numBytes);
Expand All @@ -125,15 +125,15 @@ export interface DisplayDataAmount {
* @returns The number of bytes represented by dataAmount
*/
export function displayDataAmountToBytes(
dataAmount: DisplayDataAmount
dataAmount: DisplayDataAmount,
): number {
if (!dataAmount) {
return null;
}
if (dataAmount.unit === 'GB') {
return dataAmount.value * 10 ** 9;
return dataAmount.value * GIGABYTE;
} else if (dataAmount.unit === 'MB') {
return dataAmount.value * 10 ** 6;
return dataAmount.value * MEGABYTE;
}
}

Expand All @@ -145,8 +145,8 @@ export function bytesToDisplayDataAmount(bytes: number): DisplayDataAmount {
if (bytes === null || bytes === undefined) {
return null;
}
if (bytes >= 10 ** 9) {
return {value: Math.floor(bytes / 10 ** 9), unit: 'GB'};
if (bytes >= GIGABYTE) {
return { value: Math.floor(bytes / GIGABYTE), unit: 'GB' };
}
return {value: Math.floor(bytes / 10 ** 6), unit: 'MB'};
return { value: Math.floor(bytes / MEGABYTE), unit: 'MB' };
}