Merge branch 'master' into presentational-page-components
commit
dda369c24b
|
@ -22,6 +22,7 @@
|
||||||
1. [#3649](https://github.com/influxdata/chronograf/pull/3649): Fix erroneous icons in Date Picker widget
|
1. [#3649](https://github.com/influxdata/chronograf/pull/3649): Fix erroneous icons in Date Picker widget
|
||||||
1. [#3697](https://github.com/influxdata/chronograf/pull/3697): Fix allowing hyphens in basepath
|
1. [#3697](https://github.com/influxdata/chronograf/pull/3697): Fix allowing hyphens in basepath
|
||||||
1. [#3698](https://github.com/influxdata/chronograf/pull/3698): Fix error in cell when tempVar returns no values
|
1. [#3698](https://github.com/influxdata/chronograf/pull/3698): Fix error in cell when tempVar returns no values
|
||||||
|
1. [#3733](https://github.com/influxdata/chronograf/pull/3733): Change arrows in table columns so that ascending sort points up and descending points down
|
||||||
|
|
||||||
## v1.5.0.0 [2018-05-15-RC]
|
## v1.5.0.0 [2018-05-15-RC]
|
||||||
|
|
||||||
|
|
|
@ -341,6 +341,7 @@ func MarshalDashboard(d chronograf.Dashboard) ([]byte, error) {
|
||||||
Selected: v.Selected,
|
Selected: v.Selected,
|
||||||
Type: v.Type,
|
Type: v.Type,
|
||||||
Value: v.Value,
|
Value: v.Value,
|
||||||
|
Key: v.Key,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -522,6 +523,7 @@ func UnmarshalDashboard(data []byte, d *chronograf.Dashboard) error {
|
||||||
Selected: v.Selected,
|
Selected: v.Selected,
|
||||||
Type: v.Type,
|
Type: v.Type,
|
||||||
Value: v.Value,
|
Value: v.Value,
|
||||||
|
Key: v.Key,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -640,6 +640,7 @@ type TemplateValue struct {
|
||||||
Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"`
|
Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"`
|
||||||
Value string `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
|
Value string `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
|
||||||
Selected bool `protobuf:"varint,3,opt,name=selected,proto3" json:"selected,omitempty"`
|
Selected bool `protobuf:"varint,3,opt,name=selected,proto3" json:"selected,omitempty"`
|
||||||
|
Key string `protobuf:"bytes,4,opt,name=key,proto3" json:"key,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *TemplateValue) Reset() { *m = TemplateValue{} }
|
func (m *TemplateValue) Reset() { *m = TemplateValue{} }
|
||||||
|
@ -668,6 +669,13 @@ func (m *TemplateValue) GetSelected() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *TemplateValue) GetKey() string {
|
||||||
|
if m != nil {
|
||||||
|
return m.Key
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
type TemplateQuery struct {
|
type TemplateQuery struct {
|
||||||
Command string `protobuf:"bytes,1,opt,name=command,proto3" json:"command,omitempty"`
|
Command string `protobuf:"bytes,1,opt,name=command,proto3" json:"command,omitempty"`
|
||||||
Db string `protobuf:"bytes,2,opt,name=db,proto3" json:"db,omitempty"`
|
Db string `protobuf:"bytes,2,opt,name=db,proto3" json:"db,omitempty"`
|
||||||
|
@ -1388,111 +1396,111 @@ func init() {
|
||||||
func init() { proto.RegisterFile("internal.proto", fileDescriptorInternal) }
|
func init() { proto.RegisterFile("internal.proto", fileDescriptorInternal) }
|
||||||
|
|
||||||
var fileDescriptorInternal = []byte{
|
var fileDescriptorInternal = []byte{
|
||||||
// 1685 bytes of a gzipped FileDescriptorProto
|
// 1691 bytes of a gzipped FileDescriptorProto
|
||||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0x5b, 0x8f, 0xe3, 0x48,
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0xdd, 0x8f, 0xe3, 0x48,
|
||||||
0x15, 0x96, 0x93, 0x38, 0x89, 0x4f, 0xd2, 0xbd, 0x2d, 0x33, 0xda, 0x35, 0x0b, 0x42, 0xc1, 0xe2,
|
0x11, 0x97, 0x13, 0x3b, 0x89, 0x2b, 0x99, 0xb9, 0x91, 0x59, 0xdd, 0x99, 0x03, 0xa1, 0x60, 0xf1,
|
||||||
0xd2, 0x5c, 0x76, 0x58, 0xf5, 0x0a, 0x09, 0xad, 0x76, 0x57, 0xea, 0xcb, 0xce, 0xd0, 0x73, 0xed,
|
0x31, 0x7c, 0xdc, 0x72, 0x9a, 0x13, 0x12, 0x3a, 0xdd, 0x9d, 0x34, 0x1f, 0xb7, 0xcb, 0xec, 0xe7,
|
||||||
0xa9, 0x74, 0x0f, 0x4f, 0x68, 0x55, 0xb1, 0x2b, 0x49, 0x69, 0x1d, 0xdb, 0x94, 0xcb, 0xdd, 0x6d,
|
0x6c, 0x67, 0x76, 0x78, 0x42, 0xa7, 0x4e, 0xdc, 0x49, 0x5a, 0xe7, 0xd8, 0xa6, 0xdd, 0x9e, 0x19,
|
||||||
0x9e, 0xf9, 0x1d, 0x48, 0x48, 0xf0, 0x8e, 0x10, 0x8f, 0x48, 0xbc, 0xf3, 0x03, 0xf8, 0x2b, 0xbc,
|
0xf3, 0xcc, 0xdf, 0x81, 0x84, 0x04, 0xef, 0x08, 0xf1, 0x88, 0xc4, 0x3b, 0x7f, 0x00, 0xff, 0x0a,
|
||||||
0xa2, 0x53, 0x17, 0xa7, 0xdc, 0x9d, 0x19, 0x0d, 0x12, 0xda, 0xb7, 0xfa, 0xce, 0x39, 0x39, 0x55,
|
0xaf, 0xa8, 0xfa, 0xc3, 0x69, 0xcf, 0x64, 0x57, 0x8b, 0x84, 0xee, 0xad, 0x7f, 0x55, 0x95, 0xea,
|
||||||
0x75, 0x2e, 0x5f, 0x1d, 0x07, 0xf6, 0x79, 0x2e, 0x99, 0xc8, 0x69, 0xf6, 0xb0, 0x14, 0x85, 0x2c,
|
0xea, 0xea, 0xaa, 0x5f, 0x97, 0x03, 0xfb, 0x3c, 0x97, 0x4c, 0xe4, 0x34, 0x7b, 0x58, 0x8a, 0x42,
|
||||||
0xc2, 0xb1, 0xc5, 0xf1, 0x1f, 0xfa, 0x30, 0x9c, 0x17, 0xb5, 0x48, 0x58, 0xb8, 0x0f, 0xbd, 0xf3,
|
0x16, 0xd1, 0xc8, 0xe2, 0xe4, 0x0f, 0x7d, 0x18, 0xcc, 0x8a, 0x5a, 0x2c, 0x58, 0xb4, 0x0f, 0xbd,
|
||||||
0xb3, 0xc8, 0x9b, 0x79, 0x87, 0x7d, 0xd2, 0x3b, 0x3f, 0x0b, 0x43, 0x18, 0xbc, 0xa0, 0x1b, 0x16,
|
0xf3, 0xb3, 0xd8, 0x9b, 0x7a, 0x87, 0x7d, 0xd2, 0x3b, 0x3f, 0x8b, 0x22, 0xf0, 0x5f, 0xd0, 0x0d,
|
||||||
0xf5, 0x66, 0xde, 0x61, 0x40, 0xd4, 0x1a, 0x65, 0x97, 0x4d, 0xc9, 0xa2, 0xbe, 0x96, 0xe1, 0x3a,
|
0x8b, 0x7b, 0x53, 0xef, 0x30, 0x24, 0x6a, 0x8d, 0xb2, 0xcb, 0xa6, 0x64, 0x71, 0x5f, 0xcb, 0x70,
|
||||||
0xfc, 0x10, 0xc6, 0x57, 0x15, 0x7a, 0xdb, 0xb0, 0x68, 0xa0, 0xe4, 0x2d, 0x46, 0xdd, 0x05, 0xad,
|
0x1d, 0x7d, 0x08, 0xa3, 0xd7, 0x15, 0x7a, 0xdb, 0xb0, 0xd8, 0x57, 0xf2, 0x16, 0xa3, 0xee, 0x82,
|
||||||
0xaa, 0x9b, 0x42, 0xa4, 0x91, 0xaf, 0x75, 0x16, 0x87, 0x07, 0xd0, 0xbf, 0x22, 0xcf, 0xa2, 0xa1,
|
0x56, 0xd5, 0x4d, 0x21, 0xd2, 0x38, 0xd0, 0x3a, 0x8b, 0xa3, 0x03, 0xe8, 0xbf, 0x26, 0xcf, 0xe2,
|
||||||
0x12, 0xe3, 0x32, 0x8c, 0x60, 0x74, 0xc6, 0x96, 0xb4, 0xce, 0x64, 0x34, 0x9a, 0x79, 0x87, 0x63,
|
0x81, 0x12, 0xe3, 0x32, 0x8a, 0x61, 0x78, 0xc6, 0x96, 0xb4, 0xce, 0x64, 0x3c, 0x9c, 0x7a, 0x87,
|
||||||
0x62, 0x21, 0xfa, 0xb9, 0x64, 0x19, 0x5b, 0x09, 0xba, 0x8c, 0xc6, 0xda, 0x8f, 0xc5, 0xe1, 0x43,
|
0x23, 0x62, 0x21, 0xfa, 0xb9, 0x64, 0x19, 0x5b, 0x09, 0xba, 0x8c, 0x47, 0xda, 0x8f, 0xc5, 0xd1,
|
||||||
0x08, 0xcf, 0xf3, 0x8a, 0x25, 0xb5, 0x60, 0xf3, 0xaf, 0x79, 0xf9, 0x9a, 0x09, 0xbe, 0x6c, 0xa2,
|
0x43, 0x88, 0xce, 0xf3, 0x8a, 0x2d, 0x6a, 0xc1, 0x66, 0x5f, 0xf3, 0xf2, 0x8a, 0x09, 0xbe, 0x6c,
|
||||||
0x40, 0x39, 0xd8, 0xa1, 0xc1, 0x5d, 0x9e, 0x33, 0x49, 0x71, 0x6f, 0x50, 0xae, 0x2c, 0x0c, 0x63,
|
0xe2, 0x50, 0x39, 0xd8, 0xa1, 0xc1, 0x5d, 0x9e, 0x33, 0x49, 0x71, 0x6f, 0x50, 0xae, 0x2c, 0x8c,
|
||||||
0x98, 0xce, 0xd7, 0x54, 0xb0, 0x74, 0xce, 0x12, 0xc1, 0x64, 0x34, 0x51, 0xea, 0x8e, 0x0c, 0x6d,
|
0x12, 0x98, 0xcc, 0xd6, 0x54, 0xb0, 0x74, 0xc6, 0x16, 0x82, 0xc9, 0x78, 0xac, 0xd4, 0x1d, 0x19,
|
||||||
0x5e, 0x8a, 0x15, 0xcd, 0xf9, 0xef, 0xa9, 0xe4, 0x45, 0x1e, 0x4d, 0xb5, 0x8d, 0x2b, 0xc3, 0x28,
|
0xda, 0xbc, 0x14, 0x2b, 0x9a, 0xf3, 0xdf, 0x53, 0xc9, 0x8b, 0x3c, 0x9e, 0x68, 0x1b, 0x57, 0x86,
|
||||||
0x91, 0x22, 0x63, 0xd1, 0x9e, 0x8e, 0x12, 0xae, 0xc3, 0xef, 0x42, 0x60, 0x2e, 0x43, 0x2e, 0xa2,
|
0x59, 0x22, 0x45, 0xc6, 0xe2, 0x3d, 0x9d, 0x25, 0x5c, 0x47, 0xdf, 0x85, 0xd0, 0x1c, 0x86, 0x5c,
|
||||||
0x7d, 0xa5, 0xd8, 0x0a, 0xe2, 0xbf, 0x7b, 0x10, 0x9c, 0xd1, 0x6a, 0xbd, 0x28, 0xa8, 0x48, 0xdf,
|
0xc4, 0xfb, 0x4a, 0xb1, 0x15, 0x24, 0x7f, 0xf7, 0x20, 0x3c, 0xa3, 0xd5, 0x7a, 0x5e, 0x50, 0x91,
|
||||||
0x29, 0x13, 0x1f, 0x81, 0x9f, 0xb0, 0x2c, 0xab, 0xa2, 0xfe, 0xac, 0x7f, 0x38, 0x39, 0xfa, 0xe0,
|
0xbe, 0xd3, 0x4d, 0x7c, 0x04, 0xc1, 0x82, 0x65, 0x59, 0x15, 0xf7, 0xa7, 0xfd, 0xc3, 0xf1, 0xd1,
|
||||||
0x61, 0x9b, 0xe2, 0xd6, 0xcf, 0x29, 0xcb, 0x32, 0xa2, 0xad, 0xc2, 0x8f, 0x21, 0x90, 0x6c, 0x53,
|
0x07, 0x0f, 0xdb, 0x2b, 0x6e, 0xfd, 0x9c, 0xb2, 0x2c, 0x23, 0xda, 0x2a, 0xfa, 0x18, 0x42, 0xc9,
|
||||||
0x66, 0x54, 0xb2, 0x2a, 0x1a, 0xa8, 0x9f, 0x84, 0xdb, 0x9f, 0x5c, 0x1a, 0x15, 0xd9, 0x1a, 0xdd,
|
0x36, 0x65, 0x46, 0x25, 0xab, 0x62, 0x5f, 0xfd, 0x24, 0xda, 0xfe, 0xe4, 0xd2, 0xa8, 0xc8, 0xd6,
|
||||||
0xbb, 0xa8, 0x7f, 0xff, 0xa2, 0xf1, 0xbf, 0x07, 0xb0, 0xd7, 0xd9, 0x2e, 0x9c, 0x82, 0x77, 0xab,
|
0xe8, 0xde, 0x41, 0x83, 0xfb, 0x07, 0x4d, 0xfe, 0xed, 0xc3, 0x5e, 0x67, 0xbb, 0x68, 0x02, 0xde,
|
||||||
0x4e, 0xee, 0x13, 0xef, 0x16, 0x51, 0xa3, 0x4e, 0xed, 0x13, 0xaf, 0x41, 0x74, 0xa3, 0x2a, 0xc7,
|
0xad, 0x8a, 0x3c, 0x20, 0xde, 0x2d, 0xa2, 0x46, 0x45, 0x1d, 0x10, 0xaf, 0x41, 0x74, 0xa3, 0x2a,
|
||||||
0x27, 0xde, 0x0d, 0xa2, 0xb5, 0xaa, 0x17, 0x9f, 0x78, 0xeb, 0xf0, 0x27, 0x30, 0xfa, 0x5d, 0xcd,
|
0x27, 0x20, 0xde, 0x0d, 0xa2, 0xb5, 0xaa, 0x97, 0x80, 0x78, 0xeb, 0xe8, 0x27, 0x30, 0xfc, 0x5d,
|
||||||
0x04, 0x67, 0x55, 0xe4, 0xab, 0xd3, 0xbd, 0xb7, 0x3d, 0xdd, 0xab, 0x9a, 0x89, 0x86, 0x58, 0x3d,
|
0xcd, 0x04, 0x67, 0x55, 0x1c, 0xa8, 0xe8, 0xde, 0xdb, 0x46, 0xf7, 0xaa, 0x66, 0xa2, 0x21, 0x56,
|
||||||
0x46, 0x43, 0xd5, 0x9a, 0x2e, 0x1c, 0xb5, 0x46, 0x99, 0xc4, 0xba, 0x1c, 0x69, 0x19, 0xae, 0x4d,
|
0x8f, 0xd9, 0x50, 0xb5, 0xa6, 0x0b, 0x47, 0xad, 0x51, 0x26, 0xb1, 0x2e, 0x87, 0x5a, 0x86, 0x6b,
|
||||||
0x14, 0x75, 0xb5, 0x60, 0x14, 0x7f, 0x09, 0x03, 0x7a, 0xcb, 0xaa, 0x28, 0x50, 0xfe, 0xbf, 0xff,
|
0x93, 0x45, 0x5d, 0x2d, 0x98, 0xc5, 0x5f, 0x82, 0x4f, 0x6f, 0x59, 0x15, 0x87, 0xca, 0xff, 0xf7,
|
||||||
0x86, 0x80, 0x3d, 0x3c, 0xbe, 0x65, 0xd5, 0x97, 0xb9, 0x14, 0x0d, 0x51, 0xe6, 0xe1, 0x8f, 0x61,
|
0xdf, 0x90, 0xb0, 0x87, 0xc7, 0xb7, 0xac, 0xfa, 0x32, 0x97, 0xa2, 0x21, 0xca, 0x3c, 0xfa, 0x31,
|
||||||
0x98, 0x14, 0x59, 0x21, 0xaa, 0x08, 0xee, 0x1e, 0xec, 0x14, 0xe5, 0xc4, 0xa8, 0xc3, 0x43, 0x18,
|
0x0c, 0x16, 0x45, 0x56, 0x88, 0x2a, 0x86, 0xbb, 0x81, 0x9d, 0xa2, 0x9c, 0x18, 0x75, 0x74, 0x08,
|
||||||
0x66, 0x6c, 0xc5, 0xf2, 0x54, 0xd5, 0xcd, 0xe4, 0xe8, 0x60, 0x6b, 0xf8, 0x4c, 0xc9, 0x89, 0xd1,
|
0x83, 0x8c, 0xad, 0x58, 0x9e, 0xaa, 0xba, 0x19, 0x1f, 0x1d, 0x6c, 0x0d, 0x9f, 0x29, 0x39, 0x31,
|
||||||
0x87, 0x9f, 0xc2, 0x54, 0xd2, 0x45, 0xc6, 0x5e, 0x96, 0x18, 0xc5, 0x4a, 0xd5, 0xd0, 0xe4, 0xe8,
|
0xfa, 0xe8, 0x53, 0x98, 0x48, 0x3a, 0xcf, 0xd8, 0xcb, 0x12, 0xb3, 0x58, 0xa9, 0x1a, 0x1a, 0x1f,
|
||||||
0x7d, 0x27, 0x1f, 0x8e, 0x96, 0x74, 0x6c, 0xc3, 0xcf, 0x60, 0xba, 0xe4, 0x2c, 0x4b, 0xed, 0x6f,
|
0xbd, 0xef, 0xdc, 0x87, 0xa3, 0x25, 0x1d, 0xdb, 0xe8, 0x33, 0x98, 0x2c, 0x39, 0xcb, 0x52, 0xfb,
|
||||||
0xf7, 0xd4, 0xa1, 0xa2, 0xed, 0x6f, 0x09, 0xcb, 0xe9, 0x06, 0x7f, 0xf1, 0x08, 0xcd, 0x48, 0xc7,
|
0xdb, 0x3d, 0x15, 0x54, 0xbc, 0xfd, 0x2d, 0x61, 0x39, 0xdd, 0xe0, 0x2f, 0x1e, 0xa1, 0x19, 0xe9,
|
||||||
0x3a, 0xfc, 0x1e, 0x80, 0xe4, 0x1b, 0xf6, 0xa8, 0x10, 0x1b, 0x2a, 0x4d, 0x19, 0x3a, 0x92, 0xf0,
|
0x58, 0x47, 0xdf, 0x03, 0x90, 0x7c, 0xc3, 0x1e, 0x15, 0x62, 0x43, 0xa5, 0x29, 0x43, 0x47, 0x12,
|
||||||
0x73, 0xd8, 0x4b, 0x59, 0xc2, 0x37, 0x34, 0xbb, 0xc8, 0x68, 0xc2, 0xaa, 0xe8, 0x3d, 0x75, 0x34,
|
0x7d, 0x0e, 0x7b, 0x29, 0x5b, 0xf0, 0x0d, 0xcd, 0x2e, 0x32, 0xba, 0x60, 0x55, 0xfc, 0x9e, 0x0a,
|
||||||
0xb7, 0xba, 0x5c, 0x35, 0xe9, 0x5a, 0x7f, 0xf8, 0x18, 0x82, 0x36, 0x7c, 0xd8, 0xdf, 0x5f, 0xb3,
|
0xcd, 0xad, 0x2e, 0x57, 0x4d, 0xba, 0xd6, 0x1f, 0x3e, 0x86, 0xb0, 0x4d, 0x1f, 0xf6, 0xf7, 0xd7,
|
||||||
0x46, 0x15, 0x43, 0x40, 0x70, 0x19, 0xfe, 0x00, 0xfc, 0x6b, 0x9a, 0xd5, 0xba, 0x90, 0x27, 0x47,
|
0xac, 0x51, 0xc5, 0x10, 0x12, 0x5c, 0x46, 0x3f, 0x80, 0xe0, 0x9a, 0x66, 0xb5, 0x2e, 0xe4, 0xf1,
|
||||||
0xfb, 0x5b, 0xaf, 0xc7, 0xb7, 0xbc, 0x22, 0x5a, 0xf9, 0x69, 0xef, 0x57, 0x5e, 0xfc, 0x18, 0xf6,
|
0xd1, 0xfe, 0xd6, 0xeb, 0xf1, 0x2d, 0xaf, 0x88, 0x56, 0x7e, 0xda, 0xfb, 0x95, 0x97, 0x3c, 0x86,
|
||||||
0x3a, 0x1b, 0xe1, 0xc1, 0x79, 0xf5, 0x65, 0xbe, 0x2c, 0x44, 0xc2, 0x52, 0xe5, 0x73, 0x4c, 0x1c,
|
0xbd, 0xce, 0x46, 0x18, 0x38, 0xaf, 0xbe, 0xcc, 0x97, 0x85, 0x58, 0xb0, 0x54, 0xf9, 0x1c, 0x11,
|
||||||
0x49, 0xf8, 0x3e, 0x0c, 0x53, 0xbe, 0xe2, 0xb2, 0x32, 0xe5, 0x66, 0x50, 0xfc, 0x0f, 0x0f, 0xa6,
|
0x47, 0x12, 0xbd, 0x0f, 0x83, 0x94, 0xaf, 0xb8, 0xac, 0x4c, 0xb9, 0x19, 0x94, 0xfc, 0xc3, 0x83,
|
||||||
0x6e, 0x34, 0xc3, 0x9f, 0xc2, 0xc1, 0x35, 0x13, 0x92, 0x27, 0x34, 0xbb, 0xe4, 0x1b, 0x86, 0x1b,
|
0x89, 0x9b, 0xcd, 0xe8, 0xa7, 0x70, 0x70, 0xcd, 0x84, 0xe4, 0x0b, 0x9a, 0x5d, 0xf2, 0x0d, 0xc3,
|
||||||
0xab, 0x9f, 0x8c, 0xc9, 0x3d, 0x79, 0xf8, 0x31, 0x0c, 0xab, 0x42, 0xc8, 0x93, 0x46, 0x55, 0xed,
|
0x8d, 0xd5, 0x4f, 0x46, 0xe4, 0x9e, 0x3c, 0xfa, 0x18, 0x06, 0x55, 0x21, 0xe4, 0x49, 0xa3, 0xaa,
|
||||||
0xdb, 0xa2, 0x6c, 0xec, 0x90, 0xa7, 0x6e, 0x04, 0x2d, 0x4b, 0x9e, 0xaf, 0x2c, 0x17, 0x5a, 0x1c,
|
0xf6, 0x6d, 0x59, 0x36, 0x76, 0xc8, 0x53, 0x37, 0x82, 0x96, 0x25, 0xcf, 0x57, 0x96, 0x0b, 0x2d,
|
||||||
0xfe, 0x08, 0xf6, 0x97, 0xfc, 0xf6, 0x11, 0x17, 0x95, 0x3c, 0x2d, 0xb2, 0x7a, 0x93, 0xab, 0x0a,
|
0x8e, 0x7e, 0x04, 0xfb, 0x4b, 0x7e, 0xfb, 0x88, 0x8b, 0x4a, 0x9e, 0x16, 0x59, 0xbd, 0xc9, 0x55,
|
||||||
0x1e, 0x93, 0x3b, 0xd2, 0x27, 0x83, 0xb1, 0x77, 0xd0, 0x7b, 0x32, 0x18, 0xfb, 0x07, 0xc3, 0xb8,
|
0x05, 0x8f, 0xc8, 0x1d, 0xe9, 0x13, 0x7f, 0xe4, 0x1d, 0xf4, 0x9e, 0xf8, 0xa3, 0xe0, 0x60, 0x90,
|
||||||
0x84, 0xfd, 0xee, 0x4e, 0xd8, 0x96, 0xf6, 0x10, 0x8a, 0x13, 0x74, 0x78, 0x3b, 0xb2, 0x70, 0x06,
|
0x94, 0xb0, 0xdf, 0xdd, 0x09, 0xdb, 0xd2, 0x06, 0xa1, 0x38, 0x41, 0xa7, 0xb7, 0x23, 0x8b, 0xa6,
|
||||||
0x93, 0x94, 0x57, 0x65, 0x46, 0x1b, 0x87, 0x36, 0x5c, 0x11, 0x72, 0xe0, 0x35, 0xaf, 0xf8, 0x22,
|
0x30, 0x4e, 0x79, 0x55, 0x66, 0xb4, 0x71, 0x68, 0xc3, 0x15, 0x21, 0x07, 0x5e, 0xf3, 0x8a, 0xcf,
|
||||||
0xd3, 0x54, 0x3e, 0x26, 0x16, 0xc6, 0x2b, 0xf0, 0x55, 0x59, 0x3b, 0x24, 0x14, 0x58, 0x12, 0x52,
|
0x33, 0x4d, 0xe5, 0x23, 0x62, 0x61, 0xb2, 0x82, 0x40, 0x95, 0xb5, 0x43, 0x42, 0xa1, 0x25, 0x21,
|
||||||
0xd4, 0xdf, 0x73, 0xa8, 0xff, 0x00, 0xfa, 0xbf, 0x66, 0xb7, 0xe6, 0x35, 0xc0, 0x65, 0x4b, 0x55,
|
0x45, 0xfd, 0x3d, 0x87, 0xfa, 0x0f, 0xa0, 0xff, 0x6b, 0x76, 0x6b, 0x5e, 0x03, 0x5c, 0xb6, 0x54,
|
||||||
0x03, 0x87, 0xaa, 0x1e, 0x80, 0xff, 0x5a, 0xa5, 0x5d, 0x53, 0x88, 0x06, 0xf1, 0x17, 0x30, 0xd4,
|
0xe5, 0x3b, 0x54, 0xf5, 0x00, 0x82, 0x2b, 0x75, 0xed, 0x9a, 0x42, 0x34, 0x48, 0xbe, 0x80, 0x81,
|
||||||
0x6d, 0xd1, 0x7a, 0xf6, 0x1c, 0xcf, 0x33, 0x98, 0xbc, 0x14, 0x9c, 0xe5, 0x52, 0x93, 0x8f, 0xb9,
|
0x6e, 0x8b, 0xd6, 0xb3, 0xe7, 0x78, 0x9e, 0xc2, 0xf8, 0xa5, 0xe0, 0x2c, 0x97, 0x9a, 0x7c, 0xcc,
|
||||||
0x82, 0x23, 0x8a, 0xff, 0xe6, 0xc1, 0x40, 0x65, 0x29, 0x86, 0x69, 0xc6, 0x56, 0x34, 0x69, 0x4e,
|
0x11, 0x1c, 0x51, 0xf2, 0x37, 0x0f, 0x7c, 0x75, 0x4b, 0x09, 0x4c, 0x32, 0xb6, 0xa2, 0x8b, 0xe6,
|
||||||
0x8a, 0x3a, 0x4f, 0xab, 0xc8, 0x9b, 0xf5, 0x0f, 0xfb, 0xa4, 0x23, 0xc3, 0xf2, 0x58, 0x68, 0x6d,
|
0xa4, 0xa8, 0xf3, 0xb4, 0x8a, 0xbd, 0x69, 0xff, 0xb0, 0x4f, 0x3a, 0x32, 0x2c, 0x8f, 0xb9, 0xd6,
|
||||||
0x6f, 0xd6, 0x3f, 0x0c, 0x88, 0x41, 0x78, 0xb4, 0x8c, 0x2e, 0x58, 0x66, 0xae, 0xa0, 0x01, 0x5a,
|
0xf6, 0xa6, 0xfd, 0xc3, 0x90, 0x18, 0x84, 0xa1, 0x65, 0x74, 0xce, 0x32, 0x73, 0x04, 0x0d, 0xd0,
|
||||||
0x97, 0x82, 0x2d, 0xf9, 0xad, 0xb9, 0x86, 0x41, 0x28, 0xaf, 0xea, 0x25, 0xca, 0xf5, 0x4d, 0x0c,
|
0xba, 0x14, 0x6c, 0xc9, 0x6f, 0xcd, 0x31, 0x0c, 0x42, 0x79, 0x55, 0x2f, 0x51, 0xae, 0x4f, 0x62,
|
||||||
0xc2, 0x0b, 0x2c, 0x68, 0xd5, 0x32, 0x12, 0xae, 0xd1, 0x73, 0x95, 0xd0, 0xcc, 0x52, 0x92, 0x06,
|
0x10, 0x1e, 0x60, 0x4e, 0xab, 0x96, 0x91, 0x70, 0x8d, 0x9e, 0xab, 0x05, 0xcd, 0x2c, 0x25, 0x69,
|
||||||
0xf1, 0x3f, 0x3d, 0x7c, 0xc8, 0x34, 0xc5, 0xde, 0x8b, 0xf0, 0xb7, 0x61, 0x8c, 0xf4, 0xfb, 0xd5,
|
0x90, 0xfc, 0xd3, 0xc3, 0x87, 0x4c, 0x53, 0xec, 0xbd, 0x0c, 0x7f, 0x1b, 0x46, 0x48, 0xbf, 0x5f,
|
||||||
0x35, 0x15, 0xe6, 0xc2, 0x23, 0xc4, 0xaf, 0xa9, 0x08, 0x7f, 0x01, 0x43, 0xd5, 0x1c, 0x3b, 0xe8,
|
0x5d, 0x53, 0x61, 0x0e, 0x3c, 0x44, 0x7c, 0x45, 0x45, 0xf4, 0x0b, 0x18, 0xa8, 0xe6, 0xd8, 0x41,
|
||||||
0xde, 0xba, 0x53, 0x51, 0x25, 0xc6, 0xac, 0x25, 0xc4, 0x81, 0x43, 0x88, 0xed, 0x65, 0x7d, 0xf7,
|
0xf7, 0xd6, 0x9d, 0xca, 0x2a, 0x31, 0x66, 0x2d, 0x21, 0xfa, 0x0e, 0x21, 0xb6, 0x87, 0x0d, 0xdc,
|
||||||
0xb2, 0x1f, 0x81, 0x8f, 0xcc, 0xda, 0xa8, 0xd3, 0xef, 0xf4, 0xac, 0xf9, 0x57, 0x5b, 0xc5, 0x57,
|
0xc3, 0x7e, 0x04, 0x01, 0x32, 0x6b, 0xa3, 0xa2, 0xdf, 0xe9, 0x59, 0xf3, 0xaf, 0xb6, 0x4a, 0x56,
|
||||||
0xb0, 0xd7, 0xd9, 0xb1, 0xdd, 0xc9, 0xeb, 0xee, 0xb4, 0x6d, 0xf4, 0xc0, 0x34, 0x36, 0x36, 0x47,
|
0xb0, 0xd7, 0xd9, 0xb1, 0xdd, 0xc9, 0xeb, 0xee, 0xb4, 0x6d, 0xf4, 0xd0, 0x34, 0x36, 0x36, 0x47,
|
||||||
0xc5, 0x32, 0x96, 0x48, 0x96, 0x9a, 0xaa, 0x6b, 0x71, 0xfc, 0x27, 0x6f, 0xeb, 0x57, 0xed, 0x87,
|
0xc5, 0x32, 0xb6, 0x90, 0x2c, 0x35, 0x55, 0xd7, 0x62, 0x4b, 0x16, 0x7e, 0x4b, 0x16, 0xc9, 0x9f,
|
||||||
0x25, 0x9a, 0x14, 0x9b, 0x0d, 0xcd, 0x53, 0xe3, 0xda, 0x42, 0x8c, 0x5b, 0xba, 0x30, 0xae, 0x7b,
|
0xbc, 0xed, 0x4e, 0x2a, 0x02, 0x2c, 0xda, 0x45, 0xb1, 0xd9, 0xd0, 0x3c, 0x35, 0x9b, 0x59, 0x88,
|
||||||
0xe9, 0x02, 0xb1, 0x28, 0x4d, 0x06, 0x7b, 0xa2, 0xc4, 0xda, 0xd9, 0x30, 0x5a, 0xd5, 0x82, 0x6d,
|
0x99, 0x4c, 0xe7, 0x66, 0xb3, 0x5e, 0x3a, 0x47, 0x2c, 0x4a, 0x73, 0xa7, 0x3d, 0x51, 0x62, 0x35,
|
||||||
0x58, 0x2e, 0x4d, 0x08, 0x5c, 0x51, 0xf8, 0x01, 0x8c, 0x24, 0x5d, 0x7d, 0x85, 0xf4, 0x64, 0x32,
|
0x6d, 0x18, 0xad, 0x6a, 0xc1, 0x36, 0x2c, 0x97, 0x66, 0x17, 0x57, 0x14, 0x7d, 0x00, 0x43, 0x49,
|
||||||
0x29, 0xe9, 0xea, 0x29, 0x6b, 0xc2, 0xef, 0x40, 0xa0, 0xf8, 0x52, 0xa9, 0x74, 0x3a, 0xc7, 0x4a,
|
0x57, 0x5f, 0x61, 0x0c, 0xe6, 0x6e, 0x25, 0x5d, 0x3d, 0x65, 0x4d, 0xf4, 0x1d, 0x08, 0x15, 0x83,
|
||||||
0xf0, 0x94, 0x35, 0xf1, 0x5f, 0x7b, 0x30, 0x9c, 0x33, 0x71, 0xcd, 0xc4, 0x3b, 0xbd, 0xd0, 0xee,
|
0x2a, 0x95, 0xbe, 0xe0, 0x91, 0x12, 0x3c, 0x65, 0x4d, 0xf2, 0xd7, 0x1e, 0x0c, 0x66, 0x4c, 0x5c,
|
||||||
0x5c, 0xd4, 0x7f, 0xcb, 0x5c, 0x34, 0xd8, 0x3d, 0x17, 0xf9, 0xdb, 0xb9, 0xe8, 0x01, 0xf8, 0x73,
|
0x33, 0xf1, 0x4e, 0x6f, 0xb6, 0x3b, 0x29, 0xf5, 0xdf, 0x32, 0x29, 0xf9, 0xbb, 0x27, 0xa5, 0x60,
|
||||||
0x91, 0x9c, 0x9f, 0xa9, 0x13, 0xf5, 0x89, 0x06, 0x58, 0x8d, 0xc7, 0x89, 0xe4, 0xd7, 0xcc, 0x0c,
|
0x3b, 0x29, 0x3d, 0x80, 0x60, 0x26, 0x16, 0xe7, 0x67, 0x2a, 0xa2, 0x3e, 0xd1, 0x00, 0xeb, 0xf3,
|
||||||
0x4b, 0x06, 0xdd, 0x7b, 0xb8, 0xc7, 0x3b, 0x26, 0x94, 0xff, 0x75, 0x66, 0xb2, 0x2d, 0x0a, 0x4e,
|
0x78, 0x21, 0xf9, 0x35, 0x33, 0xe3, 0x93, 0x41, 0xf7, 0x9e, 0xf2, 0xd1, 0x8e, 0x99, 0xe5, 0x7f,
|
||||||
0x8b, 0xc6, 0x30, 0xc5, 0xc1, 0x29, 0xa5, 0x92, 0x3e, 0x99, 0xbf, 0x7c, 0x61, 0xa7, 0x25, 0x57,
|
0x9d, 0xa2, 0x6c, 0xd3, 0x82, 0xd3, 0xb4, 0x09, 0x4c, 0x70, 0x94, 0x4a, 0xa9, 0xa4, 0x4f, 0x66,
|
||||||
0x16, 0xff, 0xd1, 0x83, 0xe1, 0x33, 0xda, 0x14, 0xb5, 0xbc, 0x57, 0xed, 0x33, 0x98, 0x1c, 0x97,
|
0x2f, 0x5f, 0xd8, 0xf9, 0xc9, 0x95, 0x25, 0x7f, 0xf4, 0x60, 0xf0, 0x8c, 0x36, 0x45, 0x2d, 0xef,
|
||||||
0x65, 0xc6, 0x93, 0x4e, 0x87, 0x3b, 0x22, 0xb4, 0x78, 0xee, 0xe4, 0x51, 0xc7, 0xd0, 0x15, 0xe1,
|
0xd5, 0xff, 0x14, 0xc6, 0xc7, 0x65, 0x99, 0xf1, 0x45, 0xa7, 0xe7, 0x1d, 0x11, 0x5a, 0x3c, 0x77,
|
||||||
0x83, 0x72, 0xaa, 0x86, 0x20, 0x3d, 0xd1, 0x38, 0x0f, 0x8a, 0x9e, 0x7d, 0x94, 0x12, 0x83, 0x7d,
|
0xee, 0x51, 0xe7, 0xd0, 0x15, 0xe1, 0x13, 0x73, 0xaa, 0xc6, 0x22, 0x3d, 0xe3, 0x38, 0x4f, 0x8c,
|
||||||
0x5c, 0xcb, 0x62, 0x99, 0x15, 0x37, 0x2a, 0xaa, 0x63, 0xd2, 0xe2, 0xf8, 0x5f, 0x3d, 0x18, 0x7c,
|
0x9e, 0x86, 0x94, 0x12, 0x93, 0x7d, 0x5c, 0xcb, 0x62, 0x99, 0x15, 0x37, 0x2a, 0xab, 0x23, 0xd2,
|
||||||
0x53, 0x83, 0xcb, 0x14, 0x3c, 0x6e, 0x8a, 0xca, 0xe3, 0xed, 0x18, 0x33, 0x72, 0xc6, 0x98, 0x08,
|
0xe2, 0xe4, 0x5f, 0x3d, 0xf0, 0xbf, 0xa9, 0x51, 0x66, 0x02, 0x1e, 0x37, 0x45, 0xe5, 0xf1, 0x76,
|
||||||
0x46, 0x8d, 0xa0, 0xf9, 0x8a, 0x55, 0xd1, 0x58, 0xb1, 0x98, 0x85, 0x4a, 0xa3, 0xfa, 0x55, 0xcf,
|
0xb0, 0x19, 0x3a, 0x83, 0x4d, 0x0c, 0xc3, 0x46, 0xd0, 0x7c, 0xc5, 0xaa, 0x78, 0xa4, 0x78, 0xcd,
|
||||||
0x2f, 0x01, 0xb1, 0xb0, 0xed, 0x3f, 0x70, 0xfa, 0xef, 0xe7, 0x66, 0xd4, 0x99, 0xdc, 0x1d, 0x0e,
|
0x42, 0xa5, 0x51, 0x1d, 0xac, 0x27, 0x9a, 0x90, 0x58, 0xd8, 0x76, 0x24, 0x38, 0x1d, 0xf9, 0x73,
|
||||||
0x76, 0x4d, 0x38, 0xff, 0xbf, 0x57, 0xfb, 0x3f, 0x1e, 0xf8, 0x6d, 0xf3, 0x9e, 0x76, 0x9b, 0xf7,
|
0x33, 0xfc, 0x8c, 0xef, 0x8e, 0x0b, 0xbb, 0x66, 0x9e, 0xff, 0xdf, 0x3b, 0xfe, 0x1f, 0x0f, 0x82,
|
||||||
0x74, 0xdb, 0xbc, 0x67, 0x27, 0xb6, 0x79, 0xcf, 0x4e, 0x10, 0x93, 0x0b, 0xdb, 0xbc, 0xe4, 0x02,
|
0xb6, 0x79, 0x4f, 0xbb, 0xcd, 0x7b, 0xba, 0x6d, 0xde, 0xb3, 0x13, 0xdb, 0xbc, 0x67, 0x27, 0x88,
|
||||||
0x93, 0xf5, 0x58, 0x14, 0x75, 0x79, 0xd2, 0xe8, 0xac, 0x06, 0xa4, 0xc5, 0x58, 0xf1, 0xbf, 0x59,
|
0xc9, 0x85, 0x6d, 0x5e, 0x72, 0x81, 0x97, 0xf5, 0x58, 0x14, 0x75, 0x79, 0xd2, 0xe8, 0x5b, 0x0d,
|
||||||
0x33, 0x61, 0x42, 0x1d, 0x10, 0x83, 0xb0, 0x3f, 0x9e, 0x29, 0x62, 0xd3, 0xc1, 0xd5, 0x20, 0xfc,
|
0x49, 0x8b, 0xb1, 0xe2, 0x7f, 0xb3, 0x66, 0xc2, 0xa4, 0x3a, 0x24, 0x06, 0x61, 0x7f, 0x3c, 0x53,
|
||||||
0x21, 0xf8, 0x04, 0x83, 0xa7, 0x22, 0xdc, 0xc9, 0x8b, 0x12, 0x13, 0xad, 0x45, 0xa7, 0xfa, 0x03,
|
0x54, 0xa7, 0x93, 0xab, 0x41, 0xf4, 0x43, 0x08, 0x08, 0x26, 0x4f, 0x65, 0xb8, 0x73, 0x2f, 0x4a,
|
||||||
0xc8, 0x34, 0x8a, 0xfd, 0x1c, 0xfa, 0x19, 0x0c, 0xe7, 0x6b, 0xbe, 0x94, 0x76, 0x60, 0xfc, 0x96,
|
0x4c, 0xb4, 0x16, 0x9d, 0xea, 0x4f, 0x22, 0xd3, 0x28, 0xf6, 0x03, 0xe9, 0x67, 0x30, 0x98, 0xad,
|
||||||
0x43, 0x8c, 0x7c, 0xc3, 0x94, 0x8e, 0x18, 0x93, 0xf8, 0x15, 0x04, 0xad, 0x70, 0x7b, 0x1c, 0xcf,
|
0xf9, 0x52, 0xda, 0x11, 0xf2, 0x5b, 0x0e, 0x55, 0xf2, 0x0d, 0x53, 0x3a, 0x62, 0x4c, 0x92, 0x57,
|
||||||
0x3d, 0x4e, 0x08, 0x83, 0xab, 0x9c, 0x4b, 0x4b, 0x11, 0xb8, 0xc6, 0xcb, 0xbe, 0xaa, 0x69, 0x2e,
|
0x10, 0xb6, 0xc2, 0x6d, 0x38, 0x9e, 0x1b, 0x4e, 0x04, 0xfe, 0xeb, 0x9c, 0x4b, 0x4b, 0x11, 0xb8,
|
||||||
0xb9, 0x6c, 0x2c, 0x45, 0x58, 0x1c, 0x7f, 0x62, 0x8e, 0x8f, 0xee, 0xae, 0xca, 0x92, 0x09, 0x43,
|
0xc6, 0xc3, 0xbe, 0xaa, 0x69, 0x2e, 0xb9, 0x6c, 0x2c, 0x45, 0x58, 0x9c, 0x7c, 0x62, 0xc2, 0x47,
|
||||||
0x37, 0x1a, 0xa8, 0x4d, 0x8a, 0x1b, 0xa6, 0x5f, 0x8a, 0x3e, 0xd1, 0x20, 0xfe, 0x2d, 0x04, 0xc7,
|
0x77, 0xaf, 0xcb, 0x92, 0x09, 0x43, 0x37, 0x1a, 0xa8, 0x4d, 0x8a, 0x1b, 0xa6, 0xdf, 0x8e, 0x3e,
|
||||||
0x19, 0x13, 0x92, 0xd4, 0x19, 0xdb, 0xf5, 0x82, 0xab, 0x46, 0x35, 0x27, 0xc0, 0xf5, 0x96, 0x5a,
|
0xd1, 0x20, 0xf9, 0x2d, 0x84, 0xc7, 0x19, 0x13, 0x92, 0xd4, 0x19, 0xdb, 0xf5, 0xa6, 0xab, 0x46,
|
||||||
0xfa, 0x77, 0xa8, 0xe5, 0x29, 0x2d, 0xe9, 0xf9, 0x99, 0xaa, 0xf3, 0x3e, 0x31, 0x28, 0xfe, 0xb3,
|
0x35, 0x11, 0xe0, 0x7a, 0x4b, 0x2d, 0xfd, 0x3b, 0xd4, 0xf2, 0x94, 0x96, 0xf4, 0xfc, 0x4c, 0xd5,
|
||||||
0x07, 0x03, 0xe4, 0x30, 0xc7, 0xf5, 0xe0, 0x6d, 0xfc, 0x77, 0x21, 0x8a, 0x6b, 0x9e, 0x32, 0x61,
|
0x79, 0x9f, 0x18, 0x94, 0xfc, 0xd9, 0x03, 0x1f, 0x39, 0xcc, 0x71, 0xed, 0xbf, 0x8d, 0xff, 0x2e,
|
||||||
0x2f, 0x67, 0xb1, 0x0a, 0x7a, 0xb2, 0x66, 0xed, 0xa0, 0x60, 0x10, 0xd6, 0x1a, 0x7e, 0x2d, 0xd9,
|
0x44, 0x71, 0xcd, 0x53, 0x26, 0xec, 0xe1, 0x2c, 0x56, 0x49, 0x5f, 0xac, 0x59, 0x3b, 0x3a, 0x18,
|
||||||
0x5e, 0x72, 0x6a, 0x0d, 0xc5, 0x44, 0x2b, 0x71, 0x18, 0x9c, 0xd7, 0x25, 0x13, 0xc7, 0xe9, 0x86,
|
0x84, 0xb5, 0x86, 0xdf, 0x4f, 0xb6, 0x97, 0x9c, 0x5a, 0x43, 0x31, 0xd1, 0x4a, 0x1c, 0x0f, 0x67,
|
||||||
0xdb, 0x29, 0xca, 0x91, 0xc4, 0x5f, 0xe8, 0xef, 0xaf, 0x7b, 0x4c, 0xe8, 0xed, 0xfe, 0x56, 0xbb,
|
0x75, 0xc9, 0xc4, 0x71, 0xba, 0xe1, 0x76, 0xae, 0x72, 0x24, 0xc9, 0x17, 0xfa, 0x8b, 0xec, 0x1e,
|
||||||
0x7b, 0xf2, 0xf8, 0x2f, 0x1e, 0x8c, 0x9e, 0x9b, 0xa9, 0xcd, 0xbd, 0x85, 0xf7, 0xc6, 0x5b, 0xf4,
|
0x13, 0x7a, 0xbb, 0xbf, 0xde, 0xee, 0x46, 0x9e, 0xfc, 0xc5, 0x83, 0xe1, 0x73, 0x33, 0xc7, 0xb9,
|
||||||
0x3a, 0xb7, 0x38, 0x82, 0x07, 0xd6, 0xa6, 0xb3, 0xbf, 0x8e, 0xc2, 0x4e, 0x9d, 0x89, 0xe8, 0xa0,
|
0xa7, 0xf0, 0xde, 0x78, 0x8a, 0x5e, 0xe7, 0x14, 0x47, 0xf0, 0xc0, 0xda, 0x74, 0xf6, 0xd7, 0x59,
|
||||||
0x4d, 0xd6, 0xbb, 0x7c, 0x7e, 0x5d, 0x76, 0x6d, 0x76, 0x25, 0xfc, 0x5e, 0x56, 0x66, 0x30, 0xb1,
|
0xd8, 0xa9, 0x33, 0x19, 0xf5, 0xdb, 0xcb, 0x7a, 0x97, 0x0f, 0xb2, 0xcb, 0xae, 0xcd, 0xae, 0x0b,
|
||||||
0x9f, 0x9d, 0x45, 0x66, 0x1f, 0x26, 0x57, 0x14, 0x1f, 0xc1, 0xf0, 0xb4, 0xc8, 0x97, 0x7c, 0x15,
|
0xbf, 0x77, 0x2b, 0x53, 0x18, 0xdb, 0x0f, 0xd1, 0x22, 0xb3, 0x0f, 0x93, 0x2b, 0x4a, 0x8e, 0x60,
|
||||||
0x1e, 0xc2, 0xe0, 0xb8, 0x96, 0x6b, 0xe5, 0x71, 0x72, 0xf4, 0xc0, 0x69, 0xfc, 0x5a, 0xae, 0xb5,
|
0x70, 0x5a, 0xe4, 0x4b, 0xbe, 0x8a, 0x0e, 0xc1, 0x3f, 0xae, 0xe5, 0x5a, 0x79, 0x1c, 0x1f, 0x3d,
|
||||||
0x0d, 0x51, 0x16, 0xf1, 0x67, 0x00, 0x5b, 0x19, 0xbe, 0x2e, 0xdb, 0x6c, 0xbc, 0x60, 0x37, 0x58,
|
0x70, 0x1a, 0xbf, 0x96, 0x6b, 0x6d, 0x43, 0x94, 0x45, 0xf2, 0x19, 0xc0, 0x56, 0x86, 0xaf, 0xcb,
|
||||||
0x32, 0x95, 0x19, 0xda, 0x77, 0x68, 0xe2, 0xcf, 0x21, 0x38, 0xa9, 0x79, 0x96, 0x9e, 0xe7, 0xcb,
|
0xf6, 0x36, 0x5e, 0xb0, 0x1b, 0x2c, 0x99, 0xca, 0x8c, 0xf1, 0x3b, 0x34, 0xc9, 0xe7, 0x10, 0x9e,
|
||||||
0x02, 0xa9, 0xe3, 0x35, 0x13, 0xd5, 0x36, 0x5f, 0x16, 0x62, 0xb8, 0x91, 0x45, 0xda, 0x1e, 0x32,
|
0xd4, 0x3c, 0x4b, 0xcf, 0xf3, 0x65, 0x81, 0xd4, 0x71, 0xc5, 0x44, 0xb5, 0xbd, 0x2f, 0x0b, 0x31,
|
||||||
0x68, 0x31, 0x54, 0x7f, 0x6a, 0x7c, 0xf2, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xd3, 0xfb, 0xbd,
|
0xdd, 0xc8, 0x22, 0x6d, 0x0f, 0x19, 0x34, 0x1f, 0xa8, 0xbf, 0x39, 0x3e, 0xf9, 0x6f, 0x00, 0x00,
|
||||||
0x7b, 0xe6, 0x10, 0x00, 0x00,
|
0x00, 0xff, 0xff, 0x5f, 0x2f, 0x55, 0x31, 0xf8, 0x10, 0x00, 0x00,
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,6 +100,7 @@ message TemplateValue {
|
||||||
string type = 1; // Type can be tagKey, tagValue, fieldKey, csv, measurement, database, constant
|
string type = 1; // Type can be tagKey, tagValue, fieldKey, csv, measurement, database, constant
|
||||||
string value = 2; // Value is the specific value used to replace a template in an InfluxQL query
|
string value = 2; // Value is the specific value used to replace a template in an InfluxQL query
|
||||||
bool selected = 3; // Selected states that this variable has been picked to use for replacement
|
bool selected = 3; // Selected states that this variable has been picked to use for replacement
|
||||||
|
string key = 4; // Key is the key for a specific Value if the Template Type is map (optional)
|
||||||
}
|
}
|
||||||
|
|
||||||
message TemplateQuery {
|
message TemplateQuery {
|
||||||
|
|
|
@ -158,9 +158,10 @@ type Range struct {
|
||||||
|
|
||||||
// TemplateValue is a value use to replace a template in an InfluxQL query
|
// TemplateValue is a value use to replace a template in an InfluxQL query
|
||||||
type TemplateValue struct {
|
type TemplateValue struct {
|
||||||
Value string `json:"value"` // Value is the specific value used to replace a template in an InfluxQL query
|
Value string `json:"value"` // Value is the specific value used to replace a template in an InfluxQL query
|
||||||
Type string `json:"type"` // Type can be tagKey, tagValue, fieldKey, csv, measurement, database, constant
|
Type string `json:"type"` // Type can be tagKey, tagValue, fieldKey, csv, measurement, database, constant, influxql
|
||||||
Selected bool `json:"selected"` // Selected states that this variable has been picked to use for replacement
|
Selected bool `json:"selected"` // Selected states that this variable has been picked to use for replacement
|
||||||
|
Key string `json:"key,omitempty"` // Key is the key for the Value if the Template Type is 'map'
|
||||||
}
|
}
|
||||||
|
|
||||||
// TemplateVar is a named variable within an InfluxQL query to be replaced with Values
|
// TemplateVar is a named variable within an InfluxQL query to be replaced with Values
|
||||||
|
@ -176,7 +177,7 @@ type TemplateID string
|
||||||
type Template struct {
|
type Template struct {
|
||||||
TemplateVar
|
TemplateVar
|
||||||
ID TemplateID `json:"id"` // ID is the unique ID associated with this template
|
ID TemplateID `json:"id"` // ID is the unique ID associated with this template
|
||||||
Type string `json:"type"` // Type can be fieldKeys, tagKeys, tagValues, CSV, constant, query, measurements, databases
|
Type string `json:"type"` // Type can be fieldKeys, tagKeys, tagValues, CSV, constant, measurements, databases, map, influxql
|
||||||
Label string `json:"label"` // Label is a user-facing description of the Template
|
Label string `json:"label"` // Label is a user-facing description of the Template
|
||||||
Query *TemplateQuery `json:"query,omitempty"` // Query is used to generate the choices for a template
|
Query *TemplateQuery `json:"query,omitempty"` // Query is used to generate the choices for a template
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,7 +72,7 @@ func RenderTemplate(query string, t chronograf.TemplateVar, now time.Time) (stri
|
||||||
return strings.Replace(q, t.Var, `"`+t.Values[0].Value+`"`, -1), nil
|
return strings.Replace(q, t.Var, `"`+t.Values[0].Value+`"`, -1), nil
|
||||||
case "tagValue", "timeStamp":
|
case "tagValue", "timeStamp":
|
||||||
return strings.Replace(q, t.Var, `'`+t.Values[0].Value+`'`, -1), nil
|
return strings.Replace(q, t.Var, `'`+t.Values[0].Value+`'`, -1), nil
|
||||||
case "csv", "constant":
|
case "csv", "constant", "influxql":
|
||||||
return strings.Replace(q, t.Var, t.Values[0].Value, -1), nil
|
return strings.Replace(q, t.Var, t.Values[0].Value, -1), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4090,6 +4090,10 @@
|
||||||
"enum": ["csv", "tagKey", "tagValue", "fieldKey", "timeStamp"],
|
"enum": ["csv", "tagKey", "tagValue", "fieldKey", "timeStamp"],
|
||||||
"description":
|
"description":
|
||||||
"The type will change the format of the output value. tagKey/fieldKey are double quoted; tagValue are single quoted; csv and timeStamp are not quoted."
|
"The type will change the format of the output value. tagKey/fieldKey are double quoted; tagValue are single quoted; csv and timeStamp are not quoted."
|
||||||
|
},
|
||||||
|
"key": {
|
||||||
|
"type": "string",
|
||||||
|
"description":"This will be the key for a specific value of a template variable. Used if the templateVar type is 'map'"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -15,19 +15,23 @@ func ValidTemplateRequest(template *chronograf.Template) error {
|
||||||
switch template.Type {
|
switch template.Type {
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("Unknown template type %s", template.Type)
|
return fmt.Errorf("Unknown template type %s", template.Type)
|
||||||
case "query", "constant", "csv", "fieldKeys", "tagKeys", "tagValues", "measurements", "databases":
|
case "constant", "csv", "fieldKeys", "tagKeys", "tagValues", "measurements", "databases", "map", "influxql":
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, v := range template.Values {
|
for _, v := range template.Values {
|
||||||
switch v.Type {
|
switch v.Type {
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("Unknown template variable type %s", v.Type)
|
return fmt.Errorf("Unknown template variable type %s", v.Type)
|
||||||
case "csv", "fieldKey", "tagKey", "tagValue", "measurement", "database", "constant":
|
case "csv", "fieldKey", "tagKey", "tagValue", "measurement", "database", "constant", "influxql":
|
||||||
|
}
|
||||||
|
|
||||||
|
if template.Type == "map" && v.Key == "" {
|
||||||
|
return fmt.Errorf("Templates of type 'map' require a 'key'")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if template.Type == "query" && template.Query == nil {
|
if template.Type == "influxql" && template.Query == nil {
|
||||||
return fmt.Errorf("No query set for template of type 'query'")
|
return fmt.Errorf("No query set for template of type 'influxql'")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -57,7 +57,37 @@ func TestValidTemplateRequest(t *testing.T) {
|
||||||
name: "No query set",
|
name: "No query set",
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
template: &chronograf.Template{
|
template: &chronograf.Template{
|
||||||
Type: "query",
|
Type: "influxql",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Valid Map type",
|
||||||
|
template: &chronograf.Template{
|
||||||
|
Type: "map",
|
||||||
|
TemplateVar: chronograf.TemplateVar{
|
||||||
|
Values: []chronograf.TemplateValue{
|
||||||
|
{
|
||||||
|
Key: "key",
|
||||||
|
Value: "value",
|
||||||
|
Type: "constant",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Map without Key",
|
||||||
|
wantErr: true,
|
||||||
|
template: &chronograf.Template{
|
||||||
|
Type: "map",
|
||||||
|
TemplateVar: chronograf.TemplateVar{
|
||||||
|
Values: []chronograf.TemplateValue{
|
||||||
|
{
|
||||||
|
Value: "value",
|
||||||
|
Type: "constant",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,7 +48,7 @@ interface State {
|
||||||
|
|
||||||
@ErrorHandling
|
@ErrorHandling
|
||||||
export class AllUsersPage extends PureComponent<Props, State> {
|
export class AllUsersPage extends PureComponent<Props, State> {
|
||||||
constructor(props) {
|
constructor(props: Props) {
|
||||||
super(props)
|
super(props)
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import {proxy} from 'src/utils/queryUrlGenerator'
|
import {proxy} from 'src/utils/queryUrlGenerator'
|
||||||
import {TimeRange} from '../../types'
|
import {TimeRange} from 'src/types'
|
||||||
|
|
||||||
export const getAlerts = (
|
export const getAlerts = (
|
||||||
source: string,
|
source: string,
|
||||||
|
|
|
@ -5,7 +5,9 @@ import {replace} from 'react-router-redux'
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
import queryString from 'query-string'
|
import queryString from 'query-string'
|
||||||
|
|
||||||
|
import {proxy} from 'src/utils/queryUrlGenerator'
|
||||||
import {isUserAuthorized, EDITOR_ROLE} from 'src/auth/Authorized'
|
import {isUserAuthorized, EDITOR_ROLE} from 'src/auth/Authorized'
|
||||||
|
import {parseMetaQuery} from 'src/tempVars/utils/parsing'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
getDashboards as getDashboardsAJAX,
|
getDashboards as getDashboardsAJAX,
|
||||||
|
@ -15,7 +17,6 @@ import {
|
||||||
updateDashboardCell as updateDashboardCellAJAX,
|
updateDashboardCell as updateDashboardCellAJAX,
|
||||||
addDashboardCell as addDashboardCellAJAX,
|
addDashboardCell as addDashboardCellAJAX,
|
||||||
deleteDashboardCell as deleteDashboardCellAJAX,
|
deleteDashboardCell as deleteDashboardCellAJAX,
|
||||||
getTempVarValuesBySourceQuery,
|
|
||||||
createDashboard as createDashboardAJAX,
|
createDashboard as createDashboardAJAX,
|
||||||
} from 'src/dashboards/apis'
|
} from 'src/dashboards/apis'
|
||||||
import {getMe} from 'src/shared/apis/auth'
|
import {getMe} from 'src/shared/apis/auth'
|
||||||
|
@ -48,7 +49,6 @@ import {
|
||||||
} from 'src/shared/copy/notifications'
|
} from 'src/shared/copy/notifications'
|
||||||
|
|
||||||
import {makeQueryForTemplate} from 'src/dashboards/utils/tempVars'
|
import {makeQueryForTemplate} from 'src/dashboards/utils/tempVars'
|
||||||
import parsers from 'src/shared/parsing'
|
|
||||||
import {getDeep} from 'src/utils/wrappers'
|
import {getDeep} from 'src/utils/wrappers'
|
||||||
|
|
||||||
import idNormalizer, {TYPE_ID} from 'src/normalizers/id'
|
import idNormalizer, {TYPE_ID} from 'src/normalizers/id'
|
||||||
|
@ -418,7 +418,7 @@ export const getDashboardsNamesAsync = (sourceID: string) => async (
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getDashboardAsync = (dashboardID: string) => async (
|
export const getDashboardAsync = (dashboardID: number) => async (
|
||||||
dispatch
|
dispatch
|
||||||
): Promise<Dashboard | null> => {
|
): Promise<Dashboard | null> => {
|
||||||
try {
|
try {
|
||||||
|
@ -628,25 +628,23 @@ export const hydrateTempVarValuesAsync = (
|
||||||
const dashboard = getState().dashboardUI.dashboards.find(
|
const dashboard = getState().dashboardUI.dashboards.find(
|
||||||
d => d.id === dashboardID
|
d => d.id === dashboardID
|
||||||
)
|
)
|
||||||
|
const templates: Template[] = dashboard.templates
|
||||||
|
const queries = templates
|
||||||
|
.filter(
|
||||||
|
template => getDeep<string>(template, 'query.influxql', '') !== ''
|
||||||
|
)
|
||||||
|
.map(async template => {
|
||||||
|
const query = makeQueryForTemplate(template.query)
|
||||||
|
const response = await proxy({source: source.links.proxy, query})
|
||||||
|
const values = parseMetaQuery(query, response.data)
|
||||||
|
|
||||||
const tempsWithQueries = dashboard.templates.filter(
|
return {template, values}
|
||||||
({query}) => !!query.influxql
|
|
||||||
)
|
|
||||||
|
|
||||||
const asyncQueries = tempsWithQueries.map(({query}) =>
|
|
||||||
getTempVarValuesBySourceQuery(source, {
|
|
||||||
query: makeQueryForTemplate(query),
|
|
||||||
})
|
})
|
||||||
)
|
const results = await Promise.all(queries)
|
||||||
|
|
||||||
const results = await Promise.all(asyncQueries)
|
for (const {template, values} of results) {
|
||||||
|
dispatch(editTemplateVariableValues(+dashboard.id, template.id, values))
|
||||||
results.forEach(({data}, i) => {
|
}
|
||||||
const {type, query, id} = tempsWithQueries[i]
|
|
||||||
const parsed = parsers[type](data, query.tagKey || query.measurement)
|
|
||||||
const vals = parsed[type]
|
|
||||||
dispatch(editTemplateVariableValues(+dashboard.id, id, vals))
|
|
||||||
})
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error)
|
console.error(error)
|
||||||
dispatch(errorThrown(error))
|
dispatch(errorThrown(error))
|
||||||
|
@ -814,7 +812,7 @@ const syncDashboardFromURLQueryParams = (
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getDashboardWithHydratedAndSyncedTempVarsAsync = (
|
export const getDashboardWithHydratedAndSyncedTempVarsAsync = (
|
||||||
dashboardID: string,
|
dashboardID: number,
|
||||||
source: Source,
|
source: Source,
|
||||||
router: InjectedRouter,
|
router: InjectedRouter,
|
||||||
location: Location
|
location: Location
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import AJAX from 'utils/ajax'
|
import AJAX from 'utils/ajax'
|
||||||
import {proxy} from 'utils/queryUrlGenerator'
|
|
||||||
|
|
||||||
export function getDashboards() {
|
export function getDashboards() {
|
||||||
return AJAX({
|
return AJAX({
|
||||||
|
@ -98,19 +97,3 @@ export const editTemplateVariables = async templateVariable => {
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getTempVarValuesBySourceQuery = async (source, templateQuery) => {
|
|
||||||
const {
|
|
||||||
query,
|
|
||||||
db,
|
|
||||||
// rp, TODO
|
|
||||||
tempVars,
|
|
||||||
} = templateQuery
|
|
||||||
try {
|
|
||||||
// TODO: add rp as argument to proxy
|
|
||||||
return await proxy({source: source.links.proxy, query, db, tempVars})
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error)
|
|
||||||
throw error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -495,7 +495,7 @@ DashboardPage.propTypes = {
|
||||||
sources: arrayOf(shape({})).isRequired,
|
sources: arrayOf(shape({})).isRequired,
|
||||||
params: shape({
|
params: shape({
|
||||||
sourceID: string.isRequired,
|
sourceID: string.isRequired,
|
||||||
dashboardID: string.isRequired,
|
dashboardID: number.isRequired,
|
||||||
}).isRequired,
|
}).isRequired,
|
||||||
location: shape({
|
location: shape({
|
||||||
pathname: string.isRequired,
|
pathname: string.isRequired,
|
||||||
|
|
|
@ -134,7 +134,7 @@ class AlertTabs extends PureComponent<Props, State> {
|
||||||
this.setState({services})
|
this.setState({services})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.setState({services: null})
|
this.setState({services: null})
|
||||||
this.props.notify(notifyCouldNotRetrieveKapacitorServices(kapacitor))
|
this.props.notify(notifyCouldNotRetrieveKapacitorServices(kapacitor.name))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
import React from 'react'
|
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
|
|
||||||
const CodeData = ({onClickTemplate, template}) => (
|
|
||||||
<code
|
|
||||||
className="rule-builder--message-template"
|
|
||||||
data-tip={template.text}
|
|
||||||
onClick={onClickTemplate}
|
|
||||||
>
|
|
||||||
{template.label}
|
|
||||||
</code>
|
|
||||||
)
|
|
||||||
|
|
||||||
const {func, shape, string} = PropTypes
|
|
||||||
|
|
||||||
CodeData.propTypes = {
|
|
||||||
onClickTemplate: func,
|
|
||||||
template: shape({
|
|
||||||
label: string,
|
|
||||||
text: string,
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
|
|
||||||
export default CodeData
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
import React, {SFC} from 'react'
|
||||||
|
|
||||||
|
import {RuleMessage} from 'src/types/kapacitor'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
onClickTemplate: () => void
|
||||||
|
template: RuleMessage
|
||||||
|
}
|
||||||
|
|
||||||
|
const CodeData: SFC<Props> = ({onClickTemplate, template}) => (
|
||||||
|
<code
|
||||||
|
className="rule-builder--message-template"
|
||||||
|
data-tip={template.text}
|
||||||
|
onClick={onClickTemplate}
|
||||||
|
>
|
||||||
|
{template.label}
|
||||||
|
</code>
|
||||||
|
)
|
||||||
|
|
||||||
|
export default CodeData
|
|
@ -24,7 +24,7 @@ interface Props {
|
||||||
query: QueryConfig
|
query: QueryConfig
|
||||||
isDeadman: boolean
|
isDeadman: boolean
|
||||||
isKapacitorRule: boolean
|
isKapacitorRule: boolean
|
||||||
onAddEvery: () => void
|
onAddEvery: (every?: string) => void
|
||||||
timeRange: TimeRange
|
timeRange: TimeRange
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,24 @@
|
||||||
import React from 'react'
|
import React, {SFC} from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import {PERIODS} from 'src/kapacitor/constants'
|
import {PERIODS} from 'src/kapacitor/constants'
|
||||||
import Dropdown from 'shared/components/Dropdown'
|
import Dropdown from 'src/shared/components/Dropdown'
|
||||||
|
|
||||||
|
import {AlertRule} from 'src/types'
|
||||||
|
|
||||||
const periods = PERIODS.map(text => {
|
const periods = PERIODS.map(text => {
|
||||||
return {text}
|
return {text}
|
||||||
})
|
})
|
||||||
|
|
||||||
const Deadman = ({rule, onChange}) => (
|
interface Item {
|
||||||
|
text: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
rule: AlertRule
|
||||||
|
onChange: (item: Item) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const Deadman: SFC<Props> = ({rule, onChange}) => (
|
||||||
<div className="rule-section--row rule-section--row-first rule-section--row-last">
|
<div className="rule-section--row rule-section--row-first rule-section--row-last">
|
||||||
<p>Send Alert if Data is missing for</p>
|
<p>Send Alert if Data is missing for</p>
|
||||||
<Dropdown
|
<Dropdown
|
||||||
|
@ -20,15 +31,4 @@ const Deadman = ({rule, onChange}) => (
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
const {shape, string, func} = PropTypes
|
|
||||||
|
|
||||||
Deadman.propTypes = {
|
|
||||||
rule: shape({
|
|
||||||
values: shape({
|
|
||||||
period: string,
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
onChange: func.isRequired,
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Deadman
|
export default Deadman
|
|
@ -1,7 +1,7 @@
|
||||||
import React, {Component} from 'react'
|
import React, {Component, ChangeEvent} from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import {connect} from 'react-redux'
|
import {connect} from 'react-redux'
|
||||||
import {bindActionCreators} from 'redux'
|
import {bindActionCreators} from 'redux'
|
||||||
|
import {InjectedRouter} from 'react-router'
|
||||||
|
|
||||||
import PageHeader from 'src/shared/components/PageHeader'
|
import PageHeader from 'src/shared/components/PageHeader'
|
||||||
import NameSection from 'src/kapacitor/components/NameSection'
|
import NameSection from 'src/kapacitor/components/NameSection'
|
||||||
|
@ -9,13 +9,13 @@ import ValuesSection from 'src/kapacitor/components/ValuesSection'
|
||||||
import RuleHeaderSave from 'src/kapacitor/components/RuleHeaderSave'
|
import RuleHeaderSave from 'src/kapacitor/components/RuleHeaderSave'
|
||||||
import RuleHandlers from 'src/kapacitor/components/RuleHandlers'
|
import RuleHandlers from 'src/kapacitor/components/RuleHandlers'
|
||||||
import RuleMessage from 'src/kapacitor/components/RuleMessage'
|
import RuleMessage from 'src/kapacitor/components/RuleMessage'
|
||||||
import FancyScrollbar from 'shared/components/FancyScrollbar'
|
import FancyScrollbar from 'src/shared/components/FancyScrollbar'
|
||||||
|
|
||||||
import {createRule, editRule} from 'src/kapacitor/apis'
|
import {createRule, editRule} from 'src/kapacitor/apis'
|
||||||
import buildInfluxQLQuery from 'utils/influxql'
|
import buildInfluxQLQuery from 'src/utils/influxql'
|
||||||
import {timeRanges} from 'shared/data/timeRanges'
|
import {timeRanges} from 'src/shared/data/timeRanges'
|
||||||
import {DEFAULT_RULE_ID} from 'src/kapacitor/constants'
|
import {DEFAULT_RULE_ID} from 'src/kapacitor/constants'
|
||||||
import {notify as notifyAction} from 'shared/actions/notifications'
|
import {notify as notifyAction} from 'src/shared/actions/notifications'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
notifyAlertRuleCreated,
|
notifyAlertRuleCreated,
|
||||||
|
@ -25,11 +25,52 @@ import {
|
||||||
notifyAlertRuleRequiresQuery,
|
notifyAlertRuleRequiresQuery,
|
||||||
notifyAlertRuleRequiresConditionValue,
|
notifyAlertRuleRequiresConditionValue,
|
||||||
notifyAlertRuleDeadmanInvalid,
|
notifyAlertRuleDeadmanInvalid,
|
||||||
} from 'shared/copy/notifications'
|
} from 'src/shared/copy/notifications'
|
||||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||||
|
|
||||||
|
import {
|
||||||
|
Source,
|
||||||
|
AlertRule,
|
||||||
|
Notification,
|
||||||
|
Kapacitor,
|
||||||
|
QueryConfig,
|
||||||
|
TimeRange,
|
||||||
|
} from 'src/types'
|
||||||
|
import {Handler} from 'src/types/kapacitor'
|
||||||
|
import {
|
||||||
|
KapacitorQueryConfigActions,
|
||||||
|
KapacitorRuleActions,
|
||||||
|
} from 'src/types/actions'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
source: Source
|
||||||
|
rule: AlertRule
|
||||||
|
query: QueryConfig
|
||||||
|
queryConfigs: QueryConfig[]
|
||||||
|
queryConfigActions: KapacitorQueryConfigActions
|
||||||
|
ruleActions: KapacitorRuleActions
|
||||||
|
notify: (message: Notification) => void
|
||||||
|
ruleID: string
|
||||||
|
handlersFromConfig: Handler[]
|
||||||
|
router: InjectedRouter
|
||||||
|
kapacitor: Kapacitor
|
||||||
|
configLink: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Item {
|
||||||
|
text: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TypeItem extends Item {
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface State {
|
||||||
|
timeRange: TimeRange
|
||||||
|
}
|
||||||
|
|
||||||
@ErrorHandling
|
@ErrorHandling
|
||||||
class KapacitorRule extends Component {
|
class KapacitorRule extends Component<Props, State> {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props)
|
super(props)
|
||||||
this.state = {
|
this.state = {
|
||||||
|
@ -37,146 +78,7 @@ class KapacitorRule extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleChooseTimeRange = ({lower}) => {
|
public render() {
|
||||||
const timeRange = timeRanges.find(range => range.lower === lower)
|
|
||||||
this.setState({timeRange})
|
|
||||||
}
|
|
||||||
|
|
||||||
handleCreate = pathname => {
|
|
||||||
const {notify, queryConfigs, rule, source, router, kapacitor} = this.props
|
|
||||||
|
|
||||||
const newRule = Object.assign({}, rule, {
|
|
||||||
query: queryConfigs[rule.queryID],
|
|
||||||
})
|
|
||||||
delete newRule.queryID
|
|
||||||
|
|
||||||
createRule(kapacitor, newRule)
|
|
||||||
.then(() => {
|
|
||||||
router.push(pathname || `/sources/${source.id}/alert-rules`)
|
|
||||||
notify(notifyAlertRuleCreated(newRule.name))
|
|
||||||
})
|
|
||||||
.catch(e => {
|
|
||||||
notify(notifyAlertRuleCreateFailed(newRule.name, e.data.message))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
handleEdit = pathname => {
|
|
||||||
const {notify, queryConfigs, rule, router, source} = this.props
|
|
||||||
const updatedRule = Object.assign({}, rule, {
|
|
||||||
query: queryConfigs[rule.queryID],
|
|
||||||
})
|
|
||||||
|
|
||||||
editRule(updatedRule)
|
|
||||||
.then(() => {
|
|
||||||
router.push(pathname || `/sources/${source.id}/alert-rules`)
|
|
||||||
notify(notifyAlertRuleUpdated(rule.name))
|
|
||||||
})
|
|
||||||
.catch(e => {
|
|
||||||
notify(notifyAlertRuleUpdateFailed(rule.name, e.data.message))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
handleSave = () => {
|
|
||||||
const {rule} = this.props
|
|
||||||
if (rule.id === DEFAULT_RULE_ID) {
|
|
||||||
this.handleCreate()
|
|
||||||
} else {
|
|
||||||
this.handleEdit()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleSaveToConfig = configName => () => {
|
|
||||||
const {rule, configLink, router} = this.props
|
|
||||||
const pathname = `${configLink}#${configName}`
|
|
||||||
if (this.validationError()) {
|
|
||||||
router.push({
|
|
||||||
pathname,
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (rule.id === DEFAULT_RULE_ID) {
|
|
||||||
this.handleCreate(pathname)
|
|
||||||
} else {
|
|
||||||
this.handleEdit(pathname)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleAddEvery = frequency => {
|
|
||||||
const {
|
|
||||||
rule: {id: ruleID},
|
|
||||||
ruleActions: {addEvery},
|
|
||||||
} = this.props
|
|
||||||
addEvery(ruleID, frequency)
|
|
||||||
}
|
|
||||||
|
|
||||||
handleRemoveEvery = () => {
|
|
||||||
const {
|
|
||||||
rule: {id: ruleID},
|
|
||||||
ruleActions: {removeEvery},
|
|
||||||
} = this.props
|
|
||||||
removeEvery(ruleID)
|
|
||||||
}
|
|
||||||
|
|
||||||
validationError = () => {
|
|
||||||
const {rule, query} = this.props
|
|
||||||
if (rule.trigger === 'deadman') {
|
|
||||||
return this.deadmanValidation()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!buildInfluxQLQuery({}, query)) {
|
|
||||||
return notifyAlertRuleRequiresQuery()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!rule.values.value) {
|
|
||||||
return notifyAlertRuleRequiresConditionValue()
|
|
||||||
}
|
|
||||||
|
|
||||||
return ''
|
|
||||||
}
|
|
||||||
|
|
||||||
deadmanValidation = () => {
|
|
||||||
const {query} = this.props
|
|
||||||
if (query && (!query.database || !query.measurement)) {
|
|
||||||
return notifyAlertRuleDeadmanInvalid()
|
|
||||||
}
|
|
||||||
|
|
||||||
return ''
|
|
||||||
}
|
|
||||||
|
|
||||||
handleRuleTypeDropdownChange = ({type, text}) => {
|
|
||||||
const {ruleActions, rule} = this.props
|
|
||||||
ruleActions.updateRuleValues(rule.id, rule.trigger, {
|
|
||||||
...this.props.rule.values,
|
|
||||||
[type]: text,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
handleRuleTypeInputChange = e => {
|
|
||||||
const {ruleActions, rule} = this.props
|
|
||||||
const {lower, upper} = e.target.form
|
|
||||||
|
|
||||||
ruleActions.updateRuleValues(rule.id, rule.trigger, {
|
|
||||||
...this.props.rule.values,
|
|
||||||
value: lower.value,
|
|
||||||
rangeValue: upper ? upper.value : '',
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
handleDeadmanChange = ({text}) => {
|
|
||||||
const {ruleActions, rule} = this.props
|
|
||||||
ruleActions.updateRuleValues(rule.id, rule.trigger, {period: text})
|
|
||||||
}
|
|
||||||
|
|
||||||
optionsComponents = () => {
|
|
||||||
return (
|
|
||||||
<RuleHeaderSave
|
|
||||||
onSave={this.handleSave}
|
|
||||||
validationError={this.validationError()}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {
|
const {
|
||||||
rule,
|
rule,
|
||||||
source,
|
source,
|
||||||
|
@ -191,7 +93,7 @@ class KapacitorRule extends Component {
|
||||||
return (
|
return (
|
||||||
<div className="page">
|
<div className="page">
|
||||||
<PageHeader
|
<PageHeader
|
||||||
title="Alert Rule Builder"
|
titleText="Alert Rule Builder"
|
||||||
optionsComponents={this.optionsComponents}
|
optionsComponents={this.optionsComponents}
|
||||||
sourceIndicator={true}
|
sourceIndicator={true}
|
||||||
/>
|
/>
|
||||||
|
@ -225,7 +127,7 @@ class KapacitorRule extends Component {
|
||||||
ruleActions={ruleActions}
|
ruleActions={ruleActions}
|
||||||
handlersFromConfig={handlersFromConfig}
|
handlersFromConfig={handlersFromConfig}
|
||||||
onGoToConfig={this.handleSaveToConfig}
|
onGoToConfig={this.handleSaveToConfig}
|
||||||
validationError={this.validationError()}
|
validationError={this.validationError}
|
||||||
/>
|
/>
|
||||||
<RuleMessage rule={rule} ruleActions={ruleActions} />
|
<RuleMessage rule={rule} ruleActions={ruleActions} />
|
||||||
</div>
|
</div>
|
||||||
|
@ -236,27 +138,147 @@ class KapacitorRule extends Component {
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const {arrayOf, func, shape, string} = PropTypes
|
private handleChooseTimeRange = ({lower}: TimeRange) => {
|
||||||
|
const timeRange = timeRanges.find(range => range.lower === lower)
|
||||||
|
this.setState({timeRange})
|
||||||
|
}
|
||||||
|
|
||||||
KapacitorRule.propTypes = {
|
private handleCreate = (pathname?: string) => {
|
||||||
source: shape({}).isRequired,
|
const {notify, queryConfigs, rule, source, router, kapacitor} = this.props
|
||||||
rule: shape({
|
|
||||||
values: shape({}),
|
const newRule = Object.assign({}, rule, {
|
||||||
}).isRequired,
|
query: queryConfigs[rule.queryID],
|
||||||
query: shape({}).isRequired,
|
})
|
||||||
queryConfigs: shape({}).isRequired,
|
delete newRule.queryID
|
||||||
queryConfigActions: shape({}).isRequired,
|
|
||||||
ruleActions: shape({}).isRequired,
|
createRule(kapacitor, newRule)
|
||||||
notify: func.isRequired,
|
.then(() => {
|
||||||
ruleID: string.isRequired,
|
router.push(pathname || `/sources/${source.id}/alert-rules`)
|
||||||
handlersFromConfig: arrayOf(shape({})).isRequired,
|
notify(notifyAlertRuleCreated(newRule.name))
|
||||||
router: shape({
|
})
|
||||||
push: func.isRequired,
|
.catch(e => {
|
||||||
}).isRequired,
|
notify(notifyAlertRuleCreateFailed(newRule.name, e.data.message))
|
||||||
kapacitor: shape({}).isRequired,
|
})
|
||||||
configLink: string.isRequired,
|
}
|
||||||
|
|
||||||
|
private handleEdit = (pathname?: string) => {
|
||||||
|
const {notify, queryConfigs, rule, router, source} = this.props
|
||||||
|
const updatedRule = Object.assign({}, rule, {
|
||||||
|
query: queryConfigs[rule.queryID],
|
||||||
|
})
|
||||||
|
|
||||||
|
editRule(updatedRule)
|
||||||
|
.then(() => {
|
||||||
|
router.push(pathname || `/sources/${source.id}/alert-rules`)
|
||||||
|
notify(notifyAlertRuleUpdated(rule.name))
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
notify(notifyAlertRuleUpdateFailed(rule.name, e.data.message))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleSave = () => {
|
||||||
|
const {rule} = this.props
|
||||||
|
if (rule.id === DEFAULT_RULE_ID) {
|
||||||
|
this.handleCreate()
|
||||||
|
} else {
|
||||||
|
this.handleEdit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleSaveToConfig = (configName: string) => () => {
|
||||||
|
const {rule, configLink, router} = this.props
|
||||||
|
const pathname = `${configLink}#${configName}`
|
||||||
|
|
||||||
|
if (this.validationError) {
|
||||||
|
router.push({
|
||||||
|
pathname,
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rule.id === DEFAULT_RULE_ID) {
|
||||||
|
this.handleCreate(pathname)
|
||||||
|
} else {
|
||||||
|
this.handleEdit(pathname)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleAddEvery = (frequency: string) => {
|
||||||
|
const {
|
||||||
|
rule: {id: ruleID},
|
||||||
|
ruleActions: {addEvery},
|
||||||
|
} = this.props
|
||||||
|
addEvery(ruleID, frequency)
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleRemoveEvery = () => {
|
||||||
|
const {
|
||||||
|
rule: {id: ruleID},
|
||||||
|
ruleActions: {removeEvery},
|
||||||
|
} = this.props
|
||||||
|
removeEvery(ruleID)
|
||||||
|
}
|
||||||
|
|
||||||
|
private get validationError(): string {
|
||||||
|
const {rule, query} = this.props
|
||||||
|
if (rule.trigger === 'deadman') {
|
||||||
|
return this.deadmanValidation()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!buildInfluxQLQuery({lower: ''}, query)) {
|
||||||
|
return notifyAlertRuleRequiresQuery()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rule.values.value) {
|
||||||
|
return notifyAlertRuleRequiresConditionValue()
|
||||||
|
}
|
||||||
|
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
private deadmanValidation = () => {
|
||||||
|
const {query} = this.props
|
||||||
|
if (query && (!query.database || !query.measurement)) {
|
||||||
|
return notifyAlertRuleDeadmanInvalid()
|
||||||
|
}
|
||||||
|
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleRuleTypeDropdownChange = ({type, text}: TypeItem) => {
|
||||||
|
const {ruleActions, rule} = this.props
|
||||||
|
ruleActions.updateRuleValues(rule.id, rule.trigger, {
|
||||||
|
...this.props.rule.values,
|
||||||
|
[type]: text,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleRuleTypeInputChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const {ruleActions, rule} = this.props
|
||||||
|
const {lower, upper} = e.target.form
|
||||||
|
|
||||||
|
ruleActions.updateRuleValues(rule.id, rule.trigger, {
|
||||||
|
...this.props.rule.values,
|
||||||
|
value: lower.value,
|
||||||
|
rangeValue: upper ? upper.value : '',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleDeadmanChange = ({text}: Item) => {
|
||||||
|
const {ruleActions, rule} = this.props
|
||||||
|
ruleActions.updateRuleValues(rule.id, rule.trigger, {period: text})
|
||||||
|
}
|
||||||
|
|
||||||
|
private get optionsComponents(): JSX.Element {
|
||||||
|
return (
|
||||||
|
<RuleHeaderSave
|
||||||
|
onSave={this.handleSave}
|
||||||
|
validationError={this.validationError}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapDispatchToProps = dispatch => ({
|
const mapDispatchToProps = dispatch => ({
|
|
@ -1,7 +1,12 @@
|
||||||
import React from 'react'
|
import React, {SFC} from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
|
|
||||||
const LogItemHTTP = ({logItem}) => (
|
import {LogItem} from 'src/types/kapacitor'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
logItem: LogItem
|
||||||
|
}
|
||||||
|
|
||||||
|
const LogItemHTTP: SFC<Props> = ({logItem}) => (
|
||||||
<div className="logs-table--row">
|
<div className="logs-table--row">
|
||||||
<div className="logs-table--divider">
|
<div className="logs-table--divider">
|
||||||
<div className={`logs-table--level ${logItem.lvl}`} />
|
<div className={`logs-table--level ${logItem.lvl}`} />
|
||||||
|
@ -16,17 +21,4 @@ const LogItemHTTP = ({logItem}) => (
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
const {shape, string} = PropTypes
|
|
||||||
|
|
||||||
LogItemHTTP.propTypes = {
|
|
||||||
logItem: shape({
|
|
||||||
lvl: string.isRequired,
|
|
||||||
ts: string.isRequired,
|
|
||||||
method: string.isRequired,
|
|
||||||
username: string.isRequired,
|
|
||||||
host: string.isRequired,
|
|
||||||
duration: string.isRequired,
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
|
|
||||||
export default LogItemHTTP
|
export default LogItemHTTP
|
|
@ -1,7 +1,12 @@
|
||||||
import React from 'react'
|
import React, {SFC} from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
|
|
||||||
const LogItemHTTPError = ({logItem}) => (
|
import {LogItem} from 'src/types/kapacitor'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
logItem: LogItem
|
||||||
|
}
|
||||||
|
|
||||||
|
const LogItemHTTPError: SFC<Props> = ({logItem}) => (
|
||||||
<div className="logs-table--row" key={logItem.key}>
|
<div className="logs-table--row" key={logItem.key}>
|
||||||
<div className="logs-table--divider">
|
<div className="logs-table--divider">
|
||||||
<div className={`logs-table--level ${logItem.lvl}`} />
|
<div className={`logs-table--level ${logItem.lvl}`} />
|
||||||
|
@ -16,15 +21,4 @@ const LogItemHTTPError = ({logItem}) => (
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
const {shape, string} = PropTypes
|
|
||||||
|
|
||||||
LogItemHTTPError.propTypes = {
|
|
||||||
logItem: shape({
|
|
||||||
key: string.isRequired,
|
|
||||||
lvl: string.isRequired,
|
|
||||||
ts: string.isRequired,
|
|
||||||
msg: string.isRequired,
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
|
|
||||||
export default LogItemHTTPError
|
export default LogItemHTTPError
|
|
@ -1,7 +1,12 @@
|
||||||
import React from 'react'
|
import React, {SFC} from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
|
|
||||||
const LogItemInfluxDBDebug = ({logItem}) => (
|
import {LogItem} from 'src/types/kapacitor'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
logItem: LogItem
|
||||||
|
}
|
||||||
|
|
||||||
|
const LogItemInfluxDBDebug: SFC<Props> = ({logItem}) => (
|
||||||
<div className="logs-table--row">
|
<div className="logs-table--row">
|
||||||
<div className="logs-table--divider">
|
<div className="logs-table--divider">
|
||||||
<div className={`logs-table--level ${logItem.lvl}`} />
|
<div className={`logs-table--level ${logItem.lvl}`} />
|
||||||
|
@ -20,15 +25,4 @@ const LogItemInfluxDBDebug = ({logItem}) => (
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
const {shape, string} = PropTypes
|
|
||||||
|
|
||||||
LogItemInfluxDBDebug.propTypes = {
|
|
||||||
logItem: shape({
|
|
||||||
lvl: string.isRequired,
|
|
||||||
ts: string.isRequired,
|
|
||||||
msg: string.isRequired,
|
|
||||||
cluster: string.isRequired,
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
|
|
||||||
export default LogItemInfluxDBDebug
|
export default LogItemInfluxDBDebug
|
|
@ -1,7 +1,12 @@
|
||||||
import React from 'react'
|
import React, {SFC} from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
|
|
||||||
const LogItemKapacitorDebug = ({logItem}) => (
|
import {LogItem} from 'src/types/kapacitor'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
logItem: LogItem
|
||||||
|
}
|
||||||
|
|
||||||
|
const LogItemKapacitorDebug: SFC<Props> = ({logItem}) => (
|
||||||
<div className="logs-table--row">
|
<div className="logs-table--row">
|
||||||
<div className="logs-table--divider">
|
<div className="logs-table--divider">
|
||||||
<div className={`logs-table--level ${logItem.lvl}`} />
|
<div className={`logs-table--level ${logItem.lvl}`} />
|
||||||
|
@ -16,14 +21,4 @@ const LogItemKapacitorDebug = ({logItem}) => (
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
const {shape, string} = PropTypes
|
|
||||||
|
|
||||||
LogItemKapacitorDebug.propTypes = {
|
|
||||||
logItem: shape({
|
|
||||||
lvl: string.isRequired,
|
|
||||||
ts: string.isRequired,
|
|
||||||
msg: string.isRequired,
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
|
|
||||||
export default LogItemKapacitorDebug
|
export default LogItemKapacitorDebug
|
|
@ -1,7 +1,12 @@
|
||||||
import React from 'react'
|
import React, {SFC} from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
|
|
||||||
const LogItemKapacitorError = ({logItem}) => (
|
import {LogItem} from 'src/types/kapacitor'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
logItem: LogItem
|
||||||
|
}
|
||||||
|
|
||||||
|
const LogItemKapacitorError: SFC<Props> = ({logItem}) => (
|
||||||
<div className="logs-table--row">
|
<div className="logs-table--row">
|
||||||
<div className="logs-table--divider">
|
<div className="logs-table--divider">
|
||||||
<div className={`logs-table--level ${logItem.lvl}`} />
|
<div className={`logs-table--level ${logItem.lvl}`} />
|
||||||
|
@ -16,14 +21,4 @@ const LogItemKapacitorError = ({logItem}) => (
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
const {shape, string} = PropTypes
|
|
||||||
|
|
||||||
LogItemKapacitorError.propTypes = {
|
|
||||||
logItem: shape({
|
|
||||||
lvl: string.isRequired,
|
|
||||||
ts: string.isRequired,
|
|
||||||
msg: string.isRequired,
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
|
|
||||||
export default LogItemKapacitorError
|
export default LogItemKapacitorError
|
|
@ -1,51 +0,0 @@
|
||||||
import React from 'react'
|
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
|
|
||||||
const renderKeysAndValues = (object, name) => {
|
|
||||||
if (!object) {
|
|
||||||
return <span className="logs-table--empty-cell">--</span>
|
|
||||||
}
|
|
||||||
|
|
||||||
const sortedObjKeys = Object.keys(object).sort()
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="logs-table--column">
|
|
||||||
<h1>{`${sortedObjKeys.length} ${name}`}</h1>
|
|
||||||
<div className="logs-table--scrollbox">
|
|
||||||
{sortedObjKeys.map(objKey => (
|
|
||||||
<div key={objKey} className="logs-table--key-value">
|
|
||||||
{objKey}: <span>{object[objKey]}</span>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
const LogItemKapacitorPoint = ({logItem}) => (
|
|
||||||
<div className="logs-table--row">
|
|
||||||
<div className="logs-table--divider">
|
|
||||||
<div className={`logs-table--level ${logItem.lvl}`} />
|
|
||||||
<div className="logs-table--timestamp">{logItem.ts}</div>
|
|
||||||
</div>
|
|
||||||
<div className="logs-table--details">
|
|
||||||
<div className="logs-table--service">Kapacitor Point</div>
|
|
||||||
<div className="logs-table--columns">
|
|
||||||
{renderKeysAndValues(logItem.tag, 'Tags')}
|
|
||||||
{renderKeysAndValues(logItem.field, 'Fields')}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
|
|
||||||
const {shape, string} = PropTypes
|
|
||||||
|
|
||||||
LogItemKapacitorPoint.propTypes = {
|
|
||||||
logItem: shape({
|
|
||||||
lvl: string.isRequired,
|
|
||||||
ts: string.isRequired,
|
|
||||||
tag: shape.isRequired,
|
|
||||||
field: shape.isRequired,
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
|
|
||||||
export default LogItemKapacitorPoint
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
import React, {PureComponent} from 'react'
|
||||||
|
import _ from 'lodash'
|
||||||
|
|
||||||
|
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||||
|
|
||||||
|
import {LogItem} from 'src/types/kapacitor'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
logItem: LogItem
|
||||||
|
}
|
||||||
|
|
||||||
|
@ErrorHandling
|
||||||
|
class LogItemKapacitorPoint extends PureComponent<Props> {
|
||||||
|
public render() {
|
||||||
|
const {logItem} = this.props
|
||||||
|
return (
|
||||||
|
<div className="logs-table--row">
|
||||||
|
<div className="logs-table--divider">
|
||||||
|
<div className={`logs-table--level ${logItem.lvl}`} />
|
||||||
|
<div className="logs-table--timestamp">{logItem.ts}</div>
|
||||||
|
</div>
|
||||||
|
<div className="logs-table--details">
|
||||||
|
<div className="logs-table--service">Kapacitor Point</div>
|
||||||
|
<div className="logs-table--columns">
|
||||||
|
{this.renderKeysAndValues(logItem.tag, 'Tags')}
|
||||||
|
{this.renderKeysAndValues(logItem.field, 'Fields')}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private renderKeysAndValues = (object: any, name: string) => {
|
||||||
|
if (_.isEmpty(object)) {
|
||||||
|
return <span className="logs-table--empty-cell">--</span>
|
||||||
|
}
|
||||||
|
|
||||||
|
const sortedObjKeys = Object.keys(object).sort()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="logs-table--column">
|
||||||
|
<h1>{`${sortedObjKeys.length} ${name}`}</h1>
|
||||||
|
<div className="logs-table--scrollbox">
|
||||||
|
{sortedObjKeys.map(objKey => (
|
||||||
|
<div key={objKey} className="logs-table--key-value">
|
||||||
|
{objKey}: <span>{object[objKey]}</span>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default LogItemKapacitorPoint
|
|
@ -1,7 +1,12 @@
|
||||||
import React from 'react'
|
import React, {SFC} from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
|
|
||||||
const LogItemSession = ({logItem}) => (
|
import {LogItem} from 'src/types/kapacitor'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
logItem: LogItem
|
||||||
|
}
|
||||||
|
|
||||||
|
const LogItemSession: SFC<Props> = ({logItem}) => (
|
||||||
<div className="logs-table--row">
|
<div className="logs-table--row">
|
||||||
<div className="logs-table--divider">
|
<div className="logs-table--divider">
|
||||||
<div className={`logs-table--level ${logItem.lvl}`} />
|
<div className={`logs-table--level ${logItem.lvl}`} />
|
||||||
|
@ -13,14 +18,4 @@ const LogItemSession = ({logItem}) => (
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
const {shape, string} = PropTypes
|
|
||||||
|
|
||||||
LogItemSession.propTypes = {
|
|
||||||
logItem: shape({
|
|
||||||
lvl: string.isRequired,
|
|
||||||
ts: string.isRequired,
|
|
||||||
msg: string.isRequired,
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
|
|
||||||
export default LogItemSession
|
export default LogItemSession
|
|
@ -1,12 +1,17 @@
|
||||||
import React from 'react'
|
import React, {SFC} from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
|
|
||||||
import LogsTableRow from 'src/kapacitor/components/LogsTableRow'
|
import LogsTableRow from 'src/kapacitor/components/LogsTableRow'
|
||||||
import FancyScrollbar from 'src/shared/components/FancyScrollbar'
|
import FancyScrollbar from 'src/shared/components/FancyScrollbar'
|
||||||
|
|
||||||
|
import {LogItem} from 'src/types/kapacitor'
|
||||||
|
|
||||||
const numLogsToRender = 200
|
const numLogsToRender = 200
|
||||||
|
|
||||||
const LogsTable = ({logs}) => (
|
interface Props {
|
||||||
|
logs: LogItem[]
|
||||||
|
}
|
||||||
|
|
||||||
|
const LogsTable: SFC<Props> = ({logs}) => (
|
||||||
<div className="logs-table">
|
<div className="logs-table">
|
||||||
<div className="logs-table--header">
|
<div className="logs-table--header">
|
||||||
{`${numLogsToRender} Most Recent Logs`}
|
{`${numLogsToRender} Most Recent Logs`}
|
||||||
|
@ -22,17 +27,4 @@ const LogsTable = ({logs}) => (
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
const {arrayOf, shape, string} = PropTypes
|
|
||||||
|
|
||||||
LogsTable.propTypes = {
|
|
||||||
logs: arrayOf(
|
|
||||||
shape({
|
|
||||||
key: string.isRequired,
|
|
||||||
ts: string.isRequired,
|
|
||||||
lvl: string.isRequired,
|
|
||||||
msg: string.isRequired,
|
|
||||||
})
|
|
||||||
).isRequired,
|
|
||||||
}
|
|
||||||
|
|
||||||
export default LogsTable
|
export default LogsTable
|
|
@ -1,5 +1,4 @@
|
||||||
import React from 'react'
|
import React, {SFC} from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
|
|
||||||
import LogItemSession from 'src/kapacitor/components/LogItemSession'
|
import LogItemSession from 'src/kapacitor/components/LogItemSession'
|
||||||
import LogItemHTTP from 'src/kapacitor/components/LogItemHTTP'
|
import LogItemHTTP from 'src/kapacitor/components/LogItemHTTP'
|
||||||
|
@ -9,7 +8,13 @@ import LogItemKapacitorError from 'src/kapacitor/components/LogItemKapacitorErro
|
||||||
import LogItemKapacitorDebug from 'src/kapacitor/components/LogItemKapacitorDebug'
|
import LogItemKapacitorDebug from 'src/kapacitor/components/LogItemKapacitorDebug'
|
||||||
import LogItemInfluxDBDebug from 'src/kapacitor/components/LogItemInfluxDBDebug'
|
import LogItemInfluxDBDebug from 'src/kapacitor/components/LogItemInfluxDBDebug'
|
||||||
|
|
||||||
const LogsTableRow = ({logItem}) => {
|
import {LogItem} from 'src/types/kapacitor'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
logItem: LogItem
|
||||||
|
}
|
||||||
|
|
||||||
|
const LogsTableRow: SFC<Props> = ({logItem}) => {
|
||||||
if (logItem.service === 'sessions') {
|
if (logItem.service === 'sessions') {
|
||||||
return <LogItemSession logItem={logItem} />
|
return <LogItemSession logItem={logItem} />
|
||||||
}
|
}
|
||||||
|
@ -51,15 +56,4 @@ const LogsTableRow = ({logItem}) => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const {shape, string} = PropTypes
|
|
||||||
|
|
||||||
LogsTableRow.propTypes = {
|
|
||||||
logItem: shape({
|
|
||||||
key: string.isRequired,
|
|
||||||
ts: string.isRequired,
|
|
||||||
lvl: string.isRequired,
|
|
||||||
msg: string.isRequired,
|
|
||||||
}).isRequired,
|
|
||||||
}
|
|
||||||
|
|
||||||
export default LogsTableRow
|
export default LogsTableRow
|
|
@ -1,11 +1,25 @@
|
||||||
import React, {Component} from 'react'
|
import React, {Component, ChangeEvent, KeyboardEvent} from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import {DEFAULT_RULE_ID} from 'src/kapacitor/constants'
|
import {DEFAULT_RULE_ID} from 'src/kapacitor/constants'
|
||||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||||
|
|
||||||
|
import {AlertRule} from 'src/types'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
defaultName: string
|
||||||
|
onRuleRename: (id: string, name: string) => void
|
||||||
|
rule: AlertRule
|
||||||
|
}
|
||||||
|
|
||||||
|
interface State {
|
||||||
|
reset: boolean
|
||||||
|
}
|
||||||
|
|
||||||
@ErrorHandling
|
@ErrorHandling
|
||||||
class NameSection extends Component {
|
class NameSection extends Component<Props, State> {
|
||||||
constructor(props) {
|
private inputRef: HTMLInputElement
|
||||||
|
|
||||||
|
constructor(props: Props) {
|
||||||
super(props)
|
super(props)
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
|
@ -13,14 +27,22 @@ class NameSection extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleInputBlur = reset => e => {
|
public handleInputBlur = (reset: boolean) => (
|
||||||
|
e: ChangeEvent<HTMLInputElement>
|
||||||
|
): void => {
|
||||||
const {defaultName, onRuleRename, rule} = this.props
|
const {defaultName, onRuleRename, rule} = this.props
|
||||||
|
|
||||||
onRuleRename(rule.id, reset ? defaultName : e.target.value)
|
let ruleName: string
|
||||||
|
if (reset) {
|
||||||
|
ruleName = defaultName
|
||||||
|
} else {
|
||||||
|
ruleName = e.target.value
|
||||||
|
}
|
||||||
|
onRuleRename(rule.id, ruleName)
|
||||||
this.setState({reset: false})
|
this.setState({reset: false})
|
||||||
}
|
}
|
||||||
|
|
||||||
handleKeyDown = e => {
|
public handleKeyDown = (e: KeyboardEvent<HTMLInputElement>) => {
|
||||||
if (e.key === 'Enter') {
|
if (e.key === 'Enter') {
|
||||||
this.inputRef.blur()
|
this.inputRef.blur()
|
||||||
}
|
}
|
||||||
|
@ -30,15 +52,13 @@ class NameSection extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
public render() {
|
||||||
const {rule, defaultName} = this.props
|
const {defaultName} = this.props
|
||||||
const {reset} = this.state
|
const {reset} = this.state
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="rule-section">
|
<div className="rule-section">
|
||||||
<h3 className="rule-section--heading">
|
<h3 className="rule-section--heading">{this.header}</h3>
|
||||||
{rule.id === DEFAULT_RULE_ID ? 'Name this Alert Rule' : 'Name'}
|
|
||||||
</h3>
|
|
||||||
<div className="rule-section--body">
|
<div className="rule-section--body">
|
||||||
<div className="rule-section--row rule-section--row-first rule-section--row-last">
|
<div className="rule-section--row rule-section--row-first rule-section--row-last">
|
||||||
<input
|
<input
|
||||||
|
@ -55,14 +75,18 @@ class NameSection extends Component {
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const {func, string, shape} = PropTypes
|
private get header() {
|
||||||
|
const {
|
||||||
|
rule: {id},
|
||||||
|
} = this.props
|
||||||
|
|
||||||
NameSection.propTypes = {
|
if (id === DEFAULT_RULE_ID) {
|
||||||
defaultName: string.isRequired,
|
return 'Name this Alert Rule'
|
||||||
onRuleRename: func.isRequired,
|
}
|
||||||
rule: shape({}).isRequired,
|
|
||||||
|
return 'Name'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default NameSection
|
export default NameSection
|
|
@ -1,14 +1,27 @@
|
||||||
import React from 'react'
|
import React, {SFC, ChangeEvent} from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import {CHANGES, RELATIVE_OPERATORS, SHIFTS} from 'src/kapacitor/constants'
|
|
||||||
import Dropdown from 'shared/components/Dropdown'
|
|
||||||
|
|
||||||
const mapToItems = (arr, type) => arr.map(text => ({text, type}))
|
import {CHANGES, RELATIVE_OPERATORS, SHIFTS} from 'src/kapacitor/constants'
|
||||||
|
import Dropdown from 'src/shared/components/Dropdown'
|
||||||
|
|
||||||
|
import {AlertRule} from 'src/types'
|
||||||
|
|
||||||
|
const mapToItems = (arr: string[], type: string) =>
|
||||||
|
arr.map(text => ({text, type}))
|
||||||
const changes = mapToItems(CHANGES, 'change')
|
const changes = mapToItems(CHANGES, 'change')
|
||||||
const shifts = mapToItems(SHIFTS, 'shift')
|
const shifts = mapToItems(SHIFTS, 'shift')
|
||||||
const operators = mapToItems(RELATIVE_OPERATORS, 'operator')
|
const operators = mapToItems(RELATIVE_OPERATORS, 'operator')
|
||||||
|
|
||||||
const Relative = ({
|
interface TypeItem {
|
||||||
|
type: string
|
||||||
|
text: string
|
||||||
|
}
|
||||||
|
interface Props {
|
||||||
|
onRuleTypeInputChange: (e: ChangeEvent<HTMLInputElement>) => void
|
||||||
|
onDropdownChange: (item: TypeItem) => void
|
||||||
|
rule: AlertRule
|
||||||
|
}
|
||||||
|
|
||||||
|
const Relative: SFC<Props> = ({
|
||||||
onRuleTypeInputChange,
|
onRuleTypeInputChange,
|
||||||
onDropdownChange,
|
onDropdownChange,
|
||||||
rule: {
|
rule: {
|
||||||
|
@ -46,7 +59,7 @@ const Relative = ({
|
||||||
style={{width: '160px', marginLeft: '6px'}}
|
style={{width: '160px', marginLeft: '6px'}}
|
||||||
type="text"
|
type="text"
|
||||||
name="lower"
|
name="lower"
|
||||||
spellCheck="false"
|
spellCheck={false}
|
||||||
value={value}
|
value={value}
|
||||||
onChange={onRuleTypeInputChange}
|
onChange={onRuleTypeInputChange}
|
||||||
required={true}
|
required={true}
|
||||||
|
@ -56,19 +69,4 @@ const Relative = ({
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
const {shape, string, func} = PropTypes
|
|
||||||
|
|
||||||
Relative.propTypes = {
|
|
||||||
onRuleTypeInputChange: func.isRequired,
|
|
||||||
onDropdownChange: func.isRequired,
|
|
||||||
rule: shape({
|
|
||||||
values: shape({
|
|
||||||
change: string,
|
|
||||||
shift: string,
|
|
||||||
operator: string,
|
|
||||||
value: string,
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Relative
|
export default Relative
|
|
@ -26,7 +26,7 @@ interface Props {
|
||||||
rule: AlertRule
|
rule: AlertRule
|
||||||
ruleActions: RuleActions
|
ruleActions: RuleActions
|
||||||
handlersFromConfig: Handler[]
|
handlersFromConfig: Handler[]
|
||||||
onGoToConfig: () => void
|
onGoToConfig: (configName: string) => void
|
||||||
validationError: string
|
validationError: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,22 +1,24 @@
|
||||||
import React, {Component} from 'react'
|
import React, {Component, ChangeEvent} from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
|
|
||||||
import RuleMessageText from 'src/kapacitor/components/RuleMessageText'
|
import RuleMessageText from 'src/kapacitor/components/RuleMessageText'
|
||||||
import RuleMessageTemplates from 'src/kapacitor/components/RuleMessageTemplates'
|
import RuleMessageTemplates from 'src/kapacitor/components/RuleMessageTemplates'
|
||||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||||
|
|
||||||
|
import {AlertRule} from 'src/types'
|
||||||
|
import {KapacitorRuleActions} from 'src/types/actions'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
rule: AlertRule
|
||||||
|
ruleActions: KapacitorRuleActions
|
||||||
|
}
|
||||||
|
|
||||||
@ErrorHandling
|
@ErrorHandling
|
||||||
class RuleMessage extends Component {
|
class RuleMessage extends Component<Props> {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props)
|
super(props)
|
||||||
}
|
}
|
||||||
|
|
||||||
handleChangeMessage = e => {
|
public render() {
|
||||||
const {ruleActions, rule} = this.props
|
|
||||||
ruleActions.updateMessage(rule.id, e.target.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {rule, ruleActions} = this.props
|
const {rule, ruleActions} = this.props
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -35,15 +37,11 @@ class RuleMessage extends Component {
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const {func, shape} = PropTypes
|
private handleChangeMessage = (e: ChangeEvent<HTMLTextAreaElement>) => {
|
||||||
|
const {ruleActions, rule} = this.props
|
||||||
RuleMessage.propTypes = {
|
ruleActions.updateMessage(rule.id, e.target.value)
|
||||||
rule: shape().isRequired,
|
}
|
||||||
ruleActions: shape({
|
|
||||||
updateMessage: func.isRequired,
|
|
||||||
}).isRequired,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default RuleMessage
|
export default RuleMessage
|
|
@ -1,5 +1,5 @@
|
||||||
import React, {Component} from 'react'
|
import React, {Component} from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
import ReactTooltip from 'react-tooltip'
|
import ReactTooltip from 'react-tooltip'
|
||||||
|
|
||||||
|
@ -8,19 +8,22 @@ import CodeData from 'src/kapacitor/components/CodeData'
|
||||||
import {RULE_MESSAGE_TEMPLATES} from 'src/kapacitor/constants'
|
import {RULE_MESSAGE_TEMPLATES} from 'src/kapacitor/constants'
|
||||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||||
|
|
||||||
|
import {RuleMessage} from 'src/types/kapacitor'
|
||||||
|
import {AlertRule} from 'src/types'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
rule: AlertRule
|
||||||
|
updateMessage: (id: string, message: string) => void
|
||||||
|
}
|
||||||
|
|
||||||
// needs to be React Component for CodeData click handler to work
|
// needs to be React Component for CodeData click handler to work
|
||||||
@ErrorHandling
|
@ErrorHandling
|
||||||
class RuleMessageTemplates extends Component {
|
class RuleMessageTemplates extends Component<Props> {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props)
|
super(props)
|
||||||
}
|
}
|
||||||
|
|
||||||
handleClickTemplate = template => () => {
|
public render() {
|
||||||
const {updateMessage, rule} = this.props
|
|
||||||
updateMessage(rule.id, `${rule.message} ${template.label}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
return (
|
||||||
<div className="rule-section--row rule-section--row-last">
|
<div className="rule-section--row rule-section--row-last">
|
||||||
<p>Templates:</p>
|
<p>Templates:</p>
|
||||||
|
@ -41,13 +44,11 @@ class RuleMessageTemplates extends Component {
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const {func, shape} = PropTypes
|
private handleClickTemplate = (template: RuleMessage) => () => {
|
||||||
|
const {updateMessage, rule} = this.props
|
||||||
RuleMessageTemplates.propTypes = {
|
updateMessage(rule.id, `${rule.message} ${template.label}`)
|
||||||
rule: shape().isRequired,
|
}
|
||||||
updateMessage: func.isRequired,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default RuleMessageTemplates
|
export default RuleMessageTemplates
|
|
@ -1,7 +1,13 @@
|
||||||
import React from 'react'
|
import React, {SFC, ChangeEvent} from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
|
|
||||||
const RuleMessageText = ({rule, updateMessage}) => (
|
import {AlertRule} from 'src/types'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
rule: AlertRule
|
||||||
|
updateMessage: (e: ChangeEvent<HTMLTextAreaElement>) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const RuleMessageText: SFC<Props> = ({rule, updateMessage}) => (
|
||||||
<div className="rule-builder--message">
|
<div className="rule-builder--message">
|
||||||
<textarea
|
<textarea
|
||||||
className="form-control input-sm form-malachite monotype"
|
className="form-control input-sm form-malachite monotype"
|
||||||
|
@ -13,11 +19,4 @@ const RuleMessageText = ({rule, updateMessage}) => (
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
const {func, shape} = PropTypes
|
|
||||||
|
|
||||||
RuleMessageText.propTypes = {
|
|
||||||
rule: shape().isRequired,
|
|
||||||
updateMessage: func.isRequired,
|
|
||||||
}
|
|
||||||
|
|
||||||
export default RuleMessageText
|
export default RuleMessageText
|
|
@ -1,85 +0,0 @@
|
||||||
import React from 'react'
|
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import {THRESHOLD_OPERATORS} from 'src/kapacitor/constants'
|
|
||||||
import Dropdown from 'shared/components/Dropdown'
|
|
||||||
import _ from 'lodash'
|
|
||||||
|
|
||||||
const mapToItems = (arr, type) => arr.map(text => ({text, type}))
|
|
||||||
const operators = mapToItems(THRESHOLD_OPERATORS, 'operator')
|
|
||||||
const noopSubmit = e => e.preventDefault()
|
|
||||||
const getField = ({fields}) => {
|
|
||||||
const alias = _.get(fields, ['0', 'alias'], false)
|
|
||||||
if (!alias) {
|
|
||||||
return _.get(fields, ['0', 'value'], 'Select a Time-Series')
|
|
||||||
}
|
|
||||||
|
|
||||||
return alias
|
|
||||||
}
|
|
||||||
|
|
||||||
const Threshold = ({
|
|
||||||
rule: {
|
|
||||||
values: {operator, value, rangeValue},
|
|
||||||
},
|
|
||||||
query,
|
|
||||||
onDropdownChange,
|
|
||||||
onRuleTypeInputChange,
|
|
||||||
}) => (
|
|
||||||
<div className="rule-section--row rule-section--row-first rule-section--border-bottom">
|
|
||||||
<p>Send Alert where</p>
|
|
||||||
<span className="rule-builder--metric">{getField(query)}</span>
|
|
||||||
<p>is</p>
|
|
||||||
<Dropdown
|
|
||||||
className="dropdown-180"
|
|
||||||
menuClass="dropdown-malachite"
|
|
||||||
items={operators}
|
|
||||||
selected={operator}
|
|
||||||
onChoose={onDropdownChange}
|
|
||||||
/>
|
|
||||||
<form style={{display: 'flex'}} onSubmit={noopSubmit}>
|
|
||||||
<input
|
|
||||||
className="form-control input-sm form-malachite monotype"
|
|
||||||
style={{width: '160px', marginLeft: '6px'}}
|
|
||||||
type="text"
|
|
||||||
name="lower"
|
|
||||||
spellCheck="false"
|
|
||||||
value={value}
|
|
||||||
onChange={onRuleTypeInputChange}
|
|
||||||
placeholder={
|
|
||||||
operator === 'inside range' || operator === 'outside range'
|
|
||||||
? 'Lower'
|
|
||||||
: null
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
{(operator === 'inside range' || operator === 'outside range') && (
|
|
||||||
<input
|
|
||||||
className="form-control input-sm form-malachite monotype"
|
|
||||||
name="upper"
|
|
||||||
style={{width: '160px'}}
|
|
||||||
placeholder="Upper"
|
|
||||||
type="text"
|
|
||||||
spellCheck="false"
|
|
||||||
value={rangeValue}
|
|
||||||
onChange={onRuleTypeInputChange}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
|
|
||||||
const {shape, string, func} = PropTypes
|
|
||||||
|
|
||||||
Threshold.propTypes = {
|
|
||||||
rule: shape({
|
|
||||||
values: shape({
|
|
||||||
operator: string,
|
|
||||||
rangeOperator: string,
|
|
||||||
value: string,
|
|
||||||
rangeValue: string,
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
onDropdownChange: func.isRequired,
|
|
||||||
onRuleTypeInputChange: func.isRequired,
|
|
||||||
query: shape({}).isRequired,
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Threshold
|
|
|
@ -0,0 +1,122 @@
|
||||||
|
import React, {Component, FormEvent, ChangeEvent} from 'react'
|
||||||
|
|
||||||
|
import {THRESHOLD_OPERATORS} from 'src/kapacitor/constants'
|
||||||
|
import Dropdown from 'src/shared/components/Dropdown'
|
||||||
|
import {getDeep} from 'src/utils/wrappers'
|
||||||
|
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||||
|
|
||||||
|
import {AlertRule, QueryConfig} from 'src/types'
|
||||||
|
|
||||||
|
interface TypeItem {
|
||||||
|
type: string
|
||||||
|
text: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
rule: AlertRule
|
||||||
|
onDropdownChange: (item: TypeItem) => void
|
||||||
|
onRuleTypeInputChange: (e: ChangeEvent<HTMLInputElement>) => void
|
||||||
|
query: QueryConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
@ErrorHandling
|
||||||
|
class Threshold extends Component<Props> {
|
||||||
|
public render() {
|
||||||
|
const {
|
||||||
|
rule: {
|
||||||
|
values: {operator, value},
|
||||||
|
},
|
||||||
|
query,
|
||||||
|
onDropdownChange,
|
||||||
|
onRuleTypeInputChange,
|
||||||
|
} = this.props
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="rule-section--row rule-section--row-first rule-section--border-bottom">
|
||||||
|
<p>Send Alert where</p>
|
||||||
|
<span className="rule-builder--metric">{this.getField(query)}</span>
|
||||||
|
<p>is</p>
|
||||||
|
<Dropdown
|
||||||
|
className="dropdown-180"
|
||||||
|
menuClass="dropdown-malachite"
|
||||||
|
items={this.operators}
|
||||||
|
selected={operator}
|
||||||
|
onChoose={onDropdownChange}
|
||||||
|
/>
|
||||||
|
<form style={{display: 'flex'}} onSubmit={this.noopSubmit}>
|
||||||
|
<input
|
||||||
|
className="form-control input-sm form-malachite monotype"
|
||||||
|
style={{width: '160px', marginLeft: '6px'}}
|
||||||
|
type="text"
|
||||||
|
name="lower"
|
||||||
|
spellCheck={false}
|
||||||
|
value={value}
|
||||||
|
onChange={onRuleTypeInputChange}
|
||||||
|
placeholder={this.firstInputPlaceholder}
|
||||||
|
/>
|
||||||
|
{this.secondInput}
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private get operators() {
|
||||||
|
const type = 'operator'
|
||||||
|
return THRESHOLD_OPERATORS.map(text => {
|
||||||
|
return {text, type}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private get isSecondInputRequired() {
|
||||||
|
const {rule} = this.props
|
||||||
|
const operator = getDeep<string>(rule, 'values.operator', '')
|
||||||
|
|
||||||
|
if (operator === 'inside range' || operator === 'outside range') {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private get firstInputPlaceholder() {
|
||||||
|
if (this.isSecondInputRequired) {
|
||||||
|
return 'lower'
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private get secondInput() {
|
||||||
|
const {rule, onRuleTypeInputChange} = this.props
|
||||||
|
|
||||||
|
const rangeValue = getDeep<string>(rule, 'values.rangeValue', '')
|
||||||
|
|
||||||
|
if (this.isSecondInputRequired) {
|
||||||
|
return (
|
||||||
|
<input
|
||||||
|
className="form-control input-sm form-malachite monotype"
|
||||||
|
name="upper"
|
||||||
|
style={{width: '160px'}}
|
||||||
|
placeholder="Upper"
|
||||||
|
type="text"
|
||||||
|
spellCheck={false}
|
||||||
|
value={rangeValue}
|
||||||
|
onChange={onRuleTypeInputChange}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private noopSubmit = (e: FormEvent<HTMLElement>) => e.preventDefault()
|
||||||
|
|
||||||
|
private getField = ({fields}: QueryConfig): string => {
|
||||||
|
const alias = getDeep<string>(fields, '0.alias', '')
|
||||||
|
|
||||||
|
if (!alias) {
|
||||||
|
return getDeep<string>(fields, '0.value', 'Select a Time-Series')
|
||||||
|
}
|
||||||
|
|
||||||
|
return alias
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Threshold
|
|
@ -1,89 +0,0 @@
|
||||||
import React from 'react'
|
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
|
|
||||||
import TickscriptHeader from 'src/kapacitor/components/TickscriptHeader'
|
|
||||||
import TickscriptEditor from 'src/kapacitor/components/TickscriptEditor'
|
|
||||||
import TickscriptEditorControls from 'src/kapacitor/components/TickscriptEditorControls'
|
|
||||||
import TickscriptEditorConsole from 'src/kapacitor/components/TickscriptEditorConsole'
|
|
||||||
import LogsTable from 'src/kapacitor/components/LogsTable'
|
|
||||||
|
|
||||||
const Tickscript = ({
|
|
||||||
onSave,
|
|
||||||
onExit,
|
|
||||||
task,
|
|
||||||
logs,
|
|
||||||
consoleMessage,
|
|
||||||
onSelectDbrps,
|
|
||||||
onChangeScript,
|
|
||||||
onChangeType,
|
|
||||||
onChangeID,
|
|
||||||
unsavedChanges,
|
|
||||||
isNewTickscript,
|
|
||||||
areLogsVisible,
|
|
||||||
areLogsEnabled,
|
|
||||||
onToggleLogsVisibility,
|
|
||||||
}) => (
|
|
||||||
<div className="page">
|
|
||||||
<TickscriptHeader
|
|
||||||
task={task}
|
|
||||||
onSave={onSave}
|
|
||||||
onExit={onExit}
|
|
||||||
unsavedChanges={unsavedChanges}
|
|
||||||
areLogsVisible={areLogsVisible}
|
|
||||||
areLogsEnabled={areLogsEnabled}
|
|
||||||
onToggleLogsVisibility={onToggleLogsVisibility}
|
|
||||||
isNewTickscript={isNewTickscript}
|
|
||||||
/>
|
|
||||||
<div className="page-contents--split">
|
|
||||||
<div
|
|
||||||
className="tickscript"
|
|
||||||
style={areLogsVisible ? {maxWidth: '50%'} : null}
|
|
||||||
>
|
|
||||||
<TickscriptEditorControls
|
|
||||||
isNewTickscript={isNewTickscript}
|
|
||||||
onSelectDbrps={onSelectDbrps}
|
|
||||||
onChangeType={onChangeType}
|
|
||||||
onChangeID={onChangeID}
|
|
||||||
task={task}
|
|
||||||
/>
|
|
||||||
<TickscriptEditor
|
|
||||||
script={task.tickscript}
|
|
||||||
onChangeScript={onChangeScript}
|
|
||||||
/>
|
|
||||||
<TickscriptEditorConsole
|
|
||||||
consoleMessage={consoleMessage}
|
|
||||||
unsavedChanges={unsavedChanges}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
{areLogsVisible ? <LogsTable logs={logs} /> : null}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
|
|
||||||
const {arrayOf, bool, func, shape, string} = PropTypes
|
|
||||||
|
|
||||||
Tickscript.propTypes = {
|
|
||||||
logs: arrayOf(shape()).isRequired,
|
|
||||||
onSave: func.isRequired,
|
|
||||||
onExit: func.isRequired,
|
|
||||||
source: shape({
|
|
||||||
id: string,
|
|
||||||
}),
|
|
||||||
areLogsVisible: bool,
|
|
||||||
areLogsEnabled: bool,
|
|
||||||
onToggleLogsVisibility: func.isRequired,
|
|
||||||
task: shape({
|
|
||||||
id: string,
|
|
||||||
script: string,
|
|
||||||
dbsrps: arrayOf(shape()),
|
|
||||||
}).isRequired,
|
|
||||||
onChangeScript: func.isRequired,
|
|
||||||
onSelectDbrps: func.isRequired,
|
|
||||||
consoleMessage: string,
|
|
||||||
onChangeType: func.isRequired,
|
|
||||||
onChangeID: func.isRequired,
|
|
||||||
isNewTickscript: bool.isRequired,
|
|
||||||
unsavedChanges: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Tickscript
|
|
|
@ -0,0 +1,101 @@
|
||||||
|
import React, {PureComponent, MouseEvent, ChangeEvent} from 'react'
|
||||||
|
|
||||||
|
import TickscriptHeader from 'src/kapacitor/components/TickscriptHeader'
|
||||||
|
import TickscriptEditor from 'src/kapacitor/components/TickscriptEditor'
|
||||||
|
import TickscriptEditorControls from 'src/kapacitor/components/TickscriptEditorControls'
|
||||||
|
import TickscriptEditorConsole from 'src/kapacitor/components/TickscriptEditorConsole'
|
||||||
|
import LogsTable from 'src/kapacitor/components/LogsTable'
|
||||||
|
|
||||||
|
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||||
|
|
||||||
|
import {Task} from 'src/types'
|
||||||
|
import {LogItem, DBRP} from 'src/types/kapacitor'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
logs: LogItem[]
|
||||||
|
onSave: () => void
|
||||||
|
onExit: () => void
|
||||||
|
areLogsVisible: boolean
|
||||||
|
areLogsEnabled: boolean
|
||||||
|
onToggleLogsVisibility: () => void
|
||||||
|
task: Task
|
||||||
|
onChangeScript: (tickscript: string) => void
|
||||||
|
onSelectDbrps: (dbrps: DBRP[]) => void
|
||||||
|
consoleMessage: string
|
||||||
|
onChangeType: (type: string) => (event: MouseEvent<HTMLLIElement>) => void
|
||||||
|
onChangeID: (e: ChangeEvent<HTMLInputElement>) => void
|
||||||
|
isNewTickscript: boolean
|
||||||
|
unsavedChanges: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
@ErrorHandling
|
||||||
|
class Tickscript extends PureComponent<Props> {
|
||||||
|
public render() {
|
||||||
|
const {
|
||||||
|
onSave,
|
||||||
|
onExit,
|
||||||
|
task,
|
||||||
|
consoleMessage,
|
||||||
|
onSelectDbrps,
|
||||||
|
onChangeScript,
|
||||||
|
onChangeType,
|
||||||
|
onChangeID,
|
||||||
|
unsavedChanges,
|
||||||
|
isNewTickscript,
|
||||||
|
areLogsVisible,
|
||||||
|
areLogsEnabled,
|
||||||
|
onToggleLogsVisibility,
|
||||||
|
} = this.props
|
||||||
|
return (
|
||||||
|
<div className="page">
|
||||||
|
<TickscriptHeader
|
||||||
|
task={task}
|
||||||
|
onSave={onSave}
|
||||||
|
onExit={onExit}
|
||||||
|
unsavedChanges={unsavedChanges}
|
||||||
|
areLogsVisible={areLogsVisible}
|
||||||
|
areLogsEnabled={areLogsEnabled}
|
||||||
|
onToggleLogsVisibility={onToggleLogsVisibility}
|
||||||
|
isNewTickscript={isNewTickscript}
|
||||||
|
/>
|
||||||
|
<div className="page-contents--split">
|
||||||
|
<div className="tickscript" style={this.style}>
|
||||||
|
<TickscriptEditorControls
|
||||||
|
isNewTickscript={isNewTickscript}
|
||||||
|
onSelectDbrps={onSelectDbrps}
|
||||||
|
onChangeType={onChangeType}
|
||||||
|
onChangeID={onChangeID}
|
||||||
|
task={task}
|
||||||
|
/>
|
||||||
|
<TickscriptEditor
|
||||||
|
script={task.tickscript}
|
||||||
|
onChangeScript={onChangeScript}
|
||||||
|
/>
|
||||||
|
<TickscriptEditorConsole
|
||||||
|
consoleMessage={consoleMessage}
|
||||||
|
unsavedChanges={unsavedChanges}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{this.logsTable}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private get style() {
|
||||||
|
const {areLogsVisible} = this.props
|
||||||
|
if (areLogsVisible) {
|
||||||
|
return {maxWidth: '50%'}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private get logsTable() {
|
||||||
|
const {areLogsVisible, logs} = this.props
|
||||||
|
|
||||||
|
if (areLogsVisible) {
|
||||||
|
return <LogsTable logs={logs} />
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Tickscript
|
|
@ -1,20 +1,24 @@
|
||||||
import React, {Component} from 'react'
|
import React, {Component} from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import {Controlled as CodeMirror} from 'react-codemirror2'
|
import {Controlled as CodeMirror} from 'react-codemirror2'
|
||||||
import 'src/external/codemirror'
|
import 'src/external/codemirror'
|
||||||
|
|
||||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
onChangeScript: (tickscript: string) => void
|
||||||
|
script: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const NOOP = () => {}
|
||||||
|
|
||||||
@ErrorHandling
|
@ErrorHandling
|
||||||
class TickscriptEditor extends Component {
|
class TickscriptEditor extends Component<Props> {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props)
|
super(props)
|
||||||
}
|
}
|
||||||
|
|
||||||
updateCode = (_, __, script) => {
|
public render() {
|
||||||
this.props.onChangeScript(script)
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {script} = this.props
|
const {script} = this.props
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
|
@ -31,17 +35,15 @@ class TickscriptEditor extends Component {
|
||||||
value={script}
|
value={script}
|
||||||
onBeforeChange={this.updateCode}
|
onBeforeChange={this.updateCode}
|
||||||
options={options}
|
options={options}
|
||||||
|
onTouchStart={NOOP}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const {func, string} = PropTypes
|
private updateCode = (_, __, script) => {
|
||||||
|
this.props.onChangeScript(script)
|
||||||
TickscriptEditor.propTypes = {
|
}
|
||||||
onChangeScript: func,
|
|
||||||
script: string,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default TickscriptEditor
|
export default TickscriptEditor
|
|
@ -1,7 +1,14 @@
|
||||||
import React from 'react'
|
import React, {SFC} from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
|
|
||||||
const TickscriptEditorConsole = ({consoleMessage, unsavedChanges}) => {
|
interface Props {
|
||||||
|
consoleMessage: string
|
||||||
|
unsavedChanges: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const TickscriptEditorConsole: SFC<Props> = ({
|
||||||
|
consoleMessage,
|
||||||
|
unsavedChanges,
|
||||||
|
}) => {
|
||||||
let consoleOutput = 'TICKscript is valid'
|
let consoleOutput = 'TICKscript is valid'
|
||||||
let consoleClass = 'tickscript-console--valid'
|
let consoleClass = 'tickscript-console--valid'
|
||||||
|
|
||||||
|
@ -20,11 +27,4 @@ const TickscriptEditorConsole = ({consoleMessage, unsavedChanges}) => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const {bool, string} = PropTypes
|
|
||||||
|
|
||||||
TickscriptEditorConsole.propTypes = {
|
|
||||||
consoleMessage: string,
|
|
||||||
unsavedChanges: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
export default TickscriptEditorConsole
|
export default TickscriptEditorConsole
|
|
@ -1,48 +0,0 @@
|
||||||
import React from 'react'
|
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import TickscriptType from 'src/kapacitor/components/TickscriptType'
|
|
||||||
import MultiSelectDBDropdown from 'shared/components/MultiSelectDBDropdown'
|
|
||||||
import TickscriptID, {
|
|
||||||
TickscriptStaticID,
|
|
||||||
} from 'src/kapacitor/components/TickscriptID'
|
|
||||||
|
|
||||||
const addName = list => list.map(l => ({...l, name: `${l.db}.${l.rp}`}))
|
|
||||||
|
|
||||||
const TickscriptEditorControls = ({
|
|
||||||
isNewTickscript,
|
|
||||||
onSelectDbrps,
|
|
||||||
onChangeType,
|
|
||||||
onChangeID,
|
|
||||||
task,
|
|
||||||
}) => (
|
|
||||||
<div className="tickscript-controls">
|
|
||||||
{isNewTickscript ? (
|
|
||||||
<TickscriptID onChangeID={onChangeID} id={task.id} />
|
|
||||||
) : (
|
|
||||||
<TickscriptStaticID id={task.name ? task.name : task.id} />
|
|
||||||
)}
|
|
||||||
<div className="tickscript-controls--right">
|
|
||||||
<TickscriptType type={task.type} onChangeType={onChangeType} />
|
|
||||||
<MultiSelectDBDropdown
|
|
||||||
selectedItems={addName(task.dbrps)}
|
|
||||||
onApply={onSelectDbrps}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
|
|
||||||
const {arrayOf, bool, func, shape, string} = PropTypes
|
|
||||||
|
|
||||||
TickscriptEditorControls.propTypes = {
|
|
||||||
isNewTickscript: bool.isRequired,
|
|
||||||
onSelectDbrps: func.isRequired,
|
|
||||||
onChangeType: func.isRequired,
|
|
||||||
onChangeID: func.isRequired,
|
|
||||||
task: shape({
|
|
||||||
id: string,
|
|
||||||
script: string,
|
|
||||||
dbsrps: arrayOf(shape()),
|
|
||||||
}).isRequired,
|
|
||||||
}
|
|
||||||
|
|
||||||
export default TickscriptEditorControls
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
import React, {Component, MouseEvent, ChangeEvent} from 'react'
|
||||||
|
|
||||||
|
import TickscriptType from 'src/kapacitor/components/TickscriptType'
|
||||||
|
import MultiSelectDBDropdown from 'src/shared/components/MultiSelectDBDropdown'
|
||||||
|
import TickscriptID, {
|
||||||
|
TickscriptStaticID,
|
||||||
|
} from 'src/kapacitor/components/TickscriptID'
|
||||||
|
|
||||||
|
import {Task} from 'src/types'
|
||||||
|
import {DBRP} from 'src/types/kapacitor'
|
||||||
|
|
||||||
|
interface DBRPDropdownItem extends DBRP {
|
||||||
|
name: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
isNewTickscript: boolean
|
||||||
|
onSelectDbrps: (dbrps: DBRP[]) => void
|
||||||
|
onChangeType: (type: string) => (event: MouseEvent<HTMLLIElement>) => void
|
||||||
|
onChangeID: (e: ChangeEvent<HTMLInputElement>) => void
|
||||||
|
task: Task
|
||||||
|
}
|
||||||
|
|
||||||
|
class TickscriptEditorControls extends Component<Props> {
|
||||||
|
public render() {
|
||||||
|
const {onSelectDbrps, onChangeType, task} = this.props
|
||||||
|
return (
|
||||||
|
<div className="tickscript-controls">
|
||||||
|
{this.tickscriptID}
|
||||||
|
<div className="tickscript-controls--right">
|
||||||
|
<TickscriptType type={task.type} onChangeType={onChangeType} />
|
||||||
|
<MultiSelectDBDropdown
|
||||||
|
selectedItems={this.addName(task.dbrps)}
|
||||||
|
onApply={onSelectDbrps}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private get tickscriptID() {
|
||||||
|
const {isNewTickscript, onChangeID, task} = this.props
|
||||||
|
|
||||||
|
if (isNewTickscript) {
|
||||||
|
return <TickscriptID onChangeID={onChangeID} id={task.id} />
|
||||||
|
}
|
||||||
|
|
||||||
|
return <TickscriptStaticID id={this.taskID} />
|
||||||
|
}
|
||||||
|
|
||||||
|
private get taskID() {
|
||||||
|
const {
|
||||||
|
task: {name, id},
|
||||||
|
} = this.props
|
||||||
|
if (name) {
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
|
||||||
|
private addName = (list: DBRP[]): DBRPDropdownItem[] => {
|
||||||
|
const listWithName = list.map(l => ({...l, name: `${l.db}.${l.rp}`}))
|
||||||
|
return listWithName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TickscriptEditorControls
|
|
@ -1,14 +1,18 @@
|
||||||
import React, {Component} from 'react'
|
import React, {Component, SFC, ChangeEvent} from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||||
|
|
||||||
|
interface TickscriptIDProps {
|
||||||
|
onChangeID: (e: ChangeEvent<HTMLInputElement>) => void
|
||||||
|
id: string
|
||||||
|
}
|
||||||
|
|
||||||
@ErrorHandling
|
@ErrorHandling
|
||||||
class TickscriptID extends Component {
|
class TickscriptID extends Component<TickscriptIDProps> {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props)
|
super(props)
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
public render() {
|
||||||
const {onChangeID, id} = this.props
|
const {onChangeID, id} = this.props
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -25,19 +29,11 @@ class TickscriptID extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TickscriptStaticID = ({id}) => (
|
interface TickscriptStaticIDProps {
|
||||||
|
id: string
|
||||||
|
}
|
||||||
|
export const TickscriptStaticID: SFC<TickscriptStaticIDProps> = ({id}) => (
|
||||||
<h1 className="tickscript-controls--name">{id}</h1>
|
<h1 className="tickscript-controls--name">{id}</h1>
|
||||||
)
|
)
|
||||||
|
|
||||||
const {func, string} = PropTypes
|
|
||||||
|
|
||||||
TickscriptID.propTypes = {
|
|
||||||
onChangeID: func.isRequired,
|
|
||||||
id: string.isRequired,
|
|
||||||
}
|
|
||||||
|
|
||||||
TickscriptStaticID.propTypes = {
|
|
||||||
id: string.isRequired,
|
|
||||||
}
|
|
||||||
|
|
||||||
export default TickscriptID
|
export default TickscriptID
|
|
@ -1,30 +0,0 @@
|
||||||
import React from 'react'
|
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
const STREAM = 'stream'
|
|
||||||
const BATCH = 'batch'
|
|
||||||
|
|
||||||
const TickscriptType = ({type, onChangeType}) => (
|
|
||||||
<ul className="nav nav-tablist nav-tablist-sm">
|
|
||||||
<li
|
|
||||||
className={type === STREAM ? 'active' : ''}
|
|
||||||
onClick={onChangeType(STREAM)}
|
|
||||||
>
|
|
||||||
Stream
|
|
||||||
</li>
|
|
||||||
<li
|
|
||||||
className={type === BATCH ? 'active' : ''}
|
|
||||||
onClick={onChangeType(BATCH)}
|
|
||||||
>
|
|
||||||
Batch
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
)
|
|
||||||
|
|
||||||
const {string, func} = PropTypes
|
|
||||||
|
|
||||||
TickscriptType.propTypes = {
|
|
||||||
type: string,
|
|
||||||
onChangeType: func,
|
|
||||||
}
|
|
||||||
|
|
||||||
export default TickscriptType
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
import React, {PureComponent, MouseEvent} from 'react'
|
||||||
|
|
||||||
|
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
type: string
|
||||||
|
onChangeType: (type: string) => (event: MouseEvent<HTMLLIElement>) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const STREAM = 'stream'
|
||||||
|
const BATCH = 'batch'
|
||||||
|
|
||||||
|
@ErrorHandling
|
||||||
|
class TickscriptType extends PureComponent<Props> {
|
||||||
|
public render() {
|
||||||
|
const {onChangeType} = this.props
|
||||||
|
return (
|
||||||
|
<ul className="nav nav-tablist nav-tablist-sm">
|
||||||
|
<li
|
||||||
|
className={this.getClassName(STREAM)}
|
||||||
|
onClick={onChangeType(STREAM)}
|
||||||
|
>
|
||||||
|
Stream
|
||||||
|
</li>
|
||||||
|
<li className={this.getClassName(BATCH)} onClick={onChangeType(BATCH)}>
|
||||||
|
Batch
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private getClassName(type: string) {
|
||||||
|
if (type === this.props.type) {
|
||||||
|
return 'active'
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TickscriptType
|
|
@ -1,6 +1,4 @@
|
||||||
import React from 'react'
|
import React, {SFC, ChangeEvent} from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
|
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
|
|
||||||
import Deadman from 'src/kapacitor/components/Deadman'
|
import Deadman from 'src/kapacitor/components/Deadman'
|
||||||
|
@ -9,7 +7,16 @@ import Relative from 'src/kapacitor/components/Relative'
|
||||||
import DataSection from 'src/kapacitor/components/DataSection'
|
import DataSection from 'src/kapacitor/components/DataSection'
|
||||||
import RuleGraph from 'src/kapacitor/components/RuleGraph'
|
import RuleGraph from 'src/kapacitor/components/RuleGraph'
|
||||||
|
|
||||||
import {Tab, TabList, TabPanels, TabPanel, Tabs} from 'shared/components/Tabs'
|
import {
|
||||||
|
Tab,
|
||||||
|
TabList,
|
||||||
|
TabPanels,
|
||||||
|
TabPanel,
|
||||||
|
Tabs,
|
||||||
|
} from 'src/shared/components/Tabs'
|
||||||
|
|
||||||
|
import {AlertRule, QueryConfig, Source, TimeRange} from 'src/types'
|
||||||
|
import {KapacitorQueryConfigActions} from 'src/types/actions'
|
||||||
|
|
||||||
const TABS = ['Threshold', 'Relative', 'Deadman']
|
const TABS = ['Threshold', 'Relative', 'Deadman']
|
||||||
|
|
||||||
|
@ -22,13 +29,36 @@ const handleChooseTrigger = (rule, onChooseTrigger) => triggerIndex => {
|
||||||
const initialIndex = rule => TABS.indexOf(_.startCase(rule.trigger))
|
const initialIndex = rule => TABS.indexOf(_.startCase(rule.trigger))
|
||||||
const isDeadman = rule => rule.trigger === 'deadman'
|
const isDeadman = rule => rule.trigger === 'deadman'
|
||||||
|
|
||||||
const ValuesSection = ({
|
interface Item {
|
||||||
|
text: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TypeItem extends Item {
|
||||||
|
type: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
rule: AlertRule
|
||||||
|
onChooseTrigger: () => void
|
||||||
|
onUpdateValues: () => void
|
||||||
|
query: QueryConfig
|
||||||
|
onDeadmanChange: (item: Item) => void
|
||||||
|
onRuleTypeDropdownChange: (item: TypeItem) => void
|
||||||
|
onRuleTypeInputChange: (e: ChangeEvent<HTMLInputElement>) => void
|
||||||
|
onAddEvery: (frequency: string) => void
|
||||||
|
onRemoveEvery: () => void
|
||||||
|
timeRange: TimeRange
|
||||||
|
queryConfigActions: KapacitorQueryConfigActions
|
||||||
|
source: Source
|
||||||
|
onChooseTimeRange: (timeRange: TimeRange) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const ValuesSection: SFC<Props> = ({
|
||||||
rule,
|
rule,
|
||||||
query,
|
query,
|
||||||
source,
|
source,
|
||||||
timeRange,
|
timeRange,
|
||||||
onAddEvery,
|
onAddEvery,
|
||||||
onRemoveEvery,
|
|
||||||
onChooseTrigger,
|
onChooseTrigger,
|
||||||
onDeadmanChange,
|
onDeadmanChange,
|
||||||
onChooseTimeRange,
|
onChooseTimeRange,
|
||||||
|
@ -58,7 +88,6 @@ const ValuesSection = ({
|
||||||
isKapacitorRule={true}
|
isKapacitorRule={true}
|
||||||
actions={queryConfigActions}
|
actions={queryConfigActions}
|
||||||
onAddEvery={onAddEvery}
|
onAddEvery={onAddEvery}
|
||||||
onRemoveEvery={onRemoveEvery}
|
|
||||||
isDeadman={isDeadman(rule)}
|
isDeadman={isDeadman(rule)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -97,24 +126,4 @@ const ValuesSection = ({
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
const {shape, string, func} = PropTypes
|
|
||||||
|
|
||||||
ValuesSection.propTypes = {
|
|
||||||
rule: shape({
|
|
||||||
id: string,
|
|
||||||
}).isRequired,
|
|
||||||
onChooseTrigger: func.isRequired,
|
|
||||||
onUpdateValues: func.isRequired,
|
|
||||||
query: shape({}).isRequired,
|
|
||||||
onDeadmanChange: func.isRequired,
|
|
||||||
onRuleTypeDropdownChange: func.isRequired,
|
|
||||||
onRuleTypeInputChange: func.isRequired,
|
|
||||||
onAddEvery: func.isRequired,
|
|
||||||
onRemoveEvery: func.isRequired,
|
|
||||||
timeRange: shape({}).isRequired,
|
|
||||||
queryConfigActions: shape({}).isRequired,
|
|
||||||
source: shape({}).isRequired,
|
|
||||||
onChooseTimeRange: func.isRequired,
|
|
||||||
}
|
|
||||||
|
|
||||||
export default ValuesSection
|
export default ValuesSection
|
|
@ -1,26 +1,59 @@
|
||||||
import React, {Component} from 'react'
|
import React, {Component} from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import _ from 'lodash'
|
||||||
|
import {InjectedRouter} from 'react-router'
|
||||||
import {connect} from 'react-redux'
|
import {connect} from 'react-redux'
|
||||||
|
|
||||||
import * as kapacitorRuleActionCreators from 'src/kapacitor/actions/view'
|
import * as kapacitorRuleActionCreators from 'src/kapacitor/actions/view'
|
||||||
import * as kapacitorQueryConfigActionCreators from 'src/kapacitor/actions/queryConfigs'
|
import * as kapacitorQueryConfigActionCreators from 'src/kapacitor/actions/queryConfigs'
|
||||||
|
|
||||||
import {bindActionCreators} from 'redux'
|
import {bindActionCreators} from 'redux'
|
||||||
import {getActiveKapacitor, getKapacitorConfig} from 'shared/apis/index'
|
import {getActiveKapacitor, getKapacitorConfig} from 'src/shared/apis/index'
|
||||||
import {DEFAULT_RULE_ID} from 'src/kapacitor/constants'
|
import {DEFAULT_RULE_ID} from 'src/kapacitor/constants'
|
||||||
import KapacitorRule from 'src/kapacitor/components/KapacitorRule'
|
import KapacitorRule from 'src/kapacitor/components/KapacitorRule'
|
||||||
import parseHandlersFromConfig from 'src/shared/parsing/parseHandlersFromConfig'
|
import parseHandlersFromConfig from 'src/shared/parsing/parseHandlersFromConfig'
|
||||||
import {notify as notifyAction} from 'shared/actions/notifications'
|
import {notify as notifyAction} from 'src/shared/actions/notifications'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
notifyKapacitorCreateFailed,
|
notifyKapacitorCreateFailed,
|
||||||
notifyCouldNotFindKapacitor,
|
notifyCouldNotFindKapacitor,
|
||||||
} from 'shared/copy/notifications'
|
} from 'src/shared/copy/notifications'
|
||||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||||
|
|
||||||
|
import {
|
||||||
|
Source,
|
||||||
|
Notification,
|
||||||
|
AlertRule,
|
||||||
|
QueryConfig,
|
||||||
|
Kapacitor,
|
||||||
|
} from 'src/types'
|
||||||
|
import {
|
||||||
|
KapacitorQueryConfigActions,
|
||||||
|
KapacitorRuleActions,
|
||||||
|
} from 'src/types/actions'
|
||||||
|
|
||||||
|
interface Params {
|
||||||
|
ruleID: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
source: Source
|
||||||
|
notify: (notification: Notification) => void
|
||||||
|
rules: AlertRule[]
|
||||||
|
queryConfigs: QueryConfig[]
|
||||||
|
ruleActions: KapacitorRuleActions
|
||||||
|
queryConfigActions: KapacitorQueryConfigActions
|
||||||
|
params: Params
|
||||||
|
router: InjectedRouter
|
||||||
|
}
|
||||||
|
|
||||||
|
interface State {
|
||||||
|
handlersFromConfig: any[]
|
||||||
|
kapacitor: Kapacitor | {}
|
||||||
|
}
|
||||||
|
|
||||||
@ErrorHandling
|
@ErrorHandling
|
||||||
class KapacitorRulePage extends Component {
|
class KapacitorRulePage extends Component<Props, State> {
|
||||||
constructor(props) {
|
constructor(props: Props) {
|
||||||
super(props)
|
super(props)
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
|
@ -29,7 +62,7 @@ class KapacitorRulePage extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async componentDidMount() {
|
public async componentDidMount() {
|
||||||
const {params, source, ruleActions, notify} = this.props
|
const {params, source, ruleActions, notify} = this.props
|
||||||
|
|
||||||
if (params.ruleID === 'new') {
|
if (params.ruleID === 'new') {
|
||||||
|
@ -54,9 +87,8 @@ class KapacitorRulePage extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
public render() {
|
||||||
const {
|
const {
|
||||||
rules,
|
|
||||||
params,
|
params,
|
||||||
source,
|
source,
|
||||||
router,
|
router,
|
||||||
|
@ -65,8 +97,7 @@ class KapacitorRulePage extends Component {
|
||||||
queryConfigActions,
|
queryConfigActions,
|
||||||
} = this.props
|
} = this.props
|
||||||
const {handlersFromConfig, kapacitor} = this.state
|
const {handlersFromConfig, kapacitor} = this.state
|
||||||
const rule =
|
const rule = this.rule
|
||||||
params.ruleID === 'new' ? rules[DEFAULT_RULE_ID] : rules[params.ruleID]
|
|
||||||
const query = rule && queryConfigs[rule.queryID]
|
const query = rule && queryConfigs[rule.queryID]
|
||||||
|
|
||||||
if (!query) {
|
if (!query) {
|
||||||
|
@ -84,41 +115,26 @@ class KapacitorRulePage extends Component {
|
||||||
ruleID={params.ruleID}
|
ruleID={params.ruleID}
|
||||||
router={router}
|
router={router}
|
||||||
kapacitor={kapacitor}
|
kapacitor={kapacitor}
|
||||||
configLink={`/sources/${source.id}/kapacitors/${kapacitor.id}/edit`}
|
configLink={`/sources/${source.id}/kapacitors/${this.kapacitorID}/edit`}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const {func, shape, string} = PropTypes
|
private get kapacitorID(): string {
|
||||||
|
const {kapacitor} = this.state
|
||||||
|
return _.get(kapacitor, 'id')
|
||||||
|
}
|
||||||
|
|
||||||
KapacitorRulePage.propTypes = {
|
private get rule(): AlertRule {
|
||||||
source: shape({
|
const {params, rules} = this.props
|
||||||
links: shape({
|
const ruleID = _.get(params, 'ruleID')
|
||||||
proxy: string.isRequired,
|
|
||||||
self: string.isRequired,
|
if (ruleID === 'new') {
|
||||||
}),
|
return rules[DEFAULT_RULE_ID]
|
||||||
}),
|
}
|
||||||
notify: func,
|
|
||||||
rules: shape({}).isRequired,
|
return rules[params.ruleID]
|
||||||
queryConfigs: shape({}).isRequired,
|
}
|
||||||
ruleActions: shape({
|
|
||||||
loadDefaultRule: func.isRequired,
|
|
||||||
fetchRule: func.isRequired,
|
|
||||||
chooseTrigger: func.isRequired,
|
|
||||||
addEvery: func.isRequired,
|
|
||||||
removeEvery: func.isRequired,
|
|
||||||
updateRuleValues: func.isRequired,
|
|
||||||
updateMessage: func.isRequired,
|
|
||||||
updateRuleName: func.isRequired,
|
|
||||||
}).isRequired,
|
|
||||||
queryConfigActions: shape({}).isRequired,
|
|
||||||
params: shape({
|
|
||||||
ruleID: string,
|
|
||||||
}).isRequired,
|
|
||||||
router: shape({
|
|
||||||
push: func.isRequired,
|
|
||||||
}).isRequired,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToProps = ({rules, kapacitorQueryConfigs: queryConfigs}) => ({
|
const mapStateToProps = ({rules, kapacitorQueryConfigs: queryConfigs}) => ({
|
|
@ -1,4 +1,4 @@
|
||||||
import React, {PureComponent} from 'react'
|
import React, {PureComponent, ChangeEvent} from 'react'
|
||||||
import {connect} from 'react-redux'
|
import {connect} from 'react-redux'
|
||||||
import {bindActionCreators} from 'redux'
|
import {bindActionCreators} from 'redux'
|
||||||
import uuid from 'uuid'
|
import uuid from 'uuid'
|
||||||
|
@ -18,7 +18,7 @@ import {
|
||||||
Notification,
|
Notification,
|
||||||
NotificationFunc,
|
NotificationFunc,
|
||||||
} from 'src/types'
|
} from 'src/types'
|
||||||
|
import {LogItem, DBRP} from 'src/types/kapacitor'
|
||||||
import {
|
import {
|
||||||
notifyTickscriptLoggingUnavailable,
|
notifyTickscriptLoggingUnavailable,
|
||||||
notifyTickscriptLoggingError,
|
notifyTickscriptLoggingError,
|
||||||
|
@ -76,7 +76,7 @@ interface State {
|
||||||
task: Task
|
task: Task
|
||||||
consoleMessage: string
|
consoleMessage: string
|
||||||
isEditingID: boolean
|
isEditingID: boolean
|
||||||
logs: object[]
|
logs: LogItem[]
|
||||||
areLogsVisible: boolean
|
areLogsVisible: boolean
|
||||||
areLogsEnabled: boolean
|
areLogsEnabled: boolean
|
||||||
failStr: string
|
failStr: string
|
||||||
|
@ -247,22 +247,22 @@ export class TickscriptPage extends PureComponent<Props, State> {
|
||||||
return router.push(`/sources/${sourceID}/alert-rules`)
|
return router.push(`/sources/${sourceID}/alert-rules`)
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleChangeScript = tickscript => {
|
private handleChangeScript = (tickscript: string) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
task: {...this.state.task, tickscript},
|
task: {...this.state.task, tickscript},
|
||||||
unsavedChanges: true,
|
unsavedChanges: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleSelectDbrps = dbrps => {
|
private handleSelectDbrps = (dbrps: DBRP[]) => {
|
||||||
this.setState({task: {...this.state.task, dbrps}, unsavedChanges: true})
|
this.setState({task: {...this.state.task, dbrps}, unsavedChanges: true})
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleChangeType = type => () => {
|
private handleChangeType = (type: string) => () => {
|
||||||
this.setState({task: {...this.state.task, type}, unsavedChanges: true})
|
this.setState({task: {...this.state.task, type}, unsavedChanges: true})
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleChangeID = e => {
|
private handleChangeID = (e: ChangeEvent<HTMLInputElement>) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
task: {...this.state.task, id: e.target.value},
|
task: {...this.state.task, id: e.target.value},
|
||||||
unsavedChanges: true,
|
unsavedChanges: true,
|
||||||
|
|
|
@ -3,7 +3,7 @@ import {Notification} from 'src/types'
|
||||||
export type Action = ActionPublishNotification | ActionDismissNotification
|
export type Action = ActionPublishNotification | ActionDismissNotification
|
||||||
|
|
||||||
// Publish notification
|
// Publish notification
|
||||||
export type PubishNotification = (n: Notification) => ActionPublishNotification
|
export type PublishNotification = (n: Notification) => ActionPublishNotification
|
||||||
export interface ActionPublishNotification {
|
export interface ActionPublishNotification {
|
||||||
type: 'PUBLISH_NOTIFICATION'
|
type: 'PUBLISH_NOTIFICATION'
|
||||||
payload: {
|
payload: {
|
||||||
|
|
|
@ -1,20 +1,47 @@
|
||||||
import {proxy} from 'src/utils/queryUrlGenerator'
|
import {proxy} from 'src/utils/queryUrlGenerator'
|
||||||
import {noop} from 'src/shared/actions/app'
|
import {noop} from 'src/shared/actions/app'
|
||||||
import _ from 'lodash'
|
|
||||||
|
|
||||||
import {errorThrown} from 'src/shared/actions/errors'
|
import {errorThrown} from 'src/shared/actions/errors'
|
||||||
|
import {TimeSeriesResponse, TimeSeriesSeries} from 'src/types/series'
|
||||||
|
import {Status} from 'src/types'
|
||||||
|
import {getDeep} from 'src/utils/wrappers'
|
||||||
|
|
||||||
export const handleLoading = (query, editQueryStatus) => {
|
interface Query {
|
||||||
|
host: string | string[]
|
||||||
|
text: string
|
||||||
|
id: string
|
||||||
|
database?: string
|
||||||
|
db?: string
|
||||||
|
rp?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Payload {
|
||||||
|
source: string
|
||||||
|
query: Query
|
||||||
|
tempVars: any[]
|
||||||
|
db?: string
|
||||||
|
rp?: string
|
||||||
|
resolution?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
type EditQueryStatusFunction = (queryID: string, status: Status) => void
|
||||||
|
|
||||||
|
const handleLoading = (
|
||||||
|
query: Query,
|
||||||
|
editQueryStatus: EditQueryStatusFunction
|
||||||
|
): void =>
|
||||||
editQueryStatus(query.id, {
|
editQueryStatus(query.id, {
|
||||||
loading: true,
|
loading: true,
|
||||||
})
|
})
|
||||||
}
|
|
||||||
|
|
||||||
// {results: [{}]}
|
const handleSuccess = (
|
||||||
export const handleSuccess = (data, query, editQueryStatus) => {
|
data: TimeSeriesResponse,
|
||||||
|
query: Query,
|
||||||
|
editQueryStatus: EditQueryStatusFunction
|
||||||
|
): TimeSeriesResponse => {
|
||||||
const {results} = data
|
const {results} = data
|
||||||
const error = _.get(results, ['0', 'error'], false)
|
const error = getDeep<string>(results, '0.error', null)
|
||||||
const series = _.get(results, ['0', 'series'], false)
|
const series = getDeep<TimeSeriesSeries>(results, '0.series', null)
|
||||||
// 200 from server and no results = warn
|
// 200 from server and no results = warn
|
||||||
if (!series && !error) {
|
if (!series && !error) {
|
||||||
editQueryStatus(query.id, {
|
editQueryStatus(query.id, {
|
||||||
|
@ -38,12 +65,14 @@ export const handleSuccess = (data, query, editQueryStatus) => {
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
export const handleError = (error, query, editQueryStatus) => {
|
const handleError = (
|
||||||
const message = _.get(
|
error,
|
||||||
error,
|
query: Query,
|
||||||
['data', 'message'],
|
editQueryStatus: EditQueryStatusFunction
|
||||||
error.message || 'Could not retrieve data'
|
): void => {
|
||||||
)
|
const message =
|
||||||
|
getDeep<string>(error, 'data.message', '') ||
|
||||||
|
getDeep<string>(error, 'message', 'Could not retrieve data')
|
||||||
|
|
||||||
// 400 from chrono server = fail
|
// 400 from chrono server = fail
|
||||||
editQueryStatus(query.id, {
|
editQueryStatus(query.id, {
|
||||||
|
@ -51,28 +80,10 @@ export const handleError = (error, query, editQueryStatus) => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Query {
|
|
||||||
host: string | string[]
|
|
||||||
text: string
|
|
||||||
id: string
|
|
||||||
database?: string
|
|
||||||
db?: string
|
|
||||||
rp?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Payload {
|
|
||||||
source: string
|
|
||||||
query: Query
|
|
||||||
tempVars: any[]
|
|
||||||
db?: string
|
|
||||||
rp?: string
|
|
||||||
resolution?: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export const fetchTimeSeriesAsync = async (
|
export const fetchTimeSeriesAsync = async (
|
||||||
{source, db, rp, query, tempVars, resolution}: Payload,
|
{source, db, rp, query, tempVars, resolution}: Payload,
|
||||||
editQueryStatus = noop
|
editQueryStatus: EditQueryStatusFunction = noop
|
||||||
) => {
|
): Promise<TimeSeriesResponse> => {
|
||||||
handleLoading(query, editQueryStatus)
|
handleLoading(query, editQueryStatus)
|
||||||
try {
|
try {
|
||||||
const {data} = await proxy({
|
const {data} = await proxy({
|
||||||
|
|
|
@ -178,8 +178,10 @@ class Dygraph extends Component<Props, State> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public componentWillUnmount() {
|
public componentWillUnmount() {
|
||||||
this.dygraph.destroy()
|
if (this.dygraph) {
|
||||||
delete this.dygraph
|
this.dygraph.destroy()
|
||||||
|
delete this.dygraph
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public shouldComponentUpdate(nextProps: Props, nextState: State) {
|
public shouldComponentUpdate(nextProps: Props, nextState: State) {
|
||||||
|
|
|
@ -48,7 +48,7 @@ interface TabListProps {
|
||||||
activeIndex?: number
|
activeIndex?: number
|
||||||
onActivate?: (index: number) => void
|
onActivate?: (index: number) => void
|
||||||
isKapacitorTabs?: string
|
isKapacitorTabs?: string
|
||||||
customClass: string
|
customClass?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TabList: SFC<TabListProps> = ({
|
export const TabList: SFC<TabListProps> = ({
|
||||||
|
@ -97,7 +97,7 @@ TabList.defaultProps = {
|
||||||
interface TabPanelsProps {
|
interface TabPanelsProps {
|
||||||
children: JSX.Element[] | JSX.Element
|
children: JSX.Element[] | JSX.Element
|
||||||
activeIndex?: number
|
activeIndex?: number
|
||||||
customClass: string
|
customClass?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TabPanels: SFC<TabPanelsProps> = ({
|
export const TabPanels: SFC<TabPanelsProps> = ({
|
||||||
|
@ -120,7 +120,7 @@ export const TabPanel: SFC<TabPanelProps> = ({children}) => (
|
||||||
interface TabsProps {
|
interface TabsProps {
|
||||||
children: JSX.Element[] | JSX.Element
|
children: JSX.Element[] | JSX.Element
|
||||||
onSelect?: (activeIndex: number) => void
|
onSelect?: (activeIndex: number) => void
|
||||||
tabContentsClass: string
|
tabContentsClass?: string
|
||||||
tabsClass?: string
|
tabsClass?: string
|
||||||
initialIndex?: number
|
initialIndex?: number
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,22 +1,29 @@
|
||||||
// All copy for notifications should be stored here for easy editing
|
// All copy for notifications should be stored here for easy editing
|
||||||
// and ensuring stylistic consistency
|
// and ensuring stylistic consistency
|
||||||
|
import {Notification} from 'src/types'
|
||||||
|
import {TemplateUpdate} from 'src/types/tempVars'
|
||||||
|
|
||||||
|
type NotificationExcludingMessage = Pick<
|
||||||
|
Notification,
|
||||||
|
Exclude<keyof Notification, 'message'>
|
||||||
|
>
|
||||||
|
|
||||||
import {FIVE_SECONDS, TEN_SECONDS, INFINITE} from 'src/shared/constants/index'
|
import {FIVE_SECONDS, TEN_SECONDS, INFINITE} from 'src/shared/constants/index'
|
||||||
import {MAX_RESPONSE_BYTES} from 'src/flux/constants'
|
import {MAX_RESPONSE_BYTES} from 'src/flux/constants'
|
||||||
|
|
||||||
const defaultErrorNotification = {
|
const defaultErrorNotification: NotificationExcludingMessage = {
|
||||||
type: 'error',
|
type: 'error',
|
||||||
icon: 'alert-triangle',
|
icon: 'alert-triangle',
|
||||||
duration: TEN_SECONDS,
|
duration: TEN_SECONDS,
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultSuccessNotification = {
|
const defaultSuccessNotification: NotificationExcludingMessage = {
|
||||||
type: 'success',
|
type: 'success',
|
||||||
icon: 'checkmark',
|
icon: 'checkmark',
|
||||||
duration: FIVE_SECONDS,
|
duration: FIVE_SECONDS,
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultDeletionNotification = {
|
const defaultDeletionNotification: NotificationExcludingMessage = {
|
||||||
type: 'primary',
|
type: 'primary',
|
||||||
icon: 'trash',
|
icon: 'trash',
|
||||||
duration: FIVE_SECONDS,
|
duration: FIVE_SECONDS,
|
||||||
|
@ -24,211 +31,240 @@ const defaultDeletionNotification = {
|
||||||
|
|
||||||
// Misc Notifications
|
// Misc Notifications
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
export const notifyGenericFail = () => 'Could not communicate with server.'
|
export const notifyGenericFail = (): string =>
|
||||||
|
'Could not communicate with server.'
|
||||||
|
|
||||||
export const notifyNewVersion = version => ({
|
export const notifyNewVersion = (version: string): Notification => ({
|
||||||
type: 'info',
|
type: 'info',
|
||||||
icon: 'cubo-uniform',
|
icon: 'cubo-uniform',
|
||||||
duration: INFINITE,
|
duration: INFINITE,
|
||||||
message: `Welcome to the latest Chronograf${version}. Local settings cleared.`,
|
message: `Welcome to the latest Chronograf${version}. Local settings cleared.`,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyLoadLocalSettingsFailed = error => ({
|
export const notifyLoadLocalSettingsFailed = (error: string): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
message: `Loading local settings failed: ${error}`,
|
message: `Loading local settings failed: ${error}`,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyErrorWithAltText = (type, message) => ({
|
export const notifyErrorWithAltText = (
|
||||||
|
type: string,
|
||||||
|
message: string
|
||||||
|
): Notification => ({
|
||||||
type,
|
type,
|
||||||
icon: 'triangle',
|
icon: 'triangle',
|
||||||
duration: TEN_SECONDS,
|
duration: TEN_SECONDS,
|
||||||
message,
|
message,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyPresentationMode = () => ({
|
export const notifyPresentationMode = (): Notification => ({
|
||||||
type: 'primary',
|
type: 'primary',
|
||||||
icon: 'expand-b',
|
icon: 'expand-b',
|
||||||
duration: 7500,
|
duration: 7500,
|
||||||
message: 'Press ESC to exit Presentation Mode.',
|
message: 'Press ESC to exit Presentation Mode.',
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyDataWritten = () => ({
|
export const notifyDataWritten = (): Notification => ({
|
||||||
...defaultSuccessNotification,
|
...defaultSuccessNotification,
|
||||||
message: 'Data was written successfully.',
|
message: 'Data was written successfully.',
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyDataWriteFailed = errorMessage => ({
|
export const notifyDataWriteFailed = (errorMessage: string): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
message: `Data write failed: ${errorMessage}`,
|
message: `Data write failed: ${errorMessage}`,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifySessionTimedOut = () => ({
|
export const notifySessionTimedOut = (): Notification => ({
|
||||||
type: 'primary',
|
type: 'primary',
|
||||||
icon: 'triangle',
|
icon: 'triangle',
|
||||||
duration: INFINITE,
|
duration: INFINITE,
|
||||||
message: 'Your session has timed out. Log in again to continue.',
|
message: 'Your session has timed out. Log in again to continue.',
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyServerError = {
|
export const notifyServerError: Notification = {
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
message: 'Internal Server Error. Check API Logs.',
|
message: 'Internal Server Error. Check API Logs.',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const notifyCouldNotRetrieveKapacitors = sourceID => ({
|
export const notifyCouldNotRetrieveKapacitors = (
|
||||||
|
sourceID: string
|
||||||
|
): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
message: `Internal Server Error. Could not retrieve Kapacitor Connections for source ${sourceID}.`,
|
message: `Internal Server Error. Could not retrieve Kapacitor Connections for source ${sourceID}.`,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyCouldNotRetrieveKapacitorServices = kapacitor => ({
|
export const notifyCouldNotRetrieveKapacitorServices = (
|
||||||
|
kapacitor: string
|
||||||
|
): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
message: `Interanl Server Error. Could not retrieve services for Kapacitor ${kapacitor}`,
|
message: `Internal Server Error. Could not retrieve services for Kapacitor ${kapacitor}`,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyCouldNotDeleteKapacitor = () => ({
|
export const notifyCouldNotDeleteKapacitor = (): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
message: 'Internal Server Error. Could not delete Kapacitor Connection.',
|
message: 'Internal Server Error. Could not delete Kapacitor Connection.',
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyCSVDownloadFailed = () => ({
|
export const notifyCSVDownloadFailed = (): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
message: 'Unable to download .CSV file',
|
message: 'Unable to download .CSV file',
|
||||||
})
|
})
|
||||||
|
|
||||||
// Hosts Page Notifications
|
// Hosts Page Notifications
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
export const notifyUnableToGetHosts = () => ({
|
export const notifyUnableToGetHosts = (): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
message: 'Unable to get Hosts.',
|
message: 'Unable to get Hosts.',
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyUnableToGetApps = () => ({
|
export const notifyUnableToGetApps = (): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
message: 'Unable to get Apps for Hosts.',
|
message: 'Unable to get Apps for Hosts.',
|
||||||
})
|
})
|
||||||
|
|
||||||
// InfluxDB Sources Notifications
|
// InfluxDB Sources Notifications
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
export const notifySourceCreationSucceeded = sourceName => ({
|
export const notifySourceCreationSucceeded = (
|
||||||
|
sourceName: string
|
||||||
|
): Notification => ({
|
||||||
...defaultSuccessNotification,
|
...defaultSuccessNotification,
|
||||||
icon: 'server2',
|
icon: 'server2',
|
||||||
message: `Connected to InfluxDB ${sourceName} successfully.`,
|
message: `Connected to InfluxDB ${sourceName} successfully.`,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifySourceCreationFailed = (sourceName, errorMessage) => ({
|
export const notifySourceCreationFailed = (
|
||||||
|
sourceName: string,
|
||||||
|
errorMessage: string
|
||||||
|
): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
icon: 'server2',
|
icon: 'server2',
|
||||||
message: `Unable to connect to InfluxDB ${sourceName}: ${errorMessage}`,
|
message: `Unable to connect to InfluxDB ${sourceName}: ${errorMessage}`,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifySourceUdpated = sourceName => ({
|
export const notifySourceUdpated = (sourceName: string): Notification => ({
|
||||||
...defaultSuccessNotification,
|
...defaultSuccessNotification,
|
||||||
icon: 'server2',
|
icon: 'server2',
|
||||||
message: `Updated InfluxDB ${sourceName} Connection successfully.`,
|
message: `Updated InfluxDB ${sourceName} Connection successfully.`,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifySourceUdpateFailed = (sourceName, errorMessage) => ({
|
export const notifySourceUdpateFailed = (
|
||||||
|
sourceName: string,
|
||||||
|
errorMessage: string
|
||||||
|
): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
icon: 'server2',
|
icon: 'server2',
|
||||||
message: `Failed to update InfluxDB ${sourceName} Connection: ${errorMessage}`,
|
message: `Failed to update InfluxDB ${sourceName} Connection: ${errorMessage}`,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifySourceDeleted = (sourceName: string) => ({
|
export const notifySourceDeleted = (sourceName: string): Notification => ({
|
||||||
...defaultSuccessNotification,
|
...defaultSuccessNotification,
|
||||||
icon: 'server2',
|
icon: 'server2',
|
||||||
message: `${sourceName} deleted successfully.`,
|
message: `${sourceName} deleted successfully.`,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifySourceDeleteFailed = sourceName => ({
|
export const notifySourceDeleteFailed = (sourceName: string): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
icon: 'server2',
|
icon: 'server2',
|
||||||
message: `There was a problem deleting ${sourceName}.`,
|
message: `There was a problem deleting ${sourceName}.`,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifySourceNoLongerAvailable = sourceName =>
|
export const notifySourceNoLongerAvailable = (
|
||||||
`Source ${sourceName} is no longer available. Please ensure InfluxDB is running.`
|
sourceName: string
|
||||||
|
): Notification => ({
|
||||||
export const notifyNoSourcesAvailable = sourceName =>
|
|
||||||
`Unable to connect to source ${sourceName}. No other sources available.`
|
|
||||||
|
|
||||||
export const notifyUnableToRetrieveSources = () => 'Unable to retrieve sources.'
|
|
||||||
|
|
||||||
export const notifyUnableToConnectSource = sourceName =>
|
|
||||||
`Unable to connect to source ${sourceName}.`
|
|
||||||
|
|
||||||
export const notifyErrorConnectingToSource = errorMessage => ({
|
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
|
icon: 'server2',
|
||||||
|
message: `Source ${sourceName} is no longer available. Please ensure InfluxDB is running.`,
|
||||||
|
})
|
||||||
|
|
||||||
|
export const notifyErrorConnectingToSource = (
|
||||||
|
errorMessage: string
|
||||||
|
): Notification => ({
|
||||||
|
...defaultErrorNotification,
|
||||||
|
icon: 'server2',
|
||||||
message: `Unable to connect to InfluxDB source: ${errorMessage}`,
|
message: `Unable to connect to InfluxDB source: ${errorMessage}`,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Multitenancy User Notifications
|
// Multitenancy User Notifications
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
export const notifyUserRemovedFromAllOrgs = () => ({
|
export const notifyUserRemovedFromAllOrgs = (): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
duration: INFINITE,
|
duration: INFINITE,
|
||||||
message:
|
message:
|
||||||
'You have been removed from all organizations. Please contact your administrator.',
|
'You have been removed from all organizations. Please contact your administrator.',
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyUserRemovedFromCurrentOrg = () => ({
|
export const notifyUserRemovedFromCurrentOrg = (): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
duration: INFINITE,
|
duration: INFINITE,
|
||||||
message: 'You were removed from your current organization.',
|
message: 'You were removed from your current organization.',
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyOrgHasNoSources = () => ({
|
export const notifyOrgHasNoSources = (): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
duration: INFINITE,
|
duration: INFINITE,
|
||||||
message: 'Organization has no sources configured.',
|
message: 'Organization has no sources configured.',
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyUserSwitchedOrgs = (orgName, roleName) => ({
|
export const notifyUserSwitchedOrgs = (
|
||||||
|
orgName: string,
|
||||||
|
roleName: string
|
||||||
|
): Notification => ({
|
||||||
...defaultSuccessNotification,
|
...defaultSuccessNotification,
|
||||||
type: 'primary',
|
type: 'primary',
|
||||||
message: `Now logged in to '${orgName}' as '${roleName}'.`,
|
message: `Now logged in to '${orgName}' as '${roleName}'.`,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyOrgIsPrivate = () => ({
|
export const notifyOrgIsPrivate = (): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
duration: INFINITE,
|
duration: INFINITE,
|
||||||
message:
|
message:
|
||||||
'This organization is private. To gain access, you must be explicitly added by an administrator.',
|
'This organization is private. To gain access, you must be explicitly added by an administrator.',
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyCurrentOrgDeleted = () => ({
|
export const notifyCurrentOrgDeleted = (): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
duration: INFINITE,
|
duration: INFINITE,
|
||||||
message: 'Your current organization was deleted.',
|
message: 'Your current organization was deleted.',
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyJSONFeedFailed = url => ({
|
export const notifyJSONFeedFailed = (url: string): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
message: `Failed to fetch JSON Feed for News Feed from '${url}'`,
|
message: `Failed to fetch JSON Feed for News Feed from '${url}'`,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Chronograf Admin Notifications
|
// Chronograf Admin Notifications
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
export const notifyMappingDeleted = (id, scheme) => ({
|
export const notifyMappingDeleted = (
|
||||||
|
id: string,
|
||||||
|
scheme: string
|
||||||
|
): Notification => ({
|
||||||
...defaultSuccessNotification,
|
...defaultSuccessNotification,
|
||||||
message: `Mapping ${id}/${scheme} deleted successfully.`,
|
message: `Mapping ${id}/${scheme} deleted successfully.`,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyChronografUserAddedToOrg = (user, organization) =>
|
export const notifyChronografUserAddedToOrg = (
|
||||||
`${user} has been added to ${organization} successfully.`
|
user: string,
|
||||||
|
organization: string
|
||||||
|
): string => `${user} has been added to ${organization} successfully.`
|
||||||
|
|
||||||
export const notifyChronografUserRemovedFromOrg = (user, organization) =>
|
export const notifyChronografUserRemovedFromOrg = (
|
||||||
`${user} has been removed from ${organization} successfully.`
|
user: string,
|
||||||
|
organization: string
|
||||||
|
): string => `${user} has been removed from ${organization} successfully.`
|
||||||
|
|
||||||
export const notifyChronografUserUpdated = message => ({
|
export const notifyChronografUserUpdated = (message: string): Notification => ({
|
||||||
...defaultSuccessNotification,
|
...defaultSuccessNotification,
|
||||||
message,
|
message,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyChronografOrgDeleted = orgName => ({
|
export const notifyChronografOrgDeleted = (orgName: string): Notification => ({
|
||||||
...defaultSuccessNotification,
|
...defaultSuccessNotification,
|
||||||
message: `Organization ${orgName} deleted successfully.`,
|
message: `Organization ${orgName} deleted successfully.`,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyChronografUserDeleted = (user, isAbsoluteDelete) => ({
|
export const notifyChronografUserDeleted = (
|
||||||
|
user: string,
|
||||||
|
isAbsoluteDelete: boolean
|
||||||
|
): Notification => ({
|
||||||
...defaultSuccessNotification,
|
...defaultSuccessNotification,
|
||||||
message: `${user} has been removed from ${
|
message: `${user} has been removed from ${
|
||||||
isAbsoluteDelete
|
isAbsoluteDelete
|
||||||
|
@ -237,7 +273,7 @@ export const notifyChronografUserDeleted = (user, isAbsoluteDelete) => ({
|
||||||
}`,
|
}`,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyChronografUserMissingNameAndProvider = () => ({
|
export const notifyChronografUserMissingNameAndProvider = (): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
type: 'warning',
|
type: 'warning',
|
||||||
message: 'User must have a Name and Provider.',
|
message: 'User must have a Name and Provider.',
|
||||||
|
@ -245,220 +281,238 @@ export const notifyChronografUserMissingNameAndProvider = () => ({
|
||||||
|
|
||||||
// InfluxDB Admin Notifications
|
// InfluxDB Admin Notifications
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
export const notifyDBUserCreated = () => ({
|
export const notifyDBUserCreated = (): Notification => ({
|
||||||
...defaultSuccessNotification,
|
...defaultSuccessNotification,
|
||||||
message: 'User created successfully.',
|
message: 'User created successfully.',
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyDBUserCreationFailed = errorMessage =>
|
export const notifyDBUserCreationFailed = (errorMessage: string): string =>
|
||||||
`Failed to create User: ${errorMessage}`
|
`Failed to create User: ${errorMessage}`
|
||||||
|
|
||||||
export const notifyDBUserDeleted = userName => ({
|
export const notifyDBUserDeleted = (userName: string): Notification => ({
|
||||||
...defaultSuccessNotification,
|
...defaultSuccessNotification,
|
||||||
message: `User "${userName}" deleted successfully.`,
|
message: `User "${userName}" deleted successfully.`,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyDBUserDeleteFailed = errorMessage =>
|
export const notifyDBUserDeleteFailed = (errorMessage: string): string =>
|
||||||
`Failed to delete User: ${errorMessage}`
|
`Failed to delete User: ${errorMessage}`
|
||||||
|
|
||||||
export const notifyDBUserPermissionsUpdated = () => ({
|
export const notifyDBUserPermissionsUpdated = (): Notification => ({
|
||||||
...defaultSuccessNotification,
|
...defaultSuccessNotification,
|
||||||
message: 'User Permissions updated successfully.',
|
message: 'User Permissions updated successfully.',
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyDBUserPermissionsUpdateFailed = errorMessage =>
|
export const notifyDBUserPermissionsUpdateFailed = (
|
||||||
`Failed to update User Permissions: ${errorMessage}`
|
errorMessage: string
|
||||||
|
): string => `Failed to update User Permissions: ${errorMessage}`
|
||||||
|
|
||||||
export const notifyDBUserRolesUpdated = () => ({
|
export const notifyDBUserRolesUpdated = (): Notification => ({
|
||||||
...defaultSuccessNotification,
|
...defaultSuccessNotification,
|
||||||
message: 'User Roles updated successfully.',
|
message: 'User Roles updated successfully.',
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyDBUserRolesUpdateFailed = errorMessage =>
|
export const notifyDBUserRolesUpdateFailed = (errorMessage: string): string =>
|
||||||
`Failed to update User Roles: ${errorMessage}`
|
`Failed to update User Roles: ${errorMessage}`
|
||||||
|
|
||||||
export const notifyDBUserPasswordUpdated = () => ({
|
export const notifyDBUserPasswordUpdated = (): Notification => ({
|
||||||
...defaultSuccessNotification,
|
...defaultSuccessNotification,
|
||||||
message: 'User Password updated successfully.',
|
message: 'User Password updated successfully.',
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyDBUserPasswordUpdateFailed = errorMessage =>
|
export const notifyDBUserPasswordUpdateFailed = (
|
||||||
`Failed to update User Password: ${errorMessage}`
|
errorMessage: string
|
||||||
|
): string => `Failed to update User Password: ${errorMessage}`
|
||||||
|
|
||||||
export const notifyDatabaseCreated = () => ({
|
export const notifyDatabaseCreated = (): Notification => ({
|
||||||
...defaultSuccessNotification,
|
...defaultSuccessNotification,
|
||||||
message: 'Database created successfully.',
|
message: 'Database created successfully.',
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyDBCreationFailed = errorMessage =>
|
export const notifyDBCreationFailed = (errorMessage: string): string =>
|
||||||
`Failed to create Database: ${errorMessage}`
|
`Failed to create Database: ${errorMessage}`
|
||||||
|
|
||||||
export const notifyDBDeleted = databaseName => ({
|
export const notifyDBDeleted = (databaseName: string): Notification => ({
|
||||||
...defaultSuccessNotification,
|
...defaultSuccessNotification,
|
||||||
message: `Database "${databaseName}" deleted successfully.`,
|
message: `Database "${databaseName}" deleted successfully.`,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyDBDeleteFailed = errorMessage =>
|
export const notifyDBDeleteFailed = (errorMessage: string): string =>
|
||||||
`Failed to delete Database: ${errorMessage}`
|
`Failed to delete Database: ${errorMessage}`
|
||||||
|
|
||||||
export const notifyRoleCreated = () => ({
|
export const notifyRoleCreated = (): Notification => ({
|
||||||
...defaultSuccessNotification,
|
...defaultSuccessNotification,
|
||||||
message: 'Role created successfully.',
|
message: 'Role created successfully.',
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyRoleCreationFailed = errorMessage =>
|
export const notifyRoleCreationFailed = (errorMessage: string): string =>
|
||||||
`Failed to create Role: ${errorMessage}`
|
`Failed to create Role: ${errorMessage}`
|
||||||
|
|
||||||
export const notifyRoleDeleted = roleName => ({
|
export const notifyRoleDeleted = (roleName: string): Notification => ({
|
||||||
...defaultSuccessNotification,
|
...defaultSuccessNotification,
|
||||||
message: `Role "${roleName}" deleted successfully.`,
|
message: `Role "${roleName}" deleted successfully.`,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyRoleDeleteFailed = errorMessage =>
|
export const notifyRoleDeleteFailed = (errorMessage: string): string =>
|
||||||
`Failed to delete Role: ${errorMessage}`
|
`Failed to delete Role: ${errorMessage}`
|
||||||
|
|
||||||
export const notifyRoleUsersUpdated = () => ({
|
export const notifyRoleUsersUpdated = (): Notification => ({
|
||||||
...defaultSuccessNotification,
|
...defaultSuccessNotification,
|
||||||
message: 'Role Users updated successfully.',
|
message: 'Role Users updated successfully.',
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyRoleUsersUpdateFailed = errorMessage =>
|
export const notifyRoleUsersUpdateFailed = (errorMessage: string): string =>
|
||||||
`Failed to update Role Users: ${errorMessage}`
|
`Failed to update Role Users: ${errorMessage}`
|
||||||
|
|
||||||
export const notifyRolePermissionsUpdated = () => ({
|
export const notifyRolePermissionsUpdated = (): Notification => ({
|
||||||
...defaultSuccessNotification,
|
...defaultSuccessNotification,
|
||||||
message: 'Role Permissions updated successfully.',
|
message: 'Role Permissions updated successfully.',
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyRolePermissionsUpdateFailed = errorMessage =>
|
export const notifyRolePermissionsUpdateFailed = (
|
||||||
`Failed to update Role Permissions: ${errorMessage}`
|
errorMessage: string
|
||||||
|
): string => `Failed to update Role Permissions: ${errorMessage}`
|
||||||
|
|
||||||
export const notifyRetentionPolicyCreated = () => ({
|
export const notifyRetentionPolicyCreated = (): Notification => ({
|
||||||
...defaultSuccessNotification,
|
...defaultSuccessNotification,
|
||||||
message: 'Retention Policy created successfully.',
|
message: 'Retention Policy created successfully.',
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyRetentionPolicyCreationError = () => ({
|
export const notifyRetentionPolicyCreationError = (): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
message: 'Failed to create Retention Policy. Please check name and duration.',
|
message: 'Failed to create Retention Policy. Please check name and duration.',
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyRetentionPolicyCreationFailed = errorMessage =>
|
export const notifyRetentionPolicyCreationFailed = (
|
||||||
`Failed to create Retention Policy: ${errorMessage}`
|
errorMessage: string
|
||||||
|
): string => `Failed to create Retention Policy: ${errorMessage}`
|
||||||
|
|
||||||
export const notifyRetentionPolicyDeleted = rpName => ({
|
export const notifyRetentionPolicyDeleted = (rpName: string): Notification => ({
|
||||||
...defaultSuccessNotification,
|
...defaultSuccessNotification,
|
||||||
message: `Retention Policy "${rpName}" deleted successfully.`,
|
message: `Retention Policy "${rpName}" deleted successfully.`,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyRetentionPolicyDeleteFailed = errorMessage =>
|
export const notifyRetentionPolicyDeleteFailed = (
|
||||||
`Failed to delete Retention Policy: ${errorMessage}`
|
errorMessage: string
|
||||||
|
): string => `Failed to delete Retention Policy: ${errorMessage}`
|
||||||
|
|
||||||
export const notifyRetentionPolicyUpdated = () => ({
|
export const notifyRetentionPolicyUpdated = (): Notification => ({
|
||||||
...defaultSuccessNotification,
|
...defaultSuccessNotification,
|
||||||
message: 'Retention Policy updated successfully.',
|
message: 'Retention Policy updated successfully.',
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyRetentionPolicyUpdateFailed = errorMessage =>
|
export const notifyRetentionPolicyUpdateFailed = (
|
||||||
`Failed to update Retention Policy: ${errorMessage}`
|
errorMessage: string
|
||||||
|
): string => `Failed to update Retention Policy: ${errorMessage}`
|
||||||
|
|
||||||
export const notifyQueriesError = errorMessage => ({
|
export const notifyQueriesError = (errorMessage: string): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
errorMessage,
|
message: errorMessage,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyRetentionPolicyCantHaveEmptyFields = () => ({
|
export const notifyRetentionPolicyCantHaveEmptyFields = (): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
message: 'Fields cannot be empty.',
|
message: 'Fields cannot be empty.',
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyDatabaseDeleteConfirmationRequired = databaseName => ({
|
export const notifyDatabaseDeleteConfirmationRequired = (
|
||||||
|
databaseName: string
|
||||||
|
): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
message: `Type "DELETE ${databaseName}" to confirm. This action cannot be undone.`,
|
message: `Type "DELETE ${databaseName}" to confirm. This action cannot be undone.`,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyDBUserNamePasswordInvalid = () => ({
|
export const notifyDBUserNamePasswordInvalid = (): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
message: 'Username and/or Password too short.',
|
message: 'Username and/or Password too short.',
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyRoleNameInvalid = () => ({
|
export const notifyRoleNameInvalid = (): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
message: 'Role name is too short.',
|
message: 'Role name is too short.',
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyDatabaseNameInvalid = () => ({
|
export const notifyDatabaseNameInvalid = (): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
message: 'Database name cannot be blank.',
|
message: 'Database name cannot be blank.',
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyDatabaseNameAlreadyExists = () => ({
|
export const notifyDatabaseNameAlreadyExists = (): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
message: 'A Database by this name already exists.',
|
message: 'A Database by this name already exists.',
|
||||||
})
|
})
|
||||||
|
|
||||||
// Dashboard Notifications
|
// Dashboard Notifications
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
export const notifyTempVarAlreadyExists = tempVarName => ({
|
export const notifyTempVarAlreadyExists = (
|
||||||
|
tempVarName: string
|
||||||
|
): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
icon: 'cube',
|
icon: 'cube',
|
||||||
message: `Variable '${tempVarName}' already exists. Please enter a new value.`,
|
message: `Variable '${tempVarName}' already exists. Please enter a new value.`,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyDashboardNotFound = dashboardID => ({
|
export const notifyDashboardNotFound = (dashboardID: number): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
icon: 'dash-h',
|
icon: 'dash-h',
|
||||||
message: `Dashboard ${dashboardID} could not be found`,
|
message: `Dashboard ${dashboardID} could not be found`,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyDashboardDeleted = name => ({
|
export const notifyDashboardDeleted = (name: string): Notification => ({
|
||||||
...defaultSuccessNotification,
|
...defaultSuccessNotification,
|
||||||
icon: 'dash-h',
|
icon: 'dash-h',
|
||||||
message: `Dashboard ${name} deleted successfully.`,
|
message: `Dashboard ${name} deleted successfully.`,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyDashboardExported = name => ({
|
export const notifyDashboardExported = (name: string): Notification => ({
|
||||||
...defaultSuccessNotification,
|
...defaultSuccessNotification,
|
||||||
icon: 'dash-h',
|
icon: 'dash-h',
|
||||||
message: `Dashboard ${name} exported successfully.`,
|
message: `Dashboard ${name} exported successfully.`,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyDashboardExportFailed = (name, errorMessage) => ({
|
export const notifyDashboardExportFailed = (
|
||||||
|
name: string,
|
||||||
|
errorMessage: string
|
||||||
|
): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
duration: INFINITE,
|
duration: INFINITE,
|
||||||
message: `Failed to export Dashboard ${name}: ${errorMessage}.`,
|
message: `Failed to export Dashboard ${name}: ${errorMessage}.`,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyDashboardImported = name => ({
|
export const notifyDashboardImported = (name: string): Notification => ({
|
||||||
...defaultSuccessNotification,
|
...defaultSuccessNotification,
|
||||||
icon: 'dash-h',
|
icon: 'dash-h',
|
||||||
message: `Dashboard ${name} imported successfully.`,
|
message: `Dashboard ${name} imported successfully.`,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyDashboardImportFailed = (fileName, errorMessage) => ({
|
export const notifyDashboardImportFailed = (
|
||||||
|
fileName: string,
|
||||||
|
errorMessage: string
|
||||||
|
): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
duration: INFINITE,
|
duration: INFINITE,
|
||||||
message: `Failed to import Dashboard from file ${fileName}: ${errorMessage}.`,
|
message: `Failed to import Dashboard from file ${fileName}: ${errorMessage}.`,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyDashboardDeleteFailed = (name, errorMessage) =>
|
export const notifyDashboardDeleteFailed = (
|
||||||
`Failed to delete Dashboard ${name}: ${errorMessage}.`
|
name: string,
|
||||||
|
errorMessage: string
|
||||||
|
): string => `Failed to delete Dashboard ${name}: ${errorMessage}.`
|
||||||
|
|
||||||
export const notifyCellAdded = name => ({
|
export const notifyCellAdded = (name: string): Notification => ({
|
||||||
...defaultSuccessNotification,
|
...defaultSuccessNotification,
|
||||||
icon: 'dash-h',
|
icon: 'dash-h',
|
||||||
duration: 1900,
|
duration: 1900,
|
||||||
message: `Added "${name}" to dashboard.`,
|
message: `Added "${name}" to dashboard.`,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyCellDeleted = name => ({
|
export const notifyCellDeleted = (name: string): Notification => ({
|
||||||
...defaultDeletionNotification,
|
...defaultDeletionNotification,
|
||||||
icon: 'dash-h',
|
icon: 'dash-h',
|
||||||
duration: 1900,
|
duration: 1900,
|
||||||
message: `Deleted "${name}" from dashboard.`,
|
message: `Deleted "${name}" from dashboard.`,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyBuilderDisabled = () => ({
|
export const notifyBuilderDisabled = (): Notification => ({
|
||||||
type: 'info',
|
type: 'info',
|
||||||
icon: 'graphline',
|
icon: 'graphline',
|
||||||
duration: 7500,
|
duration: 7500,
|
||||||
|
@ -467,249 +521,276 @@ export const notifyBuilderDisabled = () => ({
|
||||||
|
|
||||||
// Template Variables & URL Queries
|
// Template Variables & URL Queries
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
export const notifyInvalidTempVarValueInURLQuery = ({key, value}) => ({
|
export const notifyInvalidTempVarValueInURLQuery = ({
|
||||||
|
key,
|
||||||
|
value,
|
||||||
|
}: TemplateUpdate): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
icon: 'cube',
|
icon: 'cube',
|
||||||
message: `Invalid URL query value of '${value}' supplied for template variable '${key}'.`,
|
message: `Invalid URL query value of '${value}' supplied for template variable '${key}'.`,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyInvalidTimeRangeValueInURLQuery = () => ({
|
export const notifyInvalidTimeRangeValueInURLQuery = (): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
icon: 'cube',
|
icon: 'cube',
|
||||||
message: `Invalid URL query value supplied for lower or upper time range.`,
|
message: `Invalid URL query value supplied for lower or upper time range.`,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyInvalidZoomedTimeRangeValueInURLQuery = () => ({
|
export const notifyInvalidZoomedTimeRangeValueInURLQuery = (): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
icon: 'cube',
|
icon: 'cube',
|
||||||
message: `Invalid URL query value supplied for zoomed lower or zoomed upper time range.`,
|
message: `Invalid URL query value supplied for zoomed lower or zoomed upper time range.`,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyViewerUnauthorizedToSetTempVars = () => ({
|
export const notifyViewerUnauthorizedToSetTempVars = (): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
message: `Viewer role unauthorized to override template variable values from URL.`,
|
message: `Viewer role unauthorized to override template variable values from URL.`,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Rule Builder Notifications
|
// Rule Builder Notifications
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
export const notifyAlertRuleCreated = ruleName => ({
|
export const notifyAlertRuleCreated = (ruleName: string): Notification => ({
|
||||||
...defaultSuccessNotification,
|
...defaultSuccessNotification,
|
||||||
message: `${ruleName} created successfully.`,
|
message: `${ruleName} created successfully.`,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyAlertRuleCreateFailed = (ruleName, errorMessage) => ({
|
export const notifyAlertRuleCreateFailed = (
|
||||||
|
ruleName: string,
|
||||||
|
errorMessage: string
|
||||||
|
): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
message: `There was a problem creating ${ruleName}: ${errorMessage}`,
|
message: `There was a problem creating ${ruleName}: ${errorMessage}`,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyAlertRuleUpdated = ruleName => ({
|
export const notifyAlertRuleUpdated = (ruleName: string): Notification => ({
|
||||||
...defaultSuccessNotification,
|
...defaultSuccessNotification,
|
||||||
message: `${ruleName} saved successfully.`,
|
message: `${ruleName} saved successfully.`,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyAlertRuleUpdateFailed = (ruleName, errorMessage) => ({
|
export const notifyAlertRuleUpdateFailed = (
|
||||||
|
ruleName: string,
|
||||||
|
errorMessage: string
|
||||||
|
): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
message: `There was a problem saving ${ruleName}: ${errorMessage}`,
|
message: `There was a problem saving ${ruleName}: ${errorMessage}`,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyAlertRuleDeleted = ruleName => ({
|
export const notifyAlertRuleDeleted = (ruleName: string): Notification => ({
|
||||||
...defaultSuccessNotification,
|
...defaultSuccessNotification,
|
||||||
message: `${ruleName} deleted successfully.`,
|
message: `${ruleName} deleted successfully.`,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyAlertRuleDeleteFailed = ruleName => ({
|
export const notifyAlertRuleDeleteFailed = (
|
||||||
|
ruleName: string
|
||||||
|
): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
message: `${ruleName} could not be deleted.`,
|
message: `${ruleName} could not be deleted.`,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyAlertRuleStatusUpdated = (ruleName, updatedStatus) => ({
|
export const notifyAlertRuleStatusUpdated = (
|
||||||
|
ruleName: string,
|
||||||
|
updatedStatus: string
|
||||||
|
): Notification => ({
|
||||||
...defaultSuccessNotification,
|
...defaultSuccessNotification,
|
||||||
message: `${ruleName} ${updatedStatus} successfully.`,
|
message: `${ruleName} ${updatedStatus} successfully.`,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyAlertRuleStatusUpdateFailed = (ruleName, updatedStatus) => ({
|
export const notifyAlertRuleStatusUpdateFailed = (
|
||||||
|
ruleName: string,
|
||||||
|
updatedStatus: string
|
||||||
|
): Notification => ({
|
||||||
...defaultSuccessNotification,
|
...defaultSuccessNotification,
|
||||||
message: `${ruleName} could not be ${updatedStatus}.`,
|
message: `${ruleName} could not be ${updatedStatus}.`,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyAlertRuleRequiresQuery = () =>
|
export const notifyAlertRuleRequiresQuery = (): string =>
|
||||||
'Please select a Database, Measurement, and Field.'
|
'Please select a Database, Measurement, and Field.'
|
||||||
|
|
||||||
export const notifyAlertRuleRequiresConditionValue = () =>
|
export const notifyAlertRuleRequiresConditionValue = (): string =>
|
||||||
'Please enter a value in the Conditions section.'
|
'Please enter a value in the Conditions section.'
|
||||||
|
|
||||||
export const notifyAlertRuleDeadmanInvalid = () =>
|
export const notifyAlertRuleDeadmanInvalid = (): string =>
|
||||||
'Deadman rules require a Database and Measurement.'
|
'Deadman rules require a Database and Measurement.'
|
||||||
|
|
||||||
// Kapacitor Configuration Notifications
|
// Kapacitor Configuration Notifications
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
export const notifyKapacitorNameAlreadyTaken = kapacitorName => ({
|
export const notifyKapacitorNameAlreadyTaken = (
|
||||||
|
kapacitorName: string
|
||||||
|
): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
message: `There is already a Kapacitor Connection named "${kapacitorName}".`,
|
message: `There is already a Kapacitor Connection named "${kapacitorName}".`,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyCouldNotFindKapacitor = () => ({
|
export const notifyCouldNotFindKapacitor = (): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
message: 'We could not find a Kapacitor configuration for this source.',
|
message: 'We could not find a Kapacitor configuration for this source.',
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyRefreshKapacitorFailed = () => ({
|
export const notifyRefreshKapacitorFailed = (): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
message: 'There was an error getting the Kapacitor configuration.',
|
message: 'There was an error getting the Kapacitor configuration.',
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyAlertEndpointSaved = endpoint => ({
|
export const notifyAlertEndpointSaved = (endpoint: string): Notification => ({
|
||||||
...defaultSuccessNotification,
|
...defaultSuccessNotification,
|
||||||
message: `Alert configuration for ${endpoint} saved successfully.`,
|
message: `Alert configuration for ${endpoint} saved successfully.`,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyAlertEndpointSaveFailed = (endpoint, errorMessage) => ({
|
export const notifyAlertEndpointSaveFailed = (
|
||||||
|
endpoint: string,
|
||||||
|
errorMessage: string
|
||||||
|
): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
message: `There was an error saving the alert configuration for ${endpoint}: ${errorMessage}`,
|
message: `There was an error saving the alert configuration for ${endpoint}: ${errorMessage}`,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyAlertEndpointDeleteFailed = (
|
export const notifyAlertEndpointDeleteFailed = (
|
||||||
endpoint,
|
endpoint: string,
|
||||||
config,
|
config: string,
|
||||||
errorMessage
|
errorMessage: string
|
||||||
) => ({
|
): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
message: `There was an error deleting the alert configuration for ${endpoint}/${config}: ${errorMessage}`,
|
message: `There was an error deleting the alert configuration for ${endpoint}/${config}: ${errorMessage}`,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyAlertEndpointDeleted = (endpoint, config) => ({
|
export const notifyAlertEndpointDeleted = (
|
||||||
|
endpoint: string,
|
||||||
|
config: string
|
||||||
|
): Notification => ({
|
||||||
...defaultSuccessNotification,
|
...defaultSuccessNotification,
|
||||||
message: `Alert configuration for ${endpoint}/${config} deleted successfully.`,
|
message: `Alert configuration for ${endpoint}/${config} deleted successfully.`,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyTestAlertSent = endpoint => ({
|
export const notifyTestAlertSent = (endpoint: string): Notification => ({
|
||||||
...defaultSuccessNotification,
|
...defaultSuccessNotification,
|
||||||
duration: TEN_SECONDS,
|
duration: TEN_SECONDS,
|
||||||
message: `Test Alert sent to ${endpoint}. If the Alert does not reach its destination, please check your endpoint configuration settings.`,
|
message: `Test Alert sent to ${endpoint}. If the Alert does not reach its destination, please check your endpoint configuration settings.`,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyTestAlertFailed = (endpoint, errorMessage?) => ({
|
export const notifyTestAlertFailed = (
|
||||||
|
endpoint: string,
|
||||||
|
errorMessage: string = ''
|
||||||
|
): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
message: `There was an error sending a Test Alert to ${endpoint}${
|
message: `There was an error sending a Test Alert to ${endpoint} ${errorMessage}.`,
|
||||||
errorMessage ? `: ${errorMessage}` : '.'
|
|
||||||
}`,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyInvalidBatchSizeValue = () => ({
|
export const notifyInvalidBatchSizeValue = (): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
message: 'Batch Size cannot be empty.',
|
message: 'Batch Size cannot be empty.',
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyKapacitorConnectionFailed = () => ({
|
export const notifyKapacitorConnectionFailed = (): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
message:
|
message:
|
||||||
'Could not connect to Kapacitor. Check your connection settings in the Configuration page.',
|
'Could not connect to Kapacitor. Check your connection settings in the Configuration page.',
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyKapacitorCreated = () => ({
|
export const notifyKapacitorCreated = (): Notification => ({
|
||||||
...defaultSuccessNotification,
|
...defaultSuccessNotification,
|
||||||
message:
|
message:
|
||||||
'Connected to Kapacitor successfully! Configuring endpoints is optional.',
|
'Connected to Kapacitor successfully! Configuring endpoints is optional.',
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyKapacitorCreateFailed = () => ({
|
export const notifyKapacitorCreateFailed = (): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
message: 'There was a problem connecting to Kapacitor.',
|
message: 'There was a problem connecting to Kapacitor.',
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyKapacitorUpdated = () => ({
|
export const notifyKapacitorUpdated = (): Notification => ({
|
||||||
...defaultSuccessNotification,
|
...defaultSuccessNotification,
|
||||||
message: 'Kapacitor Connection updated successfully.',
|
message: 'Kapacitor Connection updated successfully.',
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyKapacitorUpdateFailed = () => ({
|
export const notifyKapacitorUpdateFailed = (): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
message: 'There was a problem updating the Kapacitor Connection.',
|
message: 'There was a problem updating the Kapacitor Connection.',
|
||||||
})
|
})
|
||||||
|
|
||||||
// TICKscript Notifications
|
// TICKscript Notifications
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
export const notifyTickScriptCreated = () => ({
|
export const notifyTickScriptCreated = (): Notification => ({
|
||||||
...defaultSuccessNotification,
|
...defaultSuccessNotification,
|
||||||
message: 'TICKscript successfully created.',
|
message: 'TICKscript successfully created.',
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyTickscriptCreationFailed = () =>
|
export const notifyTickscriptCreationFailed = (): string =>
|
||||||
'Failed to create TICKscript.'
|
'Failed to create TICKscript.'
|
||||||
|
|
||||||
export const notifyTickscriptUpdated = () => ({
|
export const notifyTickscriptUpdated = (): Notification => ({
|
||||||
...defaultSuccessNotification,
|
...defaultSuccessNotification,
|
||||||
message: 'TICKscript successfully updated.',
|
message: 'TICKscript successfully updated.',
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyTickscriptUpdateFailed = () => 'Failed to update TICKscript.'
|
export const notifyTickscriptUpdateFailed = (): string =>
|
||||||
|
'Failed to update TICKscript.'
|
||||||
|
|
||||||
export const notifyTickscriptLoggingUnavailable = () => ({
|
export const notifyTickscriptLoggingUnavailable = (): Notification => ({
|
||||||
type: 'warning',
|
type: 'warning',
|
||||||
icon: 'alert-triangle',
|
icon: 'alert-triangle',
|
||||||
duration: INFINITE,
|
duration: INFINITE,
|
||||||
message: 'Kapacitor version 1.4 required to view TICKscript logs',
|
message: 'Kapacitor version 1.4 required to view TICKscript logs',
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyTickscriptLoggingError = () => ({
|
export const notifyTickscriptLoggingError = (): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
message: 'Could not collect kapacitor logs',
|
message: 'Could not collect kapacitor logs',
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyKapacitorNotFound = () => ({
|
export const notifyKapacitorNotFound = (): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
message: 'We could not find a Kapacitor configuration for this source.',
|
message: 'We could not find a Kapacitor configuration for this source.',
|
||||||
})
|
})
|
||||||
|
|
||||||
// Flux notifications
|
// Flux notifications
|
||||||
export const validateSuccess = () => ({
|
export const validateSuccess = (): Notification => ({
|
||||||
...defaultSuccessNotification,
|
...defaultSuccessNotification,
|
||||||
message: 'No errors found. Happy Happy Joy Joy!',
|
message: 'No errors found. Happy Happy Joy Joy!',
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyCopyToClipboardSuccess = text => ({
|
export const notifyCopyToClipboardSuccess = (text: string): Notification => ({
|
||||||
...defaultSuccessNotification,
|
...defaultSuccessNotification,
|
||||||
icon: 'dash-h',
|
icon: 'dash-h',
|
||||||
message: `'${text}' has been copied to clipboard.`,
|
message: `'${text}' has been copied to clipboard.`,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const notifyCopyToClipboardFailed = text => ({
|
export const notifyCopyToClipboardFailed = (text: string): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
message: `'${text}' was not copied to clipboard.`,
|
message: `'${text}' was not copied to clipboard.`,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Service notifications
|
// Service notifications
|
||||||
export const couldNotGetServices = {
|
export const couldNotGetServices: Notification = {
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
message: 'We could not get services',
|
message: 'We could not get services',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const fluxCreated = {
|
export const fluxCreated: Notification = {
|
||||||
...defaultSuccessNotification,
|
...defaultSuccessNotification,
|
||||||
message: 'Flux Connection Created. Script your heart out!',
|
message: 'Flux Connection Created. Script your heart out!',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const fluxNotCreated = (message: string) => ({
|
export const fluxNotCreated = (message: string): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
message,
|
message,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const fluxNotUpdated = (message: string) => ({
|
export const fluxNotUpdated = (message: string): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
message,
|
message,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const fluxUpdated = {
|
export const fluxUpdated: Notification = {
|
||||||
...defaultSuccessNotification,
|
...defaultSuccessNotification,
|
||||||
message: 'Connection Updated. Rejoice!',
|
message: 'Connection Updated. Rejoice!',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const fluxTimeSeriesError = (message: string) => ({
|
export const fluxTimeSeriesError = (message: string): Notification => ({
|
||||||
...defaultErrorNotification,
|
...defaultErrorNotification,
|
||||||
message: `Could not get data: ${message}`,
|
message: `Could not get data: ${message}`,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const fluxResponseTruncatedError = () => {
|
export const fluxResponseTruncatedError = (): Notification => {
|
||||||
const BYTES_TO_MB = 1 / 1e6
|
const BYTES_TO_MB = 1 / 1e6
|
||||||
const APPROX_MAX_RESPONSE_MB = +(MAX_RESPONSE_BYTES * BYTES_TO_MB).toFixed(2)
|
const APPROX_MAX_RESPONSE_MB = +(MAX_RESPONSE_BYTES * BYTES_TO_MB).toFixed(2)
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,8 @@ interface TimeRangeOption extends TimeRange {
|
||||||
menuOption: string
|
menuOption: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const nowMinus30d = 'now() - 30d'
|
||||||
|
|
||||||
export const timeRanges: TimeRangeOption[] = [
|
export const timeRanges: TimeRangeOption[] = [
|
||||||
{
|
{
|
||||||
defaultGroupBy: '10s',
|
defaultGroupBy: '10s',
|
||||||
|
@ -75,7 +77,7 @@ export const timeRanges: TimeRangeOption[] = [
|
||||||
defaultGroupBy: '6h',
|
defaultGroupBy: '6h',
|
||||||
seconds: 2592000,
|
seconds: 2592000,
|
||||||
inputValue: 'Past 30d',
|
inputValue: 'Past 30d',
|
||||||
lower: 'now() - 30d',
|
lower: nowMinus30d,
|
||||||
upper: null,
|
upper: null,
|
||||||
menuOption: 'Past 30d',
|
menuOption: 'Past 30d',
|
||||||
},
|
},
|
||||||
|
@ -89,3 +91,7 @@ export const defaultTimeRange = {
|
||||||
seconds: 900,
|
seconds: 900,
|
||||||
format: FORMAT_INFLUXQL,
|
format: FORMAT_INFLUXQL,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const STATUS_PAGE_TIME_RANGE = timeRanges.find(
|
||||||
|
tr => tr.lower === nowMinus30d
|
||||||
|
)
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
import {getDeep} from 'src/utils/wrappers'
|
||||||
|
|
||||||
|
interface ParseShowSeriesResponse {
|
||||||
|
errors: string[]
|
||||||
|
series: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
const parseShowSeries = (response): ParseShowSeriesResponse => {
|
||||||
|
const results = response.results[0]
|
||||||
|
|
||||||
|
if (results.error) {
|
||||||
|
return {errors: [results.error], series: []}
|
||||||
|
}
|
||||||
|
|
||||||
|
const seriesValues = getDeep<string[]>(results, 'series.0.values', [])
|
||||||
|
|
||||||
|
if (!seriesValues.length) {
|
||||||
|
return {errors: [], series: []}
|
||||||
|
}
|
||||||
|
|
||||||
|
const series = seriesValues.map(s => s[0])
|
||||||
|
|
||||||
|
return {series, errors: []}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default parseShowSeries
|
|
@ -14,12 +14,12 @@ import {
|
||||||
notifySourceDeleteFailed,
|
notifySourceDeleteFailed,
|
||||||
} from 'src/shared/copy/notifications'
|
} from 'src/shared/copy/notifications'
|
||||||
|
|
||||||
import {Source, NotificationFunc} from 'src/types'
|
import {Source, Notification} from 'src/types'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
source: Source
|
source: Source
|
||||||
sources: Source[]
|
sources: Source[]
|
||||||
notify: NotificationFunc
|
notify: (n: Notification) => void
|
||||||
deleteKapacitor: actions.DeleteKapacitorAsync
|
deleteKapacitor: actions.DeleteKapacitorAsync
|
||||||
fetchKapacitors: actions.FetchKapacitorsAsync
|
fetchKapacitors: actions.FetchKapacitorsAsync
|
||||||
removeAndLoadSources: actions.RemoveAndLoadSources
|
removeAndLoadSources: actions.RemoveAndLoadSources
|
||||||
|
|
|
@ -11,7 +11,7 @@ import {
|
||||||
} from 'src/shared/actions/sources'
|
} from 'src/shared/actions/sources'
|
||||||
import {
|
import {
|
||||||
notify as notifyAction,
|
notify as notifyAction,
|
||||||
PubishNotification,
|
PublishNotification,
|
||||||
} from 'src/shared/actions/notifications'
|
} from 'src/shared/actions/notifications'
|
||||||
import {connect} from 'react-redux'
|
import {connect} from 'react-redux'
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ import {
|
||||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||||
|
|
||||||
interface Props extends WithRouterProps {
|
interface Props extends WithRouterProps {
|
||||||
notify: PubishNotification
|
notify: PublishNotification
|
||||||
addSource: AddSource
|
addSource: AddSource
|
||||||
updateSource: UpdateSource
|
updateSource: UpdateSource
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,49 +0,0 @@
|
||||||
// he is a library for safely encoding and decoding HTML Entities
|
|
||||||
import he from 'he'
|
|
||||||
|
|
||||||
import {fetchJSONFeed as fetchJSONFeedAJAX} from 'src/status/apis'
|
|
||||||
|
|
||||||
import {notify} from 'src/shared/actions/notifications'
|
|
||||||
import {notifyJSONFeedFailed} from 'src/shared/copy/notifications'
|
|
||||||
|
|
||||||
import * as actionTypes from 'src/status/constants/actionTypes'
|
|
||||||
|
|
||||||
const fetchJSONFeedRequested = () => ({
|
|
||||||
type: actionTypes.FETCH_JSON_FEED_REQUESTED,
|
|
||||||
})
|
|
||||||
|
|
||||||
const fetchJSONFeedCompleted = data => ({
|
|
||||||
type: actionTypes.FETCH_JSON_FEED_COMPLETED,
|
|
||||||
payload: {data},
|
|
||||||
})
|
|
||||||
|
|
||||||
const fetchJSONFeedFailed = () => ({
|
|
||||||
type: actionTypes.FETCH_JSON_FEED_FAILED,
|
|
||||||
})
|
|
||||||
|
|
||||||
export const fetchJSONFeedAsync = url => async dispatch => {
|
|
||||||
dispatch(fetchJSONFeedRequested())
|
|
||||||
try {
|
|
||||||
const {data} = await fetchJSONFeedAJAX(url)
|
|
||||||
// data could be from a webpage, and thus would be HTML
|
|
||||||
if (typeof data === 'string' || !data) {
|
|
||||||
dispatch(fetchJSONFeedFailed())
|
|
||||||
} else {
|
|
||||||
// decode HTML entities from response text
|
|
||||||
const decodedData = {
|
|
||||||
...data,
|
|
||||||
items: data.items.map(item => {
|
|
||||||
item.title = he.decode(item.title)
|
|
||||||
item.content_text = he.decode(item.content_text)
|
|
||||||
return item
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(fetchJSONFeedCompleted(decodedData))
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error)
|
|
||||||
dispatch(fetchJSONFeedFailed())
|
|
||||||
dispatch(notify(notifyJSONFeedFailed(url)))
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
// he is a library for safely encoding and decoding HTML Entities
|
||||||
|
import he from 'he'
|
||||||
|
import {Dispatch} from 'redux'
|
||||||
|
|
||||||
|
import {fetchJSONFeed as fetchJSONFeedAJAX} from 'src/status/apis'
|
||||||
|
|
||||||
|
import {notify} from 'src/shared/actions/notifications'
|
||||||
|
import {notifyJSONFeedFailed} from 'src/shared/copy/notifications'
|
||||||
|
|
||||||
|
import {JSONFeedData} from 'src/types'
|
||||||
|
import {AxiosResponse} from 'axios'
|
||||||
|
|
||||||
|
export enum ActionTypes {
|
||||||
|
FETCH_JSON_FEED_REQUESTED = 'FETCH_JSON_FEED_REQUESTED',
|
||||||
|
FETCH_JSON_FEED_COMPLETED = 'FETCH_JSON_FEED_COMPLETED',
|
||||||
|
FETCH_JSON_FEED_FAILED = 'FETCH_JSON_FEED_FAILED',
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FetchJSONFeedRequestedAction {
|
||||||
|
type: ActionTypes.FETCH_JSON_FEED_REQUESTED
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FetchJSONFeedCompletedAction {
|
||||||
|
type: ActionTypes.FETCH_JSON_FEED_COMPLETED
|
||||||
|
payload: {data: JSONFeedData}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FetchJSONFeedFailedAction {
|
||||||
|
type: ActionTypes.FETCH_JSON_FEED_FAILED
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Action =
|
||||||
|
| FetchJSONFeedRequestedAction
|
||||||
|
| FetchJSONFeedCompletedAction
|
||||||
|
| FetchJSONFeedFailedAction
|
||||||
|
|
||||||
|
const fetchJSONFeedRequested = (): FetchJSONFeedRequestedAction => ({
|
||||||
|
type: ActionTypes.FETCH_JSON_FEED_REQUESTED,
|
||||||
|
})
|
||||||
|
|
||||||
|
const fetchJSONFeedCompleted = (
|
||||||
|
data: JSONFeedData
|
||||||
|
): FetchJSONFeedCompletedAction => ({
|
||||||
|
type: ActionTypes.FETCH_JSON_FEED_COMPLETED,
|
||||||
|
payload: {data},
|
||||||
|
})
|
||||||
|
|
||||||
|
const fetchJSONFeedFailed = (): FetchJSONFeedFailedAction => ({
|
||||||
|
type: ActionTypes.FETCH_JSON_FEED_FAILED,
|
||||||
|
})
|
||||||
|
|
||||||
|
export const fetchJSONFeedAsync = (url: string) => async (
|
||||||
|
dispatch: Dispatch<Action>
|
||||||
|
): Promise<void> => {
|
||||||
|
dispatch(fetchJSONFeedRequested())
|
||||||
|
try {
|
||||||
|
const {data} = (await fetchJSONFeedAJAX(url)) as AxiosResponse<JSONFeedData>
|
||||||
|
// data could be from a webpage, and thus would be HTML
|
||||||
|
if (typeof data === 'string' || !data) {
|
||||||
|
dispatch(fetchJSONFeedFailed())
|
||||||
|
} else {
|
||||||
|
// decode HTML entities from response text
|
||||||
|
const decodedData = {
|
||||||
|
...data,
|
||||||
|
items: data.items.map(item => {
|
||||||
|
item.title = he.decode(item.title)
|
||||||
|
item.content_text = he.decode(item.content_text)
|
||||||
|
return item
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
dispatch(fetchJSONFeedCompleted(decodedData))
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
dispatch(fetchJSONFeedFailed())
|
||||||
|
dispatch(notify(notifyJSONFeedFailed(url)))
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,10 @@
|
||||||
import AJAX from 'src/utils/ajax'
|
import AJAX from 'src/utils/ajax'
|
||||||
|
import {JSONFeedData} from 'src/types'
|
||||||
|
|
||||||
const excludeBasepath = true // don't prefix route of external link with basepath/
|
const excludeBasepath = true // don't prefix route of external link with basepath/
|
||||||
|
|
||||||
export const fetchJSONFeed = url =>
|
export const fetchJSONFeed = (url: string) =>
|
||||||
AJAX(
|
AJAX<JSONFeedData>(
|
||||||
{
|
{
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
url,
|
url,
|
||||||
|
|
|
@ -1,15 +1,11 @@
|
||||||
import React, {Component} from 'react'
|
import React, {Component} from 'react'
|
||||||
|
|
||||||
import FancyScrollbar from 'shared/components/FancyScrollbar'
|
import FancyScrollbar from 'src/shared/components/FancyScrollbar'
|
||||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||||
|
|
||||||
@ErrorHandling
|
@ErrorHandling
|
||||||
class GettingStarted extends Component {
|
class GettingStarted extends Component {
|
||||||
constructor(props) {
|
public render() {
|
||||||
super(props)
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
return (
|
||||||
<FancyScrollbar className="getting-started--container">
|
<FancyScrollbar className="getting-started--container">
|
||||||
<div className="getting-started">
|
<div className="getting-started">
|
|
@ -1,9 +1,13 @@
|
||||||
import React from 'react'
|
import React, {SFC} from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import {JSONFeedData} from 'src/types'
|
||||||
|
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
|
|
||||||
const JSONFeedReader = ({data}) =>
|
interface Props {
|
||||||
|
data: JSONFeedData
|
||||||
|
}
|
||||||
|
|
||||||
|
const JSONFeedReader: SFC<Props> = ({data}) =>
|
||||||
data && data.items ? (
|
data && data.items ? (
|
||||||
<div className="newsfeed">
|
<div className="newsfeed">
|
||||||
{data.items
|
{data.items
|
||||||
|
@ -38,24 +42,4 @@ const JSONFeedReader = ({data}) =>
|
||||||
</div>
|
</div>
|
||||||
) : null
|
) : null
|
||||||
|
|
||||||
const {arrayOf, shape, string} = PropTypes
|
|
||||||
|
|
||||||
JSONFeedReader.propTypes = {
|
|
||||||
data: shape({
|
|
||||||
items: arrayOf(
|
|
||||||
shape({
|
|
||||||
author: shape({
|
|
||||||
name: string.isRequired,
|
|
||||||
}).isRequired,
|
|
||||||
content_text: string.isRequired,
|
|
||||||
date_published: string.isRequired,
|
|
||||||
id: string.isRequired,
|
|
||||||
image: string,
|
|
||||||
title: string.isRequired,
|
|
||||||
url: string.isRequired,
|
|
||||||
})
|
|
||||||
),
|
|
||||||
}).isRequired,
|
|
||||||
}
|
|
||||||
|
|
||||||
export default JSONFeedReader
|
export default JSONFeedReader
|
|
@ -1,23 +1,26 @@
|
||||||
import React, {Component} from 'react'
|
import React, {Component} from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import {connect} from 'react-redux'
|
import {connect} from 'react-redux'
|
||||||
import {bindActionCreators} from 'redux'
|
|
||||||
|
|
||||||
import {fetchJSONFeedAsync} from 'src/status/actions'
|
import {fetchJSONFeedAsync} from 'src/status/actions'
|
||||||
|
|
||||||
import FancyScrollbar from 'shared/components/FancyScrollbar'
|
import FancyScrollbar from 'src/shared/components/FancyScrollbar'
|
||||||
import JSONFeedReader from 'src/status/components/JSONFeedReader'
|
import JSONFeedReader from 'src/status/components/JSONFeedReader'
|
||||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||||
|
|
||||||
|
import {JSONFeedData} from 'src/types'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
hasCompletedFetchOnce: boolean
|
||||||
|
isFetching: boolean
|
||||||
|
isFailed: boolean
|
||||||
|
data: JSONFeedData
|
||||||
|
fetchJSONFeed: (statusFeedURL: string) => void
|
||||||
|
statusFeedURL: string
|
||||||
|
}
|
||||||
|
|
||||||
@ErrorHandling
|
@ErrorHandling
|
||||||
class NewsFeed extends Component {
|
class NewsFeed extends Component<Props> {
|
||||||
constructor(props) {
|
public render() {
|
||||||
super(props)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: implement shouldComponentUpdate based on fetching conditions
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {hasCompletedFetchOnce, isFetching, isFailed, data} = this.props
|
const {hasCompletedFetchOnce, isFetching, isFailed, data} = this.props
|
||||||
|
|
||||||
if (!hasCompletedFetchOnce) {
|
if (!hasCompletedFetchOnce) {
|
||||||
|
@ -54,25 +57,13 @@ class NewsFeed extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: implement interval polling a la AutoRefresh
|
// TODO: implement interval polling a la AutoRefresh
|
||||||
componentDidMount() {
|
public componentDidMount() {
|
||||||
const {statusFeedURL, fetchJSONFeed} = this.props
|
const {statusFeedURL, fetchJSONFeed} = this.props
|
||||||
|
|
||||||
fetchJSONFeed(statusFeedURL)
|
fetchJSONFeed(statusFeedURL)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const mstp = ({
|
||||||
const {bool, func, shape, string} = PropTypes
|
|
||||||
|
|
||||||
NewsFeed.propTypes = {
|
|
||||||
hasCompletedFetchOnce: bool.isRequired,
|
|
||||||
isFetching: bool.isRequired,
|
|
||||||
isFailed: bool.isRequired,
|
|
||||||
data: shape(),
|
|
||||||
fetchJSONFeed: func.isRequired,
|
|
||||||
statusFeedURL: string,
|
|
||||||
}
|
|
||||||
|
|
||||||
const mapStateToProps = ({
|
|
||||||
links: {
|
links: {
|
||||||
external: {statusFeed: statusFeedURL},
|
external: {statusFeed: statusFeedURL},
|
||||||
},
|
},
|
||||||
|
@ -85,8 +76,8 @@ const mapStateToProps = ({
|
||||||
statusFeedURL,
|
statusFeedURL,
|
||||||
})
|
})
|
||||||
|
|
||||||
const mapDispatchToProps = dispatch => ({
|
const mdtp = {
|
||||||
fetchJSONFeed: bindActionCreators(fetchJSONFeedAsync, dispatch),
|
fetchJSONFeed: fetchJSONFeedAsync,
|
||||||
})
|
}
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(NewsFeed)
|
export default connect(mstp, mdtp)(NewsFeed)
|
|
@ -1,6 +0,0 @@
|
||||||
export const SET_STATUS_PAGE_AUTOREFRESH = 'SET_STATUS_PAGE_AUTOREFRESH'
|
|
||||||
export const SET_STATUS_PAGE_TIME_RANGE = 'SET_STATUS_PAGE_TIME_RANGE'
|
|
||||||
|
|
||||||
export const FETCH_JSON_FEED_REQUESTED = 'FETCH_JSON_FEED_REQUESTED'
|
|
||||||
export const FETCH_JSON_FEED_COMPLETED = 'FETCH_JSON_FEED_COMPLETED'
|
|
||||||
export const FETCH_JSON_FEED_FAILED = 'FETCH_JSON_FEED_FAILED'
|
|
|
@ -1,11 +1,10 @@
|
||||||
import React, {Component} from 'react'
|
import React, {Component} from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import {connect} from 'react-redux'
|
|
||||||
|
|
||||||
import SourceIndicator from 'shared/components/SourceIndicator'
|
import FancyScrollbar from 'src/shared/components/FancyScrollbar'
|
||||||
import FancyScrollbar from 'shared/components/FancyScrollbar'
|
import LayoutRenderer from 'src/shared/components/LayoutRenderer'
|
||||||
import LayoutRenderer from 'shared/components/LayoutRenderer'
|
import {STATUS_PAGE_TIME_RANGE} from 'src/shared/data/timeRanges'
|
||||||
import PageHeader from 'shared/components/PageHeader'
|
import {AUTOREFRESH_DEFAULT} from 'src/shared/constants'
|
||||||
|
import PageHeader from 'src/shared/components/PageHeader'
|
||||||
|
|
||||||
import {fixtureStatusPageCells} from 'src/status/fixtures'
|
import {fixtureStatusPageCells} from 'src/status/fixtures'
|
||||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||||
|
@ -13,10 +12,22 @@ import {
|
||||||
TEMP_VAR_DASHBOARD_TIME,
|
TEMP_VAR_DASHBOARD_TIME,
|
||||||
TEMP_VAR_UPPER_DASHBOARD_TIME,
|
TEMP_VAR_UPPER_DASHBOARD_TIME,
|
||||||
} from 'src/shared/constants'
|
} from 'src/shared/constants'
|
||||||
|
import {Source, Cell} from 'src/types'
|
||||||
|
|
||||||
|
interface State {
|
||||||
|
cells: Cell[]
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
source: Source
|
||||||
|
}
|
||||||
|
|
||||||
|
const autoRefresh = AUTOREFRESH_DEFAULT
|
||||||
|
const timeRange = STATUS_PAGE_TIME_RANGE
|
||||||
|
|
||||||
@ErrorHandling
|
@ErrorHandling
|
||||||
class StatusPage extends Component {
|
class StatusPage extends Component<Props, State> {
|
||||||
constructor(props) {
|
constructor(props: Props) {
|
||||||
super(props)
|
super(props)
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
|
@ -24,8 +35,8 @@ class StatusPage extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
public render() {
|
||||||
const {source, autoRefresh, timeRange} = this.props
|
const {source} = this.props
|
||||||
const {cells} = this.state
|
const {cells} = this.state
|
||||||
|
|
||||||
const dashboardTime = {
|
const dashboardTime = {
|
||||||
|
@ -59,9 +70,9 @@ class StatusPage extends Component {
|
||||||
return (
|
return (
|
||||||
<div className="page">
|
<div className="page">
|
||||||
<PageHeader
|
<PageHeader
|
||||||
title="Status"
|
titleText="Status"
|
||||||
fullWidth={true}
|
fullWidth={true}
|
||||||
optionsComponents={this.optionsComponents()}
|
sourceIndicator={true}
|
||||||
/>
|
/>
|
||||||
<FancyScrollbar className="page-contents">
|
<FancyScrollbar className="page-contents">
|
||||||
<div className="dashboard container-fluid full-width">
|
<div className="dashboard container-fluid full-width">
|
||||||
|
@ -84,30 +95,6 @@ class StatusPage extends Component {
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
optionsComponents = () => {
|
|
||||||
return <SourceIndicator />
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const {number, shape, string} = PropTypes
|
export default StatusPage
|
||||||
|
|
||||||
StatusPage.propTypes = {
|
|
||||||
source: shape({
|
|
||||||
name: string.isRequired,
|
|
||||||
links: shape({
|
|
||||||
proxy: string.isRequired,
|
|
||||||
}).isRequired,
|
|
||||||
}).isRequired,
|
|
||||||
autoRefresh: number.isRequired,
|
|
||||||
timeRange: shape({
|
|
||||||
lower: string.isRequired,
|
|
||||||
}).isRequired,
|
|
||||||
}
|
|
||||||
|
|
||||||
const mapStateToProps = ({statusUI: {autoRefresh, timeRange}}) => ({
|
|
||||||
autoRefresh,
|
|
||||||
timeRange,
|
|
||||||
})
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, null)(StatusPage)
|
|
|
@ -1,9 +1,38 @@
|
||||||
import {DEFAULT_LINE_COLORS} from 'src/shared/constants/graphColorPalettes'
|
import {DEFAULT_LINE_COLORS} from 'src/shared/constants/graphColorPalettes'
|
||||||
import {TEMP_VAR_DASHBOARD_TIME} from 'src/shared/constants'
|
import {TEMP_VAR_DASHBOARD_TIME} from 'src/shared/constants'
|
||||||
|
import {NEW_DEFAULT_DASHBOARD_CELL} from 'src/dashboards/constants/index'
|
||||||
|
import {DEFAULT_AXIS} from 'src/dashboards/constants/cellEditor'
|
||||||
|
import {Cell, CellQuery, Axes} from 'src/types'
|
||||||
|
import {CellType} from 'src/types/dashboard'
|
||||||
|
|
||||||
export const fixtureStatusPageCells = [
|
const emptyQuery: CellQuery = {
|
||||||
|
query: '',
|
||||||
|
source: '',
|
||||||
|
queryConfig: {
|
||||||
|
database: '',
|
||||||
|
measurement: '',
|
||||||
|
retentionPolicy: '',
|
||||||
|
fields: [],
|
||||||
|
tags: {},
|
||||||
|
groupBy: {},
|
||||||
|
areTagsAccepted: false,
|
||||||
|
rawText: null,
|
||||||
|
range: null,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const emptyAxes: Axes = {
|
||||||
|
x: DEFAULT_AXIS,
|
||||||
|
y: DEFAULT_AXIS,
|
||||||
|
y2: DEFAULT_AXIS,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const fixtureStatusPageCells: Cell[] = [
|
||||||
{
|
{
|
||||||
|
...NEW_DEFAULT_DASHBOARD_CELL,
|
||||||
|
axes: emptyAxes,
|
||||||
i: 'alerts-bar-graph',
|
i: 'alerts-bar-graph',
|
||||||
|
type: CellType.Bar,
|
||||||
isWidget: false,
|
isWidget: false,
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 0,
|
||||||
|
@ -15,7 +44,7 @@ export const fixtureStatusPageCells = [
|
||||||
queries: [
|
queries: [
|
||||||
{
|
{
|
||||||
query: `SELECT count("value") AS "count_value" FROM "chronograf"."autogen"."alerts" WHERE time > ${TEMP_VAR_DASHBOARD_TIME} GROUP BY time(1d)`,
|
query: `SELECT count("value") AS "count_value" FROM "chronograf"."autogen"."alerts" WHERE time > ${TEMP_VAR_DASHBOARD_TIME} GROUP BY time(1d)`,
|
||||||
label: 'Events',
|
source: '',
|
||||||
queryConfig: {
|
queryConfig: {
|
||||||
database: 'chronograf',
|
database: 'chronograf',
|
||||||
measurement: 'alerts',
|
measurement: 'alerts',
|
||||||
|
@ -44,90 +73,56 @@ export const fixtureStatusPageCells = [
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
type: 'bar',
|
|
||||||
links: {
|
links: {
|
||||||
self: '/chronograf/v1/status/23/cells/c-bar-graphs-fly',
|
self: '/chronograf/v1/status/23/cells/c-bar-graphs-fly',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
...NEW_DEFAULT_DASHBOARD_CELL,
|
||||||
|
axes: emptyAxes,
|
||||||
i: 'recent-alerts',
|
i: 'recent-alerts',
|
||||||
|
type: CellType.Alerts,
|
||||||
isWidget: true,
|
isWidget: true,
|
||||||
name: 'Alerts – Last 30 Days',
|
name: 'Alerts – Last 30 Days',
|
||||||
type: 'alerts',
|
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 5,
|
y: 5,
|
||||||
w: 6.5,
|
w: 6.5,
|
||||||
h: 6,
|
h: 6,
|
||||||
legend: {},
|
legend: {},
|
||||||
queries: [
|
queries: [emptyQuery],
|
||||||
{
|
colors: DEFAULT_LINE_COLORS,
|
||||||
query: '',
|
links: {self: ''},
|
||||||
queryConfig: {
|
|
||||||
database: '',
|
|
||||||
measurement: '',
|
|
||||||
retentionPolicy: '',
|
|
||||||
fields: [],
|
|
||||||
tags: {},
|
|
||||||
groupBy: {},
|
|
||||||
areTagsAccepted: false,
|
|
||||||
rawText: null,
|
|
||||||
range: null,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
...NEW_DEFAULT_DASHBOARD_CELL,
|
||||||
|
axes: emptyAxes,
|
||||||
i: 'news-feed',
|
i: 'news-feed',
|
||||||
|
type: CellType.News,
|
||||||
isWidget: true,
|
isWidget: true,
|
||||||
name: 'News Feed',
|
name: 'News Feed',
|
||||||
type: 'news',
|
|
||||||
x: 6.5,
|
x: 6.5,
|
||||||
y: 5,
|
y: 5,
|
||||||
w: 3,
|
w: 3,
|
||||||
h: 6,
|
h: 6,
|
||||||
legend: {},
|
legend: {},
|
||||||
queries: [
|
queries: [emptyQuery],
|
||||||
{
|
colors: DEFAULT_LINE_COLORS,
|
||||||
query: '',
|
links: {self: ''},
|
||||||
queryConfig: {
|
|
||||||
database: '',
|
|
||||||
measurement: '',
|
|
||||||
retentionPolicy: '',
|
|
||||||
fields: [],
|
|
||||||
tags: {},
|
|
||||||
groupBy: {},
|
|
||||||
areTagsAccepted: false,
|
|
||||||
rawText: null,
|
|
||||||
range: null,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
...NEW_DEFAULT_DASHBOARD_CELL,
|
||||||
|
axes: emptyAxes,
|
||||||
i: 'getting-started',
|
i: 'getting-started',
|
||||||
|
type: CellType.Guide,
|
||||||
isWidget: true,
|
isWidget: true,
|
||||||
name: 'Getting Started',
|
name: 'Getting Started',
|
||||||
type: 'guide',
|
|
||||||
x: 9.5,
|
x: 9.5,
|
||||||
y: 5,
|
y: 5,
|
||||||
w: 2.5,
|
w: 2.5,
|
||||||
h: 6,
|
h: 6,
|
||||||
legend: {},
|
legend: {},
|
||||||
queries: [
|
queries: [emptyQuery],
|
||||||
{
|
colors: DEFAULT_LINE_COLORS,
|
||||||
query: '',
|
links: {self: ''},
|
||||||
queryConfig: {
|
|
||||||
database: '',
|
|
||||||
measurement: '',
|
|
||||||
retentionPolicy: '',
|
|
||||||
fields: [],
|
|
||||||
tags: {},
|
|
||||||
groupBy: {},
|
|
||||||
areTagsAccepted: false,
|
|
||||||
rawText: null,
|
|
||||||
range: null,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,19 +1,30 @@
|
||||||
import * as actionTypes from 'src/status/constants/actionTypes'
|
import {JSONFeedData} from 'src/types'
|
||||||
|
import {Action, ActionTypes} from 'src/status/actions'
|
||||||
|
|
||||||
const initialState = {
|
export interface JSONFeedReducerState {
|
||||||
|
hasCompletedFetchOnce: boolean
|
||||||
|
isFetching: boolean
|
||||||
|
isFailed: boolean
|
||||||
|
data: JSONFeedData
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialState: JSONFeedReducerState = {
|
||||||
hasCompletedFetchOnce: false,
|
hasCompletedFetchOnce: false,
|
||||||
isFetching: false,
|
isFetching: false,
|
||||||
isFailed: false,
|
isFailed: false,
|
||||||
data: null,
|
data: null,
|
||||||
}
|
}
|
||||||
|
|
||||||
const JSONFeedReducer = (state = initialState, action) => {
|
const JSONFeedReducer = (
|
||||||
|
state: JSONFeedReducerState = initialState,
|
||||||
|
action: Action
|
||||||
|
): JSONFeedReducerState => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case actionTypes.FETCH_JSON_FEED_REQUESTED: {
|
case ActionTypes.FETCH_JSON_FEED_REQUESTED: {
|
||||||
return {...state, isFetching: true, isFailed: false}
|
return {...state, isFetching: true, isFailed: false}
|
||||||
}
|
}
|
||||||
|
|
||||||
case actionTypes.FETCH_JSON_FEED_COMPLETED: {
|
case ActionTypes.FETCH_JSON_FEED_COMPLETED: {
|
||||||
const {data} = action.payload
|
const {data} = action.payload
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -25,7 +36,7 @@ const JSONFeedReducer = (state = initialState, action) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case actionTypes.FETCH_JSON_FEED_FAILED: {
|
case ActionTypes.FETCH_JSON_FEED_FAILED: {
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
isFetching: false,
|
isFetching: false,
|
|
@ -1,7 +0,0 @@
|
||||||
import statusUI from './ui'
|
|
||||||
import JSONFeed from './JSONFeed'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
statusUI,
|
|
||||||
JSONFeed,
|
|
||||||
}
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
import JSONFeed from 'src/status/reducers/JSONFeed'
|
||||||
|
export default {
|
||||||
|
JSONFeed,
|
||||||
|
}
|
|
@ -1,36 +0,0 @@
|
||||||
import {AUTOREFRESH_DEFAULT} from 'shared/constants'
|
|
||||||
import {timeRanges} from 'shared/data/timeRanges'
|
|
||||||
|
|
||||||
import * as actionTypes from 'src/status/constants/actionTypes'
|
|
||||||
|
|
||||||
const {lower, upper} = timeRanges.find(tr => tr.lower === 'now() - 30d')
|
|
||||||
|
|
||||||
const initialState = {
|
|
||||||
autoRefresh: AUTOREFRESH_DEFAULT,
|
|
||||||
timeRange: {lower, upper},
|
|
||||||
}
|
|
||||||
|
|
||||||
const statusUI = (state = initialState, action) => {
|
|
||||||
switch (action.type) {
|
|
||||||
case actionTypes.SET_STATUS_PAGE_AUTOREFRESH: {
|
|
||||||
const {milliseconds} = action.payload
|
|
||||||
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
autoRefresh: milliseconds,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
case actionTypes.SET_STATUS_PAGE_TIME_RANGE: {
|
|
||||||
const {timeRange} = action.payload
|
|
||||||
|
|
||||||
return {...state, timeRange}
|
|
||||||
}
|
|
||||||
|
|
||||||
default: {
|
|
||||||
return state
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default statusUI
|
|
|
@ -86,7 +86,7 @@
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
right: 6px;
|
right: 6px;
|
||||||
transform: translateY(-50%);
|
transform: translateY(-50%) rotate(180deg);
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transition: opacity 0.25s ease, color 0.25s ease, transform 0.25s ease;
|
transition: opacity 0.25s ease, color 0.25s ease, transform 0.25s ease;
|
||||||
|
@ -107,10 +107,10 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&__sort-asc:before {
|
&__sort-asc:before {
|
||||||
transform: translateY(-50%) rotate(0deg);
|
transform: translateY(-50%) rotate(180deg);
|
||||||
}
|
}
|
||||||
&__sort-desc:before {
|
&__sort-desc:before {
|
||||||
transform: translateY(-50%) rotate(180deg);
|
transform: translateY(-50%) rotate(0deg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,169 @@
|
||||||
|
import React, {PureComponent, ChangeEvent} from 'react'
|
||||||
|
import _ from 'lodash'
|
||||||
|
|
||||||
|
import {proxy} from 'src/utils/queryUrlGenerator'
|
||||||
|
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||||
|
import TemplateMetaQueryPreview from 'src/tempVars/components/TemplateMetaQueryPreview'
|
||||||
|
import {parseMetaQuery, isInvalidMetaQuery} from 'src/tempVars/utils/parsing'
|
||||||
|
import {getDeep} from 'src/utils/wrappers'
|
||||||
|
|
||||||
|
import {
|
||||||
|
TemplateBuilderProps,
|
||||||
|
RemoteDataState,
|
||||||
|
TemplateValueType,
|
||||||
|
} from 'src/types'
|
||||||
|
|
||||||
|
const DEBOUNCE_DELAY = 750
|
||||||
|
|
||||||
|
interface State {
|
||||||
|
metaQueryInput: string // bound to input
|
||||||
|
metaQuery: string // debounced view of metaQueryInput
|
||||||
|
metaQueryResults: string[]
|
||||||
|
metaQueryResultsStatus: RemoteDataState
|
||||||
|
}
|
||||||
|
|
||||||
|
@ErrorHandling
|
||||||
|
class CustomMetaQueryTemplateBuilder extends PureComponent<
|
||||||
|
TemplateBuilderProps,
|
||||||
|
State
|
||||||
|
> {
|
||||||
|
private handleMetaQueryChange: () => void = _.debounce(() => {
|
||||||
|
const {metaQuery, metaQueryInput} = this.state
|
||||||
|
|
||||||
|
if (metaQuery === metaQueryInput) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({metaQuery: metaQueryInput}, this.executeQuery)
|
||||||
|
}, DEBOUNCE_DELAY)
|
||||||
|
|
||||||
|
constructor(props: TemplateBuilderProps) {
|
||||||
|
super(props)
|
||||||
|
|
||||||
|
const metaQuery = getDeep<string>(props.template, 'query.influxql', '')
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
metaQuery,
|
||||||
|
metaQueryInput: metaQuery,
|
||||||
|
metaQueryResults: [],
|
||||||
|
metaQueryResultsStatus: RemoteDataState.NotStarted,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public componentDidMount() {
|
||||||
|
this.executeQuery()
|
||||||
|
}
|
||||||
|
|
||||||
|
public render() {
|
||||||
|
const {metaQueryInput} = this.state
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="temp-builder csv-temp-builder">
|
||||||
|
<div className="form-group">
|
||||||
|
<label>Meta Query</label>
|
||||||
|
<div className="temp-builder--mq-controls">
|
||||||
|
<textarea
|
||||||
|
className="form-control"
|
||||||
|
value={metaQueryInput}
|
||||||
|
onChange={this.handleMetaQueryInputChange}
|
||||||
|
onBlur={this.handleMetaQueryChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{this.renderResults()}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private renderResults() {
|
||||||
|
const {metaQueryResults, metaQueryResultsStatus} = this.state
|
||||||
|
|
||||||
|
if (this.showInvalidMetaQueryMessage) {
|
||||||
|
return (
|
||||||
|
<div className="temp-builder-results">
|
||||||
|
<p className="error">Meta Query is not valid.</p>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TemplateMetaQueryPreview
|
||||||
|
items={metaQueryResults}
|
||||||
|
loadingStatus={metaQueryResultsStatus}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private get showInvalidMetaQueryMessage(): boolean {
|
||||||
|
const {metaQuery} = this.state
|
||||||
|
|
||||||
|
return this.isInvalidMetaQuery && metaQuery !== ''
|
||||||
|
}
|
||||||
|
|
||||||
|
private get isInvalidMetaQuery(): boolean {
|
||||||
|
const {metaQuery} = this.state
|
||||||
|
|
||||||
|
return isInvalidMetaQuery(metaQuery)
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleMetaQueryInputChange = (
|
||||||
|
e: ChangeEvent<HTMLTextAreaElement>
|
||||||
|
) => {
|
||||||
|
this.setState({metaQueryInput: e.target.value})
|
||||||
|
this.handleMetaQueryChange()
|
||||||
|
}
|
||||||
|
|
||||||
|
private executeQuery = async (): Promise<void> => {
|
||||||
|
const {template, source, onUpdateTemplate} = this.props
|
||||||
|
const {metaQuery} = this.state
|
||||||
|
|
||||||
|
if (this.isInvalidMetaQuery) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({metaQueryResultsStatus: RemoteDataState.Loading})
|
||||||
|
|
||||||
|
try {
|
||||||
|
const {data} = await proxy({
|
||||||
|
source: source.links.proxy,
|
||||||
|
query: metaQuery,
|
||||||
|
})
|
||||||
|
|
||||||
|
const metaQueryResults = parseMetaQuery(metaQuery, data)
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
metaQueryResults,
|
||||||
|
metaQueryResultsStatus: RemoteDataState.Done,
|
||||||
|
})
|
||||||
|
|
||||||
|
const nextValues = metaQueryResults.map(result => {
|
||||||
|
return {
|
||||||
|
type: TemplateValueType.MetaQuery,
|
||||||
|
value: result,
|
||||||
|
selected: false,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (nextValues[0]) {
|
||||||
|
nextValues[0].selected = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const nextTemplate = {
|
||||||
|
...template,
|
||||||
|
values: nextValues,
|
||||||
|
query: {
|
||||||
|
influxql: metaQuery,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
onUpdateTemplate(nextTemplate)
|
||||||
|
} catch {
|
||||||
|
this.setState({
|
||||||
|
metaQueryResults: [],
|
||||||
|
metaQueryResultsStatus: RemoteDataState.Error,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CustomMetaQueryTemplateBuilder
|
|
@ -18,6 +18,7 @@ import MeasurementsTemplateBuilder from 'src/tempVars/components/MeasurementsTem
|
||||||
import FieldKeysTemplateBuilder from 'src/tempVars/components/FieldKeysTemplateBuilder'
|
import FieldKeysTemplateBuilder from 'src/tempVars/components/FieldKeysTemplateBuilder'
|
||||||
import TagKeysTemplateBuilder from 'src/tempVars/components/TagKeysTemplateBuilder'
|
import TagKeysTemplateBuilder from 'src/tempVars/components/TagKeysTemplateBuilder'
|
||||||
import TagValuesTemplateBuilder from 'src/tempVars/components/TagValuesTemplateBuilder'
|
import TagValuesTemplateBuilder from 'src/tempVars/components/TagValuesTemplateBuilder'
|
||||||
|
import MetaQueryTemplateBuilder from 'src/tempVars/components/MetaQueryTemplateBuilder'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Template,
|
Template,
|
||||||
|
@ -59,6 +60,7 @@ const TEMPLATE_BUILDERS = {
|
||||||
[TemplateType.FieldKeys]: FieldKeysTemplateBuilder,
|
[TemplateType.FieldKeys]: FieldKeysTemplateBuilder,
|
||||||
[TemplateType.TagKeys]: TagKeysTemplateBuilder,
|
[TemplateType.TagKeys]: TagKeysTemplateBuilder,
|
||||||
[TemplateType.TagValues]: TagValuesTemplateBuilder,
|
[TemplateType.TagValues]: TagValuesTemplateBuilder,
|
||||||
|
[TemplateType.MetaQuery]: MetaQueryTemplateBuilder,
|
||||||
}
|
}
|
||||||
|
|
||||||
const formatName = name => `:${name.replace(/:/g, '')}:`
|
const formatName = name => `:${name.replace(/:/g, '')}:`
|
||||||
|
@ -100,7 +102,9 @@ class TemplateVariableEditor extends PureComponent<Props, State> {
|
||||||
return (
|
return (
|
||||||
<div className="edit-temp-var">
|
<div className="edit-temp-var">
|
||||||
<div className="edit-temp-var--header">
|
<div className="edit-temp-var--header">
|
||||||
<h1 className="page-header__title">Edit Template Variable</h1>
|
<h1 className="page-header__title">
|
||||||
|
{isNew ? 'Create' : 'Edit'} Template Variable
|
||||||
|
</h1>
|
||||||
<div className="edit-temp-var--header-controls">
|
<div className="edit-temp-var--header-controls">
|
||||||
<button
|
<button
|
||||||
className="btn btn-default"
|
className="btn btn-default"
|
||||||
|
@ -115,7 +119,7 @@ class TemplateVariableEditor extends PureComponent<Props, State> {
|
||||||
onClick={this.handleSave}
|
onClick={this.handleSave}
|
||||||
disabled={!this.canSave}
|
disabled={!this.canSave}
|
||||||
>
|
>
|
||||||
{this.isSaving ? 'Saving...' : 'Save'}
|
{this.saveButtonText}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -182,10 +186,10 @@ class TemplateVariableEditor extends PureComponent<Props, State> {
|
||||||
|
|
||||||
private handleChooseType = ({type}) => {
|
private handleChooseType = ({type}) => {
|
||||||
const {
|
const {
|
||||||
nextTemplate: {id},
|
nextTemplate: {id, tempVar},
|
||||||
} = this.state
|
} = this.state
|
||||||
|
|
||||||
const nextNextTemplate = {...DEFAULT_TEMPLATES[type](), id}
|
const nextNextTemplate = {...DEFAULT_TEMPLATES[type](), id, tempVar}
|
||||||
|
|
||||||
this.setState({nextTemplate: nextNextTemplate})
|
this.setState({nextTemplate: nextNextTemplate})
|
||||||
}
|
}
|
||||||
|
@ -204,7 +208,12 @@ class TemplateVariableEditor extends PureComponent<Props, State> {
|
||||||
|
|
||||||
private formatName = (): void => {
|
private formatName = (): void => {
|
||||||
const {nextTemplate} = this.state
|
const {nextTemplate} = this.state
|
||||||
const tempVar = formatName(nextTemplate.tempVar)
|
|
||||||
|
let tempVar = formatName(nextTemplate.tempVar)
|
||||||
|
|
||||||
|
if (tempVar === '::') {
|
||||||
|
tempVar = ''
|
||||||
|
}
|
||||||
|
|
||||||
this.setState({nextTemplate: {...nextTemplate, tempVar}})
|
this.setState({nextTemplate: {...nextTemplate, tempVar}})
|
||||||
}
|
}
|
||||||
|
@ -272,6 +281,24 @@ class TemplateVariableEditor extends PureComponent<Props, State> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private get saveButtonText(): string {
|
||||||
|
const {isNew} = this.state
|
||||||
|
|
||||||
|
if (this.isSaving && isNew) {
|
||||||
|
return 'Creating...'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.isSaving && !isNew) {
|
||||||
|
return 'Saving...'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.isSaving && isNew) {
|
||||||
|
return 'Create'
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'Save'
|
||||||
|
}
|
||||||
|
|
||||||
private handleDelete = (): void => {
|
private handleDelete = (): void => {
|
||||||
const {onDelete} = this.props
|
const {onDelete} = this.props
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,10 @@ export const TEMPLATE_TYPES_LIST: TemplateTypesListItem[] = [
|
||||||
text: 'CSV',
|
text: 'CSV',
|
||||||
type: TemplateType.CSV,
|
type: TemplateType.CSV,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
text: 'Custom Meta Query',
|
||||||
|
type: TemplateType.MetaQuery,
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
export const TEMPLATE_VARIABLE_TYPES = {
|
export const TEMPLATE_VARIABLE_TYPES = {
|
||||||
|
@ -43,6 +47,7 @@ export const TEMPLATE_VARIABLE_TYPES = {
|
||||||
[TemplateType.FieldKeys]: TemplateValueType.FieldKey,
|
[TemplateType.FieldKeys]: TemplateValueType.FieldKey,
|
||||||
[TemplateType.TagKeys]: TemplateValueType.TagKey,
|
[TemplateType.TagKeys]: TemplateValueType.TagKey,
|
||||||
[TemplateType.TagValues]: TemplateValueType.TagValue,
|
[TemplateType.TagValues]: TemplateValueType.TagValue,
|
||||||
|
[TemplateType.MetaQuery]: TemplateValueType.MetaQuery,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TEMPLATE_VARIABLE_QUERIES = {
|
export const TEMPLATE_VARIABLE_QUERIES = {
|
||||||
|
@ -62,7 +67,7 @@ export const DEFAULT_TEMPLATES: DefaultTemplates = {
|
||||||
[TemplateType.Databases]: () => {
|
[TemplateType.Databases]: () => {
|
||||||
return {
|
return {
|
||||||
id: uuid.v4(),
|
id: uuid.v4(),
|
||||||
tempVar: ':my-databases:',
|
tempVar: '',
|
||||||
values: [
|
values: [
|
||||||
{
|
{
|
||||||
value: '_internal',
|
value: '_internal',
|
||||||
|
@ -80,7 +85,7 @@ export const DEFAULT_TEMPLATES: DefaultTemplates = {
|
||||||
[TemplateType.Measurements]: () => {
|
[TemplateType.Measurements]: () => {
|
||||||
return {
|
return {
|
||||||
id: uuid.v4(),
|
id: uuid.v4(),
|
||||||
tempVar: ':my-measurements:',
|
tempVar: '',
|
||||||
values: [],
|
values: [],
|
||||||
type: TemplateType.Measurements,
|
type: TemplateType.Measurements,
|
||||||
label: '',
|
label: '',
|
||||||
|
@ -93,7 +98,7 @@ export const DEFAULT_TEMPLATES: DefaultTemplates = {
|
||||||
[TemplateType.CSV]: () => {
|
[TemplateType.CSV]: () => {
|
||||||
return {
|
return {
|
||||||
id: uuid.v4(),
|
id: uuid.v4(),
|
||||||
tempVar: ':my-values:',
|
tempVar: '',
|
||||||
values: [],
|
values: [],
|
||||||
type: TemplateType.CSV,
|
type: TemplateType.CSV,
|
||||||
label: '',
|
label: '',
|
||||||
|
@ -103,7 +108,7 @@ export const DEFAULT_TEMPLATES: DefaultTemplates = {
|
||||||
[TemplateType.TagKeys]: () => {
|
[TemplateType.TagKeys]: () => {
|
||||||
return {
|
return {
|
||||||
id: uuid.v4(),
|
id: uuid.v4(),
|
||||||
tempVar: ':my-tag-keys:',
|
tempVar: '',
|
||||||
values: [],
|
values: [],
|
||||||
type: TemplateType.TagKeys,
|
type: TemplateType.TagKeys,
|
||||||
label: '',
|
label: '',
|
||||||
|
@ -115,7 +120,7 @@ export const DEFAULT_TEMPLATES: DefaultTemplates = {
|
||||||
[TemplateType.FieldKeys]: () => {
|
[TemplateType.FieldKeys]: () => {
|
||||||
return {
|
return {
|
||||||
id: uuid.v4(),
|
id: uuid.v4(),
|
||||||
tempVar: ':my-field-keys:',
|
tempVar: '',
|
||||||
values: [],
|
values: [],
|
||||||
type: TemplateType.FieldKeys,
|
type: TemplateType.FieldKeys,
|
||||||
label: '',
|
label: '',
|
||||||
|
@ -127,7 +132,7 @@ export const DEFAULT_TEMPLATES: DefaultTemplates = {
|
||||||
[TemplateType.TagValues]: () => {
|
[TemplateType.TagValues]: () => {
|
||||||
return {
|
return {
|
||||||
id: uuid.v4(),
|
id: uuid.v4(),
|
||||||
tempVar: ':my-tag-values:',
|
tempVar: '',
|
||||||
values: [],
|
values: [],
|
||||||
type: TemplateType.TagValues,
|
type: TemplateType.TagValues,
|
||||||
label: '',
|
label: '',
|
||||||
|
@ -136,6 +141,18 @@ export const DEFAULT_TEMPLATES: DefaultTemplates = {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
[TemplateType.MetaQuery]: () => {
|
||||||
|
return {
|
||||||
|
id: uuid.v4(),
|
||||||
|
tempVar: ':my-meta-query:',
|
||||||
|
values: [],
|
||||||
|
type: TemplateType.MetaQuery,
|
||||||
|
label: '',
|
||||||
|
query: {
|
||||||
|
influxql: '',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export const RESERVED_TEMPLATE_NAMES = [
|
export const RESERVED_TEMPLATE_NAMES = [
|
||||||
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
import parseShowDatabases from 'src/shared/parsing/showDatabases'
|
||||||
|
import parseShowFieldKeys from 'src/shared/parsing/showFieldKeys'
|
||||||
|
import parseShowTagKeys from 'src/shared/parsing/showTagKeys'
|
||||||
|
import parseShowTagValues from 'src/shared/parsing/showTagValues'
|
||||||
|
import parseShowMeasurements from 'src/shared/parsing/showMeasurements'
|
||||||
|
import parseShowSeries from 'src/shared/parsing/showSeries'
|
||||||
|
|
||||||
|
export const parseMetaQuery = (metaQuery: string, response): string[] => {
|
||||||
|
const metaQueryStart = getMetaQueryPrefix(metaQuery)
|
||||||
|
|
||||||
|
if (!metaQueryStart) {
|
||||||
|
throw new Error('Could not find parser for meta query')
|
||||||
|
}
|
||||||
|
|
||||||
|
const parser = PARSERS[metaQueryStart]
|
||||||
|
const extractor = EXTRACTORS[metaQueryStart]
|
||||||
|
const parsed = parser(response)
|
||||||
|
|
||||||
|
if (parsed.errors.length) {
|
||||||
|
throw new Error(parsed.errors)
|
||||||
|
}
|
||||||
|
|
||||||
|
return extractor(parsed)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const isInvalidMetaQuery = (metaQuery: string): boolean =>
|
||||||
|
!getMetaQueryPrefix(metaQuery)
|
||||||
|
|
||||||
|
const getMetaQueryPrefix = (metaQuery: string): string | null => {
|
||||||
|
const words = metaQuery
|
||||||
|
.trim()
|
||||||
|
.toUpperCase()
|
||||||
|
.split(' ')
|
||||||
|
const firstTwoWords = words.slice(0, 2).join(' ')
|
||||||
|
const firstThreeWords = words.slice(0, 3).join(' ')
|
||||||
|
|
||||||
|
return VALID_META_QUERY_PREFIXES.find(
|
||||||
|
q => q === firstTwoWords || q === firstThreeWords
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const VALID_META_QUERY_PREFIXES = [
|
||||||
|
'SHOW DATABASES',
|
||||||
|
'SHOW MEASUREMENTS',
|
||||||
|
'SHOW SERIES',
|
||||||
|
'SHOW TAG VALUES',
|
||||||
|
'SHOW FIELD KEYS',
|
||||||
|
'SHOW TAG KEYS',
|
||||||
|
]
|
||||||
|
|
||||||
|
const PARSERS = {
|
||||||
|
'SHOW DATABASES': parseShowDatabases,
|
||||||
|
'SHOW FIELD KEYS': parseShowFieldKeys,
|
||||||
|
'SHOW MEASUREMENTS': parseShowMeasurements,
|
||||||
|
'SHOW SERIES': parseShowSeries,
|
||||||
|
'SHOW TAG VALUES': parseShowTagValues,
|
||||||
|
'SHOW TAG KEYS': parseShowTagKeys,
|
||||||
|
}
|
||||||
|
|
||||||
|
const EXTRACTORS = {
|
||||||
|
'SHOW DATABASES': parsed => parsed.databases,
|
||||||
|
'SHOW FIELD KEYS': parsed => {
|
||||||
|
const {fieldSets} = parsed
|
||||||
|
const fieldSetsValues = Object.values(fieldSets) as string[]
|
||||||
|
|
||||||
|
return fieldSetsValues.reduce((acc, current) => [...acc, ...current], [])
|
||||||
|
},
|
||||||
|
'SHOW MEASUREMENTS': parsed => {
|
||||||
|
const {measurementSets} = parsed
|
||||||
|
|
||||||
|
return measurementSets.reduce(
|
||||||
|
(acc, current) => [...acc, ...current.measurements],
|
||||||
|
[]
|
||||||
|
)
|
||||||
|
},
|
||||||
|
'SHOW TAG KEYS': parsed => parsed.tagKeys,
|
||||||
|
'SHOW TAG VALUES': parsed => {
|
||||||
|
const {tags} = parsed
|
||||||
|
const tagsValues = Object.values(tags) as string[]
|
||||||
|
|
||||||
|
return tagsValues.reduce((acc, current) => [...acc, ...current], [])
|
||||||
|
},
|
||||||
|
'SHOW SERIES': parsed => parsed.series,
|
||||||
|
}
|
|
@ -1,4 +1,8 @@
|
||||||
import * as kapacitorQueryConfigActions from 'src/kapacitor/actions/queryConfigs'
|
import * as kapacitorQueryConfigActions from 'src/kapacitor/actions/queryConfigs'
|
||||||
|
import * as kapacitorRuleActionCreators from 'src/kapacitor/actions/view'
|
||||||
|
|
||||||
type KapacitorQueryConfigActions = typeof kapacitorQueryConfigActions
|
type KapacitorQueryConfigActions = typeof kapacitorQueryConfigActions
|
||||||
|
type KapacitorRuleActions = typeof kapacitorRuleActionCreators
|
||||||
|
|
||||||
export {KapacitorQueryConfigActions}
|
export {KapacitorQueryConfigActions}
|
||||||
|
export {KapacitorRuleActions}
|
||||||
|
|
|
@ -3,12 +3,12 @@ import {ColorString} from 'src/types/colors'
|
||||||
import {Template} from 'src/types'
|
import {Template} from 'src/types'
|
||||||
|
|
||||||
export interface Axis {
|
export interface Axis {
|
||||||
bounds: [string, string]
|
|
||||||
label: string
|
label: string
|
||||||
prefix: string
|
prefix: string
|
||||||
suffix: string
|
suffix: string
|
||||||
base: string
|
base: string
|
||||||
scale: string
|
scale: string
|
||||||
|
bounds?: [string, string]
|
||||||
}
|
}
|
||||||
|
|
||||||
export type TimeSeriesValue = string | number | null | undefined
|
export type TimeSeriesValue = string | number | null | undefined
|
||||||
|
@ -76,6 +76,7 @@ export interface Cell {
|
||||||
decimalPlaces: DecimalPlaces
|
decimalPlaces: DecimalPlaces
|
||||||
links: CellLinks
|
links: CellLinks
|
||||||
legend: Legend
|
legend: Legend
|
||||||
|
isWidget?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum CellType {
|
export enum CellType {
|
||||||
|
|
|
@ -44,6 +44,7 @@ import {
|
||||||
DygraphClass,
|
DygraphClass,
|
||||||
DygraphData,
|
DygraphData,
|
||||||
} from './dygraphs'
|
} from './dygraphs'
|
||||||
|
import {JSONFeedData} from './status'
|
||||||
import {AnnotationInterface} from './annotations'
|
import {AnnotationInterface} from './annotations'
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
@ -102,6 +103,7 @@ export {
|
||||||
SchemaFilter,
|
SchemaFilter,
|
||||||
RemoteDataState,
|
RemoteDataState,
|
||||||
URLQueryParams,
|
URLQueryParams,
|
||||||
|
JSONFeedData,
|
||||||
AnnotationInterface,
|
AnnotationInterface,
|
||||||
TemplateType,
|
TemplateType,
|
||||||
TemplateValueType,
|
TemplateValueType,
|
||||||
|
|
|
@ -32,6 +32,7 @@ export interface AlertRule {
|
||||||
error: string
|
error: string
|
||||||
created: string
|
created: string
|
||||||
modified: string
|
modified: string
|
||||||
|
queryID?: string
|
||||||
'last-enabled'?: string
|
'last-enabled'?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,7 +187,7 @@ interface OpsGenie {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Talk sends alerts to Jane Talk (https://jianliao.com/site)
|
// Talk sends alerts to Jane Talk (https://jianliao.com/site)
|
||||||
interface Talk {} // tslint:disable-line
|
interface Talk { } // tslint:disable-line
|
||||||
|
|
||||||
// TriggerValues specifies the alerting logic for a specific trigger type
|
// TriggerValues specifies the alerting logic for a specific trigger type
|
||||||
interface TriggerValues {
|
interface TriggerValues {
|
||||||
|
@ -224,7 +225,7 @@ export interface RuleMessageTemplate {
|
||||||
time: RuleMessage
|
time: RuleMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
interface RuleMessage {
|
export interface RuleMessage {
|
||||||
label: string
|
label: string
|
||||||
text: string
|
text: string
|
||||||
}
|
}
|
||||||
|
@ -411,3 +412,20 @@ export interface RuleValues {
|
||||||
rangeValue?: string | null
|
rangeValue?: string | null
|
||||||
operator?: string
|
operator?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface LogItem {
|
||||||
|
key: string
|
||||||
|
service: string
|
||||||
|
lvl: string
|
||||||
|
ts: string
|
||||||
|
msg: string
|
||||||
|
id: string
|
||||||
|
tags: string
|
||||||
|
method?: string
|
||||||
|
username?: string
|
||||||
|
host?: string
|
||||||
|
duration?: string
|
||||||
|
tag?: object
|
||||||
|
field?: object
|
||||||
|
cluster?: string
|
||||||
|
}
|
||||||
|
|
|
@ -6,6 +6,6 @@ export interface Notification {
|
||||||
message: string
|
message: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type NotificationFunc = (message: any) => Notification
|
export type NotificationFunc = (message: string) => Notification
|
||||||
|
|
||||||
export type NotificationAction = (message: Notification) => void
|
export type NotificationAction = (message: Notification) => void
|
||||||
|
|
|
@ -77,7 +77,7 @@ export interface Namespace {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Status {
|
export interface Status {
|
||||||
loading?: string
|
loading?: boolean
|
||||||
error?: string
|
error?: string
|
||||||
warn?: string
|
warn?: string
|
||||||
success?: string
|
success?: string
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
interface JSONFeedDataItem {
|
||||||
|
id: string
|
||||||
|
url: string
|
||||||
|
title: string
|
||||||
|
content_text: string
|
||||||
|
date_published: string
|
||||||
|
date_modified: string
|
||||||
|
image: string
|
||||||
|
author: {
|
||||||
|
name: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface JSONFeedData {
|
||||||
|
version: string
|
||||||
|
user_comment: string
|
||||||
|
home_page_url: string
|
||||||
|
feed_url: string
|
||||||
|
title: string
|
||||||
|
description: string
|
||||||
|
items: JSONFeedDataItem[]
|
||||||
|
}
|
|
@ -9,6 +9,7 @@ export enum TemplateValueType {
|
||||||
CSV = 'csv',
|
CSV = 'csv',
|
||||||
Points = 'points',
|
Points = 'points',
|
||||||
Constant = 'constant',
|
Constant = 'constant',
|
||||||
|
MetaQuery = 'influxql',
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TemplateValue {
|
export interface TemplateValue {
|
||||||
|
@ -34,8 +35,8 @@ export enum TemplateType {
|
||||||
TagKeys = 'tagKeys',
|
TagKeys = 'tagKeys',
|
||||||
TagValues = 'tagValues',
|
TagValues = 'tagValues',
|
||||||
CSV = 'csv',
|
CSV = 'csv',
|
||||||
Query = 'query',
|
|
||||||
Databases = 'databases',
|
Databases = 'databases',
|
||||||
|
MetaQuery = 'influxql',
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Template {
|
export interface Template {
|
||||||
|
|
Loading…
Reference in New Issue