Switch from numeral to numbro (#6344)

numeraljs is no longer maintained, and incorrectly parses high-precision
floats (such as 1.2e-7) as NaN.
This commit is contained in:
Eric Radman
2023-08-15 07:59:18 -04:00
committed by GitHub
parent d333660473
commit f8934b8312
15 changed files with 48 additions and 42 deletions

View File

@@ -62,7 +62,7 @@
"material-design-iconic-font": "^2.2.0", "material-design-iconic-font": "^2.2.0",
"mousetrap": "^1.6.1", "mousetrap": "^1.6.1",
"mustache": "^2.3.0", "mustache": "^2.3.0",
"numeral": "^2.0.6", "numbro": "^2.3.6",
"path-to-regexp": "^3.1.0", "path-to-regexp": "^3.1.0",
"prop-types": "^15.6.1", "prop-types": "^15.6.1",
"query-string": "^6.9.0", "query-string": "^6.9.0",

View File

@@ -45,7 +45,6 @@
"@types/enzyme": "^3.10.8", "@types/enzyme": "^3.10.8",
"@types/jest": "^26.0.18", "@types/jest": "^26.0.18",
"@types/leaflet": "^1.5.19", "@types/leaflet": "^1.5.19",
"@types/numeral": "0.0.28",
"@types/plotly.js": "^1.54.22", "@types/plotly.js": "^1.54.22",
"@types/react": "^17.0.0", "@types/react": "^17.0.0",
"@types/react-dom": "^17.0.0", "@types/react-dom": "^17.0.0",
@@ -90,7 +89,7 @@
"leaflet-fullscreen": "^1.0.2", "leaflet-fullscreen": "^1.0.2",
"leaflet.markercluster": "^1.1.0", "leaflet.markercluster": "^1.1.0",
"lodash": "^4.17.10", "lodash": "^4.17.10",
"numeral": "^2.0.6", "numbro": "^2.3.6",
"plotly.js": "1.58.5", "plotly.js": "1.58.5",
"react-pivottable": "^0.9.0", "react-pivottable": "^0.9.0",
"react-sortable-hoc": "^1.10.1", "react-sortable-hoc": "^1.10.1",

View File

@@ -1,12 +1,10 @@
import React from "react"; import React from "react";
import ReactDOMServer from "react-dom/server"; import ReactDOMServer from "react-dom/server";
import moment from "moment/moment"; import moment from "moment/moment";
import numeral from "numeral"; import numbro from "numbro";
import { isString, isArray, isUndefined, isFinite, isNil, toString } from "lodash"; import { isString, isArray, isUndefined, isFinite, isNil, toString } from "lodash";
import { visualizationsSettings } from "@/visualizations/visualizationsSettings"; import { visualizationsSettings } from "@/visualizations/visualizationsSettings";
numeral.options.scalePercentBy100 = false;
// eslint-disable-next-line // eslint-disable-next-line
const urlPattern = /(^|[\s\n]|<br\/?>)((?:https?|ftp):\/\/[\-A-Z0-9+\u0026\u2019@#\/%?=()~_|!:,.;]*[\-A-Z0-9+\u0026@#\/%=~()_|])/gi; const urlPattern = /(^|[\s\n]|<br\/?>)((?:https?|ftp):\/\/[\-A-Z0-9+\u0026\u2019@#\/%?=()~_|!:,.;]*[\-A-Z0-9+\u0026@#\/%=~()_|])/gi;
@@ -78,7 +76,7 @@ export function createBooleanFormatter(values: any) {
export function createNumberFormatter(format: any) { export function createNumberFormatter(format: any) {
if (isString(format) && format !== "") { if (isString(format) && format !== "") {
const n = numeral(0); // cache `numeral` instance const n = numbro(0); // cache `numbro` instance
return (value: any) => (value === null || value === "" ? "" : n.set(value).format(format)); return (value: any) => (value === null || value === "" ? "" : n.set(value).format(format));
} }
return (value: any) => toString(value); return (value: any) => toString(value);

View File

@@ -52,7 +52,7 @@
"type": "bar", "type": "bar",
"name": "a", "name": "a",
"x": ["x1", "x2", "x3", "x4"], "x": ["x1", "x2", "x3", "x4"],
"y": [20, 40, 60, 80], "y": [0.2, 0.4, 0.6, 0.8],
"error_y": { "array": [0, 0, 0, 0], "color": "red" }, "error_y": { "array": [0, 0, 0, 0], "color": "red" },
"hoverinfo": "text+x+name", "hoverinfo": "text+x+name",
"hover": [], "hover": [],
@@ -68,7 +68,7 @@
"type": "bar", "type": "bar",
"name": "b", "name": "b",
"x": ["x1", "x2", "x3", "x4"], "x": ["x1", "x2", "x3", "x4"],
"y": [80, 60, 40, 20], "y": [0.8, 0.6, 0.4, 0.2],
"error_y": { "array": [0, 0, 0, 0], "color": "blue" }, "error_y": { "array": [0, 0, 0, 0], "color": "blue" },
"hoverinfo": "text+x+name", "hoverinfo": "text+x+name",
"hover": [], "hover": [],

View File

@@ -51,7 +51,7 @@
"name": "a", "name": "a",
"mode": "lines+text", "mode": "lines+text",
"x": ["x1", "x2", "x3", "x4"], "x": ["x1", "x2", "x3", "x4"],
"y": [20, 40, 60, 80], "y": [0.2, 0.4, 0.6, 0.8],
"error_y": { "array": [0, 0, 0, 0], "color": "red" }, "error_y": { "array": [0, 0, 0, 0], "color": "red" },
"hoverinfo": "text+x+name", "hoverinfo": "text+x+name",
"hover": [], "hover": [],
@@ -65,7 +65,7 @@
"name": "b", "name": "b",
"mode": "lines+text", "mode": "lines+text",
"x": ["x1", "x2", "x3", "x4"], "x": ["x1", "x2", "x3", "x4"],
"y": [100, 100, 100, 100], "y": [1, 1, 1, 1],
"error_y": { "array": [0, 0, 0, 0], "color": "blue" }, "error_y": { "array": [0, 0, 0, 0], "color": "blue" },
"hoverinfo": "text+x+name", "hoverinfo": "text+x+name",
"hover": [], "hover": [],

View File

@@ -51,7 +51,7 @@
"name": "a", "name": "a",
"mode": "lines+text", "mode": "lines+text",
"x": ["x1", "x2", "x3", "x4"], "x": ["x1", "x2", "x3", "x4"],
"y": [20, 40, 60, 80], "y": [0.2, 0.4, 0.6, 0.8],
"error_y": { "array": [0, 0, 0, 0], "color": "red" }, "error_y": { "array": [0, 0, 0, 0], "color": "red" },
"hoverinfo": "text+x+name", "hoverinfo": "text+x+name",
"hover": [], "hover": [],
@@ -65,7 +65,7 @@
"name": "b", "name": "b",
"mode": "lines+text", "mode": "lines+text",
"x": ["x1", "x2", "x3", "x4"], "x": ["x1", "x2", "x3", "x4"],
"y": [80, 60, 40, 20], "y": [0.8, 0.6, 0.4, 0.2],
"error_y": { "array": [0, 0, 0, 0], "color": "blue" }, "error_y": { "array": [0, 0, 0, 0], "color": "blue" },
"hoverinfo": "text+x+name", "hoverinfo": "text+x+name",
"hover": [], "hover": [],

View File

@@ -60,7 +60,7 @@ function prepareSeries(series: any, options: any, additionalOptions: any) {
sourceData.set(x, { sourceData.set(x, {
x, x,
y, y,
yPercent: (y / seriesTotal) * 100, yPercent: (y / seriesTotal),
row, row,
}); });
}); });

View File

@@ -119,7 +119,7 @@ function updatePercentValues(seriesList: any, options: any) {
item.yPercent = null; item.yPercent = null;
} else { } else {
const sum = sumOfCorrespondingPoints.get(item.x); const sum = sumOfCorrespondingPoints.get(item.x);
item.yPercent = (item.y / sum) * 100; item.yPercent = (item.y / sum);
} }
yValues.push(item.yPercent); yValues.push(item.yPercent);
}); });

