mirror of https://github.com/apache/superset.git
apply redux for VisualizeModal (#2795)
* redux visualize modal * redux visualize modal - apply redux - add unit test for connect container component - fix lint error * redux visualize modal - apply redux - add unit test for connect container component - fix lint error
This commit is contained in:
parent
69685b9dcc
commit
d0a04cde49
|
@ -37,6 +37,10 @@ export const REMOVE_DATA_PREVIEW = 'REMOVE_DATA_PREVIEW';
|
|||
export const CHANGE_DATA_PREVIEW_ID = 'CHANGE_DATA_PREVIEW_ID';
|
||||
export const SAVE_QUERY = 'SAVE_QUERY';
|
||||
|
||||
export const CREATE_DATASOURCE_STARTED = 'CREATE_DATASOURCE_STARTED';
|
||||
export const CREATE_DATASOURCE_SUCCESS = 'CREATE_DATASOURCE_SUCCESS';
|
||||
export const CREATE_DATASOURCE_FAILED = 'CREATE_DATASOURCE_FAILED';
|
||||
|
||||
export function resetState() {
|
||||
return { type: RESET_STATE };
|
||||
}
|
||||
|
@ -382,3 +386,37 @@ export function popSavedQuery(saveQueryId) {
|
|||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function createDatasourceStarted() {
|
||||
return { type: CREATE_DATASOURCE_STARTED };
|
||||
}
|
||||
export function createDatasourceSuccess(response) {
|
||||
const data = JSON.parse(response);
|
||||
const datasource = `${data.table_id}__table`;
|
||||
return { type: CREATE_DATASOURCE_SUCCESS, datasource };
|
||||
}
|
||||
export function createDatasourceFailed(err) {
|
||||
return { type: CREATE_DATASOURCE_FAILED, err };
|
||||
}
|
||||
|
||||
export function createDatasource(vizOptions, context) {
|
||||
return (dispatch) => {
|
||||
dispatch(createDatasourceStarted());
|
||||
|
||||
return $.ajax({
|
||||
type: 'POST',
|
||||
url: '/superset/sqllab_viz/',
|
||||
data: {
|
||||
data: JSON.stringify(vizOptions),
|
||||
},
|
||||
context,
|
||||
dataType: 'json',
|
||||
success: (resp) => {
|
||||
dispatch(createDatasourceSuccess(resp));
|
||||
},
|
||||
error: () => {
|
||||
dispatch(createDatasourceFailed('An error occurred while creating the data source'));
|
||||
},
|
||||
});
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
/* global notify */
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
import { Alert, Button, Col, Modal } from 'react-bootstrap';
|
||||
|
||||
import Select from 'react-select';
|
||||
import { Table } from 'reactable';
|
||||
import shortid from 'shortid';
|
||||
import $ from 'jquery';
|
||||
import { getExploreUrl } from '../../explorev2/exploreUtils';
|
||||
import * as actions from '../actions';
|
||||
|
||||
const CHART_TYPES = [
|
||||
{ value: 'dist_bar', label: 'Distribution - Bar Chart', requiresTime: false },
|
||||
|
@ -17,9 +19,12 @@ const CHART_TYPES = [
|
|||
];
|
||||
|
||||
const propTypes = {
|
||||
actions: PropTypes.object.isRequired,
|
||||
onHide: PropTypes.func,
|
||||
query: PropTypes.object,
|
||||
show: PropTypes.bool,
|
||||
datasource: PropTypes.string,
|
||||
errorMessage: PropTypes.string,
|
||||
};
|
||||
const defaultProps = {
|
||||
show: false,
|
||||
|
@ -121,22 +126,14 @@ class VisualizeModal extends React.PureComponent {
|
|||
sql: this.props.query.sql,
|
||||
dbId: this.props.query.dbId,
|
||||
};
|
||||
notify.info('Creating a data source and popping a new tab');
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: '/superset/sqllab_viz/',
|
||||
async: false,
|
||||
data: {
|
||||
data: JSON.stringify(vizOptions),
|
||||
},
|
||||
dataType: 'json',
|
||||
success: (resp) => {
|
||||
|
||||
this.props.actions.createDatasource(vizOptions, this)
|
||||
.done(() => {
|
||||
const columns = Object.keys(this.state.columns).map(k => this.state.columns[k]);
|
||||
const data = JSON.parse(resp);
|
||||
const mainMetric = columns.filter(d => d.agg)[0];
|
||||
const mainGroupBy = columns.filter(d => d.is_dim)[0];
|
||||
const formData = {
|
||||
datasource: `${data.table_id}__table`,
|
||||
datasource: this.props.datasource,
|
||||
viz_type: this.state.chartType.value,
|
||||
since: '100 years ago',
|
||||
limit: '0',
|
||||
|
@ -148,14 +145,16 @@ class VisualizeModal extends React.PureComponent {
|
|||
if (mainGroupBy) {
|
||||
formData.groupby = [mainGroupBy.name];
|
||||
}
|
||||
notify.info('Creating a data source and popping a new tab');
|
||||
|
||||
window.open(getExploreUrl(formData));
|
||||
},
|
||||
error: () => notify('An error occurred while creating the data source'),
|
||||
});
|
||||
})
|
||||
.fail(() => {
|
||||
notify.error(this.props.errorMessage);
|
||||
});
|
||||
}
|
||||
changeDatasourceName(event) {
|
||||
this.setState({ datasourceName: event.target.value });
|
||||
this.validate();
|
||||
this.setState({ datasourceName: event.target.value }, this.validate);
|
||||
}
|
||||
changeCheckbox(attr, columnName, event) {
|
||||
let columns = this.mergedColumns();
|
||||
|
@ -271,4 +270,19 @@ class VisualizeModal extends React.PureComponent {
|
|||
VisualizeModal.propTypes = propTypes;
|
||||
VisualizeModal.defaultProps = defaultProps;
|
||||
|
||||
export default VisualizeModal;
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
datasource: state.datasource,
|
||||
errorMessage: state.errorMessage,
|
||||
};
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators(actions, dispatch),
|
||||
};
|
||||
}
|
||||
|
||||
export { VisualizeModal };
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(VisualizeModal);
|
||||
|
||||
|
|
|
@ -251,6 +251,25 @@ export const sqlLabReducer = function (state, action) {
|
|||
}
|
||||
return Object.assign({}, state, { queries: newQueries, queriesLastUpdate });
|
||||
},
|
||||
[actions.CREATE_DATASOURCE_STARTED]() {
|
||||
return Object.assign({}, state, {
|
||||
isDatasourceLoading: true,
|
||||
errorMessage: null,
|
||||
});
|
||||
},
|
||||
[actions.CREATE_DATASOURCE_SUCCESS]() {
|
||||
return Object.assign({}, state, {
|
||||
isDatasourceLoading: false,
|
||||
errorMessage: null,
|
||||
datasource: action.datasource,
|
||||
});
|
||||
},
|
||||
[actions.CREATE_DATASOURCE_FAILED]() {
|
||||
return Object.assign({}, state, {
|
||||
isDatasourceLoading: false,
|
||||
errorMessage: action.err,
|
||||
});
|
||||
},
|
||||
};
|
||||
if (action.type in actionHandlers) {
|
||||
return actionHandlers[action.type]();
|
||||
|
|
|
@ -126,6 +126,7 @@
|
|||
"mocha": "^3.2.0",
|
||||
"react-addons-test-utils": "^15.5.1",
|
||||
"react-test-renderer": "^15.5.1",
|
||||
"redux-mock-store": "^1.2.3",
|
||||
"sinon": "^2.1.0",
|
||||
"style-loader": "^0.16.1",
|
||||
"transform-loader": "^0.2.3",
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import { shallow } from 'enzyme';
|
||||
import { describe, it } from 'mocha';
|
||||
import { expect } from 'chai';
|
||||
import { Table } from 'reactable';
|
||||
|
||||
import { queries } from './fixtures';
|
||||
import QueryTable from '../../../javascripts/SqlLab/components/QueryTable';
|
||||
|
||||
|
||||
describe('QueryTable', () => {
|
||||
const mockedProps = {
|
||||
queries,
|
||||
|
@ -20,8 +20,9 @@ describe('QueryTable', () => {
|
|||
).to.equal(true);
|
||||
});
|
||||
it('renders a proper table', () => {
|
||||
const wrapper = mount(<QueryTable {...mockedProps} />);
|
||||
expect(wrapper.find('table')).to.have.length(1);
|
||||
expect(wrapper.find('tr')).to.have.length(4);
|
||||
const wrapper = shallow(<QueryTable {...mockedProps} />);
|
||||
expect(wrapper.find(Table)).to.have.length(1);
|
||||
expect(wrapper.find(Table).shallow().find('table')).to.have.length(1);
|
||||
expect(wrapper.find(Table).shallow().find('table').find('Tr')).to.have.length(2);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,17 +1,58 @@
|
|||
import React from 'react';
|
||||
import configureStore from 'redux-mock-store';
|
||||
import thunk from 'redux-thunk';
|
||||
|
||||
import { Modal } from 'react-bootstrap';
|
||||
import { shallow } from 'enzyme';
|
||||
import { describe, it } from 'mocha';
|
||||
import { expect } from 'chai';
|
||||
import sinon from 'sinon';
|
||||
|
||||
import $ from 'jquery';
|
||||
import { queries } from './fixtures';
|
||||
import { sqlLabReducer } from '../../../javascripts/SqlLab/reducers';
|
||||
import VisualizeModal from '../../../javascripts/SqlLab/components/VisualizeModal';
|
||||
import * as exploreUtils from '../../../javascripts/explorev2/exploreUtils';
|
||||
|
||||
global.notify = {
|
||||
info: () => {},
|
||||
error: () => {},
|
||||
};
|
||||
|
||||
describe('VisualizeModal', () => {
|
||||
const middlewares = [thunk];
|
||||
const mockStore = configureStore(middlewares);
|
||||
const initialState = sqlLabReducer(undefined, {});
|
||||
const store = mockStore(initialState);
|
||||
const mockedProps = {
|
||||
show: true,
|
||||
query: queries[0],
|
||||
};
|
||||
const mockColumns = {
|
||||
ds: {
|
||||
is_date: true,
|
||||
is_dim: false,
|
||||
name: 'ds',
|
||||
type: 'STRING',
|
||||
},
|
||||
gender: {
|
||||
is_date: false,
|
||||
is_dim: true,
|
||||
name: 'gender',
|
||||
type: 'STRING',
|
||||
},
|
||||
};
|
||||
const mockChartTypeBarChart = {
|
||||
label: 'Distribution - Bar Chart',
|
||||
requiresTime: false,
|
||||
value: 'dist_bar',
|
||||
};
|
||||
|
||||
const getVisualizeModalWrapper = () => (
|
||||
shallow(<VisualizeModal {...mockedProps} />, {
|
||||
context: { store },
|
||||
}).dive());
|
||||
|
||||
it('renders', () => {
|
||||
expect(React.isValidElement(<VisualizeModal />)).to.equal(true);
|
||||
});
|
||||
|
@ -21,7 +62,51 @@ describe('VisualizeModal', () => {
|
|||
).to.equal(true);
|
||||
});
|
||||
it('renders a Modal', () => {
|
||||
const wrapper = shallow(<VisualizeModal {...mockedProps} />);
|
||||
const wrapper = getVisualizeModalWrapper();
|
||||
expect(wrapper.find(Modal)).to.have.length(1);
|
||||
});
|
||||
|
||||
describe('visualize', () => {
|
||||
const wrapper = getVisualizeModalWrapper();
|
||||
|
||||
wrapper.setState({
|
||||
chartType: mockChartTypeBarChart,
|
||||
columns: mockColumns,
|
||||
datasourceName: 'mockDatasourceName',
|
||||
});
|
||||
|
||||
const vizOptions = {
|
||||
chartType: wrapper.state().chartType.value,
|
||||
datasourceName: wrapper.state().datasourceName,
|
||||
columns: wrapper.state().columns,
|
||||
sql: wrapper.instance().props.query.sql,
|
||||
dbId: wrapper.instance().props.query.dbId,
|
||||
};
|
||||
|
||||
let spy;
|
||||
let server;
|
||||
|
||||
beforeEach(() => {
|
||||
spy = sinon.spy($, 'ajax');
|
||||
server = sinon.fakeServer.create();
|
||||
sinon.stub(JSON, 'parse').callsFake(() => ({ table_id: 107 }));
|
||||
sinon.stub(exploreUtils, 'getExploreUrl').callsFake(() => ('mockURL'));
|
||||
});
|
||||
afterEach(() => {
|
||||
spy.restore();
|
||||
server.restore();
|
||||
JSON.parse.restore();
|
||||
exploreUtils.getExploreUrl.restore();
|
||||
});
|
||||
|
||||
it('should build request', () => {
|
||||
wrapper.instance().visualize();
|
||||
expect(spy.callCount).to.equal(1);
|
||||
|
||||
const spyCall = spy.getCall(0);
|
||||
expect(spyCall.args[0].type).to.equal('POST');
|
||||
expect(spyCall.args[0].url).to.equal('/superset/sqllab_viz/');
|
||||
expect(spyCall.args[0].data.data).to.equal(JSON.stringify(vizOptions));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue