diff --git a/app/components/Settings/Preview/Preview.react.js b/app/components/Settings/Preview/Preview.react.js
index 67d6de56e..aa28c10dd 100644
--- a/app/components/Settings/Preview/Preview.react.js
+++ b/app/components/Settings/Preview/Preview.react.js
@@ -6,7 +6,7 @@ import {Tab, Tabs, TabList, TabPanel} from 'react-tabs';
import SQLTable from './sql-table.jsx';
import CodeEditorField from './CodeEditorField.react.js';
-import ChartEditor from './ChartEditor.react.js';
+import ChartEditor from './chart-editor.jsx';
import ApacheDrillPreview from './ApacheDrillPreview.js';
import S3Preview from './S3Preview.js';
@@ -365,30 +365,22 @@ class Preview extends Component {
- Chart
Table
+ Chart
Export
-
-
+ {
- updatePreview({'chartEditor': R.merge(
- chartEditorState,
- newProps
- )});
- }}
- {...chartEditorState}
/>
-
-
+
diff --git a/app/components/Settings/Preview/chart-editor.jsx b/app/components/Settings/Preview/chart-editor.jsx
new file mode 100644
index 000000000..46511e0f7
--- /dev/null
+++ b/app/components/Settings/Preview/chart-editor.jsx
@@ -0,0 +1,134 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+import plotly from 'plotly.js/dist/plotly';
+import createPlotComponent from 'react-plotly.js/factory';
+import PlotlyEditor from 'react-chart-editor';
+import 'react-chart-editor/lib/react-chart-editor.css';
+
+const Plot = createPlotComponent(plotly);
+
+export default class ChartEditor extends React.Component {
+ static propTypes = {
+ columnNames: PropTypes.array,
+ rows: PropTypes.array
+ }
+
+ /**
+ * ChartEditor displays a Plotly.js chart using the query results
+ *
+ * @param {object} props - Component properties
+ *
+ * @param {Array} props.columnNames - Array of column names
+ * @param {Array.} props.rows - Array of rows
+ */
+ constructor(props) {
+ super(props);
+
+ this.computeDerivedProps();
+
+ /**
+ * @member {object} state - Component state
+ * @property {object} state.gd - Graph div
+ * @property {number} state.revision - Revision number
+ */
+ this.state = {
+ gd: {},
+ revision: 0
+ };
+
+ /**
+ * Increment revision counter
+ * @returns {undefined}
+ */
+ this.onEditorUpdate = () => {
+ this.setState(({revision: prevRevision}) => ({revision: prevRevision + 1}));
+ };
+
+ /**
+ * Updates graph div
+ * @param {object} gd - Graph div
+ * @returns {undefined}
+ */
+ this.onPlotUpdate = (gd) => {
+ this.setState({gd});
+ };
+ }
+
+ computeDerivedProps() {
+ /**
+ * @member {object} dataSources - Create a data source per column (used by )
+ */
+ this.dataSources = {};
+ this.props.columnNames.forEach(name => {
+ this.dataSources[name] = [];
+ });
+ this.props.rows.forEach(row => {
+ row.forEach((v, i) => {
+ const columnName = this.props.columnNames[i];
+ this.dataSources[columnName].push(v);
+ });
+ });
+
+ /**
+ * @member {Array.