Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[slices] add simple new slice form #2800

Merged
merged 7 commits into from
Jun 8, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 97 additions & 0 deletions superset/assets/javascripts/addSlice/AddSliceContainer.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Button, Panel, Grid, Row, Col } from 'react-bootstrap';
import Select from 'react-virtualized-select';
import visTypes from '../explore/stores/visTypes';

const propTypes = {
datasources: PropTypes.arrayOf(PropTypes.shape({
label: PropTypes.string.isRequired,
value: PropTypes.string.isRequired,
})).isRequired,
};

export default class AddSliceContainer extends React.PureComponent {
constructor(props) {
super(props);
const visTypeKeys = Object.keys(visTypes);
this.vizTypeOptions = visTypeKeys.map(vt => ({ label: visTypes[vt].label, value: vt }));
this.state = {
datasourceValue: this.props.datasources[0].value,
datasourceId: this.props.datasources[0].value.split('__')[0],
datasourceType: this.props.datasources[0].value.split('__')[1],
visType: 'table',
};
}

exploreUrl() {
const baseUrl = `/superset/explore/${this.state.datasourceType}/${this.state.datasourceId}`;
const formData = encodeURIComponent(JSON.stringify({ viz_type: this.state.visType }));
return `${baseUrl}?form_data=${formData}`;
}

gotoSlice() {
window.location.href = this.exploreUrl();
}

changeDatasource(e) {
this.setState({
datasourceValue: e.value,
datasourceId: e.value.split('__')[0],
datasourceType: e.value.split('__')[1],
});
}

changeSliceName(e) {
this.setState({ sliceName: e.target.value });
}

changeVisType(e) {
this.setState({ visType: e.value });
}

render() {
return (
<div className="container">
<Panel header={<h3>Create a new slice</h3>}>
<Grid>
<Row>
<Col xs={12} sm={6}>
<div>
<p>Choose a datasource</p>
<Select
clearable={false}
name="select-datasource"
onChange={this.changeDatasource.bind(this)}
options={this.props.datasources}
placeholder="Choose a datasource"
value={this.state.datasourceValue}
/>
</div>
<br />
<div>
<p>Choose a visualization type</p>
<Select
clearable={false}
name="select-vis-type"
onChange={this.changeVisType.bind(this)}
options={this.vizTypeOptions}
placeholder="Choose a visualization type"
value={this.state.visType}
/>
</div>
<br />
<Button bsStyle="primary" onClick={this.gotoSlice.bind(this)}>
Create new slice
</Button>
<br /><br />
</Col>
</Row>
</Grid>
</Panel>
</div>
);
}
}

AddSliceContainer.propTypes = propTypes;
14 changes: 14 additions & 0 deletions superset/assets/javascripts/addSlice/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from 'react';
import ReactDOM from 'react-dom';
import { appSetup } from '../common';
import AddSliceContainer from './AddSliceContainer';

appSetup();

const addSliceContainer = document.getElementById('js-add-slice-container');
const bootstrapData = JSON.parse(addSliceContainer.getAttribute('data-bootstrap'));

ReactDOM.render(
<AddSliceContainer datasources={bootstrapData.datasources} />,
addSliceContainer,
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React from 'react';
import { expect } from 'chai';
import { describe, it, beforeEach } from 'mocha';
import { shallow } from 'enzyme';
import { Button } from 'react-bootstrap';
import Select from 'react-virtualized-select';
import AddSliceContainer from '../../../javascripts/addSlice/AddSliceContainer';

const defaultProps = {
datasources: [
{ label: 'my first table', value: '1__table' },
{ label: 'another great table', value: '2__table' },
],
};

describe('AddSliceContainer', () => {
let wrapper;

beforeEach(() => {
wrapper = shallow(<AddSliceContainer {...defaultProps} />);
});

it('uses table as default visType', () => {
expect(wrapper.state().visType).to.equal('table');
});

it('renders 2 selects', () => {
expect(wrapper.find(Select)).to.have.lengthOf(2);
});

it('renders a button', () => {
expect(wrapper.find(Button)).to.have.lengthOf(1);
});

it('formats explore url', () => {
const formattedUrl = '/superset/explore/table/1?form_data=%7B%22viz_type%22%3A%22table%22%7D';
expect(wrapper.instance().exploreUrl()).to.equal(formattedUrl);
});
});
1 change: 1 addition & 0 deletions superset/assets/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const config = {
entry: {
'css-theme': APP_DIR + '/javascripts/css-theme.js',
common: APP_DIR + '/javascripts/common.js',
addSlice: ['babel-polyfill', APP_DIR + '/javascripts/addSlice/index.jsx'],
dashboard: ['babel-polyfill', APP_DIR + '/javascripts/dashboard/Dashboard.jsx'],
explore: ['babel-polyfill', APP_DIR + '/javascripts/explore/index.jsx'],
sqllab: ['babel-polyfill', APP_DIR + '/javascripts/SqlLab/index.jsx'],
Expand Down
19 changes: 19 additions & 0 deletions superset/templates/superset/add_slice.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{% extends "superset/basic.html" %}

{% block title %}
Add new slice
{% endblock %}

{% block body %}
<div
id="js-add-slice-container"
data-bootstrap="{{ bootstrap_data }}"
></div>
{% endblock %}

{% block tail_js %}
{{ super() }}
{% with filename="addSlice" %}
{% include "superset/partials/_script_tag.html" %}
{% endwith %}
{% endblock %}
16 changes: 11 additions & 5 deletions superset/views/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -372,11 +372,17 @@ def pre_delete(self, obj):
@expose('/add', methods=['GET', 'POST'])
@has_access
def add(self):
flash(__(
"To create a new slice, you can open a data source "
"through the `Sources` menu, or alter an existing slice "
"from the `Slices` menu"), "info")
return redirect('/superset/welcome')
datasources = ConnectorRegistry.get_all_datasources(db.session)
datasources = [
{'value': str(d.id) + '__' + d.type, 'label': repr(d)}
for d in datasources
]
return self.render_template(
"superset/add_slice.html",
bootstrap_data=json.dumps({
'datasources': datasources,
}),
)

appbuilder.add_view(
SliceModelView,
Expand Down