View File

@@ -65,7 +65,7 @@ function prepareOptions(options: any) {
getColorForValue: chroma getColorForValue: chroma
.scale([options.colors.min, options.colors.max]) .scale([options.colors.min, options.colors.max])
.mode("hsl") .mode("hsl")
.domain([0, 100]) .domain([0, 1])
.classes(options.colors.steps), .classes(options.colors.steps),
}); });
} }
@@ -117,7 +117,7 @@ function CorneliusRow({ options, data, index, maxRowLength }: any) {
const cells = []; const cells = [];
for (let i = 1; i < maxRowLength; i += 1) { for (let i = 1; i < maxRowLength; i += 1) {
const value = data[i]; const value = data[i];
const percentageValue = isFinite(value / baseValue) ? (value / baseValue) * 100 : null; const percentageValue = isFinite(value / baseValue) ? (value / baseValue) : null;
const cellProps = { key: `col${i}` }; const cellProps = { key: `col${i}` };
if (isNil(percentageValue)) { if (isNil(percentageValue)) {

View File

@@ -1,12 +1,12 @@
import { isNumber, isFinite, toString } from "lodash"; import { isNumber, isFinite, toString } from "lodash";
import numeral from "numeral"; import numbro from "numbro";
// TODO: allow user to specify number format string instead of delimiters only // TODO: allow user to specify number format string instead of delimiters only
// It will allow to remove this function (move all that weird formatting logic to a migration // It will allow to remove this function (move all that weird formatting logic to a migration
// that will set number format for all existing counter visualization) // that will set number format for all existing counter visualization)
function numberFormat(value: any, decimalPoints: any, decimalDelimiter: any, thousandsDelimiter: any) { function numberFormat(value: any, decimalPoints: any, decimalDelimiter: any, thousandsDelimiter: any) {
// Temporarily update locale data (restore defaults after formatting) // Temporarily update locale data (restore defaults after formatting)
const locale = numeral.localeData(); const locale = numbro.languageData();
const savedDelimiters = locale.delimiters; const savedDelimiters = locale.delimiters;
// Mimic old behavior - AngularJS `number` filter defaults: // Mimic old behavior - AngularJS `number` filter defaults:
@@ -33,7 +33,7 @@ function numberFormat(value: any, decimalPoints: any, decimalDelimiter: any, tho
} }
} }
} }
const result = numeral(value).format(formatString); const result = numbro(value).format(formatString);
locale.delimiters = savedDelimiters; locale.delimiters = savedDelimiters;
return result; return result;
@@ -61,7 +61,7 @@ function formatValue(value: any, { stringPrefix, stringSuffix, stringDecimal, st
function formatTooltip(value: any, formatString: any) { function formatTooltip(value: any, formatString: any) {
if (isNumber(value)) { if (isNumber(value)) {
return numeral(value).format(formatString); return numbro(value).format(formatString);
} }
return toString(value); return toString(value);
} }
@@ -109,9 +109,9 @@ export function getCounterData(rows: any, options: any, visualizationName: any)
} }
// @ts-expect-error ts-migrate(2339) FIXME: Property 'counterValueTooltip' does not exist on t... Remove this comment to see the full error message // @ts-expect-error ts-migrate(2339) FIXME: Property 'counterValueTooltip' does not exist on t... Remove this comment to see the full error message
result.counterValueTooltip = formatTooltip(result.counterValue, options.tooltipFormat); result.counterValueTooltip = formatTooltip(result.counterValue, options.tooltipFormat || "0,0");
// @ts-expect-error ts-migrate(2339) FIXME: Property 'targetValueTooltip' does not exist on ty... Remove this comment to see the full error message // @ts-expect-error ts-migrate(2339) FIXME: Property 'targetValueTooltip' does not exist on ty... Remove this comment to see the full error message
result.targetValueTooltip = formatTooltip(result.targetValue, options.tooltipFormat); result.targetValueTooltip = formatTooltip(result.targetValue, options.tooltipFormat || "0,0");
// @ts-expect-error ts-migrate(2339) FIXME: Property 'counterValue' does not exist on type '{}... Remove this comment to see the full error message // @ts-expect-error ts-migrate(2339) FIXME: Property 'counterValue' does not exist on type '{}... Remove this comment to see the full error message
result.counterValue = formatValue(result.counterValue, options); result.counterValue = formatValue(result.counterValue, options);
@@ -123,7 +123,7 @@ export function getCounterData(rows: any, options: any, visualizationName: any)
// @ts-expect-error ts-migrate(2339) FIXME: Property 'targetValue' does not exist on type '{}'... Remove this comment to see the full error message // @ts-expect-error ts-migrate(2339) FIXME: Property 'targetValue' does not exist on type '{}'... Remove this comment to see the full error message
if (isFinite(result.targetValue)) { if (isFinite(result.targetValue)) {
// @ts-expect-error ts-migrate(2339) FIXME: Property 'targetValue' does not exist on type '{}'... Remove this comment to see the full error message // @ts-expect-error ts-migrate(2339) FIXME: Property 'targetValue' does not exist on type '{}'... Remove this comment to see the full error message
result.targetValue = numeral(result.targetValue).format("0[.]00[0]"); result.targetValue = numbro(result.targetValue).format("0[.]00[0]");
} }
} }
} }

