Merge pull request #1996 from influxdata/feature/source-on-cell
FEATURE: Switch InfluxDB sources per chart in Dashboardspull/2070/head
commit
29f9d3d024
|
@ -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
|
||||
|
|
|
@ -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{
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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{
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -1,26 +1,17 @@
|
|||
import React, {PropTypes} from 'react'
|
||||
import React from 'react'
|
||||
|
||||
import SourceIndicator from 'shared/components/SourceIndicator'
|
||||
|
||||
const DashboardsHeader = ({sourceName}) => {
|
||||
return (
|
||||
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 sourceName={sourceName} />
|
||||
<SourceIndicator />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const {string} = PropTypes
|
||||
|
||||
DashboardsHeader.propTypes = {
|
||||
sourceName: string.isRequired,
|
||||
}
|
||||
|
||||
export default DashboardsHeader
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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} />}
|
||||
|
|
|
@ -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
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -15,7 +15,7 @@ const CustomTimeIndicator = ({queries}) => {
|
|||
: customLower
|
||||
|
||||
return (
|
||||
<span className="dash-graph--custom-time">
|
||||
<span className="custom-indicator">
|
||||
{customTimeRange}
|
||||
</span>
|
||||
)
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -4,11 +4,24 @@ import LayoutCell from 'shared/components/LayoutCell'
|
|||
import RefreshingGraph from 'shared/components/RefreshingGraph'
|
||||
import {buildQueriesForLayouts} from 'utils/influxql'
|
||||
|
||||
const Layout = ({
|
||||
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,
|
||||
|
@ -20,14 +33,16 @@ const Layout = ({
|
|||
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
|
||||
|
|
|
@ -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">
|
||||
|
@ -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,
|
||||
|
|
|
@ -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}
|
||||
<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,
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,26 +1,32 @@
|
|||
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>`
|
||||
const sourceNameTooltip = `<h1>Connected to Source:</h1><p><code>${sourceName} @ ${sourceUrl}</code></p>`
|
||||
const uuidTooltip = uuid.v4()
|
||||
|
||||
return (
|
||||
<div
|
||||
className="source-indicator"
|
||||
data-for="source-indicator-tooltip"
|
||||
data-for={uuidTooltip}
|
||||
data-tip={sourceNameTooltip}
|
||||
>
|
||||
<span className="icon server2" />
|
||||
<ReactTooltip
|
||||
id="source-indicator-tooltip"
|
||||
id={uuidTooltip}
|
||||
effect="solid"
|
||||
html={true}
|
||||
offset={{top: 2}}
|
||||
|
@ -29,7 +35,22 @@ const SourceIndicator = React.createClass({
|
|||
/>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const {shape, string} = PropTypes
|
||||
|
||||
SourceIndicator.propTypes = {
|
||||
sourceOverride: shape({
|
||||
name: string,
|
||||
url: string,
|
||||
}),
|
||||
}
|
||||
|
||||
SourceIndicator.contextTypes = {
|
||||
source: shape({
|
||||
name: string,
|
||||
url: string,
|
||||
}),
|
||||
}
|
||||
|
||||
export default SourceIndicator
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -125,7 +125,7 @@ export const SourcePage = React.createClass({
|
|||
</h1>
|
||||
</div>
|
||||
<div className="page-header__right">
|
||||
<SourceIndicator sourceName={source.name} />
|
||||
<SourceIndicator />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
@import 'components/resizer';
|
||||
@import 'components/search-widget';
|
||||
@import 'components/source-indicator';
|
||||
@import 'components/source-selector';
|
||||
@import 'components/tables';
|
||||
|
||||
// Pages
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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-indicators {
|
||||
height: 24px;
|
||||
border-radius: 3px;
|
||||
position: absolute;
|
||||
top: 3px;
|
||||
right: 0;
|
||||
display: flex;
|
||||
|
||||
.dash-graph--custom-time {
|
||||
> .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;
|
||||
height: 24px;
|
||||
font-size: 10px;
|
||||
line-height: 24px;
|
||||
margin-right: 2px;
|
||||
border-radius: 3px;
|
||||
padding: 0 7px;
|
||||
position: absolute;
|
||||
top: 3px;
|
||||
right: 2px;
|
||||
}
|
||||
}
|
||||
> .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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue