Merge branch 'master' into dropdown-autocomplete
commit
39754aa28a
|
@ -2,15 +2,18 @@
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
1. [#1450](https://github.com/influxdata/chronograf/pull/1450): Fix infinite spinner when using "/chronograf" as a basepath
|
1. [#1450](https://github.com/influxdata/chronograf/pull/1450): Fix infinite spinner when using "/chronograf" as a basepath
|
||||||
|
1. [#1458](https://github.com/influxdata/chronograf/pull/1458): New versions of Chronograf will automatically clear localStorage settings until further notice.
|
||||||
1. [#1455](https://github.com/influxdata/chronograf/issues/1455): Fix backwards sort arrows in tables
|
1. [#1455](https://github.com/influxdata/chronograf/issues/1455): Fix backwards sort arrows in tables
|
||||||
1. [#1423](https://github.com/influxdata/chronograf/issues/1423): Make logout nav item consistent with design
|
1. [#1423](https://github.com/influxdata/chronograf/issues/1423): Make logout nav item consistent with design
|
||||||
1. [#1426](https://github.com/influxdata/chronograf/issues/1426): Fix graph loading spinner
|
1. [#1426](https://github.com/influxdata/chronograf/issues/1426): Fix graph loading spinner
|
||||||
1. [#1485](https://github.com/influxdata/chronograf/issues/1485): Filter out any template variable values that are empty, whitespace, or duplicates
|
1. [#1485](https://github.com/influxdata/chronograf/pull/1485): Filter out any template variable values that are empty, whitespace, or duplicates
|
||||||
|
1. [#1484](https://github.com/influxdata/chronograf/pull/1484): Allow user to select SingleStat as Visualization Type before adding any queries and continue to be able to click Add Query
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
1. [#1477](https://github.com/influxdata/chronograf/pull/1477): Add ability to log alerts
|
1. [#1477](https://github.com/influxdata/chronograf/pull/1477): Add ability to log alerts
|
||||||
1. [#1491](https://github.com/influxdata/chronograf/pull/1491): Update go vendoring to dep and committed vendor directory
|
1. [#1491](https://github.com/influxdata/chronograf/pull/1491): Update go vendoring to dep and committed vendor directory
|
||||||
1. [#1500](https://github.com/influxdata/chronograf/pull/1500): Add autocomplete functionality to Template Variable dropdowns
|
1. [#1500](https://github.com/influxdata/chronograf/pull/1500): Add autocomplete functionality to Template Variable dropdowns
|
||||||
|
1. [#1498](https://github.com/influxdata/chronograf/pull/1498): Notify user via UI when local settings are cleared
|
||||||
|
|
||||||
### UI Improvements
|
### UI Improvements
|
||||||
1. [#1451](https://github.com/influxdata/chronograf/pull/1451): Refactor scrollbars to support non-webkit browsers
|
1. [#1451](https://github.com/influxdata/chronograf/pull/1451): Refactor scrollbars to support non-webkit browsers
|
||||||
|
|
|
@ -21,6 +21,10 @@ func Convert(influxQL string) (chronograf.QueryConfig, error) {
|
||||||
return chronograf.QueryConfig{}, err
|
return chronograf.QueryConfig{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if itsDashboardTime {
|
||||||
|
influxQL = strings.Replace(influxQL, "now() - 15m", ":dashboardTime:", 1)
|
||||||
|
}
|
||||||
|
|
||||||
raw := chronograf.QueryConfig{
|
raw := chronograf.QueryConfig{
|
||||||
RawText: &influxQL,
|
RawText: &influxQL,
|
||||||
Fields: []chronograf.Field{},
|
Fields: []chronograf.Field{},
|
||||||
|
|
|
@ -43,7 +43,7 @@ const VisView = ({
|
||||||
if (cellType === 'single-stat') {
|
if (cellType === 'single-stat') {
|
||||||
return (
|
return (
|
||||||
<RefreshingSingleStat
|
<RefreshingSingleStat
|
||||||
queries={[queries[0]]}
|
queries={queries.length ? [queries[0]] : []}
|
||||||
autoRefresh={autoRefresh}
|
autoRefresh={autoRefresh}
|
||||||
templates={templates}
|
templates={templates}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -40,6 +40,8 @@ import 'src/style/chronograf.scss'
|
||||||
|
|
||||||
import {HEARTBEAT_INTERVAL} from 'shared/constants'
|
import {HEARTBEAT_INTERVAL} from 'shared/constants'
|
||||||
|
|
||||||
|
const errorsQueue = []
|
||||||
|
|
||||||
const rootNode = document.getElementById('react-root')
|
const rootNode = document.getElementById('react-root')
|
||||||
|
|
||||||
const basepath = rootNode.dataset.basepath || ''
|
const basepath = rootNode.dataset.basepath || ''
|
||||||
|
@ -48,7 +50,7 @@ const browserHistory = useRouterHistory(createHistory)({
|
||||||
basename: basepath, // this is written in when available by the URL prefixer middleware
|
basename: basepath, // this is written in when available by the URL prefixer middleware
|
||||||
})
|
})
|
||||||
|
|
||||||
const store = configureStore(loadLocalStorage(), browserHistory)
|
const store = configureStore(loadLocalStorage(errorsQueue), browserHistory)
|
||||||
const {dispatch} = store
|
const {dispatch} = store
|
||||||
|
|
||||||
browserHistory.listen(() => {
|
browserHistory.listen(() => {
|
||||||
|
@ -67,6 +69,7 @@ const history = syncHistoryWithStore(browserHistory, store)
|
||||||
|
|
||||||
const Root = React.createClass({
|
const Root = React.createClass({
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
|
this.flushErrorsQueue()
|
||||||
this.checkAuth()
|
this.checkAuth()
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -99,6 +102,14 @@ const Root = React.createClass({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
flushErrorsQueue() {
|
||||||
|
if (errorsQueue.length) {
|
||||||
|
errorsQueue.forEach(errorText => {
|
||||||
|
dispatch(errorThrown({status: 0, auth: null}, errorText, 'warning'))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
|
|
|
@ -1,10 +1,30 @@
|
||||||
export const loadLocalStorage = () => {
|
export const loadLocalStorage = errorsQueue => {
|
||||||
try {
|
try {
|
||||||
const serializedState = localStorage.getItem('state')
|
const serializedState = localStorage.getItem('state')
|
||||||
|
|
||||||
return JSON.parse(serializedState) || {}
|
const state = JSON.parse(serializedState)
|
||||||
} catch (err) {
|
|
||||||
console.error(`Loading persisted state failed: ${err}`) // eslint-disable-line no-console
|
// eslint-disable-next-line no-undef
|
||||||
|
if (state.VERSION !== VERSION) {
|
||||||
|
const errorText =
|
||||||
|
'New version of Chronograf detected. Local settings cleared.'
|
||||||
|
|
||||||
|
console.log(errorText) // eslint-disable-line no-console
|
||||||
|
errorsQueue.push(errorText)
|
||||||
|
|
||||||
|
window.localStorage.removeItem('state')
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete state.VERSION
|
||||||
|
|
||||||
|
return state || {}
|
||||||
|
} catch (error) {
|
||||||
|
const errorText = `Loading local settings failed: ${error}`
|
||||||
|
|
||||||
|
console.error(errorText) // eslint-disable-line no-console
|
||||||
|
errorsQueue.push(errorText)
|
||||||
|
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,6 +45,7 @@ export const saveToLocalStorage = ({
|
||||||
queryConfigs,
|
queryConfigs,
|
||||||
timeRange,
|
timeRange,
|
||||||
dataExplorer,
|
dataExplorer,
|
||||||
|
VERSION, // eslint-disable-line no-undef
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
export const errorThrown = (error, altText) => ({
|
export const errorThrown = (error, altText, alertType) => ({
|
||||||
type: 'ERROR_THROWN',
|
type: 'ERROR_THROWN',
|
||||||
error,
|
error,
|
||||||
altText,
|
altText,
|
||||||
|
alertType,
|
||||||
})
|
})
|
||||||
|
|
|
@ -32,7 +32,7 @@ export const handleSuccess = (data, query, editQueryStatus) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const handleError = (error, query, editQueryStatus) => {
|
export const handleError = (error, query, editQueryStatus) => {
|
||||||
const message = _.get(error, ['data', 'message'], error)
|
const message = _.get(error, ['data', 'message'], error.toString())
|
||||||
|
|
||||||
// 400 from chrono server = fail
|
// 400 from chrono server = fail
|
||||||
editQueryStatus(query.id, {error: message})
|
editQueryStatus(query.id, {error: message})
|
||||||
|
|
|
@ -17,7 +17,7 @@ const errorsMiddleware = store => next => action => {
|
||||||
const {auth: {me}} = store.getState()
|
const {auth: {me}} = store.getState()
|
||||||
|
|
||||||
if (action.type === 'ERROR_THROWN') {
|
if (action.type === 'ERROR_THROWN') {
|
||||||
const {error: {status, auth}, altText} = action
|
const {error: {status, auth}, altText, alertType = 'error'} = action
|
||||||
|
|
||||||
if (status === HTTP_FORBIDDEN) {
|
if (status === HTTP_FORBIDDEN) {
|
||||||
const wasSessionTimeout = me !== null
|
const wasSessionTimeout = me !== null
|
||||||
|
@ -26,7 +26,7 @@ const errorsMiddleware = store => next => action => {
|
||||||
|
|
||||||
if (wasSessionTimeout) {
|
if (wasSessionTimeout) {
|
||||||
store.dispatch(
|
store.dispatch(
|
||||||
notify('error', 'Session timed out. Please login again.')
|
notify(alertType, 'Session timed out. Please login again.')
|
||||||
)
|
)
|
||||||
|
|
||||||
allowNotifications = false
|
allowNotifications = false
|
||||||
|
@ -35,9 +35,9 @@ const errorsMiddleware = store => next => action => {
|
||||||
}, notificationsBlackoutDuration)
|
}, notificationsBlackoutDuration)
|
||||||
}
|
}
|
||||||
} else if (altText) {
|
} else if (altText) {
|
||||||
store.dispatch(notify('error', altText))
|
store.dispatch(notify(alertType, altText))
|
||||||
} else {
|
} else {
|
||||||
store.dispatch(notify('error', 'Cannot communicate with server.'))
|
store.dispatch(notify(alertType, 'Cannot communicate with server.'))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue