diff --git a/CHANGELOG.md b/CHANGELOG.md index c0def4c8487..343e3ccfbb1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,25 +6,34 @@ ### Minor * **Cloudwatch**: Add AWS RDS MaximumUsedTransactionIDs metric [#15077](https://github.com/grafana/grafana/pull/15077), thx [@activeshadow](https://github.com/activeshadow) - ### Bug Fixes * **Api**: Invalid org invite code [#10506](https://github.com/grafana/grafana/issues/10506) * **Datasource**: Handles nil jsondata field gracefully [#14239](https://github.com/grafana/grafana/issues/14239) * **Gauge**: Interpolate scoped variables in repeated gauges [#15739](https://github.com/grafana/grafana/issues/15739) * **Datasource**: Empty user/password was not updated when updating datasources [#15608](https://github.com/grafana/grafana/pull/15608), thx [@Maddin-619](https://github.com/Maddin-619) -# 6.0.1 (unreleased) +# 6.0.1 (2019-03-06) ### Bug Fixes * **Metrics**: Fixes broken usagestats metrics for /metrics [#15651](https://github.com/grafana/grafana/issues/15651) * **Dashboard**: Fixes kiosk mode should have &kiosk appended to the url [#15765](https://github.com/grafana/grafana/issues/15765) * **Dashboard**: Fixes kiosk=tv mode with autofitpanels should respect header [#15650](https://github.com/grafana/grafana/issues/15650) +* **Image rendering**: Fixed image rendering issue for dashboards with auto refresh, . [#15818](https://github.com/grafana/grafana/pull/15818), [@torkelo](https://github.com/torkelo) +* **Dashboard**: Fix only users that can edit a dashboard should be able to update panel json. [#15805](https://github.com/grafana/grafana/pull/15805), [@marefr](https://github.com/marefr) +* **LDAP**: fix allow anonymous initial bind for ldap search. [#15803](https://github.com/grafana/grafana/pull/15803), [@marefr](https://github.com/marefr) +* **UX**: Fixed scrollbar not visible initially (only after manual scroll). [#15798](https://github.com/grafana/grafana/pull/15798), [@torkelo](https://github.com/torkelo) +* **Datasource admin** TestData [#15793](https://github.com/grafana/grafana/pull/15793), [@hugohaggmark](https://github.com/hugohaggmark) +* **Dashboard**: Fixed scrolling issue that caused scroll to be locked to bottom. [#15792](https://github.com/grafana/grafana/pull/15792), [@torkelo](https://github.com/torkelo) +* **Explore**: Viewers with viewers_can_edit should be able to access /explore. [#15787](https://github.com/grafana/grafana/pull/15787), [@jschill](https://github.com/jschill) +* **Security** fix: limit access to org admin and alerting pages. [#15761](https://github.com/grafana/grafana/pull/15761), [@marefr](https://github.com/marefr) +* **Panel Edit** minInterval changes did not persist [#15757](https://github.com/grafana/grafana/pull/15757), [@hugohaggmark](https://github.com/hugohaggmark) +* **Teams**: Fixed bug when getting teams for user. [#15595](https://github.com/grafana/grafana/pull/15595), [@hugohaggmark](https://github.com/hugohaggmark) +* **Stackdriver**: fix for float64 bounds for distribution metrics [#14509](https://github.com/grafana/grafana/issues/14509) +* **Stackdriver**: no reducers available for distribution type [#15179](https://github.com/grafana/grafana/issues/15179) # 6.0.0 stable (2019-02-25) ### Bug Fixes -* **Stackdriver**: fix for float64 bounds for distribution metrics [#14509](https://github.com/grafana/grafana/issues/14509) -* **Stackdriver**: no reducers available for distribution type [#15179](https://github.com/grafana/grafana/issues/15179) * **Dashboard**: fixes click after scroll in series override menu [#15621](https://github.com/grafana/grafana/issues/15621) * **MySQL**: fix mysql query using _interval_ms variable throws error [#14507](https://github.com/grafana/grafana/issues/14507) diff --git a/Gopkg.lock b/Gopkg.lock index dca36f1b3d0..235a315f1e8 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -2,30 +2,39 @@ [[projects]] + digest = "1:f8ad8a53fa865a70efbe215b0ca34735523f50ea39e0efde319ab6fc80089b44" name = "cloud.google.com/go" packages = ["compute/metadata"] + pruneopts = "NUT" revision = "056a55f54a6cc77b440b31a56a5e7c3982d32811" version = "v0.22.0" [[projects]] + digest = "1:167b6f65a6656de568092189ae791253939f076df60231fdd64588ac703892a1" name = "github.com/BurntSushi/toml" packages = ["."] + pruneopts = "NUT" revision = "b26d9c308763d68093482582cea63d69be07a0f0" version = "v0.3.0" [[projects]] branch = "master" + digest = "1:7d23e6e1889b8bb4bbb37a564708fdab4497ce232c3a99d66406c975b642a6ff" name = "github.com/Unknwon/com" packages = ["."] + pruneopts = "NUT" revision = "7677a1d7c1137cd3dd5ba7a076d0c898a1ef4520" [[projects]] branch = "master" + digest = "1:1610787cd9726e29d8fecc2a80e43e4fced008a1f560fec6688fc4d946f17835" name = "github.com/VividCortex/mysqlerr" packages = ["."] + pruneopts = "NUT" revision = "6c6b55f8796f578c870b7e19bafb16103bc40095" [[projects]] + digest = "1:ebe102b61c1615d2954734e3cfe1b6b06a5088c25a41055b38661d41ad7b8f27" name = "github.com/aws/aws-sdk-go" packages = [ "aws", @@ -69,399 +78,507 @@ "service/resourcegroupstaggingapi", "service/resourcegroupstaggingapi/resourcegroupstaggingapiiface", "service/s3", - "service/sts" + "service/sts", ] + pruneopts = "NUT" revision = "62936e15518acb527a1a9cb4a39d96d94d0fd9a2" version = "v1.16.15" [[projects]] branch = "master" + digest = "1:79cad073c7be02632d3fa52f62486848b089f560db1e94536de83a408c0f4726" name = "github.com/benbjohnson/clock" packages = ["."] + pruneopts = "NUT" revision = "7dc76406b6d3c05b5f71a86293cbcf3c4ea03b19" [[projects]] branch = "master" + digest = "1:707ebe952a8b3d00b343c01536c79c73771d100f63ec6babeaed5c79e2b8a8dd" name = "github.com/beorn7/perks" packages = ["quantile"] + pruneopts = "NUT" revision = "3a771d992973f24aa725d07868b467d1ddfceafb" [[projects]] branch = "master" + digest = "1:433a2ff0ef4e2f8634614aab3174783c5ff80120b487712db96cc3712f409583" name = "github.com/bmizerany/assert" packages = ["."] + pruneopts = "NUT" revision = "b7ed37b82869576c289d7d97fb2bbd8b64a0cb28" [[projects]] branch = "master" + digest = "1:d8f9145c361920507a4f85ffb7f70b96beaedacba2ce8c00aa663adb08689d3e" name = "github.com/bradfitz/gomemcache" packages = ["memcache"] + pruneopts = "NUT" revision = "1952afaa557dc08e8e0d89eafab110fb501c1a2b" [[projects]] branch = "master" + digest = "1:8ecb89af7dfe3ac401bdb0c9390b134ef96a97e85f732d2b0604fb7b3977839f" name = "github.com/codahale/hdrhistogram" packages = ["."] + pruneopts = "NUT" revision = "3a0bb77429bd3a61596f5e8a3172445844342120" [[projects]] + digest = "1:5dba68a1600a235630e208cb7196b24e58fcbb77bb7a6bec08fcd23f081b0a58" name = "github.com/codegangsta/cli" packages = ["."] + pruneopts = "NUT" revision = "cfb38830724cc34fedffe9a2a29fb54fa9169cd1" version = "v1.20.0" [[projects]] + digest = "1:a2c1d0e43bd3baaa071d1b9ed72c27d78169b2b269f71c105ac4ba34b1be4a39" name = "github.com/davecgh/go-spew" packages = ["spew"] + pruneopts = "NUT" revision = "346938d642f2ec3594ed81d874461961cd0faa76" version = "v1.1.0" [[projects]] + digest = "1:1b318d2dd6cea8a1a8d8ec70348852303bd3e491df74e8bca6e32eb5a4d06970" name = "github.com/denisenkom/go-mssqldb" packages = [ ".", - "internal/cp" + "internal/cp", ] + pruneopts = "NUT" revision = "270bc3860bb94dd3a3ffd047377d746c5e276726" [[projects]] branch = "master" + digest = "1:2da5f11ad66ff01a27a5c3dba4620b7eee2327be75b32c9ee9f87c9a8001ecbf" name = "github.com/facebookgo/inject" packages = ["."] + pruneopts = "NUT" revision = "cc1aa653e50f6a9893bcaef89e673e5b24e1e97b" [[projects]] branch = "master" + digest = "1:1108df7f658c90db041e0d6174d55be689aaeb0585913b9c3c7aab51a3a6b2b1" name = "github.com/facebookgo/structtag" packages = ["."] + pruneopts = "NUT" revision = "217e25fb96916cc60332e399c9aa63f5c422ceed" [[projects]] + digest = "1:ade392a843b2035effb4b4a2efa2c3bab3eb29b992e98bacf9c898b0ecb54e45" name = "github.com/fatih/color" packages = ["."] + pruneopts = "NUT" revision = "5b77d2a35fb0ede96d138fc9a99f5c9b6aef11b4" version = "v1.7.0" -[[projects]] - name = "github.com/go-ini/ini" - packages = ["."] - revision = "6529cf7c58879c08d927016dde4477f18a0634cb" - version = "v1.36.0" - [[projects]] branch = "master" + digest = "1:682a0aca743a1a4a36697f3d7f86c0ed403c4e3a780db9935f633242855eac9c" name = "github.com/go-macaron/binding" packages = ["."] + pruneopts = "NUT" revision = "ac54ee249c27dca7e76fad851a4a04b73bd1b183" [[projects]] branch = "master" + digest = "1:6326b27f8e0c8e135c8674ddbc619fae879664ac832e8e6fa6a23ce0d279ed4d" name = "github.com/go-macaron/gzip" packages = ["."] + pruneopts = "NUT" revision = "cad1c6580a07c56f5f6bc52d66002a05985c5854" [[projects]] branch = "master" + digest = "1:fb8711b648d1ff03104fc1d9593a13cb1d5120be7ba2b01641c14ccae286a9e3" name = "github.com/go-macaron/inject" packages = ["."] + pruneopts = "NUT" revision = "d8a0b8677191f4380287cfebd08e462217bac7ad" [[projects]] branch = "master" + digest = "1:21577aafe885f088e8086a3415f154c63c0b7ce956a6994df2ac5776bc01b7e3" name = "github.com/go-macaron/session" packages = [ ".", "memcache", "postgres", - "redis" + "redis", ] + pruneopts = "NUT" revision = "068d408f9c54c7fa7fcc5e2bdd3241ab21280c9e" [[projects]] + digest = "1:fddd4bada6100d6fc49a9f32f18ba5718db45a58e4b00aa6377e1cfbf06af34f" name = "github.com/go-sql-driver/mysql" packages = ["."] + pruneopts = "NUT" revision = "2cc627ac8defc45d65066ae98f898166f580f9a4" [[projects]] + digest = "1:a1efdbc2762667c8a41cbf02b19a0549c846bf2c1d08cad4f445e3344089f1f0" name = "github.com/go-stack/stack" packages = ["."] + pruneopts = "NUT" revision = "259ab82a6cad3992b4e21ff5cac294ccb06474bc" version = "v1.7.0" [[projects]] + digest = "1:06d21295033f211588d0ad7ff391cc1b27e72b60cb6d4b7db0d70cffae4cf228" name = "github.com/go-xorm/builder" packages = ["."] - revision = "bad0a612f0d6277b953910822ab5dfb30dd18237" - version = "v0.2.0" + pruneopts = "NUT" + revision = "1d658d7596c25394aab557ef5b50ef35bf706384" + version = "v0.3.4" [[projects]] + digest = "1:b26928aab0fff92592e8728c5bc9d6e404fa2017d6a8e841ae5e60a42237f6fc" name = "github.com/go-xorm/core" packages = ["."] - revision = "da1adaf7a28ca792961721a34e6e04945200c890" - version = "v0.5.7" + pruneopts = "NUT" + revision = "ccc80c1adf1f6172bbc548877f50a1163041a40a" + version = "v0.6.2" [[projects]] + digest = "1:407316703b32d68ccf5d39bdae57d411b6954e253e07d0fff0988a3f39861f2f" name = "github.com/go-xorm/xorm" packages = ["."] - revision = "1933dd69e294c0a26c0266637067f24dbb25770c" - version = "v0.6.4" + pruneopts = "NUT" + revision = "1f39c590c64924f358c0d89016ac9b2bb84e9125" + version = "v0.7.1" [[projects]] branch = "master" + digest = "1:ffbb19fb66f140b5ea059428d1f84246a055d1bc3d9456c1e5c3d143611f03d0" name = "github.com/golang/protobuf" packages = [ "proto", "ptypes", "ptypes/any", "ptypes/duration", - "ptypes/timestamp" + "ptypes/timestamp", ] + pruneopts = "NUT" revision = "927b65914520a8b7d44f5c9057611cfec6b2e2d0" [[projects]] branch = "master" + digest = "1:f14d1b50e0075fb00177f12a96dd7addf93d1e2883c25befd17285b779549795" name = "github.com/gopherjs/gopherjs" packages = ["js"] + pruneopts = "NUT" revision = "8dffc02ea1cb8398bb73f30424697c60fcf8d4c5" [[projects]] + digest = "1:3b708ebf63bfa9ba3313bedb8526bc0bb284e51474e65e958481476a9d4a12aa" name = "github.com/gorilla/websocket" packages = ["."] + pruneopts = "NUT" revision = "ea4d1f681babbce9545c9c5f3d5194a789c89f5b" version = "v1.2.0" [[projects]] + digest = "1:4e771d1c6e15ca4516ad971c34205c822b5cff2747179679d7b321e4e1bfe431" name = "github.com/gosimple/slug" packages = ["."] + pruneopts = "NUT" revision = "e9f42fa127660e552d0ad2b589868d403a9be7c6" version = "v1.1.1" [[projects]] branch = "master" + digest = "1:08e53c69cd267ef7d71eeae5d953153d0d2bc1b8e0b498731fe9acaead7001b6" name = "github.com/grafana/grafana-plugin-model" packages = [ "go/datasource", - "go/renderer" + "go/renderer", ] + pruneopts = "NUT" revision = "84176c64269d8060f99e750ee8aba6f062753336" [[projects]] branch = "master" + digest = "1:58ba5285227b0f635652cd4aa82c4cfd00b590191eadd823462f0c9f64e3ae07" name = "github.com/hashicorp/go-hclog" packages = ["."] + pruneopts = "NUT" revision = "69ff559dc25f3b435631604f573a5fa1efdb6433" [[projects]] + digest = "1:532090ffc3b05a7e4c0229dd2698d79149f2e0683df993224a8b202f607fb605" name = "github.com/hashicorp/go-plugin" packages = ["."] + pruneopts = "NUT" revision = "e8d22c780116115ae5624720c9af0c97afe4f551" [[projects]] branch = "master" + digest = "1:8925116d1edcd85fc0c014e1aa69ce12892489b48ee633a605c46d893b8c151f" name = "github.com/hashicorp/go-version" packages = ["."] + pruneopts = "NUT" revision = "23480c0665776210b5fbbac6eaaee40e3e6a96b7" [[projects]] branch = "master" + digest = "1:8deb0c5545c824dfeb0ac77ab8eb67a3d541eab76df5c85ce93064ef02d44cd0" name = "github.com/hashicorp/yamux" packages = ["."] + pruneopts = "NUT" revision = "7221087c3d281fda5f794e28c2ea4c6e4d5c4558" [[projects]] + digest = "1:efbe016b6d198cf44f1db0ed2fbdf1b36ebf1f6956cc9b76d6affa96f022d368" name = "github.com/inconshreveable/log15" packages = ["."] + pruneopts = "NUT" revision = "0decfc6c20d9ca0ad143b0e89dcaa20f810b4fb3" version = "v2.13" [[projects]] + digest = "1:1f2aebae7e7c856562355ec0198d8ca2fa222fb05e5b1b66632a1fce39631885" name = "github.com/jmespath/go-jmespath" packages = ["."] - revision = "0b12d6b5" + pruneopts = "NUT" + revision = "c2b33e84" [[projects]] + digest = "1:6ddab442e52381bab82fb6c07ef3f4b565ff7ec4b8fae96d8dd4b8573a460597" name = "github.com/jtolds/gls" packages = ["."] + pruneopts = "NUT" revision = "77f18212c9c7edc9bd6a33d383a7b545ce62f064" version = "v4.2.1" [[projects]] + digest = "1:1da1796a71eb70f1e3e085984d044f67840bb0326816ec8276231aa87b1b9fc3" name = "github.com/klauspost/compress" packages = [ "flate", - "gzip" + "gzip", ] + pruneopts = "NUT" revision = "6c8db69c4b49dd4df1fff66996cf556176d0b9bf" version = "v1.2.1" [[projects]] + digest = "1:5e55a8699c9ff7aba1e4c8952aeda209685d88d4cb63a8766c338e333b8e65d6" name = "github.com/klauspost/cpuid" packages = ["."] + pruneopts = "NUT" revision = "ae7887de9fa5d2db4eaa8174a7eff2c1ac00f2da" version = "v1.1" [[projects]] + digest = "1:b95da1293525625ef6f07be79d537b9bf2ecd7901efcf9a92193edafbd55b9ef" name = "github.com/klauspost/crc32" packages = ["."] + pruneopts = "NUT" revision = "cb6bfca970f6908083f26f39a79009d608efd5cd" version = "v1.1" [[projects]] + digest = "1:7b21c7fc5551b46d1308b4ffa9e9e49b66c7a8b0ba88c0130474b0e7a20d859f" name = "github.com/kr/pretty" packages = ["."] + pruneopts = "NUT" revision = "73f6ac0b30a98e433b289500d779f50c1a6f0712" version = "v0.1.0" [[projects]] + digest = "1:c3a7836b5904db0f8b609595b619916a6831cb35b8b714aec39f96d00c6155d8" name = "github.com/kr/text" packages = ["."] + pruneopts = "NUT" revision = "e2ffdb16a802fe2bb95e2e35ff34f0e53aeef34f" version = "v0.1.0" [[projects]] branch = "master" + digest = "1:7a1e592f0349d56fac8ce47f28469e4e7f4ce637cb26f40c88da9dff25db1c98" name = "github.com/lib/pq" packages = [ ".", - "oid" + "oid", ] + pruneopts = "NUT" revision = "d34b9ff171c21ad295489235aec8b6626023cd04" [[projects]] + digest = "1:08c231ec84231a7e23d67e4b58f975e1423695a32467a362ee55a803f9de8061" name = "github.com/mattn/go-colorable" packages = ["."] + pruneopts = "NUT" revision = "167de6bfdfba052fa6b2d3664c8f5272e23c9072" version = "v0.0.9" [[projects]] + digest = "1:bc4f7eec3b7be8c6cb1f0af6c1e3333d5bb71072951aaaae2f05067b0803f287" name = "github.com/mattn/go-isatty" packages = ["."] + pruneopts = "NUT" revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39" version = "v0.0.3" [[projects]] + digest = "1:536979f1c56397dbf91c2785159b37dec37e35d3bffa3cd1cfe66d25f51f8088" name = "github.com/mattn/go-sqlite3" packages = ["."] + pruneopts = "NUT" revision = "323a32be5a2421b8c7087225079c6c900ec397cd" version = "v1.7.0" [[projects]] + digest = "1:5985ef4caf91ece5d54817c11ea25f182697534f8ae6521eadcd628c142ac4b6" name = "github.com/matttproud/golang_protobuf_extensions" packages = ["pbutil"] + pruneopts = "NUT" revision = "3247c84500bff8d9fb6d579d800f20b3e091582c" version = "v1.0.0" [[projects]] branch = "master" + digest = "1:18b773b92ac82a451c1276bd2776c1e55ce057ee202691ab33c8d6690efcc048" name = "github.com/mitchellh/go-testing-interface" packages = ["."] + pruneopts = "NUT" revision = "a61a99592b77c9ba629d254a693acffaeb4b7e28" [[projects]] + digest = "1:3b517122f3aad1ecce45a630ea912b3092b4729f25532a911d0cb2935a1f9352" name = "github.com/oklog/run" packages = ["."] + pruneopts = "NUT" revision = "4dadeb3030eda0273a12382bb2348ffc7c9d1a39" version = "v1.0.0" [[projects]] + digest = "1:7da29c22bcc5c2ffb308324377dc00b5084650348c2799e573ed226d8cc9faf0" name = "github.com/opentracing/opentracing-go" packages = [ ".", "ext", - "log" + "log", ] + pruneopts = "NUT" revision = "1949ddbfd147afd4d964a9f00b24eb291e0e7c38" version = "v1.0.2" [[projects]] + digest = "1:748946761cf99c8b73cef5a3c0ee3e040859dd713a20cece0d0e0dc04e6ceca7" name = "github.com/patrickmn/go-cache" packages = ["."] + pruneopts = "NUT" revision = "a3647f8e31d79543b2d0f0ae2fe5c379d72cedc0" version = "v2.1.0" [[projects]] + digest = "1:5cf3f025cbee5951a4ee961de067c8a89fc95a5adabead774f82822efabab121" name = "github.com/pkg/errors" packages = ["."] + pruneopts = "NUT" revision = "645ef00459ed84a119197bfb8d8205042c6df63d" version = "v0.8.0" [[projects]] + digest = "1:4759bed95e3a52febc18c071db28790a5c6e9e106ee201a37add6f6a056f8f9c" name = "github.com/prometheus/client_golang" packages = [ "api", "api/prometheus/v1", "prometheus", - "prometheus/promhttp" + "prometheus/promhttp", ] + pruneopts = "NUT" revision = "967789050ba94deca04a5e84cce8ad472ce313c1" version = "v0.9.0-pre1" [[projects]] branch = "master" + digest = "1:32d10bdfa8f09ecf13598324dba86ab891f11db3c538b6a34d1c3b5b99d7c36b" name = "github.com/prometheus/client_model" packages = ["go"] + pruneopts = "NUT" revision = "99fa1f4be8e564e8a6b613da7fa6f46c9edafc6c" [[projects]] branch = "master" + digest = "1:768b555b86742de2f28beb37f1dedce9a75f91f871d75b5717c96399c1a78c08" name = "github.com/prometheus/common" packages = [ "expfmt", "internal/bitbucket.org/ww/goautoneg", - "model" + "model", ] + pruneopts = "NUT" revision = "d811d2e9bf898806ecfb6ef6296774b13ffc314c" [[projects]] branch = "master" + digest = "1:c4a213a8d73fbb0b13f717ba7996116602ef18ecb42b91d77405877914cb0349" name = "github.com/prometheus/procfs" packages = [ ".", "internal/util", "nfs", - "xfs" + "xfs", ] + pruneopts = "NUT" revision = "8b1c2da0d56deffdbb9e48d4414b4e674bd8083e" [[projects]] branch = "master" + digest = "1:16e2136a67ec44aa2d1d6b0fd65394b3c4a8b2a1b6730c77967f7b7b06b179b2" name = "github.com/rainycape/unidecode" packages = ["."] + pruneopts = "NUT" revision = "cb7f23ec59bec0d61b19c56cd88cee3d0cc1870c" [[projects]] + digest = "1:d917313f309bda80d27274d53985bc65651f81a5b66b820749ac7f8ef061fd04" name = "github.com/sergi/go-diff" packages = ["diffmatchpatch"] + pruneopts = "NUT" revision = "1744e2970ca51c86172c8190fadad617561ed6e7" version = "v1.0.0" [[projects]] + digest = "1:1f0b284a6858827de4c27c66b49b2b25df3e16b031c2b57b7892273131e7dd2b" name = "github.com/smartystreets/assertions" packages = [ ".", "internal/go-render/render", - "internal/oglematchers" + "internal/oglematchers", ] + pruneopts = "NUT" revision = "7678a5452ebea5b7090a6b163f844c133f523da2" version = "1.8.3" [[projects]] + digest = "1:7efd0b2309cdd6468029fa30c808c50a820c9344df07e1a4bbdaf18f282907aa" name = "github.com/smartystreets/goconvey" packages = [ "convey", "convey/gotest", - "convey/reporting" + "convey/reporting", ] + pruneopts = "NUT" revision = "9e8dc3f972df6c8fcc0375ef492c24d0bb204857" version = "1.6.3" [[projects]] branch = "master" + digest = "1:a66add8dd963bfc72649017c1b321198f596cb4958cb1a11ff91a1be8691020b" name = "github.com/teris-io/shortid" packages = ["."] + pruneopts = "NUT" revision = "771a37caa5cf0c81f585d7b6df4dfc77e0615b5c" [[projects]] + digest = "1:3d48c38e0eca8c66df62379c5ae7a83fb5cd839b94f241354c07ba077da7bc45" name = "github.com/uber/jaeger-client-go" packages = [ ".", @@ -479,45 +596,55 @@ "thrift-gen/jaeger", "thrift-gen/sampling", "thrift-gen/zipkincore", - "utils" + "utils", ] + pruneopts = "NUT" revision = "b043381d944715b469fd6b37addfd30145ca1758" version = "v2.14.0" [[projects]] + digest = "1:0f09db8429e19d57c8346ad76fbbc679341fa86073d3b8fb5ac919f0357d8f4c" name = "github.com/uber/jaeger-lib" packages = ["metrics"] + pruneopts = "NUT" revision = "ed3a127ec5fef7ae9ea95b01b542c47fbd999ce5" version = "v1.5.0" [[projects]] + digest = "1:4c7d12ad3ef47bb03892a52e2609dc9a9cff93136ca9c7d31c00b79fcbc23c7b" name = "github.com/yudai/gojsondiff" packages = [ ".", - "formatter" + "formatter", ] + pruneopts = "NUT" revision = "7b1b7adf999dab73a6eb02669c3d82dbb27a3dd6" version = "1.0.0" [[projects]] branch = "master" + digest = "1:e50cbf8eba568d59b71e08c22c2a77809ed4646ae06ef4abb32b3d3d3fdb1a77" name = "github.com/yudai/golcs" packages = ["."] + pruneopts = "NUT" revision = "ecda9a501e8220fae3b4b600c3db4b0ba22cfc68" [[projects]] branch = "master" + digest = "1:758f363e0dff33cf00b234be2efb12f919d79b42d5ae3909ff9eb69ef2c3cca5" name = "golang.org/x/crypto" packages = [ "ed25519", "ed25519/internal/edwards25519", "md4", - "pbkdf2" + "pbkdf2", ] + pruneopts = "NUT" revision = "1a580b3eff7814fc9b40602fd35256c63b50f491" [[projects]] branch = "master" + digest = "1:0b3fee9c4472022a0982ee0d81e08b3cc3e595f50befd7a4b358b48540d9d8c5" name = "golang.org/x/net" packages = [ "context", @@ -527,35 +654,43 @@ "http2/hpack", "idna", "internal/timeseries", - "trace" + "trace", ] + pruneopts = "NUT" revision = "2491c5de3490fced2f6cff376127c667efeed857" [[projects]] branch = "master" + digest = "1:46bd4e66bfce5e77f08fc2e8dcacc3676e679241ce83d9c150ff0397d686dd44" name = "golang.org/x/oauth2" packages = [ ".", "google", "internal", "jws", - "jwt" + "jwt", ] + pruneopts = "NUT" revision = "cdc340f7c179dbbfa4afd43b7614e8fcadde4269" [[projects]] branch = "master" + digest = "1:39ebcc2b11457b703ae9ee2e8cca0f68df21969c6102cb3b705f76cca0ea0239" name = "golang.org/x/sync" packages = ["errgroup"] + pruneopts = "NUT" revision = "1d60e4601c6fd243af51cc01ddf169918a5407ca" [[projects]] branch = "master" + digest = "1:ec21c5bf0572488865b93e30ffd9132afbf85bec0b20c2d6cbcf349cf2031ed5" name = "golang.org/x/sys" packages = ["unix"] + pruneopts = "NUT" revision = "7c87d13f8e835d2fb3a70a2912c811ed0c1d241b" [[projects]] + digest = "1:e7071ed636b5422cc51c0e3a6cebc229d6c9fffc528814b519a980641422d619" name = "golang.org/x/text" packages = [ "collate", @@ -571,12 +706,14 @@ "unicode/bidi", "unicode/cldr", "unicode/norm", - "unicode/rangetable" + "unicode/rangetable", ] + pruneopts = "NUT" revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" version = "v0.3.0" [[projects]] + digest = "1:dbd5568923513ee74aa626d027e2a8a352cf8f35df41d19f4e34491d1858c38b" name = "google.golang.org/appengine" packages = [ ".", @@ -589,18 +726,22 @@ "internal/modules", "internal/remote_api", "internal/urlfetch", - "urlfetch" + "urlfetch", ] + pruneopts = "NUT" revision = "150dc57a1b433e64154302bdc40b6bb8aefa313a" version = "v1.0.0" [[projects]] branch = "master" + digest = "1:3c24554c312721e98fa6b76403e7100cf974eb46b1255ea7fc6471db9a9ce498" name = "google.golang.org/genproto" packages = ["googleapis/rpc/status"] + pruneopts = "NUT" revision = "7bb2a897381c9c5ab2aeb8614f758d7766af68ff" [[projects]] + digest = "1:840b77b6eb539b830bb760b6e30b688ed2ff484bd83466fce2395835ed9367fe" name = "google.golang.org/grpc" packages = [ ".", @@ -627,78 +768,177 @@ "stats", "status", "tap", - "transport" + "transport", ] + pruneopts = "NUT" revision = "1e2570b1b19ade82d8dbb31bba4e65e9f9ef5b34" version = "v1.11.1" [[projects]] branch = "v3" + digest = "1:1244a9b3856f70d5ffb74bbfd780fc9d47f93f2049fa265c6fb602878f507bf8" name = "gopkg.in/alexcesaro/quotedprintable.v3" packages = ["."] + pruneopts = "NUT" revision = "2caba252f4dc53eaf6b553000885530023f54623" [[projects]] + digest = "1:aea6e9483c167cc6fdf1274c442558c5dda8fd3373372be04d98c79100868da1" name = "gopkg.in/asn1-ber.v1" packages = ["."] + pruneopts = "NUT" revision = "379148ca0225df7a432012b8df0355c2a2063ac0" version = "v1.2" [[projects]] + digest = "1:24bfc2e8bf971485cb5ba0f0e5b08a1b806cca5828134df76b32d1ea50f2ab49" name = "gopkg.in/bufio.v1" packages = ["."] + pruneopts = "NUT" revision = "567b2bfa514e796916c4747494d6ff5132a1dfce" version = "v1" [[projects]] + digest = "1:e05711632e1515319b014e8fe4cbe1d30ab024c473403f60cf0fdeb4c586a474" name = "gopkg.in/ini.v1" packages = ["."] + pruneopts = "NUT" revision = "6529cf7c58879c08d927016dde4477f18a0634cb" version = "v1.36.0" [[projects]] + digest = "1:c847b7fea4c7e6db5281a37dffc4620cb78c1227403a79e5aa290db517657ac1" name = "gopkg.in/ldap.v3" packages = ["."] + pruneopts = "NUT" revision = "5c2c0f997205c29de14cb6c35996370c2c5dfab1" version = "v3" [[projects]] + digest = "1:3b0cf3a465fd07f76e5fc1a9d0783c662dac0de9fc73d713ebe162768fd87b5f" name = "gopkg.in/macaron.v1" packages = ["."] + pruneopts = "NUT" revision = "c1be95e6d21e769e44e1ec33cec9da5837861c10" version = "v1.3.1" [[projects]] branch = "v2" + digest = "1:d52332f9e9f2c6343652e13aa3fd40cfd03353520c9a48d90f21215d3012d50f" name = "gopkg.in/mail.v2" packages = ["."] + pruneopts = "NUT" revision = "5bc5c8bb07bd8d2803831fbaf8cbd630fcde2c68" [[projects]] + digest = "1:00126f697efdcab42f07c89ac8bf0095fb2328aef6464e070055154088cea859" name = "gopkg.in/redis.v2" packages = ["."] + pruneopts = "NUT" revision = "e6179049628164864e6e84e973cfb56335748dea" version = "v2.3.2" [[projects]] + digest = "1:a50fabe7a46692dc7c656310add3d517abe7914df02afd151ef84da884605dc8" name = "gopkg.in/square/go-jose.v2" packages = [ ".", "cipher", - "json" + "json", ] + pruneopts = "NUT" revision = "ef984e69dd356202fd4e4910d4d9c24468bdf0b8" version = "v2.1.9" [[projects]] branch = "v2" + digest = "1:7c95b35057a0ff2e19f707173cc1a947fa43a6eb5c4d300d196ece0334046082" name = "gopkg.in/yaml.v2" packages = ["."] + pruneopts = "NUT" revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183" [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "88f0eb826b9c154ba46ea3bb64767707d86db75449ec75199eb2b8cf2b337fd4" + input-imports = [ + "github.com/BurntSushi/toml", + "github.com/Unknwon/com", + "github.com/VividCortex/mysqlerr", + "github.com/aws/aws-sdk-go/aws", + "github.com/aws/aws-sdk-go/aws/awserr", + "github.com/aws/aws-sdk-go/aws/awsutil", + "github.com/aws/aws-sdk-go/aws/credentials", + "github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds", + "github.com/aws/aws-sdk-go/aws/credentials/endpointcreds", + "github.com/aws/aws-sdk-go/aws/defaults", + "github.com/aws/aws-sdk-go/aws/ec2metadata", + "github.com/aws/aws-sdk-go/aws/endpoints", + "github.com/aws/aws-sdk-go/aws/request", + "github.com/aws/aws-sdk-go/aws/session", + "github.com/aws/aws-sdk-go/service/cloudwatch", + "github.com/aws/aws-sdk-go/service/ec2", + "github.com/aws/aws-sdk-go/service/ec2/ec2iface", + "github.com/aws/aws-sdk-go/service/resourcegroupstaggingapi", + "github.com/aws/aws-sdk-go/service/resourcegroupstaggingapi/resourcegroupstaggingapiiface", + "github.com/aws/aws-sdk-go/service/s3", + "github.com/aws/aws-sdk-go/service/sts", + "github.com/benbjohnson/clock", + "github.com/bmizerany/assert", + "github.com/codegangsta/cli", + "github.com/davecgh/go-spew/spew", + "github.com/denisenkom/go-mssqldb", + "github.com/facebookgo/inject", + "github.com/fatih/color", + "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", + "github.com/go-xorm/xorm", + "github.com/gorilla/websocket", + "github.com/gosimple/slug", + "github.com/grafana/grafana-plugin-model/go/datasource", + "github.com/grafana/grafana-plugin-model/go/renderer", + "github.com/hashicorp/go-hclog", + "github.com/hashicorp/go-plugin", + "github.com/hashicorp/go-version", + "github.com/inconshreveable/log15", + "github.com/lib/pq", + "github.com/mattn/go-isatty", + "github.com/mattn/go-sqlite3", + "github.com/opentracing/opentracing-go", + "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", + "github.com/prometheus/client_golang/prometheus/promhttp", + "github.com/prometheus/client_model/go", + "github.com/prometheus/common/expfmt", + "github.com/prometheus/common/model", + "github.com/smartystreets/goconvey/convey", + "github.com/teris-io/shortid", + "github.com/uber/jaeger-client-go/config", + "github.com/yudai/gojsondiff", + "github.com/yudai/gojsondiff/formatter", + "golang.org/x/net/context/ctxhttp", + "golang.org/x/oauth2", + "golang.org/x/oauth2/google", + "golang.org/x/oauth2/jwt", + "golang.org/x/sync/errgroup", + "gopkg.in/ini.v1", + "gopkg.in/ldap.v3", + "gopkg.in/macaron.v1", + "gopkg.in/mail.v2", + "gopkg.in/square/go-jose.v2", + "gopkg.in/yaml.v2", + ] solver-name = "gps-cdcl" solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml index 83e6890b0f4..d1bc0f55bae 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -81,11 +81,15 @@ ignored = [ [[constraint]] name = "github.com/go-xorm/core" - version = "=0.5.7" + version = "=0.6.2" + +[[override]] + name = "github.com/go-xorm/builder" + version = "=0.3.4" [[constraint]] name = "github.com/go-xorm/xorm" - version = "=0.6.4" + version = "=0.7.1" [[constraint]] name = "github.com/gorilla/websocket" diff --git a/devenv/docker/blocks/prometheus2/Dockerfile b/devenv/docker/blocks/prometheus2/Dockerfile index 03edf4c9ee2..c9a2327bd4a 100644 --- a/devenv/docker/blocks/prometheus2/Dockerfile +++ b/devenv/docker/blocks/prometheus2/Dockerfile @@ -1,3 +1,3 @@ -FROM prom/prometheus:v2.2.0 +FROM prom/prometheus:v2.7.2 ADD prometheus.yml /etc/prometheus/ ADD alert.rules /etc/prometheus/ diff --git a/latest.json b/latest.json index 7e69b431a4d..e19a0f8550d 100644 --- a/latest.json +++ b/latest.json @@ -1,4 +1,4 @@ { - "stable": "6.0.0", - "testing": "6.0.0" + "stable": "6.0.1", + "testing": "6.0.1" } diff --git a/package.json b/package.json index 04a6967fdb9..a937ba6f717 100644 --- a/package.json +++ b/package.json @@ -123,10 +123,10 @@ }, "scripts": { "dev": "webpack --progress --colors --mode development --config scripts/webpack/webpack.dev.js", - "start": "ts-node --project ./scripts/cli/tsconfig.json ./scripts/cli/index.ts --theme", - "start:hot": "ts-node --project ./scripts/cli/tsconfig.json ./scripts/cli/index.ts --hot --theme", - "start:ignoreTheme": "ts-node --project ./scripts/cli/tsconfig.json ./scripts/cli/index.ts --hot", - "watch": "ts-node --project ./scripts/cli/tsconfig.json ./scripts/cli/index.ts --theme -d watch,start", + "start": "ts-node --project ./scripts/cli/tsconfig.json ./scripts/cli/index.ts core:start --watchTheme", + "start:hot": "ts-node --project ./scripts/cli/tsconfig.json ./scripts/cli/index.ts core:start --hot --watchTheme", + "start:ignoreTheme": "ts-node --project ./scripts/cli/tsconfig.json ./scripts/cli/index.ts core:start --hot", + "watch": "yarn start -d watch,start core:start --watchTheme ", "build": "grunt build", "test": "grunt test", "tslint": "tslint -c tslint.json --project tsconfig.json", @@ -136,8 +136,11 @@ "storybook": "cd packages/grafana-ui && yarn storybook", "themes:generate": "ts-node --project ./scripts/cli/tsconfig.json ./scripts/cli/generateSassVariableFiles.ts", "prettier:check": "prettier --list-different \"**/*.{ts,tsx,scss}\"", - "gui:build": "ts-node --project ./scripts/cli/tsconfig.json ./scripts/cli/index.ts --build", - "gui:release": "ts-node --project ./scripts/cli/tsconfig.json ./scripts/cli/index.ts --release" + "gui:build": "ts-node --project ./scripts/cli/tsconfig.json ./scripts/cli/index.ts gui:build", + "gui:releasePrepare": "ts-node --project ./scripts/cli/tsconfig.json ./scripts/cli/index.ts gui:release", + "gui:publish": "cd packages/grafana-ui/dist && npm publish --access public", + "gui:release": "ts-node --project ./scripts/cli/tsconfig.json ./scripts/cli/index.ts gui:release -p", + "cli": "ts-node --project ./scripts/cli/tsconfig.json ./scripts/cli/index.ts" }, "husky": { "hooks": { @@ -169,7 +172,6 @@ "angular-native-dragdrop": "1.2.2", "angular-route": "1.6.6", "angular-sanitize": "1.6.6", - "ansicolor": "1.1.78", "baron": "^3.0.3", "brace": "^0.10.0", "classnames": "^2.2.6", diff --git a/packages/grafana-ui/src/themes/_variables.dark.scss.tmpl.ts b/packages/grafana-ui/src/themes/_variables.dark.scss.tmpl.ts index 3a2d6db458c..54c00f9237e 100644 --- a/packages/grafana-ui/src/themes/_variables.dark.scss.tmpl.ts +++ b/packages/grafana-ui/src/themes/_variables.dark.scss.tmpl.ts @@ -54,34 +54,34 @@ $orange: ${theme.colors.orange}; $purple: ${theme.colors.purple}; $variable: ${theme.colors.variable}; -$brand-primary: $orange; -$brand-success: $green-base; -$brand-warning: $brand-primary; -$brand-danger: $red-base; +$brand-primary: ${theme.colors.brandPrimary}; +$brand-success: ${theme.colors.brandSuccess}; +$brand-warning: ${theme.colors.brandWarning}; +$brand-danger: ${theme.colors.brandDanger}; -$query-red: $red-base; -$query-green: #74e680; -$query-purple: #fe85fc; -$query-keyword: #66d9ef; -$query-orange: $orange; +$query-red: ${theme.colors.queryRed}; +$query-green: ${theme.colors.queryGreen}; +$query-purple: ${theme.colors.queryPurple}; +$query-orange: ${theme.colors.orange}; +$query-keyword: ${theme.colors.queryKeyword}; // Status colors // ------------------------- -$online: $green-base; -$warn: #f79520; -$critical: $red-base; +$online: ${theme.colors.online}; +$warn: ${theme.colors.warn}; +$critical: ${theme.colors.critical}; // Scaffolding // ------------------------- $body-bg: ${theme.colors.bodyBg}; $page-bg: ${theme.colors.pageBg}; -$body-color: $gray-4; -$text-color: $gray-4; -$text-color-strong: $white; -$text-color-weak: $gray-2; -$text-color-faint: $dark-10; -$text-color-emphasis: $gray-5; +$body-color: ${theme.colors.body}; +$text-color: ${theme.colors.text}; +$text-color-strong: ${theme.colors.textStrong}; +$text-color-weak: ${theme.colors.textWeak}; +$text-color-faint: ${theme.colors.textFaint}; +$text-color-emphasis: ${theme.colors.textEmphasis}; $text-shadow-faint: 1px 1px 4px rgb(45, 45, 45); $textShadow: none; @@ -99,14 +99,14 @@ $edit-gradient: linear-gradient(180deg, $dark-2 50%, $input-black); // Links // ------------------------- -$link-color: darken($white, 11%); -$link-color-disabled: darken($link-color, 30%); -$link-hover-color: $white; -$external-link-color: $blue-light; +$link-color: ${theme.colors.link}; +$link-color-disabled: ${theme.colors.linkDisabled}; +$link-hover-color: ${theme.colors.linkHover}; +$external-link-color: ${theme.colors.linkExternal}; // Typography // ------------------------- -$headings-color: darken($white, 11%); +$headings-color: ${theme.colors.headingColor}; $abbr-border-color: $gray-2 !default; $text-muted: $text-color-weak; diff --git a/packages/grafana-ui/src/themes/_variables.light.scss.tmpl.ts b/packages/grafana-ui/src/themes/_variables.light.scss.tmpl.ts index 1b017b7eb0d..e90299f619c 100644 --- a/packages/grafana-ui/src/themes/_variables.light.scss.tmpl.ts +++ b/packages/grafana-ui/src/themes/_variables.light.scss.tmpl.ts @@ -46,34 +46,34 @@ $orange: ${theme.colors.orange}; $purple: ${theme.colors.purple}; $variable: ${theme.colors.variable}; -$brand-primary: $orange; -$brand-success: $green-base; -$brand-warning: $orange; -$brand-danger: $red-base; +$brand-primary: ${theme.colors.brandPrimary}; +$brand-success: ${theme.colors.brandSuccess}; +$brand-warning: ${theme.colors.brandWarning}; +$brand-danger: ${theme.colors.brandDanger}; -$query-red: $red-base; -$query-green: $green-base; -$query-purple: $purple; -$query-orange: $orange; -$query-keyword: $blue-base; +$query-red: ${theme.colors.queryRed}; +$query-green: ${theme.colors.queryGreen}; +$query-purple: ${theme.colors.queryPurple}; +$query-orange: ${theme.colors.orange}; +$query-keyword: ${theme.colors.queryKeyword}; // Status colors // ------------------------- -$online: $green-shade; -$warn: #f79520; -$critical: $red-shade; +$online: ${theme.colors.online}; +$warn: ${theme.colors.warn}; +$critical: ${theme.colors.critical}; // Scaffolding // ------------------------- $body-bg: ${theme.colors.bodyBg}; $page-bg: ${theme.colors.pageBg}; -$body-color: $gray-1; -$text-color: $gray-1; -$text-color-strong: $dark-1; -$text-color-weak: $gray-2; -$text-color-faint: $gray-4; -$text-color-emphasis: $dark-2; +$body-color: ${theme.colors.body}; +$text-color: ${theme.colors.text}; +$text-color-strong: ${theme.colors.textStrong}; +$text-color-weak: ${theme.colors.textWeak}; +$text-color-faint: ${theme.colors.textFaint}; +$text-color-emphasis: ${theme.colors.textEmphasis}; $text-shadow-faint: none; @@ -85,14 +85,14 @@ $edit-gradient: linear-gradient(-60deg, $gray-7, #f5f6f9 70%, $gray-7 98%); // Links // ------------------------- -$link-color: $gray-1; -$link-color-disabled: lighten($link-color, 30%); -$link-hover-color: darken($link-color, 20%); -$external-link-color: $blue-shade; +$link-color: ${theme.colors.link}; +$link-color-disabled: ${theme.colors.linkDisabled}; +$link-hover-color: ${theme.colors.linkHover}; +$external-link-color: ${theme.colors.linkExternal}; // Typography // ------------------------- -$headings-color: $text-color; +$headings-color: ${theme.colors.headingColor}; $abbr-border-color: $gray-2 !default; $text-muted: $text-color-weak; diff --git a/packages/grafana-ui/src/themes/dark.ts b/packages/grafana-ui/src/themes/dark.ts index 7c3e81a7d35..1e424c97154 100644 --- a/packages/grafana-ui/src/themes/dark.ts +++ b/packages/grafana-ui/src/themes/dark.ts @@ -46,6 +46,10 @@ const darkTheme: GrafanaTheme = { colors: { ...basicColors, inputBlack: '#09090b', + brandPrimary: basicColors.orange, + brandSuccess: basicColors.greenBase, + brandWarning: basicColors.orange, + brandDanger: basicColors.redBase, queryRed: basicColors.redBase, queryGreen: '#74e680', queryPurple: '#fe85fc', @@ -56,16 +60,16 @@ const darkTheme: GrafanaTheme = { critical: basicColors.redBase, bodyBg: basicColors.dark2, pageBg: basicColors.dark2, - bodyColor: basicColors.gray4, - textColor: basicColors.gray4, - textColorStrong: basicColors.white, - textColorWeak: basicColors.gray2, - textColorEmphasis: basicColors.gray5, - textColorFaint: basicColors.dark5, - linkColor: new tinycolor(basicColors.white).darken(11).toString(), - linkColorDisabled: new tinycolor(basicColors.white).darken(11).toString(), - linkColorHover: basicColors.white, - linkColorExternal: basicColors.blue, + body: basicColors.gray4, + text: basicColors.gray4, + textStrong: basicColors.white, + textWeak: basicColors.gray2, + textEmphasis: basicColors.gray5, + textFaint: basicColors.dark5, + link: new tinycolor(basicColors.white).darken(11).toString(), + linkDisabled: new tinycolor(basicColors.white).darken(11).toString(), + linkHover: basicColors.white, + linkExternal: basicColors.blue, headingColor: new tinycolor(basicColors.white).darken(11).toString(), }, background: { diff --git a/packages/grafana-ui/src/themes/light.ts b/packages/grafana-ui/src/themes/light.ts index 7e8f6300d84..a3994fc7458 100644 --- a/packages/grafana-ui/src/themes/light.ts +++ b/packages/grafana-ui/src/themes/light.ts @@ -47,26 +47,30 @@ const lightTheme: GrafanaTheme = { ...basicColors, variable: basicColors.blue, inputBlack: '#09090b', - queryRed: basicColors.red, + brandPrimary: basicColors.orange, + brandSuccess: basicColors.greenBase, + brandWarning: basicColors.orange, + brandDanger: basicColors.redBase, + queryRed: basicColors.redBase, queryGreen: basicColors.greenBase, queryPurple: basicColors.purple, - queryKeyword: basicColors.blue, + queryKeyword: basicColors.blueBase, queryOrange: basicColors.orange, online: basicColors.greenShade, warn: '#f79520', critical: basicColors.redShade, bodyBg: basicColors.gray7, pageBg: basicColors.gray7, - bodyColor: basicColors.gray1, - textColor: basicColors.gray1, - textColorStrong: basicColors.dark2, - textColorWeak: basicColors.gray2, - textColorEmphasis: basicColors.gray5, - textColorFaint: basicColors.dark4, - linkColor: basicColors.gray1, - linkColorDisabled: new tinycolor(basicColors.gray1).lighten(30).toString(), - linkColorHover: new tinycolor(basicColors.gray1).darken(20).toString(), - linkColorExternal: basicColors.blueLight, + body: basicColors.gray1, + text: basicColors.gray1, + textStrong: basicColors.dark2, + textWeak: basicColors.gray2, + textEmphasis: basicColors.gray5, + textFaint: basicColors.dark4, + link: basicColors.gray1, + linkDisabled: new tinycolor(basicColors.gray1).lighten(30).toString(), + linkHover: new tinycolor(basicColors.gray1).darken(20).toString(), + linkExternal: basicColors.blueLight, headingColor: basicColors.gray1, }, background: { diff --git a/packages/grafana-ui/src/types/panel.ts b/packages/grafana-ui/src/types/panel.ts index ae205100c13..260ff78df76 100644 --- a/packages/grafana-ui/src/types/panel.ts +++ b/packages/grafana-ui/src/types/panel.ts @@ -1,8 +1,9 @@ import { ComponentClass } from 'react'; import { TimeSeries, LoadingState, TableData } from './data'; import { TimeRange } from './time'; +import { ScopedVars } from './datasource'; -export type InterpolateFunction = (value: string, format?: string | Function) => string; +export type InterpolateFunction = (value: string, scopedVars?: ScopedVars, format?: string | Function) => string; export interface PanelProps { panelData: PanelData; diff --git a/packages/grafana-ui/src/types/theme.ts b/packages/grafana-ui/src/types/theme.ts index 01886afe3dc..30f1bf4685b 100644 --- a/packages/grafana-ui/src/types/theme.ts +++ b/packages/grafana-ui/src/types/theme.ts @@ -113,25 +113,33 @@ export interface GrafanaTheme extends GrafanaThemeCommons { queryPurple: string; queryKeyword: string; queryOrange: string; + brandPrimary: string; + brandSuccess: string; + brandWarning: string; + brandDanger: string; // Status colors online: string; warn: string; critical: string; + // Link colors + link: string; + linkDisabled: string; + linkHover: string; + linkExternal: string; + + // Text colors + body: string; + text: string; + textStrong: string; + textWeak: string; + textFaint: string; + textEmphasis: string; + // TODO: move to background section bodyBg: string; pageBg: string; - bodyColor: string; - textColor: string; - textColorStrong: string; - textColorWeak: string; - textColorFaint: string; - textColorEmphasis: string; - linkColor: string; - linkColorDisabled: string; - linkColorHover: string; - linkColorExternal: string; headingColor: string; }; } diff --git a/packages/grafana-ui/src/utils/valueFormats/categories.ts b/packages/grafana-ui/src/utils/valueFormats/categories.ts index 806da582bb3..bf89191c04c 100644 --- a/packages/grafana-ui/src/utils/valueFormats/categories.ts +++ b/packages/grafana-ui/src/utils/valueFormats/categories.ts @@ -137,7 +137,7 @@ export const getCategories = (): ValueFormatCategory[] => [ formats: [ { name: 'packets/sec', id: 'pps', fn: decimalSIPrefix('pps') }, { name: 'bits/sec', id: 'bps', fn: decimalSIPrefix('bps') }, - { name: 'bytes/sec', id: 'Bps', fn: decimalSIPrefix('B/s') }, + { name: 'bytes/sec', id: 'Bps', fn: decimalSIPrefix('Bs') }, { name: 'kilobytes/sec', id: 'KBs', fn: decimalSIPrefix('Bs', 1) }, { name: 'kilobits/sec', id: 'Kbits', fn: decimalSIPrefix('bps', 1) }, { name: 'megabytes/sec', id: 'MBs', fn: decimalSIPrefix('Bs', 2) }, diff --git a/pkg/api/dashboard.go b/pkg/api/dashboard.go index f1ad935e621..07c4f75778d 100644 --- a/pkg/api/dashboard.go +++ b/pkg/api/dashboard.go @@ -488,6 +488,7 @@ func (hs *HTTPServer) RestoreDashboardVersion(c *m.ReqContext, apiCmd dtos.Resto saveCmd.Dashboard.Set("version", dash.Version) saveCmd.Dashboard.Set("uid", dash.Uid) saveCmd.Message = fmt.Sprintf("Restored from version %d", version.Version) + saveCmd.FolderId = dash.FolderId return hs.PostDashboard(c, saveCmd) } diff --git a/pkg/api/dashboard_test.go b/pkg/api/dashboard_test.go index 44d5cd32430..923bf57ce8a 100644 --- a/pkg/api/dashboard_test.go +++ b/pkg/api/dashboard_test.go @@ -810,6 +810,93 @@ func TestDashboardApiEndpoint(t *testing.T) { }) }) }) + + Convey("Given dashboard in folder being restored should restore to folder", t, func() { + fakeDash := m.NewDashboard("Child dash") + fakeDash.Id = 2 + fakeDash.FolderId = 1 + fakeDash.HasAcl = false + + bus.AddHandler("test", func(query *m.GetDashboardQuery) error { + query.Result = fakeDash + return nil + }) + + bus.AddHandler("test", func(query *m.GetDashboardVersionQuery) error { + query.Result = &m.DashboardVersion{ + DashboardId: 2, + Version: 1, + Data: fakeDash.Data, + } + return nil + }) + + mock := &dashboards.FakeDashboardService{ + SaveDashboardResult: &m.Dashboard{ + Id: 2, + Uid: "uid", + Title: "Dash", + Slug: "dash", + Version: 1, + }, + } + + cmd := dtos.RestoreDashboardVersionCommand{ + Version: 1, + } + + restoreDashboardVersionScenario("When calling POST on", "/api/dashboards/id/1/restore", "/api/dashboards/id/:dashboardId/restore", mock, cmd, func(sc *scenarioContext) { + CallRestoreDashboardVersion(sc) + So(sc.resp.Code, ShouldEqual, 200) + dto := mock.SavedDashboards[0] + So(dto.Dashboard.FolderId, ShouldEqual, 1) + So(dto.Dashboard.Title, ShouldEqual, "Child dash") + So(dto.Message, ShouldEqual, "Restored from version 1") + }) + }) + + Convey("Given dashboard in general folder being restored should restore to general folder", t, func() { + fakeDash := m.NewDashboard("Child dash") + fakeDash.Id = 2 + fakeDash.HasAcl = false + + bus.AddHandler("test", func(query *m.GetDashboardQuery) error { + query.Result = fakeDash + return nil + }) + + bus.AddHandler("test", func(query *m.GetDashboardVersionQuery) error { + query.Result = &m.DashboardVersion{ + DashboardId: 2, + Version: 1, + Data: fakeDash.Data, + } + return nil + }) + + mock := &dashboards.FakeDashboardService{ + SaveDashboardResult: &m.Dashboard{ + Id: 2, + Uid: "uid", + Title: "Dash", + Slug: "dash", + Version: 1, + }, + } + + cmd := dtos.RestoreDashboardVersionCommand{ + Version: 1, + } + + restoreDashboardVersionScenario("When calling POST on", "/api/dashboards/id/1/restore", "/api/dashboards/id/:dashboardId/restore", mock, cmd, func(sc *scenarioContext) { + CallRestoreDashboardVersion(sc) + So(sc.resp.Code, ShouldEqual, 200) + dto := mock.SavedDashboards[0] + So(dto.Dashboard.FolderId, ShouldEqual, 0) + So(dto.Dashboard.Title, ShouldEqual, "Child dash") + So(dto.Message, ShouldEqual, "Restored from version 1") + }) + }) } func GetDashboardShouldReturn200(sc *scenarioContext) dtos.DashboardFullWithMeta { @@ -871,6 +958,10 @@ func CallPostDashboard(sc *scenarioContext) { sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec() } +func CallRestoreDashboardVersion(sc *scenarioContext) { + sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec() +} + func CallPostDashboardShouldReturnSuccess(sc *scenarioContext) { CallPostDashboard(sc) @@ -928,6 +1019,39 @@ func postDiffScenario(desc string, url string, routePattern string, cmd dtos.Cal }) } +func restoreDashboardVersionScenario(desc string, url string, routePattern string, mock *dashboards.FakeDashboardService, cmd dtos.RestoreDashboardVersionCommand, fn scenarioFunc) { + Convey(desc+" "+url, func() { + defer bus.ClearBusHandlers() + + hs := HTTPServer{ + Bus: bus.GetBus(), + } + + sc := setupScenarioContext(url) + sc.defaultHandler = Wrap(func(c *m.ReqContext) Response { + sc.context = c + sc.context.SignedInUser = &m.SignedInUser{ + OrgId: TestOrgID, + UserId: TestUserID, + } + sc.context.OrgRole = m.ROLE_ADMIN + + return hs.RestoreDashboardVersion(c, cmd) + }) + + origNewDashboardService := dashboards.NewService + dashboards.MockDashboardService(mock) + + sc.m.Post(routePattern, sc.defaultHandler) + + defer func() { + dashboards.NewService = origNewDashboardService + }() + + fn(sc) + }) +} + func (sc *scenarioContext) ToJSON() *simplejson.Json { var result *simplejson.Json err := json.NewDecoder(sc.resp.Body).Decode(&result) diff --git a/pkg/log/log.go b/pkg/log/log.go index 2e3b6303a6e..eb739f855ea 100644 --- a/pkg/log/log.go +++ b/pkg/log/log.go @@ -25,6 +25,7 @@ var filters map[string]log15.Lvl func init() { loggersToClose = make([]DisposableHandler, 0) loggersToReload = make([]ReloadableHandler, 0) + filters = map[string]log15.Lvl{} Root = log15.Root() Root.SetHandler(log15.DiscardHandler()) } @@ -197,7 +198,7 @@ func ReadLoggingConfig(modes []string, logsPath string, cfg *ini.File) { // Log level. _, level := getLogLevelFromConfig("log."+mode, defaultLevelName, cfg) - filters := getFilters(util.SplitString(sec.Key("filters").String())) + modeFilters := getFilters(util.SplitString(sec.Key("filters").String())) format := getLogFormat(sec.Key("format").MustString("")) var handler log15.Handler @@ -230,12 +231,18 @@ func ReadLoggingConfig(modes []string, logsPath string, cfg *ini.File) { } for key, value := range defaultFilters { + if _, exist := modeFilters[key]; !exist { + modeFilters[key] = value + } + } + + for key, value := range modeFilters { if _, exist := filters[key]; !exist { filters[key] = value } } - handler = LogFilterHandler(level, filters, handler) + handler = LogFilterHandler(level, modeFilters, handler) handlers = append(handlers, handler) } diff --git a/pkg/login/ldap.go b/pkg/login/ldap.go index c15cb865bd3..8bb331b7e59 100644 --- a/pkg/login/ldap.go +++ b/pkg/login/ldap.go @@ -18,6 +18,7 @@ import ( type ILdapConn interface { Bind(username, password string) error + UnauthenticatedBind(username string) error Search(*ldap.SearchRequest) (*ldap.SearchResult, error) StartTLS(*tls.Config) error Close() @@ -259,7 +260,17 @@ func (a *ldapAuther) initialBind(username, userPassword string) error { bindPath = fmt.Sprintf(a.server.BindDN, username) } - if err := a.conn.Bind(bindPath, userPassword); err != nil { + bindFn := func() error { + return a.conn.Bind(bindPath, userPassword) + } + + if userPassword == "" { + bindFn = func() error { + return a.conn.UnauthenticatedBind(bindPath) + } + } + + if err := bindFn(); err != nil { a.log.Info("Initial bind failed", "error", err) if ldapErr, ok := err.(*ldap.Error); ok { diff --git a/pkg/login/ldap_test.go b/pkg/login/ldap_test.go index ef20feb1373..dabafee65a6 100644 --- a/pkg/login/ldap_test.go +++ b/pkg/login/ldap_test.go @@ -13,6 +13,70 @@ import ( ) func TestLdapAuther(t *testing.T) { + Convey("initialBind", t, func() { + Convey("Given bind dn and password configured", func() { + conn := &mockLdapConn{} + var actualUsername, actualPassword string + conn.bindProvider = func(username, password string) error { + actualUsername = username + actualPassword = password + return nil + } + ldapAuther := &ldapAuther{ + conn: conn, + server: &LdapServerConf{ + BindDN: "cn=%s,o=users,dc=grafana,dc=org", + BindPassword: "bindpwd", + }, + } + err := ldapAuther.initialBind("user", "pwd") + So(err, ShouldBeNil) + So(ldapAuther.requireSecondBind, ShouldBeTrue) + So(actualUsername, ShouldEqual, "cn=user,o=users,dc=grafana,dc=org") + So(actualPassword, ShouldEqual, "bindpwd") + }) + + Convey("Given bind dn configured", func() { + conn := &mockLdapConn{} + var actualUsername, actualPassword string + conn.bindProvider = func(username, password string) error { + actualUsername = username + actualPassword = password + return nil + } + ldapAuther := &ldapAuther{ + conn: conn, + server: &LdapServerConf{ + BindDN: "cn=%s,o=users,dc=grafana,dc=org", + }, + } + err := ldapAuther.initialBind("user", "pwd") + So(err, ShouldBeNil) + So(ldapAuther.requireSecondBind, ShouldBeFalse) + So(actualUsername, ShouldEqual, "cn=user,o=users,dc=grafana,dc=org") + So(actualPassword, ShouldEqual, "pwd") + }) + + Convey("Given empty bind dn and password", func() { + conn := &mockLdapConn{} + unauthenticatedBindWasCalled := false + var actualUsername string + conn.unauthenticatedBindProvider = func(username string) error { + unauthenticatedBindWasCalled = true + actualUsername = username + return nil + } + ldapAuther := &ldapAuther{ + conn: conn, + server: &LdapServerConf{}, + } + err := ldapAuther.initialBind("user", "pwd") + So(err, ShouldBeNil) + So(ldapAuther.requireSecondBind, ShouldBeTrue) + So(unauthenticatedBindWasCalled, ShouldBeTrue) + So(actualUsername, ShouldBeEmpty) + }) + }) Convey("When translating ldap user to grafana user", t, func() { @@ -365,12 +429,26 @@ func TestLdapAuther(t *testing.T) { } type mockLdapConn struct { - result *ldap.SearchResult - searchCalled bool - searchAttributes []string + result *ldap.SearchResult + searchCalled bool + searchAttributes []string + bindProvider func(username, password string) error + unauthenticatedBindProvider func(username string) error } func (c *mockLdapConn) Bind(username, password string) error { + if c.bindProvider != nil { + return c.bindProvider(username, password) + } + + return nil +} + +func (c *mockLdapConn) UnauthenticatedBind(username string) error { + if c.unauthenticatedBindProvider != nil { + return c.unauthenticatedBindProvider(username) + } + return nil } diff --git a/pkg/services/alerting/notifier.go b/pkg/services/alerting/notifier.go index 2ef5ebbade3..1a717ae2b54 100644 --- a/pkg/services/alerting/notifier.go +++ b/pkg/services/alerting/notifier.go @@ -138,7 +138,7 @@ func (n *notificationService) uploadImage(context *EvalContext) (err error) { return err } - renderOpts.Path = fmt.Sprintf("d-solo/%s/%s?panelId=%d", ref.Uid, ref.Slug, context.Rule.PanelId) + renderOpts.Path = fmt.Sprintf("d-solo/%s/%s?orgId=%d&panelId=%d", ref.Uid, ref.Slug, context.Rule.OrgId, context.Rule.PanelId) result, err := n.renderService.Render(context.Ctx, renderOpts) if err != nil { diff --git a/pkg/services/alerting/notifiers/discord.go b/pkg/services/alerting/notifiers/discord.go index 57d9d438fa2..c7178211f0e 100644 --- a/pkg/services/alerting/notifiers/discord.go +++ b/pkg/services/alerting/notifiers/discord.go @@ -111,57 +111,20 @@ func (this *DiscordNotifier) Notify(evalContext *alerting.EvalContext) error { json, _ := bodyJSON.MarshalJSON() - content_type := "application/json" - - var body []byte - - if embeddedImage { - - var b bytes.Buffer - - w := multipart.NewWriter(&b) - - f, err := os.Open(evalContext.ImageOnDiskPath) - - if err != nil { - this.log.Error("Can't open graph file", err) - return err - } - - defer f.Close() - - fw, err := w.CreateFormField("payload_json") - if err != nil { - return err - } - - if _, err = fw.Write([]byte(string(json))); err != nil { - return err - } - - fw, err = w.CreateFormFile("file", "graph.png") - if err != nil { - return err - } - - if _, err = io.Copy(fw, f); err != nil { - return err - } - - w.Close() - - body = b.Bytes() - content_type = w.FormDataContentType() - - } else { - body = json - } - cmd := &m.SendWebhookSync{ Url: this.WebhookURL, - Body: string(body), HttpMethod: "POST", - ContentType: content_type, + ContentType: "application/json", + } + + if !embeddedImage { + cmd.Body = string(json) + } else { + err := this.embedImage(cmd, evalContext.ImageOnDiskPath, json) + if err != nil { + this.log.Error("failed to embed image", "error", err) + return err + } } if err := bus.DispatchCtx(evalContext.Ctx, cmd); err != nil { @@ -171,3 +134,45 @@ func (this *DiscordNotifier) Notify(evalContext *alerting.EvalContext) error { return nil } + +func (this *DiscordNotifier) embedImage(cmd *m.SendWebhookSync, imagePath string, existingJSONBody []byte) error { + f, err := os.Open(imagePath) + defer f.Close() + if err != nil { + if os.IsNotExist(err) { + cmd.Body = string(existingJSONBody) + return nil + } + if !os.IsNotExist(err) { + return err + } + } + + var b bytes.Buffer + w := multipart.NewWriter(&b) + + fw, err := w.CreateFormField("payload_json") + if err != nil { + return err + } + + if _, err = fw.Write([]byte(string(existingJSONBody))); err != nil { + return err + } + + fw, err = w.CreateFormFile("file", "graph.png") + if err != nil { + return err + } + + if _, err = io.Copy(fw, f); err != nil { + return err + } + + w.Close() + + cmd.Body = string(b.Bytes()) + cmd.ContentType = w.FormDataContentType() + + return nil +} diff --git a/pkg/services/rendering/phantomjs.go b/pkg/services/rendering/phantomjs.go index 1bd7489c153..29c2f39fd77 100644 --- a/pkg/services/rendering/phantomjs.go +++ b/pkg/services/rendering/phantomjs.go @@ -36,7 +36,7 @@ func (rs *RenderingService) renderViaPhantomJS(ctx context.Context, opts Opts) ( defer middleware.RemoveRenderAuthKey(renderKey) phantomDebugArg := "--debug=false" - if log.GetLogLevelFor("renderer") >= log.LvlDebug { + if log.GetLogLevelFor("rendering") >= log.LvlDebug { phantomDebugArg = "--debug=true" } @@ -64,13 +64,26 @@ func (rs *RenderingService) renderViaPhantomJS(ctx context.Context, opts Opts) ( cmd := exec.CommandContext(commandCtx, binPath, cmdArgs...) cmd.Stderr = cmd.Stdout + timezone := "" + if opts.Timezone != "" { + timezone = isoTimeOffsetToPosixTz(opts.Timezone) baseEnviron := os.Environ() - cmd.Env = appendEnviron(baseEnviron, "TZ", isoTimeOffsetToPosixTz(opts.Timezone)) + cmd.Env = appendEnviron(baseEnviron, "TZ", timezone) } + rs.log.Debug("executing Phantomjs", "binPath", binPath, "cmdArgs", cmdArgs, "timezone", timezone) + out, err := cmd.Output() + if out != nil { + rs.log.Debug("Phantomjs output", "out", string(out)) + } + + if err != nil { + rs.log.Debug("Phantomjs error", "error", err) + } + // check for timeout first if commandCtx.Err() == context.DeadlineExceeded { rs.log.Info("Rendering timed out") @@ -82,8 +95,6 @@ func (rs *RenderingService) renderViaPhantomJS(ctx context.Context, opts Opts) ( return nil, err } - rs.log.Debug("Phantomjs output", "out", string(out)) - rs.log.Debug("Image rendered", "path", pngPath) return &RenderResult{FilePath: pngPath}, nil } diff --git a/pkg/services/sqlstore/alert.go b/pkg/services/sqlstore/alert.go index 62ab348664f..7796cfd0dc7 100644 --- a/pkg/services/sqlstore/alert.go +++ b/pkg/services/sqlstore/alert.go @@ -309,7 +309,9 @@ func PauseAlert(cmd *m.PauseAlertCommand) error { params = append(params, v) } - res, err := sess.Exec(buffer.String(), params...) + sqlOrArgs := append([]interface{}{buffer.String()}, params...) + + res, err := sess.Exec(sqlOrArgs...) if err != nil { return err } diff --git a/pkg/services/sqlstore/annotation.go b/pkg/services/sqlstore/annotation.go index 274481baeca..a285b231aae 100644 --- a/pkg/services/sqlstore/annotation.go +++ b/pkg/services/sqlstore/annotation.go @@ -258,11 +258,15 @@ func (r *SqlAnnotationRepo) Delete(params *annotations.DeleteParams) error { queryParams = []interface{}{params.DashboardId, params.PanelId, params.OrgId} } - if _, err := sess.Exec(annoTagSql, queryParams...); err != nil { + sqlOrArgs := append([]interface{}{annoTagSql}, queryParams...) + + if _, err := sess.Exec(sqlOrArgs...); err != nil { return err } - if _, err := sess.Exec(sql, queryParams...); err != nil { + sqlOrArgs = append([]interface{}{sql}, queryParams...) + + if _, err := sess.Exec(sqlOrArgs...); err != nil { return err } diff --git a/pkg/services/sqlstore/dashboard_version.go b/pkg/services/sqlstore/dashboard_version.go index 1f2850b2021..7619e2ab269 100644 --- a/pkg/services/sqlstore/dashboard_version.go +++ b/pkg/services/sqlstore/dashboard_version.go @@ -51,7 +51,7 @@ func GetDashboardVersions(query *m.GetDashboardVersionsQuery) error { dashboard_version.message, dashboard_version.data,`+ dialect.Quote("user")+`.login as created_by`). - Join("LEFT", "user", `dashboard_version.created_by = `+dialect.Quote("user")+`.id`). + Join("LEFT", dialect.Quote("user"), `dashboard_version.created_by = `+dialect.Quote("user")+`.id`). Join("LEFT", "dashboard", `dashboard.id = dashboard_version.dashboard_id`). Where("dashboard_version.dashboard_id=? AND dashboard.org_id=?", query.DashboardId, query.OrgId). OrderBy("dashboard_version.version DESC"). @@ -102,7 +102,8 @@ func DeleteExpiredVersions(cmd *m.DeleteExpiredVersionsCommand) error { if len(versionIdsToDelete) > 0 { deleteExpiredSql := `DELETE FROM dashboard_version WHERE id IN (?` + strings.Repeat(",?", len(versionIdsToDelete)-1) + `)` - expiredResponse, err := sess.Exec(deleteExpiredSql, versionIdsToDelete...) + sqlOrArgs := append([]interface{}{deleteExpiredSql}, versionIdsToDelete...) + expiredResponse, err := sess.Exec(sqlOrArgs...) if err != nil { return err } diff --git a/pkg/services/sqlstore/org_users.go b/pkg/services/sqlstore/org_users.go index abbc320020e..897ef0ea1ad 100644 --- a/pkg/services/sqlstore/org_users.go +++ b/pkg/services/sqlstore/org_users.go @@ -98,7 +98,7 @@ func GetOrgUsers(query *m.GetOrgUsersQuery) error { query.Result = make([]*m.OrgUserDTO, 0) sess := x.Table("org_user") - sess.Join("INNER", "user", fmt.Sprintf("org_user.user_id=%s.id", x.Dialect().Quote("user"))) + sess.Join("INNER", x.Dialect().Quote("user"), fmt.Sprintf("org_user.user_id=%s.id", x.Dialect().Quote("user"))) whereConditions := make([]string, 0) whereParams := make([]interface{}, 0) diff --git a/pkg/services/sqlstore/team.go b/pkg/services/sqlstore/team.go index a3010a086e5..83593e6f2d7 100644 --- a/pkg/services/sqlstore/team.go +++ b/pkg/services/sqlstore/team.go @@ -280,7 +280,7 @@ func RemoveTeamMember(cmd *m.RemoveTeamMemberCommand) error { func GetTeamMembers(query *m.GetTeamMembersQuery) error { query.Result = make([]*m.TeamMemberDTO, 0) sess := x.Table("team_member") - sess.Join("INNER", "user", fmt.Sprintf("team_member.user_id=%s.id", x.Dialect().Quote("user"))) + sess.Join("INNER", x.Dialect().Quote("user"), fmt.Sprintf("team_member.user_id=%s.id", x.Dialect().Quote("user"))) if query.OrgId != 0 { sess.Where("team_member.org_id=?", query.OrgId) } diff --git a/pkg/services/sqlstore/user_test.go b/pkg/services/sqlstore/user_test.go index 526c17a8256..84640687ed9 100644 --- a/pkg/services/sqlstore/user_test.go +++ b/pkg/services/sqlstore/user_test.go @@ -208,7 +208,7 @@ func TestUserDataAccess(t *testing.T) { func GetOrgUsersForTest(query *m.GetOrgUsersQuery) error { query.Result = make([]*m.OrgUserDTO, 0) sess := x.Table("org_user") - sess.Join("LEFT ", "user", fmt.Sprintf("org_user.user_id=%s.id", x.Dialect().Quote("user"))) + sess.Join("LEFT ", x.Dialect().Quote("user"), fmt.Sprintf("org_user.user_id=%s.id", x.Dialect().Quote("user"))) sess.Where("org_user.org_id=?", query.OrgId) sess.Cols("org_user.org_id", "org_user.user_id", "user.email", "user.login", "org_user.role") diff --git a/public/app/core/components/help/help.ts b/public/app/core/components/help/help.ts index 8e8a5ed45d2..7ef54339f49 100644 --- a/public/app/core/components/help/help.ts +++ b/public/app/core/components/help/help.ts @@ -27,6 +27,7 @@ export class HelpCtrl { { keys: ['d', 'C'], description: 'Collapse all rows' }, { keys: ['d', 'a'], description: 'Toggle auto fit panels (experimental feature)' }, { keys: ['mod+o'], description: 'Toggle shared graph crosshair' }, + { keys: ['d', 'l'], description: 'Toggle all panel legends' }, ], 'Focused Panel': [ { keys: ['e'], description: 'Toggle panel edit view' }, diff --git a/public/app/core/controllers/json_editor_ctrl.ts b/public/app/core/controllers/json_editor_ctrl.ts index 7439433c55e..a0384aa8d36 100644 --- a/public/app/core/controllers/json_editor_ctrl.ts +++ b/public/app/core/controllers/json_editor_ctrl.ts @@ -5,7 +5,7 @@ export class JsonEditorCtrl { /** @ngInject */ constructor($scope) { $scope.json = angular.toJson($scope.model.object, true); - $scope.canUpdate = $scope.model.updateHandler !== void 0 && $scope.contextSrv.isEditor; + $scope.canUpdate = $scope.model.updateHandler !== void 0 && $scope.model.canUpdate; $scope.canCopy = $scope.model.enableCopy; $scope.update = () => { diff --git a/public/app/core/services/keybindingSrv.ts b/public/app/core/services/keybindingSrv.ts index 7dab7cffd6f..da096f261c6 100644 --- a/public/app/core/services/keybindingSrv.ts +++ b/public/app/core/services/keybindingSrv.ts @@ -256,6 +256,11 @@ export class KeybindingSrv { } }); + // toggle all panel legends + this.bind('d l', () => { + dashboard.toggleLegendsForAll(); + }); + // collapse all rows this.bind('d shift+c', () => { dashboard.collapseRows(); diff --git a/public/app/features/alerting/partials/alert_tab.html b/public/app/features/alerting/partials/alert_tab.html index b99859fd847..4b31edebe8e 100644 --- a/public/app/features/alerting/partials/alert_tab.html +++ b/public/app/features/alerting/partials/alert_tab.html @@ -17,7 +17,7 @@
- If an alert rule has a configured For and the query violates the configured diff --git a/public/app/features/dashboard/components/AddPanelWidget/AddPanelWidget.tsx b/public/app/features/dashboard/components/AddPanelWidget/AddPanelWidget.tsx index fe04248524a..bdcc3c9d165 100644 --- a/public/app/features/dashboard/components/AddPanelWidget/AddPanelWidget.tsx +++ b/public/app/features/dashboard/components/AddPanelWidget/AddPanelWidget.tsx @@ -100,7 +100,12 @@ export class AddPanelWidget extends React.Component { const newPanel: any = { type: panelPluginInfo.id, title: 'Panel Title', - gridPos: { x: gridPos.x, y: gridPos.y, w: gridPos.w, h: gridPos.h }, + gridPos: { + x: gridPos.x, + y: gridPos.y, + w: panelPluginInfo.defaults.gridPos.w, + h: panelPluginInfo.defaults.gridPos.h, + }, }; // apply panel template / defaults diff --git a/public/app/features/dashboard/dashgrid/PanelChrome.test.tsx b/public/app/features/dashboard/dashgrid/PanelChrome.test.tsx new file mode 100644 index 00000000000..7136a14a907 --- /dev/null +++ b/public/app/features/dashboard/dashgrid/PanelChrome.test.tsx @@ -0,0 +1,35 @@ +import { PanelChrome } from './PanelChrome'; + +jest.mock('sass/_variables.generated.scss', () => ({ + panelhorizontalpadding: 10, + panelVerticalPadding: 10, +})); + +describe('PanelChrome', () => { + let chrome: PanelChrome; + + beforeEach(() => { + chrome = new PanelChrome({ + panel: { + scopedVars: { + aaa: { value: 'AAA', text: 'upperA' }, + bbb: { value: 'BBB', text: 'upperB' }, + }, + }, + dashboard: {}, + plugin: {}, + isFullscreen: false, + }); + }); + + it('Should replace a panel variable', () => { + const out = chrome.replaceVariables('hello $aaa'); + expect(out).toBe('hello AAA'); + }); + + it('But it should prefer the local variable value', () => { + const extra = { aaa: { text: '???', value: 'XXX' } }; + const out = chrome.replaceVariables('hello $aaa and $bbb', extra); + expect(out).toBe('hello XXX and BBB'); + }); +}); diff --git a/public/app/features/dashboard/dashgrid/PanelChrome.tsx b/public/app/features/dashboard/dashgrid/PanelChrome.tsx index 80ce2f39b70..0a9d1d44ceb 100644 --- a/public/app/features/dashboard/dashgrid/PanelChrome.tsx +++ b/public/app/features/dashboard/dashgrid/PanelChrome.tsx @@ -19,6 +19,7 @@ import { profiler } from 'app/core/profiler'; import { DashboardModel, PanelModel } from '../state'; import { PanelPlugin } from 'app/types'; import { DataQueryResponse, TimeRange, LoadingState, PanelData, DataQueryError } from '@grafana/ui'; +import { ScopedVars } from '@grafana/ui'; import variables from 'sass/_variables.generated.scss'; import templateSrv from 'app/features/templating/template_srv'; @@ -85,8 +86,12 @@ export class PanelChrome extends PureComponent { }); }; - replaceVariables = (value: string, format?: string) => { - return templateSrv.replace(value, this.props.panel.scopedVars, format); + replaceVariables = (value: string, extraVars?: ScopedVars, format?: string) => { + let vars = this.props.panel.scopedVars; + if (extraVars) { + vars = vars ? { ...vars, ...extraVars } : extraVars; + } + return templateSrv.replace(value, vars, format); }; onDataResponse = (dataQueryResponse: DataQueryResponse) => { diff --git a/public/app/features/dashboard/panel_editor/VisualizationTab.tsx b/public/app/features/dashboard/panel_editor/VisualizationTab.tsx index 5330baf1be6..884615821eb 100644 --- a/public/app/features/dashboard/panel_editor/VisualizationTab.tsx +++ b/public/app/features/dashboard/panel_editor/VisualizationTab.tsx @@ -14,10 +14,10 @@ import { PluginHelp } from 'app/core/components/PluginHelp/PluginHelp'; import { FadeIn } from 'app/core/components/Animations/FadeIn'; // Types -import { PanelModel } from '../state/PanelModel'; -import { DashboardModel } from '../state/DashboardModel'; +import { PanelModel } from '../state'; +import { DashboardModel } from '../state'; import { PanelPlugin } from 'app/types/plugins'; -import { FilterInput } from 'app/core/components/FilterInput/FilterInput'; +import { VizPickerSearch } from './VizPickerSearch'; interface Props { panel: PanelModel; @@ -33,18 +33,19 @@ interface State { isVizPickerOpen: boolean; searchQuery: string; scrollTop: number; + hasBeenFocused: boolean; } export class VisualizationTab extends PureComponent { element: HTMLElement; angularOptions: AngularComponent; - searchInput: HTMLElement; constructor(props) { super(props); this.state = { isVizPickerOpen: this.props.urlOpenVizPicker, + hasBeenFocused: false, searchQuery: '', scrollTop: 0, }; @@ -162,7 +163,7 @@ export class VisualizationTab extends PureComponent { this.props.updateLocation({ query: { openVizPicker: null }, partial: true }); } - this.setState({ isVizPickerOpen: false }); + this.setState({ isVizPickerOpen: false, hasBeenFocused: false }); }; onSearchQueryChange = (value: string) => { @@ -173,23 +174,16 @@ export class VisualizationTab extends PureComponent { renderToolbar = (): JSX.Element => { const { plugin } = this.props; - const { searchQuery } = this.state; + const { isVizPickerOpen, searchQuery } = this.state; - if (this.state.isVizPickerOpen) { + if (isVizPickerOpen) { return ( - <> - elem && elem.focus()} - /> - - + ); } else { return ( diff --git a/public/app/features/dashboard/panel_editor/VizPickerSearch.tsx b/public/app/features/dashboard/panel_editor/VizPickerSearch.tsx new file mode 100644 index 00000000000..ddf9485dab9 --- /dev/null +++ b/public/app/features/dashboard/panel_editor/VizPickerSearch.tsx @@ -0,0 +1,33 @@ +import React, { PureComponent } from 'react'; + +import { FilterInput } from 'app/core/components/FilterInput/FilterInput'; + +import { PanelPlugin } from 'app/types'; + +interface Props { + plugin: PanelPlugin; + searchQuery: string; + onChange: (query: string) => void; + onClose: () => void; +} + +export class VizPickerSearch extends PureComponent { + render() { + const { searchQuery, onChange, onClose } = this.props; + return ( + <> + element && element.focus()} + /> + + + ); + } +} diff --git a/public/app/features/dashboard/state/DashboardModel.test.ts b/public/app/features/dashboard/state/DashboardModel.test.ts index cd30fc2ecdc..0d18a3b5d12 100644 --- a/public/app/features/dashboard/state/DashboardModel.test.ts +++ b/public/app/features/dashboard/state/DashboardModel.test.ts @@ -635,4 +635,32 @@ describe('DashboardModel', () => { expect(saveModel.templating.list[0].filters[0].value).toBe('server 1'); }); }); + + describe('Given a dashboard with one panel legend on and two off', () => { + let model; + + beforeEach(() => { + const data = { + panels: [ + { id: 1, type: 'graph', gridPos: { x: 0, y: 0, w: 24, h: 2 }, legend: { show: true } }, + { id: 3, type: 'graph', gridPos: { x: 0, y: 4, w: 12, h: 2 }, legend: { show: false } }, + { id: 4, type: 'graph', gridPos: { x: 12, y: 4, w: 12, h: 2 }, legend: { show: false } }, + ], + }; + model = new DashboardModel(data); + }); + + it('toggleLegendsForAll should toggle all legends on on first execution', () => { + model.toggleLegendsForAll(); + const legendsOn = model.panels.filter(panel => panel.legend.show === true); + expect(legendsOn.length).toBe(3); + }); + + it('toggleLegendsForAll should toggle all legends off on second execution', () => { + model.toggleLegendsForAll(); + model.toggleLegendsForAll(); + const legendsOn = model.panels.filter(panel => panel.legend.show === true); + expect(legendsOn.length).toBe(0); + }); + }); }); diff --git a/public/app/features/dashboard/state/DashboardModel.ts b/public/app/features/dashboard/state/DashboardModel.ts index 2a445c9a58c..cde4227d3ec 100644 --- a/public/app/features/dashboard/state/DashboardModel.ts +++ b/public/app/features/dashboard/state/DashboardModel.ts @@ -917,4 +917,20 @@ export class DashboardModel { } } } + + toggleLegendsForAll() { + const panelsWithLegends = this.panels.filter(panel => { + return panel.legend !== undefined && panel.legend !== null; + }); + + // determine if more panels are displaying legends or not + const onCount = panelsWithLegends.filter(panel => panel.legend.show).length; + const offCount = panelsWithLegends.length - onCount; + const panelLegendsOn = onCount >= offCount; + + for (const panel of panelsWithLegends) { + panel.legend.show = !panelLegendsOn; + panel.render(); + } + } } diff --git a/public/app/features/dashboard/state/PanelModel.ts b/public/app/features/dashboard/state/PanelModel.ts index c0739b6d8bc..0c3ab44d8e8 100644 --- a/public/app/features/dashboard/state/PanelModel.ts +++ b/public/app/features/dashboard/state/PanelModel.ts @@ -106,6 +106,7 @@ export class PanelModel { events: Emitter; cacheTimeout?: any; cachedPluginOptions?: any; + legend?: { show: boolean }; constructor(model) { this.events = new Emitter(); diff --git a/public/app/features/dashboard/utils/panel.ts b/public/app/features/dashboard/utils/panel.ts index 0c5d22412f5..d14432cb2eb 100644 --- a/public/app/features/dashboard/utils/panel.ts +++ b/public/app/features/dashboard/utils/panel.ts @@ -70,6 +70,7 @@ export const editPanelJson = (dashboard: DashboardModel, panel: PanelModel) => { updateHandler: (newPanel: PanelModel, oldPanel: PanelModel) => { replacePanel(dashboard, newPanel, oldPanel); }, + canUpdate: dashboard.meta.canEdit, enableCopy: true, }; diff --git a/public/app/features/datasources/partials/http_settings.html b/public/app/features/datasources/partials/http_settings.html index b6f2c4fc0dd..b4cf1084843 100644 --- a/public/app/features/datasources/partials/http_settings.html +++ b/public/app/features/datasources/partials/http_settings.html @@ -4,7 +4,7 @@
URL - @@ -59,7 +59,7 @@
Whitelisted Cookies - + Grafana Proxy deletes forwarded cookies by default. Specify cookies by name that should be forwarded to the data source. diff --git a/public/app/features/explore/LogMessageAnsi.tsx b/public/app/features/explore/LogMessageAnsi.tsx index 53147656d6a..72e15bc38f8 100644 --- a/public/app/features/explore/LogMessageAnsi.tsx +++ b/public/app/features/explore/LogMessageAnsi.tsx @@ -1,5 +1,5 @@ import React, { PureComponent } from 'react'; -import ansicolor from 'ansicolor'; +import ansicolor from 'vendor/ansicolor/ansicolor'; interface Style { [key: string]: string; diff --git a/public/app/features/explore/QueryEditor.tsx b/public/app/features/explore/QueryEditor.tsx index 1d329f1c56e..d158f6bb9f3 100644 --- a/public/app/features/explore/QueryEditor.tsx +++ b/public/app/features/explore/QueryEditor.tsx @@ -43,6 +43,9 @@ export default class QueryEditor extends PureComponent { this.props.onQueryChange(target); this.props.onExecuteQuery(); }, + onQueryChange: () => { + this.props.onQueryChange(target); + }, events: exploreEvents, panel: { datasource, targets: [target] }, dashboard: {}, diff --git a/public/app/features/panel/metrics_panel_ctrl.ts b/public/app/features/panel/metrics_panel_ctrl.ts index ceebfd82335..028585ae21e 100644 --- a/public/app/features/panel/metrics_panel_ctrl.ts +++ b/public/app/features/panel/metrics_panel_ctrl.ts @@ -224,7 +224,7 @@ class MetricsPanelCtrl extends PanelCtrl { items.push({ text: 'Explore', click: 'ctrl.explore();', - icon: 'fa fa-fw fa-rocket', + icon: 'gicon gicon-explore', shortcut: 'x', }); } diff --git a/public/app/features/playlist/playlist_srv.ts b/public/app/features/playlist/playlist_srv.ts index cb2763129ef..97ebfff7320 100644 --- a/public/app/features/playlist/playlist_srv.ts +++ b/public/app/features/playlist/playlist_srv.ts @@ -7,6 +7,7 @@ import coreModule from '../../core/core_module'; import appEvents from 'app/core/app_events'; import locationUtil from 'app/core/utils/location_util'; import kbn from 'app/core/utils/kbn'; +import { store } from 'app/store/store'; export class PlaylistSrv { private cancelPromise: any; @@ -15,6 +16,8 @@ export class PlaylistSrv { private interval: number; private startUrl: string; private numberOfLoops = 0; + private storeUnsub: () => void; + private validPlaylistUrl: string; isPlaying: boolean; /** @ngInject */ @@ -39,15 +42,16 @@ export class PlaylistSrv { const dash = this.dashboards[this.index]; const queryParams = this.$location.search(); const filteredParams = _.pickBy(queryParams, value => value !== null); + const nextDashboardUrl = locationUtil.stripBaseFromUrl(dash.url); // this is done inside timeout to make sure digest happens after // as this can be called from react this.$timeout(() => { - const stripedUrl = locationUtil.stripBaseFromUrl(dash.url); - this.$location.url(stripedUrl + '?' + toUrlParams(filteredParams)); + this.$location.url(nextDashboardUrl + '?' + toUrlParams(filteredParams)); }); this.index++; + this.validPlaylistUrl = nextDashboardUrl; this.cancelPromise = this.$timeout(() => this.next(), this.interval); } @@ -56,6 +60,15 @@ export class PlaylistSrv { this.next(); } + // Detect url changes not caused by playlist srv and stop playlist + storeUpdated() { + const state = store.getState(); + + if (state.location.path !== this.validPlaylistUrl) { + this.stop(); + } + } + start(playlistId) { this.stop(); @@ -63,6 +76,10 @@ export class PlaylistSrv { this.index = 0; this.isPlaying = true; + // setup location tracking + this.storeUnsub = store.subscribe(() => this.storeUpdated()); + this.validPlaylistUrl = this.$location.path(); + appEvents.emit('playlist-started'); return this.backendSrv.get(`/api/playlists/${playlistId}`).then(playlist => { @@ -85,6 +102,10 @@ export class PlaylistSrv { this.index = 0; this.isPlaying = false; + if (this.storeUnsub) { + this.storeUnsub(); + } + if (this.cancelPromise) { this.$timeout.cancel(this.cancelPromise); } diff --git a/public/app/features/playlist/specs/playlist_srv.test.ts b/public/app/features/playlist/specs/playlist_srv.test.ts index bfb1732d9c6..628818fd716 100644 --- a/public/app/features/playlist/specs/playlist_srv.test.ts +++ b/public/app/features/playlist/specs/playlist_srv.test.ts @@ -1,4 +1,14 @@ +import configureMockStore from 'redux-mock-store'; import { PlaylistSrv } from '../playlist_srv'; +import { setStore } from 'app/store/store'; + +const mockStore = configureMockStore(); + +setStore( + mockStore({ + location: {}, + }) +); const dashboards = [{ url: 'dash1' }, { url: 'dash2' }]; @@ -19,6 +29,7 @@ const createPlaylistSrv = (): [PlaylistSrv, { url: jest.MockInstance } const mockLocation = { url: jest.fn(), search: () => ({}), + path: () => '/playlists/1', }; const mockTimeout = jest.fn(); @@ -96,4 +107,32 @@ describe('PlaylistSrv', () => { expect(hrefMock).toHaveBeenCalledTimes(3); expect(hrefMock).toHaveBeenLastCalledWith(initialUrl); }); + + it('storeUpdated should stop playlist when navigating away', async () => { + await srv.start(1); + + srv.storeUpdated(); + + expect(srv.isPlaying).toBe(false); + }); + + it('storeUpdated should not stop playlist when navigating to next dashboard', async () => { + await srv.start(1); + + srv.next(); + + setStore( + mockStore({ + location: { + path: 'dash2', + }, + }) + ); + + expect((srv as any).validPlaylistUrl).toBe('dash2'); + + srv.storeUpdated(); + + expect(srv.isPlaying).toBe(true); + }); }); diff --git a/public/app/features/plugins/partials/plugin_edit.html b/public/app/features/plugins/partials/plugin_edit.html index 16cdfc1d1b2..d84196c47b0 100644 --- a/public/app/features/plugins/partials/plugin_edit.html +++ b/public/app/features/plugins/partials/plugin_edit.html @@ -25,7 +25,7 @@