Merge pull request #15736 from influxdata/4974p/pkger_dash_single_stat_plus_line
feat(pkger): add single stat plus line view support to pkgerpull/15749/head
commit
a78c53d3b9
131
pkger/models.go
131
pkger/models.go
|
@ -167,13 +167,14 @@ type ChartKind string
|
|||
|
||||
// available chart kinds
|
||||
const (
|
||||
ChartKindUnknown ChartKind = ""
|
||||
ChartKindSingleStat ChartKind = "single_stat"
|
||||
ChartKindUnknown ChartKind = ""
|
||||
ChartKindSingleStat ChartKind = "single_stat"
|
||||
ChartKindSingleStatPlusLine ChartKind = "single_stat_plus_line"
|
||||
)
|
||||
|
||||
func (c ChartKind) ok() bool {
|
||||
switch c {
|
||||
case ChartKindSingleStat:
|
||||
case ChartKindSingleStat, ChartKindSingleStatPlusLine:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
|
@ -457,8 +458,10 @@ type chart struct {
|
|||
DecimalPlaces int
|
||||
EnforceDecimals bool
|
||||
Shade bool
|
||||
Colors []*color
|
||||
Queries []query
|
||||
Legend legend
|
||||
Colors colors
|
||||
Queries queries
|
||||
Axes axes
|
||||
|
||||
XCol, YCol string
|
||||
XPos, YPos int
|
||||
|
@ -478,8 +481,27 @@ func (c chart) properties() influxdb.ViewProperties {
|
|||
},
|
||||
Note: c.Note,
|
||||
ShowNoteWhenEmpty: c.NoteOnEmpty,
|
||||
Queries: queries(c.Queries).influxDashQueries(),
|
||||
ViewColors: colors(c.Colors).influxViewColors(),
|
||||
Queries: c.Queries.influxDashQueries(),
|
||||
ViewColors: c.Colors.influxViewColors(),
|
||||
}
|
||||
case ChartKindSingleStatPlusLine:
|
||||
return influxdb.LinePlusSingleStatProperties{
|
||||
Type: "line-plus-single-stat",
|
||||
Prefix: c.Prefix,
|
||||
Suffix: c.Suffix,
|
||||
DecimalPlaces: influxdb.DecimalPlaces{
|
||||
IsEnforced: c.EnforceDecimals,
|
||||
Digits: int32(c.DecimalPlaces),
|
||||
},
|
||||
Note: c.Note,
|
||||
ShowNoteWhenEmpty: c.NoteOnEmpty,
|
||||
XColumn: c.XCol,
|
||||
YColumn: c.YCol,
|
||||
ShadeBelow: c.Shade,
|
||||
Legend: c.Legend.influxLegend(),
|
||||
Queries: c.Queries.influxDashQueries(),
|
||||
ViewColors: c.Colors.influxViewColors(),
|
||||
Axes: c.Axes.influxAxes(),
|
||||
}
|
||||
default:
|
||||
return nil
|
||||
|
@ -491,8 +513,8 @@ func (c chart) validProperties() []failure {
|
|||
|
||||
validatorFns := []func() []failure{
|
||||
c.validBaseProps,
|
||||
queries(c.Queries).valid,
|
||||
colors(c.Colors).valid,
|
||||
c.Queries.valid,
|
||||
c.Colors.valid,
|
||||
}
|
||||
for _, validatorFn := range validatorFns {
|
||||
fails = append(fails, validatorFn()...)
|
||||
|
@ -501,14 +523,10 @@ func (c chart) validProperties() []failure {
|
|||
// chart kind specific validations
|
||||
switch c.Kind {
|
||||
case ChartKindSingleStat:
|
||||
for i, clr := range c.Colors {
|
||||
if clr.Type != colorTypeText {
|
||||
fails = append(fails, failure{
|
||||
Field: fmt.Sprintf("colors[%d].type", i),
|
||||
Msg: "single stat charts must have color type of \"text\"",
|
||||
})
|
||||
}
|
||||
}
|
||||
fails = append(fails, c.Colors.hasTypes(colorTypeText)...)
|
||||
case ChartKindSingleStatPlusLine:
|
||||
fails = append(fails, c.Colors.hasTypes(colorTypeText, colorTypeScale)...)
|
||||
fails = append(fails, c.Axes.hasAxes("x", "y")...)
|
||||
}
|
||||
|
||||
return fails
|
||||
|
@ -533,7 +551,8 @@ func (c chart) validBaseProps() []failure {
|
|||
}
|
||||
|
||||
const (
|
||||
colorTypeText = "text"
|
||||
colorTypeText = "text"
|
||||
colorTypeScale = "scale"
|
||||
)
|
||||
|
||||
type color struct {
|
||||
|
@ -565,6 +584,25 @@ func (c colors) influxViewColors() []influxdb.ViewColor {
|
|||
return iColors
|
||||
}
|
||||
|
||||
func (c colors) hasTypes(types ...string) []failure {
|
||||
tMap := make(map[string]bool)
|
||||
for _, cc := range c {
|
||||
tMap[cc.Type] = true
|
||||
}
|
||||
|
||||
var failures []failure
|
||||
for _, t := range types {
|
||||
if !tMap[t] {
|
||||
failures = append(failures, failure{
|
||||
Field: "colors",
|
||||
Msg: fmt.Sprintf("type not found: %q", t),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return failures
|
||||
}
|
||||
|
||||
func (c colors) valid() []failure {
|
||||
var fails []failure
|
||||
if len(c) == 0 {
|
||||
|
@ -626,3 +664,60 @@ func (q queries) valid() []failure {
|
|||
|
||||
return fails
|
||||
}
|
||||
|
||||
type axis struct {
|
||||
Base string
|
||||
Label string
|
||||
Name string
|
||||
Prefix string
|
||||
Scale string
|
||||
Suffix string
|
||||
}
|
||||
|
||||
type axes []axis
|
||||
|
||||
func (a axes) influxAxes() map[string]influxdb.Axis {
|
||||
m := make(map[string]influxdb.Axis)
|
||||
for _, ax := range a {
|
||||
m[ax.Name] = influxdb.Axis{
|
||||
Bounds: []string{},
|
||||
Label: ax.Label,
|
||||
Prefix: ax.Prefix,
|
||||
Suffix: ax.Suffix,
|
||||
Base: ax.Base,
|
||||
Scale: ax.Scale,
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func (a axes) hasAxes(expectedAxes ...string) []failure {
|
||||
mAxes := make(map[string]bool)
|
||||
for _, ax := range a {
|
||||
mAxes[ax.Name] = true
|
||||
}
|
||||
|
||||
var failures []failure
|
||||
for _, expected := range expectedAxes {
|
||||
if !mAxes[expected] {
|
||||
failures = append(failures, failure{
|
||||
Field: "axes",
|
||||
Msg: fmt.Sprintf("axis not found: %q", expected),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return failures
|
||||
}
|
||||
|
||||
type legend struct {
|
||||
Orientation string
|
||||
Type string
|
||||
}
|
||||
|
||||
func (l legend) influxLegend() influxdb.Legend {
|
||||
return influxdb.Legend{
|
||||
Type: l.Type,
|
||||
Orientation: l.Orientation,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -577,6 +577,11 @@ func parseChart(r Resource) (chart, []failure) {
|
|||
Width: r.intShort("width"),
|
||||
}
|
||||
|
||||
if leg, ok := ifaceMapToResource(r["legend"]); ok {
|
||||
c.Legend.Type = leg.stringShort("type")
|
||||
c.Legend.Orientation = leg.stringShort("orientation")
|
||||
}
|
||||
|
||||
if dp, ok := r.int("decimalPlaces"); ok {
|
||||
c.EnforceDecimals = true
|
||||
c.DecimalPlaces = dp
|
||||
|
@ -585,7 +590,7 @@ func parseChart(r Resource) (chart, []failure) {
|
|||
var failures []failure
|
||||
for _, rq := range r.slcResource("queries") {
|
||||
c.Queries = append(c.Queries, query{
|
||||
Query: rq.stringShort("query"),
|
||||
Query: strings.TrimSpace(rq.stringShort("query")),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -599,6 +604,17 @@ func parseChart(r Resource) (chart, []failure) {
|
|||
})
|
||||
}
|
||||
|
||||
for _, ra := range r.slcResource("axes") {
|
||||
c.Axes = append(c.Axes, axis{
|
||||
Base: ra.stringShort("base"),
|
||||
Label: ra.stringShort("label"),
|
||||
Name: ra.Name(),
|
||||
Prefix: ra.stringShort("prefix"),
|
||||
Scale: ra.stringShort("scale"),
|
||||
Suffix: ra.stringShort("suffix"),
|
||||
})
|
||||
}
|
||||
|
||||
if fails := c.validProperties(); len(fails) > 0 {
|
||||
failures = append(failures, fails...)
|
||||
}
|
||||
|
@ -716,8 +732,15 @@ func (r Resource) intShort(key string) int {
|
|||
}
|
||||
|
||||
func (r Resource) string(key string) (string, bool) {
|
||||
s, ok := r[key].(string)
|
||||
return s, ok
|
||||
if s, ok := r[key].(string); ok {
|
||||
return s, true
|
||||
}
|
||||
|
||||
if i, ok := r[key].(int); ok {
|
||||
return strconv.Itoa(i), true
|
||||
}
|
||||
|
||||
return "", false
|
||||
}
|
||||
|
||||
func (r Resource) stringShort(key string) string {
|
||||
|
|
|
@ -532,6 +532,7 @@ spec:
|
|||
|
||||
props, ok := actualChart.Properties.(influxdb.SingleStatViewProperties)
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, "single-stat", props.GetType())
|
||||
assert.Equal(t, "single stat note", props.Note)
|
||||
assert.True(t, props.ShowNoteWhenEmpty)
|
||||
assert.True(t, props.DecimalPlaces.IsEnforced)
|
||||
|
@ -593,8 +594,8 @@ spec:
|
|||
},
|
||||
{
|
||||
name: "no colors provided",
|
||||
numErrs: 1,
|
||||
errFields: []string{"charts[0].colors"},
|
||||
numErrs: 2,
|
||||
errFields: []string{"charts[0].colors", "charts[0].colors"},
|
||||
ymlStr: `apiVersion: 0.1.0
|
||||
kind: Package
|
||||
meta:
|
||||
|
@ -751,7 +752,436 @@ spec:
|
|||
resErr := pErr.Resources[0]
|
||||
assert.Equal(t, "dashboard", resErr.Kind)
|
||||
|
||||
require.Len(t, resErr.ValidationFails, 1)
|
||||
require.Len(t, resErr.ValidationFails, tt.numErrs)
|
||||
for i, vFail := range resErr.ValidationFails {
|
||||
assert.Equal(t, tt.errFields[i], vFail.Field)
|
||||
}
|
||||
}
|
||||
t.Run(tt.name, fn)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("single stat plus line chart", func(t *testing.T) {
|
||||
testfileRunner(t, "testdata/dashboard_single_stat_plus_line", func(t *testing.T, pkg *Pkg) {
|
||||
sum := pkg.Summary()
|
||||
require.Len(t, sum.Dashboards, 1)
|
||||
|
||||
actual := sum.Dashboards[0]
|
||||
assert.Equal(t, "dash_1", actual.Name)
|
||||
assert.Equal(t, "desc1", actual.Description)
|
||||
|
||||
require.Len(t, actual.Charts, 1)
|
||||
actualChart := actual.Charts[0]
|
||||
assert.Equal(t, ChartKindSingleStatPlusLine, actualChart.Kind)
|
||||
assert.Equal(t, 3, actualChart.Height)
|
||||
assert.Equal(t, 6, actualChart.Width)
|
||||
assert.Equal(t, 1, actualChart.XPosition)
|
||||
assert.Equal(t, 2, actualChart.YPosition)
|
||||
|
||||
props, ok := actualChart.Properties.(influxdb.LinePlusSingleStatProperties)
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, "single stat plus line note", props.Note)
|
||||
assert.True(t, props.ShowNoteWhenEmpty)
|
||||
assert.True(t, props.DecimalPlaces.IsEnforced)
|
||||
assert.Equal(t, int32(1), props.DecimalPlaces.Digits)
|
||||
assert.Equal(t, "days", props.Suffix)
|
||||
assert.Equal(t, "sumtin", props.Prefix)
|
||||
assert.Equal(t, "leg_type", props.Legend.Type)
|
||||
assert.Equal(t, "horizontal", props.Legend.Orientation)
|
||||
|
||||
require.Len(t, props.Queries, 1)
|
||||
q := props.Queries[0]
|
||||
expectedQuery := `from(bucket: v.bucket) |> range(start: v.timeRangeStart) |> filter(fn: (r) => r._measurement == "mem") |> filter(fn: (r) => r._field == "used_percent") |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false) |> yield(name: "mean")`
|
||||
assert.Equal(t, expectedQuery, q.Text)
|
||||
assert.Equal(t, "advanced", q.EditMode)
|
||||
|
||||
for _, key := range []string{"x", "y"} {
|
||||
xAxis, ok := props.Axes[key]
|
||||
require.True(t, ok, "key="+key)
|
||||
assert.Equal(t, "10", xAxis.Base, "key="+key)
|
||||
assert.Equal(t, key+"_label", xAxis.Label, "key="+key)
|
||||
assert.Equal(t, key+"_prefix", xAxis.Prefix, "key="+key)
|
||||
assert.Equal(t, "linear", xAxis.Scale, "key="+key)
|
||||
assert.Equal(t, key+"_suffix", xAxis.Suffix, "key="+key)
|
||||
}
|
||||
|
||||
require.Len(t, props.ViewColors, 2)
|
||||
c := props.ViewColors[0]
|
||||
assert.NotZero(t, c.ID)
|
||||
assert.Equal(t, "laser", c.Name)
|
||||
assert.Equal(t, "text", c.Type)
|
||||
assert.Equal(t, "#8F8AF4", c.Hex)
|
||||
assert.Equal(t, 3.0, c.Value)
|
||||
|
||||
c = props.ViewColors[1]
|
||||
assert.NotZero(t, c.ID)
|
||||
assert.Equal(t, "android", c.Name)
|
||||
assert.Equal(t, "scale", c.Type)
|
||||
assert.Equal(t, "#F4CF31", c.Hex)
|
||||
assert.Equal(t, 1.0, c.Value)
|
||||
})
|
||||
|
||||
t.Run("handles invalid config", func(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
ymlStr string
|
||||
numErrs int
|
||||
errFields []string
|
||||
}{
|
||||
{
|
||||
name: "color missing hex value",
|
||||
numErrs: 1,
|
||||
errFields: []string{"charts[0].colors[0].hex"},
|
||||
ymlStr: `apiVersion: 0.1.0
|
||||
kind: Package
|
||||
meta:
|
||||
pkgName: pkg_name
|
||||
pkgVersion: 1
|
||||
description: pack description
|
||||
spec:
|
||||
resources:
|
||||
- kind: Dashboard
|
||||
name: dash_1
|
||||
description: desc1
|
||||
charts:
|
||||
- kind: Single_Stat_Plus_Line
|
||||
name: single stat plus line
|
||||
width: 6
|
||||
height: 3
|
||||
queries:
|
||||
- query: >
|
||||
from(bucket: v.bucket) |> range(start: v.timeRangeStart) |> filter(fn: (r) => r._measurement == "system") |> filter(fn: (r) => r._field == "uptime") |> last() |> map(fn: (r) => ({r with _value: r._value / 86400})) |> yield(name: "last")
|
||||
colors:
|
||||
- name: laser
|
||||
type: text
|
||||
- name: android
|
||||
type: scale
|
||||
hex: "#F4CF31"
|
||||
axes:
|
||||
- name : "x"
|
||||
label: x_label
|
||||
base: 10
|
||||
scale: linear
|
||||
- name: "y"
|
||||
label: y_label
|
||||
base: 10
|
||||
scale: linear
|
||||
`,
|
||||
},
|
||||
{
|
||||
name: "no colors provided",
|
||||
numErrs: 3,
|
||||
errFields: []string{"charts[0].colors", "charts[0].colors", "charts[0].colors"},
|
||||
ymlStr: `apiVersion: 0.1.0
|
||||
kind: Package
|
||||
meta:
|
||||
pkgName: pkg_name
|
||||
pkgVersion: 1
|
||||
description: pack description
|
||||
spec:
|
||||
resources:
|
||||
- kind: Dashboard
|
||||
name: dash_1
|
||||
description: desc1
|
||||
charts:
|
||||
- kind: Single_Stat_Plus_Line
|
||||
name: single stat plus line
|
||||
width: 6
|
||||
height: 3
|
||||
queries:
|
||||
- query: >
|
||||
from(bucket: v.bucket) |> range(start: v.timeRangeStart) |> filter(fn: (r) => r._measurement == "system") |> filter(fn: (r) => r._field == "uptime") |> last() |> map(fn: (r) => ({r with _value: r._value / 86400})) |> yield(name: "last")
|
||||
axes:
|
||||
- name : "x"
|
||||
label: x_label
|
||||
base: 10
|
||||
scale: linear
|
||||
- name: "y"
|
||||
label: y_label
|
||||
base: 10
|
||||
scale: linear
|
||||
`,
|
||||
},
|
||||
{
|
||||
name: "missing query value",
|
||||
numErrs: 1,
|
||||
errFields: []string{"charts[0].queries[0].query"},
|
||||
ymlStr: `apiVersion: 0.1.0
|
||||
kind: Package
|
||||
meta:
|
||||
pkgName: pkg_name
|
||||
pkgVersion: 1
|
||||
description: pack description
|
||||
spec:
|
||||
resources:
|
||||
- kind: Dashboard
|
||||
name: dash_1
|
||||
description: desc1
|
||||
charts:
|
||||
- kind: Single_Stat_Plus_Line
|
||||
name: single stat plus line
|
||||
width: 6
|
||||
height: 3
|
||||
queries:
|
||||
- query:
|
||||
colors:
|
||||
- name: laser
|
||||
type: text
|
||||
hex: "#abcabc"
|
||||
- name: android
|
||||
type: scale
|
||||
hex: "#F4CF31"
|
||||
axes:
|
||||
- name : "x"
|
||||
label: x_label
|
||||
base: 10
|
||||
scale: linear
|
||||
- name: "y"
|
||||
label: y_label
|
||||
base: 10
|
||||
scale: linear
|
||||
`,
|
||||
},
|
||||
{
|
||||
name: "no queries provided",
|
||||
numErrs: 1,
|
||||
errFields: []string{"charts[0].queries"},
|
||||
ymlStr: `apiVersion: 0.1.0
|
||||
kind: Package
|
||||
meta:
|
||||
pkgName: pkg_name
|
||||
pkgVersion: 1
|
||||
description: pack description
|
||||
spec:
|
||||
resources:
|
||||
- kind: Dashboard
|
||||
name: dash_1
|
||||
description: desc1
|
||||
charts:
|
||||
- kind: Single_Stat_Plus_Line
|
||||
name: single stat plus line
|
||||
width: 6
|
||||
height: 3
|
||||
colors:
|
||||
- name: laser
|
||||
type: text
|
||||
hex: "red"
|
||||
- name: android
|
||||
type: scale
|
||||
hex: "#F4CF31"
|
||||
axes:
|
||||
- name : "x"
|
||||
label: x_label
|
||||
base: 10
|
||||
scale: linear
|
||||
- name: "y"
|
||||
label: y_label
|
||||
base: 10
|
||||
scale: linear`,
|
||||
},
|
||||
{
|
||||
name: "no width provided",
|
||||
numErrs: 1,
|
||||
errFields: []string{"charts[0].width"},
|
||||
ymlStr: `apiVersion: 0.1.0
|
||||
kind: Package
|
||||
meta:
|
||||
pkgName: pkg_name
|
||||
pkgVersion: 1
|
||||
description: pack description
|
||||
spec:
|
||||
resources:
|
||||
- kind: Dashboard
|
||||
name: dash_1
|
||||
description: desc1
|
||||
charts:
|
||||
- kind: Single_Stat_Plus_Line
|
||||
name: single stat plus line
|
||||
height: 3
|
||||
queries:
|
||||
- query: >
|
||||
from(bucket: v.bucket) |> range(start: v.timeRangeStart) |> filter(fn: (r) => r._measurement == "system") |> filter(fn: (r) => r._field == "uptime") |> last() |> map(fn: (r) => ({r with _value: r._value / 86400})) |> yield(name: "last")
|
||||
colors:
|
||||
- name: laser
|
||||
type: text
|
||||
hex: green
|
||||
- name: android
|
||||
type: scale
|
||||
hex: "#F4CF31"
|
||||
axes:
|
||||
- name : "x"
|
||||
label: x_label
|
||||
base: 10
|
||||
scale: linear
|
||||
- name: "y"
|
||||
label: y_label
|
||||
base: 10
|
||||
scale: linear`,
|
||||
},
|
||||
{
|
||||
name: "no height provided",
|
||||
numErrs: 1,
|
||||
errFields: []string{"charts[0].height"},
|
||||
ymlStr: `apiVersion: 0.1.0
|
||||
kind: Package
|
||||
meta:
|
||||
pkgName: pkg_name
|
||||
pkgVersion: 1
|
||||
description: pack description
|
||||
spec:
|
||||
resources:
|
||||
- kind: Dashboard
|
||||
name: dash_1
|
||||
description: desc1
|
||||
charts:
|
||||
- kind: Single_Stat_Plus_Line
|
||||
name: single stat plus line
|
||||
width: 3
|
||||
queries:
|
||||
- query: >
|
||||
from(bucket: v.bucket) |> range(start: v.timeRangeStart) |> filter(fn: (r) => r._measurement == "system") |> filter(fn: (r) => r._field == "uptime") |> last() |> map(fn: (r) => ({r with _value: r._value / 86400})) |> yield(name: "last")
|
||||
colors:
|
||||
- name: laser
|
||||
type: text
|
||||
hex: green
|
||||
- name: android
|
||||
type: scale
|
||||
hex: "#F4CF31"
|
||||
axes:
|
||||
- name : "x"
|
||||
label: x_label
|
||||
base: 10
|
||||
scale: linear
|
||||
- name: "y"
|
||||
label: y_label
|
||||
base: 10
|
||||
scale: linear`,
|
||||
},
|
||||
{
|
||||
name: "missing text color but has scale color",
|
||||
numErrs: 1,
|
||||
errFields: []string{"charts[0].colors"},
|
||||
ymlStr: `apiVersion: 0.1.0
|
||||
kind: Package
|
||||
meta:
|
||||
pkgName: pkg_name
|
||||
pkgVersion: 1
|
||||
description: pack description
|
||||
spec:
|
||||
resources:
|
||||
- kind: Dashboard
|
||||
name: dash_1
|
||||
description: desc1
|
||||
charts:
|
||||
- kind: Single_Stat_Plus_Line
|
||||
name: single stat plus line
|
||||
width: 3
|
||||
height: 3
|
||||
queries:
|
||||
- query: >
|
||||
from(bucket: v.bucket) |> range(start: v.timeRangeStart) |> filter(fn: (r) => r._measurement == "system") |> filter(fn: (r) => r._field == "uptime") |> last() |> map(fn: (r) => ({r with _value: r._value / 86400})) |> yield(name: "last")
|
||||
colors:
|
||||
- name: android
|
||||
type: scale
|
||||
hex: "#F4CF31"
|
||||
axes:
|
||||
- name : "x"
|
||||
label: x_label
|
||||
base: 10
|
||||
scale: linear
|
||||
- name: "y"
|
||||
label: y_label
|
||||
base: 10
|
||||
scale: linear`,
|
||||
},
|
||||
{
|
||||
name: "missing x axis",
|
||||
numErrs: 1,
|
||||
errFields: []string{"charts[0].axes"},
|
||||
ymlStr: `apiVersion: 0.1.0
|
||||
kind: Package
|
||||
meta:
|
||||
pkgName: pkg_name
|
||||
pkgVersion: 1
|
||||
description: pack description
|
||||
spec:
|
||||
resources:
|
||||
- kind: Dashboard
|
||||
name: dash_1
|
||||
description: desc1
|
||||
charts:
|
||||
- kind: Single_Stat_Plus_Line
|
||||
name: single stat plus line
|
||||
width: 3
|
||||
height: 3
|
||||
queries:
|
||||
- query: >
|
||||
from(bucket: v.bucket) |> range(start: v.timeRangeStart) |> filter(fn: (r) => r._measurement == "system") |> filter(fn: (r) => r._field == "uptime") |> last() |> map(fn: (r) => ({r with _value: r._value / 86400})) |> yield(name: "last")
|
||||
colors:
|
||||
- name: first
|
||||
type: text
|
||||
hex: "#aabbaa"
|
||||
- name: android
|
||||
type: scale
|
||||
hex: "#F4CF31"
|
||||
axes:
|
||||
- name: "y"
|
||||
label: y_label
|
||||
base: 10
|
||||
scale: linear`,
|
||||
},
|
||||
{
|
||||
name: "missing y axis",
|
||||
numErrs: 1,
|
||||
errFields: []string{"charts[0].axes"},
|
||||
ymlStr: `apiVersion: 0.1.0
|
||||
kind: Package
|
||||
meta:
|
||||
pkgName: pkg_name
|
||||
pkgVersion: 1
|
||||
description: pack description
|
||||
spec:
|
||||
resources:
|
||||
- kind: Dashboard
|
||||
name: dash_1
|
||||
description: desc1
|
||||
charts:
|
||||
- kind: Single_Stat_Plus_Line
|
||||
name: single stat plus line
|
||||
width: 3
|
||||
height: 3
|
||||
queries:
|
||||
- query: >
|
||||
from(bucket: v.bucket) |> range(start: v.timeRangeStart) |> filter(fn: (r) => r._measurement == "system") |> filter(fn: (r) => r._field == "uptime") |> last() |> map(fn: (r) => ({r with _value: r._value / 86400})) |> yield(name: "last")
|
||||
colors:
|
||||
- name: first
|
||||
type: text
|
||||
hex: "#aabbaa"
|
||||
- name: android
|
||||
type: scale
|
||||
hex: "#F4CF31"
|
||||
axes:
|
||||
- name: "x"
|
||||
base: 10
|
||||
scale: linear`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
fn := func(t *testing.T) {
|
||||
_, err := Parse(EncodingYAML, FromString(tt.ymlStr))
|
||||
require.Error(t, err)
|
||||
|
||||
pErr, ok := IsParseErr(err)
|
||||
require.True(t, ok, err)
|
||||
|
||||
require.Len(t, pErr.Resources, 1)
|
||||
|
||||
resErr := pErr.Resources[0]
|
||||
assert.Equal(t, "dashboard", resErr.Kind)
|
||||
|
||||
require.Len(t, resErr.ValidationFails, tt.numErrs)
|
||||
for i, vFail := range resErr.ValidationFails {
|
||||
assert.Equal(t, tt.errFields[i], vFail.Field)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
{
|
||||
"apiVersion": "0.1.0",
|
||||
"kind": "Package",
|
||||
"meta": {
|
||||
"pkgName": "pkg_name",
|
||||
"pkgVersion": "1",
|
||||
"description": "pack description"
|
||||
},
|
||||
"spec": {
|
||||
"resources": [
|
||||
{
|
||||
"kind": "Dashboard",
|
||||
"name": "dash_1",
|
||||
"description": "desc1",
|
||||
"charts": [
|
||||
{
|
||||
"kind": "Single_Stat_Plus_Line",
|
||||
"name": "single stat plus line",
|
||||
"prefix": "sumtin",
|
||||
"suffix": "days",
|
||||
"note": "single stat plus line note",
|
||||
"noteOnEmpty": true,
|
||||
"xPos": 1,
|
||||
"yPos": 2,
|
||||
"width": 6,
|
||||
"height": 3,
|
||||
"decimalPlaces": 1,
|
||||
"shade": true,
|
||||
"xColumn": "_time",
|
||||
"yColumn": "_value",
|
||||
"legend": {
|
||||
"type": "leg_type",
|
||||
"orientation": "horizontal"
|
||||
},
|
||||
"queries": [
|
||||
{
|
||||
"query": "from(bucket: v.bucket) |> range(start: v.timeRangeStart) |> filter(fn: (r) => r._measurement == \"mem\") |> filter(fn: (r) => r._field == \"used_percent\") |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false) |> yield(name: \"mean\")"
|
||||
}
|
||||
],
|
||||
"colors": [
|
||||
{
|
||||
"name": "laser",
|
||||
"type": "text",
|
||||
"hex": "#8F8AF4",
|
||||
"value": 3
|
||||
},
|
||||
{
|
||||
"name": "android",
|
||||
"type": "scale",
|
||||
"hex": "#F4CF31",
|
||||
"value": 1
|
||||
}
|
||||
],
|
||||
"axes":[
|
||||
{
|
||||
"name": "x",
|
||||
"label": "x_label",
|
||||
"prefix": "x_prefix",
|
||||
"suffix": "x_suffix",
|
||||
"base": "10",
|
||||
"scale": "linear"
|
||||
},
|
||||
{
|
||||
"name": "y",
|
||||
"label": "y_label",
|
||||
"prefix": "y_prefix",
|
||||
"suffix": "y_suffix",
|
||||
"base": "10",
|
||||
"scale": "linear"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
apiVersion: 0.1.0
|
||||
kind: Package
|
||||
meta:
|
||||
pkgName: pkg_name
|
||||
pkgVersion: 1
|
||||
description: pack description
|
||||
spec:
|
||||
resources:
|
||||
- kind: Dashboard
|
||||
name: dash_1
|
||||
description: desc1
|
||||
charts:
|
||||
- kind: Single_Stat_Plus_Line
|
||||
name: single stat plus line
|
||||
note: single stat plus line note
|
||||
noteOnEmpty: true
|
||||
decimalPlaces: 1
|
||||
prefix: sumtin
|
||||
suffix: days
|
||||
xPos: 1
|
||||
yPos: 2
|
||||
width: 6
|
||||
height: 3
|
||||
shade: true
|
||||
legend:
|
||||
type: leg_type
|
||||
orientation: horizontal
|
||||
queries:
|
||||
- query: >
|
||||
from(bucket: v.bucket) |> range(start: v.timeRangeStart) |> filter(fn: (r) => r._measurement == "mem") |> filter(fn: (r) => r._field == "used_percent") |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false) |> yield(name: "mean")
|
||||
colors:
|
||||
- name: laser
|
||||
type: text
|
||||
hex: "#8F8AF4"
|
||||
value: 3
|
||||
- name: android
|
||||
type: scale
|
||||
hex: "#F4CF31"
|
||||
value: 1
|
||||
axes:
|
||||
- name : "x"
|
||||
label: x_label
|
||||
prefix: x_prefix
|
||||
suffix: x_suffix
|
||||
base: 10
|
||||
scale: linear
|
||||
- name: "y"
|
||||
label: y_label
|
||||
prefix: y_prefix
|
||||
suffix: y_suffix
|
||||
base: 10
|
||||
scale: linear
|
Loading…
Reference in New Issue