Merge pull request #295 from influxdata/feature/216-add-edit-sources
Add / Edit Sourcespull/313/head
commit
2a79591556
|
@ -1,6 +1,6 @@
|
||||||
import React, {PropTypes} from 'react';
|
import React, {PropTypes} from 'react';
|
||||||
import {withRouter} from 'react-router';
|
import {withRouter} from 'react-router';
|
||||||
import {getSources} from 'src/shared/apis';
|
import {getSources} from 'shared/apis';
|
||||||
|
|
||||||
const {bool, number, string, node, func, shape} = PropTypes;
|
const {bool, number, string, node, func, shape} = PropTypes;
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ import RetentionPoliciesPage from 'src/retention_policies';
|
||||||
import DataExplorer from 'src/chronograf';
|
import DataExplorer from 'src/chronograf';
|
||||||
import DatabaseManager from 'src/database_manager';
|
import DatabaseManager from 'src/database_manager';
|
||||||
import SignUp from 'src/sign_up';
|
import SignUp from 'src/sign_up';
|
||||||
import {CreateSource, ManageSources} from 'src/sources';
|
import {CreateSource, SourceForm, ManageSources} from 'src/sources';
|
||||||
import {ClusterAccountsPage, ClusterAccountPage} from 'src/cluster_accounts';
|
import {ClusterAccountsPage, ClusterAccountPage} from 'src/cluster_accounts';
|
||||||
import {RolesPageContainer, RolePageContainer} from 'src/access_control';
|
import {RolesPageContainer, RolePageContainer} from 'src/access_control';
|
||||||
import NotFound from 'src/shared/components/NotFound';
|
import NotFound from 'src/shared/components/NotFound';
|
||||||
|
@ -100,6 +100,8 @@ const Root = React.createClass({
|
||||||
<Route path="/sources/:sourceID" component={App}>
|
<Route path="/sources/:sourceID" component={App}>
|
||||||
<Route component={CheckDataNodes}>
|
<Route component={CheckDataNodes}>
|
||||||
<Route path="manage-sources" component={ManageSources} />
|
<Route path="manage-sources" component={ManageSources} />
|
||||||
|
<Route path="manage-sources/new" component={SourceForm} />
|
||||||
|
<Route path="manage-sources/:id/edit" component={SourceForm} />
|
||||||
<Route path="queries" component={QueriesPage} />
|
<Route path="queries" component={QueriesPage} />
|
||||||
<Route path="accounts" component={ClusterAccountsPage} />
|
<Route path="accounts" component={ClusterAccountsPage} />
|
||||||
<Route path="accounts/:accountID" component={ClusterAccountPage} />
|
<Route path="accounts/:accountID" component={ClusterAccountPage} />
|
||||||
|
|
|
@ -6,17 +6,25 @@ export function getSources() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createSource({url, name, username, password, isDefault}) {
|
export function getSource(sourceID) {
|
||||||
|
return AJAX({
|
||||||
|
url: `/chronograf/v1/sources/${sourceID}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createSource(attributes) {
|
||||||
return AJAX({
|
return AJAX({
|
||||||
url: '/chronograf/v1/sources',
|
url: '/chronograf/v1/sources',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
data: {
|
data: attributes,
|
||||||
url,
|
});
|
||||||
name,
|
}
|
||||||
username,
|
|
||||||
password,
|
export function updateSource(newSource) {
|
||||||
'default': isDefault,
|
return AJAX({
|
||||||
},
|
url: newSource.links.self,
|
||||||
|
method: 'PATCH',
|
||||||
|
data: newSource,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -81,7 +81,7 @@ export const ManageSources = React.createClass({
|
||||||
}
|
}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<div className="btn btn-primary">Add</div>
|
<Link to={`/sources/1/manage-sources/new`} className="btn btn-primary">Add</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,138 @@
|
||||||
|
import React, {PropTypes} from 'react';
|
||||||
|
import {withRouter} from 'react-router';
|
||||||
|
import {getSource, createSource, updateSource} from 'shared/apis';
|
||||||
|
|
||||||
|
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,
|
||||||
|
addFlashMessage: PropTypes.func.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, params, addFlashMessage} = 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': this.sourceDefault.checked,
|
||||||
|
});
|
||||||
|
if (this.state.editMode) {
|
||||||
|
updateSource(newSource).then(() => {
|
||||||
|
router.push(`/sources/${params.sourceID}/manage-sources`);
|
||||||
|
addFlashMessage({type: 'success', text: 'The source was successfully updated'});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
createSource(newSource).then(() => {
|
||||||
|
router.push(`/sources/${params.sourceID}/manage-sources`);
|
||||||
|
addFlashMessage({type: 'success', text: 'The source was successfully created'});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
if (editMode && !source.id) {
|
||||||
|
return <div className="page-spinner"></div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
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-xs-offset-2">
|
||||||
|
<div className="checkbox">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" defaultChecked={source.default} ref={(r) => this.sourceDefault = r} />
|
||||||
|
Default source
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</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);
|
|
@ -1,3 +1,4 @@
|
||||||
import CreateSource from './containers/CreateSource';
|
import CreateSource from './containers/CreateSource';
|
||||||
|
import SourceForm from './containers/SourceForm';
|
||||||
import ManageSources from './containers/ManageSources';
|
import ManageSources from './containers/ManageSources';
|
||||||
export {CreateSource, ManageSources};
|
export {CreateSource, SourceForm, ManageSources};
|
||||||
|
|
Loading…
Reference in New Issue