diff --git a/CHANGELOG.md b/CHANGELOG.md
index a438c2ef93..b253b64947 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -23,6 +23,7 @@
1. [#1209](https://github.com/influxdata/chronograf/pull/1209): HipChat Kapacitor config now uses only the subdomain instead of asking for the entire HipChat URL.
1. [#1219](https://github.com/influxdata/chronograf/pull/1219): Update query for default cell in new dashboard
1. [#1206](https://github.com/influxdata/chronograf/issues/1206): Chronograf now proxies to kapacitors behind proxy using vhost correctly.
+ 1. [#1205](https://github.com/influxdata/chronograf/pull/1205): Allow initial source to be an enterprise source.
### Features
1. [#1112](https://github.com/influxdata/chronograf/pull/1112): Add ability to delete a dashboard
diff --git a/ui/src/App.js b/ui/src/App.js
index fe4d3da391..33d4931249 100644
--- a/ui/src/App.js
+++ b/ui/src/App.js
@@ -1,18 +1,16 @@
import React, {PropTypes} from 'react'
import {connect} from 'react-redux'
-import classnames from 'classnames'
import SideNavContainer from 'src/side_nav'
+import Notifications from 'shared/components/Notifications'
import {
publishNotification as publishNotificationAction,
- dismissNotification as dismissNotificationAction,
- dismissAllNotifications as dismissAllNotificationsAction,
} from 'src/shared/actions/notifications'
const {
+ func,
node,
shape,
string,
- func,
} = PropTypes
const App = React.createClass({
@@ -24,99 +22,34 @@ const App = React.createClass({
params: shape({
sourceID: string.isRequired,
}).isRequired,
- publishNotification: func.isRequired,
- dismissNotification: func.isRequired,
- dismissAllNotifications: func.isRequired,
- notifications: shape({
- success: string,
- error: string,
- warning: string,
- }),
+ notify: func.isRequired,
},
- handleNotification({type, text}) {
- const validTypes = ['error', 'success', 'warning']
- if (!validTypes.includes(type) || text === undefined) {
- console.error("handleNotification must have a valid type and text") // eslint-disable-line no-console
- }
- this.props.publishNotification(type, text)
- },
+ handleAddFlashMessage({type, text}) {
+ const {notify} = this.props
- handleDismissNotification(type) {
- this.props.dismissNotification(type)
- },
-
- componentWillReceiveProps(nextProps) {
- if (nextProps.location.pathname !== this.props.location.pathname) {
- this.props.dismissAllNotifications()
- }
+ notify(type, text)
},
render() {
- const {params: {sourceID}} = this.props
+ const {params: {sourceID}, location} = this.props
return (
- {this.renderNotifications()}
+
{this.props.children && React.cloneElement(this.props.children, {
- addFlashMessage: this.handleNotification,
+ addFlashMessage: this.handleAddFlashMessage,
})}
)
},
-
- renderNotifications() {
- const {success, error, warning} = this.props.notifications
- if (!success && !error && !warning) {
- return null
- }
- return (
-
- {this.renderNotification('success', success)}
- {this.renderNotification('error', error)}
- {this.renderNotification('warning', warning)}
-
- )
- },
-
- renderNotification(type, message) {
- if (!message) {
- return null
- }
- const cls = classnames('alert', {
- 'alert-danger': type === 'error',
- 'alert-success': type === 'success',
- 'alert-warning': type === 'warning',
- })
- return (
-
- {message}{this.renderDismiss(type)}
-
- )
- },
-
- renderDismiss(type) {
- return (
-
- )
- },
})
-function mapStateToProps(state) {
- return {
- notifications: state.notifications,
- }
-}
-
-export default connect(mapStateToProps, {
- publishNotification: publishNotificationAction,
- dismissNotification: dismissNotificationAction,
- dismissAllNotifications: dismissAllNotificationsAction,
+export default connect(null, {
+ notify: publishNotificationAction,
})(App)
diff --git a/ui/src/shared/actions/notifications.js b/ui/src/shared/actions/notifications.js
index 52dfcf4e51..b3cfc87388 100644
--- a/ui/src/shared/actions/notifications.js
+++ b/ui/src/shared/actions/notifications.js
@@ -1,4 +1,10 @@
export function publishNotification(type, message) {
+ // this validator is purely for development purposes. It might make sense to move this to a middleware.
+ const validTypes = ['error', 'success', 'warning']
+ if (!validTypes.includes(type) || message === undefined) {
+ console.error("handleNotification must have a valid type and text") // eslint-disable-line no-console
+ }
+
return {
type: 'NOTIFICATION_RECEIVED',
payload: {
diff --git a/ui/src/shared/components/Notifications.js b/ui/src/shared/components/Notifications.js
new file mode 100644
index 0000000000..180ace259d
--- /dev/null
+++ b/ui/src/shared/components/Notifications.js
@@ -0,0 +1,98 @@
+import React, {Component, PropTypes} from 'react'
+import classnames from 'classnames'
+import {connect} from 'react-redux'
+import {bindActionCreators} from 'redux'
+
+import {
+ publishNotification as publishNotificationAction,
+ dismissNotification as dismissNotificationAction,
+ dismissAllNotifications as dismissAllNotificationsAction,
+} from 'src/shared/actions/notifications'
+
+class Notifications extends Component {
+ constructor(props) {
+ super(props)
+
+ this.renderNotification = ::this.renderNotification
+ this.renderDismiss = ::this.renderDismiss
+ }
+
+ componentWillReceiveProps(nextProps) {
+ if (nextProps.location.pathname !== this.props.location.pathname) {
+ this.props.dismissAllNotifications()
+ }
+ }
+
+ renderNotification(type, message) {
+ if (!message) {
+ return null
+ }
+ const cls = classnames('alert', {
+ 'alert-danger': type === 'error',
+ 'alert-success': type === 'success',
+ 'alert-warning': type === 'warning',
+ })
+ return (
+
+ {message}{this.renderDismiss(type)}
+
+ )
+ }
+
+ renderDismiss(type) {
+ const {dismissNotification} = this.props
+
+ return (
+
+ )
+ }
+
+ render() {
+ const {success, error, warning} = this.props.notifications
+ if (!success && !error && !warning) {
+ return null
+ }
+
+ return (
+
+ {this.renderNotification('success', success)}
+ {this.renderNotification('error', error)}
+ {this.renderNotification('warning', warning)}
+
+ )
+ }
+}
+
+const {
+ func,
+ shape,
+ string,
+} = PropTypes
+
+Notifications.propTypes = {
+ location: shape({
+ pathname: string,
+ }),
+ publishNotification: func.isRequired,
+ dismissNotification: func.isRequired,
+ dismissAllNotifications: func.isRequired,
+ notifications: shape({
+ success: string,
+ error: string,
+ warning: string,
+ }),
+}
+
+const mapStateToProps = ({notifications}) => ({
+ notifications,
+})
+
+const mapDispatchToProps = (dispatch) => ({
+ publishNotification: bindActionCreators(publishNotificationAction, dispatch),
+ dismissNotification: bindActionCreators(dismissNotificationAction, dispatch),
+ dismissAllNotifications: bindActionCreators(dismissAllNotificationsAction, dispatch),
+})
+
+export default connect(mapStateToProps, mapDispatchToProps)(Notifications)
diff --git a/ui/src/sources/components/SourceForm.js b/ui/src/sources/components/SourceForm.js
index dbb899d342..4c3ae3f9bf 100644
--- a/ui/src/sources/components/SourceForm.js
+++ b/ui/src/sources/components/SourceForm.js
@@ -11,9 +11,6 @@ const {
export const SourceForm = React.createClass({
propTypes: {
- addFlashMessage: func.isRequired,
- addSourceAction: func,
- updateSourceAction: func,
source: shape({}).isRequired,
editMode: bool.isRequired,
onInputChange: func.isRequired,
@@ -56,80 +53,55 @@ export const SourceForm = React.createClass({
render() {
const {source, editMode, onInputChange} = this.props
- if (editMode && !source.id) {
- return
- }
-
return (
-
-
-
-
-
- {editMode ? "Edit Source" : "Add a New Source"}
-
-
-
-
-
-
-
-
-
-
-
Connection Details
-
+
+
Connection Details
+
-
-
-
-
+
+ {_.get(source, 'url', '').startsWith("https") ?
+
+
+ this.sourceInsecureSkipVerify = r} />
+
+
+
+
: null}
+
+
+
+
)
},
diff --git a/ui/src/sources/containers/CreateSource.js b/ui/src/sources/containers/CreateSource.js
index 9e7e409e5d..8de5b2699c 100644
--- a/ui/src/sources/containers/CreateSource.js
+++ b/ui/src/sources/containers/CreateSource.js
@@ -1,36 +1,45 @@
import React, {PropTypes} from 'react'
import {withRouter} from 'react-router'
-import {addSource as addSourceAction} from 'src/shared/actions/sources'
-import {createSource} from 'shared/apis'
import {connect} from 'react-redux'
+import {bindActionCreators} from 'redux'
+
+import {
+ createSource as createSourceAJAX,
+ updateSource as updateSourceAJAX,
+} from 'shared/apis'
+import SourceForm from 'src/sources/components/SourceForm'
+import Notifications from 'shared/components/Notifications'
+import {
+ addSource as addSourceAction,
+ updateSource as updateSourceAction,
+} from 'src/shared/actions/sources'
+import {publishNotification} from 'src/shared/actions/notifications'
+
+const {
+ func,
+ shape,
+ string,
+} = PropTypes
export const CreateSource = React.createClass({
propTypes: {
- router: PropTypes.shape({
- push: PropTypes.func.isRequired,
+ router: shape({
+ push: func.isRequired,
}).isRequired,
- location: PropTypes.shape({
- query: PropTypes.shape({
- redirectPath: PropTypes.string,
+ location: shape({
+ query: shape({
+ redirectPath: string,
}).isRequired,
}).isRequired,
- addSourceAction: PropTypes.func,
+ addSource: func,
+ updateSource: func,
+ notify: func,
},
- handleNewSource(e) {
- e.preventDefault()
- const source = {
- url: this.sourceURL.value.trim(),
- name: this.sourceName.value,
- username: this.sourceUser.value,
- password: this.sourcePassword.value,
- isDefault: true,
- telegraf: this.sourceTelegraf.value,
+ getInitialState() {
+ return {
+ source: {},
}
- createSource(source).then(({data: sourceFromServer}) => {
- this.props.addSourceAction(sourceFromServer)
- this.redirectToApp(sourceFromServer)
- })
},
redirectToApp(source) {
@@ -43,47 +52,77 @@ export const CreateSource = React.createClass({
return this.props.router.push(fixedPath)
},
- render() {
- return (
-
-
-
-
-
-
-
Welcome to Chronograf
-
-
-
Connect to a New Source
-
+ handleInputChange(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})
+ })
+ },
-
+ handleBlurSourceURL(newSource) {
+ if (this.state.editMode) {
+ return
+ }
+
+ if (!newSource.url) {
+ return
+ }
+
+ // if there is a type on source it has already been created
+ if (newSource.type) {
+ return
+ }
+
+ createSourceAJAX(newSource).then(({data: sourceFromServer}) => {
+ this.props.addSource(sourceFromServer)
+ this.setState({source: sourceFromServer, error: null})
+ }).catch(({data: error}) => {
+ this.setState({error: error.message})
+ })
+ },
+
+ handleSubmit(newSource) {
+ const {error} = this.state
+ const {notify, updateSource} = this.props
+
+ if (error) {
+ return notify('error', error)
+ }
+
+ updateSourceAJAX(newSource).then(({data: sourceFromServer}) => {
+ updateSource(sourceFromServer)
+ this.redirectToApp(sourceFromServer)
+ }).catch(() => {
+ notify('error', 'There was a problem updating the source. Check the settings')
+ })
+ },
+
+ render() {
+ const {location} = this.props
+ const {source} = this.state
+
+ return (
+
+
+
+
+
+
+
+
+
Welcome to Chronograf
+
+
@@ -94,8 +133,12 @@ export const CreateSource = React.createClass({
},
})
-function mapStateToProps(_) {
- return {}
+function mapDispatchToProps(dispatch) {
+ return {
+ addSource: bindActionCreators(addSourceAction, dispatch),
+ updateSource: bindActionCreators(updateSourceAction, dispatch),
+ notify: bindActionCreators(publishNotification, dispatch),
+ }
}
-export default connect(mapStateToProps, {addSourceAction})(withRouter(CreateSource))
+export default connect(null, mapDispatchToProps)(withRouter(CreateSource))
diff --git a/ui/src/sources/containers/SourcePage.js b/ui/src/sources/containers/SourcePage.js
index 2a5b65b9b3..f9f259e6ec 100644
--- a/ui/src/sources/containers/SourcePage.js
+++ b/ui/src/sources/containers/SourcePage.js
@@ -78,7 +78,7 @@ export const SourcePage = React.createClass({
createSource(newSource).then(({data: sourceFromServer}) => {
this.props.addSourceAction(sourceFromServer)
- this.setState({source: sourceFromServer})
+ this.setState({source: sourceFromServer, error: null})
}).catch(({data: error}) => {
// dont want to flash this until they submit
this.setState({error: error.message})
@@ -105,22 +105,40 @@ export const SourcePage = React.createClass({
render() {
const {source, editMode} = this.state
- const {addFlashMessage, router, location, params} = this.props
+
+ if (editMode && !source.id) {
+ return
+ }
return (
-
+
+
+
+
+
+ {editMode ? "Edit Source" : "Add a New Source"}
+
+
+
+
+
+
)
},
})
diff --git a/ui/src/style/unsorted.scss b/ui/src/style/unsorted.scss
index e9de6eea6b..7dc087b49e 100644
--- a/ui/src/style/unsorted.scss
+++ b/ui/src/style/unsorted.scss
@@ -2,16 +2,6 @@
Unsorted
----------------------------------------------
*/
-.select-source-page {
- position: absolute;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- overflow: auto;
- @include custom-scrollbar($g2-kevlar, $c-pool);
- @include gradient-v($g2-kevlar, $g0-obsidian);
-}
.text-right .btn {
margin: 0 0 0 4px;
}