diff --git a/CHANGELOG.md b/CHANGELOG.md index d04c7d2355..c808c9de2e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,33 @@ -## v1.3.6.0 [unreleased] +## v1.3.7.0 [unreleased] ### Bug Fixes 1. [#1715](https://github.com/influxdata/chronograf/pull/1715): Chronograf now renders on IE11. +1. [#1845](https://github.com/influxdata/chronograf/pull/1845): Fix no-scroll bar appearing in the Data Explorer table +1. [#1866](https://github.com/influxdata/chronograf/pull/1866): Fix missing cell type (and consequently single-stat) ### Features -### UI Improvements -1. [#1796](https://github.com/influxdata/chronograf/pull/1796): Add spinner to indicate data is being written +1. [#1863](https://github.com/influxdata/chronograf/pull/1863): Improve 'new-sources' server flag example by adding 'type' key -## v1.3.5.0 [2017-07-25] +### UI Improvements +1. [#1846](https://github.com/influxdata/chronograf/pull/1846): Increase screen real estate of Query Maker in the Cell Editor Overlay + +## v1.3.6.0 [2017-08-08] +### Bug Fixes +1. [#1798](https://github.com/influxdata/chronograf/pull/1798): Fix domain not updating in visualizations when changing time range manually +1. [#1799](https://github.com/influxdata/chronograf/pull/1799): Prevent console error spam from Dygraph's synchronize method when a dashboard has only one graph +1. [#1813](https://github.com/influxdata/chronograf/pull/1813): Guarantee UUID for each Alert Table key to prevent dropping items when keys overlap + +### Features +1. [#1714](https://github.com/influxdata/chronograf/pull/1714): Add ability to edit a dashboard graph's y-axis bounds +1. [#1714](https://github.com/influxdata/chronograf/pull/1714): Add ability to edit a dashboard graph's y-axis label + +### UI Improvements +1. [#1796](https://github.com/influxdata/chronograf/pull/1796): Add spinner write data modal to indicate data is being written +1. [#1805](https://github.com/influxdata/chronograf/pull/1805): Fix bar graphs overlapping +1. [#1805](https://github.com/influxdata/chronograf/pull/1805): Assign a series consistent coloring when it appears in multiple cells +1. [#1800](https://github.com/influxdata/chronograf/pull/1800): Increase size of line protocol manual entry in Data Explorer's Write Data overlay +1. [#1812](https://github.com/influxdata/chronograf/pull/1812): Improve error message when request for Status Page News Feed fails + +## v1.3.5.0 [2017-07-27] ### Bug Fixes 1. [#1708](https://github.com/influxdata/chronograf/pull/1708): Fix z-index issue in dashboard cell context menu 1. [#1752](https://github.com/influxdata/chronograf/pull/1752): Clarify BoltPath server flag help text by making example the default path diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 27f84f45ce..f5090bb7c4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -21,7 +21,7 @@ We really like to receive feature requests, as it helps us prioritize our work. Contributing to the source code ------------------------------- -Chronograf is built using Go for its API backend and serving the front-end assets. The front-end visualization is built with React and uses NPM for package management. The assumption is that all your Go development are done in `$GOPATH/src`. `GOPATH` can be any directory under which Chronograf and all its dependencies will be cloned. For full details on the project structure, follow along below. +Chronograf is built using Go for its API backend and serving the front-end assets. The front-end visualization is built with React and uses Yarn for package management. The assumption is that all your Go development are done in `$GOPATH/src`. `GOPATH` can be any directory under which Chronograf and all its dependencies will be cloned. For full details on the project structure, follow along below. Submitting a pull request ------------------------- @@ -43,9 +43,9 @@ Signing the CLA If you are going to be contributing back to Chronograf please take a second to sign our CLA, which can be found [on our website](https://influxdata.com/community/cla/). -Installing NPM +Installing Yarn -------------- -You'll need to install NPM to manage the JavaScript modules that the front-end uses. This varies depending on what platform you're developing on, but you should be able to find an installer on [the NPM downloads page](https://nodejs.org/en/download/). +You'll need to install Yarn to manage the JavaScript modules that the front-end uses. This varies depending on what platform you're developing on, but you should be able to find an installer on [the Yarn installation page](https://yarnpkg.com/en/docs/install). Installing Go ------------- @@ -105,7 +105,7 @@ Retaining the directory structure `$GOPATH/src/github.com/influxdata` is necessa Build and Test -------------- -Make sure you have `go` and `npm` installed and the project structure as shown above. We provide a `Makefile` to get up and running quickly, so all you'll need to do is run the following: +Make sure you have `go` and `yarn` installed and the project structure as shown above. We provide a `Makefile` to get up and running quickly, so all you'll need to do is run the following: ```bash cd $GOPATH/src/github.com/influxdata/chronograf diff --git a/Makefile b/Makefile index 25c9df79b0..a4de270cc2 100644 --- a/Makefile +++ b/Makefile @@ -60,11 +60,11 @@ canned/bin_gen.go: canned/*.json go generate -x ./canned .jssrc: $(UISOURCES) - cd ui && npm run build + cd ui && yarn run build @touch .jssrc .dev-jssrc: $(UISOURCES) - cd ui && npm run build:dev + cd ui && yarn run build:dev @touch .dev-jssrc dep: .jsdep .godep @@ -98,7 +98,7 @@ gotestrace: go test -race `go list ./... | grep -v /vendor/` jstest: - cd ui && npm test + cd ui && yarn test run: ${BINARY} ./chronograf @@ -108,7 +108,7 @@ run-dev: chronogiraffe clean: if [ -f ${BINARY} ] ; then rm ${BINARY} ; fi - cd ui && npm run clean + cd ui && yarn run clean cd ui && rm -rf node_modules rm -f dist/dist_gen.go canned/bin_gen.go server/swagger_gen.go @rm -f .godep .jsdep .jssrc .dev-jssrc .bindata diff --git a/bolt/internal/internal.go b/bolt/internal/internal.go index 912d125618..6d5fbc6b74 100644 --- a/bolt/internal/internal.go +++ b/bolt/internal/internal.go @@ -183,14 +183,9 @@ func MarshalDashboard(d chronograf.Dashboard) ([]byte, error) { axes := make(map[string]*Axis, len(c.Axes)) for a, r := range c.Axes { - // need to explicitly allocate a new array because r.Bounds is - // over-written and the resulting slices from previous iterations will - // point to later iteration's data. It is _not_ enough to simply re-slice - // r.Bounds - axis := [2]int64{} - copy(axis[:], r.Bounds[:2]) axes[a] = &Axis{ - Bounds: axis[:], + Bounds: r.Bounds, + Label: r.Label, } } @@ -269,9 +264,16 @@ func UnmarshalDashboard(data []byte, d *chronograf.Dashboard) error { axes := make(map[string]chronograf.Axis, len(c.Axes)) for a, r := range c.Axes { - axis := chronograf.Axis{} - copy(axis.Bounds[:], r.Bounds[:2]) - axes[a] = axis + if r.Bounds != nil { + axes[a] = chronograf.Axis{ + Bounds: r.Bounds, + Label: r.Label, + } + } else { + axes[a] = chronograf.Axis{ + Bounds: []string{}, + } + } } cells[i] = chronograf.DashboardCell{ diff --git a/bolt/internal/internal.pb.go b/bolt/internal/internal.pb.go index eef73feb1b..d8eb0e222f 100644 --- a/bolt/internal/internal.pb.go +++ b/bolt/internal/internal.pb.go @@ -118,7 +118,9 @@ func (m *DashboardCell) GetAxes() map[string]*Axis { } type Axis struct { - Bounds []int64 `protobuf:"varint,1,rep,name=bounds" json:"bounds,omitempty"` + LegacyBounds []int64 `protobuf:"varint,1,rep,name=legacyBounds" json:"legacyBounds,omitempty"` + Bounds []string `protobuf:"bytes,2,rep,name=bounds" json:"bounds,omitempty"` + Label string `protobuf:"bytes,3,opt,name=label,proto3" json:"label,omitempty"` } func (m *Axis) Reset() { *m = Axis{} } @@ -313,65 +315,66 @@ func init() { func init() { proto.RegisterFile("internal.proto", fileDescriptorInternal) } var fileDescriptorInternal = []byte{ - // 952 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xbc, 0x56, 0xcf, 0x8e, 0xe3, 0xc4, - 0x13, 0x56, 0xc7, 0x76, 0x12, 0x57, 0x66, 0xe7, 0xf7, 0x53, 0x6b, 0xc5, 0x9a, 0x45, 0x42, 0xc1, - 0x02, 0x29, 0x20, 0x31, 0xa0, 0x5d, 0x21, 0x21, 0x6e, 0x99, 0x09, 0x5a, 0x85, 0x99, 0x5d, 0x86, - 0xce, 0xcc, 0x70, 0x42, 0xab, 0x4e, 0x52, 0x99, 0x58, 0xeb, 0xc4, 0xa6, 0x6d, 0x4f, 0xe2, 0xb7, - 0xe0, 0x09, 0x90, 0x90, 0x38, 0x71, 0xe0, 0xc0, 0x0b, 0xf0, 0x10, 0xbc, 0x10, 0xaa, 0xee, 0xf6, - 0x9f, 0xb0, 0xb3, 0x68, 0x4f, 0xdc, 0xfa, 0xab, 0xea, 0x7c, 0xe5, 0xfe, 0xea, 0xab, 0x52, 0xe0, - 0x38, 0xda, 0xe6, 0xa8, 0xb6, 0x32, 0x3e, 0x49, 0x55, 0x92, 0x27, 0xbc, 0x5f, 0xe1, 0xf0, 0xf7, - 0x0e, 0x74, 0x67, 0x49, 0xa1, 0x16, 0xc8, 0x8f, 0xa1, 0x33, 0x9d, 0x04, 0x6c, 0xc8, 0x46, 0x8e, - 0xe8, 0x4c, 0x27, 0x9c, 0x83, 0xfb, 0x42, 0x6e, 0x30, 0xe8, 0x0c, 0xd9, 0xc8, 0x17, 0xfa, 0x4c, - 0xb1, 0xab, 0x32, 0xc5, 0xc0, 0x31, 0x31, 0x3a, 0xf3, 0xc7, 0xd0, 0xbf, 0xce, 0x88, 0x6d, 0x83, - 0x81, 0xab, 0xe3, 0x35, 0xa6, 0xdc, 0xa5, 0xcc, 0xb2, 0x5d, 0xa2, 0x96, 0x81, 0x67, 0x72, 0x15, - 0xe6, 0xff, 0x07, 0xe7, 0x5a, 0x5c, 0x04, 0x5d, 0x1d, 0xa6, 0x23, 0x0f, 0xa0, 0x37, 0xc1, 0x95, - 0x2c, 0xe2, 0x3c, 0xe8, 0x0d, 0xd9, 0xa8, 0x2f, 0x2a, 0x48, 0x3c, 0x57, 0x18, 0xe3, 0xad, 0x92, - 0xab, 0xa0, 0x6f, 0x78, 0x2a, 0xcc, 0x4f, 0x80, 0x4f, 0xb7, 0x19, 0x2e, 0x0a, 0x85, 0xb3, 0x57, - 0x51, 0x7a, 0x83, 0x2a, 0x5a, 0x95, 0x81, 0xaf, 0x09, 0xee, 0xc9, 0x50, 0x95, 0xe7, 0x98, 0x4b, - 0xaa, 0x0d, 0x9a, 0xaa, 0x82, 0x3c, 0x84, 0xa3, 0xd9, 0x5a, 0x2a, 0x5c, 0xce, 0x70, 0xa1, 0x30, - 0x0f, 0x06, 0x3a, 0x7d, 0x10, 0x0b, 0x7f, 0x62, 0xe0, 0x4f, 0x64, 0xb6, 0x9e, 0x27, 0x52, 0x2d, - 0xdf, 0x4a, 0xb3, 0x4f, 0xc1, 0x5b, 0x60, 0x1c, 0x67, 0x81, 0x33, 0x74, 0x46, 0x83, 0x27, 0x8f, - 0x4e, 0xea, 0x66, 0xd4, 0x3c, 0x67, 0x18, 0xc7, 0xc2, 0xdc, 0xe2, 0x9f, 0x83, 0x9f, 0xe3, 0x26, - 0x8d, 0x65, 0x8e, 0x59, 0xe0, 0xea, 0x9f, 0xf0, 0xe6, 0x27, 0x57, 0x36, 0x25, 0x9a, 0x4b, 0xe1, - 0x6f, 0x1d, 0x78, 0x70, 0x40, 0xc5, 0x8f, 0x80, 0xed, 0xf5, 0x57, 0x79, 0x82, 0xed, 0x09, 0x95, - 0xfa, 0x8b, 0x3c, 0xc1, 0x4a, 0x42, 0x3b, 0xdd, 0x3f, 0x4f, 0xb0, 0x1d, 0xa1, 0xb5, 0xee, 0x9a, - 0x27, 0xd8, 0x9a, 0x7f, 0x0c, 0xbd, 0x1f, 0x0b, 0x54, 0x11, 0x66, 0x81, 0xa7, 0x2b, 0xff, 0xaf, - 0xa9, 0xfc, 0x5d, 0x81, 0xaa, 0x14, 0x55, 0x9e, 0x5e, 0xaa, 0x3b, 0x6e, 0xda, 0xa7, 0xcf, 0x14, - 0xcb, 0xc9, 0x1d, 0x3d, 0x13, 0xa3, 0xb3, 0x55, 0xc8, 0xf4, 0x8c, 0x14, 0xfa, 0x02, 0x5c, 0xb9, - 0xc7, 0x2c, 0xf0, 0x35, 0xff, 0x07, 0x6f, 0x10, 0xe3, 0x64, 0xbc, 0xc7, 0xec, 0xeb, 0x6d, 0xae, - 0x4a, 0xa1, 0xaf, 0x3f, 0x7e, 0x06, 0x7e, 0x1d, 0x22, 0xe7, 0xbc, 0xc2, 0x52, 0x3f, 0xd0, 0x17, - 0x74, 0xe4, 0x1f, 0x82, 0x77, 0x27, 0xe3, 0xc2, 0x08, 0x3f, 0x78, 0x72, 0xdc, 0xd0, 0x8e, 0xf7, - 0x51, 0x26, 0x4c, 0xf2, 0xab, 0xce, 0x97, 0x2c, 0x7c, 0x1f, 0x5c, 0x0a, 0xf1, 0x77, 0xa0, 0x3b, - 0x4f, 0x8a, 0xed, 0x32, 0x0b, 0xd8, 0xd0, 0x19, 0x39, 0xc2, 0xa2, 0xf0, 0x4f, 0x46, 0x56, 0x33, - 0xd2, 0xb6, 0xda, 0x6b, 0x3e, 0xfe, 0x5d, 0xe8, 0x93, 0xec, 0x2f, 0xef, 0xa4, 0xb2, 0x2d, 0xee, - 0x11, 0xbe, 0x91, 0x8a, 0x7f, 0x06, 0x5d, 0x5d, 0xe4, 0x9e, 0x36, 0x57, 0x74, 0x37, 0x94, 0x17, - 0xf6, 0x5a, 0x2d, 0x96, 0xdb, 0x12, 0xeb, 0x21, 0x78, 0xb1, 0x9c, 0x63, 0x6c, 0x67, 0xc5, 0x00, - 0x32, 0x10, 0xa9, 0x5e, 0x6a, 0xad, 0xef, 0x65, 0x36, 0xbd, 0x31, 0xb7, 0xc2, 0x6b, 0x78, 0x70, - 0x50, 0xb1, 0xae, 0xc4, 0x0e, 0x2b, 0x35, 0x82, 0xf9, 0x56, 0x20, 0x1a, 0xb3, 0x0c, 0x63, 0x5c, - 0xe4, 0xb8, 0xd4, 0x16, 0xe9, 0x8b, 0x1a, 0x87, 0xbf, 0xb0, 0x86, 0x57, 0xd7, 0xa3, 0x41, 0x5a, - 0x24, 0x9b, 0x8d, 0xdc, 0x2e, 0x2d, 0x75, 0x05, 0x49, 0xb7, 0xe5, 0xdc, 0x52, 0x77, 0x96, 0x73, - 0xc2, 0x2a, 0xb5, 0x4b, 0xa3, 0xa3, 0x52, 0x3e, 0x84, 0xc1, 0x06, 0x65, 0x56, 0x28, 0xdc, 0xe0, - 0x36, 0xb7, 0x12, 0xb4, 0x43, 0xfc, 0x11, 0xf4, 0x72, 0x79, 0xfb, 0x92, 0xda, 0x6c, 0xb4, 0xe8, - 0xe6, 0xf2, 0xf6, 0x1c, 0x4b, 0xfe, 0x1e, 0xf8, 0xab, 0x08, 0xe3, 0xa5, 0x4e, 0x19, 0xf3, 0xf5, - 0x75, 0xe0, 0x1c, 0xcb, 0xf0, 0x57, 0x06, 0xdd, 0x19, 0xaa, 0x3b, 0x54, 0x6f, 0x35, 0x99, 0xed, - 0xcd, 0xe5, 0xfc, 0xcb, 0xe6, 0x72, 0xef, 0xdf, 0x5c, 0x5e, 0xb3, 0xb9, 0x1e, 0x82, 0x37, 0x53, - 0x8b, 0xe9, 0x44, 0x7f, 0x91, 0x23, 0x0c, 0x20, 0x8f, 0x8d, 0x17, 0x79, 0x74, 0x87, 0x76, 0x9d, - 0x59, 0x14, 0xfe, 0xcc, 0xa0, 0x7b, 0x21, 0xcb, 0xa4, 0xc8, 0x5f, 0x73, 0xd8, 0x10, 0x06, 0xe3, - 0x34, 0x8d, 0xa3, 0x85, 0xcc, 0xa3, 0x64, 0x6b, 0xbf, 0xb6, 0x1d, 0xa2, 0x1b, 0xcf, 0x5b, 0xda, - 0x99, 0xef, 0x6e, 0x87, 0x68, 0x18, 0xce, 0xf4, 0xc2, 0x31, 0xdb, 0xa3, 0x35, 0x0c, 0x66, 0xcf, - 0xe8, 0x24, 0x3d, 0x70, 0x5c, 0xe4, 0xc9, 0x2a, 0x4e, 0x76, 0xfa, 0x25, 0x7d, 0x51, 0xe3, 0xf0, - 0x2f, 0x06, 0xee, 0x7f, 0xb5, 0x48, 0x8e, 0x80, 0x45, 0xb6, 0x91, 0x2c, 0xaa, 0xd7, 0x4a, 0xaf, - 0xb5, 0x56, 0x02, 0xe8, 0x95, 0x4a, 0x6e, 0x6f, 0x31, 0x0b, 0xfa, 0x7a, 0x56, 0x2b, 0xa8, 0x33, - 0x7a, 0x46, 0xcc, 0x3e, 0xf1, 0x45, 0x05, 0x6b, 0xcf, 0x43, 0xe3, 0xf9, 0xf0, 0x0f, 0x06, 0x5e, - 0xed, 0xdc, 0xb3, 0x43, 0xe7, 0x9e, 0x35, 0xce, 0x9d, 0x9c, 0x56, 0xce, 0x9d, 0x9c, 0x12, 0x16, - 0x97, 0x95, 0x73, 0xc5, 0x25, 0xa9, 0xf6, 0x4c, 0x25, 0x45, 0x7a, 0x5a, 0x1a, 0x79, 0x7d, 0x51, - 0x63, 0x6a, 0xf7, 0xf7, 0x6b, 0x54, 0xf6, 0xcd, 0xbe, 0xb0, 0x88, 0xcc, 0x71, 0xa1, 0xa7, 0xda, - 0xbc, 0xd2, 0x00, 0xfe, 0x11, 0x78, 0x82, 0x5e, 0xa1, 0x9f, 0x7a, 0x20, 0x90, 0x0e, 0x0b, 0x93, - 0x0d, 0x9f, 0xda, 0x6b, 0xc4, 0x72, 0x9d, 0xa6, 0xa8, 0xac, 0xa7, 0x0d, 0xd0, 0xdc, 0xc9, 0x0e, - 0xcd, 0x3a, 0x72, 0x84, 0x01, 0xe1, 0x0f, 0xe0, 0x8f, 0x63, 0x54, 0xb9, 0x28, 0xe2, 0xd7, 0x97, - 0x18, 0x07, 0xf7, 0x9b, 0xd9, 0xb7, 0x2f, 0xaa, 0x49, 0xa0, 0x73, 0xe3, 0x5f, 0xe7, 0x1f, 0xfe, - 0x3d, 0x97, 0xa9, 0x9c, 0x4e, 0x74, 0x63, 0x1d, 0x61, 0x51, 0xf8, 0x09, 0xb8, 0x34, 0x27, 0x2d, - 0x66, 0xf7, 0x4d, 0x33, 0x36, 0xef, 0xea, 0x7f, 0x1c, 0x4f, 0xff, 0x0e, 0x00, 0x00, 0xff, 0xff, - 0x94, 0xd8, 0xce, 0x85, 0x83, 0x08, 0x00, 0x00, + // 974 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xbc, 0x56, 0xdf, 0x6e, 0xe3, 0xc4, + 0x17, 0xd6, 0xc4, 0x76, 0x12, 0x9f, 0x76, 0xfb, 0xfb, 0x69, 0xb4, 0x62, 0xcd, 0x72, 0x13, 0x2c, + 0x90, 0x02, 0x12, 0x05, 0xed, 0x0a, 0x09, 0x71, 0x97, 0x36, 0x68, 0x55, 0xda, 0x5d, 0xca, 0xa4, + 0x2d, 0xdc, 0xa0, 0xd5, 0xc4, 0x39, 0x4d, 0xac, 0x75, 0x62, 0x33, 0xb6, 0x9b, 0xf8, 0x2d, 0x78, + 0x02, 0x24, 0x24, 0xae, 0xb8, 0xe0, 0x82, 0x17, 0xe0, 0x21, 0x78, 0x21, 0x74, 0x66, 0xc6, 0x7f, + 0xc2, 0x76, 0xd1, 0x5e, 0x71, 0x37, 0xdf, 0x39, 0xe3, 0x6f, 0x66, 0xbe, 0xf3, 0x9d, 0x23, 0xc3, + 0x51, 0xbc, 0x29, 0x50, 0x6d, 0x64, 0x72, 0x9c, 0xa9, 0xb4, 0x48, 0xf9, 0xb0, 0xc6, 0xe1, 0xef, + 0x3d, 0xe8, 0xcf, 0xd2, 0x52, 0x45, 0xc8, 0x8f, 0xa0, 0x77, 0x36, 0x0d, 0xd8, 0x88, 0x8d, 0x1d, + 0xd1, 0x3b, 0x9b, 0x72, 0x0e, 0xee, 0x0b, 0xb9, 0xc6, 0xa0, 0x37, 0x62, 0x63, 0x5f, 0xe8, 0x35, + 0xc5, 0xae, 0xaa, 0x0c, 0x03, 0xc7, 0xc4, 0x68, 0xcd, 0x1f, 0xc3, 0xf0, 0x3a, 0x27, 0xb6, 0x35, + 0x06, 0xae, 0x8e, 0x37, 0x98, 0x72, 0x97, 0x32, 0xcf, 0xb7, 0xa9, 0x5a, 0x04, 0x9e, 0xc9, 0xd5, + 0x98, 0xff, 0x1f, 0x9c, 0x6b, 0x71, 0x11, 0xf4, 0x75, 0x98, 0x96, 0x3c, 0x80, 0xc1, 0x14, 0x6f, + 0x65, 0x99, 0x14, 0xc1, 0x60, 0xc4, 0xc6, 0x43, 0x51, 0x43, 0xe2, 0xb9, 0xc2, 0x04, 0x97, 0x4a, + 0xde, 0x06, 0x43, 0xc3, 0x53, 0x63, 0x7e, 0x0c, 0xfc, 0x6c, 0x93, 0x63, 0x54, 0x2a, 0x9c, 0xbd, + 0x8a, 0xb3, 0x1b, 0x54, 0xf1, 0x6d, 0x15, 0xf8, 0x9a, 0xe0, 0x9e, 0x0c, 0x9d, 0xf2, 0x1c, 0x0b, + 0x49, 0x67, 0x83, 0xa6, 0xaa, 0x21, 0x0f, 0xe1, 0x70, 0xb6, 0x92, 0x0a, 0x17, 0x33, 0x8c, 0x14, + 0x16, 0xc1, 0x81, 0x4e, 0xef, 0xc5, 0xc2, 0x9f, 0x18, 0xf8, 0x53, 0x99, 0xaf, 0xe6, 0xa9, 0x54, + 0x8b, 0xb7, 0xd2, 0xec, 0x13, 0xf0, 0x22, 0x4c, 0x92, 0x3c, 0x70, 0x46, 0xce, 0xf8, 0xe0, 0xc9, + 0xa3, 0xe3, 0xa6, 0x18, 0x0d, 0xcf, 0x29, 0x26, 0x89, 0x30, 0xbb, 0xf8, 0x67, 0xe0, 0x17, 0xb8, + 0xce, 0x12, 0x59, 0x60, 0x1e, 0xb8, 0xfa, 0x13, 0xde, 0x7e, 0x72, 0x65, 0x53, 0xa2, 0xdd, 0x14, + 0xfe, 0xd6, 0x83, 0x07, 0x7b, 0x54, 0xfc, 0x10, 0xd8, 0x4e, 0xdf, 0xca, 0x13, 0x6c, 0x47, 0xa8, + 0xd2, 0x37, 0xf2, 0x04, 0xab, 0x08, 0x6d, 0x75, 0xfd, 0x3c, 0xc1, 0xb6, 0x84, 0x56, 0xba, 0x6a, + 0x9e, 0x60, 0x2b, 0xfe, 0x11, 0x0c, 0x7e, 0x2c, 0x51, 0xc5, 0x98, 0x07, 0x9e, 0x3e, 0xf9, 0x7f, + 0xed, 0xc9, 0xdf, 0x96, 0xa8, 0x2a, 0x51, 0xe7, 0xe9, 0xa5, 0xba, 0xe2, 0xa6, 0x7c, 0x7a, 0x4d, + 0xb1, 0x82, 0xdc, 0x31, 0x30, 0x31, 0x5a, 0x5b, 0x85, 0x4c, 0xcd, 0x48, 0xa1, 0xcf, 0xc1, 0x95, + 0x3b, 0xcc, 0x03, 0x5f, 0xf3, 0xbf, 0xff, 0x06, 0x31, 0x8e, 0x27, 0x3b, 0xcc, 0xbf, 0xda, 0x14, + 0xaa, 0x12, 0x7a, 0xfb, 0xe3, 0x67, 0xe0, 0x37, 0x21, 0x72, 0xce, 0x2b, 0xac, 0xf4, 0x03, 0x7d, + 0x41, 0x4b, 0xfe, 0x01, 0x78, 0x77, 0x32, 0x29, 0x8d, 0xf0, 0x07, 0x4f, 0x8e, 0x5a, 0xda, 0xc9, + 0x2e, 0xce, 0x85, 0x49, 0x7e, 0xd9, 0xfb, 0x82, 0x85, 0xdf, 0x83, 0x4b, 0x21, 0xaa, 0x75, 0x82, + 0x4b, 0x19, 0x55, 0x27, 0x69, 0xb9, 0x59, 0xe4, 0x01, 0x1b, 0x39, 0x63, 0x47, 0xec, 0xc5, 0xf8, + 0x3b, 0xd0, 0x9f, 0x9b, 0x6c, 0x6f, 0xe4, 0x8c, 0x7d, 0x61, 0x11, 0x7f, 0x08, 0x5e, 0x22, 0xe7, + 0x98, 0xd8, 0x36, 0x30, 0x20, 0xfc, 0x93, 0x91, 0x49, 0x4d, 0x51, 0x3a, 0xc6, 0x30, 0xcf, 0x7e, + 0x17, 0x86, 0x54, 0xb0, 0x97, 0x77, 0x52, 0x59, 0x73, 0x0c, 0x08, 0xdf, 0x48, 0xc5, 0x3f, 0x85, + 0xbe, 0xbe, 0xde, 0x3d, 0x06, 0xa9, 0xe9, 0x6e, 0x28, 0x2f, 0xec, 0xb6, 0x46, 0x66, 0xb7, 0x23, + 0x73, 0x73, 0x25, 0xaf, 0x73, 0x25, 0xb2, 0x1e, 0xd5, 0xab, 0xd2, 0x55, 0xba, 0x97, 0xd9, 0x54, + 0xd5, 0xec, 0x0a, 0xaf, 0xe1, 0xc1, 0xde, 0x89, 0xcd, 0x49, 0x6c, 0xff, 0xa4, 0x56, 0x6a, 0xdf, + 0x4a, 0x4b, 0x0d, 0x9a, 0x63, 0x82, 0x51, 0x81, 0x0b, 0xad, 0xca, 0x50, 0x34, 0x38, 0xfc, 0x85, + 0xb5, 0xbc, 0xfa, 0x3c, 0x6a, 0xc1, 0x28, 0x5d, 0xaf, 0xe5, 0x66, 0x61, 0xa9, 0x6b, 0x48, 0xba, + 0x2d, 0xe6, 0x96, 0xba, 0xb7, 0x98, 0x13, 0x56, 0x99, 0xd5, 0xb9, 0xa7, 0x32, 0x3e, 0x82, 0x83, + 0x35, 0xca, 0xbc, 0x54, 0xb8, 0xc6, 0x4d, 0x61, 0x25, 0xe8, 0x86, 0xf8, 0x23, 0x18, 0x14, 0x72, + 0xf9, 0x92, 0x0c, 0x62, 0xb4, 0xe8, 0x17, 0x72, 0x79, 0x8e, 0x15, 0x7f, 0x0f, 0xfc, 0xdb, 0x18, + 0x93, 0x85, 0x4e, 0x19, 0xdb, 0x0e, 0x75, 0xe0, 0x1c, 0xab, 0xf0, 0x57, 0x06, 0xfd, 0x19, 0xaa, + 0x3b, 0x54, 0x6f, 0xd5, 0xd3, 0xdd, 0x99, 0xe7, 0xfc, 0xcb, 0xcc, 0x73, 0xef, 0x9f, 0x79, 0x5e, + 0x3b, 0xf3, 0x1e, 0x82, 0x37, 0x53, 0xd1, 0xd9, 0x54, 0xdf, 0xc8, 0x11, 0x06, 0x90, 0xf3, 0x26, + 0x51, 0x11, 0xdf, 0xa1, 0x1d, 0x84, 0x16, 0x85, 0x3f, 0x33, 0xe8, 0x5f, 0xc8, 0x2a, 0x2d, 0x8b, + 0xd7, 0x1c, 0x36, 0x82, 0x83, 0x49, 0x96, 0x25, 0x71, 0x24, 0x8b, 0x38, 0xdd, 0xd8, 0xdb, 0x76, + 0x43, 0xb4, 0xe3, 0x79, 0x47, 0x3b, 0x73, 0xef, 0x6e, 0x88, 0xda, 0xe8, 0x54, 0x8f, 0x2a, 0x33, + 0x77, 0x3a, 0x6d, 0x64, 0x26, 0x94, 0x4e, 0xd2, 0x03, 0x27, 0x65, 0x91, 0xde, 0x26, 0xe9, 0x56, + 0xbf, 0x64, 0x28, 0x1a, 0x1c, 0xfe, 0xc5, 0xc0, 0xfd, 0xaf, 0x46, 0xd0, 0x21, 0xb0, 0xd8, 0x16, + 0x92, 0xc5, 0xcd, 0x40, 0x1a, 0x74, 0x06, 0x52, 0x00, 0x83, 0x4a, 0xc9, 0xcd, 0x12, 0xf3, 0x60, + 0xa8, 0xfb, 0xbb, 0x86, 0x3a, 0xa3, 0x7b, 0xc4, 0x4c, 0x22, 0x5f, 0xd4, 0xb0, 0xf1, 0x3c, 0xb4, + 0x9e, 0x0f, 0xff, 0x60, 0xe0, 0x35, 0xce, 0x3d, 0xdd, 0x77, 0xee, 0x69, 0xeb, 0xdc, 0xe9, 0x49, + 0xed, 0xdc, 0xe9, 0x09, 0x61, 0x71, 0x59, 0x3b, 0x57, 0x5c, 0x92, 0x6a, 0xcf, 0x54, 0x5a, 0x66, + 0x27, 0x95, 0x91, 0xd7, 0x17, 0x0d, 0xa6, 0x72, 0x7f, 0xb7, 0x42, 0x65, 0xdf, 0xec, 0x0b, 0x8b, + 0xc8, 0x1c, 0x17, 0xba, 0xab, 0xcd, 0x2b, 0x0d, 0xe0, 0x1f, 0x82, 0x27, 0xe8, 0x15, 0xfa, 0xa9, + 0x7b, 0x02, 0xe9, 0xb0, 0x30, 0xd9, 0xf0, 0xa9, 0xdd, 0x46, 0x2c, 0xd7, 0x59, 0x86, 0xca, 0x7a, + 0xda, 0x00, 0xcd, 0x9d, 0x6e, 0xd1, 0x8c, 0x23, 0x47, 0x18, 0x10, 0xfe, 0x00, 0xfe, 0x24, 0x41, + 0x55, 0x88, 0x32, 0x79, 0x7d, 0x88, 0x71, 0x70, 0xbf, 0x9e, 0x7d, 0xf3, 0xa2, 0xee, 0x04, 0x5a, + 0xb7, 0xfe, 0x75, 0xfe, 0xe1, 0xdf, 0x73, 0x99, 0xc9, 0xb3, 0xa9, 0x2e, 0xac, 0x23, 0x2c, 0x0a, + 0x3f, 0x06, 0x97, 0xfa, 0xa4, 0xc3, 0xec, 0xbe, 0xa9, 0xc7, 0xe6, 0x7d, 0xfd, 0xaf, 0xf2, 0xf4, + 0xef, 0x00, 0x00, 0x00, 0xff, 0xff, 0x79, 0x79, 0x87, 0x37, 0xbd, 0x08, 0x00, 0x00, } diff --git a/bolt/internal/internal.proto b/bolt/internal/internal.proto index 5154a216a8..c2c208693d 100644 --- a/bolt/internal/internal.proto +++ b/bolt/internal/internal.proto @@ -35,7 +35,9 @@ message DashboardCell { } message Axis { - repeated int64 bounds = 1; // bounds are an ordered 2-tuple consisting of lower and upper axis extents, respectively + repeated int64 legacyBounds = 1; // legacyBounds are an ordered 2-tuple consisting of lower and upper axis extents, respectively + repeated string bounds = 2; // bounds are an arbitrary list of client-defined bounds. + string label = 3; // label is a description of this axis } message Template { diff --git a/bolt/internal/internal_test.go b/bolt/internal/internal_test.go index cbfa2d459a..2a17f67378 100644 --- a/bolt/internal/internal_test.go +++ b/bolt/internal/internal_test.go @@ -160,7 +160,8 @@ func Test_MarshalDashboard(t *testing.T) { }, Axes: map[string]chronograf.Axis{ "y": chronograf.Axis{ - Bounds: [2]int64{0, 100}, + Bounds: []string{"0", "3", "1-7", "foo"}, + Label: "foo", }, }, Type: "line", @@ -179,3 +180,149 @@ func Test_MarshalDashboard(t *testing.T) { t.Fatalf("Dashboard protobuf copy error: diff follows:\n%s", cmp.Diff(dashboard, actual)) } } + +func Test_MarshalDashboard_WithLegacyBounds(t *testing.T) { + dashboard := chronograf.Dashboard{ + ID: 1, + Cells: []chronograf.DashboardCell{ + { + ID: "9b5367de-c552-4322-a9e8-7f384cbd235c", + X: 0, + Y: 0, + W: 4, + H: 4, + Name: "Super awesome query", + Queries: []chronograf.DashboardQuery{ + { + Command: "select * from cpu", + Label: "CPU Utilization", + Range: &chronograf.Range{ + Upper: int64(100), + }, + }, + }, + Axes: map[string]chronograf.Axis{ + "y": chronograf.Axis{ + LegacyBounds: [2]int64{0, 5}, + }, + }, + Type: "line", + }, + }, + Templates: []chronograf.Template{}, + Name: "Dashboard", + } + + expected := chronograf.Dashboard{ + ID: 1, + Cells: []chronograf.DashboardCell{ + { + ID: "9b5367de-c552-4322-a9e8-7f384cbd235c", + X: 0, + Y: 0, + W: 4, + H: 4, + Name: "Super awesome query", + Queries: []chronograf.DashboardQuery{ + { + Command: "select * from cpu", + Label: "CPU Utilization", + Range: &chronograf.Range{ + Upper: int64(100), + }, + }, + }, + Axes: map[string]chronograf.Axis{ + "y": chronograf.Axis{ + Bounds: []string{}, + }, + }, + Type: "line", + }, + }, + Templates: []chronograf.Template{}, + Name: "Dashboard", + } + + var actual chronograf.Dashboard + if buf, err := internal.MarshalDashboard(dashboard); err != nil { + t.Fatal("Error marshaling dashboard: err", err) + } else if err := internal.UnmarshalDashboard(buf, &actual); err != nil { + t.Fatal("Error unmarshaling dashboard: err:", err) + } else if !cmp.Equal(expected, actual) { + t.Fatalf("Dashboard protobuf copy error: diff follows:\n%s", cmp.Diff(expected, actual)) + } +} + +func Test_MarshalDashboard_WithNoLegacyBounds(t *testing.T) { + dashboard := chronograf.Dashboard{ + ID: 1, + Cells: []chronograf.DashboardCell{ + { + ID: "9b5367de-c552-4322-a9e8-7f384cbd235c", + X: 0, + Y: 0, + W: 4, + H: 4, + Name: "Super awesome query", + Queries: []chronograf.DashboardQuery{ + { + Command: "select * from cpu", + Label: "CPU Utilization", + Range: &chronograf.Range{ + Upper: int64(100), + }, + }, + }, + Axes: map[string]chronograf.Axis{ + "y": chronograf.Axis{ + LegacyBounds: [2]int64{}, + }, + }, + Type: "line", + }, + }, + Templates: []chronograf.Template{}, + Name: "Dashboard", + } + + expected := chronograf.Dashboard{ + ID: 1, + Cells: []chronograf.DashboardCell{ + { + ID: "9b5367de-c552-4322-a9e8-7f384cbd235c", + X: 0, + Y: 0, + W: 4, + H: 4, + Name: "Super awesome query", + Queries: []chronograf.DashboardQuery{ + { + Command: "select * from cpu", + Label: "CPU Utilization", + Range: &chronograf.Range{ + Upper: int64(100), + }, + }, + }, + Axes: map[string]chronograf.Axis{ + "y": chronograf.Axis{ + Bounds: []string{}, + }, + }, + Type: "line", + }, + }, + Templates: []chronograf.Template{}, + Name: "Dashboard", + } + + var actual chronograf.Dashboard + if buf, err := internal.MarshalDashboard(dashboard); err != nil { + t.Fatal("Error marshaling dashboard: err", err) + } else if err := internal.UnmarshalDashboard(buf, &actual); err != nil { + t.Fatal("Error unmarshaling dashboard: err:", err) + } else if !cmp.Equal(expected, actual) { + t.Fatalf("Dashboard protobuf copy error: diff follows:\n%s", cmp.Diff(expected, actual)) + } +} diff --git a/chronograf.go b/chronograf.go index 4bf273910c..319065befc 100644 --- a/chronograf.go +++ b/chronograf.go @@ -569,7 +569,9 @@ type Dashboard struct { // Axis represents the visible extents of a visualization type Axis struct { - Bounds [2]int64 `json:"bounds"` // bounds are an ordered 2-tuple consisting of lower and upper axis extents, respectively + Bounds []string `json:"bounds"` // bounds are an arbitrary list of client-defined strings that specify the viewport for a cell + LegacyBounds [2]int64 `json:"-"` // legacy bounds are for testing a migration from an earlier version of axis + Label string `json:"label"` // label is a description of this Axis } // DashboardCell holds visual and query information for a cell diff --git a/mocks/dashboards.go b/mocks/dashboards.go new file mode 100644 index 0000000000..a038f468ba --- /dev/null +++ b/mocks/dashboards.go @@ -0,0 +1,37 @@ +package mocks + +import ( + "context" + + "github.com/influxdata/chronograf" +) + +var _ chronograf.DashboardsStore = &DashboardsStore{} + +type DashboardsStore struct { + AddF func(ctx context.Context, newDashboard chronograf.Dashboard) (chronograf.Dashboard, error) + AllF func(ctx context.Context) ([]chronograf.Dashboard, error) + DeleteF func(ctx context.Context, target chronograf.Dashboard) error + GetF func(ctx context.Context, id chronograf.DashboardID) (chronograf.Dashboard, error) + UpdateF func(ctx context.Context, target chronograf.Dashboard) error +} + +func (d *DashboardsStore) Add(ctx context.Context, newDashboard chronograf.Dashboard) (chronograf.Dashboard, error) { + return d.AddF(ctx, newDashboard) +} + +func (d *DashboardsStore) All(ctx context.Context) ([]chronograf.Dashboard, error) { + return d.AllF(ctx) +} + +func (d *DashboardsStore) Delete(ctx context.Context, target chronograf.Dashboard) error { + return d.DeleteF(ctx, target) +} + +func (d *DashboardsStore) Get(ctx context.Context, id chronograf.DashboardID) (chronograf.Dashboard, error) { + return d.GetF(ctx, id) +} + +func (d *DashboardsStore) Update(ctx context.Context, target chronograf.Dashboard) error { + return d.UpdateF(ctx, target) +} diff --git a/mocks/logger.go b/mocks/logger.go index 46c7bae9f6..f2926e09a3 100644 --- a/mocks/logger.go +++ b/mocks/logger.go @@ -3,6 +3,7 @@ package mocks import ( "fmt" "io" + "testing" "github.com/influxdata/chronograf" ) @@ -72,3 +73,11 @@ func (tl *TestLogger) stringifyArg(arg interface{}) []byte { return []byte("UNKNOWN") } } + +// Dump dumps out logs into a given testing.T's logs +func (tl *TestLogger) Dump(t *testing.T) { + t.Log("== Dumping Test Logs ==") + for _, msg := range tl.Messages { + t.Logf("lvl: %s, msg: %s", msg.Level, msg.Body) + } +} diff --git a/server/cells.go b/server/cells.go index f60437c910..29d78b000d 100644 --- a/server/cells.go +++ b/server/cells.go @@ -30,11 +30,35 @@ func newCellResponses(dID chronograf.DashboardID, dcells []chronograf.DashboardC base := "/chronograf/v1/dashboards" cells := make([]dashboardCellResponse, len(dcells)) for i, cell := range dcells { - if len(cell.Queries) == 0 { - cell.Queries = make([]chronograf.DashboardQuery, 0) + newCell := chronograf.DashboardCell{} + + newCell.Queries = make([]chronograf.DashboardQuery, len(cell.Queries)) + copy(newCell.Queries, cell.Queries) + + // ensure x, y, and y2 axes always returned + labels := []string{"x", "y", "y2"} + newCell.Axes = make(map[string]chronograf.Axis, len(labels)) + + newCell.X = cell.X + newCell.Y = cell.Y + newCell.W = cell.W + newCell.H = cell.H + newCell.Name = cell.Name + newCell.ID = cell.ID + newCell.Type = cell.Type + + for _, lbl := range labels { + if axis, found := cell.Axes[lbl]; !found { + newCell.Axes[lbl] = chronograf.Axis{ + Bounds: []string{}, + } + } else { + newCell.Axes[lbl] = axis + } } + cells[i] = dashboardCellResponse{ - DashboardCell: cell, + DashboardCell: newCell, Links: dashboardCellLinks{ Self: fmt.Sprintf("%s/%d/cells/%s", base, dID, cell.ID), }, diff --git a/server/cells_test.go b/server/cells_test.go index be694b3dff..c0ade6f5f7 100644 --- a/server/cells_test.go +++ b/server/cells_test.go @@ -1,9 +1,18 @@ package server_test import ( + "context" + "encoding/json" + "net/http" + "net/http/httptest" + "net/url" + "strings" "testing" + "github.com/bouk/httprouter" + "github.com/google/go-cmp/cmp" "github.com/influxdata/chronograf" + "github.com/influxdata/chronograf/mocks" "github.com/influxdata/chronograf/server" ) @@ -20,13 +29,13 @@ func Test_Cells_CorrectAxis(t *testing.T) { &chronograf.DashboardCell{ Axes: map[string]chronograf.Axis{ "x": chronograf.Axis{ - Bounds: [2]int64{0, 100}, + Bounds: []string{"0", "100"}, }, "y": chronograf.Axis{ - Bounds: [2]int64{0, 100}, + Bounds: []string{"0", "100"}, }, "y2": chronograf.Axis{ - Bounds: [2]int64{0, 100}, + Bounds: []string{"0", "100"}, }, }, }, @@ -37,10 +46,10 @@ func Test_Cells_CorrectAxis(t *testing.T) { &chronograf.DashboardCell{ Axes: map[string]chronograf.Axis{ "axis of evil": chronograf.Axis{ - Bounds: [2]int64{666, 666}, + Bounds: []string{"666", "666"}, }, "axis of awesome": chronograf.Axis{ - Bounds: [2]int64{1337, 31337}, + Bounds: []string{"1337", "31337"}, }, }, }, @@ -58,3 +67,139 @@ func Test_Cells_CorrectAxis(t *testing.T) { }) } } + +func Test_Service_DashboardCells(t *testing.T) { + cellsTests := []struct { + name string + reqURL *url.URL + ctxParams map[string]string + mockResponse []chronograf.DashboardCell + expected []chronograf.DashboardCell + expectedCode int + }{ + { + "happy path", + &url.URL{ + Path: "/chronograf/v1/dashboards/1/cells", + }, + map[string]string{ + "id": "1", + }, + []chronograf.DashboardCell{}, + []chronograf.DashboardCell{}, + http.StatusOK, + }, + { + "cell axes should always be \"x\", \"y\", and \"y2\"", + &url.URL{ + Path: "/chronograf/v1/dashboards/1/cells", + }, + map[string]string{ + "id": "1", + }, + []chronograf.DashboardCell{ + { + ID: "3899be5a-f6eb-4347-b949-de2f4fbea859", + X: 0, + Y: 0, + W: 4, + H: 4, + Name: "CPU", + Type: "bar", + Queries: []chronograf.DashboardQuery{}, + Axes: map[string]chronograf.Axis{}, + }, + }, + []chronograf.DashboardCell{ + { + ID: "3899be5a-f6eb-4347-b949-de2f4fbea859", + X: 0, + Y: 0, + W: 4, + H: 4, + Name: "CPU", + Type: "bar", + Queries: []chronograf.DashboardQuery{}, + Axes: map[string]chronograf.Axis{ + "x": chronograf.Axis{ + Bounds: []string{}, + }, + "y": chronograf.Axis{ + Bounds: []string{}, + }, + "y2": chronograf.Axis{ + Bounds: []string{}, + }, + }, + }, + }, + http.StatusOK, + }, + } + + for _, test := range cellsTests { + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + // setup context with params + ctx := context.Background() + params := httprouter.Params{} + for k, v := range test.ctxParams { + params = append(params, httprouter.Param{k, v}) + } + ctx = httprouter.WithParams(ctx, params) + + // setup response recorder and request + rr := httptest.NewRecorder() + req := httptest.NewRequest("GET", test.reqURL.RequestURI(), strings.NewReader("")).WithContext(ctx) + + // setup mock DashboardCells store and logger + tlog := &mocks.TestLogger{} + svc := &server.Service{ + DashboardsStore: &mocks.DashboardsStore{ + GetF: func(ctx context.Context, id chronograf.DashboardID) (chronograf.Dashboard, error) { + return chronograf.Dashboard{ + ID: chronograf.DashboardID(1), + Cells: test.mockResponse, + Templates: []chronograf.Template{}, + Name: "empty dashboard", + }, nil + }, + }, + Logger: tlog, + } + + // invoke DashboardCell handler + svc.DashboardCells(rr, req) + + // setup frame to decode response into + respFrame := []struct { + chronograf.DashboardCell + Links json.RawMessage `json:"links"` // ignore links + }{} + + // decode response + resp := rr.Result() + + if resp.StatusCode != test.expectedCode { + tlog.Dump(t) + t.Fatalf("%q - Status codes do not match. Want %d (%s), Got %d (%s)", test.name, test.expectedCode, http.StatusText(test.expectedCode), resp.StatusCode, http.StatusText(resp.StatusCode)) + } + + if err := json.NewDecoder(resp.Body).Decode(&respFrame); err != nil { + t.Fatalf("%q - Error unmarshaling response body: err: %s", test.name, err) + } + + // extract actual + actual := []chronograf.DashboardCell{} + for _, rsp := range respFrame { + actual = append(actual, rsp.DashboardCell) + } + + // compare actual and expected + if !cmp.Equal(actual, test.expected) { + t.Fatalf("%q - Dashboard Cells do not match: diff: %s", test.name, cmp.Diff(actual, test.expected)) + } + }) + } +} diff --git a/server/dashboards.go b/server/dashboards.go index ee9bb8a602..62e6aac1c5 100644 --- a/server/dashboards.go +++ b/server/dashboards.go @@ -28,20 +28,19 @@ type getDashboardsResponse struct { func newDashboardResponse(d chronograf.Dashboard) *dashboardResponse { base := "/chronograf/v1/dashboards" - DashboardDefaults(&d) - AddQueryConfigs(&d) - cells := newCellResponses(d.ID, d.Cells) - templates := newTemplateResponses(d.ID, d.Templates) + dd := AddQueryConfigs(DashboardDefaults(d)) + cells := newCellResponses(dd.ID, dd.Cells) + templates := newTemplateResponses(dd.ID, dd.Templates) return &dashboardResponse{ - ID: d.ID, - Name: d.Name, + ID: dd.ID, + Name: dd.Name, Cells: cells, Templates: templates, Links: dashboardLinks{ - Self: fmt.Sprintf("%s/%d", base, d.ID), - Cells: fmt.Sprintf("%s/%d/cells", base, d.ID), - Templates: fmt.Sprintf("%s/%d/templates", base, d.ID), + Self: fmt.Sprintf("%s/%d", base, dd.ID), + Cells: fmt.Sprintf("%s/%d/cells", base, dd.ID), + Templates: fmt.Sprintf("%s/%d/templates", base, dd.ID), }, } } @@ -229,24 +228,36 @@ func ValidDashboardRequest(d *chronograf.Dashboard) error { return err } } - DashboardDefaults(d) + (*d) = DashboardDefaults(*d) return nil } // DashboardDefaults updates the dashboard with the default values // if none are specified -func DashboardDefaults(d *chronograf.Dashboard) { +func DashboardDefaults(d chronograf.Dashboard) (newDash chronograf.Dashboard) { + newDash.ID = d.ID + newDash.Templates = d.Templates + newDash.Name = d.Name + newDash.Cells = make([]chronograf.DashboardCell, len(d.Cells)) + for i, c := range d.Cells { CorrectWidthHeight(&c) - d.Cells[i] = c + newDash.Cells[i] = c } + return } // AddQueryConfigs updates all the celsl in the dashboard to have query config // objects corresponding to their influxql queries. -func AddQueryConfigs(d *chronograf.Dashboard) { +func AddQueryConfigs(d chronograf.Dashboard) (newDash chronograf.Dashboard) { + newDash.ID = d.ID + newDash.Templates = d.Templates + newDash.Name = d.Name + newDash.Cells = make([]chronograf.DashboardCell, len(d.Cells)) + for i, c := range d.Cells { AddQueryConfig(&c) - d.Cells[i] = c + newDash.Cells[i] = c } + return } diff --git a/server/dashboards_test.go b/server/dashboards_test.go index b5116913c5..ff740ba001 100644 --- a/server/dashboards_test.go +++ b/server/dashboards_test.go @@ -128,7 +128,7 @@ func TestDashboardDefaults(t *testing.T) { }, } for _, tt := range tests { - if DashboardDefaults(&tt.d); !reflect.DeepEqual(tt.d, tt.want) { + if actual := DashboardDefaults(tt.d); !reflect.DeepEqual(actual, tt.want) { t.Errorf("%q. DashboardDefaults() = %v, want %v", tt.name, tt.d, tt.want) } } @@ -222,10 +222,11 @@ func Test_newDashboardResponse(t *testing.T) { }, Axes: map[string]chronograf.Axis{ "x": chronograf.Axis{ - Bounds: [2]int64{0, 100}, + Bounds: []string{"0", "100"}, }, "y": chronograf.Axis{ - Bounds: [2]int64{2, 95}, + Bounds: []string{"2", "95"}, + Label: "foo", }, }, }, @@ -268,10 +269,14 @@ func Test_newDashboardResponse(t *testing.T) { }, Axes: map[string]chronograf.Axis{ "x": chronograf.Axis{ - Bounds: [2]int64{0, 100}, + Bounds: []string{"0", "100"}, }, "y": chronograf.Axis{ - Bounds: [2]int64{2, 95}, + Bounds: []string{"2", "95"}, + Label: "foo", + }, + "y2": chronograf.Axis{ + Bounds: []string{}, }, }, }, @@ -284,6 +289,17 @@ func Test_newDashboardResponse(t *testing.T) { ID: "b", W: 4, H: 4, + Axes: map[string]chronograf.Axis{ + "x": chronograf.Axis{ + Bounds: []string{}, + }, + "y": chronograf.Axis{ + Bounds: []string{}, + }, + "y2": chronograf.Axis{ + Bounds: []string{}, + }, + }, Queries: []chronograf.DashboardQuery{ { Command: "SELECT winning_horses from grays_sports_alamanc where time > now() - 15m", diff --git a/server/server.go b/server/server.go index eff14cbf38..d51d8148c6 100644 --- a/server/server.go +++ b/server/server.go @@ -50,7 +50,7 @@ type Server struct { KapacitorUsername string `long:"kapacitor-username" description:"Username of your Kapacitor instance" env:"KAPACITOR_USERNAME"` KapacitorPassword string `long:"kapacitor-password" description:"Password of your Kapacitor instance" env:"KAPACITOR_PASSWORD"` - NewSources string `long:"new-sources" description:"Config for adding a new InfluxDB source and Kapacitor server, in JSON as an array of objects, and surrounded by single quotes. E.g. --new-sources='[{\"influxdb\":{\"name\":\"Influx 1\",\"username\":\"user1\",\"password\":\"pass1\",\"url\":\"http://localhost:8086\",\"metaUrl\":\"http://metaurl.com\",\"insecureSkipVerify\":false,\"default\":true,\"telegraf\":\"telegraf\",\"sharedSecret\":\"hunter2\"},\"kapacitor\":{\"name\":\"Kapa 1\",\"url\":\"http://localhost:9092\",\"active\":true}}]'" env:"NEW_SOURCES" hidden:"true"` + NewSources string `long:"new-sources" description:"Config for adding a new InfluxDB source and Kapacitor server, in JSON as an array of objects, and surrounded by single quotes. E.g. --new-sources='[{\"influxdb\":{\"name\":\"Influx 1\",\"username\":\"user1\",\"password\":\"pass1\",\"url\":\"http://localhost:8086\",\"metaUrl\":\"http://metaurl.com\",\"type\":\"influx-enterprise\",\"insecureSkipVerify\":false,\"default\":true,\"telegraf\":\"telegraf\",\"sharedSecret\":\"cubeapples\"},\"kapacitor\":{\"name\":\"Kapa 1\",\"url\":\"http://localhost:9092\",\"active\":true}}]'" env:"NEW_SOURCES" hidden:"true"` Develop bool `short:"d" long:"develop" description:"Run server in develop mode."` BoltPath string `short:"b" long:"bolt-path" description:"Full path to boltDB file (e.g. './chronograf-v1.db')" env:"BOLT_PATH" default:"chronograf-v1.db"` diff --git a/ui/README.md b/ui/README.md index 997412b204..24f34aec5c 100644 --- a/ui/README.md +++ b/ui/README.md @@ -33,4 +33,4 @@ yarn upgrade packageName ``` ## Testing -Tests can be run via command line with `npm test`, from within the `/ui` directory. For more detailed reporting, use `npm test -- --reporters=verbose`. +Tests can be run via command line with `yarn test`, from within the `/ui` directory. For more detailed reporting, use `yarn test -- --reporters=verbose`. diff --git a/ui/karma.conf.js b/ui/karma.conf.js index a8a4f693f0..dad28ee4e2 100644 --- a/ui/karma.conf.js +++ b/ui/karma.conf.js @@ -16,7 +16,7 @@ module.exports = function(config) { 'spec/index.js': ['webpack', 'sourcemap'], }, // For more detailed reporting on tests, you can add 'verbose' and/or 'progress'. - // This can also be done via the command line with `npm test -- --reporters=verbose`. + // This can also be done via the command line with `yarn test -- --reporters=verbose`. reporters: ['dots'], webpack: { devtool: 'inline-source-map', diff --git a/ui/package.json b/ui/package.json index b98dc2cec3..253f0bf1dc 100644 --- a/ui/package.json +++ b/ui/package.json @@ -1,6 +1,6 @@ { "name": "chronograf-ui", - "version": "1.3.5-0", + "version": "1.3.6-0", "private": false, "license": "AGPL-3.0", "description": "", @@ -9,13 +9,13 @@ "url": "github:influxdata/chronograf" }, "scripts": { - "build": "npm run clean && env NODE_ENV=production node_modules/webpack/bin/webpack.js -p --config ./webpack/prodConfig.js", + "build": "yarn run clean && env NODE_ENV=production node_modules/webpack/bin/webpack.js -p --config ./webpack/prodConfig.js", "build:dev": "node_modules/webpack/bin/webpack.js --config ./webpack/devConfig.js", "start": "node_modules/webpack/bin/webpack.js -w --config ./webpack/devConfig.js", "lint": "node_modules/eslint/bin/eslint.js src/", "test": "karma start", - "test:lint": "npm run lint; npm run test", - "test:dev": "nodemon --exec npm run test:lint", + "test:lint": "yarn run lint; yarn run test", + "test:dev": "nodemon --exec yarn run test:lint", "clean": "rm -rf build", "storybook": "node ./storybook", "prettier": "prettier --single-quote --trailing-comma es5 --bracket-spacing false --semi false --write \"{src,spec}/**/*.js\"; eslint src --fix" diff --git a/ui/spec/dashboards/reducers/uiSpec.js b/ui/spec/dashboards/reducers/uiSpec.js index 537e851eb2..62ef3e54dd 100644 --- a/ui/spec/dashboards/reducers/uiSpec.js +++ b/ui/spec/dashboards/reducers/uiSpec.js @@ -60,6 +60,7 @@ const c1 = { w: 4, h: 4, id: 1, + i: 'im-a-cell-id-index', isEditing: false, name: 'Gigawatts', } @@ -71,18 +72,6 @@ const editingCell = { } const cells = [c1] -const tempVar = { - ...d1.templates[0], - id: '1', - type: 'measurement', - label: 'test query', - tempVar: '$HOSTS', - query: { - db: 'db1', - text: 'SHOW TAGS WHERE HUNTER = "coo"', - }, - values: ['h1', 'h2', 'h3'], -} describe('DataExplorer.Reducers.UI', () => { it('can load the dashboards', () => { diff --git a/ui/spec/shared/parsing/getRangeForDygraphSpec.js b/ui/spec/shared/parsing/getRangeForDygraphSpec.js index d467a7c79f..1c3c7d80ef 100644 --- a/ui/spec/shared/parsing/getRangeForDygraphSpec.js +++ b/ui/spec/shared/parsing/getRangeForDygraphSpec.js @@ -17,10 +17,18 @@ describe('getRangeForDygraphSpec', () => { it('does not get range when a range is provided', () => { const timeSeries = [[date, min], [date, max], [date, mid]] - const providedRange = [0, 4] + const providedRange = ['0', '4'] const actual = getRange(timeSeries, providedRange) - expect(actual).to.deep.equal(providedRange) + expect(actual).to.deep.equal([0, 4]) + }) + + it('does not use the user submitted range if they are equal', () => { + const timeSeries = [[date, min], [date, max], [date, mid]] + const providedRange = ['0', '0'] + const actual = getRange(timeSeries, providedRange) + + expect(actual).to.deep.equal([min, max]) }) it('gets the range for multiple timeSeries', () => { diff --git a/ui/src/alerts/components/AlertsTable.js b/ui/src/alerts/components/AlertsTable.js index f5dfce8932..fba3e21095 100644 --- a/ui/src/alerts/components/AlertsTable.js +++ b/ui/src/alerts/components/AlertsTable.js @@ -1,7 +1,9 @@ import React, {Component, PropTypes} from 'react' + import _ from 'lodash' import classnames from 'classnames' import {Link} from 'react-router' +import uuid from 'node-uuid' import FancyScrollbar from 'shared/components/FancyScrollbar' @@ -130,10 +132,7 @@ class AlertsTable extends Component { > {alerts.map(({name, level, time, host, value}) => { return ( -
+ {graphType.menuOption} +
+Visualization Type:
-