Merge branch 'master' into bugfix/bad-rp

pull/2130/head
Andrew Watkins 2017-10-19 08:53:01 -07:00 committed by GitHub
commit 380b3df7a1
6 changed files with 212 additions and 187 deletions

View File

@ -5,14 +5,19 @@
1. [#2093](https://github.com/influxdata/chronograf/pull/2093): Fix when exporting `SHOW DATABASES` CSV has bad data
1. [#2098](https://github.com/influxdata/chronograf/pull/2098): Fix not-equal-to highlighting in Kapacitor Rule Builder
1. [#2130](https://github.com/influxdata/chronograf/pull/2130): Fix undescriptive error messages for database and retention policy creation
1. [#2135](https://github.com/influxdata/chronograf/pull/2135): Fix drag and drop cancel button
### Features
1. [#2083](https://github.com/influxdata/chronograf/pull/2083): Every dashboard can now have its own time range
1. [#2045](https://github.com/influxdata/chronograf/pull/2045): Add CSV download option in dashboard cells
1. [#2133](https://github.com/influxdata/chronograf/pull/2133): Implicitly prepend source urls with http://
1. [#2127](https://github.com/influxdata/chronograf/pull/2127): Add support for graph zooming and point display on the millisecond-level
### UI Improvements
1. [#2111](https://github.com/influxdata/chronograf/pull/2111): Increase size of Cell Editor query tabs to reveal more of their query strings
1. [#2119](https://github.com/influxdata/chronograf/pull/2119): Add support for graph zooming and point display on the millisecond-level
1. [#2120](https://github.com/influxdata/chronograf/pull/2120): Improve appearance of Admin Page tabs on smaller screens
1. [#2119](https://github.com/influxdata/chronograf/pull/2119): Add cancel button to Tickscript editor
## v1.3.9.0 [2017-10-06]
### Bug Fixes

View File

@ -79,6 +79,10 @@ class WriteDataForm extends Component {
file = e.target.files[0]
}
if (!file) {
return
}
e.preventDefault()
e.stopPropagation()
@ -94,6 +98,7 @@ class WriteDataForm extends Component {
handleCancelFile = () => {
this.setState({uploadContent: ''})
this.fileInput.value = ''
}
handleDragOver = e => {

View File

@ -1,159 +1,139 @@
import React, {PropTypes, Component} from 'react'
import React, {PropTypes} from 'react'
import classnames from 'classnames'
import {insecureSkipVerifyText} from 'shared/copy/tooltipText'
import _ from 'lodash'
class SourceForm extends Component {
constructor(props) {
super(props)
}
const SourceForm = ({
source,
editMode,
onSubmit,
onInputChange,
onBlurSourceURL,
}) =>
<div className="panel-body">
<h4 className="text-center">Connection Details</h4>
<br />
handleBlurSourceURL = () => {
const url = this.props.source.url.trim()
if (!url) {
return
}
const newSource = {
...this.props.source,
url,
}
this.props.onBlurSourceURL(newSource)
}
render() {
const {source, editMode, onSubmit, onInputChange} = this.props
return (
<div className="panel-body">
<h4 className="text-center">Connection Details</h4>
<br />
<form onSubmit={onSubmit}>
<div className="form-group col-xs-12 col-sm-6">
<label htmlFor="connect-string">Connection String</label>
<form onSubmit={onSubmit}>
<div className="form-group col-xs-12 col-sm-6">
<label htmlFor="connect-string">Connection String</label>
<input
type="text"
name="url"
className="form-control"
id="connect-string"
placeholder="Address of InfluxDB"
onChange={onInputChange}
value={source.url}
onBlur={onBlurSourceURL}
required={true}
/>
</div>
<div className="form-group col-xs-12 col-sm-6">
<label htmlFor="name">Name</label>
<input
type="text"
name="name"
className="form-control"
id="name"
placeholder="Name this source"
onChange={onInputChange}
value={source.name}
required={true}
/>
</div>
<div className="form-group col-xs-12 col-sm-6">
<label htmlFor="username">Username</label>
<input
type="text"
name="username"
className="form-control"
id="username"
onChange={onInputChange}
value={source.username}
/>
</div>
<div className="form-group col-xs-12 col-sm-6">
<label htmlFor="password">Password</label>
<input
type="password"
name="password"
className="form-control"
id="password"
onChange={onInputChange}
value={source.password}
/>
</div>
{_.get(source, 'type', '').includes('enterprise')
? <div className="form-group col-xs-12">
<label htmlFor="meta-url">Meta Service Connection URL</label>
<input
type="text"
name="url"
name="metaUrl"
className="form-control"
id="connect-string"
placeholder="Address of InfluxDB"
id="meta-url"
placeholder="http://localhost:8091"
onChange={onInputChange}
value={source.url}
onBlur={this.handleBlurSourceURL}
required={true}
value={source.metaUrl}
/>
</div>
<div className="form-group col-xs-12 col-sm-6">
<label htmlFor="name">Name</label>
<input
type="text"
name="name"
className="form-control"
id="name"
placeholder="Name this source"
onChange={onInputChange}
value={source.name}
required={true}
/>
</div>
<div className="form-group col-xs-12 col-sm-6">
<label htmlFor="username">Username</label>
<input
type="text"
name="username"
className="form-control"
id="username"
onChange={onInputChange}
value={source.username}
/>
</div>
<div className="form-group col-xs-12 col-sm-6">
<label htmlFor="password">Password</label>
<input
type="password"
name="password"
className="form-control"
id="password"
onChange={onInputChange}
value={source.password}
/>
</div>
{_.get(source, 'type', '').includes('enterprise')
? <div className="form-group col-xs-12">
<label htmlFor="meta-url">Meta Service Connection URL</label>
<input
type="text"
name="metaUrl"
className="form-control"
id="meta-url"
placeholder="http://localhost:8091"
onChange={onInputChange}
value={source.metaUrl}
/>
</div>
: null}
<div className="form-group col-xs-12">
<label htmlFor="telegraf">Telegraf database</label>
<input
type="text"
name="telegraf"
className="form-control"
id="telegraf"
onChange={onInputChange}
value={source.telegraf}
/>
</div>
<div className="form-group col-xs-12">
: null}
<div className="form-group col-xs-12">
<label htmlFor="telegraf">Telegraf database</label>
<input
type="text"
name="telegraf"
className="form-control"
id="telegraf"
onChange={onInputChange}
value={source.telegraf}
/>
</div>
<div className="form-group col-xs-12">
<div className="form-control-static">
<input
type="checkbox"
id="defaultSourceCheckbox"
name="default"
checked={source.default}
onChange={onInputChange}
/>
<label htmlFor="defaultSourceCheckbox">
Make this the default source
</label>
</div>
</div>
{_.get(source, 'url', '').startsWith('https')
? <div className="form-group col-xs-12">
<div className="form-control-static">
<input
type="checkbox"
id="defaultSourceCheckbox"
name="default"
checked={source.default}
id="insecureSkipVerifyCheckbox"
name="insecureSkipVerify"
checked={source.insecureSkipVerify}
onChange={onInputChange}
/>
<label htmlFor="defaultSourceCheckbox">
Make this the default source
</label>
<label htmlFor="insecureSkipVerifyCheckbox">Unsafe SSL</label>
</div>
<label className="form-helper">
{insecureSkipVerifyText}
</label>
</div>
{_.get(source, 'url', '').startsWith('https')
? <div className="form-group col-xs-12">
<div className="form-control-static">
<input
type="checkbox"
id="insecureSkipVerifyCheckbox"
name="insecureSkipVerify"
checked={source.insecureSkipVerify}
onChange={onInputChange}
/>
<label htmlFor="insecureSkipVerifyCheckbox">Unsafe SSL</label>
</div>
<label className="form-helper">
{insecureSkipVerifyText}
</label>
</div>
: null}
<div className="form-group form-group-submit col-xs-12 col-sm-6 col-sm-offset-3 text-center">
<button
className={classnames('btn btn-block', {
'btn-primary': editMode,
'btn-success': !editMode,
})}
type="submit"
>
{editMode ? 'Save Changes' : 'Add Source'}
</button>
<br />
</div>
</form>
: null}
<div className="form-group form-group-submit col-xs-12 col-sm-6 col-sm-offset-3 text-center">
<button
className={classnames('btn btn-block', {
'btn-primary': editMode,
'btn-success': !editMode,
})}
type="submit"
>
{editMode ? 'Save Changes' : 'Add Source'}
</button>
<br />
</div>
)
}
}
</form>
</div>
const {bool, func, shape, string} = PropTypes

View File

@ -67,23 +67,56 @@ class SourcePage extends Component {
})
}
handleBlurSourceURL = newSource => {
if (this.state.editMode) {
handleBlurSourceURL = () => {
const {source, editMode} = this.state
if (editMode) {
this.setState(this._normalizeSource)
return
}
if (!newSource.url) {
if (!source.url) {
return
}
this.setState(this._normalizeSource, this._createSourceOnBlur)
}
handleSubmit = e => {
e.preventDefault()
const {isCreated, editMode} = this.state
const isNewSource = !editMode
if (!isCreated && isNewSource) {
return this.setState(this._normalizeSource, this._createSource)
}
this.setState(this._normalizeSource, this._updateSource)
}
handleError = (bannerText, err) => {
const {notify} = this.props
const error = this._parseError(err)
console.error('Error: ', error)
notify('error', `${bannerText}: ${error}`)
}
_normalizeSource({source}) {
const url = source.url.trim()
if (source.url.startsWith('http')) {
return {source: {...source, url}}
}
return {source: {...source, url: `http://${url}`}}
}
_createSourceOnBlur = () => {
const {source} = this.state
// if there is a type on source it has already been created
if (newSource.type) {
if (source.type) {
return
}
createSource(newSource)
createSource(source)
.then(({data: sourceFromServer}) => {
this.props.addSourceAction(sourceFromServer)
addSourceAction(sourceFromServer)
this.setState({
source: {...DEFAULT_SOURCE, ...sourceFromServer},
isCreated: true,
@ -91,31 +124,29 @@ class SourcePage extends Component {
})
.catch(err => {
// dont want to flash this until they submit
const error = this.parseError(err)
const error = this._parseError(err)
console.error('Error on source creation: ', error)
})
}
handleSubmit = e => {
e.preventDefault()
_createSource = () => {
const {source} = this.state
createSource(source)
.then(({data: sourceFromServer}) => {
addSourceAction(sourceFromServer)
this._redirect(sourceFromServer)
})
.catch(error => {
this.handleError('Unable to create source', error)
})
}
_updateSource = () => {
const {source} = this.state
const {notify} = this.props
const {isCreated, source, editMode} = this.state
const isNewSource = !editMode
if (!isCreated && isNewSource) {
return createSource(source)
.then(({data: sourceFromServer}) => {
this.props.addSourceAction(sourceFromServer)
this._redirect(sourceFromServer)
})
.catch(error => {
this.handleError('Unable to create source', error)
})
}
updateSource(source)
.then(({data: sourceFromServer}) => {
this.props.updateSourceAction(sourceFromServer)
updateSourceAction(sourceFromServer)
this._redirect(sourceFromServer)
notify('success', `New source ${source.name} added`)
})
@ -124,13 +155,6 @@ class SourcePage extends Component {
})
}
handleError = (bannerText, err) => {
const {notify} = this.props
const error = this.parseError(err)
console.error('Error: ', error)
notify('error', `${bannerText}: ${error}`)
}
_redirect = source => {
const {isInitialSource} = this.state
const {params, router} = this.props
@ -157,7 +181,7 @@ class SourcePage extends Component {
return router.push(fixedPath)
}
parseError = error => {
_parseError = error => {
return _.get(error, ['data', 'message'], error)
}

View File

@ -1,30 +1,21 @@
/*
Styles for Admin Pages
----------------------------------------------
----------------------------------------------------------------------------
*/
/*
Admin Tabs
----------------------------------------------
----------------------------------------------------------------------------
*/
.admin-tabs {
padding-right: 0;
& + div {padding-left: 0;}
}
.admin-tabs .btn-group {
margin: 0;
width: 100%;
display: flex;
flex-direction: column;
align-items: stretch;
.tab {
font-weight: 500 !important;
border-radius: $radius 0 0 $radius !important;
margin-bottom: 2px !important;
border-radius: $radius $radius 0 0 !important;
transition:
background-color 0.25s ease,
color 0.25s ease !important;
@ -32,7 +23,7 @@
text-align: left;
height: 60px !important;
line-height: 60px !important;
padding: 0 0 0 16px !important;
padding: 0 30px !important;
font-size: 17px;
background-color: transparent !important;
color: $g11-sidewalk !important;
@ -62,9 +53,29 @@
.panel-heading + .panel-body {padding-top: 0;}
}
/*
Responsive Layout for Admin Tabs on Small Screens
----------------------------------------------------------------------------
*/
@media screen and (min-width: 992px) {
.admin-tabs {
padding-right: 0px;
.btn-group {
flex-direction: column;
}
.btn-group .tab {
border-radius: $radius 0 0 $radius !important;
padding: 0 0 0 16px !important;
}
& + div {padding-left: 0px;}
}
}
/*
Admin Table
----------------------------------------------
----------------------------------------------------------------------------
*/
.admin-table .dropdown-toggle {
background-color: transparent;
@ -125,7 +136,7 @@ pre.admin-table--query {
/*
Database Manager
----------------------------------------------
----------------------------------------------------------------------------
*/
.db-manager {
margin-bottom: 8px;

View File

@ -168,7 +168,7 @@ $dash-graph-options-arrow: 8px;
position: relative;
height: $dash-graph-heading;
line-height: $dash-graph-heading;
width: calc(100% - 53px);
width: calc(100% - 78px);
padding-left: 10px;
transition: color 0.25s ease, background-color 0.25s ease,
border-color 0.25s ease;