2019-09-04 21:01:54 +05:30
|
|
|
import { sprintf, __ } from '~/locale';
|
2023-05-27 22:25:52 +05:30
|
|
|
import {
|
|
|
|
BYTES_IN_KIB,
|
|
|
|
THOUSAND,
|
|
|
|
BYTES_FORMAT_BYTES,
|
|
|
|
BYTES_FORMAT_KIB,
|
|
|
|
BYTES_FORMAT_MIB,
|
|
|
|
BYTES_FORMAT_GIB,
|
|
|
|
} from './constants';
|
2017-08-17 22:00:37 +05:30
|
|
|
|
|
|
|
/**
|
|
|
|
* Function that allows a number with an X amount of decimals
|
|
|
|
* to be formatted in the following fashion:
|
|
|
|
* * For 1 digit to the left of the decimal point and X digits to the right of it
|
|
|
|
* * * Show 3 digits to the right
|
|
|
|
* * For 2 digits to the left of the decimal point and X digits to the right of it
|
|
|
|
* * * Show 2 digits to the right
|
2018-12-13 13:39:08 +05:30
|
|
|
*/
|
2017-08-17 22:00:37 +05:30
|
|
|
export function formatRelevantDigits(number) {
|
|
|
|
let digitsLeft = '';
|
|
|
|
let relevantDigits = 0;
|
|
|
|
let formattedNumber = '';
|
2018-11-08 19:23:39 +05:30
|
|
|
if (!Number.isNaN(Number(number))) {
|
|
|
|
[digitsLeft] = number.toString().split('.');
|
2017-08-17 22:00:37 +05:30
|
|
|
switch (digitsLeft.length) {
|
|
|
|
case 1:
|
|
|
|
relevantDigits = 3;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
relevantDigits = 2;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
relevantDigits = 1;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
relevantDigits = 4;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
formattedNumber = Number(number).toFixed(relevantDigits);
|
|
|
|
}
|
|
|
|
return formattedNumber;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Utility function that calculates KiB of the given bytes.
|
|
|
|
*
|
|
|
|
* @param {Number} number bytes
|
|
|
|
* @return {Number} KiB
|
|
|
|
*/
|
|
|
|
export function bytesToKiB(number) {
|
|
|
|
return number / BYTES_IN_KIB;
|
|
|
|
}
|
2017-09-10 17:25:29 +05:30
|
|
|
|
|
|
|
/**
|
|
|
|
* Utility function that calculates MiB of the given bytes.
|
|
|
|
*
|
|
|
|
* @param {Number} number bytes
|
|
|
|
* @return {Number} MiB
|
|
|
|
*/
|
|
|
|
export function bytesToMiB(number) {
|
|
|
|
return number / (BYTES_IN_KIB * BYTES_IN_KIB);
|
|
|
|
}
|
2018-03-17 18:26:18 +05:30
|
|
|
|
|
|
|
/**
|
|
|
|
* Utility function that calculates GiB of the given bytes.
|
|
|
|
* @param {Number} number
|
|
|
|
* @returns {Number}
|
|
|
|
*/
|
|
|
|
export function bytesToGiB(number) {
|
|
|
|
return number / (BYTES_IN_KIB * BYTES_IN_KIB * BYTES_IN_KIB);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Formats the bytes in number into a more understandable
|
2023-05-27 22:25:52 +05:30
|
|
|
* representation. Returns an array with the first value being the human size
|
|
|
|
* and the second value being the format (e.g., [1.5, 'KiB']).
|
2018-03-17 18:26:18 +05:30
|
|
|
*
|
|
|
|
* @param {Number} size
|
2021-11-11 11:23:49 +05:30
|
|
|
* @param {Number} digits - The number of digits to appear after the decimal point
|
2018-03-17 18:26:18 +05:30
|
|
|
* @returns {String}
|
|
|
|
*/
|
2023-05-27 22:25:52 +05:30
|
|
|
export function numberToHumanSizeSplit(size, digits = 2) {
|
2021-09-04 01:27:46 +05:30
|
|
|
const abs = Math.abs(size);
|
|
|
|
|
|
|
|
if (abs < BYTES_IN_KIB) {
|
2023-05-27 22:25:52 +05:30
|
|
|
return [size.toString(), BYTES_FORMAT_BYTES];
|
2021-09-04 01:27:46 +05:30
|
|
|
} else if (abs < BYTES_IN_KIB ** 2) {
|
2023-05-27 22:25:52 +05:30
|
|
|
return [bytesToKiB(size).toFixed(digits), BYTES_FORMAT_KIB];
|
2021-09-04 01:27:46 +05:30
|
|
|
} else if (abs < BYTES_IN_KIB ** 3) {
|
2023-05-27 22:25:52 +05:30
|
|
|
return [bytesToMiB(size).toFixed(digits), BYTES_FORMAT_MIB];
|
|
|
|
}
|
|
|
|
return [bytesToGiB(size).toFixed(digits), BYTES_FORMAT_GIB];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Port of rails number_to_human_size
|
|
|
|
* Formats the bytes in number into a more understandable
|
|
|
|
* representation (e.g., giving it 1500 yields 1.5 KB).
|
|
|
|
*
|
|
|
|
* @param {Number} size
|
|
|
|
* @param {Number} digits - The number of digits to appear after the decimal point
|
|
|
|
* @returns {String}
|
|
|
|
*/
|
|
|
|
export function numberToHumanSize(size, digits = 2) {
|
|
|
|
const [humanSize, format] = numberToHumanSizeSplit(size, digits);
|
|
|
|
|
|
|
|
switch (format) {
|
|
|
|
case BYTES_FORMAT_BYTES:
|
|
|
|
return sprintf(__('%{size} bytes'), { size: humanSize });
|
|
|
|
case BYTES_FORMAT_KIB:
|
|
|
|
return sprintf(__('%{size} KiB'), { size: humanSize });
|
|
|
|
case BYTES_FORMAT_MIB:
|
|
|
|
return sprintf(__('%{size} MiB'), { size: humanSize });
|
|
|
|
case BYTES_FORMAT_GIB:
|
|
|
|
return sprintf(__('%{size} GiB'), { size: humanSize });
|
|
|
|
default:
|
|
|
|
return '';
|
2018-03-17 18:26:18 +05:30
|
|
|
}
|
|
|
|
}
|
2019-07-07 11:18:12 +05:30
|
|
|
|
2022-04-04 11:22:00 +05:30
|
|
|
/**
|
|
|
|
* Converts a number to kilos or megas.
|
|
|
|
*
|
|
|
|
* For example:
|
|
|
|
* - 123 becomes 123
|
|
|
|
* - 123456 becomes 123.4k
|
|
|
|
* - 123456789 becomes 123.4m
|
|
|
|
*
|
|
|
|
* @param number Number to format
|
|
|
|
* @param digits The number of digits to appear after the decimal point
|
|
|
|
* @return {string} Formatted number
|
|
|
|
*/
|
|
|
|
export function numberToMetricPrefix(number, digits = 1) {
|
|
|
|
if (number < THOUSAND) {
|
|
|
|
return number.toString();
|
|
|
|
}
|
|
|
|
if (number < THOUSAND ** 2) {
|
|
|
|
return `${(number / THOUSAND).toFixed(digits)}k`;
|
|
|
|
}
|
|
|
|
return `${(number / THOUSAND ** 2).toFixed(digits)}m`;
|
|
|
|
}
|
2019-07-07 11:18:12 +05:30
|
|
|
/**
|
|
|
|
* A simple method that returns the value of a + b
|
|
|
|
* It seems unessesary, but when combined with a reducer it
|
|
|
|
* adds up all the values in an array.
|
|
|
|
*
|
|
|
|
* e.g. `[1, 2, 3, 4, 5].reduce(sum) // => 15`
|
|
|
|
*
|
|
|
|
* @param {Float} a
|
|
|
|
* @param {Float} b
|
|
|
|
* @example
|
|
|
|
* // return 15
|
|
|
|
* [1, 2, 3, 4, 5].reduce(sum);
|
|
|
|
*
|
|
|
|
* // returns 6
|
|
|
|
* Object.values([{a: 1, b: 2, c: 3].reduce(sum);
|
|
|
|
* @returns {Float} The summed value
|
|
|
|
*/
|
|
|
|
export const sum = (a = 0, b = 0) => a + b;
|
2019-09-04 21:01:54 +05:30
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks if the provided number is odd
|
|
|
|
* @param {Int} number
|
|
|
|
*/
|
|
|
|
export const isOdd = (number = 0) => number % 2;
|
2019-12-21 20:55:43 +05:30
|
|
|
|
|
|
|
/**
|
|
|
|
* Computes the median for a given array.
|
|
|
|
* @param {Array} arr An array of numbers
|
|
|
|
* @returns {Number} The median of the given array
|
|
|
|
*/
|
2021-03-08 18:12:59 +05:30
|
|
|
export const median = (arr) => {
|
2019-12-21 20:55:43 +05:30
|
|
|
const middle = Math.floor(arr.length / 2);
|
|
|
|
const sorted = arr.sort((a, b) => a - b);
|
|
|
|
return arr.length % 2 !== 0 ? sorted[middle] : (sorted[middle - 1] + sorted[middle]) / 2;
|
|
|
|
};
|
2019-12-26 22:10:19 +05:30
|
|
|
|
|
|
|
/**
|
|
|
|
* Computes the change from one value to the other as a percentage.
|
|
|
|
* @param {Number} firstY
|
|
|
|
* @param {Number} lastY
|
|
|
|
* @returns {Number}
|
|
|
|
*/
|
|
|
|
export const changeInPercent = (firstY, lastY) => {
|
|
|
|
if (firstY === lastY) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return Math.round(((lastY - firstY) / Math.abs(firstY)) * 100);
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Computes and formats the change from one value to the other as a percentage.
|
|
|
|
* Prepends the computed percentage with either "+" or "-" to indicate an in- or decrease and
|
|
|
|
* returns a given string if the result is not finite (for example, if the first value is "0").
|
|
|
|
* @param firstY
|
|
|
|
* @param lastY
|
|
|
|
* @param nonFiniteResult
|
|
|
|
* @returns {String}
|
|
|
|
*/
|
|
|
|
export const formattedChangeInPercent = (firstY, lastY, { nonFiniteResult = '-' } = {}) => {
|
|
|
|
const change = changeInPercent(firstY, lastY);
|
|
|
|
|
|
|
|
if (!Number.isFinite(change)) {
|
|
|
|
return nonFiniteResult;
|
|
|
|
}
|
|
|
|
|
|
|
|
return `${change >= 0 ? '+' : ''}${change}%`;
|
|
|
|
};
|
2021-04-17 20:07:23 +05:30
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks whether a value is numerical in nature by converting it using parseInt
|
|
|
|
*
|
|
|
|
* Example outcomes:
|
|
|
|
* - isNumeric(100) = true
|
|
|
|
* - isNumeric('100') = true
|
|
|
|
* - isNumeric(1.0) = true
|
|
|
|
* - isNumeric('1.0') = true
|
|
|
|
* - isNumeric('abc100') = false
|
|
|
|
* - isNumeric('abc') = false
|
|
|
|
* - isNumeric(true) = false
|
|
|
|
* - isNumeric(undefined) = false
|
|
|
|
* - isNumeric(null) = false
|
|
|
|
*
|
|
|
|
* @param value
|
|
|
|
* @returns {boolean}
|
|
|
|
*/
|
|
|
|
export const isNumeric = (value) => {
|
|
|
|
return !Number.isNaN(parseInt(value, 10));
|
|
|
|
};
|
2021-06-08 01:23:25 +05:30
|
|
|
|
|
|
|
const numberRegex = /^[0-9]+$/;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks whether the value is a positive number or 0, or a string with equivalent value
|
|
|
|
*
|
|
|
|
* @param value
|
|
|
|
* @return {boolean}
|
|
|
|
*/
|
|
|
|
export const isPositiveInteger = (value) => numberRegex.test(value);
|