Replace addFlashMessage with publishNotification

Also refactoring App.js into a SFC
pull/10616/head
Alex P 2018-03-03 17:08:50 -08:00 committed by Andrew Watkins
parent 9f85542d19
commit a14f860ef1
13 changed files with 479 additions and 82 deletions

View File

@ -1,43 +1,20 @@
import React, {Component} from 'react' import React from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import {connect} from 'react-redux'
import {bindActionCreators} from 'redux'
import SideNav from 'src/side_nav' import SideNav from 'src/side_nav'
import Notifications from 'shared/components/Notifications' import Notifications from 'shared/components/Notifications'
import {publishNotification as publishNotificationAction} from 'shared/actions/notifications' const App = ({children}) =>
<div className="chronograf-root">
<Notifications />
<SideNav />
{children}
</div>
class App extends Component { const {node} = PropTypes
notify = notification => {
const {publishNotification} = this.props
publishNotification(notification)
}
render() {
return (
<div className="chronograf-root">
<Notifications />
<SideNav />
{this.props.children &&
React.cloneElement(this.props.children, {
addFlashMessage: this.notify,
})}
</div>
)
}
}
const {func, node} = PropTypes
App.propTypes = { App.propTypes = {
children: node.isRequired, children: node.isRequired,
publishNotification: func.isRequired,
} }
const mapDispatchToProps = dispatch => ({ export default App
publishNotification: bindActionCreators(publishNotificationAction, dispatch),
})
export default connect(null, mapDispatchToProps)(App)

View File

