Provide better feedback on unhappy paths for Kapacitor configuration

pull/546/head
Will Piers 2016-11-14 14:23:13 -08:00
parent 485bd4f637
commit dc5f41b5e7
3 changed files with 52 additions and 26 deletions

View File

@ -16,6 +16,7 @@ const AlertOutputs = React.createClass({
id: PropTypes.string.isRequired, id: PropTypes.string.isRequired,
}).isRequired, }).isRequired,
kapacitor: PropTypes.shape({ kapacitor: PropTypes.shape({
url: PropTypes.string.isRequired,
links: PropTypes.shape({ links: PropTypes.shape({
proxy: PropTypes.string.isRequired, proxy: PropTypes.string.isRequired,
}).isRequired, }).isRequired,
@ -31,14 +32,21 @@ const AlertOutputs = React.createClass({
}, },
componentDidMount() { componentDidMount() {
this.refreshKapacitorConfig(); this.refreshKapacitorConfig(this.props.kapacitor);
}, },
refreshKapacitorConfig() { componentWillReceiveProps(nextProps) {
getKapacitorConfig(this.props.kapacitor).then(({data: {sections}}) => { if (this.props.kapacitor.url !== nextProps.kapacitor.url) {
this.refreshKapacitorConfig(nextProps.kapacitor);
}
},
refreshKapacitorConfig(kapacitor) {
getKapacitorConfig(kapacitor).then(({data: {sections}}) => {
this.setState({configSections: sections}); this.setState({configSections: sections});
}).catch(() => { }).catch(() => {
this.props.addFlashMessage({type: 'error', text: `There was an error getting the kapacitor config`}); this.setState({configSections: null});
this.props.addFlashMessage({type: 'error', text: `There was an error getting the Kapacitor config`});
}); });
}, },
@ -50,7 +58,7 @@ const AlertOutputs = React.createClass({
if (section !== '') { if (section !== '') {
const propsToSend = this.sanitizeProperties(section, properties); const propsToSend = this.sanitizeProperties(section, properties);
updateKapacitorConfigSection(this.props.kapacitor, section, propsToSend).then(() => { updateKapacitorConfigSection(this.props.kapacitor, section, propsToSend).then(() => {
this.refreshKapacitorConfig(); this.refreshKapacitorConfig(this.props.kapacitor);
this.props.addFlashMessage({type: 'success', text: `Alert for ${section} successfully saved`}); this.props.addFlashMessage({type: 'success', text: `Alert for ${section} successfully saved`});
}).catch(() => { }).catch(() => {
this.props.addFlashMessage({type: 'error', text: `There was an error saving the kapacitor config`}); this.props.addFlashMessage({type: 'error', text: `There was an error saving the kapacitor config`});
@ -87,6 +95,11 @@ const AlertOutputs = React.createClass({
}, },
render() { render() {
const {configSections, selectedEndpoint} = this.state;
if (!configSections) { // could use this state to conditionally render spinner or error message
return null;
}
return ( return (
<div className="panel-body"> <div className="panel-body">
<h4 className="text-center">Alert Endpoints</h4> <h4 className="text-center">Alert Endpoints</h4>
@ -107,7 +120,7 @@ const AlertOutputs = React.createClass({
</div> </div>
</div> </div>
<div className="row"> <div className="row">
{this.renderAlertConfig(this.state.selectedEndpoint)} {this.renderAlertConfig(selectedEndpoint)}
</div> </div>
</div> </div>
</div> </div>
@ -115,6 +128,7 @@ const AlertOutputs = React.createClass({
}, },
renderAlertConfig(endpoint) { renderAlertConfig(endpoint) {
const {configSections} = this.state;
const save = (properties) => { const save = (properties) => {
this.handleSaveConfig(endpoint, properties); this.handleSaveConfig(endpoint, properties);
}; };
@ -122,11 +136,6 @@ const AlertOutputs = React.createClass({
this.handleTest(endpoint, properties); this.handleTest(endpoint, properties);
}; };
const {configSections} = this.state;
if (!configSections) { // could use this state to conditionally render spinner or error message
return null;
}
switch (endpoint) { switch (endpoint) {
case 'alerta': { case 'alerta': {
return <AlertaConfig onSave={save} config={this.getSection(configSections, endpoint)} />; return <AlertaConfig onSave={save} config={this.getSection(configSections, endpoint)} />;

View File

@ -1,5 +1,5 @@
import React, {PropTypes} from 'react'; import React, {PropTypes} from 'react';
import {getKapacitor, createKapacitor, updateKapacitor, pingKapacitor} from 'shared/apis'; import {getKapacitor, getKapacitorConfigSection, createKapacitor, updateKapacitor, pingKapacitor} from 'shared/apis';
import AlertOutputs from '../components/AlertOutputs'; import AlertOutputs from '../components/AlertOutputs';
export const KapacitorPage = React.createClass({ export const KapacitorPage = React.createClass({
@ -35,6 +35,27 @@ 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();
}
},
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.`});
});
},
handleKapacitorUpdate(e) { handleKapacitorUpdate(e) {
e.preventDefault(); e.preventDefault();
if (this.state.kapacitor) { if (this.state.kapacitor) {
@ -45,7 +66,7 @@ export const KapacitorPage = React.createClass({
}, },
handleCreateKapacitor() { handleCreateKapacitor() {
const {source} = this.props; const {addFlashMessage, source} = this.props;
const {newURL, newName, newUsername} = this.state; const {newURL, newName, newUsername} = this.state;
createKapacitor(source, { createKapacitor(source, {
url: newURL.trim(), url: newURL.trim(),
@ -53,7 +74,7 @@ export const KapacitorPage = React.createClass({
username: newUsername, username: newUsername,
password: this.kapacitorPassword.value, password: this.kapacitorPassword.value,
}).then(({data: createdKapacitor}) => { }).then(({data: createdKapacitor}) => {
this.props.addFlashMessage({type: 'success', text: 'Kapacitor Created!'}); addFlashMessage({type: 'success', text: 'Kapacitor Created!'});
this.setState({kapacitor: createdKapacitor}); this.setState({kapacitor: createdKapacitor});
}).catch(() => { }).catch(() => {
this.props.addFlashMessage({type: 'error', text: 'There was a problem creating the Kapacitor record'}); this.props.addFlashMessage({type: 'error', text: 'There was a problem creating the Kapacitor record'});
@ -61,7 +82,7 @@ export const KapacitorPage = React.createClass({
}, },
handleUpdateKapacitor() { handleUpdateKapacitor() {
const {addFlashMessage, source} = this.props; const {addFlashMessage} = this.props;
const {kapacitor, newURL, newName, newUsername} = this.state; const {kapacitor, newURL, newName, newUsername} = this.state;
updateKapacitor(kapacitor, { updateKapacitor(kapacitor, {
url: (newURL || kapacitor.url).trim(), url: (newURL || kapacitor.url).trim(),
@ -69,16 +90,8 @@ export const KapacitorPage = React.createClass({
username: newUsername || kapacitor.username, username: newUsername || kapacitor.username,
password: this.kapacitorPassword.value, password: this.kapacitorPassword.value,
}).then(({data: newKapacitor}) => { }).then(({data: newKapacitor}) => {
pingKapacitor(kapacitor).then(({data: {elements}}) => { addFlashMessage({type: 'success', text: 'Kapacitor Updated!'});
this.setState({kapacitor: newKapacitor}); this.setState({kapacitor: newKapacitor});
const sourceMatch = elements[0].options.urls.some((url) => url === source.url);
if (!sourceMatch && kapacitor.url !== newKapacitor.url) {
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.`});
}
addFlashMessage({type: 'success', text: 'Kapacitor Saved!'});
}).catch(() => {
this.props.addFlashMessage({type: 'error', text: 'Kapacitor Saved, but cannot connect. Check settings.'});
});
}).catch(() => { }).catch(() => {
addFlashMessage({type: 'error', text: 'There was a problem updating the Kapacitor record'}); addFlashMessage({type: 'error', text: 'There was a problem updating the Kapacitor record'});
}); });

View File

@ -38,7 +38,7 @@ export function deleteSource(source) {
export function pingKapacitor(kapacitor) { export function pingKapacitor(kapacitor) {
return AJAX({ return AJAX({
method: 'GET', method: 'GET',
url: `${kapacitor.links.proxy}?path=/kapacitor/v1/config/influxdb`, url: `${kapacitor.links.proxy}?path=/kapacitor/v1/ping`,
}); });
} }
@ -81,6 +81,10 @@ export function getKapacitorConfig(kapacitor) {
return kapacitorProxy(kapacitor, 'GET', '/kapacitor/v1/config', ''); return kapacitorProxy(kapacitor, 'GET', '/kapacitor/v1/config', '');
} }
export function getKapacitorConfigSection(kapacitor, section) {
return kapacitorProxy(kapacitor, 'GET', `/kapacitor/v1/config/${section}`, '');
}
export function updateKapacitorConfigSection(kapacitor, section, properties) { export function updateKapacitorConfigSection(kapacitor, section, properties) {
return AJAX({ return AJAX({
method: 'POST', method: 'POST',