Merge branch 'master' into features/no-tabs-de-2

pull/10616/head
Hunter Trujillo 2017-10-03 20:44:03 -06:00 committed by GitHub
commit 4f881e50fd
61 changed files with 683 additions and 347 deletions

View File

@ -5,6 +5,7 @@
1.[#2015](https://github.com/influxdata/chronograf/pull/2015): Chronograf shows real status for windows hosts when metrics are saved in non-default db - thank you, @ar7z1!
1.[#2019](https://github.com/influxdata/chronograf/pull/2006): Fix false error warning for duplicate kapacitor name
1.[#2018](https://github.com/influxdata/chronograf/pull/2018): Fix unresponsive display options and query builder in dashboards
1.[#1996](https://github.com/influxdata/chronograf/pull/1996): Able to switch InfluxDB sources on a per graph basis
### Features
1. [#1885](https://github.com/influxdata/chronograf/pull/1885): Add `fill` options to data explorer and dashboard queries
@ -18,8 +19,11 @@
1. [#2002](https://github.com/influxdata/chronograf/pull/2002): Improve usability of dashboard cell context menus
1. [#2002](https://github.com/influxdata/chronograf/pull/2002): Move dashboard cell renaming UI into Cell Editor Overlay
1. [#2040](https://github.com/influxdata/chronograf/pull/2040): Prevent the legend from overlapping graphs at the bottom of the screen
1. [#2054](https://github.com/influxdata/chronograf/pull/2054): Add a "Plus" icon to every button with an Add or Create action for clarity and consistency
1. [#2052](https://github.com/influxdata/chronograf/pull/2052): Make hovering over series smoother
1. [#2072](https://github.com/influxdata/chronograf/pull/2072): Remove tabs from Data Explorer
1. [#2057](https://github.com/influxdata/chronograf/pull/2057): Improve appearance of placeholder text in inputs
1. [#2057](https://github.com/influxdata/chronograf/pull/2057): Add ability to use "Default" values in Source Connection form
## v1.3.8.1 [unreleased]
### Bug Fixes

View File

@ -195,6 +195,7 @@ func MarshalDashboard(d chronograf.Dashboard) ([]byte, error) {
Command: q.Command,
Label: q.Label,
Range: r,
Source: q.Source,
}
}
@ -274,6 +275,7 @@ func UnmarshalDashboard(data []byte, d *chronograf.Dashboard) error {
queries[j] = chronograf.DashboardQuery{
Command: q.Command,
Label: q.Label,
Source: q.Source,
}
if q.Range.Upper != q.Range.Lower {
queries[j].Range = &chronograf.Range{

View File

@ -261,6 +261,7 @@ type Query struct {
Wheres []string `protobuf:"bytes,5,rep,name=Wheres" json:"Wheres,omitempty"`
Label string `protobuf:"bytes,6,opt,name=Label,proto3" json:"Label,omitempty"`
Range *Range `protobuf:"bytes,7,opt,name=Range" json:"Range,omitempty"`
Source string `protobuf:"bytes,8,opt,name=Source,proto3" json:"Source,omitempty"`
}
func (m *Query) Reset() { *m = Query{} }
@ -327,67 +328,70 @@ func init() {
func init() { proto.RegisterFile("internal.proto", fileDescriptorInternal) }
var fileDescriptorInternal = []byte{
// 985 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xbc, 0x56, 0xcd, 0x6e, 0x23, 0x45,
0x10, 0x56, 0xcf, 0x8f, 0xed, 0x29, 0x67, 0x03, 0x6a, 0xad, 0xd8, 0x61, 0xb9, 0x98, 0x11, 0x48,
0x06, 0x41, 0x40, 0xbb, 0x42, 0x42, 0xdc, 0x9c, 0x18, 0xad, 0x42, 0xb2, 0x4b, 0x68, 0x27, 0x81,
0x0b, 0x5a, 0xb5, 0xc7, 0x95, 0x64, 0xb4, 0x63, 0xcf, 0xd0, 0x33, 0x13, 0x7b, 0xde, 0x82, 0x27,
0x40, 0x42, 0xe2, 0xc4, 0x81, 0x03, 0x2f, 0xc0, 0x9d, 0xa7, 0x42, 0xd5, 0xdd, 0x33, 0x1e, 0xb3,
0x59, 0xb4, 0x17, 0xf6, 0xd6, 0x5f, 0x55, 0xbb, 0xba, 0xe6, 0xab, 0xfa, 0x3e, 0x19, 0xf6, 0x93,
0x55, 0x89, 0x6a, 0x25, 0xd3, 0x83, 0x5c, 0x65, 0x65, 0xc6, 0x07, 0x0d, 0x8e, 0xfe, 0x70, 0xa0,
0x37, 0xcb, 0x2a, 0x15, 0x23, 0xdf, 0x07, 0xe7, 0x78, 0x1a, 0xb2, 0x11, 0x1b, 0xbb, 0xc2, 0x39,
0x9e, 0x72, 0x0e, 0xde, 0x33, 0xb9, 0xc4, 0xd0, 0x19, 0xb1, 0x71, 0x20, 0xf4, 0x99, 0x62, 0xe7,
0x75, 0x8e, 0xa1, 0x6b, 0x62, 0x74, 0xe6, 0x0f, 0x61, 0x70, 0x51, 0x50, 0xb5, 0x25, 0x86, 0x9e,
0x8e, 0xb7, 0x98, 0x72, 0x67, 0xb2, 0x28, 0xd6, 0x99, 0x5a, 0x84, 0xbe, 0xc9, 0x35, 0x98, 0xbf,
0x0d, 0xee, 0x85, 0x38, 0x0d, 0x7b, 0x3a, 0x4c, 0x47, 0x1e, 0x42, 0x7f, 0x8a, 0x57, 0xb2, 0x4a,
0xcb, 0xb0, 0x3f, 0x62, 0xe3, 0x81, 0x68, 0x20, 0xd5, 0x39, 0xc7, 0x14, 0xaf, 0x95, 0xbc, 0x0a,
0x07, 0xa6, 0x4e, 0x83, 0xf9, 0x01, 0xf0, 0xe3, 0x55, 0x81, 0x71, 0xa5, 0x70, 0xf6, 0x22, 0xc9,
0x2f, 0x51, 0x25, 0x57, 0x75, 0x18, 0xe8, 0x02, 0x77, 0x64, 0xe8, 0x95, 0xa7, 0x58, 0x4a, 0x7a,
0x1b, 0x74, 0xa9, 0x06, 0xf2, 0x08, 0xf6, 0x66, 0x37, 0x52, 0xe1, 0x62, 0x86, 0xb1, 0xc2, 0x32,
0x1c, 0xea, 0xf4, 0x4e, 0x2c, 0xfa, 0x99, 0x41, 0x30, 0x95, 0xc5, 0xcd, 0x3c, 0x93, 0x6a, 0xf1,
0x5a, 0x9c, 0x7d, 0x0a, 0x7e, 0x8c, 0x69, 0x5a, 0x84, 0xee, 0xc8, 0x1d, 0x0f, 0x1f, 0x3d, 0x38,
0x68, 0x87, 0xd1, 0xd6, 0x39, 0xc2, 0x34, 0x15, 0xe6, 0x16, 0xff, 0x1c, 0x82, 0x12, 0x97, 0x79,
0x2a, 0x4b, 0x2c, 0x42, 0x4f, 0xff, 0x84, 0x6f, 0x7f, 0x72, 0x6e, 0x53, 0x62, 0x7b, 0x29, 0xfa,
0xdd, 0x81, 0x7b, 0x3b, 0xa5, 0xf8, 0x1e, 0xb0, 0x8d, 0xee, 0xca, 0x17, 0x6c, 0x43, 0xa8, 0xd6,
0x1d, 0xf9, 0x82, 0xd5, 0x84, 0xd6, 0x7a, 0x7e, 0xbe, 0x60, 0x6b, 0x42, 0x37, 0x7a, 0x6a, 0xbe,
0x60, 0x37, 0xfc, 0x23, 0xe8, 0xff, 0x54, 0xa1, 0x4a, 0xb0, 0x08, 0x7d, 0xfd, 0xf2, 0x5b, 0xdb,
0x97, 0xbf, 0xab, 0x50, 0xd5, 0xa2, 0xc9, 0xd3, 0x97, 0xea, 0x89, 0x9b, 0xf1, 0xe9, 0x33, 0xc5,
0x4a, 0xda, 0x8e, 0xbe, 0x89, 0xd1, 0xd9, 0x32, 0x64, 0x66, 0x46, 0x0c, 0x7d, 0x01, 0x9e, 0xdc,
0x60, 0x11, 0x06, 0xba, 0xfe, 0xfb, 0xaf, 0x20, 0xe3, 0x60, 0xb2, 0xc1, 0xe2, 0xeb, 0x55, 0xa9,
0x6a, 0xa1, 0xaf, 0x3f, 0x7c, 0x02, 0x41, 0x1b, 0xa2, 0xcd, 0x79, 0x81, 0xb5, 0xfe, 0xc0, 0x40,
0xd0, 0x91, 0x7f, 0x00, 0xfe, 0xad, 0x4c, 0x2b, 0x43, 0xfc, 0xf0, 0xd1, 0xfe, 0xb6, 0xec, 0x64,
0x93, 0x14, 0xc2, 0x24, 0xbf, 0x72, 0xbe, 0x64, 0xd1, 0x0f, 0xe0, 0x51, 0x88, 0x66, 0x9d, 0xe2,
0xb5, 0x8c, 0xeb, 0xc3, 0xac, 0x5a, 0x2d, 0x8a, 0x90, 0x8d, 0xdc, 0xb1, 0x2b, 0x76, 0x62, 0xfc,
0x1d, 0xe8, 0xcd, 0x4d, 0xd6, 0x19, 0xb9, 0xe3, 0x40, 0x58, 0xc4, 0xef, 0x83, 0x9f, 0xca, 0x39,
0xa6, 0x56, 0x06, 0x06, 0x44, 0x7f, 0x31, 0x5a, 0x52, 0x33, 0x94, 0xce, 0x62, 0x98, 0xcf, 0x7e,
0x17, 0x06, 0x34, 0xb0, 0xe7, 0xb7, 0x52, 0xd9, 0xe5, 0xe8, 0x13, 0xbe, 0x94, 0x8a, 0x7f, 0x06,
0x3d, 0xdd, 0xde, 0x1d, 0x0b, 0xd2, 0x94, 0xbb, 0xa4, 0xbc, 0xb0, 0xd7, 0x5a, 0x9a, 0xbd, 0x0e,
0xcd, 0x6d, 0x4b, 0x7e, 0xa7, 0x25, 0x5a, 0x3d, 0x9a, 0x57, 0xad, 0xa7, 0x74, 0x67, 0x65, 0x33,
0x55, 0x73, 0x2b, 0xba, 0x80, 0x7b, 0x3b, 0x2f, 0xb6, 0x2f, 0xb1, 0xdd, 0x97, 0xb6, 0x54, 0x07,
0x96, 0x5a, 0x12, 0x68, 0x81, 0x29, 0xc6, 0x25, 0x2e, 0x34, 0x2b, 0x03, 0xd1, 0xe2, 0xe8, 0x57,
0xb6, 0xad, 0xab, 0xdf, 0x23, 0x09, 0xc6, 0xd9, 0x72, 0x29, 0x57, 0x0b, 0x5b, 0xba, 0x81, 0xc4,
0xdb, 0x62, 0x6e, 0x4b, 0x3b, 0x8b, 0x39, 0x61, 0x95, 0x5b, 0x9e, 0x1d, 0x95, 0xf3, 0x11, 0x0c,
0x97, 0x28, 0x8b, 0x4a, 0xe1, 0x12, 0x57, 0xa5, 0xa5, 0xa0, 0x1b, 0xe2, 0x0f, 0xa0, 0x5f, 0xca,
0xeb, 0xe7, 0xb4, 0x20, 0x86, 0x8b, 0x5e, 0x29, 0xaf, 0x4f, 0xb0, 0xe6, 0xef, 0x41, 0x70, 0x95,
0x60, 0xba, 0xd0, 0x29, 0xb3, 0xb6, 0x03, 0x1d, 0x38, 0xc1, 0x3a, 0xfa, 0x8d, 0x41, 0x6f, 0x86,
0xea, 0x16, 0xd5, 0x6b, 0x69, 0xba, 0xeb, 0x79, 0xee, 0x7f, 0x78, 0x9e, 0x77, 0xb7, 0xe7, 0xf9,
0x5b, 0xcf, 0xbb, 0x0f, 0xfe, 0x4c, 0xc5, 0xc7, 0x53, 0xdd, 0x91, 0x2b, 0x0c, 0xa0, 0xcd, 0x9b,
0xc4, 0x65, 0x72, 0x8b, 0xd6, 0x08, 0x2d, 0x8a, 0x7e, 0x61, 0xd0, 0x3b, 0x95, 0x75, 0x56, 0x95,
0x2f, 0x6d, 0xd8, 0x08, 0x86, 0x93, 0x3c, 0x4f, 0x93, 0x58, 0x96, 0x49, 0xb6, 0xb2, 0xdd, 0x76,
0x43, 0x74, 0xe3, 0x69, 0x87, 0x3b, 0xd3, 0x77, 0x37, 0x44, 0x32, 0x3a, 0xd2, 0x56, 0x65, 0x7c,
0xa7, 0x23, 0x23, 0xe3, 0x50, 0x3a, 0x49, 0x1f, 0x38, 0xa9, 0xca, 0xec, 0x2a, 0xcd, 0xd6, 0xfa,
0x4b, 0x06, 0xa2, 0xc5, 0xd1, 0xdf, 0x0e, 0x78, 0x6f, 0xca, 0x82, 0xf6, 0x80, 0x25, 0x76, 0x90,
0x2c, 0x69, 0x0d, 0xa9, 0xdf, 0x31, 0xa4, 0x10, 0xfa, 0xb5, 0x92, 0xab, 0x6b, 0x2c, 0xc2, 0x81,
0xd6, 0x77, 0x03, 0x75, 0x46, 0x6b, 0xc4, 0x38, 0x51, 0x20, 0x1a, 0xd8, 0xee, 0x3c, 0x74, 0x76,
0xfe, 0x13, 0x6b, 0x5a, 0x43, 0xdd, 0x51, 0xb8, 0x4b, 0xcb, 0xff, 0xe7, 0x55, 0x7f, 0x32, 0xf0,
0x5b, 0xc1, 0x1c, 0xed, 0x0a, 0xe6, 0x68, 0x2b, 0x98, 0xe9, 0x61, 0x23, 0x98, 0xe9, 0x21, 0x61,
0x71, 0xd6, 0x08, 0x46, 0x9c, 0xd1, 0xb0, 0x9e, 0xa8, 0xac, 0xca, 0x0f, 0x6b, 0x33, 0xd5, 0x40,
0xb4, 0x98, 0xb6, 0xec, 0xfb, 0x1b, 0x54, 0x96, 0xea, 0x40, 0x58, 0x44, 0x3b, 0x79, 0xaa, 0xcd,
0xc4, 0x90, 0x6b, 0x00, 0xff, 0x10, 0x7c, 0x41, 0xe4, 0x69, 0x86, 0x77, 0xe6, 0xa2, 0xc3, 0xc2,
0x64, 0xa3, 0xc7, 0xf6, 0x1a, 0x55, 0xb9, 0xc8, 0x73, 0x54, 0x56, 0x4a, 0x06, 0xe8, 0xda, 0xd9,
0x1a, 0x8d, 0x0b, 0xba, 0xc2, 0x80, 0xe8, 0x47, 0x08, 0x26, 0x29, 0xaa, 0x52, 0x54, 0xe9, 0xcb,
0xde, 0xc9, 0xc1, 0xfb, 0x66, 0xf6, 0xed, 0xb3, 0x46, 0x80, 0x74, 0xde, 0xca, 0xc6, 0xfd, 0x97,
0x6c, 0x4e, 0x64, 0x2e, 0x8f, 0xa7, 0x7a, 0x9f, 0x5c, 0x61, 0x51, 0xf4, 0x31, 0x78, 0x24, 0xcf,
0x4e, 0x65, 0xef, 0x55, 0xd2, 0x9e, 0xf7, 0xf4, 0x5f, 0xa4, 0xc7, 0xff, 0x04, 0x00, 0x00, 0xff,
0xff, 0x5a, 0xf0, 0x92, 0xd4, 0x34, 0x09, 0x00, 0x00,
// 1028 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xbc, 0x56, 0x4f, 0x6f, 0xe3, 0x44,
0x14, 0xd7, 0xf8, 0x4f, 0x12, 0xbf, 0x74, 0x0b, 0x1a, 0xad, 0x58, 0xb3, 0x5c, 0x82, 0x05, 0x52,
0x40, 0x6c, 0x41, 0xbb, 0x42, 0x42, 0xdc, 0xd2, 0x06, 0xad, 0x4a, 0xbb, 0x4b, 0x99, 0xb4, 0xe5,
0x84, 0x56, 0x13, 0xe7, 0xa5, 0xb5, 0xd6, 0x89, 0xcd, 0xd8, 0x6e, 0xe3, 0x6f, 0xc1, 0x27, 0x40,
0x42, 0xe2, 0xc4, 0x81, 0x03, 0x5f, 0x80, 0xfb, 0x7e, 0x2a, 0xf4, 0x66, 0xc6, 0x8e, 0xc3, 0x76,
0xd1, 0x5e, 0xe0, 0x36, 0xbf, 0xf7, 0xc6, 0x6f, 0x66, 0xde, 0xef, 0xfd, 0x7e, 0x09, 0xec, 0x27,
0xeb, 0x12, 0xd5, 0x5a, 0xa6, 0x07, 0xb9, 0xca, 0xca, 0x8c, 0x0f, 0x1a, 0x1c, 0xfd, 0xe1, 0x40,
0x6f, 0x96, 0x55, 0x2a, 0x46, 0xbe, 0x0f, 0xce, 0xf1, 0x34, 0x64, 0x23, 0x36, 0x76, 0x85, 0x73,
0x3c, 0xe5, 0x1c, 0xbc, 0xe7, 0x72, 0x85, 0xa1, 0x33, 0x62, 0xe3, 0x40, 0xe8, 0x35, 0xc5, 0xce,
0xeb, 0x1c, 0x43, 0xd7, 0xc4, 0x68, 0xcd, 0x1f, 0xc2, 0xe0, 0xa2, 0xa0, 0x6a, 0x2b, 0x0c, 0x3d,
0x1d, 0x6f, 0x31, 0xe5, 0xce, 0x64, 0x51, 0xdc, 0x66, 0x6a, 0x11, 0xfa, 0x26, 0xd7, 0x60, 0xfe,
0x2e, 0xb8, 0x17, 0xe2, 0x34, 0xec, 0xe9, 0x30, 0x2d, 0x79, 0x08, 0xfd, 0x29, 0x2e, 0x65, 0x95,
0x96, 0x61, 0x7f, 0xc4, 0xc6, 0x03, 0xd1, 0x40, 0xaa, 0x73, 0x8e, 0x29, 0x5e, 0x29, 0xb9, 0x0c,
0x07, 0xa6, 0x4e, 0x83, 0xf9, 0x01, 0xf0, 0xe3, 0x75, 0x81, 0x71, 0xa5, 0x70, 0xf6, 0x32, 0xc9,
0x2f, 0x51, 0x25, 0xcb, 0x3a, 0x0c, 0x74, 0x81, 0x3b, 0x32, 0x74, 0xca, 0x33, 0x2c, 0x25, 0x9d,
0x0d, 0xba, 0x54, 0x03, 0x79, 0x04, 0x7b, 0xb3, 0x6b, 0xa9, 0x70, 0x31, 0xc3, 0x58, 0x61, 0x19,
0x0e, 0x75, 0x7a, 0x27, 0x16, 0xfd, 0xcc, 0x20, 0x98, 0xca, 0xe2, 0x7a, 0x9e, 0x49, 0xb5, 0x78,
0xab, 0x9e, 0x3d, 0x02, 0x3f, 0xc6, 0x34, 0x2d, 0x42, 0x77, 0xe4, 0x8e, 0x87, 0x8f, 0x1f, 0x1c,
0xb4, 0x64, 0xb4, 0x75, 0x8e, 0x30, 0x4d, 0x85, 0xd9, 0xc5, 0xbf, 0x80, 0xa0, 0xc4, 0x55, 0x9e,
0xca, 0x12, 0x8b, 0xd0, 0xd3, 0x9f, 0xf0, 0xed, 0x27, 0xe7, 0x36, 0x25, 0xb6, 0x9b, 0xa2, 0xdf,
0x1d, 0xb8, 0xb7, 0x53, 0x8a, 0xef, 0x01, 0xdb, 0xe8, 0x5b, 0xf9, 0x82, 0x6d, 0x08, 0xd5, 0xfa,
0x46, 0xbe, 0x60, 0x35, 0xa1, 0x5b, 0xcd, 0x9f, 0x2f, 0xd8, 0x2d, 0xa1, 0x6b, 0xcd, 0x9a, 0x2f,
0xd8, 0x35, 0xff, 0x04, 0xfa, 0x3f, 0x55, 0xa8, 0x12, 0x2c, 0x42, 0x5f, 0x9f, 0xfc, 0xce, 0xf6,
0xe4, 0xef, 0x2b, 0x54, 0xb5, 0x68, 0xf2, 0xf4, 0x52, 0xcd, 0xb8, 0xa1, 0x4f, 0xaf, 0x29, 0x56,
0xd2, 0x74, 0xf4, 0x4d, 0x8c, 0xd6, 0xb6, 0x43, 0x86, 0x33, 0xea, 0xd0, 0x97, 0xe0, 0xc9, 0x0d,
0x16, 0x61, 0xa0, 0xeb, 0x7f, 0xf8, 0x86, 0x66, 0x1c, 0x4c, 0x36, 0x58, 0x7c, 0xb3, 0x2e, 0x55,
0x2d, 0xf4, 0xf6, 0x87, 0x4f, 0x21, 0x68, 0x43, 0x34, 0x39, 0x2f, 0xb1, 0xd6, 0x0f, 0x0c, 0x04,
0x2d, 0xf9, 0x47, 0xe0, 0xdf, 0xc8, 0xb4, 0x32, 0x8d, 0x1f, 0x3e, 0xde, 0xdf, 0x96, 0x9d, 0x6c,
0x92, 0x42, 0x98, 0xe4, 0xd7, 0xce, 0x57, 0x2c, 0xfa, 0x93, 0x81, 0x47, 0x31, 0x22, 0x3b, 0xc5,
0x2b, 0x19, 0xd7, 0x87, 0x59, 0xb5, 0x5e, 0x14, 0x21, 0x1b, 0xb9, 0x63, 0x57, 0xec, 0xc4, 0xf8,
0x7b, 0xd0, 0x9b, 0x9b, 0xac, 0x33, 0x72, 0xc7, 0x81, 0xb0, 0x88, 0xdf, 0x07, 0x3f, 0x95, 0x73,
0x4c, 0xad, 0x0e, 0x0c, 0xa0, 0xdd, 0xb9, 0xc2, 0x65, 0xb2, 0xb1, 0x32, 0xb0, 0x88, 0xe2, 0x45,
0xb5, 0xa4, 0xb8, 0x91, 0x80, 0x45, 0xd4, 0xae, 0xb9, 0x2c, 0xda, 0x16, 0xd2, 0x9a, 0x2a, 0x17,
0xb1, 0x4c, 0x9b, 0x1e, 0x1a, 0x10, 0xfd, 0xc5, 0x68, 0xfe, 0x0d, 0xdf, 0x9d, 0x99, 0x33, 0x1d,
0x7d, 0x1f, 0x06, 0x34, 0x0b, 0x2f, 0x6e, 0xa4, 0xb2, 0x73, 0xd7, 0x27, 0x7c, 0x29, 0x15, 0xff,
0x1c, 0x7a, 0xfa, 0xe5, 0x77, 0xcc, 0x5e, 0x53, 0xee, 0x92, 0xf2, 0xc2, 0x6e, 0x6b, 0x19, 0xf4,
0x3a, 0x0c, 0xb6, 0x8f, 0xf5, 0xbb, 0x8f, 0x7d, 0x04, 0x3e, 0x8d, 0x42, 0xad, 0x6f, 0x7f, 0x67,
0x65, 0x33, 0x30, 0x66, 0x57, 0x74, 0x01, 0xf7, 0x76, 0x4e, 0x6c, 0x4f, 0x62, 0xbb, 0x27, 0x6d,
0x59, 0x0c, 0x2c, 0x6b, 0xa4, 0xfd, 0x02, 0x53, 0x8c, 0x4b, 0x5c, 0xe8, 0x7e, 0x0f, 0x44, 0x8b,
0xa3, 0x5f, 0xd9, 0xb6, 0xae, 0x3e, 0x8f, 0xd4, 0x1d, 0x67, 0xab, 0x95, 0x5c, 0x2f, 0x6c, 0xe9,
0x06, 0x52, 0xdf, 0x16, 0x73, 0x5b, 0xda, 0x59, 0xcc, 0x09, 0xab, 0xdc, 0x32, 0xe8, 0xa8, 0x9c,
0x8f, 0x60, 0xb8, 0x42, 0x59, 0x54, 0x0a, 0x57, 0xb8, 0x2e, 0x6d, 0x0b, 0xba, 0x21, 0xfe, 0x00,
0xfa, 0xa5, 0xbc, 0x7a, 0x41, 0xb3, 0x67, 0x99, 0x2c, 0xe5, 0xd5, 0x09, 0xd6, 0xfc, 0x03, 0x08,
0x96, 0x09, 0xa6, 0x0b, 0x9d, 0x32, 0x74, 0x0e, 0x74, 0xe0, 0x04, 0xeb, 0xe8, 0x37, 0x06, 0xbd,
0x19, 0xaa, 0x1b, 0x54, 0x6f, 0x65, 0x17, 0x5d, 0x3b, 0x75, 0xff, 0xc5, 0x4e, 0xbd, 0xbb, 0xed,
0xd4, 0xdf, 0xda, 0xe9, 0x7d, 0xf0, 0x67, 0x2a, 0x3e, 0x9e, 0xea, 0x1b, 0xb9, 0xc2, 0x00, 0x9a,
0xc6, 0x49, 0x5c, 0x26, 0x37, 0x68, 0x3d, 0xd6, 0xa2, 0xe8, 0x17, 0x06, 0xbd, 0x53, 0x59, 0x67,
0x55, 0xf9, 0xda, 0x84, 0x8d, 0x60, 0x38, 0xc9, 0xf3, 0x34, 0x89, 0x65, 0x99, 0x64, 0x6b, 0x7b,
0xdb, 0x6e, 0x88, 0x76, 0x3c, 0xeb, 0xf4, 0xce, 0xdc, 0xbb, 0x1b, 0x22, 0x85, 0x1e, 0x69, 0x17,
0x34, 0x96, 0xd6, 0x51, 0xa8, 0x31, 0x3f, 0x9d, 0xa4, 0x07, 0x4e, 0xaa, 0x32, 0x5b, 0xa6, 0xd9,
0xad, 0x7e, 0xc9, 0x40, 0xb4, 0x38, 0x7a, 0xe5, 0x80, 0xf7, 0x7f, 0xb9, 0xdb, 0x1e, 0xb0, 0xc4,
0x12, 0xc9, 0x92, 0xd6, 0xeb, 0xfa, 0x1d, 0xaf, 0x0b, 0xa1, 0x5f, 0x2b, 0xb9, 0xbe, 0xc2, 0x22,
0x1c, 0x68, 0xe7, 0x68, 0xa0, 0xce, 0x68, 0x8d, 0x18, 0x93, 0x0b, 0x44, 0x03, 0xdb, 0x99, 0x87,
0xce, 0xcc, 0x7f, 0x66, 0xfd, 0x70, 0xa8, 0x6f, 0x14, 0xee, 0xb6, 0xe5, 0xbf, 0xb3, 0xc1, 0x57,
0x0c, 0xfc, 0x56, 0x30, 0x47, 0xbb, 0x82, 0x39, 0xda, 0x0a, 0x66, 0x7a, 0xd8, 0x08, 0x66, 0x7a,
0x48, 0x58, 0x9c, 0x35, 0x82, 0x11, 0x67, 0x44, 0xd6, 0x53, 0x95, 0x55, 0xf9, 0x61, 0x6d, 0x58,
0x0d, 0x44, 0x8b, 0x69, 0xca, 0x7e, 0xb8, 0x46, 0x65, 0x5b, 0x1d, 0x08, 0x8b, 0x68, 0x26, 0x4f,
0xb5, 0x99, 0x98, 0xe6, 0x1a, 0xc0, 0x3f, 0x06, 0x5f, 0x50, 0xf3, 0x74, 0x87, 0x77, 0x78, 0xd1,
0x61, 0x61, 0xb2, 0x54, 0xd4, 0xfc, 0x57, 0xb1, 0xbf, 0x27, 0x16, 0x45, 0x4f, 0xec, 0xe7, 0x54,
0xfd, 0x22, 0xcf, 0x51, 0x59, 0x89, 0x19, 0xa0, 0xcf, 0xcc, 0x6e, 0xd1, 0xb8, 0xa3, 0x2b, 0x0c,
0x88, 0x7e, 0x84, 0x60, 0x92, 0xa2, 0x2a, 0x45, 0x95, 0xbe, 0xee, 0xa9, 0x1c, 0xbc, 0x6f, 0x67,
0xdf, 0x3d, 0x6f, 0x84, 0x49, 0xeb, 0xad, 0x9c, 0xdc, 0x7f, 0xc8, 0xe9, 0x44, 0xe6, 0xf2, 0x78,
0xaa, 0xe7, 0xcc, 0x15, 0x16, 0x45, 0x9f, 0x82, 0x47, 0xb2, 0xed, 0x54, 0xf6, 0xde, 0x24, 0xf9,
0x79, 0x4f, 0xff, 0x2b, 0x7b, 0xf2, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, 0xb7, 0x59, 0x2e, 0xc0,
0xa7, 0x09, 0x00, 0x00,
}

View File

@ -108,6 +108,7 @@ message Query {
repeated string Wheres = 5; // Wheres define the restrictions on the query
string Label = 6; // Label is the name of the Y-Axis
Range Range = 7; // Range is the upper and lower bound of the Y-Axis
string Source = 8; // Source is the optional URI to the data source
}
message Range {

View File

@ -162,6 +162,7 @@ func Test_MarshalDashboard(t *testing.T) {
Range: &chronograf.Range{
Upper: int64(100),
},
Source: "/chronograf/v1/sources/1",
},
},
Axes: map[string]chronograf.Axis{

View File

@ -395,6 +395,7 @@ type DashboardQuery struct {
Label string `json:"label,omitempty"` // Label is the Y-Axis label for the data
Range *Range `json:"range,omitempty"` // Range is the default Y-Axis range for the data
QueryConfig QueryConfig `json:"queryConfig,omitempty"` // QueryConfig represents the query state that is understood by the data explorer
Source string `json:"source"` // Source is the optional URI to the data source for this queryConfig
}
// TemplateQuery is used to retrieve choices for template replacement

View File

@ -8,6 +8,7 @@ After=network-online.target
[Service]
User=chronograf
Group=chronograf
EnvironmentFile=-/etc/default/chronograf
ExecStart=/usr/bin/chronograf --host 0.0.0.0 --port 8888 -b /var/lib/chronograf/chronograf-v1.db -c /usr/share/chronograf/canned
KillMode=control-group
Restart=on-failure

View File

@ -217,6 +217,7 @@ func Test_newDashboardResponse(t *testing.T) {
H: 0,
Queries: []chronograf.DashboardQuery{
{
Source: "/chronograf/v1/sources/1",
Command: "SELECT donors from hill_valley_preservation_society where time > '1985-10-25 08:00:00'",
},
},
@ -236,6 +237,7 @@ func Test_newDashboardResponse(t *testing.T) {
H: 0,
Queries: []chronograf.DashboardQuery{
{
Source: "/chronograf/v1/sources/2",
Command: "SELECT winning_horses from grays_sports_alamanc where time > now() - 15m",
},
},
@ -256,6 +258,7 @@ func Test_newDashboardResponse(t *testing.T) {
Queries: []chronograf.DashboardQuery{
{
Command: "SELECT donors from hill_valley_preservation_society where time > '1985-10-25 08:00:00'",
Source: "/chronograf/v1/sources/1",
QueryConfig: chronograf.QueryConfig{
RawText: &[]string{"SELECT donors from hill_valley_preservation_society where time > '1985-10-25 08:00:00'"}[0],
Fields: []chronograf.Field{},
@ -303,6 +306,7 @@ func Test_newDashboardResponse(t *testing.T) {
Queries: []chronograf.DashboardQuery{
{
Command: "SELECT winning_horses from grays_sports_alamanc where time > now() - 15m",
Source: "/chronograf/v1/sources/2",
QueryConfig: chronograf.QueryConfig{
Measurement: "grays_sports_alamanc",
Fields: []chronograf.Field{

View File

@ -3766,6 +3766,11 @@
"query": {
"type": "string"
},
"source": {
"type": "string",
"format": "url",
"description": "Optional URI for data source for this query"
},
"queryConfig": {
"$ref": "#/definitions/QueryConfig"
}

View File

@ -37,7 +37,7 @@ const DatabaseManager = ({
disabled={isAddDBDisabled}
onClick={addDatabase}
>
Create Database
<span className="icon plus" /> Create Database
</button>
</div>
<div className="panel-body">

View File

@ -59,7 +59,7 @@ const Header = ({
disabled={isAddRPDisabled}
onClick={onAddRetentionPolicy(database)}
>
Add Retention Policy
<span className="icon plus" /> Add Retention Policy
</button>
{database.name === '_internal'
? null

View File

@ -44,7 +44,8 @@ class FilterBar extends Component {
disabled={isEditing}
onClick={onClickCreate(type)}
>
Create {placeholderText.substring(0, placeholderText.length - 1)}
<span className="icon plus" /> Create{' '}
{placeholderText.substring(0, placeholderText.length - 1)}
</button>
</div>
)

View File

@ -154,7 +154,7 @@ class AdminPage extends Component {
<h1 className="page-header__title">Admin</h1>
</div>
<div className="page-header__right">
<SourceIndicator sourceName={source.name} />
<SourceIndicator />
</div>
</div>
</div>

View File

@ -156,7 +156,7 @@ class AlertsApp extends Component {
<h1 className="page-header__title">Alert History</h1>
</div>
<div className="page-header__right">
<SourceIndicator sourceName={source.name} />
<SourceIndicator />
<CustomTimeRangeDropdown
onApplyTimeRange={this.handleApplyTime}
timeRange={timeRange}

View File

@ -19,7 +19,7 @@ const AxesOptions = ({
const [min, max] = bounds
return (
<div className="display-options--cell">
<div className="display-options--cell y-axis-controls">
<h5 className="display-options--header">Y Axis Controls</h5>
<form autoComplete="off" style={{margin: '0 -6px'}}>
<div className="form-group col-sm-12">

View File

@ -23,10 +23,17 @@ class CellEditorOverlay extends Component {
constructor(props) {
super(props)
const {cell: {name, type, queries, axes}} = props
const {cell: {name, type, queries, axes}, sources} = props
let source = _.get(queries, ['0', 'source'], null)
source = sources.find(s => s.links.self === source) || props.source
const queriesWorkingDraft = _.cloneDeep(
queries.map(({queryConfig}) => ({...queryConfig, id: uuid.v4()}))
queries.map(({queryConfig}) => ({
...queryConfig,
id: uuid.v4(),
source,
}))
)
this.state = {
@ -141,6 +148,7 @@ class CellEditorOverlay extends Component {
return {
queryConfig: q,
query,
source: _.get(q, ['source', 'links', 'self'], null),
}
})
@ -197,6 +205,15 @@ class CellEditorOverlay extends Component {
})
}
handleSetQuerySource = source => {
const queriesWorkingDraft = this.state.queriesWorkingDraft.map(q => ({
..._.cloneDeep(q),
source,
}))
this.setState({queriesWorkingDraft})
}
getActiveQuery = () => {
const {queriesWorkingDraft, activeQueryIndex} = this.state
const activeQuery = queriesWorkingDraft[activeQueryIndex]
@ -221,9 +238,39 @@ class CellEditorOverlay extends Component {
}
}
formatSources = this.props.sources.map(s => ({
...s,
text: `${s.name} @ ${s.url}`,
}))
findSelectedSource = () => {
const {source} = this.props
const sources = this.formatSources
const query = _.get(this.state.queriesWorkingDraft, 0, false)
if (!query || !query.source) {
const defaultSource = sources.find(s => s.id === source.id)
return (defaultSource && defaultSource.text) || 'No sources'
}
const selected = sources.find(s => s.id === query.source.id)
return (selected && selected.text) || 'No sources'
}
getSource = () => {
const {source, sources} = this.props
const query = _.get(this.state.queriesWorkingDraft, 0, false)
if (!query || !query.source) {
return source
}
const querySource = sources.find(s => s.id === query.source.id)
return querySource || source
}
render() {
const {
source,
onCancel,
templates,
timeRange,
@ -232,12 +279,12 @@ class CellEditorOverlay extends Component {
} = this.props
const {
axes,
activeQueryIndex,
cellWorkingName,
cellWorkingType,
isDisplayOptionsTabActive,
queriesWorkingDraft,
axes,
} = this.state
const queryActions = {
@ -271,11 +318,14 @@ class CellEditorOverlay extends Component {
/>
<CEOBottom>
<OverlayControls
onCancel={onCancel}
sources={this.formatSources}
onSave={this.handleSaveCell}
selected={this.findSelectedSource()}
onSetQuerySource={this.handleSetQuerySource}
isSavable={queriesWorkingDraft.every(isQuerySavable)}
isDisplayOptionsTabActive={isDisplayOptionsTabActive}
onClickDisplayOptions={this.handleClickDisplayOptionsTab}
onCancel={onCancel}
onSave={this.handleSaveCell}
isSavable={queriesWorkingDraft.every(isQuerySavable)}
/>
{isDisplayOptionsTabActive
? <DisplayOptions
@ -291,7 +341,7 @@ class CellEditorOverlay extends Component {
onSetYAxisBoundMax={this.handleSetYAxisBoundMax}
/>
: <QueryMaker
source={source}
source={this.getSource()}
templates={templates}
queries={queriesWorkingDraft}
actions={queryActions}
@ -343,6 +393,7 @@ CellEditorOverlay.propTypes = {
status: shape({}),
}).isRequired,
dashboardID: string.isRequired,
sources: arrayOf(shape()),
}
CEOBottom.propTypes = {

View File

@ -7,6 +7,7 @@ import FancyScrollbar from 'shared/components/FancyScrollbar'
const Dashboard = ({
source,
sources,
onZoom,
dashboard,
onAddCell,
@ -24,16 +25,11 @@ const Dashboard = ({
}) => {
const cells = dashboard.cells.map(cell => {
const dashboardCell = {...cell}
dashboardCell.queries = dashboardCell.queries.map(
({label, query, queryConfig, db}) => ({
label,
query,
queryConfig,
db,
database: db,
text: query,
})
)
dashboardCell.queries = dashboardCell.queries.map(q => ({
...q,
database: q.db,
text: q.query,
}))
return dashboardCell
})
@ -54,17 +50,18 @@ const Dashboard = ({
/>}
{cells.length
? <LayoutRenderer
templates={templatesIncludingDashTime}
isEditable={true}
cells={cells}
onZoom={onZoom}
source={source}
sources={sources}
isEditable={true}
timeRange={timeRange}
autoRefresh={autoRefresh}
source={source}
onPositionChange={onPositionChange}
onDeleteCell={onDeleteCell}
onSummonOverlayTechnologies={onSummonOverlayTechnologies}
synchronizer={synchronizer}
onZoom={onZoom}
onDeleteCell={onDeleteCell}
onPositionChange={onPositionChange}
templates={templatesIncludingDashTime}
onSummonOverlayTechnologies={onSummonOverlayTechnologies}
/>
: <div className="dashboard__empty">
<p>This Dashboard has no Cells</p>
@ -112,6 +109,7 @@ Dashboard.propTypes = {
proxy: string,
}).isRequired,
}).isRequired,
sources: arrayOf(shape({})).isRequired,
autoRefresh: number.isRequired,
timeRange: shape({}).isRequired,
onOpenTemplateManager: func.isRequired,

View File

@ -18,7 +18,6 @@ const DashboardHeader = ({
handleChooseTimeRange,
handleChooseAutoRefresh,
handleClickPresentationButton,
source,
onAddCell,
onEditDashboard,
onToggleTempVarControls,
@ -49,7 +48,7 @@ const DashboardHeader = ({
</div>
<div className="page-header__right">
<GraphTips />
<SourceIndicator sourceName={source.name} />
<SourceIndicator />
{dashboard
? <button className="btn btn-primary btn-sm" onClick={onAddCell}>
<span className="icon plus" />
@ -107,7 +106,6 @@ DashboardHeader.defaultProps = {
}
DashboardHeader.propTypes = {
sourceID: string,
children: array,
buttonText: string,
dashboard: shape({}),
@ -121,7 +119,6 @@ DashboardHeader.propTypes = {
handleChooseTimeRange: func.isRequired,
handleChooseAutoRefresh: func.isRequired,
handleClickPresentationButton: func.isRequired,
source: shape({}),
onAddCell: func,
onEditDashboard: func,
onToggleTempVarControls: func,

View File

@ -1,26 +1,17 @@
import React, {PropTypes} from 'react'
import React from 'react'
import SourceIndicator from 'shared/components/SourceIndicator'
const DashboardsHeader = ({sourceName}) => {
return (
<div className="page-header">
<div className="page-header__container">
<div className="page-header__left">
<h1 className="page-header__title">Dashboards</h1>
</div>
<div className="page-header__right">
<SourceIndicator sourceName={sourceName} />
</div>
const DashboardsHeader = () =>
<div className="page-header">
<div className="page-header__container">
<div className="page-header__left">
<h1 className="page-header__title">Dashboards</h1>
</div>
<div className="page-header__right">
<SourceIndicator />
</div>
</div>
)
}
const {string} = PropTypes
DashboardsHeader.propTypes = {
sourceName: string.isRequired,
}
</div>
export default DashboardsHeader

View File

@ -32,7 +32,7 @@ const DashboardsPageContents = ({
className="btn btn-sm btn-primary"
onClick={onCreateDashboard}
>
Create Dashboard
<span className="icon plus" /> Create Dashboard
</button>
</div>
<div className="panel-body">

View File

@ -54,7 +54,7 @@ const DashboardsTable = ({
onClick={onCreateDashboard}
style={{marginBottom: '90px'}}
>
Create Dashboard
<span className="icon plus" /> Create Dashboard
</button>
</div>
}

View File

@ -2,16 +2,24 @@ import React, {PropTypes} from 'react'
import classnames from 'classnames'
import ConfirmButtons from 'shared/components/ConfirmButtons'
import SourceSelector from 'src/dashboards/components/SourceSelector'
const OverlayControls = ({
onCancel,
onSave,
sources,
selected,
onCancel,
isSavable,
onSetQuerySource,
isDisplayOptionsTabActive,
onClickDisplayOptions,
isSavable,
}) =>
<div className="overlay-controls">
<h3 className="overlay--graph-name">Cell Editor</h3>
<SourceSelector
sources={sources}
selected={selected}
onSetQuerySource={onSetQuerySource}
/>
<ul className="nav nav-tablist nav-tablist-sm">
<li
key="queries"
@ -29,7 +37,7 @@ const OverlayControls = ({
})}
onClick={onClickDisplayOptions(true)}
>
Display Options
Options
</li>
</ul>
<div className="overlay-controls--right">
@ -41,7 +49,7 @@ const OverlayControls = ({
</div>
</div>
const {func, bool} = PropTypes
const {arrayOf, bool, func, shape, string} = PropTypes
OverlayControls.propTypes = {
onCancel: func.isRequired,
@ -49,6 +57,9 @@ OverlayControls.propTypes = {
isDisplayOptionsTabActive: bool.isRequired,
onClickDisplayOptions: func.isRequired,
isSavable: bool,
sources: arrayOf(shape()),
onSetQuerySource: func,
selected: string,
}
export default OverlayControls

View File

@ -13,7 +13,7 @@ const buildText = q =>
q.rawText || buildInfluxQLQuery(q.range || TEMPLATE_RANGE, q) || ''
const QueryMaker = ({
source: {links},
source,
actions,
queries,
timeRange,
@ -39,7 +39,7 @@ const QueryMaker = ({
query={buildText(activeQuery)}
config={activeQuery}
onUpdate={rawTextBinder(
links,
source.links,
activeQuery.id,
actions.editRawTextAsync
)}
@ -49,6 +49,7 @@ const QueryMaker = ({
query={activeQuery}
actions={actions}
onAddQuery={onAddQuery}
source={source}
/>
</div>
: <EmptyQuery onAddQuery={onAddQuery} />}

View File

@ -0,0 +1,28 @@
import React, {PropTypes} from 'react'
import Dropdown from 'shared/components/Dropdown'
const SourceSelector = ({sources = [], selected, onSetQuerySource}) =>
sources.length > 1
? <div className="source-selector">
<h3>Source:</h3>
<Dropdown
items={sources}
buttonSize="btn-sm"
menuClass="dropdown-astronaut"
useAutoComplete={true}
selected={selected}
onChoose={onSetQuerySource}
className="dropdown-240"
/>
</div>
: null
const {arrayOf, func, shape, string} = PropTypes
SourceSelector.propTypes = {
sources: arrayOf(shape()).isRequired,
onSetQuerySource: func.isRequired,
selected: string,
}
export default SourceSelector

View File

@ -190,6 +190,7 @@ class DashboardPage extends Component {
const {
source,
sources,
timeRange,
timeRange: {lower, upper},
showTemplateControlBar,
@ -277,6 +278,7 @@ class DashboardPage extends Component {
{selectedCell
? <CellEditorOverlay
source={source}
sources={sources}
cell={selectedCell}
timeRange={timeRange}
autoRefresh={autoRefresh}
@ -324,6 +326,7 @@ class DashboardPage extends Component {
{dashboard
? <Dashboard
source={source}
sources={sources}
dashboard={dashboard}
timeRange={timeRange}
autoRefresh={autoRefresh}
@ -354,6 +357,7 @@ DashboardPage.propTypes = {
self: string,
}),
}).isRequired,
sources: arrayOf(shape({})).isRequired,
params: shape({
sourceID: string.isRequired,
dashboardID: string.isRequired,
@ -415,6 +419,7 @@ const mapStateToProps = state => {
persisted: {autoRefresh, showTemplateControlBar},
},
dashboardUI: {dashboards, timeRange, cellQueryStatus},
sources,
} = state
return {
@ -424,6 +429,7 @@ const mapStateToProps = state => {
showTemplateControlBar,
inPresentationMode,
cellQueryStatus,
sources,
}
}

View File

@ -33,13 +33,15 @@ const VisHeader = ({views, view, onToggleView, name, query, errorThrown}) =>
</li>
)}
</ul>
<div
className="btn btn-sm btn-default dlcsv"
onClick={getCSV(query, errorThrown)}
>
<span className="icon download dlcsv" />
.csv
</div>
{query
? <div
className="btn btn-sm btn-default dlcsv"
onClick={getCSV(query, errorThrown)}
>
<span className="icon download dlcsv" />
.csv
</div>
: null}
</div>
: null}
<div className="graph-title">
@ -54,7 +56,7 @@ VisHeader.propTypes = {
view: string.isRequired,
onToggleView: func.isRequired,
name: string.isRequired,
query: shape().isRequired,
query: shape(),
errorThrown: func.isRequired,
}

View File

@ -51,7 +51,7 @@ const {arrayOf, func, number, shape, string} = PropTypes
VisView.propTypes = {
view: string.isRequired,
axes: shape(),
query: shape().isRequired,
query: shape(),
queries: arrayOf(shape()).isRequired,
cellType: string,
templates: arrayOf(shape()),

View File

@ -22,12 +22,6 @@ const Header = React.createClass({
}).isRequired,
},
contextTypes: {
source: shape({
name: string,
}),
},
handleChooseTimeRange(bounds) {
this.props.actions.setTimeRange(bounds)
},
@ -48,7 +42,7 @@ const Header = React.createClass({
</div>
<div className="page-header__right">
<GraphTips />
<SourceIndicator sourceName={this.context.source.name} />
<SourceIndicator />
<div
className="btn btn-sm btn-default"
onClick={showWriteForm}

View File

@ -84,7 +84,7 @@ export const HostsPage = React.createClass({
<h1 className="page-header__title">Host List</h1>
</div>
<div className="page-header__right">
<SourceIndicator sourceName={source.name} />
<SourceIndicator />
</div>
</div>
</div>

View File

@ -59,7 +59,7 @@ const KapacitorRules = ({
className="btn btn-sm btn-primary"
style={{marginRight: '4px'}}
>
Build Rule
<span className="icon plus" /> Build Rule
</Link>
</div>
</div>
@ -99,7 +99,7 @@ const KapacitorRules = ({
)
}
const PageContents = ({children, source}) =>
const PageContents = ({children}) =>
<div className="page">
<div className="page-header">
<div className="page-header__container">
@ -109,7 +109,7 @@ const PageContents = ({children, source}) =>
</h1>
</div>
<div className="page-header__right">
<SourceIndicator sourceName={source && source.name} />
<SourceIndicator />
</div>
</div>
</div>
@ -139,7 +139,6 @@ KapacitorRules.propTypes = {
PageContents.propTypes = {
children: node,
source: shape(),
onCloseTickscript: func,
}

View File

@ -4,14 +4,13 @@ import TimeRangeDropdown from 'shared/components/TimeRangeDropdown'
import SourceIndicator from 'shared/components/SourceIndicator'
const RuleHeaderSave = ({
source,
onSave,
timeRange,
validationError,
onChooseTimeRange,
}) =>
<div className="page-header__right">
<SourceIndicator sourceName={source.name} />
<SourceIndicator />
<TimeRangeDropdown
onChooseTimeRange={onChooseTimeRange}
selected={timeRange}
@ -41,7 +40,6 @@ const RuleHeaderSave = ({
const {func, shape, string} = PropTypes
RuleHeaderSave.propTypes = {
source: shape({}).isRequired,
onSave: func.isRequired,
validationError: string.isRequired,
onChooseTimeRange: func.isRequired,

View File

@ -11,7 +11,6 @@ const addName = list => list.map(l => ({...l, name: `${l.db}.${l.rp}`}))
const TickscriptHeader = ({
task: {id, type, dbrps},
task,
source: {name},
onSave,
onChangeType,
onChangeID,
@ -26,7 +25,7 @@ const TickscriptHeader = ({
: <TickscriptStaticID id={task.name} />}
</div>
<div className="page-header__right">
<SourceIndicator sourceName={name} />
<SourceIndicator />
<TickscriptType type={type} onChangeType={onChangeType} />
<MultiSelectDBDropdown
selectedItems={addName(dbrps)}
@ -48,7 +47,6 @@ const {arrayOf, bool, func, shape, string} = PropTypes
TickscriptHeader.propTypes = {
onSave: func,
source: shape(),
onSelectDbrps: func.isRequired,
task: shape({
dbrps: arrayOf(

View File

@ -221,8 +221,8 @@ const AutoRefresh = ComposedComponent => {
return true
}
return data.every(datum => {
return datum.response.results.every(result => {
return data.every(({response}) => {
return _.get(response, 'results', []).every(result => {
return (
Object.keys(result).filter(k => k !== 'statement_id').length === 0
)

View File

@ -15,7 +15,7 @@ const CustomTimeIndicator = ({queries}) => {
: customLower
return (
<span className="dash-graph--custom-time">
<span className="custom-indicator">
{customTimeRange}
</span>
)

View File

@ -14,6 +14,17 @@ const DatabaseList = React.createClass({
propTypes: {
query: shape({}).isRequired,
onChooseNamespace: func.isRequired,
querySource: shape({
links: shape({
proxy: string.isRequired,
}).isRequired,
}),
},
getDefaultProps() {
return {
source: null,
}
},
contextTypes: {
@ -31,8 +42,23 @@ const DatabaseList = React.createClass({
},
componentDidMount() {
this.getDbRp()
},
componentDidUpdate(prevProps) {
if (_.isEqual(prevProps.querySource, this.props.querySource)) {
return
}
this.getDbRp()
},
getDbRp() {
const {source} = this.context
const proxy = source.links.proxy
const {querySource} = this.props
const proxy =
_.get(querySource, ['links', 'proxy'], null) || source.links.proxy
showDatabases(proxy).then(resp => {
const {errors, databases} = showDatabasesParser(resp.data)
if (errors.length) {

View File

@ -206,6 +206,7 @@ class Dropdown extends Component {
iconName,
buttonSize,
buttonColor,
toggleStyle,
useAutoComplete,
} = this.props
const {isOpen, searchTerm, filteredItems} = this.state
@ -222,6 +223,7 @@ class Dropdown extends Component {
{useAutoComplete && isOpen
? <div
className={`dropdown-autocomplete dropdown-toggle ${buttonSize} ${buttonColor}`}
style={toggleStyle}
>
<input
ref="dropdownAutoComplete"
@ -236,7 +238,10 @@ class Dropdown extends Component {
/>
<span className="caret" />
</div>
: <div className={`btn dropdown-toggle ${buttonSize} ${buttonColor}`}>
: <div
className={`btn dropdown-toggle ${buttonSize} ${buttonColor}`}
style={toggleStyle}
>
{iconName
? <span className={classnames('icon', {[iconName]: true})} />
: null}
@ -291,6 +296,7 @@ Dropdown.propTypes = {
menuLabel: string,
menuClass: string,
useAutoComplete: bool,
toggleStyle: shape(),
}
export default OnClickOutside(Dropdown)

View File

@ -5,7 +5,7 @@ const EmptyQueryState = ({onAddQuery}) =>
<h5>This Graph has no Queries</h5>
<br />
<div className="btn btn-primary" onClick={onAddQuery}>
Add a Query
<span className="icon plus" /> Add a Query
</div>
</div>

View File

@ -1,4 +1,5 @@
import React, {PropTypes, Component} from 'react'
import _ from 'lodash'
import FieldListItem from 'src/data_explorer/components/FieldListItem'
import GroupByTimeDropdown from 'src/data_explorer/components/GroupByTimeDropdown'
@ -26,7 +27,8 @@ class FieldList extends Component {
}
componentDidUpdate(prevProps) {
const {database, measurement, retentionPolicy} = this.props.query
const {querySource, query} = this.props
const {database, measurement, retentionPolicy} = query
const {
database: prevDB,
measurement: prevMeas,
@ -39,7 +41,8 @@ class FieldList extends Component {
if (
database === prevDB &&
measurement === prevMeas &&
retentionPolicy === prevRP
retentionPolicy === prevRP &&
_.isEqual(prevProps.querySource, querySource)
) {
return
}
@ -58,14 +61,12 @@ class FieldList extends Component {
_getFields = () => {
const {database, measurement, retentionPolicy} = this.props.query
const {source} = this.context
const proxySource = source.links.proxy
const {querySource} = this.props
showFieldKeys(
proxySource,
database,
measurement,
retentionPolicy
).then(resp => {
const proxy =
_.get(querySource, ['links', 'proxy'], null) || source.links.proxy
showFieldKeys(proxy, database, measurement, retentionPolicy).then(resp => {
const {errors, fieldSets} = showFieldKeysParser(resp.data)
if (errors.length) {
console.error('Error parsing fields keys: ', errors)
@ -171,6 +172,11 @@ FieldList.propTypes = {
applyFuncsToField: func.isRequired,
isKapacitorRule: bool,
isInDataExplorer: bool,
querySource: shape({
links: shape({
proxy: string.isRequired,
}).isRequired,
}),
}
export default FieldList

View File

@ -4,7 +4,7 @@ import ReactTooltip from 'react-tooltip'
const GraphTips = React.createClass({
render() {
const graphTipsText =
'<p><b>Graph Tips:</b><br/><br/><code>Click + Drag</code> Zoom in (X or Y)</p><p><code>Shift + Click</code> Pan Graph Window</p><p><code>Double Click</code> Reset Graph Window</p>'
'<h1>Graph Tips:</h1><p><code>Click + Drag</code> Zoom in (X or Y)</p><p><code>Shift + Click</code> Pan Graph Window</p><p><code>Double Click</code> Reset Graph Window</p>'
return (
<div
className="graph-tips"

View File

@ -4,30 +4,45 @@ import LayoutCell from 'shared/components/LayoutCell'
import RefreshingGraph from 'shared/components/RefreshingGraph'
import {buildQueriesForLayouts} from 'utils/influxql'
const Layout = ({
host,
cell,
cell: {h, axes, type},
source,
onZoom,
templates,
timeRange,
isEditable,
onEditCell,
autoRefresh,
onDeleteCell,
synchronizer,
resizeCoords,
onCancelEditCell,
onSummonOverlayTechnologies,
}) =>
import _ from 'lodash'
const getSource = (cell, source, sources, defaultSource) => {
const s = _.get(cell, ['queries', '0', 'source'], null)
if (!s) {
return source
}
return sources.find(src => src.links.self === s) || defaultSource
}
const Layout = (
{
host,
cell,
cell: {h, axes, type},
source,
sources,
onZoom,
templates,
timeRange,
isEditable,
onEditCell,
autoRefresh,
onDeleteCell,
synchronizer,
resizeCoords,
onCancelEditCell,
onSummonOverlayTechnologies,
},
{source: defaultSource}
) =>
<LayoutCell
onCancelEditCell={onCancelEditCell}
cell={cell}
isEditable={isEditable}
onEditCell={onEditCell}
onDeleteCell={onDeleteCell}
onCancelEditCell={onCancelEditCell}
onSummonOverlayTechnologies={onSummonOverlayTechnologies}
cell={cell}
>
{cell.isWidget
? <WidgetCell cell={cell} timeRange={timeRange} source={source} />
@ -36,17 +51,27 @@ const Layout = ({
type={type}
cellHeight={h}
onZoom={onZoom}
sources={sources}
timeRange={timeRange}
templates={templates}
autoRefresh={autoRefresh}
synchronizer={synchronizer}
resizeCoords={resizeCoords}
queries={buildQueriesForLayouts(cell, source, timeRange, host)}
queries={buildQueriesForLayouts(
cell,
getSource(cell, source, sources, defaultSource),
timeRange,
host
)}
/>}
</LayoutCell>
const {arrayOf, bool, func, number, shape, string} = PropTypes
Layout.contextTypes = {
source: shape(),
}
Layout.propTypes = {
autoRefresh: number.isRequired,
timeRange: shape({
@ -87,6 +112,7 @@ Layout.propTypes = {
onCancelEditCell: func,
resizeCoords: shape(),
onZoom: func,
sources: arrayOf(shape()),
}
export default Layout

View File

@ -40,16 +40,16 @@ class LayoutCell extends Component {
<div className="dash-graph">
<LayoutCellMenu
cell={cell}
onDeleteClick={this.handleDeleteClick}
onDelete={this.handleDeleteCell}
isDeleting={isDeleting}
isEditable={isEditable}
handleClickOutside={this.closeMenu}
onDelete={this.handleDeleteCell}
onEdit={this.handleSummonOverlay}
handleClickOutside={this.closeMenu}
onDeleteClick={this.handleDeleteClick}
/>
<LayoutCellHeader
cellName={cell.name}
queries={queries}
cellName={cell.name}
isEditable={isEditable}
/>
<div className="dash-graph--container">
@ -60,7 +60,7 @@ class LayoutCell extends Component {
className="no-query--button btn btn-md btn-primary"
onClick={this.handleSummonOverlay(cell)}
>
Add Graph
<span className="icon plus" /> Add Graph
</button>
</div>}
</div>
@ -69,7 +69,7 @@ class LayoutCell extends Component {
}
}
const {array, bool, func, node, number, shape, string} = PropTypes
const {arrayOf, bool, func, node, number, shape, string} = PropTypes
LayoutCell.propTypes = {
cell: shape({
@ -77,7 +77,7 @@ LayoutCell.propTypes = {
isEditing: bool,
x: number.isRequired,
y: number.isRequired,
queries: array,
queries: arrayOf(shape()),
}).isRequired,
children: node.isRequired,
onDeleteCell: func,

View File

@ -1,5 +1,4 @@
import React, {PropTypes} from 'react'
import classnames from 'classnames'
import CustomTimeIndicator from 'shared/components/CustomTimeIndicator'
@ -8,12 +7,12 @@ import {NEW_DEFAULT_DASHBOARD_CELL} from 'src/dashboards/constants/index'
const LayoutCellHeader = ({queries, isEditable, cellName}) => {
const cellNameIsDefault = cellName === NEW_DEFAULT_DASHBOARD_CELL.name
const headingClass = `dash-graph--heading ${isEditable
? 'dash-graph--heading-draggable'
: ''}`
return (
<div
className={classnames('dash-graph--heading', {
'dash-graph--heading-draggable': isEditable,
})}
>
<div className={headingClass}>
<span
className={
cellNameIsDefault
@ -22,18 +21,20 @@ const LayoutCellHeader = ({queries, isEditable, cellName}) => {
}
>
{cellName}
{queries && queries.length
? <CustomTimeIndicator queries={queries} />
: null}
<div className="dash-graph--custom-indicators">
{queries && queries.length
? <CustomTimeIndicator queries={queries} />
: null}
</div>
</span>
</div>
)
}
const {array, bool, string} = PropTypes
const {arrayOf, bool, shape, string} = PropTypes
LayoutCellHeader.propTypes = {
queries: array,
queries: arrayOf(shape()),
isEditable: bool,
cellName: string,
}

View File

@ -1,6 +1,7 @@
import React, {Component, PropTypes} from 'react'
import ReactGridLayout, {WidthProvider} from 'react-grid-layout'
import Resizeable from 'react-component-resizable'
import _ from 'lodash'
import Layout from 'src/shared/components/Layout'
@ -26,11 +27,6 @@ class LayoutRenderer extends Component {
}
}
// idea adopted from https://stackoverflow.com/questions/36862334/get-viewport-window-height-in-reactjs
updateWindowDimensions = () => {
this.setState({rowHeight: this.calculateRowHeight()})
}
handleLayoutChange = layout => {
if (!this.props.onPositionChange) {
return
@ -72,6 +68,7 @@ class LayoutRenderer extends Component {
host,
cells,
source,
sources,
onZoom,
templates,
timeRange,
@ -88,7 +85,7 @@ class LayoutRenderer extends Component {
const isDashboard = !!this.props.onPositionChange
return (
<Resizeable onResize={this.updateWindowDimensions}>
<Resizeable onResize={this.handleCellResize}>
<GridLayout
layout={cells}
cols={12}
@ -110,6 +107,7 @@ class LayoutRenderer extends Component {
host={host}
source={source}
onZoom={onZoom}
sources={sources}
templates={templates}
timeRange={timeRange}
isEditable={isEditable}
@ -172,6 +170,7 @@ LayoutRenderer.propTypes = {
isEditable: bool,
onCancelEditCell: func,
onZoom: func,
sources: arrayOf(shape({})),
}
export default LayoutRenderer

View File

@ -1,5 +1,6 @@
import React, {PropTypes} from 'react'
import classnames from 'classnames'
import _ from 'lodash'
import {showMeasurements} from 'shared/apis/metaQuery'
import showMeasurementsParser from 'shared/parsing/showMeasurements'
@ -19,6 +20,11 @@ const MeasurementList = React.createClass({
onChooseTag: func.isRequired,
onToggleTagAcceptance: func.isRequired,
onGroupByTag: func.isRequired,
querySource: shape({
links: shape({
proxy: string.isRequired,
}).isRequired,
}),
},
contextTypes: {
@ -36,6 +42,12 @@ const MeasurementList = React.createClass({
}
},
getDefaultProps() {
return {
querySource: null,
}
},
componentDidMount() {
if (!this.props.query.database) {
return
@ -45,13 +57,16 @@ const MeasurementList = React.createClass({
},
componentDidUpdate(prevProps) {
const {query} = this.props
const {query, querySource} = this.props
if (!query.database) {
return
}
if (prevProps.query.database === query.database) {
if (
prevProps.query.database === query.database &&
_.isEqual(prevProps.querySource, querySource)
) {
return
}
@ -181,7 +196,11 @@ const MeasurementList = React.createClass({
_getMeasurements() {
const {source} = this.context
const proxy = source.links.proxy
const {querySource} = this.props
const proxy =
_.get(querySource, ['links', 'proxy'], null) || source.links.proxy
showMeasurements(proxy, this.props.query.database).then(resp => {
const {errors, measurementSets} = showMeasurementsParser(resp.data)
if (errors.length) {

View File

@ -9,6 +9,7 @@ const actionBinder = (id, action) => item => action(id, item)
const SchemaExplorer = ({
query,
query: {id},
source,
actions: {
chooseTag,
groupByTag,
@ -24,17 +25,22 @@ const SchemaExplorer = ({
<div className="query-builder">
<DatabaseList
query={query}
querySource={source}
onChooseNamespace={actionBinder(id, chooseNamespace)}
/>
<MeasurementList
source={source}
query={query}
querySource={source}
onChooseTag={actionBinder(id, chooseTag)}
onGroupByTag={actionBinder(id, groupByTag)}
onChooseMeasurement={actionBinder(id, chooseMeasurement)}
onToggleTagAcceptance={actionBinder(id, toggleTagAcceptance)}
/>
<FieldList
source={source}
query={query}
querySource={source}
onToggleField={actionBinder(id, toggleFieldWithGroupByInterval)}
onFill={actionBinder(id, fill)}
onGroupByTime={actionBinder(id, groupByTime)}
@ -60,6 +66,7 @@ SchemaExplorer.propTypes = {
fill: func.isRequired,
editRawTextAsync: func.isRequired,
}).isRequired,
source: shape({}),
}
export default SchemaExplorer

View File

@ -1,35 +1,56 @@
import React, {PropTypes} from 'react'
import _ from 'lodash'
import uuid from 'node-uuid'
import ReactTooltip from 'react-tooltip'
const SourceIndicator = React.createClass({
propTypes: {
sourceName: PropTypes.string,
},
const SourceIndicator = ({sourceOverride}, {source: {name, url}}) => {
const sourceName = _.get(sourceOverride, 'name', null)
? sourceOverride.name
: name
const sourceUrl = _.get(sourceOverride, 'url', null)
? sourceOverride.url
: url
render() {
const {sourceName} = this.props
if (!sourceName) {
return null
}
const sourceNameTooltip = `Connected to <code>${sourceName}</code>`
return (
<div
className="source-indicator"
data-for="source-indicator-tooltip"
data-tip={sourceNameTooltip}
>
<span className="icon server2" />
<ReactTooltip
id="source-indicator-tooltip"
effect="solid"
html={true}
offset={{top: 2}}
place="bottom"
class="influx-tooltip place-bottom"
/>
</div>
)
},
})
if (!sourceName) {
return null
}
const sourceNameTooltip = `<h1>Connected to Source:</h1><p><code>${sourceName} @ ${sourceUrl}</code></p>`
const uuidTooltip = uuid.v4()
return (
<div
className="source-indicator"
data-for={uuidTooltip}
data-tip={sourceNameTooltip}
>
<span className="icon server2" />
<ReactTooltip
id={uuidTooltip}
effect="solid"
html={true}
offset={{top: 2}}
place="bottom"
class="influx-tooltip place-bottom"
/>
</div>
)
}
const {shape, string} = PropTypes
SourceIndicator.propTypes = {
sourceOverride: shape({
name: string,
url: string,
}),
}
SourceIndicator.contextTypes = {
source: shape({
name: string,
url: string,
}),
}
export default SourceIndicator

View File

@ -2,9 +2,9 @@ import _ from 'lodash'
const emptyFunny = [
'Looks like you dont have any queries. Be a lot cooler if you did.',
'Create a query below. Go on, I dare ya!',
'Create a query below. Have fun!',
'1) Create a query below\n2) Profit',
'Create a query. Go on, I dare ya!',
'Create a query. Have fun!',
'1) Create a query \n2) Profit',
]
export const emptyGraphCopy = _.sample(emptyFunny)

View File

@ -17,7 +17,7 @@ const kapacitorDropdown = (
to={`/sources/${source.id}/kapacitors/new`}
className="btn btn-xs btn-default"
>
Add Config
<span className="icon plus" /> Add Config
</Link>
)
}
@ -89,7 +89,7 @@ const InfluxTable = ({
to={`/sources/${source.id}/manage-sources/new`}
className="btn btn-sm btn-primary"
>
Add Source
<span className="icon plus" /> Add Source
</Link>
</div>
<div className="panel-body">

View File

@ -1,20 +1,14 @@
import React, {PropTypes} from 'react'
import React, {PropTypes, Component} from 'react'
import classnames from 'classnames'
import {insecureSkipVerifyText} from 'shared/copy/tooltipText'
import _ from 'lodash'
const {bool, func, shape} = PropTypes
class SourceForm extends Component {
constructor(props) {
super(props)
}
export const SourceForm = React.createClass({
propTypes: {
source: shape({}).isRequired,
editMode: bool.isRequired,
onInputChange: func.isRequired,
onSubmit: func.isRequired,
onBlurSourceURL: func.isRequired,
},
handleSubmitForm(e) {
handleSubmitForm = e => {
e.preventDefault()
const newSource = {
...this.props.source,
@ -31,9 +25,14 @@ export const SourceForm = React.createClass({
}
this.props.onSubmit(newSource)
},
}
handleBlurSourceURL() {
handleUseDefaultValues = () => {
this.sourceURL.value = 'http://localhost:8086'
this.sourceName.value = 'My InfluxDB'
}
handleBlurSourceURL = () => {
const url = this.sourceURL.value.trim()
if (!url) {
@ -46,7 +45,7 @@ export const SourceForm = React.createClass({
}
this.props.onBlurSourceURL(newSource)
},
}
render() {
const {source, editMode, onInputChange} = this.props
@ -58,14 +57,14 @@ export const SourceForm = React.createClass({
<form onSubmit={this.handleSubmitForm}>
<div className="form-group col-xs-12 col-sm-6">
<label htmlFor="connect-string"> Connection String</label>
<label htmlFor="connect-string">Connection String</label>
<input
type="text"
name="url"
ref={r => (this.sourceURL = r)}
className="form-control"
id="connect-string"
placeholder="http://localhost:8086"
placeholder="Address of InfluxDB"
onChange={onInputChange}
value={source.url || ''}
onBlur={this.handleBlurSourceURL}
@ -80,7 +79,7 @@ export const SourceForm = React.createClass({
ref={r => (this.sourceName = r)}
className="form-control"
id="name"
placeholder="Influx 1"
placeholder="Name this source"
onChange={onInputChange}
value={source.name || ''}
required={true}
@ -166,7 +165,7 @@ export const SourceForm = React.createClass({
</label>
</div>
: null}
<div className="form-group form-group-submit col-xs-12 col-sm-6 col-sm-offset-3">
<div className="form-group form-group-submit col-xs-12 col-sm-6 col-sm-offset-3 text-center">
<button
className={classnames('btn btn-block', {
'btn-primary': editMode,
@ -176,11 +175,29 @@ export const SourceForm = React.createClass({
>
{editMode ? 'Save Changes' : 'Add Source'}
</button>
<br />
<a
href="#"
className="btn btn-link btn-sm"
onClick={this.handleUseDefaultValues}
>
Use Default Values
</a>
</div>
</form>
</div>
)
},
})
}
}
const {bool, func, shape} = PropTypes
SourceForm.propTypes = {
source: shape({}).isRequired,
editMode: bool.isRequired,
onInputChange: func.isRequired,
onSubmit: func.isRequired,
onBlurSourceURL: func.isRequired,
}
export default SourceForm

View File

@ -62,7 +62,7 @@ class ManageSources extends Component {
<h1 className="page-header__title">Configuration</h1>
</div>
<div className="page-header__right">
<SourceIndicator sourceName={source.name} />
<SourceIndicator />
</div>
</div>
</div>

View File

@ -125,7 +125,7 @@ export const SourcePage = React.createClass({
</h1>
</div>
<div className="page-header__right">
<SourceIndicator sourceName={source.name} />
<SourceIndicator />
</div>
</div>
</div>

View File

@ -56,7 +56,7 @@ class StatusPage extends Component {
<h1 className="page-header__title">Status</h1>
</div>
<div className="page-header__right">
<SourceIndicator sourceName={source.name} />
<SourceIndicator />
</div>
</div>
</div>

View File

@ -50,6 +50,7 @@
@import 'components/resizer';
@import 'components/search-widget';
@import 'components/source-indicator';
@import 'components/source-selector';
@import 'components/tables';
// Pages

View File

@ -17,8 +17,6 @@
padding: 30px;
flex: 1 0 0;
margin-right: 8px;
&:last-child { margin-right: 0; }
}
.display-options--cellx2 {
flex: 2 0 0;
@ -29,8 +27,6 @@
color: $g11-sidewalk;
@include no-user-select();
}
.viz-type-selector {
display: flex;
flex-wrap: wrap;

View File

@ -33,6 +33,15 @@ $tooltip-code-color: $c-potassium;
text-transform: none !important;
cursor: default;
h1 {
font-size: 14px;
font-weight: 600;
margin: 0 0 6px 0;
line-height: 1.125em;
letter-spacing: 0;
font-family: $default-font;
}
p {
margin: 0;
width: 100%;
@ -70,7 +79,6 @@ $tooltip-code-color: $c-potassium;
border-color: transparent transparent $tooltip-accent transparent !important;
}
/* Kapacitor Style Tooltip */
&.kapacitor-tooltip {
border-color: $c-rainforest !important;
@ -90,14 +98,13 @@ $tooltip-code-color: $c-potassium;
.influx-tooltip__hover {
@extend .influx-tooltip;
pointer-events: auto!important;
pointer-events: auto !important;
&:hover {
visibility: visible!important;
opacity: 1!important;
visibility: visible !important;
opacity: 1 !important;
}
}
/*
Question Mark Tooltip
----------------------------------------------
@ -121,8 +128,7 @@ $qmark-tooltip-size: 15px;
background-color: $g10-wolf;
color: $g0-obsidian;
margin: 0 5px;
transition:
background-color 0.25s ease;
transition: background-color 0.25s ease;
}
.question-mark-tooltip:hover {
cursor: default;

View File

@ -18,4 +18,4 @@
font-size: 16px;
margin: 0 4px;
}
}
}

View File

@ -0,0 +1,18 @@
/*
Source Selector component styles
----------------------------------------------------------------
*/
.source-selector {
display: flex;
align-items: center;
flex-wrap: nowrap;
flex: 1 0 0;
h3 {
margin: 0 4px 0 0;
font-size: 17px;
color: $g13-mist;
@include no-user-select();
}
}

View File

@ -11,22 +11,49 @@ $dash-graph-options-arrow: 8px;
------------------------------------------------------
*/
@keyframes refreshingSpinnerA {
0% { transform: translate(-50%,-50%) scale(1.75); background-color: $g7-graphite; }
33% { transform: translate(-50%,-50%) scale(1,1); }
66% { transform: translate(-50%,-50%) scale(1,1); }
100% { transform: translate(-50%,-50%) scale(1,1); }
0% {
transform: translate(-50%, -50%) scale(1.75);
background-color: $g7-graphite;
}
33% {
transform: translate(-50%, -50%) scale(1, 1);
}
66% {
transform: translate(-50%, -50%) scale(1, 1);
}
100% {
transform: translate(-50%, -50%) scale(1, 1);
}
}
@keyframes refreshingSpinnerB {
0% { transform: translate(-50%,-50%) scale(1,1); }
33% { transform: translate(-50%,-50%) scale(1.75); background-color: $g7-graphite; }
66% { transform: translate(-50%,-50%) scale(1,1); }
100% { transform: translate(-50%,-50%) scale(1,1); }
0% {
transform: translate(-50%, -50%) scale(1, 1);
}
33% {
transform: translate(-50%, -50%) scale(1.75);
background-color: $g7-graphite;
}
66% {
transform: translate(-50%, -50%) scale(1, 1);
}
100% {
transform: translate(-50%, -50%) scale(1, 1);
}
}
@keyframes refreshingSpinnerC {
0% { transform: translate(-50%,-50%) scale(1,1); }
33% { transform: translate(-50%,-50%) scale(1,1); }
66% { transform: translate(-50%,-50%) scale(1.75); background-color: $g7-graphite; }
100% { transform: translate(-50%,-50%) scale(1,1); }
0% {
transform: translate(-50%, -50%) scale(1, 1);
}
33% {
transform: translate(-50%, -50%) scale(1, 1);
}
66% {
transform: translate(-50%, -50%) scale(1.75);
background-color: $g7-graphite;
}
100% {
transform: translate(-50%, -50%) scale(1, 1);
}
}
/*
@ -93,7 +120,6 @@ $dash-graph-options-arrow: 8px;
top: 0;
width: 100%;
height: 100%;
}
.dygraph .dygraph-child {
position: absolute;
@ -124,9 +150,7 @@ $dash-graph-options-arrow: 8px;
font-weight: 600;
font-size: 13px;
color: $g14-chromium;
transition:
color 0.25s ease,
background-color 0.25s ease;
transition: color 0.25s ease, background-color 0.25s ease;
&.dash-graph--heading-draggable:hover {
cursor: move;
background-color: $g5-pepper;
@ -146,30 +170,41 @@ $dash-graph-options-arrow: 8px;
line-height: $dash-graph-heading;
width: calc(100% - 53px);
padding-left: 10px;
transition:
color 0.25s ease,
background-color 0.25s ease,
transition: color 0.25s ease, background-color 0.25s ease,
border-color 0.25s ease;
}
.dash-graph--name.dash-graph--name__default {
font-style: italic;
}
.dash-graph--custom-time {
font-style: normal;
font-family: $code-font;
color: $c-pool;
background-color: $g2-kevlar;
.dash-graph--custom-indicators {
height: 24px;
font-size: 10px;
line-height: 24px;
border-radius: 3px;
padding: 0 7px;
position: absolute;
top: 3px;
right: 2px;
}
right: 0;
display: flex;
> .custom-indicator,
> .source-indicator {
font-size: 10px;
line-height: 24px;
padding: 0 7px;
font-style: normal;
font-family: $code-font;
color: $c-pool;
background-color: $g2-kevlar;
margin-right: 2px;
border-radius: 3px;
}
> .source-indicator {
height: 24px;
> .icon {
font-size: 12px;
margin: 0;
}
}
}
.dash-graph-context {
z-index: 2;
position: absolute;
@ -187,9 +222,7 @@ $dash-graph-options-arrow: 8px;
font-size: 12px;
position: relative;
color: $g11-sidewalk;
transition:
color 0.25s ease,
background-color 0.25s ease;
transition: color 0.25s ease, background-color 0.25s ease;
&:hover,
&.active {
@ -197,13 +230,15 @@ $dash-graph-options-arrow: 8px;
color: $g20-white;
background-color: $g5-pepper;
}
&:first-child {margin-right: 2px;}
&:first-child {
margin-right: 2px;
}
> .icon {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
transform: translate(-50%, -50%);
}
}
.dash-graph-context--confirm {
@ -230,7 +265,7 @@ $dash-graph-options-arrow: 8px;
border-bottom-color: $c-curacao;
left: 50%;
top: 0;
transform: translate(-50%,-100%);
transform: translate(-50%, -100%);
transition: border-color 0.25s ease;
}
@ -241,7 +276,6 @@ $dash-graph-options-arrow: 8px;
&:hover:before {
border-bottom-color: $c-dreamsicle;
}
}
/* Presentation Mode */
@ -257,7 +291,7 @@ $dash-graph-options-arrow: 8px;
.graph-panel__refreshing {
position: absolute;
top: -18px !important;
transform: translate(0,0);
transform: translate(0, 0);
right: 50%;
transform: translateX(50%);
width: 16px;
@ -270,12 +304,24 @@ $dash-graph-options-arrow: 8px;
border-radius: 50%;
position: absolute;
top: 50%;
transform: translate(-50%,-50%);
transform: translate(-50%, -50%);
}
div:nth-child(1) {left: 0; animation: refreshingSpinnerA 0.8s cubic-bezier(0.645, 0.045, 0.355, 1) infinite; }
div:nth-child(2) {left: 50%; animation: refreshingSpinnerB 0.8s cubic-bezier(0.645, 0.045, 0.355, 1) infinite; }
div:nth-child(3) {left: 100%; animation: refreshingSpinnerC 0.8s cubic-bezier(0.645, 0.045, 0.355, 1) infinite;}
div:nth-child(1) {
left: 0;
animation: refreshingSpinnerA 0.8s cubic-bezier(0.645, 0.045, 0.355, 1)
infinite;
}
div:nth-child(2) {
left: 50%;
animation: refreshingSpinnerB 0.8s cubic-bezier(0.645, 0.045, 0.355, 1)
infinite;
}
div:nth-child(3) {
left: 100%;
animation: refreshingSpinnerC 0.8s cubic-bezier(0.645, 0.045, 0.355, 1)
infinite;
}
}
/*
@ -291,7 +337,7 @@ $dash-graph-options-arrow: 8px;
}
.react-grid-item {
&.resizing {
background-color: fade-out($g3-castle,0.09);
background-color: fade-out($g3-castle, 0.09);
border-color: $c-pool;
border-image-slice: 3%;
border-image-repeat: initial;
@ -301,13 +347,14 @@ $dash-graph-options-arrow: 8px;
z-index: 3;
& > .react-resizable-handle {
&:before, &:after {
&:before,
&:after {
background-color: $c-comet;
}
}
}
&.react-draggable-dragging {
background-color: fade-out($g3-castle,0.09);
background-color: fade-out($g3-castle, 0.09);
border-color: $c-pool;
border-image-slice: 3%;
border-image-repeat: initial;
@ -341,14 +388,15 @@ $dash-graph-options-arrow: 8px;
}
&:before {
width: 20px;
transform: translate(-50%,-50%) rotate(-45deg);
transform: translate(-50%, -50%) rotate(-45deg);
}
&:after {
width: 12px;
transform: translate(-3px,2px) rotate(-45deg);
transform: translate(-3px, 2px) rotate(-45deg);
}
&:hover {
&:before, &:after {
&:before,
&:after {
background-color: $c-comet;
}
}

View File

@ -44,10 +44,21 @@ $overlay-z: 100;
border: 0;
background-color: $g2-kevlar;
}
.overlay-controls .nav-tablist {
width: 200px;
li {
white-space: nowrap;
justify-content: center;
flex: 1 0 50%;
}
}
.overlay-controls--right {
display: flex;
align-items: center;
flex-wrap: nowrap;
justify-content: flex-end;
flex: 1 0 0;
.toggle {
margin: 0 0 0 5px;

View File

@ -1293,7 +1293,7 @@ div.btn > .icon,
button.btn > .icon,
input.btn > .icon {
position: relative;
top: -.5px;
top: -1px;
margin: 0 4px 0 0;
font-size: 1em;
}
@ -3727,9 +3727,10 @@ fieldset[disabled] button.btn-link-alert:after {
}
.label {
display: inline-block;
padding: .2em .6em;
font-size: .75em;
line-height: 1.2em;
padding: .3em .5em;
margin: 0 3px;
font-size: .9em;
line-height: 1.1em;
vertical-align: middle;
user-select: none;
}
@ -3887,7 +3888,7 @@ p .label {
text-overflow: ellipsis;
white-space: nowrap;
flex: 1 0 0%;
flex: 1 0 0;
}
.dropdown-toggle.btn-xs .caret {
right: 7px;
@ -4010,14 +4011,10 @@ p .label {
}
.dropdown-menu li.dropdown-item {
position: relative;
display: flex;
width: 100%;
padding: 0;
margin: 0;
user-select: none;
align-items: center;
justify-content: space-between;
}
.dropdown-menu li.dropdown-item,
.dropdown-menu li.dropdown-item:hover {
@ -4034,14 +4031,14 @@ p .label {
}
.dropdown-menu li.dropdown-item > a {
padding: 7px 9px;
overflow: hidden;
font-size: 13px;
font-weight: 500;
line-height: 13px;
color: #f0fcff;
text-overflow: ellipsis;
outline: none;
transition: color .25s ease;
flex: 1 0 0%;
}
.dropdown-menu li.dropdown-item > a,
.dropdown-menu li.dropdown-item > a:hover,
@ -4073,6 +4070,21 @@ p .label {
background: linear-gradient(to right, #326bba 0%, #22adf6 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='@color1', endColorstr='@color2', GradientType=1);
}
.dropdown-menu .dropdown-sub-item {
display: inline-block;
margin-top: 4px;
font-size: 12px;
line-height: 12px;
white-space: pre-wrap;
opacity: .66;
}
.dropdown-menu .dropdown-sub-item.dropdown-sub-item--success {
color: #a5f3b4;
opacity: 1;
}
.dropdown-menu .dropdown-sub-item span.icon {
margin-right: 3px;
}
.dropdown .dropdown-menu .dropdown-actions {
position: absolute;
top: 50%;
@ -5005,6 +5017,7 @@ p .label {
padding: 0;
margin: 0;
overflow: hidden;
background-color: #383846;
border: 2px solid #383846;
border-radius: 4px;
@ -5013,7 +5026,7 @@ p .label {
.nav-tablist > li {
display: flex;
padding: 0 14px;
margin: 0;
margin: 0 2px 0 0;
font-size: 15px;
font-weight: 600;
color: #999dab;
@ -5045,6 +5058,9 @@ p .label {
cursor: not-allowed;
background-color: #202028;
}
.nav-tablist > li:last-child {
margin-right: 0;
}
/* Size Modifiers */
.nav-tablist.nav-tablist-lg {
height: 46px;
@ -5336,24 +5352,28 @@ pre[data-lang="js"]:before {
.form-control::-webkit-input-placeholder,
textarea::-webkit-input-placeholder,
input::-webkit-input-placeholder {
font-style: italic;
font-weight: 500 !important;
color: #757888;
}
.form-control::-moz-placeholder,
textarea::-moz-placeholder,
input::-moz-placeholder {
font-style: italic;
font-weight: 500 !important;
color: #757888;
}
.form-control:-ms-input-placeholder,
textarea:-ms-input-placeholder,
input:-ms-input-placeholder {
font-style: italic;
font-weight: 500 !important;
color: #757888;
}
.form-control:-moz-placeholder,
textarea:-moz-placeholder,
input:-moz-placeholder {
font-style: italic;
font-weight: 500 !important;
color: #757888;
}

View File

@ -8,7 +8,17 @@ const buildQueries = (proxy, queryConfigs, timeRange) => {
})
const queries = statements.filter(s => s.text !== null).map(s => {
return {host: [proxy], text: s.text, id: s.id, queryConfig: s.queryConfig}
let queryProxy = ''
if (s.queryConfig.source) {
queryProxy = `${s.queryConfig.source.links.proxy}`
}
return {
host: [queryProxy || proxy],
text: s.text,
id: s.id,
queryConfig: s.queryConfig,
}
})
return queries