Merge pull request #1929 from influxdata/bugfix/tr-abs-agb
Add nanosecond precision to :interval: calcpull/1951/merge
commit
3d2c012e72
25
CHANGELOG.md
25
CHANGELOG.md
|
@ -7,6 +7,7 @@
|
|||
### Features
|
||||
1. [#1928](https://github.com/influxdata/chronograf/pull/1928): Add prefix, suffix, scale, and other y-axis formatting
|
||||
1. [#1886](https://github.com/influxdata/chronograf/pull/1886): Fix limit of 100 alert rules on alert rules page
|
||||
1. [#1934](https://github.com/influxdata/chronograf/pull/1943): Zoom syncronization and enhancement
|
||||
|
||||
### UI Improvements
|
||||
1. [#1933](https://github.com/influxdata/chronograf/pull/1933): Use line-stacked graph type for memory information - thank you, @Joxit!
|
||||
|
@ -16,6 +17,30 @@
|
|||
1. [#1944](https://github.com/influxdata/chronograf/pull/1944): Improve UX of navigation to a sub-nav item in the navbar
|
||||
|
||||
## v1.3.7.0 [2017-08-23]
|
||||
## v1.3.7.0 [unreleased]
|
||||
### Features
|
||||
1. [#1928](https://github.com/influxdata/chronograf/pull/1928): Add prefix, suffix, scale, and other y-axis formatting
|
||||
|
||||
### UI Improvements
|
||||
|
||||
## v1.3.7.0
|
||||
### Bug Fixes
|
||||
1. [#1795](https://github.com/influxdata/chronograf/pull/1795): Fix uptime status on Windows hosts running Telegraf
|
||||
1. [#1715](https://github.com/influxdata/chronograf/pull/1715): Chronograf now renders on IE11.
|
||||
1. [#1870](https://github.com/influxdata/chronograf/pull/1870): Fix console error for placing prop on div
|
||||
1. [#1864](https://github.com/influxdata/chronograf/pull/1864): Fix Write Data form upload button and add `onDragExit` handler
|
||||
1. [#1891](https://github.com/influxdata/chronograf/pull/1891): Fix Kapacitor config for PagerDuty via the UI
|
||||
1. [#1872](https://github.com/influxdata/chronograf/pull/1872): Prevent stats in the legend from wrapping line
|
||||
|
||||
### Features
|
||||
1. [#1863](https://github.com/influxdata/chronograf/pull/1863): Improve 'new-sources' server flag example by adding 'type' key
|
||||
|
||||
### UI Improvements
|
||||
1. [#1862](https://github.com/influxdata/chronograf/pull/1862): Show "Add Graph" button on cells with no queries
|
||||
|
||||
## v1.3.6.1 [2017-08-14]
|
||||
**Upgrade Note** This release (1.3.6.1) fixes a possibly data corruption issue with dashboard cells' graph types. If you upgraded to 1.3.6.0 and visited any dashboard, once you have then upgraded to this release (1.3.6.1) you will need to manually reset the graph type for every cell via the cell's caret --> Edit --> Display Options. If you upgraded directly to 1.3.6.1, you should not experience this issue.
|
||||
|
||||
### Bug Fixes
|
||||
1. [#1795](https://github.com/influxdata/chronograf/pull/1795): Fix uptime status on Windows hosts running Telegraf
|
||||
1. [#1715](https://github.com/influxdata/chronograf/pull/1715): Chronograf now renders on IE11.
|
||||
|
|
|
@ -260,7 +260,7 @@ func (g *GroupByVar) parseRelative(fragment string) (time.Duration, error) {
|
|||
// example, the fragement "time > '1985-10-25T00:01:21-0800 and time <
|
||||
// '1985-10-25T00:01:22-0800'" would yield a duration of 1m'
|
||||
func (g *GroupByVar) parseAbsolute(fragment string) (time.Duration, error) {
|
||||
timePtn := `time\s[>|<]\s'([0-9\-TZ\:]+)'` // Playground: http://gobular.com/x/41a45095-c384-46ea-b73c-54ef91ab93af
|
||||
timePtn := `time\s[>|<]\s'([0-9\-T\:\.Z]+)'` // Playground: http://gobular.com/x/208f66bd-1889-4269-ab47-1efdfeeb63f0
|
||||
re, err := regexp.Compile(timePtn)
|
||||
if err != nil {
|
||||
// this is a developer error and should complain loudly
|
||||
|
|
|
@ -29,6 +29,13 @@ func Test_GroupByVar(t *testing.T) {
|
|||
1000,
|
||||
10 * time.Second,
|
||||
},
|
||||
{
|
||||
"absolute time with nano",
|
||||
"SELECT mean(usage_idle) FROM cpu WHERE time > '2017-07-24T15:33:42.994Z' and time < '2017-08-24T15:33:42.994Z' GROUP BY :interval:",
|
||||
744 * time.Hour,
|
||||
1000,
|
||||
10 * time.Second,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range gbvTests {
|
||||
|
|
|
@ -7,6 +7,7 @@ import FancyScrollbar from 'shared/components/FancyScrollbar'
|
|||
|
||||
const Dashboard = ({
|
||||
source,
|
||||
onZoom,
|
||||
dashboard,
|
||||
onAddCell,
|
||||
onEditCell,
|
||||
|
@ -71,6 +72,7 @@ const Dashboard = ({
|
|||
onDeleteCell={onDeleteCell}
|
||||
onSummonOverlayTechnologies={onSummonOverlayTechnologies}
|
||||
synchronizer={synchronizer}
|
||||
onZoom={onZoom}
|
||||
/>
|
||||
: <div className="dashboard__empty">
|
||||
<p>This Dashboard has no Cells</p>
|
||||
|
@ -127,6 +129,7 @@ Dashboard.propTypes = {
|
|||
onSelectTemplate: func.isRequired,
|
||||
showTemplateControlBar: bool,
|
||||
onCancelEditCell: func,
|
||||
onZoom: func,
|
||||
}
|
||||
|
||||
export default Dashboard
|
||||
|
|
|
@ -11,7 +11,8 @@ const DashboardHeader = ({
|
|||
buttonText,
|
||||
dashboard,
|
||||
headerText,
|
||||
timeRange,
|
||||
timeRange: {upper, lower},
|
||||
zoomedTimeRange: {zoomedLower, zoomedUpper},
|
||||
autoRefresh,
|
||||
isHidden,
|
||||
handleChooseTimeRange,
|
||||
|
@ -81,7 +82,10 @@ const DashboardHeader = ({
|
|||
/>
|
||||
<TimeRangeDropdown
|
||||
onChooseTimeRange={handleChooseTimeRange}
|
||||
selected={timeRange}
|
||||
selected={{
|
||||
upper: zoomedUpper || upper,
|
||||
lower: zoomedLower || lower,
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
className="btn btn-default btn-sm btn-square"
|
||||
|
@ -95,6 +99,13 @@ const DashboardHeader = ({
|
|||
|
||||
const {array, bool, func, number, shape, string} = PropTypes
|
||||
|
||||
DashboardHeader.defaultProps = {
|
||||
zoomedTimeRange: {
|
||||
zoomedLower: null,
|
||||
zoomedUpper: null,
|
||||
},
|
||||
}
|
||||
|
||||
DashboardHeader.propTypes = {
|
||||
sourceID: string,
|
||||
children: array,
|
||||
|
@ -115,6 +126,7 @@ DashboardHeader.propTypes = {
|
|||
onEditDashboard: func,
|
||||
onToggleTempVarControls: func,
|
||||
showTemplateControlBar: bool,
|
||||
zoomedTimeRange: shape({}),
|
||||
}
|
||||
|
||||
export default DashboardHeader
|
||||
|
|
|
@ -31,6 +31,7 @@ class DashboardPage extends Component {
|
|||
isEditMode: false,
|
||||
selectedCell: null,
|
||||
isTemplating: false,
|
||||
zoomedTimeRange: {zoomedLower: null, zoomedUpper: null},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -196,12 +197,19 @@ class DashboardPage extends Component {
|
|||
)
|
||||
}
|
||||
|
||||
handleZoomedTimeRange = (zoomedLower, zoomedUpper) => {
|
||||
this.setState({zoomedTimeRange: {zoomedLower, zoomedUpper}})
|
||||
}
|
||||
|
||||
getActiveDashboard() {
|
||||
const {params: {dashboardID}, dashboards} = this.props
|
||||
return dashboards.find(d => d.id === +dashboardID)
|
||||
}
|
||||
|
||||
render() {
|
||||
const {zoomedTimeRange} = this.state
|
||||
const {zoomedLower, zoomedUpper} = zoomedTimeRange
|
||||
|
||||
const {
|
||||
source,
|
||||
timeRange,
|
||||
|
@ -217,8 +225,11 @@ class DashboardPage extends Component {
|
|||
params: {sourceID, dashboardID},
|
||||
} = this.props
|
||||
|
||||
const lowerType = lower && lower.includes('Z') ? 'timeStamp' : 'constant'
|
||||
const upperType = upper && upper.includes('Z') ? 'timeStamp' : 'constant'
|
||||
const low = zoomedLower ? zoomedLower : lower
|
||||
const up = zoomedUpper ? zoomedUpper : upper
|
||||
|
||||
const lowerType = low && low.includes(':') ? 'timeStamp' : 'constant'
|
||||
const upperType = up && up.includes(':') ? 'timeStamp' : 'constant'
|
||||
|
||||
const dashboardTime = {
|
||||
id: 'dashtime',
|
||||
|
@ -226,7 +237,7 @@ class DashboardPage extends Component {
|
|||
type: lowerType,
|
||||
values: [
|
||||
{
|
||||
value: lower,
|
||||
value: low,
|
||||
type: lowerType,
|
||||
selected: true,
|
||||
},
|
||||
|
@ -239,7 +250,7 @@ class DashboardPage extends Component {
|
|||
type: upperType,
|
||||
values: [
|
||||
{
|
||||
value: upper || 'now()',
|
||||
value: up || 'now()',
|
||||
type: upperType,
|
||||
selected: true,
|
||||
},
|
||||
|
@ -310,6 +321,7 @@ class DashboardPage extends Component {
|
|||
sourceID={sourceID}
|
||||
dashboard={dashboard}
|
||||
timeRange={timeRange}
|
||||
zoomedTimeRange={zoomedTimeRange}
|
||||
autoRefresh={autoRefresh}
|
||||
isHidden={inPresentationMode}
|
||||
onAddCell={this.handleAddCell}
|
||||
|
@ -337,6 +349,7 @@ class DashboardPage extends Component {
|
|||
dashboard={dashboard}
|
||||
timeRange={timeRange}
|
||||
autoRefresh={autoRefresh}
|
||||
onZoom={this.handleZoomedTimeRange}
|
||||
onAddCell={this.handleAddCell}
|
||||
synchronizer={this.synchronizer}
|
||||
inPresentationMode={inPresentationMode}
|
||||
|
|
|
@ -3,6 +3,7 @@ import React, {Component, PropTypes} from 'react'
|
|||
import shallowCompare from 'react-addons-shallow-compare'
|
||||
|
||||
import _ from 'lodash'
|
||||
import moment from 'moment'
|
||||
|
||||
import Dygraphs from 'src/external/dygraph'
|
||||
import getRange from 'shared/parsing/getRangeForDygraph'
|
||||
|
@ -52,6 +53,7 @@ export default class Dygraph extends Component {
|
|||
isGraphFilled,
|
||||
isBarGraph,
|
||||
options,
|
||||
onZoom,
|
||||
} = this.props
|
||||
|
||||
const graphRef = this.graphRef
|
||||
|
@ -184,6 +186,13 @@ export default class Dygraph extends Component {
|
|||
}
|
||||
}
|
||||
},
|
||||
zoomCallback: (lower, upper) => {
|
||||
if (this.dygraph.isZoomed() === false) {
|
||||
return onZoom(null, null)
|
||||
}
|
||||
|
||||
onZoom(this.formatTimeRange(lower), this.formatTimeRange(upper))
|
||||
},
|
||||
}
|
||||
|
||||
if (isBarGraph) {
|
||||
|
@ -384,6 +393,14 @@ export default class Dygraph extends Component {
|
|||
this.dygraph.predraw_()
|
||||
}
|
||||
|
||||
formatTimeRange = timeRange => {
|
||||
if (!timeRange) {
|
||||
return ''
|
||||
}
|
||||
|
||||
return moment(timeRange).utc().format()
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
legend,
|
||||
|
@ -446,6 +463,7 @@ Dygraph.defaultProps = {
|
|||
isGraphFilled: true,
|
||||
overrideLineColors: null,
|
||||
dygraphRef: () => {},
|
||||
onZoom: () => {},
|
||||
}
|
||||
|
||||
Dygraph.propTypes = {
|
||||
|
@ -477,4 +495,5 @@ Dygraph.propTypes = {
|
|||
synchronizer: func,
|
||||
setResolution: func,
|
||||
dygraphRef: func,
|
||||
onZoom: func,
|
||||
}
|
||||
|
|
|
@ -148,6 +148,7 @@ class LayoutRenderer extends Component {
|
|||
templates,
|
||||
synchronizer,
|
||||
isEditable,
|
||||
onZoom,
|
||||
} = this.props
|
||||
|
||||
return cells.map(cell => {
|
||||
|
@ -176,6 +177,7 @@ class LayoutRenderer extends Component {
|
|||
queries={this.standardizeQueries(cell, source)}
|
||||
cellHeight={h}
|
||||
axes={axes}
|
||||
onZoom={onZoom}
|
||||
/>}
|
||||
</NameableGraph>
|
||||
</div>
|
||||
|
@ -303,6 +305,7 @@ LayoutRenderer.propTypes = {
|
|||
isStatusPage: bool,
|
||||
isEditable: bool,
|
||||
onCancelEditCell: func,
|
||||
onZoom: func,
|
||||
}
|
||||
|
||||
export default LayoutRenderer
|
||||
|
|
|
@ -46,6 +46,7 @@ export default React.createClass({
|
|||
synchronizer: func,
|
||||
setResolution: func,
|
||||
cellHeight: number,
|
||||
onZoom: func,
|
||||
},
|
||||
|
||||
getDefaultProps() {
|
||||
|
@ -101,6 +102,7 @@ export default React.createClass({
|
|||
synchronizer,
|
||||
timeRange,
|
||||
cellHeight,
|
||||
onZoom,
|
||||
} = this.props
|
||||
const {labels, timeSeries, dygraphSeries} = this._timeSeries
|
||||
|
||||
|
@ -176,6 +178,7 @@ export default React.createClass({
|
|||
synchronizer={synchronizer}
|
||||
timeRange={timeRange}
|
||||
setResolution={this.props.setResolution}
|
||||
onZoom={onZoom}
|
||||
/>
|
||||
{showSingleStat
|
||||
? <div className="single-stat single-stat-line">
|
||||
|
|
|
@ -10,6 +10,7 @@ const RefreshingSingleStat = AutoRefresh(SingleStat)
|
|||
const RefreshingGraph = ({
|
||||
axes,
|
||||
type,
|
||||
onZoom,
|
||||
queries,
|
||||
templates,
|
||||
timeRange,
|
||||
|
@ -46,6 +47,7 @@ const RefreshingGraph = ({
|
|||
synchronizer={synchronizer}
|
||||
editQueryStatus={editQueryStatus}
|
||||
axes={axes}
|
||||
onZoom={onZoom}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
@ -64,6 +66,7 @@ RefreshingGraph.propTypes = {
|
|||
axes: shape(),
|
||||
queries: arrayOf(shape()).isRequired,
|
||||
editQueryStatus: func,
|
||||
onZoom: func,
|
||||
}
|
||||
|
||||
export default RefreshingGraph
|
||||
|
|
|
@ -9,27 +9,21 @@ import CustomTimeRangeOverlay from 'shared/components/CustomTimeRangeOverlay'
|
|||
import timeRanges from 'hson!shared/data/timeRanges.hson'
|
||||
import {DROPDOWN_MENU_MAX_HEIGHT} from 'shared/constants/index'
|
||||
|
||||
const emptyTime = {lower: '', upper: ''}
|
||||
|
||||
class TimeRangeDropdown extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
const {lower, upper} = props.selected
|
||||
|
||||
super(props)
|
||||
const isTimeValid = moment(upper).isValid() && moment(lower).isValid()
|
||||
const customTimeRange = isTimeValid ? {lower, upper} : emptyTime
|
||||
|
||||
this.state = {
|
||||
autobind: false,
|
||||
isOpen: false,
|
||||
isCustomTimeRangeOpen: false,
|
||||
customTimeRange:
|
||||
moment(props.selected.upper).isValid() &&
|
||||
moment(props.selected.lower).isValid()
|
||||
? {
|
||||
lower,
|
||||
upper,
|
||||
}
|
||||
: {
|
||||
lower: '',
|
||||
upper: '',
|
||||
},
|
||||
customTimeRange,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue