Merge remote-tracking branch 'origin/master' into fun/dashboard_page
commit
1dc2976597
|
@ -0,0 +1,138 @@
|
|||
workflows:
|
||||
version: 2
|
||||
main:
|
||||
jobs:
|
||||
- build
|
||||
- deploy-nightly:
|
||||
requires:
|
||||
- build
|
||||
filters:
|
||||
branches:
|
||||
only: master
|
||||
- deploy-pre-release:
|
||||
requires:
|
||||
- build
|
||||
filters:
|
||||
branches:
|
||||
ignore: /.*/
|
||||
tags:
|
||||
only: /^[0-9]+(\.[0-9]+)*(\S*)([a|rc|beta]([0-9]+))+$/
|
||||
- deploy-release:
|
||||
requires:
|
||||
- build
|
||||
filters:
|
||||
branches:
|
||||
ignore: /.*/
|
||||
tags:
|
||||
only: /^[0-9]+(\.[0-9]+)*$/
|
||||
|
||||
|
||||
version: 2
|
||||
jobs:
|
||||
build:
|
||||
environment:
|
||||
DOCKER_TAG: chronograf-20180327
|
||||
machine: true
|
||||
steps:
|
||||
- checkout
|
||||
- run: |
|
||||
ls -lah
|
||||
pwd
|
||||
- run: ./etc/scripts/docker/pull.sh
|
||||
- run:
|
||||
name: "Run Tests"
|
||||
command: >
|
||||
./etc/scripts/docker/run.sh
|
||||
--debug
|
||||
--test
|
||||
--no-build
|
||||
- persist_to_workspace:
|
||||
root: /home/circleci
|
||||
paths:
|
||||
- project
|
||||
|
||||
deploy-nightly:
|
||||
environment:
|
||||
DOCKER_TAG: chronograf-20180327
|
||||
machine: true
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: /home/circleci
|
||||
- run: |
|
||||
./etc/scripts/docker/run.sh \
|
||||
--debug \
|
||||
--clean \
|
||||
--package \
|
||||
--platform all \
|
||||
--arch all \
|
||||
--upload \
|
||||
--nightly \
|
||||
--bucket=dl.influxdata.com/chronograf/releases
|
||||
cp build/linux/static_amd64/chronograf .
|
||||
cp build/linux/static_amd64/chronoctl .
|
||||
docker build -t chronograf .
|
||||
docker login -u "$QUAY_USER" -p $QUAY_PASS quay.io
|
||||
docker tag chronograf quay.io/influxdb/chronograf:nightly
|
||||
docker push quay.io/influxdb/chronograf:nightly
|
||||
- store_artifacts:
|
||||
path: ./build/
|
||||
|
||||
deploy-pre-release:
|
||||
environment:
|
||||
DOCKER_TAG: chronograf-20180327
|
||||
machine: true
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: /home/circleci
|
||||
- run: |
|
||||
./etc/scripts/docker/run.sh \
|
||||
--clean \
|
||||
--debug \
|
||||
--release \
|
||||
--package \
|
||||
--platform all \
|
||||
--arch all \
|
||||
--upload-overwrite \
|
||||
--upload \
|
||||
--bucket dl.influxdata.com/chronograf/releases
|
||||
cp build/linux/static_amd64/chronograf .
|
||||
cp build/linux/static_amd64/chronoctl .
|
||||
docker build -t chronograf .
|
||||
docker login -u "$QUAY_USER" -p $QUAY_PASS quay.io
|
||||
docker tag chronograf quay.io/influxdb/chronograf:${CIRCLE_SHA1:0:7}
|
||||
docker push quay.io/influxdb/chronograf:${CIRCLE_SHA1:0:7}
|
||||
docker tag chronograf quay.io/influxdb/chronograf:${CIRCLE_TAG}
|
||||
docker push quay.io/influxdb/chronograf:${CIRCLE_TAG}
|
||||
- store_artifacts:
|
||||
path: ./build/
|
||||
|
||||
deploy-release:
|
||||
environment:
|
||||
DOCKER_TAG: chronograf-20180327
|
||||
machine: true
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: /home/circleci
|
||||
- run: |
|
||||
./etc/scripts/docker/run.sh \
|
||||
--clean \
|
||||
--debug \
|
||||
--release \
|
||||
--package \
|
||||
--platform all \
|
||||
--arch all \
|
||||
--upload-overwrite \
|
||||
--upload \
|
||||
--bucket dl.influxdata.com/chronograf/releases
|
||||
cp build/linux/static_amd64/chronograf .
|
||||
cp build/linux/static_amd64/chronoctl .
|
||||
docker build -t chronograf .
|
||||
docker login -u "$QUAY_USER" -p $QUAY_PASS quay.io
|
||||
docker tag chronograf quay.io/influxdb/chronograf:${CIRCLE_SHA1:0:7}
|
||||
docker push quay.io/influxdb/chronograf:${CIRCLE_SHA1:0:7}
|
||||
docker tag chronograf quay.io/influxdb/chronograf:${CIRCLE_TAG}
|
||||
docker push quay.io/influxdb/chronograf:${CIRCLE_TAG}
|
||||
docker tag chronograf quay.io/influxdb/chronograf:latest
|
||||
docker push quay.io/influxdb/chronograf:latest
|
||||
- store_artifacts:
|
||||
path: ./build/
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
1. [#3474](https://github.com/influxdata/chronograf/pull/3474): Sort task table on Manage Alert page alphabetically
|
||||
1. [#3590](https://github.com/influxdata/chronograf/pull/3590): Redesign icons in side navigation
|
||||
1. [#3696](https://github.com/influxdata/chronograf/pull/3696): Add ability to delete entire queries in Flux Editor
|
||||
1. [#3671](https://github.com/influxdata/chronograf/pull/3671): Remove Snip functionality in hover legend
|
||||
1. [#3659](https://github.com/influxdata/chronograf/pull/3659): Upgrade Data Explorer query text field with syntax highlighting and partial multi-line support
|
||||
1. [#3663](https://github.com/influxdata/chronograf/pull/3663): Truncate message preview in Alert Rules table
|
||||
|
@ -21,6 +22,7 @@
|
|||
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. [#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]
|
||||
|
||||
|
|
|
@ -341,6 +341,7 @@ func MarshalDashboard(d chronograf.Dashboard) ([]byte, error) {
|
|||
Selected: v.Selected,
|
||||
Type: v.Type,
|
||||
Value: v.Value,
|
||||
Key: v.Key,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -522,6 +523,7 @@ func UnmarshalDashboard(data []byte, d *chronograf.Dashboard) error {
|
|||
Selected: v.Selected,
|
||||
Type: v.Type,
|
||||
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"`
|
||||
Value string `protobuf:"bytes,2,opt,name=value,proto3" json:"value,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{} }
|
||||
|
@ -668,6 +669,13 @@ func (m *TemplateValue) GetSelected() bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (m *TemplateValue) GetKey() string {
|
||||
if m != nil {
|
||||
return m.Key
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type TemplateQuery struct {
|
||||
Command string `protobuf:"bytes,1,opt,name=command,proto3" json:"command,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) }
|
||||
|
||||
var fileDescriptorInternal = []byte{
|
||||
// 1685 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0x5b, 0x8f, 0xe3, 0x48,
|
||||
0x15, 0x96, 0x93, 0x38, 0x89, 0x4f, 0xd2, 0xbd, 0x2d, 0x33, 0xda, 0x35, 0x0b, 0x42, 0xc1, 0xe2,
|
||||
0xd2, 0x5c, 0x76, 0x58, 0xf5, 0x0a, 0x09, 0xad, 0x76, 0x57, 0xea, 0xcb, 0xce, 0xd0, 0x73, 0xed,
|
||||
0xa9, 0x74, 0x0f, 0x4f, 0x68, 0x55, 0xb1, 0x2b, 0x49, 0x69, 0x1d, 0xdb, 0x94, 0xcb, 0xdd, 0x6d,
|
||||
0x9e, 0xf9, 0x1d, 0x48, 0x48, 0xf0, 0x8e, 0x10, 0x8f, 0x48, 0xbc, 0xf3, 0x03, 0xf8, 0x2b, 0xbc,
|
||||
0xa2, 0x53, 0x17, 0xa7, 0xdc, 0x9d, 0x19, 0x0d, 0x12, 0xda, 0xb7, 0xfa, 0xce, 0x39, 0x39, 0x55,
|
||||
0x75, 0x2e, 0x5f, 0x1d, 0x07, 0xf6, 0x79, 0x2e, 0x99, 0xc8, 0x69, 0xf6, 0xb0, 0x14, 0x85, 0x2c,
|
||||
0xc2, 0xb1, 0xc5, 0xf1, 0x1f, 0xfa, 0x30, 0x9c, 0x17, 0xb5, 0x48, 0x58, 0xb8, 0x0f, 0xbd, 0xf3,
|
||||
0xb3, 0xc8, 0x9b, 0x79, 0x87, 0x7d, 0xd2, 0x3b, 0x3f, 0x0b, 0x43, 0x18, 0xbc, 0xa0, 0x1b, 0x16,
|
||||
0xf5, 0x66, 0xde, 0x61, 0x40, 0xd4, 0x1a, 0x65, 0x97, 0x4d, 0xc9, 0xa2, 0xbe, 0x96, 0xe1, 0x3a,
|
||||
0xfc, 0x10, 0xc6, 0x57, 0x15, 0x7a, 0xdb, 0xb0, 0x68, 0xa0, 0xe4, 0x2d, 0x46, 0xdd, 0x05, 0xad,
|
||||
0xaa, 0x9b, 0x42, 0xa4, 0x91, 0xaf, 0x75, 0x16, 0x87, 0x07, 0xd0, 0xbf, 0x22, 0xcf, 0xa2, 0xa1,
|
||||
0x12, 0xe3, 0x32, 0x8c, 0x60, 0x74, 0xc6, 0x96, 0xb4, 0xce, 0x64, 0x34, 0x9a, 0x79, 0x87, 0x63,
|
||||
0x62, 0x21, 0xfa, 0xb9, 0x64, 0x19, 0x5b, 0x09, 0xba, 0x8c, 0xc6, 0xda, 0x8f, 0xc5, 0xe1, 0x43,
|
||||
0x08, 0xcf, 0xf3, 0x8a, 0x25, 0xb5, 0x60, 0xf3, 0xaf, 0x79, 0xf9, 0x9a, 0x09, 0xbe, 0x6c, 0xa2,
|
||||
0x40, 0x39, 0xd8, 0xa1, 0xc1, 0x5d, 0x9e, 0x33, 0x49, 0x71, 0x6f, 0x50, 0xae, 0x2c, 0x0c, 0x63,
|
||||
0x98, 0xce, 0xd7, 0x54, 0xb0, 0x74, 0xce, 0x12, 0xc1, 0x64, 0x34, 0x51, 0xea, 0x8e, 0x0c, 0x6d,
|
||||
0x5e, 0x8a, 0x15, 0xcd, 0xf9, 0xef, 0xa9, 0xe4, 0x45, 0x1e, 0x4d, 0xb5, 0x8d, 0x2b, 0xc3, 0x28,
|
||||
0x91, 0x22, 0x63, 0xd1, 0x9e, 0x8e, 0x12, 0xae, 0xc3, 0xef, 0x42, 0x60, 0x2e, 0x43, 0x2e, 0xa2,
|
||||
0x7d, 0xa5, 0xd8, 0x0a, 0xe2, 0xbf, 0x7b, 0x10, 0x9c, 0xd1, 0x6a, 0xbd, 0x28, 0xa8, 0x48, 0xdf,
|
||||
0x29, 0x13, 0x1f, 0x81, 0x9f, 0xb0, 0x2c, 0xab, 0xa2, 0xfe, 0xac, 0x7f, 0x38, 0x39, 0xfa, 0xe0,
|
||||
0x61, 0x9b, 0xe2, 0xd6, 0xcf, 0x29, 0xcb, 0x32, 0xa2, 0xad, 0xc2, 0x8f, 0x21, 0x90, 0x6c, 0x53,
|
||||
0x66, 0x54, 0xb2, 0x2a, 0x1a, 0xa8, 0x9f, 0x84, 0xdb, 0x9f, 0x5c, 0x1a, 0x15, 0xd9, 0x1a, 0xdd,
|
||||
0xbb, 0xa8, 0x7f, 0xff, 0xa2, 0xf1, 0xbf, 0x07, 0xb0, 0xd7, 0xd9, 0x2e, 0x9c, 0x82, 0x77, 0xab,
|
||||
0x4e, 0xee, 0x13, 0xef, 0x16, 0x51, 0xa3, 0x4e, 0xed, 0x13, 0xaf, 0x41, 0x74, 0xa3, 0x2a, 0xc7,
|
||||
0x27, 0xde, 0x0d, 0xa2, 0xb5, 0xaa, 0x17, 0x9f, 0x78, 0xeb, 0xf0, 0x27, 0x30, 0xfa, 0x5d, 0xcd,
|
||||
0x04, 0x67, 0x55, 0xe4, 0xab, 0xd3, 0xbd, 0xb7, 0x3d, 0xdd, 0xab, 0x9a, 0x89, 0x86, 0x58, 0x3d,
|
||||
0x46, 0x43, 0xd5, 0x9a, 0x2e, 0x1c, 0xb5, 0x46, 0x99, 0xc4, 0xba, 0x1c, 0x69, 0x19, 0xae, 0x4d,
|
||||
0x14, 0x75, 0xb5, 0x60, 0x14, 0x7f, 0x09, 0x03, 0x7a, 0xcb, 0xaa, 0x28, 0x50, 0xfe, 0xbf, 0xff,
|
||||
0x86, 0x80, 0x3d, 0x3c, 0xbe, 0x65, 0xd5, 0x97, 0xb9, 0x14, 0x0d, 0x51, 0xe6, 0xe1, 0x8f, 0x61,
|
||||
0x98, 0x14, 0x59, 0x21, 0xaa, 0x08, 0xee, 0x1e, 0xec, 0x14, 0xe5, 0xc4, 0xa8, 0xc3, 0x43, 0x18,
|
||||
0x66, 0x6c, 0xc5, 0xf2, 0x54, 0xd5, 0xcd, 0xe4, 0xe8, 0x60, 0x6b, 0xf8, 0x4c, 0xc9, 0x89, 0xd1,
|
||||
0x87, 0x9f, 0xc2, 0x54, 0xd2, 0x45, 0xc6, 0x5e, 0x96, 0x18, 0xc5, 0x4a, 0xd5, 0xd0, 0xe4, 0xe8,
|
||||
0x7d, 0x27, 0x1f, 0x8e, 0x96, 0x74, 0x6c, 0xc3, 0xcf, 0x60, 0xba, 0xe4, 0x2c, 0x4b, 0xed, 0x6f,
|
||||
0xf7, 0xd4, 0xa1, 0xa2, 0xed, 0x6f, 0x09, 0xcb, 0xe9, 0x06, 0x7f, 0xf1, 0x08, 0xcd, 0x48, 0xc7,
|
||||
0x3a, 0xfc, 0x1e, 0x80, 0xe4, 0x1b, 0xf6, 0xa8, 0x10, 0x1b, 0x2a, 0x4d, 0x19, 0x3a, 0x92, 0xf0,
|
||||
0x73, 0xd8, 0x4b, 0x59, 0xc2, 0x37, 0x34, 0xbb, 0xc8, 0x68, 0xc2, 0xaa, 0xe8, 0x3d, 0x75, 0x34,
|
||||
0xb7, 0xba, 0x5c, 0x35, 0xe9, 0x5a, 0x7f, 0xf8, 0x18, 0x82, 0x36, 0x7c, 0xd8, 0xdf, 0x5f, 0xb3,
|
||||
0x46, 0x15, 0x43, 0x40, 0x70, 0x19, 0xfe, 0x00, 0xfc, 0x6b, 0x9a, 0xd5, 0xba, 0x90, 0x27, 0x47,
|
||||
0xfb, 0x5b, 0xaf, 0xc7, 0xb7, 0xbc, 0x22, 0x5a, 0xf9, 0x69, 0xef, 0x57, 0x5e, 0xfc, 0x18, 0xf6,
|
||||
0x3a, 0x1b, 0xe1, 0xc1, 0x79, 0xf5, 0x65, 0xbe, 0x2c, 0x44, 0xc2, 0x52, 0xe5, 0x73, 0x4c, 0x1c,
|
||||
0x49, 0xf8, 0x3e, 0x0c, 0x53, 0xbe, 0xe2, 0xb2, 0x32, 0xe5, 0x66, 0x50, 0xfc, 0x0f, 0x0f, 0xa6,
|
||||
0x6e, 0x34, 0xc3, 0x9f, 0xc2, 0xc1, 0x35, 0x13, 0x92, 0x27, 0x34, 0xbb, 0xe4, 0x1b, 0x86, 0x1b,
|
||||
0xab, 0x9f, 0x8c, 0xc9, 0x3d, 0x79, 0xf8, 0x31, 0x0c, 0xab, 0x42, 0xc8, 0x93, 0x46, 0x55, 0xed,
|
||||
0xdb, 0xa2, 0x6c, 0xec, 0x90, 0xa7, 0x6e, 0x04, 0x2d, 0x4b, 0x9e, 0xaf, 0x2c, 0x17, 0x5a, 0x1c,
|
||||
0xfe, 0x08, 0xf6, 0x97, 0xfc, 0xf6, 0x11, 0x17, 0x95, 0x3c, 0x2d, 0xb2, 0x7a, 0x93, 0xab, 0x0a,
|
||||
0x1e, 0x93, 0x3b, 0xd2, 0x27, 0x83, 0xb1, 0x77, 0xd0, 0x7b, 0x32, 0x18, 0xfb, 0x07, 0xc3, 0xb8,
|
||||
0x84, 0xfd, 0xee, 0x4e, 0xd8, 0x96, 0xf6, 0x10, 0x8a, 0x13, 0x74, 0x78, 0x3b, 0xb2, 0x70, 0x06,
|
||||
0x93, 0x94, 0x57, 0x65, 0x46, 0x1b, 0x87, 0x36, 0x5c, 0x11, 0x72, 0xe0, 0x35, 0xaf, 0xf8, 0x22,
|
||||
0xd3, 0x54, 0x3e, 0x26, 0x16, 0xc6, 0x2b, 0xf0, 0x55, 0x59, 0x3b, 0x24, 0x14, 0x58, 0x12, 0x52,
|
||||
0xd4, 0xdf, 0x73, 0xa8, 0xff, 0x00, 0xfa, 0xbf, 0x66, 0xb7, 0xe6, 0x35, 0xc0, 0x65, 0x4b, 0x55,
|
||||
0x03, 0x87, 0xaa, 0x1e, 0x80, 0xff, 0x5a, 0xa5, 0x5d, 0x53, 0x88, 0x06, 0xf1, 0x17, 0x30, 0xd4,
|
||||
0x6d, 0xd1, 0x7a, 0xf6, 0x1c, 0xcf, 0x33, 0x98, 0xbc, 0x14, 0x9c, 0xe5, 0x52, 0x93, 0x8f, 0xb9,
|
||||
0x82, 0x23, 0x8a, 0xff, 0xe6, 0xc1, 0x40, 0x65, 0x29, 0x86, 0x69, 0xc6, 0x56, 0x34, 0x69, 0x4e,
|
||||
0x8a, 0x3a, 0x4f, 0xab, 0xc8, 0x9b, 0xf5, 0x0f, 0xfb, 0xa4, 0x23, 0xc3, 0xf2, 0x58, 0x68, 0x6d,
|
||||
0x6f, 0xd6, 0x3f, 0x0c, 0x88, 0x41, 0x78, 0xb4, 0x8c, 0x2e, 0x58, 0x66, 0xae, 0xa0, 0x01, 0x5a,
|
||||
0x97, 0x82, 0x2d, 0xf9, 0xad, 0xb9, 0x86, 0x41, 0x28, 0xaf, 0xea, 0x25, 0xca, 0xf5, 0x4d, 0x0c,
|
||||
0xc2, 0x0b, 0x2c, 0x68, 0xd5, 0x32, 0x12, 0xae, 0xd1, 0x73, 0x95, 0xd0, 0xcc, 0x52, 0x92, 0x06,
|
||||
0xf1, 0x3f, 0x3d, 0x7c, 0xc8, 0x34, 0xc5, 0xde, 0x8b, 0xf0, 0xb7, 0x61, 0x8c, 0xf4, 0xfb, 0xd5,
|
||||
0x35, 0x15, 0xe6, 0xc2, 0x23, 0xc4, 0xaf, 0xa9, 0x08, 0x7f, 0x01, 0x43, 0xd5, 0x1c, 0x3b, 0xe8,
|
||||
0xde, 0xba, 0x53, 0x51, 0x25, 0xc6, 0xac, 0x25, 0xc4, 0x81, 0x43, 0x88, 0xed, 0x65, 0x7d, 0xf7,
|
||||
0xb2, 0x1f, 0x81, 0x8f, 0xcc, 0xda, 0xa8, 0xd3, 0xef, 0xf4, 0xac, 0xf9, 0x57, 0x5b, 0xc5, 0x57,
|
||||
0xb0, 0xd7, 0xd9, 0xb1, 0xdd, 0xc9, 0xeb, 0xee, 0xb4, 0x6d, 0xf4, 0xc0, 0x34, 0x36, 0x36, 0x47,
|
||||
0xc5, 0x32, 0x96, 0x48, 0x96, 0x9a, 0xaa, 0x6b, 0x71, 0xfc, 0x27, 0x6f, 0xeb, 0x57, 0xed, 0x87,
|
||||
0x25, 0x9a, 0x14, 0x9b, 0x0d, 0xcd, 0x53, 0xe3, 0xda, 0x42, 0x8c, 0x5b, 0xba, 0x30, 0xae, 0x7b,
|
||||
0xe9, 0x02, 0xb1, 0x28, 0x4d, 0x06, 0x7b, 0xa2, 0xc4, 0xda, 0xd9, 0x30, 0x5a, 0xd5, 0x82, 0x6d,
|
||||
0x58, 0x2e, 0x4d, 0x08, 0x5c, 0x51, 0xf8, 0x01, 0x8c, 0x24, 0x5d, 0x7d, 0x85, 0xf4, 0x64, 0x32,
|
||||
0x29, 0xe9, 0xea, 0x29, 0x6b, 0xc2, 0xef, 0x40, 0xa0, 0xf8, 0x52, 0xa9, 0x74, 0x3a, 0xc7, 0x4a,
|
||||
0xf0, 0x94, 0x35, 0xf1, 0x5f, 0x7b, 0x30, 0x9c, 0x33, 0x71, 0xcd, 0xc4, 0x3b, 0xbd, 0xd0, 0xee,
|
||||
0x5c, 0xd4, 0x7f, 0xcb, 0x5c, 0x34, 0xd8, 0x3d, 0x17, 0xf9, 0xdb, 0xb9, 0xe8, 0x01, 0xf8, 0x73,
|
||||
0x91, 0x9c, 0x9f, 0xa9, 0x13, 0xf5, 0x89, 0x06, 0x58, 0x8d, 0xc7, 0x89, 0xe4, 0xd7, 0xcc, 0x0c,
|
||||
0x4b, 0x06, 0xdd, 0x7b, 0xb8, 0xc7, 0x3b, 0x26, 0x94, 0xff, 0x75, 0x66, 0xb2, 0x2d, 0x0a, 0x4e,
|
||||
0x8b, 0xc6, 0x30, 0xc5, 0xc1, 0x29, 0xa5, 0x92, 0x3e, 0x99, 0xbf, 0x7c, 0x61, 0xa7, 0x25, 0x57,
|
||||
0x16, 0xff, 0xd1, 0x83, 0xe1, 0x33, 0xda, 0x14, 0xb5, 0xbc, 0x57, 0xed, 0x33, 0x98, 0x1c, 0x97,
|
||||
0x65, 0xc6, 0x93, 0x4e, 0x87, 0x3b, 0x22, 0xb4, 0x78, 0xee, 0xe4, 0x51, 0xc7, 0xd0, 0x15, 0xe1,
|
||||
0x83, 0x72, 0xaa, 0x86, 0x20, 0x3d, 0xd1, 0x38, 0x0f, 0x8a, 0x9e, 0x7d, 0x94, 0x12, 0x83, 0x7d,
|
||||
0x5c, 0xcb, 0x62, 0x99, 0x15, 0x37, 0x2a, 0xaa, 0x63, 0xd2, 0xe2, 0xf8, 0x5f, 0x3d, 0x18, 0x7c,
|
||||
0x53, 0x83, 0xcb, 0x14, 0x3c, 0x6e, 0x8a, 0xca, 0xe3, 0xed, 0x18, 0x33, 0x72, 0xc6, 0x98, 0x08,
|
||||
0x46, 0x8d, 0xa0, 0xf9, 0x8a, 0x55, 0xd1, 0x58, 0xb1, 0x98, 0x85, 0x4a, 0xa3, 0xfa, 0x55, 0xcf,
|
||||
0x2f, 0x01, 0xb1, 0xb0, 0xed, 0x3f, 0x70, 0xfa, 0xef, 0xe7, 0x66, 0xd4, 0x99, 0xdc, 0x1d, 0x0e,
|
||||
0x76, 0x4d, 0x38, 0xff, 0xbf, 0x57, 0xfb, 0x3f, 0x1e, 0xf8, 0x6d, 0xf3, 0x9e, 0x76, 0x9b, 0xf7,
|
||||
0x74, 0xdb, 0xbc, 0x67, 0x27, 0xb6, 0x79, 0xcf, 0x4e, 0x10, 0x93, 0x0b, 0xdb, 0xbc, 0xe4, 0x02,
|
||||
0x93, 0xf5, 0x58, 0x14, 0x75, 0x79, 0xd2, 0xe8, 0xac, 0x06, 0xa4, 0xc5, 0x58, 0xf1, 0xbf, 0x59,
|
||||
0x33, 0x61, 0x42, 0x1d, 0x10, 0x83, 0xb0, 0x3f, 0x9e, 0x29, 0x62, 0xd3, 0xc1, 0xd5, 0x20, 0xfc,
|
||||
0x21, 0xf8, 0x04, 0x83, 0xa7, 0x22, 0xdc, 0xc9, 0x8b, 0x12, 0x13, 0xad, 0x45, 0xa7, 0xfa, 0x03,
|
||||
0xc8, 0x34, 0x8a, 0xfd, 0x1c, 0xfa, 0x19, 0x0c, 0xe7, 0x6b, 0xbe, 0x94, 0x76, 0x60, 0xfc, 0x96,
|
||||
0x43, 0x8c, 0x7c, 0xc3, 0x94, 0x8e, 0x18, 0x93, 0xf8, 0x15, 0x04, 0xad, 0x70, 0x7b, 0x1c, 0xcf,
|
||||
0x3d, 0x4e, 0x08, 0x83, 0xab, 0x9c, 0x4b, 0x4b, 0x11, 0xb8, 0xc6, 0xcb, 0xbe, 0xaa, 0x69, 0x2e,
|
||||
0xb9, 0x6c, 0x2c, 0x45, 0x58, 0x1c, 0x7f, 0x62, 0x8e, 0x8f, 0xee, 0xae, 0xca, 0x92, 0x09, 0x43,
|
||||
0x37, 0x1a, 0xa8, 0x4d, 0x8a, 0x1b, 0xa6, 0x5f, 0x8a, 0x3e, 0xd1, 0x20, 0xfe, 0x2d, 0x04, 0xc7,
|
||||
0x19, 0x13, 0x92, 0xd4, 0x19, 0xdb, 0xf5, 0x82, 0xab, 0x46, 0x35, 0x27, 0xc0, 0xf5, 0x96, 0x5a,
|
||||
0xfa, 0x77, 0xa8, 0xe5, 0x29, 0x2d, 0xe9, 0xf9, 0x99, 0xaa, 0xf3, 0x3e, 0x31, 0x28, 0xfe, 0xb3,
|
||||
0x07, 0x03, 0xe4, 0x30, 0xc7, 0xf5, 0xe0, 0x6d, 0xfc, 0x77, 0x21, 0x8a, 0x6b, 0x9e, 0x32, 0x61,
|
||||
0x2f, 0x67, 0xb1, 0x0a, 0x7a, 0xb2, 0x66, 0xed, 0xa0, 0x60, 0x10, 0xd6, 0x1a, 0x7e, 0x2d, 0xd9,
|
||||
0x5e, 0x72, 0x6a, 0x0d, 0xc5, 0x44, 0x2b, 0x71, 0x18, 0x9c, 0xd7, 0x25, 0x13, 0xc7, 0xe9, 0x86,
|
||||
0xdb, 0x29, 0xca, 0x91, 0xc4, 0x5f, 0xe8, 0xef, 0xaf, 0x7b, 0x4c, 0xe8, 0xed, 0xfe, 0x56, 0xbb,
|
||||
0x7b, 0xf2, 0xf8, 0x2f, 0x1e, 0x8c, 0x9e, 0x9b, 0xa9, 0xcd, 0xbd, 0x85, 0xf7, 0xc6, 0x5b, 0xf4,
|
||||
0x3a, 0xb7, 0x38, 0x82, 0x07, 0xd6, 0xa6, 0xb3, 0xbf, 0x8e, 0xc2, 0x4e, 0x9d, 0x89, 0xe8, 0xa0,
|
||||
0x4d, 0xd6, 0xbb, 0x7c, 0x7e, 0x5d, 0x76, 0x6d, 0x76, 0x25, 0xfc, 0x5e, 0x56, 0x66, 0x30, 0xb1,
|
||||
0x9f, 0x9d, 0x45, 0x66, 0x1f, 0x26, 0x57, 0x14, 0x1f, 0xc1, 0xf0, 0xb4, 0xc8, 0x97, 0x7c, 0x15,
|
||||
0x1e, 0xc2, 0xe0, 0xb8, 0x96, 0x6b, 0xe5, 0x71, 0x72, 0xf4, 0xc0, 0x69, 0xfc, 0x5a, 0xae, 0xb5,
|
||||
0x0d, 0x51, 0x16, 0xf1, 0x67, 0x00, 0x5b, 0x19, 0xbe, 0x2e, 0xdb, 0x6c, 0xbc, 0x60, 0x37, 0x58,
|
||||
0x32, 0x95, 0x19, 0xda, 0x77, 0x68, 0xe2, 0xcf, 0x21, 0x38, 0xa9, 0x79, 0x96, 0x9e, 0xe7, 0xcb,
|
||||
0x02, 0xa9, 0xe3, 0x35, 0x13, 0xd5, 0x36, 0x5f, 0x16, 0x62, 0xb8, 0x91, 0x45, 0xda, 0x1e, 0x32,
|
||||
0x68, 0x31, 0x54, 0x7f, 0x6a, 0x7c, 0xf2, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xd3, 0xfb, 0xbd,
|
||||
0x7b, 0xe6, 0x10, 0x00, 0x00,
|
||||
// 1691 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0xdd, 0x8f, 0xe3, 0x48,
|
||||
0x11, 0x97, 0x13, 0x3b, 0x89, 0x2b, 0x99, 0xb9, 0x91, 0x59, 0xdd, 0x99, 0x03, 0xa1, 0x60, 0xf1,
|
||||
0x31, 0x7c, 0xdc, 0x72, 0x9a, 0x13, 0x12, 0x3a, 0xdd, 0x9d, 0x34, 0x1f, 0xb7, 0xcb, 0xec, 0xe7,
|
||||
0x6c, 0x67, 0x76, 0x78, 0x42, 0xa7, 0x4e, 0xdc, 0x49, 0x5a, 0xe7, 0xd8, 0xa6, 0xdd, 0x9e, 0x19,
|
||||
0xf3, 0xcc, 0xdf, 0x81, 0x84, 0x04, 0xef, 0x08, 0xf1, 0x88, 0xc4, 0x3b, 0x7f, 0x00, 0xff, 0x0a,
|
||||
0xaf, 0xa8, 0xfa, 0xc3, 0x69, 0xcf, 0x64, 0x57, 0x8b, 0x84, 0xee, 0xad, 0x7f, 0x55, 0x95, 0xea,
|
||||
0xea, 0xea, 0xaa, 0x5f, 0x97, 0x03, 0xfb, 0x3c, 0x97, 0x4c, 0xe4, 0x34, 0x7b, 0x58, 0x8a, 0x42,
|
||||
0x16, 0xd1, 0xc8, 0xe2, 0xe4, 0x0f, 0x7d, 0x18, 0xcc, 0x8a, 0x5a, 0x2c, 0x58, 0xb4, 0x0f, 0xbd,
|
||||
0xf3, 0xb3, 0xd8, 0x9b, 0x7a, 0x87, 0x7d, 0xd2, 0x3b, 0x3f, 0x8b, 0x22, 0xf0, 0x5f, 0xd0, 0x0d,
|
||||
0x8b, 0x7b, 0x53, 0xef, 0x30, 0x24, 0x6a, 0x8d, 0xb2, 0xcb, 0xa6, 0x64, 0x71, 0x5f, 0xcb, 0x70,
|
||||
0x1d, 0x7d, 0x08, 0xa3, 0xd7, 0x15, 0x7a, 0xdb, 0xb0, 0xd8, 0x57, 0xf2, 0x16, 0xa3, 0xee, 0x82,
|
||||
0x56, 0xd5, 0x4d, 0x21, 0xd2, 0x38, 0xd0, 0x3a, 0x8b, 0xa3, 0x03, 0xe8, 0xbf, 0x26, 0xcf, 0xe2,
|
||||
0x81, 0x12, 0xe3, 0x32, 0x8a, 0x61, 0x78, 0xc6, 0x96, 0xb4, 0xce, 0x64, 0x3c, 0x9c, 0x7a, 0x87,
|
||||
0x23, 0x62, 0x21, 0xfa, 0xb9, 0x64, 0x19, 0x5b, 0x09, 0xba, 0x8c, 0x47, 0xda, 0x8f, 0xc5, 0xd1,
|
||||
0x43, 0x88, 0xce, 0xf3, 0x8a, 0x2d, 0x6a, 0xc1, 0x66, 0x5f, 0xf3, 0xf2, 0x8a, 0x09, 0xbe, 0x6c,
|
||||
0xe2, 0x50, 0x39, 0xd8, 0xa1, 0xc1, 0x5d, 0x9e, 0x33, 0x49, 0x71, 0x6f, 0x50, 0xae, 0x2c, 0x8c,
|
||||
0x12, 0x98, 0xcc, 0xd6, 0x54, 0xb0, 0x74, 0xc6, 0x16, 0x82, 0xc9, 0x78, 0xac, 0xd4, 0x1d, 0x19,
|
||||
0xda, 0xbc, 0x14, 0x2b, 0x9a, 0xf3, 0xdf, 0x53, 0xc9, 0x8b, 0x3c, 0x9e, 0x68, 0x1b, 0x57, 0x86,
|
||||
0x59, 0x22, 0x45, 0xc6, 0xe2, 0x3d, 0x9d, 0x25, 0x5c, 0x47, 0xdf, 0x85, 0xd0, 0x1c, 0x86, 0x5c,
|
||||
0xc4, 0xfb, 0x4a, 0xb1, 0x15, 0x24, 0x7f, 0xf7, 0x20, 0x3c, 0xa3, 0xd5, 0x7a, 0x5e, 0x50, 0x91,
|
||||
0xbe, 0xd3, 0x4d, 0x7c, 0x04, 0xc1, 0x82, 0x65, 0x59, 0x15, 0xf7, 0xa7, 0xfd, 0xc3, 0xf1, 0xd1,
|
||||
0x07, 0x0f, 0xdb, 0x2b, 0x6e, 0xfd, 0x9c, 0xb2, 0x2c, 0x23, 0xda, 0x2a, 0xfa, 0x18, 0x42, 0xc9,
|
||||
0x36, 0x65, 0x46, 0x25, 0xab, 0x62, 0x5f, 0xfd, 0x24, 0xda, 0xfe, 0xe4, 0xd2, 0xa8, 0xc8, 0xd6,
|
||||
0xe8, 0xde, 0x41, 0x83, 0xfb, 0x07, 0x4d, 0xfe, 0xed, 0xc3, 0x5e, 0x67, 0xbb, 0x68, 0x02, 0xde,
|
||||
0xad, 0x8a, 0x3c, 0x20, 0xde, 0x2d, 0xa2, 0x46, 0x45, 0x1d, 0x10, 0xaf, 0x41, 0x74, 0xa3, 0x2a,
|
||||
0x27, 0x20, 0xde, 0x0d, 0xa2, 0xb5, 0xaa, 0x97, 0x80, 0x78, 0xeb, 0xe8, 0x27, 0x30, 0xfc, 0x5d,
|
||||
0xcd, 0x04, 0x67, 0x55, 0x1c, 0xa8, 0xe8, 0xde, 0xdb, 0x46, 0xf7, 0xaa, 0x66, 0xa2, 0x21, 0x56,
|
||||
0x8f, 0xd9, 0x50, 0xb5, 0xa6, 0x0b, 0x47, 0xad, 0x51, 0x26, 0xb1, 0x2e, 0x87, 0x5a, 0x86, 0x6b,
|
||||
0x93, 0x45, 0x5d, 0x2d, 0x98, 0xc5, 0x5f, 0x82, 0x4f, 0x6f, 0x59, 0x15, 0x87, 0xca, 0xff, 0xf7,
|
||||
0xdf, 0x90, 0xb0, 0x87, 0xc7, 0xb7, 0xac, 0xfa, 0x32, 0x97, 0xa2, 0x21, 0xca, 0x3c, 0xfa, 0x31,
|
||||
0x0c, 0x16, 0x45, 0x56, 0x88, 0x2a, 0x86, 0xbb, 0x81, 0x9d, 0xa2, 0x9c, 0x18, 0x75, 0x74, 0x08,
|
||||
0x83, 0x8c, 0xad, 0x58, 0x9e, 0xaa, 0xba, 0x19, 0x1f, 0x1d, 0x6c, 0x0d, 0x9f, 0x29, 0x39, 0x31,
|
||||
0xfa, 0xe8, 0x53, 0x98, 0x48, 0x3a, 0xcf, 0xd8, 0xcb, 0x12, 0xb3, 0x58, 0xa9, 0x1a, 0x1a, 0x1f,
|
||||
0xbd, 0xef, 0xdc, 0x87, 0xa3, 0x25, 0x1d, 0xdb, 0xe8, 0x33, 0x98, 0x2c, 0x39, 0xcb, 0x52, 0xfb,
|
||||
0xdb, 0x3d, 0x15, 0x54, 0xbc, 0xfd, 0x2d, 0x61, 0x39, 0xdd, 0xe0, 0x2f, 0x1e, 0xa1, 0x19, 0xe9,
|
||||
0x58, 0x47, 0xdf, 0x03, 0x90, 0x7c, 0xc3, 0x1e, 0x15, 0x62, 0x43, 0xa5, 0x29, 0x43, 0x47, 0x12,
|
||||
0x7d, 0x0e, 0x7b, 0x29, 0x5b, 0xf0, 0x0d, 0xcd, 0x2e, 0x32, 0xba, 0x60, 0x55, 0xfc, 0x9e, 0x0a,
|
||||
0xcd, 0xad, 0x2e, 0x57, 0x4d, 0xba, 0xd6, 0x1f, 0x3e, 0x86, 0xb0, 0x4d, 0x1f, 0xf6, 0xf7, 0xd7,
|
||||
0xac, 0x51, 0xc5, 0x10, 0x12, 0x5c, 0x46, 0x3f, 0x80, 0xe0, 0x9a, 0x66, 0xb5, 0x2e, 0xe4, 0xf1,
|
||||
0xd1, 0xfe, 0xd6, 0xeb, 0xf1, 0x2d, 0xaf, 0x88, 0x56, 0x7e, 0xda, 0xfb, 0x95, 0x97, 0x3c, 0x86,
|
||||
0xbd, 0xce, 0x46, 0x18, 0x38, 0xaf, 0xbe, 0xcc, 0x97, 0x85, 0x58, 0xb0, 0x54, 0xf9, 0x1c, 0x11,
|
||||
0x47, 0x12, 0xbd, 0x0f, 0x83, 0x94, 0xaf, 0xb8, 0xac, 0x4c, 0xb9, 0x19, 0x94, 0xfc, 0xc3, 0x83,
|
||||
0x89, 0x9b, 0xcd, 0xe8, 0xa7, 0x70, 0x70, 0xcd, 0x84, 0xe4, 0x0b, 0x9a, 0x5d, 0xf2, 0x0d, 0xc3,
|
||||
0x8d, 0xd5, 0x4f, 0x46, 0xe4, 0x9e, 0x3c, 0xfa, 0x18, 0x06, 0x55, 0x21, 0xe4, 0x49, 0xa3, 0xaa,
|
||||
0xf6, 0x6d, 0x59, 0x36, 0x76, 0xc8, 0x53, 0x37, 0x82, 0x96, 0x25, 0xcf, 0x57, 0x96, 0x0b, 0x2d,
|
||||
0x8e, 0x7e, 0x04, 0xfb, 0x4b, 0x7e, 0xfb, 0x88, 0x8b, 0x4a, 0x9e, 0x16, 0x59, 0xbd, 0xc9, 0x55,
|
||||
0x05, 0x8f, 0xc8, 0x1d, 0xe9, 0x13, 0x7f, 0xe4, 0x1d, 0xf4, 0x9e, 0xf8, 0xa3, 0xe0, 0x60, 0x90,
|
||||
0x94, 0xb0, 0xdf, 0xdd, 0x09, 0xdb, 0xd2, 0x06, 0xa1, 0x38, 0x41, 0xa7, 0xb7, 0x23, 0x8b, 0xa6,
|
||||
0x30, 0x4e, 0x79, 0x55, 0x66, 0xb4, 0x71, 0x68, 0xc3, 0x15, 0x21, 0x07, 0x5e, 0xf3, 0x8a, 0xcf,
|
||||
0x33, 0x4d, 0xe5, 0x23, 0x62, 0x61, 0xb2, 0x82, 0x40, 0x95, 0xb5, 0x43, 0x42, 0xa1, 0x25, 0x21,
|
||||
0x45, 0xfd, 0x3d, 0x87, 0xfa, 0x0f, 0xa0, 0xff, 0x6b, 0x76, 0x6b, 0x5e, 0x03, 0x5c, 0xb6, 0x54,
|
||||
0xe5, 0x3b, 0x54, 0xf5, 0x00, 0x82, 0x2b, 0x75, 0xed, 0x9a, 0x42, 0x34, 0x48, 0xbe, 0x80, 0x81,
|
||||
0x6e, 0x8b, 0xd6, 0xb3, 0xe7, 0x78, 0x9e, 0xc2, 0xf8, 0xa5, 0xe0, 0x2c, 0x97, 0x9a, 0x7c, 0xcc,
|
||||
0x11, 0x1c, 0x51, 0xf2, 0x37, 0x0f, 0x7c, 0x75, 0x4b, 0x09, 0x4c, 0x32, 0xb6, 0xa2, 0x8b, 0xe6,
|
||||
0xa4, 0xa8, 0xf3, 0xb4, 0x8a, 0xbd, 0x69, 0xff, 0xb0, 0x4f, 0x3a, 0x32, 0x2c, 0x8f, 0xb9, 0xd6,
|
||||
0xf6, 0xa6, 0xfd, 0xc3, 0x90, 0x18, 0x84, 0xa1, 0x65, 0x74, 0xce, 0x32, 0x73, 0x04, 0x0d, 0xd0,
|
||||
0xba, 0x14, 0x6c, 0xc9, 0x6f, 0xcd, 0x31, 0x0c, 0x42, 0x79, 0x55, 0x2f, 0x51, 0xae, 0x4f, 0x62,
|
||||
0x10, 0x1e, 0x60, 0x4e, 0xab, 0x96, 0x91, 0x70, 0x8d, 0x9e, 0xab, 0x05, 0xcd, 0x2c, 0x25, 0x69,
|
||||
0x90, 0xfc, 0xd3, 0xc3, 0x87, 0x4c, 0x53, 0xec, 0xbd, 0x0c, 0x7f, 0x1b, 0x46, 0x48, 0xbf, 0x5f,
|
||||
0x5d, 0x53, 0x61, 0x0e, 0x3c, 0x44, 0x7c, 0x45, 0x45, 0xf4, 0x0b, 0x18, 0xa8, 0xe6, 0xd8, 0x41,
|
||||
0xf7, 0xd6, 0x9d, 0xca, 0x2a, 0x31, 0x66, 0x2d, 0x21, 0xfa, 0x0e, 0x21, 0xb6, 0x87, 0x0d, 0xdc,
|
||||
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, 0xd0, 0x34, 0x36, 0x36, 0x47,
|
||||
0xc5, 0x32, 0xb6, 0x90, 0x2c, 0x35, 0x55, 0xd7, 0x62, 0x4b, 0x16, 0x7e, 0x4b, 0x16, 0xc9, 0x9f,
|
||||
0xbc, 0xed, 0x4e, 0x2a, 0x02, 0x2c, 0xda, 0x45, 0xb1, 0xd9, 0xd0, 0x3c, 0x35, 0x9b, 0x59, 0x88,
|
||||
0x99, 0x4c, 0xe7, 0x66, 0xb3, 0x5e, 0x3a, 0x47, 0x2c, 0x4a, 0x73, 0xa7, 0x3d, 0x51, 0x62, 0x35,
|
||||
0x6d, 0x18, 0xad, 0x6a, 0xc1, 0x36, 0x2c, 0x97, 0x66, 0x17, 0x57, 0x14, 0x7d, 0x00, 0x43, 0x49,
|
||||
0x57, 0x5f, 0x61, 0x0c, 0xe6, 0x6e, 0x25, 0x5d, 0x3d, 0x65, 0x4d, 0xf4, 0x1d, 0x08, 0x15, 0x83,
|
||||
0x2a, 0x95, 0xbe, 0xe0, 0x91, 0x12, 0x3c, 0x65, 0x4d, 0xf2, 0xd7, 0x1e, 0x0c, 0x66, 0x4c, 0x5c,
|
||||
0x33, 0xf1, 0x4e, 0x6f, 0xb6, 0x3b, 0x29, 0xf5, 0xdf, 0x32, 0x29, 0xf9, 0xbb, 0x27, 0xa5, 0x60,
|
||||
0x3b, 0x29, 0x3d, 0x80, 0x60, 0x26, 0x16, 0xe7, 0x67, 0x2a, 0xa2, 0x3e, 0xd1, 0x00, 0xeb, 0xf3,
|
||||
0x78, 0x21, 0xf9, 0x35, 0x33, 0xe3, 0x93, 0x41, 0xf7, 0x9e, 0xf2, 0xd1, 0x8e, 0x99, 0xe5, 0x7f,
|
||||
0x9d, 0xa2, 0x6c, 0xd3, 0x82, 0xd3, 0xb4, 0x09, 0x4c, 0x70, 0x94, 0x4a, 0xa9, 0xa4, 0x4f, 0x66,
|
||||
0x2f, 0x5f, 0xd8, 0xf9, 0xc9, 0x95, 0x25, 0x7f, 0xf4, 0x60, 0xf0, 0x8c, 0x36, 0x45, 0x2d, 0xef,
|
||||
0xd5, 0xff, 0x14, 0xc6, 0xc7, 0x65, 0x99, 0xf1, 0x45, 0xa7, 0xe7, 0x1d, 0x11, 0x5a, 0x3c, 0x77,
|
||||
0xee, 0x51, 0xe7, 0xd0, 0x15, 0xe1, 0x13, 0x73, 0xaa, 0xc6, 0x22, 0x3d, 0xe3, 0x38, 0x4f, 0x8c,
|
||||
0x9e, 0x86, 0x94, 0x12, 0x93, 0x7d, 0x5c, 0xcb, 0x62, 0x99, 0x15, 0x37, 0x2a, 0xab, 0x23, 0xd2,
|
||||
0xe2, 0xe4, 0x5f, 0x3d, 0xf0, 0xbf, 0xa9, 0x51, 0x66, 0x02, 0x1e, 0x37, 0x45, 0xe5, 0xf1, 0x76,
|
||||
0xb0, 0x19, 0x3a, 0x83, 0x4d, 0x0c, 0xc3, 0x46, 0xd0, 0x7c, 0xc5, 0xaa, 0x78, 0xa4, 0x78, 0xcd,
|
||||
0x42, 0xa5, 0x51, 0x1d, 0xac, 0x27, 0x9a, 0x90, 0x58, 0xd8, 0x76, 0x24, 0x38, 0x1d, 0xf9, 0x73,
|
||||
0x33, 0xfc, 0x8c, 0xef, 0x8e, 0x0b, 0xbb, 0x66, 0x9e, 0xff, 0xdf, 0x3b, 0xfe, 0x1f, 0x0f, 0x82,
|
||||
0xb6, 0x79, 0x4f, 0xbb, 0xcd, 0x7b, 0xba, 0x6d, 0xde, 0xb3, 0x13, 0xdb, 0xbc, 0x67, 0x27, 0x88,
|
||||
0xc9, 0x85, 0x6d, 0x5e, 0x72, 0x81, 0x97, 0xf5, 0x58, 0x14, 0x75, 0x79, 0xd2, 0xe8, 0x5b, 0x0d,
|
||||
0x49, 0x8b, 0xb1, 0xe2, 0x7f, 0xb3, 0x66, 0xc2, 0xa4, 0x3a, 0x24, 0x06, 0x61, 0x7f, 0x3c, 0x53,
|
||||
0x54, 0xa7, 0x93, 0xab, 0x41, 0xf4, 0x43, 0x08, 0x08, 0x26, 0x4f, 0x65, 0xb8, 0x73, 0x2f, 0x4a,
|
||||
0x4c, 0xb4, 0x16, 0x9d, 0xea, 0x4f, 0x22, 0xd3, 0x28, 0xf6, 0x03, 0xe9, 0x67, 0x30, 0x98, 0xad,
|
||||
0xf9, 0x52, 0xda, 0x11, 0xf2, 0x5b, 0x0e, 0x55, 0xf2, 0x0d, 0x53, 0x3a, 0x62, 0x4c, 0x92, 0x57,
|
||||
0x10, 0xb6, 0xc2, 0x6d, 0x38, 0x9e, 0x1b, 0x4e, 0x04, 0xfe, 0xeb, 0x9c, 0x4b, 0x4b, 0x11, 0xb8,
|
||||
0xc6, 0xc3, 0xbe, 0xaa, 0x69, 0x2e, 0xb9, 0x6c, 0x2c, 0x45, 0x58, 0x9c, 0x7c, 0x62, 0xc2, 0x47,
|
||||
0x77, 0xaf, 0xcb, 0x92, 0x09, 0x43, 0x37, 0x1a, 0xa8, 0x4d, 0x8a, 0x1b, 0xa6, 0xdf, 0x8e, 0x3e,
|
||||
0xd1, 0x20, 0xf9, 0x2d, 0x84, 0xc7, 0x19, 0x13, 0x92, 0xd4, 0x19, 0xdb, 0xf5, 0xa6, 0xab, 0x46,
|
||||
0x35, 0x11, 0xe0, 0x7a, 0x4b, 0x2d, 0xfd, 0x3b, 0xd4, 0xf2, 0x94, 0x96, 0xf4, 0xfc, 0x4c, 0xd5,
|
||||
0x79, 0x9f, 0x18, 0x94, 0xfc, 0xd9, 0x03, 0x1f, 0x39, 0xcc, 0x71, 0xed, 0xbf, 0x8d, 0xff, 0x2e,
|
||||
0x44, 0x71, 0xcd, 0x53, 0x26, 0xec, 0xe1, 0x2c, 0x56, 0x49, 0x5f, 0xac, 0x59, 0x3b, 0x3a, 0x18,
|
||||
0x84, 0xb5, 0x86, 0xdf, 0x4f, 0xb6, 0x97, 0x9c, 0x5a, 0x43, 0x31, 0xd1, 0x4a, 0x1c, 0x0f, 0x67,
|
||||
0x75, 0xc9, 0xc4, 0x71, 0xba, 0xe1, 0x76, 0xae, 0x72, 0x24, 0xc9, 0x17, 0xfa, 0x8b, 0xec, 0x1e,
|
||||
0x13, 0x7a, 0xbb, 0xbf, 0xde, 0xee, 0x46, 0x9e, 0xfc, 0xc5, 0x83, 0xe1, 0x73, 0x33, 0xc7, 0xb9,
|
||||
0xa7, 0xf0, 0xde, 0x78, 0x8a, 0x5e, 0xe7, 0x14, 0x47, 0xf0, 0xc0, 0xda, 0x74, 0xf6, 0xd7, 0x59,
|
||||
0xd8, 0xa9, 0x33, 0x19, 0xf5, 0xdb, 0xcb, 0x7a, 0x97, 0x0f, 0xb2, 0xcb, 0xae, 0xcd, 0xae, 0x0b,
|
||||
0xbf, 0x77, 0x2b, 0x53, 0x18, 0xdb, 0x0f, 0xd1, 0x22, 0xb3, 0x0f, 0x93, 0x2b, 0x4a, 0x8e, 0x60,
|
||||
0x70, 0x5a, 0xe4, 0x4b, 0xbe, 0x8a, 0x0e, 0xc1, 0x3f, 0xae, 0xe5, 0x5a, 0x79, 0x1c, 0x1f, 0x3d,
|
||||
0x70, 0x1a, 0xbf, 0x96, 0x6b, 0x6d, 0x43, 0x94, 0x45, 0xf2, 0x19, 0xc0, 0x56, 0x86, 0xaf, 0xcb,
|
||||
0xf6, 0x36, 0x5e, 0xb0, 0x1b, 0x2c, 0x99, 0xca, 0x8c, 0xf1, 0x3b, 0x34, 0xc9, 0xe7, 0x10, 0x9e,
|
||||
0xd4, 0x3c, 0x4b, 0xcf, 0xf3, 0x65, 0x81, 0xd4, 0x71, 0xc5, 0x44, 0xb5, 0xbd, 0x2f, 0x0b, 0x31,
|
||||
0xdd, 0xc8, 0x22, 0x6d, 0x0f, 0x19, 0x34, 0x1f, 0xa8, 0xbf, 0x39, 0x3e, 0xf9, 0x6f, 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 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
|
||||
string key = 4; // Key is the key for a specific Value if the Template Type is map (optional)
|
||||
}
|
||||
|
||||
message TemplateQuery {
|
||||
|
|
|
@ -158,9 +158,10 @@ type Range struct {
|
|||
|
||||
// TemplateValue is a value use to replace a template in an InfluxQL query
|
||||
type TemplateValue struct {
|
||||
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
|
||||
Selected bool `json:"selected"` // Selected states that this variable has been picked to use for replacement
|
||||
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, influxql
|
||||
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
|
||||
|
@ -176,7 +177,7 @@ type TemplateID string
|
|||
type Template struct {
|
||||
TemplateVar
|
||||
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
|
||||
Query *TemplateQuery `json:"query,omitempty"` // Query is used to generate the choices for a template
|
||||
}
|
||||
|
|
91
circle.yml
91
circle.yml
|
@ -1,91 +0,0 @@
|
|||
---
|
||||
machine:
|
||||
services:
|
||||
- docker
|
||||
environment:
|
||||
DOCKER_TAG: chronograf-20180327
|
||||
|
||||
dependencies:
|
||||
override:
|
||||
- ./etc/scripts/docker/pull.sh
|
||||
|
||||
test:
|
||||
override:
|
||||
- >
|
||||
./etc/scripts/docker/run.sh
|
||||
--debug
|
||||
--test
|
||||
--no-build
|
||||
|
||||
deployment:
|
||||
master:
|
||||
branch: master
|
||||
commands:
|
||||
- >
|
||||
./etc/scripts/docker/run.sh
|
||||
--debug
|
||||
--clean
|
||||
--package
|
||||
--platform all
|
||||
--arch all
|
||||
--upload
|
||||
--nightly
|
||||
--bucket=dl.influxdata.com/chronograf/releases
|
||||
- sudo chown -R ubuntu:ubuntu /home/ubuntu
|
||||
- cp build/linux/static_amd64/chronograf .
|
||||
- cp build/linux/static_amd64/chronoctl .
|
||||
- docker build -t chronograf .
|
||||
- docker login -e $QUAY_EMAIL -u "$QUAY_USER" -p $QUAY_PASS quay.io
|
||||
- docker tag chronograf quay.io/influxdb/chronograf:nightly
|
||||
- docker push quay.io/influxdb/chronograf:nightly
|
||||
- mv ./build/* $CIRCLE_ARTIFACTS
|
||||
pre-release:
|
||||
tag: /^[0-9]+(\.[0-9]+)*(\S*)([a|rc|beta]([0-9]+))+$/
|
||||
commands:
|
||||
- >
|
||||
./etc/scripts/docker/run.sh
|
||||
--clean
|
||||
--debug
|
||||
--release
|
||||
--package
|
||||
--platform all
|
||||
--arch all
|
||||
--upload-overwrite
|
||||
--upload
|
||||
--bucket dl.influxdata.com/chronograf/releases
|
||||
- sudo chown -R ubuntu:ubuntu /home/ubuntu
|
||||
- cp build/linux/static_amd64/chronograf .
|
||||
- cp build/linux/static_amd64/chronoctl .
|
||||
- docker build -t chronograf .
|
||||
- docker login -e $QUAY_EMAIL -u "$QUAY_USER" -p $QUAY_PASS quay.io
|
||||
- docker tag chronograf quay.io/influxdb/chronograf:${CIRCLE_SHA1:0:7}
|
||||
- docker push quay.io/influxdb/chronograf:${CIRCLE_SHA1:0:7}
|
||||
- docker tag chronograf quay.io/influxdb/chronograf:${CIRCLE_TAG}
|
||||
- docker push quay.io/influxdb/chronograf:${CIRCLE_TAG}
|
||||
- mv ./build/* $CIRCLE_ARTIFACTS
|
||||
release:
|
||||
tag: /^[0-9]+(\.[0-9]+)*$/
|
||||
commands:
|
||||
- >
|
||||
./etc/scripts/docker/run.sh
|
||||
--clean
|
||||
--debug
|
||||
--release
|
||||
--package
|
||||
--platform all
|
||||
--arch all
|
||||
--upload-overwrite
|
||||
--upload
|
||||
--bucket dl.influxdata.com/chronograf/releases
|
||||
- sudo chown -R ubuntu:ubuntu /home/ubuntu
|
||||
- cp build/linux/static_amd64/chronograf .
|
||||
- cp build/linux/static_amd64/chronoctl .
|
||||
- docker build -t chronograf .
|
||||
- docker login -e $QUAY_EMAIL -u "$QUAY_USER" -p $QUAY_PASS quay.io
|
||||
- docker tag chronograf quay.io/influxdb/chronograf:${CIRCLE_SHA1:0:7}
|
||||
- docker push quay.io/influxdb/chronograf:${CIRCLE_SHA1:0:7}
|
||||
- docker tag chronograf quay.io/influxdb/chronograf:${CIRCLE_TAG}
|
||||
- docker push quay.io/influxdb/chronograf:${CIRCLE_TAG}
|
||||
- docker tag chronograf quay.io/influxdb/chronograf:latest
|
||||
- docker push quay.io/influxdb/chronograf:latest
|
||||
- mv ./build/* $CIRCLE_ARTIFACTS
|
|
@ -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
|
||||
case "tagValue", "timeStamp":
|
||||
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
|
||||
}
|
||||
|
||||
|
|
|
@ -4090,6 +4090,10 @@
|
|||
"enum": ["csv", "tagKey", "tagValue", "fieldKey", "timeStamp"],
|
||||
"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."
|
||||
},
|
||||
"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 {
|
||||
default:
|
||||
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 {
|
||||
switch v.Type {
|
||||
default:
|
||||
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 {
|
||||
return fmt.Errorf("No query set for template of type 'query'")
|
||||
if template.Type == "influxql" && template.Query == nil {
|
||||
return fmt.Errorf("No query set for template of type 'influxql'")
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
@ -57,7 +57,37 @@ func TestValidTemplateRequest(t *testing.T) {
|
|||
name: "No query set",
|
||||
wantErr: true,
|
||||
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",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ import UsersTable from 'src/admin/components/UsersTable'
|
|||
import RolesTable from 'src/admin/components/RolesTable'
|
||||
import QueriesPage from 'src/admin/containers/QueriesPage'
|
||||
import DatabaseManagerPage from 'src/admin/containers/DatabaseManagerPage'
|
||||
import SourceIndicator from 'shared/components/SourceIndicator'
|
||||
import PageHeader from 'shared/components/PageHeader'
|
||||
import FancyScrollbar from 'shared/components/FancyScrollbar'
|
||||
import SubSections from 'shared/components/SubSections'
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
|
@ -223,16 +223,7 @@ class AdminInfluxDBPage extends Component {
|
|||
|
||||
return (
|
||||
<div className="page">
|
||||
<div className="page-header">
|
||||
<div className="page-header__container">
|
||||
<div className="page-header__left">
|
||||
<h1 className="page-header__title">InfluxDB Admin</h1>
|
||||
</div>
|
||||
<div className="page-header__right">
|
||||
<SourceIndicator />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<PageHeader title="InfluxDB Admin" sourceIndicator={true} />
|
||||
<FancyScrollbar className="page-contents">
|
||||
{users ? (
|
||||
<div className="container-fluid">
|
||||
|
|
|
@ -2,6 +2,7 @@ import React from 'react'
|
|||
import PropTypes from 'prop-types'
|
||||
import {connect} from 'react-redux'
|
||||
|
||||
import PageHeader from 'src/shared/components/PageHeader'
|
||||
import SubSections from 'src/shared/components/SubSections'
|
||||
import FancyScrollbar from 'shared/components/FancyScrollbar'
|
||||
|
||||
|
@ -49,13 +50,7 @@ const sections = me => [
|
|||
|
||||
const AdminChronografPage = ({me, source, params: {tab}}) => (
|
||||
<div className="page">
|
||||
<div className="page-header">
|
||||
<div className="page-header__container">
|
||||
<div className="page-header__left">
|
||||
<h1 className="page-header__title">Chronograf Admin</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<PageHeader title="Chronograf Admin" />
|
||||
<FancyScrollbar className="page-contents">
|
||||
<div className="container-fluid">
|
||||
<SubSections
|
||||
|
|
|
@ -48,7 +48,7 @@ interface State {
|
|||
|
||||
@ErrorHandling
|
||||
export class AllUsersPage extends PureComponent<Props, State> {
|
||||
constructor(props) {
|
||||
constructor(props: Props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import {proxy} from 'src/utils/queryUrlGenerator'
|
||||
import {TimeRange} from '../../types'
|
||||
import {TimeRange} from 'src/types'
|
||||
|
||||
export const getAlerts = (
|
||||
source: string,
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import React, {PureComponent} from 'react'
|
||||
|
||||
import SourceIndicator from 'src/shared/components/SourceIndicator'
|
||||
import AlertsTable from 'src/alerts/components/AlertsTable'
|
||||
import NoKapacitorError from 'src/shared/components/NoKapacitorError'
|
||||
import CustomTimeRangeDropdown from 'src/shared/components/CustomTimeRangeDropdown'
|
||||
import PageHeader from 'src/shared/components/PageHeader'
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
|
||||
import {getAlerts} from 'src/alerts/apis'
|
||||
|
@ -85,7 +85,7 @@ class AlertsApp extends PureComponent<Props, State> {
|
|||
}
|
||||
public render() {
|
||||
const {isWidget, source} = this.props
|
||||
const {loading, timeRange} = this.state
|
||||
const {loading} = this.state
|
||||
|
||||
if (loading || !source) {
|
||||
return <div className="page-spinner" />
|
||||
|
@ -95,20 +95,11 @@ class AlertsApp extends PureComponent<Props, State> {
|
|||
this.renderSubComponents()
|
||||
) : (
|
||||
<div className="page alert-history-page">
|
||||
<div className="page-header">
|
||||
<div className="page-header__container">
|
||||
<div className="page-header__left">
|
||||
<h1 className="page-header__title">Alert History</h1>
|
||||
</div>
|
||||
<div className="page-header__right">
|
||||
<SourceIndicator />
|
||||
<CustomTimeRangeDropdown
|
||||
onApplyTimeRange={this.handleApplyTime}
|
||||
timeRange={timeRange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<PageHeader
|
||||
titleText="Alert History"
|
||||
optionsComponents={this.optionsComponents}
|
||||
sourceIndicator={true}
|
||||
/>
|
||||
<div className="page-contents">
|
||||
<div className="container-fluid">
|
||||
<div className="row">
|
||||
|
@ -120,6 +111,17 @@ class AlertsApp extends PureComponent<Props, State> {
|
|||
)
|
||||
}
|
||||
|
||||
private get optionsComponents(): JSX.Element {
|
||||
const {timeRange} = this.state
|
||||
|
||||
return (
|
||||
<CustomTimeRangeDropdown
|
||||
onApplyTimeRange={this.handleApplyTime}
|
||||
timeRange={timeRange}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
private fetchAlerts = (): void => {
|
||||
getAlerts(
|
||||
this.props.source.links.proxy,
|
||||
|
|
|
@ -3,7 +3,9 @@ import {replace} from 'react-router-redux'
|
|||
import _ from 'lodash'
|
||||
import queryString from 'query-string'
|
||||
|
||||
import {proxy} from 'src/utils/queryUrlGenerator'
|
||||
import {isUserAuthorized, EDITOR_ROLE} from 'src/auth/Authorized'
|
||||
import {parseMetaQuery} from 'src/tempVars/utils/parsing'
|
||||
|
||||
import {
|
||||
getDashboards as getDashboardsAJAX,
|
||||
|
@ -13,7 +15,6 @@ import {
|
|||
updateDashboardCell as updateDashboardCellAJAX,
|
||||
addDashboardCell as addDashboardCellAJAX,
|
||||
deleteDashboardCell as deleteDashboardCellAJAX,
|
||||
getTempVarValuesBySourceQuery,
|
||||
createDashboard as createDashboardAJAX,
|
||||
} from 'src/dashboards/apis'
|
||||
import {getMe} from 'src/shared/apis/auth'
|
||||
|
@ -46,7 +47,6 @@ import {
|
|||
} from 'src/shared/copy/notifications'
|
||||
|
||||
import {makeQueryForTemplate} from 'src/dashboards/utils/tempVars'
|
||||
import parsers from 'src/shared/parsing'
|
||||
import {getDeep} from 'src/utils/wrappers'
|
||||
|
||||
import idNormalizer, {TYPE_ID} from 'src/normalizers/id'
|
||||
|
@ -444,7 +444,7 @@ export const getDashboardsNamesAsync = (
|
|||
}
|
||||
}
|
||||
|
||||
export const getDashboardAsync = (dashboardID: string) => async (
|
||||
export const getDashboardAsync = (dashboardID: number) => async (
|
||||
dispatch
|
||||
): Promise<Dashboard | null> => {
|
||||
try {
|
||||
|
@ -690,25 +690,23 @@ export const hydrateTempVarValuesAsync = (
|
|||
const dashboard = getState().dashboardUI.dashboards.find(
|
||||
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(
|
||||
({query}) => !!query.influxql
|
||||
)
|
||||
|
||||
const asyncQueries = tempsWithQueries.map(({query}) =>
|
||||
getTempVarValuesBySourceQuery(source, {
|
||||
query: makeQueryForTemplate(query),
|
||||
return {template, values}
|
||||
})
|
||||
)
|
||||
const results = await Promise.all(queries)
|
||||
|
||||
const results = await Promise.all(asyncQueries)
|
||||
|
||||
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))
|
||||
})
|
||||
for (const {template, values} of results) {
|
||||
dispatch(editTemplateVariableValues(+dashboard.id, template.id, values))
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
dispatch(errorThrown(error))
|
||||
|
@ -946,7 +944,7 @@ type GetDashboardWithHydratedAndSyncedTempVarsAsyncActionCreator = (
|
|||
) => Promise<void>
|
||||
|
||||
export const getDashboardWithHydratedAndSyncedTempVarsAsync = (
|
||||
dashboardID: string,
|
||||
dashboardID: number,
|
||||
source: Source,
|
||||
router: InjectedRouter,
|
||||
location: Location
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import AJAX from 'utils/ajax'
|
||||
import {proxy} from 'utils/queryUrlGenerator'
|
||||
|
||||
export function getDashboards() {
|
||||
return AJAX({
|
||||
|
@ -98,19 +97,3 @@ export const editTemplateVariables = async templateVariable => {
|
|||
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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,147 +0,0 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import classnames from 'classnames'
|
||||
|
||||
import Authorized, {EDITOR_ROLE} from 'src/auth/Authorized'
|
||||
|
||||
import AutoRefreshDropdown from 'shared/components/AutoRefreshDropdown'
|
||||
import TimeRangeDropdown from 'shared/components/TimeRangeDropdown'
|
||||
import SourceIndicator from 'shared/components/SourceIndicator'
|
||||
import GraphTips from 'shared/components/GraphTips'
|
||||
import DashboardHeaderEdit from 'src/dashboards/components/DashboardHeaderEdit'
|
||||
import DashboardSwitcher from 'src/dashboards/components/DashboardSwitcher'
|
||||
|
||||
const DashboardHeader = ({
|
||||
names,
|
||||
onSave,
|
||||
onCancel,
|
||||
isEditMode,
|
||||
isHidden,
|
||||
dashboard,
|
||||
onAddCell,
|
||||
autoRefresh,
|
||||
activeDashboard,
|
||||
onEditDashboard,
|
||||
onManualRefresh,
|
||||
handleChooseTimeRange,
|
||||
handleChooseAutoRefresh,
|
||||
onToggleTempVarControls,
|
||||
showTemplateControlBar,
|
||||
timeRange: {upper, lower},
|
||||
handleClickPresentationButton,
|
||||
zoomedTimeRange: {lower: zoomedLower, upper: zoomedUpper},
|
||||
}) =>
|
||||
isHidden ? null : (
|
||||
<div className="page-header full-width">
|
||||
<div className="page-header__container">
|
||||
<div
|
||||
className={
|
||||
dashboard
|
||||
? 'page-header__left page-header__dash-editable'
|
||||
: 'page-header__left'
|
||||
}
|
||||
>
|
||||
{names && names.length > 1 ? (
|
||||
<DashboardSwitcher
|
||||
names={names}
|
||||
activeDashboard={activeDashboard}
|
||||
/>
|
||||
) : null}
|
||||
{dashboard ? (
|
||||
<Authorized
|
||||
requiredRole={EDITOR_ROLE}
|
||||
replaceWithIfNotAuthorized={
|
||||
<h1 className="page-header__title">{activeDashboard}</h1>
|
||||
}
|
||||
>
|
||||
<DashboardHeaderEdit
|
||||
onSave={onSave}
|
||||
onCancel={onCancel}
|
||||
activeDashboard={activeDashboard}
|
||||
onEditDashboard={onEditDashboard}
|
||||
isEditMode={isEditMode}
|
||||
/>
|
||||
</Authorized>
|
||||
) : (
|
||||
<h1 className="page-header__title">{activeDashboard}</h1>
|
||||
)}
|
||||
</div>
|
||||
<div className="page-header__right">
|
||||
<GraphTips />
|
||||
<SourceIndicator />
|
||||
{dashboard ? (
|
||||
<Authorized requiredRole={EDITOR_ROLE}>
|
||||
<button className="btn btn-primary btn-sm" onClick={onAddCell}>
|
||||
<span className="icon plus" />
|
||||
Add Cell
|
||||
</button>
|
||||
</Authorized>
|
||||
) : null}
|
||||
{dashboard ? (
|
||||
<div
|
||||
className={classnames('btn btn-default btn-sm', {
|
||||
active: showTemplateControlBar,
|
||||
})}
|
||||
onClick={onToggleTempVarControls}
|
||||
>
|
||||
<span className="icon cube" />Template Variables
|
||||
</div>
|
||||
) : null}
|
||||
<AutoRefreshDropdown
|
||||
onChoose={handleChooseAutoRefresh}
|
||||
onManualRefresh={onManualRefresh}
|
||||
selected={autoRefresh}
|
||||
iconName="refresh"
|
||||
/>
|
||||
<TimeRangeDropdown
|
||||
onChooseTimeRange={handleChooseTimeRange}
|
||||
selected={{
|
||||
upper: zoomedUpper || upper,
|
||||
lower: zoomedLower || lower,
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
className="btn btn-default btn-sm btn-square"
|
||||
onClick={handleClickPresentationButton}
|
||||
>
|
||||
<span className="icon expand-a" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
const {arrayOf, bool, func, number, shape, string} = PropTypes
|
||||
|
||||
DashboardHeader.defaultProps = {
|
||||
zoomedTimeRange: {
|
||||
lower: null,
|
||||
upper: null,
|
||||
},
|
||||
}
|
||||
|
||||
DashboardHeader.propTypes = {
|
||||
activeDashboard: string.isRequired,
|
||||
onEditDashboard: func,
|
||||
dashboard: shape({}),
|
||||
timeRange: shape({
|
||||
lower: string,
|
||||
upper: string,
|
||||
}).isRequired,
|
||||
autoRefresh: number.isRequired,
|
||||
isHidden: bool.isRequired,
|
||||
isEditMode: bool,
|
||||
handleChooseTimeRange: func.isRequired,
|
||||
handleChooseAutoRefresh: func.isRequired,
|
||||
onManualRefresh: func.isRequired,
|
||||
handleClickPresentationButton: func.isRequired,
|
||||
onAddCell: func,
|
||||
onToggleTempVarControls: func,
|
||||
showTemplateControlBar: bool,
|
||||
zoomedTimeRange: shape({}),
|
||||
onCancel: func,
|
||||
onSave: func,
|
||||
names: arrayOf(shape({})).isRequired,
|
||||
}
|
||||
|
||||
export default DashboardHeader
|
|
@ -0,0 +1,189 @@
|
|||
import React, {Component} from 'react'
|
||||
import classnames from 'classnames'
|
||||
|
||||
import Authorized, {EDITOR_ROLE} from 'src/auth/Authorized'
|
||||
|
||||
import PageHeader from 'src/shared/components/PageHeader'
|
||||
import PageHeaderTitle from 'src/shared/components/PageHeaderTitle'
|
||||
import AutoRefreshDropdown from 'src/shared/components/AutoRefreshDropdown'
|
||||
import TimeRangeDropdown from 'src/shared/components/TimeRangeDropdown'
|
||||
import GraphTips from 'src/shared/components/GraphTips'
|
||||
import DashboardHeaderEdit from 'src/dashboards/components/DashboardHeaderEdit'
|
||||
import DashboardSwitcher from 'src/dashboards/components/DashboardSwitcher'
|
||||
import {Dashboard, TimeRange} from 'src/types'
|
||||
|
||||
interface DashboardName {
|
||||
text: string
|
||||
}
|
||||
|
||||
interface Props {
|
||||
activeDashboard: string
|
||||
dashboard: Dashboard
|
||||
onEditDashboard: () => void
|
||||
timeRange: TimeRange
|
||||
autoRefresh: number
|
||||
isEditMode?: boolean
|
||||
handleChooseTimeRange: (timeRange: TimeRange) => void
|
||||
handleChooseAutoRefresh: () => void
|
||||
onManualRefresh: () => void
|
||||
handleClickPresentationButton: () => void
|
||||
onAddCell: () => void
|
||||
onToggleTempVarControls: () => void
|
||||
showTemplateControlBar: boolean
|
||||
zoomedTimeRange: TimeRange
|
||||
onCancel: () => void
|
||||
onSave: () => void
|
||||
names: DashboardName[]
|
||||
isHidden: boolean
|
||||
}
|
||||
|
||||
class DashboardHeader extends Component<Props> {
|
||||
public static defaultProps: Partial<Props> = {
|
||||
zoomedTimeRange: {
|
||||
upper: null,
|
||||
lower: null,
|
||||
},
|
||||
}
|
||||
|
||||
public render() {
|
||||
const {isHidden} = this.props
|
||||
|
||||
return (
|
||||
<PageHeader
|
||||
fullWidth={true}
|
||||
sourceIndicator={true}
|
||||
titleComponents={this.renderPageTitle}
|
||||
optionsComponents={this.optionsComponents}
|
||||
inPresentationMode={isHidden}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
private get renderPageTitle(): JSX.Element {
|
||||
return (
|
||||
<>
|
||||
{this.dashboardSwitcher}
|
||||
{this.dashboardTitle}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
private get optionsComponents(): JSX.Element {
|
||||
const {
|
||||
handleChooseAutoRefresh,
|
||||
onManualRefresh,
|
||||
autoRefresh,
|
||||
handleChooseTimeRange,
|
||||
timeRange: {upper, lower},
|
||||
zoomedTimeRange: {upper: zoomedUpper, lower: zoomedLower},
|
||||
handleClickPresentationButton,
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
<>
|
||||
<GraphTips />
|
||||
{this.addCellButton}
|
||||
{this.tempVarsButton}
|
||||
<AutoRefreshDropdown
|
||||
onChoose={handleChooseAutoRefresh}
|
||||
onManualRefresh={onManualRefresh}
|
||||
selected={autoRefresh}
|
||||
iconName="refresh"
|
||||
/>
|
||||
<TimeRangeDropdown
|
||||
onChooseTimeRange={handleChooseTimeRange}
|
||||
selected={{
|
||||
upper: zoomedUpper || upper,
|
||||
lower: zoomedLower || lower,
|
||||
}}
|
||||
/>
|
||||
<button
|
||||
className="btn btn-default btn-sm btn-square"
|
||||
onClick={handleClickPresentationButton}
|
||||
>
|
||||
<span className="icon expand-a" />
|
||||
</button>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
private get addCellButton(): JSX.Element {
|
||||
const {dashboard, onAddCell} = this.props
|
||||
|
||||
if (dashboard) {
|
||||
return (
|
||||
<Authorized requiredRole={EDITOR_ROLE}>
|
||||
<button className="btn btn-primary btn-sm" onClick={onAddCell}>
|
||||
<span className="icon plus" />
|
||||
Add Cell
|
||||
</button>
|
||||
</Authorized>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private get tempVarsButton(): JSX.Element {
|
||||
const {
|
||||
dashboard,
|
||||
showTemplateControlBar,
|
||||
onToggleTempVarControls,
|
||||
} = this.props
|
||||
|
||||
if (dashboard) {
|
||||
return (
|
||||
<div
|
||||
className={classnames('btn btn-default btn-sm', {
|
||||
active: showTemplateControlBar,
|
||||
})}
|
||||
onClick={onToggleTempVarControls}
|
||||
>
|
||||
<span className="icon cube" />Template Variables
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private get dashboardSwitcher(): JSX.Element {
|
||||
const {names, activeDashboard} = this.props
|
||||
|
||||
if (names && names.length > 1) {
|
||||
return (
|
||||
<DashboardSwitcher names={names} activeDashboard={activeDashboard} />
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private get dashboardTitle(): JSX.Element {
|
||||
const {
|
||||
dashboard,
|
||||
activeDashboard,
|
||||
onSave,
|
||||
onCancel,
|
||||
onEditDashboard,
|
||||
isEditMode,
|
||||
} = this.props
|
||||
|
||||
if (dashboard) {
|
||||
return (
|
||||
<Authorized
|
||||
requiredRole={EDITOR_ROLE}
|
||||
replaceWithIfNotAuthorized={
|
||||
<PageHeaderTitle title={activeDashboard} />
|
||||
}
|
||||
>
|
||||
<DashboardHeaderEdit
|
||||
onSave={onSave}
|
||||
onCancel={onCancel}
|
||||
activeDashboard={activeDashboard}
|
||||
onEditDashboard={onEditDashboard}
|
||||
isEditMode={isEditMode}
|
||||
/>
|
||||
</Authorized>
|
||||
)
|
||||
}
|
||||
|
||||
return <PageHeaderTitle title={activeDashboard} />
|
||||
}
|
||||
}
|
||||
|
||||
export default DashboardHeader
|
|
@ -1,18 +0,0 @@
|
|||
import React from 'react'
|
||||
|
||||
import SourceIndicator from 'src/shared/components/SourceIndicator'
|
||||
|
||||
const DashboardsHeader = (): JSX.Element => (
|
||||
<div className="page-header">
|
||||
<div className="page-header__container">
|
||||
<div className="page-header__left">
|
||||
<h1 className="page-header__title">Dashboards</h1>
|
||||
</div>
|
||||
<div className="page-header__right">
|
||||
<SourceIndicator />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
export default DashboardsHeader
|
|
@ -12,7 +12,7 @@ import {
|
|||
applyMasks,
|
||||
insertTempVar,
|
||||
unMask,
|
||||
} from 'src/dashboards/constants'
|
||||
} from 'src/tempVars/constants'
|
||||
|
||||
@ErrorHandling
|
||||
class QueryTextArea extends Component {
|
||||
|
|
|
@ -4,8 +4,8 @@ import {connect} from 'react-redux'
|
|||
import download from 'src/external/download'
|
||||
import _ from 'lodash'
|
||||
|
||||
import DashboardsHeader from 'src/dashboards/components/DashboardsHeader'
|
||||
import DashboardsContents from 'src/dashboards/components/DashboardsPageContents'
|
||||
import PageHeader from 'src/shared/components/PageHeader'
|
||||
|
||||
import {createDashboard} from 'src/dashboards/apis'
|
||||
import {
|
||||
|
@ -54,7 +54,7 @@ class DashboardsPage extends PureComponent<Props> {
|
|||
|
||||
return (
|
||||
<div className="page">
|
||||
<DashboardsHeader />
|
||||
<PageHeader titleText="Dashboards" sourceIndicator={true} />
|
||||
<DashboardsContents
|
||||
dashboardLink={dashboardLink}
|
||||
dashboards={dashboards}
|
||||
|
|
|
@ -32,7 +32,7 @@ export const generateURLQueryParamsFromTempVars = (
|
|||
const selected = values.find(value => value.selected === true)
|
||||
const strippedTempVar = stripTempVar(tempVar)
|
||||
|
||||
urlQueryParams[strippedTempVar] = selected.value
|
||||
urlQueryParams[strippedTempVar] = _.get(selected, 'value', '')
|
||||
})
|
||||
|
||||
return urlQueryParams
|
||||
|
|
|
@ -24,8 +24,8 @@ class WriteDataHeader extends PureComponent<Props> {
|
|||
|
||||
return (
|
||||
<div className="write-data-form--header">
|
||||
<div className="page-header__left">
|
||||
<h1 className="page-header__title">Write Data To</h1>
|
||||
<div className="page-header--left">
|
||||
<h1 className="page-header--title">Write Data To</h1>
|
||||
<DatabaseDropdown
|
||||
source={source}
|
||||
onSelectDatabase={handleSelectDatabase}
|
||||
|
@ -45,7 +45,7 @@ class WriteDataHeader extends PureComponent<Props> {
|
|||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div className="page-header__right">
|
||||
<div className="page-header--right">
|
||||
<span className="page-header__dismiss" onClick={onClose} />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -12,10 +12,13 @@ import {stripPrefix} from 'src/utils/basepath'
|
|||
import QueryMaker from 'src/data_explorer/components/QueryMaker'
|
||||
import Visualization from 'src/data_explorer/components/Visualization'
|
||||
import WriteDataForm from 'src/data_explorer/components/WriteDataForm'
|
||||
import Header from 'src/data_explorer/containers/Header'
|
||||
import ResizeContainer from 'src/shared/components/ResizeContainer'
|
||||
import OverlayTechnologies from 'src/shared/components/OverlayTechnologies'
|
||||
import ManualRefresh from 'src/shared/components/ManualRefresh'
|
||||
import AutoRefreshDropdown from 'src/shared/components/AutoRefreshDropdown'
|
||||
import TimeRangeDropdown from 'src/shared/components/TimeRangeDropdown'
|
||||
import GraphTips from 'src/shared/components/GraphTips'
|
||||
import PageHeader from 'src/shared/components/PageHeader'
|
||||
|
||||
import {VIS_VIEWS, AUTO_GROUP_BY, TEMPLATES} from 'src/shared/constants'
|
||||
import {MINIMUM_HEIGHTS, INITIAL_HEIGHTS} from 'src/data_explorer/constants'
|
||||
|
@ -93,11 +96,9 @@ export class DataExplorer extends PureComponent<Props, State> {
|
|||
autoRefresh,
|
||||
queryConfigs,
|
||||
manualRefresh,
|
||||
onManualRefresh,
|
||||
errorThrownAction,
|
||||
writeLineProtocol,
|
||||
queryConfigActions,
|
||||
handleChooseAutoRefresh,
|
||||
} = this.props
|
||||
|
||||
const {showWriteForm} = this.state
|
||||
|
@ -115,13 +116,11 @@ export class DataExplorer extends PureComponent<Props, State> {
|
|||
/>
|
||||
</OverlayTechnologies>
|
||||
) : null}
|
||||
<Header
|
||||
timeRange={timeRange}
|
||||
autoRefresh={autoRefresh}
|
||||
showWriteForm={this.handleOpenWriteData}
|
||||
onChooseTimeRange={this.handleChooseTimeRange}
|
||||
onChooseAutoRefresh={handleChooseAutoRefresh}
|
||||
onManualRefresh={onManualRefresh}
|
||||
<PageHeader
|
||||
titleText="Data Explorer"
|
||||
fullWidth={true}
|
||||
optionsComponents={this.optionsComponents}
|
||||
sourceIndicator={true}
|
||||
/>
|
||||
<ResizeContainer
|
||||
containerClass="page-contents"
|
||||
|
@ -186,6 +185,40 @@ export class DataExplorer extends PureComponent<Props, State> {
|
|||
const {timeRange} = this.props
|
||||
return buildRawText(this.activeQuery, timeRange)
|
||||
}
|
||||
|
||||
private get optionsComponents(): JSX.Element {
|
||||
const {
|
||||
timeRange,
|
||||
autoRefresh,
|
||||
onManualRefresh,
|
||||
handleChooseAutoRefresh,
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
<>
|
||||
<GraphTips />
|
||||
<div
|
||||
className="btn btn-sm btn-default"
|
||||
onClick={this.handleOpenWriteData}
|
||||
data-test="write-data-button"
|
||||
>
|
||||
<span className="icon pencil" />
|
||||
Write Data
|
||||
</div>
|
||||
<AutoRefreshDropdown
|
||||
iconName="refresh"
|
||||
selected={autoRefresh}
|
||||
onChoose={handleChooseAutoRefresh}
|
||||
onManualRefresh={onManualRefresh}
|
||||
/>
|
||||
<TimeRangeDropdown
|
||||
selected={timeRange}
|
||||
page="DataExplorer"
|
||||
onChooseTimeRange={this.handleChooseTimeRange}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = state => {
|
||||
|
|
|
@ -1,63 +0,0 @@
|
|||
import React, {PureComponent} from 'react'
|
||||
|
||||
import AutoRefreshDropdown from 'src/shared/components/AutoRefreshDropdown'
|
||||
import TimeRangeDropdown from 'src/shared/components/TimeRangeDropdown'
|
||||
import SourceIndicator from 'src/shared/components/SourceIndicator'
|
||||
import GraphTips from 'src/shared/components/GraphTips'
|
||||
import {TimeRange} from 'src/types'
|
||||
|
||||
interface Props {
|
||||
onChooseAutoRefresh: () => void
|
||||
onManualRefresh: () => void
|
||||
onChooseTimeRange: (timeRange: TimeRange) => void
|
||||
showWriteForm: () => void
|
||||
autoRefresh: number
|
||||
timeRange: TimeRange
|
||||
}
|
||||
|
||||
class Header extends PureComponent<Props> {
|
||||
public render() {
|
||||
const {
|
||||
timeRange,
|
||||
autoRefresh,
|
||||
showWriteForm,
|
||||
onManualRefresh,
|
||||
onChooseTimeRange,
|
||||
onChooseAutoRefresh,
|
||||
} = this.props
|
||||
return (
|
||||
<div className="page-header full-width">
|
||||
<div className="page-header__container">
|
||||
<div className="page-header__left">
|
||||
<h1 className="page-header__title">Data Explorer</h1>
|
||||
</div>
|
||||
<div className="page-header__right">
|
||||
<GraphTips />
|
||||
<SourceIndicator />
|
||||
<div
|
||||
className="btn btn-sm btn-default"
|
||||
onClick={showWriteForm}
|
||||
data-test="write-data-button"
|
||||
>
|
||||
<span className="icon pencil" />
|
||||
Write Data
|
||||
</div>
|
||||
<AutoRefreshDropdown
|
||||
iconName="refresh"
|
||||
selected={autoRefresh}
|
||||
onChoose={onChooseAutoRefresh}
|
||||
onManualRefresh={onManualRefresh}
|
||||
/>
|
||||
<TimeRangeDropdown
|
||||
selected={timeRange}
|
||||
page="DataExplorer"
|
||||
onChooseTimeRange={onChooseTimeRange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default Header
|
|
@ -3,7 +3,10 @@ import _ from 'lodash'
|
|||
import AJAX from 'src/utils/ajax'
|
||||
import {Service, FluxTable} from 'src/types'
|
||||
import {updateService} from 'src/shared/apis'
|
||||
import {parseResponse} from 'src/shared/parsing/flux/response'
|
||||
import {
|
||||
parseResponse,
|
||||
parseResponseError,
|
||||
} from 'src/shared/parsing/flux/response'
|
||||
import {MAX_RESPONSE_BYTES} from 'src/flux/constants'
|
||||
|
||||
export const getSuggestions = async (url: string) => {
|
||||
|
@ -56,6 +59,9 @@ export const getTimeSeries = async (
|
|||
service.links.proxy
|
||||
}?path=/v1/query${mark}orgName=defaulorgname${and}q=${garbage}`
|
||||
|
||||
let responseBody: string
|
||||
let responseByteLength: number
|
||||
|
||||
try {
|
||||
// We are using the `fetch` API here since the `AJAX` utility lacks support
|
||||
// for limiting response size. The `AJAX` utility depends on
|
||||
|
@ -66,16 +72,28 @@ export const getTimeSeries = async (
|
|||
const resp = await fetch(url, {method: 'POST'})
|
||||
const {body, byteLength} = await decodeFluxRespWithLimit(resp)
|
||||
|
||||
return {
|
||||
tables: parseResponse(body),
|
||||
didTruncate: byteLength >= MAX_RESPONSE_BYTES,
|
||||
}
|
||||
responseBody = body
|
||||
responseByteLength = byteLength
|
||||
} catch (error) {
|
||||
console.error('Problem fetching data', error)
|
||||
|
||||
throw _.get(error, 'headers.x-influx-error', false) ||
|
||||
_.get(error, 'data.message', 'unknown error 🤷')
|
||||
}
|
||||
|
||||
try {
|
||||
return {
|
||||
tables: parseResponse(responseBody),
|
||||
didTruncate: responseByteLength >= MAX_RESPONSE_BYTES,
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Could not parse response body', error)
|
||||
|
||||
return {
|
||||
tables: parseResponseError(responseBody),
|
||||
didTruncate: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const updateScript = async (service: Service, script: string) => {
|
||||
|
|
|
@ -3,12 +3,13 @@ import _ from 'lodash'
|
|||
|
||||
import FancyScrollbar from 'src/shared/components/FancyScrollbar'
|
||||
import ExpressionNode from 'src/flux/components/ExpressionNode'
|
||||
import VariableName from 'src/flux/components/VariableName'
|
||||
import VariableNode from 'src/flux/components/VariableNode'
|
||||
import FuncSelector from 'src/flux/components/FuncSelector'
|
||||
import BodyDelete from 'src/flux/components/BodyDelete'
|
||||
import {funcNames} from 'src/flux/constants'
|
||||
|
||||
import {Service} from 'src/types'
|
||||
import {FlatBody, Suggestion} from 'src/types/flux'
|
||||
import {Body, Suggestion} from 'src/types/flux'
|
||||
|
||||
interface Props {
|
||||
service: Service
|
||||
|
@ -16,21 +17,25 @@ interface Props {
|
|||
suggestions: Suggestion[]
|
||||
onAppendFrom: () => void
|
||||
onAppendJoin: () => void
|
||||
}
|
||||
|
||||
interface Body extends FlatBody {
|
||||
id: string
|
||||
onDeleteBody: (bodyID: string) => void
|
||||
}
|
||||
|
||||
class BodyBuilder extends PureComponent<Props> {
|
||||
public render() {
|
||||
const bodybuilder = this.props.body.map((b, i) => {
|
||||
const {body, onDeleteBody} = this.props
|
||||
|
||||
const bodybuilder = body.map((b, i) => {
|
||||
if (b.declarations.length) {
|
||||
return b.declarations.map(d => {
|
||||
if (d.funcs) {
|
||||
return (
|
||||
<div className="declaration" key={i}>
|
||||
<VariableName name={d.name} assignedToQuery={true} />
|
||||
<div className="func-node--wrapper">
|
||||
<VariableNode name={d.name} assignedToQuery={true} />
|
||||
<div className="func-node--menu">
|
||||
<BodyDelete bodyID={b.id} onDeleteBody={onDeleteBody} />
|
||||
</div>
|
||||
</div>
|
||||
<ExpressionNode
|
||||
bodyID={b.id}
|
||||
declarationID={d.id}
|
||||
|
@ -38,6 +43,7 @@ class BodyBuilder extends PureComponent<Props> {
|
|||
funcs={d.funcs}
|
||||
declarationsFromBody={this.declarationsFromBody}
|
||||
isLastBody={this.isLastBody(i)}
|
||||
onDeleteBody={onDeleteBody}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
@ -45,7 +51,16 @@ class BodyBuilder extends PureComponent<Props> {
|
|||
|
||||
return (
|
||||
<div className="declaration" key={i}>
|
||||
<VariableName name={b.source} assignedToQuery={false} />
|
||||
<div className="func-node--wrapper">
|
||||
<VariableNode name={b.source} assignedToQuery={false} />
|
||||
<div className="func-node--menu">
|
||||
<BodyDelete
|
||||
bodyID={b.id}
|
||||
type="variable"
|
||||
onDeleteBody={onDeleteBody}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
@ -59,6 +74,7 @@ class BodyBuilder extends PureComponent<Props> {
|
|||
funcNames={this.funcNames}
|
||||
declarationsFromBody={this.declarationsFromBody}
|
||||
isLastBody={this.isLastBody(i)}
|
||||
onDeleteBody={onDeleteBody}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
import React, {PureComponent} from 'react'
|
||||
import ConfirmButton from 'src/shared/components/ConfirmButton'
|
||||
|
||||
type BodyType = 'variable' | 'query'
|
||||
|
||||
interface Props {
|
||||
bodyID: string
|
||||
type?: BodyType
|
||||
onDeleteBody: (bodyID: string) => void
|
||||
}
|
||||
|
||||
class BodyDelete extends PureComponent<Props> {
|
||||
public static defaultProps: Partial<Props> = {
|
||||
type: 'query',
|
||||
}
|
||||
|
||||
public render() {
|
||||
const {type} = this.props
|
||||
|
||||
if (type === 'variable') {
|
||||
return (
|
||||
<button
|
||||
className="btn btn-sm btn-square btn-danger"
|
||||
title="Delete Variable"
|
||||
onClick={this.handleDelete}
|
||||
>
|
||||
<span className="icon remove" />
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<ConfirmButton
|
||||
icon="trash"
|
||||
type="btn-danger"
|
||||
confirmText="Delete Query"
|
||||
square={true}
|
||||
confirmAction={this.handleDelete}
|
||||
position="right"
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
private handleDelete = (): void => {
|
||||
this.props.onDeleteBody(this.props.bodyID)
|
||||
}
|
||||
}
|
||||
|
||||
export default BodyDelete
|
|
@ -1,12 +1,12 @@
|
|||
import React, {PureComponent, Fragment} from 'react'
|
||||
import _ from 'lodash'
|
||||
|
||||
import {FluxContext} from 'src/flux/containers/FluxPage'
|
||||
import FuncSelector from 'src/flux/components/FuncSelector'
|
||||
import FuncNode from 'src/flux/components/FuncNode'
|
||||
import YieldFuncNode from 'src/flux/components/YieldFuncNode'
|
||||
import {getDeep} from 'src/utils/wrappers'
|
||||
|
||||
import {Func} from 'src/types/flux'
|
||||
import {Func, Context} from 'src/types/flux'
|
||||
|
||||
interface Props {
|
||||
funcNames: any[]
|
||||
|
@ -15,13 +15,13 @@ interface Props {
|
|||
declarationID?: string
|
||||
declarationsFromBody: string[]
|
||||
isLastBody: boolean
|
||||
onDeleteBody: (bodyID: string) => void
|
||||
}
|
||||
|
||||
interface State {
|
||||
nonYieldableIndexesToggled: {
|
||||
[x: number]: boolean
|
||||
}
|
||||
isImplicitYieldToggled: boolean
|
||||
}
|
||||
|
||||
// an Expression is a group of one or more functions
|
||||
|
@ -31,7 +31,6 @@ class ExpressionNode extends PureComponent<Props, State> {
|
|||
|
||||
this.state = {
|
||||
nonYieldableIndexesToggled: {},
|
||||
isImplicitYieldToggled: this.isImplicitYieldToggled,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -42,6 +41,7 @@ class ExpressionNode extends PureComponent<Props, State> {
|
|||
funcNames,
|
||||
funcs,
|
||||
declarationsFromBody,
|
||||
onDeleteBody,
|
||||
} = this.props
|
||||
|
||||
const {nonYieldableIndexesToggled} = this.state
|
||||
|
@ -57,13 +57,17 @@ class ExpressionNode extends PureComponent<Props, State> {
|
|||
service,
|
||||
data,
|
||||
scriptUpToYield,
|
||||
}) => {
|
||||
}: Context) => {
|
||||
let isAfterRange = false
|
||||
let isAfterFilter = false
|
||||
|
||||
return (
|
||||
<>
|
||||
{funcs.map((func, i) => {
|
||||
if (func.name === 'yield') {
|
||||
return null
|
||||
}
|
||||
|
||||
if (func.name === 'range') {
|
||||
isAfterRange = true
|
||||
}
|
||||
|
@ -72,22 +76,7 @@ class ExpressionNode extends PureComponent<Props, State> {
|
|||
isAfterFilter = true
|
||||
}
|
||||
|
||||
if (func.name === 'yield') {
|
||||
const script = scriptUpToYield(bodyID, declarationID, i, true)
|
||||
|
||||
return (
|
||||
<YieldFuncNode
|
||||
index={i}
|
||||
key={i}
|
||||
func={func}
|
||||
data={data}
|
||||
script={script}
|
||||
bodyID={bodyID}
|
||||
service={service}
|
||||
declarationID={declarationID}
|
||||
/>
|
||||
)
|
||||
}
|
||||
const isYieldable = isAfterFilter && isAfterRange
|
||||
|
||||
const funcNode = (
|
||||
<FuncNode
|
||||
|
@ -100,21 +89,26 @@ class ExpressionNode extends PureComponent<Props, State> {
|
|||
onChangeArg={onChangeArg}
|
||||
onDelete={onDeleteFuncNode}
|
||||
onToggleYield={onToggleYield}
|
||||
isYieldable={isAfterFilter && isAfterRange}
|
||||
isYielding={this.isBeforeFuncYield(i)}
|
||||
isYieldable={isYieldable}
|
||||
isYielding={this.isBeforeYielding(i)}
|
||||
isYieldedInScript={this.isYieldNodeIndex(i + 1)}
|
||||
declarationID={declarationID}
|
||||
onGenerateScript={onGenerateScript}
|
||||
declarationsFromBody={declarationsFromBody}
|
||||
onToggleYieldWithLast={this.handleToggleYieldWithLast}
|
||||
onDeleteBody={onDeleteBody}
|
||||
/>
|
||||
)
|
||||
|
||||
if (nonYieldableIndexesToggled[i]) {
|
||||
const script = scriptUpToYield(
|
||||
if (
|
||||
nonYieldableIndexesToggled[i] ||
|
||||
this.isYieldNodeIndex(i + 1)
|
||||
) {
|
||||
const script: string = scriptUpToYield(
|
||||
bodyID,
|
||||
declarationID,
|
||||
i,
|
||||
false
|
||||
isYieldable
|
||||
)
|
||||
|
||||
return (
|
||||
|
@ -131,42 +125,9 @@ class ExpressionNode extends PureComponent<Props, State> {
|
|||
/>
|
||||
</Fragment>
|
||||
)
|
||||
} else if (this.isEndOfScript(i)) {
|
||||
const script = scriptUpToYield(bodyID, declarationID, i, true)
|
||||
|
||||
return (
|
||||
<Fragment key={`${i}-notInScript`}>
|
||||
<FuncNode
|
||||
key={i}
|
||||
index={i}
|
||||
func={func}
|
||||
funcs={funcs}
|
||||
bodyID={bodyID}
|
||||
service={service}
|
||||
onChangeArg={onChangeArg}
|
||||
onDelete={onDeleteFuncNode}
|
||||
onToggleYield={this.handleHideImplicitYield}
|
||||
isYieldable={isAfterFilter && isAfterRange}
|
||||
isYielding={this.isBeforeFuncYield(i)}
|
||||
declarationID={declarationID}
|
||||
onGenerateScript={onGenerateScript}
|
||||
declarationsFromBody={declarationsFromBody}
|
||||
onToggleYieldWithLast={this.handleToggleYieldWithLast}
|
||||
/>
|
||||
<YieldFuncNode
|
||||
index={i}
|
||||
func={func}
|
||||
data={data}
|
||||
script={script}
|
||||
bodyID={bodyID}
|
||||
service={service}
|
||||
declarationID={declarationID}
|
||||
/>
|
||||
</Fragment>
|
||||
)
|
||||
} else {
|
||||
return funcNode
|
||||
}
|
||||
|
||||
return funcNode
|
||||
})}
|
||||
<FuncSelector
|
||||
bodyID={bodyID}
|
||||
|
@ -181,45 +142,26 @@ class ExpressionNode extends PureComponent<Props, State> {
|
|||
)
|
||||
}
|
||||
|
||||
private isBeforeFuncYield(funcIndex: number): boolean {
|
||||
const {funcs, isLastBody} = this.props
|
||||
const {isImplicitYieldToggled} = this.state
|
||||
private isBeforeYielding(funcIndex: number): boolean {
|
||||
const {nonYieldableIndexesToggled} = this.state
|
||||
const beforeToggledLastYield = !!nonYieldableIndexesToggled[funcIndex]
|
||||
|
||||
if (
|
||||
funcIndex === funcs.length - 1 &&
|
||||
isLastBody &&
|
||||
isImplicitYieldToggled
|
||||
) {
|
||||
if (beforeToggledLastYield) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (funcIndex === funcs.length - 1) {
|
||||
return false
|
||||
}
|
||||
|
||||
const nextFunc = funcs[funcIndex + 1]
|
||||
|
||||
if (nextFunc.name === 'yield') {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
return this.isYieldNodeIndex(funcIndex + 1)
|
||||
}
|
||||
|
||||
private get isImplicitYieldToggled(): boolean {
|
||||
const {isLastBody} = this.props
|
||||
|
||||
return isLastBody && this.isLastFuncYield
|
||||
}
|
||||
|
||||
private get isLastFuncYield(): boolean {
|
||||
private isYieldNodeIndex(funcIndex: number): boolean {
|
||||
const {funcs} = this.props
|
||||
const funcName = getDeep<string>(funcs, `${funcIndex}.name`, '')
|
||||
|
||||
return _.get(funcs, `${funcs.length - 1}.name`) !== 'yield'
|
||||
return funcName === 'yield'
|
||||
}
|
||||
|
||||
// if funcNode is not yieldable, add last before yield()
|
||||
private handleToggleYieldWithLast = (funcNodeIndex: number) => {
|
||||
private handleToggleYieldWithLast = (funcNodeIndex: number): void => {
|
||||
this.setState(({nonYieldableIndexesToggled}) => {
|
||||
const isFuncYieldToggled = !!nonYieldableIndexesToggled[funcNodeIndex]
|
||||
|
||||
|
@ -231,20 +173,6 @@ class ExpressionNode extends PureComponent<Props, State> {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
private handleHideImplicitYield = () => {
|
||||
this.setState(() => ({
|
||||
isImplicitYieldToggled: false,
|
||||
}))
|
||||
}
|
||||
|
||||
private isEndOfScript(index: number): boolean {
|
||||
const {isLastBody, funcs} = this.props
|
||||
const {isImplicitYieldToggled} = this.state
|
||||
const isLastScriptFunc = isLastBody && index === funcs.length - 1
|
||||
|
||||
return isLastScriptFunc && isImplicitYieldToggled
|
||||
}
|
||||
}
|
||||
|
||||
export default ExpressionNode
|
||||
|
|
|
@ -5,9 +5,11 @@ import {tagKeys as fetchTagKeys} from 'src/shared/apis/flux/metaQueries'
|
|||
import parseValuesColumn from 'src/shared/parsing/flux/values'
|
||||
import FilterTagList from 'src/flux/components/FilterTagList'
|
||||
import Walker from 'src/flux/ast/walker'
|
||||
import {makeCancelable} from 'src/utils/promises'
|
||||
|
||||
import {Service} from 'src/types'
|
||||
import {Links, OnChangeArg, Func, FilterNode} from 'src/types/flux'
|
||||
import {WrappedCancelablePromise} from 'src/types/promises'
|
||||
|
||||
interface Props {
|
||||
links: Links
|
||||
|
@ -28,6 +30,8 @@ interface State {
|
|||
}
|
||||
|
||||
class FilterArgs extends PureComponent<Props, State> {
|
||||
private fetchTagKeysResponse?: WrappedCancelablePromise<string>
|
||||
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
|
@ -52,15 +56,24 @@ class FilterArgs extends PureComponent<Props, State> {
|
|||
}
|
||||
|
||||
public async componentDidMount() {
|
||||
const {db, service} = this.props
|
||||
|
||||
try {
|
||||
this.convertStringToNodes()
|
||||
const response = await fetchTagKeys(service, db, [])
|
||||
const response = await this.getTagKeys()
|
||||
const tagKeys = parseValuesColumn(response)
|
||||
this.setState({tagKeys})
|
||||
|
||||
this.setState({
|
||||
tagKeys,
|
||||
})
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
if (!error.isCanceled) {
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
if (this.fetchTagKeysResponse) {
|
||||
this.fetchTagKeysResponse.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -91,6 +104,14 @@ class FilterArgs extends PureComponent<Props, State> {
|
|||
/>
|
||||
)
|
||||
}
|
||||
|
||||
private getTagKeys(): Promise<string> {
|
||||
const {db, service} = this.props
|
||||
|
||||
this.fetchTagKeysResponse = makeCancelable(fetchTagKeys(service, db, []))
|
||||
|
||||
return this.fetchTagKeysResponse.promise
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = ({links}) => {
|
||||
|
|
|
@ -3,6 +3,7 @@ import {connect} from 'react-redux'
|
|||
|
||||
import FluxOverlay from 'src/flux/components/FluxOverlay'
|
||||
import {OverlayContext} from 'src/shared/components/OverlayTechnology'
|
||||
import PageHeader from 'src/shared/components/PageHeader'
|
||||
import {
|
||||
showOverlay as showOverlayAction,
|
||||
ShowOverlay,
|
||||
|
@ -18,18 +19,19 @@ interface Props {
|
|||
class FluxHeader extends PureComponent<Props> {
|
||||
public render() {
|
||||
return (
|
||||
<div className="page-header full-width">
|
||||
<div className="page-header__container">
|
||||
<div className="page-header__left">
|
||||
<h1 className="page-header__title">Flux Editor</h1>
|
||||
</div>
|
||||
<div className="page-header__right">
|
||||
<button onClick={this.overlay} className="btn btn-sm btn-default">
|
||||
Edit Connection
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<PageHeader
|
||||
titleText="Flux Editor"
|
||||
fullWidth={true}
|
||||
optionsComponents={this.optionsComponents}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
private get optionsComponents(): JSX.Element {
|
||||
return (
|
||||
<button onClick={this.overlay} className="btn btn-sm btn-default">
|
||||
Edit Connection
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -29,10 +29,10 @@ class FluxOverlay extends PureComponent<Props> {
|
|||
return (
|
||||
<div className="flux-overlay">
|
||||
<div className="template-variable-manager--header">
|
||||
<div className="page-header__left">
|
||||
<h1 className="page-header__title">Connect to Flux</h1>
|
||||
<div className="page-header--left">
|
||||
<h1 className="page-header--title">Connect to Flux</h1>
|
||||
</div>
|
||||
<div className="page-header__right">
|
||||
<div className="page-header--right">
|
||||
<span
|
||||
className="page-header__dismiss"
|
||||
onClick={this.props.onDismiss}
|
||||
|
|
|
@ -8,7 +8,7 @@ import {ErrorHandling} from 'src/shared/decorators/errors'
|
|||
import FromDatabaseDropdown from 'src/flux/components/FromDatabaseDropdown'
|
||||
|
||||
import {funcNames, argTypes} from 'src/flux/constants'
|
||||
import {OnChangeArg, Arg} from 'src/types/flux'
|
||||
import {OnChangeArg, Arg, OnGenerateScript} from 'src/types/flux'
|
||||
import {Service} from 'src/types'
|
||||
|
||||
interface Props {
|
||||
|
@ -22,7 +22,7 @@ interface Props {
|
|||
bodyID: string
|
||||
declarationID: string
|
||||
onChangeArg: OnChangeArg
|
||||
onGenerateScript: () => void
|
||||
onGenerateScript: OnGenerateScript
|
||||
}
|
||||
|
||||
@ErrorHandling
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React, {PureComponent, ChangeEvent, KeyboardEvent} from 'react'
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
import {OnChangeArg} from 'src/types/flux'
|
||||
import {OnChangeArg, OnGenerateScript} from 'src/types/flux'
|
||||
|
||||
interface Props {
|
||||
funcID: string
|
||||
|
@ -10,7 +10,7 @@ interface Props {
|
|||
bodyID: string
|
||||
declarationID: string
|
||||
onChangeArg: OnChangeArg
|
||||
onGenerateScript: () => void
|
||||
onGenerateScript: OnGenerateScript
|
||||
autoFocus?: boolean
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ import React, {PureComponent, ReactElement, MouseEvent} from 'react'
|
|||
import FuncArg from 'src/flux/components/FuncArg'
|
||||
import {OnChangeArg} from 'src/types/flux'
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
import {Func} from 'src/types/flux'
|
||||
import {Func, OnGenerateScript} from 'src/types/flux'
|
||||
import {funcNames} from 'src/flux/constants'
|
||||
import JoinArgs from 'src/flux/components/JoinArgs'
|
||||
import FilterArgs from 'src/flux/components/FilterArgs'
|
||||
|
@ -15,7 +15,7 @@ interface Props {
|
|||
bodyID: string
|
||||
onChangeArg: OnChangeArg
|
||||
declarationID: string
|
||||
onGenerateScript: () => void
|
||||
onGenerateScript: OnGenerateScript
|
||||
declarationsFromBody: string[]
|
||||
onStopPropagation: (e: MouseEvent<HTMLElement>) => void
|
||||
}
|
||||
|
|
|
@ -2,9 +2,11 @@ import React, {PureComponent, MouseEvent} from 'react'
|
|||
import classnames from 'classnames'
|
||||
import _ from 'lodash'
|
||||
|
||||
import BodyDelete from 'src/flux/components/BodyDelete'
|
||||
import FuncArgs from 'src/flux/components/FuncArgs'
|
||||
import FuncArgsPreview from 'src/flux/components/FuncArgsPreview'
|
||||
import {
|
||||
OnGenerateScript,
|
||||
OnDeleteFuncNode,
|
||||
OnChangeArg,
|
||||
OnToggleYield,
|
||||
|
@ -23,11 +25,13 @@ interface Props {
|
|||
onDelete: OnDeleteFuncNode
|
||||
onToggleYield: OnToggleYield
|
||||
onChangeArg: OnChangeArg
|
||||
onGenerateScript: () => void
|
||||
onGenerateScript: OnGenerateScript
|
||||
onToggleYieldWithLast: (funcNodeIndex: number) => void
|
||||
declarationsFromBody: string[]
|
||||
isYielding: boolean
|
||||
isYieldable: boolean
|
||||
onDeleteBody: (bodyID: string) => void
|
||||
isYieldedInScript: boolean
|
||||
}
|
||||
|
||||
interface State {
|
||||
|
@ -53,14 +57,16 @@ export default class FuncNode extends PureComponent<Props, State> {
|
|||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className={this.nodeClassName}
|
||||
onClick={this.handleToggleEdit}
|
||||
title="Edit function arguments"
|
||||
>
|
||||
<div className="func-node--connector" />
|
||||
<div className="func-node--name">{func.name}</div>
|
||||
<FuncArgsPreview func={func} />
|
||||
<div className="func-node--wrapper">
|
||||
<div
|
||||
className={this.nodeClassName}
|
||||
onClick={this.handleToggleEdit}
|
||||
title="Edit function arguments"
|
||||
>
|
||||
<div className="func-node--connector" />
|
||||
<div className="func-node--name">{func.name}</div>
|
||||
<FuncArgsPreview func={func} />
|
||||
</div>
|
||||
{this.funcMenu}
|
||||
</div>
|
||||
{this.funcArgs}
|
||||
|
@ -103,13 +109,7 @@ export default class FuncNode extends PureComponent<Props, State> {
|
|||
return (
|
||||
<div className="func-node--menu">
|
||||
{this.yieldToggleButton}
|
||||
<button
|
||||
className="btn btn-sm btn-square btn-danger"
|
||||
onClick={this.handleDelete}
|
||||
title="Delete this Function"
|
||||
>
|
||||
<span className="icon trash" />
|
||||
</button>
|
||||
{this.deleteButton}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -140,6 +140,24 @@ export default class FuncNode extends PureComponent<Props, State> {
|
|||
)
|
||||
}
|
||||
|
||||
private get deleteButton(): JSX.Element {
|
||||
const {func, bodyID, onDeleteBody} = this.props
|
||||
|
||||
if (func.name === 'from') {
|
||||
return <BodyDelete onDeleteBody={onDeleteBody} bodyID={bodyID} />
|
||||
}
|
||||
|
||||
return (
|
||||
<button
|
||||
className="btn btn-sm btn-square btn-danger"
|
||||
onClick={this.handleDelete}
|
||||
title="Delete this Function"
|
||||
>
|
||||
<span className="icon remove" />
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
private get nodeClassName(): string {
|
||||
const {isYielding} = this.props
|
||||
const {editing} = this.state
|
||||
|
@ -147,14 +165,14 @@ export default class FuncNode extends PureComponent<Props, State> {
|
|||
return classnames('func-node', {active: isYielding || editing})
|
||||
}
|
||||
|
||||
private handleDelete = (e: MouseEvent<HTMLElement>): void => {
|
||||
e.stopPropagation()
|
||||
private handleDelete = (): void => {
|
||||
const {func, bodyID, declarationID} = this.props
|
||||
|
||||
this.props.onDelete({funcID: func.id, bodyID, declarationID})
|
||||
}
|
||||
|
||||
private handleToggleEdit = (): void => {
|
||||
private handleToggleEdit = (e: MouseEvent<HTMLElement>): void => {
|
||||
e.stopPropagation()
|
||||
this.setState({editing: !this.state.editing})
|
||||
}
|
||||
|
||||
|
@ -166,11 +184,12 @@ export default class FuncNode extends PureComponent<Props, State> {
|
|||
index,
|
||||
bodyID,
|
||||
declarationID,
|
||||
isYieldable,
|
||||
onToggleYieldWithLast,
|
||||
isYieldable,
|
||||
isYieldedInScript,
|
||||
} = this.props
|
||||
|
||||
if (isYieldable) {
|
||||
if (isYieldedInScript || isYieldable) {
|
||||
onToggleYield(bodyID, declarationID, index)
|
||||
} else {
|
||||
onToggleYieldWithLast(index)
|
||||
|
|
|
@ -7,6 +7,7 @@ import {
|
|||
Suggestion,
|
||||
OnChangeScript,
|
||||
OnSubmitScript,
|
||||
OnDeleteBody,
|
||||
FlatBody,
|
||||
ScriptStatus,
|
||||
} from 'src/types/flux'
|
||||
|
@ -22,6 +23,7 @@ interface Props {
|
|||
status: ScriptStatus
|
||||
suggestions: Suggestion[]
|
||||
onChangeScript: OnChangeScript
|
||||
onDeleteBody: OnDeleteBody
|
||||
onSubmitScript: OnSubmitScript
|
||||
onAppendFrom: () => void
|
||||
onAppendJoin: () => void
|
||||
|
@ -63,7 +65,14 @@ class TimeMachine extends PureComponent<Props> {
|
|||
}
|
||||
|
||||
private get builder() {
|
||||
const {body, service, suggestions, onAppendFrom, onAppendJoin} = this.props
|
||||
const {
|
||||
body,
|
||||
service,
|
||||
suggestions,
|
||||
onAppendFrom,
|
||||
onDeleteBody,
|
||||
onAppendJoin,
|
||||
} = this.props
|
||||
|
||||
return {
|
||||
name: 'Build',
|
||||
|
@ -75,6 +84,7 @@ class TimeMachine extends PureComponent<Props> {
|
|||
body={body}
|
||||
service={service}
|
||||
suggestions={suggestions}
|
||||
onDeleteBody={onDeleteBody}
|
||||
onAppendFrom={onAppendFrom}
|
||||
onAppendJoin={onAppendJoin}
|
||||
/>
|
||||
|
|
|
@ -1,3 +1,19 @@
|
|||
export const emptyAST = {
|
||||
type: 'Program',
|
||||
location: {
|
||||
start: {
|
||||
line: 1,
|
||||
column: 1,
|
||||
},
|
||||
end: {
|
||||
line: 1,
|
||||
column: 1,
|
||||
},
|
||||
source: '',
|
||||
},
|
||||
body: [],
|
||||
}
|
||||
|
||||
export const ast = {
|
||||
type: 'File',
|
||||
start: 0,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import {ast} from 'src/flux/constants/ast'
|
||||
import {ast, emptyAST} from 'src/flux/constants/ast'
|
||||
import * as editor from 'src/flux/constants/editor'
|
||||
import * as argTypes from 'src/flux/constants/argumentTypes'
|
||||
import * as funcNames from 'src/flux/constants/funcNames'
|
||||
|
@ -10,6 +10,7 @@ const MAX_RESPONSE_BYTES = 1e7 // 10 MB
|
|||
|
||||
export {
|
||||
ast,
|
||||
emptyAST,
|
||||
funcNames,
|
||||
argTypes,
|
||||
editor,
|
||||
|
|
|
@ -15,7 +15,7 @@ import {UpdateScript} from 'src/flux/actions'
|
|||
|
||||
import {bodyNodes} from 'src/flux/helpers'
|
||||
import {getSuggestions, getAST, getTimeSeries} from 'src/flux/apis'
|
||||
import {builder, argTypes} from 'src/flux/constants'
|
||||
import {builder, argTypes, emptyAST} from 'src/flux/constants'
|
||||
|
||||
import {Source, Service, Notification, FluxTable} from 'src/types'
|
||||
import {
|
||||
|
@ -114,6 +114,7 @@ export class FluxPage extends PureComponent<Props, State> {
|
|||
onAppendJoin={this.handleAppendJoin}
|
||||
onChangeScript={this.handleChangeScript}
|
||||
onSubmitScript={this.handleSubmitScript}
|
||||
onDeleteBody={this.handleDeleteBody}
|
||||
/>
|
||||
</div>
|
||||
</KeyboardShortcuts>
|
||||
|
@ -331,12 +332,19 @@ export class FluxPage extends PureComponent<Props, State> {
|
|||
this.getASTResponse(script)
|
||||
}
|
||||
|
||||
private handleDeleteBody = (bodyID: string): void => {
|
||||
const newBody = this.state.body.filter(b => b.id !== bodyID)
|
||||
const script = this.getBodyToScript(newBody)
|
||||
|
||||
this.getASTResponse(script)
|
||||
}
|
||||
|
||||
private handleScriptUpToYield = (
|
||||
bodyID: string,
|
||||
declarationID: string,
|
||||
funcNodeIndex: number,
|
||||
isYieldable: boolean
|
||||
) => {
|
||||
): string => {
|
||||
const {body: bodies} = this.state
|
||||
|
||||
const bodyIndex = bodies.findIndex(b => b.id === bodyID)
|
||||
|
@ -601,7 +609,8 @@ export class FluxPage extends PureComponent<Props, State> {
|
|||
const {links} = this.props
|
||||
|
||||
if (!script) {
|
||||
return
|
||||
this.props.updateScript(script)
|
||||
return this.setState({ast: emptyAST, body: []})
|
||||
}
|
||||
|
||||
try {
|
||||
|
|
|
@ -5,9 +5,9 @@ import {bindActionCreators} from 'redux'
|
|||
import _ from 'lodash'
|
||||
|
||||
import HostsTable from 'src/hosts/components/HostsTable'
|
||||
import SourceIndicator from 'shared/components/SourceIndicator'
|
||||
import AutoRefreshDropdown from 'shared/components/AutoRefreshDropdown'
|
||||
import ManualRefresh from 'src/shared/components/ManualRefresh'
|
||||
import PageHeader from 'src/shared/components/PageHeader'
|
||||
|
||||
import {getCpuAndLoadForHosts, getLayouts, getAppsForHosts} from '../apis'
|
||||
import {getEnv} from 'src/shared/apis/env'
|
||||
|
@ -110,31 +110,15 @@ export class HostsPage extends Component {
|
|||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
source,
|
||||
autoRefresh,
|
||||
onChooseAutoRefresh,
|
||||
onManualRefresh,
|
||||
} = this.props
|
||||
const {source} = this.props
|
||||
const {hosts, hostsLoading, hostsError} = this.state
|
||||
return (
|
||||
<div className="page hosts-list-page">
|
||||
<div className="page-header">
|
||||
<div className="page-header__container">
|
||||
<div className="page-header__left">
|
||||
<h1 className="page-header__title">Host List</h1>
|
||||
</div>
|
||||
<div className="page-header__right">
|
||||
<SourceIndicator />
|
||||
<AutoRefreshDropdown
|
||||
iconName="refresh"
|
||||
selected={autoRefresh}
|
||||
onChoose={onChooseAutoRefresh}
|
||||
onManualRefresh={onManualRefresh}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<PageHeader
|
||||
title="Host List"
|
||||
optionsComponents={this.optionsComponents}
|
||||
sourceIndicator={true}
|
||||
/>
|
||||
<div className="page-contents">
|
||||
<div className="container-fluid">
|
||||
<div className="row">
|
||||
|
@ -153,6 +137,19 @@ export class HostsPage extends Component {
|
|||
)
|
||||
}
|
||||
|
||||
optionsComponents = () => {
|
||||
const {autoRefresh, onChooseAutoRefresh, onManualRefresh} = this.props
|
||||
|
||||
return (
|
||||
<AutoRefreshDropdown
|
||||
iconName="refresh"
|
||||
selected={autoRefresh}
|
||||
onChoose={onChooseAutoRefresh}
|
||||
onManualRefresh={onManualRefresh}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
clearInterval(this.intervalID)
|
||||
this.intervalID = false
|
||||
|
|
|
@ -134,7 +134,7 @@ class AlertTabs extends PureComponent<Props, State> {
|
|||
this.setState({services})
|
||||
} catch (error) {
|
||||
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
|
||||
isDeadman: boolean
|
||||
isKapacitorRule: boolean
|
||||
onAddEvery: () => void
|
||||
onAddEvery: (every?: string) => void
|
||||
timeRange: TimeRange
|
||||
}
|
||||
|
||||
|
|
|
@ -1,13 +1,24 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React, {SFC} from 'react'
|
||||
|
||||
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 => {
|
||||
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">
|
||||
<p>Send Alert if Data is missing for</p>
|
||||
<Dropdown
|
||||
|
@ -20,15 +31,4 @@ const Deadman = ({rule, onChange}) => (
|
|||
</div>
|
||||
)
|
||||
|
||||
const {shape, string, func} = PropTypes
|
||||
|
||||
Deadman.propTypes = {
|
||||
rule: shape({
|
||||
values: shape({
|
||||
period: string,
|
||||
}),
|
||||
}),
|
||||
onChange: func.isRequired,
|
||||
}
|
||||
|
||||
export default Deadman
|
|
@ -3,6 +3,7 @@ import React, {ChangeEvent, MouseEvent, PureComponent} from 'react'
|
|||
import AlertOutputs from 'src/kapacitor/components/AlertOutputs'
|
||||
import Input from 'src/kapacitor/components/KapacitorFormInput'
|
||||
import FancyScrollbar from 'src/shared/components/FancyScrollbar'
|
||||
import PageHeader from 'src/shared/components/PageHeader'
|
||||
import KapacitorFormSkipVerify from 'src/kapacitor/components/KapacitorFormSkipVerify'
|
||||
|
||||
import {Kapacitor, Source, Notification, NotificationFunc} from 'src/types'
|
||||
|
@ -38,13 +39,7 @@ class KapacitorForm extends PureComponent<Props> {
|
|||
|
||||
return (
|
||||
<div className="page">
|
||||
<div className="page-header">
|
||||
<div className="page-header__container">
|
||||
<div className="page-header__left">
|
||||
<h1 className="page-header__title">{this.headerText}</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<PageHeader titleText={this.headerText} />
|
||||
<FancyScrollbar className="page-contents">
|
||||
<div className="container-fluid">
|
||||
<div className="row">
|
||||
|
|
|
@ -1,20 +1,21 @@
|
|||
import React, {Component} from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React, {Component, ChangeEvent} from 'react'
|
||||
import {connect} from 'react-redux'
|
||||
import {bindActionCreators} from 'redux'
|
||||
import {InjectedRouter} from 'react-router'
|
||||
|
||||
import PageHeader from 'src/shared/components/PageHeader'
|
||||
import NameSection from 'src/kapacitor/components/NameSection'
|
||||
import ValuesSection from 'src/kapacitor/components/ValuesSection'
|
||||
import RuleHeader from 'src/kapacitor/components/RuleHeader'
|
||||
import RuleHeaderSave from 'src/kapacitor/components/RuleHeaderSave'
|
||||
import RuleHandlers from 'src/kapacitor/components/RuleHandlers'
|
||||
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 buildInfluxQLQuery from 'utils/influxql'
|
||||
import {timeRanges} from 'shared/data/timeRanges'
|
||||
import buildInfluxQLQuery from 'src/utils/influxql'
|
||||
import {timeRanges} from 'src/shared/data/timeRanges'
|
||||
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 {
|
||||
notifyAlertRuleCreated,
|
||||
|
@ -24,11 +25,52 @@ import {
|
|||
notifyAlertRuleRequiresQuery,
|
||||
notifyAlertRuleRequiresConditionValue,
|
||||
notifyAlertRuleDeadmanInvalid,
|
||||
} from 'shared/copy/notifications'
|
||||
} from 'src/shared/copy/notifications'
|
||||
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
|
||||
class KapacitorRule extends Component {
|
||||
class KapacitorRule extends Component<Props, State> {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
|
@ -36,137 +78,7 @@ class KapacitorRule extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
handleChooseTimeRange = ({lower}) => {
|
||||
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})
|
||||
}
|
||||
|
||||
render() {
|
||||
public render() {
|
||||
const {
|
||||
rule,
|
||||
source,
|
||||
|
@ -180,10 +92,10 @@ class KapacitorRule extends Component {
|
|||
|
||||
return (
|
||||
<div className="page">
|
||||
<RuleHeader
|
||||
source={source}
|
||||
onSave={this.handleSave}
|
||||
validationError={this.validationError()}
|
||||
<PageHeader
|
||||
titleText="Alert Rule Builder"
|
||||
optionsComponents={this.optionsComponents}
|
||||
sourceIndicator={true}
|
||||
/>
|
||||
<FancyScrollbar className="page-contents fancy-scroll--kapacitor">
|
||||
<div className="container-fluid">
|
||||
|
@ -215,7 +127,7 @@ class KapacitorRule extends Component {
|
|||
ruleActions={ruleActions}
|
||||
handlersFromConfig={handlersFromConfig}
|
||||
onGoToConfig={this.handleSaveToConfig}
|
||||
validationError={this.validationError()}
|
||||
validationError={this.validationError}
|
||||
/>
|
||||
<RuleMessage rule={rule} ruleActions={ruleActions} />
|
||||
</div>
|
||||
|
@ -226,27 +138,147 @@ class KapacitorRule extends Component {
|
|||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const {arrayOf, func, shape, string} = PropTypes
|
||||
private handleChooseTimeRange = ({lower}: TimeRange) => {
|
||||
const timeRange = timeRanges.find(range => range.lower === lower)
|
||||
this.setState({timeRange})
|
||||
}
|
||||
|
||||
KapacitorRule.propTypes = {
|
||||
source: shape({}).isRequired,
|
||||
rule: shape({
|
||||
values: shape({}),
|
||||
}).isRequired,
|
||||
query: shape({}).isRequired,
|
||||
queryConfigs: shape({}).isRequired,
|
||||
queryConfigActions: shape({}).isRequired,
|
||||
ruleActions: shape({}).isRequired,
|
||||
notify: func.isRequired,
|
||||
ruleID: string.isRequired,
|
||||
handlersFromConfig: arrayOf(shape({})).isRequired,
|
||||
router: shape({
|
||||
push: func.isRequired,
|
||||
}).isRequired,
|
||||
kapacitor: shape({}).isRequired,
|
||||
configLink: string.isRequired,
|
||||
private handleCreate = (pathname?: string) => {
|
||||
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))
|
||||
})
|
||||
}
|
||||
|
||||
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 => ({
|
|
@ -1,7 +1,12 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React, {SFC} from 'react'
|
||||
|
||||
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--divider">
|
||||
<div className={`logs-table--level ${logItem.lvl}`} />
|
||||
|
@ -16,17 +21,4 @@ const LogItemHTTP = ({logItem}) => (
|
|||
</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
|
|
@ -1,7 +1,12 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React, {SFC} from 'react'
|
||||
|
||||
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--divider">
|
||||
<div className={`logs-table--level ${logItem.lvl}`} />
|
||||
|
@ -16,15 +21,4 @@ const LogItemHTTPError = ({logItem}) => (
|
|||
</div>
|
||||
)
|
||||
|
||||
const {shape, string} = PropTypes
|
||||
|
||||
LogItemHTTPError.propTypes = {
|
||||
logItem: shape({
|
||||
key: string.isRequired,
|
||||
lvl: string.isRequired,
|
||||
ts: string.isRequired,
|
||||
msg: string.isRequired,
|
||||
}),
|
||||
}
|
||||
|
||||
export default LogItemHTTPError
|
|
@ -1,7 +1,12 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React, {SFC} from 'react'
|
||||
|
||||
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--divider">
|
||||
<div className={`logs-table--level ${logItem.lvl}`} />
|
||||
|
@ -20,15 +25,4 @@ const LogItemInfluxDBDebug = ({logItem}) => (
|
|||
</div>
|
||||
)
|
||||
|
||||
const {shape, string} = PropTypes
|
||||
|
||||
LogItemInfluxDBDebug.propTypes = {
|
||||
logItem: shape({
|
||||
lvl: string.isRequired,
|
||||
ts: string.isRequired,
|
||||
msg: string.isRequired,
|
||||
cluster: string.isRequired,
|
||||
}),
|
||||
}
|
||||
|
||||
export default LogItemInfluxDBDebug
|
|
@ -1,7 +1,12 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React, {SFC} from 'react'
|
||||
|
||||
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--divider">
|
||||
<div className={`logs-table--level ${logItem.lvl}`} />
|
||||
|
@ -16,14 +21,4 @@ const LogItemKapacitorDebug = ({logItem}) => (
|
|||
</div>
|
||||
)
|
||||
|
||||
const {shape, string} = PropTypes
|
||||
|
||||
LogItemKapacitorDebug.propTypes = {
|
||||
logItem: shape({
|
||||
lvl: string.isRequired,
|
||||
ts: string.isRequired,
|
||||
msg: string.isRequired,
|
||||
}),
|
||||
}
|
||||
|
||||
export default LogItemKapacitorDebug
|
|
@ -1,7 +1,12 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React, {SFC} from 'react'
|
||||
|
||||
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--divider">
|
||||
<div className={`logs-table--level ${logItem.lvl}`} />
|
||||
|
@ -16,14 +21,4 @@ const LogItemKapacitorError = ({logItem}) => (
|
|||
</div>
|
||||
)
|
||||
|
||||
const {shape, string} = PropTypes
|
||||
|
||||
LogItemKapacitorError.propTypes = {
|
||||
logItem: shape({
|
||||
lvl: string.isRequired,
|
||||
ts: string.isRequired,
|
||||
msg: string.isRequired,
|
||||
}),
|
||||
}
|
||||
|
||||
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 PropTypes from 'prop-types'
|
||||
import React, {SFC} from 'react'
|
||||
|
||||
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--divider">
|
||||
<div className={`logs-table--level ${logItem.lvl}`} />
|
||||
|
@ -13,14 +18,4 @@ const LogItemSession = ({logItem}) => (
|
|||
</div>
|
||||
)
|
||||
|
||||
const {shape, string} = PropTypes
|
||||
|
||||
LogItemSession.propTypes = {
|
||||
logItem: shape({
|
||||
lvl: string.isRequired,
|
||||
ts: string.isRequired,
|
||||
msg: string.isRequired,
|
||||
}),
|
||||
}
|
||||
|
||||
export default LogItemSession
|
|
@ -1,12 +1,17 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React, {SFC} from 'react'
|
||||
|
||||
import LogsTableRow from 'src/kapacitor/components/LogsTableRow'
|
||||
import FancyScrollbar from 'src/shared/components/FancyScrollbar'
|
||||
|
||||
import {LogItem} from 'src/types/kapacitor'
|
||||
|
||||
const numLogsToRender = 200
|
||||
|
||||
const LogsTable = ({logs}) => (
|
||||
interface Props {
|
||||
logs: LogItem[]
|
||||
}
|
||||
|
||||
const LogsTable: SFC<Props> = ({logs}) => (
|
||||
<div className="logs-table">
|
||||
<div className="logs-table--header">
|
||||
{`${numLogsToRender} Most Recent Logs`}
|
||||
|
@ -22,17 +27,4 @@ const LogsTable = ({logs}) => (
|
|||
</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
|
|
@ -1,5 +1,4 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React, {SFC} from 'react'
|
||||
|
||||
import LogItemSession from 'src/kapacitor/components/LogItemSession'
|
||||
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 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') {
|
||||
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
|
|
@ -1,28 +0,0 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
const LogsToggle = ({areLogsVisible, onToggleLogsVisibility}) => (
|
||||
<ul className="nav nav-tablist nav-tablist-sm nav-tablist-malachite logs-toggle">
|
||||
<li
|
||||
className={areLogsVisible ? null : 'active'}
|
||||
onClick={onToggleLogsVisibility}
|
||||
>
|
||||
Editor
|
||||
</li>
|
||||
<li
|
||||
className={areLogsVisible ? 'active' : null}
|
||||
onClick={onToggleLogsVisibility}
|
||||
>
|
||||
Editor + Logs
|
||||
</li>
|
||||
</ul>
|
||||
)
|
||||
|
||||
const {bool, func} = PropTypes
|
||||
|
||||
LogsToggle.propTypes = {
|
||||
areLogsVisible: bool,
|
||||
onToggleLogsVisibility: func.isRequired,
|
||||
}
|
||||
|
||||
export default LogsToggle
|
|
@ -0,0 +1,68 @@
|
|||
import React, {PureComponent} from 'react'
|
||||
|
||||
interface Props {
|
||||
areLogsVisible: boolean
|
||||
areLogsEnabled: boolean
|
||||
onToggleLogsVisibility: () => void
|
||||
}
|
||||
|
||||
class LogsToggle extends PureComponent<Props> {
|
||||
public render() {
|
||||
return (
|
||||
<ul className="nav nav-tablist nav-tablist-sm nav-tablist-malachite">
|
||||
{this.leftTab}
|
||||
{this.rightTab}
|
||||
</ul>
|
||||
)
|
||||
}
|
||||
|
||||
private get leftTab(): JSX.Element {
|
||||
const {areLogsEnabled, areLogsVisible, onToggleLogsVisibility} = this.props
|
||||
|
||||
if (areLogsEnabled) {
|
||||
return (
|
||||
<li
|
||||
className={areLogsVisible ? null : 'active'}
|
||||
onClick={onToggleLogsVisibility}
|
||||
>
|
||||
Editor
|
||||
</li>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<li
|
||||
className={areLogsVisible ? 'disabled' : ' disabled active'}
|
||||
title="Log viewing is currently disabled"
|
||||
>
|
||||
Editor
|
||||
</li>
|
||||
)
|
||||
}
|
||||
|
||||
private get rightTab(): JSX.Element {
|
||||
const {areLogsEnabled, areLogsVisible, onToggleLogsVisibility} = this.props
|
||||
|
||||
if (areLogsEnabled) {
|
||||
return (
|
||||
<li
|
||||
className={areLogsVisible ? 'active' : null}
|
||||
onClick={onToggleLogsVisibility}
|
||||
>
|
||||
Editor + Logs
|
||||
</li>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<li
|
||||
className={areLogsVisible ? 'disabled active' : ' disabled'}
|
||||
title="Log viewing is currently disabled"
|
||||
>
|
||||
Editor + Logs
|
||||
</li>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default LogsToggle
|
|
@ -1,11 +1,25 @@
|
|||
import React, {Component} from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React, {Component, ChangeEvent, KeyboardEvent} from 'react'
|
||||
|
||||
import {DEFAULT_RULE_ID} from 'src/kapacitor/constants'
|
||||
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
|
||||
class NameSection extends Component {
|
||||
constructor(props) {
|
||||
class NameSection extends Component<Props, State> {
|
||||
private inputRef: HTMLInputElement
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props)
|
||||
|
||||
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
|
||||
|
||||
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})
|
||||
}
|
||||
|
||||
handleKeyDown = e => {
|
||||
public handleKeyDown = (e: KeyboardEvent<HTMLInputElement>) => {
|
||||
if (e.key === 'Enter') {
|
||||
this.inputRef.blur()
|
||||
}
|
||||
|
@ -30,15 +52,13 @@ class NameSection extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const {rule, defaultName} = this.props
|
||||
public render() {
|
||||
const {defaultName} = this.props
|
||||
const {reset} = this.state
|
||||
|
||||
return (
|
||||
<div className="rule-section">
|
||||
<h3 className="rule-section--heading">
|
||||
{rule.id === DEFAULT_RULE_ID ? 'Name this Alert Rule' : 'Name'}
|
||||
</h3>
|
||||
<h3 className="rule-section--heading">{this.header}</h3>
|
||||
<div className="rule-section--body">
|
||||
<div className="rule-section--row rule-section--row-first rule-section--row-last">
|
||||
<input
|
||||
|
@ -55,14 +75,18 @@ class NameSection extends Component {
|
|||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const {func, string, shape} = PropTypes
|
||||
private get header() {
|
||||
const {
|
||||
rule: {id},
|
||||
} = this.props
|
||||
|
||||
NameSection.propTypes = {
|
||||
defaultName: string.isRequired,
|
||||
onRuleRename: func.isRequired,
|
||||
rule: shape({}).isRequired,
|
||||
if (id === DEFAULT_RULE_ID) {
|
||||
return 'Name this Alert Rule'
|
||||
}
|
||||
|
||||
return 'Name'
|
||||
}
|
||||
}
|
||||
|
||||
export default NameSection
|
|
@ -1,14 +1,27 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import {CHANGES, RELATIVE_OPERATORS, SHIFTS} from 'src/kapacitor/constants'
|
||||
import Dropdown from 'shared/components/Dropdown'
|
||||
import React, {SFC, ChangeEvent} from 'react'
|
||||
|
||||
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 shifts = mapToItems(SHIFTS, 'shift')
|
||||
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,
|
||||
onDropdownChange,
|
||||
rule: {
|
||||
|
@ -46,7 +59,7 @@ const Relative = ({
|
|||
style={{width: '160px', marginLeft: '6px'}}
|
||||
type="text"
|
||||
name="lower"
|
||||
spellCheck="false"
|
||||
spellCheck={false}
|
||||
value={value}
|
||||
onChange={onRuleTypeInputChange}
|
||||
required={true}
|
||||
|
@ -56,19 +69,4 @@ const Relative = ({
|
|||
</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
|
|
@ -26,7 +26,7 @@ interface Props {
|
|||
rule: AlertRule
|
||||
ruleActions: RuleActions
|
||||
handlersFromConfig: Handler[]
|
||||
onGoToConfig: () => void
|
||||
onGoToConfig: (configName: string) => void
|
||||
validationError: string
|
||||
}
|
||||
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
import React, {Component} from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import RuleHeaderSave from 'src/kapacitor/components/RuleHeaderSave'
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
|
||||
@ErrorHandling
|
||||
class RuleHeader extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
}
|
||||
|
||||
render() {
|
||||
const {source, onSave, validationError} = this.props
|
||||
|
||||
return (
|
||||
<div className="page-header">
|
||||
<div className="page-header__container">
|
||||
<div className="page-header__left">
|
||||
<h1 className="page-header__title">Alert Rule Builder</h1>
|
||||
</div>
|
||||
<RuleHeaderSave
|
||||
source={source}
|
||||
onSave={onSave}
|
||||
validationError={validationError}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const {func, shape, string} = PropTypes
|
||||
|
||||
RuleHeader.propTypes = {
|
||||
source: shape({}).isRequired,
|
||||
onSave: func.isRequired,
|
||||
validationError: string.isRequired,
|
||||
}
|
||||
|
||||
export default RuleHeader
|
|
@ -1,11 +1,13 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React, {SFC} from 'react'
|
||||
import ReactTooltip from 'react-tooltip'
|
||||
import SourceIndicator from 'shared/components/SourceIndicator'
|
||||
|
||||
const RuleHeaderSave = ({onSave, validationError}) => (
|
||||
<div className="page-header__right">
|
||||
<SourceIndicator />
|
||||
interface Props {
|
||||
onSave: () => void
|
||||
validationError?: string
|
||||
}
|
||||
|
||||
const RuleHeaderSave: SFC<Props> = ({onSave, validationError}) => (
|
||||
<>
|
||||
{validationError ? (
|
||||
<button
|
||||
className="btn btn-success btn-sm disabled"
|
||||
|
@ -26,14 +28,7 @@ const RuleHeaderSave = ({onSave, validationError}) => (
|
|||
place="bottom"
|
||||
class="influx-tooltip kapacitor-tooltip"
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
|
||||
const {func, string} = PropTypes
|
||||
|
||||
RuleHeaderSave.propTypes = {
|
||||
onSave: func.isRequired,
|
||||
validationError: string.isRequired,
|
||||
}
|
||||
|
||||
export default RuleHeaderSave
|
|
@ -1,22 +1,24 @@
|
|||
import React, {Component} from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React, {Component, ChangeEvent} from 'react'
|
||||
|
||||
import RuleMessageText from 'src/kapacitor/components/RuleMessageText'
|
||||
import RuleMessageTemplates from 'src/kapacitor/components/RuleMessageTemplates'
|
||||
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
|
||||
class RuleMessage extends Component {
|
||||
class RuleMessage extends Component<Props> {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
}
|
||||
|
||||
handleChangeMessage = e => {
|
||||
const {ruleActions, rule} = this.props
|
||||
ruleActions.updateMessage(rule.id, e.target.value)
|
||||
}
|
||||
|
||||
render() {
|
||||
public render() {
|
||||
const {rule, ruleActions} = this.props
|
||||
|
||||
return (
|
||||
|
@ -35,15 +37,11 @@ class RuleMessage extends Component {
|
|||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const {func, shape} = PropTypes
|
||||
|
||||
RuleMessage.propTypes = {
|
||||
rule: shape().isRequired,
|
||||
ruleActions: shape({
|
||||
updateMessage: func.isRequired,
|
||||
}).isRequired,
|
||||
private handleChangeMessage = (e: ChangeEvent<HTMLTextAreaElement>) => {
|
||||
const {ruleActions, rule} = this.props
|
||||
ruleActions.updateMessage(rule.id, e.target.value)
|
||||
}
|
||||
}
|
||||
|
||||
export default RuleMessage
|
|
@ -1,5 +1,5 @@
|
|||
import React, {Component} from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import _ from 'lodash'
|
||||
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 {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
|
||||
@ErrorHandling
|
||||
class RuleMessageTemplates extends Component {
|
||||
class RuleMessageTemplates extends Component<Props> {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
}
|
||||
|
||||
handleClickTemplate = template => () => {
|
||||
const {updateMessage, rule} = this.props
|
||||
updateMessage(rule.id, `${rule.message} ${template.label}`)
|
||||
}
|
||||
|
||||
render() {
|
||||
public render() {
|
||||
return (
|
||||
<div className="rule-section--row rule-section--row-last">
|
||||
<p>Templates:</p>
|
||||
|
@ -41,13 +44,11 @@ class RuleMessageTemplates extends Component {
|
|||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const {func, shape} = PropTypes
|
||||
|
||||
RuleMessageTemplates.propTypes = {
|
||||
rule: shape().isRequired,
|
||||
updateMessage: func.isRequired,
|
||||
private handleClickTemplate = (template: RuleMessage) => () => {
|
||||
const {updateMessage, rule} = this.props
|
||||
updateMessage(rule.id, `${rule.message} ${template.label}`)
|
||||
}
|
||||
}
|
||||
|
||||
export default RuleMessageTemplates
|
|
@ -1,7 +1,13 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React, {SFC, ChangeEvent} from 'react'
|
||||
|
||||
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">
|
||||
<textarea
|
||||
className="form-control input-sm form-malachite monotype"
|
||||
|
@ -13,11 +19,4 @@ const RuleMessageText = ({rule, updateMessage}) => (
|
|||
</div>
|
||||
)
|
||||
|
||||
const {func, shape} = PropTypes
|
||||
|
||||
RuleMessageText.propTypes = {
|
||||
rule: shape().isRequired,
|
||||
updateMessage: func.isRequired,
|
||||
}
|
||||
|
||||
export default RuleMessageText
|
|
@ -6,10 +6,10 @@ const TICKscriptOverlay = ({tickscript, onClose}) => (
|
|||
<OverlayTechnologies>
|
||||
<div className="tick-script-overlay">
|
||||
<div className="write-data-form--header">
|
||||
<div className="page-header__left">
|
||||
<h1 className="page-header__title">Generated TICKscript</h1>
|
||||
<div className="page-header--left">
|
||||
<h1 className="page-header--title">Generated TICKscript</h1>
|
||||
</div>
|
||||
<div className="page-header__right">
|
||||
<div className="page-header--right">
|
||||
<span className="page-header__dismiss" onClick={onClose} />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -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 PropTypes from 'prop-types'
|
||||
|
||||
import {Controlled as CodeMirror} from 'react-codemirror2'
|
||||
import 'src/external/codemirror'
|
||||
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
|
||||
interface Props {
|
||||
onChangeScript: (tickscript: string) => void
|
||||
script: string
|
||||
}
|
||||
|
||||
const NOOP = () => {}
|
||||
|
||||
@ErrorHandling
|
||||
class TickscriptEditor extends Component {
|
||||
class TickscriptEditor extends Component<Props> {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
}
|
||||
|
||||
updateCode = (_, __, script) => {
|
||||
this.props.onChangeScript(script)
|
||||
}
|
||||
|
||||
render() {
|
||||
public render() {
|
||||
const {script} = this.props
|
||||
|
||||
const options = {
|
||||
|
@ -31,17 +35,15 @@ class TickscriptEditor extends Component {
|
|||
value={script}
|
||||
onBeforeChange={this.updateCode}
|
||||
options={options}
|
||||
onTouchStart={NOOP}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const {func, string} = PropTypes
|
||||
|
||||
TickscriptEditor.propTypes = {
|
||||
onChangeScript: func,
|
||||
script: string,
|
||||
private updateCode = (_, __, script) => {
|
||||
this.props.onChangeScript(script)
|
||||
}
|
||||
}
|
||||
|
||||
export default TickscriptEditor
|
|
@ -1,7 +1,14 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React, {SFC} from 'react'
|
||||
|
||||
const TickscriptEditorConsole = ({consoleMessage, unsavedChanges}) => {
|
||||
interface Props {
|
||||
consoleMessage: string
|
||||
unsavedChanges: boolean
|
||||
}
|
||||
|
||||
const TickscriptEditorConsole: SFC<Props> = ({
|
||||
consoleMessage,
|
||||
unsavedChanges,
|
||||
}) => {
|
||||
let consoleOutput = 'TICKscript is 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
|
|
@ -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,6 +1,6 @@
|
|||
import React, {SFC} from 'react'
|
||||
import React, {Component} from 'react'
|
||||
|
||||
import SourceIndicator from 'src/shared/components/SourceIndicator'
|
||||
import PageHeader from 'src/shared/components/PageHeader'
|
||||
import LogsToggle from 'src/kapacitor/components/LogsToggle'
|
||||
import ConfirmButton from 'src/shared/components/ConfirmButton'
|
||||
import TickscriptSave, {Task} from 'src/kapacitor/components/TickscriptSave'
|
||||
|
@ -16,53 +16,70 @@ interface Props {
|
|||
onToggleLogsVisibility: () => void
|
||||
}
|
||||
|
||||
const TickscriptHeader: SFC<Props> = ({
|
||||
task,
|
||||
onSave,
|
||||
onExit,
|
||||
unsavedChanges,
|
||||
areLogsEnabled,
|
||||
areLogsVisible,
|
||||
isNewTickscript,
|
||||
onToggleLogsVisibility,
|
||||
}) => (
|
||||
<div className="page-header full-width">
|
||||
<div className="page-header__container">
|
||||
<div className="page-header__left">
|
||||
<h1 className="page-header__title">TICKscript Editor</h1>
|
||||
</div>
|
||||
{areLogsEnabled && (
|
||||
class TickscriptHeader extends Component<Props> {
|
||||
public render() {
|
||||
return (
|
||||
<PageHeader
|
||||
titleText="TICKscript Editor"
|
||||
fullWidth={true}
|
||||
sourceIndicator={true}
|
||||
optionsComponents={this.optionsComponents}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
private get optionsComponents(): JSX.Element {
|
||||
const {
|
||||
task,
|
||||
onSave,
|
||||
unsavedChanges,
|
||||
isNewTickscript,
|
||||
areLogsEnabled,
|
||||
areLogsVisible,
|
||||
onToggleLogsVisibility,
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
<>
|
||||
<LogsToggle
|
||||
areLogsEnabled={areLogsEnabled}
|
||||
areLogsVisible={areLogsVisible}
|
||||
onToggleLogsVisibility={onToggleLogsVisibility}
|
||||
/>
|
||||
)}
|
||||
<div className="page-header__right">
|
||||
<SourceIndicator />
|
||||
<TickscriptSave
|
||||
task={task}
|
||||
onSave={onSave}
|
||||
unsavedChanges={unsavedChanges}
|
||||
isNewTickscript={isNewTickscript}
|
||||
/>
|
||||
{unsavedChanges ? (
|
||||
<ConfirmButton
|
||||
text="Exit"
|
||||
confirmText="Discard unsaved changes?"
|
||||
confirmAction={onExit}
|
||||
/>
|
||||
) : (
|
||||
<button
|
||||
className="btn btn-default btn-sm"
|
||||
title="Return to Alert Rules"
|
||||
onClick={onExit}
|
||||
>
|
||||
Exit
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
{this.saveButton}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
private get saveButton(): JSX.Element {
|
||||
const {unsavedChanges, onExit} = this.props
|
||||
|
||||
if (unsavedChanges) {
|
||||
return (
|
||||
<ConfirmButton
|
||||
text="Exit"
|
||||
confirmText="Discard unsaved changes?"
|
||||
confirmAction={onExit}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<button
|
||||
className="btn btn-default btn-sm"
|
||||
title="Return to Alert Rules"
|
||||
onClick={onExit}
|
||||
>
|
||||
Exit
|
||||
</button>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default TickscriptHeader
|
||||
|
|
|
@ -1,14 +1,18 @@
|
|||
import React, {Component} from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import React, {Component, SFC, ChangeEvent} from 'react'
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
|
||||
interface TickscriptIDProps {
|
||||
onChangeID: (e: ChangeEvent<HTMLInputElement>) => void
|
||||
id: string
|
||||
}
|
||||
|
||||
@ErrorHandling
|
||||
class TickscriptID extends Component {
|
||||
class TickscriptID extends Component<TickscriptIDProps> {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
}
|
||||
|
||||
render() {
|
||||
public render() {
|
||||
const {onChangeID, id} = this.props
|
||||
|
||||
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>
|
||||
)
|
||||
|
||||
const {func, string} = PropTypes
|
||||
|
||||
TickscriptID.propTypes = {
|
||||
onChangeID: func.isRequired,
|
||||
id: string.isRequired,
|
||||
}
|
||||
|
||||
TickscriptStaticID.propTypes = {
|
||||
id: string.isRequired,
|
||||
}
|
||||
|
||||
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 PropTypes from 'prop-types'
|
||||
|
||||
import React, {SFC, ChangeEvent} from 'react'
|
||||
import _ from 'lodash'
|
||||
|
||||
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 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']
|
||||
|
||||
|
@ -22,13 +29,36 @@ const handleChooseTrigger = (rule, onChooseTrigger) => triggerIndex => {
|
|||
const initialIndex = rule => TABS.indexOf(_.startCase(rule.trigger))
|
||||
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,
|
||||
query,
|
||||
source,
|
||||
timeRange,
|
||||
onAddEvery,
|
||||
onRemoveEvery,
|
||||
onChooseTrigger,
|
||||
onDeadmanChange,
|
||||
onChooseTimeRange,
|
||||
|
@ -58,7 +88,6 @@ const ValuesSection = ({
|
|||
isKapacitorRule={true}
|
||||
actions={queryConfigActions}
|
||||
onAddEvery={onAddEvery}
|
||||
onRemoveEvery={onRemoveEvery}
|
||||
isDeadman={isDeadman(rule)}
|
||||
/>
|
||||
</div>
|
||||
|
@ -97,24 +126,4 @@ const ValuesSection = ({
|
|||
</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
|
|
@ -1,26 +1,59 @@
|
|||
import React, {Component} from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import _ from 'lodash'
|
||||
import {InjectedRouter} from 'react-router'
|
||||
import {connect} from 'react-redux'
|
||||
|
||||
import * as kapacitorRuleActionCreators from 'src/kapacitor/actions/view'
|
||||
import * as kapacitorQueryConfigActionCreators from 'src/kapacitor/actions/queryConfigs'
|
||||
|
||||
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 KapacitorRule from 'src/kapacitor/components/KapacitorRule'
|
||||
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 {
|
||||
notifyKapacitorCreateFailed,
|
||||
notifyCouldNotFindKapacitor,
|
||||
} from 'shared/copy/notifications'
|
||||
} from 'src/shared/copy/notifications'
|
||||
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
|
||||
class KapacitorRulePage extends Component {
|
||||
constructor(props) {
|
||||
class KapacitorRulePage extends Component<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
|
@ -29,7 +62,7 @@ class KapacitorRulePage extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
public async componentDidMount() {
|
||||
const {params, source, ruleActions, notify} = this.props
|
||||
|
||||
if (params.ruleID === 'new') {
|
||||
|
@ -54,9 +87,8 @@ class KapacitorRulePage extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
public render() {
|
||||
const {
|
||||
rules,
|
||||
params,
|
||||
source,
|
||||
router,
|
||||
|
@ -65,8 +97,7 @@ class KapacitorRulePage extends Component {
|
|||
queryConfigActions,
|
||||
} = this.props
|
||||
const {handlersFromConfig, kapacitor} = this.state
|
||||
const rule =
|
||||
params.ruleID === 'new' ? rules[DEFAULT_RULE_ID] : rules[params.ruleID]
|
||||
const rule = this.rule
|
||||
const query = rule && queryConfigs[rule.queryID]
|
||||
|
||||
if (!query) {
|
||||
|
@ -84,41 +115,26 @@ class KapacitorRulePage extends Component {
|
|||
ruleID={params.ruleID}
|
||||
router={router}
|
||||
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 = {
|
||||
source: shape({
|
||||
links: shape({
|
||||
proxy: string.isRequired,
|
||||
self: string.isRequired,
|
||||
}),
|
||||
}),
|
||||
notify: func,
|
||||
rules: shape({}).isRequired,
|
||||
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,
|
||||
private get rule(): AlertRule {
|
||||
const {params, rules} = this.props
|
||||
const ruleID = _.get(params, 'ruleID')
|
||||
|
||||
if (ruleID === 'new') {
|
||||
return rules[DEFAULT_RULE_ID]
|
||||
}
|
||||
|
||||
return rules[params.ruleID]
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = ({rules, kapacitorQueryConfigs: queryConfigs}) => ({
|
|
@ -7,9 +7,9 @@ import {getActiveKapacitor} from 'src/shared/apis'
|
|||
import * as kapacitorActionCreators from '../actions/view'
|
||||
|
||||
import KapacitorRules from 'src/kapacitor/components/KapacitorRules'
|
||||
import SourceIndicator from 'src/shared/components/SourceIndicator'
|
||||
import FancyScrollbar from 'src/shared/components/FancyScrollbar'
|
||||
import QuestionMarkTooltip from 'src/shared/components/QuestionMarkTooltip'
|
||||
import PageHeader from 'src/shared/components/PageHeader'
|
||||
|
||||
import {Source, Kapacitor, AlertRule} from 'src/types'
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
|
@ -89,20 +89,11 @@ interface PageContentsProps {
|
|||
|
||||
const PageContents: SFC<PageContentsProps> = ({children}) => (
|
||||
<div className="page">
|
||||
<div className="page-header">
|
||||
<div className="page-header__container">
|
||||
<div className="page-header__left">
|
||||
<h1 className="page-header__title">Manage Tasks</h1>
|
||||
</div>
|
||||
<div className="page-header__right">
|
||||
<QuestionMarkTooltip
|
||||
tipID="manage-tasks--tooltip"
|
||||
tipContent="<b>Alert Rules</b> generate a TICKscript for<br/>you using our Builder UI.<br/><br/>Not all TICKscripts can be edited<br/>using the Builder."
|
||||
/>
|
||||
<SourceIndicator />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<PageHeader
|
||||
titleText="Manage Tasks"
|
||||
optionsComponents={renderHeaderOptions()}
|
||||
sourceIndicator={true}
|
||||
/>
|
||||
<FancyScrollbar className="page-contents fancy-scroll--kapacitor">
|
||||
<div className="container-fluid">
|
||||
<div className="row">
|
||||
|
@ -113,6 +104,15 @@ const PageContents: SFC<PageContentsProps> = ({children}) => (
|
|||
</div>
|
||||
)
|
||||
|
||||
const renderHeaderOptions = (): JSX.Element => {
|
||||
return (
|
||||
<QuestionMarkTooltip
|
||||
tipID="manage-tasks--tooltip"
|
||||
tipContent="<b>Alert Rules</b> generate a TICKscript for<br/>you using our Builder UI.<br/><br/>Not all TICKscripts can be edited<br/>using the Builder."
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
rules: Object.values(state.rules),
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import React, {PureComponent} from 'react'
|
||||
import React, {PureComponent, ChangeEvent} from 'react'
|
||||
import {connect} from 'react-redux'
|
||||
import {bindActionCreators} from 'redux'
|
||||
import uuid from 'uuid'
|
||||
|
@ -18,7 +18,7 @@ import {
|
|||
Notification,
|
||||
NotificationFunc,
|
||||
} from 'src/types'
|
||||
|
||||
import {LogItem, DBRP} from 'src/types/kapacitor'
|
||||
import {
|
||||
notifyTickscriptLoggingUnavailable,
|
||||
notifyTickscriptLoggingError,
|
||||
|
@ -76,7 +76,7 @@ interface State {
|
|||
task: Task
|
||||
consoleMessage: string
|
||||
isEditingID: boolean
|
||||
logs: object[]
|
||||
logs: LogItem[]
|
||||
areLogsVisible: boolean
|
||||
areLogsEnabled: boolean
|
||||
failStr: string
|
||||
|
@ -247,22 +247,22 @@ export class TickscriptPage extends PureComponent<Props, State> {
|
|||
return router.push(`/sources/${sourceID}/alert-rules`)
|
||||
}
|
||||
|
||||
private handleChangeScript = tickscript => {
|
||||
private handleChangeScript = (tickscript: string) => {
|
||||
this.setState({
|
||||
task: {...this.state.task, tickscript},
|
||||
unsavedChanges: true,
|
||||
})
|
||||
}
|
||||
|
||||
private handleSelectDbrps = dbrps => {
|
||||
private handleSelectDbrps = (dbrps: DBRP[]) => {
|
||||
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})
|
||||
}
|
||||
|
||||
private handleChangeID = e => {
|
||||
private handleChangeID = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
this.setState({
|
||||
task: {...this.state.task, id: e.target.value},
|
||||
unsavedChanges: true,
|
||||
|
|
|
@ -3,6 +3,8 @@ import React, {PureComponent} from 'react'
|
|||
import {Source, Namespace} from 'src/types'
|
||||
import classnames from 'classnames'
|
||||
import Dropdown from 'src/shared/components/Dropdown'
|
||||
import PageHeader from 'src/shared/components/PageHeader'
|
||||
import PageHeaderTitle from 'src/shared/components/PageHeaderTitle'
|
||||
import TimeRangeDropdown from 'src/logs/components/TimeRangeDropdown'
|
||||
|
||||
import {TimeRange} from 'src/types'
|
||||
|
@ -27,37 +29,47 @@ interface Props {
|
|||
|
||||
class LogViewerHeader extends PureComponent<Props> {
|
||||
public render(): JSX.Element {
|
||||
const {timeRange} = this.props
|
||||
return (
|
||||
<div className="page-header full-width">
|
||||
<div className="page-header__container">
|
||||
<div className="page-header__left">
|
||||
{this.status}
|
||||
<h1 className="page-header__title logs-viewer-header-title">
|
||||
Log Viewer
|
||||
</h1>
|
||||
</div>
|
||||
<div className="page-header__right">
|
||||
<Dropdown
|
||||
className="dropdown-300"
|
||||
items={this.sourceDropDownItems}
|
||||
selected={this.selectedSource}
|
||||
onChoose={this.handleChooseSource}
|
||||
/>
|
||||
<Dropdown
|
||||
className="dropdown-180"
|
||||
iconName="disks"
|
||||
items={this.namespaceDropDownItems}
|
||||
selected={this.selectedNamespace}
|
||||
onChoose={this.handleChooseNamespace}
|
||||
/>
|
||||
<TimeRangeDropdown
|
||||
onChooseTimeRange={this.handleChooseTimeRange}
|
||||
selected={timeRange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<PageHeader
|
||||
titleComponents={this.renderHeaderTitle}
|
||||
fullWidth={true}
|
||||
optionsComponents={this.optionsComponents}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
private get renderHeaderTitle(): JSX.Element {
|
||||
return (
|
||||
<>
|
||||
{this.status}
|
||||
<PageHeaderTitle title="Logs Viewer" />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
private get optionsComponents(): JSX.Element {
|
||||
const {timeRange} = this.props
|
||||
|
||||
return (
|
||||
<>
|
||||
<Dropdown
|
||||
className="dropdown-300"
|
||||
items={this.sourceDropDownItems}
|
||||
selected={this.selectedSource}
|
||||
onChoose={this.handleChooseSource}
|
||||
/>
|
||||
<Dropdown
|
||||
className="dropdown-180"
|
||||
iconName="disks"
|
||||
items={this.namespaceDropDownItems}
|
||||
selected={this.selectedNamespace}
|
||||
onChoose={this.handleChooseNamespace}
|
||||
/>
|
||||
<TimeRangeDropdown
|
||||
onChooseTimeRange={this.handleChooseTimeRange}
|
||||
selected={timeRange}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ import {Notification} from 'src/types'
|
|||
export type Action = ActionPublishNotification | ActionDismissNotification
|
||||
|
||||
// Publish notification
|
||||
export type PubishNotification = (n: Notification) => ActionPublishNotification
|
||||
export type PublishNotification = (n: Notification) => ActionPublishNotification
|
||||
export interface ActionPublishNotification {
|
||||
type: 'PUBLISH_NOTIFICATION'
|
||||
payload: {
|
||||
|
|
|
@ -1,20 +1,47 @@
|
|||
import {proxy} from 'src/utils/queryUrlGenerator'
|
||||
import {noop} from 'src/shared/actions/app'
|
||||
import _ from 'lodash'
|
||||
|
||||
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, {
|
||||
loading: true,
|
||||
})
|
||||
}
|
||||
|
||||
// {results: [{}]}
|
||||
export const handleSuccess = (data, query, editQueryStatus) => {
|
||||
const handleSuccess = (
|
||||
data: TimeSeriesResponse,
|
||||
query: Query,
|
||||
editQueryStatus: EditQueryStatusFunction
|
||||
): TimeSeriesResponse => {
|
||||
const {results} = data
|
||||
const error = _.get(results, ['0', 'error'], false)
|
||||
const series = _.get(results, ['0', 'series'], false)
|
||||
const error = getDeep<string>(results, '0.error', null)
|
||||
const series = getDeep<TimeSeriesSeries>(results, '0.series', null)
|
||||
// 200 from server and no results = warn
|
||||
if (!series && !error) {
|
||||
editQueryStatus(query.id, {
|
||||
|
@ -38,12 +65,14 @@ export const handleSuccess = (data, query, editQueryStatus) => {
|
|||
return data
|
||||
}
|
||||
|
||||
export const handleError = (error, query, editQueryStatus) => {
|
||||
const message = _.get(
|
||||
error,
|
||||
['data', 'message'],
|
||||
error.message || 'Could not retrieve data'
|
||||
)
|
||||
const handleError = (
|
||||
error,
|
||||
query: Query,
|
||||
editQueryStatus: EditQueryStatusFunction
|
||||
): void => {
|
||||
const message =
|
||||
getDeep<string>(error, 'data.message', '') ||
|
||||
getDeep<string>(error, 'message', 'Could not retrieve data')
|
||||
|
||||
// 400 from chrono server = fail
|
||||
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 (
|
||||
{source, db, rp, query, tempVars, resolution}: Payload,
|
||||
editQueryStatus = noop
|
||||
) => {
|
||||
editQueryStatus: EditQueryStatusFunction = noop
|
||||
): Promise<TimeSeriesResponse> => {
|
||||
handleLoading(query, editQueryStatus)
|
||||
try {
|
||||
const {data} = await proxy({
|
||||
|
|
|
@ -45,6 +45,10 @@ class AnnotationInput extends Component<Props, State> {
|
|||
</div>
|
||||
)
|
||||
}
|
||||
public handleClickOutside = () => {
|
||||
this.props.onConfirmUpdate()
|
||||
this.setState({isEditing: false})
|
||||
}
|
||||
|
||||
private handleInputClick = () => {
|
||||
this.setState({isEditing: true})
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
import React, {PureComponent} from 'react'
|
||||
import classnames from 'classnames'
|
||||
import {ClickOutside} from 'src/shared/components/ClickOutside'
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
|
||||
type Position = 'top' | 'bottom' | 'left' | 'right'
|
||||
|
||||
interface Props {
|
||||
text?: string
|
||||
confirmText?: string
|
||||
|
@ -12,6 +15,7 @@ interface Props {
|
|||
icon?: string
|
||||
disabled?: boolean
|
||||
customClass?: string
|
||||
position?: Position
|
||||
}
|
||||
|
||||
interface State {
|
||||
|
@ -47,10 +51,11 @@ class ConfirmButton extends PureComponent<Props, State> {
|
|||
className={this.className}
|
||||
onClick={this.handleButtonClick}
|
||||
ref={r => (this.buttonDiv = r)}
|
||||
title={confirmText}
|
||||
>
|
||||
{icon && <span className={`icon ${icon}`} />}
|
||||
{text && text}
|
||||
<div className={`confirm-button--tooltip ${this.calculatedPosition}`}>
|
||||
<div className={this.tooltipClassName}>
|
||||
<div
|
||||
className="confirm-button--confirmation"
|
||||
onClick={this.handleConfirmClick}
|
||||
|
@ -64,18 +69,6 @@ class ConfirmButton extends PureComponent<Props, State> {
|
|||
)
|
||||
}
|
||||
|
||||
private get className() {
|
||||
const {type, size, square, disabled, customClass} = this.props
|
||||
const {expanded} = this.state
|
||||
|
||||
const customClassString = customClass ? ` ${customClass}` : ''
|
||||
const squareString = square ? ' btn-square' : ''
|
||||
const expandedString = expanded ? ' active' : ''
|
||||
const disabledString = disabled ? ' disabled' : ''
|
||||
|
||||
return `confirm-button btn ${type} ${size}${customClassString}${squareString}${expandedString}${disabledString}`
|
||||
}
|
||||
|
||||
private handleButtonClick = () => {
|
||||
if (this.props.disabled) {
|
||||
return
|
||||
|
@ -92,9 +85,27 @@ class ConfirmButton extends PureComponent<Props, State> {
|
|||
this.setState({expanded: false})
|
||||
}
|
||||
|
||||
private get calculatedPosition() {
|
||||
private get className(): string {
|
||||
const {type, size, square, disabled, customClass} = this.props
|
||||
const {expanded} = this.state
|
||||
|
||||
return classnames(`confirm-button btn ${type} ${size}`, {
|
||||
[customClass]: customClass,
|
||||
'btn-square': square,
|
||||
active: expanded,
|
||||
disabled,
|
||||
})
|
||||
}
|
||||
|
||||
private get tooltipClassName(): string {
|
||||
const {position} = this.props
|
||||
|
||||
if (position) {
|
||||
return `confirm-button--tooltip ${position}`
|
||||
}
|
||||
|
||||
if (!this.buttonDiv || !this.tooltipDiv) {
|
||||
return ''
|
||||
return 'confirm-button--tooltip bottom'
|
||||
}
|
||||
|
||||
const windowWidth = window.innerWidth
|
||||
|
@ -104,10 +115,10 @@ class ConfirmButton extends PureComponent<Props, State> {
|
|||
const rightGap = windowWidth - buttonRect.right
|
||||
|
||||
if (tooltipRect.width / 2 > rightGap) {
|
||||
return 'left'
|
||||
return 'confirm-button--tooltip left'
|
||||
}
|
||||
|
||||
return 'bottom'
|
||||
return 'confirm-button--tooltip bottom'
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -178,8 +178,10 @@ class Dygraph extends Component<Props, State> {
|
|||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
this.dygraph.destroy()
|
||||
delete this.dygraph
|
||||
if (this.dygraph) {
|
||||
this.dygraph.destroy()
|
||||
delete this.dygraph
|
||||
}
|
||||
}
|
||||
|
||||
public shouldComponentUpdate(nextProps: Props, nextState: State) {
|
||||
|
|
|
@ -112,6 +112,13 @@ class NewAnnotation extends Component<Props, State> {
|
|||
)
|
||||
}
|
||||
|
||||
public handleClickOutside = () => {
|
||||
const {onDismissAddingAnnotation, isTempHovering} = this.props
|
||||
if (!isTempHovering) {
|
||||
onDismissAddingAnnotation()
|
||||
}
|
||||
}
|
||||
|
||||
private clampWithinGraphTimerange = (timestamp: number): number => {
|
||||
const [xRangeStart] = this.props.dygraph.xAxisRange()
|
||||
return Math.max(xRangeStart, timestamp)
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
import React, {Component, ReactElement} from 'react'
|
||||
import classnames from 'classnames'
|
||||
|
||||
import Title from 'src/shared/components/PageHeaderTitle'
|
||||
import SourceIndicator from 'src/shared/components/SourceIndicator'
|
||||
|
||||
interface Props {
|
||||
titleText?: string
|
||||
titleComponents?: ReactElement<any>
|
||||
optionsComponents?: ReactElement<any>
|
||||
fullWidth?: boolean
|
||||
sourceIndicator?: boolean
|
||||
inPresentationMode?: boolean
|
||||
}
|
||||
|
||||
class PageHeader extends Component<Props> {
|
||||
public render() {
|
||||
const {inPresentationMode} = this.props
|
||||
|
||||
if (inPresentationMode) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={this.className}>
|
||||
<div className="page-header--container">
|
||||
<div className="page-header--left">{this.renderLeft}</div>
|
||||
<div className="page-header--right">
|
||||
{this.sourceIndicator}
|
||||
{this.renderRight}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
private get sourceIndicator(): JSX.Element {
|
||||
const {sourceIndicator} = this.props
|
||||
|
||||
if (!sourceIndicator) {
|
||||
return
|
||||
}
|
||||
|
||||
return <SourceIndicator />
|
||||
}
|
||||
|
||||
private get renderLeft(): JSX.Element {
|
||||
const {titleText, titleComponents} = this.props
|
||||
|
||||
if (!titleText && !titleComponents) {
|
||||
console.error(
|
||||
'PageHeader requires either titleText or titleComponents prop'
|
||||
)
|
||||
}
|
||||
|
||||
if (!titleComponents) {
|
||||
return <Title title={titleText} />
|
||||
}
|
||||
|
||||
return titleComponents
|
||||
}
|
||||
|
||||
private get renderRight(): JSX.Element {
|
||||
const {optionsComponents} = this.props
|
||||
|
||||
if (!optionsComponents) {
|
||||
return
|
||||
}
|
||||
|
||||
return optionsComponents
|
||||
}
|
||||
|
||||
private get className(): string {
|
||||
const {fullWidth} = this.props
|
||||
|
||||
return classnames('page-header', {'full-width': fullWidth})
|
||||
}
|
||||
}
|
||||
|
||||
export default PageHeader
|
|
@ -0,0 +1,11 @@
|
|||
import React, {SFC} from 'react'
|
||||
|
||||
interface Props {
|
||||
title: string
|
||||
}
|
||||
|
||||
const PageTitle: SFC<Props> = ({title}) => (
|
||||
<h1 className="page-header--title">{title}</h1>
|
||||
)
|
||||
|
||||
export default PageTitle
|
|
@ -1,47 +1,46 @@
|
|||
import React, {SFC} from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import _ from 'lodash'
|
||||
import uuid from 'uuid'
|
||||
|
||||
import ReactTooltip from 'react-tooltip'
|
||||
|
||||
import {SourceContext} from 'src/CheckSources'
|
||||
import {Source} from 'src/types'
|
||||
|
||||
interface Props {
|
||||
sourceOverride?: Source
|
||||
}
|
||||
|
||||
const SourceIndicator: SFC<Props> = (
|
||||
{sourceOverride},
|
||||
{source: {name, url}}
|
||||
) => {
|
||||
const getTooltipText = (source: Source, sourceOverride: Source): string => {
|
||||
const {name, url} = source
|
||||
const sourceName: string = _.get(sourceOverride, 'name', name)
|
||||
const sourceUrl: string = _.get(sourceOverride, 'url', url)
|
||||
const sourceNameTooltip: string = `<h1>Connected to Source:</h1><p><code>${sourceName} @ ${sourceUrl}</code></p>`
|
||||
const uuidTooltip: string = uuid.v4()
|
||||
|
||||
return sourceName ? (
|
||||
<div
|
||||
className="source-indicator"
|
||||
data-for={uuidTooltip}
|
||||
data-tip={sourceNameTooltip}
|
||||
>
|
||||
<span className="icon disks" />
|
||||
<ReactTooltip
|
||||
id={uuidTooltip}
|
||||
effect="solid"
|
||||
html={true}
|
||||
place="left"
|
||||
class="influx-tooltip"
|
||||
/>
|
||||
</div>
|
||||
) : null
|
||||
return `<h1>Connected to Source:</h1><p><code>${sourceName} @ ${sourceUrl}</code></p>`
|
||||
}
|
||||
|
||||
const {shape} = PropTypes
|
||||
const SourceIndicator: SFC<Props> = ({sourceOverride}) => {
|
||||
const uuidTooltip: string = uuid.v4()
|
||||
|
||||
SourceIndicator.contextTypes = {
|
||||
source: shape({}),
|
||||
return (
|
||||
<SourceContext.Consumer>
|
||||
{(source: Source) => (
|
||||
<div
|
||||
className="source-indicator"
|
||||
data-for={uuidTooltip}
|
||||
data-tip={getTooltipText(source, sourceOverride)}
|
||||
>
|
||||
<span className="icon disks" />
|
||||
<ReactTooltip
|
||||
id={uuidTooltip}
|
||||
effect="solid"
|
||||
html={true}
|
||||
place="left"
|
||||
class="influx-tooltip"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</SourceContext.Consumer>
|
||||
)
|
||||
}
|
||||
|
||||
export default SourceIndicator
|
||||
|
|
|
@ -48,7 +48,7 @@ interface TabListProps {
|
|||
activeIndex?: number
|
||||
onActivate?: (index: number) => void
|
||||
isKapacitorTabs?: string
|
||||
customClass: string
|
||||
customClass?: string
|
||||
}
|
||||
|
||||
export const TabList: SFC<TabListProps> = ({
|
||||
|
@ -97,7 +97,7 @@ TabList.defaultProps = {
|
|||
interface TabPanelsProps {
|
||||
children: JSX.Element[] | JSX.Element
|
||||
activeIndex?: number
|
||||
customClass: string
|
||||
customClass?: string
|
||||
}
|
||||
|
||||
export const TabPanels: SFC<TabPanelsProps> = ({
|
||||
|
@ -120,7 +120,7 @@ export const TabPanel: SFC<TabPanelProps> = ({children}) => (
|
|||
interface TabsProps {
|
||||
children: JSX.Element[] | JSX.Element
|
||||
onSelect?: (activeIndex: number) => void
|
||||
tabContentsClass: string
|
||||
tabContentsClass?: string
|
||||
tabsClass?: string
|
||||
initialIndex?: number
|
||||
}
|
||||
|
|
|
@ -1,22 +1,29 @@
|
|||
// All copy for notifications should be stored here for easy editing
|
||||
// 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 {MAX_RESPONSE_BYTES} from 'src/flux/constants'
|
||||
|
||||
const defaultErrorNotification = {
|
||||
const defaultErrorNotification: NotificationExcludingMessage = {
|
||||
type: 'error',
|
||||
icon: 'alert-triangle',
|
||||
duration: TEN_SECONDS,
|
||||
}
|
||||
|
||||
const defaultSuccessNotification = {
|
||||
const defaultSuccessNotification: NotificationExcludingMessage = {
|
||||
type: 'success',
|
||||
icon: 'checkmark',
|
||||
duration: FIVE_SECONDS,
|
||||
}
|
||||
|
||||
const defaultDeletionNotification = {
|
||||
const defaultDeletionNotification: NotificationExcludingMessage = {
|
||||
type: 'primary',
|
||||
icon: 'trash',
|
||||
duration: FIVE_SECONDS,
|
||||
|
@ -24,211 +31,240 @@ const defaultDeletionNotification = {
|
|||
|
||||
// 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',
|
||||
icon: 'cubo-uniform',
|
||||
duration: INFINITE,
|
||||
message: `Welcome to the latest Chronograf${version}. Local settings cleared.`,
|
||||
})
|
||||
|
||||
export const notifyLoadLocalSettingsFailed = error => ({
|
||||
export const notifyLoadLocalSettingsFailed = (error: string): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: `Loading local settings failed: ${error}`,
|
||||
})
|
||||
|
||||
export const notifyErrorWithAltText = (type, message) => ({
|
||||
export const notifyErrorWithAltText = (
|
||||
type: string,
|
||||
message: string
|
||||
): Notification => ({
|
||||
type,
|
||||
icon: 'triangle',
|
||||
duration: TEN_SECONDS,
|
||||
message,
|
||||
})
|
||||
|
||||
export const notifyPresentationMode = () => ({
|
||||
export const notifyPresentationMode = (): Notification => ({
|
||||
type: 'primary',
|
||||
icon: 'expand-b',
|
||||
duration: 7500,
|
||||
message: 'Press ESC to exit Presentation Mode.',
|
||||
})
|
||||
|
||||
export const notifyDataWritten = () => ({
|
||||
export const notifyDataWritten = (): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: 'Data was written successfully.',
|
||||
})
|
||||
|
||||
export const notifyDataWriteFailed = errorMessage => ({
|
||||
export const notifyDataWriteFailed = (errorMessage: string): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: `Data write failed: ${errorMessage}`,
|
||||
})
|
||||
|
||||
export const notifySessionTimedOut = () => ({
|
||||
export const notifySessionTimedOut = (): Notification => ({
|
||||
type: 'primary',
|
||||
icon: 'triangle',
|
||||
duration: INFINITE,
|
||||
message: 'Your session has timed out. Log in again to continue.',
|
||||
})
|
||||
|
||||
export const notifyServerError = {
|
||||
export const notifyServerError: Notification = {
|
||||
...defaultErrorNotification,
|
||||
message: 'Internal Server Error. Check API Logs.',
|
||||
}
|
||||
|
||||
export const notifyCouldNotRetrieveKapacitors = sourceID => ({
|
||||
export const notifyCouldNotRetrieveKapacitors = (
|
||||
sourceID: string
|
||||
): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: `Internal Server Error. Could not retrieve Kapacitor Connections for source ${sourceID}.`,
|
||||
})
|
||||
|
||||
export const notifyCouldNotRetrieveKapacitorServices = kapacitor => ({
|
||||
export const notifyCouldNotRetrieveKapacitorServices = (
|
||||
kapacitor: string
|
||||
): Notification => ({
|
||||
...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,
|
||||
message: 'Internal Server Error. Could not delete Kapacitor Connection.',
|
||||
})
|
||||
|
||||
export const notifyCSVDownloadFailed = () => ({
|
||||
export const notifyCSVDownloadFailed = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: 'Unable to download .CSV file',
|
||||
})
|
||||
|
||||
// Hosts Page Notifications
|
||||
// ----------------------------------------------------------------------------
|
||||
export const notifyUnableToGetHosts = () => ({
|
||||
export const notifyUnableToGetHosts = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: 'Unable to get Hosts.',
|
||||
})
|
||||
|
||||
export const notifyUnableToGetApps = () => ({
|
||||
export const notifyUnableToGetApps = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: 'Unable to get Apps for Hosts.',
|
||||
})
|
||||
|
||||
// InfluxDB Sources Notifications
|
||||
// ----------------------------------------------------------------------------
|
||||
export const notifySourceCreationSucceeded = sourceName => ({
|
||||
export const notifySourceCreationSucceeded = (
|
||||
sourceName: string
|
||||
): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
icon: 'server2',
|
||||
message: `Connected to InfluxDB ${sourceName} successfully.`,
|
||||
})
|
||||
|
||||
export const notifySourceCreationFailed = (sourceName, errorMessage) => ({
|
||||
export const notifySourceCreationFailed = (
|
||||
sourceName: string,
|
||||
errorMessage: string
|
||||
): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
icon: 'server2',
|
||||
message: `Unable to connect to InfluxDB ${sourceName}: ${errorMessage}`,
|
||||
})
|
||||
|
||||
export const notifySourceUdpated = sourceName => ({
|
||||
export const notifySourceUdpated = (sourceName: string): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
icon: 'server2',
|
||||
message: `Updated InfluxDB ${sourceName} Connection successfully.`,
|
||||
})
|
||||
|
||||
export const notifySourceUdpateFailed = (sourceName, errorMessage) => ({
|
||||
export const notifySourceUdpateFailed = (
|
||||
sourceName: string,
|
||||
errorMessage: string
|
||||
): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
icon: 'server2',
|
||||
message: `Failed to update InfluxDB ${sourceName} Connection: ${errorMessage}`,
|
||||
})
|
||||
|
||||
export const notifySourceDeleted = (sourceName: string) => ({
|
||||
export const notifySourceDeleted = (sourceName: string): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
icon: 'server2',
|
||||
message: `${sourceName} deleted successfully.`,
|
||||
})
|
||||
|
||||
export const notifySourceDeleteFailed = sourceName => ({
|
||||
export const notifySourceDeleteFailed = (sourceName: string): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
icon: 'server2',
|
||||
message: `There was a problem deleting ${sourceName}.`,
|
||||
})
|
||||
|
||||
export const notifySourceNoLongerAvailable = sourceName =>
|
||||
`Source ${sourceName} is no longer available. Please ensure InfluxDB is running.`
|
||||
|
||||
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 => ({
|
||||
export const notifySourceNoLongerAvailable = (
|
||||
sourceName: string
|
||||
): Notification => ({
|
||||
...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}`,
|
||||
})
|
||||
|
||||
// Multitenancy User Notifications
|
||||
// ----------------------------------------------------------------------------
|
||||
export const notifyUserRemovedFromAllOrgs = () => ({
|
||||
export const notifyUserRemovedFromAllOrgs = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
duration: INFINITE,
|
||||
message:
|
||||
'You have been removed from all organizations. Please contact your administrator.',
|
||||
})
|
||||
|
||||
export const notifyUserRemovedFromCurrentOrg = () => ({
|
||||
export const notifyUserRemovedFromCurrentOrg = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
duration: INFINITE,
|
||||
message: 'You were removed from your current organization.',
|
||||
})
|
||||
|
||||
export const notifyOrgHasNoSources = () => ({
|
||||
export const notifyOrgHasNoSources = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
duration: INFINITE,
|
||||
message: 'Organization has no sources configured.',
|
||||
})
|
||||
|
||||
export const notifyUserSwitchedOrgs = (orgName, roleName) => ({
|
||||
export const notifyUserSwitchedOrgs = (
|
||||
orgName: string,
|
||||
roleName: string
|
||||
): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
type: 'primary',
|
||||
message: `Now logged in to '${orgName}' as '${roleName}'.`,
|
||||
})
|
||||
|
||||
export const notifyOrgIsPrivate = () => ({
|
||||
export const notifyOrgIsPrivate = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
duration: INFINITE,
|
||||
message:
|
||||
'This organization is private. To gain access, you must be explicitly added by an administrator.',
|
||||
})
|
||||
|
||||
export const notifyCurrentOrgDeleted = () => ({
|
||||
export const notifyCurrentOrgDeleted = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
duration: INFINITE,
|
||||
message: 'Your current organization was deleted.',
|
||||
})
|
||||
|
||||
export const notifyJSONFeedFailed = url => ({
|
||||
export const notifyJSONFeedFailed = (url: string): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: `Failed to fetch JSON Feed for News Feed from '${url}'`,
|
||||
})
|
||||
|
||||
// Chronograf Admin Notifications
|
||||
// ----------------------------------------------------------------------------
|
||||
export const notifyMappingDeleted = (id, scheme) => ({
|
||||
export const notifyMappingDeleted = (
|
||||
id: string,
|
||||
scheme: string
|
||||
): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: `Mapping ${id}/${scheme} deleted successfully.`,
|
||||
})
|
||||
|
||||
export const notifyChronografUserAddedToOrg = (user, organization) =>
|
||||
`${user} has been added to ${organization} successfully.`
|
||||
export const notifyChronografUserAddedToOrg = (
|
||||
user: string,
|
||||
organization: string
|
||||
): string => `${user} has been added to ${organization} successfully.`
|
||||
|
||||
export const notifyChronografUserRemovedFromOrg = (user, organization) =>
|
||||
`${user} has been removed from ${organization} successfully.`
|
||||
export const notifyChronografUserRemovedFromOrg = (
|
||||
user: string,
|
||||
organization: string
|
||||
): string => `${user} has been removed from ${organization} successfully.`
|
||||
|
||||
export const notifyChronografUserUpdated = message => ({
|
||||
export const notifyChronografUserUpdated = (message: string): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message,
|
||||
})
|
||||
|
||||
export const notifyChronografOrgDeleted = orgName => ({
|
||||
export const notifyChronografOrgDeleted = (orgName: string): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: `Organization ${orgName} deleted successfully.`,
|
||||
})
|
||||
|
||||
export const notifyChronografUserDeleted = (user, isAbsoluteDelete) => ({
|
||||
export const notifyChronografUserDeleted = (
|
||||
user: string,
|
||||
isAbsoluteDelete: boolean
|
||||
): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: `${user} has been removed from ${
|
||||
isAbsoluteDelete
|
||||
|
@ -237,7 +273,7 @@ export const notifyChronografUserDeleted = (user, isAbsoluteDelete) => ({
|
|||
}`,
|
||||
})
|
||||
|
||||
export const notifyChronografUserMissingNameAndProvider = () => ({
|
||||
export const notifyChronografUserMissingNameAndProvider = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
type: 'warning',
|
||||
message: 'User must have a Name and Provider.',
|
||||
|
@ -245,220 +281,238 @@ export const notifyChronografUserMissingNameAndProvider = () => ({
|
|||
|
||||
// InfluxDB Admin Notifications
|
||||
// ----------------------------------------------------------------------------
|
||||
export const notifyDBUserCreated = () => ({
|
||||
export const notifyDBUserCreated = (): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: 'User created successfully.',
|
||||
})
|
||||
|
||||
export const notifyDBUserCreationFailed = errorMessage =>
|
||||
export const notifyDBUserCreationFailed = (errorMessage: string): string =>
|
||||
`Failed to create User: ${errorMessage}`
|
||||
|
||||
export const notifyDBUserDeleted = userName => ({
|
||||
export const notifyDBUserDeleted = (userName: string): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: `User "${userName}" deleted successfully.`,
|
||||
})
|
||||
|
||||
export const notifyDBUserDeleteFailed = errorMessage =>
|
||||
export const notifyDBUserDeleteFailed = (errorMessage: string): string =>
|
||||
`Failed to delete User: ${errorMessage}`
|
||||
|
||||
export const notifyDBUserPermissionsUpdated = () => ({
|
||||
export const notifyDBUserPermissionsUpdated = (): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: 'User Permissions updated successfully.',
|
||||
})
|
||||
|
||||
export const notifyDBUserPermissionsUpdateFailed = errorMessage =>
|
||||
`Failed to update User Permissions: ${errorMessage}`
|
||||
export const notifyDBUserPermissionsUpdateFailed = (
|
||||
errorMessage: string
|
||||
): string => `Failed to update User Permissions: ${errorMessage}`
|
||||
|
||||
export const notifyDBUserRolesUpdated = () => ({
|
||||
export const notifyDBUserRolesUpdated = (): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: 'User Roles updated successfully.',
|
||||
})
|
||||
|
||||
export const notifyDBUserRolesUpdateFailed = errorMessage =>
|
||||
export const notifyDBUserRolesUpdateFailed = (errorMessage: string): string =>
|
||||
`Failed to update User Roles: ${errorMessage}`
|
||||
|
||||
export const notifyDBUserPasswordUpdated = () => ({
|
||||
export const notifyDBUserPasswordUpdated = (): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: 'User Password updated successfully.',
|
||||
})
|
||||
|
||||
export const notifyDBUserPasswordUpdateFailed = errorMessage =>
|
||||
`Failed to update User Password: ${errorMessage}`
|
||||
export const notifyDBUserPasswordUpdateFailed = (
|
||||
errorMessage: string
|
||||
): string => `Failed to update User Password: ${errorMessage}`
|
||||
|
||||
export const notifyDatabaseCreated = () => ({
|
||||
export const notifyDatabaseCreated = (): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: 'Database created successfully.',
|
||||
})
|
||||
|
||||
export const notifyDBCreationFailed = errorMessage =>
|
||||
export const notifyDBCreationFailed = (errorMessage: string): string =>
|
||||
`Failed to create Database: ${errorMessage}`
|
||||
|
||||
export const notifyDBDeleted = databaseName => ({
|
||||
export const notifyDBDeleted = (databaseName: string): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: `Database "${databaseName}" deleted successfully.`,
|
||||
})
|
||||
|
||||
export const notifyDBDeleteFailed = errorMessage =>
|
||||
export const notifyDBDeleteFailed = (errorMessage: string): string =>
|
||||
`Failed to delete Database: ${errorMessage}`
|
||||
|
||||
export const notifyRoleCreated = () => ({
|
||||
export const notifyRoleCreated = (): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: 'Role created successfully.',
|
||||
})
|
||||
|
||||
export const notifyRoleCreationFailed = errorMessage =>
|
||||
export const notifyRoleCreationFailed = (errorMessage: string): string =>
|
||||
`Failed to create Role: ${errorMessage}`
|
||||
|
||||
export const notifyRoleDeleted = roleName => ({
|
||||
export const notifyRoleDeleted = (roleName: string): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: `Role "${roleName}" deleted successfully.`,
|
||||
})
|
||||
|
||||
export const notifyRoleDeleteFailed = errorMessage =>
|
||||
export const notifyRoleDeleteFailed = (errorMessage: string): string =>
|
||||
`Failed to delete Role: ${errorMessage}`
|
||||
|
||||
export const notifyRoleUsersUpdated = () => ({
|
||||
export const notifyRoleUsersUpdated = (): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: 'Role Users updated successfully.',
|
||||
})
|
||||
|
||||
export const notifyRoleUsersUpdateFailed = errorMessage =>
|
||||
export const notifyRoleUsersUpdateFailed = (errorMessage: string): string =>
|
||||
`Failed to update Role Users: ${errorMessage}`
|
||||
|
||||
export const notifyRolePermissionsUpdated = () => ({
|
||||
export const notifyRolePermissionsUpdated = (): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: 'Role Permissions updated successfully.',
|
||||
})
|
||||
|
||||
export const notifyRolePermissionsUpdateFailed = errorMessage =>
|
||||
`Failed to update Role Permissions: ${errorMessage}`
|
||||
export const notifyRolePermissionsUpdateFailed = (
|
||||
errorMessage: string
|
||||
): string => `Failed to update Role Permissions: ${errorMessage}`
|
||||
|
||||
export const notifyRetentionPolicyCreated = () => ({
|
||||
export const notifyRetentionPolicyCreated = (): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: 'Retention Policy created successfully.',
|
||||
})
|
||||
|
||||
export const notifyRetentionPolicyCreationError = () => ({
|
||||
export const notifyRetentionPolicyCreationError = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: 'Failed to create Retention Policy. Please check name and duration.',
|
||||
})
|
||||
|
||||
export const notifyRetentionPolicyCreationFailed = errorMessage =>
|
||||
`Failed to create Retention Policy: ${errorMessage}`
|
||||
export const notifyRetentionPolicyCreationFailed = (
|
||||
errorMessage: string
|
||||
): string => `Failed to create Retention Policy: ${errorMessage}`
|
||||
|
||||
export const notifyRetentionPolicyDeleted = rpName => ({
|
||||
export const notifyRetentionPolicyDeleted = (rpName: string): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: `Retention Policy "${rpName}" deleted successfully.`,
|
||||
})
|
||||
|
||||
export const notifyRetentionPolicyDeleteFailed = errorMessage =>
|
||||
`Failed to delete Retention Policy: ${errorMessage}`
|
||||
export const notifyRetentionPolicyDeleteFailed = (
|
||||
errorMessage: string
|
||||
): string => `Failed to delete Retention Policy: ${errorMessage}`
|
||||
|
||||
export const notifyRetentionPolicyUpdated = () => ({
|
||||
export const notifyRetentionPolicyUpdated = (): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: 'Retention Policy updated successfully.',
|
||||
})
|
||||
|
||||
export const notifyRetentionPolicyUpdateFailed = errorMessage =>
|
||||
`Failed to update Retention Policy: ${errorMessage}`
|
||||
export const notifyRetentionPolicyUpdateFailed = (
|
||||
errorMessage: string
|
||||
): string => `Failed to update Retention Policy: ${errorMessage}`
|
||||
|
||||
export const notifyQueriesError = errorMessage => ({
|
||||
export const notifyQueriesError = (errorMessage: string): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
errorMessage,
|
||||
message: errorMessage,
|
||||
})
|
||||
|
||||
export const notifyRetentionPolicyCantHaveEmptyFields = () => ({
|
||||
export const notifyRetentionPolicyCantHaveEmptyFields = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: 'Fields cannot be empty.',
|
||||
})
|
||||
|
||||
export const notifyDatabaseDeleteConfirmationRequired = databaseName => ({
|
||||
export const notifyDatabaseDeleteConfirmationRequired = (
|
||||
databaseName: string
|
||||
): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: `Type "DELETE ${databaseName}" to confirm. This action cannot be undone.`,
|
||||
})
|
||||
|
||||
export const notifyDBUserNamePasswordInvalid = () => ({
|
||||
export const notifyDBUserNamePasswordInvalid = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: 'Username and/or Password too short.',
|
||||
})
|
||||
|
||||
export const notifyRoleNameInvalid = () => ({
|
||||
export const notifyRoleNameInvalid = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: 'Role name is too short.',
|
||||
})
|
||||
|
||||
export const notifyDatabaseNameInvalid = () => ({
|
||||
export const notifyDatabaseNameInvalid = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: 'Database name cannot be blank.',
|
||||
})
|
||||
|
||||
export const notifyDatabaseNameAlreadyExists = () => ({
|
||||
export const notifyDatabaseNameAlreadyExists = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: 'A Database by this name already exists.',
|
||||
})
|
||||
|
||||
// Dashboard Notifications
|
||||
// ----------------------------------------------------------------------------
|
||||
export const notifyTempVarAlreadyExists = tempVarName => ({
|
||||
export const notifyTempVarAlreadyExists = (
|
||||
tempVarName: string
|
||||
): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
icon: 'cube',
|
||||
message: `Variable '${tempVarName}' already exists. Please enter a new value.`,
|
||||
})
|
||||
|
||||
export const notifyDashboardNotFound = dashboardID => ({
|
||||
export const notifyDashboardNotFound = (dashboardID: number): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
icon: 'dash-h',
|
||||
message: `Dashboard ${dashboardID} could not be found`,
|
||||
})
|
||||
|
||||
export const notifyDashboardDeleted = name => ({
|
||||
export const notifyDashboardDeleted = (name: string): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
icon: 'dash-h',
|
||||
message: `Dashboard ${name} deleted successfully.`,
|
||||
})
|
||||
|
||||
export const notifyDashboardExported = name => ({
|
||||
export const notifyDashboardExported = (name: string): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
icon: 'dash-h',
|
||||
message: `Dashboard ${name} exported successfully.`,
|
||||
})
|
||||
|
||||
export const notifyDashboardExportFailed = (name, errorMessage) => ({
|
||||
export const notifyDashboardExportFailed = (
|
||||
name: string,
|
||||
errorMessage: string
|
||||
): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
duration: INFINITE,
|
||||
message: `Failed to export Dashboard ${name}: ${errorMessage}.`,
|
||||
})
|
||||
|
||||
export const notifyDashboardImported = name => ({
|
||||
export const notifyDashboardImported = (name: string): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
icon: 'dash-h',
|
||||
message: `Dashboard ${name} imported successfully.`,
|
||||
})
|
||||
|
||||
export const notifyDashboardImportFailed = (fileName, errorMessage) => ({
|
||||
export const notifyDashboardImportFailed = (
|
||||
fileName: string,
|
||||
errorMessage: string
|
||||
): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
duration: INFINITE,
|
||||
message: `Failed to import Dashboard from file ${fileName}: ${errorMessage}.`,
|
||||
})
|
||||
|
||||
export const notifyDashboardDeleteFailed = (name, errorMessage) =>
|
||||
`Failed to delete Dashboard ${name}: ${errorMessage}.`
|
||||
export const notifyDashboardDeleteFailed = (
|
||||
name: string,
|
||||
errorMessage: string
|
||||
): string => `Failed to delete Dashboard ${name}: ${errorMessage}.`
|
||||
|
||||
export const notifyCellAdded = name => ({
|
||||
export const notifyCellAdded = (name: string): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
icon: 'dash-h',
|
||||
duration: 1900,
|
||||
message: `Added "${name}" to dashboard.`,
|
||||
})
|
||||
|
||||
export const notifyCellDeleted = name => ({
|
||||
export const notifyCellDeleted = (name: string): Notification => ({
|
||||
...defaultDeletionNotification,
|
||||
icon: 'dash-h',
|
||||
duration: 1900,
|
||||
message: `Deleted "${name}" from dashboard.`,
|
||||
})
|
||||
|
||||
export const notifyBuilderDisabled = () => ({
|
||||
export const notifyBuilderDisabled = (): Notification => ({
|
||||
type: 'info',
|
||||
icon: 'graphline',
|
||||
duration: 7500,
|
||||
|
@ -467,249 +521,276 @@ export const notifyBuilderDisabled = () => ({
|
|||
|
||||
// Template Variables & URL Queries
|
||||
// ----------------------------------------------------------------------------
|
||||
export const notifyInvalidTempVarValueInURLQuery = ({key, value}) => ({
|
||||
export const notifyInvalidTempVarValueInURLQuery = ({
|
||||
key,
|
||||
value,
|
||||
}: TemplateUpdate): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
icon: 'cube',
|
||||
message: `Invalid URL query value of '${value}' supplied for template variable '${key}'.`,
|
||||
})
|
||||
|
||||
export const notifyInvalidTimeRangeValueInURLQuery = () => ({
|
||||
export const notifyInvalidTimeRangeValueInURLQuery = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
icon: 'cube',
|
||||
message: `Invalid URL query value supplied for lower or upper time range.`,
|
||||
})
|
||||
|
||||
export const notifyInvalidZoomedTimeRangeValueInURLQuery = () => ({
|
||||
export const notifyInvalidZoomedTimeRangeValueInURLQuery = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
icon: 'cube',
|
||||
message: `Invalid URL query value supplied for zoomed lower or zoomed upper time range.`,
|
||||
})
|
||||
|
||||
export const notifyViewerUnauthorizedToSetTempVars = () => ({
|
||||
export const notifyViewerUnauthorizedToSetTempVars = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: `Viewer role unauthorized to override template variable values from URL.`,
|
||||
})
|
||||
|
||||
// Rule Builder Notifications
|
||||
// ----------------------------------------------------------------------------
|
||||
export const notifyAlertRuleCreated = ruleName => ({
|
||||
export const notifyAlertRuleCreated = (ruleName: string): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: `${ruleName} created successfully.`,
|
||||
})
|
||||
|
||||
export const notifyAlertRuleCreateFailed = (ruleName, errorMessage) => ({
|
||||
export const notifyAlertRuleCreateFailed = (
|
||||
ruleName: string,
|
||||
errorMessage: string
|
||||
): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: `There was a problem creating ${ruleName}: ${errorMessage}`,
|
||||
})
|
||||
|
||||
export const notifyAlertRuleUpdated = ruleName => ({
|
||||
export const notifyAlertRuleUpdated = (ruleName: string): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: `${ruleName} saved successfully.`,
|
||||
})
|
||||
|
||||
export const notifyAlertRuleUpdateFailed = (ruleName, errorMessage) => ({
|
||||
export const notifyAlertRuleUpdateFailed = (
|
||||
ruleName: string,
|
||||
errorMessage: string
|
||||
): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: `There was a problem saving ${ruleName}: ${errorMessage}`,
|
||||
})
|
||||
|
||||
export const notifyAlertRuleDeleted = ruleName => ({
|
||||
export const notifyAlertRuleDeleted = (ruleName: string): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: `${ruleName} deleted successfully.`,
|
||||
})
|
||||
|
||||
export const notifyAlertRuleDeleteFailed = ruleName => ({
|
||||
export const notifyAlertRuleDeleteFailed = (
|
||||
ruleName: string
|
||||
): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: `${ruleName} could not be deleted.`,
|
||||
})
|
||||
|
||||
export const notifyAlertRuleStatusUpdated = (ruleName, updatedStatus) => ({
|
||||
export const notifyAlertRuleStatusUpdated = (
|
||||
ruleName: string,
|
||||
updatedStatus: string
|
||||
): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: `${ruleName} ${updatedStatus} successfully.`,
|
||||
})
|
||||
|
||||
export const notifyAlertRuleStatusUpdateFailed = (ruleName, updatedStatus) => ({
|
||||
export const notifyAlertRuleStatusUpdateFailed = (
|
||||
ruleName: string,
|
||||
updatedStatus: string
|
||||
): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: `${ruleName} could not be ${updatedStatus}.`,
|
||||
})
|
||||
|
||||
export const notifyAlertRuleRequiresQuery = () =>
|
||||
export const notifyAlertRuleRequiresQuery = (): string =>
|
||||
'Please select a Database, Measurement, and Field.'
|
||||
|
||||
export const notifyAlertRuleRequiresConditionValue = () =>
|
||||
export const notifyAlertRuleRequiresConditionValue = (): string =>
|
||||
'Please enter a value in the Conditions section.'
|
||||
|
||||
export const notifyAlertRuleDeadmanInvalid = () =>
|
||||
export const notifyAlertRuleDeadmanInvalid = (): string =>
|
||||
'Deadman rules require a Database and Measurement.'
|
||||
|
||||
// Kapacitor Configuration Notifications
|
||||
// ----------------------------------------------------------------------------
|
||||
export const notifyKapacitorNameAlreadyTaken = kapacitorName => ({
|
||||
export const notifyKapacitorNameAlreadyTaken = (
|
||||
kapacitorName: string
|
||||
): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: `There is already a Kapacitor Connection named "${kapacitorName}".`,
|
||||
})
|
||||
|
||||
export const notifyCouldNotFindKapacitor = () => ({
|
||||
export const notifyCouldNotFindKapacitor = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: 'We could not find a Kapacitor configuration for this source.',
|
||||
})
|
||||
|
||||
export const notifyRefreshKapacitorFailed = () => ({
|
||||
export const notifyRefreshKapacitorFailed = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: 'There was an error getting the Kapacitor configuration.',
|
||||
})
|
||||
|
||||
export const notifyAlertEndpointSaved = endpoint => ({
|
||||
export const notifyAlertEndpointSaved = (endpoint: string): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: `Alert configuration for ${endpoint} saved successfully.`,
|
||||
})
|
||||
|
||||
export const notifyAlertEndpointSaveFailed = (endpoint, errorMessage) => ({
|
||||
export const notifyAlertEndpointSaveFailed = (
|
||||
endpoint: string,
|
||||
errorMessage: string
|
||||
): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: `There was an error saving the alert configuration for ${endpoint}: ${errorMessage}`,
|
||||
})
|
||||
|
||||
export const notifyAlertEndpointDeleteFailed = (
|
||||
endpoint,
|
||||
config,
|
||||
errorMessage
|
||||
) => ({
|
||||
endpoint: string,
|
||||
config: string,
|
||||
errorMessage: string
|
||||
): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
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,
|
||||
message: `Alert configuration for ${endpoint}/${config} deleted successfully.`,
|
||||
})
|
||||
|
||||
export const notifyTestAlertSent = endpoint => ({
|
||||
export const notifyTestAlertSent = (endpoint: string): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
duration: TEN_SECONDS,
|
||||
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,
|
||||
message: `There was an error sending a Test Alert to ${endpoint}${
|
||||
errorMessage ? `: ${errorMessage}` : '.'
|
||||
}`,
|
||||
message: `There was an error sending a Test Alert to ${endpoint} ${errorMessage}.`,
|
||||
})
|
||||
|
||||
export const notifyInvalidBatchSizeValue = () => ({
|
||||
export const notifyInvalidBatchSizeValue = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: 'Batch Size cannot be empty.',
|
||||
})
|
||||
|
||||
export const notifyKapacitorConnectionFailed = () => ({
|
||||
export const notifyKapacitorConnectionFailed = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message:
|
||||
'Could not connect to Kapacitor. Check your connection settings in the Configuration page.',
|
||||
})
|
||||
|
||||
export const notifyKapacitorCreated = () => ({
|
||||
export const notifyKapacitorCreated = (): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message:
|
||||
'Connected to Kapacitor successfully! Configuring endpoints is optional.',
|
||||
})
|
||||
|
||||
export const notifyKapacitorCreateFailed = () => ({
|
||||
export const notifyKapacitorCreateFailed = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: 'There was a problem connecting to Kapacitor.',
|
||||
})
|
||||
|
||||
export const notifyKapacitorUpdated = () => ({
|
||||
export const notifyKapacitorUpdated = (): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: 'Kapacitor Connection updated successfully.',
|
||||
})
|
||||
|
||||
export const notifyKapacitorUpdateFailed = () => ({
|
||||
export const notifyKapacitorUpdateFailed = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: 'There was a problem updating the Kapacitor Connection.',
|
||||
})
|
||||
|
||||
// TICKscript Notifications
|
||||
// ----------------------------------------------------------------------------
|
||||
export const notifyTickScriptCreated = () => ({
|
||||
export const notifyTickScriptCreated = (): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: 'TICKscript successfully created.',
|
||||
})
|
||||
|
||||
export const notifyTickscriptCreationFailed = () =>
|
||||
export const notifyTickscriptCreationFailed = (): string =>
|
||||
'Failed to create TICKscript.'
|
||||
|
||||
export const notifyTickscriptUpdated = () => ({
|
||||
export const notifyTickscriptUpdated = (): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
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',
|
||||
icon: 'alert-triangle',
|
||||
duration: INFINITE,
|
||||
message: 'Kapacitor version 1.4 required to view TICKscript logs',
|
||||
})
|
||||
|
||||
export const notifyTickscriptLoggingError = () => ({
|
||||
export const notifyTickscriptLoggingError = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: 'Could not collect kapacitor logs',
|
||||
})
|
||||
|
||||
export const notifyKapacitorNotFound = () => ({
|
||||
export const notifyKapacitorNotFound = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: 'We could not find a Kapacitor configuration for this source.',
|
||||
})
|
||||
|
||||
// Flux notifications
|
||||
export const validateSuccess = () => ({
|
||||
export const validateSuccess = (): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: 'No errors found. Happy Happy Joy Joy!',
|
||||
})
|
||||
|
||||
export const notifyCopyToClipboardSuccess = text => ({
|
||||
export const notifyCopyToClipboardSuccess = (text: string): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
icon: 'dash-h',
|
||||
message: `'${text}' has been copied to clipboard.`,
|
||||
})
|
||||
|
||||
export const notifyCopyToClipboardFailed = text => ({
|
||||
export const notifyCopyToClipboardFailed = (text: string): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: `'${text}' was not copied to clipboard.`,
|
||||
})
|
||||
|
||||
// Service notifications
|
||||
export const couldNotGetServices = {
|
||||
export const couldNotGetServices: Notification = {
|
||||
...defaultErrorNotification,
|
||||
message: 'We could not get services',
|
||||
}
|
||||
|
||||
export const fluxCreated = {
|
||||
export const fluxCreated: Notification = {
|
||||
...defaultSuccessNotification,
|
||||
message: 'Flux Connection Created. Script your heart out!',
|
||||
}
|
||||
|
||||
export const fluxNotCreated = (message: string) => ({
|
||||
export const fluxNotCreated = (message: string): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message,
|
||||
})
|
||||
|
||||
export const fluxNotUpdated = (message: string) => ({
|
||||
export const fluxNotUpdated = (message: string): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message,
|
||||
})
|
||||
|
||||
export const fluxUpdated = {
|
||||
export const fluxUpdated: Notification = {
|
||||
...defaultSuccessNotification,
|
||||
message: 'Connection Updated. Rejoice!',
|
||||
}
|
||||
|
||||
export const fluxTimeSeriesError = (message: string) => ({
|
||||
export const fluxTimeSeriesError = (message: string): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: `Could not get data: ${message}`,
|
||||
})
|
||||
|
||||
export const fluxResponseTruncatedError = () => {
|
||||
export const fluxResponseTruncatedError = (): Notification => {
|
||||
const BYTES_TO_MB = 1 / 1e6
|
||||
const APPROX_MAX_RESPONSE_MB = +(MAX_RESPONSE_BYTES * BYTES_TO_MB).toFixed(2)
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue