diff --git a/superset/assets/package-lock.json b/superset/assets/package-lock.json index 60eb0128e..16cc11b04 100644 --- a/superset/assets/package-lock.json +++ b/superset/assets/package-lock.json @@ -4700,9 +4700,9 @@ "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==" }, "bignumber.js": { - "version": "2.4.0", - "resolved": "http://registry.npmjs.org/bignumber.js/-/bignumber.js-2.4.0.tgz", - "integrity": "sha1-g4qZLan51zfg9LLbC+YrsJ3Qxeg=" + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-8.1.0.tgz", + "integrity": "sha512-hRv8jfqOBRnK1oGd0zDbfZv5blY3gy4QIsZZQ35mLCEMp/YdZmnrphBhX02SRKyLlohl+Sx6Ol7RlQhVLj/TAg==" }, "binary-extensions": { "version": "1.12.0", @@ -12553,6 +12553,13 @@ "stream-to-buffer": "^0.1.0", "tinycolor2": "^1.1.2", "url-regex": "^3.0.0" + }, + "dependencies": { + "bignumber.js": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-2.4.0.tgz", + "integrity": "sha1-g4qZLan51zfg9LLbC+YrsJ3Qxeg=" + } } }, "jpeg-js": { diff --git a/superset/assets/package.json b/superset/assets/package.json index 232d9eb95..5a33dace8 100644 --- a/superset/assets/package.json +++ b/superset/assets/package.json @@ -51,11 +51,6 @@ "@superset-ui/color": "^0.9.5", "@superset-ui/connection": "^0.9.5", "@superset-ui/core": "^0.9.5", - "@superset-ui/number-format": "^0.9.5", - "@superset-ui/time-format": "^0.9.5", - "@superset-ui/translation": "^0.9.5", - "@superset-ui/legacy-preset-chart-big-number": "^0.1.1", - "@superset-ui/legacy-preset-chart-nvd3": "^0.1.1", "@superset-ui/legacy-plugin-chart-calendar": "^0.1.1", "@superset-ui/legacy-plugin-chart-chord": "^0.1.1", "@superset-ui/legacy-plugin-chart-country-map": "^0.1.1", @@ -65,8 +60,8 @@ "@superset-ui/legacy-plugin-chart-histogram": "^0.1.1", "@superset-ui/legacy-plugin-chart-horizon": "^0.1.1", "@superset-ui/legacy-plugin-chart-iframe": "^0.1.1", - "@superset-ui/legacy-plugin-chart-markup": "^0.1.1", "@superset-ui/legacy-plugin-chart-map-box": "^0.1.1", + "@superset-ui/legacy-plugin-chart-markup": "^0.1.1", "@superset-ui/legacy-plugin-chart-paired-t-test": "^0.1.0", "@superset-ui/legacy-plugin-chart-parallel-coordinates": "^0.1.1", "@superset-ui/legacy-plugin-chart-partition": "^0.1.1", @@ -78,8 +73,14 @@ "@superset-ui/legacy-plugin-chart-treemap": "^0.1.1", "@superset-ui/legacy-plugin-chart-word-cloud": "^0.1.1", "@superset-ui/legacy-plugin-chart-world-map": "^0.1.1", + "@superset-ui/legacy-preset-chart-big-number": "^0.1.1", + "@superset-ui/legacy-preset-chart-nvd3": "^0.1.1", + "@superset-ui/number-format": "^0.9.5", + "@superset-ui/time-format": "^0.9.5", + "@superset-ui/translation": "^0.9.5", "@vx/responsive": "0.0.172", "abortcontroller-polyfill": "^1.1.9", + "bignumber.js": "^8.1.0", "bootstrap": "^3.3.6", "bootstrap-slider": "^10.0.0", "brace": "^0.11.1", diff --git a/superset/assets/spec/javascripts/chart/transformBigNumber_spec.js b/superset/assets/spec/javascripts/chart/transformBigNumber_spec.js new file mode 100644 index 000000000..1500a4243 --- /dev/null +++ b/superset/assets/spec/javascripts/chart/transformBigNumber_spec.js @@ -0,0 +1,53 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import BigNumber from 'bignumber.js'; +import transform from 'src/chart/transformBigNumber'; + +describe('transformBigNumber', () => { + it('should transform BigNumber on its own', () => { + expect(transform(new BigNumber(123.456))).toBe(123.456); + }); + + it('should transform BigNumber in objects', () => { + expect(transform({ + foo: new BigNumber(123), + bar: 456, + baz: null, + })).toEqual({ foo: 123, bar: 456, baz: null }); + }); + + it('should transform BigNumber in arrays', () => { + expect(transform([ + { foo: new BigNumber(123) }, + { bar: 456 }, + ])).toEqual([{ foo: 123 }, { bar: 456 }]); + }); + + it('should transform BigNumber in nested structures', () => { + expect(transform([{ + x: new BigNumber(123), + y: [{ foo: new BigNumber(456) }, { bar: 'str' }], + z: { some: [new BigNumber(789)] }, + }])).toEqual([{ + x: 123, + y: [{ foo: 456 }, { bar: 'str' }], + z: { some: [789] }, + }]); + }); +}); diff --git a/superset/assets/src/chart/ChartRenderer.jsx b/superset/assets/src/chart/ChartRenderer.jsx index e4e5d44fa..dc057a339 100644 --- a/superset/assets/src/chart/ChartRenderer.jsx +++ b/superset/assets/src/chart/ChartRenderer.jsx @@ -23,6 +23,7 @@ import React from 'react'; import { ChartProps, SuperChart } from '@superset-ui/chart'; import { Tooltip } from 'react-bootstrap'; import { Logger, LOG_ACTIONS_RENDER_CHART } from '../logger/LogUtils'; +import transformBigNumber from './transformBigNumber'; const propTypes = { annotationData: PropTypes.object, @@ -67,6 +68,7 @@ class ChartRenderer extends React.Component { this.handleAddFilter = this.handleAddFilter.bind(this); this.handleRenderSuccess = this.handleRenderSuccess.bind(this); this.handleRenderFailure = this.handleRenderFailure.bind(this); + this.preTransformProps = this.preTransformProps.bind(this); } shouldComponentUpdate(nextProps, nextState) { @@ -164,6 +166,18 @@ class ChartRenderer extends React.Component { } } + preTransformProps(chartProps) { + const payload = chartProps.payload; + const data = transformBigNumber(payload.data); + return new ChartProps({ + ...chartProps, + payload: { + ...payload, + data, + }, + }); + } + renderTooltip() { const { tooltip } = this.state; if (tooltip && tooltip.content) { @@ -209,6 +223,7 @@ class ChartRenderer extends React.Component { className={`${snakeCase(vizType)}`} chartType={vizType} chartProps={skipChartRendering ? null : this.prepareChartProps()} + preTransformProps={this.preTransformProps} onRenderSuccess={this.handleRenderSuccess} onRenderFailure={this.handleRenderFailure} /> diff --git a/superset/assets/src/chart/transformBigNumber.js b/superset/assets/src/chart/transformBigNumber.js new file mode 100644 index 000000000..dffa02a7f --- /dev/null +++ b/superset/assets/src/chart/transformBigNumber.js @@ -0,0 +1,45 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +// This method transforms any BigNumber object in the given payload to its +// 64-bit float representation. It is a temporary fix so charts receive +// floats instead of BigNumber instances in their props to properly render. +import BigNumber from 'bignumber.js'; + +export default function transform(payload) { + if (!payload) { + return payload; + } else if (BigNumber.isBigNumber(payload)) { + return payload.toNumber(); + } else if (payload.constructor === Object) { + for (const key in payload) { + if (payload.hasOwnProperty(key)) { + // Modify in place to prevent creating large payloads + // eslint-disable-next-line no-param-reassign + payload[key] = transform(payload[key]); + } + } + } else if (payload.constructor === Array) { + payload.forEach((elem, idx) => { + // Modify in place to prevent creating large payloads + // eslint-disable-next-line no-param-reassign + payload[idx] = transform(elem); + }); + } + return payload; +}