diff --git a/frontend/src/metabase/visualizations/components/ScalarValue/ScalarValue.jsx b/frontend/src/metabase/visualizations/components/ScalarValue/ScalarValue.jsx index 245fd69d9cd7392649f272d5b988d32703717d7c..e3064b072d4fd7bdfbd600e28ec84482660c4364 100644 --- a/frontend/src/metabase/visualizations/components/ScalarValue/ScalarValue.jsx +++ b/frontend/src/metabase/visualizations/components/ScalarValue/ScalarValue.jsx @@ -3,6 +3,7 @@ */ /* eslint-disable react/prop-types */ import React, { useMemo } from "react"; +import { t } from "ttag"; import Icon from "metabase/components/Icon"; import Tooltip from "metabase/core/components/Tooltip"; @@ -53,7 +54,7 @@ const ScalarValue = ({ fontSize={fontSize} data-testid="scalar-value" > - {value} + {value ?? t`null`} </ScalarValueWrapper> ); }; diff --git a/frontend/src/metabase/visualizations/visualizations/Gauge.jsx b/frontend/src/metabase/visualizations/visualizations/Gauge/Gauge.jsx similarity index 99% rename from frontend/src/metabase/visualizations/visualizations/Gauge.jsx rename to frontend/src/metabase/visualizations/visualizations/Gauge/Gauge.jsx index f2fc18c3c68b2fe86b0a1acd03d2afec5b33deda..b1bab27493249be3fb0748ba21bf7e417fd6179f 100644 --- a/frontend/src/metabase/visualizations/visualizations/Gauge.jsx +++ b/frontend/src/metabase/visualizations/visualizations/Gauge/Gauge.jsx @@ -14,6 +14,7 @@ import { columnSettings } from "metabase/visualizations/lib/settings/column"; import ChartSettingGaugeSegments from "metabase/visualizations/components/settings/ChartSettingGaugeSegments"; import { isNumeric } from "metabase-lib/types/utils/isa"; import { GaugeArcPath } from "./Gauge.styled"; +import { getValue } from "./utils"; const MAX_WIDTH = 500; const PADDING_BOTTOM = 10; @@ -207,7 +208,7 @@ export default class Gauge extends Component { ]) .clamp(true); - const value = rows[0][0] || 0; + const value = getValue(rows); const column = cols[0]; const valuePosition = (value, distance) => { diff --git a/frontend/src/metabase/visualizations/visualizations/Gauge.styled.tsx b/frontend/src/metabase/visualizations/visualizations/Gauge/Gauge.styled.tsx similarity index 100% rename from frontend/src/metabase/visualizations/visualizations/Gauge.styled.tsx rename to frontend/src/metabase/visualizations/visualizations/Gauge/Gauge.styled.tsx diff --git a/frontend/src/metabase/visualizations/visualizations/Gauge/index.js b/frontend/src/metabase/visualizations/visualizations/Gauge/index.js new file mode 100644 index 0000000000000000000000000000000000000000..bbfe8eb69d5c5df216dafb258539b53eaf69d801 --- /dev/null +++ b/frontend/src/metabase/visualizations/visualizations/Gauge/index.js @@ -0,0 +1 @@ +export { default } from "./Gauge"; diff --git a/frontend/src/metabase/visualizations/visualizations/Gauge/utils.ts b/frontend/src/metabase/visualizations/visualizations/Gauge/utils.ts new file mode 100644 index 0000000000000000000000000000000000000000..1317ee308e25275c91bed56d0d0e6c4bd9f2ec5b --- /dev/null +++ b/frontend/src/metabase/visualizations/visualizations/Gauge/utils.ts @@ -0,0 +1,13 @@ +export const getValue = (rows: unknown[][]) => { + const rawValue = rows[0] && rows[0][0]; + + if (rawValue === "Infinity") { + return Infinity; + } + + if (typeof rawValue !== "number") { + return 0; + } + + return rawValue; +}; diff --git a/frontend/src/metabase/visualizations/visualizations/Gauge/utils.unit.spec.ts b/frontend/src/metabase/visualizations/visualizations/Gauge/utils.unit.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..d5b653ad0fe92bf3edf8b08d331f2ed47481be42 --- /dev/null +++ b/frontend/src/metabase/visualizations/visualizations/Gauge/utils.unit.spec.ts @@ -0,0 +1,27 @@ +import { getValue } from "./utils"; + +describe("Visualizations > Gauge > utils", () => { + const valueTestCases = [ + [[[null]], 0], + [[[undefined]], 0], + [[["foo"]], 0], + [[[""]], 0], + [[[0]], 0], + [[[1]], 1], + [ + [ + [1, 2, 3], + [4, 5, 6], + ], + 1, + ], + [[3], 0], + [[["Infinity"]], Infinity], + ]; + + valueTestCases.forEach(([input, output]) => { + it(`should return ${output} for ${JSON.stringify(input)}`, () => { + expect(getValue(input as unknown[][])).toEqual(output); + }); + }); +}); diff --git a/frontend/src/metabase/visualizations/visualizations/Progress.jsx b/frontend/src/metabase/visualizations/visualizations/Progress/Progress.jsx similarity index 98% rename from frontend/src/metabase/visualizations/visualizations/Progress.jsx rename to frontend/src/metabase/visualizations/visualizations/Progress/Progress.jsx index 7d216502f2ba09213d6e0a015734351f29336c1d..dda23bf867770d70421d50f7202c9708df2c75fe 100644 --- a/frontend/src/metabase/visualizations/visualizations/Progress.jsx +++ b/frontend/src/metabase/visualizations/visualizations/Progress/Progress.jsx @@ -13,6 +13,8 @@ import { color } from "metabase/lib/colors"; import { columnSettings } from "metabase/visualizations/lib/settings/column"; import { isNumeric } from "metabase-lib/types/utils/isa"; +import { getValue } from "./utils"; + const BORDER_RADIUS = 5; const MAX_BAR_HEIGHT = 65; @@ -136,7 +138,8 @@ export default class Progress extends Component { onVisualizationClick, visualizationIsClickable, } = this.props; - const value = rows[0] && typeof rows[0][0] === "number" ? rows[0][0] : 0; + + const value = getValue(rows); const column = cols[0]; const goal = settings["progress.goal"] || 0; diff --git a/frontend/src/metabase/visualizations/visualizations/Progress/index.js b/frontend/src/metabase/visualizations/visualizations/Progress/index.js new file mode 100644 index 0000000000000000000000000000000000000000..c9ad22f2dcb48ad15ca9145a1fa045557d19d98b --- /dev/null +++ b/frontend/src/metabase/visualizations/visualizations/Progress/index.js @@ -0,0 +1 @@ +export { default } from "./Progress"; diff --git a/frontend/src/metabase/visualizations/visualizations/Progress/utils.ts b/frontend/src/metabase/visualizations/visualizations/Progress/utils.ts new file mode 100644 index 0000000000000000000000000000000000000000..1317ee308e25275c91bed56d0d0e6c4bd9f2ec5b --- /dev/null +++ b/frontend/src/metabase/visualizations/visualizations/Progress/utils.ts @@ -0,0 +1,13 @@ +export const getValue = (rows: unknown[][]) => { + const rawValue = rows[0] && rows[0][0]; + + if (rawValue === "Infinity") { + return Infinity; + } + + if (typeof rawValue !== "number") { + return 0; + } + + return rawValue; +}; diff --git a/frontend/src/metabase/visualizations/visualizations/Progress/utils.unit.spec.ts b/frontend/src/metabase/visualizations/visualizations/Progress/utils.unit.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..0e5677f50d6aa3afe54dfc0d92d793b6e7065314 --- /dev/null +++ b/frontend/src/metabase/visualizations/visualizations/Progress/utils.unit.spec.ts @@ -0,0 +1,27 @@ +import { getValue } from "./utils"; + +describe("Visualizations > Progress > utils", () => { + const valueTestCases = [ + [[[null]], 0], + [[[undefined]], 0], + [[["foo"]], 0], + [[[""]], 0], + [[[0]], 0], + [[[1]], 1], + [ + [ + [1, 2, 3], + [4, 5, 6], + ], + 1, + ], + [[3], 0], + [[["Infinity"]], Infinity], + ]; + + valueTestCases.forEach(([input, output]) => { + it(`should return ${output} for ${JSON.stringify(input)}`, () => { + expect(getValue(input as unknown[][])).toEqual(output); + }); + }); +});