From 603b1d14c721dc05c4da130e4b91628072c710a3 Mon Sep 17 00:00:00 2001 From: Paul Rosenzweig <paulrosenzweig@users.noreply.github.com> Date: Fri, 14 Jun 2019 17:29:32 -0400 Subject: [PATCH] Format compact currency and scientific style values (#10059) --- frontend/src/metabase/lib/formatting.js | 27 +++++++++++++++++ .../test/metabase/lib/formatting.unit.spec.js | 30 ++++++++++++++++++- 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/frontend/src/metabase/lib/formatting.js b/frontend/src/metabase/lib/formatting.js index f5e60478e20..17cc1280e4d 100644 --- a/frontend/src/metabase/lib/formatting.js +++ b/frontend/src/metabase/lib/formatting.js @@ -252,6 +252,33 @@ function formatNumberCompact(value: number, options: FormattingOptions) { if (options.number_style === "percent") { return formatNumberCompactWithoutOptions(value * 100) + "%"; } + if (options.number_style === "currency") { + try { + const { value: currency } = numberFormatterForOptions({ + ...options, + currency_style: "symbol", + }) + .formatToParts(value) + .find(p => p.type === "currency"); + + // this special case ensures the "~" comes before the currency + if (value !== 0 && value >= -0.01 && value <= 0.01) { + return `~${currency}0`; + } + return currency + formatNumberCompactWithoutOptions(value); + } catch (e) { + // Intl.NumberFormat failed, so we fall back to a non-currency number + return formatNumberCompactWithoutOptions(value); + } + } + if (options.number_style === "scientific") { + return formatNumberScientific(value, { + ...options, + // unsetting maximumFractionDigits prevents truncation of small numbers + maximumFractionDigits: undefined, + minimumFractionDigits: 1, + }); + } return formatNumberCompactWithoutOptions(value); } diff --git a/frontend/test/metabase/lib/formatting.unit.spec.js b/frontend/test/metabase/lib/formatting.unit.spec.js index 8c614ffeffe..630b6eeb7d2 100644 --- a/frontend/test/metabase/lib/formatting.unit.spec.js +++ b/frontend/test/metabase/lib/formatting.unit.spec.js @@ -45,7 +45,7 @@ describe("formatting", () => { expect(formatNumber(1000, { compact: true })).toEqual("1.0k"); expect(formatNumber(1111, { compact: true })).toEqual("1.1k"); }); - it("should format compact percentages", () => { + it("should format percentages", () => { const options = { compact: true, number_style: "percent" }; expect(formatNumber(0, options)).toEqual("0%"); expect(formatNumber(0.001, options)).toEqual("0.1%"); @@ -58,6 +58,34 @@ describe("formatting", () => { expect(formatNumber(11.11, options)).toEqual("1.1k%"); expect(formatNumber(-0.22, options)).toEqual("-22%"); }); + it("should format scientific notation", () => { + const options = { compact: true, number_style: "scientific" }; + expect(formatNumber(0, options)).toEqual("0.0e+0"); + expect(formatNumber(0.0001, options)).toEqual("1.0e-4"); + expect(formatNumber(0.01, options)).toEqual("1.0e-2"); + expect(formatNumber(0.5, options)).toEqual("5.0e-1"); + expect(formatNumber(123456.78, options)).toEqual("1.2e+5"); + expect(formatNumber(-123456.78, options)).toEqual("-1.2e+5"); + }); + it("should format currency values", () => { + const options = { + compact: true, + number_style: "currency", + currency: "USD", + }; + expect(formatNumber(0, options)).toEqual("$0"); + expect(formatNumber(0.001, options)).toEqual("~$0"); + expect(formatNumber(7.24, options)).toEqual("$7"); + expect(formatNumber(1234.56, options)).toEqual("$1.2k"); + expect(formatNumber(1234567.89, options)).toEqual("$1.2M"); + expect(formatNumber(-1234567.89, options)).toEqual("$-1.2M"); + expect( + formatNumber(1234567.89, { ...options, currency: "CNY" }), + ).toEqual("CNÂ¥1.2M"); + expect( + formatNumber(1234567.89, { ...options, currency_style: "name" }), + ).toEqual("$1.2M"); + }); }); it("should format to correct number of decimal places", () => { expect(formatNumber(0.1)).toEqual("0.1"); -- GitLab