diff --git a/superset/assets/spec/javascripts/visualizations/core/createLoadableRenderer_spec.jsx b/superset/assets/spec/javascripts/visualizations/core/createLoadableRenderer_spec.jsx deleted file mode 100644 index 21e3f9fd329..00000000000 --- a/superset/assets/spec/javascripts/visualizations/core/createLoadableRenderer_spec.jsx +++ /dev/null @@ -1,112 +0,0 @@ -/** - * 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 React from 'react'; -import { shallow } from 'enzyme'; -import createLoadableRenderer from 'src/visualizations/core/components/createLoadableRenderer'; - -describe('createLoadableRenderer', () => { - function TestComponent() { - return ( -
test
- ); - } - let loadChartSuccess; - let render; - let loading; - let LoadableRenderer; - - beforeEach(() => { - loadChartSuccess = jest.fn(() => Promise.resolve(TestComponent)); - render = jest.fn((loaded) => { - const { Chart } = loaded; - return (); - }); - loading = jest.fn(() => (
Loading
)); - LoadableRenderer = createLoadableRenderer({ - loader: { - Chart: loadChartSuccess, - }, - loading, - render, - }); - }); - - describe('returns a LoadableRenderer class', () => { - it('LoadableRenderer.preload() preloads the lazy-load components', () => { - expect(LoadableRenderer.preload).toBeInstanceOf(Function); - LoadableRenderer.preload(); - expect(loadChartSuccess).toHaveBeenCalledTimes(1); - }); - - it('calls onRenderSuccess when succeeds', (done) => { - const onRenderSuccess = jest.fn(); - const onRenderFailure = jest.fn(); - shallow( - , - ); - expect(loadChartSuccess).toHaveBeenCalled(); - setTimeout(() => { - expect(render).toHaveBeenCalledTimes(1); - expect(onRenderSuccess).toHaveBeenCalledTimes(1); - expect(onRenderFailure).not.toHaveBeenCalled(); - done(); - }, 10); - }); - - it('calls onRenderFailure when fails', (done) => { - const loadChartFailure = jest.fn(() => Promise.reject('Invalid chart')); - const FailedRenderer = createLoadableRenderer({ - loader: { - Chart: loadChartFailure, - }, - loading, - render, - }); - const onRenderSuccess = jest.fn(); - const onRenderFailure = jest.fn(); - shallow( - , - ); - expect(loadChartFailure).toHaveBeenCalledTimes(1); - setTimeout(() => { - expect(render).not.toHaveBeenCalled(); - expect(onRenderSuccess).not.toHaveBeenCalled(); - expect(onRenderFailure).toHaveBeenCalledTimes(1); - done(); - }, 10); - }); - - it('renders the lazy-load components', (done) => { - const wrapper = shallow(); - // lazy-loaded component not rendered immediately - expect(wrapper.find(TestComponent)).toHaveLength(0); - setTimeout(() => { - // but rendered after the component is loaded. - expect(wrapper.find(TestComponent)).toHaveLength(1); - done(); - }, 10); - }); - }); -}); diff --git a/superset/assets/src/chart/ChartRenderer.jsx b/superset/assets/src/chart/ChartRenderer.jsx index 420acdb3667..a05ecaf2376 100644 --- a/superset/assets/src/chart/ChartRenderer.jsx +++ b/superset/assets/src/chart/ChartRenderer.jsx @@ -20,10 +20,9 @@ import dompurify from 'dompurify'; import { snakeCase } from 'lodash'; import PropTypes from 'prop-types'; import React from 'react'; -import { ChartProps } from '@superset-ui/chart'; +import { ChartProps, SuperChart } from '@superset-ui/chart'; import { Tooltip } from 'react-bootstrap'; import { Logger, LOG_ACTIONS_RENDER_CHART } from '../logger'; -import SuperChart from '../visualizations/core/components/SuperChart'; const propTypes = { annotationData: PropTypes.object, diff --git a/superset/assets/src/visualizations/core/components/SuperChart.jsx b/superset/assets/src/visualizations/core/components/SuperChart.jsx deleted file mode 100644 index 0c7e6e69517..00000000000 --- a/superset/assets/src/visualizations/core/components/SuperChart.jsx +++ /dev/null @@ -1,186 +0,0 @@ -/** - * 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 React from 'react'; -import PropTypes from 'prop-types'; -import { createSelector } from 'reselect'; -import { getChartComponentRegistry, getChartTransformPropsRegistry, ChartProps } from '@superset-ui/chart'; -import createLoadableRenderer from './createLoadableRenderer'; -import { safeStringify } from '../../../utils/safeStringify'; - -const IDENTITY = x => x; - -const propTypes = { - id: PropTypes.string, - className: PropTypes.string, - chartProps: PropTypes.instanceOf(ChartProps), - chartType: PropTypes.string.isRequired, - preTransformProps: PropTypes.func, - overrideTransformProps: PropTypes.func, - postTransformProps: PropTypes.func, - onRenderSuccess: PropTypes.func, - onRenderFailure: PropTypes.func, -}; -const defaultProps = { - id: '', - className: '', - preTransformProps: IDENTITY, - overrideTransformProps: undefined, - postTransformProps: IDENTITY, - onRenderSuccess() {}, - onRenderFailure() {}, -}; - -class SuperChart extends React.PureComponent { - constructor(props) { - super(props); - - this.renderChart = this.renderChart.bind(this); - this.renderLoading = this.renderLoading.bind(this); - - // memoized function so it will not recompute - // and return previous value - // unless one of - // - preTransformProps - // - transformProps - // - postTransformProps - // - chartProps - // is changed. - this.processChartProps = createSelector( - input => input.preTransformProps, - input => input.transformProps, - input => input.postTransformProps, - input => input.chartProps, - (pre, transform, post, chartProps) => post(transform(pre(chartProps))), - ); - - const componentRegistry = getChartComponentRegistry(); - const transformPropsRegistry = getChartTransformPropsRegistry(); - - // memoized function so it will not recompute - // and return previous value - // unless one of - // - chartType - // - overrideTransformProps - // is changed. - this.createLoadableRenderer = createSelector( - input => input.chartType, - input => input.overrideTransformProps, - (chartType, overrideTransformProps) => { - if (chartType) { - const LoadableRenderer = createLoadableRenderer({ - loader: { - Chart: () => componentRegistry.getAsPromise(chartType), - transformProps: overrideTransformProps - ? () => Promise.resolve(overrideTransformProps) - : () => transformPropsRegistry.getAsPromise(chartType), - }, - loading: loadingProps => this.renderLoading(loadingProps, chartType), - render: this.renderChart, - }); - - // Trigger preloading. - LoadableRenderer.preload(); - - return LoadableRenderer; - } - return null; - }, - ); - } - - - renderChart(loaded, props) { - const Chart = loaded.Chart.default || loaded.Chart; - const transformProps = loaded.transformProps.default || loaded.transformProps; - const { - chartProps, - preTransformProps, - postTransformProps, - } = props; - - return ( - - ); - } - - renderLoading(loadingProps, chartType) { - const { error } = loadingProps; - - if (error) { - return ( -
- ERROR  - chartType="{chartType}" — - {safeStringify(error)} -
- ); - } - - return null; - } - - render() { - const { - id, - className, - preTransformProps, - postTransformProps, - chartProps, - onRenderSuccess, - onRenderFailure, - } = this.props; - - // Create LoadableRenderer and start preloading - // the lazy-loaded Chart components - const LoadableRenderer = this.createLoadableRenderer(this.props); - - // Do not render if chartProps is not available. - // but the pre-loading has been started in this.createLoadableRenderer - // to prepare for rendering once chartProps becomes available. - if (!chartProps) { - return null; - } - - return ( -
- {LoadableRenderer && ( - - )} -
- ); - } -} - -SuperChart.propTypes = propTypes; -SuperChart.defaultProps = defaultProps; - -export default SuperChart; diff --git a/superset/assets/src/visualizations/core/components/createLoadableRenderer.js b/superset/assets/src/visualizations/core/components/createLoadableRenderer.js deleted file mode 100644 index 9c0317962a5..00000000000 --- a/superset/assets/src/visualizations/core/components/createLoadableRenderer.js +++ /dev/null @@ -1,64 +0,0 @@ -/** - * 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 Loadable from 'react-loadable'; -import PropTypes from 'prop-types'; - -const propTypes = { - onRenderSuccess: PropTypes.func, - onRenderFailure: PropTypes.func, -}; - -const defaultProps = { - onRenderSuccess() {}, - onRenderFailure() {}, -}; - -export default function createLoadableRenderer(options) { - const LoadableRenderer = Loadable.Map(options); - - // Extends the behavior of LoadableComponent - // generated by react-loadable - // to provide post-render listeners - class CustomLoadableRenderer extends LoadableRenderer { - componentDidMount() { - this.afterRender(); - } - - componentDidUpdate() { - this.afterRender(); - } - - afterRender() { - const { loaded, loading, error } = this.state; - if (!loading) { - if (error) { - this.props.onRenderFailure(error); - } else if (loaded && Object.keys(loaded).length > 0) { - this.props.onRenderSuccess(); - } - } - } - } - - CustomLoadableRenderer.defaultProps = defaultProps; - CustomLoadableRenderer.propTypes = propTypes; - CustomLoadableRenderer.preload = LoadableRenderer.preload; - - return CustomLoadableRenderer; -}