@ -12,6 +12,7 @@ import ManualRefresh from 'src/shared/components/ManualRefresh'
import {getCpuAndLoadForHosts, getLayouts, getAppsForHosts} from '../apis' import {getCpuAndLoadForHosts, getLayouts, getAppsForHosts} from '../apis'
import {getEnv} from 'src/shared/apis/env' import {getEnv} from 'src/shared/apis/env'
import {setAutoRefresh} from 'shared/actions/app' import {setAutoRefresh} from 'shared/actions/app'
import {publishNotification as publishNotificationAction} from 'shared/actions/notifications'
class HostsPage extends Component { class HostsPage extends Component {
constructor(props) { constructor(props) {
@ -25,7 +26,7 @@ class HostsPage extends Component {
} }
async fetchHostsData() { async fetchHostsData() {
const {source, links, addFlashMessage} = this.props const {source, links, publishNotification} = this.props
const {telegrafSystemInterval} = await getEnv(links.environment) const {telegrafSystemInterval} = await getEnv(links.environment)
const hostsError = 'Unable to get hosts' const hostsError = 'Unable to get hosts'
try { try {
@ -51,7 +52,12 @@ class HostsPage extends Component {
}) })
} catch (error) { } catch (error) {
console.error(error) console.error(error)
addFlashMessage({type: 'error', text: hostsError}) publishNotification({
icon: 'alert-triangle',
type: 'danger',
duration: 5000,
message: hostsError,
})
this.setState({ this.setState({
hostsError, hostsError,
hostsLoading: false, hostsLoading: false,
@ -60,14 +66,19 @@ class HostsPage extends Component {
} }
async componentDidMount() { async componentDidMount() {
const {addFlashMessage, autoRefresh} = this.props const {publishNotification, autoRefresh} = this.props
this.setState({hostsLoading: true}) // Only print this once this.setState({hostsLoading: true}) // Only print this once
const {data} = await getLayouts() const {data} = await getLayouts()
this.layouts = data.layouts this.layouts = data.layouts
if (!this.layouts) { if (!this.layouts) {
const layoutError = 'Unable to get apps for hosts' const layoutError = 'Unable to get apps for hosts'
addFlashMessage({type: 'error', text: layoutError}) publishNotification({
icon: 'alert-triangle',
type: 'danger',
duration: 5000,
message: layoutError,
})
this.setState({ this.setState({
hostsError: layoutError, hostsError: layoutError,
hostsLoading: false, hostsLoading: false,
@ -169,11 +180,11 @@ HostsPage.propTypes = {
links: shape({ links: shape({
environment: string.isRequired, environment: string.isRequired,
}), }),
addFlashMessage: func,
autoRefresh: number.isRequired, autoRefresh: number.isRequired,
manualRefresh: number, manualRefresh: number,
onChooseAutoRefresh: func.isRequired, onChooseAutoRefresh: func.isRequired,
onManualRefresh: func.isRequired, onManualRefresh: func.isRequired,
publishNotification: func.isRequired,
} }
HostsPage.defaultProps = { HostsPage.defaultProps = {
@ -182,6 +193,7 @@ HostsPage.defaultProps = {
const mapDispatchToProps = dispatch => ({ const mapDispatchToProps = dispatch => ({
onChooseAutoRefresh: bindActionCreators(setAutoRefresh, dispatch), onChooseAutoRefresh: bindActionCreators(setAutoRefresh, dispatch),
publishNotification: bindActionCreators(publishNotificationAction, dispatch),
}) })
export default connect(mapStateToProps, mapDispatchToProps)( export default connect(mapStateToProps, mapDispatchToProps)(

View File

@ -176,7 +176,7 @@ export const deleteRule = rule => dispatch => {
}) })
.catch(() => { .catch(() => {
dispatch( dispatch(
publishNotification('error', `${rule.name} could not be deleted`) publishNotification('danger', `${rule.name} could not be deleted`)
) )
}) })
} }
@ -190,7 +190,7 @@ export const updateRuleStatus = (rule, status) => dispatch => {
}) })
.catch(() => { .catch(() => {
dispatch( dispatch(
publishNotification('error', `${rule.name} could not be ${status}`) publishNotification('danger', `${rule.name} could not be ${status}`)
) )
}) })
} }

View File

@ -1,6 +1,10 @@
import React, {Component} from 'react' import React, {Component} from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import {connect} from 'react-redux'
import {bindActionCreators} from 'redux'
import _ from 'lodash' import _ from 'lodash'
import {publishNotification as publishNotificationAction} from 'shared/actions/notifications'
import {Tab, Tabs, TabPanel, TabPanels, TabList} from 'shared/components/Tabs' import {Tab, Tabs, TabPanel, TabPanels, TabList} from 'shared/components/Tabs'
import { import {
@ -48,8 +52,10 @@ class AlertTabs extends Component {
this.setState({configSections: sections}) this.setState({configSections: sections})
} catch (error) { } catch (error) {
this.setState({configSections: null}) this.setState({configSections: null})
this.props.addFlashMessage({ this.props.publishNotification({
type: 'error', type: 'danger',
icon: 'alert-triangle',
duration: 10000,
text: 'There was an error getting the Kapacitor config', text: 'There was an error getting the Kapacitor config',
}) })
} }
@ -81,15 +87,19 @@ class AlertTabs extends Component {
propsToSend propsToSend
) )
this.refreshKapacitorConfig(this.props.kapacitor) this.refreshKapacitorConfig(this.props.kapacitor)
this.props.addFlashMessage({ this.props.publishNotification({
type: 'success', type: 'success',
icon: 'checkmark',
duration: 5000,
text: `Alert configuration for ${section} successfully saved.`, text: `Alert configuration for ${section} successfully saved.`,
}) })
return true return true
} catch ({data: {error}}) { } catch ({data: {error}}) {
const errorMsg = _.join(_.drop(_.split(error, ': '), 2), ': ') const errorMsg = _.join(_.drop(_.split(error, ': '), 2), ': ')
this.props.addFlashMessage({ this.props.publishNotification({
type: 'error', type: 'danger',
icon: 'alert-triangle',
duration: 10000,
text: `There was an error saving the alert configuration for ${section}: ${errorMsg}`, text: `There was an error saving the alert configuration for ${section}: ${errorMsg}`,
}) })
return false return false
@ -103,19 +113,25 @@ class AlertTabs extends Component {
try { try {
const {data} = await testAlertOutput(this.props.kapacitor, section) const {data} = await testAlertOutput(this.props.kapacitor, section)
if (data.success) { if (data.success) {
this.props.addFlashMessage({ this.props.publishNotification({
type: 'success', type: 'success',
icon: 'checkmark',
duration: 5000,
text: `Successfully triggered an alert to ${section}. If the alert does not reach its destination, please check your configuration settings.`, text: `Successfully triggered an alert to ${section}. If the alert does not reach its destination, please check your configuration settings.`,
}) })
} else { } else {
this.props.addFlashMessage({ this.props.publishNotification({
type: 'error', type: 'danger',
icon: 'alert-triangle',
duration: 10000,
text: `There was an error sending an alert to ${section}: ${data.message}`, text: `There was an error sending an alert to ${section}: ${data.message}`,
}) })
} }
} catch (error) { } catch (error) {
this.props.addFlashMessage({ this.props.publishNotification({
type: 'error', type: 'danger',
icon: 'alert-triangle',
duration: 10000,
text: `There was an error sending an alert to ${section}.`, text: `There was an error sending an alert to ${section}.`,
}) })
} }
@ -329,8 +345,12 @@ AlertTabs.propTypes = {
proxy: string.isRequired, proxy: string.isRequired,
}).isRequired, }).isRequired,
}), }),
addFlashMessage: func.isRequired, publishNotification: func.isRequired,
hash: string.isRequired, hash: string.isRequired,
} }
export default AlertTabs const mapDispatchToProps = dispatch => ({
publishNotification: bindActionCreators(publishNotificationAction, dispatch),
})
export default connect(null, mapDispatchToProps)(AlertTabs)

View File

@ -97,7 +97,6 @@ DataSection.propTypes = {
query: shape({ query: shape({
id: string.isRequired, id: string.isRequired,
}).isRequired, }).isRequired,
addFlashMessage: func,
actions: shape({ actions: shape({
chooseNamespace: func.isRequired, chooseNamespace: func.isRequired,
chooseMeasurement: func.isRequired, chooseMeasurement: func.isRequired,

View File

@ -0,0 +1,161 @@
import React, {Component, PropTypes} from 'react'
import AlertTabs from 'src/kapacitor/components/AlertTabs'
import FancyScrollbar from 'shared/components/FancyScrollbar'
class KapacitorForm extends Component {
render() {
const {
onInputChange,
onChangeUrl,
onReset,
kapacitor,
onSubmit,
exists,
} = 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 className="page-header__title">{`${exists
? 'Configure'
: 'Add a New'} Kapacitor Connection`}</h1>
</div>
</div>
</div>
<FancyScrollbar className="page-contents">
<div className="container-fluid">
<div className="row">
<div className="col-md-3">
<div className="panel">
<div className="panel-heading">
<h2 className="panel-title">Connection Details</h2>
</div>
<div className="panel-body">
<form onSubmit={onSubmit}>
<div>
<div className="form-group">
<label htmlFor="kapaUrl">Kapacitor URL</label>
<input
className="form-control"
id="kapaUrl"
name="kapaUrl"
placeholder={url}
value={url}
onChange={onChangeUrl}
spellCheck="false"
/>
</div>
<div className="form-group">
<label htmlFor="name">Name</label>
<input
className="form-control"
id="name"
name="name"
placeholder={name}
value={name}
onChange={onInputChange}
spellCheck="false"
maxLength="33"
/>
</div>
<div className="form-group">
<label htmlFor="username">Username</label>
<input
className="form-control"
id="username"
name="username"
placeholder="username"
value={username || ''}
onChange={onInputChange}
spellCheck="false"
/>
</div>
<div className="form-group">
<label htmlFor="password">Password</label>
<input
className="form-control"
id="password"
type="password"
name="password"
placeholder="password"
value={password || ''}
onChange={onInputChange}
spellCheck="false"
/>
</div>
</div>
<div className="form-group form-group-submit col-xs-12 text-center">
<button
className="btn btn-default"
type="button"
onClick={onReset}
>
Reset
</button>
<button className="btn btn-success" type="submit">
{exists ? 'Update' : 'Connect'}
</button>
</div>
</form>
</div>
</div>
</div>
<div className="col-md-9">
{this.renderAlertOutputs()}
</div>
</div>
</div>
</FancyScrollbar>
</div>
)
}
// TODO: move these to another page. they dont belong on this page
renderAlertOutputs() {
const {exists, kapacitor, source, hash} = this.props
if (exists) {
return <AlertTabs source={source} kapacitor={kapacitor} hash={hash} />
}
return (
<div className="panel">
<div className="panel-heading">
<h2 className="panel-title">Configure Alert Endpoints</h2>
</div>
<div className="panel-body">
<div className="generic-empty-state">
<h4 className="no-user-select">
Connect to an active Kapacitor instance to configure alerting
endpoints
</h4>
</div>
</div>
</div>
)
}
}
const {func, shape, string, bool} = PropTypes
KapacitorForm.propTypes = {
onSubmit: func.isRequired,
onInputChange: func.isRequired,
onChangeUrl: func.isRequired,
onReset: func.isRequired,
kapacitor: shape({
url: string.isRequired,
name: string.isRequired,
username: string,
password: string,
}).isRequired,
source: shape({}).isRequired,
exists: bool.isRequired,
hash: string.isRequired,
}
export default KapacitorForm

View File

@ -1,5 +1,7 @@
import React, {Component} from 'react' import React, {Component} from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import {connect} from 'react-redux'
import {bindActionCreators} from 'redux'
import NameSection from 'src/kapacitor/components/NameSection' import NameSection from 'src/kapacitor/components/NameSection'
import ValuesSection from 'src/kapacitor/components/ValuesSection' import ValuesSection from 'src/kapacitor/components/ValuesSection'
@ -12,6 +14,7 @@ import {createRule, editRule} from 'src/kapacitor/apis'
import buildInfluxQLQuery from 'utils/influxql' import buildInfluxQLQuery from 'utils/influxql'
import {timeRanges} from 'shared/data/timeRanges' import {timeRanges} from 'shared/data/timeRanges'
import {DEFAULT_RULE_ID} from 'src/kapacitor/constants' import {DEFAULT_RULE_ID} from 'src/kapacitor/constants'
import {publishNotification as publishNotificationAction} from 'shared/actions/notifications'
class KapacitorRule extends Component { class KapacitorRule extends Component {
constructor(props) { constructor(props) {
@ -28,7 +31,7 @@ class KapacitorRule extends Component {
handleCreate = pathname => { handleCreate = pathname => {
const { const {
addFlashMessage, publishNotification,
queryConfigs, queryConfigs,
rule, rule,
source, source,
@ -44,18 +47,25 @@ class KapacitorRule extends Component {
createRule(kapacitor, newRule) createRule(kapacitor, newRule)
.then(() => { .then(() => {
router.push(pathname || `/sources/${source.id}/alert-rules`) router.push(pathname || `/sources/${source.id}/alert-rules`)
addFlashMessage({type: 'success', text: 'Rule successfully created'}) publishNotification({
type: 'success',
icon: 'checkmark',
duration: 5000,
message: 'Rule successfully created',
})
}) })
.catch(() => { .catch(() => {
addFlashMessage({ publishNotification({
type: 'error', type: 'danger',
icon: 'alert-triangle',
duration: 10000,
text: 'There was a problem creating the rule', text: 'There was a problem creating the rule',
}) })
}) })
} }
handleEdit = pathname => { handleEdit = pathname => {
const {addFlashMessage, queryConfigs, rule, router, source} = this.props const {publishNotification, queryConfigs, rule, router, source} = this.props
const updatedRule = Object.assign({}, rule, { const updatedRule = Object.assign({}, rule, {
query: queryConfigs[rule.queryID], query: queryConfigs[rule.queryID],
}) })
@ -63,14 +73,18 @@ class KapacitorRule extends Component {
editRule(updatedRule) editRule(updatedRule)
.then(() => { .then(() => {
router.push(pathname || `/sources/${source.id}/alert-rules`) router.push(pathname || `/sources/${source.id}/alert-rules`)
addFlashMessage({ publishNotification({
type: 'success', type: 'success',
icon: 'checkmark',
duration: 5000,
text: `${rule.name} successfully saved!`, text: `${rule.name} successfully saved!`,
}) })
}) })
.catch(e => { .catch(e => {
addFlashMessage({ publishNotification({
type: 'error', type: 'danger',
icon: 'alert-triangle',
duration: 10000,
text: `There was a problem saving ${rule.name}: ${e.data.message}`, text: `There was a problem saving ${rule.name}: ${e.data.message}`,
}) })
}) })
@ -234,7 +248,7 @@ KapacitorRule.propTypes = {
queryConfigs: shape({}).isRequired, queryConfigs: shape({}).isRequired,
queryConfigActions: shape({}).isRequired, queryConfigActions: shape({}).isRequired,
ruleActions: shape({}).isRequired, ruleActions: shape({}).isRequired,
addFlashMessage: func.isRequired, publishNotification: func.isRequired,
ruleID: string.isRequired, ruleID: string.isRequired,
handlersFromConfig: arrayOf(shape({})).isRequired, handlersFromConfig: arrayOf(shape({})).isRequired,
router: shape({ router: shape({
@ -244,4 +258,8 @@ KapacitorRule.propTypes = {
configLink: string.isRequired, configLink: string.isRequired,
} }
export default KapacitorRule const mapDispatchToProps = dispatch => ({
publishNotification: bindActionCreators(publishNotificationAction, dispatch),
})
export default connect(null, mapDispatchToProps)(KapacitorRule)

View File

@ -0,0 +1,202 @@
import React, {Component, PropTypes} from 'react'
import {withRouter} from 'react-router'
import {connect} from 'react-redux'
import {bindActionCreators} from 'redux'
import {publishNotification as publishNotificationAction} from 'shared/actions/notifications'
import {
getKapacitor,
createKapacitor,
updateKapacitor,
pingKapacitor,
} from 'shared/apis'
import KapacitorForm from '../components/KapacitorForm'
const defaultName = 'My Kapacitor'
const kapacitorPort = '9092'
class KapacitorPage extends Component {
constructor(props) {
super(props)
this.state = {
kapacitor: {
url: this._parseKapacitorURL(),
name: defaultName,
username: '',
password: '',
},
exists: false,
}
}
componentDidMount() {
const {source, params: {id}} = this.props
if (!id) {
return
}
getKapacitor(source, id).then(kapacitor => {
this.setState({kapacitor})
this.checkKapacitorConnection(kapacitor)
})
}
checkKapacitorConnection = async kapacitor => {
try {
await pingKapacitor(kapacitor)
this.setState({exists: true})
} catch (error) {
this.setState({exists: false})
this.props.publishNotification({
type: 'danger',
icon: 'alert-triangle',
duration: 10000,
text: 'Could not connect to Kapacitor. Check settings.',
})
}
}
handleInputChange = e => {
const {value, name} = e.target
this.setState(prevState => {
const update = {[name]: value}
return {kapacitor: {...prevState.kapacitor, ...update}}
})
}
handleChangeUrl = ({value}) => {
this.setState({kapacitor: {...this.state.kapacitor, url: value}})
}
handleSubmit = e => {
e.preventDefault()
const {
publishNotification,
source,
source: {kapacitors = []},
params,
router,
} = this.props
const {kapacitor} = this.state
kapacitor.name = kapacitor.name.trim()
const isNameTaken = kapacitors.some(k => k.name === kapacitor.name)
const isNew = !params.id
if (isNew && isNameTaken) {
publishNotification({
type: 'danger',
icon: 'alert-triangle',
duration: 10000,
text: `There is already a Kapacitor configuration named "${kapacitor.name}"`,
})
return
}
if (params.id) {
updateKapacitor(kapacitor)
.then(({data}) => {
this.setState({kapacitor: data})
this.checkKapacitorConnection(data)
publishNotification({
type: 'success',
icon: 'checkmark',
duration: 5000,
message: 'Kapacitor Updated!',
})
})
.catch(() => {
publishNotification({
type: 'danger',
icon: 'alert-triangle',
duration: 10000,
text: 'There was a problem updating the Kapacitor record',
})
})
} else {
createKapacitor(source, kapacitor)
.then(({data}) => {
// need up update kapacitor with info from server to AlertOutputs
this.setState({kapacitor: data})
this.checkKapacitorConnection(data)
router.push(`/sources/${source.id}/kapacitors/${data.id}/edit`)
publishNotification({
type: 'success',
icon: 'checkmark',
duration: 5000,
text: 'Kapacitor Created! Configuring endpoints is optional.',
})
})
.catch(() => {
publishNotification({
type: 'danger',
icon: 'alert-triangle',
duration: 10000,
text: 'There was a problem creating the Kapacitor record',
})
})
}
}
handleResetToDefaults = e => {
e.preventDefault()
const defaultState = {
url: this._parseKapacitorURL(),
name: defaultName,
username: '',
password: '',
}
this.setState({kapacitor: {...defaultState}})
}
_parseKapacitorURL = () => {
const parser = document.createElement('a')
parser.href = this.props.source.url
return `${parser.protocol}//${parser.hostname}:${kapacitorPort}`
}
render() {
const {source, location, params} = this.props
const hash = (location && location.hash) || (params && params.hash) || ''
const {kapacitor, exists} = this.state
return (
<KapacitorForm
onSubmit={this.handleSubmit}
onInputChange={this.handleInputChange}
onChangeUrl={this.handleChangeUrl}
onReset={this.handleResetToDefaults}
kapacitor={kapacitor}
source={source}
exists={exists}
hash={hash}
/>
)
}
}
const {array, func, shape, string} = PropTypes
KapacitorPage.propTypes = {
publishNotification: func.isRequired,
params: shape({
id: string,
}).isRequired,
router: shape({
push: func.isRequired,
}).isRequired,
source: shape({
id: string.isRequired,
url: string.isRequired,
kapacitors: array,
}),
location: shape({pathname: string, hash: string}).isRequired,
}
const mapDispatchToProps = dispatch => ({
publishNotification: bindActionCreators(publishNotificationAction, dispatch),
})
export default connect(null, mapDispatchToProps)(withRouter(KapacitorPage))

View File

@ -10,6 +10,7 @@ import {getActiveKapacitor, getKapacitorConfig} from 'shared/apis/index'
import {DEFAULT_RULE_ID} from 'src/kapacitor/constants' import {DEFAULT_RULE_ID} from 'src/kapacitor/constants'
import KapacitorRule from 'src/kapacitor/components/KapacitorRule' import KapacitorRule from 'src/kapacitor/components/KapacitorRule'
import parseHandlersFromConfig from 'src/shared/parsing/parseHandlersFromConfig' import parseHandlersFromConfig from 'src/shared/parsing/parseHandlersFromConfig'
import {publishNotification as publishNotificationAction} from 'shared/actions/notifications'
class KapacitorRulePage extends Component { class KapacitorRulePage extends Component {
constructor(props) { constructor(props) {
@ -22,7 +23,7 @@ class KapacitorRulePage extends Component {
} }
async componentDidMount() { async componentDidMount() {
const {params, source, ruleActions, addFlashMessage} = this.props const {params, source, ruleActions, publishNotification} = this.props
if (params.ruleID === 'new') { if (params.ruleID === 'new') {
ruleActions.loadDefaultRule() ruleActions.loadDefaultRule()
@ -32,8 +33,10 @@ class KapacitorRulePage extends Component {
const kapacitor = await getActiveKapacitor(this.props.source) const kapacitor = await getActiveKapacitor(this.props.source)
if (!kapacitor) { if (!kapacitor) {
return addFlashMessage({ return publishNotification({
type: 'error', type: 'danger',
icon: 'alert-triangle',
duration: 10000,
text: "We couldn't find a configured Kapacitor for this source", // eslint-disable-line quotes text: "We couldn't find a configured Kapacitor for this source", // eslint-disable-line quotes
}) })
} }
@ -43,8 +46,10 @@ class KapacitorRulePage extends Component {
const handlersFromConfig = parseHandlersFromConfig(kapacitorConfig) const handlersFromConfig = parseHandlersFromConfig(kapacitorConfig)
this.setState({kapacitor, handlersFromConfig}) this.setState({kapacitor, handlersFromConfig})
} catch (error) { } catch (error) {
addFlashMessage({ publishNotification({
type: 'error', type: 'danger',
icon: 'alert-triangle',
duration: 10000,
text: 'There was a problem communicating with Kapacitor', text: 'There was a problem communicating with Kapacitor',
}) })
console.error(error) console.error(error)
@ -60,7 +65,6 @@ class KapacitorRulePage extends Component {
router, router,
ruleActions, ruleActions,
queryConfigs, queryConfigs,
addFlashMessage,
queryConfigActions, queryConfigActions,
} = this.props } = this.props
const {handlersFromConfig, kapacitor} = this.state const {handlersFromConfig, kapacitor} = this.state
@ -79,7 +83,6 @@ class KapacitorRulePage extends Component {
queryConfigs={queryConfigs} queryConfigs={queryConfigs}
queryConfigActions={queryConfigActions} queryConfigActions={queryConfigActions}
ruleActions={ruleActions} ruleActions={ruleActions}
addFlashMessage={addFlashMessage}
handlersFromConfig={handlersFromConfig} handlersFromConfig={handlersFromConfig}
ruleID={params.ruleID} ruleID={params.ruleID}
router={router} router={router}
@ -99,7 +102,7 @@ KapacitorRulePage.propTypes = {
self: string.isRequired, self: string.isRequired,
}), }),
}), }),
addFlashMessage: func, publishNotification: func,
rules: shape({}).isRequired, rules: shape({}).isRequired,
queryConfigs: shape({}).isRequired, queryConfigs: shape({}).isRequired,
ruleActions: shape({ ruleActions: shape({
@ -128,6 +131,7 @@ const mapStateToProps = ({rules, kapacitorQueryConfigs: queryConfigs}) => ({
const mapDispatchToProps = dispatch => ({ const mapDispatchToProps = dispatch => ({
ruleActions: bindActionCreators(kapacitorRuleActionCreators, dispatch), ruleActions: bindActionCreators(kapacitorRuleActionCreators, dispatch),
publishNotification: bindActionCreators(publishNotificationAction, dispatch),
queryConfigActions: bindActionCreators( queryConfigActions: bindActionCreators(
kapacitorQueryConfigActionCreators, kapacitorQueryConfigActionCreators,
dispatch dispatch

View File

@ -78,7 +78,6 @@ KapacitorRulesPage.propTypes = {
deleteRule: func.isRequired, deleteRule: func.isRequired,
updateRuleStatus: func.isRequired, updateRuleStatus: func.isRequired,
}).isRequired, }).isRequired,
addFlashMessage: func,
} }
const mapStateToProps = state => { const mapStateToProps = state => {

View File

@ -12,7 +12,6 @@ export const KapacitorTasksPage = React.createClass({
kapacitors: PropTypes.string.isRequired, kapacitors: PropTypes.string.isRequired,
}).isRequired, }).isRequired,
}).isRequired, }).isRequired,
addFlashMessage: PropTypes.func,
}, },
getInitialState() { getInitialState() {

View File

@ -72,7 +72,7 @@ export const removeAndLoadSources = source => async dispatch => {
dispatch(loadSources(newSources)) dispatch(loadSources(newSources))
} catch (err) { } catch (err) {
dispatch( dispatch(
publishNotification('error', 'Internal Server Error. Check API Logs') publishNotification('danger', 'Internal Server Error. Check API Logs')
) )
} }
} }
@ -84,7 +84,7 @@ export const fetchKapacitorsAsync = source => async dispatch => {
} catch (err) { } catch (err) {
dispatch( dispatch(
publishNotification( publishNotification(
'error', 'danger',
`Internal Server Error. Could not retrieve kapacitors for source ${source.id}.` `Internal Server Error. Could not retrieve kapacitors for source ${source.id}.`
) )
) )
@ -105,7 +105,7 @@ export const deleteKapacitorAsync = kapacitor => async dispatch => {
} catch (err) { } catch (err) {
dispatch( dispatch(
publishNotification( publishNotification(
'error', 'danger',
'Internal Server Error. Could not delete Kapacitor config.' 'Internal Server Error. Could not delete Kapacitor config.'
) )
) )

View File

@ -9,6 +9,7 @@ import {
setActiveKapacitorAsync, setActiveKapacitorAsync,
deleteKapacitorAsync, deleteKapacitorAsync,
} from 'shared/actions/sources' } from 'shared/actions/sources'
import {publishNotification as publishNotificationAction} from 'shared/actions/notifications'
import FancyScrollbar from 'shared/components/FancyScrollbar' import FancyScrollbar from 'shared/components/FancyScrollbar'
import SourceIndicator from 'shared/components/SourceIndicator' import SourceIndicator from 'shared/components/SourceIndicator'
@ -36,18 +37,22 @@ class ManageSources extends Component {
} }
handleDeleteSource = source => () => { handleDeleteSource = source => () => {
const {addFlashMessage} = this.props const {publishNotification} = this.props
try { try {
this.props.removeAndLoadSources(source) this.props.removeAndLoadSources(source)
addFlashMessage({ publishNotification({
type: 'success', type: 'success',
text: `Deleted source ${source.name}`, icon: 'checkmark',
duration: 5000,
message: `Deleted source ${source.name}`,
}) })
} catch (e) { } catch (e) {
addFlashMessage({ publishNotification({
type: 'error', type: 'danger',
text: 'Could not remove source from Chronograf', icon: 'alert-triangle',
duration: 10000,
message: 'Could not remove source from Chronograf',
}) })
} }
} }
@ -101,7 +106,7 @@ ManageSources.propTypes = {
}), }),
}), }),
sources: array, sources: array,
addFlashMessage: func, publishNotification: func.isRequired,
removeAndLoadSources: func.isRequired, removeAndLoadSources: func.isRequired,
fetchKapacitors: func.isRequired, fetchKapacitors: func.isRequired,
setActiveKapacitor: func.isRequired, setActiveKapacitor: func.isRequired,
@ -117,6 +122,7 @@ const mapDispatchToProps = dispatch => ({
fetchKapacitors: bindActionCreators(fetchKapacitorsAsync, dispatch), fetchKapacitors: bindActionCreators(fetchKapacitorsAsync, dispatch),
setActiveKapacitor: bindActionCreators(setActiveKapacitorAsync, dispatch), setActiveKapacitor: bindActionCreators(setActiveKapacitorAsync, dispatch),
deleteKapacitor: bindActionCreators(deleteKapacitorAsync, dispatch), deleteKapacitor: bindActionCreators(deleteKapacitorAsync, dispatch),
publishNotification: bindActionCreators(publishNotificationAction, dispatch),
}) })
export default connect(mapStateToProps, mapDispatchToProps)(ManageSources) export default connect(mapStateToProps, mapDispatchToProps)(ManageSources)