diff --git a/.circleci/config.yml b/.circleci/config.yml index df82df9fa801c..23414436bf8f4 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -19,7 +19,7 @@ version: 2 jobs: mysql-integration-test: docker: - - image: circleci/golang:1.11.5 + - image: circleci/golang:1.12.4 - image: circleci/mysql:5.6-ram environment: MYSQL_ROOT_PASSWORD: rootpass @@ -39,7 +39,7 @@ jobs: postgres-integration-test: docker: - - image: circleci/golang:1.11.5 + - image: circleci/golang:1.12.4 - image: circleci/postgres:9.3-ram environment: POSTGRES_USER: grafanatest @@ -58,7 +58,7 @@ jobs: cache-server-test: docker: - - image: circleci/golang:1.11.5 + - image: circleci/golang:1.12.4 - image: circleci/redis:4-alpine - image: memcached working_directory: /go/src/github.com/grafana/grafana @@ -88,7 +88,7 @@ jobs: backend-lint: docker: - - image: circleci/golang:1.11.5 + - image: circleci/golang:1.12.4 environment: # we need CGO because of go-sqlite3 CGO_ENABLED: 1 @@ -120,7 +120,7 @@ jobs: test-backend: docker: - - image: circleci/golang:1.11.5 + - image: circleci/golang:1.12.4 working_directory: /go/src/github.com/grafana/grafana steps: - checkout @@ -130,7 +130,7 @@ jobs: build-all: docker: - - image: grafana/build-container:1.2.4 + - image: grafana/build-container:1.2.6 working_directory: /go/src/github.com/grafana/grafana steps: - checkout @@ -174,7 +174,7 @@ jobs: build: docker: - - image: grafana/build-container:1.2.4 + - image: grafana/build-container:1.2.6 working_directory: /go/src/github.com/grafana/grafana steps: - checkout @@ -243,7 +243,7 @@ jobs: build-enterprise: docker: - - image: grafana/build-container:1.2.4 + - image: grafana/build-container:1.2.6 working_directory: /go/src/github.com/grafana/grafana steps: - checkout @@ -275,7 +275,7 @@ jobs: build-all-enterprise: docker: - - image: grafana/build-container:1.2.4 + - image: grafana/build-container:1.2.6 working_directory: /go/src/github.com/grafana/grafana steps: - checkout diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 837891f6c41e9..d923c215be589 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -5,7 +5,7 @@ 3. If it's a new feature or config option it will need a docs update. Docs are under the docs folder in repo root. 4. If the PR is unfinished, mark it as a draft PR. 5. Rebase your PR if it gets out of sync with master -6. Name your RP as `: Describe your change`. If it's a fix or feature relevant for changelog describe the user impact in the title. The PR title is used in changelog for issues marked with `add to changelog` label. +6. Name your PR as `: Describe your change`. If it's a fix or feature relevant for changelog describe the user impact in the title. The PR title is used in changelog for issues marked with `add to changelog` label. --> **What this PR does / why we need it**: diff --git a/CHANGELOG.md b/CHANGELOG.md index dd07f39a6cb61..5e8fec5ac833d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,31 @@ # 6.2.0 (unreleased) +# 6.1.4 (2019-04-16) + +### Bug Fixes + * **DataPanel**: Added missing built-in interval variables to scopedVars. [#16556](https://github.com/grafana/grafana/pull/16556), [@torkelo](https://github.com/torkelo) + * **Explore**: Adds maxDataPoints to data source query options . [#16513](https://github.com/grafana/grafana/pull/16513), [@hugohaggmark](https://github.com/hugohaggmark) + * **Explore**: Fixes so intervals are recalculated on run query. [#16510](https://github.com/grafana/grafana/pull/16510), [@hugohaggmark](https://github.com/hugohaggmark) + * **Heatmap**: Fix for empty graph when panel is too narrow (#16378). [#16460](https://github.com/grafana/grafana/pull/16460), [@alexanderzobnin](https://github.com/alexanderzobnin) + * **Heatmap**: Fixed auto decimals when bucket name is not number. [#16609](https://github.com/grafana/grafana/pull/16609), [@torkelo](https://github.com/torkelo) + * **QueryInspector**: Now shows error responses again. [#16514](https://github.com/grafana/grafana/pull/16514), [@torkelo](https://github.com/torkelo) + +# 6.1.3 (2019-04-09) + +### Bug Fixes + * **Graph**: Fixed auto decimals in legend values for some units like `ms` and `s`. [#16455](https://github.com/grafana/grafana/pull/16455), [@torkelo](https://github.com/torkelo) + * **Graph**: Fixed png rendering with legend to the right. [#16463](https://github.com/grafana/grafana/pull/16463), [@torkelo](https://github.com/torkelo) + * **Singlestat**: Use decimals when manually specified. [#16451](https://github.com/grafana/grafana/pull/16451), [@torkelo](https://github.com/torkelo) + * **UI Switch**: Fix broken UI switches. Fixes Default Data Source switch, Explore Logs switches, Gauge option switches. [#16303](https://github.com/grafana/grafana/pull/16303), [@dprokop](https://github.com/dprokop) + +# 6.1.2 (2019-04-08) + + ### Bug Fixes + * **Graph**: Fixed series legend color for hidden series. [#16438](https://github.com/grafana/grafana/pull/16438), [@Ijin08](https://github.com/Ijin08) + * **Graph**: Fixed tooltip highlight on white theme. [#16429](https://github.com/grafana/grafana/pull/16429), [@torkelo](https://github.com/torkelo) + * **Styles**: Fixed menu hover highlight border. [#16431](https://github.com/grafana/grafana/pull/16431), [@torkelo](https://github.com/torkelo) + * **Singlestat Panel**: Correctly use the override decimals. [#16413](https://github.com/grafana/grafana/pull/16413), [@torkelo](https://github.com/torkelo) + # 6.1.1 (2019-04-05) ### Bug Fixes diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d21ef5232d643..272e53787601f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -52,3 +52,31 @@ Closes #12864 ``` If the pull request needs changes before its merged the new commits should be rebased into one commit before its merged. + +## Backend dependency management + +The Grafana project uses [Go modules](https://golang.org/cmd/go/#hdr-Modules__module_versions__and_more) to manage dependencies on external packages. This requires a working Go environment with version 1.11 or greater installed. + +All dependencies are vendored in the `vendor/` directory. + +To add or update a new dependency, use the `go get` command: + +```bash +# Pick the latest tagged release. +go get example.com/some/module/pkg + +# Pick a specific version. +go get example.com/some/module/pkg@vX.Y.Z +``` + +Tidy up the `go.mod` and `go.sum` files and copy the new/updated dependency to the `vendor/` directory: + + +```bash +# The GO111MODULE variable can be omitted when the code isn't located in GOPATH. +GO111MODULE=on go mod tidy + +GO111MODULE=on go mod vendor +``` + +You have to commit the changes to `go.mod`, `go.sum` and the `vendor/` directory before submitting the pull request. diff --git a/Dockerfile b/Dockerfile index 9f07dc79c1d16..e1ae6a7508f3d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Golang build container -FROM golang:1.11.5 +FROM golang:1.12.4 WORKDIR $GOPATH/src/github.com/grafana/grafana @@ -53,7 +53,7 @@ ENV PATH=/usr/share/grafana/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bi WORKDIR $GF_PATHS_HOME RUN apt-get update && apt-get upgrade -y && \ - apt-get install -qq -y libfontconfig ca-certificates && \ + apt-get install -qq -y libfontconfig1 ca-certificates && \ apt-get autoremove -y && \ rm -rf /var/lib/apt/lists/* diff --git a/Gopkg.lock b/Gopkg.lock index 235a315f1e801..fe3d682b59a40 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -200,14 +200,9 @@ [[projects]] branch = "master" - digest = "1:21577aafe885f088e8086a3415f154c63c0b7ce956a6994df2ac5776bc01b7e3" + digest = "1:f43e840e8efb7b5047c1f60057702550fcdefd2b29e3a73ccea25e27d2e83fda" name = "github.com/go-macaron/session" - packages = [ - ".", - "memcache", - "postgres", - "redis", - ] + packages = ["."] pruneopts = "NUT" revision = "068d408f9c54c7fa7fcc5e2bdd3241ab21280c9e" @@ -346,12 +341,11 @@ revision = "c2b33e84" [[projects]] - digest = "1:6ddab442e52381bab82fb6c07ef3f4b565ff7ec4b8fae96d8dd4b8573a460597" + digest = "1:395b1480ae42c3fec6fff19823e66e173819f85826811387f9045c88515a7f0f" name = "github.com/jtolds/gls" packages = ["."] pruneopts = "NUT" - revision = "77f18212c9c7edc9bd6a33d383a7b545ce62f064" - version = "v4.2.1" + revision = "b4936e06046bbecbb94cae9c18127ebe510a2cb9" [[projects]] digest = "1:1da1796a71eb70f1e3e085984d044f67840bb0326816ec8276231aa87b1b9fc3" @@ -546,19 +540,19 @@ version = "v1.0.0" [[projects]] - digest = "1:1f0b284a6858827de4c27c66b49b2b25df3e16b031c2b57b7892273131e7dd2b" + digest = "1:a0509115762ee481fd95b60521b4dcc5ad226c54b741a4924f4f28c0cc6aabc8" name = "github.com/smartystreets/assertions" packages = [ ".", + "internal/go-diff/diffmatchpatch", "internal/go-render/render", "internal/oglematchers", ] pruneopts = "NUT" - revision = "7678a5452ebea5b7090a6b163f844c133f523da2" - version = "1.8.3" + revision = "f487f9de1cd36ebab28235b9373028812fb47cbd" [[projects]] - digest = "1:7efd0b2309cdd6468029fa30c808c50a820c9344df07e1a4bbdaf18f282907aa" + digest = "1:4dccd132a83155851c5e9faaa134ee3a931965c666b6b3c076e238fe9b3577a4" name = "github.com/smartystreets/goconvey" packages = [ "convey", @@ -566,8 +560,7 @@ "convey/reporting", ] pruneopts = "NUT" - revision = "9e8dc3f972df6c8fcc0375ef492c24d0bb204857" - version = "1.6.3" + revision = "68dc04aab96ae4326137d6b77330c224063a927e" [[projects]] branch = "master" @@ -885,6 +878,7 @@ "github.com/aws/aws-sdk-go/service/sts", "github.com/benbjohnson/clock", "github.com/bmizerany/assert", + "github.com/bradfitz/gomemcache/memcache", "github.com/codegangsta/cli", "github.com/davecgh/go-spew/spew", "github.com/denisenkom/go-mssqldb", @@ -893,9 +887,6 @@ "github.com/go-macaron/binding", "github.com/go-macaron/gzip", "github.com/go-macaron/session", - "github.com/go-macaron/session/memcache", - "github.com/go-macaron/session/postgres", - "github.com/go-macaron/session/redis", "github.com/go-sql-driver/mysql", "github.com/go-stack/stack", "github.com/go-xorm/core", @@ -908,6 +899,7 @@ "github.com/hashicorp/go-plugin", "github.com/hashicorp/go-version", "github.com/inconshreveable/log15", + "github.com/jtolds/gls", "github.com/lib/pq", "github.com/mattn/go-isatty", "github.com/mattn/go-sqlite3", @@ -915,7 +907,6 @@ "github.com/opentracing/opentracing-go/ext", "github.com/opentracing/opentracing-go/log", "github.com/patrickmn/go-cache", - "github.com/pkg/errors", "github.com/prometheus/client_golang/api", "github.com/prometheus/client_golang/api/prometheus/v1", "github.com/prometheus/client_golang/prometheus", @@ -923,6 +914,7 @@ "github.com/prometheus/client_model/go", "github.com/prometheus/common/expfmt", "github.com/prometheus/common/model", + "github.com/smartystreets/assertions", "github.com/smartystreets/goconvey/convey", "github.com/teris-io/shortid", "github.com/uber/jaeger-client-go/config", @@ -937,6 +929,7 @@ "gopkg.in/ldap.v3", "gopkg.in/macaron.v1", "gopkg.in/mail.v2", + "gopkg.in/redis.v2", "gopkg.in/square/go-jose.v2", "gopkg.in/yaml.v2", ] diff --git a/Gopkg.toml b/Gopkg.toml deleted file mode 100644 index d1bc0f55bae00..0000000000000 --- a/Gopkg.toml +++ /dev/null @@ -1,217 +0,0 @@ -# Gopkg.toml example -# -# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md -# for detailed Gopkg.toml documentation. -# -# required = ["github.com/user/thing/cmd/thing"] -# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] -# -# [[constraint]] -# name = "github.com/user/project" -# version = "1.0.0" -# -# [[constraint]] -# name = "github.com/user/project2" -# branch = "dev" -# source = "github.com/myfork/project2" -# -# [[override]] -# name = "github.com/x/y" -# version = "2.4.0" - -ignored = [ - "github.com/grafana/grafana/data/*", - "github.com/grafana/grafana/public/*", - "github.com/grafana/grafana/node_modules/*" - ] - -[[constraint]] - name = "github.com/BurntSushi/toml" - version = "0.3.0" - -[[constraint]] - branch = "master" - name = "github.com/Unknwon/com" - #version = "1.0.0" - -[[constraint]] - name = "github.com/aws/aws-sdk-go" - version = "1.13.56" - -[[constraint]] - branch = "master" - name = "github.com/benbjohnson/clock" - -[[constraint]] - branch = "master" - name = "github.com/bmizerany/assert" - -[[constraint]] - name = "github.com/codegangsta/cli" - version = "1.20.0" - -[[constraint]] - name = "github.com/davecgh/go-spew" - version = "1.1.0" - -[[constraint]] - name = "github.com/fatih/color" - version = "1.5.0" - -[[constraint]] - branch = "master" - name = "github.com/go-macaron/binding" - -[[constraint]] - branch = "master" - name = "github.com/go-macaron/gzip" - -[[constraint]] - branch = "master" - name = "github.com/go-macaron/session" - -[[constraint]] - name = "github.com/go-sql-driver/mysql" - revision = "2cc627ac8defc45d65066ae98f898166f580f9a4" - #version = "1.3.0" //keeping this since we would rather depend on version then commit - -[[constraint]] - name = "github.com/go-stack/stack" - version = "1.7.0" - -[[constraint]] - name = "github.com/go-xorm/core" - version = "=0.6.2" - -[[override]] - name = "github.com/go-xorm/builder" - version = "=0.3.4" - -[[constraint]] - name = "github.com/go-xorm/xorm" - version = "=0.7.1" - -[[constraint]] - name = "github.com/gorilla/websocket" - version = "1.2.0" - -[[constraint]] - name = "github.com/gosimple/slug" - version = "1.1.1" - -[[constraint]] - branch = "master" - name = "github.com/grafana/grafana-plugin-model" - -[[constraint]] - branch = "master" - name = "github.com/hashicorp/go-hclog" - -[[constraint]] - name = "github.com/hashicorp/go-plugin" - revision = "e8d22c780116115ae5624720c9af0c97afe4f551" - -[[constraint]] - branch = "master" - name = "github.com/hashicorp/go-version" - -[[constraint]] - name = "github.com/inconshreveable/log15" - version = "2.13.0" - -[[constraint]] - branch = "master" - name = "github.com/lib/pq" - -[[constraint]] - name = "github.com/mattn/go-isatty" - version = "0.0.3" - -[[constraint]] - name = "github.com/mattn/go-sqlite3" - version = "1.7.0" - -[[constraint]] - name = "github.com/opentracing/opentracing-go" - version = "1.0.2" - -[[constraint]] - name = "github.com/patrickmn/go-cache" - version = "2.1.0" - -[[constraint]] - name = "github.com/prometheus/client_golang" - version = "0.9.0-pre1" - -[[constraint]] - branch = "master" - name = "github.com/prometheus/client_model" - -[[constraint]] - branch = "master" - name = "github.com/prometheus/common" - -[[constraint]] - name = "github.com/smartystreets/goconvey" - version = "1.6.3" - -[[constraint]] - name = "github.com/uber/jaeger-client-go" - version = "2.11.2" - -[[constraint]] - name = "github.com/yudai/gojsondiff" - version = "1.0.0" - -[[constraint]] - branch = "master" - name = "golang.org/x/net" - -[[constraint]] - branch = "master" - name = "golang.org/x/oauth2" - -[[constraint]] - branch = "master" - name = "golang.org/x/sync" - -[[constraint]] - name = "gopkg.in/mail.v2" - branch = "v2" - -[[constraint]] - name = "gopkg.in/ini.v1" - version = "1.32.0" - -[[constraint]] - name = "gopkg.in/macaron.v1" - version = "1.2.4" - -[[constraint]] - branch = "v2" - name = "gopkg.in/yaml.v2" - -[prune] - non-go = true - go-tests = true - unused-packages = true - -[[constraint]] - branch = "master" - name = "github.com/teris-io/shortid" - -[[constraint]] - name = "github.com/denisenkom/go-mssqldb" - revision = "270bc3860bb94dd3a3ffd047377d746c5e276726" - -[[constraint]] - name = "github.com/VividCortex/mysqlerr" - branch = "master" - -[[constraint]] - name = "gopkg.in/square/go-jose.v2" - version = "2.1.9" - -[[constraint]] - name = "gopkg.in/ldap.v3" - version = "3.0.0" diff --git a/Makefile b/Makefile index 365a925d61c39..2e06a95696515 100644 --- a/Makefile +++ b/Makefile @@ -13,15 +13,15 @@ deps: deps-js build-go: @echo "build go files" - go run build.go build + GO111MODULE=on go run build.go build build-server: @echo "build server" - go run build.go build-server + GO111MODULE=on go run build.go build-server build-cli: @echo "build in CI environment" - go run build.go build-cli + GO111MODULE=on go run build.go build-cli build-js: @echo "build frontend" @@ -32,7 +32,7 @@ build: build-go build-js build-docker-dev: @echo "build development container" @echo "\033[92mInfo:\033[0m the frontend code is expected to be built already." - go run build.go -goos linux -pkg-arch amd64 ${OPT} build pkg-archive latest + GO111MODULE=on go run build.go -goos linux -pkg-arch amd64 ${OPT} build pkg-archive latest cp dist/grafana-latest.linux-x64.tar.gz packaging/docker cd packaging/docker && docker build --tag grafana/grafana:dev . @@ -46,7 +46,7 @@ lint-go: test-go: @echo "test backend" - go test -v ./pkg/... + GO111MODULE=on go test -v ./pkg/... test-js: @echo "test frontend" diff --git a/ROADMAP.md b/ROADMAP.md index b5e62578475ee..03c4fc5fb7c89 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,32 +1,4 @@ -# Roadmap (2018-08-07) - This roadmap is a tentative plan for the core development team. Things change constantly as PRs come in and priorities change. But it will give you an idea of our current vision and plan. -### Short term (1-2 months) - - PRs & Bugs - - React Panel Support - - React Query Editor Support - - Metrics & Log Explore UI - - Grafana UI library shared between grafana & plugins - - Seperate visualization from panels - - More reuse between Explore & dashboard - - Explore logging support for more data sources - -### Mid term (2-4 months) - - Drilldown links - - Dashboards as code workflows - - React migration - - New panels - -### Long term (4 - 8 months) - - Alerting improvements (silence, per series tracking, etc) - -### In a distant future far far away - - Meta queries - - Integrated light weight TSDB - - Web socket & live data sources - -### Outside contributions -We know this is being worked on right now by contributors (and we hope to merge it when it's ready). - +Go to the Issues tab on GitHub. There you will find, at the top, 3 pinned roadmap issues. diff --git a/build.go b/build.go index 3a9a7598b7272..41441e9d8920f 100644 --- a/build.go +++ b/build.go @@ -270,7 +270,7 @@ func createDebPackages() { defaultFileSrc: "packaging/deb/default/grafana-server", systemdFileSrc: "packaging/deb/systemd/grafana-server.service", - depends: []string{"adduser", "libfontconfig"}, + depends: []string{"adduser", "libfontconfig1"}, }) } @@ -449,7 +449,6 @@ func gruntBuildArg(task string) []string { } func setup() { - runPrint("go", "get", "-v", "github.com/golang/dep") runPrint("go", "install", "-v", "./pkg/cmd/grafana-server") } diff --git a/conf/defaults.ini b/conf/defaults.ini index ab0cc83cccd53..c550e5bfdee33 100644 --- a/conf/defaults.ini +++ b/conf/defaults.ini @@ -117,37 +117,6 @@ type = database # memcache: 127.0.0.1:11211 connstr = -#################################### Session ############################# -[session] -# Either "memory", "file", "redis", "mysql", "postgres", "memcache", default is "file" -provider = file - -# Provider config options -# memory: not have any config yet -# file: session dir path, is relative to grafana data_path -# redis: config like redis server e.g. `addr=127.0.0.1:6379,pool_size=100,db=grafana` -# postgres: user=a password=b host=localhost port=5432 dbname=c sslmode=disable -# mysql: go-sql-driver/mysql dsn config string, examples: -# `user:password@tcp(127.0.0.1:3306)/database_name` -# `user:password@unix(/var/run/mysqld/mysqld.sock)/database_name` -# memcache: 127.0.0.1:11211 - - -provider_config = sessions - -# Session cookie name -cookie_name = grafana_sess - -# If you use session in https only, default is false -cookie_secure = false - -# Session life time, default is 86400 (means 86400 seconds or 24 hours) -session_life_time = 86400 -gc_interval_time = 86400 - -# Connection Max Lifetime default is 14400 (means 14400 seconds or 4 hours) -conn_max_lifetime = 14400 - #################################### Data proxy ########################### [dataproxy] @@ -394,6 +363,10 @@ enabled = false config_file = /etc/grafana/ldap.toml allow_sign_up = true +# LDAP backround sync (Enterprise only) +sync_cron = @hourly +active_sync_enabled = false + #################################### SMTP / Emailing ##################### [smtp] enabled = false @@ -613,8 +586,13 @@ server_url = callback_url = [panels] +# here for to support old env variables, can remove after a few months enable_alpha = false disable_sanitize_html = false +[plugins] +enable_alpha = false +app_tls_skip_verify_insecure = false + [enterprise] license_path = diff --git a/conf/provisioning/dashboards/sample.yaml b/conf/provisioning/dashboards/sample.yaml index d70bd42563486..6f3ac570ca428 100644 --- a/conf/provisioning/dashboards/sample.yaml +++ b/conf/provisioning/dashboards/sample.yaml @@ -5,6 +5,7 @@ apiVersion: 1 # - name: 'default' # orgId: 1 # folder: '' +# folderUid: '' # type: file # options: # path: /var/lib/grafana/dashboards diff --git a/conf/sample.ini b/conf/sample.ini index 8d3cc0c2a1cfc..674e07bf4785b 100644 --- a/conf/sample.ini +++ b/conf/sample.ini @@ -113,28 +113,6 @@ log_queries = # memcache: 127.0.0.1:11211 ;connstr = -#################################### Session #################################### -[session] -# Either "memory", "file", "redis", "mysql", "postgres", default is "file" -;provider = file - -# Provider config options -# memory: not have any config yet -# file: session dir path, is relative to grafana data_path -# redis: config like redis server e.g. `addr=127.0.0.1:6379,pool_size=100,db=grafana` -# mysql: go-sql-driver/mysql dsn config string, e.g. `user:password@tcp(127.0.0.1:3306)/database_name` -# postgres: user=a password=b host=localhost port=5432 dbname=c sslmode=disable -;provider_config = sessions - -# Session cookie name -;cookie_name = grafana_sess - -# If you use session in https only, default is false -;cookie_secure = false - -# Session life time, default is 86400 (means 86400 seconds or 24 hours) -;session_life_time = 86400 - #################################### Data proxy ########################### [dataproxy] @@ -540,7 +518,10 @@ log_queries = ;license_path = [panels] -;enable_alpha = false # If set to true Grafana will allow script tags in text panels. Not recommended as it enable XSS vulnerabilities. ;disable_sanitize_html = false +[plugins] +;enable_alpha = false +;app_tls_skip_verify_insecure = false + diff --git a/devenv/dashboards.yaml b/devenv/dashboards.yaml index c59d712776921..98c726408de48 100644 --- a/devenv/dashboards.yaml +++ b/devenv/dashboards.yaml @@ -3,7 +3,8 @@ apiVersion: 1 providers: - name: 'gdev dashboards' folder: 'gdev dashboards' + folderUid: '' type: file - updateIntervalSeconds: 15 + updateIntervalSeconds: 60 options: path: devenv/dev-dashboards diff --git a/devenv/datasources.yaml b/devenv/datasources.yaml index 1922743fca85f..af673d96c5a04 100644 --- a/devenv/datasources.yaml +++ b/devenv/datasources.yaml @@ -22,10 +22,11 @@ datasources: access: proxy database: site user: grafana - password: grafana url: http://localhost:8086 jsonData: timeInterval: "15s" + secureJsonData: + password: grafana - name: gdev-opentsdb type: opentsdb @@ -95,19 +96,62 @@ datasources: timeField: "@timestamp" esVersion: 60 + - name: gdev-elasticsearch-v6-filebeat + type: elasticsearch + access: proxy + database: "[filebeat-]YYYY.MM.DD" + url: http://localhost:11200 + jsonData: + interval: Daily + timeField: "@timestamp" + esVersion: 60 + + - name: gdev-elasticsearch-v7-metrics + type: elasticsearch + access: proxy + database: "[metrics-]YYYY.MM.DD" + url: http://localhost:12200 + jsonData: + timeInterval: 10s + interval: Daily + timeField: "@timestamp" + esVersion: 70 + + - name: gdev-elasticsearch-v7-logs + type: elasticsearch + access: proxy + database: "[logs-]YYYY.MM.DD" + url: http://localhost:12200 + jsonData: + interval: Daily + timeField: "@timestamp" + esVersion: 70 + + - name: gdev-elasticsearch-v7-filebeat + type: elasticsearch + access: proxy + database: "[filebeat-]YYYY.MM.DD" + url: http://localhost:12200 + jsonData: + interval: Daily + timeField: "@timestamp" + esVersion: 70 + - name: gdev-mysql type: mysql url: localhost:3306 database: grafana user: grafana - password: password + secureJsonData: + password: password - name: gdev-mysql-ds-tests type: mysql url: localhost:3306 database: grafana_ds_tests user: grafana - password: password + secureJsonData: + password: password - name: gdev-mssql type: mssql diff --git a/devenv/dev-dashboards/testdata_alerts.json b/devenv/dev-dashboards/alerting/testdata_alerts.json similarity index 92% rename from devenv/dev-dashboards/testdata_alerts.json rename to devenv/dev-dashboards/alerting/testdata_alerts.json index 9f36638c0128d..d3b70f0052b23 100644 --- a/devenv/dev-dashboards/testdata_alerts.json +++ b/devenv/dev-dashboards/alerting/testdata_alerts.json @@ -22,17 +22,11 @@ "conditions": [ { "evaluator": { - "params": [ - 60 - ], + "params": [60], "type": "gt" }, "query": { - "params": [ - "A", - "5m", - "now" - ] + "params": ["A", "5m", "now"] }, "reducer": { "params": [], @@ -149,17 +143,11 @@ "conditions": [ { "evaluator": { - "params": [ - 177 - ], + "params": [177], "type": "gt" }, "query": { - "params": [ - "A", - "5m", - "now" - ] + "params": ["A", "5m", "now"] }, "reducer": { "params": [], @@ -278,20 +266,14 @@ "conditions": [ { "evaluator": { - "params": [ - 1 - ], + "params": [1], "type": "gt" }, "operator": { "type": "and" }, "query": { - "params": [ - "A", - "15m", - "now" - ] + "params": ["A", "15m", "now"] }, "reducer": { "params": [], @@ -409,20 +391,14 @@ "conditions": [ { "evaluator": { - "params": [ - 177 - ], + "params": [177], "type": "gt" }, "operator": { "type": "and" }, "query": { - "params": [ - "A", - "15m", - "now" - ] + "params": ["A", "15m", "now"] }, "reducer": { "params": [], @@ -540,20 +516,14 @@ "conditions": [ { "evaluator": { - "params": [ - 100 - ], + "params": [100], "type": "gt" }, "operator": { "type": "and" }, "query": { - "params": [ - "A", - "5m", - "now" - ] + "params": ["A", "5m", "now"] }, "reducer": { "params": [], @@ -670,9 +640,7 @@ "revision": 2, "schemaVersion": 16, "style": "dark", - "tags": [ - "grafana-test" - ], + "tags": ["gdev", "alerting"], "templating": { "list": [] }, @@ -681,32 +649,11 @@ "to": "now" }, "timepicker": { - "refresh_intervals": [ - "5s", - "10s", - "30s", - "1m", - "5m", - "15m", - "30m", - "1h", - "2h", - "1d" - ], - "time_options": [ - "5m", - "15m", - "1h", - "6h", - "12h", - "24h", - "2d", - "7d", - "30d" - ] + "refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"], + "time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"] }, "timezone": "browser", "title": "Alerting with TestData", "uid": "7MeksYbmk", "version": 7 -} \ No newline at end of file +} diff --git a/devenv/dev-dashboards/datasource_tests_elasticsearch_compare.json b/devenv/dev-dashboards/datasource-elasticsearch/elasticsearch_compare.json similarity index 99% rename from devenv/dev-dashboards/datasource_tests_elasticsearch_compare.json rename to devenv/dev-dashboards/datasource-elasticsearch/elasticsearch_compare.json index c631ea0a1518d..3ceb2a3970bce 100644 --- a/devenv/dev-dashboards/datasource_tests_elasticsearch_compare.json +++ b/devenv/dev-dashboards/datasource-elasticsearch/elasticsearch_compare.json @@ -17,14 +17,13 @@ "editable": true, "gnetId": null, "graphTooltip": 0, - "iteration": 1545263815779, + "iteration": 1555595032099, "links": [ { + "asDropdown": true, "icon": "external link", - "tags": [ - "gdev", - "elasticsearch" - ], + "tags": ["gdev", "elasticsearch", "datasource-test"], + "title": "Dashboards", "type": "dashboards" } ], @@ -1824,13 +1823,7 @@ "id": "1", "meta": {}, "settings": { - "percents": [ - 25, - 50, - 75, - 95, - 99 - ] + "percents": [25, 50, 75, 95, 99] }, "type": "percentiles" } @@ -1941,13 +1934,7 @@ "meta": {}, "settings": { "missing": null, - "percents": [ - 25, - 50, - 75, - 95, - 99 - ] + "percents": [25, 50, 75, 95, 99] }, "type": "percentiles" } @@ -5856,12 +5843,9 @@ } ], "refresh": false, - "schemaVersion": 16, + "schemaVersion": 18, "style": "dark", - "tags": [ - "gdev", - "elasticsearch" - ], + "tags": ["elasticsearch", "gdev", "datasource-test"], "templating": { "list": [ { @@ -5870,7 +5854,9 @@ "value": "gdev-elasticsearch-v5-metrics" }, "hide": 0, + "includeAll": false, "label": "Version One", + "multi": false, "name": "version_one", "options": [], "query": "elasticsearch", @@ -5885,7 +5871,9 @@ "value": "gdev-elasticsearch-v6-metrics" }, "hide": 0, + "includeAll": false, "label": "Version Two", + "multi": false, "name": "version_two", "options": [], "query": "elasticsearch", @@ -5901,32 +5889,11 @@ "to": "now" }, "timepicker": { - "refresh_intervals": [ - "5s", - "10s", - "30s", - "1m", - "5m", - "15m", - "30m", - "1h", - "2h", - "1d" - ], - "time_options": [ - "5m", - "15m", - "1h", - "6h", - "12h", - "24h", - "2d", - "7d", - "30d" - ] + "refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"], + "time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"] }, "timezone": "", "title": "Datasource tests - Elasticsearch comparison", "uid": "fuFWehBmk", - "version": 4 -} \ No newline at end of file + "version": 2 +} diff --git a/devenv/dev-dashboards/datasource_tests_elasticsearch_v2.json b/devenv/dev-dashboards/datasource-elasticsearch/elasticsearch_v2.json similarity index 85% rename from devenv/dev-dashboards/datasource_tests_elasticsearch_v2.json rename to devenv/dev-dashboards/datasource-elasticsearch/elasticsearch_v2.json index e7c580bb75e40..011c98b0b80c6 100644 --- a/devenv/dev-dashboards/datasource_tests_elasticsearch_v2.json +++ b/devenv/dev-dashboards/datasource-elasticsearch/elasticsearch_v2.json @@ -28,14 +28,13 @@ "editable": true, "gnetId": null, "graphTooltip": 0, - "iteration": 1542303970887, + "iteration": 1554310942895, "links": [ { + "asDropdown": true, "icon": "external link", - "tags": [ - "gdev", - "elasticsearch" - ], + "tags": ["gdev", "elasticsearch", "datasource-test"], + "title": "Dashboards", "type": "dashboards" } ], @@ -232,13 +231,7 @@ "id": "1", "meta": {}, "settings": { - "percents": [ - 25, - 50, - 75, - 95, - 99 - ] + "percents": [25, 50, 75, 95, 99] }, "type": "percentiles" } @@ -458,11 +451,7 @@ }, { "colorMode": null, - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], + "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], "dateFormat": "YYYY-MM-DD HH:mm:ss", "decimals": 2, "pattern": "/.*/", @@ -586,14 +575,79 @@ "title": "ES Log query", "transform": "json", "type": "table" + }, + { + "circleMaxSize": 30, + "circleMinSize": 2, + "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], + "datasource": "gdev-elasticsearch-v2-metrics", + "decimals": 0, + "esGeoPoint": "@location", + "esMetric": "Average", + "gridPos": { + "h": 12, + "w": 24, + "x": 0, + "y": 27 + }, + "hideEmpty": false, + "hideZero": false, + "id": 8, + "initialZoom": 1, + "links": [], + "locationData": "geohash", + "mapCenter": "(0°, 0°)", + "mapCenterLatitude": 0, + "mapCenterLongitude": 0, + "maxDataPoints": 1, + "mouseWheelZoom": false, + "showLegend": true, + "stickyLabels": false, + "tableQueryOptions": { + "geohashField": "geohash", + "latitudeField": "latitude", + "longitudeField": "longitude", + "metricField": "metric", + "queryType": "geohash" + }, + "targets": [ + { + "bucketAggs": [ + { + "fake": true, + "field": "@location", + "id": "3", + "settings": { + "precision": 2 + }, + "type": "geohash_grid" + } + ], + "metrics": [ + { + "field": "@value", + "id": "1", + "meta": {}, + "settings": {}, + "type": "avg" + } + ], + "refId": "A", + "target": "", + "timeField": "@timestamp" + } + ], + "thresholds": "0,10", + "title": "World map panel", + "type": "grafana-worldmap-panel", + "unitPlural": "", + "unitSingle": "", + "valueName": "total" } ], - "schemaVersion": 16, + "schemaVersion": 18, "style": "dark", - "tags": [ - "elasticsearch", - "gdev" - ], + "tags": ["elasticsearch", "gdev", "datasource-test"], "templating": { "list": [ { @@ -616,34 +670,13 @@ "enable": true, "notice": false, "now": true, - "refresh_intervals": [ - "5s", - "10s", - "30s", - "1m", - "5m", - "15m", - "30m", - "1h", - "2h", - "1d" - ], + "refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"], "status": "Stable", - "time_options": [ - "5m", - "15m", - "1h", - "6h", - "12h", - "24h", - "2d", - "7d", - "30d" - ], + "time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"], "type": "timepicker" }, "timezone": "browser", "title": "Datasource tests - Elasticsearch v2", "uid": "RlqLq2fiz", - "version": 2 -} \ No newline at end of file + "version": 5 +} diff --git a/devenv/dev-dashboards/datasource_tests_elasticsearch_v5.json b/devenv/dev-dashboards/datasource-elasticsearch/elasticsearch_v5.json similarity index 85% rename from devenv/dev-dashboards/datasource_tests_elasticsearch_v5.json rename to devenv/dev-dashboards/datasource-elasticsearch/elasticsearch_v5.json index a117815037bd1..7434c72f4d347 100644 --- a/devenv/dev-dashboards/datasource_tests_elasticsearch_v5.json +++ b/devenv/dev-dashboards/datasource-elasticsearch/elasticsearch_v5.json @@ -28,16 +28,13 @@ "editable": true, "gnetId": null, "graphTooltip": 0, - "iteration": 1542303896062, + "iteration": 1554310560048, "links": [ { - "asDropdown": false, + "asDropdown": true, "icon": "external link", - "tags": [ - "gdev", - "elasticsearch" - ], - "title": "Dashboard", + "tags": ["gdev", "elasticsearch", "datasource-test"], + "title": "Dashboards", "type": "dashboards" } ], @@ -234,13 +231,7 @@ "id": "1", "meta": {}, "settings": { - "percents": [ - 25, - 50, - 75, - 95, - 99 - ] + "percents": [25, 50, 75, 95, 99] }, "type": "percentiles" } @@ -460,11 +451,7 @@ }, { "colorMode": null, - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], + "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], "dateFormat": "YYYY-MM-DD HH:mm:ss", "decimals": 2, "pattern": "/.*/", @@ -588,14 +575,80 @@ "title": "ES Log query", "transform": "json", "type": "table" + }, + { + "circleMaxSize": 30, + "circleMinSize": 2, + "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], + "datasource": "gdev-elasticsearch-v5-metrics", + "decimals": 0, + "esGeoPoint": "@location", + "esLocationName": "", + "esMetric": "Average", + "gridPos": { + "h": 12, + "w": 24, + "x": 0, + "y": 27 + }, + "hideEmpty": false, + "hideZero": false, + "id": 8, + "initialZoom": 1, + "links": [], + "locationData": "geohash", + "mapCenter": "(0°, 0°)", + "mapCenterLatitude": 0, + "mapCenterLongitude": 0, + "maxDataPoints": 1, + "mouseWheelZoom": false, + "showLegend": true, + "stickyLabels": false, + "tableQueryOptions": { + "geohashField": "geohash", + "latitudeField": "latitude", + "longitudeField": "longitude", + "metricField": "metric", + "queryType": "geohash" + }, + "targets": [ + { + "bucketAggs": [ + { + "fake": true, + "field": "@location", + "id": "3", + "settings": { + "precision": 2 + }, + "type": "geohash_grid" + } + ], + "metrics": [ + { + "field": "@value", + "id": "1", + "meta": {}, + "settings": {}, + "type": "avg" + } + ], + "refId": "A", + "target": "", + "timeField": "@timestamp" + } + ], + "thresholds": "0,10", + "title": "World map panel", + "type": "grafana-worldmap-panel", + "unitPlural": "", + "unitSingle": "", + "valueName": "total" } ], - "schemaVersion": 16, + "schemaVersion": 18, "style": "dark", - "tags": [ - "elasticsearch", - "gdev" - ], + "tags": ["elasticsearch", "gdev", "datasource-test"], "templating": { "list": [ { @@ -618,34 +671,13 @@ "enable": true, "notice": false, "now": true, - "refresh_intervals": [ - "5s", - "10s", - "30s", - "1m", - "5m", - "15m", - "30m", - "1h", - "2h", - "1d" - ], + "refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"], "status": "Stable", - "time_options": [ - "5m", - "15m", - "1h", - "6h", - "12h", - "24h", - "2d", - "7d", - "30d" - ], + "time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"], "type": "timepicker" }, "timezone": "browser", "title": "Datasource tests - Elasticsearch v5", "uid": "8HjT32Bmz", - "version": 27 -} \ No newline at end of file + "version": 5 +} diff --git a/devenv/dev-dashboards/datasource_tests_elasticsearch_v6.json b/devenv/dev-dashboards/datasource-elasticsearch/elasticsearch_v6.json similarity index 84% rename from devenv/dev-dashboards/datasource_tests_elasticsearch_v6.json rename to devenv/dev-dashboards/datasource-elasticsearch/elasticsearch_v6.json index ee5306d40cc98..7a143704cc093 100644 --- a/devenv/dev-dashboards/datasource_tests_elasticsearch_v6.json +++ b/devenv/dev-dashboards/datasource-elasticsearch/elasticsearch_v6.json @@ -13,7 +13,7 @@ "type": "dashboard" }, { - "datasource": "Elastic 5 Logs", + "datasource": "gdev-elasticsearch-v6-logs", "enable": false, "iconColor": "rgba(255, 96, 96, 1)", "limit": 100, @@ -28,14 +28,13 @@ "editable": true, "gnetId": null, "graphTooltip": 0, - "iteration": 1542303999511, + "iteration": 1554310839317, "links": [ { + "asDropdown": true, "icon": "external link", - "tags": [ - "gdev", - "elasticsearch" - ], + "tags": ["gdev", "elasticsearch", "datasource-test"], + "title": "Dashboards", "type": "dashboards" } ], @@ -232,13 +231,7 @@ "id": "1", "meta": {}, "settings": { - "percents": [ - 25, - 50, - 75, - 95, - 99 - ] + "percents": [25, 50, 75, 95, 99] }, "type": "percentiles" } @@ -458,11 +451,7 @@ }, { "colorMode": null, - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], + "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], "dateFormat": "YYYY-MM-DD HH:mm:ss", "decimals": 2, "pattern": "/.*/", @@ -586,14 +575,79 @@ "title": "ES Log query", "transform": "json", "type": "table" + }, + { + "circleMaxSize": 30, + "circleMinSize": 2, + "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], + "datasource": "gdev-elasticsearch-v6-metrics", + "decimals": 0, + "esGeoPoint": "@location", + "esMetric": "Average", + "gridPos": { + "h": 12, + "w": 24, + "x": 0, + "y": 27 + }, + "hideEmpty": false, + "hideZero": false, + "id": 8, + "initialZoom": "1", + "links": [], + "locationData": "geohash", + "mapCenter": "(0°, 0°)", + "mapCenterLatitude": 0, + "mapCenterLongitude": 0, + "maxDataPoints": 1, + "mouseWheelZoom": false, + "showLegend": true, + "stickyLabels": false, + "tableQueryOptions": { + "geohashField": "geohash", + "latitudeField": "latitude", + "longitudeField": "longitude", + "metricField": "metric", + "queryType": "geohash" + }, + "targets": [ + { + "bucketAggs": [ + { + "fake": true, + "field": "@location", + "id": "3", + "settings": { + "precision": 2 + }, + "type": "geohash_grid" + } + ], + "metrics": [ + { + "field": "@value", + "id": "1", + "meta": {}, + "settings": {}, + "type": "avg" + } + ], + "refId": "A", + "target": "", + "timeField": "@timestamp" + } + ], + "thresholds": "0,10", + "title": "World map panel", + "type": "grafana-worldmap-panel", + "unitPlural": "", + "unitSingle": "", + "valueName": "total" } ], - "schemaVersion": 16, + "schemaVersion": 18, "style": "dark", - "tags": [ - "elasticsearch", - "gdev" - ], + "tags": ["elasticsearch", "gdev", "datasource-test"], "templating": { "list": [ { @@ -616,34 +670,13 @@ "enable": true, "notice": false, "now": true, - "refresh_intervals": [ - "5s", - "10s", - "30s", - "1m", - "5m", - "15m", - "30m", - "1h", - "2h", - "1d" - ], + "refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"], "status": "Stable", - "time_options": [ - "5m", - "15m", - "1h", - "6h", - "12h", - "24h", - "2d", - "7d", - "30d" - ], + "time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"], "type": "timepicker" }, "timezone": "browser", "title": "Datasource tests - Elasticsearch v6", "uid": "NF8Pq2Biz", - "version": 2 -} \ No newline at end of file + "version": 5 +} diff --git a/devenv/dev-dashboards/datasource-elasticsearch/elasticsearch_v6_filebeat.json b/devenv/dev-dashboards/datasource-elasticsearch/elasticsearch_v6_filebeat.json new file mode 100644 index 0000000000000..ca50d72c13fc9 --- /dev/null +++ b/devenv/dev-dashboards/datasource-elasticsearch/elasticsearch_v6_filebeat.json @@ -0,0 +1,263 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "iteration": 1554902936982, + "links": [ + { + "asDropdown": true, + "icon": "external link", + "tags": ["gdev", "elasticsearch", "datasource-test"], + "title": "Dashboards", + "type": "dashboards" + } + ], + "panels": [ + { + "aliasColors": { + "error": "red" + }, + "bars": true, + "dashLength": 10, + "dashes": false, + "datasource": "gdev-elasticsearch-v6-filebeat", + "fill": 1, + "gridPos": { + "h": 5, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "bucketAggs": [ + { + "fake": true, + "field": "fields.level", + "id": "3", + "settings": { + "min_doc_count": 1, + "order": "desc", + "orderBy": "_term", + "size": "10" + }, + "type": "terms" + }, + { + "field": "@timestamp", + "id": "2", + "settings": { + "interval": "5m", + "min_doc_count": 1, + "trimEdges": 0 + }, + "type": "date_histogram" + } + ], + "metrics": [ + { + "field": "select field", + "id": "1", + "type": "count" + } + ], + "query": "fields.app:grafana", + "refId": "A", + "timeField": "@timestamp" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Panel Title", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "columns": [ + { + "text": "@timestamp", + "value": "@timestamp" + }, + { + "text": "fields.level", + "value": "fields.level" + }, + { + "text": "message", + "value": "message" + } + ], + "datasource": "gdev-elasticsearch-v6-filebeat", + "fontSize": "100%", + "gridPos": { + "h": 22, + "w": 24, + "x": 0, + "y": 5 + }, + "id": 2, + "links": [], + "pageSize": null, + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "@timestamp", + "type": "date" + }, + { + "alias": "Level", + "colorMode": null, + "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "fields.level", + "thresholds": [""], + "type": "string", + "unit": "short", + "valueMaps": [] + }, + { + "alias": "Message", + "colorMode": null, + "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], + "decimals": 2, + "pattern": "message", + "preserveFormat": false, + "sanitize": false, + "thresholds": [], + "type": "string", + "unit": "short" + } + ], + "targets": [ + { + "bucketAggs": [], + "metrics": [ + { + "field": "select field", + "id": "1", + "meta": {}, + "settings": { + "size": 500 + }, + "type": "raw_document" + } + ], + "query": "fields.app:grafana", + "refId": "A", + "timeField": "@timestamp" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Panel Title", + "transform": "json", + "type": "table" + } + ], + "schemaVersion": 18, + "style": "dark", + "tags": ["gdev", "elasticsearch", "datasource-test"], + "templating": { + "list": [ + { + "datasource": "gdev-elasticsearch-v6-filebeat", + "filters": [], + "hide": 0, + "label": "", + "name": "Filters", + "skipUrlSync": false, + "type": "adhoc" + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"], + "time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"] + }, + "timezone": "", + "title": "Datasource tests - Elasticsearch v6 Filebeat", + "uid": "06tPt4gZz", + "version": 8 +} diff --git a/devenv/dev-dashboards/datasource-elasticsearch/elasticsearch_v7.json b/devenv/dev-dashboards/datasource-elasticsearch/elasticsearch_v7.json new file mode 100644 index 0000000000000..b9f23c57bb861 --- /dev/null +++ b/devenv/dev-dashboards/datasource-elasticsearch/elasticsearch_v7.json @@ -0,0 +1,683 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": false, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "limit": 100, + "name": "Annotations & Alerts", + "showIn": 0, + "type": "dashboard" + }, + { + "datasource": "gdev-elasticsearch-v7-logs", + "enable": false, + "iconColor": "rgba(255, 96, 96, 1)", + "limit": 100, + "name": "test", + "query": "", + "showIn": 0, + "textField": "description", + "type": "alert" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 2342, + "iteration": 1555593977614, + "links": [ + { + "asDropdown": true, + "icon": "external link", + "tags": ["gdev", "elasticsearch", "datasource-test"], + "title": "Dashboards", + "type": "dashboards" + } + ], + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "gdev-elasticsearch-v7-metrics", + "editable": true, + "error": false, + "fill": 1, + "grid": {}, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 1, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "bucketAggs": [ + { + "field": "@hostname", + "id": "3", + "settings": { + "min_doc_count": 1, + "order": "asc", + "orderBy": "1", + "size": "5" + }, + "type": "terms" + }, + { + "field": "@timestamp", + "id": "2", + "settings": { + "interval": "auto", + "min_doc_count": 0, + "trimEdges": 0 + }, + "type": "date_histogram" + } + ], + "dsType": "elasticsearch", + "metrics": [ + { + "field": "@value", + "id": "1", + "meta": {}, + "settings": {}, + "type": "max" + } + ], + "query": "*", + "refId": "A", + "target": "", + "timeField": "@timestamp" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Top 5 servers", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "Count": "#6ED0E0" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "gdev-elasticsearch-v7-metrics", + "editable": true, + "error": false, + "fill": 1, + "grid": {}, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 7 + }, + "id": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "Count", + "lines": false, + "yaxis": 2, + "zindex": -1 + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "{{metric}}", + "bucketAggs": [ + { + "field": "@timestamp", + "id": "2", + "settings": { + "interval": "5m", + "min_doc_count": 0, + "trimEdges": 0 + }, + "type": "date_histogram" + } + ], + "dsType": "elasticsearch", + "metrics": [ + { + "field": "@value", + "id": "1", + "meta": {}, + "settings": { + "percents": [25, 50, 75, 95, 99] + }, + "type": "percentiles" + } + ], + "query": "@metric:cpu", + "refId": "A", + "target": "", + "timeField": "@timestamp" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Percentiles & Metric filter", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "Count": "#6ED0E0" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "gdev-elasticsearch-v7-metrics", + "editable": true, + "error": false, + "fill": 1, + "grid": {}, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 7 + }, + "id": 3, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "Count", + "lines": false, + "yaxis": 2, + "zindex": -1 + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "{{metric}}", + "bucketAggs": [ + { + "field": "@timestamp", + "id": "2", + "settings": { + "interval": "auto", + "min_doc_count": 0, + "trimEdges": 0 + }, + "type": "date_histogram" + } + ], + "dsType": "elasticsearch", + "metrics": [ + { + "field": "@value", + "id": "1", + "meta": { + "std_deviation_bounds_lower": true, + "std_deviation_bounds_upper": true + }, + "settings": {}, + "type": "extended_stats" + } + ], + "query": "@metric:cpu", + "refId": "A", + "target": "", + "timeField": "@timestamp" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Standard dev", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "columns": [ + { + "text": "@hostname", + "value": "@hostname" + }, + { + "text": "Average", + "value": "Average" + }, + { + "text": "Max", + "value": "Max" + }, + { + "text": "Sum", + "value": "Sum" + } + ], + "datasource": "gdev-elasticsearch-v7-metrics", + "editable": true, + "error": false, + "fontSize": "100%", + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 13 + }, + "id": 6, + "links": [], + "pageSize": null, + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "@timestamp", + "type": "date" + }, + { + "colorMode": null, + "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "targets": [ + { + "bucketAggs": [ + { + "field": "@hostname", + "id": "2", + "settings": { + "min_doc_count": 1, + "order": "asc", + "orderBy": "_term", + "size": "0" + }, + "type": "terms" + } + ], + "dsType": "elasticsearch", + "metrics": [ + { + "field": "@value", + "id": "1", + "meta": {}, + "settings": {}, + "type": "avg" + }, + { + "field": "@value", + "id": "3", + "meta": {}, + "settings": {}, + "type": "max" + }, + { + "field": "@value", + "id": "4", + "meta": {}, + "settings": {}, + "type": "sum" + } + ], + "refId": "B", + "timeField": "@timestamp" + } + ], + "title": "ES Metrics", + "transform": "table", + "type": "table" + }, + { + "columns": [ + { + "text": "@timestamp", + "value": "@timestamp" + }, + { + "text": "@message", + "value": "@message" + }, + { + "text": "tags", + "value": "tags" + }, + { + "text": "description", + "value": "description" + } + ], + "datasource": "gdev-elasticsearch-v7-logs", + "editable": true, + "error": false, + "fontSize": "100%", + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 20 + }, + "id": 5, + "links": [], + "pageSize": null, + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "@timestamp", + "type": "date" + } + ], + "targets": [ + { + "bucketAggs": [], + "dsType": "elasticsearch", + "metrics": [ + { + "field": "select field", + "id": "1", + "meta": {}, + "settings": { + "size": 500 + }, + "type": "raw_document" + } + ], + "refId": "A", + "target": "", + "timeField": "@timestamp" + } + ], + "title": "ES Log query", + "transform": "json", + "type": "table" + }, + { + "circleMaxSize": 30, + "circleMinSize": 2, + "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], + "datasource": "gdev-elasticsearch-v7-metrics", + "decimals": 0, + "esGeoPoint": "@location", + "esMetric": "Average", + "gridPos": { + "h": 12, + "w": 24, + "x": 0, + "y": 27 + }, + "hideEmpty": false, + "hideZero": false, + "id": 8, + "initialZoom": "1", + "links": [], + "locationData": "geohash", + "mapCenter": "(0°, 0°)", + "mapCenterLatitude": 0, + "mapCenterLongitude": 0, + "maxDataPoints": 1, + "mouseWheelZoom": false, + "showLegend": true, + "stickyLabels": false, + "tableQueryOptions": { + "geohashField": "geohash", + "latitudeField": "latitude", + "longitudeField": "longitude", + "metricField": "metric", + "queryType": "geohash" + }, + "targets": [ + { + "bucketAggs": [ + { + "fake": true, + "field": "@location", + "id": "3", + "settings": { + "precision": 2 + }, + "type": "geohash_grid" + } + ], + "metrics": [ + { + "field": "@value", + "id": "1", + "meta": {}, + "settings": {}, + "type": "avg" + } + ], + "refId": "A", + "target": "", + "timeField": "@timestamp" + } + ], + "thresholds": "0,10", + "title": "World map panel", + "type": "grafana-worldmap-panel", + "unitPlural": "", + "unitSingle": "", + "valueName": "total" + } + ], + "schemaVersion": 18, + "style": "dark", + "tags": ["elasticsearch", "gdev", "datasource-test"], + "templating": { + "list": [ + { + "datasource": "gdev-elasticsearch-v7-metrics", + "filters": [], + "hide": 0, + "label": "", + "name": "Filters", + "skipUrlSync": false, + "type": "adhoc" + } + ] + }, + "time": { + "from": "now-30m", + "to": "now" + }, + "timepicker": { + "collapse": false, + "enable": true, + "notice": false, + "now": true, + "refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"], + "status": "Stable", + "time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"], + "type": "timepicker" + }, + "timezone": "browser", + "title": "Datasource tests - Elasticsearch v7", + "uid": "Y-RvmuRWk", + "version": 1 +} diff --git a/devenv/dev-dashboards/datasource-elasticsearch/elasticsearch_v7_filebeat.json b/devenv/dev-dashboards/datasource-elasticsearch/elasticsearch_v7_filebeat.json new file mode 100644 index 0000000000000..5f2e26d87cae9 --- /dev/null +++ b/devenv/dev-dashboards/datasource-elasticsearch/elasticsearch_v7_filebeat.json @@ -0,0 +1,264 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 2341, + "iteration": 1555591591930, + "links": [ + { + "asDropdown": true, + "icon": "external link", + "tags": ["gdev", "elasticsearch", "datasource-test"], + "title": "Dashboards", + "type": "dashboards" + } + ], + "panels": [ + { + "aliasColors": { + "error": "red" + }, + "bars": true, + "dashLength": 10, + "dashes": false, + "datasource": "gdev-elasticsearch-v7-filebeat", + "fill": 1, + "gridPos": { + "h": 5, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "bucketAggs": [ + { + "fake": true, + "field": "fields.level", + "id": "3", + "settings": { + "min_doc_count": 1, + "order": "desc", + "orderBy": "_term", + "size": "10" + }, + "type": "terms" + }, + { + "field": "@timestamp", + "id": "2", + "settings": { + "interval": "5m", + "min_doc_count": 1, + "trimEdges": 0 + }, + "type": "date_histogram" + } + ], + "metrics": [ + { + "field": "select field", + "id": "1", + "type": "count" + } + ], + "query": "fields.app:grafana", + "refId": "A", + "timeField": "@timestamp" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Panel Title", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "columns": [ + { + "text": "@timestamp", + "value": "@timestamp" + }, + { + "text": "fields.level", + "value": "fields.level" + }, + { + "text": "message", + "value": "message" + } + ], + "datasource": "gdev-elasticsearch-v7-filebeat", + "fontSize": "100%", + "gridPos": { + "h": 22, + "w": 24, + "x": 0, + "y": 5 + }, + "id": 2, + "links": [], + "pageSize": null, + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "@timestamp", + "type": "date" + }, + { + "alias": "Level", + "colorMode": null, + "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "fields.level", + "thresholds": [""], + "type": "string", + "unit": "short", + "valueMaps": [] + }, + { + "alias": "Message", + "colorMode": null, + "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], + "decimals": 2, + "pattern": "message", + "preserveFormat": false, + "sanitize": false, + "thresholds": [], + "type": "string", + "unit": "short" + } + ], + "targets": [ + { + "bucketAggs": [], + "metrics": [ + { + "field": "select field", + "id": "1", + "meta": {}, + "settings": { + "size": 500 + }, + "type": "raw_document" + } + ], + "query": "fields.app:grafana", + "refId": "A", + "timeField": "@timestamp" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Panel Title", + "transform": "json", + "type": "table" + } + ], + "schemaVersion": 18, + "style": "dark", + "tags": ["elasticsearch", "gdev", "datasource-test"], + "templating": { + "list": [ + { + "datasource": "gdev-elasticsearch-v7-filebeat", + "filters": [], + "hide": 0, + "label": "", + "name": "Filters", + "skipUrlSync": false, + "type": "adhoc" + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"], + "time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"] + }, + "timezone": "", + "title": "Datasource tests - Elasticsearch v7 Filebeat", + "uid": "M94gguRWz", + "version": 1 +} diff --git a/devenv/dev-dashboards/datasource-influxdb/influxdb-templated.json b/devenv/dev-dashboards/datasource-influxdb/influxdb-templated.json new file mode 100644 index 0000000000000..8a73979bb935b --- /dev/null +++ b/devenv/dev-dashboards/datasource-influxdb/influxdb-templated.json @@ -0,0 +1,323 @@ +{ + "annotations": { + "enable": false, + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "iteration": 1556259111212, + "links": [], + "panels": [ + { + "aliasColors": {}, + "annotate": { + "enable": false + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "gdev-influxdb", + "editable": true, + "error": false, + "fill": 2, + "grid": {}, + "gridPos": { + "h": 9, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 1, + "interval": "$summarize", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "resolution": 100, + "scale": 1, + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "alias": "$tag_hostname", + "dsType": "influxdb", + "groupBy": [ + { + "params": ["auto"], + "type": "time" + }, + { + "params": ["hostname"], + "type": "tag" + } + ], + "measurement": "logins.count", + "policy": "default", + "query": "SELECT mean(\"value\") FROM \"logins.count\" WHERE \"hostname\" =~ /$Hostname$/ AND $timeFilter GROUP BY time($interval), \"hostname\"", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": ["value"], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "datacenter", + "operator": "=~", + "value": "/^$datacenter$/" + }, + { + "condition": "AND", + "key": "hostname", + "operator": "=~", + "value": "/^$host$/" + } + ], + "target": "" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Selected Servers", + "tooltip": { + "msResolution": false, + "query_as_alias": true, + "shared": false, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + }, + "zerofill": true + } + ], + "refresh": false, + "schemaVersion": 18, + "style": "dark", + "tags": ["gdev", "datasource-test", "influxdb"], + "templating": { + "list": [ + { + "allValue": null, + "current": { + "text": "America", + "value": "America" + }, + "datasource": "gdev-influxdb", + "definition": "", + "hide": 0, + "includeAll": false, + "label": null, + "multi": false, + "name": "datacenter", + "options": [], + "query": "SHOW TAG VALUES WITH KEY = \"datacenter\" ", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": null, + "tags": [], + "tagsQuery": null, + "type": "query", + "useTags": false + }, + { + "allFormat": "regex values", + "allValue": null, + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": "gdev-influxdb", + "definition": "", + "hide": 0, + "includeAll": true, + "label": null, + "multi": true, + "multiFormat": "regex values", + "name": "host", + "options": [], + "query": "SHOW TAG VALUES WITH KEY = \"hostname\" WHERE \"datacenter\" =~ /^$datacenter$/", + "refresh": 1, + "refresh_on_load": false, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": null, + "tags": [], + "tagsQuery": null, + "type": "query", + "useTags": false + }, + { + "allFormat": "glob", + "auto": true, + "auto_count": 5, + "auto_min": "10s", + "current": { + "text": "1m", + "value": "1m" + }, + "datasource": null, + "hide": 0, + "includeAll": false, + "label": "", + "name": "summarize", + "options": [ + { + "selected": false, + "text": "auto", + "value": "$__auto_interval_summarize" + }, + { + "selected": true, + "text": "1m", + "value": "1m" + }, + { + "selected": false, + "text": "10m", + "value": "10m" + }, + { + "selected": false, + "text": "30m", + "value": "30m" + }, + { + "selected": false, + "text": "1h", + "value": "1h" + }, + { + "selected": false, + "text": "6h", + "value": "6h" + }, + { + "selected": false, + "text": "12h", + "value": "12h" + }, + { + "selected": false, + "text": "1d", + "value": "1d" + }, + { + "selected": false, + "text": "7d", + "value": "7d" + }, + { + "selected": false, + "text": "14d", + "value": "14d" + }, + { + "selected": false, + "text": "30d", + "value": "30d" + } + ], + "query": "1m,10m,30m,1h,6h,12h,1d,7d,14d,30d", + "refresh": 2, + "refresh_on_load": false, + "skipUrlSync": false, + "type": "interval" + }, + { + "datasource": "InfluxDB", + "filters": [], + "hide": 0, + "label": null, + "name": "adhoc", + "skipUrlSync": false, + "type": "adhoc" + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "collapse": false, + "enable": true, + "notice": false, + "now": true, + "refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"], + "status": "Stable", + "time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"], + "type": "timepicker" + }, + "timezone": "browser", + "title": "Datasource tests - InfluxDB Templated", + "uid": "000000002", + "version": 2 +} diff --git a/devenv/dev-dashboards/datasource_tests_mssql_fakedata.json b/devenv/dev-dashboards/datasource-mssql/mssql_fakedata.json similarity index 96% rename from devenv/dev-dashboards/datasource_tests_mssql_fakedata.json rename to devenv/dev-dashboards/datasource-mssql/mssql_fakedata.json index e810a686134bc..5522b0d0e2d5c 100644 --- a/devenv/dev-dashboards/datasource_tests_mssql_fakedata.json +++ b/devenv/dev-dashboards/datasource-mssql/mssql_fakedata.json @@ -319,11 +319,7 @@ { "alias": "", "colorMode": null, - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], + "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], "decimals": 2, "pattern": "/.*/", "thresholds": [], @@ -346,7 +342,7 @@ ], "schemaVersion": 16, "style": "dark", - "tags": ["gdev", "mssql", "fake-data-gen"], + "tags": ["gdev", "mssql", "datasource-test"], "templating": { "list": [ { @@ -486,32 +482,11 @@ "to": "now" }, "timepicker": { - "refresh_intervals": [ - "5s", - "10s", - "30s", - "1m", - "5m", - "15m", - "30m", - "1h", - "2h", - "1d" - ], - "time_options": [ - "5m", - "15m", - "1h", - "6h", - "12h", - "24h", - "2d", - "7d", - "30d" - ] + "refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"], + "time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"] }, "timezone": "", "title": "Datasource tests - MSSQL", "uid": "86Js1xRmk", "version": 1 -} \ No newline at end of file +} diff --git a/devenv/dev-dashboards/datasource_tests_mssql_unittest.json b/devenv/dev-dashboards/datasource-mssql/mssql_unittest.json similarity index 97% rename from devenv/dev-dashboards/datasource_tests_mssql_unittest.json rename to devenv/dev-dashboards/datasource-mssql/mssql_unittest.json index b2d757ae188fc..e37fb3dce17d4 100644 --- a/devenv/dev-dashboards/datasource_tests_mssql_unittest.json +++ b/devenv/dev-dashboards/datasource-mssql/mssql_unittest.json @@ -90,11 +90,7 @@ { "alias": "", "colorMode": null, - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], + "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], "decimals": 2, "pattern": "/.*/", "thresholds": [], @@ -143,11 +139,7 @@ { "alias": "", "colorMode": null, - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], + "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], "decimals": 2, "pattern": "/.*/", "thresholds": [], @@ -197,11 +189,7 @@ { "alias": "", "colorMode": null, - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], + "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], "decimals": 2, "pattern": "/.*/", "thresholds": [], @@ -251,11 +239,7 @@ { "alias": "", "colorMode": null, - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], + "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], "decimals": 2, "pattern": "/.*/", "thresholds": [], @@ -305,11 +289,7 @@ { "alias": "", "colorMode": null, - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], + "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], "decimals": 2, "pattern": "/.*/", "thresholds": [], @@ -2124,9 +2104,7 @@ "mode": "series", "name": null, "show": true, - "values": [ - "total" - ] + "values": ["total"] }, "yaxes": [ { @@ -2212,9 +2190,7 @@ "mode": "series", "name": null, "show": true, - "values": [ - "total" - ] + "values": ["total"] }, "yaxes": [ { @@ -2299,9 +2275,7 @@ "mode": "histogram", "name": null, "show": true, - "values": [ - "current" - ] + "values": ["current"] }, "yaxes": [ { @@ -2387,9 +2361,7 @@ "mode": "histogram", "name": null, "show": true, - "values": [ - "total" - ] + "values": ["total"] }, "yaxes": [ { @@ -2474,9 +2446,7 @@ "mode": "histogram", "name": null, "show": true, - "values": [ - "current" - ] + "values": ["current"] }, "yaxes": [ { @@ -2562,9 +2532,7 @@ "mode": "histogram", "name": null, "show": true, - "values": [ - "total" - ] + "values": ["total"] }, "yaxes": [ { @@ -2649,9 +2617,7 @@ "mode": "histogram", "name": null, "show": true, - "values": [ - "current" - ] + "values": ["current"] }, "yaxes": [ { @@ -2737,9 +2703,7 @@ "mode": "histogram", "name": null, "show": true, - "values": [ - "total" - ] + "values": ["total"] }, "yaxes": [ { @@ -2768,10 +2732,7 @@ "refresh": false, "schemaVersion": 16, "style": "dark", - "tags": [ - "gdev", - "mssql" - ], + "tags": ["gdev", "mssql", "datasource-test"], "templating": { "list": [ { @@ -2871,32 +2832,11 @@ "to": "2018-03-15T13:55:01.000Z" }, "timepicker": { - "refresh_intervals": [ - "5s", - "10s", - "30s", - "1m", - "5m", - "15m", - "30m", - "1h", - "2h", - "1d" - ], - "time_options": [ - "5m", - "15m", - "1h", - "6h", - "12h", - "24h", - "2d", - "7d", - "30d" - ] + "refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"], + "time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"] }, "timezone": "", "title": "Datasource tests - MSSQL (unit test)", "uid": "GlAqcPgmz", "version": 2 -} \ No newline at end of file +} diff --git a/devenv/dev-dashboards/datasource_tests_mysql_fakedata.json b/devenv/dev-dashboards/datasource-mysql/mysql_fakedata.json similarity index 95% rename from devenv/dev-dashboards/datasource_tests_mysql_fakedata.json rename to devenv/dev-dashboards/datasource-mysql/mysql_fakedata.json index ebeb452fc4c79..31de0a8100585 100644 --- a/devenv/dev-dashboards/datasource_tests_mysql_fakedata.json +++ b/devenv/dev-dashboards/datasource-mysql/mysql_fakedata.json @@ -323,11 +323,7 @@ { "alias": "", "colorMode": null, - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], + "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], "decimals": 2, "pattern": "/.*/", "thresholds": [], @@ -352,11 +348,7 @@ ], "schemaVersion": 16, "style": "dark", - "tags": [ - "gdev", - "fake-data-gen", - "mysql" - ], + "tags": ["gdev", "mysql", "datasource-tags"], "templating": { "list": [ { @@ -502,32 +494,11 @@ "to": "now" }, "timepicker": { - "refresh_intervals": [ - "5s", - "10s", - "30s", - "1m", - "5m", - "15m", - "30m", - "1h", - "2h", - "1d" - ], - "time_options": [ - "5m", - "15m", - "1h", - "6h", - "12h", - "24h", - "2d", - "7d", - "30d" - ] + "refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"], + "time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"] }, "timezone": "", "title": "Datasource tests - MySQL", "uid": "DGsCac3kz", "version": 8 -} \ No newline at end of file +} diff --git a/devenv/dev-dashboards/datasource_tests_mysql_unittest.json b/devenv/dev-dashboards/datasource-mysql/mysql_unittest.json similarity index 97% rename from devenv/dev-dashboards/datasource_tests_mysql_unittest.json rename to devenv/dev-dashboards/datasource-mysql/mysql_unittest.json index 0255f3c0c914c..420e1c6ba30f3 100644 --- a/devenv/dev-dashboards/datasource_tests_mysql_unittest.json +++ b/devenv/dev-dashboards/datasource-mysql/mysql_unittest.json @@ -90,11 +90,7 @@ { "alias": "", "colorMode": null, - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], + "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], "decimals": 2, "pattern": "/.*/", "thresholds": [], @@ -143,11 +139,7 @@ { "alias": "", "colorMode": null, - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], + "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], "decimals": 2, "pattern": "/.*/", "thresholds": [], @@ -197,11 +189,7 @@ { "alias": "", "colorMode": null, - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], + "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], "decimals": 2, "pattern": "/.*/", "thresholds": [], @@ -251,11 +239,7 @@ { "alias": "", "colorMode": null, - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], + "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], "decimals": 2, "pattern": "/.*/", "thresholds": [], @@ -305,11 +289,7 @@ { "alias": "", "colorMode": null, - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], + "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], "decimals": 2, "pattern": "/.*/", "thresholds": [], @@ -1938,9 +1918,7 @@ "mode": "series", "name": null, "show": true, - "values": [ - "total" - ] + "values": ["total"] }, "yaxes": [ { @@ -2026,9 +2004,7 @@ "mode": "series", "name": null, "show": true, - "values": [ - "total" - ] + "values": ["total"] }, "yaxes": [ { @@ -2113,9 +2089,7 @@ "mode": "histogram", "name": null, "show": true, - "values": [ - "current" - ] + "values": ["current"] }, "yaxes": [ { @@ -2201,9 +2175,7 @@ "mode": "histogram", "name": null, "show": true, - "values": [ - "total" - ] + "values": ["total"] }, "yaxes": [ { @@ -2288,9 +2260,7 @@ "mode": "histogram", "name": null, "show": true, - "values": [ - "current" - ] + "values": ["current"] }, "yaxes": [ { @@ -2376,9 +2346,7 @@ "mode": "histogram", "name": null, "show": true, - "values": [ - "total" - ] + "values": ["total"] }, "yaxes": [ { @@ -2463,9 +2431,7 @@ "mode": "histogram", "name": null, "show": true, - "values": [ - "current" - ] + "values": ["current"] }, "yaxes": [ { @@ -2551,9 +2517,7 @@ "mode": "histogram", "name": null, "show": true, - "values": [ - "total" - ] + "values": ["total"] }, "yaxes": [ { @@ -2582,10 +2546,7 @@ "refresh": false, "schemaVersion": 16, "style": "dark", - "tags": [ - "gdev", - "mysql" - ], + "tags": ["gdev", "mysql", "datasource-test"], "templating": { "list": [ { @@ -2683,32 +2644,11 @@ "to": "2018-03-15T13:55:01.000Z" }, "timepicker": { - "refresh_intervals": [ - "5s", - "10s", - "30s", - "1m", - "5m", - "15m", - "30m", - "1h", - "2h", - "1d" - ], - "time_options": [ - "5m", - "15m", - "1h", - "6h", - "12h", - "24h", - "2d", - "7d", - "30d" - ] + "refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"], + "time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"] }, "timezone": "", "title": "Datasource tests - MySQL (unittest)", "uid": "Hmf8FDkmz", "version": 2 -} \ No newline at end of file +} diff --git a/devenv/dev-dashboards/datasource_tests_postgres_fakedata.json b/devenv/dev-dashboards/datasource-postgres/postgres_fakedata.json similarity index 99% rename from devenv/dev-dashboards/datasource_tests_postgres_fakedata.json rename to devenv/dev-dashboards/datasource-postgres/postgres_fakedata.json index 962e522c802fd..5efa5536adf82 100644 --- a/devenv/dev-dashboards/datasource_tests_postgres_fakedata.json +++ b/devenv/dev-dashboards/datasource-postgres/postgres_fakedata.json @@ -347,7 +347,7 @@ ], "schemaVersion": 16, "style": "dark", - "tags": ["gdev", "fake-data-gen", "postgres"], + "tags": ["gdev", "postgres", "datasource-test"], "templating": { "list": [ { diff --git a/devenv/dev-dashboards/datasource_tests_postgres_unittest.json b/devenv/dev-dashboards/datasource-postgres/postgres_unittest.json similarity index 97% rename from devenv/dev-dashboards/datasource_tests_postgres_unittest.json rename to devenv/dev-dashboards/datasource-postgres/postgres_unittest.json index 3c56868e9ffc0..600a3e917e395 100644 --- a/devenv/dev-dashboards/datasource_tests_postgres_unittest.json +++ b/devenv/dev-dashboards/datasource-postgres/postgres_unittest.json @@ -90,11 +90,7 @@ { "alias": "", "colorMode": null, - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], + "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], "decimals": 2, "pattern": "/.*/", "thresholds": [], @@ -143,11 +139,7 @@ { "alias": "", "colorMode": null, - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], + "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], "decimals": 2, "pattern": "/.*/", "thresholds": [], @@ -197,11 +189,7 @@ { "alias": "", "colorMode": null, - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], + "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], "decimals": 2, "pattern": "/.*/", "thresholds": [], @@ -251,11 +239,7 @@ { "alias": "", "colorMode": null, - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], + "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], "decimals": 2, "pattern": "/.*/", "thresholds": [], @@ -305,11 +289,7 @@ { "alias": "", "colorMode": null, - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], + "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], "decimals": 2, "pattern": "/.*/", "thresholds": [], @@ -1914,9 +1894,7 @@ "mode": "series", "name": null, "show": true, - "values": [ - "total" - ] + "values": ["total"] }, "yaxes": [ { @@ -2002,9 +1980,7 @@ "mode": "series", "name": null, "show": true, - "values": [ - "total" - ] + "values": ["total"] }, "yaxes": [ { @@ -2089,9 +2065,7 @@ "mode": "histogram", "name": null, "show": true, - "values": [ - "current" - ] + "values": ["current"] }, "yaxes": [ { @@ -2177,9 +2151,7 @@ "mode": "histogram", "name": null, "show": true, - "values": [ - "total" - ] + "values": ["total"] }, "yaxes": [ { @@ -2264,9 +2236,7 @@ "mode": "histogram", "name": null, "show": true, - "values": [ - "current" - ] + "values": ["current"] }, "yaxes": [ { @@ -2352,9 +2322,7 @@ "mode": "histogram", "name": null, "show": true, - "values": [ - "total" - ] + "values": ["total"] }, "yaxes": [ { @@ -2439,9 +2407,7 @@ "mode": "histogram", "name": null, "show": true, - "values": [ - "current" - ] + "values": ["current"] }, "yaxes": [ { @@ -2527,9 +2493,7 @@ "mode": "histogram", "name": null, "show": true, - "values": [ - "total" - ] + "values": ["total"] }, "yaxes": [ { @@ -2558,10 +2522,7 @@ "refresh": false, "schemaVersion": 16, "style": "dark", - "tags": [ - "gdev", - "postgres" - ], + "tags": ["gdev", "postgres", "datasource-test"], "templating": { "list": [ { @@ -2570,9 +2531,7 @@ "selected": true, "tags": [], "text": "All", - "value": [ - "$__all" - ] + "value": ["$__all"] }, "datasource": "gdev-postgres-ds-tests", "hide": 0, @@ -2663,32 +2622,11 @@ "to": "2018-03-15T13:55:01.000Z" }, "timepicker": { - "refresh_intervals": [ - "5s", - "10s", - "30s", - "1m", - "5m", - "15m", - "30m", - "1h", - "2h", - "1d" - ], - "time_options": [ - "5m", - "15m", - "1h", - "6h", - "12h", - "24h", - "2d", - "7d", - "30d" - ] + "refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"], + "time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"] }, "timezone": "", "title": "Datasource tests - Postgres (unittest)", "uid": "vHQdlVziz", "version": 1 -} \ No newline at end of file +} diff --git a/devenv/dev-dashboards/datasource-testdata/demo1.json b/devenv/dev-dashboards/datasource-testdata/demo1.json new file mode 100644 index 0000000000000..12895214b277d --- /dev/null +++ b/devenv/dev-dashboards/datasource-testdata/demo1.json @@ -0,0 +1,1103 @@ +{ + "annotations": { + "enable": false, + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 1, + "links": [], + "panels": [ + { + "aliasColors": { + "cpu": "#E24D42", + "memory": "#1f78c1", + "statsd.fakesite.counters.session_start.desktop.count": "#6ED0E0" + }, + "annotate": { + "enable": false + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "editable": true, + "fill": 3, + "grid": { + "max": null, + "min": 0 + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 0 + }, + "id": 4, + "interactive": true, + "legend": { + "avg": false, + "current": true, + "max": false, + "min": true, + "show": true, + "total": false, + "values": false + }, + "legend_counts": true, + "lines": true, + "linewidth": 2, + "nullPointMode": "connected", + "options": false, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "resolution": 100, + "scale": 1, + "seriesOverrides": [ + { + "alias": "cpu", + "fill": 0, + "lines": true, + "yaxis": 2, + "zindex": 2 + }, + { + "alias": "memory", + "pointradius": 2, + "points": true + } + ], + "spaceLength": 10, + "spyable": true, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "memory", + "hide": false, + "refId": "A", + "scenarioId": "random_walk", + "target": "alias(movingAverage(scaleToSeconds(apps.fakesite.web_server_01.counters.request_status.code_302.count, 10), 20), 'cpu')" + }, + { + "alias": "cpu", + "refId": "B", + "scenarioId": "random_walk", + "target": "alias(statsd.fakesite.counters.session_start.desktop.count, 'memory')" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "timezone": "browser", + "title": "Memory / CPU", + "tooltip": { + "msResolution": false, + "query_as_alias": true, + "shared": false, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "percent", + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + }, + "zerofill": true + }, + { + "aliasColors": { + "logins": "#5195ce", + "logins (-1 day)": "#447EBC", + "logins (-1 hour)": "#705da0" + }, + "annotate": { + "enable": false + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "editable": true, + "fill": 1, + "grid": { + "max": null, + "min": 0 + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 0 + }, + "id": 3, + "interactive": true, + "legend": { + "alignAsTable": false, + "avg": false, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "legend_counts": true, + "lines": true, + "linewidth": 1, + "nullPointMode": "connected", + "options": false, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "resolution": 100, + "scale": 1, + "seriesOverrides": [], + "spaceLength": 10, + "spyable": true, + "stack": true, + "steppedLine": false, + "targets": [ + { + "alias": "logins", + "refId": "A", + "scenarioId": "random_walk", + "target": "alias(movingAverage(scaleToSeconds(apps.fakesite.web_server_01.counters.requests.count, 1), 2), 'logins')" + }, + { + "alias": "logins (-1h)", + "refId": "B", + "scenarioId": "random_walk", + "target": "alias(movingAverage(timeShift(scaleToSeconds(apps.fakesite.web_server_01.counters.requests.count, 1), '1h'), 2), 'logins (-1 hour)')" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": "1h", + "timezone": "browser", + "title": "logins", + "tooltip": { + "msResolution": false, + "query_as_alias": true, + "shared": false, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + }, + "zerofill": true + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": true, + "colors": ["#629e51", "rgba(237, 129, 40, 0.89)", "rgba(245, 54, 54, 0.9)"], + "editable": true, + "error": false, + "format": "bytes", + "gauge": { + "maxValue": 300, + "minValue": 0, + "show": true, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 16, + "y": 0 + }, + "id": 22, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "refId": "A", + "target": "scale(apps.backend.backend_01.counters.requests.count, 0.4)" + } + ], + "thresholds": "200,270", + "title": "Memory", + "type": "singlestat", + "valueFontSize": "100%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": true, + "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], + "editable": true, + "error": false, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 20, + "y": 0 + }, + "id": 16, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "refId": "A", + "target": "apps.backend.backend_02.counters.requests.count" + } + ], + "thresholds": "100,270", + "title": "Sign ups", + "type": "singlestat", + "valueFontSize": "100%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": true, + "colors": ["#629e51", "rgba(237, 129, 40, 0.89)", "rgba(245, 54, 54, 0.9)"], + "editable": true, + "error": false, + "format": "none", + "gauge": { + "maxValue": 300, + "minValue": 0, + "show": true, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 16, + "y": 4 + }, + "id": 21, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "refId": "A", + "target": "scale(apps.backend.backend_01.counters.requests.count, 0.8)" + } + ], + "thresholds": "200,270", + "title": "Logouts", + "type": "singlestat", + "valueFontSize": "100%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": true, + "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], + "editable": true, + "error": false, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 20, + "y": 4 + }, + "id": 17, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "refId": "A", + "target": "apps.backend.backend_04.counters.requests.count" + } + ], + "thresholds": "100,270", + "title": "Sign outs", + "type": "singlestat", + "valueFontSize": "100%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "aliasColors": { + "web_server_01": "#badff4", + "web_server_02": "#5195ce", + "web_server_03": "#1f78c1", + "web_server_04": "#0a437c" + }, + "annotate": { + "enable": false + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "editable": true, + "fill": 6, + "grid": { + "max": null, + "min": 0 + }, + "gridPos": { + "h": 11, + "w": 16, + "x": 0, + "y": 7 + }, + "id": 2, + "interactive": true, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "legend_counts": true, + "lines": true, + "linewidth": 1, + "nullPointMode": "connected", + "options": false, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "resolution": 100, + "scale": 1, + "seriesOverrides": [], + "spaceLength": 10, + "spyable": true, + "stack": true, + "steppedLine": false, + "targets": [ + { + "alias": "web_server_01", + "refId": "A", + "scenarioId": "random_walk", + "target": "aliasByNode(movingAverage(scaleToSeconds(apps.fakesite.*.counters.requests.count, 1), 2), 2)" + }, + { + "alias": "web_server_02", + "refId": "B", + "scenarioId": "random_walk" + }, + { + "alias": "web_server_03", + "refId": "C", + "scenarioId": "random_walk" + }, + { + "alias": "web_server_04", + "refId": "D", + "scenarioId": "random_walk" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "timezone": "browser", + "title": "server requests", + "tooltip": { + "msResolution": false, + "query_as_alias": true, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + }, + "zerofill": true + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": true, + "colors": ["#629e51", "rgba(237, 129, 40, 0.89)", "rgba(245, 54, 54, 0.9)"], + "editable": true, + "error": false, + "format": "none", + "gauge": { + "maxValue": 300, + "minValue": 0, + "show": true, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 6, + "w": 4, + "x": 16, + "y": 7 + }, + "id": 26, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "refId": "A", + "target": "scale(apps.backend.backend_01.counters.requests.count, 0.2)" + } + ], + "thresholds": "200,270", + "title": "Google hits", + "type": "singlestat", + "valueFontSize": "100%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": true, + "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], + "editable": true, + "error": false, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 20, + "y": 7 + }, + "id": 15, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "refId": "A", + "target": "scale(apps.backend.backend_01.counters.requests.count, 0.7)" + } + ], + "thresholds": "100,270", + "title": "Logins", + "type": "singlestat", + "valueFontSize": "100%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": true, + "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], + "editable": true, + "error": false, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 20, + "y": 10 + }, + "id": 18, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "refId": "A", + "target": "scale(apps.backend.backend_03.counters.requests.count, 0.3)" + } + ], + "thresholds": "100,270", + "title": "Support calls", + "type": "singlestat", + "valueFontSize": "100%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": true, + "colors": ["#629e51", "rgba(237, 129, 40, 0.89)", "rgba(245, 54, 54, 0.9)"], + "editable": true, + "error": false, + "format": "none", + "gauge": { + "maxValue": 300, + "minValue": 0, + "show": true, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 5, + "w": 8, + "x": 16, + "y": 13 + }, + "id": 24, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "refId": "A", + "target": "scale(apps.backend.backend_01.counters.requests.count, 0.2)" + } + ], + "thresholds": "200,270", + "title": "Google hits", + "type": "singlestat", + "valueFontSize": "100%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "aliasColors": { + "upper_25": "#F9E2D2", + "upper_50": "#F2C96D", + "upper_75": "#EAB839" + }, + "annotate": { + "enable": false + }, + "bars": true, + "dashLength": 10, + "dashes": false, + "editable": true, + "fill": 1, + "grid": { + "max": null, + "min": 0 + }, + "gridPos": { + "h": 11, + "w": 24, + "x": 0, + "y": 18 + }, + "id": 5, + "interactive": true, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "legend_counts": true, + "lines": false, + "linewidth": 2, + "nullPointMode": "connected", + "options": false, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "resolution": 100, + "scale": 1, + "seriesOverrides": [], + "spaceLength": 10, + "spyable": true, + "stack": true, + "steppedLine": false, + "targets": [ + { + "refId": "A", + "scenarioId": "random_walk", + "stringInput": "", + "target": "aliasByNode(summarize(statsd.fakesite.timers.ads_timer.*, '4min', 'avg'), 4)" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "timezone": "browser", + "title": "client side full page load", + "tooltip": { + "msResolution": false, + "query_as_alias": true, + "shared": false, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + }, + "zerofill": true + } + ], + "refresh": false, + "schemaVersion": 18, + "style": "dark", + "tags": ["gdev", "demo"], + "templating": { + "list": [] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "collapse": false, + "enable": true, + "notice": false, + "now": true, + "refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"], + "status": "Stable", + "time_options": ["5m", "15m", "1h", "2h", " 6h", "12h", "24h", "2d", "7d", "30d"], + "type": "timepicker" + }, + "timezone": "browser", + "title": "TestData - Demo Dashboard", + "uid": "000000003", + "version": 2 +} diff --git a/devenv/dev-dashboards/feature-templating/testdata-repeating.json b/devenv/dev-dashboards/feature-templating/testdata-repeating.json new file mode 100644 index 0000000000000..7335ed34e0117 --- /dev/null +++ b/devenv/dev-dashboards/feature-templating/testdata-repeating.json @@ -0,0 +1,1365 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "iteration": 1554990747424, + "links": [], + "panels": [ + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": ["#299c46", "rgba(237, 129, 40, 0.89)", "#d44a3a"], + "datasource": "gdev-testdata", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 0, + "y": 0 + }, + "id": 7, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "maxPerRow": 4, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "repeat": "Servers", + "repeatDirection": "h", + "scopedVars": { + "Servers": { + "selected": false, + "text": "server1", + "value": "server1" + } + }, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "refId": "A", + "scenarioId": "random_walk", + "stringInput": "" + } + ], + "thresholds": "50,90", + "timeFrom": null, + "timeShift": null, + "title": "$Servers", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": ["#299c46", "rgba(237, 129, 40, 0.89)", "#d44a3a"], + "datasource": "gdev-testdata", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 6, + "y": 0 + }, + "id": 8, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "maxPerRow": 4, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "repeat": null, + "repeatDirection": "h", + "repeatIteration": 1554990747424, + "repeatPanelId": 7, + "scopedVars": { + "Servers": { + "selected": false, + "text": "server2", + "value": "server2" + } + }, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "refId": "A", + "scenarioId": "random_walk", + "stringInput": "" + } + ], + "thresholds": "50,90", + "timeFrom": null, + "timeShift": null, + "title": "$Servers", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": ["#299c46", "rgba(237, 129, 40, 0.89)", "#d44a3a"], + "datasource": "gdev-testdata", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 12, + "y": 0 + }, + "id": 9, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "maxPerRow": 4, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "repeat": null, + "repeatDirection": "h", + "repeatIteration": 1554990747424, + "repeatPanelId": 7, + "scopedVars": { + "Servers": { + "selected": false, + "text": "server3", + "value": "server3" + } + }, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "refId": "A", + "scenarioId": "random_walk", + "stringInput": "" + } + ], + "thresholds": "50,90", + "timeFrom": null, + "timeShift": null, + "title": "$Servers", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": ["#299c46", "rgba(237, 129, 40, 0.89)", "#d44a3a"], + "datasource": "gdev-testdata", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 18, + "y": 0 + }, + "id": 10, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "maxPerRow": 4, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "repeat": null, + "repeatDirection": "h", + "repeatIteration": 1554990747424, + "repeatPanelId": 7, + "scopedVars": { + "Servers": { + "selected": false, + "text": "server4", + "value": "server4" + } + }, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "refId": "A", + "scenarioId": "random_walk", + "stringInput": "" + } + ], + "thresholds": "50,90", + "timeFrom": null, + "timeShift": null, + "title": "$Servers", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": ["#299c46", "rgba(237, 129, 40, 0.89)", "#d44a3a"], + "datasource": "gdev-testdata", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 0, + "y": 4 + }, + "id": 11, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "maxPerRow": 4, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "repeat": null, + "repeatDirection": "h", + "repeatIteration": 1554990747424, + "repeatPanelId": 7, + "scopedVars": { + "Servers": { + "selected": false, + "text": "server5", + "value": "server5" + } + }, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "refId": "A", + "scenarioId": "random_walk", + "stringInput": "" + } + ], + "thresholds": "50,90", + "timeFrom": null, + "timeShift": null, + "title": "$Servers", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": ["#299c46", "rgba(237, 129, 40, 0.89)", "#d44a3a"], + "datasource": "gdev-testdata", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 6, + "y": 4 + }, + "id": 12, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "maxPerRow": 4, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "repeat": null, + "repeatDirection": "h", + "repeatIteration": 1554990747424, + "repeatPanelId": 7, + "scopedVars": { + "Servers": { + "selected": false, + "text": "server6", + "value": "server6" + } + }, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "refId": "A", + "scenarioId": "random_walk", + "stringInput": "" + } + ], + "thresholds": "50,90", + "timeFrom": null, + "timeShift": null, + "title": "$Servers", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": ["#299c46", "rgba(237, 129, 40, 0.89)", "#d44a3a"], + "datasource": "gdev-testdata", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 12, + "y": 4 + }, + "id": 13, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "maxPerRow": 4, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "repeat": null, + "repeatDirection": "h", + "repeatIteration": 1554990747424, + "repeatPanelId": 7, + "scopedVars": { + "Servers": { + "selected": false, + "text": "server7", + "value": "server7" + } + }, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "refId": "A", + "scenarioId": "random_walk", + "stringInput": "" + } + ], + "thresholds": "50,90", + "timeFrom": null, + "timeShift": null, + "title": "$Servers", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": ["#299c46", "rgba(237, 129, 40, 0.89)", "#d44a3a"], + "datasource": "gdev-testdata", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 18, + "y": 4 + }, + "id": 14, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "maxPerRow": 4, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "repeat": null, + "repeatDirection": "h", + "repeatIteration": 1554990747424, + "repeatPanelId": 7, + "scopedVars": { + "Servers": { + "selected": false, + "text": "server8", + "value": "server8" + } + }, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "refId": "A", + "scenarioId": "random_walk", + "stringInput": "" + } + ], + "thresholds": "50,90", + "timeFrom": null, + "timeShift": null, + "title": "$Servers", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "datasource": "gdev-testdata", + "gridPos": { + "h": 5, + "w": 6, + "x": 0, + "y": 8 + }, + "id": 2, + "links": [], + "maxPerRow": 4, + "nullPointMode": "null", + "options": { + "baseColor": "#299c46", + "maxValue": 100, + "minValue": 0, + "orientation": "auto", + "showThresholdLabels": false, + "showThresholdMarkers": true, + "thresholds": [ + { + "color": "#7EB26D", + "index": 0, + "value": null + }, + { + "color": "#ef843c", + "index": 1, + "value": 75 + }, + { + "color": "#e24d42", + "index": 2, + "value": 90 + } + ], + "valueMappings": [], + "valueOptions": { + "decimals": "2", + "prefix": "", + "stat": "mean", + "suffix": "", + "unit": "ms" + } + }, + "pluginVersion": "6.1.0-pre", + "repeat": "Servers", + "repeatDirection": "h", + "scopedVars": { + "Servers": { + "selected": false, + "text": "server1", + "value": "server1" + } + }, + "targets": [ + { + "refId": "A", + "scenarioId": "csv_metric_values", + "stringInput": "1,20,90,30,5,0" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "$Servers", + "type": "gauge" + }, + { + "datasource": "gdev-testdata", + "gridPos": { + "h": 5, + "w": 6, + "x": 6, + "y": 8 + }, + "id": 15, + "links": [], + "maxPerRow": 4, + "nullPointMode": "null", + "options": { + "baseColor": "#299c46", + "maxValue": 100, + "minValue": 0, + "orientation": "auto", + "showThresholdLabels": false, + "showThresholdMarkers": true, + "thresholds": [ + { + "color": "#7EB26D", + "index": 0, + "value": null + }, + { + "color": "#ef843c", + "index": 1, + "value": 75 + }, + { + "color": "#e24d42", + "index": 2, + "value": 90 + } + ], + "valueMappings": [], + "valueOptions": { + "decimals": "2", + "prefix": "", + "stat": "mean", + "suffix": "", + "unit": "ms" + } + }, + "pluginVersion": "6.1.0-pre", + "repeat": null, + "repeatDirection": "h", + "repeatIteration": 1554990747424, + "repeatPanelId": 2, + "scopedVars": { + "Servers": { + "selected": false, + "text": "server2", + "value": "server2" + } + }, + "targets": [ + { + "refId": "A", + "scenarioId": "csv_metric_values", + "stringInput": "1,20,90,30,5,0" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "$Servers", + "type": "gauge" + }, + { + "datasource": "gdev-testdata", + "gridPos": { + "h": 5, + "w": 6, + "x": 12, + "y": 8 + }, + "id": 16, + "links": [], + "maxPerRow": 4, + "nullPointMode": "null", + "options": { + "baseColor": "#299c46", + "maxValue": 100, + "minValue": 0, + "orientation": "auto", + "showThresholdLabels": false, + "showThresholdMarkers": true, + "thresholds": [ + { + "color": "#7EB26D", + "index": 0, + "value": null + }, + { + "color": "#ef843c", + "index": 1, + "value": 75 + }, + { + "color": "#e24d42", + "index": 2, + "value": 90 + } + ], + "valueMappings": [], + "valueOptions": { + "decimals": "2", + "prefix": "", + "stat": "mean", + "suffix": "", + "unit": "ms" + } + }, + "pluginVersion": "6.1.0-pre", + "repeat": null, + "repeatDirection": "h", + "repeatIteration": 1554990747424, + "repeatPanelId": 2, + "scopedVars": { + "Servers": { + "selected": false, + "text": "server3", + "value": "server3" + } + }, + "targets": [ + { + "refId": "A", + "scenarioId": "csv_metric_values", + "stringInput": "1,20,90,30,5,0" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "$Servers", + "type": "gauge" + }, + { + "datasource": "gdev-testdata", + "gridPos": { + "h": 5, + "w": 6, + "x": 18, + "y": 8 + }, + "id": 17, + "links": [], + "maxPerRow": 4, + "nullPointMode": "null", + "options": { + "baseColor": "#299c46", + "maxValue": 100, + "minValue": 0, + "orientation": "auto", + "showThresholdLabels": false, + "showThresholdMarkers": true, + "thresholds": [ + { + "color": "#7EB26D", + "index": 0, + "value": null + }, + { + "color": "#ef843c", + "index": 1, + "value": 75 + }, + { + "color": "#e24d42", + "index": 2, + "value": 90 + } + ], + "valueMappings": [], + "valueOptions": { + "decimals": "2", + "prefix": "", + "stat": "mean", + "suffix": "", + "unit": "ms" + } + }, + "pluginVersion": "6.1.0-pre", + "repeat": null, + "repeatDirection": "h", + "repeatIteration": 1554990747424, + "repeatPanelId": 2, + "scopedVars": { + "Servers": { + "selected": false, + "text": "server4", + "value": "server4" + } + }, + "targets": [ + { + "refId": "A", + "scenarioId": "csv_metric_values", + "stringInput": "1,20,90,30,5,0" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "$Servers", + "type": "gauge" + }, + { + "datasource": "gdev-testdata", + "gridPos": { + "h": 5, + "w": 6, + "x": 0, + "y": 13 + }, + "id": 18, + "links": [], + "maxPerRow": 4, + "nullPointMode": "null", + "options": { + "baseColor": "#299c46", + "maxValue": 100, + "minValue": 0, + "orientation": "auto", + "showThresholdLabels": false, + "showThresholdMarkers": true, + "thresholds": [ + { + "color": "#7EB26D", + "index": 0, + "value": null + }, + { + "color": "#ef843c", + "index": 1, + "value": 75 + }, + { + "color": "#e24d42", + "index": 2, + "value": 90 + } + ], + "valueMappings": [], + "valueOptions": { + "decimals": "2", + "prefix": "", + "stat": "mean", + "suffix": "", + "unit": "ms" + } + }, + "pluginVersion": "6.1.0-pre", + "repeat": null, + "repeatDirection": "h", + "repeatIteration": 1554990747424, + "repeatPanelId": 2, + "scopedVars": { + "Servers": { + "selected": false, + "text": "server5", + "value": "server5" + } + }, + "targets": [ + { + "refId": "A", + "scenarioId": "csv_metric_values", + "stringInput": "1,20,90,30,5,0" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "$Servers", + "type": "gauge" + }, + { + "datasource": "gdev-testdata", + "gridPos": { + "h": 5, + "w": 6, + "x": 6, + "y": 13 + }, + "id": 19, + "links": [], + "maxPerRow": 4, + "nullPointMode": "null", + "options": { + "baseColor": "#299c46", + "maxValue": 100, + "minValue": 0, + "orientation": "auto", + "showThresholdLabels": false, + "showThresholdMarkers": true, + "thresholds": [ + { + "color": "#7EB26D", + "index": 0, + "value": null + }, + { + "color": "#ef843c", + "index": 1, + "value": 75 + }, + { + "color": "#e24d42", + "index": 2, + "value": 90 + } + ], + "valueMappings": [], + "valueOptions": { + "decimals": "2", + "prefix": "", + "stat": "mean", + "suffix": "", + "unit": "ms" + } + }, + "pluginVersion": "6.1.0-pre", + "repeat": null, + "repeatDirection": "h", + "repeatIteration": 1554990747424, + "repeatPanelId": 2, + "scopedVars": { + "Servers": { + "selected": false, + "text": "server6", + "value": "server6" + } + }, + "targets": [ + { + "refId": "A", + "scenarioId": "csv_metric_values", + "stringInput": "1,20,90,30,5,0" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "$Servers", + "type": "gauge" + }, + { + "datasource": "gdev-testdata", + "gridPos": { + "h": 5, + "w": 6, + "x": 12, + "y": 13 + }, + "id": 20, + "links": [], + "maxPerRow": 4, + "nullPointMode": "null", + "options": { + "baseColor": "#299c46", + "maxValue": 100, + "minValue": 0, + "orientation": "auto", + "showThresholdLabels": false, + "showThresholdMarkers": true, + "thresholds": [ + { + "color": "#7EB26D", + "index": 0, + "value": null + }, + { + "color": "#ef843c", + "index": 1, + "value": 75 + }, + { + "color": "#e24d42", + "index": 2, + "value": 90 + } + ], + "valueMappings": [], + "valueOptions": { + "decimals": "2", + "prefix": "", + "stat": "mean", + "suffix": "", + "unit": "ms" + } + }, + "pluginVersion": "6.1.0-pre", + "repeat": null, + "repeatDirection": "h", + "repeatIteration": 1554990747424, + "repeatPanelId": 2, + "scopedVars": { + "Servers": { + "selected": false, + "text": "server7", + "value": "server7" + } + }, + "targets": [ + { + "refId": "A", + "scenarioId": "csv_metric_values", + "stringInput": "1,20,90,30,5,0" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "$Servers", + "type": "gauge" + }, + { + "datasource": "gdev-testdata", + "gridPos": { + "h": 5, + "w": 6, + "x": 18, + "y": 13 + }, + "id": 21, + "links": [], + "maxPerRow": 4, + "nullPointMode": "null", + "options": { + "baseColor": "#299c46", + "maxValue": 100, + "minValue": 0, + "orientation": "auto", + "showThresholdLabels": false, + "showThresholdMarkers": true, + "thresholds": [ + { + "color": "#7EB26D", + "index": 0, + "value": null + }, + { + "color": "#ef843c", + "index": 1, + "value": 75 + }, + { + "color": "#e24d42", + "index": 2, + "value": 90 + } + ], + "valueMappings": [], + "valueOptions": { + "decimals": "2", + "prefix": "", + "stat": "mean", + "suffix": "", + "unit": "ms" + } + }, + "pluginVersion": "6.1.0-pre", + "repeat": null, + "repeatDirection": "h", + "repeatIteration": 1554990747424, + "repeatPanelId": 2, + "scopedVars": { + "Servers": { + "selected": false, + "text": "server8", + "value": "server8" + } + }, + "targets": [ + { + "refId": "A", + "scenarioId": "csv_metric_values", + "stringInput": "1,20,90,30,5,0" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "$Servers", + "type": "gauge" + } + ], + "refresh": false, + "schemaVersion": 18, + "style": "dark", + "tags": ["gdev", "templating"], + "templating": { + "list": [ + { + "allValue": null, + "current": { + "tags": [], + "text": "All", + "value": ["$__all"] + }, + "hide": 0, + "includeAll": true, + "label": null, + "multi": true, + "name": "Servers", + "options": [ + { + "selected": true, + "text": "All", + "value": "$__all" + }, + { + "selected": false, + "text": "server1", + "value": "server1" + }, + { + "selected": false, + "text": "server2", + "value": "server2" + }, + { + "selected": false, + "text": "server3", + "value": "server3" + }, + { + "selected": false, + "text": "server4", + "value": "server4" + }, + { + "selected": false, + "text": "server5", + "value": "server5" + }, + { + "selected": false, + "text": "server6", + "value": "server6" + }, + { + "selected": false, + "text": "server7", + "value": "server7" + }, + { + "selected": false, + "text": "server8", + "value": "server8" + } + ], + "query": "server1,server2,server3,server4,server5,server6,server7,server8", + "skipUrlSync": false, + "type": "custom" + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"], + "time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"] + }, + "timezone": "", + "title": "TestData Repeating Panels", + "uid": "Ei74RD9mz", + "version": 1 +} diff --git a/devenv/dev-dashboards/home.json b/devenv/dev-dashboards/home.json new file mode 100644 index 0000000000000..8608b0b82647f --- /dev/null +++ b/devenv/dev-dashboards/home.json @@ -0,0 +1,171 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "links": [], + "panels": [ + { + "folderId": null, + "gridPos": { + "h": 26, + "w": 6, + "x": 0, + "y": 0 + }, + "headings": true, + "id": 7, + "limit": 100, + "links": [], + "query": "", + "recent": true, + "search": false, + "starred": true, + "tags": [], + "timeFrom": null, + "timeShift": null, + "title": "Starred", + "type": "dashlist" + }, + { + "folderId": null, + "gridPos": { + "h": 13, + "w": 6, + "x": 6, + "y": 0 + }, + "headings": false, + "id": 8, + "limit": 1000, + "links": [], + "query": "", + "recent": false, + "search": true, + "starred": false, + "tags": ["panel-demo"], + "timeFrom": null, + "timeShift": null, + "title": "tag: panel-demo", + "type": "dashlist" + }, + { + "folderId": null, + "gridPos": { + "h": 13, + "w": 6, + "x": 12, + "y": 0 + }, + "headings": false, + "id": 2, + "limit": 1000, + "links": [], + "query": "", + "recent": false, + "search": true, + "starred": false, + "tags": ["panel-tests"], + "timeFrom": null, + "timeShift": null, + "title": "tag: panel-tests", + "type": "dashlist" + }, + { + "folderId": null, + "gridPos": { + "h": 26, + "w": 6, + "x": 18, + "y": 0 + }, + "headings": false, + "id": 5, + "limit": 1000, + "links": [], + "query": "", + "recent": false, + "search": true, + "starred": false, + "tags": ["gdev", "datasource-test"], + "timeFrom": null, + "timeShift": null, + "title": "Data source tests", + "type": "dashlist" + }, + { + "folderId": null, + "gridPos": { + "h": 13, + "w": 6, + "x": 6, + "y": 13 + }, + "headings": false, + "id": 3, + "limit": 1000, + "links": [], + "query": "", + "recent": false, + "search": true, + "starred": false, + "tags": ["gdev", "demo"], + "timeFrom": null, + "timeShift": null, + "title": "tag: dashboard-demo", + "type": "dashlist" + }, + { + "folderId": null, + "gridPos": { + "h": 13, + "w": 6, + "x": 12, + "y": 13 + }, + "headings": false, + "id": 4, + "limit": 1000, + "links": [], + "query": "", + "recent": false, + "search": true, + "starred": false, + "tags": ["templating", "gdev"], + "timeFrom": null, + "timeShift": null, + "title": "tag: templating", + "type": "dashlist" + } + ], + "schemaVersion": 18, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"], + "time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"] + }, + "timezone": "", + "title": "Grafana Dev Overview & Home", + "uid": "j6T00KRZz", + "version": 1 +} diff --git a/devenv/dev-dashboards/panel-bargauge/animated_demo.json b/devenv/dev-dashboards/panel-bargauge/animated_demo.json new file mode 100644 index 0000000000000..1a215d2767798 --- /dev/null +++ b/devenv/dev-dashboards/panel-bargauge/animated_demo.json @@ -0,0 +1,475 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "links": [], + "panels": [ + { + "gridPos": { + "h": 7, + "w": 18, + "x": 0, + "y": 0 + }, + "id": 7, + "links": [], + "options": { + "displayMode": "gradient", + "maxValue": 100, + "minValue": 0, + "orientation": "vertical", + "thresholds": [ + { + "color": "green", + "index": 0, + "value": null + }, + { + "color": "orange", + "index": 1, + "value": 40 + }, + { + "color": "red", + "index": 2, + "value": 80 + } + ], + "valueMappings": [], + "valueOptions": { + "decimals": null, + "prefix": "", + "stat": "mean", + "suffix": "", + "unit": "watt" + } + }, + "targets": [ + { + "refId": "A", + "scenarioId": "random_walk" + }, + { + "refId": "B", + "scenarioId": "random_walk" + }, + { + "refId": "C", + "scenarioId": "random_walk" + }, + { + "refId": "D", + "scenarioId": "random_walk" + }, + { + "refId": "E", + "scenarioId": "csv_metric_values", + "stringInput": "10003,33333" + }, + { + "refId": "F", + "scenarioId": "random_walk" + }, + { + "refId": "G", + "scenarioId": "random_walk" + }, + { + "refId": "H", + "scenarioId": "csv_metric_values", + "stringInput": "100,100,100" + }, + { + "refId": "I", + "scenarioId": "random_walk" + }, + { + "refId": "J", + "scenarioId": "random_walk" + }, + { + "refId": "K", + "scenarioId": "random_walk" + }, + { + "refId": "L", + "scenarioId": "random_walk" + }, + { + "refId": "M", + "scenarioId": "random_walk" + }, + { + "refId": "N", + "scenarioId": "random_walk" + }, + { + "refId": "O", + "scenarioId": "random_walk" + }, + { + "refId": "P", + "scenarioId": "random_walk" + }, + { + "refId": "Q", + "scenarioId": "random_walk" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Usage", + "type": "bargauge" + }, + { + "gridPos": { + "h": 22, + "w": 6, + "x": 18, + "y": 0 + }, + "id": 8, + "links": [], + "options": { + "displayMode": "gradient", + "maxValue": 100, + "minValue": 0, + "orientation": "horizontal", + "thresholds": [ + { + "color": "green", + "index": 0, + "value": null + }, + { + "color": "orange", + "index": 1, + "value": 55 + }, + { + "color": "red", + "index": 2, + "value": 95 + } + ], + "valueMappings": [], + "valueOptions": { + "decimals": null, + "prefix": "", + "stat": "mean", + "suffix": "", + "unit": "watt" + } + }, + "targets": [ + { + "refId": "E", + "scenarioId": "random_walk" + }, + { + "refId": "H", + "scenarioId": "csv_metric_values", + "stringInput": "100,100,100" + }, + { + "refId": "A", + "scenarioId": "random_walk" + }, + { + "refId": "B", + "scenarioId": "random_walk" + }, + { + "refId": "C", + "scenarioId": "random_walk" + }, + { + "refId": "D", + "scenarioId": "random_walk" + }, + { + "refId": "I", + "scenarioId": "random_walk" + }, + { + "refId": "J", + "scenarioId": "random_walk" + }, + { + "refId": "K", + "scenarioId": "random_walk" + }, + { + "refId": "L", + "scenarioId": "random_walk" + }, + { + "refId": "M", + "scenarioId": "random_walk" + }, + { + "refId": "N", + "scenarioId": "random_walk" + }, + { + "refId": "O", + "scenarioId": "random_walk" + }, + { + "refId": "P", + "scenarioId": "random_walk" + }, + { + "refId": "Q", + "scenarioId": "random_walk" + }, + { + "refId": "F", + "scenarioId": "random_walk" + }, + { + "refId": "G", + "scenarioId": "random_walk" + }, + { + "refId": "R", + "scenarioId": "random_walk" + }, + { + "refId": "S", + "scenarioId": "random_walk" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Usage", + "type": "bargauge" + }, + { + "gridPos": { + "h": 15, + "w": 11, + "x": 0, + "y": 7 + }, + "id": 6, + "links": [], + "options": { + "displayMode": "gradient", + "maxValue": 100, + "minValue": 0, + "orientation": "horizontal", + "thresholds": [ + { + "color": "blue", + "index": 0, + "value": null + }, + { + "color": "green", + "index": 1, + "value": 20 + }, + { + "color": "orange", + "index": 2, + "value": 40 + }, + { + "color": "red", + "index": 3, + "value": 80 + } + ], + "valueMappings": [], + "valueOptions": { + "decimals": null, + "prefix": "", + "stat": "mean", + "suffix": "", + "unit": "celsius" + } + }, + "targets": [ + { + "alias": "Inside", + "refId": "H", + "scenarioId": "csv_metric_values", + "stringInput": "100,100,100" + }, + { + "alias": "Outhouse", + "refId": "A", + "scenarioId": "random_walk" + }, + { + "alias": "Area B", + "refId": "B", + "scenarioId": "random_walk" + }, + { + "alias": "Basement", + "refId": "C", + "scenarioId": "random_walk" + }, + { + "alias": "Garage", + "refId": "D", + "scenarioId": "random_walk" + }, + { + "alias": "Attic", + "refId": "E", + "scenarioId": "random_walk" + }, + { + "refId": "F", + "scenarioId": "random_walk" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Temperature", + "type": "bargauge" + }, + { + "gridPos": { + "h": 15, + "w": 7, + "x": 11, + "y": 7 + }, + "id": 9, + "links": [], + "options": { + "displayMode": "basic", + "maxValue": 100, + "minValue": 0, + "orientation": "horizontal", + "thresholds": [ + { + "color": "blue", + "index": 0, + "value": null + }, + { + "color": "green", + "index": 1, + "value": 20 + }, + { + "color": "orange", + "index": 2, + "value": 40 + }, + { + "color": "red", + "index": 3, + "value": 80 + } + ], + "valueMappings": [], + "valueOptions": { + "decimals": null, + "prefix": "", + "stat": "mean", + "suffix": "", + "unit": "celsius" + } + }, + "targets": [ + { + "alias": "Inside", + "refId": "H", + "scenarioId": "csv_metric_values", + "stringInput": "100,100,100" + }, + { + "alias": "Outhouse", + "refId": "A", + "scenarioId": "random_walk" + }, + { + "alias": "Area B", + "refId": "B", + "scenarioId": "random_walk" + }, + { + "alias": "Basement", + "refId": "C", + "scenarioId": "random_walk" + }, + { + "alias": "Garage", + "refId": "D", + "scenarioId": "random_walk" + }, + { + "alias": "Attic", + "refId": "E", + "scenarioId": "random_walk" + }, + { + "refId": "F", + "scenarioId": "random_walk" + }, + { + "refId": "G", + "scenarioId": "random_walk" + }, + { + "refId": "I", + "scenarioId": "random_walk" + }, + { + "refId": "J", + "scenarioId": "random_walk" + }, + { + "refId": "K", + "scenarioId": "random_walk" + }, + { + "refId": "L", + "scenarioId": "random_walk" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Temperature", + "type": "bargauge" + } + ], + "refresh": false, + "schemaVersion": 18, + "style": "dark", + "tags": ["gdev", "bargauge", "panel-demo"], + "templating": { + "list": [] + }, + "time": { + "from": "now-30m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": ["1s", "5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"], + "time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"] + }, + "timezone": "", + "title": "Bar Gauge Animated Demo", + "uid": "k5IUwQeikaa", + "version": 4 +} diff --git a/devenv/dev-dashboards/panel-bargauge/gradient_demo.json b/devenv/dev-dashboards/panel-bargauge/gradient_demo.json new file mode 100644 index 0000000000000..3e5c224db4527 --- /dev/null +++ b/devenv/dev-dashboards/panel-bargauge/gradient_demo.json @@ -0,0 +1,367 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "links": [], + "panels": [ + { + "gridPos": { + "h": 7, + "w": 18, + "x": 0, + "y": 0 + }, + "id": 7, + "links": [], + "options": { + "displayMode": "gradient", + "maxValue": 100, + "minValue": 0, + "orientation": "vertical", + "thresholds": [ + { + "color": "green", + "index": 0, + "value": null + }, + { + "color": "orange", + "index": 1, + "value": 40 + }, + { + "color": "red", + "index": 2, + "value": 80 + } + ], + "valueMappings": [], + "valueOptions": { + "decimals": null, + "prefix": "", + "stat": "mean", + "suffix": "", + "unit": "watt" + } + }, + "targets": [ + { + "refId": "A", + "scenarioId": "random_walk" + }, + { + "refId": "B", + "scenarioId": "random_walk" + }, + { + "refId": "C", + "scenarioId": "random_walk" + }, + { + "refId": "D", + "scenarioId": "random_walk" + }, + { + "refId": "E", + "scenarioId": "csv_metric_values", + "stringInput": "10003,33333" + }, + { + "refId": "F", + "scenarioId": "random_walk" + }, + { + "refId": "G", + "scenarioId": "random_walk" + }, + { + "refId": "H", + "scenarioId": "csv_metric_values", + "stringInput": "100,100,100" + }, + { + "refId": "I", + "scenarioId": "random_walk" + }, + { + "refId": "J", + "scenarioId": "random_walk" + }, + { + "refId": "K", + "scenarioId": "random_walk" + }, + { + "refId": "L", + "scenarioId": "random_walk" + }, + { + "refId": "M", + "scenarioId": "random_walk" + }, + { + "refId": "N", + "scenarioId": "random_walk" + }, + { + "refId": "O", + "scenarioId": "random_walk" + }, + { + "refId": "P", + "scenarioId": "random_walk" + }, + { + "refId": "Q", + "scenarioId": "random_walk" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Usage", + "type": "bargauge" + }, + { + "gridPos": { + "h": 20, + "w": 6, + "x": 18, + "y": 0 + }, + "id": 8, + "links": [], + "options": { + "displayMode": "gradient", + "maxValue": 100, + "minValue": 0, + "orientation": "horizontal", + "thresholds": [ + { + "color": "green", + "index": 0, + "value": null + }, + { + "color": "orange", + "index": 1, + "value": 65 + }, + { + "color": "red", + "index": 2, + "value": 95 + } + ], + "valueMappings": [], + "valueOptions": { + "decimals": null, + "prefix": "", + "stat": "mean", + "suffix": "", + "unit": "watt" + } + }, + "targets": [ + { + "refId": "E", + "scenarioId": "random_walk" + }, + { + "refId": "H", + "scenarioId": "csv_metric_values", + "stringInput": "100,100,100" + }, + { + "refId": "A", + "scenarioId": "random_walk" + }, + { + "refId": "B", + "scenarioId": "random_walk" + }, + { + "refId": "C", + "scenarioId": "random_walk" + }, + { + "refId": "D", + "scenarioId": "random_walk" + }, + { + "refId": "I", + "scenarioId": "random_walk" + }, + { + "refId": "J", + "scenarioId": "random_walk" + }, + { + "refId": "K", + "scenarioId": "random_walk" + }, + { + "refId": "L", + "scenarioId": "random_walk" + }, + { + "refId": "M", + "scenarioId": "random_walk" + }, + { + "refId": "N", + "scenarioId": "random_walk" + }, + { + "refId": "O", + "scenarioId": "random_walk" + }, + { + "refId": "P", + "scenarioId": "random_walk" + }, + { + "refId": "Q", + "scenarioId": "random_walk" + }, + { + "refId": "F", + "scenarioId": "random_walk" + }, + { + "refId": "G", + "scenarioId": "random_walk" + }, + { + "refId": "R", + "scenarioId": "random_walk" + }, + { + "refId": "S", + "scenarioId": "random_walk" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Usage", + "type": "bargauge" + }, + { + "gridPos": { + "h": 13, + "w": 18, + "x": 0, + "y": 7 + }, + "id": 6, + "links": [], + "options": { + "displayMode": "gradient", + "maxValue": 100, + "minValue": 0, + "orientation": "horizontal", + "thresholds": [ + { + "color": "blue", + "index": 0, + "value": null + }, + { + "color": "green", + "index": 1, + "value": 20 + }, + { + "color": "orange", + "index": 2, + "value": 40 + }, + { + "color": "red", + "index": 3, + "value": 80 + } + ], + "valueMappings": [], + "valueOptions": { + "decimals": null, + "prefix": "", + "stat": "mean", + "suffix": "", + "unit": "celsius" + } + }, + "targets": [ + { + "alias": "Inside", + "refId": "H", + "scenarioId": "csv_metric_values", + "stringInput": "100,100,100" + }, + { + "alias": "Outhouse", + "refId": "A", + "scenarioId": "random_walk" + }, + { + "alias": "Area B", + "refId": "B", + "scenarioId": "random_walk" + }, + { + "alias": "Basement", + "refId": "C", + "scenarioId": "random_walk" + }, + { + "alias": "Garage", + "refId": "D", + "scenarioId": "random_walk" + }, + { + "alias": "Attic", + "refId": "E", + "scenarioId": "random_walk" + }, + { + "refId": "F", + "scenarioId": "random_walk" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Temperature", + "type": "bargauge" + } + ], + "schemaVersion": 18, + "style": "dark", + "tags": ["gdev", "bargauge", "panel-demo"], + "templating": { + "list": [] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"], + "time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"] + }, + "timezone": "", + "title": "Bar Gauge Gradient Demo", + "uid": "RndRQw6mz", + "version": 3 +} diff --git a/devenv/dev-dashboards/panel-bargauge/many_modes_demo.json b/devenv/dev-dashboards/panel-bargauge/many_modes_demo.json new file mode 100644 index 0000000000000..fb08950538f00 --- /dev/null +++ b/devenv/dev-dashboards/panel-bargauge/many_modes_demo.json @@ -0,0 +1,393 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "links": [], + "panels": [ + { + "gridPos": { + "h": 7, + "w": 22, + "x": 0, + "y": 0 + }, + "id": 7, + "links": [], + "options": { + "displayMode": "lcd", + "maxValue": 100, + "minValue": 0, + "orientation": "vertical", + "thresholds": [ + { + "color": "green", + "index": 0, + "value": null + }, + { + "color": "orange", + "index": 1, + "value": 40 + }, + { + "color": "red", + "index": 2, + "value": 80 + } + ], + "valueMappings": [], + "valueOptions": { + "decimals": null, + "prefix": "", + "stat": "mean", + "suffix": "", + "unit": "watt" + } + }, + "targets": [ + { + "refId": "A", + "scenarioId": "random_walk" + }, + { + "refId": "B", + "scenarioId": "random_walk" + }, + { + "refId": "C", + "scenarioId": "random_walk" + }, + { + "refId": "D", + "scenarioId": "random_walk" + }, + { + "refId": "E", + "scenarioId": "csv_metric_values", + "stringInput": "10003,33333" + }, + { + "refId": "F", + "scenarioId": "random_walk" + }, + { + "refId": "G", + "scenarioId": "random_walk" + }, + { + "refId": "H", + "scenarioId": "csv_metric_values", + "stringInput": "100,100,100" + }, + { + "refId": "I", + "scenarioId": "random_walk" + }, + { + "refId": "J", + "scenarioId": "random_walk" + }, + { + "refId": "K", + "scenarioId": "random_walk" + }, + { + "refId": "L", + "scenarioId": "random_walk" + }, + { + "refId": "M", + "scenarioId": "random_walk" + }, + { + "refId": "N", + "scenarioId": "random_walk" + }, + { + "refId": "O", + "scenarioId": "random_walk" + }, + { + "refId": "P", + "scenarioId": "random_walk" + }, + { + "refId": "Q", + "scenarioId": "random_walk" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Usage", + "type": "bargauge" + }, + { + "gridPos": { + "h": 20, + "w": 2, + "x": 22, + "y": 0 + }, + "id": 11, + "links": [], + "options": { + "displayMode": "lcd", + "maxValue": 100, + "minValue": 0, + "orientation": "vertical", + "thresholds": [ + { + "color": "green", + "index": 0, + "value": null + }, + { + "color": "red", + "index": 1, + "value": 80 + } + ], + "valueMappings": [], + "valueOptions": { + "decimals": null, + "prefix": "", + "stat": "mean", + "suffix": "", + "unit": "percent" + } + }, + "targets": [ + { + "refId": "A", + "scenarioId": "random_walk" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Progress", + "type": "bargauge" + }, + { + "gridPos": { + "h": 13, + "w": 10, + "x": 0, + "y": 7 + }, + "id": 6, + "links": [], + "options": { + "displayMode": "gradient", + "maxValue": 100, + "minValue": 0, + "orientation": "horizontal", + "thresholds": [ + { + "color": "blue", + "index": 0, + "value": null + }, + { + "color": "green", + "index": 1, + "value": 20 + }, + { + "color": "orange", + "index": 2, + "value": 40 + }, + { + "color": "red", + "index": 3, + "value": 80 + } + ], + "valueMappings": [], + "valueOptions": { + "decimals": null, + "prefix": "", + "stat": "mean", + "suffix": "", + "unit": "celsius" + } + }, + "targets": [ + { + "alias": "Inside", + "refId": "H", + "scenarioId": "csv_metric_values", + "stringInput": "100,100,100" + }, + { + "alias": "Outhouse", + "refId": "A", + "scenarioId": "random_walk" + }, + { + "alias": "Area B", + "refId": "B", + "scenarioId": "random_walk" + }, + { + "alias": "Basement", + "refId": "C", + "scenarioId": "random_walk" + }, + { + "alias": "Garage", + "refId": "D", + "scenarioId": "random_walk" + }, + { + "alias": "Attic", + "refId": "E", + "scenarioId": "random_walk" + }, + { + "refId": "F", + "scenarioId": "random_walk" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Temperature", + "type": "bargauge" + }, + { + "gridPos": { + "h": 13, + "w": 12, + "x": 10, + "y": 7 + }, + "id": 8, + "links": [], + "options": { + "displayMode": "basic", + "maxValue": 100, + "minValue": 0, + "orientation": "horizontal", + "thresholds": [ + { + "color": "green", + "index": 0, + "value": null + }, + { + "color": "purple", + "index": 1, + "value": 50 + }, + { + "color": "blue", + "index": 2, + "value": 70 + } + ], + "valueMappings": [], + "valueOptions": { + "decimals": null, + "prefix": "", + "stat": "mean", + "suffix": "", + "unit": "watt" + } + }, + "targets": [ + { + "refId": "H", + "scenarioId": "csv_metric_values", + "stringInput": "100,100,100" + }, + { + "refId": "A", + "scenarioId": "random_walk" + }, + { + "refId": "B", + "scenarioId": "random_walk" + }, + { + "refId": "C", + "scenarioId": "random_walk" + }, + { + "refId": "D", + "scenarioId": "random_walk" + }, + { + "refId": "I", + "scenarioId": "random_walk" + }, + { + "refId": "J", + "scenarioId": "random_walk" + }, + { + "refId": "K", + "scenarioId": "random_walk" + }, + { + "refId": "L", + "scenarioId": "random_walk" + }, + { + "refId": "M", + "scenarioId": "random_walk" + }, + { + "refId": "N", + "scenarioId": "random_walk" + }, + { + "refId": "O", + "scenarioId": "random_walk" + }, + { + "refId": "P", + "scenarioId": "random_walk" + }, + { + "refId": "Q", + "scenarioId": "random_walk" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Usage", + "type": "bargauge" + } + ], + "schemaVersion": 18, + "style": "dark", + "tags": ["gdev", "bargauge", "panel-demo"], + "templating": { + "list": [] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"], + "time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"] + }, + "timezone": "", + "title": "Bar Gauge All Modes Demo", + "uid": "zt2f6NgZzaa", + "version": 1 +} diff --git a/devenv/dev-dashboards/panel-bargauge/retro_led_demo.json b/devenv/dev-dashboards/panel-bargauge/retro_led_demo.json new file mode 100644 index 0000000000000..4f2e22f73304d --- /dev/null +++ b/devenv/dev-dashboards/panel-bargauge/retro_led_demo.json @@ -0,0 +1,388 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "links": [], + "panels": [ + { + "gridPos": { + "h": 8, + "w": 22, + "x": 0, + "y": 0 + }, + "id": 7, + "links": [], + "options": { + "displayMode": "lcd", + "maxValue": 100, + "minValue": 0, + "orientation": "vertical", + "thresholds": [ + { + "color": "green", + "index": 0, + "value": null + }, + { + "color": "orange", + "index": 1, + "value": 40 + }, + { + "color": "red", + "index": 2, + "value": 80 + } + ], + "valueMappings": [], + "valueOptions": { + "decimals": null, + "prefix": "", + "stat": "mean", + "suffix": "", + "unit": "watt" + } + }, + "targets": [ + { + "refId": "A", + "scenarioId": "random_walk" + }, + { + "refId": "B", + "scenarioId": "random_walk" + }, + { + "refId": "C", + "scenarioId": "random_walk" + }, + { + "refId": "D", + "scenarioId": "random_walk" + }, + { + "refId": "E", + "scenarioId": "csv_metric_values", + "stringInput": "10003,33333" + }, + { + "refId": "F", + "scenarioId": "random_walk" + }, + { + "refId": "G", + "scenarioId": "random_walk" + }, + { + "refId": "H", + "scenarioId": "csv_metric_values", + "stringInput": "100,100,100" + }, + { + "refId": "I", + "scenarioId": "random_walk" + }, + { + "refId": "J", + "scenarioId": "random_walk" + }, + { + "refId": "K", + "scenarioId": "random_walk" + }, + { + "refId": "L", + "scenarioId": "random_walk" + }, + { + "refId": "M", + "scenarioId": "random_walk" + }, + { + "refId": "N", + "scenarioId": "random_walk" + }, + { + "refId": "O", + "scenarioId": "random_walk" + }, + { + "refId": "P", + "scenarioId": "random_walk" + }, + { + "refId": "Q", + "scenarioId": "random_walk" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Usage", + "type": "bargauge" + }, + { + "gridPos": { + "h": 21, + "w": 2, + "x": 22, + "y": 0 + }, + "id": 11, + "links": [], + "options": { + "displayMode": "lcd", + "maxValue": 100, + "minValue": 0, + "orientation": "vertical", + "thresholds": [ + { + "color": "green", + "index": 0, + "value": null + }, + { + "color": "red", + "index": 1, + "value": 80 + } + ], + "valueMappings": [], + "valueOptions": { + "decimals": null, + "prefix": "", + "stat": "mean", + "suffix": "", + "unit": "percent" + } + }, + "targets": [ + { + "refId": "A", + "scenarioId": "random_walk" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Progress", + "type": "bargauge" + }, + { + "gridPos": { + "h": 13, + "w": 10, + "x": 0, + "y": 8 + }, + "id": 6, + "links": [], + "options": { + "displayMode": "lcd", + "maxValue": 100, + "minValue": 0, + "orientation": "horizontal", + "thresholds": [ + { + "color": "green", + "index": 0, + "value": null + }, + { + "color": "orange", + "index": 1, + "value": 40 + }, + { + "color": "red", + "index": 2, + "value": 80 + } + ], + "valueMappings": [], + "valueOptions": { + "decimals": null, + "prefix": "", + "stat": "mean", + "suffix": "", + "unit": "celsius" + } + }, + "targets": [ + { + "alias": "Inside", + "refId": "H", + "scenarioId": "csv_metric_values", + "stringInput": "100,100,100" + }, + { + "alias": "Outhouse", + "refId": "A", + "scenarioId": "random_walk" + }, + { + "alias": "Area B", + "refId": "B", + "scenarioId": "random_walk" + }, + { + "alias": "Basement", + "refId": "C", + "scenarioId": "random_walk" + }, + { + "alias": "Garage", + "refId": "D", + "scenarioId": "random_walk" + }, + { + "alias": "Attic", + "refId": "E", + "scenarioId": "random_walk" + }, + { + "refId": "F", + "scenarioId": "random_walk" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Temperature", + "type": "bargauge" + }, + { + "gridPos": { + "h": 13, + "w": 12, + "x": 10, + "y": 8 + }, + "id": 8, + "links": [], + "options": { + "displayMode": "lcd", + "maxValue": 100, + "minValue": 0, + "orientation": "horizontal", + "thresholds": [ + { + "color": "green", + "index": 0, + "value": null + }, + { + "color": "orange", + "index": 1, + "value": 85 + }, + { + "color": "red", + "index": 2, + "value": 95 + } + ], + "valueMappings": [], + "valueOptions": { + "decimals": null, + "prefix": "", + "stat": "mean", + "suffix": "", + "unit": "watt" + } + }, + "targets": [ + { + "refId": "H", + "scenarioId": "csv_metric_values", + "stringInput": "100,100,100" + }, + { + "refId": "A", + "scenarioId": "random_walk" + }, + { + "refId": "B", + "scenarioId": "random_walk" + }, + { + "refId": "C", + "scenarioId": "random_walk" + }, + { + "refId": "D", + "scenarioId": "random_walk" + }, + { + "refId": "I", + "scenarioId": "random_walk" + }, + { + "refId": "J", + "scenarioId": "random_walk" + }, + { + "refId": "K", + "scenarioId": "random_walk" + }, + { + "refId": "L", + "scenarioId": "random_walk" + }, + { + "refId": "M", + "scenarioId": "random_walk" + }, + { + "refId": "N", + "scenarioId": "random_walk" + }, + { + "refId": "O", + "scenarioId": "random_walk" + }, + { + "refId": "P", + "scenarioId": "random_walk" + }, + { + "refId": "Q", + "scenarioId": "random_walk" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Usage", + "type": "bargauge" + } + ], + "schemaVersion": 18, + "style": "dark", + "tags": ["gdev", "bargauge", "panel-demo"], + "templating": { + "list": [] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"], + "time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"] + }, + "timezone": "", + "title": "Bar Gauge LED Demo", + "uid": "0G3rbkqmkaa", + "version": 42 +} diff --git a/devenv/dev-dashboards/panel_tests_multiseries_gauge.json b/devenv/dev-dashboards/panel-gauge/gauge-multi-series.json similarity index 98% rename from devenv/dev-dashboards/panel_tests_multiseries_gauge.json rename to devenv/dev-dashboards/panel-gauge/gauge-multi-series.json index 91313b7d4391f..2f89d3ea9f313 100644 --- a/devenv/dev-dashboards/panel_tests_multiseries_gauge.json +++ b/devenv/dev-dashboards/panel-gauge/gauge-multi-series.json @@ -277,7 +277,7 @@ ], "schemaVersion": 17, "style": "dark", - "tags": [], + "tags": ["panel-tests", "gdev", "gauge"], "templating": { "list": [] }, @@ -290,7 +290,7 @@ "time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"] }, "timezone": "", - "title": "Multi series gauges", + "title": "Panel Tests - Gauge Multi Series", "uid": "szkuR1umk", "version": 7 } diff --git a/devenv/dev-dashboards/panel_tests_gauge.json b/devenv/dev-dashboards/panel-gauge/gauge_tests.json similarity index 98% rename from devenv/dev-dashboards/panel_tests_gauge.json rename to devenv/dev-dashboards/panel-gauge/gauge_tests.json index c6e81ececc810..abcde39bd630f 100644 --- a/devenv/dev-dashboards/panel_tests_gauge.json +++ b/devenv/dev-dashboards/panel-gauge/gauge_tests.json @@ -1160,10 +1160,7 @@ "refresh": false, "schemaVersion": 17, "style": "dark", - "tags": [ - "gdev", - "panel-tests" - ], + "tags": ["gdev", "panel-tests"], "templating": { "list": [ { @@ -1172,9 +1169,7 @@ "selected": true, "tags": [], "text": "All", - "value": [ - "$__all" - ] + "value": ["$__all"] }, "hide": 0, "includeAll": true, @@ -1219,29 +1214,8 @@ "to": "now" }, "timepicker": { - "refresh_intervals": [ - "5s", - "10s", - "30s", - "1m", - "5m", - "15m", - "30m", - "1h", - "2h", - "1d" - ], - "time_options": [ - "5m", - "15m", - "1h", - "6h", - "12h", - "24h", - "2d", - "7d", - "30d" - ] + "refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"], + "time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"] }, "timezone": "", "title": "Panel Tests - Gauge", diff --git a/devenv/dev-dashboards/panel_tests_graph_time_regions.json b/devenv/dev-dashboards/panel-graph/graph-time-regions.json similarity index 99% rename from devenv/dev-dashboards/panel_tests_graph_time_regions.json rename to devenv/dev-dashboards/panel-graph/graph-time-regions.json index 7803303c9b29c..6832b5adc27ce 100644 --- a/devenv/dev-dashboards/panel_tests_graph_time_regions.json +++ b/devenv/dev-dashboards/panel-graph/graph-time-regions.json @@ -561,7 +561,7 @@ "refresh": false, "schemaVersion": 18, "style": "dark", - "tags": ["gdev", "panel-tests"], + "tags": ["gdev", "panel-tests", "graph"], "templating": { "list": [] }, @@ -574,7 +574,7 @@ "time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"] }, "timezone": "browser", - "title": "Panel Tests - Graph (Time Regions)", + "title": "Panel Tests - Graph Time Regions", "uid": "XMjIZPmik", "version": 9 } diff --git a/devenv/dev-dashboards/panel_tests_graph.json b/devenv/dev-dashboards/panel-graph/graph_tests.json similarity index 99% rename from devenv/dev-dashboards/panel_tests_graph.json rename to devenv/dev-dashboards/panel-graph/graph_tests.json index ba677764a43bf..0cc42ce42be0e 100644 --- a/devenv/dev-dashboards/panel_tests_graph.json +++ b/devenv/dev-dashboards/panel-graph/graph_tests.json @@ -1632,10 +1632,7 @@ "revision": 8, "schemaVersion": 16, "style": "dark", - "tags": [ - "gdev", - "panel-tests" - ], + "tags": ["gdev", "panel-tests", "graph"], "templating": { "list": [] }, @@ -1644,29 +1641,8 @@ "to": "now" }, "timepicker": { - "refresh_intervals": [ - "5s", - "10s", - "30s", - "1m", - "5m", - "15m", - "30m", - "1h", - "2h", - "1d" - ], - "time_options": [ - "5m", - "15m", - "1h", - "6h", - "12h", - "24h", - "2d", - "7d", - "30d" - ] + "refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"], + "time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"] }, "timezone": "browser", "title": "Panel Tests - Graph", diff --git a/devenv/dev-dashboards/panel_tests_polystat.json b/devenv/dev-dashboards/panel-polystat/polystat_test.json similarity index 98% rename from devenv/dev-dashboards/panel_tests_polystat.json rename to devenv/dev-dashboards/panel-polystat/polystat_test.json index 51d3085c4384d..5ec741eff89e6 100644 --- a/devenv/dev-dashboards/panel_tests_polystat.json +++ b/devenv/dev-dashboards/panel-polystat/polystat_test.json @@ -28,11 +28,7 @@ "value": "triggered" } ], - "colors": [ - "#299c46", - "rgba(237, 129, 40, 0.89)", - "#d44a3a" - ], + "colors": ["#299c46", "rgba(237, 129, 40, 0.89)", "#d44a3a"], "d3DivId": "d3_svg_4", "datasource": "gdev-testdata", "decimals": 2, @@ -115,11 +111,7 @@ }, "id": 4, "links": [], - "notcolors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], + "notcolors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], "operatorName": "avg", "operatorOptions": [ { @@ -1114,11 +1106,7 @@ "value": "triggered" } ], - "colors": [ - "#299c46", - "rgba(237, 129, 40, 0.89)", - "#d44a3a" - ], + "colors": ["#299c46", "rgba(237, 129, 40, 0.89)", "#d44a3a"], "d3DivId": "d3_svg_5", "datasource": "gdev-testdata", "decimals": 2, @@ -1201,11 +1189,7 @@ }, "id": 5, "links": [], - "notcolors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], + "notcolors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], "operatorName": "avg", "operatorOptions": [ { @@ -2221,11 +2205,7 @@ "value": "triggered" } ], - "colors": [ - "#299c46", - "rgba(237, 129, 40, 0.89)", - "#d44a3a" - ], + "colors": ["#299c46", "rgba(237, 129, 40, 0.89)", "#d44a3a"], "d3DivId": "d3_svg_2", "datasource": "gdev-testdata", "decimals": 2, @@ -2308,11 +2288,7 @@ }, "id": 2, "links": [], - "notcolors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], + "notcolors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], "operatorName": "avg", "operatorOptions": [ { @@ -3300,10 +3276,7 @@ ], "schemaVersion": 16, "style": "dark", - "tags": [ - "panel-test", - "gdev" - ], + "tags": ["panel-test", "gdev", "polystat"], "templating": { "list": [] }, @@ -3312,29 +3285,8 @@ "to": "now" }, "timepicker": { - "refresh_intervals": [ - "5s", - "10s", - "30s", - "1m", - "5m", - "15m", - "30m", - "1h", - "2h", - "1d" - ], - "time_options": [ - "5m", - "15m", - "1h", - "6h", - "12h", - "24h", - "2d", - "7d", - "30d" - ] + "refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"], + "time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"] }, "timezone": "", "title": "Panel Tests - Polystat", diff --git a/devenv/dev-dashboards/panel_tests_singlestat.json b/devenv/dev-dashboards/panel-singlestat/singlestat_test.json similarity index 92% rename from devenv/dev-dashboards/panel_tests_singlestat.json rename to devenv/dev-dashboards/panel-singlestat/singlestat_test.json index 2d69f27bcb6bb..773c36b130374 100644 --- a/devenv/dev-dashboards/panel_tests_singlestat.json +++ b/devenv/dev-dashboards/panel-singlestat/singlestat_test.json @@ -21,11 +21,7 @@ "cacheTimeout": null, "colorBackground": false, "colorValue": true, - "colors": [ - "#299c46", - "rgba(237, 129, 40, 0.89)", - "#d44a3a" - ], + "colors": ["#299c46", "rgba(237, 129, 40, 0.89)", "#d44a3a"], "datasource": "gdev-testdata", "decimals": null, "description": "", @@ -106,11 +102,7 @@ "colorBackground": false, "colorPrefix": false, "colorValue": true, - "colors": [ - "#d44a3a", - "rgba(237, 129, 40, 0.89)", - "#299c46" - ], + "colors": ["#d44a3a", "rgba(237, 129, 40, 0.89)", "#299c46"], "datasource": "gdev-testdata", "decimals": null, "description": "", @@ -191,11 +183,7 @@ "colorBackground": true, "colorPrefix": false, "colorValue": false, - "colors": [ - "#d44a3a", - "rgba(237, 129, 40, 0.89)", - "#299c46" - ], + "colors": ["#d44a3a", "rgba(237, 129, 40, 0.89)", "#299c46"], "datasource": "gdev-testdata", "decimals": null, "description": "", @@ -276,11 +264,7 @@ "colorBackground": false, "colorPrefix": false, "colorValue": true, - "colors": [ - "#299c46", - "rgba(237, 129, 40, 0.89)", - "#d44a3a" - ], + "colors": ["#299c46", "rgba(237, 129, 40, 0.89)", "#d44a3a"], "datasource": "gdev-testdata", "decimals": null, "description": "", @@ -361,11 +345,7 @@ "colorBackground": false, "colorPrefix": false, "colorValue": true, - "colors": [ - "#299c46", - "rgba(237, 129, 40, 0.89)", - "#d44a3a" - ], + "colors": ["#299c46", "rgba(237, 129, 40, 0.89)", "#d44a3a"], "datasource": "gdev-testdata", "decimals": null, "description": "", @@ -446,11 +426,7 @@ "colorBackground": false, "colorPrefix": false, "colorValue": true, - "colors": [ - "#299c46", - "rgba(237, 129, 40, 0.89)", - "#d44a3a" - ], + "colors": ["#299c46", "rgba(237, 129, 40, 0.89)", "#d44a3a"], "datasource": "gdev-testdata", "decimals": null, "description": "", @@ -531,10 +507,7 @@ "revision": 8, "schemaVersion": 16, "style": "dark", - "tags": [ - "gdev", - "panel-tests" - ], + "tags": ["gdev", "panel-tests"], "templating": { "list": [] }, @@ -543,29 +516,8 @@ "to": "now" }, "timepicker": { - "refresh_intervals": [ - "5s", - "10s", - "30s", - "1m", - "5m", - "15m", - "30m", - "1h", - "2h", - "1d" - ], - "time_options": [ - "5m", - "15m", - "1h", - "6h", - "12h", - "24h", - "2d", - "7d", - "30d" - ] + "refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"], + "time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"] }, "timezone": "browser", "title": "Panel Tests - Singlestat", diff --git a/devenv/dev-dashboards/panel_tests_table.json b/devenv/dev-dashboards/panel-table/table_tests.json similarity index 75% rename from devenv/dev-dashboards/panel_tests_table.json rename to devenv/dev-dashboards/panel-table/table_tests.json index ff0288c340ae5..c301dd23b6a59 100644 --- a/devenv/dev-dashboards/panel_tests_table.json +++ b/devenv/dev-dashboards/panel-table/table_tests.json @@ -46,49 +46,31 @@ { "alias": "", "colorMode": "cell", - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], + "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], "dateFormat": "YYYY-MM-DD HH:mm:ss", "decimals": 2, "mappingType": 1, "pattern": "ColorCell", - "thresholds": [ - "5", - "10" - ], + "thresholds": ["5", "10"], "type": "number", "unit": "currencyUSD" }, { "alias": "", "colorMode": "value", - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], + "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], "dateFormat": "YYYY-MM-DD HH:mm:ss", "decimals": 2, "mappingType": 1, "pattern": "ColorValue", - "thresholds": [ - "5", - "10" - ], + "thresholds": ["5", "10"], "type": "number", "unit": "Bps" }, { "alias": "", "colorMode": null, - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], + "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], "decimals": 2, "pattern": "/.*/", "thresholds": [], @@ -159,49 +141,31 @@ { "alias": "", "colorMode": "cell", - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], + "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], "dateFormat": "YYYY-MM-DD HH:mm:ss", "decimals": 2, "mappingType": 1, "pattern": "ColorCell", - "thresholds": [ - "5", - "10" - ], + "thresholds": ["5", "10"], "type": "number", "unit": "currencyUSD" }, { "alias": "", "colorMode": "value", - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], + "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], "dateFormat": "YYYY-MM-DD HH:mm:ss", "decimals": 2, "mappingType": 1, "pattern": "ColorValue", - "thresholds": [ - "5", - "10" - ], + "thresholds": ["5", "10"], "type": "number", "unit": "Bps" }, { "alias": "", "colorMode": null, - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], + "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], "decimals": 2, "pattern": "/.*/", "thresholds": [], @@ -259,30 +223,19 @@ { "alias": "", "colorMode": "row", - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], + "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], "dateFormat": "YYYY-MM-DD HH:mm:ss", "decimals": 2, "mappingType": 1, "pattern": "/Color/", - "thresholds": [ - "5", - "10" - ], + "thresholds": ["5", "10"], "type": "number", "unit": "currencyUSD" }, { "alias": "", "colorMode": null, - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], + "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], "decimals": 2, "pattern": "/.*/", "thresholds": [], @@ -334,49 +287,31 @@ { "alias": "", "colorMode": "cell", - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], + "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], "dateFormat": "YYYY-MM-DD HH:mm:ss", "decimals": 2, "mappingType": 1, "pattern": "ColorCell", - "thresholds": [ - "5", - "10" - ], + "thresholds": ["5", "10"], "type": "number", "unit": "currencyUSD" }, { "alias": "", "colorMode": "value", - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], + "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], "dateFormat": "YYYY-MM-DD HH:mm:ss", "decimals": 2, "mappingType": 1, "pattern": "ColorValue", - "thresholds": [ - "5", - "10" - ], + "thresholds": ["5", "10"], "type": "number", "unit": "Bps" }, { "alias": "", "colorMode": null, - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], + "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], "decimals": 2, "pattern": "/.*/", "thresholds": [], @@ -434,11 +369,7 @@ { "alias": "", "colorMode": "cell", - "colors": [ - "rgba(245, 54, 54, 0.5)", - "rgba(237, 129, 40, 0.5)", - "rgba(50, 172, 45, 0.5)" - ], + "colors": ["rgba(245, 54, 54, 0.5)", "rgba(237, 129, 40, 0.5)", "rgba(50, 172, 45, 0.5)"], "dateFormat": "YYYY-MM-DD HH:mm:ss", "decimals": 2, "link": true, @@ -447,42 +378,28 @@ "linkUrl": "http://www.grafana.com", "mappingType": 1, "pattern": "ColorCell", - "thresholds": [ - "5", - "10" - ], + "thresholds": ["5", "10"], "type": "number", "unit": "currencyUSD" }, { "alias": "", "colorMode": "value", - "colors": [ - "rgba(245, 54, 54, 0.5)", - "rgba(237, 129, 40, 0.5)", - "rgba(50, 172, 45, 0.5)" - ], + "colors": ["rgba(245, 54, 54, 0.5)", "rgba(237, 129, 40, 0.5)", "rgba(50, 172, 45, 0.5)"], "dateFormat": "YYYY-MM-DD HH:mm:ss", "decimals": 2, "link": true, "linkUrl": "http://www.grafana.com", "mappingType": 1, "pattern": "ColorValue", - "thresholds": [ - "5", - "10" - ], + "thresholds": ["5", "10"], "type": "number", "unit": "Bps" }, { "alias": "", "colorMode": null, - "colors": [ - "rgba(245, 54, 54, 0.9)", - "rgba(237, 129, 40, 0.89)", - "rgba(50, 172, 45, 0.97)" - ], + "colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"], "decimals": 2, "pattern": "/.*/", "thresholds": [], @@ -516,10 +433,7 @@ "revision": 8, "schemaVersion": 16, "style": "dark", - "tags": [ - "gdev", - "panel-tests" - ], + "tags": ["gdev", "panel-tests"], "templating": { "list": [] }, @@ -528,32 +442,11 @@ "to": "now" }, "timepicker": { - "refresh_intervals": [ - "5s", - "10s", - "30s", - "1m", - "5m", - "15m", - "30m", - "1h", - "2h", - "1d" - ], - "time_options": [ - "5m", - "15m", - "1h", - "6h", - "12h", - "24h", - "2d", - "7d", - "30d" - ] + "refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"], + "time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"] }, "timezone": "browser", "title": "Panel Tests - Table", "uid": "pttable", "version": 2 -} \ No newline at end of file +} diff --git a/devenv/dev-dashboards/panel_tests_slow_queries_and_annotations.json b/devenv/dev-dashboards/scenarios/slow_queries_and_annotations.json similarity index 98% rename from devenv/dev-dashboards/panel_tests_slow_queries_and_annotations.json rename to devenv/dev-dashboards/scenarios/slow_queries_and_annotations.json index 08bf6dce9d010..c0b0ab8425d06 100644 --- a/devenv/dev-dashboards/panel_tests_slow_queries_and_annotations.json +++ b/devenv/dev-dashboards/scenarios/slow_queries_and_annotations.json @@ -19,9 +19,7 @@ "matchAny": false, "name": "annotations", "showIn": 0, - "tags": [ - "asd" - ], + "tags": ["asd"], "type": "tags" } ] @@ -1135,29 +1133,8 @@ "to": "now" }, "timepicker": { - "refresh_intervals": [ - "5s", - "10s", - "30s", - "1m", - "5m", - "15m", - "30m", - "1h", - "2h", - "1d" - ], - "time_options": [ - "5m", - "15m", - "1h", - "6h", - "12h", - "24h", - "2d", - "7d", - "30d" - ] + "refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"], + "time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"] }, "timezone": "", "title": "Panel tests - Slow Queries & Annotations", diff --git a/devenv/docker/blocks/elastic6/docker-compose.yaml b/devenv/docker/blocks/elastic6/docker-compose.yaml index dd2439f88e42a..4d4f2ca898f2a 100644 --- a/devenv/docker/blocks/elastic6/docker-compose.yaml +++ b/devenv/docker/blocks/elastic6/docker-compose.yaml @@ -1,7 +1,7 @@ # You need to run 'sysctl -w vm.max_map_count=262144' on the host machine elasticsearch6: - image: docker.elastic.co/elasticsearch/elasticsearch-oss:6.2.4 + image: docker.elastic.co/elasticsearch/elasticsearch-oss:6.7.1 command: elasticsearch ports: - "11200:9200" @@ -13,3 +13,11 @@ environment: FD_DATASOURCE: elasticsearch6 FD_PORT: 11200 + + filebeat6: + image: docker.elastic.co/beats/filebeat-oss:6.7.1 + command: filebeat -e -strict.perms=false + volumes: + - ./docker/blocks/elastic6/filebeat.yml:/usr/share/filebeat/filebeat.yml:ro + - /var/log:/var/log:ro + - ../data/log:/var/log/grafana:ro diff --git a/devenv/docker/blocks/elastic6/filebeat.yml b/devenv/docker/blocks/elastic6/filebeat.yml new file mode 100644 index 0000000000000..7836e6b35d79e --- /dev/null +++ b/devenv/docker/blocks/elastic6/filebeat.yml @@ -0,0 +1,1978 @@ +######################## Filebeat Configuration ############################ + +# This file is a full configuration example documenting all non-deprecated +# options in comments. For a shorter configuration example, that contains only +# the most common options, please see filebeat.yml in the same directory. +# +# You can find the full configuration reference here: +# https://www.elastic.co/guide/en/beats/filebeat/index.html + + +#========================== Modules configuration ============================ +filebeat.modules: + +#------------------------------- System Module ------------------------------- +#- module: system + # Syslog + #syslog: + #enabled: true + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + + # Convert the timestamp to UTC. Requires Elasticsearch >= 6.1. + #var.convert_timezone: false + + # Input configuration (advanced). Any input configuration option + # can be added under this section. + #input: + + # Authorization logs + #auth: + #enabled: true + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + + # Convert the timestamp to UTC. Requires Elasticsearch >= 6.1. + #var.convert_timezone: false + + # Input configuration (advanced). Any input configuration option + # can be added under this section. + #input: + +#------------------------------- Apache2 Module ------------------------------ +#- module: apache2 + # Access logs + #access: + #enabled: true + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + + # Input configuration (advanced). Any input configuration option + # can be added under this section. + #input: + + # Error logs + #error: + #enabled: true + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + + # Input configuration (advanced). Any input configuration option + # can be added under this section. + #input: + +#------------------------------- Auditd Module ------------------------------- +#- module: auditd + #log: + #enabled: true + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + + # Input configuration (advanced). Any input configuration option + # can be added under this section. + #input: + +#---------------------------- elasticsearch Module --------------------------- +- module: elasticsearch + # Server log + server: + enabled: true + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + + # Convert the timestamp to UTC. Requires Elasticsearch >= 6.1. + #var.convert_timezone: false + + gc: + enabled: true + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + + audit: + enabled: true + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + + # Convert the timestamp to UTC. Requires Elasticsearch >= 6.1. + #var.convert_timezone: false + + slowlog: + enabled: true + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + + # Convert the timestamp to UTC. Requires Elasticsearch >= 6.1. + #var.convert_timezone: false + + deprecation: + enabled: true + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + + # Convert the timestamp to UTC. Requires Elasticsearch >= 6.1. + #var.convert_timezone: false + + +#------------------------------- haproxy Module ------------------------------ +- module: haproxy + # All logs + log: + enabled: true + + # Set which input to use between syslog (default) or file. + #var.input: + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + +#------------------------------- Icinga Module ------------------------------- +#- module: icinga + # Main logs + #main: + #enabled: true + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + + # Input configuration (advanced). Any input configuration option + # can be added under this section. + #input: + + # Debug logs + #debug: + #enabled: true + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + + # Input configuration (advanced). Any input configuration option + # can be added under this section. + #input: + + # Startup logs + #startup: + #enabled: true + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + + # Input configuration (advanced). Any input configuration option + # can be added under this section. + #input: + +#--------------------------------- IIS Module -------------------------------- +#- module: iis + # Access logs + #access: + #enabled: true + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + + # Input configuration (advanced). Any input configuration option + # can be added under this section. + #input: + + # Error logs + #error: + #enabled: true + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + + # Input configuration (advanced). Any input configuration option + # can be added under this section. + #input: + +#-------------------------------- Kafka Module ------------------------------- +- module: kafka + # All logs + log: + enabled: true + + # Set custom paths for Kafka. If left empty, + # Filebeat will look under /opt. + #var.kafka_home: + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + + # Convert the timestamp to UTC. Requires Elasticsearch >= 6.1. + #var.convert_timezone: false + +#------------------------------- kibana Module ------------------------------- +- module: kibana + # All logs + log: + enabled: true + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + +#------------------------------ logstash Module ------------------------------ +#- module: logstash + # logs + #log: + #enabled: true + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + # var.paths: + + # Slow logs + #slowlog: + #enabled: true + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + +#------------------------------- mongodb Module ------------------------------ +#- module: mongodb + # Logs + #log: + #enabled: true + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + + # Input configuration (advanced). Any input configuration option + # can be added under this section. + #input: + +#-------------------------------- MySQL Module ------------------------------- +#- module: mysql + # Error logs + #error: + #enabled: true + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + + # Input configuration (advanced). Any input configuration option + # can be added under this section. + #input: + + # Slow logs + #slowlog: + #enabled: true + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + + # Input configuration (advanced). Any input configuration option + # can be added under this section. + #input: + +#-------------------------------- Nginx Module ------------------------------- +#- module: nginx + # Access logs + #access: + #enabled: true + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + + # Input configuration (advanced). Any input configuration option + # can be added under this section. + #input: + + # Convert the timestamp to UTC. Requires Elasticsearch >= 6.1. + #var.convert_timezone: false + + # Error logs + #error: + #enabled: true + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + + # Input configuration (advanced). Any input configuration option + # can be added under this section. + #input: + + # Convert the timestamp to UTC. Requires Elasticsearch >= 6.1. + #var.convert_timezone: false + +#------------------------------- Osquery Module ------------------------------ +- module: osquery + result: + enabled: true + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + + # If true, all fields created by this module are prefixed with + # `osquery.result`. Set to false to copy the fields in the root + # of the document. The default is true. + #var.use_namespace: true + +#----------------------------- PostgreSQL Module ----------------------------- +#- module: postgresql + # Logs + #log: + #enabled: true + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + + # Input configuration (advanced). Any input configuration option + # can be added under this section. + #input: + +#-------------------------------- Redis Module ------------------------------- +#- module: redis + # Main logs + #log: + #enabled: true + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: ["/var/log/redis/redis-server.log*"] + + # Slow logs, retrieved via the Redis API (SLOWLOG) + #slowlog: + #enabled: true + + # The Redis hosts to connect to. + #var.hosts: ["localhost:6379"] + + # Optional, the password to use when connecting to Redis. + #var.password: + +#------------------------------- Traefik Module ------------------------------ +#- module: traefik + # Access logs + #access: + #enabled: true + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + + # Input configuration (advanced). Any input configuration option + # can be added under this section. + #input: + + +#=========================== Filebeat inputs ============================= + +# List of inputs to fetch data. +filebeat.inputs: +# Each - is an input. Most options can be set at the input level, so +# you can use different inputs for various configurations. +# Below are the input specific configurations. + +# Type of the files. Based on this the way the file is read is decided. +# The different types cannot be mixed in one input +# +# Possible options are: +# * log: Reads every line of the log file (default) +# * stdin: Reads the standard in + +#------------------------------ Log input -------------------------------- +- type: log + enabled: false + paths: + - /var/log/*.log +- type: log + enabled: true + paths: + - /var/log/grafana/grafana.log + include_lines: ['lvl=info'] + fields: + app: grafana + level: info +- type: log + enabled: true + paths: + - /var/log/grafana/grafana.log + include_lines: ['lvl=eror'] + fields: + app: grafana + level: error +- type: log + enabled: true + paths: + - /var/log/grafana/grafana.log + include_lines: ['lvl=warn'] + fields: + app: grafana + level: warning +- type: log + enabled: true + paths: + - /var/log/grafana/grafana.log + include_lines: ['lvl=dbug'] + fields: + app: grafana + level: debug + +#- type: log + + # Change to true to enable this input configuration. + #enabled: false + + # Paths that should be crawled and fetched. Glob based paths. + # To fetch all ".log" files from a specific level of subdirectories + # /var/log/*/*.log can be used. + # For each file found under this path, a harvester is started. + # Make sure not file is defined twice as this can lead to unexpected behaviour. + #paths: + #- /var/log/*.log + #- c:\programdata\elasticsearch\logs\* + + # Configure the file encoding for reading files with international characters + # following the W3C recommendation for HTML5 (http://www.w3.org/TR/encoding). + # Some sample encodings: + # plain, utf-8, utf-16be-bom, utf-16be, utf-16le, big5, gb18030, gbk, + # hz-gb-2312, euc-kr, euc-jp, iso-2022-jp, shift-jis, ... + #encoding: plain + + + # Exclude lines. A list of regular expressions to match. It drops the lines that are + # matching any regular expression from the list. The include_lines is called before + # exclude_lines. By default, no lines are dropped. + #exclude_lines: ['^DBG'] + + # Include lines. A list of regular expressions to match. It exports the lines that are + # matching any regular expression from the list. The include_lines is called before + # exclude_lines. By default, all the lines are exported. + #include_lines: ['^ERR', '^WARN'] + + # Exclude files. A list of regular expressions to match. Filebeat drops the files that + # are matching any regular expression from the list. By default, no files are dropped. + #exclude_files: ['.gz$'] + + # Optional additional fields. These fields can be freely picked + # to add additional information to the crawled log files for filtering + #fields: + # level: debug + # review: 1 + + # Set to true to store the additional fields as top level fields instead + # of under the "fields" sub-dictionary. In case of name conflicts with the + # fields added by Filebeat itself, the custom fields overwrite the default + # fields. + #fields_under_root: false + + # Ignore files which were modified more then the defined timespan in the past. + # ignore_older is disabled by default, so no files are ignored by setting it to 0. + # Time strings like 2h (2 hours), 5m (5 minutes) can be used. + #ignore_older: 0 + + # How often the input checks for new files in the paths that are specified + # for harvesting. Specify 1s to scan the directory as frequently as possible + # without causing Filebeat to scan too frequently. Default: 10s. + #scan_frequency: 10s + + # Defines the buffer size every harvester uses when fetching the file + #harvester_buffer_size: 16384 + + # Maximum number of bytes a single log event can have + # All bytes after max_bytes are discarded and not sent. The default is 10MB. + # This is especially useful for multiline log messages which can get large. + #max_bytes: 10485760 + + ### Recursive glob configuration + + # Expand "**" patterns into regular glob patterns. + #recursive_glob.enabled: true + + ### JSON configuration + + # Decode JSON options. Enable this if your logs are structured in JSON. + # JSON key on which to apply the line filtering and multiline settings. This key + # must be top level and its value must be string, otherwise it is ignored. If + # no text key is defined, the line filtering and multiline features cannot be used. + #json.message_key: + + # By default, the decoded JSON is placed under a "json" key in the output document. + # If you enable this setting, the keys are copied top level in the output document. + #json.keys_under_root: false + + # If keys_under_root and this setting are enabled, then the values from the decoded + # JSON object overwrite the fields that Filebeat normally adds (type, source, offset, etc.) + # in case of conflicts. + #json.overwrite_keys: false + + # If this setting is enabled, Filebeat adds a "error.message" and "error.key: json" key in case of JSON + # unmarshaling errors or when a text key is defined in the configuration but cannot + # be used. + #json.add_error_key: false + + ### Multiline options + + # Multiline can be used for log messages spanning multiple lines. This is common + # for Java Stack Traces or C-Line Continuation + + # The regexp Pattern that has to be matched. The example pattern matches all lines starting with [ + #multiline.pattern: ^\[ + + # Defines if the pattern set under pattern should be negated or not. Default is false. + #multiline.negate: false + + # Match can be set to "after" or "before". It is used to define if lines should be append to a pattern + # that was (not) matched before or after or as long as a pattern is not matched based on negate. + # Note: After is the equivalent to previous and before is the equivalent to to next in Logstash + #multiline.match: after + + # The maximum number of lines that are combined to one event. + # In case there are more the max_lines the additional lines are discarded. + # Default is 500 + #multiline.max_lines: 500 + + # After the defined timeout, an multiline event is sent even if no new pattern was found to start a new event + # Default is 5s. + #multiline.timeout: 5s + + # Setting tail_files to true means filebeat starts reading new files at the end + # instead of the beginning. If this is used in combination with log rotation + # this can mean that the first entries of a new file are skipped. + #tail_files: false + + # The Ingest Node pipeline ID associated with this input. If this is set, it + # overwrites the pipeline option from the Elasticsearch output. + #pipeline: + + # If symlinks is enabled, symlinks are opened and harvested. The harvester is opening the + # original for harvesting but will report the symlink name as source. + #symlinks: false + + # Backoff values define how aggressively filebeat crawls new files for updates + # The default values can be used in most cases. Backoff defines how long it is waited + # to check a file again after EOF is reached. Default is 1s which means the file + # is checked every second if new lines were added. This leads to a near real time crawling. + # Every time a new line appears, backoff is reset to the initial value. + #backoff: 1s + + # Max backoff defines what the maximum backoff time is. After having backed off multiple times + # from checking the files, the waiting time will never exceed max_backoff independent of the + # backoff factor. Having it set to 10s means in the worst case a new line can be added to a log + # file after having backed off multiple times, it takes a maximum of 10s to read the new line + #max_backoff: 10s + + # The backoff factor defines how fast the algorithm backs off. The bigger the backoff factor, + # the faster the max_backoff value is reached. If this value is set to 1, no backoff will happen. + # The backoff value will be multiplied each time with the backoff_factor until max_backoff is reached + #backoff_factor: 2 + + # Max number of harvesters that are started in parallel. + # Default is 0 which means unlimited + #harvester_limit: 0 + + ### Harvester closing options + + # Close inactive closes the file handler after the predefined period. + # The period starts when the last line of the file was, not the file ModTime. + # Time strings like 2h (2 hours), 5m (5 minutes) can be used. + #close_inactive: 5m + + # Close renamed closes a file handler when the file is renamed or rotated. + # Note: Potential data loss. Make sure to read and understand the docs for this option. + #close_renamed: false + + # When enabling this option, a file handler is closed immediately in case a file can't be found + # any more. In case the file shows up again later, harvesting will continue at the last known position + # after scan_frequency. + #close_removed: true + + # Closes the file handler as soon as the harvesters reaches the end of the file. + # By default this option is disabled. + # Note: Potential data loss. Make sure to read and understand the docs for this option. + #close_eof: false + + ### State options + + # Files for the modification data is older then clean_inactive the state from the registry is removed + # By default this is disabled. + #clean_inactive: 0 + + # Removes the state for file which cannot be found on disk anymore immediately + #clean_removed: true + + # Close timeout closes the harvester after the predefined time. + # This is independent if the harvester did finish reading the file or not. + # By default this option is disabled. + # Note: Potential data loss. Make sure to read and understand the docs for this option. + #close_timeout: 0 + + # Defines if inputs is enabled + #enabled: true + +#----------------------------- Stdin input ------------------------------- +# Configuration to use stdin input +#- type: stdin + +#------------------------- Redis slowlog input --------------------------- +# Experimental: Config options for the redis slow log input +#- type: redis + #enabled: false + + # List of hosts to pool to retrieve the slow log information. + #hosts: ["localhost:6379"] + + # How often the input checks for redis slow log. + #scan_frequency: 10s + + # Timeout after which time the input should return an error + #timeout: 1s + + # Network type to be used for redis connection. Default: tcp + #network: tcp + + # Max number of concurrent connections. Default: 10 + #maxconn: 10 + + # Redis AUTH password. Empty by default. + #password: foobared + +#------------------------------ Udp input -------------------------------- +# Experimental: Config options for the udp input +#- type: udp + #enabled: false + + # Maximum size of the message received over UDP + #max_message_size: 10KiB + +#------------------------------ TCP input -------------------------------- +# Experimental: Config options for the TCP input +#- type: tcp + #enabled: false + + # The host and port to receive the new event + #host: "localhost:9000" + + # Character used to split new message + #line_delimiter: "\n" + + # Maximum size in bytes of the message received over TCP + #max_message_size: 20MiB + + # The number of seconds of inactivity before a remote connection is closed. + #timeout: 300s + + # Use SSL settings for TCP. + #ssl.enabled: true + + # List of supported/valid TLS versions. By default all TLS versions 1.0 up to + # 1.2 are enabled. + #ssl.supported_protocols: [TLSv1.0, TLSv1.1, TLSv1.2] + + # SSL configuration. By default is off. + # List of root certificates for client verifications + #ssl.certificate_authorities: ["/etc/pki/root/ca.pem"] + + # Certificate for SSL server authentication. + #ssl.certificate: "/etc/pki/client/cert.pem" + + # Server Certificate Key, + #ssl.key: "/etc/pki/client/cert.key" + + # Optional passphrase for decrypting the Certificate Key. + #ssl.key_passphrase: '' + + # Configure cipher suites to be used for SSL connections. + #ssl.cipher_suites: [] + + # Configure curve types for ECDHE based cipher suites. + #ssl.curve_types: [] + + # Configure what types of client authentication are supported. Valid options + # are `none`, `optional`, and `required`. Default is required. + #ssl.client_authentication: "required" + +#------------------------------ Syslog input -------------------------------- +# Experimental: Config options for the Syslog input +# Accept RFC3164 formatted syslog event via UDP. +#- type: syslog + #enabled: false + #protocol.udp: + # The host and port to receive the new event + #host: "localhost:9000" + + # Maximum size of the message received over UDP + #max_message_size: 10KiB + +# Accept RFC3164 formatted syslog event via TCP. +#- type: syslog + #enabled: false + + #protocol.tcp: + # The host and port to receive the new event + #host: "localhost:9000" + + # Character used to split new message + #line_delimiter: "\n" + + # Maximum size in bytes of the message received over TCP + #max_message_size: 20MiB + + # The number of seconds of inactivity before a remote connection is closed. + #timeout: 300s + + # Use SSL settings for TCP. + #ssl.enabled: true + + # List of supported/valid TLS versions. By default all TLS versions 1.0 up to + # 1.2 are enabled. + #ssl.supported_protocols: [TLSv1.0, TLSv1.1, TLSv1.2] + + # SSL configuration. By default is off. + # List of root certificates for client verifications + #ssl.certificate_authorities: ["/etc/pki/root/ca.pem"] + + # Certificate for SSL server authentication. + #ssl.certificate: "/etc/pki/client/cert.pem" + + # Server Certificate Key, + #ssl.key: "/etc/pki/client/cert.key" + + # Optional passphrase for decrypting the Certificate Key. + #ssl.key_passphrase: '' + + # Configure cipher suites to be used for SSL connections. + #ssl.cipher_suites: [] + + # Configure curve types for ECDHE based cipher suites. + #ssl.curve_types: [] + + # Configure what types of client authentication are supported. Valid options + # are `none`, `optional`, and `required`. Default is required. + #ssl.client_authentication: "required" + +#------------------------------ Docker input -------------------------------- +# Experimental: Docker input reads and parses `json-file` logs from Docker +#- type: docker + #enabled: false + + # Combine partial lines flagged by `json-file` format + #combine_partials: true + + # Use this to read from all containers, replace * with a container id to read from one: + #containers: + # stream: all # can be all, stdout or stderr + # ids: + # - '*' + +#========================== Filebeat autodiscover ============================== + +# Autodiscover allows you to detect changes in the system and spawn new modules +# or inputs as they happen. + +#filebeat.autodiscover: + # List of enabled autodiscover providers +# providers: +# - type: docker +# templates: +# - condition: +# equals.docker.container.image: busybox +# config: +# - type: log +# paths: +# - /var/lib/docker/containers/${data.docker.container.id}/*.log + +#========================= Filebeat global options ============================ + +# Name of the registry file. If a relative path is used, it is considered relative to the +# data path. +#filebeat.registry_file: ${path.data}/registry + +# The permissions mask to apply on registry file. The default value is 0600. +# Must be a valid Unix-style file permissions mask expressed in octal notation. +# This option is not supported on Windows. +#filebeat.registry_file_permissions: 0600 + +# The timeout value that controls when registry entries are written to disk +# (flushed). When an unwritten update exceeds this value, it triggers a write to +# disk. When registry_flush is set to 0s, the registry is written to disk after +# each batch of events has been published successfully. The default value is 0s. +#filebeat.registry_flush: 0s + +# By default Ingest pipelines are not updated if a pipeline with the same ID +# already exists. If this option is enabled Filebeat overwrites pipelines +# everytime a new Elasticsearch connection is established. +#filebeat.overwrite_pipelines: false + +# How long filebeat waits on shutdown for the publisher to finish. +# Default is 0, not waiting. +#filebeat.shutdown_timeout: 0 + +# Enable filebeat config reloading +#filebeat.config: + #inputs: + #enabled: false + #path: inputs.d/*.yml + #reload.enabled: true + #reload.period: 10s + #modules: + #enabled: false + #path: modules.d/*.yml + #reload.enabled: true + #reload.period: 10s + +#================================ General ====================================== + +# The name of the shipper that publishes the network data. It can be used to group +# all the transactions sent by a single shipper in the web interface. +# If this options is not defined, the hostname is used. +#name: + +# The tags of the shipper are included in their own field with each +# transaction published. Tags make it easy to group servers by different +# logical properties. +#tags: ["service-X", "web-tier"] + +# Optional fields that you can specify to add additional information to the +# output. Fields can be scalar values, arrays, dictionaries, or any nested +# combination of these. +#fields: +# env: staging + +# If this option is set to true, the custom fields are stored as top-level +# fields in the output document instead of being grouped under a fields +# sub-dictionary. Default is false. +#fields_under_root: false + +# Internal queue configuration for buffering events to be published. +#queue: + # Queue type by name (default 'mem') + # The memory queue will present all available events (up to the outputs + # bulk_max_size) to the output, the moment the output is ready to server + # another batch of events. + #mem: + # Max number of events the queue can buffer. + #events: 4096 + + # Hints the minimum number of events stored in the queue, + # before providing a batch of events to the outputs. + # The default value is set to 2048. + # A value of 0 ensures events are immediately available + # to be sent to the outputs. + #flush.min_events: 2048 + + # Maximum duration after which events are available to the outputs, + # if the number of events stored in the queue is < min_flush_events. + #flush.timeout: 1s + + # The spool queue will store events in a local spool file, before + # forwarding the events to the outputs. + # + # Beta: spooling to disk is currently a beta feature. Use with care. + # + # The spool file is a circular buffer, which blocks once the file/buffer is full. + # Events are put into a write buffer and flushed once the write buffer + # is full or the flush_timeout is triggered. + # Once ACKed by the output, events are removed immediately from the queue, + # making space for new events to be persisted. + #spool: + # The file namespace configures the file path and the file creation settings. + # Once the file exists, the `size`, `page_size` and `prealloc` settings + # will have no more effect. + #file: + # Location of spool file. The default value is ${path.data}/spool.dat. + #path: "${path.data}/spool.dat" + + # Configure file permissions if file is created. The default value is 0600. + #permissions: 0600 + + # File size hint. The spool blocks, once this limit is reached. The default value is 100 MiB. + #size: 100MiB + + # The files page size. A file is split into multiple pages of the same size. The default value is 4KiB. + #page_size: 4KiB + + # If prealloc is set, the required space for the file is reserved using + # truncate. The default value is true. + #prealloc: true + + # Spool writer settings + # Events are serialized into a write buffer. The write buffer is flushed if: + # - The buffer limit has been reached. + # - The configured limit of buffered events is reached. + # - The flush timeout is triggered. + #write: + # Sets the write buffer size. + #buffer_size: 1MiB + + # Maximum duration after which events are flushed if the write buffer + # is not full yet. The default value is 1s. + #flush.timeout: 1s + + # Number of maximum buffered events. The write buffer is flushed once the + # limit is reached. + #flush.events: 16384 + + # Configure the on-disk event encoding. The encoding can be changed + # between restarts. + # Valid encodings are: json, ubjson, and cbor. + #codec: cbor + #read: + # Reader flush timeout, waiting for more events to become available, so + # to fill a complete batch as required by the outputs. + # If flush_timeout is 0, all available events are forwarded to the + # outputs immediately. + # The default value is 0s. + #flush.timeout: 0s + +# Sets the maximum number of CPUs that can be executing simultaneously. The +# default is the number of logical CPUs available in the system. +#max_procs: + +#================================ Processors =================================== + +# Processors are used to reduce the number of fields in the exported event or to +# enhance the event with external metadata. This section defines a list of +# processors that are applied one by one and the first one receives the initial +# event: +# +# event -> filter1 -> event1 -> filter2 ->event2 ... +# +# The supported processors are drop_fields, drop_event, include_fields, +# decode_json_fields, and add_cloud_metadata. +# +# For example, you can use the following processors to keep the fields that +# contain CPU load percentages, but remove the fields that contain CPU ticks +# values: +# +#processors: +#- include_fields: +# fields: ["cpu"] +#- drop_fields: +# fields: ["cpu.user", "cpu.system"] +# +# The following example drops the events that have the HTTP response code 200: +# +#processors: +#- drop_event: +# when: +# equals: +# http.code: 200 +# +# The following example renames the field a to b: +# +#processors: +#- rename: +# fields: +# - from: "a" +# to: "b" +# +# The following example tokenizes the string into fields: +# +#processors: +#- dissect: +# tokenizer: "%{key1} - %{key2}" +# field: "message" +# target_prefix: "dissect" +# +# The following example enriches each event with metadata from the cloud +# provider about the host machine. It works on EC2, GCE, DigitalOcean, +# Tencent Cloud, and Alibaba Cloud. +# +#processors: +#- add_cloud_metadata: ~ +# +# The following example enriches each event with the machine's local time zone +# offset from UTC. +# +#processors: +#- add_locale: +# format: offset +# +# The following example enriches each event with docker metadata, it matches +# given fields to an existing container id and adds info from that container: +# +#processors: +#- add_docker_metadata: +# host: "unix:///var/run/docker.sock" +# match_fields: ["system.process.cgroup.id"] +# match_pids: ["process.pid", "process.ppid"] +# match_source: true +# match_source_index: 4 +# match_short_id: false +# cleanup_timeout: 60 +# labels.dedot: false +# # To connect to Docker over TLS you must specify a client and CA certificate. +# #ssl: +# # certificate_authority: "/etc/pki/root/ca.pem" +# # certificate: "/etc/pki/client/cert.pem" +# # key: "/etc/pki/client/cert.key" +# +# The following example enriches each event with docker metadata, it matches +# container id from log path available in `source` field (by default it expects +# it to be /var/lib/docker/containers/*/*.log). +# +#processors: +#- add_docker_metadata: ~ +# +# The following example enriches each event with host metadata. +# +#processors: +#- add_host_metadata: +# netinfo.enabled: false +# +# The following example enriches each event with process metadata using +# process IDs included in the event. +# +#processors: +#- add_process_metadata: +# match_pids: ["system.process.ppid"] +# target: system.process.parent +# +# The following example decodes fields containing JSON strings +# and replaces the strings with valid JSON objects. +# +#processors: +#- decode_json_fields: +# fields: ["field1", "field2", ...] +# process_array: false +# max_depth: 1 +# target: "" +# overwrite_keys: false + +#============================= Elastic Cloud ================================== + +# These settings simplify using filebeat with the Elastic Cloud (https://cloud.elastic.co/). + +# The cloud.id setting overwrites the `output.elasticsearch.hosts` and +# `setup.kibana.host` options. +# You can find the `cloud.id` in the Elastic Cloud web UI. +#cloud.id: + +# The cloud.auth setting overwrites the `output.elasticsearch.username` and +# `output.elasticsearch.password` settings. The format is `<user>:<pass>`. +#cloud.auth: + +#================================ Outputs ====================================== + +# Configure what output to use when sending the data collected by the beat. + +#-------------------------- Elasticsearch output ------------------------------- +output.elasticsearch: + # Boolean flag to enable or disable the output module. + #enabled: true + + # Array of hosts to connect to. + # Scheme and port can be left out and will be set to the default (http and 9200) + # In case you specify and additional path, the scheme is required: http://localhost:9200/path + # IPv6 addresses should always be defined as: https://[2001:db8::1]:9200 + hosts: ["elasticsearch6:9200"] + + # Enabled ilm (beta) to use index lifecycle management instead daily indices. + #ilm.enabled: false + #ilm.rollover_alias: "filebeat" + #ilm.pattern: "{now/d}-000001" + + # Set gzip compression level. + #compression_level: 0 + + # Configure escaping HTML symbols in strings. + #escape_html: true + + # Optional protocol and basic auth credentials. + #protocol: "https" + #username: "elastic" + #password: "changeme" + + # Dictionary of HTTP parameters to pass within the URL with index operations. + #parameters: + #param1: value1 + #param2: value2 + + # Number of workers per Elasticsearch host. + #worker: 1 + + # Optional index name. The default is "filebeat" plus date + # and generates [filebeat-]YYYY.MM.DD keys. + # In case you modify this pattern you must update setup.template.name and setup.template.pattern accordingly. + index: "filebeat-%{+yyyy.MM.dd}" + + # Optional ingest node pipeline. By default no pipeline will be used. + #pipeline: "" + + # Optional HTTP path + #path: "/elasticsearch" + + # Custom HTTP headers to add to each request + #headers: + # X-My-Header: Contents of the header + + # Proxy server URL + #proxy_url: http://proxy:3128 + + # The number of times a particular Elasticsearch index operation is attempted. If + # the indexing operation doesn't succeed after this many retries, the events are + # dropped. The default is 3. + #max_retries: 3 + + # The maximum number of events to bulk in a single Elasticsearch bulk API index request. + # The default is 50. + #bulk_max_size: 50 + + # The number of seconds to wait before trying to reconnect to Elasticsearch + # after a network error. After waiting backoff.init seconds, the Beat + # tries to reconnect. If the attempt fails, the backoff timer is increased + # exponentially up to backoff.max. After a successful connection, the backoff + # timer is reset. The default is 1s. + #backoff.init: 1s + + # The maximum number of seconds to wait before attempting to connect to + # Elasticsearch after a network error. The default is 60s. + #backoff.max: 60s + + # Configure HTTP request timeout before failing a request to Elasticsearch. + #timeout: 90 + + # Use SSL settings for HTTPS. + #ssl.enabled: true + + # Configure SSL verification mode. If `none` is configured, all server hosts + # and certificates will be accepted. In this mode, SSL-based connections are + # susceptible to man-in-the-middle attacks. Use only for testing. Default is + # `full`. + #ssl.verification_mode: full + + # List of supported/valid TLS versions. By default all TLS versions from 1.0 up to + # 1.2 are enabled. + #ssl.supported_protocols: [TLSv1.0, TLSv1.1, TLSv1.2] + + # List of root certificates for HTTPS server verifications + #ssl.certificate_authorities: ["/etc/pki/root/ca.pem"] + + # Certificate for SSL client authentication + #ssl.certificate: "/etc/pki/client/cert.pem" + + # Client certificate key + #ssl.key: "/etc/pki/client/cert.key" + + # Optional passphrase for decrypting the certificate key. + #ssl.key_passphrase: '' + + # Configure cipher suites to be used for SSL connections + #ssl.cipher_suites: [] + + # Configure curve types for ECDHE-based cipher suites + #ssl.curve_types: [] + + # Configure what types of renegotiation are supported. Valid options are + # never, once, and freely. Default is never. + #ssl.renegotiation: never + + +#----------------------------- Logstash output --------------------------------- +#output.logstash: + # Boolean flag to enable or disable the output module. + #enabled: true + + # The Logstash hosts + #hosts: ["localhost:5044"] + + # Number of workers per Logstash host. + #worker: 1 + + # Set gzip compression level. + #compression_level: 3 + + # Configure escaping HTML symbols in strings. + #escape_html: true + + # Optional maximum time to live for a connection to Logstash, after which the + # connection will be re-established. A value of `0s` (the default) will + # disable this feature. + # + # Not yet supported for async connections (i.e. with the "pipelining" option set) + #ttl: 30s + + # Optionally load-balance events between Logstash hosts. Default is false. + #loadbalance: false + + # Number of batches to be sent asynchronously to Logstash while processing + # new batches. + #pipelining: 2 + + # If enabled only a subset of events in a batch of events is transferred per + # transaction. The number of events to be sent increases up to `bulk_max_size` + # if no error is encountered. + #slow_start: false + + # The number of seconds to wait before trying to reconnect to Logstash + # after a network error. After waiting backoff.init seconds, the Beat + # tries to reconnect. If the attempt fails, the backoff timer is increased + # exponentially up to backoff.max. After a successful connection, the backoff + # timer is reset. The default is 1s. + #backoff.init: 1s + + # The maximum number of seconds to wait before attempting to connect to + # Logstash after a network error. The default is 60s. + #backoff.max: 60s + + # Optional index name. The default index name is set to filebeat + # in all lowercase. + #index: 'filebeat' + + # SOCKS5 proxy server URL + #proxy_url: socks5://user:password@socks5-server:2233 + + # Resolve names locally when using a proxy server. Defaults to false. + #proxy_use_local_resolver: false + + # Enable SSL support. SSL is automatically enabled if any SSL setting is set. + #ssl.enabled: true + + # Configure SSL verification mode. If `none` is configured, all server hosts + # and certificates will be accepted. In this mode, SSL based connections are + # susceptible to man-in-the-middle attacks. Use only for testing. Default is + # `full`. + #ssl.verification_mode: full + + # List of supported/valid TLS versions. By default all TLS versions from 1.0 up to + # 1.2 are enabled. + #ssl.supported_protocols: [TLSv1.0, TLSv1.1, TLSv1.2] + + # Optional SSL configuration options. SSL is off by default. + # List of root certificates for HTTPS server verifications + #ssl.certificate_authorities: ["/etc/pki/root/ca.pem"] + + # Certificate for SSL client authentication + #ssl.certificate: "/etc/pki/client/cert.pem" + + # Client certificate key + #ssl.key: "/etc/pki/client/cert.key" + + # Optional passphrase for decrypting the Certificate Key. + #ssl.key_passphrase: '' + + # Configure cipher suites to be used for SSL connections + #ssl.cipher_suites: [] + + # Configure curve types for ECDHE-based cipher suites + #ssl.curve_types: [] + + # Configure what types of renegotiation are supported. Valid options are + # never, once, and freely. Default is never. + #ssl.renegotiation: never + + # The number of times to retry publishing an event after a publishing failure. + # After the specified number of retries, the events are typically dropped. + # Some Beats, such as Filebeat and Winlogbeat, ignore the max_retries setting + # and retry until all events are published. Set max_retries to a value less + # than 0 to retry until all events are published. The default is 3. + #max_retries: 3 + + # The maximum number of events to bulk in a single Logstash request. The + # default is 2048. + #bulk_max_size: 2048 + + # The number of seconds to wait for responses from the Logstash server before + # timing out. The default is 30s. + #timeout: 30s + +#------------------------------- Kafka output ---------------------------------- +#output.kafka: + # Boolean flag to enable or disable the output module. + #enabled: true + + # The list of Kafka broker addresses from which to fetch the cluster metadata. + # The cluster metadata contain the actual Kafka brokers events are published + # to. + #hosts: ["localhost:9092"] + + # The Kafka topic used for produced events. The setting can be a format string + # using any event field. To set the topic from document type use `%{[type]}`. + #topic: beats + + # The Kafka event key setting. Use format string to create a unique event key. + # By default no event key will be generated. + #key: '' + + # The Kafka event partitioning strategy. Default hashing strategy is `hash` + # using the `output.kafka.key` setting or randomly distributes events if + # `output.kafka.key` is not configured. + #partition.hash: + # If enabled, events will only be published to partitions with reachable + # leaders. Default is false. + #reachable_only: false + + # Configure alternative event field names used to compute the hash value. + # If empty `output.kafka.key` setting will be used. + # Default value is empty list. + #hash: [] + + # Authentication details. Password is required if username is set. + #username: '' + #password: '' + + # Kafka version filebeat is assumed to run against. Defaults to the "1.0.0". + #version: '1.0.0' + + # Configure JSON encoding + #codec.json: + # Pretty-print JSON event + #pretty: false + + # Configure escaping HTML symbols in strings. + #escape_html: true + + # Metadata update configuration. Metadata contains leader information + # used to decide which broker to use when publishing. + #metadata: + # Max metadata request retry attempts when cluster is in middle of leader + # election. Defaults to 3 retries. + #retry.max: 3 + + # Wait time between retries during leader elections. Default is 250ms. + #retry.backoff: 250ms + + # Refresh metadata interval. Defaults to every 10 minutes. + #refresh_frequency: 10m + + # The number of concurrent load-balanced Kafka output workers. + #worker: 1 + + # The number of times to retry publishing an event after a publishing failure. + # After the specified number of retries, events are typically dropped. + # Some Beats, such as Filebeat, ignore the max_retries setting and retry until + # all events are published. Set max_retries to a value less than 0 to retry + # until all events are published. The default is 3. + #max_retries: 3 + + # The maximum number of events to bulk in a single Kafka request. The default + # is 2048. + #bulk_max_size: 2048 + + # The number of seconds to wait for responses from the Kafka brokers before + # timing out. The default is 30s. + #timeout: 30s + + # The maximum duration a broker will wait for number of required ACKs. The + # default is 10s. + #broker_timeout: 10s + + # The number of messages buffered for each Kafka broker. The default is 256. + #channel_buffer_size: 256 + + # The keep-alive period for an active network connection. If 0s, keep-alives + # are disabled. The default is 0 seconds. + #keep_alive: 0 + + # Sets the output compression codec. Must be one of none, snappy and gzip. The + # default is gzip. + #compression: gzip + + # Set the compression level. Currently only gzip provides a compression level + # between 0 and 9. The default value is chosen by the compression algorithm. + #compression_level: 4 + + # The maximum permitted size of JSON-encoded messages. Bigger messages will be + # dropped. The default value is 1000000 (bytes). This value should be equal to + # or less than the broker's message.max.bytes. + #max_message_bytes: 1000000 + + # The ACK reliability level required from broker. 0=no response, 1=wait for + # local commit, -1=wait for all replicas to commit. The default is 1. Note: + # If set to 0, no ACKs are returned by Kafka. Messages might be lost silently + # on error. + #required_acks: 1 + + # The configurable ClientID used for logging, debugging, and auditing + # purposes. The default is "beats". + #client_id: beats + + # Enable SSL support. SSL is automatically enabled if any SSL setting is set. + #ssl.enabled: true + + # Optional SSL configuration options. SSL is off by default. + # List of root certificates for HTTPS server verifications + #ssl.certificate_authorities: ["/etc/pki/root/ca.pem"] + + # Configure SSL verification mode. If `none` is configured, all server hosts + # and certificates will be accepted. In this mode, SSL based connections are + # susceptible to man-in-the-middle attacks. Use only for testing. Default is + # `full`. + #ssl.verification_mode: full + + # List of supported/valid TLS versions. By default all TLS versions from 1.0 up to + # 1.2 are enabled. + #ssl.supported_protocols: [TLSv1.0, TLSv1.1, TLSv1.2] + + # Certificate for SSL client authentication + #ssl.certificate: "/etc/pki/client/cert.pem" + + # Client Certificate Key + #ssl.key: "/etc/pki/client/cert.key" + + # Optional passphrase for decrypting the Certificate Key. + #ssl.key_passphrase: '' + + # Configure cipher suites to be used for SSL connections + #ssl.cipher_suites: [] + + # Configure curve types for ECDHE-based cipher suites + #ssl.curve_types: [] + + # Configure what types of renegotiation are supported. Valid options are + # never, once, and freely. Default is never. + #ssl.renegotiation: never + +#------------------------------- Redis output ---------------------------------- +#output.redis: + # Boolean flag to enable or disable the output module. + #enabled: true + + # Configure JSON encoding + #codec.json: + # Pretty print json event + #pretty: false + + # Configure escaping HTML symbols in strings. + #escape_html: true + + # The list of Redis servers to connect to. If load-balancing is enabled, the + # events are distributed to the servers in the list. If one server becomes + # unreachable, the events are distributed to the reachable servers only. + #hosts: ["localhost:6379"] + + # The name of the Redis list or channel the events are published to. The + # default is filebeat. + #key: filebeat + + # The password to authenticate to Redis with. The default is no authentication. + #password: + + # The Redis database number where the events are published. The default is 0. + #db: 0 + + # The Redis data type to use for publishing events. If the data type is list, + # the Redis RPUSH command is used. If the data type is channel, the Redis + # PUBLISH command is used. The default value is list. + #datatype: list + + # The number of workers to use for each host configured to publish events to + # Redis. Use this setting along with the loadbalance option. For example, if + # you have 2 hosts and 3 workers, in total 6 workers are started (3 for each + # host). + #worker: 1 + + # If set to true and multiple hosts or workers are configured, the output + # plugin load balances published events onto all Redis hosts. If set to false, + # the output plugin sends all events to only one host (determined at random) + # and will switch to another host if the currently selected one becomes + # unreachable. The default value is true. + #loadbalance: true + + # The Redis connection timeout in seconds. The default is 5 seconds. + #timeout: 5s + + # The number of times to retry publishing an event after a publishing failure. + # After the specified number of retries, the events are typically dropped. + # Some Beats, such as Filebeat, ignore the max_retries setting and retry until + # all events are published. Set max_retries to a value less than 0 to retry + # until all events are published. The default is 3. + #max_retries: 3 + + # The number of seconds to wait before trying to reconnect to Redis + # after a network error. After waiting backoff.init seconds, the Beat + # tries to reconnect. If the attempt fails, the backoff timer is increased + # exponentially up to backoff.max. After a successful connection, the backoff + # timer is reset. The default is 1s. + #backoff.init: 1s + + # The maximum number of seconds to wait before attempting to connect to + # Redis after a network error. The default is 60s. + #backoff.max: 60s + + # The maximum number of events to bulk in a single Redis request or pipeline. + # The default is 2048. + #bulk_max_size: 2048 + + # The URL of the SOCKS5 proxy to use when connecting to the Redis servers. The + # value must be a URL with a scheme of socks5://. + #proxy_url: + + # This option determines whether Redis hostnames are resolved locally when + # using a proxy. The default value is false, which means that name resolution + # occurs on the proxy server. + #proxy_use_local_resolver: false + + # Enable SSL support. SSL is automatically enabled, if any SSL setting is set. + #ssl.enabled: true + + # Configure SSL verification mode. If `none` is configured, all server hosts + # and certificates will be accepted. In this mode, SSL based connections are + # susceptible to man-in-the-middle attacks. Use only for testing. Default is + # `full`. + #ssl.verification_mode: full + + # List of supported/valid TLS versions. By default all TLS versions 1.0 up to + # 1.2 are enabled. + #ssl.supported_protocols: [TLSv1.0, TLSv1.1, TLSv1.2] + + # Optional SSL configuration options. SSL is off by default. + # List of root certificates for HTTPS server verifications + #ssl.certificate_authorities: ["/etc/pki/root/ca.pem"] + + # Certificate for SSL client authentication + #ssl.certificate: "/etc/pki/client/cert.pem" + + # Client Certificate Key + #ssl.key: "/etc/pki/client/cert.key" + + # Optional passphrase for decrypting the Certificate Key. + #ssl.key_passphrase: '' + + # Configure cipher suites to be used for SSL connections + #ssl.cipher_suites: [] + + # Configure curve types for ECDHE based cipher suites + #ssl.curve_types: [] + + # Configure what types of renegotiation are supported. Valid options are + # never, once, and freely. Default is never. + #ssl.renegotiation: never + +#------------------------------- File output ----------------------------------- +#output.file: + # Boolean flag to enable or disable the output module. + #enabled: true + + # Configure JSON encoding + #codec.json: + # Pretty-print JSON event + #pretty: false + + # Configure escaping HTML symbols in strings. + #escape_html: true + + # Path to the directory where to save the generated files. The option is + # mandatory. + #path: "/tmp/filebeat" + + # Name of the generated files. The default is `filebeat` and it generates + # files: `filebeat`, `filebeat.1`, `filebeat.2`, etc. + #filename: filebeat + + # Maximum size in kilobytes of each file. When this size is reached, and on + # every filebeat restart, the files are rotated. The default value is 10240 + # kB. + #rotate_every_kb: 10000 + + # Maximum number of files under path. When this number of files is reached, + # the oldest file is deleted and the rest are shifted from last to first. The + # default is 7 files. + #number_of_files: 7 + + # Permissions to use for file creation. The default is 0600. + #permissions: 0600 + + +#----------------------------- Console output --------------------------------- +#output.console: + # Boolean flag to enable or disable the output module. + #enabled: true + + # Configure JSON encoding + #codec.json: + # Pretty-print JSON event + #pretty: false + + # Configure escaping HTML symbols in strings. + #escape_html: true + +#================================= Paths ====================================== + +# The home path for the filebeat installation. This is the default base path +# for all other path settings and for miscellaneous files that come with the +# distribution (for example, the sample dashboards). +# If not set by a CLI flag or in the configuration file, the default for the +# home path is the location of the binary. +#path.home: + +# The configuration path for the filebeat installation. This is the default +# base path for configuration files, including the main YAML configuration file +# and the Elasticsearch template file. If not set by a CLI flag or in the +# configuration file, the default for the configuration path is the home path. +#path.config: ${path.home} + +# The data path for the filebeat installation. This is the default base path +# for all the files in which filebeat needs to store its data. If not set by a +# CLI flag or in the configuration file, the default for the data path is a data +# subdirectory inside the home path. +#path.data: ${path.home}/data + +# The logs path for a filebeat installation. This is the default location for +# the Beat's log files. If not set by a CLI flag or in the configuration file, +# the default for the logs path is a logs subdirectory inside the home path. +#path.logs: ${path.home}/logs + +#================================ Keystore ========================================== +# Location of the Keystore containing the keys and their sensitive values. +#keystore.path: "${path.config}/beats.keystore" + +#============================== Dashboards ===================================== +# These settings control loading the sample dashboards to the Kibana index. Loading +# the dashboards are disabled by default and can be enabled either by setting the +# options here, or by using the `-setup` CLI flag or the `setup` command. +#setup.dashboards.enabled: false + +# The directory from where to read the dashboards. The default is the `kibana` +# folder in the home path. +#setup.dashboards.directory: ${path.home}/kibana + +# The URL from where to download the dashboards archive. It is used instead of +# the directory if it has a value. +#setup.dashboards.url: + +# The file archive (zip file) from where to read the dashboards. It is used instead +# of the directory when it has a value. +#setup.dashboards.file: + +# In case the archive contains the dashboards from multiple Beats, this lets you +# select which one to load. You can load all the dashboards in the archive by +# setting this to the empty string. +#setup.dashboards.beat: filebeat + +# The name of the Kibana index to use for setting the configuration. Default is ".kibana" +#setup.dashboards.kibana_index: .kibana + +# The Elasticsearch index name. This overwrites the index name defined in the +# dashboards and index pattern. Example: testbeat-* +#setup.dashboards.index: + +# Always use the Kibana API for loading the dashboards instead of autodetecting +# how to install the dashboards by first querying Elasticsearch. +#setup.dashboards.always_kibana: false + +# If true and Kibana is not reachable at the time when dashboards are loaded, +# it will retry to reconnect to Kibana instead of exiting with an error. +#setup.dashboards.retry.enabled: false + +# Duration interval between Kibana connection retries. +#setup.dashboards.retry.interval: 1s + +# Maximum number of retries before exiting with an error, 0 for unlimited retrying. +#setup.dashboards.retry.maximum: 0 + + +#============================== Template ===================================== + +# A template is used to set the mapping in Elasticsearch +# By default template loading is enabled and the template is loaded. +# These settings can be adjusted to load your own template or overwrite existing ones. + +# Set to false to disable template loading. +#setup.template.enabled: true + +# Template name. By default the template name is "filebeat-%{[beat.version]}" +# The template name and pattern has to be set in case the Elasticsearch index pattern is modified. +setup.template.name: "filebeat" + +# Template pattern. By default the template pattern is "-%{[beat.version]}-*" to apply to the default index settings. +# The first part is the version of the beat and then -* is used to match all daily indices. +# The template name and pattern has to be set in case the Elasticsearch index pattern is modified. +setup.template.pattern: "filebeat-*" + +# Path to fields.yml file to generate the template +#setup.template.fields: "${path.config}/fields.yml" + +# A list of fields to be added to the template and Kibana index pattern. Also +# specify setup.template.overwrite: true to overwrite the existing template. +# This setting is experimental. +#setup.template.append_fields: +#- name: field_name +# type: field_type + +# Enable JSON template loading. If this is enabled, the fields.yml is ignored. +#setup.template.json.enabled: false + +# Path to the JSON template file +#setup.template.json.path: "${path.config}/template.json" + +# Name under which the template is stored in Elasticsearch +#setup.template.json.name: "" + +# Overwrite existing template +#setup.template.overwrite: false + +# Elasticsearch template settings +setup.template.settings: + + # A dictionary of settings to place into the settings.index dictionary + # of the Elasticsearch template. For more details, please check + # https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping.html + #index: + #number_of_shards: 1 + #codec: best_compression + #number_of_routing_shards: 30 + + # A dictionary of settings for the _source field. For more details, please check + # https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-source-field.html + #_source: + #enabled: false + +#============================== Kibana ===================================== + +# Starting with Beats version 6.0.0, the dashboards are loaded via the Kibana API. +# This requires a Kibana endpoint configuration. +setup.kibana: + + # Kibana Host + # Scheme and port can be left out and will be set to the default (http and 5601) + # In case you specify and additional path, the scheme is required: http://localhost:5601/path + # IPv6 addresses should always be defined as: https://[2001:db8::1]:5601 + #host: "localhost:5601" + + # Optional protocol and basic auth credentials. + #protocol: "https" + #username: "elastic" + #password: "changeme" + + # Optional HTTP path + #path: "" + + # Use SSL settings for HTTPS. Default is true. + #ssl.enabled: true + + # Configure SSL verification mode. If `none` is configured, all server hosts + # and certificates will be accepted. In this mode, SSL based connections are + # susceptible to man-in-the-middle attacks. Use only for testing. Default is + # `full`. + #ssl.verification_mode: full + + # List of supported/valid TLS versions. By default all TLS versions from 1.0 up to + # 1.2 are enabled. + #ssl.supported_protocols: [TLSv1.0, TLSv1.1, TLSv1.2] + + # SSL configuration. The default is off. + # List of root certificates for HTTPS server verifications + #ssl.certificate_authorities: ["/etc/pki/root/ca.pem"] + + # Certificate for SSL client authentication + #ssl.certificate: "/etc/pki/client/cert.pem" + + # Client certificate key + #ssl.key: "/etc/pki/client/cert.key" + + # Optional passphrase for decrypting the certificate key. + #ssl.key_passphrase: '' + + # Configure cipher suites to be used for SSL connections + #ssl.cipher_suites: [] + + # Configure curve types for ECDHE-based cipher suites + #ssl.curve_types: [] + + + +#================================ Logging ====================================== +# There are four options for the log output: file, stderr, syslog, eventlog +# The file output is the default. + +# Sets log level. The default log level is info. +# Available log levels are: error, warning, info, debug +#logging.level: info + +# Enable debug output for selected components. To enable all selectors use ["*"] +# Other available selectors are "beat", "publish", "service" +# Multiple selectors can be chained. +#logging.selectors: [ ] + +# Send all logging output to syslog. The default is false. +#logging.to_syslog: false + +# Send all logging output to Windows Event Logs. The default is false. +#logging.to_eventlog: false + +# If enabled, filebeat periodically logs its internal metrics that have changed +# in the last period. For each metric that changed, the delta from the value at +# the beginning of the period is logged. Also, the total values for +# all non-zero internal metrics are logged on shutdown. The default is true. +#logging.metrics.enabled: true + +# The period after which to log the internal metrics. The default is 30s. +#logging.metrics.period: 30s + +# Logging to rotating files. Set logging.to_files to false to disable logging to +# files. +logging.to_files: true +logging.files: + # Configure the path where the logs are written. The default is the logs directory + # under the home path (the binary location). + #path: /var/log/filebeat + + # The name of the files where the logs are written to. + #name: filebeat + + # Configure log file size limit. If limit is reached, log file will be + # automatically rotated + #rotateeverybytes: 10485760 # = 10MB + + # Number of rotated log files to keep. Oldest files will be deleted first. + #keepfiles: 7 + + # The permissions mask to apply when rotating log files. The default value is 0600. + # Must be a valid Unix-style file permissions mask expressed in octal notation. + #permissions: 0600 + + # Enable log file rotation on time intervals in addition to size-based rotation. + # Intervals must be at least 1s. Values of 1m, 1h, 24h, 7*24h, 30*24h, and 365*24h + # are boundary-aligned with minutes, hours, days, weeks, months, and years as + # reported by the local system clock. All other intervals are calculated from the + # Unix epoch. Defaults to disabled. + #interval: 0 + +# Set to true to log messages in JSON format. +#logging.json: false + + +#============================== Xpack Monitoring ===================================== +# filebeat can export internal metrics to a central Elasticsearch monitoring cluster. +# This requires xpack monitoring to be enabled in Elasticsearch. +# The reporting is disabled by default. + +# Set to true to enable the monitoring reporter. +#xpack.monitoring.enabled: false + +# Uncomment to send the metrics to Elasticsearch. Most settings from the +# Elasticsearch output are accepted here as well. Any setting that is not set is +# automatically inherited from the Elasticsearch output configuration, so if you +# have the Elasticsearch output configured, you can simply uncomment the +# following line, and leave the rest commented out. +#xpack.monitoring.elasticsearch: + + # Array of hosts to connect to. + # Scheme and port can be left out and will be set to the default (http and 9200) + # In case you specify and additional path, the scheme is required: http://localhost:9200/path + # IPv6 addresses should always be defined as: https://[2001:db8::1]:9200 + #hosts: ["localhost:9200"] + + # Set gzip compression level. + #compression_level: 0 + + # Optional protocol and basic auth credentials. + #protocol: "https" + #username: "beats_system" + #password: "changeme" + + # Dictionary of HTTP parameters to pass within the URL with index operations. + #parameters: + #param1: value1 + #param2: value2 + + # Custom HTTP headers to add to each request + #headers: + # X-My-Header: Contents of the header + + # Proxy server url + #proxy_url: http://proxy:3128 + + # The number of times a particular Elasticsearch index operation is attempted. If + # the indexing operation doesn't succeed after this many retries, the events are + # dropped. The default is 3. + #max_retries: 3 + + # The maximum number of events to bulk in a single Elasticsearch bulk API index request. + # The default is 50. + #bulk_max_size: 50 + + # The number of seconds to wait before trying to reconnect to Elasticsearch + # after a network error. After waiting backoff.init seconds, the Beat + # tries to reconnect. If the attempt fails, the backoff timer is increased + # exponentially up to backoff.max. After a successful connection, the backoff + # timer is reset. The default is 1s. + #backoff.init: 1s + + # The maximum number of seconds to wait before attempting to connect to + # Elasticsearch after a network error. The default is 60s. + #backoff.max: 60s + + # Configure HTTP request timeout before failing an request to Elasticsearch. + #timeout: 90 + + # Use SSL settings for HTTPS. + #ssl.enabled: true + + # Configure SSL verification mode. If `none` is configured, all server hosts + # and certificates will be accepted. In this mode, SSL based connections are + # susceptible to man-in-the-middle attacks. Use only for testing. Default is + # `full`. + #ssl.verification_mode: full + + # List of supported/valid TLS versions. By default all TLS versions from 1.0 up to + # 1.2 are enabled. + #ssl.supported_protocols: [TLSv1.0, TLSv1.1, TLSv1.2] + + # SSL configuration. The default is off. + # List of root certificates for HTTPS server verifications + #ssl.certificate_authorities: ["/etc/pki/root/ca.pem"] + + # Certificate for SSL client authentication + #ssl.certificate: "/etc/pki/client/cert.pem" + + # Client certificate key + #ssl.key: "/etc/pki/client/cert.key" + + # Optional passphrase for decrypting the certificate key. + #ssl.key_passphrase: '' + + # Configure cipher suites to be used for SSL connections + #ssl.cipher_suites: [] + + # Configure curve types for ECDHE-based cipher suites + #ssl.curve_types: [] + + # Configure what types of renegotiation are supported. Valid options are + # never, once, and freely. Default is never. + #ssl.renegotiation: never + + #metrics.period: 10s + #state.period: 1m + +#================================ HTTP Endpoint ====================================== +# Each beat can expose internal metrics through a HTTP endpoint. For security +# reasons the endpoint is disabled by default. This feature is currently experimental. +# Stats can be access through http://localhost:5066/stats . For pretty JSON output +# append ?pretty to the URL. + +# Defines if the HTTP endpoint is enabled. +#http.enabled: false + +# The HTTP endpoint will bind to this hostname or IP address. It is recommended to use only localhost. +#http.host: localhost + +# Port on which the HTTP endpoint will bind. Default is 5066. +#http.port: 5066 + +#============================= Process Security ================================ + +# Enable or disable seccomp system call filtering on Linux. Default is enabled. +#seccomp.enabled: true diff --git a/devenv/docker/blocks/elastic7/docker-compose.yaml b/devenv/docker/blocks/elastic7/docker-compose.yaml new file mode 100644 index 0000000000000..3ef922c890c3f --- /dev/null +++ b/devenv/docker/blocks/elastic7/docker-compose.yaml @@ -0,0 +1,23 @@ +# You need to run 'sysctl -w vm.max_map_count=262144' on the host machine + + elasticsearch7: + image: docker.elastic.co/elasticsearch/elasticsearch-oss:7.0.0 + command: elasticsearch -E "discovery.type=single-node" + ports: + - "12200:9200" + - "12300:9300" + + fake-elastic7-data: + image: grafana/fake-data-gen + network_mode: bridge + environment: + FD_DATASOURCE: elasticsearch7 + FD_PORT: 12200 + + filebeat7: + image: docker.elastic.co/beats/filebeat-oss:7.0.0 + command: filebeat -e -strict.perms=false + volumes: + - ./docker/blocks/elastic7/filebeat.yml:/usr/share/filebeat/filebeat.yml:ro + - /var/log:/var/log:ro + - ../data/log:/var/log/grafana:ro diff --git a/devenv/docker/blocks/elastic7/elasticsearch.yml b/devenv/docker/blocks/elastic7/elasticsearch.yml new file mode 100644 index 0000000000000..c57b2c1290809 --- /dev/null +++ b/devenv/docker/blocks/elastic7/elasticsearch.yml @@ -0,0 +1,2 @@ +script.inline: on +script.indexed: on diff --git a/devenv/docker/blocks/elastic7/filebeat.yml b/devenv/docker/blocks/elastic7/filebeat.yml new file mode 100644 index 0000000000000..ef78ad8e28fc4 --- /dev/null +++ b/devenv/docker/blocks/elastic7/filebeat.yml @@ -0,0 +1,1978 @@ +######################## Filebeat Configuration ############################ + +# This file is a full configuration example documenting all non-deprecated +# options in comments. For a shorter configuration example, that contains only +# the most common options, please see filebeat.yml in the same directory. +# +# You can find the full configuration reference here: +# https://www.elastic.co/guide/en/beats/filebeat/index.html + + +#========================== Modules configuration ============================ +filebeat.modules: + +#------------------------------- System Module ------------------------------- +#- module: system + # Syslog + #syslog: + #enabled: true + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + + # Convert the timestamp to UTC. Requires Elasticsearch >= 6.1. + #var.convert_timezone: false + + # Input configuration (advanced). Any input configuration option + # can be added under this section. + #input: + + # Authorization logs + #auth: + #enabled: true + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + + # Convert the timestamp to UTC. Requires Elasticsearch >= 6.1. + #var.convert_timezone: false + + # Input configuration (advanced). Any input configuration option + # can be added under this section. + #input: + +#------------------------------- Apache2 Module ------------------------------ +#- module: apache2 + # Access logs + #access: + #enabled: true + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + + # Input configuration (advanced). Any input configuration option + # can be added under this section. + #input: + + # Error logs + #error: + #enabled: true + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + + # Input configuration (advanced). Any input configuration option + # can be added under this section. + #input: + +#------------------------------- Auditd Module ------------------------------- +#- module: auditd + #log: + #enabled: true + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + + # Input configuration (advanced). Any input configuration option + # can be added under this section. + #input: + +#---------------------------- elasticsearch Module --------------------------- +- module: elasticsearch + # Server log + server: + enabled: true + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + + # Convert the timestamp to UTC. Requires Elasticsearch >= 6.1. + #var.convert_timezone: false + + gc: + enabled: true + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + + audit: + enabled: true + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + + # Convert the timestamp to UTC. Requires Elasticsearch >= 6.1. + #var.convert_timezone: false + + slowlog: + enabled: true + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + + # Convert the timestamp to UTC. Requires Elasticsearch >= 6.1. + #var.convert_timezone: false + + deprecation: + enabled: true + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + + # Convert the timestamp to UTC. Requires Elasticsearch >= 6.1. + #var.convert_timezone: false + + +#------------------------------- haproxy Module ------------------------------ +- module: haproxy + # All logs + log: + enabled: true + + # Set which input to use between syslog (default) or file. + #var.input: + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + +#------------------------------- Icinga Module ------------------------------- +#- module: icinga + # Main logs + #main: + #enabled: true + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + + # Input configuration (advanced). Any input configuration option + # can be added under this section. + #input: + + # Debug logs + #debug: + #enabled: true + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + + # Input configuration (advanced). Any input configuration option + # can be added under this section. + #input: + + # Startup logs + #startup: + #enabled: true + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + + # Input configuration (advanced). Any input configuration option + # can be added under this section. + #input: + +#--------------------------------- IIS Module -------------------------------- +#- module: iis + # Access logs + #access: + #enabled: true + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + + # Input configuration (advanced). Any input configuration option + # can be added under this section. + #input: + + # Error logs + #error: + #enabled: true + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + + # Input configuration (advanced). Any input configuration option + # can be added under this section. + #input: + +#-------------------------------- Kafka Module ------------------------------- +- module: kafka + # All logs + log: + enabled: true + + # Set custom paths for Kafka. If left empty, + # Filebeat will look under /opt. + #var.kafka_home: + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + + # Convert the timestamp to UTC. Requires Elasticsearch >= 6.1. + #var.convert_timezone: false + +#------------------------------- kibana Module ------------------------------- +- module: kibana + # All logs + log: + enabled: true + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + +#------------------------------ logstash Module ------------------------------ +#- module: logstash + # logs + #log: + #enabled: true + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + # var.paths: + + # Slow logs + #slowlog: + #enabled: true + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + +#------------------------------- mongodb Module ------------------------------ +#- module: mongodb + # Logs + #log: + #enabled: true + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + + # Input configuration (advanced). Any input configuration option + # can be added under this section. + #input: + +#-------------------------------- MySQL Module ------------------------------- +#- module: mysql + # Error logs + #error: + #enabled: true + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + + # Input configuration (advanced). Any input configuration option + # can be added under this section. + #input: + + # Slow logs + #slowlog: + #enabled: true + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + + # Input configuration (advanced). Any input configuration option + # can be added under this section. + #input: + +#-------------------------------- Nginx Module ------------------------------- +#- module: nginx + # Access logs + #access: + #enabled: true + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + + # Input configuration (advanced). Any input configuration option + # can be added under this section. + #input: + + # Convert the timestamp to UTC. Requires Elasticsearch >= 6.1. + #var.convert_timezone: false + + # Error logs + #error: + #enabled: true + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + + # Input configuration (advanced). Any input configuration option + # can be added under this section. + #input: + + # Convert the timestamp to UTC. Requires Elasticsearch >= 6.1. + #var.convert_timezone: false + +#------------------------------- Osquery Module ------------------------------ +- module: osquery + result: + enabled: true + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + + # If true, all fields created by this module are prefixed with + # `osquery.result`. Set to false to copy the fields in the root + # of the document. The default is true. + #var.use_namespace: true + +#----------------------------- PostgreSQL Module ----------------------------- +#- module: postgresql + # Logs + #log: + #enabled: true + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + + # Input configuration (advanced). Any input configuration option + # can be added under this section. + #input: + +#-------------------------------- Redis Module ------------------------------- +#- module: redis + # Main logs + #log: + #enabled: true + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: ["/var/log/redis/redis-server.log*"] + + # Slow logs, retrieved via the Redis API (SLOWLOG) + #slowlog: + #enabled: true + + # The Redis hosts to connect to. + #var.hosts: ["localhost:6379"] + + # Optional, the password to use when connecting to Redis. + #var.password: + +#------------------------------- Traefik Module ------------------------------ +#- module: traefik + # Access logs + #access: + #enabled: true + + # Set custom paths for the log files. If left empty, + # Filebeat will choose the paths depending on your OS. + #var.paths: + + # Input configuration (advanced). Any input configuration option + # can be added under this section. + #input: + + +#=========================== Filebeat inputs ============================= + +# List of inputs to fetch data. +filebeat.inputs: +# Each - is an input. Most options can be set at the input level, so +# you can use different inputs for various configurations. +# Below are the input specific configurations. + +# Type of the files. Based on this the way the file is read is decided. +# The different types cannot be mixed in one input +# +# Possible options are: +# * log: Reads every line of the log file (default) +# * stdin: Reads the standard in + +#------------------------------ Log input -------------------------------- +- type: log + enabled: false + paths: + - /var/log/*.log +- type: log + enabled: true + paths: + - /var/log/grafana/grafana.log + include_lines: ['lvl=info'] + fields: + app: grafana + level: info +- type: log + enabled: true + paths: + - /var/log/grafana/grafana.log + include_lines: ['lvl=eror'] + fields: + app: grafana + level: error +- type: log + enabled: true + paths: + - /var/log/grafana/grafana.log + include_lines: ['lvl=warn'] + fields: + app: grafana + level: warning +- type: log + enabled: true + paths: + - /var/log/grafana/grafana.log + include_lines: ['lvl=dbug'] + fields: + app: grafana + level: debug + +#- type: log + + # Change to true to enable this input configuration. + #enabled: false + + # Paths that should be crawled and fetched. Glob based paths. + # To fetch all ".log" files from a specific level of subdirectories + # /var/log/*/*.log can be used. + # For each file found under this path, a harvester is started. + # Make sure not file is defined twice as this can lead to unexpected behaviour. + #paths: + #- /var/log/*.log + #- c:\programdata\elasticsearch\logs\* + + # Configure the file encoding for reading files with international characters + # following the W3C recommendation for HTML5 (http://www.w3.org/TR/encoding). + # Some sample encodings: + # plain, utf-8, utf-16be-bom, utf-16be, utf-16le, big5, gb18030, gbk, + # hz-gb-2312, euc-kr, euc-jp, iso-2022-jp, shift-jis, ... + #encoding: plain + + + # Exclude lines. A list of regular expressions to match. It drops the lines that are + # matching any regular expression from the list. The include_lines is called before + # exclude_lines. By default, no lines are dropped. + #exclude_lines: ['^DBG'] + + # Include lines. A list of regular expressions to match. It exports the lines that are + # matching any regular expression from the list. The include_lines is called before + # exclude_lines. By default, all the lines are exported. + #include_lines: ['^ERR', '^WARN'] + + # Exclude files. A list of regular expressions to match. Filebeat drops the files that + # are matching any regular expression from the list. By default, no files are dropped. + #exclude_files: ['.gz$'] + + # Optional additional fields. These fields can be freely picked + # to add additional information to the crawled log files for filtering + #fields: + # level: debug + # review: 1 + + # Set to true to store the additional fields as top level fields instead + # of under the "fields" sub-dictionary. In case of name conflicts with the + # fields added by Filebeat itself, the custom fields overwrite the default + # fields. + #fields_under_root: false + + # Ignore files which were modified more then the defined timespan in the past. + # ignore_older is disabled by default, so no files are ignored by setting it to 0. + # Time strings like 2h (2 hours), 5m (5 minutes) can be used. + #ignore_older: 0 + + # How often the input checks for new files in the paths that are specified + # for harvesting. Specify 1s to scan the directory as frequently as possible + # without causing Filebeat to scan too frequently. Default: 10s. + #scan_frequency: 10s + + # Defines the buffer size every harvester uses when fetching the file + #harvester_buffer_size: 16384 + + # Maximum number of bytes a single log event can have + # All bytes after max_bytes are discarded and not sent. The default is 10MB. + # This is especially useful for multiline log messages which can get large. + #max_bytes: 10485760 + + ### Recursive glob configuration + + # Expand "**" patterns into regular glob patterns. + #recursive_glob.enabled: true + + ### JSON configuration + + # Decode JSON options. Enable this if your logs are structured in JSON. + # JSON key on which to apply the line filtering and multiline settings. This key + # must be top level and its value must be string, otherwise it is ignored. If + # no text key is defined, the line filtering and multiline features cannot be used. + #json.message_key: + + # By default, the decoded JSON is placed under a "json" key in the output document. + # If you enable this setting, the keys are copied top level in the output document. + #json.keys_under_root: false + + # If keys_under_root and this setting are enabled, then the values from the decoded + # JSON object overwrite the fields that Filebeat normally adds (type, source, offset, etc.) + # in case of conflicts. + #json.overwrite_keys: false + + # If this setting is enabled, Filebeat adds a "error.message" and "error.key: json" key in case of JSON + # unmarshaling errors or when a text key is defined in the configuration but cannot + # be used. + #json.add_error_key: false + + ### Multiline options + + # Multiline can be used for log messages spanning multiple lines. This is common + # for Java Stack Traces or C-Line Continuation + + # The regexp Pattern that has to be matched. The example pattern matches all lines starting with [ + #multiline.pattern: ^\[ + + # Defines if the pattern set under pattern should be negated or not. Default is false. + #multiline.negate: false + + # Match can be set to "after" or "before". It is used to define if lines should be append to a pattern + # that was (not) matched before or after or as long as a pattern is not matched based on negate. + # Note: After is the equivalent to previous and before is the equivalent to to next in Logstash + #multiline.match: after + + # The maximum number of lines that are combined to one event. + # In case there are more the max_lines the additional lines are discarded. + # Default is 500 + #multiline.max_lines: 500 + + # After the defined timeout, an multiline event is sent even if no new pattern was found to start a new event + # Default is 5s. + #multiline.timeout: 5s + + # Setting tail_files to true means filebeat starts reading new files at the end + # instead of the beginning. If this is used in combination with log rotation + # this can mean that the first entries of a new file are skipped. + #tail_files: false + + # The Ingest Node pipeline ID associated with this input. If this is set, it + # overwrites the pipeline option from the Elasticsearch output. + #pipeline: + + # If symlinks is enabled, symlinks are opened and harvested. The harvester is opening the + # original for harvesting but will report the symlink name as source. + #symlinks: false + + # Backoff values define how aggressively filebeat crawls new files for updates + # The default values can be used in most cases. Backoff defines how long it is waited + # to check a file again after EOF is reached. Default is 1s which means the file + # is checked every second if new lines were added. This leads to a near real time crawling. + # Every time a new line appears, backoff is reset to the initial value. + #backoff: 1s + + # Max backoff defines what the maximum backoff time is. After having backed off multiple times + # from checking the files, the waiting time will never exceed max_backoff independent of the + # backoff factor. Having it set to 10s means in the worst case a new line can be added to a log + # file after having backed off multiple times, it takes a maximum of 10s to read the new line + #max_backoff: 10s + + # The backoff factor defines how fast the algorithm backs off. The bigger the backoff factor, + # the faster the max_backoff value is reached. If this value is set to 1, no backoff will happen. + # The backoff value will be multiplied each time with the backoff_factor until max_backoff is reached + #backoff_factor: 2 + + # Max number of harvesters that are started in parallel. + # Default is 0 which means unlimited + #harvester_limit: 0 + + ### Harvester closing options + + # Close inactive closes the file handler after the predefined period. + # The period starts when the last line of the file was, not the file ModTime. + # Time strings like 2h (2 hours), 5m (5 minutes) can be used. + #close_inactive: 5m + + # Close renamed closes a file handler when the file is renamed or rotated. + # Note: Potential data loss. Make sure to read and understand the docs for this option. + #close_renamed: false + + # When enabling this option, a file handler is closed immediately in case a file can't be found + # any more. In case the file shows up again later, harvesting will continue at the last known position + # after scan_frequency. + #close_removed: true + + # Closes the file handler as soon as the harvesters reaches the end of the file. + # By default this option is disabled. + # Note: Potential data loss. Make sure to read and understand the docs for this option. + #close_eof: false + + ### State options + + # Files for the modification data is older then clean_inactive the state from the registry is removed + # By default this is disabled. + #clean_inactive: 0 + + # Removes the state for file which cannot be found on disk anymore immediately + #clean_removed: true + + # Close timeout closes the harvester after the predefined time. + # This is independent if the harvester did finish reading the file or not. + # By default this option is disabled. + # Note: Potential data loss. Make sure to read and understand the docs for this option. + #close_timeout: 0 + + # Defines if inputs is enabled + #enabled: true + +#----------------------------- Stdin input ------------------------------- +# Configuration to use stdin input +#- type: stdin + +#------------------------- Redis slowlog input --------------------------- +# Experimental: Config options for the redis slow log input +#- type: redis + #enabled: false + + # List of hosts to pool to retrieve the slow log information. + #hosts: ["localhost:6379"] + + # How often the input checks for redis slow log. + #scan_frequency: 10s + + # Timeout after which time the input should return an error + #timeout: 1s + + # Network type to be used for redis connection. Default: tcp + #network: tcp + + # Max number of concurrent connections. Default: 10 + #maxconn: 10 + + # Redis AUTH password. Empty by default. + #password: foobared + +#------------------------------ Udp input -------------------------------- +# Experimental: Config options for the udp input +#- type: udp + #enabled: false + + # Maximum size of the message received over UDP + #max_message_size: 10KiB + +#------------------------------ TCP input -------------------------------- +# Experimental: Config options for the TCP input +#- type: tcp + #enabled: false + + # The host and port to receive the new event + #host: "localhost:9000" + + # Character used to split new message + #line_delimiter: "\n" + + # Maximum size in bytes of the message received over TCP + #max_message_size: 20MiB + + # The number of seconds of inactivity before a remote connection is closed. + #timeout: 300s + + # Use SSL settings for TCP. + #ssl.enabled: true + + # List of supported/valid TLS versions. By default all TLS versions 1.0 up to + # 1.2 are enabled. + #ssl.supported_protocols: [TLSv1.0, TLSv1.1, TLSv1.2] + + # SSL configuration. By default is off. + # List of root certificates for client verifications + #ssl.certificate_authorities: ["/etc/pki/root/ca.pem"] + + # Certificate for SSL server authentication. + #ssl.certificate: "/etc/pki/client/cert.pem" + + # Server Certificate Key, + #ssl.key: "/etc/pki/client/cert.key" + + # Optional passphrase for decrypting the Certificate Key. + #ssl.key_passphrase: '' + + # Configure cipher suites to be used for SSL connections. + #ssl.cipher_suites: [] + + # Configure curve types for ECDHE based cipher suites. + #ssl.curve_types: [] + + # Configure what types of client authentication are supported. Valid options + # are `none`, `optional`, and `required`. Default is required. + #ssl.client_authentication: "required" + +#------------------------------ Syslog input -------------------------------- +# Experimental: Config options for the Syslog input +# Accept RFC3164 formatted syslog event via UDP. +#- type: syslog + #enabled: false + #protocol.udp: + # The host and port to receive the new event + #host: "localhost:9000" + + # Maximum size of the message received over UDP + #max_message_size: 10KiB + +# Accept RFC3164 formatted syslog event via TCP. +#- type: syslog + #enabled: false + + #protocol.tcp: + # The host and port to receive the new event + #host: "localhost:9000" + + # Character used to split new message + #line_delimiter: "\n" + + # Maximum size in bytes of the message received over TCP + #max_message_size: 20MiB + + # The number of seconds of inactivity before a remote connection is closed. + #timeout: 300s + + # Use SSL settings for TCP. + #ssl.enabled: true + + # List of supported/valid TLS versions. By default all TLS versions 1.0 up to + # 1.2 are enabled. + #ssl.supported_protocols: [TLSv1.0, TLSv1.1, TLSv1.2] + + # SSL configuration. By default is off. + # List of root certificates for client verifications + #ssl.certificate_authorities: ["/etc/pki/root/ca.pem"] + + # Certificate for SSL server authentication. + #ssl.certificate: "/etc/pki/client/cert.pem" + + # Server Certificate Key, + #ssl.key: "/etc/pki/client/cert.key" + + # Optional passphrase for decrypting the Certificate Key. + #ssl.key_passphrase: '' + + # Configure cipher suites to be used for SSL connections. + #ssl.cipher_suites: [] + + # Configure curve types for ECDHE based cipher suites. + #ssl.curve_types: [] + + # Configure what types of client authentication are supported. Valid options + # are `none`, `optional`, and `required`. Default is required. + #ssl.client_authentication: "required" + +#------------------------------ Docker input -------------------------------- +# Experimental: Docker input reads and parses `json-file` logs from Docker +#- type: docker + #enabled: false + + # Combine partial lines flagged by `json-file` format + #combine_partials: true + + # Use this to read from all containers, replace * with a container id to read from one: + #containers: + # stream: all # can be all, stdout or stderr + # ids: + # - '*' + +#========================== Filebeat autodiscover ============================== + +# Autodiscover allows you to detect changes in the system and spawn new modules +# or inputs as they happen. + +#filebeat.autodiscover: + # List of enabled autodiscover providers +# providers: +# - type: docker +# templates: +# - condition: +# equals.docker.container.image: busybox +# config: +# - type: log +# paths: +# - /var/lib/docker/containers/${data.docker.container.id}/*.log + +#========================= Filebeat global options ============================ + +# Name of the registry file. If a relative path is used, it is considered relative to the +# data path. +#filebeat.registry_file: ${path.data}/registry + +# The permissions mask to apply on registry file. The default value is 0600. +# Must be a valid Unix-style file permissions mask expressed in octal notation. +# This option is not supported on Windows. +#filebeat.registry_file_permissions: 0600 + +# The timeout value that controls when registry entries are written to disk +# (flushed). When an unwritten update exceeds this value, it triggers a write to +# disk. When registry_flush is set to 0s, the registry is written to disk after +# each batch of events has been published successfully. The default value is 0s. +#filebeat.registry_flush: 0s + +# By default Ingest pipelines are not updated if a pipeline with the same ID +# already exists. If this option is enabled Filebeat overwrites pipelines +# everytime a new Elasticsearch connection is established. +#filebeat.overwrite_pipelines: false + +# How long filebeat waits on shutdown for the publisher to finish. +# Default is 0, not waiting. +#filebeat.shutdown_timeout: 0 + +# Enable filebeat config reloading +#filebeat.config: + #inputs: + #enabled: false + #path: inputs.d/*.yml + #reload.enabled: true + #reload.period: 10s + #modules: + #enabled: false + #path: modules.d/*.yml + #reload.enabled: true + #reload.period: 10s + +#================================ General ====================================== + +# The name of the shipper that publishes the network data. It can be used to group +# all the transactions sent by a single shipper in the web interface. +# If this options is not defined, the hostname is used. +#name: + +# The tags of the shipper are included in their own field with each +# transaction published. Tags make it easy to group servers by different +# logical properties. +#tags: ["service-X", "web-tier"] + +# Optional fields that you can specify to add additional information to the +# output. Fields can be scalar values, arrays, dictionaries, or any nested +# combination of these. +#fields: +# env: staging + +# If this option is set to true, the custom fields are stored as top-level +# fields in the output document instead of being grouped under a fields +# sub-dictionary. Default is false. +#fields_under_root: false + +# Internal queue configuration for buffering events to be published. +#queue: + # Queue type by name (default 'mem') + # The memory queue will present all available events (up to the outputs + # bulk_max_size) to the output, the moment the output is ready to server + # another batch of events. + #mem: + # Max number of events the queue can buffer. + #events: 4096 + + # Hints the minimum number of events stored in the queue, + # before providing a batch of events to the outputs. + # The default value is set to 2048. + # A value of 0 ensures events are immediately available + # to be sent to the outputs. + #flush.min_events: 2048 + + # Maximum duration after which events are available to the outputs, + # if the number of events stored in the queue is < min_flush_events. + #flush.timeout: 1s + + # The spool queue will store events in a local spool file, before + # forwarding the events to the outputs. + # + # Beta: spooling to disk is currently a beta feature. Use with care. + # + # The spool file is a circular buffer, which blocks once the file/buffer is full. + # Events are put into a write buffer and flushed once the write buffer + # is full or the flush_timeout is triggered. + # Once ACKed by the output, events are removed immediately from the queue, + # making space for new events to be persisted. + #spool: + # The file namespace configures the file path and the file creation settings. + # Once the file exists, the `size`, `page_size` and `prealloc` settings + # will have no more effect. + #file: + # Location of spool file. The default value is ${path.data}/spool.dat. + #path: "${path.data}/spool.dat" + + # Configure file permissions if file is created. The default value is 0600. + #permissions: 0600 + + # File size hint. The spool blocks, once this limit is reached. The default value is 100 MiB. + #size: 100MiB + + # The files page size. A file is split into multiple pages of the same size. The default value is 4KiB. + #page_size: 4KiB + + # If prealloc is set, the required space for the file is reserved using + # truncate. The default value is true. + #prealloc: true + + # Spool writer settings + # Events are serialized into a write buffer. The write buffer is flushed if: + # - The buffer limit has been reached. + # - The configured limit of buffered events is reached. + # - The flush timeout is triggered. + #write: + # Sets the write buffer size. + #buffer_size: 1MiB + + # Maximum duration after which events are flushed if the write buffer + # is not full yet. The default value is 1s. + #flush.timeout: 1s + + # Number of maximum buffered events. The write buffer is flushed once the + # limit is reached. + #flush.events: 16384 + + # Configure the on-disk event encoding. The encoding can be changed + # between restarts. + # Valid encodings are: json, ubjson, and cbor. + #codec: cbor + #read: + # Reader flush timeout, waiting for more events to become available, so + # to fill a complete batch as required by the outputs. + # If flush_timeout is 0, all available events are forwarded to the + # outputs immediately. + # The default value is 0s. + #flush.timeout: 0s + +# Sets the maximum number of CPUs that can be executing simultaneously. The +# default is the number of logical CPUs available in the system. +#max_procs: + +#================================ Processors =================================== + +# Processors are used to reduce the number of fields in the exported event or to +# enhance the event with external metadata. This section defines a list of +# processors that are applied one by one and the first one receives the initial +# event: +# +# event -> filter1 -> event1 -> filter2 ->event2 ... +# +# The supported processors are drop_fields, drop_event, include_fields, +# decode_json_fields, and add_cloud_metadata. +# +# For example, you can use the following processors to keep the fields that +# contain CPU load percentages, but remove the fields that contain CPU ticks +# values: +# +#processors: +#- include_fields: +# fields: ["cpu"] +#- drop_fields: +# fields: ["cpu.user", "cpu.system"] +# +# The following example drops the events that have the HTTP response code 200: +# +#processors: +#- drop_event: +# when: +# equals: +# http.code: 200 +# +# The following example renames the field a to b: +# +#processors: +#- rename: +# fields: +# - from: "a" +# to: "b" +# +# The following example tokenizes the string into fields: +# +#processors: +#- dissect: +# tokenizer: "%{key1} - %{key2}" +# field: "message" +# target_prefix: "dissect" +# +# The following example enriches each event with metadata from the cloud +# provider about the host machine. It works on EC2, GCE, DigitalOcean, +# Tencent Cloud, and Alibaba Cloud. +# +#processors: +#- add_cloud_metadata: ~ +# +# The following example enriches each event with the machine's local time zone +# offset from UTC. +# +#processors: +#- add_locale: +# format: offset +# +# The following example enriches each event with docker metadata, it matches +# given fields to an existing container id and adds info from that container: +# +#processors: +#- add_docker_metadata: +# host: "unix:///var/run/docker.sock" +# match_fields: ["system.process.cgroup.id"] +# match_pids: ["process.pid", "process.ppid"] +# match_source: true +# match_source_index: 4 +# match_short_id: false +# cleanup_timeout: 60 +# labels.dedot: false +# # To connect to Docker over TLS you must specify a client and CA certificate. +# #ssl: +# # certificate_authority: "/etc/pki/root/ca.pem" +# # certificate: "/etc/pki/client/cert.pem" +# # key: "/etc/pki/client/cert.key" +# +# The following example enriches each event with docker metadata, it matches +# container id from log path available in `source` field (by default it expects +# it to be /var/lib/docker/containers/*/*.log). +# +#processors: +#- add_docker_metadata: ~ +# +# The following example enriches each event with host metadata. +# +#processors: +#- add_host_metadata: +# netinfo.enabled: false +# +# The following example enriches each event with process metadata using +# process IDs included in the event. +# +#processors: +#- add_process_metadata: +# match_pids: ["system.process.ppid"] +# target: system.process.parent +# +# The following example decodes fields containing JSON strings +# and replaces the strings with valid JSON objects. +# +#processors: +#- decode_json_fields: +# fields: ["field1", "field2", ...] +# process_array: false +# max_depth: 1 +# target: "" +# overwrite_keys: false + +#============================= Elastic Cloud ================================== + +# These settings simplify using filebeat with the Elastic Cloud (https://cloud.elastic.co/). + +# The cloud.id setting overwrites the `output.elasticsearch.hosts` and +# `setup.kibana.host` options. +# You can find the `cloud.id` in the Elastic Cloud web UI. +#cloud.id: + +# The cloud.auth setting overwrites the `output.elasticsearch.username` and +# `output.elasticsearch.password` settings. The format is `<user>:<pass>`. +#cloud.auth: + +#================================ Outputs ====================================== + +# Configure what output to use when sending the data collected by the beat. + +#-------------------------- Elasticsearch output ------------------------------- +output.elasticsearch: + # Boolean flag to enable or disable the output module. + #enabled: true + + # Array of hosts to connect to. + # Scheme and port can be left out and will be set to the default (http and 9200) + # In case you specify and additional path, the scheme is required: http://localhost:9200/path + # IPv6 addresses should always be defined as: https://[2001:db8::1]:9200 + hosts: ["elasticsearch7:9200"] + + # Enabled ilm (beta) to use index lifecycle management instead daily indices. + #ilm.enabled: false + #ilm.rollover_alias: "filebeat" + #ilm.pattern: "{now/d}-000001" + + # Set gzip compression level. + #compression_level: 0 + + # Configure escaping HTML symbols in strings. + #escape_html: true + + # Optional protocol and basic auth credentials. + #protocol: "https" + #username: "elastic" + #password: "changeme" + + # Dictionary of HTTP parameters to pass within the URL with index operations. + #parameters: + #param1: value1 + #param2: value2 + + # Number of workers per Elasticsearch host. + #worker: 1 + + # Optional index name. The default is "filebeat" plus date + # and generates [filebeat-]YYYY.MM.DD keys. + # In case you modify this pattern you must update setup.template.name and setup.template.pattern accordingly. + index: "filebeat-%{+yyyy.MM.dd}" + + # Optional ingest node pipeline. By default no pipeline will be used. + #pipeline: "" + + # Optional HTTP path + #path: "/elasticsearch" + + # Custom HTTP headers to add to each request + #headers: + # X-My-Header: Contents of the header + + # Proxy server URL + #proxy_url: http://proxy:3128 + + # The number of times a particular Elasticsearch index operation is attempted. If + # the indexing operation doesn't succeed after this many retries, the events are + # dropped. The default is 3. + #max_retries: 3 + + # The maximum number of events to bulk in a single Elasticsearch bulk API index request. + # The default is 50. + #bulk_max_size: 50 + + # The number of seconds to wait before trying to reconnect to Elasticsearch + # after a network error. After waiting backoff.init seconds, the Beat + # tries to reconnect. If the attempt fails, the backoff timer is increased + # exponentially up to backoff.max. After a successful connection, the backoff + # timer is reset. The default is 1s. + #backoff.init: 1s + + # The maximum number of seconds to wait before attempting to connect to + # Elasticsearch after a network error. The default is 60s. + #backoff.max: 60s + + # Configure HTTP request timeout before failing a request to Elasticsearch. + #timeout: 90 + + # Use SSL settings for HTTPS. + #ssl.enabled: true + + # Configure SSL verification mode. If `none` is configured, all server hosts + # and certificates will be accepted. In this mode, SSL-based connections are + # susceptible to man-in-the-middle attacks. Use only for testing. Default is + # `full`. + #ssl.verification_mode: full + + # List of supported/valid TLS versions. By default all TLS versions from 1.0 up to + # 1.2 are enabled. + #ssl.supported_protocols: [TLSv1.0, TLSv1.1, TLSv1.2] + + # List of root certificates for HTTPS server verifications + #ssl.certificate_authorities: ["/etc/pki/root/ca.pem"] + + # Certificate for SSL client authentication + #ssl.certificate: "/etc/pki/client/cert.pem" + + # Client certificate key + #ssl.key: "/etc/pki/client/cert.key" + + # Optional passphrase for decrypting the certificate key. + #ssl.key_passphrase: '' + + # Configure cipher suites to be used for SSL connections + #ssl.cipher_suites: [] + + # Configure curve types for ECDHE-based cipher suites + #ssl.curve_types: [] + + # Configure what types of renegotiation are supported. Valid options are + # never, once, and freely. Default is never. + #ssl.renegotiation: never + + +#----------------------------- Logstash output --------------------------------- +#output.logstash: + # Boolean flag to enable or disable the output module. + #enabled: true + + # The Logstash hosts + #hosts: ["localhost:5044"] + + # Number of workers per Logstash host. + #worker: 1 + + # Set gzip compression level. + #compression_level: 3 + + # Configure escaping HTML symbols in strings. + #escape_html: true + + # Optional maximum time to live for a connection to Logstash, after which the + # connection will be re-established. A value of `0s` (the default) will + # disable this feature. + # + # Not yet supported for async connections (i.e. with the "pipelining" option set) + #ttl: 30s + + # Optionally load-balance events between Logstash hosts. Default is false. + #loadbalance: false + + # Number of batches to be sent asynchronously to Logstash while processing + # new batches. + #pipelining: 2 + + # If enabled only a subset of events in a batch of events is transferred per + # transaction. The number of events to be sent increases up to `bulk_max_size` + # if no error is encountered. + #slow_start: false + + # The number of seconds to wait before trying to reconnect to Logstash + # after a network error. After waiting backoff.init seconds, the Beat + # tries to reconnect. If the attempt fails, the backoff timer is increased + # exponentially up to backoff.max. After a successful connection, the backoff + # timer is reset. The default is 1s. + #backoff.init: 1s + + # The maximum number of seconds to wait before attempting to connect to + # Logstash after a network error. The default is 60s. + #backoff.max: 60s + + # Optional index name. The default index name is set to filebeat + # in all lowercase. + #index: 'filebeat' + + # SOCKS5 proxy server URL + #proxy_url: socks5://user:password@socks5-server:2233 + + # Resolve names locally when using a proxy server. Defaults to false. + #proxy_use_local_resolver: false + + # Enable SSL support. SSL is automatically enabled if any SSL setting is set. + #ssl.enabled: true + + # Configure SSL verification mode. If `none` is configured, all server hosts + # and certificates will be accepted. In this mode, SSL based connections are + # susceptible to man-in-the-middle attacks. Use only for testing. Default is + # `full`. + #ssl.verification_mode: full + + # List of supported/valid TLS versions. By default all TLS versions from 1.0 up to + # 1.2 are enabled. + #ssl.supported_protocols: [TLSv1.0, TLSv1.1, TLSv1.2] + + # Optional SSL configuration options. SSL is off by default. + # List of root certificates for HTTPS server verifications + #ssl.certificate_authorities: ["/etc/pki/root/ca.pem"] + + # Certificate for SSL client authentication + #ssl.certificate: "/etc/pki/client/cert.pem" + + # Client certificate key + #ssl.key: "/etc/pki/client/cert.key" + + # Optional passphrase for decrypting the Certificate Key. + #ssl.key_passphrase: '' + + # Configure cipher suites to be used for SSL connections + #ssl.cipher_suites: [] + + # Configure curve types for ECDHE-based cipher suites + #ssl.curve_types: [] + + # Configure what types of renegotiation are supported. Valid options are + # never, once, and freely. Default is never. + #ssl.renegotiation: never + + # The number of times to retry publishing an event after a publishing failure. + # After the specified number of retries, the events are typically dropped. + # Some Beats, such as Filebeat and Winlogbeat, ignore the max_retries setting + # and retry until all events are published. Set max_retries to a value less + # than 0 to retry until all events are published. The default is 3. + #max_retries: 3 + + # The maximum number of events to bulk in a single Logstash request. The + # default is 2048. + #bulk_max_size: 2048 + + # The number of seconds to wait for responses from the Logstash server before + # timing out. The default is 30s. + #timeout: 30s + +#------------------------------- Kafka output ---------------------------------- +#output.kafka: + # Boolean flag to enable or disable the output module. + #enabled: true + + # The list of Kafka broker addresses from which to fetch the cluster metadata. + # The cluster metadata contain the actual Kafka brokers events are published + # to. + #hosts: ["localhost:9092"] + + # The Kafka topic used for produced events. The setting can be a format string + # using any event field. To set the topic from document type use `%{[type]}`. + #topic: beats + + # The Kafka event key setting. Use format string to create a unique event key. + # By default no event key will be generated. + #key: '' + + # The Kafka event partitioning strategy. Default hashing strategy is `hash` + # using the `output.kafka.key` setting or randomly distributes events if + # `output.kafka.key` is not configured. + #partition.hash: + # If enabled, events will only be published to partitions with reachable + # leaders. Default is false. + #reachable_only: false + + # Configure alternative event field names used to compute the hash value. + # If empty `output.kafka.key` setting will be used. + # Default value is empty list. + #hash: [] + + # Authentication details. Password is required if username is set. + #username: '' + #password: '' + + # Kafka version filebeat is assumed to run against. Defaults to the "1.0.0". + #version: '1.0.0' + + # Configure JSON encoding + #codec.json: + # Pretty-print JSON event + #pretty: false + + # Configure escaping HTML symbols in strings. + #escape_html: true + + # Metadata update configuration. Metadata contains leader information + # used to decide which broker to use when publishing. + #metadata: + # Max metadata request retry attempts when cluster is in middle of leader + # election. Defaults to 3 retries. + #retry.max: 3 + + # Wait time between retries during leader elections. Default is 250ms. + #retry.backoff: 250ms + + # Refresh metadata interval. Defaults to every 10 minutes. + #refresh_frequency: 10m + + # The number of concurrent load-balanced Kafka output workers. + #worker: 1 + + # The number of times to retry publishing an event after a publishing failure. + # After the specified number of retries, events are typically dropped. + # Some Beats, such as Filebeat, ignore the max_retries setting and retry until + # all events are published. Set max_retries to a value less than 0 to retry + # until all events are published. The default is 3. + #max_retries: 3 + + # The maximum number of events to bulk in a single Kafka request. The default + # is 2048. + #bulk_max_size: 2048 + + # The number of seconds to wait for responses from the Kafka brokers before + # timing out. The default is 30s. + #timeout: 30s + + # The maximum duration a broker will wait for number of required ACKs. The + # default is 10s. + #broker_timeout: 10s + + # The number of messages buffered for each Kafka broker. The default is 256. + #channel_buffer_size: 256 + + # The keep-alive period for an active network connection. If 0s, keep-alives + # are disabled. The default is 0 seconds. + #keep_alive: 0 + + # Sets the output compression codec. Must be one of none, snappy and gzip. The + # default is gzip. + #compression: gzip + + # Set the compression level. Currently only gzip provides a compression level + # between 0 and 9. The default value is chosen by the compression algorithm. + #compression_level: 4 + + # The maximum permitted size of JSON-encoded messages. Bigger messages will be + # dropped. The default value is 1000000 (bytes). This value should be equal to + # or less than the broker's message.max.bytes. + #max_message_bytes: 1000000 + + # The ACK reliability level required from broker. 0=no response, 1=wait for + # local commit, -1=wait for all replicas to commit. The default is 1. Note: + # If set to 0, no ACKs are returned by Kafka. Messages might be lost silently + # on error. + #required_acks: 1 + + # The configurable ClientID used for logging, debugging, and auditing + # purposes. The default is "beats". + #client_id: beats + + # Enable SSL support. SSL is automatically enabled if any SSL setting is set. + #ssl.enabled: true + + # Optional SSL configuration options. SSL is off by default. + # List of root certificates for HTTPS server verifications + #ssl.certificate_authorities: ["/etc/pki/root/ca.pem"] + + # Configure SSL verification mode. If `none` is configured, all server hosts + # and certificates will be accepted. In this mode, SSL based connections are + # susceptible to man-in-the-middle attacks. Use only for testing. Default is + # `full`. + #ssl.verification_mode: full + + # List of supported/valid TLS versions. By default all TLS versions from 1.0 up to + # 1.2 are enabled. + #ssl.supported_protocols: [TLSv1.0, TLSv1.1, TLSv1.2] + + # Certificate for SSL client authentication + #ssl.certificate: "/etc/pki/client/cert.pem" + + # Client Certificate Key + #ssl.key: "/etc/pki/client/cert.key" + + # Optional passphrase for decrypting the Certificate Key. + #ssl.key_passphrase: '' + + # Configure cipher suites to be used for SSL connections + #ssl.cipher_suites: [] + + # Configure curve types for ECDHE-based cipher suites + #ssl.curve_types: [] + + # Configure what types of renegotiation are supported. Valid options are + # never, once, and freely. Default is never. + #ssl.renegotiation: never + +#------------------------------- Redis output ---------------------------------- +#output.redis: + # Boolean flag to enable or disable the output module. + #enabled: true + + # Configure JSON encoding + #codec.json: + # Pretty print json event + #pretty: false + + # Configure escaping HTML symbols in strings. + #escape_html: true + + # The list of Redis servers to connect to. If load-balancing is enabled, the + # events are distributed to the servers in the list. If one server becomes + # unreachable, the events are distributed to the reachable servers only. + #hosts: ["localhost:6379"] + + # The name of the Redis list or channel the events are published to. The + # default is filebeat. + #key: filebeat + + # The password to authenticate to Redis with. The default is no authentication. + #password: + + # The Redis database number where the events are published. The default is 0. + #db: 0 + + # The Redis data type to use for publishing events. If the data type is list, + # the Redis RPUSH command is used. If the data type is channel, the Redis + # PUBLISH command is used. The default value is list. + #datatype: list + + # The number of workers to use for each host configured to publish events to + # Redis. Use this setting along with the loadbalance option. For example, if + # you have 2 hosts and 3 workers, in total 6 workers are started (3 for each + # host). + #worker: 1 + + # If set to true and multiple hosts or workers are configured, the output + # plugin load balances published events onto all Redis hosts. If set to false, + # the output plugin sends all events to only one host (determined at random) + # and will switch to another host if the currently selected one becomes + # unreachable. The default value is true. + #loadbalance: true + + # The Redis connection timeout in seconds. The default is 5 seconds. + #timeout: 5s + + # The number of times to retry publishing an event after a publishing failure. + # After the specified number of retries, the events are typically dropped. + # Some Beats, such as Filebeat, ignore the max_retries setting and retry until + # all events are published. Set max_retries to a value less than 0 to retry + # until all events are published. The default is 3. + #max_retries: 3 + + # The number of seconds to wait before trying to reconnect to Redis + # after a network error. After waiting backoff.init seconds, the Beat + # tries to reconnect. If the attempt fails, the backoff timer is increased + # exponentially up to backoff.max. After a successful connection, the backoff + # timer is reset. The default is 1s. + #backoff.init: 1s + + # The maximum number of seconds to wait before attempting to connect to + # Redis after a network error. The default is 60s. + #backoff.max: 60s + + # The maximum number of events to bulk in a single Redis request or pipeline. + # The default is 2048. + #bulk_max_size: 2048 + + # The URL of the SOCKS5 proxy to use when connecting to the Redis servers. The + # value must be a URL with a scheme of socks5://. + #proxy_url: + + # This option determines whether Redis hostnames are resolved locally when + # using a proxy. The default value is false, which means that name resolution + # occurs on the proxy server. + #proxy_use_local_resolver: false + + # Enable SSL support. SSL is automatically enabled, if any SSL setting is set. + #ssl.enabled: true + + # Configure SSL verification mode. If `none` is configured, all server hosts + # and certificates will be accepted. In this mode, SSL based connections are + # susceptible to man-in-the-middle attacks. Use only for testing. Default is + # `full`. + #ssl.verification_mode: full + + # List of supported/valid TLS versions. By default all TLS versions 1.0 up to + # 1.2 are enabled. + #ssl.supported_protocols: [TLSv1.0, TLSv1.1, TLSv1.2] + + # Optional SSL configuration options. SSL is off by default. + # List of root certificates for HTTPS server verifications + #ssl.certificate_authorities: ["/etc/pki/root/ca.pem"] + + # Certificate for SSL client authentication + #ssl.certificate: "/etc/pki/client/cert.pem" + + # Client Certificate Key + #ssl.key: "/etc/pki/client/cert.key" + + # Optional passphrase for decrypting the Certificate Key. + #ssl.key_passphrase: '' + + # Configure cipher suites to be used for SSL connections + #ssl.cipher_suites: [] + + # Configure curve types for ECDHE based cipher suites + #ssl.curve_types: [] + + # Configure what types of renegotiation are supported. Valid options are + # never, once, and freely. Default is never. + #ssl.renegotiation: never + +#------------------------------- File output ----------------------------------- +#output.file: + # Boolean flag to enable or disable the output module. + #enabled: true + + # Configure JSON encoding + #codec.json: + # Pretty-print JSON event + #pretty: false + + # Configure escaping HTML symbols in strings. + #escape_html: true + + # Path to the directory where to save the generated files. The option is + # mandatory. + #path: "/tmp/filebeat" + + # Name of the generated files. The default is `filebeat` and it generates + # files: `filebeat`, `filebeat.1`, `filebeat.2`, etc. + #filename: filebeat + + # Maximum size in kilobytes of each file. When this size is reached, and on + # every filebeat restart, the files are rotated. The default value is 10240 + # kB. + #rotate_every_kb: 10000 + + # Maximum number of files under path. When this number of files is reached, + # the oldest file is deleted and the rest are shifted from last to first. The + # default is 7 files. + #number_of_files: 7 + + # Permissions to use for file creation. The default is 0600. + #permissions: 0600 + + +#----------------------------- Console output --------------------------------- +#output.console: + # Boolean flag to enable or disable the output module. + #enabled: true + + # Configure JSON encoding + #codec.json: + # Pretty-print JSON event + #pretty: false + + # Configure escaping HTML symbols in strings. + #escape_html: true + +#================================= Paths ====================================== + +# The home path for the filebeat installation. This is the default base path +# for all other path settings and for miscellaneous files that come with the +# distribution (for example, the sample dashboards). +# If not set by a CLI flag or in the configuration file, the default for the +# home path is the location of the binary. +#path.home: + +# The configuration path for the filebeat installation. This is the default +# base path for configuration files, including the main YAML configuration file +# and the Elasticsearch template file. If not set by a CLI flag or in the +# configuration file, the default for the configuration path is the home path. +#path.config: ${path.home} + +# The data path for the filebeat installation. This is the default base path +# for all the files in which filebeat needs to store its data. If not set by a +# CLI flag or in the configuration file, the default for the data path is a data +# subdirectory inside the home path. +#path.data: ${path.home}/data + +# The logs path for a filebeat installation. This is the default location for +# the Beat's log files. If not set by a CLI flag or in the configuration file, +# the default for the logs path is a logs subdirectory inside the home path. +#path.logs: ${path.home}/logs + +#================================ Keystore ========================================== +# Location of the Keystore containing the keys and their sensitive values. +#keystore.path: "${path.config}/beats.keystore" + +#============================== Dashboards ===================================== +# These settings control loading the sample dashboards to the Kibana index. Loading +# the dashboards are disabled by default and can be enabled either by setting the +# options here, or by using the `-setup` CLI flag or the `setup` command. +#setup.dashboards.enabled: false + +# The directory from where to read the dashboards. The default is the `kibana` +# folder in the home path. +#setup.dashboards.directory: ${path.home}/kibana + +# The URL from where to download the dashboards archive. It is used instead of +# the directory if it has a value. +#setup.dashboards.url: + +# The file archive (zip file) from where to read the dashboards. It is used instead +# of the directory when it has a value. +#setup.dashboards.file: + +# In case the archive contains the dashboards from multiple Beats, this lets you +# select which one to load. You can load all the dashboards in the archive by +# setting this to the empty string. +#setup.dashboards.beat: filebeat + +# The name of the Kibana index to use for setting the configuration. Default is ".kibana" +#setup.dashboards.kibana_index: .kibana + +# The Elasticsearch index name. This overwrites the index name defined in the +# dashboards and index pattern. Example: testbeat-* +#setup.dashboards.index: + +# Always use the Kibana API for loading the dashboards instead of autodetecting +# how to install the dashboards by first querying Elasticsearch. +#setup.dashboards.always_kibana: false + +# If true and Kibana is not reachable at the time when dashboards are loaded, +# it will retry to reconnect to Kibana instead of exiting with an error. +#setup.dashboards.retry.enabled: false + +# Duration interval between Kibana connection retries. +#setup.dashboards.retry.interval: 1s + +# Maximum number of retries before exiting with an error, 0 for unlimited retrying. +#setup.dashboards.retry.maximum: 0 + + +#============================== Template ===================================== + +# A template is used to set the mapping in Elasticsearch +# By default template loading is enabled and the template is loaded. +# These settings can be adjusted to load your own template or overwrite existing ones. + +# Set to false to disable template loading. +#setup.template.enabled: true + +# Template name. By default the template name is "filebeat-%{[beat.version]}" +# The template name and pattern has to be set in case the Elasticsearch index pattern is modified. +setup.template.name: "filebeat" + +# Template pattern. By default the template pattern is "-%{[beat.version]}-*" to apply to the default index settings. +# The first part is the version of the beat and then -* is used to match all daily indices. +# The template name and pattern has to be set in case the Elasticsearch index pattern is modified. +setup.template.pattern: "filebeat-*" + +# Path to fields.yml file to generate the template +#setup.template.fields: "${path.config}/fields.yml" + +# A list of fields to be added to the template and Kibana index pattern. Also +# specify setup.template.overwrite: true to overwrite the existing template. +# This setting is experimental. +#setup.template.append_fields: +#- name: field_name +# type: field_type + +# Enable JSON template loading. If this is enabled, the fields.yml is ignored. +#setup.template.json.enabled: false + +# Path to the JSON template file +#setup.template.json.path: "${path.config}/template.json" + +# Name under which the template is stored in Elasticsearch +#setup.template.json.name: "" + +# Overwrite existing template +#setup.template.overwrite: false + +# Elasticsearch template settings +setup.template.settings: + + # A dictionary of settings to place into the settings.index dictionary + # of the Elasticsearch template. For more details, please check + # https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping.html + #index: + #number_of_shards: 1 + #codec: best_compression + #number_of_routing_shards: 30 + + # A dictionary of settings for the _source field. For more details, please check + # https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-source-field.html + #_source: + #enabled: false + +#============================== Kibana ===================================== + +# Starting with Beats version 6.0.0, the dashboards are loaded via the Kibana API. +# This requires a Kibana endpoint configuration. +setup.kibana: + + # Kibana Host + # Scheme and port can be left out and will be set to the default (http and 5601) + # In case you specify and additional path, the scheme is required: http://localhost:5601/path + # IPv6 addresses should always be defined as: https://[2001:db8::1]:5601 + #host: "localhost:5601" + + # Optional protocol and basic auth credentials. + #protocol: "https" + #username: "elastic" + #password: "changeme" + + # Optional HTTP path + #path: "" + + # Use SSL settings for HTTPS. Default is true. + #ssl.enabled: true + + # Configure SSL verification mode. If `none` is configured, all server hosts + # and certificates will be accepted. In this mode, SSL based connections are + # susceptible to man-in-the-middle attacks. Use only for testing. Default is + # `full`. + #ssl.verification_mode: full + + # List of supported/valid TLS versions. By default all TLS versions from 1.0 up to + # 1.2 are enabled. + #ssl.supported_protocols: [TLSv1.0, TLSv1.1, TLSv1.2] + + # SSL configuration. The default is off. + # List of root certificates for HTTPS server verifications + #ssl.certificate_authorities: ["/etc/pki/root/ca.pem"] + + # Certificate for SSL client authentication + #ssl.certificate: "/etc/pki/client/cert.pem" + + # Client certificate key + #ssl.key: "/etc/pki/client/cert.key" + + # Optional passphrase for decrypting the certificate key. + #ssl.key_passphrase: '' + + # Configure cipher suites to be used for SSL connections + #ssl.cipher_suites: [] + + # Configure curve types for ECDHE-based cipher suites + #ssl.curve_types: [] + + + +#================================ Logging ====================================== +# There are four options for the log output: file, stderr, syslog, eventlog +# The file output is the default. + +# Sets log level. The default log level is info. +# Available log levels are: error, warning, info, debug +#logging.level: info + +# Enable debug output for selected components. To enable all selectors use ["*"] +# Other available selectors are "beat", "publish", "service" +# Multiple selectors can be chained. +#logging.selectors: [ ] + +# Send all logging output to syslog. The default is false. +#logging.to_syslog: false + +# Send all logging output to Windows Event Logs. The default is false. +#logging.to_eventlog: false + +# If enabled, filebeat periodically logs its internal metrics that have changed +# in the last period. For each metric that changed, the delta from the value at +# the beginning of the period is logged. Also, the total values for +# all non-zero internal metrics are logged on shutdown. The default is true. +#logging.metrics.enabled: true + +# The period after which to log the internal metrics. The default is 30s. +#logging.metrics.period: 30s + +# Logging to rotating files. Set logging.to_files to false to disable logging to +# files. +logging.to_files: true +logging.files: + # Configure the path where the logs are written. The default is the logs directory + # under the home path (the binary location). + #path: /var/log/filebeat + + # The name of the files where the logs are written to. + #name: filebeat + + # Configure log file size limit. If limit is reached, log file will be + # automatically rotated + #rotateeverybytes: 10485760 # = 10MB + + # Number of rotated log files to keep. Oldest files will be deleted first. + #keepfiles: 7 + + # The permissions mask to apply when rotating log files. The default value is 0600. + # Must be a valid Unix-style file permissions mask expressed in octal notation. + #permissions: 0600 + + # Enable log file rotation on time intervals in addition to size-based rotation. + # Intervals must be at least 1s. Values of 1m, 1h, 24h, 7*24h, 30*24h, and 365*24h + # are boundary-aligned with minutes, hours, days, weeks, months, and years as + # reported by the local system clock. All other intervals are calculated from the + # Unix epoch. Defaults to disabled. + #interval: 0 + +# Set to true to log messages in JSON format. +#logging.json: false + + +#============================== Xpack Monitoring ===================================== +# filebeat can export internal metrics to a central Elasticsearch monitoring cluster. +# This requires xpack monitoring to be enabled in Elasticsearch. +# The reporting is disabled by default. + +# Set to true to enable the monitoring reporter. +#xpack.monitoring.enabled: false + +# Uncomment to send the metrics to Elasticsearch. Most settings from the +# Elasticsearch output are accepted here as well. Any setting that is not set is +# automatically inherited from the Elasticsearch output configuration, so if you +# have the Elasticsearch output configured, you can simply uncomment the +# following line, and leave the rest commented out. +#xpack.monitoring.elasticsearch: + + # Array of hosts to connect to. + # Scheme and port can be left out and will be set to the default (http and 9200) + # In case you specify and additional path, the scheme is required: http://localhost:9200/path + # IPv6 addresses should always be defined as: https://[2001:db8::1]:9200 + #hosts: ["localhost:9200"] + + # Set gzip compression level. + #compression_level: 0 + + # Optional protocol and basic auth credentials. + #protocol: "https" + #username: "beats_system" + #password: "changeme" + + # Dictionary of HTTP parameters to pass within the URL with index operations. + #parameters: + #param1: value1 + #param2: value2 + + # Custom HTTP headers to add to each request + #headers: + # X-My-Header: Contents of the header + + # Proxy server url + #proxy_url: http://proxy:3128 + + # The number of times a particular Elasticsearch index operation is attempted. If + # the indexing operation doesn't succeed after this many retries, the events are + # dropped. The default is 3. + #max_retries: 3 + + # The maximum number of events to bulk in a single Elasticsearch bulk API index request. + # The default is 50. + #bulk_max_size: 50 + + # The number of seconds to wait before trying to reconnect to Elasticsearch + # after a network error. After waiting backoff.init seconds, the Beat + # tries to reconnect. If the attempt fails, the backoff timer is increased + # exponentially up to backoff.max. After a successful connection, the backoff + # timer is reset. The default is 1s. + #backoff.init: 1s + + # The maximum number of seconds to wait before attempting to connect to + # Elasticsearch after a network error. The default is 60s. + #backoff.max: 60s + + # Configure HTTP request timeout before failing an request to Elasticsearch. + #timeout: 90 + + # Use SSL settings for HTTPS. + #ssl.enabled: true + + # Configure SSL verification mode. If `none` is configured, all server hosts + # and certificates will be accepted. In this mode, SSL based connections are + # susceptible to man-in-the-middle attacks. Use only for testing. Default is + # `full`. + #ssl.verification_mode: full + + # List of supported/valid TLS versions. By default all TLS versions from 1.0 up to + # 1.2 are enabled. + #ssl.supported_protocols: [TLSv1.0, TLSv1.1, TLSv1.2] + + # SSL configuration. The default is off. + # List of root certificates for HTTPS server verifications + #ssl.certificate_authorities: ["/etc/pki/root/ca.pem"] + + # Certificate for SSL client authentication + #ssl.certificate: "/etc/pki/client/cert.pem" + + # Client certificate key + #ssl.key: "/etc/pki/client/cert.key" + + # Optional passphrase for decrypting the certificate key. + #ssl.key_passphrase: '' + + # Configure cipher suites to be used for SSL connections + #ssl.cipher_suites: [] + + # Configure curve types for ECDHE-based cipher suites + #ssl.curve_types: [] + + # Configure what types of renegotiation are supported. Valid options are + # never, once, and freely. Default is never. + #ssl.renegotiation: never + + #metrics.period: 10s + #state.period: 1m + +#================================ HTTP Endpoint ====================================== +# Each beat can expose internal metrics through a HTTP endpoint. For security +# reasons the endpoint is disabled by default. This feature is currently experimental. +# Stats can be access through http://localhost:5066/stats . For pretty JSON output +# append ?pretty to the URL. + +# Defines if the HTTP endpoint is enabled. +#http.enabled: false + +# The HTTP endpoint will bind to this hostname or IP address. It is recommended to use only localhost. +#http.host: localhost + +# Port on which the HTTP endpoint will bind. Default is 5066. +#http.port: 5066 + +#============================= Process Security ================================ + +# Enable or disable seccomp system call filtering on Linux. Default is enabled. +#seccomp.enabled: true diff --git a/devenv/docker/blocks/openldap/notes.md b/devenv/docker/blocks/openldap/notes.md index 65155423616d5..fb41308597068 100644 --- a/devenv/docker/blocks/openldap/notes.md +++ b/devenv/docker/blocks/openldap/notes.md @@ -2,7 +2,7 @@ Any ldif files added to the prepopulate subdirectory will be automatically imported into the OpenLdap database. -The ldif files add three users, `ldapviewer`, `ldapeditor` and `ldapadmin`. Two groups, `admins` and `users`, are added that correspond with the group mappings in the default conf/ldap.toml. `ldapadmin` is a member of `admins` and `ldapeditor` is a member of `users`. +The ldif files add eight users, `ldap-admin`, `ldap-editor`, `ldap-viewer`, `ldap-carl`, `ldap-daniel`, `ldap-leo`, `ldap-tobias` and `ldap-torkel`. Two groups, `admins` and `users`, are added that correspond with the group mappings in the default conf/ldap.toml. `ldap-admin` is a member of `admins` and `ldap-editor` is a member of `users`. Note that users that are added here need to specify a `memberOf` attribute manually as well as the `member` attribute for the group. The `memberOf` module usually does this automatically (if you add a group in Apache Directory Studio for example) but this does not work in the entrypoint script as it uses the `slapadd` command to add entries before the server has started and before the `memberOf` module is loaded. @@ -39,7 +39,5 @@ frontend ldap-daniel editors ldap-editors - - no groups ldap-viewer diff --git a/docs/sources/administration/provisioning.md b/docs/sources/administration/provisioning.md index d34def097018c..da95a311635bf 100644 --- a/docs/sources/administration/provisioning.md +++ b/docs/sources/administration/provisioning.md @@ -30,33 +30,19 @@ Checkout the [configuration](/installation/configuration) page for more informat ### Using Environment Variables -All options in the configuration file (listed below) can be overridden -using environment variables using the syntax: +It is possible to use environment variable interpolation in all 3 provisioning config types. Allowed syntax +is either `$ENV_VAR_NAME` or `${ENV_VAR_NAME}` and can be used only for values not for keys or bigger parts +of the configs. It is not available in the dashboards definition files just the dashboard provisioning +configuration. +Example: -```bash -GF__ -``` - -Where the section name is the text within the brackets. Everything -should be upper case and `.` should be replaced by `_`. For example, given these configuration settings: - -```bash -# default section -instance_name = ${HOSTNAME} - -[security] -admin_user = admin - -[auth.google] -client_secret = 0ldS3cretKey -``` - -Overriding will be done like so: - -```bash -export GF_DEFAULT_INSTANCE_NAME=my-instance -export GF_SECURITY_ADMIN_USER=true -export GF_AUTH_GOOGLE_CLIENT_SECRET=newS3cretKey +```yaml +datasources: +- name: Graphite + url: http://localhost:$PORT + user: $USER + secureJsonData: + password: $PASSWORD ```
@@ -107,7 +93,7 @@ datasources: orgId: 1 # url url: http://localhost:8080 - # database password, if used + # Deprecated, use secureJsonData.password password: # database user, if used user: @@ -117,7 +103,7 @@ datasources: basicAuth: # basic auth username basicAuthUser: - # basic auth password + # Deprecated, use secureJsonData.basicAuthPassword basicAuthPassword: # enable/disable with credentials headers withCredentials: @@ -133,6 +119,10 @@ datasources: tlsCACert: "..." tlsClientCert: "..." tlsClientKey: "..." + # database password, if used + password: + # basic auth password + basicAuthPassword: version: 1 # allow users to edit datasources from the UI. editable: false @@ -156,7 +146,7 @@ Since not all datasources have the same configuration settings we only have the | tlsSkipVerify | boolean | *All* | Controls whether a client verifies the server's certificate chain and host name. | | graphiteVersion | string | Graphite | Graphite version | | timeInterval | string | Prometheus, Elasticsearch, InfluxDB, MySQL, PostgreSQL & MSSQL | Lowest interval/step value that should be used for this data source | -| esVersion | number | Elasticsearch | Elasticsearch version as a number (2/5/56/60) | +| esVersion | number | Elasticsearch | Elasticsearch version as a number (2/5/56/60/70) | | timeField | string | Elasticsearch | Which field that should be used as timestamp | | interval | string | Elasticsearch | Index date time format. nil(No Pattern), 'Hourly', 'Daily', 'Weekly', 'Monthly' or 'Yearly' | | authType | string | Cloudwatch | Auth provider. keys/credentials/arn | @@ -184,8 +174,8 @@ Secure json data is a map of settings that will be encrypted with [secret key](/ | tlsCACert | string | *All* |CA cert for out going requests | | tlsClientCert | string | *All* |TLS Client cert for outgoing requests | | tlsClientKey | string | *All* |TLS Client key for outgoing requests | -| password | string | PostgreSQL | password | -| user | string | PostgreSQL | user | +| password | string | *All* | password | +| basicAuthPassword | string | *All* | password for basic authentication | | accessKey | string | Cloudwatch | Access key for connecting to Cloudwatch | | secretKey | string | Cloudwatch | Secret key for connecting to Cloudwatch | @@ -199,13 +189,24 @@ The dashboard provider config file looks somewhat like this: apiVersion: 1 providers: + # provider name - name: 'default' + # org id. will default to orgId 1 if not specified orgId: 1 + # name of the dashboard folder. Required folder: '' + # folder UID. will be automatically generated if not specified + folderUid: '' + # provider type. Required type: file + # disable dashboard deletion disableDeletion: false - updateIntervalSeconds: 10 #how often Grafana will scan for changed dashboards + # enable dashboard editing + editable: true + # how often Grafana will scan for changed dashboards + updateIntervalSeconds: 10 options: + # path to dashboard files on disk. Required path: /var/lib/grafana/dashboards ``` @@ -397,7 +398,7 @@ The following sections detail the supported settings for each alert notification | ---- | | apiKey | | apiUrl | -[ autoClose ] +| autoClose | #### Alert notification `telegram` @@ -421,3 +422,10 @@ The following sections detail the supported settings for each alert notification | url | | username | | password | + +#### Alert notification `googlechat` + +| Name | +| ---- | +| url | + diff --git a/docs/sources/alerting/notifications.md b/docs/sources/alerting/notifications.md index 8aafdb0362cae..28d1c8802164a 100644 --- a/docs/sources/alerting/notifications.md +++ b/docs/sources/alerting/notifications.md @@ -27,7 +27,7 @@ can configure and setup a new Notification Channel. You specify a name and a type, and type specific options. You can also test the notification to make sure it's setup correctly. -### Send on all alerts +### Default (send on all alerts) When checked, this option will notify for all alert rules - existing and new. @@ -165,25 +165,28 @@ Once these two properties are set, you can send the alerts to Kafka for further Notifications can be sent by setting up an incoming webhook in Google Hangouts chat. Configuring such a webhook is described [here](https://developers.google.com/hangouts/chat/how-tos/webhooks). -### All supported notifier +### All supported notifiers -Name | Type |Support images +Name | Type | Supports images -----|------------ | ------ -Slack | `slack` | yes -Pagerduty | `pagerduty` | yes +DingDing | `dingding` | yes, external only +Discord | `discord` | yes Email | `email` | yes -Webhook | `webhook` | link -Kafka | `kafka` | no -Google Hangouts Chat | `googlechat` | yes -Hipchat | `hipchat` | yes -VictorOps | `victorops` | yes -Sensu | `sensu` | yes -OpsGenie | `opsgenie` | yes -Threema | `threema` | yes -Pushover | `pushover` | no -Telegram | `telegram` | no -Line | `line` | no -Prometheus Alertmanager | `prometheus-alertmanager` | no +Google Hangouts Chat | `googlechat` | yes, external only +Hipchat | `hipchat` | yes, external only +Kafka | `kafka` | yes, external only +Line | `line` | yes, external only +Microsoft Teams | `teams` | yes, external only +OpsGenie | `opsgenie` | yes, external only +Pagerduty | `pagerduty` | yes, external only +Prometheus Alertmanager | `prometheus-alertmanager` | yes, external only +Pushover | `pushover` | yes +Sensu | `sensu` | yes, external only +Slack | `slack` | yes +Telegram | `telegram` | yes +Threema | `threema` | yes, external only +VictorOps | `victorops` | yes, external only +Webhook | `webhook` | yes, external only # Enable images in notifications {#external-image-store} @@ -192,9 +195,7 @@ Amazon S3, Webdav, Google Cloud Storage and Azure Blob Storage. So to set that u Be aware that some notifiers requires public access to the image to be able to include it in the notification. So make sure to enable public access to the images. If you're using local image uploader, your Grafana instance need to be accessible by the internet. -Currently only the Email Channels attaches images if no external image store is specified. To include images in alert notifications for other channels then you need to set up an external image store. - -This is an optional requirement. You can get Slack and email notifications without setting this up. +Notification services which need public image access are marked as 'external only'. # Configure the link back to Grafana from alert notifications diff --git a/docs/sources/features/datasources/cloudwatch.md b/docs/sources/features/datasources/cloudwatch.md index 9c7fd5207c31c..7a00b377122e8 100644 --- a/docs/sources/features/datasources/cloudwatch.md +++ b/docs/sources/features/datasources/cloudwatch.md @@ -29,9 +29,10 @@ Name | Description ------------ | ------------- *Name* | The data source name. This is how you refer to the data source in panels & queries. *Default* | Default data source means that it will be pre-selected for new panels. -*Credentials* profile name | Specify the name of the profile to use (if you use `~/.aws/credentials` file), leave blank for default. *Default Region* | Used in query editor to set region (can be changed on per query basis) *Custom Metrics namespace* | Specify the CloudWatch namespace of Custom metrics +*Auth Provider* | Specify the provider to get credentials. +*Credentials* profile name | Specify the name of the profile to use (if you use `~/.aws/credentials` file), leave blank for default. *Assume Role Arn* | Specify the ARN of the role to assume ## Authentication @@ -85,6 +86,16 @@ Here is a minimal policy example: } ``` +### AWS credentials +If Auth Provider is `Credentials file`, Grafana try to get credentials by following order. + +- Environment variables. (`AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`) +- Hard-code credentials. +- Shared credentials file. +- IAM role for Amazon EC2. + +Checkout AWS docs on [Configuring the AWS SDK for Go](https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html) + ### AWS credentials file Create a file at `~/.aws/credentials`. That is the `HOME` path for user running grafana-server. diff --git a/docs/sources/features/datasources/elasticsearch.md b/docs/sources/features/datasources/elasticsearch.md index aa60eb7cbc15f..b7bec92577646 100644 --- a/docs/sources/features/datasources/elasticsearch.md +++ b/docs/sources/features/datasources/elasticsearch.md @@ -58,10 +58,12 @@ a time pattern for the index name or a wildcard. ### Elasticsearch version -Be sure to specify your Elasticsearch version in the version selection dropdown. This is very important as there are differences how queries are composed. -Currently the versions available is 2.x, 5.x, 5.6+ or 6.0+. 5.6+ means a version of 5.6 or less than 6.0. 6.0+ means a version of 6.0 or higher, 6.3.2 for example. +Be sure to specify your Elasticsearch version in the version selection dropdown. This is very important as there are differences on how queries are composed. +Currently the versions available are `2.x`, `5.x`, `5.6+`, `6.0+` or `7.0+`. The value `5.6+` means version 5.6 or higher, but lower than 6.0. The value `6.0+` means +version 6.0 or higher, but lower than 7.0. Finally, `7.0+` means version 7.0 or higher, but lower than 8.0. ### Min time interval + A lower limit for the auto group by time interval. Recommended to be set to write frequency, for example `1m` if your data is written every minute. This option can also be overridden/configured in a dashboard panel under data source options. It's important to note that this value **needs** to be formatted as a number followed by a valid time identifier, e.g. `1m` (1 minute) or `30s` (30 seconds). The following time identifiers are supported: diff --git a/docs/sources/features/datasources/prometheus.md b/docs/sources/features/datasources/prometheus.md index 2516be195f8cb..9a91b842a7997 100644 --- a/docs/sources/features/datasources/prometheus.md +++ b/docs/sources/features/datasources/prometheus.md @@ -69,13 +69,13 @@ types of template variables. Variable of the type _Query_ allows you to query Prometheus for a list of metrics, labels or label values. The Prometheus data source plugin provides the following functions you can use in the `Query` input field. -| Name | Description | -| ----------------------------- | ----------------------------------------------------------------------- | -| _label_names()_ | Returns a list of label names. | -| _label_values(label)_ | Returns a list of label values for the `label` in every metric. | -| _label_values(metric, label)_ | Returns a list of label values for the `label` in the specified metric. | -| _metrics(metric)_ | Returns a list of metrics matching the specified `metric` regex. | -| _query_result(query)_ | Returns a list of Prometheus query result for the `query`. | +| Name | Description | +| -------------------------------- | ----------------------------------------------------------------------- | +| _label_\__names()_ | Returns a list of label names. | +| _label_\__values(label)_ | Returns a list of label values for the `label` in every metric. | +| _label_\__values(metric, label)_ | Returns a list of label values for the `label` in the specified metric. | +| _metrics(metric)_ | Returns a list of metrics matching the specified `metric` regex. | +| _query_\__result(query)_ | Returns a list of Prometheus query result for the `query`. | For details of _metric names_, _label names_ and _label values_ are please refer to the [Prometheus documentation](http://prometheus.io/docs/concepts/data_model/#metric-names-and-labels). diff --git a/docs/sources/features/explore/index.md b/docs/sources/features/explore/index.md index bf5811baea6db..6774c071183ee 100644 --- a/docs/sources/features/explore/index.md +++ b/docs/sources/features/explore/index.md @@ -67,7 +67,7 @@ The autocomplete menu can be trigger by pressing Ctrl + Space. The Autocomplete Suggestions can appear under the query field - click on them to update your query with the suggested change. -* For counters (monotonously increasing metrics), a rate function will be suggested. +* For counters (monotonically increasing metrics), a rate function will be suggested. * For buckets, a histogram function will be suggested. * For recording rules, possible to expand the rules. diff --git a/docs/sources/http_api/admin.md b/docs/sources/http_api/admin.md index 1cb20a7f7e9d0..f96a69331fcde 100644 --- a/docs/sources/http_api/admin.md +++ b/docs/sources/http_api/admin.md @@ -447,3 +447,36 @@ Content-Type: application/json "message": "User auth token revoked" } ``` + +## Reload provisioning configurations + +`POST /api/admin/provisioning/dashboards/reload` + +`POST /api/admin/provisioning/datasources/reload` + +`POST /api/admin/provisioning/notifications/reload` + +Reloads the provisioning config files for specified type and provision entities again. It won't return +until the new provisioned entities are already stored in the database. In case of dashboards, it will stop +polling for changes in dashboard files and then restart it with new configs after returning. + +Only works with Basic Authentication (username and password). See [introduction](http://docs.grafana.org/http_api/admin/#admin-api) for an explanation. + +**Example Request**: + +```http +POST /api/admin/provisioning/dashboards/reload HTTP/1.1 +Accept: application/json +Content-Type: application/json +``` + +**Example Response**: + +```http +HTTP/1.1 200 +Content-Type: application/json + +{ + "message": "Dashboards config reloaded" +} +``` diff --git a/docs/sources/http_api/folder_dashboard_search.md b/docs/sources/http_api/folder_dashboard_search.md index 73b5dd90b8749..0a736a277b78d 100644 --- a/docs/sources/http_api/folder_dashboard_search.md +++ b/docs/sources/http_api/folder_dashboard_search.md @@ -23,7 +23,8 @@ Query parameters: - **dashboardIds** – List of dashboard id's to search for - **folderIds** – List of folder id's to search in for dashboards - **starred** – Flag indicating if only starred Dashboards should be returned -- **limit** – Limit the number of returned results +- **limit** – Limit the number of returned results (max 5000) +- **page** – Use this parameter to access hits beyond limit. Numbering starts at 1. limit param acts as page size. **Example request for retrieving folders and dashboards of the general folder**: @@ -95,4 +96,4 @@ Content-Type: application/json "uri":"db/production-overview" // deprecated in Grafana v5.0 } ] -``` \ No newline at end of file +``` diff --git a/docs/sources/http_api/index.md b/docs/sources/http_api/index.md index b29722548cbdc..b75f8d9384d0a 100644 --- a/docs/sources/http_api/index.md +++ b/docs/sources/http_api/index.md @@ -30,7 +30,7 @@ dashboards, creating users and updating data sources. * [Snapshot API]({{< relref "http_api/snapshot.md" >}}) * [Annotations API]({{< relref "http_api/annotations.md" >}}) * [Alerting API]({{< relref "http_api/alerting.md" >}}) -* [Alert Notification Channels API]({{< relref "http_api/alert_notification_channels.md" >}}) +* [Alert Notification Channels API]({{< relref "http_api/alerting_notification_channels.md" >}}) * [User API]({{< relref "http_api/user.md" >}}) * [Team API]({{< relref "http_api/team.md" >}}) * [Admin API]({{< relref "http_api/admin.md" >}}) diff --git a/docs/sources/http_api/playlist.md b/docs/sources/http_api/playlist.md index 7c33900969b58..18b9ac540c2d7 100644 --- a/docs/sources/http_api/playlist.md +++ b/docs/sources/http_api/playlist.md @@ -7,6 +7,7 @@ type = "docs" [menu.docs] name = "Playlist" parent = "http_api" +identifier = "http_api_playlist" +++ # Playlist API @@ -28,7 +29,7 @@ Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk Querystring Parameters: These parameters are used as querystring parameters. - + - **query** - Limit response to playlist having a name like this value. - **limit** - Limit response to *X* number of playlist. @@ -153,7 +154,7 @@ Content-Type: application/json "id": 5, "title":"my other dasboard" "order": 2, - + } ] ``` diff --git a/docs/sources/index.md b/docs/sources/index.md index a0b1ff42ea031..744b04203e432 100644 --- a/docs/sources/index.md +++ b/docs/sources/index.md @@ -3,7 +3,7 @@ title = "Grafana documentation" description = "Guides, Installation & Feature Documentation" keywords = ["grafana", "installation", "documentation"] type = "docs" -aliases = ["v1.1", "guides/reference/admin"] +aliases = ["v1.1", "guides/reference/admin", "v3.1"] +++ # Grafana Documentation diff --git a/docs/sources/installation/configuration.md b/docs/sources/installation/configuration.md index ae96ac44eb76f..6d58d200c9802 100644 --- a/docs/sources/installation/configuration.md +++ b/docs/sources/installation/configuration.md @@ -383,39 +383,6 @@ below. - [LDAP Authentication]({{< relref "auth/ldap.md" >}}) (auth.ldap) - [Auth Proxy]({{< relref "auth/auth-proxy.md" >}}) (auth.proxy) -## [session] - -### provider - -Valid values are `memory`, `file`, `mysql`, `postgres`, `memcache` or `redis`. Default is `file`. - -### provider_config - -This option should be configured differently depending on what type of -session provider you have configured. - -- **file:** session file path, e.g. `data/sessions` -- **mysql:** go-sql-driver/mysql dsn config string, e.g. `user:password@tcp(127.0.0.1:3306)/database_name` -- **postgres:** ex: `user=a password=b host=localhost port=5432 dbname=c sslmode=verify-full` -- **memcache:** ex: `127.0.0.1:11211` -- **redis:** ex: `addr=127.0.0.1:6379,pool_size=100,prefix=grafana`. For unix socket, use for example: `network=unix,addr=/var/run/redis/redis.sock,pool_size=100,db=grafana` - -Postgres valid `sslmode` are `disable`, `require`, `verify-ca`, and `verify-full` (default). - -### cookie_name - -The name of the Grafana session cookie. - -### cookie_secure - -Set to true if you host Grafana behind HTTPS only. Defaults to `false`. - -### session_life_time - -How long sessions lasts in seconds. Defaults to `86400` (24 hours). - -
- ## [dataproxy] ### logging @@ -604,7 +571,7 @@ basic auth password Path to JSON key file associated with a Google service account to authenticate and authorize. Service Account keys can be created and downloaded from https://console.developers.google.com/permissions/serviceaccounts. -Service Account should have "Storage Object Writer" role. +Service Account should have "Storage Object Writer" role. The access control model of the bucket needs to be "Set object-level and bucket-level permissions". Grafana itself will make the images public readable. ### bucket name Bucket Name on Google Cloud Storage. @@ -651,26 +618,66 @@ This limit will protect the server from render overloading and make sure notific value is `5`. -### evaluation_timeout_seconds +### evaluation_timeout_seconds -Default setting for alert calculation timeout. Default value is `30` +Default setting for alert calculation timeout. Default value is `30` ### notification_timeout_seconds -Default setting for alert notification timeout. Default value is `30` +Default setting for alert notification timeout. Default value is `30` ### max_attempts -Default setting for max attempts to sending alert notifications. Default value is `3` +Default setting for max attempts to sending alert notifications. Default value is `3` ## [panels] -### enable_alpha -Set to true if you want to test panels that are not yet ready for general usage. - ### disable_sanitize_html + If set to true Grafana will allow script tags in text panels. Not recommended as it enable XSS vulnerabilities. Default is false. This settings was introduced in Grafana v6.0. +## [plugins] + +### enable_alpha + +Set to true if you want to test alpha plugins that are not yet ready for general usage. + +
+ +# Removed options +Please note that these options have been removed. + +## [session] +**Removed starting from Grafana v6.2. Please use [remote_cache](#remote-cache) option instead.** + +### provider + +Valid values are `memory`, `file`, `mysql`, `postgres`, `memcache` or `redis`. Default is `file`. + +### provider_config + +This option should be configured differently depending on what type of +session provider you have configured. + +- **file:** session file path, e.g. `data/sessions` +- **mysql:** go-sql-driver/mysql dsn config string, e.g. `user:password@tcp(127.0.0.1:3306)/database_name` +- **postgres:** ex: `user=a password=b host=localhost port=5432 dbname=c sslmode=verify-full` +- **memcache:** ex: `127.0.0.1:11211` +- **redis:** ex: `addr=127.0.0.1:6379,pool_size=100,prefix=grafana`. For unix socket, use for example: `network=unix,addr=/var/run/redis/redis.sock,pool_size=100,db=grafana` + +Postgres valid `sslmode` are `disable`, `require`, `verify-ca`, and `verify-full` (default). + +### cookie_name + +The name of the Grafana session cookie. + +### cookie_secure + +Set to true if you host Grafana behind HTTPS only. Defaults to `false`. + +### session_life_time + +How long sessions lasts in seconds. Defaults to `86400` (24 hours). diff --git a/docs/sources/installation/debian.md b/docs/sources/installation/debian.md index dc522ce6111f4..c22d7814cb661 100644 --- a/docs/sources/installation/debian.md +++ b/docs/sources/installation/debian.md @@ -27,7 +27,7 @@ installation. ```bash wget -sudo apt-get install -y adduser libfontconfig +sudo apt-get install -y adduser libfontconfig1 sudo dpkg -i grafana__amd64.deb ``` @@ -35,7 +35,7 @@ Example: ```bash wget https://dl.grafana.com/oss/release/grafana_5.4.2_amd64.deb -sudo apt-get install -y adduser libfontconfig +sudo apt-get install -y adduser libfontconfig1 sudo dpkg -i grafana_5.4.2_amd64.deb ``` diff --git a/docs/sources/installation/index.md b/docs/sources/installation/index.md index a86f426dc13c6..62736311e6a33 100644 --- a/docs/sources/installation/index.md +++ b/docs/sources/installation/index.md @@ -3,7 +3,7 @@ title = "Installation" description = "Install guide for Grafana" keywords = ["grafana", "installation", "documentation"] type = "docs" -aliases = ["installation/installation/", "v2.1/installation/install/"] +aliases = ["installation/installation/", "v2.1/installation/install/", "install"] [menu.docs] name = "Installation" identifier = "installation" diff --git a/docs/sources/installation/upgrading.md b/docs/sources/installation/upgrading.md index 511d6117eb3d0..6d9974216bc50 100644 --- a/docs/sources/installation/upgrading.md +++ b/docs/sources/installation/upgrading.md @@ -148,3 +148,15 @@ login_maximum_lifetime_days = 1 ``` The default cookie name for storing the auth token is `grafana_session`. you can configure this with `login_cookie_name` in `[auth]` settings. + + +## Upgrading to v6.2 + +Datasources store passwords and basic auth passwords in secureJsonData encrypted by default. Existing datasource +will keep working with unencrypted passwords. If you want to migrate to encrypted storage for your existing datasources +you can do that by: +- For datasources created through UI, you need to go to datasource config, re enter the password or basic auth +password and save the datasource. +- For datasources created by provisioning, you need to update your config file and use secureJsonData.password or +secureJsonData.basicAuthPassword field. See [provisioning docs](/administration/provisioning) for example of current +configuration. diff --git a/docs/sources/plugins/developing/backend-plugins-guide.md b/docs/sources/plugins/developing/backend-plugins-guide.md new file mode 100644 index 0000000000000..2fda91a2e555c --- /dev/null +++ b/docs/sources/plugins/developing/backend-plugins-guide.md @@ -0,0 +1,288 @@ ++++ +title = "Developing Backend Plugins" +keywords = ["grafana", "plugins", "backend", "plugin", "backend-plugins", "documentation"] +type = "docs" +[menu.docs] +name = "Developing Backend Plugins" +parent = "developing" +weight = 5 ++++ + +# Backend Plugins + +Grafana added support for plugins in Grafana 3.0 and this enabled the Grafana community to create panel plugins and datasource plugins. It was wildly successful and has made Grafana much more useful as you can integrate it with anything and do any type of custom visualization that you want. However, these plugin hooks are on the frontend only and we also want to provide hooks into the Grafana backend to allow the community to extend and improve Grafana in new ways. + +Once Grafana introduced the alerting feature, external datasource plugins needed a backend component for the Grafana server to execute queries for evaluating alert rules (as the alerting engine cannot call frontend JavaScript code). So the the obvious first backend plugin type is the **Datasource backend plugin** and it is a new component for an existing datasource plugin. This new plugin type will enable alerting for external datasource plugins but can also be used for achieving different goals such as query caching, request proxying, custom authentication methods, and more. + +## Grafana's Backend Plugin System + +The backend plugin feature is implemented with the [HashiCorp plugin system](https://github.com/hashicorp/go-plugin) which is a Go plugin system over RPC. Grafana server launches each plugin as a subprocess and communicates with it over RPC. This approach has a number of benefits: + +- Plugins can't crash your grafana process: a panic in a plugin doesn't panic the server. +- Plugins are easy to develop: just write a Go application and `go build` (or use any other language which supports gRPC). +- Plugins can be relatively secure: The plugin only has access to the interfaces and args given to it, not to the entire memory space of the process. + +## Datasource Plugin Interface + +The plugin interface is very simple and described as a Go interface type in [Grafana](https://github.com/grafana/grafana/blob/6724aaeff9a332dc73b4ee0f8abe0621f7253142/pkg/tsdb/query_endpoint.go#L10-L12) and as a general [RPC service](https://github.com/grafana/grafana-plugin-model/blob/84176c64269d8060f99e750ee8aba6f062753336/datasource.proto#L96-L98) in the corresponding `.proto` (protocol buffer file): + +```go +type TsdbQueryEndpoint interface { + Query(ctx context.Context, ds *models.DataSource, query *TsdbQuery) (*Response, error) +} +``` + +```protobuf +service DatasourcePlugin { + rpc Query(DatasourceRequest) returns (DatasourceResponse); +} +``` + +Thus, a datasource plugin should only implement the `Query()` method. + +## Introduction to building a backend component for a plugin + +The [Simple JSON backend](https://github.com/grafana/simple-json-backend-datasource) datasource is a good example of writing a simple backend plugin in Go. Let's take a look at some key points. + +### Metadata + +The plugin needs to know it has a backend component, this is done in the `plugin.json` file by setting two fields: `backend` and `executable`. If you want to enable alerting for your datasource, set the `alerting` field to `true` as well. + +```json +{ + "id": "grafana-simple-json-backend-datasource", + "name": "Simple Json backend", + "type": "datasource", + + "metrics": true, + "annotations": true, + "backend": true, + "alerting": true, + "executable": "simple-json-plugin", + ... +} +``` + +`executable` should be the the the first part of the binary filename. The actual binary filename has 3 possible endings: + +- \_linux_amd64 +- \_darwin_amd64 +- \_windows_amd64.exe + +When Grafana loads the plugin binary, it uses the executable field plus the current OS (Grafana knows which OS it is running on) to load in the correct version of the plugin. So in Simple JSON the executable field is `simple-json-plugin` and the 3 binaries are named: + +- `simple-json-plugin_darwin_amd64` +- `simple-json-plugin_linux_amd64` +- `simple-json-plugin_windows_amd64.exe` + +The resulting plugin directory will look like this: + +```text +simple-json-backend-datasource/ +|-- dist/ +| |-- partials/ +| |-- module.js +| |-- plugin.json +| |-- simple-json-plugin_linux_amd64 +| |-- simple-json-plugin_darwin_amd64 +| |-- simple-json-plugin_windows_amd64.exe +... +``` + +### Plugin code + +A `pkg/` directory contains three `.go` files: + +- `plugin.go` - an entry point of the plugin. This file would be very similar for your datasource - you just need to change some details like the plugin name etc. +- `datasource.go` - contains `Query()` method implementation and other plugin logic. +- `models.go` - types for request and response specific to your datasource. + +The datasource type is declared in [`datasource.go`](https://github.com/grafana/simple-json-backend-datasource/blob/7927ff0db60c3402dbf954a454f19d7230e18deb/pkg/datasource.go#L21-L24): + +```go +package main + +import ( + plugin "github.com/hashicorp/go-plugin" +) + +type JsonDatasource struct { + plugin.NetRPCUnsupportedPlugin +} +``` + +The only requirement for the plugin type is that it should extend `plugin.NetRPCUnsupportedPlugin`. You can include more fields into your struct if you want to add some datasource-specific features, like logging, cache etc: + +```go +type JsonDatasource struct { + plugin.NetRPCUnsupportedPlugin + logger hclog.Logger +} +``` + +The main method you should implement is the [`Query()`](https://github.com/grafana/simple-json-backend-datasource/blob/7927ff0db60c3402dbf954a454f19d7230e18deb/pkg/datasource.go#L26): + +```go +func (t *JsonDatasource) Query(ctx context.Context, tsdbReq *datasource.DatasourceRequest) (*datasource.DatasourceResponse, error) { +... +``` + +#### Request format + +In order to call this method from the [frontend part of your datasource](https://github.com/grafana/simple-json-backend-datasource/blob/7927ff0db60c3402dbf954a454f19d7230e18deb/src/datasource.ts#L116), use the `/api/tsdb/query` endpoint: + +```js +class SimpleJSONDatasource { + ... + + doTsdbRequest(options) { + const tsdbRequest = { + from: options.range.from.valueOf().toString(), + to: options.range.to.valueOf().toString(), + queries: options.targets, + }; + + return this.backendSrv.datasourceRequest({ + url: '/api/tsdb/query', + method: 'POST', + data: tsdbRequest + }); + } +} +``` + +This endpoint gets data in the following format (see [pkg/api/metrics.go](https://github.com/grafana/grafana/blob/7b63913dc1d79da07f0329cf19dc4c2704ec488f/pkg/api/metrics.go#L16) and [pkg/api/dtos/models.go](https://github.com/grafana/grafana/blob/7b63913dc1d79da07f0329cf19dc4c2704ec488f/pkg/api/dtos/models.go#L43-L47)): + +```js +{ + from: "1555324640782", // Optional, time range from + to: "1555328240782", // Optional, time range to + queries: [ + { + datasourceId: 42, // Required + refId: "A", // Optional, default is "A" + maxDataPoints: 100, // Optional, default is 100 + intervalMs: 1000, // Optional, default is 1000 + + myFieldFoo: "bar", // Any other fields, + myFieldBar: "baz", // defined by user + ... + }, + ... + ] +} +``` + +There is only one query function but it is possible to move all your queries to the backend. In order to achieve this, you could add a kind of `queryType` field to your query model and check this type in the backend code. The Stackdriver and Cloudwatch core plugins have examples of supporting multiple types of queries if you need/want to do this: + +- Stackdriver: [pkg/tsdb/stackdriver/stackdriver.go](https://github.com/grafana/grafana/blob/6724aaeff9a332dc73b4ee0f8abe0621f7253142/pkg/tsdb/stackdriver/stackdriver.go#L75-L88) +- Cloudwatch: [pkg/tsdb/cloudwatch/cloudwatch.go](https://github.com/grafana/grafana/blob/7b63913dc1d79da07f0329cf19dc4c2704ec488f/pkg/tsdb/cloudwatch/cloudwatch.go#L62-L74) + +#### Response format + +Go types for the query response can be found in Grafana tsdb models ([pkg/tsdb/models.go](https://github.com/grafana/grafana/blob/7b63913dc1d79da07f0329cf19dc4c2704ec488f/pkg/tsdb/models.go#L22-L34)) or in the corresponding protocol buffer file ([datasource.proto](https://github.com/grafana/grafana-plugin-model/blob/84176c64269d8060f99e750ee8aba6f062753336/datasource.proto#L26-L36)) + +```protobuf +// datasource.proto + +message DatasourceResponse { + repeated QueryResult results = 1; +} + +message QueryResult { + string error = 1; + string refId = 2; + string metaJson = 3; + repeated TimeSeries series = 4; + repeated Table tables = 5; +} +``` + +```go +// pkg/tsdb/models.go + +type Response struct { + Results map[string]*QueryResult `json:"results"` + Message string `json:"message,omitempty"` +} + +type QueryResult struct { + Error error `json:"-"` + ErrorString string `json:"error,omitempty"` + RefId string `json:"refId"` + Meta *simplejson.Json `json:"meta,omitempty"` + Series TimeSeriesSlice `json:"series"` + Tables []*Table `json:"tables"` +} +``` + +The resulting JSON response which the frontend will receive looks like this: + +```js +results: { + A: { + refId: "A", + series: [ + { name: "series_1", points: [...] }, + { name: "series_2", points: [...] }, + ... + ], + tables: null, + // Request metadata (any arbitrary JSON). + // Optional, empty field will be omitted. + meta: {}, + // Error message. Optional, empty field will be omitted. + error: "Request failed", + } +} +``` + +### Logging + +Logs from the plugin will be automatically sent to the Grafana server and will appear in its log flow. Grafana server reads logs from the plugin's `stderr` stream, so with the standard `log` package you have to set output to `os.Stderr` first: + +```go +func main() { + log.SetOutput(os.Stderr) + log.Println("from plugin!") + ... +} +``` + +Another option for logging - using [go-hclog](https://github.com/hashicorp/go-hclog) package: + +```go +package main + +import ( + hclog "github.com/hashicorp/go-hclog" +) + +var pluginLogger = hclog.New(&hclog.LoggerOptions{ + Name: "simple-json-backend-datasource", + Level: hclog.LevelFromString("DEBUG"), +}) + +func main() { + pluginLogger.Debug("Running Simple JSON backend datasource") + ... +} +``` + +### Building the backend binary + +Building the binary depends on which OS you are using. + +For a Linux distro, the build command would be: + +```sh +go build -o ./dist/simple-json-plugin_linux_amd64 ./pkg +``` + +On Windows, the command would be: + +```sh +go build -o ./dist/simple-json-plugin_windows_amd64.exe ./pkg +``` + +Restart your Grafana server and then check the Grafana logs to make sure your plugin is loaded properly. diff --git a/docs/sources/reference/dashboard_folders.md b/docs/sources/reference/dashboard_folders.md index 2c287c6891b3f..2f7f3980561e2 100644 --- a/docs/sources/reference/dashboard_folders.md +++ b/docs/sources/reference/dashboard_folders.md @@ -47,6 +47,6 @@ The Dashboard Folder Page is similar to the Manage Dashboards page and is where Permissions can assigned to a folder and inherited by the containing dashboards. An Access Control List (ACL) is used where **Organization Role**, **Team** and Individual **User** can be assigned permissions. Read the - [Dashboard & Folder Permissions]({{< relref "administration/permissions.md#dashboard-folder-permissions" >}}) docs for more detail + [Dashboard & Folder Permissions]({{< relref "permissions/dashboard_folder_permissions.md" >}}) docs for more detail on the permission system. diff --git a/docs/sources/reference/dashboard_history.md b/docs/sources/reference/dashboard_history.md index 0f91347ae653b..18e700dfdbd6d 100644 --- a/docs/sources/reference/dashboard_history.md +++ b/docs/sources/reference/dashboard_history.md @@ -11,9 +11,9 @@ weight = 100 # Dashboard Version History -Whenever you save a version of your dashboard, a copy of that version is saved so that previous versions of your dashboard are never lost. A list of these versions is available by clicking the dashboard menu dropdown, and clicking "Version history". +Whenever you save a version of your dashboard, a copy of that version is saved so that previous versions of your dashboard are never lost. A list of these versions is available by entering the dashboard settings and then selecting "Versions" in the left side menu. - + The dashboard version history feature lets you compare and restore to previously saved dashboard versions. @@ -21,20 +21,20 @@ The dashboard version history feature lets you compare and restore to previously To compare two dashboard versions, select the two versions from the list that you wish to compare. Once selected, the "Compare versions" button will become clickable. Click the button to view the diff between the two versions. - + Upon clicking the button, you'll be brought to the diff view. By default, you'll see a textual summary of the changes, like in the image below. - + -If you want to view the diff of the raw JSON that represents your dashboard, you can do that as well by clicking the "JSON Diff" tab on the left. +If you want to view the diff of the raw JSON that represents your dashboard, you can do that as well by clicking the "View JSON Diff" button at the bottom. -If you want to restore to the version you are diffing against, you can do so by clicking the "Restore to version " button in the top right. +If you want to restore to the version you are diffing against, you can do so by clicking the "Restore to version \" button in the top right. ## Restoring to a previously saved dashboard version -If you need to restore to a previously saved dashboard version, you can do so by either clicking the "Restore" button on the right of a row in the dashboard version list, or by clicking the "Restore to version " button appearing in the diff view. Clicking the button will bring up the following popup prompting you to confirm the restoration. +If you need to restore to a previously saved dashboard version, you can do so by either clicking the "Restore" button on the right of a row in the dashboard version list, or by clicking the "Restore to version \" button appearing in the diff view. Clicking the button will bring up the following popup prompting you to confirm the restoration. - + After restoring to a previous version, a new version will be created containing the same exact data as the previous version, only with a different version number. This is indicated in the "Notes column" for the row in the new dashboard version. This is done simply to ensure your previous dashboard versions are not affected by the change. diff --git a/docs/sources/reference/playlist.md b/docs/sources/reference/playlist.md index 182e69eebd0f3..2a633f258fed7 100644 --- a/docs/sources/reference/playlist.md +++ b/docs/sources/reference/playlist.md @@ -4,6 +4,7 @@ keywords = ["grafana", "dashboard", "documentation", "playlist"] type = "docs" [menu.docs] parent = "dashboard_features" +identifier = "feature_playlist" weight = 4 +++ diff --git a/docs/sources/reference/sharing.md b/docs/sources/reference/sharing.md index 118fd3676df09..aebf76090f3a3 100644 --- a/docs/sources/reference/sharing.md +++ b/docs/sources/reference/sharing.md @@ -39,7 +39,7 @@ Click a panel title to open the panel menu, then click share in the panel menu t ### Direct Link Rendered Image -You also get a link to service side rendered PNG of the panel. Useful if you want to share an image of the panel. Please note that for OSX and Windows, you will need to ensure that a `phantomjs` binary is available under `tools/phantomjs/phantomjs`. For Linux, a `phantomjs` binary is included - however, you should ensure that any requisite libraries (e.g. libfontconfig) are available. +You also get a link to service side rendered PNG of the panel. Useful if you want to share an image of the panel. Please note that for OSX and Windows, you will need to ensure that a `phantomjs` binary is available under `tools/phantomjs/phantomjs`. For Linux, a `phantomjs` binary is included - however, you should ensure that any requisite libraries (e.g. libfontconfig1) are available. Example of a link to a server-side rendered PNG: @@ -58,7 +58,7 @@ http://play.grafana.org/render/dashboard-solo/db/grafana-play-home?orgId=1&panel You can embed a panel using an iframe on another web site. This tab will show you the html that you need to use. -> *Notice* This sharing require either anonymous access or setting [cookie_samesite]({{< relref "installation/configuration/#cookie-samesite" >}}) to none +> *Notice* This sharing require either anonymous access or setting [cookie_samesite]({{< relref "installation/configuration.md#cookie-samesite" >}}) to none Example: diff --git a/docs/sources/reference/templating.md b/docs/sources/reference/templating.md index 2be2b6863a9a1..e3fc4e2ca8f1a 100644 --- a/docs/sources/reference/templating.md +++ b/docs/sources/reference/templating.md @@ -57,7 +57,7 @@ Formats multi-value variable into a regex string. ```bash servers = ['test1.', 'test2'] String to interpolate: '${servers:regex}' -Interpolation result: '(test\.|test2)' +Interpolation result: '(test1\.|test2)' ``` ### Pipe @@ -66,7 +66,7 @@ Formats multi-value variable into a pipe-separated string. ```bash servers = ['test1.', 'test2'] String to interpolate: '${servers:pipe}' -Interpolation result: 'test.|test2' +Interpolation result: 'test1.|test2' ``` ### Csv @@ -75,7 +75,7 @@ Formats multi-value variable as a comma-separated string. ```bash servers = ['test1', 'test2'] String to interpolate: '${servers:csv}' -Interpolation result: 'test,test2' +Interpolation result: 'test1,test2' ``` ### Json diff --git a/docs/sources/reference/timerange.md b/docs/sources/reference/timerange.md index 4121ed8793102..03fcdda570855 100644 --- a/docs/sources/reference/timerange.md +++ b/docs/sources/reference/timerange.md @@ -53,7 +53,7 @@ From Dashboard settings, click the Timepicker tab. From here you can specify the ### Defining Now -Users often ask, [when will then be now](https://www.youtube.com/watch?v=VeZ9HhHU86o)? Grafana offers the ability to override the `now` value on a per dashboard basis. Most commonly, this feature is used to accommodate known delays in data aggregation to avoid null values. +Grafana offers the ability to override the `now` value on a per dashboard basis. Most commonly, this feature is used to accommodate known delays in data aggregation to avoid null values. ## Panel time overrides & timeshift diff --git a/docs/versions.json b/docs/versions.json index d1eab9afa5199..a0857a7f3afab 100644 --- a/docs/versions.json +++ b/docs/versions.json @@ -1,5 +1,6 @@ [ - { "version": "v6.0", "path": "/", "archived": false, "current": true }, + { "version": "v6.1", "path": "/", "archived": false, "current": true }, + { "version": "v6.0", "path": "/v6.0", "archived": true }, { "version": "v5.4", "path": "/v5.4", "archived": true }, { "version": "v5.3", "path": "/v5.3", "archived": true }, { "version": "v5.2", "path": "/v5.2", "archived": true }, diff --git a/go.mod b/go.mod new file mode 100644 index 0000000000000..fc72780af2f49 --- /dev/null +++ b/go.mod @@ -0,0 +1,85 @@ +module github.com/grafana/grafana + +go 1.12 + +require ( + github.com/BurntSushi/toml v0.3.1 + github.com/Unknwon/com v0.0.0-20190214221849-2d12a219ccaf + github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f + github.com/aws/aws-sdk-go v1.18.5 + github.com/benbjohnson/clock v0.0.0-20161215174838-7dc76406b6d3 + github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737 + github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd // indirect + github.com/codegangsta/cli v1.20.0 + github.com/davecgh/go-spew v1.1.1 + github.com/denisenkom/go-mssqldb v0.0.0-20190315220205-a8ed825ac853 + github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 // indirect + github.com/facebookgo/inject v0.0.0-20180706035515-f23751cae28b + github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 // indirect + github.com/facebookgo/structtag v0.0.0-20150214074306-217e25fb9691 // indirect + github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 // indirect + github.com/fatih/color v1.7.0 + github.com/go-macaron/binding v0.0.0-20170611065819-ac54ee249c27 + github.com/go-macaron/gzip v0.0.0-20160222043647-cad1c6580a07 + github.com/go-macaron/inject v0.0.0-20160627170012-d8a0b8677191 // indirect + github.com/go-macaron/session v0.0.0-20190131233854-0a0a789bf193 + github.com/go-sql-driver/mysql v1.4.1 + github.com/go-stack/stack v1.8.0 + github.com/go-xorm/core v0.6.2 + github.com/go-xorm/xorm v0.7.1 + github.com/gobwas/glob v0.2.3 + github.com/google/go-cmp v0.2.0 // indirect + github.com/gopherjs/gopherjs v0.0.0-20190411002643-bd77b112433e // indirect + github.com/gorilla/websocket v1.4.0 + github.com/gosimple/slug v1.4.2 + github.com/grafana/grafana-plugin-model v0.0.0-20180518082423-84176c64269d + github.com/hashicorp/go-hclog v0.8.0 + github.com/hashicorp/go-plugin v0.0.0-20190220160451-3f118e8ee104 + github.com/hashicorp/go-version v1.1.0 + github.com/inconshreveable/log15 v0.0.0-20180818164646-67afb5ed74ec + github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 // indirect + github.com/klauspost/compress v1.4.1 // indirect + github.com/klauspost/cpuid v1.2.0 // indirect + github.com/lib/pq v1.0.0 + github.com/mattn/go-colorable v0.1.1 // indirect + github.com/mattn/go-isatty v0.0.7 + github.com/mattn/go-sqlite3 v1.10.0 + github.com/onsi/ginkgo v1.8.0 // indirect + github.com/onsi/gomega v1.5.0 // indirect + github.com/opentracing/opentracing-go v1.1.0 + github.com/patrickmn/go-cache v2.1.0+incompatible + github.com/pkg/errors v0.8.1 + github.com/prometheus/client_golang v0.9.2 + github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 + github.com/prometheus/common v0.2.0 + github.com/rainycape/unidecode v0.0.0-20150907023854-cb7f23ec59be // indirect + github.com/robfig/cron v0.0.0-20180505203441-b41be1df6967 + github.com/sergi/go-diff v1.0.0 // indirect + github.com/smartystreets/assertions v0.0.0-20190401211740-f487f9de1cd3 // indirect + github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a + github.com/stretchr/testify v1.3.0 + github.com/teris-io/shortid v0.0.0-20171029131806-771a37caa5cf + github.com/uber-go/atomic v1.3.2 // indirect + github.com/uber/jaeger-client-go v2.16.0+incompatible + github.com/uber/jaeger-lib v2.0.0+incompatible // indirect + github.com/yudai/gojsondiff v1.0.0 + github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 // indirect + github.com/yudai/pp v2.0.1+incompatible // indirect + go.uber.org/atomic v1.3.2 // indirect + golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a // indirect + golang.org/x/net v0.0.0-20190415100556-4a65cf94b679 + golang.org/x/oauth2 v0.0.0-20190319182350-c85d3e98c914 + golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6 + golang.org/x/sys v0.0.0-20190415081028-16da32be82c5 // indirect + golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373 + gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect + gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d // indirect + gopkg.in/bufio.v1 v1.0.0-20140618132640-567b2bfa514e // indirect + gopkg.in/ini.v1 v1.42.0 + gopkg.in/ldap.v3 v3.0.2 + gopkg.in/macaron.v1 v1.3.2 + gopkg.in/mail.v2 v2.3.1 + gopkg.in/redis.v2 v2.3.2 + gopkg.in/square/go-jose.v2 v2.3.0 + gopkg.in/yaml.v2 v2.2.2 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000000000..55223ecbc74e8 --- /dev/null +++ b/go.sum @@ -0,0 +1,281 @@ +cloud.google.com/go v0.34.0 h1:eOI3/cP2VTU6uZLDYAoic+eyzzB9YyGmJ7eIjl8rOPg= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/Unknwon/com v0.0.0-20190214221849-2d12a219ccaf h1:g3hliyjkDSCLzNlOEc6Bd1dngsiIwPb9LfPuYUv+F+Y= +github.com/Unknwon/com v0.0.0-20190214221849-2d12a219ccaf/go.mod h1:voKvFVpXBJxdIPeqjoJuLK+UVcRlo/JLjeToGxPYu68= +github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f h1:HR5nRmUQgXrwqZOwZ2DAc/aCi3Bu3xENpspW935vxu0= +github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f/go.mod h1:f3HiCrHjHBdcm6E83vGaXh1KomZMA2P6aeo3hKx/wg0= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/aws/aws-sdk-go v1.18.5 h1:S6j4o4AoJpq98DRc7wQrQsPZg73NyntGtUj6K6NPnuY= +github.com/aws/aws-sdk-go v1.18.5/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/benbjohnson/clock v0.0.0-20161215174838-7dc76406b6d3 h1:wOysYcIdqv3WnvwqFFzrYCFALPED7qkUGaLXu359GSc= +github.com/benbjohnson/clock v0.0.0-20161215174838-7dc76406b6d3/go.mod h1:UMqtWQTnOe4byzwe7Zhwh8f8s+36uszN51sJrSIZlTE= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737 h1:rRISKWyXfVxvoa702s91Zl5oREZTrR3yv+tXrrX7G/g= +github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60= +github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= +github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= +github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w= +github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= +github.com/codegangsta/cli v1.20.0 h1:iX1FXEgwzd5+XN6wk5cVHOGQj6Q3Dcp20lUeS4lHNTw= +github.com/codegangsta/cli v1.20.0/go.mod h1:/qJNoX69yVSKu5o4jLyXAENLRyk1uhi7zkbQ3slBdOA= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/denisenkom/go-mssqldb v0.0.0-20181014144952-4e0d7dc8888f/go.mod h1:xN/JuLBIz4bjkxNmByTiV1IbhfnYb6oo99phBn4Eqhc= +github.com/denisenkom/go-mssqldb v0.0.0-20190315220205-a8ed825ac853 h1:tTngnoO/B6HQnJ+pK8tN7kEAhmhIfaJOutqq/A4/JTM= +github.com/denisenkom/go-mssqldb v0.0.0-20190315220205-a8ed825ac853/go.mod h1:xN/JuLBIz4bjkxNmByTiV1IbhfnYb6oo99phBn4Eqhc= +github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 h1:0JZ+dUmQeA8IIVUMzysrX4/AKuQwWhV2dYQuPZdvdSQ= +github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= +github.com/facebookgo/inject v0.0.0-20180706035515-f23751cae28b h1:V6c4/dSTNhSaNn4c5ulbakfv277qCvs7byFYv7P83iQ= +github.com/facebookgo/inject v0.0.0-20180706035515-f23751cae28b/go.mod h1:oO8UHw+fDHjDsk4CTy/E96WDzFUYozAtBAaGNoVL0+c= +github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A= +github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg= +github.com/facebookgo/structtag v0.0.0-20150214074306-217e25fb9691 h1:KnnwHN59Jxec0htA2pe/i0/WI9vxXLQifdhBrP3lqcQ= +github.com/facebookgo/structtag v0.0.0-20150214074306-217e25fb9691/go.mod h1:sKLL1iua/0etWfo/nPCmyz+v2XDMXy+Ho53W7RAuZNY= +github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 h1:E2s37DuLxFhQDg5gKsWoLBOB0n+ZW8s599zru8FJ2/Y= +github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0= +github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-macaron/binding v0.0.0-20170611065819-ac54ee249c27 h1:ieTTL9+RAtpcMaskwWNN19Vdrsl4X+k2CWsQijWNsAU= +github.com/go-macaron/binding v0.0.0-20170611065819-ac54ee249c27/go.mod h1:u+H6rwW+HQwUL+w5uaEJSpIlVZDye1o9MB4Su0JfRfM= +github.com/go-macaron/gzip v0.0.0-20160222043647-cad1c6580a07 h1:YSIA98PevNf1NtCa/J6cz7gjzpz99WVAOa9Eg0klKps= +github.com/go-macaron/gzip v0.0.0-20160222043647-cad1c6580a07/go.mod h1://cJFfDp/70L0oTNAMB+M8Jd0rpuIx/55iARuJ6StwE= +github.com/go-macaron/inject v0.0.0-20160627170012-d8a0b8677191 h1:NjHlg70DuOkcAMqgt0+XA+NHwtu66MkTVVgR4fFWbcI= +github.com/go-macaron/inject v0.0.0-20160627170012-d8a0b8677191/go.mod h1:VFI2o2q9kYsC4o7VP1HrEVosiZZTd+MVT3YZx4gqvJw= +github.com/go-macaron/session v0.0.0-20190131233854-0a0a789bf193 h1:z/nqwd+ql/r6Q3QGnwNd6B89UjPytM0be5pDQV9TuWw= +github.com/go-macaron/session v0.0.0-20190131233854-0a0a789bf193/go.mod h1:ScEJm9Gk+ez5JJTml5WlBIqavAfuE5nF8e4Gvyz/X+A= +github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-xorm/builder v0.3.2 h1:pSsZQRRzJNapKEAEhigw3xLmiLPeAYv5GFlpYZ8+a5I= +github.com/go-xorm/builder v0.3.2/go.mod h1:v8mE3MFBgtL+RGFNfUnAMUqqfk/Y4W5KuwCFQIEpQLk= +github.com/go-xorm/core v0.6.0/go.mod h1:d8FJ9Br8OGyQl12MCclmYBuBqqxsyeedpXciV5Myih8= +github.com/go-xorm/core v0.6.2 h1:EJLcSxf336POJr670wKB55Mah9f93xzvGYzNRgnT8/Y= +github.com/go-xorm/core v0.6.2/go.mod h1:bwPIfLdm/FzWgVUH8WPVlr+uJhscvNGFcaZKXsI3n2c= +github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:9wScpmSP5A3Bk8V3XHWUcJmYTh+ZnlHVyc+A4oZYS3Y= +github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM= +github.com/go-xorm/xorm v0.7.1 h1:Kj7mfuqctPdX60zuxP6EoEut0f3E6K66H6hcoxiHUMc= +github.com/go-xorm/xorm v0.7.1/go.mod h1:EHS1htMQFptzMaIHKyzqpHGw6C9Rtug75nsq6DA9unI= +github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= +github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg= +github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20190411002643-bd77b112433e h1:XWcjeEtTFTOVA9Fs1w7n2XBftk5ib4oZrhzWk0B+3eA= +github.com/gopherjs/gopherjs v0.0.0-20190411002643-bd77b112433e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gosimple/slug v1.4.2 h1:jDmprx3q/9Lfk4FkGZtvzDQ9Cj9eAmsjzeQGp24PeiQ= +github.com/gosimple/slug v1.4.2/go.mod h1:ER78kgg1Mv0NQGlXiDe57DpCyfbNywXXZ9mIorhxAf0= +github.com/grafana/grafana-plugin-model v0.0.0-20180518082423-84176c64269d h1:J3XXvgaMHzZ+gC/pStYNc6k+LjPuhPeAevwgN0AqTeM= +github.com/grafana/grafana-plugin-model v0.0.0-20180518082423-84176c64269d/go.mod h1:26i1retIKRnMtFVuSmJe6N6D1d1ifdzOMi507YjCYm4= +github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= +github.com/hashicorp/go-hclog v0.8.0 h1:z3ollgGRg8RjfJH6UVBaG54R70GFd++QOkvnJH3VSBY= +github.com/hashicorp/go-hclog v0.8.0/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-plugin v0.0.0-20190220160451-3f118e8ee104 h1:9iQ/zrTOJqzP+kH37s6xNb6T1RysiT7fnDD3DJbspVw= +github.com/hashicorp/go-plugin v0.0.0-20190220160451-3f118e8ee104/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY= +github.com/hashicorp/go-version v1.1.0 h1:bPIoEKD27tNdebFGGxxYwcL4nepeY4j1QP23PFRGzg0= +github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M= +github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/inconshreveable/log15 v0.0.0-20180818164646-67afb5ed74ec h1:CGkYB1Q7DSsH/ku+to+foV4agt2F2miquaLUgF6L178= +github.com/inconshreveable/log15 v0.0.0-20180818164646-67afb5ed74ec/go.mod h1:cOaXtrgN4ScfRrD9Bre7U1thNq5RtJ8ZoP4iXVGRj6o= +github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 h1:vr3AYkKovP8uR8AvSGGUK1IDqRa5lAAvEkZG1LKaCRc= +github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= +github.com/jackc/pgx v3.2.0+incompatible h1:0Vihzu20St42/UDsvZGdNE6jak7oi/UOeMzwMPHkgFY= +github.com/jackc/pgx v3.2.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 h1:uC1QfSlInpQF+M0ao65imhwqKnz3Q2z/d8PWZRMQvDM= +github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= +github.com/klauspost/compress v1.4.1 h1:8VMb5+0wMgdBykOV96DwNwKFQ+WTI4pzYURP99CcB9E= +github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/cpuid v1.2.0 h1:NMpwD2G9JSFOE1/TJjGSo5zG7Yb2bTe7eq1jH+irmeE= +github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A= +github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg= +github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= +github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.7 h1:UvyT9uN+3r7yLEYSlJsbQGdsaB/a0DlgWP3pql6iwOc= +github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o= +github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77 h1:7GoSOOW2jpsfkntVKaS2rAr1TJqfcxotyaUcuxoZSzg= +github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= +github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= +github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.2 h1:awm861/B8OKDd2I/6o1dy3ra4BamzKhYOiGItCeZ740= +github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.2.0 h1:kUZDBDTdBVBYBj5Tmh2NZLlF60mfjA27rM34b+cVwNU= +github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a h1:9a8MnZMP0X2nLJdBg+pBmGgkJlSaKC2KaQmTCk1XDtE= +github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/rainycape/unidecode v0.0.0-20150907023854-cb7f23ec59be h1:ta7tUOvsPHVHGom5hKW5VXNc2xZIkfCKP8iaqOyYtUQ= +github.com/rainycape/unidecode v0.0.0-20150907023854-cb7f23ec59be/go.mod h1:MIDFMn7db1kT65GmV94GzpX9Qdi7N/pQlwb+AN8wh+Q= +github.com/robfig/cron v0.0.0-20180505203441-b41be1df6967 h1:x7xEyJDP7Hv3LVgvWhzioQqbC/KtuUhTigKlH/8ehhE= +github.com/robfig/cron v0.0.0-20180505203441-b41be1df6967/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k= +github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 h1:pntxY8Ary0t43dCZ5dqY4YTJCObLY1kIXl0uzMv+7DE= +github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304 h1:Jpy1PXuP99tXNrhbq2BaPz9B+jNAvH1JPQQpG/9GCXY= +github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v0.0.0-20190401211740-f487f9de1cd3 h1:hBSHahWMEgzwRyS6dRpxY0XyjZsHyQ61s084wo5PJe0= +github.com/smartystreets/assertions v0.0.0-20190401211740-f487f9de1cd3/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= +github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a h1:pa8hGb/2YqsZKovtsgrwcDH1RZhVbTKCjLp47XpqCDs= +github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/teris-io/shortid v0.0.0-20171029131806-771a37caa5cf h1:Z2X3Os7oRzpdJ75iPqWZc0HeJWFYNCvKsfpQwFpRNTA= +github.com/teris-io/shortid v0.0.0-20171029131806-771a37caa5cf/go.mod h1:M8agBzgqHIhgj7wEn9/0hJUZcrvt9VY+Ln+S1I5Mha0= +github.com/uber-go/atomic v1.3.2 h1:Azu9lPBWRNKzYXSIwRfgRuDuS0YKsK4NFhiQv98gkxo= +github.com/uber-go/atomic v1.3.2/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g= +github.com/uber/jaeger-client-go v2.16.0+incompatible h1:Q2Pp6v3QYiocMxomCaJuwQGFt7E53bPYqEgug/AoBtY= +github.com/uber/jaeger-client-go v2.16.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= +github.com/uber/jaeger-lib v2.0.0+incompatible h1:iMSCV0rmXEogjNWPh2D0xk9YVKvrtGoHJNe9ebLu/pw= +github.com/uber/jaeger-lib v2.0.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= +github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA= +github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= +github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M= +github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= +github.com/yudai/pp v2.0.1+incompatible h1:Q4//iY4pNF6yPLZIigmvcl7k/bPgrcTPIFIcmawg5bI= +github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= +github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs= +github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= +go.uber.org/atomic v1.3.2 h1:2Oa65PReHzfn29GpvgsYwloV9AVFHPDk8tYxt2c2tr4= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a h1:Igim7XhdOpBnWPuYJ70XcNpq8q3BCACtVgNfoJxOV7g= +golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190415100556-4a65cf94b679 h1:tzVWzOrXxwAwdSCMrf+mbNrZFxwS0+HLP4m2qxtfdhk= +golang.org/x/net v0.0.0-20190415100556-4a65cf94b679/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/oauth2 v0.0.0-20190319182350-c85d3e98c914 h1:jIOcLT9BZzyJ9ce+IwwZ+aF9yeCqzrR+NrD68a/SHKw= +golang.org/x/oauth2 v0.0.0-20190319182350-c85d3e98c914/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6 h1:bjcUS9ztw9kFmmIxJInhon/0Is3p+EHBKNgquIzo1OI= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190415081028-16da32be82c5 h1:UMbOtg4ZL2GyTAolLE9QfNvzskWvFkI935Z98i9moXA= +golang.org/x/sys v0.0.0-20190415081028-16da32be82c5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373 h1:PPwnA7z1Pjf7XYaBP9GL1VAMZmcIWyFz7QCMSIIa3Bg= +golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/grpc v1.14.0 h1:ArxJuB1NWfPY6r9Gp9gqwplT0Ge7nqv9msgu03lHLmo= +google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= +gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= +gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d h1:TxyelI5cVkbREznMhfzycHdkp5cLA7DpE+GKjSslYhM= +gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw= +gopkg.in/bufio.v1 v1.0.0-20140618132640-567b2bfa514e h1:wGA78yza6bu/mWcc4QfBuIEHEtc06xdiU0X8sY36yUU= +gopkg.in/bufio.v1 v1.0.0-20140618132640-567b2bfa514e/go.mod h1:xsQCaysVCudhrYTfzYWe577fCe7Ceci+6qjO2Rdc0Z4= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/ini.v1 v1.42.0 h1:7N3gPTt50s8GuLortA00n8AqRTk75qOP98+mTPpgzRk= +gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ldap.v3 v3.0.2 h1:R6RBtabK6e1GO0eQKtkyOFbAHO73QesLzI2w2DZ6b9w= +gopkg.in/ldap.v3 v3.0.2/go.mod h1:oxD7NyBuxchC+SgJDE1Q5Od05eGt29SDQVBmV+HYbzw= +gopkg.in/macaron.v1 v1.3.2 h1:AvWIaPmwBUA87/OWzePkoxeaw6YJWDfBt1pDFPBnLf8= +gopkg.in/macaron.v1 v1.3.2/go.mod h1:PrsiawTWAGZs6wFbT5hlr7SQ2Ns9h7cUVtcUu4lQOVo= +gopkg.in/mail.v2 v2.3.1 h1:WYFn/oANrAGP2C0dcV6/pbkPzv8yGzqTjPmTeO7qoXk= +gopkg.in/mail.v2 v2.3.1/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw= +gopkg.in/redis.v2 v2.3.2 h1:GPVIIB/JnL1wvfULefy3qXmPu1nfNu2d0yA09FHgwfs= +gopkg.in/redis.v2 v2.3.2/go.mod h1:4wl9PJ/CqzeHk3LVq1hNLHH8krm3+AXEgut4jVc++LU= +gopkg.in/square/go-jose.v2 v2.3.0 h1:nLzhkFyl5bkblqYBoiWJUt5JkWOzmiaBtCxdJAqJd3U= +gopkg.in/square/go-jose.v2 v2.3.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/stretchr/testify.v1 v1.2.2/go.mod h1:QI5V/q6UbPmuhtm10CaFZxED9NreB8PnFYN9JcR6TxU= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/jest.config.js b/jest.config.js index c5c6bcb9f5f1c..09342e1472079 100644 --- a/jest.config.js +++ b/jest.config.js @@ -23,4 +23,5 @@ module.exports = { "./public/test/jest-setup.ts" ], "snapshotSerializers": ["enzyme-to-json/serializer"], + "globals": { "ts-jest": { "isolatedModules": true } }, }; diff --git a/latest.json b/latest.json index bc1ac9d90cc74..42613210e0f1f 100644 --- a/latest.json +++ b/latest.json @@ -1,4 +1,4 @@ { - "stable": "6.0.2", - "testing": "6.0.2" + "stable": "6.1.3", + "testing": "6.1.3" } diff --git a/package.json b/package.json index cfdfd996f9b7b..87ab3a09c7e7b 100644 --- a/package.json +++ b/package.json @@ -5,126 +5,128 @@ "company": "Grafana Labs" }, "name": "grafana", - "version": "6.1.0-pre", + "version": "6.2.0-pre", "repository": { "type": "git", "url": "http://github.com/grafana/grafana.git" }, "devDependencies": { - "@babel/core": "^7.3.4", - "@babel/plugin-syntax-dynamic-import": "^7.0.0", - "@babel/preset-env": "^7.3.4", - "@babel/preset-react": "^7.0.0", - "@babel/preset-typescript": "^7.3.3", - "@emotion/core": "^10.0.10", - "@rtsao/plugin-proposal-class-properties": "^7.0.1-patch.1", - "@types/angular": "^1.6.6", - "@types/chalk": "^2.2.0", - "@types/classnames": "^2.2.6", - "@types/clipboard": "^2.0.1", - "@types/commander": "^2.12.2", - "@types/d3": "^4.10.1", - "@types/enzyme": "^3.1.13", - "@types/inquirer": "^0.0.43", - "@types/jest": "^24.0.11", - "@types/jquery": "^1.10.35", - "@types/node": "^8.0.31", - "@types/papaparse": "^4.5.9", - "@types/react": "^16.8.8", - "@types/react-dom": "^16.8.2", - "@types/react-grid-layout": "^0.16.6", - "@types/react-select": "^2.0.4", - "@types/react-transition-group": "^2.0.15", - "@types/react-virtualized": "^9.18.12", + "@babel/core": "7.4.3", + "@babel/plugin-syntax-dynamic-import": "7.2.0", + "@babel/preset-env": "7.4.2", + "@babel/preset-react": "7.0.0", + "@babel/preset-typescript": "7.3.3", + "@emotion/core": "10.0.10", + "@rtsao/plugin-proposal-class-properties": "7.0.1-patch.1", + "@types/angular": "1.6.54", + "@types/chalk": "2.2.0", + "@types/classnames": "2.2.7", + "@types/clipboard": "2.0.1", + "@types/commander": "2.12.2", + "@types/d3": "4.13.1", + "@types/enzyme": "3.9.0", + "@types/inquirer": "0.0.43", + "@types/jest": "24.0.11", + "@types/jquery": "1.10.35", + "@types/lodash": "4.14.123", + "@types/node": "11.13.4", + "@types/papaparse": "4.5.9", + "@types/react": "16.8.13", + "@types/react-dom": "16.8.4", + "@types/react-grid-layout": "0.16.7", + "@types/react-select": "2.0.15", + "@types/react-transition-group": "2.0.16", + "@types/react-virtualized": "9.18.12", + "@types/react-window": "1.7.0", "angular-mocks": "1.6.6", - "autoprefixer": "^9.4.10", - "axios": "^0.18.0", - "babel-core": "^7.0.0-bridge", - "babel-jest": "^24.6.0", - "babel-loader": "^8.0.4", - "babel-plugin-angularjs-annotate": "^0.10.0", - "chalk": "^2.4.2", - "clean-webpack-plugin": "^2.0.0", - "concurrently": "^4.1.0", - "css-loader": "^2.1.1", - "enzyme": "^3.6.0", - "enzyme-adapter-react-16": "^1.5.0", - "enzyme-to-json": "^3.3.4", - "es6-promise": "^3.0.2", - "es6-shim": "^0.35.3", - "execa": "^1.0.0", - "expect.js": "~0.2.0", + "autoprefixer": "9.5.0", + "axios": "0.18.0", + "babel-core": "7.0.0-bridge.0", + "babel-jest": "24.6.0", + "babel-loader": "8.0.5", + "babel-plugin-angularjs-annotate": "0.10.0", + "chalk": "2.4.2", + "clean-webpack-plugin": "2.0.0", + "concurrently": "4.1.0", + "css-loader": "2.1.1", + "enzyme": "3.9.0", + "enzyme-adapter-react-16": "1.11.2", + "enzyme-to-json": "3.3.5", + "es6-promise": "3.3.1", + "es6-shim": "0.35.5", + "execa": "1.0.0", + "expect.js": "0.2.0", "expose-loader": "0.7.5", - "file-loader": "^3.0.1", - "fork-ts-checker-webpack-plugin": "^1.0.0", - "gaze": "^1.1.2", - "glob": "~7.1.3", + "file-loader": "3.0.1", + "fork-ts-checker-webpack-plugin": "1.0.0", + "gaze": "1.1.3", + "glob": "7.1.3", "grunt": "1.0.1", - "grunt-angular-templates": "^1.1.0", - "grunt-cli": "~1.2.0", - "grunt-contrib-clean": "~1.0.0", - "grunt-contrib-compress": "^1.3.0", - "grunt-contrib-copy": "~1.0.0", - "grunt-exec": "^1.0.1", - "grunt-newer": "^1.3.0", - "grunt-notify": "^0.4.5", - "grunt-postcss": "^0.8.0", - "grunt-sass-lint": "^0.2.4", + "grunt-angular-templates": "1.1.0", + "grunt-cli": "1.2.0", + "grunt-contrib-clean": "1.0.0", + "grunt-contrib-compress": "1.4.3", + "grunt-contrib-copy": "1.0.0", + "grunt-exec": "1.0.1", + "grunt-newer": "1.3.0", + "grunt-notify": "0.4.5", + "grunt-postcss": "0.8.0", + "grunt-sass-lint": "0.2.4", "grunt-usemin": "3.1.1", - "grunt-webpack": "^3.0.2", + "grunt-webpack": "3.1.3", "html-loader": "0.5.5", - "html-webpack-harddisk-plugin": "^1.0.1", - "html-webpack-plugin": "^3.2.0", - "husky": "^1.3.1", - "inquirer": "^6.2.2", - "jest": "^24.6.0", - "jest-date-mock": "^1.0.6", - "lint-staged": "^8.1.3", + "html-webpack-harddisk-plugin": "1.0.1", + "html-webpack-plugin": "3.2.0", + "husky": "1.3.1", + "inquirer": "6.2.2", + "jest": "24.6.0", + "jest-date-mock": "1.0.7", + "lint-staged": "8.1.5", "load-grunt-tasks": "3.5.2", - "mini-css-extract-plugin": "^0.5.0", - "mocha": "^4.0.1", - "monaco-editor": "^0.15.6", - "ng-annotate-loader": "^0.6.1", - "ng-annotate-webpack-plugin": "^0.3.0", - "ngtemplate-loader": "^2.0.1", - "node-sass": "^4.11.0", - "npm": "^6.9.0", - "optimize-css-assets-webpack-plugin": "^5.0.1", - "ora": "^3.2.0", - "phantomjs-prebuilt": "^2.1.15", - "postcss-browser-reporter": "^0.5.0", - "postcss-loader": "^3.0.0", - "postcss-reporter": "^6.0.1", + "mini-css-extract-plugin": "0.5.0", + "mocha": "4.1.0", + "monaco-editor": "0.15.6", + "ng-annotate-loader": "0.6.1", + "ng-annotate-webpack-plugin": "0.3.0", + "ngtemplate-loader": "2.0.1", + "node-sass": "4.11.0", + "npm": "6.9.0", + "optimize-css-assets-webpack-plugin": "5.0.1", + "ora": "3.2.0", + "phantomjs-prebuilt": "2.1.16", + "postcss-browser-reporter": "0.5.0", + "postcss-loader": "3.0.0", + "postcss-reporter": "6.0.1", "prettier": "1.16.4", - "react-hooks-testing-library": "^0.3.7", - "react-hot-loader": "^4.3.6", - "react-test-renderer": "^16.5.0", - "redux-mock-store": "^1.5.3", - "regexp-replace-loader": "^1.0.1", - "rimraf": "^2.6.3", - "sass-lint": "^1.10.2", + "react-hooks-testing-library": "0.3.7", + "react-hot-loader": "4.8.0", + "react-test-renderer": "16.8.4", + "redux-mock-store": "1.5.3", + "regexp-replace-loader": "1.0.1", + "rimraf": "2.6.3", + "sass-lint": "1.12.1", "sass-loader": "7.1.0", - "semver": "^5.6.0", + "semver": "5.7.0", "sinon": "1.17.6", "style-loader": "0.23.1", "systemjs": "0.20.19", - "systemjs-plugin-css": "^0.1.36", - "terser-webpack-plugin": "^1.2.3", - "ts-jest": "^24.0.1", + "systemjs-plugin-css": "0.1.37", + "terser-webpack-plugin": "1.2.3", + "ts-jest": "24.0.1", "ts-loader": "5.3.3", "ts-node": "8.0.2", "tslib": "1.9.3", "tslint": "5.14.0", - "tslint-loader": "^3.5.3", - "tslint-react": "^3.6.0", + "tslint-loader": "3.5.4", + "tslint-react": "3.6.0", "typescript": "3.4.1", "webpack": "4.29.6", "webpack-bundle-analyzer": "3.1.0", - "webpack-cleanup-plugin": "^0.5.1", + "webpack-cleanup-plugin": "0.5.1", "webpack-cli": "3.2.3", "webpack-dev-server": "3.2.1", "webpack-merge": "4.2.1", - "zone.js": "^0.7.2" + "zone.js": "0.7.8" }, "scripts": { "dev": "webpack --progress --colors --mode development --config scripts/webpack/webpack.dev.js", @@ -170,62 +172,63 @@ }, "license": "Apache-2.0", "dependencies": { - "@babel/polyfill": "^7.0.0", + "@babel/polyfill": "7.2.5", "@torkelo/react-select": "2.4.1", - "@types/reselect": "^2.2.0", + "@types/reselect": "2.2.0", "angular": "1.6.6", "angular-bindonce": "0.3.1", "angular-native-dragdrop": "1.2.2", "angular-route": "1.6.6", "angular-sanitize": "1.6.6", - "baron": "^3.0.3", - "brace": "^0.10.0", - "classnames": "^2.2.6", - "clipboard": "^2.0.4", - "d3": "^4.11.0", - "d3-scale-chromatic": "^1.3.0", - "eventemitter3": "^2.0.3", - "file-saver": "^1.3.3", - "immutable": "^3.8.2", - "jquery": "^3.2.1", - "lodash": "^4.17.10", - "moment": "^2.22.2", - "mousetrap": "^1.6.0", - "mousetrap-global-bind": "^1.1.0", - "nodemon": "^1.18.10", - "papaparse": "^4.6.3", - "prismjs": "^1.6.0", - "prop-types": "^15.6.2", - "rc-cascader": "^0.14.0", - "react": "^16.8.4", - "react-dom": "^16.8.4", + "baron": "3.0.3", + "brace": "0.10.0", + "calculate-size": "1.1.1", + "classnames": "2.2.6", + "clipboard": "2.0.4", + "d3": "4.13.0", + "d3-scale-chromatic": "1.3.3", + "eventemitter3": "2.0.3", + "file-saver": "1.3.8", + "immutable": "3.8.2", + "jquery": "3.4.0", + "lodash": "4.17.11", + "moment": "2.24.0", + "mousetrap": "1.6.3", + "mousetrap-global-bind": "1.1.0", + "nodemon": "1.18.10", + "papaparse": "4.6.3", + "prismjs": "1.16.0", + "prop-types": "15.7.2", + "rc-cascader": "0.14.0", + "react": "16.8.6", + "react-dom": "16.8.6", "react-grid-layout": "0.16.6", "react-highlight-words": "0.11.0", - "react-popper": "^1.3.0", - "react-redux": "^5.0.7", - "react-sizeme": "^2.3.6", - "react-table": "^6.8.6", - "react-transition-group": "^2.2.1", - "react-virtualized": "^9.21.0", - "redux": "^4.0.0", - "redux-logger": "^3.0.6", - "redux-thunk": "^2.3.0", - "remarkable": "^1.7.1", - "reselect": "^4.0.0", + "react-popper": "1.3.3", + "react-redux": "5.1.1", + "react-sizeme": "2.5.2", + "react-table": "6.9.2", + "react-transition-group": "2.6.1", + "react-virtualized": "9.21.0", + "react-window": "1.7.1", + "redux": "4.0.1", + "redux-logger": "3.0.6", + "redux-thunk": "2.3.0", + "remarkable": "1.7.1", + "reselect": "4.0.0", "rst2html": "github:thoward/rst2html#990cb89", - "rxjs": "^6.3.3", - "slate": "^0.33.4", - "slate-plain-serializer": "^0.5.10", - "slate-prism": "^0.5.0", - "slate-react": "^0.12.4", - "tether": "^1.4.0", + "rxjs": "6.4.0", + "slate": "0.33.8", + "slate-plain-serializer": "0.5.41", + "slate-prism": "0.5.0", + "slate-react": "0.12.11", + "tether": "1.4.5", "tether-drop": "https://github.com/torkelo/drop/tarball/master", - "tinycolor2": "^1.4.1", - "xss": "^1.0.3" + "tinycolor2": "1.4.1", + "xss": "1.0.3" }, "resolutions": { - "caniuse-db": "1.0.30000772", - "**/@types/react": "16.8.8" + "caniuse-db": "1.0.30000772" }, "workspaces": { "packages": [ diff --git a/packages/grafana-ui/.storybook/config.ts b/packages/grafana-ui/.storybook/config.ts index b87604438d723..98a4ee8bd9e04 100644 --- a/packages/grafana-ui/.storybook/config.ts +++ b/packages/grafana-ui/.storybook/config.ts @@ -2,7 +2,17 @@ import { configure, addDecorator } from '@storybook/react'; import { withKnobs } from '@storybook/addon-knobs'; import { withTheme } from '../src/utils/storybook/withTheme'; import { withPaddedStory } from '../src/utils/storybook/withPaddedStory'; - +import 'jquery'; +import '../../../public/vendor/flot/jquery.flot.js'; +import '../../../public/vendor/flot/jquery.flot.selection'; +import '../../../public/vendor/flot/jquery.flot.time'; +import '../../../public/vendor/flot/jquery.flot.stack'; +import '../../../public/vendor/flot/jquery.flot.pie'; +import '../../../public/vendor/flot/jquery.flot.stackpercent'; +import '../../../public/vendor/flot/jquery.flot.fillbelow'; +import '../../../public/vendor/flot/jquery.flot.crosshair'; +import '../../../public/vendor/flot/jquery.flot.dashes'; +import '../../../public/vendor/flot/jquery.flot.gauge'; // @ts-ignore import lightTheme from '../../../public/sass/grafana.light.scss'; // @ts-ignore diff --git a/packages/grafana-ui/package.json b/packages/grafana-ui/package.json index 5dd006832a6fb..1ae257b6016cd 100644 --- a/packages/grafana-ui/package.json +++ b/packages/grafana-ui/package.json @@ -20,62 +20,63 @@ "license": "Apache-2.0", "dependencies": { "@torkelo/react-select": "2.1.1", - "@types/react-color": "^2.14.0", - "classnames": "^2.2.5", - "d3": "^5.7.0", - "jquery": "^3.2.1", - "lodash": "^4.17.10", - "moment": "^2.22.2", - "papaparse": "^4.6.3", - "react": "^16.8.4", - "react-color": "^2.17.0", - "react-custom-scrollbars": "^4.2.1", - "react-dom": "^16.8.4", + "@types/react-color": "2.17.0", + "classnames": "2.2.6", + "d3": "5.9.1", + "jquery": "3.4.0", + "lodash": "4.17.11", + "moment": "2.24.0", + "papaparse": "4.6.3", + "react": "16.8.6", + "react-calendar": "2.18.1", + "react-color": "2.17.0", + "react-custom-scrollbars": "4.2.1", + "react-dom": "16.8.6", "react-highlight-words": "0.11.0", - "react-popper": "^1.3.0", - "react-storybook-addon-props-combinations": "^1.1.0", - "react-transition-group": "^2.2.1", - "react-virtualized": "^9.21.0", - "tether": "^1.4.0", + "react-popper": "1.3.3", + "react-storybook-addon-props-combinations": "1.1.0", + "react-transition-group": "2.6.1", + "react-virtualized": "9.21.0", + "tether": "1.4.5", "tether-drop": "https://github.com/torkelo/drop/tarball/master", - "tinycolor2": "^1.4.1" + "tinycolor2": "1.4.1" }, "devDependencies": { - "@storybook/addon-actions": "^5.0.5", - "@storybook/addon-info": "^5.0.5", - "@storybook/addon-knobs": "^5.0.5", - "@storybook/react": "^5.0.5", - "@storybook/theming": "^5.0.5", - "@types/classnames": "^2.2.6", - "@types/d3": "^5.7.0", - "@types/jest": "^23.3.2", - "@types/jquery": "^1.10.35", - "@types/lodash": "^4.14.119", - "@types/node": "^10.12.18", - "@types/papaparse": "^4.5.9", - "@types/pretty-format": "^20.0.1", - "@types/react": "^16.8.8", - "@types/react-custom-scrollbars": "^4.0.5", - "@types/react-test-renderer": "^16.0.3", - "@types/react-transition-group": "^2.0.15", - "@types/storybook__addon-actions": "^3.4.1", - "@types/storybook__addon-info": "^4.1.1", - "@types/storybook__addon-knobs": "^4.0.0", - "@types/storybook__react": "^4.0.0", - "@types/tether-drop": "^1.4.8", - "@types/tinycolor2": "^1.4.1", - "awesome-typescript-loader": "^5.2.1", - "pretty-format": "^24.5.0", - "react-docgen-typescript-loader": "^3.0.0", - "react-docgen-typescript-webpack-plugin": "^1.1.0", - "react-test-renderer": "^16.7.0", - "rollup": "^1.1.2", - "rollup-plugin-commonjs": "^9.2.0", - "rollup-plugin-node-resolve": "^4.0.0", - "rollup-plugin-sourcemaps": "^0.4.2", - "rollup-plugin-terser": "^4.0.4", - "rollup-plugin-typescript2": "^0.19.2", - "rollup-plugin-visualizer": "^0.9.2", + "@storybook/addon-actions": "5.0.6", + "@storybook/addon-info": "5.0.6", + "@storybook/addon-knobs": "5.0.6", + "@storybook/react": "5.0.6", + "@storybook/theming": "5.0.6", + "@types/classnames": "2.2.7", + "@types/d3": "5.7.1", + "@types/jest": "23.3.14", + "@types/jquery": "1.10.35", + "@types/lodash": "4.14.123", + "@types/node": "10.14.1", + "@types/papaparse": "4.5.9", + "@types/pretty-format": "20.0.1", + "@types/react": "16.8.13", + "@types/react-custom-scrollbars": "4.0.5", + "@types/react-test-renderer": "16.8.1", + "@types/react-transition-group": "2.0.16", + "@types/storybook__addon-actions": "3.4.2", + "@types/storybook__addon-info": "4.1.1", + "@types/storybook__addon-knobs": "4.0.4", + "@types/storybook__react": "4.0.1", + "@types/tether-drop": "1.4.8", + "@types/tinycolor2": "1.4.1", + "awesome-typescript-loader": "5.2.1", + "pretty-format": "24.5.0", + "react-docgen-typescript-loader": "3.0.1", + "react-docgen-typescript-webpack-plugin": "1.1.0", + "react-test-renderer": "16.8.4", + "rollup": "1.6.0", + "rollup-plugin-commonjs": "9.2.1", + "rollup-plugin-node-resolve": "4.0.1", + "rollup-plugin-sourcemaps": "0.4.2", + "rollup-plugin-terser": "4.0.4", + "rollup-plugin-typescript2": "0.19.3", + "rollup-plugin-visualizer": "0.9.2", "typescript": "3.4.1" }, "resolutions": { diff --git a/packages/grafana-ui/src/components/BarGauge/BarGauge.tsx b/packages/grafana-ui/src/components/BarGauge/BarGauge.tsx index 6622545229e98..9c5bf65638203 100644 --- a/packages/grafana-ui/src/components/BarGauge/BarGauge.tsx +++ b/packages/grafana-ui/src/components/BarGauge/BarGauge.tsx @@ -136,8 +136,9 @@ export class BarGauge extends PureComponent { const valueRange = maxValue - minValue; const maxSize = isVert ? maxBarHeight : maxBarWidth; const cellSpacing = itemSpacing!; - const cellCount = maxSize / 20; - const cellSize = (maxSize - cellSpacing * cellCount) / cellCount; + const cellWidth = 12; + const cellCount = Math.floor(maxSize / cellWidth); + const cellSize = Math.floor((maxSize - cellSpacing * cellCount) / cellCount); const valueColor = getValueColor(this.props); const valueStyles = getValueStyles(value.text, valueColor, valueWidth, valueHeight); @@ -286,7 +287,7 @@ export function getTitleStyles(props: Props): { wrapper: CSSProperties; title: C titleStyles.width = `${titleDim.width}px`; titleStyles.textAlign = 'right'; - titleStyles.marginRight = '10px'; + titleStyles.paddingRight = '10px'; } } @@ -344,6 +345,11 @@ function calculateBarAndValueDimensions(props: Props): BarAndValueDimensions { } } + // console.log('titleDim', titleDim); + // console.log('valueWidth', valueWidth); + // console.log('width', width); + // console.log('total', titleDim.width + maxBarWidth + valueWidth); + return { valueWidth, valueHeight, @@ -409,7 +415,8 @@ export function getBasicAndGradientStyles(props: Props): BasicAndGradientStyles barStyles.transition = 'width 1s'; barStyles.height = `${maxBarHeight}px`; barStyles.width = `${barWidth}px`; - barStyles.marginRight = '10px'; + + valueStyles.paddingLeft = '10px'; if (isBasic) { // Basic styles diff --git a/packages/grafana-ui/src/components/BarGauge/__snapshots__/BarGauge.test.tsx.snap b/packages/grafana-ui/src/components/BarGauge/__snapshots__/BarGauge.test.tsx.snap index 7a9fb4b468ba2..4bb9395dd96ed 100644 --- a/packages/grafana-ui/src/components/BarGauge/__snapshots__/BarGauge.test.tsx.snap +++ b/packages/grafana-ui/src/components/BarGauge/__snapshots__/BarGauge.test.tsx.snap @@ -20,6 +20,7 @@ exports[`BarGauge Render with basic options should render 1`] = ` "display": "flex", "fontSize": "27.27px", "height": "300px", + "paddingLeft": "10px", "width": "60px", } } @@ -33,7 +34,6 @@ exports[`BarGauge Render with basic options should render 1`] = ` "borderRadius": "3px", "borderRight": "2px solid #73BF69", "height": "300px", - "marginRight": "10px", "transition": "width 1s", "width": "60px", } diff --git a/packages/grafana-ui/src/components/BigValue/BigValue.tsx b/packages/grafana-ui/src/components/BigValue/BigValue.tsx index f232beca108ed..abc6a2e4e091e 100644 --- a/packages/grafana-ui/src/components/BigValue/BigValue.tsx +++ b/packages/grafana-ui/src/components/BigValue/BigValue.tsx @@ -1,6 +1,7 @@ // Library import React, { PureComponent, ReactNode, CSSProperties } from 'react'; import $ from 'jquery'; +import { css } from 'emotion'; // Utils import { getColorFromHexRgbOrName } from '../../utils'; @@ -98,36 +99,67 @@ export class BigValue extends PureComponent { return {value.text}; }; - render() { - const { height, width, value, prefix, suffix, sparkline, backgroundColor } = this.props; + renderSparkline(sparkline: BigValueSparkline) { + const { height, width } = this.props; const plotCss: CSSProperties = {}; plotCss.position = 'absolute'; - - if (sparkline) { - if (sparkline.full) { - plotCss.bottom = '5px'; - plotCss.left = '-5px'; - plotCss.width = width - 10 + 'px'; - const dynamicHeightMargin = height <= 100 ? 5 : Math.round(height / 100) * 15 + 5; - plotCss.height = height - dynamicHeightMargin + 'px'; - } else { - plotCss.bottom = '0px'; - plotCss.left = '-5px'; - plotCss.width = width - 10 + 'px'; - plotCss.height = Math.floor(height * 0.25) + 'px'; - } + plotCss.bottom = '0px'; + plotCss.left = '0px'; + plotCss.width = width + 'px'; + + if (sparkline.full) { + const dynamicHeightMargin = height <= 100 ? 5 : Math.round(height / 100) * 15 + 5; + plotCss.height = height - dynamicHeightMargin + 'px'; + } else { + plotCss.height = Math.floor(height * 0.25) + 'px'; } + return
(this.canvasElement = element)} />; + } + + render() { + const { height, width, value, prefix, suffix, sparkline, backgroundColor } = this.props; return ( -
- +
+ {value.title && ( +
+ {value.title} +
+ )} + {this.renderText(prefix, '0px 2px 0px 0px')} {this.renderText(value)} {this.renderText(suffix)} - {sparkline &&
(this.canvasElement = element)} />} + {sparkline && this.renderSparkline(sparkline)}
); } diff --git a/packages/grafana-ui/src/components/BigValue/_BigValue.scss b/packages/grafana-ui/src/components/BigValue/_BigValue.scss deleted file mode 100644 index 13603daa4579e..0000000000000 --- a/packages/grafana-ui/src/components/BigValue/_BigValue.scss +++ /dev/null @@ -1,15 +0,0 @@ -.big-value { - position: relative; - display: table; -} - -.big-value__value { - line-height: 1; - display: table-cell; - vertical-align: middle; - text-align: center; - position: relative; - z-index: 1; - font-size: 3em; - font-weight: $font-weight-semi-bold; -} diff --git a/packages/grafana-ui/src/components/Button/AbstractButton.tsx b/packages/grafana-ui/src/components/Button/AbstractButton.tsx index 68dc303191b00..38f225273adb0 100644 --- a/packages/grafana-ui/src/components/Button/AbstractButton.tsx +++ b/packages/grafana-ui/src/components/Button/AbstractButton.tsx @@ -65,35 +65,28 @@ const getButtonStyles = (theme: GrafanaTheme, size: ButtonSize, variant: ButtonV background, fontSize, iconDistance, + height, fontWeight = theme.typography.weight.semibold; switch (size) { - case ButtonSize.ExtraSmall: - padding = `${theme.spacing.xs} ${theme.spacing.sm}`; - fontSize = theme.typography.size.xs; - iconDistance = theme.spacing.xs; - break; case ButtonSize.Small: padding = `${theme.spacing.xs} ${theme.spacing.sm}`; fontSize = theme.typography.size.sm; iconDistance = theme.spacing.xs; + height = theme.height.sm; break; case ButtonSize.Large: padding = `${theme.spacing.md} ${theme.spacing.lg}`; fontSize = theme.typography.size.lg; fontWeight = theme.typography.weight.regular; iconDistance = theme.spacing.sm; - break; - case ButtonSize.ExtraLarge: - padding = `${theme.spacing.md} ${theme.spacing.lg}`; - fontSize = theme.typography.size.lg; - fontWeight = theme.typography.weight.regular; - iconDistance = theme.spacing.sm; + height = theme.height.lg; break; default: padding = `${theme.spacing.sm} ${theme.spacing.md}`; iconDistance = theme.spacing.sm; fontSize = theme.typography.size.base; + height = theme.height.md; } switch (variant) { @@ -133,7 +126,8 @@ const getButtonStyles = (theme: GrafanaTheme, size: ButtonSize, variant: ButtonV return { button: css` label: button; - display: inline-block; + display: flex; + align-items: center; font-weight: ${fontWeight}; font-size: ${fontSize}; font-family: ${theme.typography.fontFamily.sansSerif}; @@ -143,6 +137,7 @@ const getButtonStyles = (theme: GrafanaTheme, size: ButtonSize, variant: ButtonV vertical-align: middle; cursor: pointer; border: none; + height: ${height}; border-radius: ${borderRadius}; ${background}; @@ -161,6 +156,7 @@ const getButtonStyles = (theme: GrafanaTheme, size: ButtonSize, variant: ButtonV icon: css` label: button-icon; margin-right: ${iconDistance}; + filter: brightness(100); `, }; }; diff --git a/packages/grafana-ui/src/components/Button/Button.story.tsx b/packages/grafana-ui/src/components/Button/Button.story.tsx index 5189db1e0ed57..0938c618d5fab 100644 --- a/packages/grafana-ui/src/components/Button/Button.story.tsx +++ b/packages/grafana-ui/src/components/Button/Button.story.tsx @@ -48,7 +48,7 @@ ButtonStories.add('with icon', () => { Plus: 'fa fa-plus', User: 'fa fa-user', Gear: 'fa fa-gear', - Annotation: 'gicon gicon-add-annotation', + Annotation: 'gicon gicon-annotation', }, 'fa fa-plus' ); diff --git a/public/app/core/components/ClickOutsideWrapper/ClickOutsideWrapper.tsx b/packages/grafana-ui/src/components/ClickOutsideWrapper/ClickOutsideWrapper.tsx similarity index 94% rename from public/app/core/components/ClickOutsideWrapper/ClickOutsideWrapper.tsx rename to packages/grafana-ui/src/components/ClickOutsideWrapper/ClickOutsideWrapper.tsx index 63191862ebb58..c435be0f3840e 100644 --- a/public/app/core/components/ClickOutsideWrapper/ClickOutsideWrapper.tsx +++ b/packages/grafana-ui/src/components/ClickOutsideWrapper/ClickOutsideWrapper.tsx @@ -22,7 +22,7 @@ export class ClickOutsideWrapper extends PureComponent { window.removeEventListener('click', this.onOutsideClick, false); } - onOutsideClick = event => { + onOutsideClick = (event: any) => { const domNode = ReactDOM.findDOMNode(this) as Element; if (!domNode || !domNode.contains(event.target)) { diff --git a/packages/grafana-ui/src/components/CustomScrollbar/CustomScrollbar.tsx b/packages/grafana-ui/src/components/CustomScrollbar/CustomScrollbar.tsx index 945e3d825d812..f2f6b236e14b4 100644 --- a/packages/grafana-ui/src/components/CustomScrollbar/CustomScrollbar.tsx +++ b/packages/grafana-ui/src/components/CustomScrollbar/CustomScrollbar.tsx @@ -2,6 +2,7 @@ import React, { Component } from 'react'; import isNil from 'lodash/isNil'; import classNames from 'classnames'; import Scrollbars from 'react-custom-scrollbars'; +import { cx, css } from 'emotion'; interface Props { className?: string; @@ -10,8 +11,8 @@ interface Props { autoHideDuration?: number; autoHeightMax?: string; hideTracksWhenNotNeeded?: boolean; - renderTrackHorizontal?: React.FunctionComponent; - renderTrackVertical?: React.FunctionComponent; + hideHorizontalTrack?: boolean; + hideVerticalTrack?: boolean; scrollTop?: number; setScrollTop: (event: any) => void; autoHeightMin?: number | string; @@ -79,8 +80,8 @@ export class CustomScrollbar extends Component { autoHide, autoHideTimeout, hideTracksWhenNotNeeded, - renderTrackHorizontal, - renderTrackVertical, + hideHorizontalTrack, + hideVerticalTrack, } = this.props; return ( @@ -96,8 +97,28 @@ export class CustomScrollbar extends Component { // Before these where set to inhert but that caused problems with cut of legends in firefox autoHeightMax={autoHeightMax} autoHeightMin={autoHeightMin} - renderTrackHorizontal={renderTrackHorizontal || (props =>
)} - renderTrackVertical={renderTrackVertical || (props =>
)} + renderTrackHorizontal={props => ( +
+ )} + renderTrackVertical={props => ( +
+ )} renderThumbHorizontal={props =>
} renderThumbVertical={props =>
} renderView={props =>
} diff --git a/packages/grafana-ui/src/components/CustomScrollbar/__snapshots__/CustomScrollbar.test.tsx.snap b/packages/grafana-ui/src/components/CustomScrollbar/__snapshots__/CustomScrollbar.test.tsx.snap index dd3f59ad1e199..b348f7dd8bd06 100644 --- a/packages/grafana-ui/src/components/CustomScrollbar/__snapshots__/CustomScrollbar.test.tsx.snap +++ b/packages/grafana-ui/src/components/CustomScrollbar/__snapshots__/CustomScrollbar.test.tsx.snap @@ -37,7 +37,7 @@ exports[`CustomScrollbar renders correctly 1`] = `

{ } render() { - const { height, width } = this.props; + const { height, width, value } = this.props; return (
(this.canvasElement = element)} - /> + > + {value.title && ( +
+ {value.title} +
+ )} +
); } } diff --git a/packages/grafana-ui/src/components/Graph/Graph.tsx b/packages/grafana-ui/src/components/Graph/Graph.tsx index b8ecc400217ec..60068da4c3dd0 100644 --- a/packages/grafana-ui/src/components/Graph/Graph.tsx +++ b/packages/grafana-ui/src/components/Graph/Graph.tsx @@ -1,11 +1,12 @@ // Libraries import $ from 'jquery'; import React, { PureComponent } from 'react'; +import uniqBy from 'lodash/uniqBy'; // Types import { TimeRange, GraphSeriesXY } from '../../types'; -interface GraphProps { +export interface GraphProps { series: GraphSeriesXY[]; timeRange: TimeRange; // NOTE: we should aim to make `time` a property of the axis, not force it for all graphs showLines?: boolean; @@ -46,7 +47,16 @@ export class Graph extends PureComponent { const ticks = width / 100; const min = timeRange.from.valueOf(); const max = timeRange.to.valueOf(); - + const yaxes = uniqBy( + series.map(s => { + return { + show: true, + index: s.yAxis, + position: s.yAxis === 1 ? 'left' : 'right', + }; + }), + yAxisConfig => yAxisConfig.index + ); const flotOptions = { legend: { show: false, @@ -80,6 +90,7 @@ export class Graph extends PureComponent { ticks: ticks, timeformat: timeFormat(ticks, min, max), }, + yaxes, grid: { minBorderMargin: 0, markings: [], @@ -94,7 +105,6 @@ export class Graph extends PureComponent { }; try { - console.log('Graph render'); $.plot(this.element, series, flotOptions); } catch (err) { console.log('Graph rendering error', err, flotOptions, series); diff --git a/packages/grafana-ui/src/components/Graph/GraphLegend.story.tsx b/packages/grafana-ui/src/components/Graph/GraphLegend.story.tsx new file mode 100644 index 0000000000000..1acc4d50a36b9 --- /dev/null +++ b/packages/grafana-ui/src/components/Graph/GraphLegend.story.tsx @@ -0,0 +1,105 @@ +import React from 'react'; +import { storiesOf } from '@storybook/react'; + +import { GraphLegend } from './GraphLegend'; +import { action } from '@storybook/addon-actions'; +import { select, number } from '@storybook/addon-knobs'; +import { withHorizontallyCenteredStory } from '../../utils/storybook/withCenteredStory'; +import { generateLegendItems } from '../Legend/Legend.story'; +import { LegendPlacement, LegendDisplayMode } from '../Legend/Legend'; + +const GraphLegendStories = storiesOf('Visualizations/Graph/GraphLegend', module); +GraphLegendStories.addDecorator(withHorizontallyCenteredStory); + +const getStoriesKnobs = (isList = false) => { + const statsToDisplay = select( + 'Stats to display', + { + none: [], + 'single (min)': [{ text: '10ms', title: 'min', numeric: 10 }], + 'multiple (min, max)': [ + { text: '10ms', title: 'min', numeric: 10 }, + { text: '100ms', title: 'max', numeric: 100 }, + ], + }, + [] + ); + + const numberOfSeries = number('Number of series', 3); + + const containerWidth = select( + 'Container width', + { + Small: '200px', + Medium: '500px', + 'Full width': '100%', + }, + '100%' + ); + + const legendPlacement = select( + 'Legend placement', + { + under: 'under', + right: 'right', + }, + 'under' + ); + + return { + statsToDisplay, + numberOfSeries, + containerWidth, + legendPlacement, + }; +}; + +GraphLegendStories.add('list', () => { + const { statsToDisplay, numberOfSeries, containerWidth, legendPlacement } = getStoriesKnobs(true); + return ( +
+ { + action('Series label clicked')(item, event); + }} + onSeriesColorChange={(label, color) => { + action('Series color changed')(label, color); + }} + onSeriesAxisToggle={(label, useRightYAxis) => { + action('Series axis toggle')(label, useRightYAxis); + }} + onToggleSort={sortBy => { + action('Toggle legend sort')(sortBy); + }} + placement={legendPlacement} + /> +
+ ); +}); + +GraphLegendStories.add('table', () => { + const { statsToDisplay, numberOfSeries, containerWidth, legendPlacement } = getStoriesKnobs(); + return ( +
+ { + action('Series label clicked')(item); + }} + onSeriesColorChange={(label, color) => { + action('Series color changed')(label, color); + }} + onSeriesAxisToggle={(label, useRightYAxis) => { + action('Series axis toggle')(label, useRightYAxis); + }} + onToggleSort={sortBy => { + action('Toggle legend sort')(sortBy); + }} + placement={legendPlacement} + /> +
+ ); +}); diff --git a/packages/grafana-ui/src/components/Graph/GraphLegend.tsx b/packages/grafana-ui/src/components/Graph/GraphLegend.tsx new file mode 100644 index 0000000000000..451acf4bac805 --- /dev/null +++ b/packages/grafana-ui/src/components/Graph/GraphLegend.tsx @@ -0,0 +1,118 @@ +import React, { useContext } from 'react'; +import { LegendProps, LegendItem, LegendDisplayMode } from '../Legend/Legend'; +import { GraphLegendListItem, GraphLegendTableRow } from './GraphLegendItem'; +import { SeriesColorChangeHandler, SeriesAxisToggleHandler } from './GraphWithLegend'; +import { LegendTable } from '../Legend/LegendTable'; +import { LegendList } from '../Legend/LegendList'; +import union from 'lodash/union'; +import sortBy from 'lodash/sortBy'; +import { ThemeContext } from '../../themes/ThemeContext'; +import { css } from 'emotion'; +import { selectThemeVariant } from '../../themes/index'; + +interface GraphLegendProps extends LegendProps { + displayMode: LegendDisplayMode; + sortBy?: string; + sortDesc?: boolean; + onSeriesColorChange: SeriesColorChangeHandler; + onSeriesAxisToggle?: SeriesAxisToggleHandler; + onToggleSort: (sortBy: string) => void; + onLabelClick: (item: LegendItem, event: React.MouseEvent) => void; +} + +export const GraphLegend: React.FunctionComponent = ({ + items, + displayMode, + sortBy: sortKey, + sortDesc, + onToggleSort, + onSeriesAxisToggle, + placement, + className, + ...graphLegendItemProps +}) => { + const theme = useContext(ThemeContext); + + if (displayMode === LegendDisplayMode.Table) { + const columns = items + .map(item => { + if (item.displayValues) { + return item.displayValues.map(i => i.title); + } + return []; + }) + .reduce( + (acc, current) => { + return union(acc, current.filter(item => !!item)); + }, + [''] + ) as string[]; + + const sortedItems = sortKey + ? sortBy(items, item => { + if (item.displayValues) { + const stat = item.displayValues.filter(stat => stat.title === sortKey)[0]; + return stat && stat.numeric; + } + return undefined; + }) + : items; + + const legendTableEvenRowBackground = selectThemeVariant( + { + dark: theme.colors.dark6, + light: theme.colors.gray5, + }, + theme.type + ); + + return ( + ( + { + if (onSeriesAxisToggle) { + onSeriesAxisToggle(item.label, item.yAxis === 1 ? 2 : 1); + } + }} + className={css` + background: ${index % 2 === 0 ? legendTableEvenRowBackground : 'none'}; + `} + {...graphLegendItemProps} + /> + )} + onToggleSort={onToggleSort} + /> + ); + } + return ( + ( + { + if (onSeriesAxisToggle) { + onSeriesAxisToggle(item.label, item.yAxis === 1 ? 2 : 1); + } + }} + {...graphLegendItemProps} + /> + )} + /> + ); +}; diff --git a/packages/grafana-ui/src/components/Graph/GraphLegendItem.tsx b/packages/grafana-ui/src/components/Graph/GraphLegendItem.tsx new file mode 100644 index 0000000000000..e116287d4d21e --- /dev/null +++ b/packages/grafana-ui/src/components/Graph/GraphLegendItem.tsx @@ -0,0 +1,117 @@ +import React, { useContext } from 'react'; +import { css, cx } from 'emotion'; +import { LegendSeriesIcon } from '../Legend/LegendSeriesIcon'; +import { LegendItem } from '../Legend/Legend'; +import { SeriesColorChangeHandler } from './GraphWithLegend'; +import { LegendStatsList } from '../Legend/LegendStatsList'; +import { ThemeContext } from '../../themes/ThemeContext'; + +export interface GraphLegendItemProps { + key?: React.Key; + item: LegendItem; + className?: string; + onLabelClick: (item: LegendItem, event: React.MouseEvent) => void; + onSeriesColorChange: SeriesColorChangeHandler; + onToggleAxis: () => void; +} + +export const GraphLegendListItem: React.FunctionComponent = ({ + item, + onSeriesColorChange, + onToggleAxis, + onLabelClick, +}) => { + return ( + <> + onSeriesColorChange(item.label, color)} + onToggleAxis={onToggleAxis} + yAxis={item.yAxis} + /> +
onLabelClick(item, event)} + className={css` + cursor: pointer; + white-space: nowrap; + `} + > + {item.label} +
+ + {item.displayValues && } + + ); +}; + +export const GraphLegendTableRow: React.FunctionComponent = ({ + item, + onSeriesColorChange, + onToggleAxis, + onLabelClick, + className, +}) => { + const theme = useContext(ThemeContext); + + return ( + + + + onSeriesColorChange(item.label, color)} + onToggleAxis={onToggleAxis} + yAxis={item.yAxis} + /> +
onLabelClick(item, event)} + className={css` + cursor: pointer; + white-space: nowrap; + `} + > + {item.label}{' '} + {item.yAxis === 2 && ( + + (right y-axis) + + )} +
+
+ + {item.displayValues && + item.displayValues.map((stat, index) => { + return ( + + {stat.text} + + ); + })} + + ); +}; diff --git a/packages/grafana-ui/src/components/Graph/GraphWithLegend.story.tsx b/packages/grafana-ui/src/components/Graph/GraphWithLegend.story.tsx new file mode 100644 index 0000000000000..c0fbf52d38fd6 --- /dev/null +++ b/packages/grafana-ui/src/components/Graph/GraphWithLegend.story.tsx @@ -0,0 +1,87 @@ +import React from 'react'; +import { storiesOf } from '@storybook/react'; + +import { select, text } from '@storybook/addon-knobs'; +import { withHorizontallyCenteredStory } from '../../utils/storybook/withCenteredStory'; +import { GraphWithLegend } from './GraphWithLegend'; + +import { mockGraphWithLegendData } from './mockGraphWithLegendData'; +import { action } from '@storybook/addon-actions'; +import { LegendPlacement, LegendDisplayMode } from '../Legend/Legend'; +const GraphWithLegendStories = storiesOf('Visualizations/Graph/GraphWithLegend', module); +GraphWithLegendStories.addDecorator(withHorizontallyCenteredStory); + +const getStoriesKnobs = () => { + const containerWidth = select( + 'Container width', + { + Small: '200px', + Medium: '500px', + 'Full width': '100%', + }, + '100%' + ); + const containerHeight = select( + 'Container height', + { + Small: '200px', + Medium: '400px', + 'Full height': '100%', + }, + '400px' + ); + + const rightAxisSeries = text('Right y-axis series, i.e. A,C', ''); + + const legendPlacement = select( + 'Legend placement', + { + under: 'under', + right: 'right', + }, + 'under' + ); + const renderLegendAsTable = select( + 'Render legend as', + { + list: false, + table: true, + }, + false + ); + + return { + containerWidth, + containerHeight, + rightAxisSeries, + legendPlacement, + renderLegendAsTable, + }; +}; + +GraphWithLegendStories.add('default', () => { + const { containerWidth, containerHeight, rightAxisSeries, legendPlacement, renderLegendAsTable } = getStoriesKnobs(); + + const props = mockGraphWithLegendData({ + onSeriesColorChange: action('Series color changed'), + onSeriesAxisToggle: action('Series y-axis changed'), + displayMode: renderLegendAsTable ? LegendDisplayMode.Table : LegendDisplayMode.List, + }); + const series = props.series.map(s => { + if ( + rightAxisSeries + .split(',') + .map(s => s.trim()) + .indexOf(s.label.split('-')[0]) > -1 + ) { + s.yAxis = 2; + } + + return s; + }); + return ( +
+ , +
+ ); +}); diff --git a/packages/grafana-ui/src/components/Graph/GraphWithLegend.tsx b/packages/grafana-ui/src/components/Graph/GraphWithLegend.tsx new file mode 100644 index 0000000000000..162c24758eae7 --- /dev/null +++ b/packages/grafana-ui/src/components/Graph/GraphWithLegend.tsx @@ -0,0 +1,125 @@ +// Libraries +import _ from 'lodash'; +import React from 'react'; + +import { css } from 'emotion'; +import { Graph, GraphProps } from './Graph'; +import { LegendRenderOptions, LegendItem, LegendDisplayMode } from '../Legend/Legend'; +import { GraphLegend } from './GraphLegend'; +import { CustomScrollbar } from '../CustomScrollbar/CustomScrollbar'; +import { GraphSeriesValue } from '../../types/graph'; + +export type SeriesOptionChangeHandler = (label: string, option: TOption) => void; +export type SeriesColorChangeHandler = SeriesOptionChangeHandler; +export type SeriesAxisToggleHandler = SeriesOptionChangeHandler; + +export interface GraphWithLegendProps extends GraphProps, LegendRenderOptions { + isLegendVisible: boolean; + displayMode: LegendDisplayMode; + sortLegendBy?: string; + sortLegendDesc?: boolean; + onSeriesColorChange: SeriesColorChangeHandler; + onSeriesAxisToggle?: SeriesAxisToggleHandler; + onSeriesToggle?: (label: string, event: React.MouseEvent) => void; + onToggleSort: (sortBy: string) => void; +} + +const getGraphWithLegendStyles = ({ placement }: GraphWithLegendProps) => ({ + wrapper: css` + display: flex; + flex-direction: ${placement === 'under' ? 'column' : 'row'}; + height: 100%; + `, + graphContainer: css` + min-height: 65%; + flex-grow: 1; + `, + legendContainer: css` + padding: 10px 0; + max-height: ${placement === 'under' ? '35%' : 'none'}; + `, +}); + +const shouldHideLegendItem = (data: GraphSeriesValue[][], hideEmpty = false, hideZero = false) => { + const isZeroOnlySeries = data.reduce((acc, current) => acc + (current[1] || 0), 0) === 0; + const isNullOnlySeries = !data.reduce((acc, current) => acc && current[1] !== null, true); + + return (hideEmpty && isNullOnlySeries) || (hideZero && isZeroOnlySeries); +}; + +export const GraphWithLegend: React.FunctionComponent = (props: GraphWithLegendProps) => { + const { + series, + timeRange, + width, + height, + showBars, + showLines, + showPoints, + sortLegendBy, + sortLegendDesc, + isLegendVisible, + displayMode, + placement, + onSeriesAxisToggle, + onSeriesColorChange, + onSeriesToggle, + onToggleSort, + hideEmpty, + hideZero, + } = props; + const { graphContainer, wrapper, legendContainer } = getGraphWithLegendStyles(props); + + const legendItems = series.reduce((acc, s) => { + return shouldHideLegendItem(s.data, hideEmpty, hideZero) + ? acc + : acc.concat([ + { + label: s.label, + color: s.color, + isVisible: s.isVisible, + yAxis: s.yAxis, + displayValues: s.info || [], + }, + ]); + }, []); + + return ( +
+
+ !!s.isVisible)} + timeRange={timeRange} + showLines={showLines} + showPoints={showPoints} + showBars={showBars} + width={width} + height={height} + key={isLegendVisible ? 'legend-visible' : 'legend-invisible'} + /> +
+ + {isLegendVisible && ( +
+ + { + if (onSeriesToggle) { + onSeriesToggle(item.label, event); + } + }} + onSeriesColorChange={onSeriesColorChange} + onSeriesAxisToggle={onSeriesAxisToggle} + onToggleSort={onToggleSort} + /> + +
+ )} +
+ ); +}; diff --git a/packages/grafana-ui/src/components/Graph/mockGraphWithLegendData.ts b/packages/grafana-ui/src/components/Graph/mockGraphWithLegendData.ts new file mode 100644 index 0000000000000..2e150eb04ea53 --- /dev/null +++ b/packages/grafana-ui/src/components/Graph/mockGraphWithLegendData.ts @@ -0,0 +1,3316 @@ +import { GraphWithLegendProps } from './GraphWithLegend'; +import moment from 'moment'; +import { LegendDisplayMode } from '../Legend/Legend'; +// import { LegendList } from '../Legend/LegendList'; + +export const mockGraphWithLegendData = ({ + displayMode, + onSeriesColorChange, + onSeriesAxisToggle, +}: Partial): GraphWithLegendProps => ({ + series: [ + { + label: 'A-series', + data: [ + [1554793274247, 20.313880709398614], + [1554793294247, 20.08104852830009], + [1554793314247, 19.992843162258378], + [1554793334247, 20.41499645651864], + [1554793354247, 20.121418991609794], + [1554793374247, 19.680864164371194], + [1554793394247, 19.246572984138286], + [1554793414247, 19.46125180187392], + [1554793434247, 19.039716655273562], + [1554793454247, 18.92237339584932], + [1554793474247, 19.032006074688397], + [1554793494247, 18.554026324427063], + [1554793514247, 18.638230492753188], + [1554793534247, 18.30793730234939], + [1554793554247, 18.19449466810041], + [1554793574247, 18.344646319460164], + [1554793594247, 18.11110436496195], + [1554793614247, 18.22114686279577], + [1554793634247, 17.963238261916597], + [1554793654247, 18.066099068004895], + [1554793674247, 17.820666244047295], + [1554793694247, 17.658322234243347], + [1554793714247, 17.446542397799462], + [1554793734247, 17.371388468792254], + [1554793754247, 17.217876617816966], + [1554793774247, 17.257521109488476], + [1554793794247, 17.58336498893354], + [1554793814247, 17.59090539787382], + [1554793834247, 17.87356599440561], + [1554793854247, 17.4806967502818], + [1554793874247, 17.92887698327966], + [1554793894247, 17.905603390367062], + [1554793914247, 18.3347835049674], + [1554793934247, 18.25272866220099], + [1554793954247, 17.864277261462757], + [1554793974247, 18.152124227305972], + [1554793994247, 18.259495538365456], + [1554794014247, 18.489018553448787], + [1554794034247, 18.821247189702426], + [1554794054247, 19.08003017107941], + [1554794074247, 19.491262702076856], + [1554794094247, 19.1827682465781], + [1554794114247, 19.182869096769963], + [1554794134247, 19.095115140924634], + [1554794154247, 19.05299994112004], + [1554794174247, 18.590606725871183], + [1554794194247, 19.07931422785976], + [1554794214247, 19.477891144970496], + [1554794234247, 19.21897148797869], + [1554794254247, 18.77220964737733], + [1554794274247, 18.803310056748714], + [1554794294247, 18.88481860551549], + [1554794314247, 19.194980590780798], + [1554794334247, 19.13519891641105], + [1554794354247, 19.22496773205921], + [1554794374247, 18.735469623659885], + [1554794394247, 19.021576009377863], + [1554794414247, 19.246289879789813], + [1554794434247, 19.105419144705216], + [1554794454247, 19.571674122877262], + [1554794474247, 19.891144340237346], + [1554794494247, 19.676557234305022], + [1554794514247, 19.345971553425187], + [1554794534247, 19.048466632282935], + [1554794554247, 18.570617820383877], + [1554794574247, 18.734467617535582], + [1554794594247, 19.04927504415475], + [1554794614247, 19.166389592466707], + [1554794634247, 18.794409779030502], + [1554794654247, 19.181010534033533], + [1554794674247, 19.37350362803945], + [1554794694247, 18.950932112848196], + [1554794714247, 18.488019913458178], + [1554794734247, 18.86684581263146], + [1554794754247, 18.983697195043614], + [1554794774247, 18.531710787820366], + [1554794794247, 19.01566943622132], + [1554794814247, 19.40748484804793], + [1554794834247, 19.435103380796], + [1554794854247, 19.39782995665856], + [1554794874247, 19.438254903387058], + [1554794894247, 19.10031735117575], + [1554794914247, 18.980821678099883], + [1554794934247, 18.834722745415952], + [1554794954247, 18.373878360320436], + [1554794974247, 18.84943998519851], + [1554794994247, 19.106939136485085], + [1554795014247, 19.052362017480817], + [1554795034247, 18.648880645925313], + [1554795054247, 18.8814523423611], + [1554795074247, 18.857826541729597], + [1554795094247, 19.008845156827967], + [1554795114247, 19.28178805280102], + [1554795134247, 19.602626486969534], + [1554795154247, 19.985163722852473], + [1554795174247, 20.322606652974994], + [1554795194247, 20.586587642388157], + [1554795214247, 20.39315542962396], + [1554795234247, 20.842997727238604], + [1554795254247, 20.479452567602156], + [1554795274247, 20.56819178541087], + [1554795294247, 20.317663197821815], + [1554795314247, 20.188138468315195], + [1554795334247, 19.705561316215853], + [1554795354247, 19.479509927065397], + [1554795374247, 19.447752179188306], + [1554795394247, 19.181232835157697], + [1554795414247, 19.459427085329224], + [1554795434247, 19.05132746752971], + [1554795454247, 18.841056436711025], + [1554795474247, 18.831360086228283], + [1554795494247, 18.86658975782061], + [1554795514247, 18.698033676789784], + [1554795534247, 18.929839598501857], + [1554795554247, 19.390241447580827], + [1554795574247, 19.339437395648535], + [1554795594247, 19.666634660902492], + [1554795614247, 19.767170656886673], + [1554795634247, 19.911342704118248], + [1554795654247, 20.37312718893495], + [1554795674247, 20.43933881511363], + [1554795694247, 20.653859896728182], + [1554795714247, 20.77646124725375], + [1554795734247, 20.98307062620013], + [1554795754247, 20.76453112065912], + [1554795774247, 20.705974067242977], + [1554795794247, 20.260579571260333], + [1554795814247, 20.662046577866715], + [1554795834247, 20.2449850759113], + [1554795854247, 19.756051593693513], + [1554795874247, 19.619517424157557], + [1554795894247, 19.29791716902326], + [1554795914247, 19.179238038293985], + [1554795934247, 19.46627554259614], + [1554795954247, 19.66575441011187], + [1554795974247, 19.940391553759927], + [1554795994247, 20.298913074442243], + [1554796014247, 20.13096011323593], + [1554796034247, 20.23340372021052], + [1554796054247, 20.585390686449408], + [1554796074247, 20.997775066783095], + [1554796094247, 21.04685139350083], + [1554796114247, 20.778323773832028], + [1554796134247, 20.72898684239931], + [1554796154247, 20.746854320861416], + [1554796174247, 21.080311484818665], + [1554796194247, 21.318217286443893], + [1554796214247, 21.54956043220836], + [1554796234247, 21.271074017912362], + [1554796254247, 21.116019947184835], + [1554796274247, 20.62448718389609], + [1554796294247, 20.721537234112986], + [1554796314247, 20.36305734406211], + [1554796334247, 20.42644876993651], + [1554796354247, 20.16545544539798], + [1554796374247, 20.26968616779487], + [1554796394247, 20.3397829790123], + [1554796414247, 20.03067628549628], + [1554796434247, 20.131150696804713], + [1554796454247, 19.996918423173987], + [1554796474247, 20.3383860035356], + [1554796494247, 19.874575784832267], + [1554796514247, 19.874280591895396], + [1554796534247, 19.555747916068814], + [1554796554247, 19.512322604239518], + [1554796574247, 19.971727883913204], + [1554796594247, 19.972663038357112], + [1554796614247, 20.215750537357355], + [1554796634247, 19.811615680952983], + [1554796654247, 19.420570259916218], + [1554796674247, 19.78388048792971], + [1554796694247, 19.809444584661886], + [1554796714247, 19.744609482332653], + [1554796734247, 20.039793233334624], + [1554796754247, 19.656750321018873], + [1554796774247, 19.655016503008568], + [1554796794247, 19.91706698974138], + [1554796814247, 20.023553168738367], + [1554796834247, 20.077071328813926], + [1554796854247, 19.88531080019798], + [1554796874247, 20.274356827283746], + [1554796894247, 19.871521517855285], + [1554796914247, 19.849189625281237], + [1554796934247, 19.545290760324306], + [1554796954247, 19.18091527224302], + [1554796974247, 19.452336236879457], + [1554796994247, 19.146012613561403], + [1554797014247, 19.354033871521427], + [1554797034247, 19.374660496846577], + [1554797054247, 19.545775904269995], + [1554797074247, 19.466624079433085], + [1554797094247, 19.024037215414324], + [1554797114247, 18.676381124829952], + [1554797134247, 18.607609672523235], + [1554797154247, 18.45093227466119], + [1554797174247, 18.497642680307425], + [1554797194247, 18.84995936205565], + [1554797214247, 19.254794470921848], + [1554797234247, 19.118449528190986], + [1554797254247, 19.30669615290519], + [1554797274247, 19.289538518091465], + [1554797294247, 19.402478297163942], + [1554797314247, 19.142856488362764], + [1554797334247, 18.86825661399161], + [1554797354247, 18.439007909998104], + [1554797374247, 18.776471890064464], + [1554797394247, 18.491952005082823], + [1554797414247, 18.44926487148877], + [1554797434247, 18.610300172432634], + [1554797454247, 18.800869256547237], + [1554797474247, 19.155873759250404], + [1554797494247, 19.31190799141301], + [1554797514247, 18.825285394687576], + [1554797534247, 19.095824434613274], + [1554797554247, 19.578941846370167], + [1554797574247, 19.53513022972872], + [1554797594247, 19.3934810416622], + [1554797614247, 19.763910623076562], + [1554797634247, 19.804650392017304], + [1554797654247, 20.20814902135129], + [1554797674247, 20.42627007519049], + [1554797694247, 20.511388593346943], + [1554797714247, 20.433559812648035], + [1554797734247, 20.020788343527283], + [1554797754247, 19.82882881602156], + [1554797774247, 19.956206997916635], + [1554797794247, 19.56420055511053], + [1554797814247, 19.58095464334045], + [1554797834247, 19.102116442251454], + [1554797854247, 19.321044748170134], + [1554797874247, 19.278620558285734], + [1554797894247, 19.084803610335157], + [1554797914247, 19.163238894440624], + [1554797934247, 19.025819265964852], + [1554797954247, 18.738817306013523], + [1554797974247, 18.510704203480046], + [1554797994247, 18.92399476064368], + [1554798014247, 18.440467253152406], + [1554798034247, 18.283511925716606], + [1554798054247, 18.19183485113992], + [1554798074247, 17.83694725296019], + [1554798094247, 18.017076994342407], + [1554798114247, 18.413747553873502], + [1554798134247, 18.005072087426772], + [1554798154247, 17.65050119520046], + [1554798174247, 17.457829234397302], + [1554798194247, 17.275106596433275], + [1554798214247, 17.004692080070477], + [1554798234247, 17.22971019286104], + [1554798254247, 16.894301628540166], + [1554798274247, 16.44401141001666], + [1554798294247, 16.09012511787796], + [1554798314247, 15.833370717085522], + [1554798334247, 15.678198461092794], + [1554798354247, 15.617087273922538], + [1554798374247, 15.642521752347575], + [1554798394247, 15.824114909605015], + [1554798414247, 15.83242331224305], + [1554798434247, 16.26807306007194], + [1554798454247, 15.873706905242111], + [1554798474247, 16.164271858937447], + [1554798494247, 16.273629141890627], + [1554798514247, 15.837914408005892], + [1554798534247, 16.05357618383023], + [1554798554247, 16.358538521510823], + [1554798574247, 16.625077510565273], + [1554798594247, 16.235680011268176], + [1554798614247, 16.61406857262163], + [1554798634247, 16.158350150979114], + [1554798654247, 15.812238103859952], + [1554798674247, 15.650024480664284], + [1554798694247, 15.154774996351108], + [1554798714247, 15.08214977373202], + [1554798734247, 15.227710040181536], + [1554798754247, 15.373882728706388], + [1554798774247, 15.107453513219458], + [1554798794247, 14.849139739563727], + [1554798814247, 14.814129962471274], + [1554798834247, 14.542311965505606], + [1554798854247, 14.427101844163694], + [1554798874247, 14.74888608186797], + [1554798894247, 14.792451034664934], + [1554798914247, 15.175048493928175], + [1554798934247, 15.014974152971416], + [1554798954247, 15.268983047378917], + [1554798974247, 15.282030183678799], + [1554798994247, 15.602132376241688], + [1554799014247, 15.23005106786267], + [1554799034247, 15.636887587953181], + [1554799054247, 15.805420273666], + [1554799074247, 16.048541268247742], + [1554799094247, 15.838719939306882], + [1554799114247, 15.708752782909732], + [1554799134247, 16.066680817193237], + [1554799154247, 16.08650897981167], + [1554799174247, 16.256833754570117], + [1554799194247, 16.58911099339985], + [1554799214247, 16.649537934236353], + [1554799234247, 16.887066362197004], + [1554799254247, 16.47612075923721], + [1554799274247, 16.295702450730463], + [1554799294247, 15.959097792634903], + [1554799314247, 15.576774485820334], + [1554799334247, 15.903959111453402], + [1554799354247, 15.850548648128646], + [1554799374247, 15.988279814202075], + [1554799394247, 16.04008606971051], + [1554799414247, 16.334614032926087], + [1554799434247, 16.487440096615437], + [1554799454247, 16.075387529551623], + [1554799474247, 16.01349775782911], + [1554799494247, 16.40687699618258], + [1554799514247, 16.776868163518795], + [1554799534247, 17.185567067824188], + [1554799554247, 17.015084468455086], + [1554799574247, 17.088300049509055], + [1554799594247, 17.08802703704262], + [1554799614247, 17.451986823807108], + [1554799634247, 16.95292997178481], + [1554799654247, 16.51059402590916], + [1554799674247, 16.60084209687119], + [1554799694247, 17.06600437213062], + [1554799714247, 17.233540826974814], + [1554799734247, 16.945799567917064], + [1554799754247, 17.37443597552288], + [1554799774247, 16.90064599344329], + [1554799794247, 17.22123127821873], + [1554799814247, 16.954378456750387], + [1554799834247, 17.148060018111345], + [1554799854247, 17.090794394519804], + [1554799874247, 17.35099506839045], + [1554799894247, 17.62732436629698], + [1554799914247, 17.576380903908223], + [1554799934247, 17.5787616954438], + [1554799954247, 17.89583025685836], + [1554799974247, 18.376038600962016], + [1554799994247, 17.91345499687831], + [1554800014247, 17.564064762434413], + [1554800034247, 18.034917870957752], + [1554800054247, 18.105816481120268], + [1554800074247, 17.77072863251834], + [1554800094247, 17.992278168519807], + [1554800114247, 18.07420472728541], + [1554800134247, 18.022893864572822], + [1554800154247, 18.511067946730545], + [1554800174247, 18.53868749198732], + [1554800194247, 18.4665014110292], + [1554800214247, 18.93261420838234], + [1554800234247, 18.62757758529829], + [1554800254247, 18.82704470974516], + [1554800274247, 18.617547568653528], + [1554800294247, 18.73952779241911], + [1554800314247, 18.444297284601785], + [1554800334247, 18.406712402146002], + [1554800354247, 18.53724765698832], + [1554800374247, 18.68355494811299], + [1554800394247, 19.05074641300459], + [1554800414247, 19.410594032681672], + [1554800434247, 19.13445258188613], + [1554800454247, 18.759185011234695], + [1554800474247, 18.68542467209139], + [1554800494247, 19.06896639146912], + [1554800514247, 18.6051957309167], + [1554800534247, 18.42031016075946], + [1554800554247, 18.348974546182863], + [1554800574247, 18.20505247170292], + [1554800594247, 18.69452503019689], + [1554800614247, 18.934944507853064], + [1554800634247, 18.66230144695166], + [1554800654247, 18.771678982276487], + [1554800674247, 18.902003446382544], + [1554800694247, 18.817100898765727], + [1554800714247, 18.59223352705925], + [1554800734247, 18.25969133611703], + [1554800754247, 17.831061793894364], + [1554800774247, 17.6728034881081], + [1554800794247, 17.233411759672073], + [1554800814247, 16.8450149813612], + [1554800834247, 16.755767493272042], + [1554800854247, 16.41492274775498], + [1554800874247, 16.334526892010413], + [1554800894247, 16.29889828198967], + [1554800914247, 16.122001485153216], + [1554800934247, 15.738121737315627], + [1554800954247, 16.182985021379192], + [1554800974247, 15.77999826616122], + [1554800994247, 15.870712900527263], + [1554801014247, 16.220417258476434], + [1554801034247, 15.824531476775649], + [1554801054247, 15.385318138167277], + [1554801074247, 15.402539411608153], + [1554801094247, 15.435752247259211], + [1554801114247, 15.141629819254383], + [1554801134247, 14.871864320006623], + [1554801154247, 14.873766246615965], + [1554801174247, 15.345995441924948], + [1554801194247, 15.557439903201686], + [1554801214247, 15.555467370168937], + [1554801234247, 15.767954832856459], + [1554801254247, 15.724226707330411], + [1554801274247, 16.141832734977395], + [1554801294247, 16.078874676735936], + [1554801314247, 16.520447865480683], + [1554801334247, 16.852278087210898], + [1554801354247, 16.391326466348595], + [1554801374247, 16.83676425276248], + [1554801394247, 17.326748972037034], + [1554801414247, 17.48254647807906], + [1554801434247, 17.785717992907795], + [1554801454247, 18.161130877112615], + [1554801474247, 18.65474919931944], + [1554801494247, 19.151368669051376], + [1554801514247, 19.51103704690084], + [1554801534247, 19.244060870618746], + [1554801554247, 18.762678457259234], + [1554801574247, 18.283405636211146], + [1554801594247, 18.2058134112917], + [1554801614247, 18.318742517158878], + [1554801634247, 18.125680497027943], + [1554801654247, 17.859067813647037], + [1554801674247, 17.430770939942565], + [1554801694247, 17.48829025285418], + [1554801714247, 17.41660346714896], + [1554801734247, 17.267176902967986], + [1554801754247, 17.134933206965716], + [1554801774247, 16.859998621613713], + [1554801794247, 17.17957666828268], + [1554801814247, 16.85553452636789], + [1554801834247, 17.021618900377234], + [1554801854247, 17.28697744467099], + [1554801874247, 17.026404541469358], + [1554801894247, 16.74964033058671], + [1554801914247, 17.1446553563511], + [1554801934247, 16.686389751463988], + [1554801954247, 16.813825821001483], + [1554801974247, 17.00642230043151], + [1554801994247, 17.377258024761936], + [1554802014247, 17.50127422146399], + [1554802034247, 17.3817548239187], + [1554802054247, 17.291601771428926], + [1554802074247, 17.221925959717726], + [1554802094247, 17.465156492221098], + [1554802114247, 17.356019827095594], + [1554802134247, 17.779054323656062], + [1554802154247, 18.062316118223833], + [1554802174247, 17.86066337329332], + [1554802194247, 17.642699917109947], + [1554802214247, 17.889975752328375], + [1554802234247, 18.20280332736594], + [1554802254247, 18.128064273603368], + [1554802274247, 18.341350547206854], + [1554802294247, 18.69202676598315], + [1554802314247, 18.997182695237544], + [1554802334247, 18.56932097324519], + [1554802354247, 18.127417617110936], + [1554802374247, 18.563591061578247], + [1554802394247, 18.935739093711494], + [1554802414247, 19.328009657837754], + [1554802434247, 19.051987873183407], + [1554802454247, 19.302136515646502], + [1554802474247, 19.444975293950954], + [1554802494247, 19.056805905772976], + [1554802514247, 19.489349320985696], + [1554802534247, 19.029312427568964], + [1554802554247, 18.66188283167321], + [1554802574247, 18.966232924802636], + [1554802594247, 19.333887271116005], + [1554802614247, 19.49454092865925], + [1554802634247, 19.225058732253423], + [1554802654247, 19.50584851870466], + [1554802674247, 19.825454559183065], + [1554802694247, 20.275633981781876], + [1554802714247, 19.796255964131436], + [1554802734247, 19.51553115747093], + [1554802754247, 19.168722344585948], + [1554802774247, 19.259002618369472], + [1554802794247, 19.41016958266869], + [1554802814247, 19.907823260030593], + [1554802834247, 19.631151352570843], + [1554802854247, 19.905244374936135], + [1554802874247, 19.798764882824536], + [1554802894247, 20.008082677788725], + [1554802914247, 20.064688572823655], + [1554802934247, 19.98935102323253], + [1554802954247, 19.685443067226227], + [1554802974247, 19.24365424044176], + [1554802994247, 19.67853298503077], + [1554803014247, 19.417464736403762], + [1554803034247, 19.099948997361082], + [1554803054247, 18.884888830958005], + [1554803074247, 19.275934909503246], + [1554803094247, 18.857388403280176], + [1554803114247, 18.395179891885807], + [1554803134247, 18.15582485375867], + [1554803154247, 18.461384373169917], + [1554803174247, 18.65820855056107], + [1554803194247, 18.780890910474543], + [1554803214247, 18.934246513949834], + [1554803234247, 18.940994398971654], + [1554803254247, 18.80380381297457], + [1554803274247, 18.975556784451616], + [1554803294247, 18.937892650321324], + [1554803314247, 19.208253250171996], + [1554803334247, 19.479912061820972], + [1554803354247, 19.817839292405047], + [1554803374247, 20.216166795485478], + [1554803394247, 20.037801151725823], + [1554803414247, 20.089230983878828], + [1554803434247, 19.82509936207721], + [1554803454247, 19.499858580193926], + [1554803474247, 19.241945160507615], + [1554803494247, 19.59878062745236], + [1554803514247, 19.769393970536225], + [1554803534247, 19.618300805498567], + [1554803554247, 19.308561167940837], + [1554803574247, 18.97105055750365], + [1554803594247, 18.686699428116373], + [1554803614247, 18.678264142459323], + [1554803634247, 18.20910669657999], + [1554803654247, 18.400110408790137], + [1554803674247, 18.586150272944028], + [1554803694247, 19.04398053920283], + [1554803714247, 18.668729219956465], + [1554803734247, 18.98873600767759], + [1554803754247, 18.56574832702069], + [1554803774247, 18.79337113112325], + [1554803794247, 18.593258461416298], + [1554803814247, 18.800523265764216], + [1554803834247, 18.65948976366625], + [1554803854247, 18.817685852229896], + [1554803874247, 18.340420869044404], + [1554803894247, 18.18299492246204], + [1554803914247, 17.802066447573516], + [1554803934247, 18.071547724968173], + [1554803954247, 18.049751013799774], + [1554803974247, 17.87610824900385], + [1554803994247, 18.070504699571167], + [1554804014247, 18.27223858743518], + [1554804034247, 18.659606010902305], + [1554804054247, 18.39868265036132], + [1554804074247, 18.629068097966716], + [1554804094247, 18.337125728095433], + [1554804114247, 17.95304427209962], + [1554804134247, 18.116835197158572], + [1554804154247, 17.98894688777001], + [1554804174247, 18.487042644098864], + [1554804194247, 18.48570091736673], + [1554804214247, 18.512055466874543], + [1554804234247, 18.333051234583998], + [1554804254247, 18.603280990702924], + [1554804274247, 18.40207930027631], + [1554804294247, 17.971588925595327], + [1554804314247, 17.961758137993403], + [1554804334247, 18.226019089234516], + [1554804354247, 18.35225998608116], + [1554804374247, 18.639765096991333], + [1554804394247, 18.550712331665693], + [1554804414247, 18.692217967806517], + [1554804434247, 19.050071777223973], + [1554804454247, 19.37757827497838], + [1554804474247, 19.256081586202434], + [1554804494247, 18.90425477864548], + [1554804514247, 19.328915814839135], + [1554804534247, 18.94477208210245], + [1554804554247, 18.921554398027723], + [1554804574247, 19.2492095289071], + [1554804594247, 19.24109165045788], + [1554804614247, 19.204718006137995], + [1554804634247, 19.314243927875925], + [1554804654247, 18.93826896103946], + [1554804674247, 18.843386261025607], + [1554804694247, 18.452727827390838], + [1554804714247, 18.31288494939828], + [1554804734247, 18.28969441044889], + [1554804754247, 18.279839879184603], + [1554804774247, 17.89656879221293], + [1554804794247, 17.779765781544064], + [1554804814247, 18.047473543757114], + [1554804834247, 17.581871597783845], + [1554804854247, 17.788255131385938], + [1554804874247, 17.73564406039265], + [1554804894247, 17.85521468570053], + [1554804914247, 17.93504986472167], + [1554804934247, 18.346975101938344], + [1554804954247, 18.746813567661178], + [1554804974247, 18.513442964330473], + [1554804994247, 18.689558935359702], + [1554805014247, 18.81268731017689], + [1554805034247, 18.92030204915925], + [1554805054247, 18.525588855553714], + [1554805074247, 18.39543929691923], + [1554805094247, 18.724426995823144], + [1554805114247, 18.97615036082755], + [1554805134247, 18.735574008669783], + [1554805154247, 18.51218532804814], + [1554805174247, 19.002998946420824], + [1554805194247, 19.327807288989124], + [1554805214247, 19.782716047902646], + [1554805234247, 20.0799405830441], + [1554805254247, 20.309169195940356], + [1554805274247, 20.424494554101425], + [1554805294247, 20.016587666434507], + [1554805314247, 19.90717258752296], + [1554805334247, 19.705116713312897], + [1554805354247, 19.714068611166343], + [1554805374247, 20.092668883679085], + [1554805394247, 20.45876075819353], + [1554805414247, 19.978968126702078], + [1554805434247, 19.726344289707207], + [1554805454247, 19.67555531958179], + [1554805474247, 19.248318379398153], + [1554805494247, 18.92559402301265], + [1554805514247, 19.05593780593657], + [1554805534247, 18.78655877710173], + [1554805554247, 18.72278713083883], + [1554805574247, 18.883178543004075], + [1554805594247, 19.214524420867246], + [1554805614247, 19.312331181864046], + [1554805634247, 19.36197097685949], + [1554805654247, 18.873989064227487], + [1554805674247, 18.50980867117683], + [1554805694247, 18.591329413843802], + [1554805714247, 18.440948189650424], + [1554805734247, 18.49790909406058], + [1554805754247, 18.22993181565998], + [1554805774247, 18.176792706963482], + [1554805794247, 17.742068630596], + [1554805814247, 18.127171061480716], + [1554805834247, 18.61113434280144], + [1554805854247, 18.266545971249155], + [1554805874247, 18.051239661919034], + [1554805894247, 18.121586360148203], + [1554805914247, 18.28596328116828], + [1554805934247, 18.03804682147004], + [1554805954247, 17.92912894978805], + [1554805974247, 18.248018885767422], + [1554805994247, 18.170264071486372], + [1554806014247, 18.047108689907635], + [1554806034247, 18.379913022515094], + [1554806054247, 18.7985656956094], + [1554806074247, 18.456930330499166], + [1554806094247, 18.295835868859527], + [1554806114247, 18.19306037002757], + [1554806134247, 17.93075614519311], + [1554806154247, 17.57537661265962], + [1554806174247, 17.182737877206783], + [1554806194247, 17.608978667641548], + [1554806214247, 18.091581656416327], + [1554806234247, 18.12482889513131], + [1554806254247, 18.185538016887143], + [1554806274247, 18.20938728273094], + [1554806294247, 18.57802459483719], + [1554806314247, 18.27478663407127], + [1554806334247, 18.18309828031528], + [1554806354247, 18.046046587405275], + [1554806374247, 18.110230133577016], + [1554806394247, 17.77958854513807], + [1554806414247, 17.755552238573014], + [1554806434247, 17.93407403212182], + [1554806454247, 17.834950651753168], + [1554806474247, 17.62487333533259], + [1554806494247, 17.818756369279967], + [1554806514247, 17.39004492227227], + [1554806534247, 17.193372581431124], + [1554806554247, 16.95129928749413], + [1554806574247, 17.016306124404707], + [1554806594247, 16.712795603328992], + [1554806614247, 16.53416774729842], + [1554806634247, 16.291809836675082], + [1554806654247, 16.672668617071984], + [1554806674247, 16.873191162896983], + [1554806694247, 17.10782981368545], + [1554806714247, 16.727951485311106], + [1554806734247, 16.96036493957726], + [1554806754247, 16.514521429647758], + [1554806774247, 16.084114804956304], + [1554806794247, 16.30254578168955], + [1554806814247, 16.534087254833164], + [1554806834247, 16.056953526055793], + [1554806854247, 15.584026045940329], + [1554806874247, 15.618649451155633], + [1554806894247, 15.538672348396526], + [1554806914247, 15.9620988253781], + [1554806934247, 16.43967579598588], + [1554806954247, 16.828110677544426], + [1554806974247, 16.71539758814196], + [1554806994247, 16.91114798772243], + [1554807014247, 16.970190521091418], + [1554807034247, 16.652980147832025], + [1554807054247, 16.95589224983671], + [1554807074247, 17.42272242301996], + [1554807094247, 17.268816017793508], + [1554807114247, 16.977764959290678], + [1554807134247, 17.30696723687278], + [1554807154247, 16.809909430780127], + [1554807174247, 16.834741273519402], + [1554807194247, 16.417886405774215], + [1554807214247, 16.762016909140442], + [1554807234247, 17.138100938886808], + [1554807254247, 17.230621881528826], + [1554807274247, 17.72741817378255], + [1554807294247, 17.776039783674833], + [1554807314247, 17.87884125809111], + [1554807334247, 17.38224934430264], + [1554807354247, 17.412052920655796], + [1554807374247, 17.75691024403483], + [1554807394247, 17.435099479511265], + [1554807414247, 17.151274766857476], + [1554807434247, 17.593342658698447], + [1554807454247, 17.334653653522253], + [1554807474247, 17.476092698124962], + [1554807494247, 17.630521911429216], + [1554807514247, 18.00861111106235], + [1554807534247, 18.17241595532054], + [1554807554247, 18.19384073799544], + [1554807574247, 18.17660445507042], + [1554807594247, 17.889367920812205], + [1554807614247, 17.662933364897235], + [1554807634247, 17.996510291559048], + [1554807654247, 18.10999075434485], + [1554807674247, 18.08907251127535], + [1554807694247, 18.362301935391887], + [1554807714247, 18.73675882969702], + [1554807734247, 18.777242368554464], + [1554807754247, 18.728454583314942], + [1554807774247, 18.67778255980091], + [1554807794247, 18.21170532262526], + [1554807814247, 18.336013592669683], + [1554807834247, 18.486708118751547], + [1554807854247, 18.481457501410357], + [1554807874247, 18.580337444483], + [1554807894247, 18.585776154287643], + [1554807914247, 18.277367743334594], + [1554807934247, 18.4748120256564], + [1554807954247, 17.988109644084805], + [1554807974247, 17.50359155734211], + [1554807994247, 17.054621181707596], + [1554808014247, 17.050657416275882], + [1554808034247, 17.53340725427101], + [1554808054247, 17.2823824698551], + [1554808074247, 17.230073631700503], + [1554808094247, 17.660070302810404], + [1554808114247, 17.715497232909698], + [1554808134247, 17.89362479407042], + [1554808154247, 17.675851255462916], + [1554808174247, 17.798916844787072], + [1554808194247, 17.370179004365454], + [1554808214247, 16.935754571814158], + [1554808234247, 16.575111172315417], + [1554808254247, 16.957750516945833], + [1554808274247, 16.906067262875016], + [1554808294247, 17.147262833877377], + [1554808314247, 17.25481302019992], + [1554808334247, 16.88623932971355], + [1554808354247, 16.826900270442206], + [1554808374247, 17.10501975118114], + [1554808394247, 17.374628130862487], + [1554808414247, 17.07918741156744], + [1554808434247, 17.23444863499987], + [1554808454247, 16.810847489538], + [1554808474247, 17.113170666785386], + [1554808494247, 17.034661603204178], + [1554808514247, 17.423832159197985], + [1554808534247, 17.384975048960655], + [1554808554247, 17.157321849221564], + [1554808574247, 17.295587749135628], + [1554808594247, 17.422000437377765], + [1554808614247, 17.569027537150625], + [1554808634247, 17.802041495838445], + [1554808654247, 17.424428662815046], + [1554808674247, 17.75925159046375], + [1554808694247, 18.22257416365628], + [1554808714247, 18.044788857332886], + [1554808734247, 17.71747698325384], + [1554808754247, 17.42290034812379], + [1554808774247, 17.78912609157009], + [1554808794247, 18.1697394821823], + [1554808814247, 18.370976940779865], + [1554808834247, 18.29486854059247], + [1554808854247, 18.551667794503583], + [1554808874247, 18.39828137765856], + [1554808894247, 18.25110684354119], + [1554808914247, 18.424132243647602], + [1554808934247, 17.928269310694105], + [1554808954247, 17.891590956635838], + [1554808974247, 17.615722459795265], + [1554808994247, 17.772868766141663], + [1554809014247, 17.3521751556697], + [1554809034247, 17.11182923580405], + [1554809054247, 17.305146213842725], + [1554809074247, 17.492812063228744], + [1554809094247, 17.15927912926812], + [1554809114247, 17.121703806114706], + [1554809134247, 17.501420046950543], + [1554809154247, 17.66727157116937], + [1554809174247, 17.812646877248156], + [1554809194247, 17.8037690723927], + [1554809214247, 17.80162956689889], + [1554809234247, 18.086665506982694], + [1554809254247, 18.03889674669137], + [1554809274247, 17.677390098732573], + [1554809294247, 17.879679198772564], + [1554809314247, 17.584585692982444], + [1554809334247, 17.959637391545176], + [1554809354247, 17.70704655382901], + [1554809374247, 17.689773136209624], + [1554809394247, 17.647501038318484], + [1554809414247, 18.10854669233636], + [1554809434247, 18.547843706612916], + [1554809454247, 18.982618348379056], + [1554809474247, 19.409752361871913], + [1554809494247, 19.86787108134553], + [1554809514247, 19.444411700870905], + [1554809534247, 19.89027726349466], + [1554809554247, 20.055647760029323], + [1554809574247, 20.332601604977377], + [1554809594247, 20.186961614150928], + [1554809614247, 19.91407780746553], + [1554809634247, 20.06820779595699], + [1554809654247, 20.080243472499426], + [1554809674247, 19.87713706193293], + [1554809694247, 19.681250241399276], + [1554809714247, 19.407668380876753], + [1554809734247, 19.56481750238362], + [1554809754247, 20.004756709116997], + [1554809774247, 19.535665690455815], + [1554809794247, 19.703425271030913], + [1554809814247, 19.54778722171676], + [1554809834247, 19.420410850783384], + [1554809854247, 19.753529304758832], + [1554809874247, 19.982263471778904], + [1554809894247, 19.648157753690636], + [1554809914247, 19.603042433340118], + [1554809934247, 19.589539301758066], + [1554809954247, 19.754466582431032], + [1554809974247, 20.200289417535693], + [1554809994247, 20.535073990717688], + [1554810014247, 20.96943211675856], + [1554810034247, 20.603270299687363], + [1554810054247, 20.173587705343607], + [1554810074247, 20.49979443254795], + [1554810094247, 20.822318394334552], + [1554810114247, 20.71823032496461], + [1554810134247, 20.536638182114388], + [1554810154247, 20.16245224098834], + [1554810174247, 20.365654035559984], + [1554810194247, 20.750786422033908], + [1554810214247, 20.88604429258989], + [1554810234247, 21.18290294700043], + [1554810254247, 20.96277049586266], + [1554810274247, 21.32180279162898], + [1554810294247, 21.0016299534294], + [1554810314247, 20.515341526228337], + [1554810334247, 20.780007817271024], + [1554810354247, 21.129163926216105], + [1554810374247, 20.934017218027808], + [1554810394247, 20.510533890923607], + [1554810414247, 20.960082138122935], + [1554810434247, 20.872825242653533], + [1554810454247, 21.292186812890325], + [1554810474247, 21.760142931714785], + [1554810494247, 21.306646483526887], + [1554810514247, 21.437367768346387], + [1554810534247, 20.988811366969344], + [1554810554247, 20.826107468511292], + [1554810574247, 21.013480581344588], + [1554810594247, 20.878538074356992], + [1554810614247, 20.445714347430684], + [1554810634247, 20.54588524875655], + [1554810654247, 20.934978857440115], + [1554810674247, 21.105549392177977], + [1554810694247, 21.207736265000023], + [1554810714247, 21.203503866950733], + [1554810734247, 21.429431725814705], + [1554810754247, 21.89991339950124], + [1554810774247, 21.83477989894718], + [1554810794247, 21.78661197761795], + [1554810814247, 22.13335025227573], + [1554810834247, 22.516701040475297], + [1554810854247, 22.310167692370655], + [1554810874247, 22.475935327328717], + [1554810894247, 22.8694841788587], + [1554810914247, 23.05226599324635], + [1554810934247, 22.866715279406986], + [1554810954247, 23.008981145929027], + [1554810974247, 23.36750693188728], + [1554810994247, 23.48291778171053], + [1554811014247, 23.240930373151908], + [1554811034247, 22.944886738114114], + [1554811054247, 23.158830075240527], + [1554811074247, 23.596562495280565], + [1554811094247, 23.40021118468351], + [1554811114247, 23.42527640835139], + [1554811134247, 23.881198207863623], + [1554811154247, 24.090637642151574], + [1554811174247, 23.847092938048707], + [1554811194247, 23.572586528171684], + [1554811214247, 24.047730244352827], + [1554811234247, 24.28476980671547], + [1554811254247, 24.220078573950836], + [1554811274247, 24.46310903911906], + [1554811294247, 24.466900483058215], + [1554811314247, 24.792636886264376], + [1554811334247, 24.409607815763987], + [1554811354247, 24.04038145482966], + [1554811374247, 23.94228680381039], + [1554811394247, 23.783424741152356], + [1554811414247, 23.99408856096362], + [1554811434247, 24.47637383884743], + [1554811454247, 24.51629571775181], + [1554811474247, 24.22032496180614], + [1554811494247, 23.999718831088842], + [1554811514247, 24.05610267025658], + [1554811534247, 24.266273560654778], + [1554811554247, 23.899707062230714], + [1554811574247, 23.449757627088108], + [1554811594247, 23.275400835189835], + [1554811614247, 23.358131530933832], + [1554811634247, 22.858872033834462], + [1554811654247, 23.155103991605444], + [1554811674247, 23.546405884685615], + [1554811694247, 23.90917052403149], + [1554811714247, 23.543095226841295], + [1554811734247, 23.06667148021866], + [1554811754247, 23.299268579089393], + [1554811774247, 22.996973766301174], + [1554811794247, 22.96294946666954], + [1554811814247, 23.416145844721562], + [1554811834247, 23.445491666152734], + [1554811854247, 23.78238653255798], + [1554811874247, 23.970608966935178], + [1554811894247, 24.0777671680898], + [1554811914247, 24.00485380564156], + [1554811934247, 23.615361773996426], + [1554811954247, 24.042391986475458], + [1554811974247, 24.30736210082872], + [1554811994247, 24.553424136396035], + [1554812014247, 24.071551516329688], + [1554812034247, 23.912887651146793], + [1554812054247, 24.058433667682323], + [1554812074247, 24.38218660318733], + [1554812094247, 23.95689725397855], + [1554812114247, 24.317964378479104], + [1554812134247, 24.5559033202204], + [1554812154247, 24.94115173656496], + [1554812174247, 24.53212651671396], + [1554812194247, 24.33543858114263], + [1554812214247, 24.054507222611196], + [1554812234247, 24.345650133921207], + [1554812254247, 24.146007669420054], + [1554812274247, 23.826238279851083], + [1554812294247, 23.337278633231435], + [1554812314247, 23.391970698372745], + [1554812334247, 23.854408022629926], + [1554812354247, 23.74054371722396], + [1554812374247, 23.358933571121483], + [1554812394247, 23.53597766617613], + [1554812414247, 23.214915406643048], + [1554812434247, 22.72418254100616], + [1554812454247, 23.124702432769304], + [1554812474247, 22.646160083682506], + [1554812494247, 22.95948496526543], + [1554812514247, 22.908704358394786], + [1554812534247, 23.24272599646963], + [1554812554247, 22.948667210920263], + [1554812574247, 22.88147470162189], + [1554812594247, 23.335409408552557], + [1554812614247, 23.2645912633166], + [1554812634247, 23.172964825433606], + [1554812654247, 22.792339297136], + [1554812674247, 22.451584230344984], + [1554812694247, 22.256332645514753], + [1554812714247, 22.70493151367683], + [1554812734247, 23.19120036442452], + [1554812754247, 22.98024145197298], + [1554812774247, 23.310399865487852], + [1554812794247, 23.423185487024213], + [1554812814247, 23.08331352748343], + [1554812834247, 22.843268303245647], + [1554812854247, 22.796590167015605], + [1554812874247, 22.680223263419595], + [1554812894247, 22.1936616130379], + [1554812914247, 22.276714302075444], + [1554812934247, 22.478761618242125], + [1554812954247, 22.744794053235506], + [1554812974247, 22.533635764779486], + [1554812994247, 22.856595863520614], + [1554813014247, 23.297624790450946], + [1554813034247, 23.744759897505187], + [1554813054247, 23.78062656641052], + [1554813074247, 23.670312262657962], + [1554813094247, 23.94875247338334], + [1554813114247, 24.159246180951172], + [1554813134247, 23.729042572247714], + [1554813154247, 23.851976354313422], + [1554813174247, 24.33054746691777], + [1554813194247, 24.431817667166843], + [1554813214247, 24.900251155368196], + [1554813234247, 25.38279196750522], + [1554813254247, 25.122592302324744], + [1554813274247, 25.477135073121406], + [1554813294247, 25.129731525812613], + [1554813314247, 25.09671010378041], + [1554813334247, 24.90703450812979], + [1554813354247, 24.410500684901685], + [1554813374247, 24.81457973663616], + [1554813394247, 24.468295893431918], + [1554813414247, 24.899199539507308], + [1554813434247, 24.85172339452315], + [1554813454247, 25.344326207633387], + [1554813474247, 25.17219266393189], + [1554813494247, 24.693990881064718], + [1554813514247, 24.388403883062693], + [1554813534247, 24.326079764182648], + [1554813554247, 24.411873941334573], + [1554813574247, 24.270472386262604], + [1554813594247, 24.324012831628146], + [1554813614247, 24.099857615227467], + [1554813634247, 24.21954267428356], + [1554813654247, 24.650473211711404], + [1554813674247, 24.44907260287802], + [1554813694247, 24.107046790019766], + [1554813714247, 24.510413313602093], + [1554813734247, 24.88113783461183], + [1554813754247, 24.73526251148137], + [1554813774247, 25.149750677672976], + [1554813794247, 25.014564303805702], + [1554813814247, 25.026928370829886], + [1554813834247, 24.86256716448043], + [1554813854247, 24.560488758456557], + [1554813874247, 24.615621474980536], + [1554813894247, 24.138639002410695], + [1554813914247, 23.940103271596822], + [1554813934247, 24.06200449551318], + [1554813954247, 24.159453290017183], + [1554813974247, 24.214708220020334], + [1554813994247, 23.94120965407676], + [1554814014247, 23.95298355113604], + [1554814034247, 24.314485240167457], + [1554814054247, 24.335912954173985], + [1554814074247, 24.52467444905973], + [1554814094247, 24.385124477285046], + [1554814114247, 24.700108123691678], + [1554814134247, 24.90576677567081], + [1554814154247, 24.99310554556539], + [1554814174247, 25.195800841696705], + [1554814194247, 25.278335915127883], + [1554814214247, 25.414083468286634], + [1554814234247, 25.52353974423631], + [1554814254247, 25.295016469723016], + [1554814274247, 25.419288424881053], + [1554814294247, 25.126441819261434], + [1554814314247, 24.681588328242032], + [1554814334247, 24.810238455213636], + [1554814354247, 24.410339756314695], + [1554814374247, 24.396192731458672], + [1554814394247, 24.325590744742602], + [1554814414247, 24.00219866428782], + [1554814434247, 23.57700638622354], + [1554814454247, 23.539308621824333], + [1554814474247, 23.190753289360014], + [1554814494247, 23.00850401336011], + [1554814514247, 23.137994435866098], + [1554814534247, 23.197808317385363], + [1554814554247, 22.756545947551], + [1554814574247, 22.942948839743238], + [1554814594247, 23.072813723042167], + [1554814614247, 22.881504025565448], + [1554814634247, 23.138709943466257], + [1554814654247, 23.06237555382352], + [1554814674247, 23.10019915491298], + [1554814694247, 23.51780549910103], + [1554814714247, 23.274386831939132], + [1554814734247, 22.780534530293703], + [1554814754247, 22.64347728787694], + [1554814774247, 22.578901585680992], + [1554814794247, 22.73474307069496], + [1554814814247, 22.3017582734572], + [1554814834247, 22.23466427843663], + [1554814854247, 22.21301416289505], + ], + color: '#7EB26D', + info: [ + { title: 'min', text: '14.42', numeric: 14.427101844163694 }, + { title: 'max', text: '18.42', numeric: 18.427101844163694 }, + ], + isVisible: true, + yAxis: 1, + }, + { + label: 'B-series', + data: [ + [1554793274247, 9.248820139157093], + [1554793294247, 9.273875054706759], + [1554793314247, 9.352176032498832], + [1554793334247, 9.807948429334353], + [1554793354247, 9.607817141399979], + [1554793374247, 9.827775726389026], + [1554793394247, 9.386666730812092], + [1554793414247, 9.372938370724333], + [1554793434247, 9.783904274932814], + [1554793454247, 9.93568291865629], + [1554793474247, 10.285904951141445], + [1554793494247, 10.356151800899413], + [1554793514247, 10.087924134921929], + [1554793534247, 10.130969065761265], + [1554793554247, 10.039871466196065], + [1554793574247, 10.48196042129985], + [1554793594247, 10.81294570657847], + [1554793614247, 10.425308181694218], + [1554793634247, 10.630859250874947], + [1554793654247, 10.735866163433657], + [1554793674247, 10.414049311911526], + [1554793694247, 10.443991943278128], + [1554793714247, 10.295408470211672], + [1554793734247, 10.614658355598694], + [1554793754247, 11.076290920269997], + [1554793774247, 11.425597202690865], + [1554793794247, 11.262277454840875], + [1554793814247, 11.17043615581524], + [1554793834247, 11.275581328847908], + [1554793854247, 11.481598266537757], + [1554793874247, 11.953363680050632], + [1554793894247, 12.422008588787305], + [1554793914247, 12.069849672231994], + [1554793934247, 11.943803466171598], + [1554793954247, 12.075583775000037], + [1554793974247, 12.068750850266534], + [1554793994247, 11.936651489454178], + [1554794014247, 11.996688750970568], + [1554794034247, 12.052434480528358], + [1554794054247, 12.536599186046683], + [1554794074247, 13.023718202899493], + [1554794094247, 12.966075141324536], + [1554794114247, 12.540756307703582], + [1554794134247, 12.712148183846951], + [1554794154247, 12.256702310766554], + [1554794174247, 12.212372314019388], + [1554794194247, 12.247568287118359], + [1554794214247, 12.010251845188867], + [1554794234247, 11.7115171988383], + [1554794254247, 11.981072233758754], + [1554794274247, 11.970827657632446], + [1554794294247, 12.117812031971802], + [1554794314247, 11.885655481089309], + [1554794334247, 12.139423837249328], + [1554794354247, 12.629111619970866], + [1554794374247, 12.838751307157468], + [1554794394247, 12.698782425513922], + [1554794414247, 12.228729591764855], + [1554794434247, 12.212858609888734], + [1554794454247, 12.549516160357083], + [1554794474247, 12.12789035051455], + [1554794494247, 11.843341194402191], + [1554794514247, 11.70830817970737], + [1554794534247, 11.512228940393427], + [1554794554247, 11.395363965811262], + [1554794574247, 11.86036846413425], + [1554794594247, 12.06123558542618], + [1554794614247, 12.204159715000836], + [1554794634247, 12.271910337675797], + [1554794654247, 12.282439537392525], + [1554794674247, 12.03790201620353], + [1554794694247, 11.829464424427744], + [1554794714247, 11.493890332653676], + [1554794734247, 11.413793733691467], + [1554794754247, 10.917571315788575], + [1554794774247, 10.502250358068137], + [1554794794247, 10.943314534163564], + [1554794814247, 11.371349945440832], + [1554794834247, 10.976930007662157], + [1554794854247, 10.499203550344646], + [1554794874247, 10.8294008121535], + [1554794894247, 10.830849260190083], + [1554794914247, 10.679528914904482], + [1554794934247, 11.124683240448253], + [1554794954247, 11.007602273533589], + [1554794974247, 11.291030570800228], + [1554794994247, 10.878973316312234], + [1554795014247, 10.783601804652415], + [1554795034247, 10.433756430969048], + [1554795054247, 10.024756414413504], + [1554795074247, 9.73857829270142], + [1554795094247, 9.501542190816165], + [1554795114247, 9.236454777535167], + [1554795134247, 9.703872577154437], + [1554795154247, 9.63913490209853], + [1554795174247, 9.380130864761673], + [1554795194247, 9.416021803813496], + [1554795214247, 9.427268719159454], + [1554795234247, 9.628563778508864], + [1554795254247, 9.31603705937074], + [1554795274247, 9.288467805990262], + [1554795294247, 9.445118597922967], + [1554795314247, 9.532344831308432], + [1554795334247, 9.079446462804185], + [1554795354247, 9.170228355998656], + [1554795374247, 9.086782779998948], + [1554795394247, 9.167605210581598], + [1554795414247, 9.337226400746871], + [1554795434247, 9.742704787869735], + [1554795454247, 9.737360720830406], + [1554795474247, 10.137939689453866], + [1554795494247, 9.700801043894144], + [1554795514247, 9.768218908003545], + [1554795534247, 9.75411192216661], + [1554795554247, 9.995651363958773], + [1554795574247, 9.6245144237306], + [1554795594247, 9.226961963966849], + [1554795614247, 8.753654850082542], + [1554795634247, 8.47135391545531], + [1554795654247, 8.183973941349567], + [1554795674247, 8.489931082159094], + [1554795694247, 8.817639566937025], + [1554795714247, 8.830670343882522], + [1554795734247, 8.892737303950666], + [1554795754247, 8.617048476643877], + [1554795774247, 8.956785057895], + [1554795794247, 8.9991406285351], + [1554795814247, 9.356203855221441], + [1554795834247, 8.99285081187721], + [1554795854247, 8.808922317600796], + [1554795874247, 9.159210350271348], + [1554795894247, 9.18335663931962], + [1554795914247, 9.373201449339069], + [1554795934247, 8.968119468638838], + [1554795954247, 8.576562756144522], + [1554795974247, 8.2637127277604], + [1554795994247, 8.721724203921328], + [1554796014247, 8.48997462768482], + [1554796034247, 8.923630475037411], + [1554796054247, 8.87332008767114], + [1554796074247, 8.600691352718252], + [1554796094247, 9.06144030038234], + [1554796114247, 8.573016788676542], + [1554796134247, 8.681863903053694], + [1554796154247, 8.286195763190447], + [1554796174247, 8.760651174815626], + [1554796194247, 8.782606476359007], + [1554796214247, 8.9825170729235], + [1554796234247, 8.50917994378477], + [1554796254247, 8.745078588661844], + [1554796274247, 8.486368444624361], + [1554796294247, 8.333749227691007], + [1554796314247, 7.920482802236725], + [1554796334247, 8.118910114704367], + [1554796354247, 8.052092789154447], + [1554796374247, 8.541526055677005], + [1554796394247, 8.532160960797517], + [1554796414247, 8.035315149728314], + [1554796434247, 8.153626777679058], + [1554796454247, 8.33489217274486], + [1554796474247, 8.63434786317988], + [1554796494247, 9.072612270861644], + [1554796514247, 9.15410238978958], + [1554796534247, 9.33569542338061], + [1554796554247, 9.617098624150145], + [1554796574247, 10.022020147992146], + [1554796594247, 9.96942587043037], + [1554796614247, 9.638489822305603], + [1554796634247, 9.148499945010006], + [1554796654247, 9.046323760634762], + [1554796674247, 8.950899003863489], + [1554796694247, 9.011582132180608], + [1554796714247, 8.821456019019363], + [1554796734247, 9.317497357412448], + [1554796754247, 8.933797285164973], + [1554796774247, 8.696553723087488], + [1554796794247, 8.486435423924668], + [1554796814247, 8.143914447574895], + [1554796834247, 7.663636585550101], + [1554796854247, 7.512977158724448], + [1554796874247, 7.3230605728686795], + [1554796894247, 6.9231107879457525], + [1554796914247, 6.982154895754249], + [1554796934247, 6.736558799914573], + [1554796954247, 6.62557430103121], + [1554796974247, 6.5962473119591], + [1554796994247, 7.009103777604233], + [1554797014247, 7.181557924155956], + [1554797034247, 7.354116677397331], + [1554797054247, 7.12587782475754], + [1554797074247, 6.866345342957572], + [1554797094247, 7.17115251468767], + [1554797114247, 6.722184764408618], + [1554797134247, 6.696153361069251], + [1554797154247, 6.9207740284137085], + [1554797174247, 6.6119572131599895], + [1554797194247, 6.815945935756884], + [1554797214247, 6.95466363827982], + [1554797234247, 6.7285014667012355], + [1554797254247, 6.891818567042779], + [1554797274247, 6.89849891212912], + [1554797294247, 6.460695100547899], + [1554797314247, 6.0069925335796475], + [1554797334247, 6.2603322238560875], + [1554797354247, 5.977611497076692], + [1554797374247, 5.942359898081184], + [1554797394247, 5.562777480448413], + [1554797414247, 5.841398822617335], + [1554797434247, 5.818365744964448], + [1554797454247, 5.571787499171553], + [1554797474247, 5.579907439786188], + [1554797494247, 5.398124887811567], + [1554797514247, 5.89247467855865], + [1554797534247, 6.109491399069382], + [1554797554247, 5.695647549392316], + [1554797574247, 5.869284172406741], + [1554797594247, 5.690239022459525], + [1554797614247, 5.450820783424683], + [1554797634247, 5.524583351054576], + [1554797654247, 5.36614969566086], + [1554797674247, 5.204730683218754], + [1554797694247, 5.427484119934154], + [1554797714247, 5.565761968712947], + [1554797734247, 5.932909999509335], + [1554797754247, 5.610458298441828], + [1554797774247, 5.324880465000206], + [1554797794247, 5.419125551757933], + [1554797814247, 5.02300209165337], + [1554797834247, 5.352305000126072], + [1554797854247, 5.36748698339688], + [1554797874247, 5.258792248781452], + [1554797894247, 5.125077286167015], + [1554797914247, 5.492028016529195], + [1554797934247, 5.568653332100721], + [1554797954247, 5.825704870348322], + [1554797974247, 6.27267451715126], + [1554797994247, 6.001452331648551], + [1554798014247, 5.8585768410841235], + [1554798034247, 5.819201114148435], + [1554798054247, 5.618753511565376], + [1554798074247, 5.24963457018995], + [1554798094247, 5.50387501275164], + [1554798114247, 5.84091043365146], + [1554798134247, 5.821629272116871], + [1554798154247, 6.210352707759286], + [1554798174247, 5.952483297516694], + [1554798194247, 6.031666355548255], + [1554798214247, 5.790748754808771], + [1554798234247, 5.594603662397832], + [1554798254247, 5.811695120800497], + [1554798274247, 5.837715057496696], + [1554798294247, 6.249345269583456], + [1554798314247, 5.934712699943487], + [1554798334247, 6.376771693988007], + [1554798354247, 6.1569566425758575], + [1554798374247, 5.711519906753933], + [1554798394247, 5.869137479992213], + [1554798414247, 5.560979081989093], + [1554798434247, 5.882435554334975], + [1554798454247, 5.388570139180064], + [1554798474247, 5.659073675509275], + [1554798494247, 5.5982211991238415], + [1554798514247, 5.6870744245787845], + [1554798534247, 5.600717003335124], + [1554798554247, 5.340048174168355], + [1554798574247, 5.095171088107014], + [1554798594247, 5.405805007535655], + [1554798614247, 5.271225976449607], + [1554798634247, 4.982494391562869], + [1554798654247, 5.2276371554858265], + [1554798674247, 5.442769621857752], + [1554798694247, 5.044185095640327], + [1554798714247, 4.79576810257608], + [1554798734247, 4.453831871416357], + [1554798754247, 4.618243387467281], + [1554798774247, 4.57918370988977], + [1554798794247, 4.4832728526544745], + [1554798814247, 4.024337135722461], + [1554798834247, 3.851845907034049], + [1554798854247, 3.542163220970746], + [1554798874247, 3.9690958016116413], + [1554798894247, 4.158181186559055], + [1554798914247, 4.079568209963879], + [1554798934247, 3.634349523153986], + [1554798954247, 3.3598575963443826], + [1554798974247, 3.16802878490503], + [1554798994247, 3.0133968929917563], + [1554799014247, 3.3437902298453492], + [1554799034247, 3.675049740942942], + [1554799054247, 3.467177915984232], + [1554799074247, 3.3518871913608907], + [1554799094247, 3.1957041604556817], + [1554799114247, 2.927123761256529], + [1554799134247, 3.2523340095072575], + [1554799154247, 3.015290599561679], + [1554799174247, 2.9890942934718248], + [1554799194247, 3.143167106507552], + [1554799214247, 3.5681222443713825], + [1554799234247, 3.2396432204688566], + [1554799254247, 3.24901159853982], + [1554799274247, 3.3625936643841348], + [1554799294247, 3.3339645808631038], + [1554799314247, 3.4205949091651635], + [1554799334247, 3.593597781275604], + [1554799354247, 3.4861342898248844], + [1554799374247, 3.8907746271806865], + [1554799394247, 4.111342004275268], + [1554799414247, 4.5959477789863366], + [1554799434247, 4.262140254359245], + [1554799454247, 4.134177960593391], + [1554799474247, 3.6575368680515146], + [1554799494247, 3.937414100768729], + [1554799514247, 4.078725112633452], + [1554799534247, 3.6451505190142974], + [1554799554247, 3.8471615375736894], + [1554799574247, 4.115159681991413], + [1554799594247, 3.9742174075208], + [1554799614247, 3.685238600479783], + [1554799634247, 4.103333280579201], + [1554799654247, 4.018245494514007], + [1554799674247, 4.446780576803342], + [1554799694247, 4.793421236531562], + [1554799714247, 4.554098466596562], + [1554799734247, 5.0417143849764425], + [1554799754247, 4.973734699399603], + [1554799774247, 5.193809388225786], + [1554799794247, 5.586071096427007], + [1554799814247, 5.778047979188536], + [1554799834247, 6.192594160585018], + [1554799854247, 5.927676977504205], + [1554799874247, 5.7050333060389695], + [1554799894247, 6.1718889065434634], + [1554799914247, 5.966274359120673], + [1554799934247, 5.5056942032960166], + [1554799954247, 5.160442061460211], + [1554799974247, 4.96018368853153], + [1554799994247, 4.691238462710444], + [1554800014247, 4.532492207601897], + [1554800034247, 4.07403732545026], + [1554800054247, 4.220770009365944], + [1554800074247, 4.0290646354752635], + [1554800094247, 3.8737691030982773], + [1554800114247, 4.238658311988558], + [1554800134247, 4.221236984114166], + [1554800154247, 4.6669293808298375], + [1554800174247, 4.843390965598206], + [1554800194247, 5.060187956069504], + [1554800214247, 4.868078717632957], + [1554800234247, 4.679175899389998], + [1554800254247, 4.777389196992289], + [1554800274247, 5.145363815002936], + [1554800294247, 4.781852858563081], + [1554800314247, 4.971885981820668], + [1554800334247, 4.646445194315369], + [1554800354247, 5.020517271418575], + [1554800374247, 4.7023153801084225], + [1554800394247, 4.876203872672264], + [1554800414247, 4.925017187669332], + [1554800434247, 4.663330164585453], + [1554800454247, 4.737769778515407], + [1554800474247, 4.3073255475285555], + [1554800494247, 3.903303008949847], + [1554800514247, 4.329087565576297], + [1554800534247, 3.977267569905087], + [1554800554247, 3.8740696509486328], + [1554800574247, 3.6792996433238767], + [1554800594247, 3.972924170147491], + [1554800614247, 3.7307104568781844], + [1554800634247, 3.867618350171384], + [1554800654247, 4.221917146372988], + [1554800674247, 4.3589781205929], + [1554800694247, 4.263474974513956], + [1554800714247, 3.836080641849756], + [1554800734247, 3.443769259025261], + [1554800754247, 3.3972787053685054], + [1554800774247, 3.7643724876162024], + [1554800794247, 4.170506414878274], + [1554800814247, 4.441115469873164], + [1554800834247, 4.371381466672394], + [1554800854247, 4.2168701882977295], + [1554800874247, 4.235647487408082], + [1554800894247, 3.9459791663426493], + [1554800914247, 4.017151772199118], + [1554800934247, 4.367278988021905], + [1554800954247, 4.342883446992778], + [1554800974247, 4.329662881338973], + [1554800994247, 4.283512014326498], + [1554801014247, 4.5715550079307645], + [1554801034247, 4.8311393525220945], + [1554801054247, 4.485030491381298], + [1554801074247, 4.34901947903894], + [1554801094247, 4.754091657245004], + [1554801114247, 4.8317691761516635], + [1554801134247, 5.204902590034885], + [1554801154247, 5.132781976138682], + [1554801174247, 5.034906361767744], + [1554801194247, 4.767543856573749], + [1554801214247, 5.094041902089003], + [1554801234247, 4.929546085290836], + [1554801254247, 4.697829514794909], + [1554801274247, 5.025374415167784], + [1554801294247, 5.096887871269491], + [1554801314247, 5.364791455663852], + [1554801334247, 5.561817762992182], + [1554801354247, 5.469314840240021], + [1554801374247, 5.95262630215483], + [1554801394247, 6.213311956412662], + [1554801414247, 5.715304095448328], + [1554801434247, 6.08523588145186], + [1554801454247, 5.857696643773423], + [1554801474247, 6.268212934058957], + [1554801494247, 6.5603945673698], + [1554801514247, 6.125495029826776], + [1554801534247, 6.110878886315267], + [1554801554247, 5.775584198941563], + [1554801574247, 6.001104024362178], + [1554801594247, 6.0476835587793705], + [1554801614247, 5.955664108319069], + [1554801634247, 5.955184743612128], + [1554801654247, 5.9330618446677414], + [1554801674247, 5.8424118755201855], + [1554801694247, 5.62553004227859], + [1554801714247, 6.0869222772786395], + [1554801734247, 5.803355849422298], + [1554801754247, 5.387776194851587], + [1554801774247, 5.40981853663267], + [1554801794247, 5.351276314268535], + [1554801814247, 5.788250432657768], + [1554801834247, 6.103420102386489], + [1554801854247, 6.211025937006611], + [1554801874247, 5.8449537650030825], + [1554801894247, 5.365170741934555], + [1554801914247, 4.887574074342324], + [1554801934247, 4.897693584588608], + [1554801954247, 5.318243270154184], + [1554801974247, 4.9396552679865025], + [1554801994247, 5.32527754563186], + [1554802014247, 4.886074615684099], + [1554802034247, 4.847379978693837], + [1554802054247, 4.504956591530262], + [1554802074247, 4.307454044981433], + [1554802094247, 3.867514732543229], + [1554802114247, 4.090981756269712], + [1554802134247, 4.578287695242435], + [1554802154247, 4.639711326460183], + [1554802174247, 4.245817171069919], + [1554802194247, 4.633160402543173], + [1554802214247, 5.112224969641575], + [1554802234247, 5.0089061103738945], + [1554802254247, 4.822364064588437], + [1554802274247, 5.212440187109399], + [1554802294247, 4.929867512296385], + [1554802314247, 5.245183785839094], + [1554802334247, 5.008463578035349], + [1554802354247, 5.1378596145435935], + [1554802374247, 5.033798588757337], + [1554802394247, 5.476424927294858], + [1554802414247, 5.972598629566117], + [1554802434247, 6.370358278045766], + [1554802454247, 5.893722712045765], + [1554802474247, 5.993207071076519], + [1554802494247, 5.930735938671154], + [1554802514247, 5.448559121598676], + [1554802534247, 5.207154019732361], + [1554802554247, 4.853297326279563], + [1554802574247, 5.04987559253604], + [1554802594247, 4.847597124701677], + [1554802614247, 5.146928442837356], + [1554802634247, 4.699178752084193], + [1554802654247, 4.6411064164223825], + [1554802674247, 4.665072535289884], + [1554802694247, 4.529885143860296], + [1554802714247, 4.996514308630512], + [1554802734247, 5.22226329518542], + [1554802754247, 5.575602394914211], + [1554802774247, 5.422257363444805], + [1554802794247, 5.855827664152273], + [1554802814247, 5.58414729075323], + [1554802834247, 5.103587756899033], + [1554802854247, 4.686442663523442], + [1554802874247, 4.351199700286399], + [1554802894247, 4.446556476531035], + [1554802914247, 4.877022325792788], + [1554802934247, 5.06408000687434], + [1554802954247, 4.891564589262834], + [1554802974247, 5.286434271773061], + [1554802994247, 5.524908643196997], + [1554803014247, 5.924389675102854], + [1554803034247, 5.547245691246638], + [1554803054247, 5.202222179374266], + [1554803074247, 5.168745154790057], + [1554803094247, 4.675315213121577], + [1554803114247, 4.470816264658528], + [1554803134247, 4.738579106980465], + [1554803154247, 4.369706105812872], + [1554803174247, 4.62735842629406], + [1554803194247, 4.153751390299434], + [1554803214247, 4.136048104401695], + [1554803234247, 3.7990691391221483], + [1554803254247, 3.8795830766275676], + [1554803274247, 3.772500704071465], + [1554803294247, 3.9319620260590384], + [1554803314247, 3.559929630866206], + [1554803334247, 3.6113629367099938], + [1554803354247, 3.7376027498577726], + [1554803374247, 3.5578753439899113], + [1554803394247, 4.018133755965429], + [1554803414247, 4.288623643831334], + [1554803434247, 4.318645979671817], + [1554803454247, 4.749471110335788], + [1554803474247, 4.372628054764743], + [1554803494247, 4.622094039373034], + [1554803514247, 4.244606535531101], + [1554803534247, 3.816516521086009], + [1554803554247, 4.017892070701937], + [1554803574247, 3.89079416050709], + [1554803594247, 4.261198695219943], + [1554803614247, 4.428362341587736], + [1554803634247, 4.880986638912973], + [1554803654247, 5.0299660882410775], + [1554803674247, 5.411982269567302], + [1554803694247, 5.194408289760711], + [1554803714247, 5.012769948412448], + [1554803734247, 5.0072233733100004], + [1554803754247, 5.401394397533787], + [1554803774247, 5.326562162713341], + [1554803794247, 5.623163927554523], + [1554803814247, 5.5559453288335785], + [1554803834247, 5.577487170979451], + [1554803854247, 6.045429148567111], + [1554803874247, 5.7407369273358855], + [1554803894247, 5.9662724514162395], + [1554803914247, 5.626123193057087], + [1554803934247, 5.827530375461689], + [1554803954247, 6.219201754092099], + [1554803974247, 6.300657792657276], + [1554803994247, 6.542166827712119], + [1554804014247, 6.303296215678175], + [1554804034247, 6.252832131614809], + [1554804054247, 6.001141932163406], + [1554804074247, 6.452357078229282], + [1554804094247, 6.5222239382705745], + [1554804114247, 6.320907147559073], + [1554804134247, 6.811884397530322], + [1554804154247, 7.032984930368987], + [1554804174247, 6.715498474732585], + [1554804194247, 6.672161634739476], + [1554804214247, 6.994547337932146], + [1554804234247, 6.858854183936963], + [1554804254247, 6.633667847711406], + [1554804274247, 6.52885680764893], + [1554804294247, 6.2708537451521265], + [1554804314247, 6.325984685221548], + [1554804334247, 6.265281332886626], + [1554804354247, 5.790005511484586], + [1554804374247, 5.909314128865535], + [1554804394247, 6.019228158579621], + [1554804414247, 5.767753759200176], + [1554804434247, 5.877389216946951], + [1554804454247, 6.344658548950036], + [1554804474247, 6.2725006803076315], + [1554804494247, 6.159015121408378], + [1554804514247, 6.177644730506093], + [1554804534247, 6.574127902942029], + [1554804554247, 6.279446561068236], + [1554804574247, 6.532293875875611], + [1554804594247, 6.546265619012084], + [1554804614247, 6.669672237291822], + [1554804634247, 6.458459577608597], + [1554804654247, 6.3181910426234555], + [1554804674247, 6.330484950381867], + [1554804694247, 6.704701222610657], + [1554804714247, 6.296604674112797], + [1554804734247, 6.045934293115862], + [1554804754247, 5.626761485544506], + [1554804774247, 5.984868539333273], + [1554804794247, 5.782143366601749], + [1554804814247, 5.881833269531409], + [1554804834247, 6.341620115867811], + [1554804854247, 6.190837619933998], + [1554804874247, 5.7755446957461265], + [1554804894247, 5.927590146263014], + [1554804914247, 6.229025865781088], + [1554804934247, 5.9289926927844325], + [1554804954247, 6.283677647437369], + [1554804974247, 5.887290894902884], + [1554804994247, 5.60516096881941], + [1554805014247, 5.124922711378898], + [1554805034247, 5.022411278302609], + [1554805054247, 5.441282885351261], + [1554805074247, 5.211041708475881], + [1554805094247, 5.315539280767537], + [1554805114247, 4.860316378001272], + [1554805134247, 4.597541762813888], + [1554805154247, 4.701388340442914], + [1554805174247, 4.8857311808651795], + [1554805194247, 4.911170700334517], + [1554805214247, 4.7607973589457275], + [1554805234247, 5.2374533806100105], + [1554805254247, 5.635862787165801], + [1554805274247, 5.190782427510569], + [1554805294247, 5.040752906711101], + [1554805314247, 5.431677208644257], + [1554805334247, 5.276048739941259], + [1554805354247, 5.175810345425181], + [1554805374247, 5.448545682460811], + [1554805394247, 5.168286373993526], + [1554805414247, 4.915522433549292], + [1554805434247, 5.2403189761702755], + [1554805454247, 5.549674728141264], + [1554805474247, 5.346700869868238], + [1554805494247, 5.188114699782227], + [1554805514247, 5.054805968686958], + [1554805534247, 4.921991599219343], + [1554805554247, 5.252967706754598], + [1554805574247, 5.528822819853359], + [1554805594247, 5.163180135702445], + [1554805614247, 5.459094564903271], + [1554805634247, 5.205802999429608], + [1554805654247, 5.654372323923422], + [1554805674247, 6.005308016326213], + [1554805694247, 6.225307598518053], + [1554805714247, 6.265609851224129], + [1554805734247, 6.464569754513396], + [1554805754247, 6.213421273189288], + [1554805774247, 6.109005465627603], + [1554805794247, 6.388571590681015], + [1554805814247, 5.940826816262089], + [1554805834247, 6.152567556318539], + [1554805854247, 5.6778725758159245], + [1554805874247, 5.5459357762000145], + [1554805894247, 5.245881317787439], + [1554805914247, 5.16962721413826], + [1554805934247, 5.07586323530142], + [1554805954247, 5.079999397697077], + [1554805974247, 5.110929127356195], + [1554805994247, 5.4651260693748345], + [1554806014247, 5.333693563931255], + [1554806034247, 5.107568465043172], + [1554806054247, 5.549034075311475], + [1554806074247, 5.680774155981773], + [1554806094247, 5.449462358103411], + [1554806114247, 5.296928229571512], + [1554806134247, 4.801889842979068], + [1554806154247, 5.266423958416515], + [1554806174247, 5.394775355310104], + [1554806194247, 4.986628678003934], + [1554806214247, 4.927257141199989], + [1554806234247, 4.736707861872728], + [1554806254247, 5.217522955513845], + [1554806274247, 5.159523886652105], + [1554806294247, 5.1343440103709375], + [1554806314247, 5.4355027352491065], + [1554806334247, 4.989476007458429], + [1554806354247, 4.962491244463504], + [1554806374247, 5.234929203969406], + [1554806394247, 5.354611454712647], + [1554806414247, 5.819971337557214], + [1554806434247, 5.4537351462427655], + [1554806454247, 5.675427728347797], + [1554806474247, 5.717239078112083], + [1554806494247, 5.9665112054249505], + [1554806514247, 6.330042031470756], + [1554806534247, 6.554062137484854], + [1554806554247, 6.98908148194185], + [1554806574247, 6.550888018972389], + [1554806594247, 6.76067898332396], + [1554806614247, 6.766932559585224], + [1554806634247, 6.884507789101927], + [1554806654247, 6.982112269213111], + [1554806674247, 6.612531075414423], + [1554806694247, 6.831170284034089], + [1554806714247, 6.564458211861151], + [1554806734247, 6.5928702335259555], + [1554806754247, 6.307307819202318], + [1554806774247, 6.14296202627164], + [1554806794247, 5.850517533316699], + [1554806814247, 6.013477089375544], + [1554806834247, 5.788350959514567], + [1554806854247, 6.213462521998331], + [1554806874247, 6.135358062071788], + [1554806894247, 6.5090674301724265], + [1554806914247, 6.366207234773551], + [1554806934247, 6.717787701154512], + [1554806954247, 6.938004745742623], + [1554806974247, 6.608685270420923], + [1554806994247, 6.616342669591905], + [1554807014247, 7.111245244027054], + [1554807034247, 6.8382135174842515], + [1554807054247, 7.233472706615843], + [1554807074247, 7.086607581699311], + [1554807094247, 7.469047250077706], + [1554807114247, 7.230352648399958], + [1554807134247, 7.227645424764407], + [1554807154247, 7.4153920798629915], + [1554807174247, 7.026938941179673], + [1554807194247, 6.834372496767788], + [1554807214247, 6.632614720484994], + [1554807234247, 6.9176209603808205], + [1554807254247, 7.093991324735687], + [1554807274247, 7.49838324274419], + [1554807294247, 7.248815237417004], + [1554807314247, 7.59741703470027], + [1554807334247, 7.767235801748564], + [1554807354247, 7.798699694025993], + [1554807374247, 8.022398085783173], + [1554807394247, 8.219990876891334], + [1554807414247, 8.112971309076434], + [1554807434247, 8.391034098841457], + [1554807454247, 8.363882609872281], + [1554807474247, 7.971781311420273], + [1554807494247, 7.523868567624482], + [1554807514247, 7.597999604461199], + [1554807534247, 7.98131948849502], + [1554807554247, 8.211001366222089], + [1554807574247, 8.339946777071436], + [1554807594247, 8.321908649004829], + [1554807614247, 8.283911248846037], + [1554807634247, 7.95287844789605], + [1554807654247, 7.907639543478707], + [1554807674247, 7.8725971247401745], + [1554807694247, 7.510817707264657], + [1554807714247, 7.453138721251027], + [1554807734247, 7.945662384008237], + [1554807754247, 7.689782595310916], + [1554807774247, 7.222797934226393], + [1554807794247, 7.198697752316905], + [1554807814247, 7.134050929634677], + [1554807834247, 6.8576983886263525], + [1554807854247, 6.813355504109371], + [1554807874247, 6.871596166448773], + [1554807894247, 6.4936669876216335], + [1554807914247, 6.856768002872756], + [1554807934247, 6.49860793254361], + [1554807954247, 6.293200026824586], + [1554807974247, 5.947670166407878], + [1554807994247, 6.022336570265149], + [1554808014247, 6.518767909482903], + [1554808034247, 6.239492464787651], + [1554808054247, 6.727058806972739], + [1554808074247, 7.121308144408187], + [1554808094247, 6.782001741160709], + [1554808114247, 6.911079377114777], + [1554808134247, 6.8930569721432065], + [1554808154247, 7.026120004477112], + [1554808174247, 7.426405016599918], + [1554808194247, 7.101843615788554], + [1554808214247, 6.682553980564458], + [1554808234247, 6.489957896759141], + [1554808254247, 6.935104685760811], + [1554808274247, 7.272271426738921], + [1554808294247, 6.896043753021477], + [1554808314247, 6.453354071271065], + [1554808334247, 6.6400664095774005], + [1554808354247, 6.43533378238653], + [1554808374247, 6.892462502509553], + [1554808394247, 6.815418828468179], + [1554808414247, 6.884193266819189], + [1554808434247, 6.626443732396062], + [1554808454247, 6.9516516783657165], + [1554808474247, 7.049560022739215], + [1554808494247, 7.1055987133330785], + [1554808514247, 6.750008467983265], + [1554808534247, 7.207166348519568], + [1554808554247, 6.7168905957818845], + [1554808574247, 7.13070327526958], + [1554808594247, 7.079731512657319], + [1554808614247, 7.510314201924746], + [1554808634247, 7.706230930087699], + [1554808654247, 7.81411401302101], + [1554808674247, 7.478003760714301], + [1554808694247, 7.922427996204289], + [1554808714247, 7.907863457551709], + [1554808734247, 8.248186807433832], + [1554808754247, 8.576712081296638], + [1554808774247, 8.214689808808208], + [1554808794247, 8.663946930276753], + [1554808814247, 8.194761986653258], + [1554808834247, 8.575717709102516], + [1554808854247, 8.345850007916788], + [1554808874247, 8.612381234175777], + [1554808894247, 8.758703497768783], + [1554808914247, 8.45228506635527], + [1554808934247, 8.365323711621404], + [1554808954247, 8.772268719879923], + [1554808974247, 8.414503354013195], + [1554808994247, 8.33575391274245], + [1554809014247, 7.847212876502609], + [1554809034247, 7.820165181384834], + [1554809054247, 7.749613823906183], + [1554809074247, 8.171181374434301], + [1554809094247, 8.012821172876176], + [1554809114247, 7.632473633132171], + [1554809134247, 7.927346280103529], + [1554809154247, 8.38222644684866], + [1554809174247, 8.873146858741773], + [1554809194247, 9.139361430999534], + [1554809214247, 8.773999973423352], + [1554809234247, 8.503974910333003], + [1554809254247, 8.851608924895134], + [1554809274247, 9.258358922834823], + [1554809294247, 9.004521432325152], + [1554809314247, 8.663646594659093], + [1554809334247, 9.062943096024762], + [1554809354247, 8.927196322628053], + [1554809374247, 8.860884892690317], + [1554809394247, 8.72560917543646], + [1554809414247, 8.62396089915321], + [1554809434247, 8.767613126137167], + [1554809454247, 9.055419594223759], + [1554809474247, 8.569888672466254], + [1554809494247, 8.736703861623493], + [1554809514247, 8.94976206317658], + [1554809534247, 8.521394791609685], + [1554809554247, 8.3698829938199], + [1554809574247, 8.645533125455511], + [1554809594247, 8.389932129633864], + [1554809614247, 8.119152603087166], + [1554809634247, 8.119883595476143], + [1554809654247, 8.070896546230118], + [1554809674247, 8.11029896993352], + [1554809694247, 8.060761966261271], + [1554809714247, 8.50921225305014], + [1554809734247, 8.725356063040449], + [1554809754247, 8.727934761508802], + [1554809774247, 8.356828269208117], + [1554809794247, 8.637691261479478], + [1554809814247, 8.500996427635334], + [1554809834247, 8.343058481731683], + [1554809854247, 8.091250360224562], + [1554809874247, 7.706923991641506], + [1554809894247, 7.994107748320774], + [1554809914247, 7.675799246882235], + [1554809934247, 7.197886464997558], + [1554809954247, 7.188277445993742], + [1554809974247, 7.036209963564159], + [1554809994247, 6.947875119270903], + [1554810014247, 7.044499042781682], + [1554810034247, 6.663631394974621], + [1554810054247, 6.544553868473274], + [1554810074247, 6.244585802324538], + [1554810094247, 5.790424680888914], + [1554810114247, 5.597125792706711], + [1554810134247, 5.838197514962413], + [1554810154247, 5.569538296626776], + [1554810174247, 5.622066021193228], + [1554810194247, 5.6709480376132335], + [1554810214247, 5.3826562886664515], + [1554810234247, 5.495003785016907], + [1554810254247, 5.129314033185204], + [1554810274247, 4.709722774580275], + [1554810294247, 5.058233056559091], + [1554810314247, 5.149581150382685], + [1554810334247, 5.313471284226376], + [1554810354247, 5.724599134003778], + [1554810374247, 5.329889761110913], + [1554810394247, 5.746948046516922], + [1554810414247, 5.627652937866056], + [1554810434247, 5.142896397418332], + [1554810454247, 5.046133901694889], + [1554810474247, 5.507954638298896], + [1554810494247, 5.685628153810458], + [1554810514247, 6.159063025037185], + [1554810534247, 6.586439421400087], + [1554810554247, 6.882778595688622], + [1554810574247, 7.2490121652682395], + [1554810594247, 6.992372134925944], + [1554810614247, 6.866722248884183], + [1554810634247, 6.490212612921014], + [1554810654247, 6.104505357845294], + [1554810674247, 6.367774595212844], + [1554810694247, 6.083761787710358], + [1554810714247, 5.737294108204808], + [1554810734247, 6.102847667978216], + [1554810754247, 6.318239116092701], + [1554810774247, 5.920431833139119], + [1554810794247, 5.509946128359078], + [1554810814247, 5.124840200214926], + [1554810834247, 5.49899101103313], + [1554810854247, 5.470314709501598], + [1554810874247, 5.375614537897641], + [1554810894247, 5.3648225965695495], + [1554810914247, 5.135118670963028], + [1554810934247, 5.3362339554547065], + [1554810954247, 5.218712068436682], + [1554810974247, 5.412912108653002], + [1554810994247, 5.470415053122083], + [1554811014247, 5.728323741298232], + [1554811034247, 5.6932642393444075], + [1554811054247, 5.749008578598318], + [1554811074247, 6.09970432098925], + [1554811094247, 6.071920828705983], + [1554811114247, 5.828661341760444], + [1554811134247, 5.524965142249962], + [1554811154247, 5.575358061295394], + [1554811174247, 5.446919825099063], + [1554811194247, 5.93800790342962], + [1554811214247, 6.071568697482172], + [1554811234247, 6.310969859015277], + [1554811254247, 5.821955584869536], + [1554811274247, 6.199421058701339], + [1554811294247, 6.674118388812211], + [1554811314247, 6.673227102219742], + [1554811334247, 6.195363115639559], + [1554811354247, 5.820263795090813], + [1554811374247, 5.915530667539109], + [1554811394247, 6.331135066773232], + [1554811414247, 5.948853295013205], + [1554811434247, 5.451153941151292], + [1554811454247, 5.3919812114719905], + [1554811474247, 4.933551578138852], + [1554811494247, 5.099962987800049], + [1554811514247, 5.4460689354241545], + [1554811534247, 5.298376393189034], + [1554811554247, 5.051670370021742], + [1554811574247, 5.065328716862751], + [1554811594247, 4.942328036504453], + [1554811614247, 5.430221059400023], + [1554811634247, 5.338449689010827], + [1554811654247, 5.5716140235693805], + [1554811674247, 5.57866789314628], + [1554811694247, 5.090129632378411], + [1554811714247, 5.3389428704372515], + [1554811734247, 5.640001527104899], + [1554811754247, 5.8258428437827146], + [1554811774247, 6.045096248760302], + [1554811794247, 6.013981734904431], + [1554811814247, 5.915532054198841], + [1554811834247, 6.034610673432962], + [1554811854247, 6.414970154241204], + [1554811874247, 6.867945955465651], + [1554811894247, 6.933730078574364], + [1554811914247, 6.875497349505578], + [1554811934247, 6.809570407471085], + [1554811954247, 6.750819417545482], + [1554811974247, 7.028896424987769], + [1554811994247, 7.487999347921053], + [1554812014247, 7.200375020912814], + [1554812034247, 6.729037158447847], + [1554812054247, 6.2332135753766265], + [1554812074247, 6.2788869958132345], + [1554812094247, 6.551210083494132], + [1554812114247, 6.948556190676634], + [1554812134247, 6.810029771056861], + [1554812154247, 6.36992272456798], + [1554812174247, 6.144755770243405], + [1554812194247, 5.819900475823894], + [1554812214247, 5.842632687609575], + [1554812234247, 6.0229913623019105], + [1554812254247, 5.59543607823725], + [1554812274247, 5.240974306421704], + [1554812294247, 4.961540573276396], + [1554812314247, 5.063113720528529], + [1554812334247, 4.701806251073283], + [1554812354247, 4.383406380737377], + [1554812374247, 4.551643367095542], + [1554812394247, 4.501437131078793], + [1554812414247, 4.5896287936775515], + [1554812434247, 4.396798361915996], + [1554812454247, 4.094488884344564], + [1554812474247, 3.763950671274415], + [1554812494247, 3.3649910218348174], + [1554812514247, 2.9420483196562572], + [1554812534247, 2.4690716873035665], + [1554812554247, 2.40032467067903], + [1554812574247, 2.3999430459174027], + [1554812594247, 1.9716754362118059], + [1554812614247, 2.22897786032354], + [1554812634247, 1.936502183061513], + [1554812654247, 1.6697202952760788], + [1554812674247, 1.6161425233220745], + [1554812694247, 1.2979508442614471], + [1554812714247, 1.7795512009915573], + [1554812734247, 1.9775676458236746], + [1554812754247, 1.9857859272271818], + [1554812774247, 1.9712956178036478], + [1554812794247, 1.9954131810535451], + [1554812814247, 1.6639380475508858], + [1554812834247, 1.2921332932291232], + [1554812854247, 1.5623317516730828], + [1554812874247, 1.5630008010336873], + [1554812894247, 1.2945730371419555], + [1554812914247, 1.1345153304204763], + [1554812934247, 0.6485479592305394], + [1554812954247, 0.9712442704296393], + [1554812974247, 0.47564130406558597], + [1554812994247, 0.20444990972474225], + [1554813014247, -0.047090913437836], + [1554813034247, 0.2921861763460779], + [1554813054247, -0.15467934586406012], + [1554813074247, -0.3425495302000647], + [1554813094247, -0.19797787217917812], + [1554813114247, 0.24356265774967373], + [1554813134247, 0.6623693719986659], + [1554813154247, 1.0886329481274146], + [1554813174247, 0.7905383067051148], + [1554813194247, 0.43695310832152934], + [1554813214247, 0.5450623072818498], + [1554813234247, 0.9831498244033907], + [1554813254247, 0.5367271614005622], + [1554813274247, 0.34521375260155496], + [1554813294247, 0.49674059769702794], + [1554813314247, 0.8545220988091075], + [1554813334247, 1.1454002559545144], + [1554813354247, 1.5939691226426291], + [1554813374247, 1.2925743210955847], + [1554813394247, 1.202697680270512], + [1554813414247, 0.8248346749243624], + [1554813434247, 1.0508182706093616], + [1554813454247, 0.8933882588609936], + [1554813474247, 1.0868459054070774], + [1554813494247, 1.215067537959666], + [1554813514247, 1.6859453420595623], + [1554813534247, 1.8408803337528425], + [1554813554247, 1.503566069541031], + [1554813574247, 1.5025754914986305], + [1554813594247, 1.757013848848623], + [1554813614247, 1.8005931714680625], + [1554813634247, 1.993059816901711], + [1554813654247, 1.733598878547323], + [1554813674247, 1.7996930998117175], + [1554813694247, 1.7718023286326967], + [1554813714247, 1.9424689430549809], + [1554813734247, 1.8262152184502831], + [1554813754247, 1.8579680942725383], + [1554813774247, 1.9147990478151855], + [1554813794247, 1.5793884871771346], + [1554813814247, 1.7840058908387082], + [1554813834247, 1.524252777720136], + [1554813854247, 1.4086013386788108], + [1554813874247, 1.6938093491734791], + [1554813894247, 1.5204801601796416], + [1554813914247, 1.3677304479303785], + [1554813934247, 0.9070965699397421], + [1554813954247, 0.9001093789228389], + [1554813974247, 1.3596888033017467], + [1554813994247, 1.4244525184581716], + [1554814014247, 1.0681045937169595], + [1554814034247, 1.5021342501361263], + [1554814054247, 1.4735658199316348], + [1554814074247, 1.4142680194453459], + [1554814094247, 1.5307344331738741], + [1554814114247, 1.7600295139395037], + [1554814134247, 1.309541539278152], + [1554814154247, 0.8147628448203794], + [1554814174247, 1.2615036691775383], + [1554814194247, 1.7594036318960855], + [1554814214247, 1.3904263592100619], + [1554814234247, 1.088464774283428], + [1554814254247, 1.261188919478455], + [1554814274247, 0.7793099148276835], + [1554814294247, 0.7216892684946898], + [1554814314247, 0.5979274119186977], + [1554814334247, 0.7518018696509412], + [1554814354247, 0.877188700342351], + [1554814374247, 0.9674514096611574], + [1554814394247, 1.1939480091418346], + [1554814414247, 1.4909691399213152], + [1554814434247, 1.3506310992415735], + [1554814454247, 1.0871979315135374], + [1554814474247, 0.8619366874699526], + [1554814494247, 0.46428502886042183], + [1554814514247, 0.7896726455955152], + [1554814534247, 1.1538665346611536], + [1554814554247, 0.9916800353742865], + [1554814574247, 0.5090921441099303], + [1554814594247, 0.8273292250812865], + [1554814614247, 0.881693750857172], + [1554814634247, 0.8101430303449187], + [1554814654247, 1.0941807855302021], + [1554814674247, 0.9874142260877046], + [1554814694247, 0.8635324695445575], + [1554814714247, 0.9077447503631652], + [1554814734247, 0.6122162804684913], + [1554814754247, 0.15771010809450015], + [1554814774247, -0.13091442032472111], + [1554814794247, -0.2896902546208621], + [1554814814247, 0.09852909084992972], + [1554814834247, 0.39703026948260606], + [1554814854247, 0.2283837169989657], + ], + color: '#EAB839', + info: [ + { title: 'min', text: '14.42', numeric: 14.427101844163694 }, + { title: 'max', text: '18.42', numeric: 18.427101844163694 }, + ], + isVisible: true, + yAxis: 1, + }, + { + label: 'C-series', + data: [ + [1554793274247, 49.69913267127473], + [1554793294247, 49.33359410789192], + [1554793314247, 49.78163348684188], + [1554793334247, 50.17676830260008], + [1554793354247, 50.40926697029897], + [1554793374247, 50.063754605356486], + [1554793394247, 50.076999844329656], + [1554793414247, 49.948006752209906], + [1554793434247, 49.62287160565001], + [1554793454247, 50.03914976018486], + [1554793474247, 50.36736533496234], + [1554793494247, 50.21324796822654], + [1554793514247, 49.99112476335388], + [1554793534247, 49.84106879158749], + [1554793554247, 49.412375094520144], + [1554793574247, 49.78349539263808], + [1554793594247, 50.25259706652223], + [1554793614247, 49.888060632553064], + [1554793634247, 49.464424676361375], + [1554793654247, 49.095492684839165], + [1554793674247, 49.06868173776792], + [1554793694247, 48.574525936741985], + [1554793714247, 48.216592532164306], + [1554793734247, 47.98607300294584], + [1554793754247, 47.83078553622775], + [1554793774247, 47.93338669184849], + [1554793794247, 48.31669530028857], + [1554793814247, 47.82408913984656], + [1554793834247, 47.863721900360474], + [1554793854247, 47.51177912971504], + [1554793874247, 47.757151295055756], + [1554793894247, 47.95834636268655], + [1554793914247, 47.61863670851333], + [1554793934247, 47.93496547494361], + [1554793954247, 48.27168892260189], + [1554793974247, 48.44358577552156], + [1554793994247, 48.29808350161488], + [1554794014247, 48.10007721078963], + [1554794034247, 48.2714717233677], + [1554794054247, 48.05508995997583], + [1554794074247, 47.868813005942215], + [1554794094247, 47.876025343915664], + [1554794114247, 48.32683862002359], + [1554794134247, 48.342512548370195], + [1554794154247, 48.38648493951903], + [1554794174247, 48.199354522690825], + [1554794194247, 48.492498553794455], + [1554794214247, 48.380215201095], + [1554794234247, 48.115635145152744], + [1554794254247, 48.490793461399434], + [1554794274247, 48.900207945175495], + [1554794294247, 49.22861321463161], + [1554794314247, 49.4870357160768], + [1554794334247, 49.09749063286741], + [1554794354247, 49.092467346240014], + [1554794374247, 49.48778572019057], + [1554794394247, 49.979432673247885], + [1554794414247, 50.071201766907855], + [1554794434247, 49.9744124782064], + [1554794454247, 49.55016977456924], + [1554794474247, 49.06533151723648], + [1554794494247, 49.261080300725936], + [1554794514247, 49.26585857314833], + [1554794534247, 49.2429751536119], + [1554794554247, 49.346043390042986], + [1554794574247, 48.95990675036499], + [1554794594247, 49.12651334454535], + [1554794614247, 49.29857292163306], + [1554794634247, 49.186770426141514], + [1554794654247, 48.79264174796861], + [1554794674247, 48.88789309162548], + [1554794694247, 49.04173033445755], + [1554794714247, 49.403693322860484], + [1554794734247, 49.21528708472506], + [1554794754247, 49.349890005123356], + [1554794774247, 49.82581895338948], + [1554794794247, 50.10348602630898], + [1554794814247, 50.5396830040285], + [1554794834247, 50.152316888567], + [1554794854247, 49.849522224408226], + [1554794874247, 49.839186901052365], + [1554794894247, 49.51423985768722], + [1554794914247, 49.47484962979224], + [1554794934247, 49.69559173812953], + [1554794954247, 50.061967708930766], + [1554794974247, 49.72554084142337], + [1554794994247, 50.203775891826396], + [1554795014247, 50.46185209673081], + [1554795034247, 50.47156978415908], + [1554795054247, 50.501613750647564], + [1554795074247, 50.94633357030688], + [1554795094247, 51.210166610968514], + [1554795114247, 51.10160382793679], + [1554795134247, 51.1997077763274], + [1554795154247, 51.487603830051704], + [1554795174247, 51.36947130848638], + [1554795194247, 51.506665895696045], + [1554795214247, 51.47614904037313], + [1554795234247, 50.98365689110939], + [1554795254247, 50.85070473835243], + [1554795274247, 50.43383257691916], + [1554795294247, 50.232766901028626], + [1554795314247, 50.07161209496396], + [1554795334247, 49.837713407554816], + [1554795354247, 50.143606201515325], + [1554795374247, 50.345131163346394], + [1554795394247, 50.18313221599123], + [1554795414247, 49.84883601334913], + [1554795434247, 49.5272710525089], + [1554795454247, 49.215130902407815], + [1554795474247, 48.97804448667156], + [1554795494247, 49.31482206869563], + [1554795514247, 49.53974601218905], + [1554795534247, 49.07096949398067], + [1554795554247, 48.71727129896322], + [1554795574247, 48.93720156267952], + [1554795594247, 49.392801702481954], + [1554795614247, 49.216552679751196], + [1554795634247, 49.23021526312906], + [1554795654247, 49.36899096723609], + [1554795674247, 49.09191616409923], + [1554795694247, 49.15661848532974], + [1554795714247, 49.13503380602352], + [1554795734247, 49.55044458774344], + [1554795754247, 49.46886788033894], + [1554795774247, 49.30135034486024], + [1554795794247, 49.297518995279404], + [1554795814247, 48.925566481922225], + [1554795834247, 49.27559370678866], + [1554795854247, 49.332340911077424], + [1554795874247, 49.26076465409638], + [1554795894247, 49.53767640806078], + [1554795914247, 49.8030905200301], + [1554795934247, 49.32264966726677], + [1554795954247, 49.544792317070254], + [1554795974247, 49.21562164942147], + [1554795994247, 49.07254074465956], + [1554796014247, 49.18878762024898], + [1554796034247, 49.2306235947342], + [1554796054247, 49.62054143705226], + [1554796074247, 49.63187621927985], + [1554796094247, 49.98017604831396], + [1554796114247, 49.7600715923475], + [1554796134247, 49.27655228840302], + [1554796154247, 49.62483387018148], + [1554796174247, 49.21209572522005], + [1554796194247, 48.744631547286936], + [1554796214247, 48.63286811583694], + [1554796234247, 49.12296413252627], + [1554796254247, 48.910115698414295], + [1554796274247, 48.96613678532863], + [1554796294247, 49.05941150019551], + [1554796314247, 49.508439412178774], + [1554796334247, 49.16173498832025], + [1554796354247, 49.45053302619814], + [1554796374247, 49.00286141334283], + [1554796394247, 49.30217759710238], + [1554796414247, 49.501741513928174], + [1554796434247, 49.4972198005734], + [1554796454247, 49.16075824584829], + [1554796474247, 49.37241873098192], + [1554796494247, 49.63656657285561], + [1554796514247, 49.43718574292024], + [1554796534247, 49.48756155841603], + [1554796554247, 49.24303681625806], + [1554796574247, 49.382518871358485], + [1554796594247, 49.02247723343229], + [1554796614247, 49.27667512613039], + [1554796634247, 49.64825856084839], + [1554796654247, 49.321745040753285], + [1554796674247, 48.91447440186897], + [1554796694247, 48.81302425720652], + [1554796714247, 48.905546629260954], + [1554796734247, 49.07774732856527], + [1554796754247, 49.227140342516535], + [1554796774247, 49.72198806496772], + [1554796794247, 49.48668530730508], + [1554796814247, 49.46590246465986], + [1554796834247, 48.99586979519719], + [1554796854247, 48.798302244243935], + [1554796874247, 48.61059457103293], + [1554796894247, 48.93616700832869], + [1554796914247, 49.36797907473593], + [1554796934247, 49.47791061560138], + [1554796954247, 49.05321495421578], + [1554796974247, 49.193714250569805], + [1554796994247, 49.16178917646284], + [1554797014247, 49.61296666235341], + [1554797034247, 49.12291229001563], + [1554797054247, 48.95504159499004], + [1554797074247, 49.32814845656858], + [1554797094247, 48.943532330596284], + [1554797114247, 48.46180988614885], + [1554797134247, 48.11959030750559], + [1554797154247, 48.09494703813437], + [1554797174247, 47.983429675390965], + [1554797194247, 47.56241734828039], + [1554797214247, 47.979661755353014], + [1554797234247, 48.123073042355], + [1554797254247, 48.27362205867366], + [1554797274247, 48.71404324003502], + [1554797294247, 48.89226743535597], + [1554797314247, 49.29328058894711], + [1554797334247, 49.084461777558545], + [1554797354247, 48.83021345179746], + [1554797374247, 48.91026000597451], + [1554797394247, 48.99484128183615], + [1554797414247, 48.86756007189439], + [1554797434247, 48.479138233845504], + [1554797454247, 48.374298022845906], + [1554797474247, 48.286981712867664], + [1554797494247, 48.198201299191574], + [1554797514247, 47.77195291962695], + [1554797534247, 47.738964722883075], + [1554797554247, 48.13659961076256], + [1554797574247, 47.915605075289456], + [1554797594247, 48.30049282619518], + [1554797614247, 48.23976344811622], + [1554797634247, 48.165658285800426], + [1554797654247, 47.86756846582645], + [1554797674247, 48.29556200780647], + [1554797694247, 48.29145743008182], + [1554797714247, 47.8840989961646], + [1554797734247, 48.00901203088797], + [1554797754247, 47.641268558534534], + [1554797774247, 47.85700504489876], + [1554797794247, 47.754409771890366], + [1554797814247, 47.46442119094209], + [1554797834247, 47.37778670338178], + [1554797854247, 47.69125754568886], + [1554797874247, 47.65675109438546], + [1554797894247, 47.35188105593815], + [1554797914247, 46.99017604656002], + [1554797934247, 46.49962289247365], + [1554797954247, 46.50698076300431], + [1554797974247, 46.529341299373776], + [1554797994247, 46.14246130646399], + [1554798014247, 46.64128938702536], + [1554798034247, 46.71332038658063], + [1554798054247, 46.22766299792843], + [1554798074247, 46.655383290728864], + [1554798094247, 46.45705284677324], + [1554798114247, 46.45713571405586], + [1554798134247, 46.86151766756407], + [1554798154247, 46.90672301003809], + [1554798174247, 46.51535856335299], + [1554798194247, 46.10570297530587], + [1554798214247, 46.33418626714916], + [1554798234247, 46.003003880616205], + [1554798254247, 46.2925486741529], + [1554798274247, 46.39633084477583], + [1554798294247, 46.16591301596327], + [1554798314247, 46.416551590010194], + [1554798334247, 46.45425310871843], + [1554798354247, 46.0032881844452], + [1554798374247, 45.82313918899386], + [1554798394247, 46.219193352046396], + [1554798414247, 45.8586762819549], + [1554798434247, 46.040014378177375], + [1554798454247, 46.236218833624115], + [1554798474247, 46.45926020739284], + [1554798494247, 46.897768102161415], + [1554798514247, 47.36566794657619], + [1554798534247, 47.2382175292508], + [1554798554247, 47.50315436537415], + [1554798574247, 47.195192237664564], + [1554798594247, 47.63493540272602], + [1554798614247, 47.507004471059325], + [1554798634247, 47.97730627271725], + [1554798654247, 47.84750321321647], + [1554798674247, 47.779067424183054], + [1554798694247, 47.51070588382222], + [1554798714247, 47.31024519328251], + [1554798734247, 47.38794688477116], + [1554798754247, 47.32981223758303], + [1554798774247, 47.72299840553466], + [1554798794247, 47.95529996227096], + [1554798814247, 48.31157095625241], + [1554798834247, 48.023368909559515], + [1554798854247, 47.72332648683902], + [1554798874247, 47.8896007675284], + [1554798894247, 47.52159434109153], + [1554798914247, 47.36082882158501], + [1554798934247, 47.25781883471349], + [1554798954247, 47.345951933554566], + [1554798974247, 46.94903667465156], + [1554798994247, 47.39688904725867], + [1554799014247, 47.52423404078518], + [1554799034247, 47.0397640935533], + [1554799054247, 47.46602364797375], + [1554799074247, 47.111211461266905], + [1554799094247, 47.601388184562914], + [1554799114247, 47.68148443042845], + [1554799134247, 47.58525617262463], + [1554799154247, 47.78701709976165], + [1554799174247, 48.036966778117275], + [1554799194247, 47.970336996592096], + [1554799214247, 47.759473765364], + [1554799234247, 47.34751038233216], + [1554799254247, 47.57114234065436], + [1554799274247, 47.907061454075155], + [1554799294247, 48.084671942100634], + [1554799314247, 47.681986292923746], + [1554799334247, 47.95817351464097], + [1554799354247, 48.04032430472102], + [1554799374247, 47.97074694936207], + [1554799394247, 48.053606942051346], + [1554799414247, 48.03665265330263], + [1554799434247, 48.40213107480879], + [1554799454247, 48.66966744616825], + [1554799474247, 48.37860616360151], + [1554799494247, 48.69223531031285], + [1554799514247, 48.897104105650236], + [1554799534247, 48.72228611537678], + [1554799554247, 49.20245075823246], + [1554799574247, 49.08271267686173], + [1554799594247, 49.01995415573646], + [1554799614247, 49.405566345327166], + [1554799634247, 49.338088388754954], + [1554799654247, 49.42610506682994], + [1554799674247, 49.26870188087562], + [1554799694247, 48.99504223682648], + [1554799714247, 49.13641512533093], + [1554799734247, 48.68046815153081], + [1554799754247, 48.23884835789657], + [1554799774247, 48.34490487390389], + [1554799794247, 47.8621097886342], + [1554799814247, 48.10324901149713], + [1554799834247, 47.65769254778163], + [1554799854247, 48.04863600220461], + [1554799874247, 48.504658322467876], + [1554799894247, 48.84155760382869], + [1554799914247, 48.78203918293767], + [1554799934247, 48.69555264932167], + [1554799954247, 48.534953659795086], + [1554799974247, 48.32753840030407], + [1554799994247, 48.319124059010136], + [1554800014247, 48.08900748459846], + [1554800034247, 48.41592904647356], + [1554800054247, 48.654168369087024], + [1554800074247, 48.174716148384945], + [1554800094247, 47.838563784529015], + [1554800114247, 47.688834110534465], + [1554800134247, 48.01330592764464], + [1554800154247, 47.66787416286568], + [1554800174247, 47.480850102022586], + [1554800194247, 47.831846287590565], + [1554800214247, 47.41691220431661], + [1554800234247, 47.8412914393716], + [1554800254247, 47.83510232228141], + [1554800274247, 47.773877998469274], + [1554800294247, 47.515405390707095], + [1554800314247, 47.993473718819686], + [1554800334247, 48.34644356161968], + [1554800354247, 48.36355857235089], + [1554800374247, 48.57236022294879], + [1554800394247, 48.90877596270302], + [1554800414247, 49.062335690183524], + [1554800434247, 48.90760032123759], + [1554800454247, 48.40792258975594], + [1554800474247, 48.15638977565654], + [1554800494247, 48.514039980655234], + [1554800514247, 48.95574910285047], + [1554800534247, 48.99709284602056], + [1554800554247, 49.38005823887513], + [1554800574247, 49.65241792934206], + [1554800594247, 49.95055381158393], + [1554800614247, 50.28428874387261], + [1554800634247, 50.47285733412508], + [1554800654247, 50.35112364359045], + [1554800674247, 50.5519475699319], + [1554800694247, 50.61198314523461], + [1554800714247, 51.027913008897656], + [1554800734247, 50.822749098517605], + [1554800754247, 51.234030918977524], + [1554800774247, 51.207186361081156], + [1554800794247, 51.05369641506709], + [1554800814247, 51.20809949100641], + [1554800834247, 51.00097254666107], + [1554800854247, 50.502863733149596], + [1554800874247, 50.079695380284896], + [1554800894247, 49.86342104655181], + [1554800914247, 49.46833918185673], + [1554800934247, 49.6119576574696], + [1554800954247, 49.963978699045946], + [1554800974247, 49.59214014681593], + [1554800994247, 50.08518436521155], + [1554801014247, 50.40915968570567], + [1554801034247, 50.602524820648696], + [1554801054247, 50.985501356814034], + [1554801074247, 50.60559150837181], + [1554801094247, 50.485487661329294], + [1554801114247, 50.867623335094024], + [1554801134247, 50.96489864591541], + [1554801154247, 51.15309133118275], + [1554801174247, 51.24579939680081], + [1554801194247, 51.424479415888285], + [1554801214247, 51.5588899009813], + [1554801234247, 51.54490468599705], + [1554801254247, 51.40662689618962], + [1554801274247, 51.75006583094692], + [1554801294247, 52.20228577285978], + [1554801314247, 52.348547272368506], + [1554801334247, 52.39186508724331], + [1554801354247, 52.542927652025924], + [1554801374247, 52.27966546246372], + [1554801394247, 52.20452443809642], + [1554801414247, 51.915875146571814], + [1554801434247, 51.85700055331651], + [1554801454247, 51.41503493304628], + [1554801474247, 51.91375992161767], + [1554801494247, 51.64979593631921], + [1554801514247, 51.59721672310636], + [1554801534247, 51.36646019351009], + [1554801554247, 51.17970052059037], + [1554801574247, 51.51534040387782], + [1554801594247, 51.88251684232427], + [1554801614247, 51.703014931819474], + [1554801634247, 51.547017299912504], + [1554801654247, 51.275856922468904], + [1554801674247, 51.71448641006434], + [1554801694247, 51.576144190557336], + [1554801714247, 51.354383834775916], + [1554801734247, 51.04396571574281], + [1554801754247, 50.876641592142796], + [1554801774247, 51.336655229980316], + [1554801794247, 50.867416279953595], + [1554801814247, 51.130911647942355], + [1554801834247, 51.18234874849458], + [1554801854247, 51.50380094567395], + [1554801874247, 51.828265541951005], + [1554801894247, 51.41901070104453], + [1554801914247, 50.99815354555354], + [1554801934247, 51.32753225892714], + [1554801954247, 51.59398074693891], + [1554801974247, 51.83542718732424], + [1554801994247, 51.927373369486894], + [1554802014247, 52.34926003699012], + [1554802034247, 52.33484803971464], + [1554802054247, 52.32711385955333], + [1554802074247, 51.83460572908414], + [1554802094247, 51.71984751064315], + [1554802114247, 51.77033331018975], + [1554802134247, 51.350955694201005], + [1554802154247, 51.65773417914936], + [1554802174247, 51.48342088576234], + [1554802194247, 51.16267545464356], + [1554802214247, 51.323530207826956], + [1554802234247, 51.567191168336976], + [1554802254247, 51.13294706734198], + [1554802274247, 50.79800554137457], + [1554802294247, 51.04722627688948], + [1554802314247, 51.318544212080354], + [1554802334247, 51.532386858163754], + [1554802354247, 51.47703791469364], + [1554802374247, 51.78920946190912], + [1554802394247, 51.85211680399902], + [1554802414247, 51.99320526572213], + [1554802434247, 51.57547183300737], + [1554802454247, 51.97761981686591], + [1554802474247, 51.87004631283087], + [1554802494247, 52.158068947935384], + [1554802514247, 51.94930117584308], + [1554802534247, 51.53478371041338], + [1554802554247, 51.17882972197612], + [1554802574247, 50.701283694457466], + [1554802594247, 50.90473753625081], + [1554802614247, 50.65241735456049], + [1554802634247, 50.438246098999585], + [1554802654247, 50.37870735226924], + [1554802674247, 50.85584471285298], + [1554802694247, 51.274089045530395], + [1554802714247, 51.59978276742954], + [1554802734247, 51.562936160576584], + [1554802754247, 51.42151903058987], + [1554802774247, 51.894976900116355], + [1554802794247, 51.83169631691224], + [1554802814247, 51.79801425800586], + [1554802834247, 51.479633959435034], + [1554802854247, 51.70290776584143], + [1554802874247, 51.757226685563765], + [1554802894247, 52.03704183387305], + [1554802914247, 52.3819953868567], + [1554802934247, 51.88287073947722], + [1554802954247, 52.10125989403958], + [1554802974247, 51.872702036903526], + [1554802994247, 52.009175627089505], + [1554803014247, 52.50785086552939], + [1554803034247, 52.36391362787773], + [1554803054247, 52.77582474643076], + [1554803074247, 53.14634835172726], + [1554803094247, 53.571861564649836], + [1554803114247, 53.34550413497026], + [1554803134247, 53.53080010106201], + [1554803154247, 53.73421984607534], + [1554803174247, 53.56007952437269], + [1554803194247, 53.131414787142056], + [1554803214247, 52.94547963572799], + [1554803234247, 53.14281647882233], + [1554803254247, 52.73823765064605], + [1554803274247, 52.956467351101274], + [1554803294247, 53.35534255411743], + [1554803314247, 53.192930959674406], + [1554803334247, 53.32694937486834], + [1554803354247, 53.15027458209927], + [1554803374247, 53.5587680311651], + [1554803394247, 53.568883926439334], + [1554803414247, 53.80781403307825], + [1554803434247, 54.170116862726246], + [1554803454247, 53.79726949862653], + [1554803474247, 54.118793890386996], + [1554803494247, 54.19522192357821], + [1554803514247, 53.93837314058516], + [1554803534247, 53.61455261022302], + [1554803554247, 53.25549925605131], + [1554803574247, 53.30871660112379], + [1554803594247, 53.025228370296], + [1554803614247, 52.715005370790905], + [1554803634247, 52.26518145403466], + [1554803654247, 51.77433258023653], + [1554803674247, 51.92907944820857], + [1554803694247, 51.799802420253314], + [1554803714247, 52.23576201540642], + [1554803734247, 51.94765338498968], + [1554803754247, 51.65532307329866], + [1554803774247, 51.95953898434276], + [1554803794247, 52.30572709425199], + [1554803814247, 52.50628901507423], + [1554803834247, 52.18392152073497], + [1554803854247, 52.37085384093291], + [1554803874247, 51.958905637529526], + [1554803894247, 52.33884893220496], + [1554803914247, 51.945176746826625], + [1554803934247, 52.2903551152492], + [1554803954247, 52.45484660570278], + [1554803974247, 52.26531643836918], + [1554803994247, 51.83132366758987], + [1554804014247, 51.72448213626581], + [1554804034247, 51.387397812656125], + [1554804054247, 51.482075969410865], + [1554804074247, 51.516830773532355], + [1554804094247, 51.48614199714788], + [1554804114247, 51.1107772949971], + [1554804134247, 51.58592082858312], + [1554804154247, 52.01002593365593], + [1554804174247, 52.05010430476184], + [1554804194247, 51.69390021751488], + [1554804214247, 52.10787479914773], + [1554804234247, 52.17172758152165], + [1554804254247, 51.78777541365326], + [1554804274247, 51.67579928345696], + [1554804294247, 51.94442819030671], + [1554804314247, 51.80897520694817], + [1554804334247, 51.67986689129912], + [1554804354247, 51.55210735174368], + [1554804374247, 51.77569039319583], + [1554804394247, 51.45788841681898], + [1554804414247, 51.87269232666622], + [1554804434247, 51.82302735551395], + [1554804454247, 52.31024585013042], + [1554804474247, 51.93060365264004], + [1554804494247, 52.40571312978707], + [1554804514247, 52.39673639936394], + [1554804534247, 52.18557628791588], + [1554804554247, 52.60978266763105], + [1554804574247, 52.16131048329209], + [1554804594247, 52.505784425001984], + [1554804614247, 52.32401176586753], + [1554804634247, 52.30325652498879], + [1554804654247, 52.28613876880225], + [1554804674247, 52.080496843116386], + [1554804694247, 51.61527428444171], + [1554804714247, 51.83680620548246], + [1554804734247, 52.30374804621723], + [1554804754247, 52.67939694931608], + [1554804774247, 52.94943544533422], + [1554804794247, 53.24374366240067], + [1554804814247, 52.768273806147725], + [1554804834247, 53.074934594212785], + [1554804854247, 52.8116690446343], + [1554804874247, 52.420101586577], + [1554804894247, 52.375842717401966], + [1554804914247, 52.3698756882421], + [1554804934247, 51.87583553645484], + [1554804954247, 51.54912664248644], + [1554804974247, 51.990562270095786], + [1554804994247, 52.090483035778746], + [1554805014247, 51.67299602002489], + [1554805034247, 51.378645555389255], + [1554805054247, 51.18008092332962], + [1554805074247, 50.90350661363346], + [1554805094247, 50.85344076579689], + [1554805114247, 50.75969452484323], + [1554805134247, 51.15665586466479], + [1554805154247, 51.311445500103396], + [1554805174247, 51.236856143793126], + [1554805194247, 51.17414261055051], + [1554805214247, 51.108641060373124], + [1554805234247, 50.75890985719905], + [1554805254247, 50.48058630203468], + [1554805274247, 50.76721935252362], + [1554805294247, 50.5330383603889], + [1554805314247, 50.26520598051574], + [1554805334247, 50.60944764624979], + [1554805354247, 50.74484810624328], + [1554805374247, 51.01668313286863], + [1554805394247, 51.05429730952428], + [1554805414247, 51.39068964671044], + [1554805434247, 51.317735823836614], + [1554805454247, 51.25736086149264], + [1554805474247, 50.922379102839166], + [1554805494247, 50.98179933241315], + [1554805514247, 51.374526290084134], + [1554805534247, 51.40831930835523], + [1554805554247, 51.443173852379545], + [1554805574247, 51.4683090318251], + [1554805594247, 51.709059003470124], + [1554805614247, 52.19184281346864], + [1554805634247, 52.35070138588975], + [1554805654247, 51.97957436658507], + [1554805674247, 51.91458431154472], + [1554805694247, 52.41026984953236], + [1554805714247, 52.275201030560105], + [1554805734247, 52.18307838063212], + [1554805754247, 52.060069338900774], + [1554805774247, 51.61450171082168], + [1554805794247, 52.09853956209946], + [1554805814247, 52.588843625759424], + [1554805834247, 52.80348947533139], + [1554805854247, 53.28197181050794], + [1554805874247, 53.70501200876997], + [1554805894247, 53.89498917310595], + [1554805914247, 53.99791259724504], + [1554805934247, 53.62968839158572], + [1554805954247, 53.99473243614239], + [1554805974247, 53.97607431885154], + [1554805994247, 54.1654752913762], + [1554806014247, 54.29381284957149], + [1554806034247, 54.26736760766921], + [1554806054247, 54.72579383573786], + [1554806074247, 54.87585753445682], + [1554806094247, 54.90114957236757], + [1554806114247, 54.45131273475261], + [1554806134247, 54.00663438718738], + [1554806154247, 54.36866367166484], + [1554806174247, 54.455988047905954], + [1554806194247, 54.53444237413403], + [1554806214247, 54.259447240560334], + [1554806234247, 54.739815020637415], + [1554806254247, 54.53713835073127], + [1554806274247, 54.207215355017205], + [1554806294247, 54.5440608018207], + [1554806314247, 54.358821571481016], + [1554806334247, 54.72879724971994], + [1554806354247, 54.90023956328739], + [1554806374247, 54.74057764265007], + [1554806394247, 54.75935443450963], + [1554806414247, 55.02078995986204], + [1554806434247, 55.47735667708813], + [1554806454247, 55.728823396928945], + [1554806474247, 56.163253634213675], + [1554806494247, 55.8515954825293], + [1554806514247, 56.129890392645194], + [1554806534247, 55.74162749726028], + [1554806554247, 56.21329274387774], + [1554806574247, 55.998639128941015], + [1554806594247, 56.17167173612524], + [1554806614247, 56.37502616405982], + [1554806634247, 56.163483013167344], + [1554806654247, 55.84694130467721], + [1554806674247, 55.45846837023379], + [1554806694247, 55.04755139168062], + [1554806714247, 55.023136962195196], + [1554806734247, 55.03318249113286], + [1554806754247, 55.15746201013343], + [1554806774247, 54.69192101415061], + [1554806794247, 54.84111015085251], + [1554806814247, 54.58742405929199], + [1554806834247, 54.97799911256185], + [1554806854247, 54.764821076597485], + [1554806874247, 54.78776554693746], + [1554806894247, 54.36349387408045], + [1554806914247, 53.89745720207634], + [1554806934247, 54.17384926356723], + [1554806954247, 53.846082255988286], + [1554806974247, 53.90613692731394], + [1554806994247, 53.87258573355891], + [1554807014247, 54.17549073728332], + [1554807034247, 53.68618357720563], + [1554807054247, 53.513969787757105], + [1554807074247, 53.0552099855896], + [1554807094247, 52.765588324483865], + [1554807114247, 52.658001079532866], + [1554807134247, 53.07486561753133], + [1554807154247, 52.69459960292874], + [1554807174247, 52.98255693457559], + [1554807194247, 53.20218278203097], + [1554807214247, 52.97957847809027], + [1554807234247, 53.203425156589425], + [1554807254247, 53.12562342353098], + [1554807274247, 52.98722273991035], + [1554807294247, 52.82655589418688], + [1554807314247, 52.52987556980093], + [1554807334247, 52.491534753287645], + [1554807354247, 52.55176305705825], + [1554807374247, 52.13841375230353], + [1554807394247, 51.834840312920164], + [1554807414247, 52.184416639498664], + [1554807434247, 51.72479740399346], + [1554807454247, 52.155588780091456], + [1554807474247, 51.843576760185535], + [1554807494247, 51.63505755687057], + [1554807514247, 51.328848338540325], + [1554807534247, 51.17434126071598], + [1554807554247, 51.22528683963288], + [1554807574247, 51.45420767833925], + [1554807594247, 51.22268991224942], + [1554807614247, 50.79238198146152], + [1554807634247, 50.45484627009857], + [1554807654247, 50.85902478247322], + [1554807674247, 51.05110301744823], + [1554807694247, 51.441065782940804], + [1554807714247, 51.72675194566211], + [1554807734247, 51.34741055949714], + [1554807754247, 50.920382272281294], + [1554807774247, 50.70536279085003], + [1554807794247, 50.55798114104046], + [1554807814247, 50.725557394433494], + [1554807834247, 50.60243126287948], + [1554807854247, 50.14375392566316], + [1554807874247, 50.2002531691062], + [1554807894247, 50.200943028986934], + [1554807914247, 49.93557347736677], + [1554807934247, 50.3241686237509], + [1554807954247, 50.74023874549823], + [1554807974247, 50.381498198272375], + [1554807994247, 50.52372793713143], + [1554808014247, 50.59619769171313], + [1554808034247, 50.89556341815888], + [1554808054247, 50.86443137192155], + [1554808074247, 50.63167033746789], + [1554808094247, 50.13964173171047], + [1554808114247, 50.25093231733134], + [1554808134247, 50.08498877315317], + [1554808154247, 50.11947998142], + [1554808174247, 49.987009677804366], + [1554808194247, 49.840080913269475], + [1554808214247, 50.209998565510354], + [1554808234247, 50.531756264070935], + [1554808254247, 50.74837122490037], + [1554808274247, 50.7311698620495], + [1554808294247, 50.26107114525714], + [1554808314247, 50.57160680670211], + [1554808334247, 50.658461548491324], + [1554808354247, 50.32651326535061], + [1554808374247, 50.661562835023595], + [1554808394247, 50.44958975353214], + [1554808414247, 50.22399999500883], + [1554808434247, 50.58871685273966], + [1554808454247, 50.6742183549089], + [1554808474247, 50.32618916949026], + [1554808494247, 49.97104996971649], + [1554808514247, 50.435289475414216], + [1554808534247, 50.60512926447027], + [1554808554247, 50.73020639421864], + [1554808574247, 50.99932725118429], + [1554808594247, 51.34816166255093], + [1554808614247, 51.26324189269789], + [1554808634247, 50.85324941286893], + [1554808654247, 50.72520384570293], + [1554808674247, 51.089644509784655], + [1554808694247, 51.542456610721025], + [1554808714247, 51.777359837645164], + [1554808734247, 52.135547900174195], + [1554808754247, 52.28862099588846], + [1554808774247, 51.997792836163434], + [1554808794247, 52.305297731262264], + [1554808814247, 52.221352299608874], + [1554808834247, 52.02839560401225], + [1554808854247, 51.63103387134092], + [1554808874247, 51.54216467728416], + [1554808894247, 51.55386052088342], + [1554808914247, 51.17586087923488], + [1554808934247, 50.76208251333271], + [1554808954247, 50.317727703878695], + [1554808974247, 50.090846251422974], + [1554808994247, 50.06945817010757], + [1554809014247, 50.02269714272485], + [1554809034247, 49.9014869250931], + [1554809054247, 49.54981076067255], + [1554809074247, 49.84951930203291], + [1554809094247, 49.47499972389107], + [1554809114247, 49.62465014644696], + [1554809134247, 49.24747194031203], + [1554809154247, 49.069372398247346], + [1554809174247, 49.51527762106267], + [1554809194247, 49.55929829562035], + [1554809214247, 49.14007484550787], + [1554809234247, 49.55967463057968], + [1554809254247, 49.92414029604148], + [1554809274247, 50.28248263822046], + [1554809294247, 50.43547187450998], + [1554809314247, 50.01088683196451], + [1554809334247, 49.677926301450555], + [1554809354247, 49.97511400319861], + [1554809374247, 50.224853104822266], + [1554809394247, 50.220580489563496], + [1554809414247, 50.32549316137843], + [1554809434247, 50.81418718936579], + [1554809454247, 51.28120757217762], + [1554809474247, 51.465547229465], + [1554809494247, 51.37421458009423], + [1554809514247, 51.04893929102602], + [1554809534247, 50.66827537100915], + [1554809554247, 51.010305384682916], + [1554809574247, 50.74651884448325], + [1554809594247, 50.61682216706967], + [1554809614247, 50.45361096216425], + [1554809634247, 50.90490891959407], + [1554809654247, 50.622456452782494], + [1554809674247, 50.50344283767147], + [1554809694247, 50.46493050792487], + [1554809714247, 50.35998380458337], + [1554809734247, 50.1328954252928], + [1554809754247, 49.84079495406359], + [1554809774247, 50.13123680838925], + [1554809794247, 50.20403867276622], + [1554809814247, 50.004272675190784], + [1554809834247, 49.723751138918296], + [1554809854247, 49.49859072862423], + [1554809874247, 49.538307673194836], + [1554809894247, 49.62089922968913], + [1554809914247, 49.82385421066983], + [1554809934247, 49.84161674017104], + [1554809954247, 49.526737636369795], + [1554809974247, 49.931126418386356], + [1554809994247, 49.53343714924538], + [1554810014247, 49.42313707765715], + [1554810034247, 49.16979485487088], + [1554810054247, 49.652563787202645], + [1554810074247, 49.48023797398182], + [1554810094247, 49.966840603633734], + [1554810114247, 49.472083383816674], + [1554810134247, 49.37956146522102], + [1554810154247, 48.913166987107715], + [1554810174247, 48.70672990770373], + [1554810194247, 49.1880143597863], + [1554810214247, 49.49138355568559], + [1554810234247, 49.0630916077481], + [1554810254247, 48.85748269209717], + [1554810274247, 49.28639478935244], + [1554810294247, 49.13826091989152], + [1554810314247, 48.983630923627935], + [1554810334247, 48.68240787752351], + [1554810354247, 48.36663230019177], + [1554810374247, 48.52948288449895], + [1554810394247, 48.82498752624838], + [1554810414247, 49.10206080290292], + [1554810434247, 48.8130786016997], + [1554810454247, 48.663637941429585], + [1554810474247, 48.78385244438397], + [1554810494247, 48.5385370554751], + [1554810514247, 48.65982342796413], + [1554810534247, 48.2793032813205], + [1554810554247, 48.368720363392434], + [1554810574247, 47.95631221866125], + [1554810594247, 48.04947801392955], + [1554810614247, 47.92730902313688], + [1554810634247, 47.791227561595186], + [1554810654247, 47.696413872767344], + [1554810674247, 48.003461905264565], + [1554810694247, 48.41866753821385], + [1554810714247, 48.3323818553399], + [1554810734247, 48.55875807089029], + [1554810754247, 48.69664614708888], + [1554810774247, 48.39911556887364], + [1554810794247, 48.11355417510691], + [1554810814247, 47.68051884606699], + [1554810834247, 47.1839923323315], + [1554810854247, 47.521145818447444], + [1554810874247, 47.435239847122254], + [1554810894247, 47.80415137706029], + [1554810914247, 47.63696258266796], + [1554810934247, 48.03428238075079], + [1554810954247, 47.94997360430622], + [1554810974247, 47.55449851528431], + [1554810994247, 47.78824911083491], + [1554811014247, 47.4893779355486], + [1554811034247, 47.64650668855729], + [1554811054247, 47.22649114069579], + [1554811074247, 47.10626496382279], + [1554811094247, 46.853256635084975], + [1554811114247, 46.58521435687729], + [1554811134247, 46.46807667444405], + [1554811154247, 46.59110720595821], + [1554811174247, 46.47156843975408], + [1554811194247, 46.30570534424654], + [1554811214247, 46.327884115808345], + [1554811234247, 45.87249321102525], + [1554811254247, 45.93662730816857], + [1554811274247, 45.830703114024715], + [1554811294247, 45.7471098907337], + [1554811314247, 45.97554190426588], + [1554811334247, 45.83195232100273], + [1554811354247, 46.311066254110614], + [1554811374247, 46.502026295217874], + [1554811394247, 46.85743404788076], + [1554811414247, 47.058397205858235], + [1554811434247, 46.71734957659286], + [1554811454247, 47.00406489994063], + [1554811474247, 46.908589679853144], + [1554811494247, 46.46429522803091], + [1554811514247, 46.35314410074062], + [1554811534247, 46.08606779214885], + [1554811554247, 45.59440554131089], + [1554811574247, 46.01004712520209], + [1554811594247, 46.33290514899631], + [1554811614247, 45.90387315090703], + [1554811634247, 45.804826673859495], + [1554811654247, 45.58814979542495], + [1554811674247, 45.6383366715778], + [1554811694247, 46.098869094510555], + [1554811714247, 46.27645434323368], + [1554811734247, 46.38377282639434], + [1554811754247, 46.60623046278854], + [1554811774247, 46.853513275876644], + [1554811794247, 46.81150563219055], + [1554811814247, 46.325544759803684], + [1554811834247, 46.39222319511721], + [1554811854247, 46.05237287548122], + [1554811874247, 46.357861427033505], + [1554811894247, 45.872808350625355], + [1554811914247, 45.73033158647349], + [1554811934247, 46.181966738488526], + [1554811954247, 46.61144780966708], + [1554811974247, 46.944186256067475], + [1554811994247, 46.446866815105544], + [1554812014247, 46.87455438198626], + [1554812034247, 46.49680004841036], + [1554812054247, 46.110314234703566], + [1554812074247, 45.72718212902214], + [1554812094247, 45.855039988603075], + [1554812114247, 45.831083020621925], + [1554812134247, 45.934195744884576], + [1554812154247, 45.793162191919734], + [1554812174247, 45.595669324309405], + [1554812194247, 45.34395417586054], + [1554812214247, 45.48878147415903], + [1554812234247, 45.18708811432028], + [1554812254247, 45.68654757702763], + [1554812274247, 45.25733330257729], + [1554812294247, 44.802476591068185], + [1554812314247, 44.90227449426073], + [1554812334247, 44.77621515016869], + [1554812354247, 44.43700939403772], + [1554812374247, 44.89535195708861], + [1554812394247, 44.66555490148931], + [1554812414247, 44.77656357009823], + [1554812434247, 45.0781456336617], + [1554812454247, 45.02266276801925], + [1554812474247, 45.17853761454366], + [1554812494247, 45.206345465197174], + [1554812514247, 44.74293332634654], + [1554812534247, 45.12058926393326], + [1554812554247, 45.484527330308026], + [1554812574247, 45.72220471641109], + [1554812594247, 46.13939152292791], + [1554812614247, 46.00759269422592], + [1554812634247, 46.15320023087146], + [1554812654247, 46.31453520052207], + [1554812674247, 46.63327463975146], + [1554812694247, 46.74008671110519], + [1554812714247, 46.43464466851368], + [1554812734247, 46.09437986713492], + [1554812754247, 45.76744795370013], + [1554812774247, 46.15933621956665], + [1554812794247, 46.49926171251873], + [1554812814247, 46.26031394263079], + [1554812834247, 46.40700021317878], + [1554812854247, 46.019356637458465], + [1554812874247, 45.663769053656914], + [1554812894247, 46.11543163861163], + [1554812914247, 46.01937845681326], + [1554812934247, 46.053876490893266], + [1554812954247, 46.49976036351762], + [1554812974247, 46.48642420084204], + [1554812994247, 46.33380830950621], + [1554813014247, 46.46158553555841], + [1554813034247, 45.974232040531696], + [1554813054247, 45.84763240974679], + [1554813074247, 46.06094295457176], + [1554813094247, 45.57542828478516], + [1554813114247, 45.107768244929794], + [1554813134247, 45.29289069830043], + [1554813154247, 45.50682878428712], + [1554813174247, 45.48588008195146], + [1554813194247, 44.98951523195182], + [1554813214247, 44.682577096293755], + [1554813234247, 44.84745376781998], + [1554813254247, 44.58220779177513], + [1554813274247, 44.34705935598955], + [1554813294247, 43.91212590970287], + [1554813314247, 44.04615663810462], + [1554813334247, 43.78133590063513], + [1554813354247, 43.41643624560887], + [1554813374247, 43.63708147900446], + [1554813394247, 43.38739883558116], + [1554813414247, 43.64690789208579], + [1554813434247, 43.240387286772794], + [1554813454247, 43.02887852514058], + [1554813474247, 42.64466609459708], + [1554813494247, 42.59509438582544], + [1554813514247, 42.800700150025904], + [1554813534247, 42.99279809120495], + [1554813554247, 42.71212019392293], + [1554813574247, 42.26453618628849], + [1554813594247, 42.156627021840094], + [1554813614247, 42.18984321867831], + [1554813634247, 42.29340892976422], + [1554813654247, 42.593900952016476], + [1554813674247, 42.2330620746611], + [1554813694247, 41.86806010030196], + [1554813714247, 41.92031494441884], + [1554813734247, 41.77029002001442], + [1554813754247, 41.62068939271727], + [1554813774247, 41.27522742225526], + [1554813794247, 41.59092178660088], + [1554813814247, 41.197602991055604], + [1554813834247, 40.894310341221576], + [1554813854247, 40.9605769039487], + [1554813874247, 40.924569026392284], + [1554813894247, 40.6219617605231], + [1554813914247, 40.66747690052986], + [1554813934247, 40.3502087650845], + [1554813954247, 40.75856493329949], + [1554813974247, 40.77424153954944], + [1554813994247, 40.765533525784875], + [1554814014247, 40.7150752518103], + [1554814034247, 41.07494126786947], + [1554814054247, 41.50291852374512], + [1554814074247, 41.247377467265686], + [1554814094247, 41.60383347544849], + [1554814114247, 41.21723434866782], + [1554814134247, 41.17362119491221], + [1554814154247, 41.5483199633518], + [1554814174247, 41.26881119300047], + [1554814194247, 41.11926507536818], + [1554814214247, 41.279830040613255], + [1554814234247, 41.37424366244724], + [1554814254247, 41.23223435709267], + [1554814274247, 41.22891130945054], + [1554814294247, 40.84273309880227], + [1554814314247, 40.77105807274393], + [1554814334247, 40.86144344756839], + [1554814354247, 40.53399404435103], + [1554814374247, 40.89965536321252], + [1554814394247, 40.551632896315354], + [1554814414247, 40.27233656089394], + [1554814434247, 39.79467584395313], + [1554814454247, 39.5446056978286], + [1554814474247, 39.21168731652927], + [1554814494247, 39.53512815542741], + [1554814514247, 39.99562353822233], + [1554814534247, 39.85823942167259], + [1554814554247, 40.124808305253865], + [1554814574247, 40.356725295094996], + [1554814594247, 39.88169507281861], + [1554814614247, 40.09602202671889], + [1554814634247, 40.32994988463872], + [1554814654247, 40.6652027871041], + [1554814674247, 40.33146187156191], + [1554814694247, 39.89510766819647], + [1554814714247, 40.282027306139604], + [1554814734247, 40.34382349011193], + [1554814754247, 40.74449254471113], + [1554814774247, 40.605736246604756], + [1554814794247, 40.71323696936045], + [1554814814247, 40.98756203169225], + [1554814834247, 41.15554546599332], + [1554814854247, 40.97696657263369], + ], + color: '#6ED0E0', + info: [ + { title: 'min', text: '14.42', numeric: 14.427101844163694 }, + { title: 'max', text: '18.42', numeric: 18.427101844163694 }, + ], + isVisible: true, + yAxis: 1, + }, + ], + timeRange: { + from: moment('2019-04-09T07:01:14.247Z'), + to: moment('2019-04-09T13:01:14.247Z'), + raw: { + from: 'now-6h', + to: 'now', + }, + }, + width: 944, + height: 294, + isLegendVisible: true, + showBars: false, + showLines: true, + showPoints: false, + placement: 'under', + onSeriesColorChange: (label, color) => { + if (onSeriesColorChange) { + onSeriesColorChange(label, color); + } + }, + onSeriesAxisToggle: (label, yAxis) => { + if (onSeriesAxisToggle) { + onSeriesAxisToggle(label, yAxis); + } + }, + onToggleSort: () => {}, + displayMode: displayMode || LegendDisplayMode.List, +}); diff --git a/packages/grafana-ui/src/components/Legend/Legend.story.tsx b/packages/grafana-ui/src/components/Legend/Legend.story.tsx new file mode 100644 index 0000000000000..3cd561f03014a --- /dev/null +++ b/packages/grafana-ui/src/components/Legend/Legend.story.tsx @@ -0,0 +1,142 @@ +import React from 'react'; +import { storiesOf } from '@storybook/react'; +import { LegendList, LegendPlacement, LegendItem, LegendTable } from './Legend'; +import tinycolor from 'tinycolor2'; +import { DisplayValue } from '../../types/index'; +import { number, select, text } from '@storybook/addon-knobs'; +import { action } from '@storybook/addon-actions'; +import { GraphLegendListItem, GraphLegendTableRow, GraphLegendItemProps } from '../Graph/GraphLegendItem'; + +export const generateLegendItems = (numberOfSeries: number, statsToDisplay?: DisplayValue[]): LegendItem[] => { + const alphabet = 'abcdefghijklmnopqrstuvwxyz'.split(''); + + return [...new Array(numberOfSeries)].map((item, i) => { + return { + label: `${alphabet[i].toUpperCase()}-series`, + color: tinycolor.fromRatio({ h: i / alphabet.length, s: 1, v: 1 }).toHexString(), + isVisible: true, + yAxis: 1, + displayValues: statsToDisplay || [], + }; + }); +}; + +const getStoriesKnobs = (table = false) => { + const numberOfSeries = number('Number of series', 3); + const containerWidth = select( + 'Container width', + { + Small: '200px', + Medium: '500px', + 'Full width': '100%', + }, + '100%' + ); + + const rawRenderer = (item: LegendItem) => ( + <> + Label: {item.label}, Color: {item.color}, isVisible:{' '} + {item.isVisible ? 'yes' : 'no'} + + ); + + const customRenderer = (component: React.ComponentType) => (item: LegendItem) => + React.createElement(component, { + item, + onLabelClick: action('GraphLegendItem label clicked'), + onSeriesColorChange: action('Series color changed'), + onToggleAxis: action('Y-axis toggle'), + }); + + const typeSpecificRenderer = table + ? { + 'Custom renderer(GraphLegendTablerow)': 'custom-tabe', + } + : { + 'Custom renderer(GraphLegendListItem)': 'custom-list', + }; + const legendItemRenderer = select( + 'Item rendered', + { + 'Raw renderer': 'raw', + ...typeSpecificRenderer, + }, + 'raw' + ); + + const rightAxisSeries = text('Right y-axis series, i.e. A,C', ''); + + const legendPlacement = select( + 'Legend placement', + { + under: 'under', + right: 'right', + }, + 'under' + ); + + return { + numberOfSeries, + containerWidth, + itemRenderer: + legendItemRenderer === 'raw' + ? rawRenderer + : customRenderer(legendItemRenderer === 'custom-list' ? GraphLegendListItem : GraphLegendTableRow), + rightAxisSeries, + legendPlacement, + }; +}; + +const LegendStories = storiesOf('UI/Legend/Legend', module); + +LegendStories.add('list', () => { + const { numberOfSeries, itemRenderer, containerWidth, rightAxisSeries, legendPlacement } = getStoriesKnobs(); + let items = generateLegendItems(numberOfSeries); + + items = items.map(i => { + if ( + rightAxisSeries + .split(',') + .map(s => s.trim()) + .indexOf(i.label.split('-')[0]) > -1 + ) { + i.yAxis = 2; + } + + return i; + }); + return ( +
+ +
+ ); +}); + +LegendStories.add('table', () => { + const { numberOfSeries, itemRenderer, containerWidth, rightAxisSeries, legendPlacement } = getStoriesKnobs(true); + let items = generateLegendItems(numberOfSeries); + + items = items.map(i => { + if ( + rightAxisSeries + .split(',') + .map(s => s.trim()) + .indexOf(i.label.split('-')[0]) > -1 + ) { + i.yAxis = 2; + } + + return { + ...i, + info: [ + { title: 'min', text: '14.42', numeric: 14.427101844163694 }, + { title: 'max', text: '18.42', numeric: 18.427101844163694 }, + ], + }; + }); + return ( +
+ +
+ ); +}); diff --git a/packages/grafana-ui/src/components/Legend/Legend.tsx b/packages/grafana-ui/src/components/Legend/Legend.tsx new file mode 100644 index 0000000000000..6f417f7257463 --- /dev/null +++ b/packages/grafana-ui/src/components/Legend/Legend.tsx @@ -0,0 +1,43 @@ +import { DisplayValue } from '../../types/index'; + +import { LegendList } from './LegendList'; +import { LegendTable } from './LegendTable'; + +export enum LegendDisplayMode { + List = 'list', + Table = 'table', +} +export interface LegendBasicOptions { + isVisible: boolean; + asTable: boolean; +} + +export interface LegendRenderOptions { + placement: LegendPlacement; + hideEmpty?: boolean; + hideZero?: boolean; +} + +export type LegendPlacement = 'under' | 'right' | 'over'; // Over used by piechart + +export interface LegendOptions extends LegendBasicOptions, LegendRenderOptions {} + +export interface LegendItem { + label: string; + color: string; + isVisible: boolean; + yAxis: number; + displayValues?: DisplayValue[]; +} + +export interface LegendComponentProps { + className?: string; + items: LegendItem[]; + placement: LegendPlacement; + // Function to render given item + itemRenderer?: (item: LegendItem, index: number) => JSX.Element; +} + +export interface LegendProps extends LegendComponentProps {} + +export { LegendList, LegendTable }; diff --git a/packages/grafana-ui/src/components/Legend/LegendList.tsx b/packages/grafana-ui/src/components/Legend/LegendList.tsx new file mode 100644 index 0000000000000..d103aa3ed8067 --- /dev/null +++ b/packages/grafana-ui/src/components/Legend/LegendList.tsx @@ -0,0 +1,66 @@ +import React, { useContext } from 'react'; +import { LegendComponentProps, LegendItem } from './Legend'; +import { InlineList } from '../List/InlineList'; +import { List } from '../List/List'; +import { css, cx } from 'emotion'; +import { ThemeContext } from '../../themes/ThemeContext'; + +export const LegendList: React.FunctionComponent = ({ + items, + itemRenderer, + placement, + className, +}) => { + const theme = useContext(ThemeContext); + + const renderItem = (item: LegendItem, index: number) => { + return ( + + {itemRenderer ? itemRenderer(item, index) : item.label} + + ); + }; + + const getItemKey = (item: LegendItem) => item.label; + + const styles = { + wrapper: cx( + css` + display: flex; + flex-wrap: wrap; + justify-content: space-between; + width: 100%; + `, + className + ), + section: css` + display: flex; + `, + sectionRight: css` + justify-content: flex-end; + flex-grow: 1; + `, + }; + + return placement === 'under' ? ( +
+
+ item.yAxis === 1)} renderItem={renderItem} getItemKey={getItemKey} /> +
+
+ item.yAxis !== 1)} renderItem={renderItem} getItemKey={getItemKey} /> +
+
+ ) : ( + + ); +}; + +LegendList.displayName = 'LegendList'; diff --git a/packages/grafana-ui/src/components/Legend/LegendSeriesIcon.tsx b/packages/grafana-ui/src/components/Legend/LegendSeriesIcon.tsx new file mode 100644 index 0000000000000..1913c2e500d25 --- /dev/null +++ b/packages/grafana-ui/src/components/Legend/LegendSeriesIcon.tsx @@ -0,0 +1,35 @@ +import React from 'react'; +import { SeriesColorPicker } from '../ColorPicker/ColorPicker'; +import { SeriesIcon } from './SeriesIcon'; + +interface LegendSeriesIconProps { + color: string; + yAxis: number; + onColorChange: (color: string) => void; + onToggleAxis?: () => void; +} + +export const LegendSeriesIcon: React.FunctionComponent = ({ + yAxis, + color, + onColorChange, + onToggleAxis, +}) => { + return ( + + {({ ref, showColorPicker, hideColorPicker }) => ( + + + + )} + + ); +}; + +LegendSeriesIcon.displayName = 'LegendSeriesIcon'; diff --git a/packages/grafana-ui/src/components/Legend/LegendStatsList.tsx b/packages/grafana-ui/src/components/Legend/LegendStatsList.tsx new file mode 100644 index 0000000000000..b53f3cc2a536c --- /dev/null +++ b/packages/grafana-ui/src/components/Legend/LegendStatsList.tsx @@ -0,0 +1,28 @@ +import React from 'react'; +import { InlineList } from '../List/InlineList'; +import { css } from 'emotion'; +import { DisplayValue } from '../../types/displayValue'; +import capitalize from 'lodash/capitalize'; + +const LegendItemStat: React.FunctionComponent<{ stat: DisplayValue }> = ({ stat }) => { + return ( +
+ {stat.title && `${capitalize(stat.title)}:`} {stat.text} +
+ ); +}; + +LegendItemStat.displayName = 'LegendItemStat'; + +export const LegendStatsList: React.FunctionComponent<{ stats: DisplayValue[] }> = ({ stats }) => { + if (stats.length === 0) { + return null; + } + return } />; +}; + +LegendStatsList.displayName = 'LegendStatsList'; diff --git a/packages/grafana-ui/src/components/Legend/LegendTable.tsx b/packages/grafana-ui/src/components/Legend/LegendTable.tsx new file mode 100644 index 0000000000000..38a6bd1497b96 --- /dev/null +++ b/packages/grafana-ui/src/components/Legend/LegendTable.tsx @@ -0,0 +1,83 @@ +import React, { useContext } from 'react'; +import { css, cx } from 'emotion'; +import { LegendComponentProps } from './Legend'; +import { ThemeContext } from '../../themes/ThemeContext'; + +interface LegendTableProps extends LegendComponentProps { + columns: string[]; + sortBy?: string; + sortDesc?: boolean; + onToggleSort?: (sortBy: string) => void; +} + +export const LegendTable: React.FunctionComponent = ({ + items, + columns, + sortBy, + sortDesc, + itemRenderer, + className, + onToggleSort, +}) => { + const theme = useContext(ThemeContext); + + return ( + + + + {columns.map(columnHeader => { + return ( + + ); + })} + + + + {items.map((item, index) => { + return itemRenderer ? ( + itemRenderer(item, index) + ) : ( + + + + ); + })} + +
{ + if (onToggleSort) { + onToggleSort(columnHeader); + } + }} + > + {columnHeader} + {sortBy === columnHeader && ( + + )} +
{item.label}
+ ); +}; diff --git a/packages/grafana-ui/src/components/Legend/SeriesIcon.tsx b/packages/grafana-ui/src/components/Legend/SeriesIcon.tsx new file mode 100644 index 0000000000000..091d79f7fd0d0 --- /dev/null +++ b/packages/grafana-ui/src/components/Legend/SeriesIcon.tsx @@ -0,0 +1,5 @@ +import React from 'react'; + +export const SeriesIcon: React.FunctionComponent<{ color: string }> = ({ color }) => { + return ; +}; diff --git a/packages/grafana-ui/src/components/List/AbstractList.test.tsx b/packages/grafana-ui/src/components/List/AbstractList.test.tsx new file mode 100644 index 0000000000000..f38b7cd2988e5 --- /dev/null +++ b/packages/grafana-ui/src/components/List/AbstractList.test.tsx @@ -0,0 +1,42 @@ +import React from 'react'; +import { shallow } from 'enzyme'; +import { AbstractList } from './AbstractList'; + +describe('AbstractList', () => { + it('renders items using renderItem prop function', () => { + const items = [{ name: 'Item 1', id: 'item1' }, { name: 'Item 2', id: 'item2' }, { name: 'Item 3', id: 'item3' }]; + + const list = shallow( + ( +
+

{item.name}

+ {item.id} +
+ )} + /> + ); + + expect(list).toMatchSnapshot(); + }); + + it('allows custom item key', () => { + const items = [{ name: 'Item 1', id: 'item1' }, { name: 'Item 2', id: 'item2' }, { name: 'Item 3', id: 'item3' }]; + + const list = shallow( + item.id} + renderItem={item => ( +
+

{item.name}

+ {item.id} +
+ )} + /> + ); + + expect(list).toMatchSnapshot(); + }); +}); diff --git a/packages/grafana-ui/src/components/List/AbstractList.tsx b/packages/grafana-ui/src/components/List/AbstractList.tsx new file mode 100644 index 0000000000000..7c978753276a4 --- /dev/null +++ b/packages/grafana-ui/src/components/List/AbstractList.tsx @@ -0,0 +1,53 @@ +import React from 'react'; +import { cx, css } from 'emotion'; + +export interface ListProps { + items: T[]; + renderItem: (item: T, index: number) => JSX.Element; + getItemKey?: (item: T) => string; + className?: string; +} + +interface AbstractListProps extends ListProps { + inline?: boolean; +} + +export class AbstractList extends React.PureComponent> { + constructor(props: AbstractListProps) { + super(props); + this.getListStyles = this.getListStyles.bind(this); + } + + getListStyles() { + const { inline, className } = this.props; + return { + list: cx([ + css` + list-style-type: none; + margin: 0; + padding: 0; + `, + className, + ]), + item: css` + display: ${(inline && 'inline-block') || 'block'}; + `, + }; + } + + render() { + const { items, renderItem, getItemKey } = this.props; + const styles = this.getListStyles(); + return ( +
    + {items.map((item, i) => { + return ( +
  • + {renderItem(item, i)} +
  • + ); + })} +
+ ); + } +} diff --git a/packages/grafana-ui/src/components/List/InlineList.tsx b/packages/grafana-ui/src/components/List/InlineList.tsx new file mode 100644 index 0000000000000..aadfd84046f8a --- /dev/null +++ b/packages/grafana-ui/src/components/List/InlineList.tsx @@ -0,0 +1,8 @@ +import React from 'react'; +import { ListProps, AbstractList } from './AbstractList'; + +export class InlineList extends React.PureComponent> { + render() { + return ; + } +} diff --git a/packages/grafana-ui/src/components/List/List.story.tsx b/packages/grafana-ui/src/components/List/List.story.tsx new file mode 100644 index 0000000000000..3911039b5225e --- /dev/null +++ b/packages/grafana-ui/src/components/List/List.story.tsx @@ -0,0 +1,68 @@ +import React from 'react'; +import { storiesOf } from '@storybook/react'; +import { number, select } from '@storybook/addon-knobs'; +import { List } from './List'; +import { css, cx } from 'emotion'; +import tinycolor from 'tinycolor2'; +import { InlineList } from './InlineList'; + +const ListStories = storiesOf('UI/List', module); + +const generateListItems = (numberOfItems: number) => { + return [...new Array(numberOfItems)].map((item, i) => { + return { + name: `Item-${i}`, + id: `item-${i}`, + }; + }); +}; + +const getStoriesKnobs = (inline = false) => { + const numberOfItems = number('Number of items', 3); + const rawRenderer = (item: any) => <>{item.name}; + const customRenderer = (item: any, index: number) => ( +
+ {item.name} +
+ ); + + const itemRenderer = select( + 'Item rendered', + { + 'Raw renderer': 'raw', + 'Custom renderer': 'custom', + }, + 'raw' + ); + + return { + numberOfItems, + renderItem: itemRenderer === 'raw' ? rawRenderer : customRenderer, + }; +}; + +ListStories.add('default', () => { + const { numberOfItems, renderItem } = getStoriesKnobs(); + return ; +}); + +ListStories.add('inline', () => { + const { numberOfItems, renderItem } = getStoriesKnobs(true); + return ; +}); diff --git a/packages/grafana-ui/src/components/List/List.tsx b/packages/grafana-ui/src/components/List/List.tsx new file mode 100644 index 0000000000000..1fcc7d9ae0138 --- /dev/null +++ b/packages/grafana-ui/src/components/List/List.tsx @@ -0,0 +1,8 @@ +import React from 'react'; +import { ListProps, AbstractList } from './AbstractList'; + +export class List extends React.PureComponent> { + render() { + return ; + } +} diff --git a/packages/grafana-ui/src/components/List/__snapshots__/AbstractList.test.tsx.snap b/packages/grafana-ui/src/components/List/__snapshots__/AbstractList.test.tsx.snap new file mode 100644 index 0000000000000..b4c30ebce0683 --- /dev/null +++ b/packages/grafana-ui/src/components/List/__snapshots__/AbstractList.test.tsx.snap @@ -0,0 +1,93 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`AbstractList allows custom item key 1`] = ` +
    +
  • +
    +

    + Item 1 +

    + + item1 + +
    +
  • +
  • +
    +

    + Item 2 +

    + + item2 + +
    +
  • +
  • +
    +

    + Item 3 +

    + + item3 + +
    +
  • +
+`; + +exports[`AbstractList renders items using renderItem prop function 1`] = ` +
    +
  • +
    +

    + Item 1 +

    + + item1 + +
    +
  • +
  • +
    +

    + Item 2 +

    + + item2 + +
    +
  • +
  • +
    +

    + Item 3 +

    + + item3 + +
    +
  • +
+`; diff --git a/packages/grafana-ui/src/components/RefreshPicker/RefreshPicker.story.tsx b/packages/grafana-ui/src/components/RefreshPicker/RefreshPicker.story.tsx new file mode 100644 index 0000000000000..5400e87694fc2 --- /dev/null +++ b/packages/grafana-ui/src/components/RefreshPicker/RefreshPicker.story.tsx @@ -0,0 +1,32 @@ +import React from 'react'; +import { storiesOf } from '@storybook/react'; +import { action } from '@storybook/addon-actions'; +import { withCenteredStory } from '../../utils/storybook/withCenteredStory'; +import { UseState } from '../../utils/storybook/UseState'; +import { RefreshPicker } from './RefreshPicker'; + +const RefreshSelectStories = storiesOf('UI/RefreshPicker', module); + +RefreshSelectStories.addDecorator(withCenteredStory); + +RefreshSelectStories.add('default', () => { + return ( + + {(value, updateValue) => { + return ( + { + action('onIntervalChanged fired')(interval); + }} + onRefresh={() => { + action('onRefresh fired')(); + }} + /> + ); + }} + + ); +}); diff --git a/packages/grafana-ui/src/components/RefreshPicker/RefreshPicker.tsx b/packages/grafana-ui/src/components/RefreshPicker/RefreshPicker.tsx new file mode 100644 index 0000000000000..b53355e01783f --- /dev/null +++ b/packages/grafana-ui/src/components/RefreshPicker/RefreshPicker.tsx @@ -0,0 +1,81 @@ +import React, { PureComponent } from 'react'; +import classNames from 'classnames'; + +import { SelectOptionItem, ButtonSelect, Tooltip } from '@grafana/ui'; + +export const offOption = { label: 'Off', value: '' }; +export const defaultIntervals = ['5s', '10s', '30s', '1m', '5m', '15m', '30m', '1h', '2h', '1d']; + +export interface Props { + intervals?: string[]; + onRefresh: () => any; + onIntervalChanged: (interval: string) => void; + value?: string; + tooltip: string; +} + +export class RefreshPicker extends PureComponent { + static defaultProps = { + intervals: defaultIntervals, + }; + + constructor(props: Props) { + super(props); + } + + hasNoIntervals = () => { + const { intervals } = this.props; + // Current implementaion returns an array with length of 1 consisting of + // an empty string when auto-refresh is empty in dashboard settings + if (!intervals || intervals.length < 1 || (intervals.length === 1 && intervals[0] === '')) { + return true; + } + return false; + }; + + intervalsToOptions = (intervals: string[] = defaultIntervals): Array> => { + const options = intervals.map(interval => ({ label: interval, value: interval })); + options.unshift(offOption); + return options; + }; + + onChangeSelect = (item: SelectOptionItem) => { + const { onIntervalChanged } = this.props; + if (onIntervalChanged) { + // @ts-ignore + onIntervalChanged(item.value); + } + }; + + render() { + const { onRefresh, intervals, tooltip, value } = this.props; + const options = this.intervalsToOptions(this.hasNoIntervals() ? defaultIntervals : intervals); + const currentValue = value || ''; + const selectedValue = options.find(item => item.value === currentValue) || offOption; + + const cssClasses = classNames({ + 'refresh-picker': true, + 'refresh-picker--off': selectedValue.label === offOption.label, + }); + + return ( +
+
+ + + + +
+
+ ); + } +} diff --git a/packages/grafana-ui/src/components/RefreshPicker/_RefreshPicker.scss b/packages/grafana-ui/src/components/RefreshPicker/_RefreshPicker.scss new file mode 100644 index 0000000000000..bfa67d87582c9 --- /dev/null +++ b/packages/grafana-ui/src/components/RefreshPicker/_RefreshPicker.scss @@ -0,0 +1,36 @@ +.refresh-picker { + position: relative; + display: none; + + .refresh-picker-buttons { + display: flex; + } + + .navbar-button--refresh { + border-right: 0; + } + + .gf-form-input--form-dropdown { + position: static; + } + + .gf-form-select-box__menu { + position: absolute; + left: 0; + width: 100%; + } + + .select-button-value { + color: $orange; + } + + &--off { + .select-button-value { + display: none; + } + } + + @include media-breakpoint-up(sm) { + display: block; + } +} diff --git a/packages/grafana-ui/src/components/Select/ButtonSelect.story.tsx b/packages/grafana-ui/src/components/Select/ButtonSelect.story.tsx new file mode 100644 index 0000000000000..0e50be5b9427b --- /dev/null +++ b/packages/grafana-ui/src/components/Select/ButtonSelect.story.tsx @@ -0,0 +1,41 @@ +import React from 'react'; +import { storiesOf } from '@storybook/react'; +import { action } from '@storybook/addon-actions'; +import { withKnobs, object, text } from '@storybook/addon-knobs'; +import { withCenteredStory } from '../../utils/storybook/withCenteredStory'; +import { UseState } from '../../utils/storybook/UseState'; +import { SelectOptionItem } from './Select'; +import { ButtonSelect } from './ButtonSelect'; + +const ButtonSelectStories = storiesOf('UI/Select/ButtonSelect', module); + +ButtonSelectStories.addDecorator(withCenteredStory).addDecorator(withKnobs); + +ButtonSelectStories.add('default', () => { + const intialState: SelectOptionItem = { label: 'A label', value: 'A value' }; + const value = object>('Selected Value:', intialState); + const options = object>>('Options:', [ + intialState, + { label: 'Another label', value: 'Another value' }, + ]); + + return ( + + {(value, updateValue) => { + return ( + { + action('onChanged fired')(value); + updateValue(value); + }} + label={value.label ? value.label : ''} + className="refresh-select" + iconClass={text('iconClass', 'fa fa-clock-o fa-fw')} + /> + ); + }} + + ); +}); diff --git a/packages/grafana-ui/src/components/Select/ButtonSelect.tsx b/packages/grafana-ui/src/components/Select/ButtonSelect.tsx new file mode 100644 index 0000000000000..5b079d0195f6e --- /dev/null +++ b/packages/grafana-ui/src/components/Select/ButtonSelect.tsx @@ -0,0 +1,88 @@ +import React, { PureComponent } from 'react'; +import Select, { SelectOptionItem } from './Select'; +import { PopperContent } from '@grafana/ui/src/components/Tooltip/PopperController'; + +interface ButtonComponentProps { + label: string | undefined; + className: string | undefined; + iconClass?: string; +} + +const ButtonComponent = (buttonProps: ButtonComponentProps) => (props: any) => { + const { label, className, iconClass } = buttonProps; + + return ( + + ); +}; + +export interface Props { + className: string | undefined; + options: Array>; + value: SelectOptionItem; + label?: string; + iconClass?: string; + components?: any; + maxMenuHeight?: number; + onChange: (item: SelectOptionItem) => void; + tooltipContent?: PopperContent; + isMenuOpen?: boolean; + onOpenMenu?: () => void; + onCloseMenu?: () => void; +} + +export class ButtonSelect extends PureComponent> { + onChange = (item: SelectOptionItem) => { + const { onChange } = this.props; + onChange(item); + }; + + render() { + const { + className, + options, + value, + label, + iconClass, + components, + maxMenuHeight, + tooltipContent, + isMenuOpen, + onOpenMenu, + onCloseMenu, + } = this.props; + const combinedComponents = { + ...components, + Control: ButtonComponent({ label, className, iconClass }), + }; + return ( + { return ( -
- { - console.log('Data', data, text); - action('Data')(data, text); - }} - /> -
+ { + console.log('Data', data, text); + action('Data')(data, text); + }} + /> ); }); diff --git a/packages/grafana-ui/src/components/Table/TableInputCSV.test.tsx b/packages/grafana-ui/src/components/Table/TableInputCSV.test.tsx index 62d63a9df4508..7052c69fa4b2d 100644 --- a/packages/grafana-ui/src/components/Table/TableInputCSV.test.tsx +++ b/packages/grafana-ui/src/components/Table/TableInputCSV.test.tsx @@ -9,6 +9,8 @@ describe('TableInputCSV', () => { const tree = renderer .create( { // console.log('Table:', table, 'from:', text); diff --git a/packages/grafana-ui/src/components/Table/TableInputCSV.tsx b/packages/grafana-ui/src/components/Table/TableInputCSV.tsx index 15a834e29c55c..b45a8fba4c092 100644 --- a/packages/grafana-ui/src/components/Table/TableInputCSV.tsx +++ b/packages/grafana-ui/src/components/Table/TableInputCSV.tsx @@ -1,12 +1,13 @@ import React from 'react'; import debounce from 'lodash/debounce'; import { SeriesData } from '../../types/data'; -import { AutoSizer } from 'react-virtualized'; import { CSVConfig, readCSV } from '../../utils/csv'; interface Props { config?: CSVConfig; text: string; + width: string | number; + height: string | number; onSeriesParsed: (data: SeriesData[], text: string) => void; } @@ -58,28 +59,30 @@ export class TableInputCSV extends React.PureComponent { }; render() { + const { width, height } = this.props; const { data } = this.state; - return ( - - {({ height, width }) => ( -
- -
-
- -
-
+ diff --git a/public/app/features/dashboard/components/TimePicker/TimePickerCtrl.ts b/public/app/features/dashboard/components/TimePicker/TimePickerCtrl.ts index 0c388c27f8dba..5b973bfcebfeb 100644 --- a/public/app/features/dashboard/components/TimePicker/TimePickerCtrl.ts +++ b/public/app/features/dashboard/components/TimePicker/TimePickerCtrl.ts @@ -108,7 +108,7 @@ export class TimePickerCtrl { this.timeOptions = rangeUtil.getRelativeTimesList(this.panel, this.rangeString); this.refresh = { value: this.dashboard.refresh, - options: _.map(this.panel.refresh_intervals, (interval: any) => { + options: this.panel.refresh_intervals.map((interval: any) => { return { text: interval, value: interval }; }), }; diff --git a/public/app/features/dashboard/components/TimePicker/template.html b/public/app/features/dashboard/components/TimePicker/template.html index 481082a2cf6da..2821dd0ced537 100644 --- a/public/app/features/dashboard/components/TimePicker/template.html +++ b/public/app/features/dashboard/components/TimePicker/template.html @@ -1,27 +1,25 @@ - +
@@ -41,7 +39,7 @@
Custom range
-
+
@@ -75,11 +73,7 @@
- -
-
- -
+
diff --git a/public/app/features/dashboard/dashgrid/DashboardPanel.tsx b/public/app/features/dashboard/dashgrid/DashboardPanel.tsx index 8f03bef954be3..44ae626cc2050 100644 --- a/public/app/features/dashboard/dashgrid/DashboardPanel.tsx +++ b/public/app/features/dashboard/dashgrid/DashboardPanel.tsx @@ -17,8 +17,9 @@ import { PanelResizer } from './PanelResizer'; // Types import { PanelModel, DashboardModel } from '../state'; -import { PanelPlugin } from 'app/types'; -import { AngularPanelPlugin, ReactPanelPlugin } from '@grafana/ui/src/types/panel'; +import { PanelPluginMeta } from 'app/types'; +import { AngularPanelPlugin, PanelPlugin } from '@grafana/ui/src/types/panel'; +import { AutoSizer } from 'react-virtualized'; export interface Props { panel: PanelModel; @@ -28,7 +29,7 @@ export interface Props { } export interface State { - plugin: PanelPlugin; + plugin: PanelPluginMeta; angularPanel: AngularComponent; } @@ -36,7 +37,7 @@ export class DashboardPanel extends PureComponent { element: HTMLElement; specialPanels = {}; - constructor(props) { + constructor(props: Props) { super(props); this.state = { @@ -60,7 +61,7 @@ export class DashboardPanel extends PureComponent { return ; } - onPluginTypeChanged = (plugin: PanelPlugin) => { + onPluginTypeChanged = (plugin: PanelPluginMeta) => { this.loadPlugin(plugin.id); }; @@ -91,7 +92,7 @@ export class DashboardPanel extends PureComponent { } } - async importPanelPluginModule(plugin: PanelPlugin): Promise { + async importPanelPluginModule(plugin: PanelPluginMeta): Promise { if (plugin.hasBeenImported) { return plugin; } @@ -100,8 +101,8 @@ export class DashboardPanel extends PureComponent { const importedPlugin = await importPanelPlugin(plugin.module); if (importedPlugin instanceof AngularPanelPlugin) { plugin.angularPlugin = importedPlugin as AngularPanelPlugin; - } else if (importedPlugin instanceof ReactPanelPlugin) { - plugin.reactPlugin = importedPlugin as ReactPanelPlugin; + } else if (importedPlugin instanceof PanelPlugin) { + plugin.vizPlugin = importedPlugin as PanelPlugin; } } catch (e) { plugin = getPanelPluginNotFound(plugin.id); @@ -149,17 +150,27 @@ export class DashboardPanel extends PureComponent { }; renderReactPanel() { - const { dashboard, panel, isFullscreen, isEditing } = this.props; + const { dashboard, panel, isFullscreen } = this.props; const { plugin } = this.state; return ( - + + {({ width, height }) => { + if (width === 0) { + return null; + } + return ( + + ); + }} + ); } @@ -199,7 +210,7 @@ export class DashboardPanel extends PureComponent { onMouseLeave={this.onMouseLeave} style={styles} > - {plugin.reactPlugin && this.renderReactPanel()} + {plugin.vizPlugin && this.renderReactPanel()} {plugin.angularPlugin && this.renderAngularPanel()}
)} diff --git a/public/app/features/dashboard/dashgrid/DataPanel.test.tsx b/public/app/features/dashboard/dashgrid/DataPanel.test.tsx deleted file mode 100644 index 35000a957f619..0000000000000 --- a/public/app/features/dashboard/dashgrid/DataPanel.test.tsx +++ /dev/null @@ -1,60 +0,0 @@ -// Library -import React from 'react'; - -import { DataPanel, getProcessedSeriesData } from './DataPanel'; - -describe('DataPanel', () => { - let dataPanel: DataPanel; - - beforeEach(() => { - dataPanel = new DataPanel({ - queries: [], - panelId: 1, - widthPixels: 100, - refreshCounter: 1, - datasource: 'xxx', - children: r => { - return
hello
; - }, - onError: (message, error) => {}, - }); - }); - - it('starts with unloaded state', () => { - expect(dataPanel.state.isFirstLoad).toBe(true); - }); - - it('converts timeseries to table skipping nulls', () => { - const input1 = { - target: 'Field Name', - datapoints: [[100, 1], [200, 2]], - }; - const input2 = { - // without target - target: '', - datapoints: [[100, 1], [200, 2]], - }; - const data = getProcessedSeriesData([null, input1, input2, null, null]); - expect(data.length).toBe(2); - expect(data[0].fields[0].name).toBe(input1.target); - expect(data[0].rows).toBe(input1.datapoints); - - // Default name - expect(data[1].fields[0].name).toEqual('Value'); - - // Every colun should have a name and a type - for (const table of data) { - for (const column of table.fields) { - expect(column.name).toBeDefined(); - expect(column.type).toBeDefined(); - } - } - }); - - it('supports null values from query OK', () => { - expect(getProcessedSeriesData([null, null, null, null])).toEqual([]); - expect(getProcessedSeriesData(undefined)).toEqual([]); - expect(getProcessedSeriesData((null as unknown) as any[])).toEqual([]); - expect(getProcessedSeriesData([])).toEqual([]); - }); -}); diff --git a/public/app/features/dashboard/dashgrid/DataPanel.tsx b/public/app/features/dashboard/dashgrid/DataPanel.tsx deleted file mode 100644 index 62be96ed40caa..0000000000000 --- a/public/app/features/dashboard/dashgrid/DataPanel.tsx +++ /dev/null @@ -1,221 +0,0 @@ -// Library -import React, { Component } from 'react'; - -// Services -import { DatasourceSrv, getDatasourceSrv } from 'app/features/plugins/datasource_srv'; -// Utils -import kbn from 'app/core/utils/kbn'; -// Types -import { - DataQueryOptions, - DataQueryError, - LoadingState, - SeriesData, - TimeRange, - ScopedVars, - toSeriesData, - guessFieldTypes, -} from '@grafana/ui'; - -interface RenderProps { - loading: LoadingState; - data: SeriesData[]; -} - -export interface Props { - datasource: string | null; - queries: any[]; - panelId: number; - dashboardId?: number; - isVisible?: boolean; - timeRange?: TimeRange; - widthPixels: number; - refreshCounter: number; - minInterval?: string; - maxDataPoints?: number; - scopedVars?: ScopedVars; - children: (r: RenderProps) => JSX.Element; - onDataResponse?: (data?: SeriesData[]) => void; - onError: (message: string, error: DataQueryError) => void; -} - -export interface State { - isFirstLoad: boolean; - loading: LoadingState; - data?: SeriesData[]; -} - -/** - * All panels will be passed tables that have our best guess at colum type set - * - * This is also used by PanelChrome for snapshot support - */ -export function getProcessedSeriesData(results?: any[]): SeriesData[] { - if (!results) { - return []; - } - - const series: SeriesData[] = []; - for (const r of results) { - if (r) { - series.push(guessFieldTypes(toSeriesData(r))); - } - } - return series; -} - -export class DataPanel extends Component { - static defaultProps = { - isVisible: true, - dashboardId: 1, - }; - - dataSourceSrv: DatasourceSrv = getDatasourceSrv(); - isUnmounted = false; - - constructor(props: Props) { - super(props); - - this.state = { - loading: LoadingState.NotStarted, - isFirstLoad: true, - }; - } - - componentDidMount() { - this.issueQueries(); - } - - componentWillUnmount() { - this.isUnmounted = true; - } - - async componentDidUpdate(prevProps: Props) { - if (!this.hasPropsChanged(prevProps)) { - return; - } - - this.issueQueries(); - } - - hasPropsChanged(prevProps: Props) { - return this.props.refreshCounter !== prevProps.refreshCounter; - } - - private issueQueries = async () => { - const { - isVisible, - queries, - datasource, - panelId, - dashboardId, - timeRange, - widthPixels, - maxDataPoints, - scopedVars, - onDataResponse, - onError, - } = this.props; - - if (!isVisible) { - return; - } - - if (!queries.length) { - this.setState({ loading: LoadingState.Done }); - return; - } - - this.setState({ loading: LoadingState.Loading }); - - try { - const ds = await this.dataSourceSrv.get(datasource, scopedVars); - - // TODO interpolate variables - const minInterval = this.props.minInterval || ds.interval; - const intervalRes = kbn.calculateInterval(timeRange, widthPixels, minInterval); - - const queryOptions: DataQueryOptions = { - timezone: 'browser', - panelId: panelId, - dashboardId: dashboardId, - range: timeRange, - rangeRaw: timeRange.raw, - interval: intervalRes.interval, - intervalMs: intervalRes.intervalMs, - targets: queries, - maxDataPoints: maxDataPoints || widthPixels, - scopedVars: scopedVars || {}, - cacheTimeout: null, - }; - - const resp = await ds.query(queryOptions); - - if (this.isUnmounted) { - return; - } - - // Make sure the data is SeriesData[] - const data = getProcessedSeriesData(resp.data); - if (onDataResponse) { - onDataResponse(data); - } - - this.setState({ - data, - loading: LoadingState.Done, - isFirstLoad: false, - }); - } catch (err) { - console.log('DataPanel error', err); - - let message = 'Query error'; - - if (err.message) { - message = err.message; - } else if (err.data && err.data.message) { - message = err.data.message; - } else if (err.data && err.data.error) { - message = err.data.error; - } else if (err.status) { - message = `Query error: ${err.status} ${err.statusText}`; - } - - onError(message, err); - this.setState({ isFirstLoad: false, loading: LoadingState.Error }); - } - }; - - render() { - const { queries } = this.props; - const { loading, isFirstLoad, data } = this.state; - - // do not render component until we have first data - if (isFirstLoad && (loading === LoadingState.Loading || loading === LoadingState.NotStarted)) { - return this.renderLoadingState(); - } - - if (!queries.length) { - return ( -
-

Add a query to get some data!

-
- ); - } - - return ( - <> - {loading === LoadingState.Loading && this.renderLoadingState()} - {this.props.children({ loading, data })} - - ); - } - - private renderLoadingState(): JSX.Element { - return ( -
- -
- ); - } -} diff --git a/public/app/features/dashboard/dashgrid/PanelChrome.test.tsx b/public/app/features/dashboard/dashgrid/PanelChrome.test.tsx index 52bbd494f9a05..32ce937b91e98 100644 --- a/public/app/features/dashboard/dashgrid/PanelChrome.test.tsx +++ b/public/app/features/dashboard/dashgrid/PanelChrome.test.tsx @@ -11,10 +11,8 @@ describe('PanelChrome', () => { bbb: { value: 'BBB', text: 'upperB' }, }, }, - dashboard: {}, - plugin: {}, isFullscreen: false, - }); + } as any); }); it('Should replace a panel variable', () => { diff --git a/public/app/features/dashboard/dashgrid/PanelChrome.tsx b/public/app/features/dashboard/dashgrid/PanelChrome.tsx index 0d1ccbbda7a21..148c559f6aac8 100644 --- a/public/app/features/dashboard/dashgrid/PanelChrome.tsx +++ b/public/app/features/dashboard/dashgrid/PanelChrome.tsx @@ -1,14 +1,12 @@ // Libraries import React, { PureComponent } from 'react'; -import { AutoSizer } from 'react-virtualized'; // Services import { getTimeSrv, TimeSrv } from '../services/TimeSrv'; // Components import { PanelHeader } from './PanelHeader/PanelHeader'; -import { DataPanel } from './DataPanel'; -import ErrorBoundary from '../../../core/components/ErrorBoundary/ErrorBoundary'; +import ErrorBoundary from 'app/core/components/ErrorBoundary/ErrorBoundary'; // Utils import { applyPanelTimeOverrides } from 'app/features/dashboard/utils/panel'; @@ -18,112 +16,182 @@ import config from 'app/core/config'; // Types import { DashboardModel, PanelModel } from '../state'; -import { PanelPlugin } from 'app/types'; -import { TimeRange, LoadingState, DataQueryError, SeriesData, toLegacyResponseData } from '@grafana/ui'; +import { PanelPluginMeta } from 'app/types'; +import { LoadingState, PanelData } from '@grafana/ui'; import { ScopedVars } from '@grafana/ui'; import templateSrv from 'app/features/templating/template_srv'; -import { getProcessedSeriesData } from './DataPanel'; +import { getProcessedSeriesData } from '../state/PanelQueryState'; +import { Unsubscribable } from 'rxjs'; const DEFAULT_PLUGIN_ERROR = 'Error in plugin'; export interface Props { panel: PanelModel; dashboard: DashboardModel; - plugin: PanelPlugin; + plugin: PanelPluginMeta; isFullscreen: boolean; - isEditing: boolean; + width: number; + height: number; } export interface State { - refreshCounter: number; + isFirstLoad: boolean; renderCounter: number; - timeInfo?: string; - timeRange?: TimeRange; errorMessage: string | null; + + // Current state of all events + data: PanelData; } export class PanelChrome extends PureComponent { timeSrv: TimeSrv = getTimeSrv(); + querySubscription: Unsubscribable; + delayedStateUpdate: Partial; - constructor(props) { + constructor(props: Props) { super(props); - this.state = { - refreshCounter: 0, + isFirstLoad: true, renderCounter: 0, errorMessage: null, + data: { + state: LoadingState.NotStarted, + series: [], + }, }; } componentDidMount() { - this.props.panel.events.on('refresh', this.onRefresh); - this.props.panel.events.on('render', this.onRender); - this.props.dashboard.panelInitialized(this.props.panel); + const { panel, dashboard } = this.props; + panel.events.on('refresh', this.onRefresh); + panel.events.on('render', this.onRender); + dashboard.panelInitialized(this.props.panel); + + // Move snapshot data into the query response + if (this.hasPanelSnapshot) { + this.setState({ + data: { + state: LoadingState.Done, + series: getProcessedSeriesData(panel.snapshotData), + }, + isFirstLoad: false, + }); + } else if (!this.wantsQueryExecution) { + this.setState({ isFirstLoad: false }); + } } componentWillUnmount() { this.props.panel.events.off('refresh', this.onRefresh); + if (this.querySubscription) { + this.querySubscription.unsubscribe(); + this.querySubscription = null; + } } + // Updates the response with information from the stream + // The next is outside a react synthetic event so setState is not batched + // So in this context we can only do a single call to setState + panelDataObserver = { + next: (data: PanelData) => { + let { errorMessage, isFirstLoad } = this.state; + + if (data.state === LoadingState.Error) { + const { error } = data; + if (error) { + if (this.state.errorMessage !== error.message) { + errorMessage = error.message; + } + } + } else { + errorMessage = null; + } + + if (data.state === LoadingState.Done) { + // If we are doing a snapshot save data in panel model + if (this.props.dashboard.snapshot) { + this.props.panel.snapshotData = data.series; + } + if (this.state.isFirstLoad) { + isFirstLoad = false; + } + } + + const stateUpdate = { isFirstLoad, errorMessage, data }; + + if (this.isVisible) { + this.setState(stateUpdate); + } else { + // if we are getting data while another panel is in fullscreen / edit mode + // we need to store the data but not update state yet + this.delayedStateUpdate = stateUpdate; + } + }, + }; + onRefresh = () => { console.log('onRefresh'); if (!this.isVisible) { return; } - const { panel } = this.props; + const { panel, width } = this.props; const timeData = applyPanelTimeOverrides(panel, this.timeSrv.timeRange()); - this.setState({ - refreshCounter: this.state.refreshCounter + 1, - timeRange: timeData.timeRange, - timeInfo: timeData.timeInfo, - }); - }; + // Issue Query + if (this.wantsQueryExecution) { + if (width < 0) { + console.log('Refresh skippted, no width yet... wait till we know'); + return; + } - onRender = () => { - this.setState({ - renderCounter: this.state.renderCounter + 1, - }); - }; + const queryRunner = panel.getQueryRunner(); - replaceVariables = (value: string, extraVars?: ScopedVars, format?: string) => { - let vars = this.props.panel.scopedVars; - if (extraVars) { - vars = vars ? { ...vars, ...extraVars } : extraVars; + if (!this.querySubscription) { + this.querySubscription = queryRunner.subscribe(this.panelDataObserver); + } + + queryRunner.run({ + datasource: panel.datasource, + queries: panel.targets, + panelId: panel.id, + dashboardId: this.props.dashboard.id, + timezone: this.props.dashboard.timezone, + timeRange: timeData.timeRange, + timeInfo: timeData.timeInfo, + widthPixels: width, + maxDataPoints: panel.maxDataPoints, + minInterval: panel.interval, + scopedVars: panel.scopedVars, + cacheTimeout: panel.cacheTimeout, + }); } - return templateSrv.replace(value, vars, format); }; - onDataResponse = (data?: SeriesData[]) => { - if (this.props.dashboard.isSnapshot()) { - this.props.panel.snapshotData = data; - } - // clear error state (if any) - this.clearErrorState(); + onRender = () => { + const stateUpdate = { renderCounter: this.state.renderCounter + 1 }; - if (this.props.isEditing) { - const events = this.props.panel.events; - if (!data) { - data = []; - } + // If we have received a data update while hidden copy over that state as well + if (this.delayedStateUpdate) { + Object.assign(stateUpdate, this.delayedStateUpdate); + this.delayedStateUpdate = null; + } - // Angular query editors expect TimeSeries|TableData - events.emit('data-received', data.map(v => toLegacyResponseData(v))); + this.setState(stateUpdate); + }; - // Notify react query editors - events.emit('series-data-received', data); - } + onOptionsChange = (options: any) => { + this.props.panel.updateOptions(options); }; - onDataError = (message: string, error: DataQueryError) => { - if (this.state.errorMessage !== message) { - this.setState({ errorMessage: message }); + replaceVariables = (value: string, extraVars?: ScopedVars, format?: string) => { + let vars = this.props.panel.scopedVars; + if (extraVars) { + vars = vars ? { ...vars, ...extraVars } : extraVars; } - // this event is used by old query editors - this.props.panel.events.emit('data-error', error); + return templateSrv.replace(value, vars, format); }; onPanelError = (message: string) => { @@ -132,12 +200,6 @@ export class PanelChrome extends PureComponent { } }; - clearErrorState() { - if (this.state.errorMessage) { - this.setState({ errorMessage: null }); - } - } - get isVisible() { return !this.props.dashboard.otherPanelInFullscreen(this.props.panel); } @@ -147,110 +209,83 @@ export class PanelChrome extends PureComponent { return panel.snapshotData && panel.snapshotData.length; } - get needsQueryExecution() { - return this.hasPanelSnapshot || this.props.plugin.dataFormats.length > 0; + get wantsQueryExecution() { + return this.props.plugin.dataFormats.length > 0 && !this.hasPanelSnapshot; } - get getDataForPanel() { - return this.hasPanelSnapshot ? getProcessedSeriesData(this.props.panel.snapshotData) : null; - } - - renderPanelPlugin(loading: LoadingState, data: SeriesData[], width: number, height: number): JSX.Element { + renderPanel(width: number, height: number): JSX.Element { const { panel, plugin } = this.props; - const { timeRange, renderCounter } = this.state; - const PanelComponent = plugin.reactPlugin.panel; + const { renderCounter, data, isFirstLoad } = this.state; + const PanelComponent = plugin.vizPlugin.panel; // This is only done to increase a counter that is used by backend // image rendering (phantomjs/headless chrome) to know when to capture image + const loading = data.state; if (loading === LoadingState.Done) { profiler.renderingCompleted(panel.id); } + // do not render component until we have first data + if (isFirstLoad && (loading === LoadingState.Loading || loading === LoadingState.NotStarted)) { + return this.renderLoadingState(); + } + return ( -
- -
+ <> + {loading === LoadingState.Loading && this.renderLoadingState()} +
+ +
+ ); } - renderPanelBody = (width: number, height: number): JSX.Element => { - const { panel } = this.props; - const { refreshCounter, timeRange } = this.state; - const { datasource, targets } = panel; + private renderLoadingState(): JSX.Element { return ( - <> - {this.needsQueryExecution ? ( - - {({ loading, data }) => { - return this.renderPanelPlugin(loading, data, width, height); - }} - - ) : ( - this.renderPanelPlugin(LoadingState.Done, this.getDataForPanel, width, height) - )} - +
+ +
); - }; + } render() { - const { dashboard, panel, isFullscreen } = this.props; - const { errorMessage, timeInfo } = this.state; + const { dashboard, panel, isFullscreen, width, height } = this.props; + const { errorMessage, data } = this.state; const { transparent } = panel; const containerClassNames = `panel-container panel-container--absolute ${transparent ? 'panel-transparent' : ''}`; return ( - - {({ width, height }) => { - if (width === 0) { - return null; - } - - return ( -
- - - {({ error, errorInfo }) => { - if (errorInfo) { - this.onPanelError(error.message || DEFAULT_PLUGIN_ERROR); - return null; - } - return this.renderPanelBody(width, height); - }} - -
- ); - }} -
+
+ + + {({ error, errorInfo }) => { + if (errorInfo) { + this.onPanelError(error.message || DEFAULT_PLUGIN_ERROR); + return null; + } + return this.renderPanel(width, height); + }} + +
); } } diff --git a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeader.tsx b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeader.tsx index a8a3560743f55..ed1bf82b27ad8 100644 --- a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeader.tsx +++ b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeader.tsx @@ -9,7 +9,7 @@ import templateSrv from 'app/features/templating/template_srv'; import { DashboardModel } from 'app/features/dashboard/state/DashboardModel'; import { PanelModel } from 'app/features/dashboard/state/PanelModel'; -import { ClickOutsideWrapper } from 'app/core/components/ClickOutsideWrapper/ClickOutsideWrapper'; +import { ClickOutsideWrapper } from '@grafana/ui'; export interface Props { panel: PanelModel; diff --git a/public/app/features/dashboard/dashgrid/PanelPluginNotFound.tsx b/public/app/features/dashboard/dashgrid/PanelPluginNotFound.tsx index f0c7eff1fa3ef..c8704f84ce900 100644 --- a/public/app/features/dashboard/dashgrid/PanelPluginNotFound.tsx +++ b/public/app/features/dashboard/dashgrid/PanelPluginNotFound.tsx @@ -6,8 +6,8 @@ import React, { PureComponent } from 'react'; import { AlertBox } from 'app/core/components/AlertBox/AlertBox'; // Types -import { PanelPlugin, AppNotificationSeverity } from 'app/types'; -import { PanelProps, ReactPanelPlugin } from '@grafana/ui'; +import { PanelPluginMeta, AppNotificationSeverity } from 'app/types'; +import { PanelProps, PanelPlugin, PluginType } from '@grafana/ui'; interface Props { pluginId: string; @@ -34,7 +34,7 @@ class PanelPluginNotFound extends PureComponent { } } -export function getPanelPluginNotFound(id: string): PanelPlugin { +export function getPanelPluginNotFound(id: string): PanelPluginMeta { const NotFound = class NotFound extends PureComponent { render() { return ; @@ -45,6 +45,7 @@ export function getPanelPluginNotFound(id: string): PanelPlugin { id: id, name: id, sort: 100, + type: PluginType.panel, module: '', baseUrl: '', dataFormats: [], @@ -62,7 +63,7 @@ export function getPanelPluginNotFound(id: string): PanelPlugin { updated: '', version: '', }, - reactPlugin: new ReactPanelPlugin(NotFound), + vizPlugin: new PanelPlugin(NotFound), angularPlugin: null, }; } diff --git a/public/app/features/dashboard/panel_editor/PanelEditor.tsx b/public/app/features/dashboard/panel_editor/PanelEditor.tsx index 1bc42a2fd88b9..bc49207e5cc4f 100644 --- a/public/app/features/dashboard/panel_editor/PanelEditor.tsx +++ b/public/app/features/dashboard/panel_editor/PanelEditor.tsx @@ -13,16 +13,16 @@ import { AngularComponent } from 'app/core/services/AngularLoader'; import { PanelModel } from '../state/PanelModel'; import { DashboardModel } from '../state/DashboardModel'; -import { PanelPlugin } from 'app/types/plugins'; +import { PanelPluginMeta } from 'app/types/plugins'; import { Tooltip } from '@grafana/ui'; interface PanelEditorProps { panel: PanelModel; dashboard: DashboardModel; - plugin: PanelPlugin; + plugin: PanelPluginMeta; angularPanel?: AngularComponent; - onTypeChanged: (newType: PanelPlugin) => void; + onTypeChanged: (newType: PanelPluginMeta) => void; } interface PanelEditorTab { diff --git a/public/app/features/dashboard/panel_editor/QueriesTab.tsx b/public/app/features/dashboard/panel_editor/QueriesTab.tsx index 0553a61287cf8..75f4ded618e47 100644 --- a/public/app/features/dashboard/panel_editor/QueriesTab.tsx +++ b/public/app/features/dashboard/panel_editor/QueriesTab.tsx @@ -12,14 +12,16 @@ import { QueryEditorRow } from './QueryEditorRow'; // Services import { getDatasourceSrv } from 'app/features/plugins/datasource_srv'; -import { BackendSrv, getBackendSrv } from 'app/core/services/backend_srv'; +import { getBackendSrv } from 'app/core/services/backend_srv'; import config from 'app/core/config'; // Types import { PanelModel } from '../state/PanelModel'; import { DashboardModel } from '../state/DashboardModel'; -import { DataQuery, DataSourceSelectItem } from '@grafana/ui/src/types'; +import { DataQuery, DataSourceSelectItem, PanelData, LoadingState } from '@grafana/ui/src/types'; import { PluginHelp } from 'app/core/components/PluginHelp/PluginHelp'; +import { PanelQueryRunnerFormat } from '../state/PanelQueryRunner'; +import { Unsubscribable } from 'rxjs'; interface Props { panel: PanelModel; @@ -33,11 +35,13 @@ interface State { isPickerOpen: boolean; isAddingMixed: boolean; scrollTop: number; + data: PanelData; } export class QueriesTab extends PureComponent { datasources: DataSourceSelectItem[] = getDatasourceSrv().getMetricSources(); - backendSrv: BackendSrv = getBackendSrv(); + backendSrv = getBackendSrv(); + querySubscription: Unsubscribable; state: State = { isLoadingHelp: false, @@ -46,6 +50,37 @@ export class QueriesTab extends PureComponent { isPickerOpen: false, isAddingMixed: false, scrollTop: 0, + data: { + state: LoadingState.NotStarted, + series: [], + }, + }; + + componentDidMount() { + const { panel } = this.props; + const queryRunner = panel.getQueryRunner(); + + this.querySubscription = queryRunner.subscribe(this.panelDataObserver, PanelQueryRunnerFormat.both); + } + + componentWillUnmount() { + if (this.querySubscription) { + this.querySubscription.unsubscribe(); + this.querySubscription = null; + } + } + + // Updates the response with information from the stream + panelDataObserver = { + next: (data: PanelData) => { + const { panel } = this.props; + if (data.state === LoadingState.Error) { + panel.events.emit('data-error', data.error); + } else if (data.state === LoadingState.Done) { + panel.events.emit('data-received', data.legacy); + } + this.setState({ data }); + }, }; findCurrentDataSource(): DataSourceSelectItem { @@ -122,6 +157,7 @@ export class QueriesTab extends PureComponent { const { panel } = this.props; const index = _.indexOf(panel.targets, query); + // @ts-ignore _.move(panel.targets, index, index + direction); this.forceUpdate(); @@ -152,6 +188,7 @@ export class QueriesTab extends PureComponent { current={null} autoFocus={true} onBlur={this.onMixedPickerBlur} + openMenuOnFocus={true} /> ); }; @@ -177,7 +214,7 @@ export class QueriesTab extends PureComponent { render() { const { panel, dashboard } = this.props; - const { currentDS, scrollTop } = this.state; + const { currentDS, scrollTop, data } = this.state; const queryInspector: EditorToolbarView = { title: 'Query Inspector', @@ -192,7 +229,7 @@ export class QueriesTab extends PureComponent { return ( { key={query.refId} panel={panel} dashboard={dashboard} + data={data} query={query} onChange={query => this.onQueryChange(query, index)} onRemoveQuery={this.onRemoveQuery} diff --git a/public/app/features/dashboard/panel_editor/QueryEditorRow.test.ts b/public/app/features/dashboard/panel_editor/QueryEditorRow.test.ts new file mode 100644 index 0000000000000..ccddec2657bd9 --- /dev/null +++ b/public/app/features/dashboard/panel_editor/QueryEditorRow.test.ts @@ -0,0 +1,45 @@ +import { PanelData, LoadingState, DataQueryRequest } from '@grafana/ui'; +import { filterPanelDataToQuery } from './QueryEditorRow'; + +function makePretendRequest(requestId: string, subRequests?: DataQueryRequest[]): DataQueryRequest { + return { + requestId, + // subRequests, + } as DataQueryRequest; +} + +describe('filterPanelDataToQuery', () => { + const data = { + state: LoadingState.Done, + series: [ + { refId: 'A', fields: [{ name: 'AAA' }], rows: [], meta: {} }, + { refId: 'B', fields: [{ name: 'B111' }], rows: [], meta: {} }, + { refId: 'B', fields: [{ name: 'B222' }], rows: [], meta: {} }, + { refId: 'B', fields: [{ name: 'B333' }], rows: [], meta: {} }, + { refId: 'C', fields: [{ name: 'CCCC' }], rows: [], meta: { requestId: 'sub3' } }, + ], + error: { + refId: 'B', + message: 'Error!!', + }, + request: makePretendRequest('111', [ + makePretendRequest('sub1'), + makePretendRequest('sub2'), + makePretendRequest('sub3'), + ]), + } as PanelData; + + it('should not have an error unless the refId matches', () => { + const panelData = filterPanelDataToQuery(data, 'A'); + expect(panelData.series.length).toBe(1); + expect(panelData.series[0].refId).toBe('A'); + expect(panelData.error).toBeUndefined(); + }); + + it('should match the error to the query', () => { + const panelData = filterPanelDataToQuery(data, 'B'); + expect(panelData.series.length).toBe(3); + expect(panelData.series[0].refId).toBe('B'); + expect(panelData.error!.refId).toBe('B'); + }); +}); diff --git a/public/app/features/dashboard/panel_editor/QueryEditorRow.tsx b/public/app/features/dashboard/panel_editor/QueryEditorRow.tsx index 83e32859cfc9e..8b5f6b964f248 100644 --- a/public/app/features/dashboard/panel_editor/QueryEditorRow.tsx +++ b/public/app/features/dashboard/panel_editor/QueryEditorRow.tsx @@ -11,11 +11,12 @@ import { getTimeSrv } from 'app/features/dashboard/services/TimeSrv'; // Types import { PanelModel } from '../state/PanelModel'; -import { DataQuery, DataSourceApi, TimeRange, DataQueryError, SeriesData } from '@grafana/ui'; +import { DataQuery, DataSourceApi, TimeRange, PanelData, LoadingState, DataQueryRequest } from '@grafana/ui'; import { DashboardModel } from '../state/DashboardModel'; interface Props { panel: PanelModel; + data: PanelData; query: DataQuery; dashboard: DashboardModel; onAddQuery: (query?: DataQuery) => void; @@ -31,8 +32,7 @@ interface State { datasource: DataSourceApi | null; isCollapsed: boolean; hasTextEditMode: boolean; - queryError: DataQueryError | null; - queryResponse: SeriesData[] | null; + queryResponse?: PanelData; } export class QueryEditorRow extends PureComponent { @@ -45,67 +45,19 @@ export class QueryEditorRow extends PureComponent { isCollapsed: false, loadedDataSourceValue: undefined, hasTextEditMode: false, - queryError: null, queryResponse: null, }; componentDidMount() { this.loadDatasource(); - this.props.panel.events.on('refresh', this.onPanelRefresh); - this.props.panel.events.on('data-error', this.onPanelDataError); - this.props.panel.events.on('data-received', this.onPanelDataReceived); - this.props.panel.events.on('series-data-received', this.onSeriesDataReceived); } componentWillUnmount() { - this.props.panel.events.off('refresh', this.onPanelRefresh); - this.props.panel.events.off('data-error', this.onPanelDataError); - this.props.panel.events.off('data-received', this.onPanelDataReceived); - this.props.panel.events.off('series-data-received', this.onSeriesDataReceived); - if (this.angularQueryEditor) { this.angularQueryEditor.destroy(); } } - onPanelDataError = (error: DataQueryError) => { - // Some query controllers listen to data error events and need a digest - if (this.angularQueryEditor) { - // for some reason this needs to be done in next tick - setTimeout(this.angularQueryEditor.digest); - return; - } - - // if error relates to this query store it in state and pass it on to query editor - if (error.refId === this.props.query.refId) { - this.setState({ queryError: error }); - } - }; - - // Only used by angular plugins - onPanelDataReceived = () => { - // Some query controllers listen to data error events and need a digest - if (this.angularQueryEditor) { - // for some reason this needs to be done in next tick - setTimeout(this.angularQueryEditor.digest); - } - }; - - // Only used by the React Query Editors - onSeriesDataReceived = (data: SeriesData[]) => { - if (!this.angularQueryEditor) { - // only pass series related to this query to query editor - const filterByRefId = data.filter(series => series.refId === this.props.query.refId); - this.setState({ queryResponse: filterByRefId, queryError: null }); - } - }; - - onPanelRefresh = () => { - if (this.angularScope) { - this.angularScope.range = getTimeSrv().timeRange(); - } - }; - getAngularQueryComponentScope(): AngularQueryComponentScope { const { panel, query, dashboard } = this.props; const { datasource } = this.state; @@ -134,8 +86,23 @@ export class QueryEditorRow extends PureComponent { }); } - componentDidUpdate() { + componentDidUpdate(prevProps: Props) { const { loadedDataSourceValue } = this.state; + const { data, query } = this.props; + + if (data !== prevProps.data) { + this.setState({ queryResponse: filterPanelDataToQuery(data, query.refId) }); + + if (this.angularScope) { + this.angularScope.range = getTimeSrv().timeRange(); + } + + if (this.angularQueryEditor) { + // Some query controllers listen to data error events and need a digest + // for some reason this needs to be done in next tick + setTimeout(this.angularQueryEditor.digest); + } + } // check if we need to load another datasource if (loadedDataSourceValue !== this.props.dataSourceValue) { @@ -173,8 +140,8 @@ export class QueryEditorRow extends PureComponent { }; renderPluginEditor() { - const { query, onChange } = this.props; - const { datasource, queryResponse, queryError } = this.state; + const { query, data, onChange } = this.props; + const { datasource, queryResponse } = this.state; if (datasource.components.QueryCtrl) { return
(this.element = element)} />; @@ -190,7 +157,7 @@ export class QueryEditorRow extends PureComponent { onChange={onChange} onRunQuery={this.onRunQuery} queryResponse={queryResponse} - queryError={queryError} + panelData={data} /> ); } @@ -225,10 +192,14 @@ export class QueryEditorRow extends PureComponent { }; renderCollapsedText(): string | null { + const { datasource } = this.state; + if (datasource.getQueryDisplayText) { + return datasource.getQueryDisplayText(this.props.query); + } + if (this.angularScope && this.angularScope.getCollapsedText) { return this.angularScope.getCollapsedText(); } - return null; } @@ -309,3 +280,33 @@ export interface AngularQueryComponentScope { getCollapsedText?: () => string; range: TimeRange; } + +/** + * Get a version of the PanelData limited to the query we are looking at + */ +export function filterPanelDataToQuery(data: PanelData, refId: string): PanelData | undefined { + const series = data.series.filter(series => series.refId === refId); + + // No matching series + if (!series.length) { + return undefined; + } + + // Don't pass the request if all requests are the same + const request: DataQueryRequest = undefined; + // TODO: look in sub-requets to match the info + + // Only say this is an error if the error links to the query + let state = LoadingState.Done; + const error = data.error && data.error.refId === refId ? data.error : undefined; + if (error) { + state = LoadingState.Error; + } + + return { + state, + series, + request, + error, + }; +} diff --git a/public/app/features/dashboard/panel_editor/QueryInspector.tsx b/public/app/features/dashboard/panel_editor/QueryInspector.tsx index 25c3c68e21e96..a72fbdb7e8ff0 100644 --- a/public/app/features/dashboard/panel_editor/QueryInspector.tsx +++ b/public/app/features/dashboard/panel_editor/QueryInspector.tsx @@ -39,14 +39,20 @@ export class QueryInspector extends PureComponent { componentDidMount() { const { panel } = this.props; - panel.events.on('refresh', this.onPanelRefresh); + appEvents.on('ds-request-response', this.onDataSourceResponse); + appEvents.on('ds-request-error', this.onRequestError); + + panel.events.on('refresh', this.onPanelRefresh); panel.refresh(); } componentWillUnmount() { const { panel } = this.props; + appEvents.off('ds-request-response', this.onDataSourceResponse); + appEvents.on('ds-request-error', this.onRequestError); + panel.events.off('refresh', this.onPanelRefresh); } @@ -73,6 +79,10 @@ export class QueryInspector extends PureComponent { })); }; + onRequestError = (err: any) => { + this.onDataSourceResponse(err); + }; + onDataSourceResponse = (response: any = {}) => { if (this.state.isMocking) { this.handleMocking(response); diff --git a/public/app/features/dashboard/panel_editor/VisualizationTab.tsx b/public/app/features/dashboard/panel_editor/VisualizationTab.tsx index b13a417fd738c..3247cf631a764 100644 --- a/public/app/features/dashboard/panel_editor/VisualizationTab.tsx +++ b/public/app/features/dashboard/panel_editor/VisualizationTab.tsx @@ -16,15 +16,16 @@ import { FadeIn } from 'app/core/components/Animations/FadeIn'; // Types import { PanelModel } from '../state'; import { DashboardModel } from '../state'; -import { PanelPlugin } from 'app/types/plugins'; +import { PanelPluginMeta } from 'app/types/plugins'; import { VizPickerSearch } from './VizPickerSearch'; +import PluginStateinfo from 'app/features/plugins/PluginStateInfo'; interface Props { panel: PanelModel; dashboard: DashboardModel; - plugin: PanelPlugin; + plugin: PanelPluginMeta; angularPanel?: AngularComponent; - onTypeChanged: (newType: PanelPlugin) => void; + onTypeChanged: (newType: PanelPluginMeta) => void; updateLocation: typeof updateLocation; urlOpenVizPicker: boolean; } @@ -53,7 +54,7 @@ export class VisualizationTab extends PureComponent { getReactPanelOptions = () => { const { panel, plugin } = this.props; - return panel.getOptions(plugin.reactPlugin.defaults); + return panel.getOptions(plugin.vizPlugin.defaults); }; renderPanelOptions() { @@ -63,8 +64,8 @@ export class VisualizationTab extends PureComponent { return
(this.element = element)} />; } - if (plugin.reactPlugin) { - const PanelEditor = plugin.reactPlugin.editor; + if (plugin.vizPlugin) { + const PanelEditor = plugin.vizPlugin.editor; if (PanelEditor) { return ; @@ -196,7 +197,7 @@ export class VisualizationTab extends PureComponent { } }; - onTypeChanged = (plugin: PanelPlugin) => { + onTypeChanged = (plugin: PanelPluginMeta) => { if (plugin.id === this.props.plugin.id) { this.setState({ isVizPickerOpen: false }); } else { @@ -238,6 +239,7 @@ export class VisualizationTab extends PureComponent { onClose={this.onCloseVizPicker} /> + {this.renderPanelOptions()} diff --git a/public/app/features/dashboard/panel_editor/VizPickerSearch.tsx b/public/app/features/dashboard/panel_editor/VizPickerSearch.tsx index ddf9485dab907..beb9a8508f969 100644 --- a/public/app/features/dashboard/panel_editor/VizPickerSearch.tsx +++ b/public/app/features/dashboard/panel_editor/VizPickerSearch.tsx @@ -2,10 +2,10 @@ import React, { PureComponent } from 'react'; import { FilterInput } from 'app/core/components/FilterInput/FilterInput'; -import { PanelPlugin } from 'app/types'; +import { PanelPluginMeta } from 'app/types'; interface Props { - plugin: PanelPlugin; + plugin: PanelPluginMeta; searchQuery: string; onChange: (query: string) => void; onClose: () => void; diff --git a/public/app/features/dashboard/panel_editor/VizTypePicker.tsx b/public/app/features/dashboard/panel_editor/VizTypePicker.tsx index efbfed65a99d4..71a02f9644eea 100644 --- a/public/app/features/dashboard/panel_editor/VizTypePicker.tsx +++ b/public/app/features/dashboard/panel_editor/VizTypePicker.tsx @@ -1,13 +1,13 @@ import React, { PureComponent } from 'react'; import config from 'app/core/config'; -import { PanelPlugin } from 'app/types/plugins'; +import { PanelPluginMeta } from 'app/types/plugins'; import VizTypePickerPlugin from './VizTypePickerPlugin'; import { EmptySearchResult } from '@grafana/ui'; export interface Props { - current: PanelPlugin; - onTypeChanged: (newType: PanelPlugin) => void; + current: PanelPluginMeta; + onTypeChanged: (newType: PanelPluginMeta) => void; searchQuery: string; onClose: () => void; } @@ -25,16 +25,16 @@ export class VizTypePicker extends PureComponent { return filteredPluginList.length - 1; } - get getPanelPlugins(): PanelPlugin[] { + get getPanelPlugins(): PanelPluginMeta[] { const allPanels = config.panels; return Object.keys(allPanels) .filter(key => allPanels[key]['hideFromList'] === false) .map(key => allPanels[key]) - .sort((a: PanelPlugin, b: PanelPlugin) => a.sort - b.sort); + .sort((a: PanelPluginMeta, b: PanelPluginMeta) => a.sort - b.sort); } - renderVizPlugin = (plugin: PanelPlugin, index: number) => { + renderVizPlugin = (plugin: PanelPluginMeta, index: number) => { const { onTypeChanged } = this.props; const isCurrent = plugin.id === this.props.current.id; @@ -48,7 +48,7 @@ export class VizTypePicker extends PureComponent { ); }; - getFilteredPluginList = (): PanelPlugin[] => { + getFilteredPluginList = (): PanelPluginMeta[] => { const { searchQuery } = this.props; const regex = new RegExp(searchQuery, 'i'); const pluginList = this.pluginList; diff --git a/public/app/features/dashboard/panel_editor/VizTypePickerPlugin.tsx b/public/app/features/dashboard/panel_editor/VizTypePickerPlugin.tsx index 430cf7c7ee398..a91917e918c67 100644 --- a/public/app/features/dashboard/panel_editor/VizTypePickerPlugin.tsx +++ b/public/app/features/dashboard/panel_editor/VizTypePickerPlugin.tsx @@ -1,10 +1,10 @@ import React from 'react'; import classNames from 'classnames'; -import { PanelPlugin } from 'app/types/plugins'; +import { PanelPluginMeta } from 'app/types/plugins'; interface Props { isCurrent: boolean; - plugin: PanelPlugin; + plugin: PanelPluginMeta; onClick: () => void; } diff --git a/public/app/features/dashboard/services/ChangeTracker.ts b/public/app/features/dashboard/services/ChangeTracker.ts index 77434525085a6..7fe365cd8e004 100644 --- a/public/app/features/dashboard/services/ChangeTracker.ts +++ b/public/app/features/dashboard/services/ChangeTracker.ts @@ -141,8 +141,8 @@ export class ChangeTracker { const current = this.cleanDashboardFromIgnoredChanges(this.current.getSaveModelClone()); const original = this.cleanDashboardFromIgnoredChanges(this.original); - const currentTimepicker = _.find(current.nav, { type: 'timepicker' }); - const originalTimepicker = _.find(original.nav, { type: 'timepicker' }); + const currentTimepicker: any = _.find(current.nav, { type: 'timepicker' }); + const originalTimepicker: any = _.find(original.nav, { type: 'timepicker' }); if (currentTimepicker && originalTimepicker) { currentTimepicker.now = originalTimepicker.now; diff --git a/public/app/features/dashboard/services/DashboardSrv.ts b/public/app/features/dashboard/services/DashboardSrv.ts index c82aed13e445c..66e6d1d0b70d5 100644 --- a/public/app/features/dashboard/services/DashboardSrv.ts +++ b/public/app/features/dashboard/services/DashboardSrv.ts @@ -3,6 +3,7 @@ import { appEvents } from 'app/core/app_events'; import locationUtil from 'app/core/utils/location_util'; import { DashboardModel } from '../state/DashboardModel'; import { removePanel } from '../utils/panel'; +import { DashboardMeta } from 'app/types'; export class DashboardSrv { dashboard: DashboardModel; @@ -12,9 +13,12 @@ export class DashboardSrv { appEvents.on('save-dashboard', this.saveDashboard.bind(this), $rootScope); appEvents.on('panel-change-view', this.onPanelChangeView); appEvents.on('remove-panel', this.onRemovePanel); + + // Export to react + setDashboardSrv(this); } - create(dashboard, meta) { + create(dashboard: any, meta: DashboardMeta) { return new DashboardModel(dashboard, meta); } @@ -223,3 +227,17 @@ export class DashboardSrv { } coreModule.service('dashboardSrv', DashboardSrv); + +// +// Code below is to export the service to react components +// + +let singletonInstance: DashboardSrv; + +export function setDashboardSrv(instance: DashboardSrv) { + singletonInstance = instance; +} + +export function getDashboardSrv(): DashboardSrv { + return singletonInstance; +} diff --git a/public/app/features/dashboard/services/TimeSrv.test.ts b/public/app/features/dashboard/services/TimeSrv.test.ts index e5b4c24078540..8bb93fc3aec5f 100644 --- a/public/app/features/dashboard/services/TimeSrv.test.ts +++ b/public/app/features/dashboard/services/TimeSrv.test.ts @@ -1,5 +1,6 @@ -import { TimeSrv } from './TimeSrv'; import moment from 'moment'; +import { TimeSrv } from './TimeSrv'; +import { ContextSrvStub } from 'test/specs/helpers'; describe('timeSrv', () => { const rootScope = { @@ -26,7 +27,7 @@ describe('timeSrv', () => { }; beforeEach(() => { - timeSrv = new TimeSrv(rootScope, jest.fn(), location, timer, { isGrafanaVisibile: jest.fn() }); + timeSrv = new TimeSrv(rootScope as any, jest.fn() as any, location as any, timer, new ContextSrvStub() as any); timeSrv.init(_dashboard); _dashboard.refresh = false; }); @@ -56,7 +57,7 @@ describe('timeSrv', () => { })), }; - timeSrv = new TimeSrv(rootScope, jest.fn(), location, timer, { isGrafanaVisibile: jest.fn() }); + timeSrv = new TimeSrv(rootScope as any, jest.fn() as any, location as any, timer, new ContextSrvStub() as any); timeSrv.init(_dashboard); const time = timeSrv.timeRange(); expect(time.raw.from).toBe('now-2d'); @@ -71,7 +72,7 @@ describe('timeSrv', () => { })), }; - timeSrv = new TimeSrv(rootScope, jest.fn(), location, timer, { isGrafanaVisibile: jest.fn() }); + timeSrv = new TimeSrv(rootScope as any, jest.fn() as any, location as any, timer, new ContextSrvStub() as any); timeSrv.init(_dashboard); const time = timeSrv.timeRange(); @@ -87,7 +88,7 @@ describe('timeSrv', () => { })), }; - timeSrv = new TimeSrv(rootScope, jest.fn(), location, timer, { isGrafanaVisibile: jest.fn() }); + timeSrv = new TimeSrv(rootScope as any, jest.fn() as any, location as any, timer, new ContextSrvStub() as any); // dashboard saved with refresh on _dashboard.refresh = true; @@ -104,7 +105,7 @@ describe('timeSrv', () => { })), }; - timeSrv = new TimeSrv(rootScope, jest.fn(), location, timer, { isGrafanaVisibile: jest.fn() }); + timeSrv = new TimeSrv(rootScope as any, jest.fn() as any, location as any, timer, new ContextSrvStub() as any); timeSrv.init(_dashboard); const time = timeSrv.timeRange(); @@ -120,7 +121,7 @@ describe('timeSrv', () => { })), }; - timeSrv = new TimeSrv(rootScope, jest.fn(), location, timer, { isGrafanaVisibile: jest.fn() }); + timeSrv = new TimeSrv(rootScope as any, jest.fn() as any, location as any, timer, new ContextSrvStub() as any); timeSrv.init(_dashboard); const time = timeSrv.timeRange(); @@ -136,7 +137,7 @@ describe('timeSrv', () => { })), }; - timeSrv = new TimeSrv(rootScope, jest.fn(), location, timer, { isGrafanaVisibile: jest.fn() }); + timeSrv = new TimeSrv(rootScope as any, jest.fn() as any, location as any, timer, new ContextSrvStub() as any); _dashboard.time.from = 'now-6h'; timeSrv.init(_dashboard); diff --git a/public/app/features/dashboard/services/TimeSrv.ts b/public/app/features/dashboard/services/TimeSrv.ts index fb521d9b8490d..5fa0c63c35e71 100644 --- a/public/app/features/dashboard/services/TimeSrv.ts +++ b/public/app/features/dashboard/services/TimeSrv.ts @@ -8,19 +8,28 @@ import coreModule from 'app/core/core_module'; import * as dateMath from 'app/core/utils/datemath'; // Types -import { TimeRange } from '@grafana/ui'; +import { TimeRange, RawTimeRange } from '@grafana/ui'; +import { ITimeoutService, ILocationService } from 'angular'; +import { ContextSrv } from 'app/core/services/context_srv'; +import { DashboardModel } from '../state/DashboardModel'; export class TimeSrv { time: any; refreshTimer: any; - refresh: boolean; + refresh: any; oldRefresh: boolean; - dashboard: any; + dashboard: Partial; timeAtLoad: any; private autoRefreshBlocked: boolean; /** @ngInject */ - constructor($rootScope, private $timeout, private $location, private timer, private contextSrv) { + constructor( + $rootScope: any, + private $timeout: ITimeoutService, + private $location: ILocationService, + private timer: any, + private contextSrv: ContextSrv + ) { // default time this.time = { from: '6h', to: 'now' }; @@ -35,7 +44,7 @@ export class TimeSrv { }); } - init(dashboard) { + init(dashboard: Partial) { this.timer.cancelAll(); this.dashboard = dashboard; @@ -63,7 +72,7 @@ export class TimeSrv { } } - private parseUrlParam(value) { + private parseUrlParam(value: any) { if (value.indexOf('now') !== -1) { return value; } @@ -121,9 +130,10 @@ export class TimeSrv { return this.timeAtLoad && (this.timeAtLoad.from !== this.time.from || this.timeAtLoad.to !== this.time.to); } - setAutoRefresh(interval) { + setAutoRefresh(interval: any) { this.dashboard.refresh = interval; this.cancelNextRefresh(); + if (interval) { const intervalMs = kbn.interval_to_ms(interval); @@ -135,22 +145,24 @@ export class TimeSrv { ); } - // update url - const params = this.$location.search(); - if (interval) { - params.refresh = interval; - this.$location.search(params); - } else if (params.refresh) { - delete params.refresh; - this.$location.search(params); - } + // update url inside timeout to so that a digest happens after (called from react) + this.$timeout(() => { + const params = this.$location.search(); + if (interval) { + params.refresh = interval; + this.$location.search(params); + } else if (params.refresh) { + delete params.refresh; + this.$location.search(params); + } + }); } refreshDashboard() { this.dashboard.timeRangeUpdated(this.timeRange()); } - private startNextRefreshTimer(afterMs) { + private startNextRefreshTimer(afterMs: number) { this.cancelNextRefresh(); this.refreshTimer = this.timer.register( this.$timeout(() => { @@ -168,7 +180,7 @@ export class TimeSrv { this.timer.cancel(this.refreshTimer); } - setTime(time, fromRouteUpdate?) { + setTime(time: RawTimeRange, fromRouteUpdate?: boolean) { _.extend(this.time, time); // disable refresh if zoom in or zoom out @@ -221,7 +233,7 @@ export class TimeSrv { }; } - zoomOut(e, factor) { + zoomOut(e: any, factor: number) { const range = this.timeRange(); const timespan = range.to.valueOf() - range.from.valueOf(); @@ -234,7 +246,7 @@ export class TimeSrv { } } -let singleton; +let singleton: TimeSrv; export function setTimeSrv(srv: TimeSrv) { singleton = srv; diff --git a/public/app/features/dashboard/state/DashboardMigrator.ts b/public/app/features/dashboard/state/DashboardMigrator.ts index d7c63f834b17c..d6264fbf8fef3 100644 --- a/public/app/features/dashboard/state/DashboardMigrator.ts +++ b/public/app/features/dashboard/state/DashboardMigrator.ts @@ -109,7 +109,7 @@ export class DashboardMigrator { if (oldVersion < 6) { // move pulldowns to new schema - const annotations = _.find(old.pulldowns, { type: 'annotations' }); + const annotations: any = _.find(old.pulldowns, { type: 'annotations' }); if (annotations) { this.dashboard.annotations = { diff --git a/public/app/features/dashboard/state/DashboardModel.test.ts b/public/app/features/dashboard/state/DashboardModel.test.ts index 0d18a3b5d1225..fe6ae90631e59 100644 --- a/public/app/features/dashboard/state/DashboardModel.test.ts +++ b/public/app/features/dashboard/state/DashboardModel.test.ts @@ -6,7 +6,7 @@ jest.mock('app/core/services/context_srv', () => ({})); describe('DashboardModel', () => { describe('when creating new dashboard model defaults only', () => { - let model; + let model: DashboardModel; beforeEach(() => { model = new DashboardModel({}, {}); @@ -27,7 +27,7 @@ describe('DashboardModel', () => { }); describe('when getting next panel id', () => { - let model; + let model: DashboardModel; beforeEach(() => { model = new DashboardModel({ @@ -69,7 +69,7 @@ describe('DashboardModel', () => { }); describe('row and panel manipulation', () => { - let dashboard; + let dashboard: DashboardModel; beforeEach(() => { dashboard = new DashboardModel({}); @@ -112,7 +112,7 @@ describe('DashboardModel', () => { }); describe('Given editable false dashboard', () => { - let model; + let model: DashboardModel; beforeEach(() => { model = new DashboardModel({ editable: false }); @@ -130,8 +130,8 @@ describe('DashboardModel', () => { }); describe('when loading dashboard with old influxdb query schema', () => { - let model; - let target; + let model: DashboardModel; + let target: any; beforeEach(() => { model = new DashboardModel({ @@ -197,7 +197,7 @@ describe('DashboardModel', () => { }); describe('when creating dashboard model with missing list for annoations or templating', () => { - let model; + let model: DashboardModel; beforeEach(() => { model = new DashboardModel({ @@ -222,7 +222,7 @@ describe('DashboardModel', () => { }); describe('Formatting epoch timestamp when timezone is set as utc', () => { - let dashboard; + let dashboard: DashboardModel; beforeEach(() => { dashboard = new DashboardModel({ timezone: 'utc' }); @@ -242,7 +242,7 @@ describe('DashboardModel', () => { }); describe('updateSubmenuVisibility with empty lists', () => { - let model; + let model: DashboardModel; beforeEach(() => { model = new DashboardModel({}); @@ -255,7 +255,7 @@ describe('DashboardModel', () => { }); describe('updateSubmenuVisibility with annotation', () => { - let model; + let model: DashboardModel; beforeEach(() => { model = new DashboardModel({ @@ -272,7 +272,7 @@ describe('DashboardModel', () => { }); describe('updateSubmenuVisibility with template var', () => { - let model; + let model: DashboardModel; beforeEach(() => { model = new DashboardModel({ @@ -289,7 +289,7 @@ describe('DashboardModel', () => { }); describe('updateSubmenuVisibility with hidden template var', () => { - let model; + let model: DashboardModel; beforeEach(() => { model = new DashboardModel({ @@ -306,7 +306,7 @@ describe('DashboardModel', () => { }); describe('updateSubmenuVisibility with hidden annotation toggle', () => { - let dashboard; + let dashboard: DashboardModel; beforeEach(() => { dashboard = new DashboardModel({ @@ -323,7 +323,7 @@ describe('DashboardModel', () => { }); describe('When collapsing row', () => { - let dashboard; + let dashboard: DashboardModel; beforeEach(() => { dashboard = new DashboardModel({ @@ -365,7 +365,7 @@ describe('DashboardModel', () => { }); describe('When expanding row', () => { - let dashboard; + let dashboard: DashboardModel; beforeEach(() => { dashboard = new DashboardModel({ @@ -637,7 +637,7 @@ describe('DashboardModel', () => { }); describe('Given a dashboard with one panel legend on and two off', () => { - let model; + let model: DashboardModel; beforeEach(() => { const data = { diff --git a/public/app/features/dashboard/state/DashboardModel.ts b/public/app/features/dashboard/state/DashboardModel.ts index cde4227d3ec73..cfe4f5363376b 100644 --- a/public/app/features/dashboard/state/DashboardModel.ts +++ b/public/app/features/dashboard/state/DashboardModel.ts @@ -1,5 +1,5 @@ // Libaries -import moment from 'moment'; +import moment, { MomentInput } from 'moment'; import _ from 'lodash'; // Constants @@ -12,11 +12,17 @@ import { contextSrv } from 'app/core/services/context_srv'; import sortByKeys from 'app/core/utils/sort_by_keys'; // Types -import { PanelModel } from './PanelModel'; +import { PanelModel, GridPos } from './PanelModel'; import { DashboardMigrator } from './DashboardMigrator'; import { TimeRange } from '@grafana/ui/src'; import { UrlQueryValue, KIOSK_MODE_TV, DashboardMeta } from 'app/types'; +export interface CloneOptions { + saveVariables?: boolean; + saveTimerange?: boolean; + message?: string; +} + export class DashboardModel { id: any; uid: string; @@ -31,9 +37,9 @@ export class DashboardModel { time: any; private originalTime: any; timepicker: any; - templating: any; + templating: { list: any[] }; private originalTemplating: any; - annotations: any; + annotations: { list: any[] }; refresh: any; snapshot: any; schemaVersion: number; @@ -61,7 +67,7 @@ export class DashboardModel { originalTemplating: true, }; - constructor(data, meta?) { + constructor(data: any, meta?: DashboardMeta) { if (!data) { data = {}; } @@ -88,7 +94,7 @@ export class DashboardModel { this.version = data.version || 0; this.links = data.links || []; this.gnetId = data.gnetId || null; - this.panels = _.map(data.panels || [], panelData => new PanelModel(panelData)); + this.panels = _.map(data.panels || [], (panelData: any) => new PanelModel(panelData)); this.resetOriginalVariables(); this.resetOriginalTime(); @@ -124,7 +130,7 @@ export class DashboardModel { }); } - private initMeta(meta) { + private initMeta(meta: DashboardMeta) { meta = meta || {}; meta.canShare = meta.canShare !== false; @@ -146,7 +152,7 @@ export class DashboardModel { } // cleans meta data and other non persistent state - getSaveModelClone(options?) { + getSaveModelClone(options?: CloneOptions) { const defaults = _.defaults(options || {}, { saveVariables: true, saveTimerange: true, @@ -164,13 +170,15 @@ export class DashboardModel { // get variable save models copy.templating = { - list: _.map(this.templating.list, variable => (variable.getSaveModel ? variable.getSaveModel() : variable)), + list: _.map(this.templating.list, (variable: any) => + variable.getSaveModel ? variable.getSaveModel() : variable + ), }; if (!defaults.saveVariables) { for (let i = 0; i < copy.templating.list.length; i++) { const current = copy.templating.list[i]; - const original = _.find(this.originalTemplating, { name: current.name, type: current.type }); + const original: any = _.find(this.originalTemplating, { name: current.name, type: current.type }); if (!original) { continue; @@ -190,8 +198,8 @@ export class DashboardModel { // get panel save models copy.panels = _.chain(this.panels) - .filter(panel => panel.type !== 'add-panel') - .map(panel => panel.getSaveModel()) + .filter((panel: PanelModel) => panel.type !== 'add-panel') + .map((panel: PanelModel) => panel.getSaveModel()) .value(); // sort by keys @@ -243,7 +251,7 @@ export class DashboardModel { return this.meta.fullscreen && !panel.fullscreen; } - private ensureListExist(data) { + private ensureListExist(data: any) { if (!data) { data = {}; } @@ -273,13 +281,13 @@ export class DashboardModel { return max + 1; } - forEachPanel(callback) { + forEachPanel(callback: (panel: PanelModel, index: number) => void) { for (let i = 0; i < this.panels.length; i++) { callback(this.panels[i], i); } } - getPanelById(id): PanelModel { + getPanelById(id: number): PanelModel { for (const panel of this.panels) { if (panel.id === id) { return panel; @@ -288,7 +296,7 @@ export class DashboardModel { return null; } - addPanel(panelData) { + addPanel(panelData: any) { panelData.id = this.getNextPanelId(); const panel = new PanelModel(panelData); @@ -357,7 +365,7 @@ export class DashboardModel { this.events.emit('repeats-processed'); } - cleanUpRowRepeats(rowPanels) { + cleanUpRowRepeats(rowPanels: PanelModel[]) { const panelsToRemove = []; for (let i = 0; i < rowPanels.length; i++) { const panel = rowPanels[i]; @@ -376,7 +384,7 @@ export class DashboardModel { let rowPanels = row.panels; if (!row.collapsed) { - const rowPanelIndex = _.findIndex(this.panels, p => p.id === row.id); + const rowPanelIndex = _.findIndex(this.panels, (p: PanelModel) => p.id === row.id); rowPanels = this.getRowPanels(rowPanelIndex); } @@ -385,13 +393,13 @@ export class DashboardModel { for (let i = 0; i < rowPanels.length; i++) { const panel = rowPanels[i]; if (panel.repeat) { - const panelIndex = _.findIndex(this.panels, p => p.id === panel.id); + const panelIndex = _.findIndex(this.panels, (p: PanelModel) => p.id === panel.id); this.repeatPanel(panel, panelIndex); } } } - getPanelRepeatClone(sourcePanel, valueIndex, sourcePanelIndex) { + getPanelRepeatClone(sourcePanel: PanelModel, valueIndex: number, sourcePanelIndex: number) { // if first clone return source if (valueIndex === 0) { return sourcePanel; @@ -409,7 +417,7 @@ export class DashboardModel { return clone; } - getRowRepeatClone(sourceRowPanel, valueIndex, sourcePanelIndex) { + getRowRepeatClone(sourceRowPanel: PanelModel, valueIndex: number, sourcePanelIndex: number) { // if first clone return source if (valueIndex === 0) { if (!sourceRowPanel.collapsed) { @@ -421,7 +429,7 @@ export class DashboardModel { const clone = new PanelModel(sourceRowPanel.getSaveModel()); // for row clones we need to figure out panels under row to clone and where to insert clone - let rowPanels, insertPos; + let rowPanels: PanelModel[], insertPos: number; if (sourceRowPanel.collapsed) { rowPanels = _.cloneDeep(sourceRowPanel.panels); clone.panels = rowPanels; @@ -429,7 +437,7 @@ export class DashboardModel { insertPos = sourcePanelIndex + valueIndex; } else { rowPanels = this.getRowPanels(sourcePanelIndex); - clone.panels = _.map(rowPanels, panel => panel.getSaveModel()); + clone.panels = _.map(rowPanels, (panel: PanelModel) => panel.getSaveModel()); // insert copied row after preceding row's panels insertPos = sourcePanelIndex + (rowPanels.length + 1) * valueIndex; } @@ -440,7 +448,7 @@ export class DashboardModel { } repeatPanel(panel: PanelModel, panelIndex: number) { - const variable = _.find(this.templating.list, { name: panel.repeat }); + const variable: any = _.find(this.templating.list, { name: panel.repeat } as any); if (!variable) { return; } @@ -495,11 +503,11 @@ export class DashboardModel { } } - repeatRow(panel: PanelModel, panelIndex: number, variable) { + repeatRow(panel: PanelModel, panelIndex: number, variable: any) { const selectedOptions = this.getSelectedVariableOptions(variable); let yPos = panel.gridPos.y; - function setScopedVars(panel, variableOption) { + function setScopedVars(panel: PanelModel, variableOption: any) { panel.scopedVars = panel.scopedVars || {}; panel.scopedVars[variable.name] = variableOption; } @@ -515,7 +523,7 @@ export class DashboardModel { if (panel.collapsed) { // For collapsed row just copy its panels and set scoped vars and proper IDs - _.each(rowPanels, (rowPanel, i) => { + _.each(rowPanels, (rowPanel: PanelModel, i: number) => { setScopedVars(rowPanel, option); if (optionIndex > 0) { this.updateRepeatedPanelIds(rowPanel, true); @@ -527,7 +535,7 @@ export class DashboardModel { } else { // insert after 'row' panel const insertPos = panelIndex + (rowPanels.length + 1) * optionIndex + 1; - _.each(rowPanels, (rowPanel, i) => { + _.each(rowPanels, (rowPanel: PanelModel, i: number) => { setScopedVars(rowPanel, option); if (optionIndex > 0) { const cloneRowPanel = new PanelModel(rowPanel); @@ -562,8 +570,8 @@ export class DashboardModel { return panel; } - getSelectedVariableOptions(variable) { - let selectedOptions; + getSelectedVariableOptions(variable: any) { + let selectedOptions: any[]; if (variable.current.text === 'All') { selectedOptions = variable.options.slice(1, variable.options.length); } else { @@ -578,7 +586,7 @@ export class DashboardModel { } const rowYPos = rowPanel.gridPos.y; const positions = _.map(rowPanel.panels, 'gridPos'); - const maxPos = _.maxBy(positions, pos => { + const maxPos = _.maxBy(positions, (pos: GridPos) => { return pos.y + pos.h; }); return maxPos.y + maxPos.h - rowYPos; @@ -628,7 +636,7 @@ export class DashboardModel { } } - setPanelFocus(id) { + setPanelFocus(id: number) { this.meta.focusPanelId = id; } @@ -638,12 +646,12 @@ export class DashboardModel { return true; } - const visibleVars = _.filter(this.templating.list, variable => variable.hide !== 2); + const visibleVars = _.filter(this.templating.list, (variable: any) => variable.hide !== 2); if (visibleVars.length > 0) { return true; } - const visibleAnnotations = _.filter(this.annotations.list, annotation => annotation.hide !== true); + const visibleAnnotations = _.filter(this.annotations.list, (annotation: any) => annotation.hide !== true); if (visibleAnnotations.length > 0) { return true; } @@ -652,7 +660,7 @@ export class DashboardModel { })(); } - getPanelInfoById(panelId) { + getPanelInfoById(panelId: number) { for (let i = 0; i < this.panels.length; i++) { if (this.panels[i].id === panelId) { return { @@ -665,7 +673,7 @@ export class DashboardModel { return null; } - duplicatePanel(panel) { + duplicatePanel(panel: PanelModel) { const newPanel = panel.getSaveModel(); newPanel.id = this.getNextPanelId(); @@ -690,7 +698,7 @@ export class DashboardModel { return newPanel; } - formatDate(date, format?) { + formatDate(date: MomentInput, format?: string) { date = moment.isMoment(date) ? date : moment(date); format = format || 'YYYY-MM-DD HH:mm:ss'; const timezone = this.getTimezone(); @@ -710,7 +718,7 @@ export class DashboardModel { if (row.collapsed) { row.collapsed = false; - const hasRepeat = _.some(row.panels, p => p.repeat); + const hasRepeat = _.some(row.panels as PanelModel[], (p: PanelModel) => p.repeat); if (row.panels.length > 0) { // Use first panel to figure out if it was moved or pushed @@ -761,7 +769,7 @@ export class DashboardModel { // remove panels _.pull(this.panels, ...rowPanels); // save panel models inside row panel - row.panels = _.map(rowPanels, panel => panel.getSaveModel()); + row.panels = _.map(rowPanels, (panel: PanelModel) => panel.getSaveModel()); row.collapsed = true; // emit change event @@ -789,11 +797,11 @@ export class DashboardModel { return rowPanels; } - on(eventName, callback) { + on(eventName: string, callback: Function) { this.events.on(eventName, callback); } - off(eventName, callback?) { + off(eventName: string, callback?: Function) { this.events.off(eventName, callback); } @@ -809,7 +817,7 @@ export class DashboardModel { return this.graphTooltip === 1; } - getRelativeTime(date) { + getRelativeTime(date: MomentInput) { date = moment.isMoment(date) ? date : moment(date); return this.timezone === 'browser' ? moment(date).fromNow() : moment.utc(date).fromNow(); @@ -827,7 +835,7 @@ export class DashboardModel { return this.timezone ? this.timezone : contextSrv.user.timezone; } - private updateSchema(old) { + private updateSchema(old: any) { const migrator = new DashboardMigrator(this); migrator.updateSchema(old); } @@ -841,7 +849,7 @@ export class DashboardModel { } resetOriginalVariables() { - this.originalTemplating = _.map(this.templating.list, variable => { + this.originalTemplating = _.map(this.templating.list, (variable: any) => { return { name: variable.name, type: variable.type, @@ -856,7 +864,7 @@ export class DashboardModel { return false; } - const updated = _.map(this.templating.list, variable => { + const updated = _.map(this.templating.list, (variable: any) => { return { name: variable.name, type: variable.type, diff --git a/public/app/features/dashboard/state/PanelModel.test.ts b/public/app/features/dashboard/state/PanelModel.test.ts index 366c933d58d61..6cde516d1af6a 100644 --- a/public/app/features/dashboard/state/PanelModel.test.ts +++ b/public/app/features/dashboard/state/PanelModel.test.ts @@ -1,6 +1,6 @@ import { PanelModel } from './PanelModel'; import { getPanelPlugin } from '../../plugins/__mocks__/pluginMocks'; -import { ReactPanelPlugin, AngularPanelPlugin } from '@grafana/ui/src/types/panel'; +import { PanelPlugin, AngularPanelPlugin } from '@grafana/ui/src/types/panel'; class TablePanelCtrl {} @@ -123,13 +123,13 @@ describe('PanelModel', () => { describe('when changing to react panel', () => { const onPanelTypeChanged = jest.fn(); - const reactPlugin = new ReactPanelPlugin({} as any).setPanelChangeHandler(onPanelTypeChanged as any); + const reactPlugin = new PanelPlugin({} as any).setPanelChangeHandler(onPanelTypeChanged as any); beforeEach(() => { model.changePlugin( getPanelPlugin({ id: 'react', - reactPlugin: reactPlugin, + vizPlugin: reactPlugin, }) ); }); diff --git a/public/app/features/dashboard/state/PanelModel.ts b/public/app/features/dashboard/state/PanelModel.ts index f43ee5387799b..e79d8df00acce 100644 --- a/public/app/features/dashboard/state/PanelModel.ts +++ b/public/app/features/dashboard/state/PanelModel.ts @@ -7,9 +7,11 @@ import { getNextRefIdChar } from 'app/core/utils/query'; // Types import { DataQuery, Threshold, ScopedVars, DataQueryResponseData } from '@grafana/ui'; -import { PanelPlugin } from 'app/types'; +import { PanelPluginMeta } from 'app/types'; import config from 'app/core/config'; +import { PanelQueryRunner } from './PanelQueryRunner'; + export interface GridPos { x: number; y: number; @@ -25,6 +27,7 @@ const notPersistedProperties: { [str: string]: boolean } = { hasRefreshed: true, cachedPluginOptions: true, plugin: true, + queryRunner: true, }; // For angular panels we need to clean up properties when changing type @@ -114,7 +117,8 @@ export class PanelModel { cacheTimeout?: any; cachedPluginOptions?: any; legend?: { show: boolean }; - plugin?: PanelPlugin; + plugin?: PanelPluginMeta; + private queryRunner?: PanelQueryRunner; constructor(model: any) { this.events = new Emitter(); @@ -245,23 +249,23 @@ export class PanelModel { }); } - private getPluginVersion(plugin: PanelPlugin): string { + private getPluginVersion(plugin: PanelPluginMeta): string { return this.plugin && this.plugin.info.version ? this.plugin.info.version : config.buildInfo.version; } - pluginLoaded(plugin: PanelPlugin) { + pluginLoaded(plugin: PanelPluginMeta) { this.plugin = plugin; - if (plugin.reactPlugin && plugin.reactPlugin.onPanelMigration) { + if (plugin.vizPlugin && plugin.vizPlugin.onPanelMigration) { const version = this.getPluginVersion(plugin); if (version !== this.pluginVersion) { - this.options = plugin.reactPlugin.onPanelMigration(this); + this.options = plugin.vizPlugin.onPanelMigration(this); this.pluginVersion = version; } } } - changePlugin(newPlugin: PanelPlugin) { + changePlugin(newPlugin: PanelPluginMeta) { const pluginId = newPlugin.id; const oldOptions: any = this.getOptionsToRemember(); const oldPluginId = this.type; @@ -288,7 +292,7 @@ export class PanelModel { this.plugin = newPlugin; // Let panel plugins inspect options from previous panel and keep any that it can use - const reactPanel = newPlugin.reactPlugin; + const reactPanel = newPlugin.vizPlugin; if (reactPanel) { if (reactPanel.onPanelTypeChanged) { @@ -322,8 +326,19 @@ export class PanelModel { }); } + getQueryRunner(): PanelQueryRunner { + if (!this.queryRunner) { + this.queryRunner = new PanelQueryRunner(); + } + return this.queryRunner; + } + destroy() { this.events.emit('panel-teardown'); this.events.removeAllListeners(); + + if (this.queryRunner) { + this.queryRunner.destroy(); + } } } diff --git a/public/app/features/dashboard/state/PanelQueryRunner.test.ts b/public/app/features/dashboard/state/PanelQueryRunner.test.ts new file mode 100644 index 0000000000000..16cd2bc349bfe --- /dev/null +++ b/public/app/features/dashboard/state/PanelQueryRunner.test.ts @@ -0,0 +1,210 @@ +import { PanelQueryRunner } from './PanelQueryRunner'; +import { + PanelData, + DataQueryRequest, + DataStreamObserver, + DataStreamState, + LoadingState, + ScopedVars, +} from '@grafana/ui/src/types'; +import moment from 'moment'; + +jest.mock('app/core/services/backend_srv'); + +interface ScenarioContext { + setup: (fn: () => void) => void; + maxDataPoints?: number | null; + widthPixels: number; + dsInterval?: string; + minInterval?: string; + events?: PanelData[]; + res?: PanelData; + queryCalledWith?: DataQueryRequest; + observer: DataStreamObserver; + runner: PanelQueryRunner; + scopedVars: ScopedVars; +} + +type ScenarioFn = (ctx: ScenarioContext) => void; + +function describeQueryRunnerScenario(description: string, scenarioFn: ScenarioFn) { + describe(description, () => { + let setupFn = () => {}; + + const ctx: ScenarioContext = { + widthPixels: 200, + scopedVars: { + server: { text: 'Server1', value: 'server-1' }, + }, + runner: new PanelQueryRunner(), + observer: (args: any) => {}, + setup: (fn: () => void) => { + setupFn = fn; + }, + }; + + const response: any = { + data: [{ target: 'hello', datapoints: [] }], + }; + + beforeEach(async () => { + setupFn(); + + const datasource: any = { + name: 'TestDB', + interval: ctx.dsInterval, + query: (options: DataQueryRequest, observer: DataStreamObserver) => { + ctx.queryCalledWith = options; + ctx.observer = observer; + return Promise.resolve(response); + }, + testDatasource: jest.fn(), + }; + + const args: any = { + datasource, + scopedVars: ctx.scopedVars, + minInterval: ctx.minInterval, + widthPixels: ctx.widthPixels, + maxDataPoints: ctx.maxDataPoints, + timeRange: { + from: moment().subtract(1, 'days'), + to: moment(), + raw: { from: '1h', to: 'now' }, + }, + panelId: 0, + queries: [{ refId: 'A', test: 1 }], + }; + + ctx.runner = new PanelQueryRunner(); + ctx.runner.subscribe({ + next: (data: PanelData) => { + ctx.events.push(data); + }, + }); + + ctx.events = []; + ctx.res = await ctx.runner.run(args); + }); + + scenarioFn(ctx); + }); +} + +describe('PanelQueryRunner', () => { + describeQueryRunnerScenario('simple scenario', ctx => { + it('should set requestId on request', async () => { + expect(ctx.queryCalledWith.requestId).toBe('Q100'); + }); + + it('should set datasource name on request', async () => { + expect(ctx.queryCalledWith.targets[0].datasource).toBe('TestDB'); + }); + + it('should pass scopedVars to datasource with interval props', async () => { + expect(ctx.queryCalledWith.scopedVars.server.text).toBe('Server1'); + expect(ctx.queryCalledWith.scopedVars.__interval.text).toBe('5m'); + expect(ctx.queryCalledWith.scopedVars.__interval_ms.text).toBe('300000'); + }); + }); + + describeQueryRunnerScenario('with no maxDataPoints or minInterval', ctx => { + ctx.setup(() => { + ctx.maxDataPoints = null; + ctx.widthPixels = 200; + }); + + it('should return data', async () => { + expect(ctx.res.error).toBeUndefined(); + expect(ctx.res.series.length).toBe(1); + }); + + it('should use widthPixels as maxDataPoints', async () => { + expect(ctx.queryCalledWith.maxDataPoints).toBe(200); + }); + + it('should calculate interval based on width', async () => { + expect(ctx.queryCalledWith.interval).toBe('5m'); + }); + + it('fast query should only publish 1 data events', async () => { + expect(ctx.events.length).toBe(1); + }); + }); + + describeQueryRunnerScenario('with no panel min interval but datasource min interval', ctx => { + ctx.setup(() => { + ctx.widthPixels = 20000; + ctx.dsInterval = '15s'; + }); + + it('should limit interval to data source min interval', async () => { + expect(ctx.queryCalledWith.interval).toBe('15s'); + }); + }); + + describeQueryRunnerScenario('with panel min interval and data source min interval', ctx => { + ctx.setup(() => { + ctx.widthPixels = 20000; + ctx.dsInterval = '15s'; + ctx.minInterval = '30s'; + }); + + it('should limit interval to panel min interval', async () => { + expect(ctx.queryCalledWith.interval).toBe('30s'); + }); + }); + + describeQueryRunnerScenario('with maxDataPoints', ctx => { + ctx.setup(() => { + ctx.maxDataPoints = 10; + }); + + it('should pass maxDataPoints if specified', async () => { + expect(ctx.queryCalledWith.maxDataPoints).toBe(10); + }); + }); + + describeQueryRunnerScenario('when datasource is streaming data', ctx => { + let streamState: DataStreamState; + let isUnsubbed = false; + + beforeEach(() => { + streamState = { + state: LoadingState.Streaming, + key: 'test-stream-1', + series: [ + { + rows: [], + fields: [], + name: 'I am a magic stream', + }, + ], + request: { + requestId: ctx.queryCalledWith.requestId, + } as any, + unsubscribe: () => { + isUnsubbed = true; + }, + }; + ctx.observer(streamState); + }); + + it('should push another update to subscriber', async () => { + expect(ctx.events.length).toBe(2); + }); + + it('should set state to streaming', async () => { + expect(ctx.events[1].state).toBe(LoadingState.Streaming); + }); + + it('should not unsubscribe', async () => { + expect(isUnsubbed).toBe(false); + }); + + it('destroy should unsubscribe streams', async () => { + ctx.runner.destroy(); + expect(isUnsubbed).toBe(true); + }); + }); +}); diff --git a/public/app/features/dashboard/state/PanelQueryRunner.ts b/public/app/features/dashboard/state/PanelQueryRunner.ts new file mode 100644 index 0000000000000..04c4f9f7a746c --- /dev/null +++ b/public/app/features/dashboard/state/PanelQueryRunner.ts @@ -0,0 +1,218 @@ +// Libraries +import cloneDeep from 'lodash/cloneDeep'; +import throttle from 'lodash/throttle'; +import { Subject, Unsubscribable, PartialObserver } from 'rxjs'; + +// Services & Utils +import { getDatasourceSrv } from 'app/features/plugins/datasource_srv'; +import kbn from 'app/core/utils/kbn'; +import templateSrv from 'app/features/templating/template_srv'; +import { PanelQueryState } from './PanelQueryState'; + +// Types +import { PanelData, DataQuery, TimeRange, ScopedVars, DataQueryRequest, DataSourceApi } from '@grafana/ui'; + +export interface QueryRunnerOptions { + datasource: string | DataSourceApi; + queries: TQuery[]; + panelId: number; + dashboardId?: number; + timezone?: string; + timeRange: TimeRange; + timeInfo?: string; // String description of time range for display + widthPixels: number; + maxDataPoints: number | undefined | null; + minInterval: string | undefined | null; + scopedVars?: ScopedVars; + cacheTimeout?: string; + delayStateNotification?: number; // default 100ms. +} + +export enum PanelQueryRunnerFormat { + series = 'series', + legacy = 'legacy', + both = 'both', +} + +let counter = 100; +function getNextRequestId() { + return 'Q' + counter++; +} + +export class PanelQueryRunner { + private subject?: Subject; + + private state = new PanelQueryState(); + + constructor() { + this.state.onStreamingDataUpdated = this.onStreamingDataUpdated; + } + + /** + * Listen for updates to the PanelData. If a query has already run for this panel, + * the results will be immediatly passed to the observer + */ + subscribe(observer: PartialObserver, format = PanelQueryRunnerFormat.series): Unsubscribable { + if (!this.subject) { + this.subject = new Subject(); // Delay creating a subject until someone is listening + } + + if (format === PanelQueryRunnerFormat.legacy) { + this.state.sendLegacy = true; + } else if (format === PanelQueryRunnerFormat.both) { + this.state.sendSeries = true; + this.state.sendLegacy = true; + } else { + this.state.sendSeries = true; + } + + // Send the last result + if (this.state.isStarted()) { + observer.next(this.state.getDataAfterCheckingFormats()); + } + + return this.subject.subscribe(observer); + } + + async run(options: QueryRunnerOptions): Promise { + if (!this.subject) { + this.subject = new Subject(); + } + + const { state } = this; + + const { + queries, + timezone, + datasource, + panelId, + dashboardId, + timeRange, + timeInfo, + cacheTimeout, + widthPixels, + maxDataPoints, + scopedVars, + minInterval, + delayStateNotification, + } = options; + + // filter out hidden queries & deep clone them + const clonedAndFilteredQueries = cloneDeep(queries.filter(q => !q.hide)); + + const request: DataQueryRequest = { + requestId: getNextRequestId(), + timezone, + panelId, + dashboardId, + range: timeRange, + timeInfo, + interval: '', + intervalMs: 0, + targets: clonedAndFilteredQueries, + maxDataPoints: maxDataPoints || widthPixels, + scopedVars: scopedVars || {}, + cacheTimeout, + startTime: Date.now(), + }; + + // Add deprecated property + (request as any).rangeRaw = timeRange.raw; + + let loadingStateTimeoutId = 0; + + try { + const ds = await getDataSource(datasource, request.scopedVars); + + // Attach the datasource name to each query + request.targets = request.targets.map(query => { + if (!query.datasource) { + query.datasource = ds.name; + } + return query; + }); + + const lowerIntervalLimit = minInterval ? templateSrv.replace(minInterval, request.scopedVars) : ds.interval; + const norm = kbn.calculateInterval(timeRange, widthPixels, lowerIntervalLimit); + + // make shallow copy of scoped vars, + // and add built in variables interval and interval_ms + request.scopedVars = Object.assign({}, request.scopedVars, { + __interval: { text: norm.interval, value: norm.interval }, + __interval_ms: { text: norm.intervalMs.toString(), value: norm.intervalMs }, + }); + + request.interval = norm.interval; + request.intervalMs = norm.intervalMs; + + // Check if we can reuse the already issued query + const active = state.getActiveRunner(); + if (active) { + if (state.isSameQuery(ds, request)) { + // Maybe cancel if it has run too long? + console.log('Trying to execute query while last one has yet to complete, returning same promise'); + return active; + } else { + state.cancel('Query Changed while running'); + } + } + + // Send a loading status event on slower queries + loadingStateTimeoutId = window.setTimeout(() => { + if (state.getActiveRunner()) { + this.subject.next(this.state.validateStreamsAndGetPanelData()); + } + }, delayStateNotification || 500); + + const data = await state.execute(ds, request); + + // Clear the delayed loading state timeout + clearTimeout(loadingStateTimeoutId); + + // Broadcast results + this.subject.next(data); + return data; + } catch (err) { + clearTimeout(loadingStateTimeoutId); + + const data = state.setError(err); + this.subject.next(data); + return data; + } + } + + /** + * Called after every streaming event. This should be throttled so we + * avoid accidentally overwhelming the browser + */ + onStreamingDataUpdated = throttle( + () => { + this.subject.next(this.state.validateStreamsAndGetPanelData()); + }, + 50, + { trailing: true, leading: true } + ); + + /** + * Called when the panel is closed + */ + destroy() { + // Tell anyone listening that we are done + if (this.subject) { + this.subject.complete(); + } + + // Will cancel and disconnect any open requets + this.state.cancel('destroy'); + } +} + +async function getDataSource( + datasource: string | DataSourceApi | null, + scopedVars: ScopedVars +): Promise { + if (datasource && (datasource as any).query) { + return datasource as DataSourceApi; + } + return await getDatasourceSrv().get(datasource as string, scopedVars); +} diff --git a/public/app/features/dashboard/state/PanelQueryState.test.ts b/public/app/features/dashboard/state/PanelQueryState.test.ts new file mode 100644 index 0000000000000..486d6f29e03fc --- /dev/null +++ b/public/app/features/dashboard/state/PanelQueryState.test.ts @@ -0,0 +1,200 @@ +import { toDataQueryError, PanelQueryState, getProcessedSeriesData } from './PanelQueryState'; +import { MockDataSourceApi } from 'test/mocks/datasource_srv'; +import { DataQueryResponse, LoadingState } from '@grafana/ui'; +import { getQueryOptions } from 'test/helpers/getQueryOptions'; + +describe('PanelQueryState', () => { + it('converts anythign to an error', () => { + let err = toDataQueryError(undefined); + expect(err.message).toEqual('Query error'); + + err = toDataQueryError('STRING ERRROR'); + expect(err.message).toEqual('STRING ERRROR'); + + err = toDataQueryError({ message: 'hello' }); + expect(err.message).toEqual('hello'); + }); + + it('keeps track of running queries', async () => { + const state = new PanelQueryState(); + expect(state.getActiveRunner()).toBeFalsy(); + let hasRun = false; + const dsRunner = new Promise((resolve, reject) => { + // The status should be running when we get here + expect(state.getActiveRunner()).toBeTruthy(); + resolve({ data: ['x', 'y'] }); + hasRun = true; + }); + const ds = new MockDataSourceApi('test'); + ds.queryResolver = dsRunner; + + // should not actually run for an empty query + let empty = await state.execute(ds, getQueryOptions({})); + expect(state.getActiveRunner()).toBeFalsy(); + expect(empty.series.length).toBe(0); + expect(hasRun).toBeFalsy(); + + empty = await state.execute( + ds, + getQueryOptions({ targets: [{ hide: true, refId: 'X' }, { hide: true, refId: 'Y' }, { hide: true, refId: 'Z' }] }) + ); + // should not run any hidden queries' + expect(state.getActiveRunner()).toBeFalsy(); + expect(empty.series.length).toBe(0); + expect(hasRun).toBeFalsy(); + }); +}); + +describe('getProcessedSeriesData', () => { + it('converts timeseries to table skipping nulls', () => { + const input1 = { + target: 'Field Name', + datapoints: [[100, 1], [200, 2]], + }; + const input2 = { + // without target + target: '', + datapoints: [[100, 1], [200, 2]], + }; + const data = getProcessedSeriesData([null, input1, input2, null, null]); + expect(data.length).toBe(2); + expect(data[0].fields[0].name).toBe(input1.target); + expect(data[0].rows).toBe(input1.datapoints); + + // Default name + expect(data[1].fields[0].name).toEqual('Value'); + + // Every colun should have a name and a type + for (const table of data) { + for (const column of table.fields) { + expect(column.name).toBeDefined(); + expect(column.type).toBeDefined(); + } + } + }); + + it('supports null values from query OK', () => { + expect(getProcessedSeriesData([null, null, null, null])).toEqual([]); + expect(getProcessedSeriesData(undefined)).toEqual([]); + expect(getProcessedSeriesData((null as unknown) as any[])).toEqual([]); + expect(getProcessedSeriesData([])).toEqual([]); + }); +}); + +function makeSeriesStub(refId: string) { + return { + fields: [{ name: 'a' }], + rows: [], + refId, + }; +} + +describe('stream handling', () => { + const state = new PanelQueryState(); + state.onStreamingDataUpdated = () => { + // nothing + }; + state.request = { + requestId: '123', + range: { + raw: { + from: 123, // if string it gets revaluated + }, + }, + } as any; + state.response = { + state: LoadingState.Done, + series: [makeSeriesStub('A'), makeSeriesStub('B')], + }; + + it('gets the response', () => { + const data = state.validateStreamsAndGetPanelData(); + expect(data.series.length).toBe(2); + expect(data.state).toBe(LoadingState.Done); + expect(data.series[0].refId).toBe('A'); + }); + + it('adds a stream event', () => { + // Post a stream event + state.dataStreamObserver({ + state: LoadingState.Loading, + key: 'C', + request: state.request, // From the same request + series: [makeSeriesStub('C')], + unsubscribe: () => {}, + }); + expect(state.streams.length).toBe(1); + + const data = state.validateStreamsAndGetPanelData(); + expect(data.series.length).toBe(3); + expect(data.state).toBe(LoadingState.Streaming); + expect(data.series[2].refId).toBe('C'); + }); + + it('add another stream event (with a differnet key)', () => { + // Post a stream event + state.dataStreamObserver({ + state: LoadingState.Loading, + key: 'D', + request: state.request, // From the same request + series: [makeSeriesStub('D')], + unsubscribe: () => {}, + }); + expect(state.streams.length).toBe(2); + + const data = state.validateStreamsAndGetPanelData(); + expect(data.series.length).toBe(4); + expect(data.state).toBe(LoadingState.Streaming); + expect(data.series[3].refId).toBe('D'); + }); + + it('replace the first stream value, but keep the order', () => { + // Post a stream event + state.dataStreamObserver({ + state: LoadingState.Loading, + key: 'C', // The key to replace previous index 2 + request: state.request, // From the same request + series: [makeSeriesStub('X')], + unsubscribe: () => {}, + }); + expect(state.streams.length).toBe(2); + + const data = state.validateStreamsAndGetPanelData(); + expect(data.series[2].refId).toBe('X'); + }); + + it('ignores streams from a differnet request', () => { + // Post a stream event + state.dataStreamObserver({ + state: LoadingState.Loading, + key: 'Z', // Note with key 'A' it would still overwrite + request: { + ...state.request, + requestId: 'XXX', // Different request and id + } as any, + series: [makeSeriesStub('C')], + unsubscribe: () => {}, + }); + + expect(state.streams.length).toBe(2); // no change + const data = state.validateStreamsAndGetPanelData(); + expect(data.series.length).toBe(4); + }); + + it('removes streams when the query changes', () => { + state.request = { + ...state.request, + requestId: 'somethine else', + } as any; + state.response = { + state: LoadingState.Done, + series: [makeSeriesStub('F')], + }; + expect(state.streams.length).toBe(2); // unchanged + + const data = state.validateStreamsAndGetPanelData(); + expect(data.series.length).toBe(1); + expect(data.series[0].refId).toBe('F'); + expect(state.streams.length).toBe(0); // no streams + }); +}); diff --git a/public/app/features/dashboard/state/PanelQueryState.ts b/public/app/features/dashboard/state/PanelQueryState.ts new file mode 100644 index 0000000000000..69f9aeb71e2b2 --- /dev/null +++ b/public/app/features/dashboard/state/PanelQueryState.ts @@ -0,0 +1,360 @@ +// Libraries +import isString from 'lodash/isString'; +import isEqual from 'lodash/isEqual'; + +// Utils & Services +import { getBackendSrv } from 'app/core/services/backend_srv'; +import * as dateMath from 'app/core/utils/datemath'; +import { guessFieldTypes, toSeriesData, isSeriesData } from '@grafana/ui/src/utils'; + +// Types +import { + DataSourceApi, + DataQueryRequest, + PanelData, + LoadingState, + toLegacyResponseData, + DataQueryError, + DataStreamObserver, + DataStreamState, + SeriesData, + DataQueryResponseData, +} from '@grafana/ui'; + +export class PanelQueryState { + // The current/last running request + request = { + startTime: 0, + endTime: 1000, // Somethign not zero + } as DataQueryRequest; + + // The result back from the datasource query + response = { + state: LoadingState.NotStarted, + series: [], + } as PanelData; + + // Active stream results + streams: DataStreamState[] = []; + + sendSeries = false; + sendLegacy = false; + + // A promise for the running query + private executor?: Promise; + private rejector = (reason?: any) => {}; + private datasource: DataSourceApi = {} as any; + + isFinished(state: LoadingState) { + return state === LoadingState.Done || state === LoadingState.Error; + } + + isStarted() { + return this.response.state !== LoadingState.NotStarted; + } + + isSameQuery(ds: DataSourceApi, req: DataQueryRequest) { + if (ds !== this.datasource) { + return false; + } + + // For now just check that the targets look the same + return isEqual(this.request.targets, req.targets); + } + + /** + * Return the currently running query + */ + getActiveRunner(): Promise | undefined { + return this.executor; + } + + cancel(reason: string) { + const { request } = this; + this.executor = null; + + try { + // If no endTime the call to datasource.query did not complete + // call rejector to reject the executor promise + if (!request.endTime) { + request.endTime = Date.now(); + this.rejector('Canceled:' + reason); + } + + // Cancel any open HTTP request with the same ID + if (request.requestId) { + getBackendSrv().resolveCancelerIfExists(request.requestId); + } + } catch (err) { + console.log('Error canceling request', err); + } + + // Close any open streams + this.closeStreams(true); + } + + execute(ds: DataSourceApi, req: DataQueryRequest): Promise { + this.request = req; + + // Return early if there are no queries to run + if (!req.targets.length) { + console.log('No queries, so return early'); + this.request.endTime = Date.now(); + this.closeStreams(); + return Promise.resolve( + (this.response = { + state: LoadingState.Done, + series: [], // Clear the data + legacy: [], + }) + ); + } + + // Set the loading state immediatly + this.response.state = LoadingState.Loading; + this.executor = new Promise((resolve, reject) => { + this.rejector = reject; + + return ds + .query(this.request, this.dataStreamObserver) + .then(resp => { + this.request.endTime = Date.now(); + this.executor = null; + + // Make sure we send something back -- called run() w/o subscribe! + if (!(this.sendSeries || this.sendLegacy)) { + this.sendSeries = true; + } + + // Save the result state + this.response = { + state: LoadingState.Done, + request: this.request, + series: this.sendSeries ? getProcessedSeriesData(resp.data) : [], + legacy: this.sendLegacy ? translateToLegacyData(resp.data) : undefined, + }; + resolve(this.validateStreamsAndGetPanelData()); + }) + .catch(err => { + this.executor = null; + resolve(this.setError(err)); + }); + }); + + return this.executor; + } + + // Send a notice when the stream has updated the current model + onStreamingDataUpdated: () => void; + + // This gets all stream events and keeps track of them + // it will then delegate real changes to the PanelQueryRunner + dataStreamObserver: DataStreamObserver = (stream: DataStreamState) => { + // Streams only work with the 'series' format + this.sendSeries = true; + + // Add the stream to our list + let found = false; + const active = this.streams.map(s => { + if (s.key === stream.key) { + found = true; + return stream; + } + return s; + }); + + if (!found) { + if (shouldDisconnect(this.request, stream)) { + console.log('Got stream update from old stream, unsubscribing'); + stream.unsubscribe(); + return; + } + active.push(stream); + } + + this.streams = active; + this.onStreamingDataUpdated(); + }; + + closeStreams(keepSeries = false) { + if (!this.streams.length) { + return; + } + + const series: SeriesData[] = []; + + for (const stream of this.streams) { + if (stream.series) { + series.push.apply(series, stream.series); + } + + try { + stream.unsubscribe(); + } catch { + console.log('Failed to unsubscribe to stream'); + } + } + + this.streams = []; + + // Move the series from streams to the resposne + if (keepSeries) { + const { response } = this; + this.response = { + ...response, + series: [ + ...response.series, + ...series, // Append the streamed series + ], + }; + } + } + + /** + * This is called before broadcasting data to listeners. Given that + * stream events can happen at any point, we need to make sure to + * only return data from active streams. + */ + validateStreamsAndGetPanelData(): PanelData { + const { response, streams, request } = this; + + // When not streaming, return the response + request + if (!streams.length) { + return { + ...response, + request: request, + }; + } + + let done = this.isFinished(response.state); + const series = [...response.series]; + const active: DataStreamState[] = []; + + for (const stream of this.streams) { + if (shouldDisconnect(request, stream)) { + console.log('getPanelData() - shouldDisconnect true, unsubscribing to steam'); + stream.unsubscribe(); + continue; + } + + active.push(stream); + series.push.apply(series, stream.series); + + if (!this.isFinished(stream.state)) { + done = false; + } + } + + this.streams = active; + + // Update the time range + let timeRange = this.request.range; + if (isString(timeRange.raw.from)) { + timeRange = { + from: dateMath.parse(timeRange.raw.from, false), + to: dateMath.parse(timeRange.raw.to, true), + raw: timeRange.raw, + }; + } + + return { + state: done ? LoadingState.Done : LoadingState.Streaming, + series, // Union of series from response and all streams + legacy: this.sendLegacy ? translateToLegacyData(series) : undefined, + request: { + ...this.request, + range: timeRange, // update the time range + }, + }; + } + + /** + * Make sure all requested formats exist on the data + */ + getDataAfterCheckingFormats(): PanelData { + const { response, sendLegacy, sendSeries } = this; + if (sendLegacy && (!response.legacy || !response.legacy.length)) { + response.legacy = response.series.map(v => toLegacyResponseData(v)); + } + if (sendSeries && !response.series.length && response.legacy) { + response.series = response.legacy.map(v => toSeriesData(v)); + } + return this.validateStreamsAndGetPanelData(); + } + + setError(err: any): PanelData { + if (!this.request.endTime) { + this.request.endTime = Date.now(); + } + this.closeStreams(true); + this.response = { + ...this.response, // Keep any existing data + state: LoadingState.Error, + error: toDataQueryError(err), + }; + return this.validateStreamsAndGetPanelData(); + } +} + +export function shouldDisconnect(source: DataQueryRequest, state: DataStreamState) { + // It came from the same the same request, so keep it + if (source === state.request || state.request.requestId.startsWith(source.requestId)) { + return false; + } + + // We should be able to check that it is the same query regardless of + // if it came from the same request. This will be important for #16676 + + return true; +} + +export function toDataQueryError(err: any): DataQueryError { + const error = (err || {}) as DataQueryError; + if (!error.message) { + if (typeof err === 'string' || err instanceof String) { + return { message: err } as DataQueryError; + } + + let message = 'Query error'; + if (error.message) { + message = error.message; + } else if (error.data && error.data.message) { + message = error.data.message; + } else if (error.data && error.data.error) { + message = error.data.error; + } else if (error.status) { + message = `Query error: ${error.status} ${error.statusText}`; + } + error.message = message; + } + return error; +} + +function translateToLegacyData(data: DataQueryResponseData) { + return data.map(v => { + if (isSeriesData(v)) { + return toLegacyResponseData(v); + } + return v; + }); +} + +/** + * All panels will be passed tables that have our best guess at colum type set + * + * This is also used by PanelChrome for snapshot support + */ +export function getProcessedSeriesData(results?: any[]): SeriesData[] { + if (!results) { + return []; + } + + const series: SeriesData[] = []; + for (const r of results) { + if (r) { + series.push(guessFieldTypes(toSeriesData(r))); + } + } + + return series; +} diff --git a/public/app/features/dashboard/utils/getPanelMenu.ts b/public/app/features/dashboard/utils/getPanelMenu.ts index 568e9ba4f7fd5..a6e967b733f6e 100644 --- a/public/app/features/dashboard/utils/getPanelMenu.ts +++ b/public/app/features/dashboard/utils/getPanelMenu.ts @@ -57,7 +57,7 @@ export const getPanelMenu = (dashboard: DashboardModel, panel: PanelModel) => { menu.push({ text: 'View', - iconClassName: 'fa fa-fw fa-eye', + iconClassName: 'gicon gicon-viewer', onClick: onViewPanel, shortcut: 'v', }); @@ -65,7 +65,7 @@ export const getPanelMenu = (dashboard: DashboardModel, panel: PanelModel) => { if (dashboard.meta.canEdit) { menu.push({ text: 'Edit', - iconClassName: 'fa fa-fw fa-edit', + iconClassName: 'gicon gicon-editor', onClick: onEditPanel, shortcut: 'e', }); diff --git a/public/app/features/datasources/DashboardsTable.tsx b/public/app/features/datasources/DashboardsTable.tsx index 077dc1dba6337..6c6bad8c88e5b 100644 --- a/public/app/features/datasources/DashboardsTable.tsx +++ b/public/app/features/datasources/DashboardsTable.tsx @@ -19,7 +19,7 @@ const DashboardsTable: FC = ({ dashboards, onImport, onRemove }) => { return ( - + {dashboard.imported ? ( diff --git a/public/app/features/datasources/DataSourcesListItem.tsx b/public/app/features/datasources/DataSourcesListItem.tsx index d0ff69a66ee76..de3ac71f0b112 100644 --- a/public/app/features/datasources/DataSourcesListItem.tsx +++ b/public/app/features/datasources/DataSourcesListItem.tsx @@ -21,7 +21,7 @@ export class DataSourcesListItem extends PureComponent {
{dataSource.name} - {dataSource.isDefault && default} + {dataSource.isDefault && default}
{dataSource.url}
diff --git a/public/app/features/datasources/DataSourcesListPage.tsx b/public/app/features/datasources/DataSourcesListPage.tsx index 09442f5739c40..9f881446aeccc 100644 --- a/public/app/features/datasources/DataSourcesListPage.tsx +++ b/public/app/features/datasources/DataSourcesListPage.tsx @@ -39,7 +39,7 @@ export interface Props { const emptyListModel = { title: 'There are no data sources defined yet', - buttonIcon: 'gicon gicon-add-datasources', + buttonIcon: 'gicon gicon-datasources', buttonLink: 'datasources/new', buttonTitle: 'Add data source', proTip: 'You can also define data sources through configuration files.', diff --git a/public/app/features/datasources/__snapshots__/DashboardsTable.test.tsx.snap b/public/app/features/datasources/__snapshots__/DashboardsTable.test.tsx.snap index a85cbd4ad9ba9..cd327ba9fb2a9 100644 --- a/public/app/features/datasources/__snapshots__/DashboardsTable.test.tsx.snap +++ b/public/app/features/datasources/__snapshots__/DashboardsTable.test.tsx.snap @@ -20,7 +20,7 @@ exports[`Render should render table 1`] = ` className="width-1" > @@ -50,7 +50,7 @@ exports[`Render should render table 1`] = ` className="width-1" > diff --git a/public/app/features/datasources/partials/http_settings.html b/public/app/features/datasources/partials/http_settings.html index 755284bf7a8eb..3c078f4befee3 100644 --- a/public/app/features/datasources/partials/http_settings.html +++ b/public/app/features/datasources/partials/http_settings.html @@ -99,8 +99,14 @@
Basic Auth Details
- Password - +
diff --git a/public/app/features/datasources/settings/DataSourceSettingsPage.test.tsx b/public/app/features/datasources/settings/DataSourceSettingsPage.test.tsx index 204eeb8b1e90d..d4664418f0700 100644 --- a/public/app/features/datasources/settings/DataSourceSettingsPage.test.tsx +++ b/public/app/features/datasources/settings/DataSourceSettingsPage.test.tsx @@ -2,11 +2,13 @@ import React from 'react'; import { shallow } from 'enzyme'; import { DataSourceSettingsPage, Props } from './DataSourceSettingsPage'; import { NavModel } from 'app/types'; -import { DataSourceSettings } from '@grafana/ui'; +import { DataSourceSettings, DataSourcePlugin, DataSourceConstructor } from '@grafana/ui'; import { getMockDataSource } from '../__mocks__/dataSourcesMocks'; import { getMockPlugin } from '../../plugins/__mocks__/pluginMocks'; import { setDataSourceName, setIsDefault } from '../state/actions'; +const pluginMock = new DataSourcePlugin({} as DataSourceConstructor); + const setup = (propOverrides?: object) => { const props: Props = { navModel: {} as NavModel, @@ -18,10 +20,10 @@ const setup = (propOverrides?: object) => { setDataSourceName, updateDataSource: jest.fn(), setIsDefault, + plugin: pluginMock, + ...propOverrides, }; - Object.assign(props, propOverrides); - return shallow(); }; @@ -35,6 +37,7 @@ describe('Render', () => { it('should render loader', () => { const wrapper = setup({ dataSource: {} as DataSourceSettings, + plugin: pluginMock, }); expect(wrapper).toMatchSnapshot(); @@ -43,6 +46,7 @@ describe('Render', () => { it('should render beta info text', () => { const wrapper = setup({ dataSourceMeta: { ...getMockPlugin(), state: 'beta' }, + plugin: pluginMock, }); expect(wrapper).toMatchSnapshot(); @@ -51,6 +55,7 @@ describe('Render', () => { it('should render alpha info text', () => { const wrapper = setup({ dataSourceMeta: { ...getMockPlugin(), state: 'alpha' }, + plugin: pluginMock, }); expect(wrapper).toMatchSnapshot(); @@ -59,6 +64,7 @@ describe('Render', () => { it('should render is ready only message', () => { const wrapper = setup({ dataSource: { ...getMockDataSource(), readOnly: true }, + plugin: pluginMock, }); expect(wrapper).toMatchSnapshot(); diff --git a/public/app/features/datasources/settings/DataSourceSettingsPage.tsx b/public/app/features/datasources/settings/DataSourceSettingsPage.tsx index 27f60865c2176..489ccd4234b94 100644 --- a/public/app/features/datasources/settings/DataSourceSettingsPage.tsx +++ b/public/app/features/datasources/settings/DataSourceSettingsPage.tsx @@ -22,8 +22,10 @@ import { getRouteParamsId } from 'app/core/selectors/location'; // Types import { NavModel, Plugin, StoreState } from 'app/types/'; -import { DataSourceSettings } from '@grafana/ui/src/types/'; +import { DataSourceSettings, DataSourcePlugin } from '@grafana/ui/src/types/'; import { getDataSourceLoadingNav } from '../state/navModel'; +import PluginStateinfo from 'app/features/plugins/PluginStateInfo'; +import { importDataSourcePlugin } from 'app/features/plugins/plugin_loader'; export interface Props { navModel: NavModel; @@ -35,33 +37,46 @@ export interface Props { setDataSourceName: typeof setDataSourceName; updateDataSource: typeof updateDataSource; setIsDefault: typeof setIsDefault; + plugin?: DataSourcePlugin; } interface State { dataSource: DataSourceSettings; + plugin: DataSourcePlugin; isTesting?: boolean; testingMessage?: string; testingStatus?: string; } -enum DataSourceStates { - Alpha = 'alpha', - Beta = 'beta', -} - export class DataSourceSettingsPage extends PureComponent { constructor(props: Props) { super(props); this.state = { - dataSource: {} as DataSourceSettings, + dataSource: props.dataSource, + plugin: props.plugin, }; } + async loadPlugin(pluginId?: string) { + const { dataSourceMeta } = this.props; + let importedPlugin: DataSourcePlugin; + + try { + importedPlugin = await importDataSourcePlugin(dataSourceMeta.module); + } catch (e) { + console.log('Failed to import plugin module', e); + } + + this.setState({ plugin: importedPlugin }); + } + async componentDidMount() { const { loadDataSource, pageId } = this.props; - await loadDataSource(pageId); + if (!this.state.plugin) { + await this.loadPlugin(); + } } componentDidUpdate(prevProps: Props) { @@ -75,7 +90,7 @@ export class DataSourceSettingsPage extends PureComponent { onSubmit = async (evt: React.FormEvent) => { evt.preventDefault(); - await this.props.updateDataSource({ ...this.state.dataSource, name: this.props.dataSource.name }); + await this.props.updateDataSource({ ...this.state.dataSource }); this.testDataSource(); }; @@ -110,32 +125,6 @@ export class DataSourceSettingsPage extends PureComponent { return this.props.dataSource.readOnly === true; } - shouldRenderInfoBox() { - const { state } = this.props.dataSourceMeta; - - return state === DataSourceStates.Alpha || state === DataSourceStates.Beta; - } - - getInfoText() { - const { dataSourceMeta } = this.props; - - switch (dataSourceMeta.state) { - case DataSourceStates.Alpha: - return ( - 'This plugin is marked as being in alpha state, which means it is in early development phase and updates' + - ' will include breaking changes.' - ); - - case DataSourceStates.Beta: - return ( - 'This plugin is marked as being in a beta development state. This means it is in currently in active' + - ' development and could be missing important features.' - ); - } - - return null; - } - renderIsReadOnlyMessage() { return (
@@ -186,8 +175,8 @@ export class DataSourceSettingsPage extends PureComponent { } render() { - const { dataSource, dataSourceMeta, navModel, setDataSourceName, setIsDefault } = this.props; - const { testingMessage, testingStatus } = this.state; + const { dataSourceMeta, navModel, setDataSourceName, setIsDefault } = this.props; + const { testingMessage, testingStatus, plugin, dataSource } = this.state; return ( @@ -196,7 +185,7 @@ export class DataSourceSettingsPage extends PureComponent {
{this.isReadOnly() && this.renderIsReadOnlyMessage()} - {this.shouldRenderInfoBox() &&
{this.getInfoText()}
} + { onNameChange={name => setDataSourceName(name)} /> - {dataSourceMeta.module && ( + {dataSourceMeta.module && plugin && ( @@ -248,7 +238,6 @@ export class DataSourceSettingsPage extends PureComponent { function mapStateToProps(state: StoreState) { const pageId = getRouteParamsId(state.location); const dataSource = getDataSource(state.dataSources, pageId); - return { navModel: getNavModel(state.navIndex, `datasource-settings-${pageId}`, getDataSourceLoadingNav('settings')), dataSource: getDataSource(state.dataSources, pageId), diff --git a/public/app/features/datasources/settings/HttpSettingsCtrl.ts b/public/app/features/datasources/settings/HttpSettingsCtrl.ts index 5cdebe7b9abc4..5b23311805717 100644 --- a/public/app/features/datasources/settings/HttpSettingsCtrl.ts +++ b/public/app/features/datasources/settings/HttpSettingsCtrl.ts @@ -1,4 +1,5 @@ import { coreModule } from 'app/core/core'; +import { createChangeHandler, createResetHandler, PasswordFieldEnum } from '../utils/passwordHandlers'; coreModule.directive('datasourceHttpSettings', () => { return { @@ -20,6 +21,9 @@ coreModule.directive('datasourceHttpSettings', () => { $scope.getSuggestUrls = () => { return [$scope.suggestUrl]; }; + + $scope.onBasicAuthPasswordReset = createResetHandler($scope, PasswordFieldEnum.BasicAuthPassword); + $scope.onBasicAuthPasswordChange = createChangeHandler($scope, PasswordFieldEnum.BasicAuthPassword); }, }, }; diff --git a/public/app/features/datasources/settings/PluginSettings.tsx b/public/app/features/datasources/settings/PluginSettings.tsx index 8b65accd50a17..5761af8271087 100644 --- a/public/app/features/datasources/settings/PluginSettings.tsx +++ b/public/app/features/datasources/settings/PluginSettings.tsx @@ -1,10 +1,11 @@ import React, { PureComponent } from 'react'; import _ from 'lodash'; import { Plugin } from 'app/types'; -import { DataSourceSettings } from '@grafana/ui/src/types'; +import { DataSourceSettings, DataSourcePlugin } from '@grafana/ui/src/types'; import { getAngularLoader, AngularComponent } from 'app/core/services/AngularLoader'; export interface Props { + plugin: DataSourcePlugin; dataSource: DataSourceSettings; dataSourceMeta: Plugin; onModelChange: (dataSource: DataSourceSettings) => void; @@ -25,21 +26,29 @@ export class PluginSettings extends PureComponent { ctrl: { datasourceMeta: props.dataSourceMeta, current: _.cloneDeep(props.dataSource) }, onModelChanged: this.onModelChanged, }; + this.onModelChanged = this.onModelChanged.bind(this); } componentDidMount() { + const { plugin } = this.props; + if (!this.element) { return; } - const loader = getAngularLoader(); - const template = ''; + if (!plugin.components.ConfigEditor) { + // React editor is not specified, let's render angular editor + // How to apprach this better? Introduce ReactDataSourcePlugin interface and typeguard it here? + const loader = getAngularLoader(); + const template = ''; - this.component = loader.load(this.element, this.scopeProps, template); + this.component = loader.load(this.element, this.scopeProps, template); + } } componentDidUpdate(prevProps) { - if (this.props.dataSource !== prevProps.dataSource) { + const { plugin } = this.props; + if (!plugin.components.ConfigEditor && this.props.dataSource !== prevProps.dataSource) { this.scopeProps.ctrl.current = _.cloneDeep(this.props.dataSource); this.component.digest(); @@ -57,7 +66,21 @@ export class PluginSettings extends PureComponent { }; render() { - return
(this.element = element)} />; + const { plugin, dataSource } = this.props; + + if (!plugin) { + return null; + } + + return ( +
(this.element = element)}> + {plugin.components.ConfigEditor && + React.createElement(plugin.components.ConfigEditor, { + options: dataSource, + onOptionsChange: this.onModelChanged, + })} +
+ ); } } diff --git a/public/app/features/datasources/settings/__snapshots__/DataSourceSettingsPage.test.tsx.snap b/public/app/features/datasources/settings/__snapshots__/DataSourceSettingsPage.test.tsx.snap index 6855bf22b30d0..13495a99bf501 100644 --- a/public/app/features/datasources/settings/__snapshots__/DataSourceSettingsPage.test.tsx.snap +++ b/public/app/features/datasources/settings/__snapshots__/DataSourceSettingsPage.test.tsx.snap @@ -11,11 +11,9 @@ exports[`Render should render alpha info text 1`] = ` -
- This plugin is marked as being in alpha state, which means it is in early development phase and updates will include breaking changes. -
+
-
- This plugin is marked as being in a beta development state. This means it is in currently in active development and could be missing important features. -
+
+
This datasource was added by config and cannot be modified using the UI. Please contact your server admin to update this datasource.
+
('LOAD_DATA_SOURCE').create(); @@ -50,7 +51,7 @@ export function loadDataSources(): ThunkResult { export function loadDataSource(id: number): ThunkResult { return async dispatch => { const dataSource = await getBackendSrv().get(`/api/datasources/${id}`); - const pluginInfo = await getBackendSrv().get(`/api/plugins/${dataSource.type}/settings`); + const pluginInfo = await getPluginSettings(dataSource.type); dispatch(dataSourceLoaded(dataSource)); dispatch(dataSourceMetaLoaded(pluginInfo)); dispatch(updateNavIndex(buildNavModel(dataSource, pluginInfo))); diff --git a/public/app/features/datasources/state/navModel.ts b/public/app/features/datasources/state/navModel.ts index 6e215a46c6997..41f706eb97b5c 100644 --- a/public/app/features/datasources/state/navModel.ts +++ b/public/app/features/datasources/state/navModel.ts @@ -1,5 +1,5 @@ import { NavModel, NavModelItem } from 'app/types'; -import { PluginMeta, DataSourceSettings } from '@grafana/ui/src/types'; +import { PluginMeta, DataSourceSettings, PluginType } from '@grafana/ui/src/types'; import config from 'app/core/config'; export function buildNavModel(dataSource: DataSourceSettings, pluginMeta: PluginMeta): NavModelItem { @@ -67,6 +67,7 @@ export function getDataSourceLoadingNav(pageName: string): NavModel { }, { id: '1', + type: PluginType.datasource, name: '', info: { author: { @@ -83,7 +84,7 @@ export function getDataSourceLoadingNav(pageName: string): NavModel { updated: '', version: '', }, - includes: [{ type: '', name: '', path: '' }], + includes: [], module: '', baseUrl: '', } diff --git a/public/app/features/datasources/state/reducers.test.ts b/public/app/features/datasources/state/reducers.test.ts index 540089f3e6549..5c396efb43cb9 100644 --- a/public/app/features/datasources/state/reducers.test.ts +++ b/public/app/features/datasources/state/reducers.test.ts @@ -14,22 +14,22 @@ import { } from './actions'; import { getMockDataSources, getMockDataSource } from '../__mocks__/dataSourcesMocks'; import { LayoutModes } from 'app/core/components/LayoutSelector/LayoutSelector'; -import { DataSourcesState } from 'app/types'; -import { PluginMetaInfo } from '@grafana/ui'; - -const mockPlugin = () => ({ - defaultNavUrl: 'defaultNavUrl', - enabled: true, - hasUpdate: true, - id: 'id', - info: {} as PluginMetaInfo, - latestVersion: 'latestVersion', - name: 'name', - pinned: true, - state: 'state', - type: 'type', - module: {}, -}); +import { DataSourcesState, Plugin } from 'app/types'; +import { PluginMetaInfo, PluginType } from '@grafana/ui'; + +const mockPlugin = () => + ({ + defaultNavUrl: 'defaultNavUrl', + enabled: true, + hasUpdate: true, + id: 'id', + info: {} as PluginMetaInfo, + latestVersion: 'latestVersion', + name: 'name', + pinned: true, + type: PluginType.datasource, + module: 'path/to/module', + } as Plugin); describe('dataSourcesReducer', () => { describe('when dataSourcesLoaded is dispatched', () => { diff --git a/public/app/features/datasources/utils/passwordHandlers.test.ts b/public/app/features/datasources/utils/passwordHandlers.test.ts new file mode 100644 index 0000000000000..f1bf86f34eb4c --- /dev/null +++ b/public/app/features/datasources/utils/passwordHandlers.test.ts @@ -0,0 +1,35 @@ +import { createResetHandler, PasswordFieldEnum, Ctrl } from './passwordHandlers'; + +describe('createResetHandler', () => { + Object.keys(PasswordFieldEnum).forEach(fieldKey => { + const field: any = PasswordFieldEnum[fieldKey as any]; + + it(`should reset existing ${field} field`, () => { + const event: any = { + preventDefault: () => {}, + }; + const ctrl: Ctrl = { + current: { + [field]: 'set', + secureJsonData: { + [field]: 'set', + }, + secureJsonFields: {}, + }, + }; + + createResetHandler(ctrl, field)(event); + expect(ctrl).toEqual({ + current: { + [field]: null, + secureJsonData: { + [field]: '', + }, + secureJsonFields: { + [field]: false, + }, + }, + }); + }); + }); +}); diff --git a/public/app/features/datasources/utils/passwordHandlers.ts b/public/app/features/datasources/utils/passwordHandlers.ts new file mode 100644 index 0000000000000..25f9298fb3d1c --- /dev/null +++ b/public/app/features/datasources/utils/passwordHandlers.ts @@ -0,0 +1,45 @@ +/** + * Set of handlers for secure password field in Angular components. They handle backward compatibility with + * passwords stored in plain text fields. + */ + +import { SyntheticEvent } from 'react'; + +export enum PasswordFieldEnum { + Password = 'password', + BasicAuthPassword = 'basicAuthPassword', +} + +/** + * Basic shape for settings controllers in at the moment mostly angular datasource plugins. + */ +export type Ctrl = { + current: { + secureJsonFields: { + [key: string]: boolean; + }; + secureJsonData?: { + [key: string]: string; + }; + password?: string; + basicAuthPassword?: string; + }; +}; + +export const createResetHandler = (ctrl: Ctrl, field: PasswordFieldEnum) => ( + event: SyntheticEvent +) => { + event.preventDefault(); + // Reset also normal plain text password to remove it and only save it in secureJsonData. + ctrl.current[field] = null; + ctrl.current.secureJsonFields[field] = false; + ctrl.current.secureJsonData = ctrl.current.secureJsonData || {}; + ctrl.current.secureJsonData[field] = ''; +}; + +export const createChangeHandler = (ctrl: any, field: PasswordFieldEnum) => ( + event: SyntheticEvent +) => { + ctrl.current.secureJsonData = ctrl.current.secureJsonData || {}; + ctrl.current.secureJsonData[field] = event.currentTarget.value; +}; diff --git a/public/app/features/explore/Explore.tsx b/public/app/features/explore/Explore.tsx index 24d186cbbba68..45deefedccecc 100644 --- a/public/app/features/explore/Explore.tsx +++ b/public/app/features/explore/Explore.tsx @@ -3,7 +3,6 @@ import React, { ComponentClass } from 'react'; import { hot } from 'react-hot-loader'; // @ts-ignore import { connect } from 'react-redux'; -// @ts-ignore import _ from 'lodash'; import { AutoSizer } from 'react-virtualized'; @@ -118,7 +117,6 @@ export class Explore extends React.PureComponent { const initialQueries: DataQuery[] = ensureQueries(queries); const initialRange = { from: parseTime(range.from), to: parseTime(range.to) }; const width = this.el ? this.el.offsetWidth : 0; - // initialize the whole explore first time we mount and if browser history contains a change in datasource if (!initialized) { this.props.initializeExplore( diff --git a/public/app/features/explore/ExploreToolbar.tsx b/public/app/features/explore/ExploreToolbar.tsx index 36a6e696d4d07..0ee34958f4fe1 100644 --- a/public/app/features/explore/ExploreToolbar.tsx +++ b/public/app/features/explore/ExploreToolbar.tsx @@ -3,12 +3,19 @@ import { connect } from 'react-redux'; import { hot } from 'react-hot-loader'; import { ExploreId } from 'app/types/explore'; -import { DataSourceSelectItem, RawTimeRange, TimeRange } from '@grafana/ui'; +import { DataSourceSelectItem, RawTimeRange, TimeRange, ClickOutsideWrapper } from '@grafana/ui'; import { DataSourcePicker } from 'app/core/components/Select/DataSourcePicker'; import { StoreState } from 'app/types/store'; -import { changeDatasource, clearQueries, splitClose, runQueries, splitOpen } from './state/actions'; +import { + changeDatasource, + clearQueries, + splitClose, + runQueries, + splitOpen, + changeRefreshInterval, +} from './state/actions'; import TimePicker from './TimePicker'; -import { ClickOutsideWrapper } from 'app/core/components/ClickOutsideWrapper/ClickOutsideWrapper'; +import { RefreshPicker, SetInterval } from '@grafana/ui'; enum IconSide { left = 'left', @@ -31,9 +38,9 @@ const createResponsiveButton = (options: { return ( ); }; @@ -51,20 +58,22 @@ interface StateProps { range: RawTimeRange; selectedDatasource: DataSourceSelectItem; splitted: boolean; + refreshInterval: string; } interface DispatchProps { changeDatasource: typeof changeDatasource; clearAll: typeof clearQueries; - runQuery: typeof runQueries; + runQueries: typeof runQueries; closeSplit: typeof splitClose; split: typeof splitOpen; + changeRefreshInterval: typeof changeRefreshInterval; } type Props = StateProps & DispatchProps & OwnProps; export class UnConnectedExploreToolbar extends PureComponent { - constructor(props) { + constructor(props: Props) { super(props); } @@ -77,23 +86,32 @@ export class UnConnectedExploreToolbar extends PureComponent { }; onRunQuery = () => { - this.props.runQuery(this.props.exploreId); + return this.props.runQueries(this.props.exploreId); }; onCloseTimePicker = () => { this.props.timepickerRef.current.setState({ isOpen: false }); }; + onChangeRefreshInterval = (item: string) => { + const { changeRefreshInterval, exploreId } = this.props; + changeRefreshInterval(exploreId, item); + }; + render() { const { datasourceMissing, exploreDatasources, + closeSplit, exploreId, loading, range, selectedDatasource, splitted, timepickerRef, + refreshInterval, + onChangeTime, + split, } = this.props; return ( @@ -109,7 +127,7 @@ export class UnConnectedExploreToolbar extends PureComponent { )}
{splitted && ( - this.props.closeSplit(exploreId)}> + closeSplit(exploreId)}> )} @@ -133,7 +151,7 @@ export class UnConnectedExploreToolbar extends PureComponent { {createResponsiveButton({ splitted, title: 'Split', - onClick: this.props.split, + onClick: split, iconClassName: 'fa fa-fw fa-columns icon-margin-right', iconSide: IconSide.left, })} @@ -141,11 +159,20 @@ export class UnConnectedExploreToolbar extends PureComponent { ) : null}
- + + + + {refreshInterval && }
+
-
@@ -169,7 +196,14 @@ export class UnConnectedExploreToolbar extends PureComponent { const mapStateToProps = (state: StoreState, { exploreId }: OwnProps): StateProps => { const splitted = state.explore.split; const exploreItem = state.explore[exploreId]; - const { datasourceInstance, datasourceMissing, exploreDatasources, queryTransactions, range } = exploreItem; + const { + datasourceInstance, + datasourceMissing, + exploreDatasources, + queryTransactions, + range, + refreshInterval, + } = exploreItem; const selectedDatasource = datasourceInstance ? exploreDatasources.find(datasource => datasource.name === datasourceInstance.name) : undefined; @@ -182,13 +216,15 @@ const mapStateToProps = (state: StoreState, { exploreId }: OwnProps): StateProps range, selectedDatasource, splitted, + refreshInterval, }; }; const mapDispatchToProps: DispatchProps = { changeDatasource, + changeRefreshInterval, clearAll: clearQueries, - runQuery: runQueries, + runQueries, closeSplit: splitClose, split: splitOpen, }; diff --git a/public/app/features/explore/NoDataSourceCallToAction.tsx b/public/app/features/explore/NoDataSourceCallToAction.tsx index 12733c3265a1b..ba1d7a488e1d9 100644 --- a/public/app/features/explore/NoDataSourceCallToAction.tsx +++ b/public/app/features/explore/NoDataSourceCallToAction.tsx @@ -1,6 +1,6 @@ import React, { useContext } from 'react'; import { css } from 'emotion'; -import { ThemeContext, ExtraLargeLinkButton, CallToActionCard } from '@grafana/ui'; +import { ThemeContext, LargeLinkButton, CallToActionCard } from '@grafana/ui'; export const NoDataSourceCallToAction = () => { const theme = useContext(ThemeContext); @@ -22,9 +22,9 @@ export const NoDataSourceCallToAction = () => { ); const ctaElement = ( - + Add data source - + ); const cardClassName = css` diff --git a/public/app/features/explore/QueryField.tsx b/public/app/features/explore/QueryField.tsx index 333bc5778863f..58d860f54addc 100644 --- a/public/app/features/explore/QueryField.tsx +++ b/public/app/features/explore/QueryField.tsx @@ -1,4 +1,3 @@ -// @ts-ignore import _ from 'lodash'; import React, { Context } from 'react'; import ReactDOM from 'react-dom'; @@ -15,7 +14,7 @@ import { CompletionItem, CompletionItemGroup, TypeaheadOutput } from 'app/types/ import ClearPlugin from './slate-plugins/clear'; import NewlinePlugin from './slate-plugins/newline'; -import Typeahead from './Typeahead'; +import { TypeaheadWithTheme } from './Typeahead'; import { makeFragment, makeValue } from './Value'; import PlaceholdersBuffer from './PlaceholdersBuffer'; @@ -152,6 +151,9 @@ export class QueryField extends React.PureComponent { + const { onQueryChange } = this.props; + if (onQueryChange) { + onQueryChange(Plain.serialize(this.state.value)); + } + }; + executeOnQueryChangeAndExecuteQueries = () => { // Send text change to parent const { onQueryChange, onExecuteQuery } = this.props; @@ -359,7 +368,11 @@ export class QueryField extends React.PureComponent 0 + ? this.state.suggestions.reduce((totalCount, current) => totalCount + current.items.length, 0) + : 0; + this.setState({ typeaheadIndex: Math.min(itemsCount - 1, typeaheadIndex + 1) }); } break; } @@ -404,8 +417,6 @@ export class QueryField extends React.PureComponent {}; - onClickMenu = (item: CompletionItem) => { // Manually triggering change const change = this.applyTypeahead(this.state.value.change(), item); @@ -461,12 +472,13 @@ export class QueryField extends React.PureComponent - ); @@ -495,7 +507,6 @@ export class QueryField extends React.PureComponent - {group.map(option => ( + {group.map((option: any) => (
  • this.handleClickRelativeOption(option)}>{option.display}
  • diff --git a/public/app/features/explore/Typeahead.tsx b/public/app/features/explore/Typeahead.tsx index 6d6c60c055334..b28ab4a610d35 100644 --- a/public/app/features/explore/Typeahead.tsx +++ b/public/app/features/explore/Typeahead.tsx @@ -1,107 +1,131 @@ -import React from 'react'; -import Highlighter from 'react-highlight-words'; +import React, { createRef } from 'react'; +import _ from 'lodash'; +import { FixedSizeList } from 'react-window'; + +import { Themeable, withTheme } from '@grafana/ui'; import { CompletionItem, CompletionItemGroup } from 'app/types/explore'; +import { TypeaheadItem } from './TypeaheadItem'; +import { TypeaheadInfo } from './TypeaheadInfo'; +import { flattenGroupItems, calculateLongestLabel, calculateListSizes } from './utils/typeahead'; -function scrollIntoView(el: HTMLElement) { - if (!el || !el.offsetParent) { - return; - } - const container = el.offsetParent as HTMLElement; - if (el.offsetTop > container.scrollTop + container.offsetHeight || el.offsetTop < container.scrollTop) { - container.scrollTop = el.offsetTop - container.offsetTop; - } +interface Props extends Themeable { + groupedItems: CompletionItemGroup[]; + menuRef: any; + selectedItem: CompletionItem | null; + onClickItem: (suggestion: CompletionItem) => void; + prefix?: string; + typeaheadIndex: number; } -interface TypeaheadItemProps { - isSelected: boolean; - item: CompletionItem; - onClickItem: (Suggestion) => void; - prefix?: string; +interface State { + allItems: CompletionItem[]; + listWidth: number; + listHeight: number; + itemHeight: number; } -class TypeaheadItem extends React.PureComponent { - el: HTMLElement; +export class Typeahead extends React.PureComponent { + listRef: any = createRef(); + documentationRef: any = createRef(); - componentDidUpdate(prevProps) { - if (this.props.isSelected && !prevProps.isSelected) { - requestAnimationFrame(() => { - scrollIntoView(this.el); - }); - } + constructor(props: Props) { + super(props); + + const allItems = flattenGroupItems(props.groupedItems); + const longestLabel = calculateLongestLabel(allItems); + const { listWidth, listHeight, itemHeight } = calculateListSizes(props.theme, allItems, longestLabel); + this.state = { listWidth, listHeight, itemHeight, allItems }; } - getRef = el => { - this.el = el; + componentDidUpdate = (prevProps: Readonly) => { + if (prevProps.typeaheadIndex !== this.props.typeaheadIndex && this.listRef && this.listRef.current) { + if (prevProps.typeaheadIndex === 1 && this.props.typeaheadIndex === 0) { + this.listRef.current.scrollToItem(0); // special case for handling the first group label + this.refreshDocumentation(); + return; + } + const index = this.state.allItems.findIndex(item => item === this.props.selectedItem); + this.listRef.current.scrollToItem(index); + this.refreshDocumentation(); + } + + if (_.isEqual(prevProps.groupedItems, this.props.groupedItems) === false) { + const allItems = flattenGroupItems(this.props.groupedItems); + const longestLabel = calculateLongestLabel(allItems); + const { listWidth, listHeight, itemHeight } = calculateListSizes(this.props.theme, allItems, longestLabel); + this.setState({ listWidth, listHeight, itemHeight, allItems }, () => this.refreshDocumentation()); + } }; - onClick = () => { - this.props.onClickItem(this.props.item); + refreshDocumentation = () => { + if (!this.documentationRef.current) { + return; + } + + const index = this.state.allItems.findIndex(item => item === this.props.selectedItem); + const item = this.state.allItems[index]; + + if (item) { + this.documentationRef.current.refresh(item); + } }; - render() { - const { isSelected, item, prefix } = this.props; - const className = isSelected ? 'typeahead-item typeahead-item__selected' : 'typeahead-item'; - const label = item.label || ''; - return ( -
  • - - {item.documentation && isSelected ?
    {item.documentation}
    : null} -
  • - ); - } -} + onMouseEnter = (item: CompletionItem) => { + this.documentationRef.current.refresh(item); + }; -interface TypeaheadGroupProps { - items: CompletionItem[]; - label: string; - onClickItem: (suggestion: CompletionItem) => void; - selected: CompletionItem; - prefix?: string; -} + onMouseLeave = () => { + this.documentationRef.current.hide(); + }; -class TypeaheadGroup extends React.PureComponent { render() { - const { items, label, selected, onClickItem, prefix } = this.props; + const { menuRef, selectedItem, onClickItem, prefix, theme } = this.props; + const { listWidth, listHeight, itemHeight, allItems } = this.state; + return ( -
  • -
    {label}
    -
  • diff --git a/public/app/features/templating/template_srv.ts b/public/app/features/templating/template_srv.ts index e0d35295556b7..e7f21eb4ce74c 100644 --- a/public/app/features/templating/template_srv.ts +++ b/public/app/features/templating/template_srv.ts @@ -309,7 +309,7 @@ export class TemplateSrv { } distributeVariable(value, variable) { - value = _.map(value, (val, index) => { + value = _.map(value, (val: any, index: number) => { if (index !== 0) { return variable + '=' + val; } else { diff --git a/public/app/features/templating/variable_srv.ts b/public/app/features/templating/variable_srv.ts index f4d9572184693..b69ad3c3075ef 100644 --- a/public/app/features/templating/variable_srv.ts +++ b/public/app/features/templating/variable_srv.ts @@ -200,7 +200,7 @@ export class VariableSrv { return variable.setValue(selected); } else { - const currentOption = _.find(variable.options, { + const currentOption: any = _.find(variable.options, { text: variable.current.text, }); if (currentOption) { @@ -222,7 +222,7 @@ export class VariableSrv { } return promise.then(() => { - let option = _.find(variable.options, op => { + let option: any = _.find(variable.options, op => { return op.text === urlValue || op.value === urlValue; }); @@ -233,7 +233,7 @@ export class VariableSrv { defaultText = []; for (let n = 0; n < urlValue.length; n++) { - const t = _.find(variable.options, op => { + const t: any = _.find(variable.options, op => { return op.value === urlValue[n]; }); @@ -279,10 +279,10 @@ export class VariableSrv { } setAdhocFilter(options) { - let variable = _.find(this.variables, { + let variable: any = _.find(this.variables, { type: 'adhoc', datasource: options.datasource, - }); + } as any); if (!variable) { variable = this.createVariableFromModel({ name: 'Filters', @@ -293,7 +293,7 @@ export class VariableSrv { } const filters = variable.filters; - let filter = _.find(filters, { key: options.key, value: options.value }); + let filter: any = _.find(filters, { key: options.key, value: options.value }); if (!filter) { filter = { key: options.key, value: options.value }; diff --git a/public/app/features/users/InviteeRow.tsx b/public/app/features/users/InviteeRow.tsx index fd9ff32fbdd75..3844ab45e9843 100644 --- a/public/app/features/users/InviteeRow.tsx +++ b/public/app/features/users/InviteeRow.tsx @@ -27,19 +27,19 @@ class InviteeRow extends PureComponent { {invitee.email} {invitee.name} -