Merge branch 'master' into condense-de-lists
commit
232cf73707
|
@ -2,9 +2,14 @@
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
1. [#1364](https://github.com/influxdata/chronograf/pull/1364): Fix link to home when using the --basepath option
|
1. [#1364](https://github.com/influxdata/chronograf/pull/1364): Fix link to home when using the --basepath option
|
||||||
|
1. [#1370](https://github.com/influxdata/chronograf/pull/1370): Remove notification to login outside of session timeout
|
||||||
|
1. [#1376](https://github.com/influxdata/chronograf/pull/1376): Fix queries built in query builder with math functions in fields
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
### UI Improvements
|
### UI Improvements
|
||||||
|
1. [#1378](https://github.com/influxdata/chronograf/pull/1378): Save query time range for dashboards
|
||||||
1. [#1365](https://github.com/influxdata/chronograf/pull/1365): Show red indicator on Hosts Page for an offline host
|
1. [#1365](https://github.com/influxdata/chronograf/pull/1365): Show red indicator on Hosts Page for an offline host
|
||||||
|
1. [#1373](https://github.com/influxdata/chronograf/pull/1373): Re-address dashboard cell stacking contexts
|
||||||
|
|
||||||
## v1.2.0-beta10 [2017-04-28]
|
## v1.2.0-beta10 [2017-04-28]
|
||||||
|
|
||||||
|
|
|
@ -289,6 +289,12 @@ type GroupBy struct {
|
||||||
Tags []string `json:"tags"`
|
Tags []string `json:"tags"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DurationRange represents the lower and upper durations of the query config
|
||||||
|
type DurationRange struct {
|
||||||
|
Upper string `json:"upper"`
|
||||||
|
Lower string `json:"lower"`
|
||||||
|
}
|
||||||
|
|
||||||
// QueryConfig represents UI query from the data explorer
|
// QueryConfig represents UI query from the data explorer
|
||||||
type QueryConfig struct {
|
type QueryConfig struct {
|
||||||
ID string `json:"id,omitempty"`
|
ID string `json:"id,omitempty"`
|
||||||
|
@ -300,6 +306,7 @@ type QueryConfig struct {
|
||||||
GroupBy GroupBy `json:"groupBy"`
|
GroupBy GroupBy `json:"groupBy"`
|
||||||
AreTagsAccepted bool `json:"areTagsAccepted"`
|
AreTagsAccepted bool `json:"areTagsAccepted"`
|
||||||
RawText *string `json:"rawText"`
|
RawText *string `json:"rawText"`
|
||||||
|
Range *DurationRange `json:"range"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// KapacitorNode adds arguments and properties to an alert
|
// KapacitorNode adds arguments and properties to an alert
|
||||||
|
|
107
influx/query.go
107
influx/query.go
|
@ -2,6 +2,7 @@ package influx
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/influxdata/chronograf"
|
"github.com/influxdata/chronograf"
|
||||||
"github.com/influxdata/influxdb/influxql"
|
"github.com/influxdata/influxdb/influxql"
|
||||||
|
@ -102,6 +103,8 @@ func Convert(influxQL string) (chronograf.QueryConfig, error) {
|
||||||
fields := map[string][]string{}
|
fields := map[string][]string{}
|
||||||
for _, fld := range stmt.Fields {
|
for _, fld := range stmt.Fields {
|
||||||
switch f := fld.Expr.(type) {
|
switch f := fld.Expr.(type) {
|
||||||
|
default:
|
||||||
|
return raw, nil
|
||||||
case *influxql.Call:
|
case *influxql.Call:
|
||||||
// only support certain query config functions
|
// only support certain query config functions
|
||||||
if _, ok := supportedFuncs[f.Name]; !ok {
|
if _, ok := supportedFuncs[f.Name]; !ok {
|
||||||
|
@ -172,6 +175,14 @@ func Convert(influxQL string) (chronograf.QueryConfig, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the condition has a time range we report back its duration
|
||||||
|
if dur, ok := hasTimeRange(stmt.Condition); ok {
|
||||||
|
qc.Range = &chronograf.DurationRange{
|
||||||
|
Lower: shortDur(dur),
|
||||||
|
Upper: "now",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return qc, nil
|
return qc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,31 +211,36 @@ func isNow(exp influxql.Expr) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func isDuration(exp influxql.Expr) bool {
|
func isDuration(exp influxql.Expr) (time.Duration, bool) {
|
||||||
switch e := exp.(type) {
|
switch e := exp.(type) {
|
||||||
case *influxql.ParenExpr:
|
case *influxql.ParenExpr:
|
||||||
return isDuration(e.Expr)
|
return isDuration(e.Expr)
|
||||||
case *influxql.DurationLiteral, *influxql.NumberLiteral, *influxql.IntegerLiteral, *influxql.TimeLiteral:
|
case *influxql.DurationLiteral:
|
||||||
return true
|
return e.Val, true
|
||||||
|
case *influxql.NumberLiteral, *influxql.IntegerLiteral, *influxql.TimeLiteral:
|
||||||
|
return 0, false
|
||||||
}
|
}
|
||||||
return false
|
return 0, false
|
||||||
}
|
}
|
||||||
|
|
||||||
func isPreviousTime(exp influxql.Expr) bool {
|
func isPreviousTime(exp influxql.Expr) (time.Duration, bool) {
|
||||||
if p, ok := exp.(*influxql.ParenExpr); ok {
|
if p, ok := exp.(*influxql.ParenExpr); ok {
|
||||||
return isPreviousTime(p.Expr)
|
return isPreviousTime(p.Expr)
|
||||||
} else if bin, ok := exp.(*influxql.BinaryExpr); ok {
|
} else if bin, ok := exp.(*influxql.BinaryExpr); ok {
|
||||||
now := isNow(bin.LHS) || isNow(bin.RHS) // either side can be now
|
now := isNow(bin.LHS) || isNow(bin.RHS) // either side can be now
|
||||||
op := bin.Op == influxql.SUB
|
op := bin.Op == influxql.SUB
|
||||||
dur := isDuration(bin.LHS) || isDuration(bin.RHS) // either side can be a isDuration
|
dur, hasDur := isDuration(bin.LHS)
|
||||||
return now && op && dur
|
if !hasDur {
|
||||||
|
dur, hasDur = isDuration(bin.RHS)
|
||||||
|
}
|
||||||
|
return dur, now && op && hasDur
|
||||||
} else if isNow(exp) { // just comparing to now
|
} else if isNow(exp) { // just comparing to now
|
||||||
return true
|
return 0, true
|
||||||
}
|
}
|
||||||
return false
|
return 0, false
|
||||||
}
|
}
|
||||||
|
|
||||||
func isTimeRange(exp influxql.Expr) bool {
|
func isTimeRange(exp influxql.Expr) (time.Duration, bool) {
|
||||||
if p, ok := exp.(*influxql.ParenExpr); ok {
|
if p, ok := exp.(*influxql.ParenExpr); ok {
|
||||||
return isTimeRange(p.Expr)
|
return isTimeRange(p.Expr)
|
||||||
} else if bin, ok := exp.(*influxql.BinaryExpr); ok {
|
} else if bin, ok := exp.(*influxql.BinaryExpr); ok {
|
||||||
|
@ -234,21 +250,28 @@ func isTimeRange(exp influxql.Expr) bool {
|
||||||
case influxql.LT, influxql.LTE, influxql.GT, influxql.GTE:
|
case influxql.LT, influxql.LTE, influxql.GT, influxql.GTE:
|
||||||
op = true
|
op = true
|
||||||
}
|
}
|
||||||
prev := isPreviousTime(bin.LHS) || isPreviousTime(bin.RHS)
|
dur, prev := isPreviousTime(bin.LHS)
|
||||||
return tm && op && prev
|
if !prev {
|
||||||
|
dur, prev = isPreviousTime(bin.RHS)
|
||||||
|
}
|
||||||
|
return dur, tm && op && prev
|
||||||
}
|
}
|
||||||
return false
|
return 0, false
|
||||||
}
|
}
|
||||||
|
|
||||||
func hasTimeRange(exp influxql.Expr) bool {
|
func hasTimeRange(exp influxql.Expr) (time.Duration, bool) {
|
||||||
if p, ok := exp.(*influxql.ParenExpr); ok {
|
if p, ok := exp.(*influxql.ParenExpr); ok {
|
||||||
return hasTimeRange(p.Expr)
|
return hasTimeRange(p.Expr)
|
||||||
} else if isTimeRange(exp) {
|
} else if dur, ok := isTimeRange(exp); ok {
|
||||||
return true
|
return dur, true
|
||||||
} else if bin, ok := exp.(*influxql.BinaryExpr); ok {
|
} else if bin, ok := exp.(*influxql.BinaryExpr); ok {
|
||||||
return isTimeRange(bin.LHS) || isTimeRange(bin.RHS)
|
dur, ok := isTimeRange(bin.LHS)
|
||||||
|
if !ok {
|
||||||
|
dur, ok = isTimeRange(bin.RHS)
|
||||||
|
}
|
||||||
|
return dur, ok
|
||||||
}
|
}
|
||||||
return false
|
return 0, false
|
||||||
}
|
}
|
||||||
|
|
||||||
func isTagLogic(exp influxql.Expr) ([]tagFilter, bool) {
|
func isTagLogic(exp influxql.Expr) ([]tagFilter, bool) {
|
||||||
|
@ -256,7 +279,7 @@ func isTagLogic(exp influxql.Expr) ([]tagFilter, bool) {
|
||||||
return isTagLogic(p.Expr)
|
return isTagLogic(p.Expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
if isTimeRange(exp) {
|
if _, ok := isTimeRange(exp); ok {
|
||||||
return nil, true
|
return nil, true
|
||||||
} else if tf, ok := isTagFilter(exp); ok {
|
} else if tf, ok := isTagFilter(exp); ok {
|
||||||
return []tagFilter{tf}, true
|
return []tagFilter{tf}, true
|
||||||
|
@ -278,7 +301,10 @@ func isTagLogic(exp influxql.Expr) ([]tagFilter, bool) {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
tm := isTimeRange(bin.LHS) || isTimeRange(bin.RHS)
|
_, tm := isTimeRange(bin.LHS)
|
||||||
|
if !tm {
|
||||||
|
_, tm = isTimeRange(bin.RHS)
|
||||||
|
}
|
||||||
tf := lhsOK || rhsOK
|
tf := lhsOK || rhsOK
|
||||||
if tm && tf {
|
if tm && tf {
|
||||||
if lhsOK {
|
if lhsOK {
|
||||||
|
@ -305,35 +331,6 @@ func isTagLogic(exp influxql.Expr) ([]tagFilter, bool) {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
func hasTagFilter(exp influxql.Expr) bool {
|
|
||||||
if _, ok := isTagFilter(exp); ok {
|
|
||||||
return true
|
|
||||||
} else if p, ok := exp.(*influxql.ParenExpr); ok {
|
|
||||||
return hasTagFilter(p.Expr)
|
|
||||||
} else if bin, ok := exp.(*influxql.BinaryExpr); ok {
|
|
||||||
or := bin.Op == influxql.OR
|
|
||||||
and := bin.Op == influxql.AND
|
|
||||||
op := or || and
|
|
||||||
return op && (hasTagFilter(bin.LHS) || hasTagFilter(bin.RHS))
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func singleTagFilter(exp influxql.Expr) (tagFilter, bool) {
|
|
||||||
if p, ok := exp.(*influxql.ParenExpr); ok {
|
|
||||||
return singleTagFilter(p.Expr)
|
|
||||||
} else if tf, ok := isTagFilter(exp); ok {
|
|
||||||
return tf, true
|
|
||||||
} else if bin, ok := exp.(*influxql.BinaryExpr); ok && bin.Op == influxql.OR {
|
|
||||||
lhs, lhsOK := singleTagFilter(bin.LHS)
|
|
||||||
rhs, rhsOK := singleTagFilter(bin.RHS)
|
|
||||||
if lhsOK && rhsOK && lhs.Op == rhs.Op && lhs.Tag == rhs.Tag {
|
|
||||||
return lhs, true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return tagFilter{}, false
|
|
||||||
}
|
|
||||||
|
|
||||||
func isVarRef(exp influxql.Expr) bool {
|
func isVarRef(exp influxql.Expr) bool {
|
||||||
if p, ok := exp.(*influxql.ParenExpr); ok {
|
if p, ok := exp.(*influxql.ParenExpr); ok {
|
||||||
return isVarRef(p.Expr)
|
return isVarRef(p.Expr)
|
||||||
|
@ -409,3 +406,15 @@ var supportedFuncs = map[string]bool{
|
||||||
"spread": true,
|
"spread": true,
|
||||||
"stddev": true,
|
"stddev": true,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// shortDur converts duration into the queryConfig duration format
|
||||||
|
func shortDur(d time.Duration) string {
|
||||||
|
s := d.String()
|
||||||
|
if strings.HasSuffix(s, "m0s") {
|
||||||
|
s = s[:len(s)-2]
|
||||||
|
}
|
||||||
|
if strings.HasSuffix(s, "h0m") {
|
||||||
|
s = s[:len(s)-2]
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
|
@ -27,6 +27,214 @@ func TestConvert(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "Test math",
|
||||||
|
influxQL: `SELECT count("event_id")/3 as "event_count_id" from discource.autogen.discourse_events where time > now() - 7d group by time(1d), "event_type"`,
|
||||||
|
RawText: `SELECT count("event_id")/3 as "event_count_id" from discource.autogen.discourse_events where time > now() - 7d group by time(1d), "event_type"`,
|
||||||
|
want: chronograf.QueryConfig{
|
||||||
|
Fields: []chronograf.Field{},
|
||||||
|
Tags: map[string][]string{},
|
||||||
|
GroupBy: chronograf.GroupBy{
|
||||||
|
Tags: []string{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Test range",
|
||||||
|
influxQL: `SELECT usage_user from telegraf.autogen.cpu where "host" != 'myhost' and time > now() - 15m`,
|
||||||
|
want: chronograf.QueryConfig{
|
||||||
|
Database: "telegraf",
|
||||||
|
Measurement: "cpu",
|
||||||
|
RetentionPolicy: "autogen",
|
||||||
|
Fields: []chronograf.Field{
|
||||||
|
chronograf.Field{
|
||||||
|
Field: "usage_user",
|
||||||
|
Funcs: []string{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Tags: map[string][]string{"host": []string{"myhost"}},
|
||||||
|
GroupBy: chronograf.GroupBy{
|
||||||
|
Time: "",
|
||||||
|
Tags: []string{},
|
||||||
|
},
|
||||||
|
AreTagsAccepted: false,
|
||||||
|
Range: &chronograf.DurationRange{
|
||||||
|
Lower: "15m",
|
||||||
|
Upper: "now",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Test invalid range",
|
||||||
|
influxQL: `SELECT usage_user from telegraf.autogen.cpu where "host" != 'myhost' and time > now() - 15`,
|
||||||
|
RawText: `SELECT usage_user from telegraf.autogen.cpu where "host" != 'myhost' and time > now() - 15`,
|
||||||
|
want: chronograf.QueryConfig{
|
||||||
|
Fields: []chronograf.Field{},
|
||||||
|
Tags: map[string][]string{},
|
||||||
|
GroupBy: chronograf.GroupBy{
|
||||||
|
Tags: []string{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Test range with no duration",
|
||||||
|
influxQL: `SELECT usage_user from telegraf.autogen.cpu where "host" != 'myhost' and time > now()`,
|
||||||
|
want: chronograf.QueryConfig{
|
||||||
|
Database: "telegraf",
|
||||||
|
Measurement: "cpu",
|
||||||
|
RetentionPolicy: "autogen",
|
||||||
|
Fields: []chronograf.Field{
|
||||||
|
chronograf.Field{
|
||||||
|
Field: "usage_user",
|
||||||
|
Funcs: []string{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Tags: map[string][]string{"host": []string{"myhost"}},
|
||||||
|
GroupBy: chronograf.GroupBy{
|
||||||
|
Time: "",
|
||||||
|
Tags: []string{},
|
||||||
|
},
|
||||||
|
AreTagsAccepted: false,
|
||||||
|
Range: &chronograf.DurationRange{
|
||||||
|
Lower: "0s",
|
||||||
|
Upper: "now",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Test range with no tags",
|
||||||
|
influxQL: `SELECT usage_user from telegraf.autogen.cpu where time > now() - 15m`,
|
||||||
|
want: chronograf.QueryConfig{
|
||||||
|
Database: "telegraf",
|
||||||
|
Measurement: "cpu",
|
||||||
|
RetentionPolicy: "autogen",
|
||||||
|
Tags: map[string][]string{},
|
||||||
|
Fields: []chronograf.Field{
|
||||||
|
chronograf.Field{
|
||||||
|
Field: "usage_user",
|
||||||
|
Funcs: []string{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
GroupBy: chronograf.GroupBy{
|
||||||
|
Time: "",
|
||||||
|
Tags: []string{},
|
||||||
|
},
|
||||||
|
AreTagsAccepted: false,
|
||||||
|
Range: &chronograf.DurationRange{
|
||||||
|
Lower: "15m",
|
||||||
|
Upper: "now",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Test range with no tags nor duration",
|
||||||
|
influxQL: `SELECT usage_user from telegraf.autogen.cpu where time`,
|
||||||
|
RawText: `SELECT usage_user from telegraf.autogen.cpu where time`,
|
||||||
|
want: chronograf.QueryConfig{
|
||||||
|
Fields: []chronograf.Field{},
|
||||||
|
Tags: map[string][]string{},
|
||||||
|
GroupBy: chronograf.GroupBy{
|
||||||
|
Tags: []string{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Test with no time range",
|
||||||
|
influxQL: `SELECT usage_user from telegraf.autogen.cpu where "host" != 'myhost' and time`,
|
||||||
|
RawText: `SELECT usage_user from telegraf.autogen.cpu where "host" != 'myhost' and time`,
|
||||||
|
want: chronograf.QueryConfig{
|
||||||
|
Fields: []chronograf.Field{},
|
||||||
|
Tags: map[string][]string{},
|
||||||
|
GroupBy: chronograf.GroupBy{
|
||||||
|
Tags: []string{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Test with no where clauses",
|
||||||
|
influxQL: `SELECT usage_user from telegraf.autogen.cpu`,
|
||||||
|
want: chronograf.QueryConfig{
|
||||||
|
Database: "telegraf",
|
||||||
|
Measurement: "cpu",
|
||||||
|
RetentionPolicy: "autogen",
|
||||||
|
Fields: []chronograf.Field{
|
||||||
|
chronograf.Field{
|
||||||
|
Field: "usage_user",
|
||||||
|
Funcs: []string{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Tags: map[string][]string{},
|
||||||
|
GroupBy: chronograf.GroupBy{
|
||||||
|
Time: "",
|
||||||
|
Tags: []string{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Test tags accepted",
|
||||||
|
influxQL: `SELECT usage_user from telegraf.autogen.cpu where "host" = 'myhost' and time > now() - 15m`,
|
||||||
|
want: chronograf.QueryConfig{
|
||||||
|
Database: "telegraf",
|
||||||
|
Measurement: "cpu",
|
||||||
|
RetentionPolicy: "autogen",
|
||||||
|
Fields: []chronograf.Field{
|
||||||
|
chronograf.Field{
|
||||||
|
Field: "usage_user",
|
||||||
|
Funcs: []string{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Tags: map[string][]string{"host": []string{"myhost"}},
|
||||||
|
GroupBy: chronograf.GroupBy{
|
||||||
|
Time: "",
|
||||||
|
Tags: []string{},
|
||||||
|
},
|
||||||
|
AreTagsAccepted: true,
|
||||||
|
Range: &chronograf.DurationRange{
|
||||||
|
Lower: "15m",
|
||||||
|
Upper: "now",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Test mixed tag logic",
|
||||||
|
influxQL: `SELECT usage_user from telegraf.autogen.cpu where ("host" = 'myhost' or "this" = 'those') and ("howdy" != 'doody') and time > now() - 15m`,
|
||||||
|
RawText: `SELECT usage_user from telegraf.autogen.cpu where ("host" = 'myhost' or "this" = 'those') and ("howdy" != 'doody') and time > now() - 15m`,
|
||||||
|
want: chronograf.QueryConfig{
|
||||||
|
Fields: []chronograf.Field{},
|
||||||
|
Tags: map[string][]string{},
|
||||||
|
GroupBy: chronograf.GroupBy{
|
||||||
|
Tags: []string{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Test tags accepted",
|
||||||
|
influxQL: `SELECT usage_user from telegraf.autogen.cpu where ("host" = 'myhost' OR "host" = 'yourhost') and ("these" = 'those') and time > now() - 15m`,
|
||||||
|
want: chronograf.QueryConfig{
|
||||||
|
Database: "telegraf",
|
||||||
|
Measurement: "cpu",
|
||||||
|
RetentionPolicy: "autogen",
|
||||||
|
Fields: []chronograf.Field{
|
||||||
|
chronograf.Field{
|
||||||
|
Field: "usage_user",
|
||||||
|
Funcs: []string{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Tags: map[string][]string{
|
||||||
|
"host": []string{"myhost", "yourhost"},
|
||||||
|
"these": []string{"those"},
|
||||||
|
},
|
||||||
|
GroupBy: chronograf.GroupBy{
|
||||||
|
Time: "",
|
||||||
|
Tags: []string{},
|
||||||
|
},
|
||||||
|
AreTagsAccepted: true,
|
||||||
|
Range: &chronograf.DurationRange{
|
||||||
|
Lower: "15m",
|
||||||
|
Upper: "now",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
@ -37,6 +245,11 @@ func TestConvert(t *testing.T) {
|
||||||
}
|
}
|
||||||
if tt.RawText != "" {
|
if tt.RawText != "" {
|
||||||
tt.want.RawText = &tt.RawText
|
tt.want.RawText = &tt.RawText
|
||||||
|
if got.RawText == nil {
|
||||||
|
t.Errorf("Convert() = nil, want %s", tt.RawText)
|
||||||
|
} else if *got.RawText != tt.RawText {
|
||||||
|
t.Errorf("Convert() = %s, want %s", *got.RawText, tt.RawText)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(got, tt.want) {
|
if !reflect.DeepEqual(got, tt.want) {
|
||||||
t.Errorf("Convert() = %#v, want %#v", got, tt.want)
|
t.Errorf("Convert() = %#v, want %#v", got, tt.want)
|
||||||
|
|
|
@ -283,6 +283,10 @@ func Test_newDashboardResponse(t *testing.T) {
|
||||||
},
|
},
|
||||||
Tags: make(map[string][]string, 0),
|
Tags: make(map[string][]string, 0),
|
||||||
AreTagsAccepted: false,
|
AreTagsAccepted: false,
|
||||||
|
Range: &chronograf.DurationRange{
|
||||||
|
Lower: "15m",
|
||||||
|
Upper: "now",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -299,7 +303,7 @@ func Test_newDashboardResponse(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
if got := newDashboardResponse(tt.d); !reflect.DeepEqual(got, tt.want) {
|
if got := newDashboardResponse(tt.d); !reflect.DeepEqual(got, tt.want) {
|
||||||
t.Errorf("%q. newDashboardResponse() = \n%+v\n\n, want\n\n%+v", tt.name, got, tt.want)
|
t.Errorf("%q. newDashboardResponse() = \n%#v\n\n, want\n\n%#v", tt.name, got, tt.want)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2536,7 +2536,11 @@
|
||||||
"time": "10m",
|
"time": "10m",
|
||||||
"tags": []
|
"tags": []
|
||||||
},
|
},
|
||||||
"areTagsAccepted": true
|
"areTagsAccepted": true,
|
||||||
|
"range": {
|
||||||
|
"lower": "15m",
|
||||||
|
"upper": "now"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"properties": {
|
"properties": {
|
||||||
"id": {
|
"id": {
|
||||||
|
@ -2598,6 +2602,21 @@
|
||||||
"funcs"
|
"funcs"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"range": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"lower": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"upper": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"lower",
|
||||||
|
"upper"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
|
|
|
@ -33,8 +33,6 @@ const errorsMiddleware = store => next => action => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
allowNotifications = true
|
allowNotifications = true
|
||||||
}, notificationsBlackoutDuration)
|
}, notificationsBlackoutDuration)
|
||||||
} else {
|
|
||||||
store.dispatch(notify('error', 'Please login to use Chronograf.'))
|
|
||||||
}
|
}
|
||||||
} else if (altText) {
|
} else if (altText) {
|
||||||
store.dispatch(notify('error', altText))
|
store.dispatch(notify('error', altText))
|
||||||
|
|
|
@ -86,7 +86,6 @@ $dash-graph-options-arrow: 8px;
|
||||||
top: $dash-graph-heading;
|
top: $dash-graph-heading;
|
||||||
left: 0;
|
left: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
z-index: 0;
|
|
||||||
|
|
||||||
& > div:not(.graph-empty) {
|
& > div:not(.graph-empty) {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
@ -164,7 +163,7 @@ $dash-graph-options-arrow: 8px;
|
||||||
.dash-graph--options {
|
.dash-graph--options {
|
||||||
width: $dash-graph-heading;
|
width: $dash-graph-heading;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 1;
|
z-index: 11;
|
||||||
right: 0px;
|
right: 0px;
|
||||||
top: 0px;
|
top: 0px;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue