Rename and refactor the source form

pull/10616/head
Will Piers 2016-10-27 11:59:17 -07:00
parent 8530c0c69d
commit 6ab29756ec
6 changed files with 154 additions and 187 deletions

View File

@ -13,7 +13,7 @@ import RetentionPoliciesPage from 'src/retention_policies';
import DataExplorer from 'src/chronograf';
import DatabaseManager from 'src/database_manager';
import SignUp from 'src/sign_up';
import {CreateSource, NewSource, ManageSources} from 'src/sources';
import {CreateSource, SourceForm, ManageSources} from 'src/sources';
import {ClusterAccountsPage, ClusterAccountPage} from 'src/cluster_accounts';
import {RolesPageContainer, RolePageContainer} from 'src/access_control';
import NotFound from 'src/shared/components/NotFound';
@ -100,8 +100,8 @@ const Root = React.createClass({
<Route path="/sources/:sourceID" component={App}>
<Route component={CheckDataNodes}>
<Route path="manage-sources" component={ManageSources} />
<Route path="manage-sources/new" component={NewSource} />
<Route path="manage-sources/:id/edit" component={NewSource} />
<Route path="manage-sources/new" component={SourceForm} />
<Route path="manage-sources/:id/edit" component={SourceForm} />
<Route path="queries" component={QueriesPage} />
<Route path="accounts" component={ClusterAccountsPage} />
<Route path="accounts/:accountID" component={ClusterAccountPage} />

View File

@ -12,25 +12,19 @@ export function getSource(sourceID) {
});
}
export function createSource({url, name, username, password, isDefault}) {
export function createSource(attributes) {
return AJAX({
url: '/chronograf/v1/sources',
method: 'POST',
data: {
url,
name,
username,
password,
'default': isDefault,
},
data: attributes,
});
}
export function updateSource(sourceID, attributes) {
export function updateSource(newSource) {
return AJAX({
url: `/chronograf/v1/sources/${sourceID}`,
method: 'PUT',
data: attributes,
url: newSource.links.self,
method: 'PATCH',
data: newSource,
});
}

View File

@ -1,5 +1,3 @@
// Initial Source Creation Page
// Not the "Add Source" page, that's in NewSource
import React, {PropTypes} from 'react';
import {withRouter} from 'react-router';
import {createSource} from 'shared/apis';

View File

@ -1,168 +0,0 @@
import React, {PropTypes} from 'react';
import {withRouter} from 'react-router';
import {getSource, createSource, updateSource} from 'shared/apis';
// TODO: Add default checkbox
// TODO: wire up default checkbox
// TODO: make this go back to the manage sources page.
// TODO: change to SourceForm
// TODO: loading spinner while waiting for edit page to load.
// TODO: make Kapacitor a dropdown
// TODO: populate Kapacitor dropdown
export const NewSource = React.createClass({
propTypes: {
params: PropTypes.shape({
id: PropTypes.string,
}),
router: PropTypes.shape({
push: PropTypes.func.isRequired,
}).isRequired,
location: PropTypes.shape({
query: PropTypes.shape({
redirectPath: PropTypes.string,
}).isRequired,
}).isRequired,
},
getInitialState() {
return (
{
url: '',
name: '',
username: '',
password: '',
isDefault: false,
editMode: (this.props.params.id !== undefined),
});
},
componentDidMount() {
getSource(this.props.params.id).then(({data: source}) => {
const {url, name, username, password} = source;
const isDefault = source.default; // default is a reserved word
const loadedSource = {
url: url,
name: name,
username: username,
password: password,
isDefault: isDefault,
};
this.setState(loadedSource);
});
},
handleSubmit(e) {
e.preventDefault();
const source = {
url: this.sourceURL.value,
name: this.sourceName.value,
username: this.sourceUsername.value,
password: this.sourcePassword.value,
isDefault: true,
};
if (this.state.editMode) {
updateSource(this.props.params.id, source).then(({data: sourceFromServer}) => {
this.redirectToApp(sourceFromServer);
});
} else {
createSource(source).then(({data: sourceFromServer}) => {
this.redirectToApp(sourceFromServer);
});
}
},
redirectToApp(source) {
const {redirectPath} = this.props.location.query;
if (!redirectPath) {
return this.props.router.push(`/sources/${source.id}/hosts`);
}
const fixedPath = redirectPath.replace(/\/sources\/[^/]*/, `/sources/${source.id}`);
return this.props.router.push(fixedPath);
},
/*
* `e` is the change event
*
* Assumes the input is named source[propertyName]
*/
onInputChange(e) {
const val = e.target.value;
const name = e.target.name;
const matchResults = name.match(/source\[(\w+)\]/);
if (matchResults !== null) {
const newState = {source: {}};
newState[matchResults[1]] = val;
this.setState(newState);
}
},
submitBtnLabel() {
return this.state.editMode ? "Update" : "Create";
},
titleText() {
return this.state.editMode ? "Update Existing Source" : "Connect to a New Source";
},
render() {
// TODO: Replace text above form when Editing
return (
<div id="select-source-page">
<div className="container">
<div className="row">
<div className="col-md-8 col-md-offset-2">
<div className="panel panel-summer">
<div className="panel-body">
<h4 className="text-center">{this.titleText()}</h4>
<br/>
<form onSubmit={this.handleSubmit}>
<div>
<div className="form-group col-xs-6 col-sm-4 col-sm-offset-2">
<label htmlFor="connect-string">Connection String</label>
<input type="text" name="source[url]" ref={(r) => this.sourceURL = r} className="form-control" id="connect-string" placeholder="http://localhost:8086" onChange={this.onInputChange} value={this.state.url}></input>
</div>
<div className="form-group col-xs-6 col-sm-4">
<label htmlFor="name">Name</label>
<input type="text" name="source[name]" ref={(r) => this.sourceName = r} className="form-control" id="name" placeholder="Influx 1" onChange={this.onInputChange} value={this.state.name}></input>
</div>
<div className="form-group col-xs-6 col-sm-4 col-sm-offset-2">
<label htmlFor="username">Username</label>
<input type="text" name="source[username]" ref={(r) => this.sourceUsername = r} className="form-control" id="username" onChange={this.onInputChange} value={this.state.username}></input>
</div>
<div className="form-group col-xs-6 col-sm-4">
<label htmlFor="password">Password</label>
<input type="password" name="source[password]" ref={(r) => this.sourcePassword = r} className="form-control" id="password" onChange={this.onInputChange} value={this.state.password}></input>
</div>
<div className="form-group col-xs-6 col-sm-4 col-sm-offset-2">
<label htmlFor="database">Database</label>
<input type="text" name="source[telegraf]" ref={(r) => this.sourceDatabase = r} className="form-control" id="database" placeholder="telegraf" onChange={this.onInputChange} value={this.state.database}></input>
</div>
<div className="form-group col-xs-6 col-sm-4">
<label htmlFor="kapacitor">Kapacitor</label>
<select name="source[kapacitor]" ref={(r) => this.sourceKapacitor = r} className="form-control" id="kapacitor">
<option>Foo</option>
<option>Bar</option>
<option>Baz</option>
</select>
</div>
</div>
<div className="form-group col-xs-12 text-center">
<button className="btn btn-success" type="submit">{this.submitBtnLabel()}</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
);
},
});
export default withRouter(NewSource);

View File

@ -0,0 +1,143 @@
import React, {PropTypes} from 'react';
import {withRouter} from 'react-router';
import {getSource, createSource, updateSource} from 'shared/apis';
// TODO: Add default checkbox
// TODO: wire up default checkbox
// TODO: loading spinner while waiting for edit page to load.
// TODO: populate Kapacitor dropdown
export const SourceForm = React.createClass({
propTypes: {
params: PropTypes.shape({
id: PropTypes.string,
}),
router: PropTypes.shape({
push: PropTypes.func.isRequired,
}).isRequired,
location: PropTypes.shape({
query: PropTypes.shape({
redirectPath: PropTypes.string,
}).isRequired,
}).isRequired,
},
getInitialState() {
return {
source: {},
editMode: this.props.params.id !== undefined,
};
},
componentDidMount() {
if (!this.state.editMode) {
return;
}
getSource(this.props.params.id).then(({data: source}) => {
this.setState({source});
});
},
handleSubmit(e) {
e.preventDefault();
const {router} = this.props;
const newSource = Object.assign({}, this.state.source, {
url: this.sourceURL.value,
name: this.sourceName.value,
username: this.sourceUsername.value,
password: this.sourcePassword.value,
'default': true,
});
if (this.state.editMode) {
updateSource(newSource).then(() => {
// TODO: use the source.id that comes back from the server, when goller's PR gets merged and the autogenerated code gets banished!
router.push(`/sources/${1}/manage-sources`);
});
} else {
createSource(newSource).then(() => {
// TODO: use the source.id that comes back from the server, when goller's PR gets merged and the autogenerated code gets banished!
router.push(`/sources/${1}/manage-sources`);
});
}
},
onInputChange(e) {
const val = e.target.value;
const name = e.target.name;
this.setState((prevState) => {
const newSource = Object.assign({}, prevState.source, {
[name]: val,
});
return Object.assign({}, prevState, {source: newSource});
});
},
render() {
const {source, editMode} = this.state;
return (
<div id="source-form-page">
<div className="enterprise-header">
<div className="enterprise-header__container">
<div className="enterprise-header__left">
<h1>
Source Form
</h1>
</div>
</div>
</div>
<div className="container">
<div className="row">
<div className="col-md-8 col-md-offset-2">
<div className="panel panel-summer">
<div className="panel-body">
<h4 className="text-center">{editMode ? "Update Existing Source" : "Connect to a New Source"}</h4>
<br/>
<form onSubmit={this.handleSubmit}>
<div>
<div className="form-group col-xs-6 col-sm-4 col-sm-offset-2">
<label htmlFor="connect-string">Connection String</label>
<input type="text" name="url" ref={(r) => this.sourceURL = r} className="form-control" id="connect-string" placeholder="http://localhost:8086" onChange={this.onInputChange} value={source.url || ''}></input>
</div>
<div className="form-group col-xs-6 col-sm-4">
<label htmlFor="name">Name</label>
<input type="text" name="name" ref={(r) => this.sourceName = r} className="form-control" id="name" placeholder="Influx 1" onChange={this.onInputChange} value={source.name || ''}></input>
</div>
<div className="form-group col-xs-6 col-sm-4 col-sm-offset-2">
<label htmlFor="username">Username</label>
<input type="text" name="username" ref={(r) => this.sourceUsername = r} className="form-control" id="username" onChange={this.onInputChange} value={source.username || ''}></input>
</div>
<div className="form-group col-xs-6 col-sm-4">
<label htmlFor="password">Password</label>
<input type="password" name="password" ref={(r) => this.sourcePassword = r} className="form-control" id="password" onChange={this.onInputChange} value={source.password || ''}></input>
</div>
<div className="form-group col-xs-6 col-sm-4 col-sm-offset-2">
<label htmlFor="database">Database</label>
<input type="text" name="telegraf" ref={(r) => this.sourceDatabase = r} className="form-control" id="database" placeholder="telegraf" onChange={this.onInputChange} value={source.database || ''}></input>
</div>
<div className="form-group col-xs-6 col-sm-4">
<label htmlFor="kapacitor">Kapacitor</label>
<select name="kapacitor" ref={(r) => this.sourceKapacitor = r} className="form-control" id="kapacitor">
<option>Foo</option>
<option>Bar</option>
<option>Baz</option>
</select>
</div>
</div>
<div className="form-group col-xs-12 text-center">
<button className="btn btn-success" type="submit">{editMode ? "Update" : "Create"}</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
);
},
});
export default withRouter(SourceForm);

View File

@ -1,4 +1,4 @@
import CreateSource from './containers/CreateSource';
import NewSource from './containers/NewSource';
import SourceForm from './containers/SourceForm';
import ManageSources from './containers/ManageSources';
export {CreateSource, NewSource, ManageSources};
export {CreateSource, SourceForm, ManageSources};