View File

@@ -16,7 +16,7 @@ type Props = OwnProps & typeof FunnelBar.defaultProps;
export default function FunnelBar({ color, value, align, className, children }: Props) { export default function FunnelBar({ color, value, align, className, children }: Props) {
return ( return (
<div className={cx("funnel-bar", `funnel-bar-${align}`, className)}> <div className={cx("funnel-bar", `funnel-bar-${align}`, className)}>
<div className="funnel-bar-value" style={{ backgroundColor: color, width: value + "%" }} /> <div className="funnel-bar-value" style={{ backgroundColor: color, width: value * 100 + "%" }} />
<div className="funnel-bar-label">{children}</div> <div className="funnel-bar-label">{children}</div>
</div> </div>
); );

View File

@@ -79,7 +79,7 @@ export default function Renderer({ data, options }: any) {
align: "center", align: "center",
render: (value: any) => ( render: (value: any) => (
// @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message // @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message
<FunnelBar className="funnel-percent-column" value={(value / maxToPrevious) * 100.0}> <FunnelBar className="funnel-percent-column" value={(value / maxToPrevious)}>
{formatPercentValue(value)} {formatPercentValue(value)}
</FunnelBar> </FunnelBar>
), ),

View File

@@ -32,9 +32,9 @@ export default function prepareData(rows: any, options: any) {
const maxVal = maxBy(data, d => d.value).value; const maxVal = maxBy(data, d => d.value).value;
data.forEach((d, i) => { data.forEach((d, i) => {
// @ts-expect-error ts-migrate(2339) FIXME: Property 'pctMax' does not exist on type '{ step: ... Remove this comment to see the full error message // @ts-expect-error ts-migrate(2339) FIXME: Property 'pctMax' does not exist on type '{ step: ... Remove this comment to see the full error message
d.pctMax = (d.value / maxVal) * 100.0; d.pctMax = (d.value / maxVal);
// @ts-expect-error ts-migrate(2339) FIXME: Property 'pctPrevious' does not exist on type '{ s... Remove this comment to see the full error message // @ts-expect-error ts-migrate(2339) FIXME: Property 'pctPrevious' does not exist on type '{ s... Remove this comment to see the full error message
d.pctPrevious = i === 0 || d.value === data[i - 1].value ? 100.0 : (d.value / data[i - 1].value) * 100.0; d.pctPrevious = i === 0 || d.value === data[i - 1].value ? 1.0 : (d.value / data[i - 1].value);
}); });
return data.slice(0, options.itemsLimit); return data.slice(0, options.itemsLimit);

View File

@@ -2066,11 +2066,6 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.13.4.tgz#1581d6c16e3d4803eb079c87d4ac893ee7501c2c" resolved "https://registry.yarnpkg.com/@types/node/-/node-13.13.4.tgz#1581d6c16e3d4803eb079c87d4ac893ee7501c2c"
integrity sha512-x26ur3dSXgv5AwKS0lNfbjpCakGIduWU1DU91Zz58ONRWrIKGunmZBNv4P7N+e27sJkiGDsw/3fT4AtsqQBrBA== integrity sha512-x26ur3dSXgv5AwKS0lNfbjpCakGIduWU1DU91Zz58ONRWrIKGunmZBNv4P7N+e27sJkiGDsw/3fT4AtsqQBrBA==
"@types/numeral@0.0.28":
version "0.0.28"
resolved "https://registry.yarnpkg.com/@types/numeral/-/numeral-0.0.28.tgz#e43928f0bda10b169b6f7ecf99e3ddf836b8ebe4"
integrity sha512-Sjsy10w6XFHDktJJdXzBJmoondAKW+LcGpRFH+9+zXEDj0cOH8BxJuZA9vUDSMAzU1YRJlsPKmZEEiTYDlICLw==
"@types/plotly.js@^1.54.22": "@types/plotly.js@^1.54.22":
version "1.54.22" version "1.54.22"
resolved "https://registry.yarnpkg.com/@types/plotly.js/-/plotly.js-1.54.22.tgz#001b9cfafc5e0bdf133bc6ab6e30ff0af39e584d" resolved "https://registry.yarnpkg.com/@types/plotly.js/-/plotly.js-1.54.22.tgz#001b9cfafc5e0bdf133bc6ab6e30ff0af39e584d"
@@ -2843,6 +2838,11 @@ big.js@^5.2.2:
resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328"
integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==
bignumber.js@^8.1.1:
version "8.1.1"
resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-8.1.1.tgz#4b072ae5aea9c20f6730e4e5d529df1271c4d885"
integrity sha512-QD46ppGintwPGuL1KqmwhR0O+N2cZUg8JG/VzwI2e28sM9TqHjQB10lI4QAaMHVbLzwVLLAwEglpKPViWX+5NQ==
binary-extensions@^2.0.0: binary-extensions@^2.0.0:
version "2.2.0" version "2.2.0"
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
@@ -7580,10 +7580,12 @@ number-is-integer@^1.0.1:
dependencies: dependencies:
is-finite "^1.0.1" is-finite "^1.0.1"
numeral@^2.0.6: numbro@^2.3.6:
version "2.0.6" version "2.3.6"
resolved "https://registry.yarnpkg.com/numeral/-/numeral-2.0.6.tgz#4ad080936d443c2561aed9f2197efffe25f4e506" resolved "https://registry.yarnpkg.com/numbro/-/numbro-2.3.6.tgz#4bd622ebe59ccbc49dad365c5b9eed200781fa21"
integrity sha1-StCAk21EPCVhrtnyGX7//iX05QY= integrity sha512-pxpoTT3hVxQGaOA2RTzXR/muonQNd1K1HPJbWo7QOmxPwiPmoFCFfsG9XXgW3uqjyzezJ0P9IvCPDXUtJexjwg==
dependencies:
bignumber.js "^8.1.1"
numeric@^1.2.6: numeric@^1.2.6:
version "1.2.6" version "1.2.6"

View File

@@ -1844,7 +1844,7 @@
leaflet-fullscreen "^1.0.2" leaflet-fullscreen "^1.0.2"
leaflet.markercluster "^1.1.0" leaflet.markercluster "^1.1.0"
lodash "^4.17.10" lodash "^4.17.10"
numeral "^2.0.6" numbro "^2.3.6"
plotly.js "1.58.5" plotly.js "1.58.5"
react-pivottable "^0.9.0" react-pivottable "^0.9.0"
react-sortable-hoc "^1.10.1" react-sortable-hoc "^1.10.1"
@@ -3355,6 +3355,11 @@ big.js@^5.2.2:
resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328"
integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==
bignumber.js@^8.1.1:
version "8.1.1"
resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-8.1.1.tgz#4b072ae5aea9c20f6730e4e5d529df1271c4d885"
integrity sha512-QD46ppGintwPGuL1KqmwhR0O+N2cZUg8JG/VzwI2e28sM9TqHjQB10lI4QAaMHVbLzwVLLAwEglpKPViWX+5NQ==
binary-extensions@^1.0.0: binary-extensions@^1.0.0:
version "1.13.0" version "1.13.0"
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.0.tgz#9523e001306a32444b907423f1de2164222f6ab1" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.0.tgz#9523e001306a32444b907423f1de2164222f6ab1"
@@ -10623,10 +10628,12 @@ number-is-integer@^1.0.1:
dependencies: dependencies:
is-finite "^1.0.1" is-finite "^1.0.1"
numeral@^2.0.6: numbro@^2.3.6:
version "2.0.6" version "2.3.6"
resolved "https://registry.yarnpkg.com/numeral/-/numeral-2.0.6.tgz#4ad080936d443c2561aed9f2197efffe25f4e506" resolved "https://registry.yarnpkg.com/numbro/-/numbro-2.3.6.tgz#4bd622ebe59ccbc49dad365c5b9eed200781fa21"
integrity sha1-StCAk21EPCVhrtnyGX7//iX05QY= integrity sha512-pxpoTT3hVxQGaOA2RTzXR/muonQNd1K1HPJbWo7QOmxPwiPmoFCFfsG9XXgW3uqjyzezJ0P9IvCPDXUtJexjwg==
dependencies:
bignumber.js "^8.1.1"
numeric@^1.2.6: numeric@^1.2.6:
version "1.2.6" version "1.2.6"