Merge pull request #879 from influxdata/kap-defaults
Refactor Kapacitor Settings Pagepull/10616/head
commit
fe8756ad5c
|
@ -1,6 +1,9 @@
|
|||
## v1.2.0 [unreleased]
|
||||
|
||||
### Bug Fixes
|
||||
1. [#879](https://github.com/influxdata/chronograf/pull/879): Fix several kapacitor configuration page state bugs; [#875](https://github.com/influxdata/chronograf/issues/875), [#876](https://github.com/influxdata/chronograf/issues/876), [#878](https://github.com/influxdata/chronograf/issues/878)
|
||||
2. [#872](https://github.com/influxdata/chronograf/pull/872): Fix incorrect data source response
|
||||
|
||||
### Features
|
||||
### UI Improvements
|
||||
|
||||
|
|
|
@ -0,0 +1,146 @@
|
|||
import React, {PropTypes} from 'react';
|
||||
import AlertOutputs from './AlertOutputs';
|
||||
|
||||
const {
|
||||
func,
|
||||
shape,
|
||||
string,
|
||||
bool,
|
||||
} = PropTypes;
|
||||
|
||||
const KapacitorForm = React.createClass({
|
||||
propTypes: {
|
||||
onSubmit: func.isRequired,
|
||||
onInputChange: func.isRequired,
|
||||
onReset: func.isRequired,
|
||||
kapacitor: shape({
|
||||
url: string.isRequired,
|
||||
name: string.isRequired,
|
||||
username: string,
|
||||
password: string,
|
||||
}).isRequired,
|
||||
source: shape({}).isRequired,
|
||||
addFlashMessage: func.isRequired,
|
||||
exists: bool.isRequired,
|
||||
},
|
||||
|
||||
render() {
|
||||
const {onInputChange, onReset, kapacitor, source, onSubmit} = this.props;
|
||||
const {url, name, username, password} = kapacitor;
|
||||
|
||||
return (
|
||||
<div className="page">
|
||||
<div className="page-header">
|
||||
<div className="page-header__container">
|
||||
<div className="page-header__left">
|
||||
<h1>
|
||||
Configure Kapacitor
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="page-contents">
|
||||
<div className="container-fluid">
|
||||
<div className="row">
|
||||
<div className="col-md-8 col-md-offset-2">
|
||||
<div className="panel panel-minimal">
|
||||
<div className="panel-body">
|
||||
<p>
|
||||
Kapacitor is used as the monitoring and alerting agent.
|
||||
This page will let you configure which Kapacitor to use and
|
||||
set up alert end points like email, Slack, and others.
|
||||
</p>
|
||||
<hr/>
|
||||
<h4 className="text-center">Connect Kapacitor to Source</h4>
|
||||
<h4 className="text-center">{source.url}</h4>
|
||||
<br/>
|
||||
<form onSubmit={onSubmit}>
|
||||
<div>
|
||||
<div className="form-group col-xs-12 col-sm-8 col-sm-offset-2 col-md-4 col-md-offset-2">
|
||||
<label htmlFor="url">Kapacitor URL</label>
|
||||
<input
|
||||
className="form-control"
|
||||
id="url"
|
||||
name="url"
|
||||
placeholder={url}
|
||||
value={url}
|
||||
onChange={onInputChange}>
|
||||
</input>
|
||||
</div>
|
||||
<div className="form-group col-xs-12 col-sm-8 col-sm-offset-2 col-md-4 col-md-offset-0">
|
||||
<label htmlFor="name">Name</label>
|
||||
<input
|
||||
className="form-control"
|
||||
id="name"
|
||||
name="name"
|
||||
placeholder={name}
|
||||
value={name}
|
||||
onChange={onInputChange}>
|
||||
</input>
|
||||
</div>
|
||||
<div className="form-group col-xs-12 col-sm-4 col-sm-offset-2 col-md-4 col-md-offset-2">
|
||||
<label htmlFor="username">Username</label>
|
||||
<input
|
||||
className="form-control"
|
||||
id="username"
|
||||
name="username"
|
||||
placeholder="username"
|
||||
value={username}
|
||||
onChange={onInputChange}>
|
||||
</input>
|
||||
</div>
|
||||
<div className="form-group col-xs-12 col-sm-4 col-md-4">
|
||||
<label htmlFor="password">Password</label>
|
||||
<input
|
||||
className="form-control"
|
||||
id="password"
|
||||
type="password"
|
||||
name="password"
|
||||
placeholder="password"
|
||||
value={password}
|
||||
onChange={onInputChange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="form-group form-group-submit col-xs-12 text-center">
|
||||
<button className="btn btn-info" onClick={onReset}>Reset to Default</button>
|
||||
<button className="btn btn-success" type="submit">Connect Kapacitor</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="row">
|
||||
<div className="col-md-8 col-md-offset-2">
|
||||
{this.renderAlertOutputs()}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
|
||||
// TODO: move these to another page. they dont belong on this page
|
||||
renderAlertOutputs() {
|
||||
const {exists, kapacitor, addFlashMessage, source} = this.props;
|
||||
|
||||
if (exists) {
|
||||
return <AlertOutputs source={source} kapacitor={kapacitor} addFlashMessage={addFlashMessage} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="panel panel-minimal">
|
||||
<div className="panel-body">
|
||||
<h4 className="text-center">Configure Alert Endpoints</h4>
|
||||
<br/>
|
||||
<p className="text-center">Set your Kapacitor connection info to configure alerting endpoints.</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
export default KapacitorForm;
|
|
@ -1,36 +1,50 @@
|
|||
import React, {PropTypes} from 'react';
|
||||
import {getKapacitor, getKapacitorConfigSection, createKapacitor, updateKapacitor, pingKapacitor} from 'shared/apis';
|
||||
import AlertOutputs from '../components/AlertOutputs';
|
||||
// default values for name & url
|
||||
const defaultKapacitorName = "My Kapacitor";
|
||||
const defaultKapacitorUrl = "http://localhost:9092";
|
||||
import {
|
||||
getKapacitor,
|
||||
createKapacitor,
|
||||
updateKapacitor,
|
||||
pingKapacitor,
|
||||
} from 'shared/apis';
|
||||
import KapacitorForm from '../components/KapacitorForm';
|
||||
|
||||
const defaultName = "My Kapacitor";
|
||||
const kapacitorPort = "9092";
|
||||
|
||||
const {
|
||||
func,
|
||||
shape,
|
||||
string,
|
||||
} = PropTypes;
|
||||
|
||||
export const KapacitorPage = React.createClass({
|
||||
propTypes: {
|
||||
source: PropTypes.shape({
|
||||
id: PropTypes.string.isRequired,
|
||||
source: shape({
|
||||
id: string.isRequired,
|
||||
url: string.isRequired,
|
||||
}),
|
||||
addFlashMessage: PropTypes.func,
|
||||
addFlashMessage: func,
|
||||
},
|
||||
|
||||
getInitialState() {
|
||||
return {
|
||||
kapacitor: null,
|
||||
canConnect: false,
|
||||
kapacitor: {
|
||||
url: this._parseKapacitorURL(),
|
||||
name: defaultName,
|
||||
username: '',
|
||||
password: '',
|
||||
},
|
||||
exists: false,
|
||||
};
|
||||
},
|
||||
|
||||
componentDidMount() {
|
||||
this.fetchKapacitor();
|
||||
},
|
||||
|
||||
fetchKapacitor() {
|
||||
const {source} = this.props;
|
||||
getKapacitor(source).then((kapacitor) => {
|
||||
if (!kapacitor) {
|
||||
return;
|
||||
}
|
||||
this.setState({kapacitor}, () => {
|
||||
|
||||
this.setState({kapacitor, exists: true}, () => {
|
||||
pingKapacitor(kapacitor).catch(() => {
|
||||
this.props.addFlashMessage({type: 'error', text: 'Could not connect to Kapacitor. Check settings.'});
|
||||
});
|
||||
|
@ -38,176 +52,73 @@ export const KapacitorPage = React.createClass({
|
|||
});
|
||||
},
|
||||
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
if (!prevState.kapacitor || !this.state.kapacitor) {
|
||||
return;
|
||||
}
|
||||
if (prevState.kapacitor.url !== this.state.kapacitor.url) {
|
||||
this.checkKapacitorSetup();
|
||||
}
|
||||
render() {
|
||||
const {source, addFlashMessage} = this.props;
|
||||
const {kapacitor, exists} = this.state;
|
||||
|
||||
return (
|
||||
<KapacitorForm
|
||||
onSubmit={this.handleSubmit}
|
||||
onInputChange={this.handleInputChange}
|
||||
onReset={this.handleResetToDefaults}
|
||||
kapacitor={kapacitor}
|
||||
source={source}
|
||||
addFlashMessage={addFlashMessage}
|
||||
exists={exists}
|
||||
/>
|
||||
);
|
||||
},
|
||||
|
||||
checkKapacitorSetup() {
|
||||
const {addFlashMessage, source} = this.props;
|
||||
getKapacitorConfigSection(this.state.kapacitor, 'influxdb').then(({data: {elements}}) => {
|
||||
const sourceMatch = elements[0].options.urls.some((url) => url === source.url);
|
||||
if (!sourceMatch) {
|
||||
addFlashMessage({type: 'warning', text: `Warning: Kapacitor is configured to use an instance of InfluxDB which does not match the URL of your current source. Please ensure your InfluxDB source and Kapacitor's InfluxDB configuration point to the same server.`});
|
||||
}
|
||||
}).catch(() => {
|
||||
addFlashMessage({type: 'error', text: `Could not connect to Kapacitor. Check connection settings.`});
|
||||
handleInputChange(e) {
|
||||
const val = e.target.value;
|
||||
const name = e.target.name;
|
||||
|
||||
this.setState((prevState) => {
|
||||
const update = {[name]: val.trim()};
|
||||
return {kapacitor: {...prevState.kapacitor, ...update}};
|
||||
});
|
||||
},
|
||||
|
||||
handleKapacitorUpdate(e) {
|
||||
|
||||
handleSubmit(e) {
|
||||
e.preventDefault();
|
||||
if (this.state.kapacitor) {
|
||||
this.handleUpdateKapacitor();
|
||||
} else {
|
||||
this.handleCreateKapacitor();
|
||||
}
|
||||
},
|
||||
|
||||
handleCreateKapacitor() {
|
||||
const {addFlashMessage, source} = this.props;
|
||||
const {newURL, newName, newUsername} = this.state;
|
||||
createKapacitor(source, {
|
||||
url: newURL.trim(),
|
||||
name: newName.trim(),
|
||||
username: newUsername,
|
||||
password: this.kapacitorPassword.value,
|
||||
}).then(({data: createdKapacitor}) => {
|
||||
addFlashMessage({type: 'success', text: 'Kapacitor Created!'});
|
||||
this.setState({kapacitor: createdKapacitor});
|
||||
}).catch(() => {
|
||||
this.props.addFlashMessage({type: 'error', text: 'There was a problem creating the Kapacitor record'});
|
||||
});
|
||||
},
|
||||
const {kapacitor, exists} = this.state;
|
||||
|
||||
handleUpdateKapacitor() {
|
||||
const {addFlashMessage} = this.props;
|
||||
const {kapacitor, newURL, newName, newUsername} = this.state;
|
||||
updateKapacitor(kapacitor, {
|
||||
url: (newURL || kapacitor.url).trim(),
|
||||
name: (newName || kapacitor.name).trim(),
|
||||
username: newUsername || kapacitor.username,
|
||||
password: this.kapacitorPassword.value,
|
||||
}).then(({data: newKapacitor}) => {
|
||||
if (exists) {
|
||||
updateKapacitor(kapacitor).then(() => {
|
||||
addFlashMessage({type: 'success', text: 'Kapacitor Updated!'});
|
||||
this.setState({kapacitor: newKapacitor});
|
||||
}).catch(() => {
|
||||
addFlashMessage({type: 'error', text: 'There was a problem updating the Kapacitor record'});
|
||||
});
|
||||
},
|
||||
|
||||
updateName() {
|
||||
this.setState({newName: this.kapacitorName.value});
|
||||
},
|
||||
|
||||
updateURL() {
|
||||
this.setState({newURL: this.kapacitorURL.value});
|
||||
},
|
||||
|
||||
updateUsername() {
|
||||
this.setState({newUsername: this.kapacitorUser.value});
|
||||
} else {
|
||||
createKapacitor(source, kapacitor).then(({data}) => {
|
||||
// need up update kapacitor with info from server to AlertOutputs
|
||||
this.setState({kapacitor: data, exists: true});
|
||||
addFlashMessage({type: 'success', text: 'Kapacitor Created!'});
|
||||
}).catch(() => {
|
||||
addFlashMessage({type: 'error', text: 'There was a problem creating the Kapacitor record'});
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
handleResetToDefaults(e) {
|
||||
e.preventDefault();
|
||||
this.setState({
|
||||
newURL: defaultKapacitorUrl,
|
||||
newName: defaultKapacitorName,
|
||||
});
|
||||
const defaultState = {
|
||||
url: this._parseKapacitorURL(),
|
||||
name: defaultName,
|
||||
username: '',
|
||||
password: '',
|
||||
};
|
||||
|
||||
this.setState({kapacitor: {...defaultState}});
|
||||
},
|
||||
|
||||
render() {
|
||||
const {kapacitor, newName, newURL, newUsername} = this.state;
|
||||
// if the fields in state are defined, use them. otherwise use the defaults
|
||||
const name = newName === undefined ? kapacitor && kapacitor.name || defaultKapacitorName : newName;
|
||||
const url = newURL === undefined ? kapacitor && kapacitor.url || defaultKapacitorUrl : newURL;
|
||||
const username = newUsername === undefined ? kapacitor && kapacitor.username || '' : newUsername;
|
||||
_parseKapacitorURL() {
|
||||
const parser = document.createElement('a');
|
||||
parser.href = this.props.source.url;
|
||||
|
||||
|
||||
return (
|
||||
<div className="page">
|
||||
<div className="page-header">
|
||||
<div className="page-header__container">
|
||||
<div className="page-header__left">
|
||||
<h1>
|
||||
Configure Kapacitor
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="page-contents">
|
||||
<div className="container-fluid">
|
||||
<div className="row">
|
||||
<div className="col-md-8 col-md-offset-2">
|
||||
<div className="panel panel-minimal">
|
||||
<div className="panel-body">
|
||||
<p>
|
||||
Kapacitor is used as the monitoring and alerting agent.
|
||||
This page will let you configure which Kapacitor to use and
|
||||
set up alert end points like email, Slack, and others.
|
||||
</p>
|
||||
<hr/>
|
||||
<h4 className="text-center">Connection Details</h4>
|
||||
<br/>
|
||||
<form onSubmit={this.handleKapacitorUpdate}>
|
||||
<div>
|
||||
<div className="form-group col-xs-12 col-sm-8 col-sm-offset-2 col-md-4 col-md-offset-2">
|
||||
<label htmlFor="connect-string">Connection String</label>
|
||||
<input ref={(r) => this.kapacitorURL = r} className="form-control" id="connect-string" placeholder={defaultKapacitorUrl} value={url} onChange={this.updateURL}></input>
|
||||
</div>
|
||||
<div className="form-group col-xs-12 col-sm-8 col-sm-offset-2 col-md-4 col-md-offset-0">
|
||||
<label htmlFor="name">Name</label>
|
||||
<input ref={(r) => this.kapacitorName = r} className="form-control" id="name" placeholder={defaultKapacitorName} value={name} onChange={this.updateName}></input>
|
||||
</div>
|
||||
<div className="form-group col-xs-12 col-sm-4 col-sm-offset-2 col-md-4 col-md-offset-2">
|
||||
<label htmlFor="username">Username</label>
|
||||
<input ref={(r) => this.kapacitorUser = r} className="form-control" id="username" value={username} onChange={this.updateUsername}></input>
|
||||
</div>
|
||||
<div className="form-group col-xs-12 col-sm-4 col-md-4">
|
||||
<label htmlFor="password">Password</label>
|
||||
<input ref={(r) => this.kapacitorPassword = r} className="form-control" id="password" type="password"></input>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="form-group form-group-submit col-xs-12 text-center">
|
||||
<button className="btn btn-info" onClick={this.handleResetToDefaults}>Reset to Default</button>
|
||||
<button className="btn btn-success" type="submit">Connect Kapacitor</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="row">
|
||||
<div className="col-md-8 col-md-offset-2">
|
||||
{this.renderAlertOutputs()}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
|
||||
renderAlertOutputs() {
|
||||
const {kapacitor} = this.state;
|
||||
if (kapacitor) {
|
||||
return <AlertOutputs source={this.props.source} kapacitor={kapacitor} addFlashMessage={this.props.addFlashMessage} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="panel panel-minimal">
|
||||
<div className="panel-body">
|
||||
<h4 className="text-center">Configure Alert Endpoints</h4>
|
||||
<br/>
|
||||
<p className="text-center">Set your Kapacitor connection info to configure alerting endpoints.</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
return `${parser.protocol}//${parser.hostname}:${kapacitorPort}`;
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
@ -78,9 +78,9 @@ export function createKapacitor(source, {url, name = 'My Kapacitor', username, p
|
|||
});
|
||||
}
|
||||
|
||||
export function updateKapacitor(kapacitor, {url, name = 'My Kapacitor', username, password}) {
|
||||
export function updateKapacitor({links, url, name = 'My Kapacitor', username, password}) {
|
||||
return AJAX({
|
||||
url: kapacitor.links.self,
|
||||
url: links.self,
|
||||
method: 'PATCH',
|
||||
data: {
|
||||
name,
|
||||
|
|
Loading…
Reference in New Issue