From 4e57726e96188b69e4bf39f82c761dec6a871eea Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 13 Jul 2023 15:12:48 +0100 Subject: [PATCH 01/42] Update dependency jest-junit to v16 (#71555) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 62f5fe5f53a..2da34ca8ee2 100644 --- a/package.json +++ b/package.json @@ -209,7 +209,7 @@ "jest-date-mock": "1.0.8", "jest-environment-jsdom": "29.3.1", "jest-fail-on-console": "3.1.1", - "jest-junit": "15.0.0", + "jest-junit": "16.0.0", "jest-matcher-utils": "29.3.1", "lerna": "5.5.4", "lint-staged": "13.2.3", diff --git a/yarn.lock b/yarn.lock index 6103dc00782..e9c4bba36eb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -19340,7 +19340,7 @@ __metadata: jest-date-mock: 1.0.8 jest-environment-jsdom: 29.3.1 jest-fail-on-console: 3.1.1 - jest-junit: 15.0.0 + jest-junit: 16.0.0 jest-matcher-utils: 29.3.1 jquery: 3.7.0 js-yaml: ^4.1.0 @@ -21757,15 +21757,15 @@ __metadata: languageName: node linkType: hard -"jest-junit@npm:15.0.0": - version: 15.0.0 - resolution: "jest-junit@npm:15.0.0" +"jest-junit@npm:16.0.0": + version: 16.0.0 + resolution: "jest-junit@npm:16.0.0" dependencies: mkdirp: ^1.0.4 strip-ansi: ^6.0.1 uuid: ^8.3.2 xml: ^1.0.1 - checksum: e8fe4d2f2ab843383ac41820a6fe495739d154ec435cd44ba590b44ec7fd62095676f3eef13f98392f81d4a3727ea58b4f4fad231fe367ac31243952b9ad716f + checksum: 412aa4bfeec4254a9b34f417fda79107c7cbd295e56ffeb299ac9c977545910fbabe57c91c6cd1f12b700d4a1f60f79872b0075003f02da87d463e30fc2d9d78 languageName: node linkType: hard From e9e2d9ff83591038ac0ef9055f63386322f24cf8 Mon Sep 17 00:00:00 2001 From: Selene Date: Thu, 13 Jul 2023 16:29:38 +0200 Subject: [PATCH 02/42] Core: Update thema, cuetsy and cue fork (#71527) * Update cue fork * Update dashboard schema * Fix lint --- .../kinds/core/dashboard/schema-reference.md | 10 +++++----- go.mod | 10 +++++----- go.sum | 12 ++++++------ pkg/codegen/jenny_tsveneerindex.go | 4 ++-- pkg/kinds/dashboard/dashboard_spec_gen.go | 4 ++-- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/docs/sources/developers/kinds/core/dashboard/schema-reference.md b/docs/sources/developers/kinds/core/dashboard/schema-reference.md index 17b617d931f..8b3206a752e 100644 --- a/docs/sources/developers/kinds/core/dashboard/schema-reference.md +++ b/docs/sources/developers/kinds/core/dashboard/schema-reference.md @@ -301,11 +301,11 @@ For example, if a value is within a certain range, you can configure a range val Range to match against and the result to apply when the value is within the range -| Property | Type | Required | Default | Description | -|----------|-------------------------------------------|----------|---------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `from` | number or null | **Yes** | | Min value of the range. It can be null which means -Infinity
Constraint: `>=-1.797693134862315708145274237317043567981E+308 & <=1.797693134862315708145274237317043567981E+308`. | -| `result` | [ValueMappingResult](#valuemappingresult) | **Yes** | | Result used as replacement with text and color when the value matches | -| `to` | number or null | **Yes** | | Max value of the range. It can be null which means +Infinity
Constraint: `>=-1.797693134862315708145274237317043567981E+308 & <=1.797693134862315708145274237317043567981E+308`. | +| Property | Type | Required | Default | Description | +|----------|-------------------------------------------|----------|---------|-----------------------------------------------------------------------| +| `from` | number or null | **Yes** | | Min value of the range. It can be null which means -Infinity | +| `result` | [ValueMappingResult](#valuemappingresult) | **Yes** | | Result used as replacement with text and color when the value matches | +| `to` | number or null | **Yes** | | Max value of the range. It can be null which means +Infinity | ### ValueMappingResult diff --git a/go.mod b/go.mod index 3d1ab434046..4d257ebf0ed 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ replace github.com/denisenkom/go-mssqldb => github.com/grafana/go-mssqldb v0.9.2 replace github.com/docker/docker => github.com/moby/moby v23.0.4+incompatible // contains openapi encoder fixes. remove ASAP -replace cuelang.org/go => github.com/sdboyer/cue v0.5.0-beta.2.0.20230419165817-251c3ae823d8 +replace cuelang.org/go => github.com/sdboyer/cue v0.5.0-beta.2.0.20230712135403-bdc4772ae055 // For some insane reason, client-go seems to have a broken v12.0.0 tag on it that forces us to // hoist a replace statement. @@ -59,7 +59,7 @@ require ( github.com/google/wire v0.5.0 github.com/gorilla/websocket v1.5.0 github.com/grafana/alerting v0.0.0-20230606080147-55b8d71c7890 - github.com/grafana/cuetsy v0.1.9 + github.com/grafana/cuetsy v0.1.10 github.com/grafana/grafana-aws-sdk v0.15.0 github.com/grafana/grafana-azure-sdk-go v1.7.0 github.com/grafana/grafana-plugin-sdk-go v0.165.0 @@ -122,7 +122,7 @@ require ( gopkg.in/mail.v2 v2.3.1 gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 - xorm.io/builder v0.3.6 + xorm.io/builder v0.3.6 // indirect xorm.io/core v0.7.3 xorm.io/xorm v0.8.2 ) @@ -176,7 +176,7 @@ require ( github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-msgpack v0.5.5 // indirect - github.com/hashicorp/go-multierror v1.1.1 + github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-sockaddr v1.0.2 // indirect github.com/hashicorp/golang-lru v0.6.0 // indirect github.com/hashicorp/yamux v0.1.1 // indirect @@ -264,7 +264,7 @@ require ( github.com/grafana/dataplane/sdata v0.0.6 github.com/grafana/go-mssqldb v0.9.1 github.com/grafana/kindsys v0.0.0-20230508162304-452481b63482 - github.com/grafana/thema v0.0.0-20230615161902-b6e21996aef8 + github.com/grafana/thema v0.0.0-20230712153715-375c1b45f3ed github.com/ory/fosite v0.44.1-0.20230317114349-45a6785cc54f github.com/redis/go-redis/v9 v9.0.2 github.com/weaveworks/common v0.0.0-20230511094633-334485600903 diff --git a/go.sum b/go.sum index eadef68c59a..f89e304492b 100644 --- a/go.sum +++ b/go.sum @@ -1360,8 +1360,8 @@ github.com/grafana/alerting v0.0.0-20230606080147-55b8d71c7890 h1:ubNIgVGX4PQ9YI github.com/grafana/alerting v0.0.0-20230606080147-55b8d71c7890/go.mod h1:zEflOvMVchYhRbFb5ziXVR/JG67FOLBzQTjhHh9xaI4= github.com/grafana/codejen v0.0.3 h1:tAWxoTUuhgmEqxJPOLtJoxlPBbMULFwKFOcRsPRPXDw= github.com/grafana/codejen v0.0.3/go.mod h1:zmwwM/DRyQB7pfuBjTWII3CWtxcXh8LTwAYGfDfpR6s= -github.com/grafana/cuetsy v0.1.9 h1:EwT8BqHoC0B3B4Y6Lg/D1aeYUKnQC1+2jjOHNsOuUfU= -github.com/grafana/cuetsy v0.1.9/go.mod h1:Ix97+CPD8ws9oSSxR3/Lf4ahU1I4Np83kjJmDVnLZvc= +github.com/grafana/cuetsy v0.1.10 h1:+W9/7roI8LorL+D1RJhKGdhsTZ81adrK9dHS0r7qsXs= +github.com/grafana/cuetsy v0.1.10/go.mod h1:Ix97+CPD8ws9oSSxR3/Lf4ahU1I4Np83kjJmDVnLZvc= github.com/grafana/dataplane/examples v0.0.0-20230404174214-4d6fd58a18ad h1:bROIOQEkRlxAt+Epn9Pos8ytkVqoIAvnaUZOAb7EgEU= github.com/grafana/dataplane/examples v0.0.0-20230404174214-4d6fd58a18ad/go.mod h1:h5YwY8s407/17XF5/dS8XrUtsTVV2RnuW8+m1Mp46mg= github.com/grafana/dataplane/sdata v0.0.6 h1:Ejlj8d1Hvy/uDLeI4sOvL34Y8WLlVDd9iN270F+8aTw= @@ -1394,8 +1394,8 @@ github.com/grafana/saml v0.4.13-0.20230331080031-67cbfa09c7b6 h1:oHn/OOUkECNX06D github.com/grafana/saml v0.4.13-0.20230331080031-67cbfa09c7b6/go.mod h1:igEejV+fihTIlHXYP8zOec3V5A8y3lws5bQBFsTm4gA= github.com/grafana/sqlds/v2 v2.3.10 h1:HWKhE0vR6LoEiE+Is8CSZOgaB//D1yqb2ntkass9Fd4= github.com/grafana/sqlds/v2 v2.3.10/go.mod h1:c6ibxnxRVGxV/0YkEgvy7QpQH/lyifFyV7K/14xvdIs= -github.com/grafana/thema v0.0.0-20230615161902-b6e21996aef8 h1:ESVwKjvGWVucGY65rJq0Hny3a6p8UYqEbClqXhP2qJk= -github.com/grafana/thema v0.0.0-20230615161902-b6e21996aef8/go.mod h1:KWAKeFXxQYiJ/kBVbijBLRVq9atxkfkeeFIvmj4clEA= +github.com/grafana/thema v0.0.0-20230712153715-375c1b45f3ed h1:TMtHc+B0SSNw2in6Ro1dAiBYSPRp4NzKgndFDfupt18= +github.com/grafana/thema v0.0.0-20230712153715-375c1b45f3ed/go.mod h1:3zLJnssFRPCnebCBRlq53t5LgYv9P1mbj0XMozZMTww= github.com/grafana/xorm v0.8.3-0.20220614223926-2fcda7565af6 h1:I9dh1MXGX0wGyxdV/Sl7+ugnki4Dfsy8lv2s5Yf887o= github.com/grafana/xorm v0.8.3-0.20220614223926-2fcda7565af6/go.mod h1:ZkJLEYLoVyg7amJK/5r779bHyzs2AU8f8VMiP6BM7uY= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= @@ -2247,8 +2247,8 @@ github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdh github.com/scaleway/scaleway-sdk-go v1.0.0-beta.14 h1:yFl3jyaSVLNYXlnNYM5z2pagEk1dYQhfr1p20T1NyKY= github.com/scaleway/scaleway-sdk-go v1.0.0-beta.14/go.mod h1:fCa7OJZ/9DRTnOKmxvT6pn+LPWUptQAmHF/SBJUGEcg= github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g= -github.com/sdboyer/cue v0.5.0-beta.2.0.20230419165817-251c3ae823d8 h1:R7AphSCwo1rqpRCftz9wn2azIGAtdgn1AjxTiSdFJ1o= -github.com/sdboyer/cue v0.5.0-beta.2.0.20230419165817-251c3ae823d8/go.mod h1:okjJBHFQFer+a41sAe2SaGm1glWS8oEb6CmJvn5Zdws= +github.com/sdboyer/cue v0.5.0-beta.2.0.20230712135403-bdc4772ae055 h1:ilCOPMIGucstzXKgCVzAT8g6tu+Ejyk0J1HhXZN2xm0= +github.com/sdboyer/cue v0.5.0-beta.2.0.20230712135403-bdc4772ae055/go.mod h1:okjJBHFQFer+a41sAe2SaGm1glWS8oEb6CmJvn5Zdws= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/seatgeek/logrus-gelf-formatter v0.0.0-20210219220335-367fa274be2c/go.mod h1:/THDZYi7F/BsVEcYzYPqdcWFQ+1C2InkawTKfLOAnzg= diff --git a/pkg/codegen/jenny_tsveneerindex.go b/pkg/codegen/jenny_tsveneerindex.go index b3dc445a832..06981281148 100644 --- a/pkg/codegen/jenny_tsveneerindex.go +++ b/pkg/codegen/jenny_tsveneerindex.go @@ -150,7 +150,7 @@ func (gen *genTSVeneerIndex) extractTSIndexVeneerElements(def kindsys.Kind, tf * return nil, terr } - vpath := fmt.Sprintf("v%v", thema.LatestVersion(lin)[0]) + vpath := fmt.Sprintf("v%v", thema.Lineage.Latest(lin).Version()) if def.Props().Common().Maturity.Less(kindsys.MaturityStable) { vpath = "x" } @@ -182,7 +182,7 @@ func (gen *genTSVeneerIndex) extractTSIndexVeneerElements(def kindsys.Kind, tf * // and exports all the symbols in the list. // // TODO generate code such that tsc enforces type compatibility between raw and veneer decls`, - lin.Name(), thema.LatestVersion(lin), filepath.ToSlash(filepath.Join(gen.dir, vtfile))) + lin.Name(), thema.Lineage.Latest(lin).Version(), filepath.ToSlash(filepath.Join(gen.dir, vtfile))) customComments := []ast.Comment{{Text: customstr}} if len(custom) > 0 { diff --git a/pkg/kinds/dashboard/dashboard_spec_gen.go b/pkg/kinds/dashboard/dashboard_spec_gen.go index dfeac2c4409..437e9ec96b9 100644 --- a/pkg/kinds/dashboard/dashboard_spec_gen.go +++ b/pkg/kinds/dashboard/dashboard_spec_gen.go @@ -612,13 +612,13 @@ type RangeMap struct { // Range to match against and the result to apply when the value is within the range Options struct { // Min value of the range. It can be null which means -Infinity - From *float32 `json:"from"` + From *float64 `json:"from"` // Result used as replacement with text and color when the value matches Result ValueMappingResult `json:"result"` // Max value of the range. It can be null which means +Infinity - To *float32 `json:"to"` + To *float64 `json:"to"` } `json:"options"` Type RangeMapType `json:"type"` } From d4a8bb69585ffe8f43d5439a79785ac2afa6e661 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 13 Jul 2023 15:32:15 +0100 Subject: [PATCH 03/42] Update emotion monorepo (#71573) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 6 +- packages/grafana-ui/package.json | 4 +- yarn.lock | 171 ++++++++++++++++--------------- 3 files changed, 95 insertions(+), 86 deletions(-) diff --git a/package.json b/package.json index 2da34ca8ee2..73b06fb9c0d 100644 --- a/package.json +++ b/package.json @@ -100,7 +100,7 @@ "@betterer/cli": "5.4.0", "@betterer/eslint": "5.4.0", "@betterer/regexp": "5.4.0", - "@emotion/eslint-plugin": "11.10.0", + "@emotion/eslint-plugin": "11.11.0", "@grafana/e2e": "workspace:*", "@grafana/eslint-config": "5.1.0", "@grafana/eslint-plugin": "link:./packages/grafana-eslint-rules", @@ -254,8 +254,8 @@ }, "dependencies": { "@daybrush/utils": "1.13.0", - "@emotion/css": "11.10.6", - "@emotion/react": "11.10.6", + "@emotion/css": "11.11.2", + "@emotion/react": "11.11.1", "@glideapps/glide-data-grid": "^5.2.1", "@grafana/aws-sdk": "0.0.44", "@grafana/data": "workspace:*", diff --git a/packages/grafana-ui/package.json b/packages/grafana-ui/package.json index 64c838ffe1e..daeac7c5d03 100644 --- a/packages/grafana-ui/package.json +++ b/packages/grafana-ui/package.json @@ -47,8 +47,8 @@ "not IE 11" ], "dependencies": { - "@emotion/css": "11.10.6", - "@emotion/react": "11.10.6", + "@emotion/css": "11.11.2", + "@emotion/react": "11.11.1", "@grafana/data": "10.1.0-pre", "@grafana/e2e-selectors": "10.1.0-pre", "@grafana/faro-web-sdk": "1.1.0", diff --git a/yarn.lock b/yarn.lock index e9c4bba36eb..7f072277950 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2696,22 +2696,22 @@ __metadata: languageName: node linkType: hard -"@emotion/babel-plugin@npm:^11.10.6": - version: 11.10.6 - resolution: "@emotion/babel-plugin@npm:11.10.6" +"@emotion/babel-plugin@npm:^11.11.0": + version: 11.11.0 + resolution: "@emotion/babel-plugin@npm:11.11.0" dependencies: "@babel/helper-module-imports": ^7.16.7 "@babel/runtime": ^7.18.3 - "@emotion/hash": ^0.9.0 - "@emotion/memoize": ^0.8.0 - "@emotion/serialize": ^1.1.1 + "@emotion/hash": ^0.9.1 + "@emotion/memoize": ^0.8.1 + "@emotion/serialize": ^1.1.2 babel-plugin-macros: ^3.1.0 convert-source-map: ^1.5.0 escape-string-regexp: ^4.0.0 find-root: ^1.1.0 source-map: ^0.5.7 - stylis: 4.1.3 - checksum: 3eed138932e8edf2598352e69ad949b9db3051a4d6fcff190dacbac9aa838d7ef708b9f3e6c48660625d9311dae82d73477ae4e7a31139feef5eb001a5528421 + stylis: 4.2.0 + checksum: 6b363edccc10290f7a23242c06f88e451b5feb2ab94152b18bb8883033db5934fb0e421e2d67d09907c13837c21218a3ac28c51707778a54d6cd3706c0c2f3f9 languageName: node linkType: hard @@ -2749,16 +2749,16 @@ __metadata: languageName: node linkType: hard -"@emotion/cache@npm:^11.10.5": - version: 11.10.5 - resolution: "@emotion/cache@npm:11.10.5" +"@emotion/cache@npm:^11.11.0": + version: 11.11.0 + resolution: "@emotion/cache@npm:11.11.0" dependencies: - "@emotion/memoize": ^0.8.0 - "@emotion/sheet": ^1.2.1 - "@emotion/utils": ^1.2.0 - "@emotion/weak-memoize": ^0.3.0 - stylis: 4.1.3 - checksum: 1dd2d9af2d3ecbd3d4469ecdf91a335eef6034c851b57a474471b2d2280613eb35bbed98c0368cc4625f188619fbdaf04cf07e8107aaffce94b2178444c0fe7b + "@emotion/memoize": ^0.8.1 + "@emotion/sheet": ^1.2.2 + "@emotion/utils": ^1.2.1 + "@emotion/weak-memoize": ^0.3.1 + stylis: 4.2.0 + checksum: 8eb1dc22beaa20c21a2e04c284d5a2630a018a9d51fb190e52de348c8d27f4e8ca4bbab003d68b4f6cd9cc1c569ca747a997797e0f76d6c734a660dc29decf08 languageName: node linkType: hard @@ -2788,25 +2788,25 @@ __metadata: languageName: node linkType: hard -"@emotion/css@npm:11.10.6": - version: 11.10.6 - resolution: "@emotion/css@npm:11.10.6" +"@emotion/css@npm:11.11.2": + version: 11.11.2 + resolution: "@emotion/css@npm:11.11.2" dependencies: - "@emotion/babel-plugin": ^11.10.6 - "@emotion/cache": ^11.10.5 - "@emotion/serialize": ^1.1.1 - "@emotion/sheet": ^1.2.1 - "@emotion/utils": ^1.2.0 - checksum: 010ca5e1d0434923c431eab2c6f8226ab4415310a053ece6e4133011c7dc621de099469e57314b013e682c3b6ffd09a91cc6473538c185095d2afca79d81fb95 + "@emotion/babel-plugin": ^11.11.0 + "@emotion/cache": ^11.11.0 + "@emotion/serialize": ^1.1.2 + "@emotion/sheet": ^1.2.2 + "@emotion/utils": ^1.2.1 + checksum: 1edea109dfc31005243334bc351ba127220ea5c4986225e0f1b8f7aa71fb2f83fb8f51d8f5b8afb8432d4c6397c23f5061038449f2876888eecc6eac1dd2f0da languageName: node linkType: hard -"@emotion/eslint-plugin@npm:11.10.0": - version: 11.10.0 - resolution: "@emotion/eslint-plugin@npm:11.10.0" +"@emotion/eslint-plugin@npm:11.11.0": + version: 11.11.0 + resolution: "@emotion/eslint-plugin@npm:11.11.0" peerDependencies: eslint: 6 || 7 || 8 - checksum: b848600bbd047a5100e541369ab56ee84f7a4fae59f811b3835ba686c5b35d0c564953f946c9912d98df0e70fa5533b574f629aa10791e02bcd268263ff7adf1 + checksum: 2d555b6790700e0d0c2862d4aa2fd697ea5851faa7e406ab459028e66daad2ee0dc3dec29362c2edc2656a63f826ac15629112d3e9aca64323fa40f9e5674bd4 languageName: node linkType: hard @@ -2817,10 +2817,10 @@ __metadata: languageName: node linkType: hard -"@emotion/hash@npm:^0.9.0": - version: 0.9.0 - resolution: "@emotion/hash@npm:0.9.0" - checksum: b63428f7c8186607acdca5d003700cecf0ded519d0b5c5cc3b3154eafcad6ff433f8361bd2bac8882715b557e6f06945694aeb6ba8b25c6095d7a88570e2e0bb +"@emotion/hash@npm:^0.9.1": + version: 0.9.1 + resolution: "@emotion/hash@npm:0.9.1" + checksum: 716e17e48bf9047bf9383982c071de49f2615310fb4e986738931776f5a823bc1f29c84501abe0d3df91a3803c80122d24e28b57351bca9e01356ebb33d89876 languageName: node linkType: hard @@ -2838,31 +2838,31 @@ __metadata: languageName: node linkType: hard -"@emotion/memoize@npm:^0.8.0": - version: 0.8.0 - resolution: "@emotion/memoize@npm:0.8.0" - checksum: c87bb110b829edd8e1c13b90a6bc37cebc39af29c7599a1e66a48e06f9bec43e8e53495ba86278cc52e7589549492c8dfdc81d19f4fdec0cee6ba13d2ad2c928 +"@emotion/memoize@npm:^0.8.1": + version: 0.8.1 + resolution: "@emotion/memoize@npm:0.8.1" + checksum: a19cc01a29fcc97514948eaab4dc34d8272e934466ed87c07f157887406bc318000c69ae6f813a9001c6a225364df04249842a50e692ef7a9873335fbcc141b0 languageName: node linkType: hard -"@emotion/react@npm:11.10.6": - version: 11.10.6 - resolution: "@emotion/react@npm:11.10.6" +"@emotion/react@npm:11.11.1": + version: 11.11.1 + resolution: "@emotion/react@npm:11.11.1" dependencies: "@babel/runtime": ^7.18.3 - "@emotion/babel-plugin": ^11.10.6 - "@emotion/cache": ^11.10.5 - "@emotion/serialize": ^1.1.1 - "@emotion/use-insertion-effect-with-fallbacks": ^1.0.0 - "@emotion/utils": ^1.2.0 - "@emotion/weak-memoize": ^0.3.0 + "@emotion/babel-plugin": ^11.11.0 + "@emotion/cache": ^11.11.0 + "@emotion/serialize": ^1.1.2 + "@emotion/use-insertion-effect-with-fallbacks": ^1.0.1 + "@emotion/utils": ^1.2.1 + "@emotion/weak-memoize": ^0.3.1 hoist-non-react-statics: ^3.3.1 peerDependencies: react: ">=16.8.0" peerDependenciesMeta: "@types/react": optional: true - checksum: 4762042e39126ffaffe76052dc65c9bb0ba6b8893013687ba3cc13ed4dd834c31597f1230684c3c078e90aecc13ab6cd0e3cde0dec8b7761affd2571f4d80019 + checksum: aec3c36650f5f0d3d4445ff44d73dd88712b1609645b6af3e6d08049cfbc51f1785fe13dea1a1d4ab1b0800d68f2339ab11e459687180362b1ef98863155aae5 languageName: node linkType: hard @@ -2928,16 +2928,16 @@ __metadata: languageName: node linkType: hard -"@emotion/serialize@npm:^1.1.1": - version: 1.1.1 - resolution: "@emotion/serialize@npm:1.1.1" +"@emotion/serialize@npm:^1.1.2": + version: 1.1.2 + resolution: "@emotion/serialize@npm:1.1.2" dependencies: - "@emotion/hash": ^0.9.0 - "@emotion/memoize": ^0.8.0 - "@emotion/unitless": ^0.8.0 - "@emotion/utils": ^1.2.0 + "@emotion/hash": ^0.9.1 + "@emotion/memoize": ^0.8.1 + "@emotion/unitless": ^0.8.1 + "@emotion/utils": ^1.2.1 csstype: ^3.0.2 - checksum: 24cfd5b16e6f2335c032ca33804a876e0442aaf8f9c94d269d23735ebd194fb1ed142542dd92191a3e6ef8bad5bd560dfc5aaf363a1b70954726dbd4dd93085c + checksum: 413c352e657f1b5e27ea6437b3ef7dcc3860669b7ae17fd5c18bfbd44e033af1acc56b64d252284a813ca4f3b3e1b0841c42d3fb08e02d2df56fd3cd63d72986 languageName: node linkType: hard @@ -2962,10 +2962,10 @@ __metadata: languageName: node linkType: hard -"@emotion/sheet@npm:^1.2.1": - version: 1.2.1 - resolution: "@emotion/sheet@npm:1.2.1" - checksum: ce78763588ea522438156344d9f592203e2da582d8d67b32e1b0b98eaba26994c6c270f8c7ad46442fc9c0a9f048685d819cd73ca87e544520fd06f0e24a1562 +"@emotion/sheet@npm:^1.2.2": + version: 1.2.2 + resolution: "@emotion/sheet@npm:1.2.2" + checksum: d973273c9c15f1c291ca2269728bf044bd3e92a67bca87943fa9ec6c3cd2b034f9a6bfe95ef1b5d983351d128c75b547b43ff196a00a3875f7e1d269793cecfe languageName: node linkType: hard @@ -2983,10 +2983,10 @@ __metadata: languageName: node linkType: hard -"@emotion/unitless@npm:^0.8.0": - version: 0.8.0 - resolution: "@emotion/unitless@npm:0.8.0" - checksum: 176141117ed23c0eb6e53a054a69c63e17ae532ec4210907a20b2208f91771821835f1c63dd2ec63e30e22fcc984026d7f933773ee6526dd038e0850919fae7a +"@emotion/unitless@npm:^0.8.1": + version: 0.8.1 + resolution: "@emotion/unitless@npm:0.8.1" + checksum: 385e21d184d27853bb350999471f00e1429fa4e83182f46cd2c164985999d9b46d558dc8b9cc89975cb337831ce50c31ac2f33b15502e85c299892e67e7b4a88 languageName: node linkType: hard @@ -2999,6 +2999,15 @@ __metadata: languageName: node linkType: hard +"@emotion/use-insertion-effect-with-fallbacks@npm:^1.0.1": + version: 1.0.1 + resolution: "@emotion/use-insertion-effect-with-fallbacks@npm:1.0.1" + peerDependencies: + react: ">=16.8.0" + checksum: 700b6e5bbb37a9231f203bb3af11295eed01d73b2293abece0bc2a2237015e944d7b5114d4887ad9a79776504aa51ed2a8b0ddbc117c54495dd01a6b22f93786 + languageName: node + linkType: hard + "@emotion/utils@npm:0.11.3": version: 0.11.3 resolution: "@emotion/utils@npm:0.11.3" @@ -3020,10 +3029,10 @@ __metadata: languageName: node linkType: hard -"@emotion/utils@npm:^1.2.0": - version: 1.2.0 - resolution: "@emotion/utils@npm:1.2.0" - checksum: 55457a49ddd4db6a014ea0454dc09eaa23eedfb837095c8ff90470cb26a303f7ceb5fcc1e2190ef64683e64cfd33d3ba3ca3109cd87d12bc9e379e4195c9a4dd +"@emotion/utils@npm:^1.2.1": + version: 1.2.1 + resolution: "@emotion/utils@npm:1.2.1" + checksum: e0b44be0705b56b079c55faff93952150be69e79b660ae70ddd5b6e09fc40eb1319654315a9f34bb479d7f4ec94be6068c061abbb9e18b9778ae180ad5d97c73 languageName: node linkType: hard @@ -3034,10 +3043,10 @@ __metadata: languageName: node linkType: hard -"@emotion/weak-memoize@npm:^0.3.0": - version: 0.3.0 - resolution: "@emotion/weak-memoize@npm:0.3.0" - checksum: f43ef4c8b7de70d9fa5eb3105921724651e4188e895beb71f0c5919dc899a7b8743e1fdd99d38b9092dd5722c7be2312ebb47fbdad0c4e38bea58f6df5885cc0 +"@emotion/weak-memoize@npm:^0.3.1": + version: 0.3.1 + resolution: "@emotion/weak-memoize@npm:0.3.1" + checksum: b2be47caa24a8122622ea18cd2d650dbb4f8ad37b636dc41ed420c2e082f7f1e564ecdea68122b546df7f305b159bf5ab9ffee872abd0f052e687428459af594 languageName: node linkType: hard @@ -4118,8 +4127,8 @@ __metadata: resolution: "@grafana/ui@workspace:packages/grafana-ui" dependencies: "@babel/core": 7.22.1 - "@emotion/css": 11.10.6 - "@emotion/react": 11.10.6 + "@emotion/css": 11.11.2 + "@emotion/react": 11.11.1 "@grafana/data": 10.1.0-pre "@grafana/e2e-selectors": 10.1.0-pre "@grafana/faro-web-sdk": 1.1.0 @@ -19146,9 +19155,9 @@ __metadata: "@betterer/eslint": 5.4.0 "@betterer/regexp": 5.4.0 "@daybrush/utils": 1.13.0 - "@emotion/css": 11.10.6 - "@emotion/eslint-plugin": 11.10.0 - "@emotion/react": 11.10.6 + "@emotion/css": 11.11.2 + "@emotion/eslint-plugin": 11.11.0 + "@emotion/react": 11.11.1 "@glideapps/glide-data-grid": ^5.2.1 "@grafana/aws-sdk": 0.0.44 "@grafana/data": "workspace:*" @@ -30829,10 +30838,10 @@ __metadata: languageName: node linkType: hard -"stylis@npm:4.1.3": - version: 4.1.3 - resolution: "stylis@npm:4.1.3" - checksum: d04dbffcb9bf2c5ca8d8dc09534203c75df3bf711d33973ea22038a99cc475412a350b661ebd99cbc01daa50d7eedcf0d130d121800eb7318759a197023442a6 +"stylis@npm:4.2.0": + version: 4.2.0 + resolution: "stylis@npm:4.2.0" + checksum: 0eb6cc1b866dc17a6037d0a82ac7fa877eba6a757443e79e7c4f35bacedbf6421fadcab4363b39667b43355cbaaa570a3cde850f776498e5450f32ed2f9b7584 languageName: node linkType: hard From 0149df741b6ab830a11a210b0e43ba9d95b86c55 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 13 Jul 2023 14:48:28 +0000 Subject: [PATCH 04/42] Update dependency @rollup/plugin-json to v6 (#71577) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- packages/grafana-data/package.json | 2 +- packages/grafana-schema/package.json | 2 +- yarn.lock | 12 ++++++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/grafana-data/package.json b/packages/grafana-data/package.json index df0173b7fa4..be1a5552d7b 100644 --- a/packages/grafana-data/package.json +++ b/packages/grafana-data/package.json @@ -63,7 +63,7 @@ "devDependencies": { "@grafana/tsconfig": "^1.2.0-rc1", "@rollup/plugin-commonjs": "23.0.2", - "@rollup/plugin-json": "5.0.1", + "@rollup/plugin-json": "6.0.0", "@rollup/plugin-node-resolve": "15.1.0", "@testing-library/dom": "9.3.0", "@testing-library/jest-dom": "5.16.5", diff --git a/packages/grafana-schema/package.json b/packages/grafana-schema/package.json index f48a0fe1759..624535944e4 100644 --- a/packages/grafana-schema/package.json +++ b/packages/grafana-schema/package.json @@ -38,7 +38,7 @@ "devDependencies": { "@grafana/tsconfig": "^1.2.0-rc1", "@rollup/plugin-commonjs": "23.0.2", - "@rollup/plugin-json": "5.0.1", + "@rollup/plugin-json": "6.0.0", "@rollup/plugin-node-resolve": "15.1.0", "esbuild": "0.18.6", "glob": "^10.2.7", diff --git a/yarn.lock b/yarn.lock index 7f072277950..8724a81bb41 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3745,7 +3745,7 @@ __metadata: "@grafana/schema": 10.1.0-pre "@grafana/tsconfig": ^1.2.0-rc1 "@rollup/plugin-commonjs": 23.0.2 - "@rollup/plugin-json": 5.0.1 + "@rollup/plugin-json": 6.0.0 "@rollup/plugin-node-resolve": 15.1.0 "@testing-library/dom": 9.3.0 "@testing-library/jest-dom": 5.16.5 @@ -4078,7 +4078,7 @@ __metadata: dependencies: "@grafana/tsconfig": ^1.2.0-rc1 "@rollup/plugin-commonjs": 23.0.2 - "@rollup/plugin-json": 5.0.1 + "@rollup/plugin-json": 6.0.0 "@rollup/plugin-node-resolve": 15.1.0 esbuild: 0.18.6 glob: ^10.2.7 @@ -7248,9 +7248,9 @@ __metadata: languageName: node linkType: hard -"@rollup/plugin-json@npm:5.0.1": - version: 5.0.1 - resolution: "@rollup/plugin-json@npm:5.0.1" +"@rollup/plugin-json@npm:6.0.0": + version: 6.0.0 + resolution: "@rollup/plugin-json@npm:6.0.0" dependencies: "@rollup/pluginutils": ^5.0.1 peerDependencies: @@ -7258,7 +7258,7 @@ __metadata: peerDependenciesMeta: rollup: optional: true - checksum: 1b2f45f49cd3f3dcf2bd1b5987f330cc23bb1abfe049d8ca3d441eacbb8f9a052692b3f062023e175359de7db6dd55ef804393beab15d90aeb3fbf540494a036 + checksum: 77cfc941edaf77a5307977704ffaba706d83bea66f265b2b68f14be2a0af6d08b0fb1b04fdd773146c84cc70938ff64b00ae946808fd6ac057058af824d78128 languageName: node linkType: hard From 17a93e7b2ea15301a6adb69531871ab7cac56774 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 13 Jul 2023 14:53:25 +0000 Subject: [PATCH 05/42] Update dependency @grafana/eslint-config to v6 (#71575) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 425 ++++++++++++++++++++------------------------------- 2 files changed, 168 insertions(+), 259 deletions(-) diff --git a/package.json b/package.json index 73b06fb9c0d..09b558cbff2 100644 --- a/package.json +++ b/package.json @@ -102,7 +102,7 @@ "@betterer/regexp": "5.4.0", "@emotion/eslint-plugin": "11.11.0", "@grafana/e2e": "workspace:*", - "@grafana/eslint-config": "5.1.0", + "@grafana/eslint-config": "6.0.0", "@grafana/eslint-plugin": "link:./packages/grafana-eslint-rules", "@grafana/toolkit": "workspace:*", "@grafana/tsconfig": "^1.3.0-rc1", diff --git a/yarn.lock b/yarn.lock index 8724a81bb41..ddcb96ebf45 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3050,17 +3050,6 @@ __metadata: languageName: node linkType: hard -"@es-joy/jsdoccomment@npm:~0.36.0": - version: 0.36.0 - resolution: "@es-joy/jsdoccomment@npm:0.36.0" - dependencies: - comment-parser: 1.3.1 - esquery: ^1.4.0 - jsdoc-type-pratt-parser: ~3.1.0 - checksum: c2fa95bc01f6b2a0caa521adaa37562b10b12095b5308948f3e122880d2ae9684c09e5b0e0809ac3e31e17580886d2d3b41fbf4ff4831649efce8cba8e30cf5c - languageName: node - linkType: hard - "@es-joy/jsdoccomment@npm:~0.39.4": version: 0.39.4 resolution: "@es-joy/jsdoccomment@npm:0.39.4" @@ -3552,24 +3541,7 @@ __metadata: languageName: node linkType: hard -"@eslint/eslintrc@npm:^1.3.3": - version: 1.3.3 - resolution: "@eslint/eslintrc@npm:1.3.3" - dependencies: - ajv: ^6.12.4 - debug: ^4.3.2 - espree: ^9.4.0 - globals: ^13.15.0 - ignore: ^5.2.0 - import-fresh: ^3.2.1 - js-yaml: ^4.1.0 - minimatch: ^3.1.2 - strip-json-comments: ^3.1.1 - checksum: f03e9d6727efd3e0719da2051ea80c0c73d20e28c171121527dbb868cd34232ca9c1d0525a66e517a404afea26624b1e47895b6a92474678418c2f50c9566694 - languageName: node - linkType: hard - -"@eslint/eslintrc@npm:^2.1.0": +"@eslint/eslintrc@npm:^2.0.3, @eslint/eslintrc@npm:^2.1.0": version: 2.1.0 resolution: "@eslint/eslintrc@npm:2.1.0" dependencies: @@ -3586,6 +3558,13 @@ __metadata: languageName: node linkType: hard +"@eslint/js@npm:8.42.0": + version: 8.42.0 + resolution: "@eslint/js@npm:8.42.0" + checksum: 750558843ac458f7da666122083ee05306fc087ecc1e5b21e7e14e23885775af6c55bcc92283dff1862b7b0d8863ec676c0f18c7faf1219c722fe91a8ece56b6 + languageName: node + linkType: hard + "@eslint/js@npm:8.44.0": version: 8.44.0 resolution: "@eslint/js@npm:8.44.0" @@ -3877,19 +3856,19 @@ __metadata: languageName: unknown linkType: soft -"@grafana/eslint-config@npm:5.1.0": - version: 5.1.0 - resolution: "@grafana/eslint-config@npm:5.1.0" +"@grafana/eslint-config@npm:6.0.0": + version: 6.0.0 + resolution: "@grafana/eslint-config@npm:6.0.0" dependencies: - "@typescript-eslint/eslint-plugin": 5.42.0 - "@typescript-eslint/parser": 5.42.0 - eslint: 8.26.0 - eslint-config-prettier: 8.5.0 - eslint-plugin-jsdoc: 39.6.2 - eslint-plugin-react: 7.31.10 + "@typescript-eslint/eslint-plugin": 5.59.9 + "@typescript-eslint/parser": 5.59.9 + eslint: 8.42.0 + eslint-config-prettier: 8.8.0 + eslint-plugin-jsdoc: 46.2.6 + eslint-plugin-react: 7.32.2 eslint-plugin-react-hooks: 4.6.0 typescript: 4.8.4 - checksum: 525b3dfd956a895219979850b65a760ab19c9872e1c2432cc4f6a831fd3da1dd4e97bb1e046de2012dccd018f71ad88df57e2e1af357ad540d1f0107116d3550 + checksum: a22d21282ba88a3b27d7a68ca6cbd01fe18c39aa3227b23079a0303d3c4265937c8371f8a0ea87acb843c9cec9fc82c649e2a8f47698613af8259edc85fd027c languageName: node linkType: hard @@ -4309,17 +4288,6 @@ __metadata: languageName: node linkType: hard -"@humanwhocodes/config-array@npm:^0.11.6": - version: 0.11.7 - resolution: "@humanwhocodes/config-array@npm:0.11.7" - dependencies: - "@humanwhocodes/object-schema": ^1.2.1 - debug: ^4.1.1 - minimatch: ^3.0.5 - checksum: cf506dc45d9488af7fbf108ea6ac2151ba1a25e6d2b94b9b4fc36d2c1e4099b89ff560296dbfa13947e44604d4ca4a90d97a4fb167370bf8dd01a6ca2b6d83ac - languageName: node - linkType: hard - "@humanwhocodes/module-importer@npm:^1.0.1": version: 1.0.1 resolution: "@humanwhocodes/module-importer@npm:1.0.1" @@ -10926,6 +10894,30 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/eslint-plugin@npm:5.59.9": + version: 5.59.9 + resolution: "@typescript-eslint/eslint-plugin@npm:5.59.9" + dependencies: + "@eslint-community/regexpp": ^4.4.0 + "@typescript-eslint/scope-manager": 5.59.9 + "@typescript-eslint/type-utils": 5.59.9 + "@typescript-eslint/utils": 5.59.9 + debug: ^4.3.4 + grapheme-splitter: ^1.0.4 + ignore: ^5.2.0 + natural-compare-lite: ^1.4.0 + semver: ^7.3.7 + tsutils: ^3.21.0 + peerDependencies: + "@typescript-eslint/parser": ^5.0.0 + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + typescript: + optional: true + checksum: bd2428e307085d7fa6699913b6e61d65eb450bbcd26f884390cbf16722b80e1d80dc289c72774be1cdffd022744894204c3242f40ba3ffdfa05d3f210c4130bb + languageName: node + linkType: hard + "@typescript-eslint/parser@npm:5.42.0": version: 5.42.0 resolution: "@typescript-eslint/parser@npm:5.42.0" @@ -10943,6 +10935,23 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/parser@npm:5.59.9": + version: 5.59.9 + resolution: "@typescript-eslint/parser@npm:5.59.9" + dependencies: + "@typescript-eslint/scope-manager": 5.59.9 + "@typescript-eslint/types": 5.59.9 + "@typescript-eslint/typescript-estree": 5.59.9 + debug: ^4.3.4 + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + typescript: + optional: true + checksum: 69b07d0a5bc6e1d24d23916c057ea9f2f53a0e7fb6dabadff92987c299640edee2c013fb93269322c7124e87b5c515529001397eae33006dfb40e1dcdf1902d7 + languageName: node + linkType: hard + "@typescript-eslint/scope-manager@npm:5.11.0": version: 5.11.0 resolution: "@typescript-eslint/scope-manager@npm:5.11.0" @@ -10973,6 +10982,16 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/scope-manager@npm:5.59.9": + version: 5.59.9 + resolution: "@typescript-eslint/scope-manager@npm:5.59.9" + dependencies: + "@typescript-eslint/types": 5.59.9 + "@typescript-eslint/visitor-keys": 5.59.9 + checksum: 362c22662d844440a7e14223d8cc0722f77ff21ad8f78deb0ee3b3f21de01b8846bf25fbbf527544677e83d8ff48008b3f7d40b39ddec55994ea4a1863e9ec0a + languageName: node + linkType: hard + "@typescript-eslint/type-utils@npm:5.42.0": version: 5.42.0 resolution: "@typescript-eslint/type-utils@npm:5.42.0" @@ -10990,6 +11009,23 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/type-utils@npm:5.59.9": + version: 5.59.9 + resolution: "@typescript-eslint/type-utils@npm:5.59.9" + dependencies: + "@typescript-eslint/typescript-estree": 5.59.9 + "@typescript-eslint/utils": 5.59.9 + debug: ^4.3.4 + tsutils: ^3.21.0 + peerDependencies: + eslint: "*" + peerDependenciesMeta: + typescript: + optional: true + checksum: 6bc2619c5024c152b181eff1f44c9b5e7d0fc75ce9403f03b39d59fc1e13191b2fbaf6730f26a1caae22922ac47489f39c2cebccdd713588f6963169ed2a7958 + languageName: node + linkType: hard + "@typescript-eslint/types@npm:5.11.0": version: 5.11.0 resolution: "@typescript-eslint/types@npm:5.11.0" @@ -11011,6 +11047,13 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/types@npm:5.59.9": + version: 5.59.9 + resolution: "@typescript-eslint/types@npm:5.59.9" + checksum: 283f8fee1ee590eeccc2e0fcd3526c856c4b1e2841af2cdcd09eeac842a42cfb32f6bc8b40385380f3dbc3ee29da30f1819115eedf9e16f69ff5a160aeddd8fa + languageName: node + linkType: hard + "@typescript-eslint/typescript-estree@npm:5.11.0": version: 5.11.0 resolution: "@typescript-eslint/typescript-estree@npm:5.11.0" @@ -11065,6 +11108,24 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/typescript-estree@npm:5.59.9": + version: 5.59.9 + resolution: "@typescript-eslint/typescript-estree@npm:5.59.9" + dependencies: + "@typescript-eslint/types": 5.59.9 + "@typescript-eslint/visitor-keys": 5.59.9 + debug: ^4.3.4 + globby: ^11.1.0 + is-glob: ^4.0.3 + semver: ^7.3.7 + tsutils: ^3.21.0 + peerDependenciesMeta: + typescript: + optional: true + checksum: c0c9b81f20a2a4337f07bc3ccdc9c1dabd765f59096255ed9a149e91e5c9517b25c2b6655f8f073807cfc13500c7451fbd9bb62e5e572c07cc07945ab042db89 + languageName: node + linkType: hard + "@typescript-eslint/utils@npm:5.42.0": version: 5.42.0 resolution: "@typescript-eslint/utils@npm:5.42.0" @@ -11083,6 +11144,24 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/utils@npm:5.59.9": + version: 5.59.9 + resolution: "@typescript-eslint/utils@npm:5.59.9" + dependencies: + "@eslint-community/eslint-utils": ^4.2.0 + "@types/json-schema": ^7.0.9 + "@types/semver": ^7.3.12 + "@typescript-eslint/scope-manager": 5.59.9 + "@typescript-eslint/types": 5.59.9 + "@typescript-eslint/typescript-estree": 5.59.9 + eslint-scope: ^5.1.1 + semver: ^7.3.7 + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + checksum: 22ec5962886de7dcf65f99c37aad9fb189a3bef6b2b07c81887fb82a0e8bf137246da58e64fb02141352285708440be13acd7f6db1ca19e96f86724813ac4646 + languageName: node + linkType: hard + "@typescript-eslint/utils@npm:^5.10.0": version: 5.11.0 resolution: "@typescript-eslint/utils@npm:5.11.0" @@ -11147,6 +11226,16 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/visitor-keys@npm:5.59.9": + version: 5.59.9 + resolution: "@typescript-eslint/visitor-keys@npm:5.59.9" + dependencies: + "@typescript-eslint/types": 5.59.9 + eslint-visitor-keys: ^3.3.0 + checksum: 2909ce761f7fe546592cd3c43e33263d8a5fa619375fd2fdffbc72ffc33e40d6feacafb28c79f36c638fcc2225048e7cc08c61cbac6ca63723dc68610d80e3e6 + languageName: node + linkType: hard + "@visx/bounds@npm:3.0.0": version: 3.0.0 resolution: "@visx/bounds@npm:3.0.0" @@ -12370,18 +12459,6 @@ __metadata: languageName: node linkType: hard -"array.prototype.flatmap@npm:^1.3.0": - version: 1.3.0 - resolution: "array.prototype.flatmap@npm:1.3.0" - dependencies: - call-bind: ^1.0.2 - define-properties: ^1.1.3 - es-abstract: ^1.19.2 - es-shim-unscopables: ^1.0.0 - checksum: 818538f39409c4045d874be85df0dbd195e1446b14d22f95bdcfefea44ae77db44e42dcd89a559254ec5a7c8b338cfc986cc6d641e3472f9a5326b21eb2976a2 - languageName: node - linkType: hard - "array.prototype.flatmap@npm:^1.3.1": version: 1.3.1 resolution: "array.prototype.flatmap@npm:1.3.1" @@ -16549,34 +16626,6 @@ __metadata: languageName: node linkType: hard -"es-abstract@npm:^1.19.2": - version: 1.19.5 - resolution: "es-abstract@npm:1.19.5" - dependencies: - call-bind: ^1.0.2 - es-to-primitive: ^1.2.1 - function-bind: ^1.1.1 - get-intrinsic: ^1.1.1 - get-symbol-description: ^1.0.0 - has: ^1.0.3 - has-symbols: ^1.0.3 - internal-slot: ^1.0.3 - is-callable: ^1.2.4 - is-negative-zero: ^2.0.2 - is-regex: ^1.1.4 - is-shared-array-buffer: ^1.0.2 - is-string: ^1.0.7 - is-weakref: ^1.0.2 - object-inspect: ^1.12.0 - object-keys: ^1.1.1 - object.assign: ^4.1.2 - string.prototype.trimend: ^1.0.4 - string.prototype.trimstart: ^1.0.4 - unbox-primitive: ^1.0.1 - checksum: 55199b0f179a12b3b0ec9c9f2e3a27a7561686e4f88d46f9ef32c836448a336e367c14d8f792612fc83a64113896e478259e4dffbbcffb3efdd06650f6360324 - languageName: node - linkType: hard - "es-abstract@npm:^1.19.5": version: 1.20.1 resolution: "es-abstract@npm:1.20.1" @@ -17055,17 +17104,6 @@ __metadata: languageName: node linkType: hard -"eslint-config-prettier@npm:8.5.0": - version: 8.5.0 - resolution: "eslint-config-prettier@npm:8.5.0" - peerDependencies: - eslint: ">=7.0.0" - bin: - eslint-config-prettier: bin/cli.js - checksum: 0d0f5c32e7a0ad91249467ce71ca92394ccd343178277d318baf32063b79ea90216f4c81d1065d60f96366fdc60f151d4d68ae7811a58bd37228b84c2083f893 - languageName: node - linkType: hard - "eslint-config-prettier@npm:8.8.0": version: 8.8.0 resolution: "eslint-config-prettier@npm:8.8.0" @@ -17142,20 +17180,22 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-jsdoc@npm:39.6.2": - version: 39.6.2 - resolution: "eslint-plugin-jsdoc@npm:39.6.2" +"eslint-plugin-jsdoc@npm:46.2.6": + version: 46.2.6 + resolution: "eslint-plugin-jsdoc@npm:46.2.6" dependencies: - "@es-joy/jsdoccomment": ~0.36.0 + "@es-joy/jsdoccomment": ~0.39.4 + are-docs-informative: ^0.0.2 comment-parser: 1.3.1 debug: ^4.3.4 escape-string-regexp: ^4.0.0 - esquery: ^1.4.0 - semver: ^7.3.8 + esquery: ^1.5.0 + is-builtin-module: ^3.2.1 + semver: ^7.5.1 spdx-expression-parse: ^3.0.1 peerDependencies: eslint: ^7.0.0 || ^8.0.0 - checksum: 613c541a644d441e5465139b2a1934842a29c701fb89f0380f105be28180c1fa2f3c08b421b134b87fef194d4fb4dab4006a972a084e476eebb14cf5bb9399fe + checksum: e082c3e88843521e121cdcad1999407a9c586bd55549b40b72865af8af853b06b7e883f80875930615796be71d79cf9d9a73d0e910b2fb67e9934f05400a34b8 languageName: node linkType: hard @@ -17224,30 +17264,6 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-react@npm:7.31.10": - version: 7.31.10 - resolution: "eslint-plugin-react@npm:7.31.10" - dependencies: - array-includes: ^3.1.5 - array.prototype.flatmap: ^1.3.0 - doctrine: ^2.1.0 - estraverse: ^5.3.0 - jsx-ast-utils: ^2.4.1 || ^3.0.0 - minimatch: ^3.1.2 - object.entries: ^1.1.5 - object.fromentries: ^2.0.5 - object.hasown: ^1.1.1 - object.values: ^1.1.5 - prop-types: ^15.8.1 - resolve: ^2.0.0-next.3 - semver: ^6.3.0 - string.prototype.matchall: ^4.0.7 - peerDependencies: - eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 - checksum: f013669c296483559a760648fa06425f161b1aff93c668f14c4561c933d22a7836b745b88a795c53cab929c71513d5fd1f2ffdddff915709f01b77ac25f5b71b - languageName: node - linkType: hard - "eslint-plugin-react@npm:7.32.2": version: 7.32.2 resolution: "eslint-plugin-react@npm:7.32.2" @@ -17283,16 +17299,6 @@ __metadata: languageName: node linkType: hard -"eslint-scope@npm:^7.1.1": - version: 7.1.1 - resolution: "eslint-scope@npm:7.1.1" - dependencies: - esrecurse: ^4.3.0 - estraverse: ^5.2.0 - checksum: 9f6e974ab2db641ca8ab13508c405b7b859e72afe9f254e8131ff154d2f40c99ad4545ce326fd9fde3212ff29707102562a4834f1c48617b35d98c71a97fbf3e - languageName: node - linkType: hard - "eslint-scope@npm:^7.2.0": version: 7.2.0 resolution: "eslint-scope@npm:7.2.0" @@ -17358,12 +17364,15 @@ __metadata: languageName: node linkType: hard -"eslint@npm:8.26.0": - version: 8.26.0 - resolution: "eslint@npm:8.26.0" +"eslint@npm:8.42.0": + version: 8.42.0 + resolution: "eslint@npm:8.42.0" dependencies: - "@eslint/eslintrc": ^1.3.3 - "@humanwhocodes/config-array": ^0.11.6 + "@eslint-community/eslint-utils": ^4.2.0 + "@eslint-community/regexpp": ^4.4.0 + "@eslint/eslintrc": ^2.0.3 + "@eslint/js": 8.42.0 + "@humanwhocodes/config-array": ^0.11.10 "@humanwhocodes/module-importer": ^1.0.1 "@nodelib/fs.walk": ^1.2.8 ajv: ^6.10.0 @@ -17372,24 +17381,22 @@ __metadata: debug: ^4.3.2 doctrine: ^3.0.0 escape-string-regexp: ^4.0.0 - eslint-scope: ^7.1.1 - eslint-utils: ^3.0.0 - eslint-visitor-keys: ^3.3.0 - espree: ^9.4.0 - esquery: ^1.4.0 + eslint-scope: ^7.2.0 + eslint-visitor-keys: ^3.4.1 + espree: ^9.5.2 + esquery: ^1.4.2 esutils: ^2.0.2 fast-deep-equal: ^3.1.3 file-entry-cache: ^6.0.1 find-up: ^5.0.0 glob-parent: ^6.0.2 - globals: ^13.15.0 - grapheme-splitter: ^1.0.4 + globals: ^13.19.0 + graphemer: ^1.4.0 ignore: ^5.2.0 import-fresh: ^3.0.0 imurmurhash: ^0.1.4 is-glob: ^4.0.0 is-path-inside: ^3.0.3 - js-sdsl: ^4.1.4 js-yaml: ^4.1.0 json-stable-stringify-without-jsonify: ^1.0.1 levn: ^0.4.1 @@ -17397,13 +17404,12 @@ __metadata: minimatch: ^3.1.2 natural-compare: ^1.4.0 optionator: ^0.9.1 - regexpp: ^3.2.0 strip-ansi: ^6.0.1 strip-json-comments: ^3.1.0 text-table: ^0.2.0 bin: eslint: bin/eslint.js - checksum: a2aced939ea060f77d10dcfced5cfeb940f63f383fd7ab1decadea64170ab552582e1c5909db1db641d4283178c9bc569f19b0f8900e00314a5f783e4b3f759d + checksum: 07105397b5f2ff4064b983b8971e8c379ec04b1dfcc9d918976b3e00377189000161dac991d82ba14f8759e466091b8c71146f602930ca810c290ee3fcb3faf0 languageName: node linkType: hard @@ -17456,18 +17462,7 @@ __metadata: languageName: node linkType: hard -"espree@npm:^9.4.0": - version: 9.4.0 - resolution: "espree@npm:9.4.0" - dependencies: - acorn: ^8.8.0 - acorn-jsx: ^5.3.2 - eslint-visitor-keys: ^3.3.0 - checksum: 2e3020dde67892d2ba3632413b44d0dc31d92c29ce72267d7ec24216a562f0a6494d3696e2fa39a3ec8c0e0088d773947ab2925fbb716801a11eb8dd313ac89c - languageName: node - linkType: hard - -"espree@npm:^9.6.0": +"espree@npm:^9.5.2, espree@npm:^9.6.0": version: 9.6.0 resolution: "espree@npm:9.6.0" dependencies: @@ -17488,7 +17483,7 @@ __metadata: languageName: node linkType: hard -"esquery@npm:^1.0.1, esquery@npm:^1.3.1, esquery@npm:^1.4.0": +"esquery@npm:^1.0.1, esquery@npm:^1.3.1": version: 1.4.0 resolution: "esquery@npm:1.4.0" dependencies: @@ -19028,15 +19023,6 @@ __metadata: languageName: node linkType: hard -"globals@npm:^13.15.0": - version: 13.15.0 - resolution: "globals@npm:13.15.0" - dependencies: - type-fest: ^0.20.2 - checksum: 383ade0873b2ab29ce6d143466c203ed960491575bc97406395e5c8434026fb02472ab2dfff5bc16689b8460269b18fda1047975295cd0183904385c51258bae - languageName: node - linkType: hard - "globals@npm:^13.19.0": version: 13.19.0 resolution: "globals@npm:13.19.0" @@ -19163,7 +19149,7 @@ __metadata: "@grafana/data": "workspace:*" "@grafana/e2e": "workspace:*" "@grafana/e2e-selectors": "workspace:*" - "@grafana/eslint-config": 5.1.0 + "@grafana/eslint-config": 6.0.0 "@grafana/eslint-plugin": "link:./packages/grafana-eslint-rules" "@grafana/experimental": 1.4.2 "@grafana/faro-core": 1.1.0 @@ -22175,13 +22161,6 @@ __metadata: languageName: node linkType: hard -"js-sdsl@npm:^4.1.4": - version: 4.1.4 - resolution: "js-sdsl@npm:4.1.4" - checksum: 1977cea4ab18e0e03e28bdf0371d8b443fad65ca0988e0faa216406faf6bb943714fe8f7cc7a5bfe5f35ba3d94ddae399f4d10200f547f2c3320688b0670d726 - languageName: node - linkType: hard - "js-tokens@npm:^3.0.0 || ^4.0.0, js-tokens@npm:^4.0.0": version: 4.0.0 resolution: "js-tokens@npm:4.0.0" @@ -22250,13 +22229,6 @@ __metadata: languageName: node linkType: hard -"jsdoc-type-pratt-parser@npm:~3.1.0": - version: 3.1.0 - resolution: "jsdoc-type-pratt-parser@npm:3.1.0" - checksum: 2f437b57621f1e481918165f6cf0e48256628a9e510d8b3f88a2ab667bf2128bf8b94c628b57c43e78f555ca61983e9c282814703840dc091d2623992214a061 - languageName: node - linkType: hard - "jsdoc-type-pratt-parser@npm:~4.0.0": version: 4.0.0 resolution: "jsdoc-type-pratt-parser@npm:4.0.0" @@ -24784,17 +24756,6 @@ __metadata: languageName: node linkType: hard -"object.entries@npm:^1.1.5": - version: 1.1.5 - resolution: "object.entries@npm:1.1.5" - dependencies: - call-bind: ^1.0.2 - define-properties: ^1.1.3 - es-abstract: ^1.19.1 - checksum: d658696f74fd222060d8428d2a9fda2ce736b700cb06f6bdf4a16a1892d145afb746f453502b2fa55d1dca8ead6f14ddbcf66c545df45adadea757a6c4cd86c7 - languageName: node - linkType: hard - "object.entries@npm:^1.1.6": version: 1.1.6 resolution: "object.entries@npm:1.1.6" @@ -24806,17 +24767,6 @@ __metadata: languageName: node linkType: hard -"object.fromentries@npm:^2.0.5": - version: 2.0.5 - resolution: "object.fromentries@npm:2.0.5" - dependencies: - call-bind: ^1.0.2 - define-properties: ^1.1.3 - es-abstract: ^1.19.1 - checksum: 61a0b565ded97b76df9e30b569729866e1824cce902f98e90bb106e84f378aea20163366f66dc75c9000e2aad2ed0caf65c6f530cb2abc4c0c0f6c982102db4b - languageName: node - linkType: hard - "object.fromentries@npm:^2.0.6": version: 2.0.6 resolution: "object.fromentries@npm:2.0.6" @@ -24828,16 +24778,6 @@ __metadata: languageName: node linkType: hard -"object.hasown@npm:^1.1.1": - version: 1.1.1 - resolution: "object.hasown@npm:1.1.1" - dependencies: - define-properties: ^1.1.4 - es-abstract: ^1.19.5 - checksum: d8ed4907ce57f48b93e3b53c418fd6787bf226a51e8d698c91e39b78e80fe5b124cb6282f6a9d5be21cf9e2c7829ab10206dcc6112b7748860eefe641880c793 - languageName: node - linkType: hard - "object.hasown@npm:^1.1.2": version: 1.1.2 resolution: "object.hasown@npm:1.1.2" @@ -24848,17 +24788,6 @@ __metadata: languageName: node linkType: hard -"object.values@npm:^1.1.5": - version: 1.1.5 - resolution: "object.values@npm:1.1.5" - dependencies: - call-bind: ^1.0.2 - define-properties: ^1.1.3 - es-abstract: ^1.19.1 - checksum: 0f17e99741ebfbd0fa55ce942f6184743d3070c61bd39221afc929c8422c4907618c8da694c6915bc04a83ab3224260c779ba37fc07bb668bdc5f33b66a902a4 - languageName: node - linkType: hard - "object.values@npm:^1.1.6": version: 1.1.6 resolution: "object.values@npm:1.1.6" @@ -28819,16 +28748,6 @@ __metadata: languageName: node linkType: hard -"resolve@npm:^2.0.0-next.3": - version: 2.0.0-next.3 - resolution: "resolve@npm:2.0.0-next.3" - dependencies: - is-core-module: ^2.2.0 - path-parse: ^1.0.6 - checksum: f34b3b93ada77d64a6d590c06a83e198f3a827624c4ec972260905fa6c4d612164fbf0200d16d2beefea4ad1755b001f4a9a1293d8fc2322a8f7d6bf692c4ff5 - languageName: node - linkType: hard - "resolve@npm:^2.0.0-next.4": version: 2.0.0-next.4 resolution: "resolve@npm:2.0.0-next.4" @@ -28865,16 +28784,6 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@^2.0.0-next.3#~builtin": - version: 2.0.0-next.3 - resolution: "resolve@patch:resolve@npm%3A2.0.0-next.3#~builtin::version=2.0.0-next.3&hash=c3c19d" - dependencies: - is-core-module: ^2.2.0 - path-parse: ^1.0.6 - checksum: 21684b4d99a4877337cdbd5484311c811b3e8910edb5d868eec85c6e6550b0f570d911f9a384f9e176172d6713f2715bd0b0887fa512cb8c6aeece018de6a9f8 - languageName: node - linkType: hard - "resolve@patch:resolve@^2.0.0-next.4#~builtin": version: 2.0.0-next.4 resolution: "resolve@patch:resolve@npm%3A2.0.0-next.4#~builtin::version=2.0.0-next.4&hash=c3c19d" @@ -30493,7 +30402,7 @@ __metadata: languageName: node linkType: hard -"string.prototype.matchall@npm:^4.0.7, string.prototype.matchall@npm:^4.0.8": +"string.prototype.matchall@npm:^4.0.8": version: 4.0.8 resolution: "string.prototype.matchall@npm:4.0.8" dependencies: From 3a21061dbbbf8815b25307d57d5dfedcb0070263 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 13 Jul 2023 14:58:36 +0000 Subject: [PATCH 06/42] Update dependency css-minimizer-webpack-plugin to v5 (#71578) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 612 ++++++++++++++++++++++++++------------------------- 2 files changed, 318 insertions(+), 296 deletions(-) diff --git a/package.json b/package.json index 09b558cbff2..d821b51eae1 100644 --- a/package.json +++ b/package.json @@ -181,7 +181,7 @@ "codeowners": "^5.1.1", "copy-webpack-plugin": "11.0.0", "css-loader": "6.8.1", - "css-minimizer-webpack-plugin": "4.2.2", + "css-minimizer-webpack-plugin": "5.0.1", "cypress": "9.5.1", "esbuild": "0.18.6", "esbuild-loader": "3.0.1", diff --git a/yarn.lock b/yarn.lock index ddcb96ebf45..8f6834d8545 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4554,6 +4554,15 @@ __metadata: languageName: node linkType: hard +"@jest/schemas@npm:^29.6.0": + version: 29.6.0 + resolution: "@jest/schemas@npm:29.6.0" + dependencies: + "@sinclair/typebox": ^0.27.8 + checksum: c00511c69cf89138a7d974404d3a5060af375b5a52b9c87215d91873129b382ca11c1ff25bd6d605951404bb381ddce5f8091004a61e76457da35db1f5c51365 + languageName: node + linkType: hard + "@jest/source-map@npm:^29.2.0": version: 29.2.0 resolution: "@jest/source-map@npm:29.2.0" @@ -4638,20 +4647,6 @@ __metadata: languageName: node linkType: hard -"@jest/types@npm:^29.2.1": - version: 29.2.1 - resolution: "@jest/types@npm:29.2.1" - dependencies: - "@jest/schemas": ^29.0.0 - "@types/istanbul-lib-coverage": ^2.0.0 - "@types/istanbul-reports": ^3.0.0 - "@types/node": "*" - "@types/yargs": ^17.0.8 - chalk: ^4.0.0 - checksum: a83f20727425179aa05974aa7553c307d207fbb6b7ae5ab1e37fbb6ba9b6655f26655301fc804f2545d33f4c4a6b59d41eed1737c005d2b83fce9e14841b4150 - languageName: node - linkType: hard - "@jest/types@npm:^29.3.1": version: 29.3.1 resolution: "@jest/types@npm:29.3.1" @@ -4680,6 +4675,20 @@ __metadata: languageName: node linkType: hard +"@jest/types@npm:^29.6.1": + version: 29.6.1 + resolution: "@jest/types@npm:29.6.1" + dependencies: + "@jest/schemas": ^29.6.0 + "@types/istanbul-lib-coverage": ^2.0.0 + "@types/istanbul-reports": ^3.0.0 + "@types/node": "*" + "@types/yargs": ^17.0.8 + chalk: ^4.0.0 + checksum: 89fc1ccf71a84fe0da643e0675b1cfe6a6f19ea72e935b2ab1dbdb56ec547e94433fb59b3536d3832a6e156c077865b7176fe9dae707dab9c3d2f9405ba6233c + languageName: node + linkType: hard + "@jridgewell/gen-mapping@npm:^0.1.0": version: 0.1.1 resolution: "@jridgewell/gen-mapping@npm:0.1.1" @@ -4801,6 +4810,16 @@ __metadata: languageName: node linkType: hard +"@jridgewell/trace-mapping@npm:^0.3.18": + version: 0.3.18 + resolution: "@jridgewell/trace-mapping@npm:0.3.18" + dependencies: + "@jridgewell/resolve-uri": 3.1.0 + "@jridgewell/sourcemap-codec": 1.4.14 + checksum: 0572669f855260808c16fe8f78f5f1b4356463b11d3f2c7c0b5580c8ba1cbf4ae53efe9f627595830856e57dbac2325ac17eb0c3dd0ec42102e6f227cc289c02 + languageName: node + linkType: hard + "@jridgewell/trace-mapping@npm:^0.3.9": version: 0.3.13 resolution: "@jridgewell/trace-mapping@npm:0.3.13" @@ -7369,6 +7388,13 @@ __metadata: languageName: node linkType: hard +"@sinclair/typebox@npm:^0.27.8": + version: 0.27.8 + resolution: "@sinclair/typebox@npm:0.27.8" + checksum: 00bd7362a3439021aa1ea51b0e0d0a0e8ca1351a3d54c606b115fdcc49b51b16db6e5f43b4fe7a28c38688523e22a94d49dd31168868b655f0d4d50f032d07a1 + languageName: node + linkType: hard + "@sinonjs/commons@npm:^1.7.0": version: 1.8.3 resolution: "@sinonjs/commons@npm:1.8.3" @@ -12061,7 +12087,7 @@ __metadata: languageName: node linkType: hard -"ajv-keywords@npm:^5.0.0": +"ajv-keywords@npm:^5.0.0, ajv-keywords@npm:^5.1.0": version: 5.1.0 resolution: "ajv-keywords@npm:5.1.0" dependencies: @@ -12108,6 +12134,18 @@ __metadata: languageName: node linkType: hard +"ajv@npm:^8.9.0": + version: 8.12.0 + resolution: "ajv@npm:8.12.0" + dependencies: + fast-deep-equal: ^3.1.1 + json-schema-traverse: ^1.0.0 + require-from-string: ^2.0.2 + uri-js: ^4.2.2 + checksum: 4dc13714e316e67537c8b31bc063f99a1d9d9a497eb4bbd55191ac0dcd5e4985bbb71570352ad6f1e76684fb6d790928f96ba3b2d4fd6e10024be9612fe3f001 + languageName: node + linkType: hard + "angular-bindonce@npm:0.3.1": version: 0.3.1 resolution: "angular-bindonce@npm:0.3.1" @@ -13292,7 +13330,7 @@ __metadata: languageName: node linkType: hard -"browserslist@npm:^4.0.0, browserslist@npm:^4.14.5, browserslist@npm:^4.16.6, browserslist@npm:^4.20.3, browserslist@npm:^4.21.3, browserslist@npm:^4.21.4, browserslist@npm:^4.21.5": +"browserslist@npm:^4.0.0, browserslist@npm:^4.14.5, browserslist@npm:^4.21.3, browserslist@npm:^4.21.4, browserslist@npm:^4.21.5": version: 4.21.7 resolution: "browserslist@npm:4.21.7" dependencies: @@ -14807,12 +14845,12 @@ __metadata: languageName: node linkType: hard -"css-declaration-sorter@npm:^6.2.2": - version: 6.2.2 - resolution: "css-declaration-sorter@npm:6.2.2" +"css-declaration-sorter@npm:^6.3.1": + version: 6.4.1 + resolution: "css-declaration-sorter@npm:6.4.1" peerDependencies: postcss: ^8.0.9 - checksum: afd3aea1b763b7abb5a9d0e10e973e99520b528522be421d9ef13d4fa7ead2cd48acd85d48c0fd0e954f596da2181dafbafc176a080ab017ebd1909a8231c9b4 + checksum: cbdc9e0d481011b1a28fd5b60d4eb55fe204391d31a0b1b490b2cecf4baa85810f9b8c48adab4df644f4718104ed3ed72c64a9745e3216173767bf4aeca7f9b8 languageName: node linkType: hard @@ -14878,16 +14916,16 @@ __metadata: languageName: node linkType: hard -"css-minimizer-webpack-plugin@npm:4.2.2": - version: 4.2.2 - resolution: "css-minimizer-webpack-plugin@npm:4.2.2" +"css-minimizer-webpack-plugin@npm:5.0.1": + version: 5.0.1 + resolution: "css-minimizer-webpack-plugin@npm:5.0.1" dependencies: - cssnano: ^5.1.8 - jest-worker: ^29.1.2 - postcss: ^8.4.17 - schema-utils: ^4.0.0 - serialize-javascript: ^6.0.0 - source-map: ^0.6.1 + "@jridgewell/trace-mapping": ^0.3.18 + cssnano: ^6.0.1 + jest-worker: ^29.4.3 + postcss: ^8.4.24 + schema-utils: ^4.0.1 + serialize-javascript: ^6.0.1 peerDependencies: webpack: ^5.0.0 peerDependenciesMeta: @@ -14903,7 +14941,7 @@ __metadata: optional: true lightningcss: optional: true - checksum: 5417e76a445f35832aa96807c835b8e92834a6cd285b1b788dfe3ca0fa90fec7eb2dd6efa9d3649f9d8244b99b7da2d065951603b94918e8f6a366a5049cacdd + checksum: 10055802c61d1ae72584eac03b6bd221ecbefde11d337be44a5459d8de075b38f91b80949f95cd0c3a10295615ee013f82130bfac5fe9b5b3e8e75531f232680 languageName: node linkType: hard @@ -14967,7 +15005,7 @@ __metadata: languageName: node linkType: hard -"css-tree@npm:^1.1.2, css-tree@npm:^1.1.3": +"css-tree@npm:^1.1.2": version: 1.1.3 resolution: "css-tree@npm:1.1.3" dependencies: @@ -14977,7 +15015,7 @@ __metadata: languageName: node linkType: hard -"css-tree@npm:^2.3.1": +"css-tree@npm:^2.2.1, css-tree@npm:^2.3.1": version: 2.3.1 resolution: "css-tree@npm:2.3.1" dependencies: @@ -14987,6 +15025,16 @@ __metadata: languageName: node linkType: hard +"css-tree@npm:~2.2.0": + version: 2.2.1 + resolution: "css-tree@npm:2.2.1" + dependencies: + mdn-data: 2.0.28 + source-map-js: ^1.0.1 + checksum: b94aa8cc2f09e6f66c91548411fcf74badcbad3e150345074715012d16333ce573596ff5dfca03c2a87edf1924716db765120f94247e919d72753628ba3aba27 + languageName: node + linkType: hard + "css-what@npm:^5.0.0": version: 5.1.0 resolution: "css-what@npm:5.1.0" @@ -15038,73 +15086,72 @@ __metadata: languageName: node linkType: hard -"cssnano-preset-default@npm:^5.2.8": - version: 5.2.8 - resolution: "cssnano-preset-default@npm:5.2.8" +"cssnano-preset-default@npm:^6.0.1": + version: 6.0.1 + resolution: "cssnano-preset-default@npm:6.0.1" dependencies: - css-declaration-sorter: ^6.2.2 - cssnano-utils: ^3.1.0 - postcss-calc: ^8.2.3 - postcss-colormin: ^5.3.0 - postcss-convert-values: ^5.1.1 - postcss-discard-comments: ^5.1.1 - postcss-discard-duplicates: ^5.1.0 - postcss-discard-empty: ^5.1.1 - postcss-discard-overridden: ^5.1.0 - postcss-merge-longhand: ^5.1.4 - postcss-merge-rules: ^5.1.1 - postcss-minify-font-values: ^5.1.0 - postcss-minify-gradients: ^5.1.1 - postcss-minify-params: ^5.1.3 - postcss-minify-selectors: ^5.2.0 - postcss-normalize-charset: ^5.1.0 - postcss-normalize-display-values: ^5.1.0 - postcss-normalize-positions: ^5.1.0 - postcss-normalize-repeat-style: ^5.1.0 - postcss-normalize-string: ^5.1.0 - postcss-normalize-timing-functions: ^5.1.0 - postcss-normalize-unicode: ^5.1.0 - postcss-normalize-url: ^5.1.0 - postcss-normalize-whitespace: ^5.1.1 - postcss-ordered-values: ^5.1.1 - postcss-reduce-initial: ^5.1.0 - postcss-reduce-transforms: ^5.1.0 - postcss-svgo: ^5.1.0 - postcss-unique-selectors: ^5.1.1 + css-declaration-sorter: ^6.3.1 + cssnano-utils: ^4.0.0 + postcss-calc: ^9.0.0 + postcss-colormin: ^6.0.0 + postcss-convert-values: ^6.0.0 + postcss-discard-comments: ^6.0.0 + postcss-discard-duplicates: ^6.0.0 + postcss-discard-empty: ^6.0.0 + postcss-discard-overridden: ^6.0.0 + postcss-merge-longhand: ^6.0.0 + postcss-merge-rules: ^6.0.1 + postcss-minify-font-values: ^6.0.0 + postcss-minify-gradients: ^6.0.0 + postcss-minify-params: ^6.0.0 + postcss-minify-selectors: ^6.0.0 + postcss-normalize-charset: ^6.0.0 + postcss-normalize-display-values: ^6.0.0 + postcss-normalize-positions: ^6.0.0 + postcss-normalize-repeat-style: ^6.0.0 + postcss-normalize-string: ^6.0.0 + postcss-normalize-timing-functions: ^6.0.0 + postcss-normalize-unicode: ^6.0.0 + postcss-normalize-url: ^6.0.0 + postcss-normalize-whitespace: ^6.0.0 + postcss-ordered-values: ^6.0.0 + postcss-reduce-initial: ^6.0.0 + postcss-reduce-transforms: ^6.0.0 + postcss-svgo: ^6.0.0 + postcss-unique-selectors: ^6.0.0 peerDependencies: postcss: ^8.2.15 - checksum: 3a95a4d9d3b9ee970df17132a939c2c0a22bc52854bbad6a06ebb682b2c4840716b0c7323ea39fb345eef53e5ee64be9ee4e7477cbc4ac63ba901cf2beed427d + checksum: 451080ae47c93e6525c7133c36426968ee758eb9115132ba481e6b12d50775f4d086635bb2f807957e017fc9d253aa876aa64800be6b3d000ada90721b9ea410 languageName: node linkType: hard -"cssnano-utils@npm:^3.1.0": - version: 3.1.0 - resolution: "cssnano-utils@npm:3.1.0" +"cssnano-utils@npm:^4.0.0": + version: 4.0.0 + resolution: "cssnano-utils@npm:4.0.0" peerDependencies: postcss: ^8.2.15 - checksum: 975c84ce9174cf23bb1da1e9faed8421954607e9ea76440cd3bb0c1bea7e17e490d800fca5ae2812d1d9e9d5524eef23ede0a3f52497d7ccc628e5d7321536f2 + checksum: 7db9b3eb4ec7cc7b2d1a3caf8c2d3b6b067bb8404b93dc183907325db3231e396350a50e5388beda02dab03404d5e8d226977b2b87adc11768173e0259e80219 languageName: node linkType: hard -"cssnano@npm:^5.1.8": - version: 5.1.8 - resolution: "cssnano@npm:5.1.8" +"cssnano@npm:^6.0.1": + version: 6.0.1 + resolution: "cssnano@npm:6.0.1" dependencies: - cssnano-preset-default: ^5.2.8 - lilconfig: ^2.0.3 - yaml: ^1.10.2 + cssnano-preset-default: ^6.0.1 + lilconfig: ^2.1.0 peerDependencies: postcss: ^8.2.15 - checksum: 8ff769094400447a5ecf708e1a10050daf450bcf08d9c778806bbc7b942d68e0fac7a8c3b41dbb820620dab7f0395838e74b1c1fe1dbca57fd8cf00f0d1f8555 + checksum: 15e0777189edf2d4287ed3628f65d78c9934a2c0729e29811e85bd760653a0142477b3c2dde9e0a51438c509b2b926e6482215cd8d4e6704e3eb1ab38d1dba0c languageName: node linkType: hard -"csso@npm:^4.2.0": - version: 4.2.0 - resolution: "csso@npm:4.2.0" +"csso@npm:^5.0.5": + version: 5.0.5 + resolution: "csso@npm:5.0.5" dependencies: - css-tree: ^1.1.2 - checksum: 380ba9663da3bcea58dee358a0d8c4468bb6539be3c439dc266ac41c047217f52fd698fb7e4b6b6ccdfb8cf53ef4ceed8cc8ceccb8dfca2aa628319826b5b998 + css-tree: ~2.2.0 + checksum: 0ad858d36bf5012ed243e9ec69962a867509061986d2ee07cc040a4b26e4d062c00d4c07e5ba8d430706ceb02dd87edd30a52b5937fd45b1b6f2119c4993d59a languageName: node linkType: hard @@ -19290,7 +19337,7 @@ __metadata: copy-webpack-plugin: 11.0.0 core-js: 3.31.0 css-loader: 6.8.1 - css-minimizer-webpack-plugin: 4.2.2 + css-minimizer-webpack-plugin: 5.0.1 cypress: 9.5.1 d3: 7.8.5 d3-force: 3.0.0 @@ -21965,20 +22012,6 @@ __metadata: languageName: node linkType: hard -"jest-util@npm:^29.2.1": - version: 29.2.1 - resolution: "jest-util@npm:29.2.1" - dependencies: - "@jest/types": ^29.2.1 - "@types/node": "*" - chalk: ^4.0.0 - ci-info: ^3.2.0 - graceful-fs: ^4.2.9 - picomatch: ^2.2.3 - checksum: 781bd14a65599d24b7449877020f4da32e8cb8fbc31c4e849c589ffde58f0eec27de9f690dba182e3ca369fe651c0bb9c307de29a0927d12777677ded56bafb8 - languageName: node - linkType: hard - "jest-util@npm:^29.5.0": version: 29.5.0 resolution: "jest-util@npm:29.5.0" @@ -21993,6 +22026,20 @@ __metadata: languageName: node linkType: hard +"jest-util@npm:^29.6.1": + version: 29.6.1 + resolution: "jest-util@npm:29.6.1" + dependencies: + "@jest/types": ^29.6.1 + "@types/node": "*" + chalk: ^4.0.0 + ci-info: ^3.2.0 + graceful-fs: ^4.2.9 + picomatch: ^2.2.3 + checksum: fc553556c1350c443449cadaba5fb9d604628e8b5ceb6ceaf4e7e08975b24277d0a14bf2e0f956024e03c23e556fcb074659423422a06fbedf2ab52978697ac7 + languageName: node + linkType: hard + "jest-validate@npm:^29.3.1": version: 29.3.1 resolution: "jest-validate@npm:29.3.1" @@ -22056,18 +22103,6 @@ __metadata: languageName: node linkType: hard -"jest-worker@npm:^29.1.2": - version: 29.2.1 - resolution: "jest-worker@npm:29.2.1" - dependencies: - "@types/node": "*" - jest-util: ^29.2.1 - merge-stream: ^2.0.0 - supports-color: ^8.0.0 - checksum: 10365612fae02412376e963de9f069d854deaf5aec8ff818ce49c299cd0373256a387a2da68db8225fb0f18483f2cc9072a52d1846881d44b756b1e36bc7f4ed - languageName: node - linkType: hard - "jest-worker@npm:^29.3.1": version: 29.3.1 resolution: "jest-worker@npm:29.3.1" @@ -22092,6 +22127,18 @@ __metadata: languageName: node linkType: hard +"jest-worker@npm:^29.4.3": + version: 29.6.1 + resolution: "jest-worker@npm:29.6.1" + dependencies: + "@types/node": "*" + jest-util: ^29.6.1 + merge-stream: ^2.0.0 + supports-color: ^8.0.0 + checksum: 0af309ea4db17c4c47e84a9246f907960a15577683c005fdeafc8f3c06bc455136f95a6f28fa2a3e924b767eb4dacd9b40915a7707305f88586f099af3ac27a8 + languageName: node + linkType: hard + "jest@npm:29.3.1": version: 29.3.1 resolution: "jest@npm:29.3.1" @@ -22739,20 +22786,13 @@ __metadata: languageName: node linkType: hard -"lilconfig@npm:2.1.0": +"lilconfig@npm:2.1.0, lilconfig@npm:^2.1.0": version: 2.1.0 resolution: "lilconfig@npm:2.1.0" checksum: 8549bb352b8192375fed4a74694cd61ad293904eee33f9d4866c2192865c44c4eb35d10782966242634e0cbc1e91fe62b1247f148dc5514918e3a966da7ea117 languageName: node linkType: hard -"lilconfig@npm:^2.0.3": - version: 2.0.3 - resolution: "lilconfig@npm:2.0.3" - checksum: 39fcd06c9f94bec0f7be969f89abcead96cf9334682007df63e6fbe9bdb0566cf8e1ca53a8f56d2acca802f28e8acbabe8ed4e6265ed5e419b6a1397db003741 - languageName: node - linkType: hard - "lines-and-columns@npm:^1.1.6": version: 1.1.6 resolution: "lines-and-columns@npm:1.1.6" @@ -23350,6 +23390,13 @@ __metadata: languageName: node linkType: hard +"mdn-data@npm:2.0.28": + version: 2.0.28 + resolution: "mdn-data@npm:2.0.28" + checksum: f51d587a6ebe8e426c3376c74ea6df3e19ec8241ed8e2466c9c8a3904d5d04397199ea4f15b8d34d14524b5de926d8724ae85207984be47e165817c26e49e0aa + languageName: node + linkType: hard + "mdn-data@npm:2.0.30": version: 2.0.30 resolution: "mdn-data@npm:2.0.30" @@ -24401,13 +24448,6 @@ __metadata: languageName: node linkType: hard -"normalize-url@npm:^6.0.1": - version: 6.1.0 - resolution: "normalize-url@npm:6.1.0" - checksum: 4a4944631173e7d521d6b80e4c85ccaeceb2870f315584fa30121f505a6dfd86439c5e3fdd8cd9e0e291290c41d0c3599f0cb12ab356722ed242584c30348e50 - languageName: node - linkType: hard - "now-and-later@npm:^2.0.0": version: 2.0.1 resolution: "now-and-later@npm:2.0.1" @@ -25667,77 +25707,77 @@ __metadata: languageName: node linkType: hard -"postcss-calc@npm:^8.2.3": - version: 8.2.4 - resolution: "postcss-calc@npm:8.2.4" +"postcss-calc@npm:^9.0.0": + version: 9.0.1 + resolution: "postcss-calc@npm:9.0.1" dependencies: - postcss-selector-parser: ^6.0.9 + postcss-selector-parser: ^6.0.11 postcss-value-parser: ^4.2.0 peerDependencies: postcss: ^8.2.2 - checksum: 314b4cebb0c4ed0cf8356b4bce71eca78f5a7842e6a3942a3bba49db168d5296b2bd93c3f735ae1c616f2651d94719ade33becc03c73d2d79c7394fb7f73eabb + checksum: 7327ed83bfec544ab8b3e38353baa72ff6d04378b856db4ad82dbd68ce0b73668867ef182b5d4025f9dd9aa9c64aacc50cd1bd9db8d8b51ccc4cb97866b9d72b languageName: node linkType: hard -"postcss-colormin@npm:^5.3.0": - version: 5.3.0 - resolution: "postcss-colormin@npm:5.3.0" +"postcss-colormin@npm:^6.0.0": + version: 6.0.0 + resolution: "postcss-colormin@npm:6.0.0" dependencies: - browserslist: ^4.16.6 + browserslist: ^4.21.4 caniuse-api: ^3.0.0 colord: ^2.9.1 postcss-value-parser: ^4.2.0 peerDependencies: postcss: ^8.2.15 - checksum: 3d3e3cc25071407fb73d68541ca1039ebd154fceb649041461a8a3cab0400cc89b42dbb34a4eeaf573be4ba2370ce23af5e01aff5e03a8d72275f40605577212 + checksum: f7113758df45a198f4cf310b317e5bc49fcbd2648064245a5cddcb46e892593950592d4040136bf3b0c8fd64973b0dda3b4b0865b72b5bd94af244cf52418c67 languageName: node linkType: hard -"postcss-convert-values@npm:^5.1.1": - version: 5.1.1 - resolution: "postcss-convert-values@npm:5.1.1" +"postcss-convert-values@npm:^6.0.0": + version: 6.0.0 + resolution: "postcss-convert-values@npm:6.0.0" dependencies: - browserslist: ^4.20.3 + browserslist: ^4.21.4 postcss-value-parser: ^4.2.0 peerDependencies: postcss: ^8.2.15 - checksum: 5f582b2159a27faf8667fcba27bc0bbe953d89ceba33579a7b9cc6363555bf05e6aaad9708a2496a335d82e67e5164bdb69f9a58cdc7e3f68abd2e7a3178e5f8 + checksum: 511ca9358148fc336808d0f58f1e6ad330b73c1a87f32581f3d541ffa66cb61f2a36c8e76d1defb7c54c577c83f11d9bf2eb0d27a83c963c315b8eb149935bd7 languageName: node linkType: hard -"postcss-discard-comments@npm:^5.1.1": - version: 5.1.1 - resolution: "postcss-discard-comments@npm:5.1.1" +"postcss-discard-comments@npm:^6.0.0": + version: 6.0.0 + resolution: "postcss-discard-comments@npm:6.0.0" peerDependencies: postcss: ^8.2.15 - checksum: 578c3cb3e8c6194cf8b5f2170abd6636bf2fe1ec9ba6e03431f5a7e4aae22c6c6605a5e8e2731e824df07c1188f3defa2f4ba28da4adafe45c068af1189f1f2c + checksum: 9be073707b5ef781c616ddd32ffd98faf14bf8b40027f341d5a4fb7989fa7b017087ad54146a370fe38295b1f2568b9f5522f4e4c1a1d09fe0e01abd9f5ae00d languageName: node linkType: hard -"postcss-discard-duplicates@npm:^5.1.0": - version: 5.1.0 - resolution: "postcss-discard-duplicates@npm:5.1.0" +"postcss-discard-duplicates@npm:^6.0.0": + version: 6.0.0 + resolution: "postcss-discard-duplicates@npm:6.0.0" peerDependencies: postcss: ^8.2.15 - checksum: 88d6964201b1f4ed6bf7a32cefe68e86258bb6e42316ca01d9b32bdb18e7887d02594f89f4a2711d01b51ea6e3fcca8c54be18a59770fe5f4521c61d3eb6ca35 + checksum: 999dfc652a60c96f782cc37fbe0d04a89bec88b5ed943f06555166eebf03c6ee47cd56947f1373d84c8161687d1ca23ff6badd1278b5482c506614cf617bc21d languageName: node linkType: hard -"postcss-discard-empty@npm:^5.1.1": - version: 5.1.1 - resolution: "postcss-discard-empty@npm:5.1.1" +"postcss-discard-empty@npm:^6.0.0": + version: 6.0.0 + resolution: "postcss-discard-empty@npm:6.0.0" peerDependencies: postcss: ^8.2.15 - checksum: 970adb12fae5c214c0768236ad9a821552626e77dedbf24a8213d19cc2c4a531a757cd3b8cdd3fc22fb1742471b8692a1db5efe436a71236dec12b1318ee8ff4 + checksum: 0d6cc604719d4a70569db77de75e60b3b7e9b99a4521879f6047d71325556e9f46d6bd13aecbbd857c35f075c503c1f8b1be442329fb8e9653c24cbf2fb42f3e languageName: node linkType: hard -"postcss-discard-overridden@npm:^5.1.0": - version: 5.1.0 - resolution: "postcss-discard-overridden@npm:5.1.0" +"postcss-discard-overridden@npm:^6.0.0": + version: 6.0.0 + resolution: "postcss-discard-overridden@npm:6.0.0" peerDependencies: postcss: ^8.2.15 - checksum: d64d4a545aa2c81b22542895cfcddc787d24119f294d35d29b0599a1c818b3cc51f4ee80b80f5a0a09db282453dd5ac49f104c2117cc09112d0ac9b40b499a41 + checksum: f2d244bb574cf2c0974c56a1af7131f3833e14515be99c68e6fa6fe82df47cb2c9befa413b9ec92f5f067567c682dc253980a0dede3cc697f6cc9135dfc17ec7 languageName: node linkType: hard @@ -25762,77 +25802,77 @@ __metadata: languageName: node linkType: hard -"postcss-merge-longhand@npm:^5.1.4": - version: 5.1.4 - resolution: "postcss-merge-longhand@npm:5.1.4" +"postcss-merge-longhand@npm:^6.0.0": + version: 6.0.0 + resolution: "postcss-merge-longhand@npm:6.0.0" dependencies: postcss-value-parser: ^4.2.0 - stylehacks: ^5.1.0 + stylehacks: ^6.0.0 peerDependencies: postcss: ^8.2.15 - checksum: 3245531aebcd0d2fe6982e142c088ae96ed5242885349e6160e68fc007cdc10d8b0f3e57d7987e3ba07fc9f7d0f6f278972fecaa517c0fa8594bdeaed82393f0 + checksum: 86d1eda1b845cc7bc781a18db714d8e3ed639f673a7a9f416ecae8b8822235a87724e32d06477c707b40bc2ef96a16e87d831b89188354921791fce0de50103b languageName: node linkType: hard -"postcss-merge-rules@npm:^5.1.1": - version: 5.1.1 - resolution: "postcss-merge-rules@npm:5.1.1" +"postcss-merge-rules@npm:^6.0.1": + version: 6.0.1 + resolution: "postcss-merge-rules@npm:6.0.1" dependencies: - browserslist: ^4.16.6 + browserslist: ^4.21.4 caniuse-api: ^3.0.0 - cssnano-utils: ^3.1.0 + cssnano-utils: ^4.0.0 postcss-selector-parser: ^6.0.5 peerDependencies: postcss: ^8.2.15 - checksum: 163cba5b688346b6bd142b677439257ada6f910dd32dbcffa2a7a58719a609bb9859f597da382bbd8be14a259bea26248aefd99aa890e8fd3753424dfedbde6e + checksum: db003c820319181647806f087ead22598faffee745713026b5c8ea637936dc737a55fdc8d7631731879f49ba675a880dda174f21ae62c8f5aa4b0fda1a81f19a languageName: node linkType: hard -"postcss-minify-font-values@npm:^5.1.0": - version: 5.1.0 - resolution: "postcss-minify-font-values@npm:5.1.0" +"postcss-minify-font-values@npm:^6.0.0": + version: 6.0.0 + resolution: "postcss-minify-font-values@npm:6.0.0" dependencies: postcss-value-parser: ^4.2.0 peerDependencies: postcss: ^8.2.15 - checksum: 35e858fa41efa05acdeb28f1c76579c409fdc7eabb1744c3bd76e895bb9fea341a016746362a67609688ab2471f587202b9a3e14ea28ad677754d663a2777ece + checksum: 60de1e405a8849387714980d85f30c8e3df4b7b3083850086656ef50cdaf41605426373f28c0c43dcadfd1d78816b8e425571f12a024120dced1c7e8facb5073 languageName: node linkType: hard -"postcss-minify-gradients@npm:^5.1.1": - version: 5.1.1 - resolution: "postcss-minify-gradients@npm:5.1.1" +"postcss-minify-gradients@npm:^6.0.0": + version: 6.0.0 + resolution: "postcss-minify-gradients@npm:6.0.0" dependencies: colord: ^2.9.1 - cssnano-utils: ^3.1.0 + cssnano-utils: ^4.0.0 postcss-value-parser: ^4.2.0 peerDependencies: postcss: ^8.2.15 - checksum: 27354072a07c5e6dab36731103b94ca2354d4ed3c5bc6aacfdf2ede5a55fa324679d8fee5450800bc50888dbb5e9ed67569c0012040c2be128143d0cebb36d67 + checksum: f2399211f78b88d122f4c7248cb2cc887b49304eb3315c7332c6216aec361113aca6fe0dac43289f70f0c3f25c97fb10cd74417aab5c2f5f51b64b1ef2c5af13 languageName: node linkType: hard -"postcss-minify-params@npm:^5.1.3": - version: 5.1.3 - resolution: "postcss-minify-params@npm:5.1.3" +"postcss-minify-params@npm:^6.0.0": + version: 6.0.0 + resolution: "postcss-minify-params@npm:6.0.0" dependencies: - browserslist: ^4.16.6 - cssnano-utils: ^3.1.0 + browserslist: ^4.21.4 + cssnano-utils: ^4.0.0 postcss-value-parser: ^4.2.0 peerDependencies: postcss: ^8.2.15 - checksum: 2d218f6b82474310c866b690210595a5e6a4c695f174f9100b018adb4a171bd67b1adaba26c241b3d41a4ea0f4962e0f5a77cf12ae60d9db76f80b0c7cbd6bcd + checksum: 1cd9e372cfa27a9849f6994b03cc031534b519299bd1e392062b524405ba76906d23261ab5c0bb505289343c8ffb6a44414265f96a3e04a28181493eb032af01 languageName: node linkType: hard -"postcss-minify-selectors@npm:^5.2.0": - version: 5.2.0 - resolution: "postcss-minify-selectors@npm:5.2.0" +"postcss-minify-selectors@npm:^6.0.0": + version: 6.0.0 + resolution: "postcss-minify-selectors@npm:6.0.0" dependencies: postcss-selector-parser: ^6.0.5 peerDependencies: postcss: ^8.2.15 - checksum: 651fbac038aaba10efaf4ed793d008439042954e5025462c14964ce24ca4bde868bb25ee846a4ff41df8a719fb8ee9f159ef0a036f54e6a09ed937bcc6884cf0 + checksum: 13ce0a1055fdc4571df8d289c4e5dac983e22ac9b449af2c1418ea536b9176a5354d1a487cc0047789f0981053263675d50c7db7cba99588ecb7ff0045fba818 languageName: node linkType: hard @@ -25893,137 +25933,136 @@ __metadata: languageName: node linkType: hard -"postcss-normalize-charset@npm:^5.1.0": - version: 5.1.0 - resolution: "postcss-normalize-charset@npm:5.1.0" +"postcss-normalize-charset@npm:^6.0.0": + version: 6.0.0 + resolution: "postcss-normalize-charset@npm:6.0.0" peerDependencies: postcss: ^8.2.15 - checksum: e79d92971fc05b8b3c9b72f3535a574e077d13c69bef68156a0965f397fdf157de670da72b797f57b0e3bac8f38155b5dd1735ecab143b9cc4032d72138193b4 + checksum: 186a94083f6d41dbda884bf915ff7fe9d9d19828c50dbf02a7e00c90673bec52e5962afd648220598c40940fb1ed5b93bc25697c395cd38ef30b6fd04e48580e languageName: node linkType: hard -"postcss-normalize-display-values@npm:^5.1.0": - version: 5.1.0 - resolution: "postcss-normalize-display-values@npm:5.1.0" +"postcss-normalize-display-values@npm:^6.0.0": + version: 6.0.0 + resolution: "postcss-normalize-display-values@npm:6.0.0" dependencies: postcss-value-parser: ^4.2.0 peerDependencies: postcss: ^8.2.15 - checksum: b6eb7b9b02c3bdd62bbc54e01e2b59733d73a1c156905d238e178762962efe0c6f5104544da39f32cade8a4fb40f10ff54b63a8ebfbdff51e8780afb9fbdcf86 + checksum: 4f8da7cf817e4c66004d3b2d88603aeadc7f9b55caca1bbba27f45e81ae8c65db8ff252488c8fd9ebb3e5c62f85e475131dcee9754346320453bc2b40865afd9 languageName: node linkType: hard -"postcss-normalize-positions@npm:^5.1.0": - version: 5.1.0 - resolution: "postcss-normalize-positions@npm:5.1.0" +"postcss-normalize-positions@npm:^6.0.0": + version: 6.0.0 + resolution: "postcss-normalize-positions@npm:6.0.0" dependencies: postcss-value-parser: ^4.2.0 peerDependencies: postcss: ^8.2.15 - checksum: 08a1f12cc8e192120c1ee14dc93e603546be507d826a75c2c6ef3224b5e3a17628a42a952317e8349b2708ffdef0560b84dcc20521104317eaa62291cca009f6 + checksum: 34dedb07f906b28eb77c57be34899c5c694b81b91c6bfff1e6e9a251aa8f28fea0fdb35a7cdda0fc83e4248b078343a2d76e4485c3ef87f469b24332fa1788cd languageName: node linkType: hard -"postcss-normalize-repeat-style@npm:^5.1.0": - version: 5.1.0 - resolution: "postcss-normalize-repeat-style@npm:5.1.0" +"postcss-normalize-repeat-style@npm:^6.0.0": + version: 6.0.0 + resolution: "postcss-normalize-repeat-style@npm:6.0.0" dependencies: postcss-value-parser: ^4.2.0 peerDependencies: postcss: ^8.2.15 - checksum: 65176c37741d3321fd346586bf42c292a9dab1e4b77a1004d9cde2ae9e015f6fe330c57b44d0ca854a48bd7db0b169875b8d2b5ca501ac9b5381068c337aac19 + checksum: a53b994bb6594f5c48bd7083a46e6a47c1cf02843bcb864d37e7919c08a6f1d7dbbfee8a6abc2afb5d15554b667abc69d696b90d43066ceb97f835e6c8272098 languageName: node linkType: hard -"postcss-normalize-string@npm:^5.1.0": - version: 5.1.0 - resolution: "postcss-normalize-string@npm:5.1.0" +"postcss-normalize-string@npm:^6.0.0": + version: 6.0.0 + resolution: "postcss-normalize-string@npm:6.0.0" dependencies: postcss-value-parser: ^4.2.0 peerDependencies: postcss: ^8.2.15 - checksum: 6e549c6e5b2831e34c7bdd46d8419e2278f6af1d5eef6d26884a37c162844e60339340c57e5e06058cdbe32f27fc6258eef233e811ed2f71168ef2229c236ada + checksum: 3d55f31ec0d008e7c8e8db0dc03e6e4f2cf8365f6578a0929b7098753c9db3c7de56a134d011fb3c9d8af8b004f0776169194cdfa25654af4919634cdb6ba7b0 languageName: node linkType: hard -"postcss-normalize-timing-functions@npm:^5.1.0": - version: 5.1.0 - resolution: "postcss-normalize-timing-functions@npm:5.1.0" +"postcss-normalize-timing-functions@npm:^6.0.0": + version: 6.0.0 + resolution: "postcss-normalize-timing-functions@npm:6.0.0" dependencies: postcss-value-parser: ^4.2.0 peerDependencies: postcss: ^8.2.15 - checksum: da550f50e90b0b23e17b67449a7d1efd1aa68288e66d4aa7614ca6f5cc012896be1972b7168eee673d27da36504faccf7b9f835c0f7e81243f966a42c8c030aa + checksum: 67021374f8f18474788d8bc99d31af6a13efc5baf961c1e9f0c6b1e265fb21ac1ad56c489d988fcde9e0d049e9b62c8b0b350cc1e79d7d3bff9f00f7c97d6221 languageName: node linkType: hard -"postcss-normalize-unicode@npm:^5.1.0": - version: 5.1.0 - resolution: "postcss-normalize-unicode@npm:5.1.0" +"postcss-normalize-unicode@npm:^6.0.0": + version: 6.0.0 + resolution: "postcss-normalize-unicode@npm:6.0.0" dependencies: - browserslist: ^4.16.6 + browserslist: ^4.21.4 postcss-value-parser: ^4.2.0 peerDependencies: postcss: ^8.2.15 - checksum: 3570c90050f190811b5dbf7b4cf4f30f0b627c1ba5fbe5ad332e8b0aa7ef14b3d0aa2af1cb1074d0267aec8c9771e28866d867c8a8a0c433b6c34e50445f9c16 + checksum: 0f246bf5511ae2294d8ec0decda6abee58c62e301a3a8f6542fa090bb426359caee156b96cc1e7f4b3a3f2cd9f62b410a446cf101e710d8fa71c704cfb057a5d languageName: node linkType: hard -"postcss-normalize-url@npm:^5.1.0": - version: 5.1.0 - resolution: "postcss-normalize-url@npm:5.1.0" - dependencies: - normalize-url: ^6.0.1 - postcss-value-parser: ^4.2.0 - peerDependencies: - postcss: ^8.2.15 - checksum: 3bd4b3246d6600230bc827d1760b24cb3101827ec97570e3016cbe04dc0dd28f4dbe763245d1b9d476e182c843008fbea80823061f1d2219b96f0d5c724a24c0 - languageName: node - linkType: hard - -"postcss-normalize-whitespace@npm:^5.1.1": - version: 5.1.1 - resolution: "postcss-normalize-whitespace@npm:5.1.1" +"postcss-normalize-url@npm:^6.0.0": + version: 6.0.0 + resolution: "postcss-normalize-url@npm:6.0.0" dependencies: postcss-value-parser: ^4.2.0 peerDependencies: postcss: ^8.2.15 - checksum: 12d8fb6d1c1cba208cc08c1830959b7d7ad447c3f5581873f7e185f99a9a4230c43d3af21ca12c818e4690a5085a95b01635b762ad4a7bef69d642609b4c0e19 + checksum: 93160c02e54c45cbe8ade7122bf34e25c41ac39656b2ddb15d342ce557efc17873fc6dd1439dd8d814152ebdfbba3ee2c16601d41b085ecaad73e6f2d037cd43 languageName: node linkType: hard -"postcss-ordered-values@npm:^5.1.1": - version: 5.1.1 - resolution: "postcss-ordered-values@npm:5.1.1" +"postcss-normalize-whitespace@npm:^6.0.0": + version: 6.0.0 + resolution: "postcss-normalize-whitespace@npm:6.0.0" dependencies: - cssnano-utils: ^3.1.0 postcss-value-parser: ^4.2.0 peerDependencies: postcss: ^8.2.15 - checksum: d56825ef03225ccaeff9704b86008d012b91b0ace4b219f6d443aca628b7f0a1da922abc4a3fb8ca802baf09320abaa983f278ac416e1caf2658d119491686a4 + checksum: 77940955fb0b47b46468a3e17bb9b86eb2f2c572649271a4db600b981f68c9c1ed71197b58d7a351c1b2d1aee2eb79b1e11b3021eb28604fd1a8d0ded21dfb2a languageName: node linkType: hard -"postcss-reduce-initial@npm:^5.1.0": - version: 5.1.0 - resolution: "postcss-reduce-initial@npm:5.1.0" +"postcss-ordered-values@npm:^6.0.0": + version: 6.0.0 + resolution: "postcss-ordered-values@npm:6.0.0" dependencies: - browserslist: ^4.16.6 + cssnano-utils: ^4.0.0 + postcss-value-parser: ^4.2.0 + peerDependencies: + postcss: ^8.2.15 + checksum: 162d60e9fd7d6717457194e943ba63ed6d149ae3b4f150324e65b485312be5d1c99ae140e47698e9f8943967c1575b65c922081263a8fa22a2489ed705eb0202 + languageName: node + linkType: hard + +"postcss-reduce-initial@npm:^6.0.0": + version: 6.0.0 + resolution: "postcss-reduce-initial@npm:6.0.0" + dependencies: + browserslist: ^4.21.4 caniuse-api: ^3.0.0 peerDependencies: postcss: ^8.2.15 - checksum: 2cb10fa3fa7d7df9e4376df64d19177debd5cfe6d8fde52327d27de425eb28d5d85fa45c857cf7c0aed35d16455b6f4762b53959480f92a1dfa4b51a1d780a32 + checksum: 988001da75b969733756d9cec9bb37cfae9a667c888c0394d8aa84af7fa6fe134cdd997b63d657900f72541310c5a396db3436367bf91908bc4c7f7ce965c511 languageName: node linkType: hard -"postcss-reduce-transforms@npm:^5.1.0": - version: 5.1.0 - resolution: "postcss-reduce-transforms@npm:5.1.0" +"postcss-reduce-transforms@npm:^6.0.0": + version: 6.0.0 + resolution: "postcss-reduce-transforms@npm:6.0.0" dependencies: postcss-value-parser: ^4.2.0 peerDependencies: postcss: ^8.2.15 - checksum: 0c6af2cba20e3ff63eb9ad045e634ddfb9c3e5c0e614c020db2a02f3aa20632318c4ede9e0c995f9225d9a101e673de91c0a6e10bb2fa5da6d6c75d15a55882f + checksum: 17c27b1858897ee37a4f80af0d76c5ce895466392acac1ead75cbb71ac290ab57b209f47d5d205f6ea60c1697109f09531de005ef17d8826d545bbc02891351a languageName: node linkType: hard @@ -26073,7 +26112,7 @@ __metadata: languageName: node linkType: hard -"postcss-selector-parser@npm:^6.0.13": +"postcss-selector-parser@npm:^6.0.11, postcss-selector-parser@npm:^6.0.13": version: 6.0.13 resolution: "postcss-selector-parser@npm:6.0.13" dependencies: @@ -26093,16 +26132,6 @@ __metadata: languageName: node linkType: hard -"postcss-selector-parser@npm:^6.0.9": - version: 6.0.9 - resolution: "postcss-selector-parser@npm:6.0.9" - dependencies: - cssesc: ^3.0.0 - util-deprecate: ^1.0.2 - checksum: f8161ab4d3e5c76b8467189c6d164ba0f6b6e74677435f29e34caa1df01e052b582b4ae4f7468b2243c4befdd8bdcdb7685542d1b2fca8deae21b3e849c78802 - languageName: node - linkType: hard - "postcss-sorting@npm:^7.0.1": version: 7.0.1 resolution: "postcss-sorting@npm:7.0.1" @@ -26112,26 +26141,26 @@ __metadata: languageName: node linkType: hard -"postcss-svgo@npm:^5.1.0": - version: 5.1.0 - resolution: "postcss-svgo@npm:5.1.0" +"postcss-svgo@npm:^6.0.0": + version: 6.0.0 + resolution: "postcss-svgo@npm:6.0.0" dependencies: postcss-value-parser: ^4.2.0 - svgo: ^2.7.0 + svgo: ^3.0.2 peerDependencies: postcss: ^8.2.15 - checksum: d86eb5213d9f700cf5efe3073799b485fb7cacae0c731db3d7749c9c2b1c9bc85e95e0baeca439d699ff32ea24815fc916c4071b08f67ed8219df229ce1129bd + checksum: 14c68b7c275dbbbbf1f954e313ff812dacea88970165d7859c1683e2530ea51cd333372b8c0d440d4e9525768f34a8dab5f0846d3445bbb478a87a99f69e9abb languageName: node linkType: hard -"postcss-unique-selectors@npm:^5.1.1": - version: 5.1.1 - resolution: "postcss-unique-selectors@npm:5.1.1" +"postcss-unique-selectors@npm:^6.0.0": + version: 6.0.0 + resolution: "postcss-unique-selectors@npm:6.0.0" dependencies: postcss-selector-parser: ^6.0.5 peerDependencies: postcss: ^8.2.15 - checksum: 637e7b786e8558265775c30400c54b6b3b24d4748923f4a39f16a65fd0e394f564ccc9f0a1d3c0e770618a7637a7502ea1d0d79f731d429cb202255253c23278 + checksum: 5fbfeaf796c6442853ce3afd03ae8c306fcb83b0b7ee59cbdc9aad57a1e601e65a2a5efd1e25edaa5c7c62e05d3795f357fe95933de0868a78a5d1d1f541be34 languageName: node linkType: hard @@ -26171,17 +26200,6 @@ __metadata: languageName: node linkType: hard -"postcss@npm:^8.4.17": - version: 8.4.18 - resolution: "postcss@npm:8.4.18" - dependencies: - nanoid: ^3.3.4 - picocolors: ^1.0.0 - source-map-js: ^1.0.2 - checksum: 9349fd99849b2e3d2e134ff949b7770ecb12375f352723ce2bcc06167eba3850ea7844c1b191a85cd915d6a396b4e8ee9a5267e6cc5d8d003d0cbc7a97555d39 - languageName: node - linkType: hard - "postcss@npm:^8.4.24": version: 8.4.25 resolution: "postcss@npm:8.4.25" @@ -29188,6 +29206,18 @@ __metadata: languageName: node linkType: hard +"schema-utils@npm:^4.0.1": + version: 4.2.0 + resolution: "schema-utils@npm:4.2.0" + dependencies: + "@types/json-schema": ^7.0.9 + ajv: ^8.9.0 + ajv-formats: ^2.1.1 + ajv-keywords: ^5.1.0 + checksum: 26a0463d47683258106e6652e9aeb0823bf0b85843039e068b57da1892f7ae6b6b1094d48e9ed5ba5cbe9f7166469d880858b9d91abe8bd249421eb813850cde + languageName: node + linkType: hard + "screenfull@npm:^5.1.0": version: 5.1.0 resolution: "screenfull@npm:5.1.0" @@ -30147,13 +30177,6 @@ __metadata: languageName: node linkType: hard -"stable@npm:^0.1.8": - version: 0.1.8 - resolution: "stable@npm:0.1.8" - checksum: 2ff482bb100285d16dd75cd8f7c60ab652570e8952c0bfa91828a2b5f646a0ff533f14596ea4eabd48bb7f4aeea408dce8f8515812b975d958a4cc4fa6b9dfeb - languageName: node - linkType: hard - "stack-generator@npm:^2.0.5": version: 2.0.5 resolution: "stack-generator@npm:2.0.5" @@ -30625,15 +30648,15 @@ __metadata: languageName: node linkType: hard -"stylehacks@npm:^5.1.0": - version: 5.1.0 - resolution: "stylehacks@npm:5.1.0" +"stylehacks@npm:^6.0.0": + version: 6.0.0 + resolution: "stylehacks@npm:6.0.0" dependencies: - browserslist: ^4.16.6 + browserslist: ^4.21.4 postcss-selector-parser: ^6.0.4 peerDependencies: postcss: ^8.2.15 - checksum: 310b3452c11fd443b0d327aa2d5b43ae7479407339204b7ad11cf2e16d33b690c1cbf47a21b737ef112411e53563f0f996c5fa3642d135c896329950a008277f + checksum: b6071ab5f4451576e3a445f7304b41c43329f84d7a7987a91442febaabc1de51e62f1e37c4f37fad21990d3f573a8110bd31e09f9df7b8628465e19b1cdc702b languageName: node linkType: hard @@ -30819,20 +30842,19 @@ __metadata: languageName: node linkType: hard -"svgo@npm:^2.7.0": - version: 2.8.0 - resolution: "svgo@npm:2.8.0" +"svgo@npm:^3.0.2": + version: 3.0.2 + resolution: "svgo@npm:3.0.2" dependencies: "@trysound/sax": 0.2.0 commander: ^7.2.0 - css-select: ^4.1.3 - css-tree: ^1.1.3 - csso: ^4.2.0 + css-select: ^5.1.0 + css-tree: ^2.2.1 + csso: ^5.0.5 picocolors: ^1.0.0 - stable: ^0.1.8 bin: svgo: bin/svgo - checksum: b92f71a8541468ffd0b81b8cdb36b1e242eea320bf3c1a9b2c8809945853e9d8c80c19744267eb91cabf06ae9d5fff3592d677df85a31be4ed59ff78534fa420 + checksum: 381ba14aa782e71ab7033227634a3041c11fa3e2769aeaf0df43a08a615de61925108e34f55af6e7c5146f4a3109e78deabb4fa9d687e36d45d1f848b4e23d17 languageName: node linkType: hard @@ -33518,7 +33540,7 @@ __metadata: languageName: node linkType: hard -"yaml@npm:^1.10.0, yaml@npm:^1.10.2, yaml@npm:^1.7.2": +"yaml@npm:^1.10.0, yaml@npm:^1.7.2": version: 1.10.2 resolution: "yaml@npm:1.10.2" checksum: ce4ada136e8a78a0b08dc10b4b900936912d15de59905b2bf415b4d33c63df1d555d23acb2a41b23cf9fb5da41c256441afca3d6509de7247daa062fd2c5ea5f From bb48417ba05dad6931de6d7264a0c0ba913a927f Mon Sep 17 00:00:00 2001 From: Laura Benz <48948963+L-M-K-B@users.noreply.github.com> Date: Thu, 13 Jul 2023 17:00:28 +0200 Subject: [PATCH 07/42] refactor: remove cta for users with reading rights (#71380) * refactor: remove cta for users with reading rights * feat: add tests * refactor: replace folder uid * refactor: replace folder uid --- .../components/BrowseView.test.tsx | 15 ++++++++++- .../components/BrowseView.tsx | 25 +++++++++++-------- 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/public/app/features/browse-dashboards/components/BrowseView.test.tsx b/public/app/features/browse-dashboards/components/BrowseView.test.tsx index 608bdd6490c..b0a1ade87f1 100644 --- a/public/app/features/browse-dashboards/components/BrowseView.test.tsx +++ b/public/app/features/browse-dashboards/components/BrowseView.test.tsx @@ -9,7 +9,8 @@ import { wellFormedTree } from '../fixtures/dashboardsTreeItem.fixture'; import { BrowseView } from './BrowseView'; -const [mockTree, { folderA, folderA_folderA, folderA_folderB, folderA_folderB_dashbdB, dashbdD }] = wellFormedTree(); +const [mockTree, { folderA, folderA_folderA, folderA_folderB, folderA_folderB_dashbdB, dashbdD, folderB_empty }] = + wellFormedTree(); function render(...[ui, options]: Parameters) { rtlRender({ui}, options); @@ -143,6 +144,18 @@ describe('browse-dashboards BrowseView', () => { expect(grandparentCheckbox).not.toBeChecked(); expect(grandparentCheckbox).toBePartiallyChecked(); }); + + describe('when there is no item in the folder', () => { + it('shows a CTA for creating a dashboard if the user has editor rights', async () => { + render(); + expect(await screen.findByText('Create Dashboard')).toBeInTheDocument(); + }); + + it('shows a simple message if the user has viewer rights', async () => { + render(); + expect(await screen.findByText('This folder is empty')).toBeInTheDocument(); + }); + }); }); async function expandFolder(uid: string) { diff --git a/public/app/features/browse-dashboards/components/BrowseView.tsx b/public/app/features/browse-dashboards/components/BrowseView.tsx index 21baa345355..4c657da02db 100644 --- a/public/app/features/browse-dashboards/components/BrowseView.tsx +++ b/public/app/features/browse-dashboards/components/BrowseView.tsx @@ -1,5 +1,6 @@ import React, { useCallback } from 'react'; +import { CallToActionCard } from '@grafana/ui'; import EmptyListCTA from 'app/core/components/EmptyListCTA/EmptyListCTA'; import { DashboardViewItem } from 'app/features/search/types'; import { useDispatch } from 'app/types'; @@ -115,16 +116,20 @@ export function BrowseView({ folderUID, width, height, canSelect }: BrowseViewPr if (status === 'fulfilled' && flatTree.length === 0) { return (
- '} - proTipLink={folderUID && 'dashboards'} - proTipLinkTitle={folderUID && 'Browse dashboards'} - proTipTarget="" - /> + {canSelect ? ( + '} + proTipLink={folderUID && 'dashboards'} + proTipLinkTitle={folderUID && 'Browse dashboards'} + proTipTarget="" + /> + ) : ( + This folder is empty} /> + )}
); } From 718401d2501345bd4c1925aba1b2c58ea89fa730 Mon Sep 17 00:00:00 2001 From: Sonia Aguilar <33540275+soniaAguilarPeiron@users.noreply.github.com> Date: Thu, 13 Jul 2023 17:02:47 +0200 Subject: [PATCH 08/42] Alerting: Add smart type selection when creating a new alert rule (#71071) * Add smart type selection when creating a new alert rule * Auto switch when switch button has not been clicked yet * remove unnecessay code after the last refacgtor * Refactor * Remove unneeded prop * Move SmartAlertTypeDetector to its own file * Fix tests * Refactor: new useSetExpressionAndDataSource hook * Fix expressions not been propagated when switching from one type to another * Change texts * Update tests * Update text in switch button * Update texts and tests * Refactor: move code to getCanSwitch new method * Move smart alert after queries and remove auto-switch * Remove expressions and restore them when switching between grafana and cloud type * Rename previous expression state * Fix tests * Add data source name for data source-managed alert selection * Update reducer when changing cloud data source * PR review suggestions * PR review suggestions 2nd part * PR review suggestions 3th part * Fix canSwitch * Update texts on smart alert --------- Co-authored-by: Virginia Cepeda --- .../RuleEditorCloudOnlyAllowed.test.tsx | 135 +++++++------ .../unified/RuleEditorCloudRules.test.tsx | 53 ++++-- .../AlertType.test.tsx | 91 --------- ...rtType.tsx => CloudDataSourceSelector.tsx} | 53 +----- .../QueryAndExpressionsStep.tsx | 170 ++++++++++++++--- .../SmartAlertTypeDetector.tsx | 180 ++++++++++++++++++ .../query-and-alert-condition/reducer.ts | 8 + public/test/helpers/alertingRuleEditor.tsx | 3 - 8 files changed, 460 insertions(+), 233 deletions(-) delete mode 100644 public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/AlertType.test.tsx rename public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/{AlertType.tsx => CloudDataSourceSelector.tsx} (55%) create mode 100644 public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/SmartAlertTypeDetector.tsx diff --git a/public/app/features/alerting/unified/RuleEditorCloudOnlyAllowed.test.tsx b/public/app/features/alerting/unified/RuleEditorCloudOnlyAllowed.test.tsx index 01c66b8cf27..b1a2a6ea4fc 100644 --- a/public/app/features/alerting/unified/RuleEditorCloudOnlyAllowed.test.tsx +++ b/public/app/features/alerting/unified/RuleEditorCloudOnlyAllowed.test.tsx @@ -36,6 +36,75 @@ jest.mock('app/features/query/components/QueryEditorRow', () => ({ QueryEditorRow: () =>

hi

, })); +jest.mock('./components/rule-editor/util', () => { + const originalModule = jest.requireActual('./components/rule-editor/util'); + return { + ...originalModule, + getThresholdsForQueries: jest.fn(() => ({})), + }; +}); + +const dataSources = { + // can edit rules + loki: mockDataSource( + { + type: DataSourceType.Loki, + name: 'loki with ruler', + }, + { alerting: true } + ), + loki_disabled: mockDataSource( + { + type: DataSourceType.Loki, + name: 'loki disabled for alerting', + jsonData: { + manageAlerts: false, + }, + }, + { alerting: true } + ), + // can edit rules + prom: mockDataSource( + { + type: DataSourceType.Prometheus, + name: 'cortex with ruler', + }, + { alerting: true } + ), + // cannot edit rules + loki_local_rule_store: mockDataSource( + { + type: DataSourceType.Loki, + name: 'loki with local rule store', + }, + { alerting: true } + ), + // cannot edit rules + prom_no_ruler_api: mockDataSource( + { + type: DataSourceType.Loki, + name: 'cortex without ruler api', + }, + { alerting: true } + ), + // not a supported datasource type + splunk: mockDataSource( + { + type: 'splunk', + name: 'splunk', + }, + { alerting: true } + ), +}; + +jest.mock('@grafana/runtime', () => ({ + ...jest.requireActual('@grafana/runtime'), + getDataSourceSrv: jest.fn(() => ({ + getInstanceSettings: () => dataSources.prom, + get: () => dataSources.prom, + })), +})); + jest.spyOn(config, 'getAllDataSources'); const mocks = { @@ -74,59 +143,6 @@ describe('RuleEditor cloud: checking editable data sources', () => { disableRBAC(); it('for cloud alerts, should only allow to select editable rules sources', async () => { - const dataSources = { - // can edit rules - loki: mockDataSource( - { - type: DataSourceType.Loki, - name: 'loki with ruler', - }, - { alerting: true } - ), - loki_disabled: mockDataSource( - { - type: DataSourceType.Loki, - name: 'loki disabled for alerting', - jsonData: { - manageAlerts: false, - }, - }, - { alerting: true } - ), - // can edit rules - prom: mockDataSource( - { - type: DataSourceType.Prometheus, - name: 'cortex with ruler', - }, - { alerting: true } - ), - // cannot edit rules - loki_local_rule_store: mockDataSource( - { - type: DataSourceType.Loki, - name: 'loki with local rule store', - }, - { alerting: true } - ), - // cannot edit rules - prom_no_ruler_api: mockDataSource( - { - type: DataSourceType.Loki, - name: 'cortex without ruler api', - }, - { alerting: true } - ), - // not a supported datasource type - splunk: mockDataSource( - { - type: 'splunk', - name: 'splunk', - }, - { alerting: true } - ), - }; - mocks.api.discoverFeatures.mockImplementation(async (dataSourceName) => { if (dataSourceName === 'loki with ruler' || dataSourceName === 'cortex with ruler') { return getDiscoverFeaturesMock(PromApplication.Cortex, { rulerApiEnabled: true }); @@ -168,11 +184,22 @@ describe('RuleEditor cloud: checking editable data sources', () => { await waitForElementToBeRemoved(screen.getAllByTestId('Spinner')); await ui.inputs.name.find(); - await userEvent.click(await ui.buttons.lotexAlert.get()); + + const removeExpressionsButtons = screen.getAllByLabelText('Remove expression'); + expect(removeExpressionsButtons).toHaveLength(2); + + const switchToCloudButton = screen.getByText('Switch to data source-managed alert rule'); + expect(switchToCloudButton).toBeInTheDocument(); + + await userEvent.click(switchToCloudButton); + + //expressions are removed after switching to data-source managed + expect(screen.queryAllByLabelText('Remove expression')).toHaveLength(0); // check that only rules sources that have ruler available are there const dataSourceSelect = ui.inputs.dataSource.get(); await userEvent.click(byRole('combobox').get(dataSourceSelect)); + expect(await byText('loki with ruler').query()).toBeInTheDocument(); expect(byText('cortex with ruler').query()).toBeInTheDocument(); expect(byText('loki with local rule store').query()).not.toBeInTheDocument(); diff --git a/public/app/features/alerting/unified/RuleEditorCloudRules.test.tsx b/public/app/features/alerting/unified/RuleEditorCloudRules.test.tsx index 0ed3e4bf9bc..228a0980ade 100644 --- a/public/app/features/alerting/unified/RuleEditorCloudRules.test.tsx +++ b/public/app/features/alerting/unified/RuleEditorCloudRules.test.tsx @@ -1,4 +1,4 @@ -import { waitFor, screen, within, waitForElementToBeRemoved } from '@testing-library/react'; +import { screen, waitFor, waitForElementToBeRemoved, within } from '@testing-library/react'; import userEvent, { PointerEventsCheckLevel } from '@testing-library/user-event'; import React from 'react'; import { renderRuleEditor, ui } from 'test/helpers/alertingRuleEditor'; @@ -36,6 +36,33 @@ jest.mock('app/features/query/components/QueryEditorRow', () => ({ QueryEditorRow: () =>

hi

, })); +jest.mock('./components/rule-editor/util', () => { + const originalModule = jest.requireActual('./components/rule-editor/util'); + return { + ...originalModule, + getThresholdsForQueries: jest.fn(() => ({})), + }; +}); + +const dataSources = { + default: mockDataSource( + { + type: 'prometheus', + name: 'Prom', + isDefault: true, + }, + { alerting: true } + ), +}; + +jest.mock('@grafana/runtime', () => ({ + ...jest.requireActual('@grafana/runtime'), + getDataSourceSrv: jest.fn(() => ({ + getInstanceSettings: () => dataSources.default, + get: () => dataSources.default, + })), +})); + jest.mock('app/core/components/AppChrome/AppChromeUpdate', () => ({ AppChromeUpdate: ({ actions }: { actions: React.ReactNode }) =>
{actions}
, })); @@ -73,17 +100,6 @@ describe('RuleEditor cloud', () => { disableRBAC(); it('can create a new cloud alert', async () => { - const dataSources = { - default: mockDataSource( - { - type: 'prometheus', - name: 'Prom', - isDefault: true, - }, - { alerting: true } - ), - }; - setDataSourceSrv(new MockDataSourceSrv(dataSources)); mocks.getAllDataSources.mockReturnValue(Object.values(dataSources)); mocks.api.setRulerRuleGroup.mockResolvedValue(); @@ -118,7 +134,18 @@ describe('RuleEditor cloud', () => { renderRuleEditor(); await waitForElementToBeRemoved(screen.getAllByTestId('Spinner')); - await userEvent.click(await ui.buttons.lotexAlert.find()); + const removeExpressionsButtons = screen.getAllByLabelText('Remove expression'); + expect(removeExpressionsButtons).toHaveLength(2); + + const switchToCloudButton = screen.getByText('Switch to data source-managed alert rule'); + expect(switchToCloudButton).toBeInTheDocument(); + + await userEvent.click(switchToCloudButton); + + //expressions are removed after switching to data-source managed + expect(screen.queryAllByLabelText('Remove expression')).toHaveLength(0); + + expect(screen.getByTestId('datasource-picker')).toBeInTheDocument(); const dataSourceSelect = ui.inputs.dataSource.get(); await userEvent.click(byRole('combobox').get(dataSourceSelect)); diff --git a/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/AlertType.test.tsx b/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/AlertType.test.tsx deleted file mode 100644 index 14041e827bb..00000000000 --- a/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/AlertType.test.tsx +++ /dev/null @@ -1,91 +0,0 @@ -import { render } from '@testing-library/react'; -import React from 'react'; -import { FormProvider, useForm } from 'react-hook-form'; -import { Provider } from 'react-redux'; -import { Router } from 'react-router-dom'; -import { byText } from 'testing-library-selector'; - -import { locationService } from '@grafana/runtime'; -import { contextSrv } from 'app/core/services/context_srv'; -import { configureStore } from 'app/store/configureStore'; -import { AccessControlAction } from 'app/types'; - -import { AlertType } from './AlertType'; - -const ui = { - ruleTypePicker: { - grafanaManagedButton: byText('Grafana managed alert'), - mimirOrLokiButton: byText('Mimir or Loki alert'), - mimirOrLokiRecordingButton: byText('Mimir or Loki recording rule'), - }, -}; - -const FormProviderWrapper = ({ children }: React.PropsWithChildren<{}>) => { - const methods = useForm({}); - return {children}; -}; - -function renderAlertTypeStep() { - const store = configureStore(); - - render( - - - - - , - { wrapper: FormProviderWrapper } - ); -} - -describe('RuleTypePicker', () => { - describe('RBAC', () => { - it('Should display grafana and mimir alert when user has rule create and write permissions', async () => { - jest.spyOn(contextSrv, 'hasPermission').mockImplementation((action) => { - return [AccessControlAction.AlertingRuleCreate, AccessControlAction.AlertingRuleExternalWrite].includes( - action as AccessControlAction - ); - }); - - renderAlertTypeStep(); - - expect(ui.ruleTypePicker.grafanaManagedButton.get()).toBeInTheDocument(); - expect(ui.ruleTypePicker.mimirOrLokiButton.get()).toBeInTheDocument(); - }); - - it('Should not display the recording rule button', async () => { - jest.spyOn(contextSrv, 'hasPermission').mockImplementation((action) => { - return [AccessControlAction.AlertingRuleCreate, AccessControlAction.AlertingRuleExternalWrite].includes( - action as AccessControlAction - ); - }); - - renderAlertTypeStep(); - expect(ui.ruleTypePicker.mimirOrLokiRecordingButton.query()).not.toBeInTheDocument(); - }); - - it('Should hide grafana button when user does not have rule create permission', () => { - jest.spyOn(contextSrv, 'hasPermission').mockImplementation((action) => { - return [AccessControlAction.AlertingRuleExternalWrite].includes(action as AccessControlAction); - }); - - renderAlertTypeStep(); - - expect(ui.ruleTypePicker.grafanaManagedButton.query()).not.toBeInTheDocument(); - expect(ui.ruleTypePicker.mimirOrLokiButton.get()).toBeInTheDocument(); - expect(ui.ruleTypePicker.mimirOrLokiRecordingButton.query()).not.toBeInTheDocument(); - }); - - it('Should hide mimir alert and mimir recording when user does not have rule external write permission', () => { - jest.spyOn(contextSrv, 'hasPermission').mockImplementation((action) => { - return [AccessControlAction.AlertingRuleCreate].includes(action as AccessControlAction); - }); - - renderAlertTypeStep(); - - expect(ui.ruleTypePicker.grafanaManagedButton.get()).toBeInTheDocument(); - expect(ui.ruleTypePicker.mimirOrLokiButton.query()).not.toBeInTheDocument(); - expect(ui.ruleTypePicker.mimirOrLokiRecordingButton.query()).not.toBeInTheDocument(); - }); - }); -}); diff --git a/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/AlertType.tsx b/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/CloudDataSourceSelector.tsx similarity index 55% rename from public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/AlertType.tsx rename to public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/CloudDataSourceSelector.tsx index a11a2884077..c8140a5eec1 100644 --- a/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/AlertType.tsx +++ b/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/CloudDataSourceSelector.tsx @@ -4,24 +4,17 @@ import { useFormContext } from 'react-hook-form'; import { DataSourceInstanceSettings, GrafanaTheme2 } from '@grafana/data'; import { Field, InputControl, useStyles2 } from '@grafana/ui'; -import { contextSrv } from 'app/core/services/context_srv'; -import { AccessControlAction } from 'app/types'; import { RuleFormType, RuleFormValues } from '../../../types/rule-form'; import { CloudRulesSourcePicker } from '../CloudRulesSourcePicker'; -import { RuleTypePicker } from '../rule-types/RuleTypePicker'; -interface Props { - editingExistingRule: boolean; +export interface CloudDataSourceSelectorProps { + onChangeCloudDatasource: (datasourceUid: string) => void; } - -export const AlertType = ({ editingExistingRule }: Props) => { - const { enabledRuleTypes, defaultRuleType } = getAvailableRuleTypes(); - +export const CloudDataSourceSelector = ({ onChangeCloudDatasource }: CloudDataSourceSelectorProps) => { const { control, formState: { errors }, - getValues, setValue, watch, } = useFormContext(); @@ -31,26 +24,6 @@ export const AlertType = ({ editingExistingRule }: Props) => { return ( <> - {!editingExistingRule && ruleFormType !== RuleFormType.cloudRecording && ( - - ( - - )} - name="type" - control={control} - rules={{ - required: { value: true, message: 'Please select alert type' }, - }} - /> - - )} -
{(ruleFormType === RuleFormType.cloudAlerting || ruleFormType === RuleFormType.cloudRecording) && ( { // reset expression as they don't need to persist after changing datasources setValue('expression', ''); onChange(ds?.name ?? null); + onChangeCloudDatasource(ds?.uid ?? null); }} /> )} @@ -86,25 +60,6 @@ export const AlertType = ({ editingExistingRule }: Props) => { ); }; -function getAvailableRuleTypes() { - const canCreateGrafanaRules = contextSrv.hasAccess( - AccessControlAction.AlertingRuleCreate, - contextSrv.hasEditPermissionInFolders - ); - const canCreateCloudRules = contextSrv.hasAccess(AccessControlAction.AlertingRuleExternalWrite, contextSrv.isEditor); - const defaultRuleType = canCreateGrafanaRules ? RuleFormType.grafana : RuleFormType.cloudAlerting; - - const enabledRuleTypes: RuleFormType[] = []; - if (canCreateGrafanaRules) { - enabledRuleTypes.push(RuleFormType.grafana); - } - if (canCreateCloudRules) { - enabledRuleTypes.push(RuleFormType.cloudAlerting, RuleFormType.cloudRecording); - } - - return { enabledRuleTypes, defaultRuleType }; -} - const getStyles = (theme: GrafanaTheme2) => ({ formInput: css` width: 330px; diff --git a/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/QueryAndExpressionsStep.tsx b/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/QueryAndExpressionsStep.tsx index 6d83fa64b36..1118e04c4fb 100644 --- a/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/QueryAndExpressionsStep.tsx +++ b/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/QueryAndExpressionsStep.tsx @@ -1,5 +1,6 @@ import { css } from '@emotion/css'; -import React, { useCallback, useEffect, useMemo, useReducer } from 'react'; +import { cloneDeep } from 'lodash'; +import React, { useCallback, useEffect, useMemo, useReducer, useState } from 'react'; import { useFormContext } from 'react-hook-form'; import { getDefaultRelativeTimeRange, GrafanaTheme2 } from '@grafana/data'; @@ -9,13 +10,15 @@ import { config, getDataSourceSrv } from '@grafana/runtime'; import { Alert, Button, Dropdown, Field, Icon, InputControl, Menu, MenuItem, Tooltip, useStyles2 } from '@grafana/ui'; import { H5 } from '@grafana/ui/src/unstable'; import { isExpressionQuery } from 'app/features/expressions/guards'; -import { ExpressionQueryType, expressionTypes } from 'app/features/expressions/types'; +import { ExpressionDatasourceUID, ExpressionQueryType, expressionTypes } from 'app/features/expressions/types'; +import { useDispatch } from 'app/types'; import { AlertQuery } from 'app/types/unified-alerting-dto'; import { useRulesSourcesWithRuler } from '../../../hooks/useRuleSourcesWithRuler'; +import { fetchAllPromBuildInfoAction } from '../../../state/actions'; import { RuleFormType, RuleFormValues } from '../../../types/rule-form'; import { getDefaultOrFirstCompatibleDataSource } from '../../../utils/datasource'; -import { isPromOrLokiQuery } from '../../../utils/rule-form'; +import { isPromOrLokiQuery, PromOrLokiQuery } from '../../../utils/rule-form'; import { ExpressionEditor } from '../ExpressionEditor'; import { ExpressionsEditor } from '../ExpressionsEditor'; import { NeedHelpInfo } from '../NeedHelpInfo'; @@ -24,13 +27,16 @@ import { RecordingRuleEditor } from '../RecordingRuleEditor'; import { RuleEditorSection } from '../RuleEditorSection'; import { errorFromSeries, refIdExists } from '../util'; -import { AlertType } from './AlertType'; +import { CloudDataSourceSelector } from './CloudDataSourceSelector'; +import { SmartAlertTypeDetector } from './SmartAlertTypeDetector'; import { + addExpressions, addNewDataQuery, addNewExpression, duplicateQuery, queriesAndExpressionsReducer, removeExpression, + removeExpressions, rewireExpressions, setDataQueries, setRecordingRulesQueries, @@ -68,6 +74,11 @@ export const QueryAndExpressionsStep = ({ editingExistingRule, onDataChange }: P const isRecordingRuleType = type === RuleFormType.cloudRecording; const isCloudAlertRuleType = type === RuleFormType.cloudAlerting; + const dispatchReduxAction = useDispatch(); + useEffect(() => { + dispatchReduxAction(fetchAllPromBuildInfoAction()); + }, [dispatchReduxAction]); + const rulesSourcesWithRuler = useRulesSourcesWithRuler(); const runQueriesPreview = useCallback(() => { @@ -135,6 +146,8 @@ export const QueryAndExpressionsStep = ({ editingExistingRule, onDataChange }: P [condition, queries, handleSetCondition] ); + const updateExpressionAndDatasource = useSetExpressionAndDataSource(); + const onChangeQueries = useCallback( (updatedQueries: AlertQuery[]) => { // Most data sources triggers onChange and onRunQueries consecutively @@ -144,6 +157,8 @@ export const QueryAndExpressionsStep = ({ editingExistingRule, onDataChange }: P // This way we can access up to date queries in runQueriesPreview without waiting for re-render setValue('queries', updatedQueries, { shouldValidate: false }); + updateExpressionAndDatasource(updatedQueries); + dispatch(setDataQueries(updatedQueries)); dispatch(updateExpressionTimeRange()); // check if we need to rewire expressions @@ -156,7 +171,7 @@ export const QueryAndExpressionsStep = ({ editingExistingRule, onDataChange }: P } }); }, - [queries, setValue] + [queries, setValue, updateExpressionAndDatasource] ); const onChangeRecordingRulesQueries = useCallback( @@ -236,9 +251,84 @@ export const QueryAndExpressionsStep = ({ editingExistingRule, onDataChange }: P const styles = useStyles2(getStyles); + // Cloud alerts load data from form values + // whereas Grafana managed alerts load data from reducer + //when data source is changed in the cloud selector we need to update the queries in the reducer + + const onChangeCloudDatasource = useCallback( + (datasourceUid: string) => { + const newQueries = cloneDeep(queries); + newQueries[0].datasourceUid = datasourceUid; + setValue('queries', newQueries, { shouldValidate: false }); + + updateExpressionAndDatasource(newQueries); + + dispatch(setDataQueries(newQueries)); + }, + [queries, setValue, updateExpressionAndDatasource, dispatch] + ); + + // ExpressionEditor for cloud query needs to update queries in the reducer and in the form + // otherwise the value is not updated for Grafana managed alerts + + const onChangeExpression = (value: string) => { + const newQueries = cloneDeep(queries); + + if (newQueries[0].model) { + if (isPromOrLokiQuery(newQueries[0].model)) { + newQueries[0].model.expr = value; + } else { + // first time we come from grafana-managed type + // we need to convert the model to PromOrLokiQuery + const promLoki: PromOrLokiQuery = { + ...cloneDeep(newQueries[0].model), + expr: value, + }; + newQueries[0].model = promLoki; + } + } + + setValue('queries', newQueries, { shouldValidate: false }); + + updateExpressionAndDatasource(newQueries); + + dispatch(setDataQueries(newQueries)); + runQueriesPreview(); + }; + + const removeExpressionsInQueries = useCallback(() => dispatch(removeExpressions()), [dispatch]); + + const addExpressionsInQueries = useCallback( + (expressions: AlertQuery[]) => dispatch(addExpressions(expressions)), + [dispatch] + ); + + // we need to keep track of the previous expressions to be able to restore them when switching back to grafana managed + const [prevExpressions, setPrevExpressions] = useState([]); + + const restoreExpressionsInQueries = useCallback(() => { + addExpressionsInQueries(prevExpressions); + }, [prevExpressions, addExpressionsInQueries]); + + const onClickSwitch = useCallback(() => { + const typeInForm = getValues('type'); + if (typeInForm === RuleFormType.cloudAlerting) { + setValue('type', RuleFormType.grafana); + setPrevExpressions.length > 0 && restoreExpressionsInQueries(); + } else { + setValue('type', RuleFormType.cloudAlerting); + const expressions = queries.filter((query) => query.datasourceUid === ExpressionDatasourceUID); + setPrevExpressions(expressions); + removeExpressionsInQueries(); + } + }, [getValues, setValue, queries, removeExpressionsInQueries, restoreExpressionsInQueries, setPrevExpressions]); + return ( - + {/* This is the cloud data source selector */} + {(type === RuleFormType.cloudRecording || type === RuleFormType.cloudAlerting) && ( + + )} {/* This is the PromQL Editor for recording rules */} {isRecordingRuleType && dataSourceName && ( @@ -255,24 +345,33 @@ export const QueryAndExpressionsStep = ({ editingExistingRule, onDataChange }: P {/* This is the PromQL Editor for Cloud rules */} {isCloudAlertRuleType && dataSourceName && ( - - { - return ( - - ); - }} - control={control} - rules={{ - required: { value: true, message: 'A valid expression is required' }, - }} + + + { + return ( + + ); + }} + control={control} + rules={{ + required: { value: true, message: 'A valid expression is required' }, + }} + /> + + - + )} {/* This is the editor for Grafana managed rules */} @@ -319,6 +418,12 @@ export const QueryAndExpressionsStep = ({ editingExistingRule, onDataChange }: P Add query + {/* Expression Queries */}
Expressions
Manipulate data returned from queries with math and other operations
@@ -418,3 +523,22 @@ const getStyles = (theme: GrafanaTheme2) => ({ color: ${theme.colors.text.link}; `, }); + +const useSetExpressionAndDataSource = () => { + const { setValue } = useFormContext(); + return (updatedQueries: AlertQuery[]) => { + // update data source name and expression if it's been changed in the queries from the reducer when prom or loki query + const query = updatedQueries[0]; + const dataSourceSettings = getDataSourceSrv().getInstanceSettings(query.datasourceUid); + if (!dataSourceSettings) { + throw new Error('The Data source has not been defined.'); + } + setValue('dataSourceName', dataSourceSettings.name); + + if (isPromOrLokiQuery(query.model)) { + const expression = query.model.expr; + + setValue('expression', expression); + } + }; +}; diff --git a/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/SmartAlertTypeDetector.tsx b/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/SmartAlertTypeDetector.tsx new file mode 100644 index 00000000000..067939436ee --- /dev/null +++ b/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/SmartAlertTypeDetector.tsx @@ -0,0 +1,180 @@ +import { css } from '@emotion/css'; +import React from 'react'; +import { useFormContext } from 'react-hook-form'; + +import { DataSourceInstanceSettings, GrafanaTheme2 } from '@grafana/data'; +import { Stack } from '@grafana/experimental'; +import { DataSourceJsonData } from '@grafana/schema'; +import { Alert, useStyles2 } from '@grafana/ui'; +import { contextSrv } from 'app/core/core'; +import { ExpressionDatasourceUID } from 'app/features/expressions/types'; +import { AccessControlAction } from 'app/types'; +import { AlertQuery } from 'app/types/unified-alerting-dto'; + +import { RuleFormType, RuleFormValues } from '../../../types/rule-form'; +import { NeedHelpInfo } from '../NeedHelpInfo'; + +function getAvailableRuleTypes() { + const canCreateGrafanaRules = contextSrv.hasAccess( + AccessControlAction.AlertingRuleCreate, + contextSrv.hasEditPermissionInFolders + ); + const canCreateCloudRules = contextSrv.hasAccess(AccessControlAction.AlertingRuleExternalWrite, contextSrv.isEditor); + const defaultRuleType = canCreateGrafanaRules ? RuleFormType.grafana : RuleFormType.cloudAlerting; + + const enabledRuleTypes: RuleFormType[] = []; + if (canCreateGrafanaRules) { + enabledRuleTypes.push(RuleFormType.grafana); + } + if (canCreateCloudRules) { + enabledRuleTypes.push(RuleFormType.cloudAlerting, RuleFormType.cloudRecording); + } + + return { enabledRuleTypes, defaultRuleType }; +} + +const onlyOneDSInQueries = (queries: AlertQuery[]) => { + return queries.filter((q) => q.datasourceUid !== ExpressionDatasourceUID).length === 1; +}; +const getCanSwitch = ({ + queries, + ruleFormType, + editingExistingRule, + rulesSourcesWithRuler, +}: { + rulesSourcesWithRuler: Array>; + queries: AlertQuery[]; + ruleFormType: RuleFormType | undefined; + editingExistingRule: boolean; +}) => { + // get available rule types + const availableRuleTypes = getAvailableRuleTypes(); + + // check if we have only one query in queries and if it's a cloud datasource + const onlyOneDS = onlyOneDSInQueries(queries); + const dataSourceIdFromQueries = queries[0]?.datasourceUid ?? ''; + const isRecordingRuleType = ruleFormType === RuleFormType.cloudRecording; + + //let's check if we switch to cloud type + const canSwitchToCloudRule = + !editingExistingRule && + !isRecordingRuleType && + onlyOneDS && + rulesSourcesWithRuler.some((dsJsonData) => dsJsonData.uid === dataSourceIdFromQueries); + + const canSwitchToGrafanaRule = !editingExistingRule && !isRecordingRuleType; + // check for enabled types + const grafanaTypeEnabled = availableRuleTypes.enabledRuleTypes.includes(RuleFormType.grafana); + const cloudTypeEnabled = availableRuleTypes.enabledRuleTypes.includes(RuleFormType.cloudAlerting); + + // can we switch to the other type? (cloud or grafana) + const canSwitchFromCloudToGrafana = + ruleFormType === RuleFormType.cloudAlerting && grafanaTypeEnabled && canSwitchToGrafanaRule; + const canSwitchFromGrafanaToCloud = + ruleFormType === RuleFormType.grafana && canSwitchToCloudRule && cloudTypeEnabled && canSwitchToCloudRule; + + return canSwitchFromCloudToGrafana || canSwitchFromGrafanaToCloud; +}; + +export interface SmartAlertTypeDetectorProps { + editingExistingRule: boolean; + rulesSourcesWithRuler: Array>; + queries: AlertQuery[]; + onClickSwitch: () => void; +} + +const getContentText = (ruleFormType: RuleFormType, isEditing: boolean, dataSourceName: string, canSwitch: boolean) => { + if (isEditing) { + if (ruleFormType === RuleFormType.grafana) { + return { + contentText: `Grafana-managed alert rules allow you to create alerts that can act on data from any of our supported data sources, including having multiple data sources in the same rule. You can also add expressions to transform your data and set alert conditions. Using images in alert notifications is also supported. `, + title: `This alert rule is managed by Grafana.`, + }; + } else { + return { + contentText: `Data source-managed alert rules can be used for Grafana Mimir or Grafana Loki data sources which have been configured to support rule creation. The use of expressions or multiple queries is not supported.`, + title: `This alert rule is managed by the data source ${dataSourceName}.`, + }; + } + } + if (canSwitch) { + if (ruleFormType === RuleFormType.cloudAlerting) { + return { + contentText: + 'Data source-managed alert rules can be used for Grafana Mimir or Grafana Loki data sources which have been configured to support rule creation. The use of expressions or multiple queries is not supported.', + title: `This alert rule is managed by the data source ${dataSourceName}. If you want to use expressions or have multiple queries, switch to a Grafana-managed alert rule.`, + }; + } else { + return { + contentText: + 'Grafana-managed alert rules allow you to create alerts that can act on data from any of our supported data sources, including having multiple data sources in the same rule. You can also add expressions to transform your data and set alert conditions. Using images in alert notifications is also supported.', + title: `This alert rule will be managed by Grafana. The selected data source is configured to support rule creation. You can switch to data source-managed alert rule.`, + }; + } + } else { + // it can be only grafana rule + return { + contentText: `Grafana-managed alert rules allow you to create alerts that can act on data from any of our supported data sources, including having multiple data sources in the same rule. You can also add expressions to transform your data and set alert conditions. Using images in alert notifications is also supported.`, + title: `Based on the selected data sources this alert rule will be managed by Grafana.`, + }; + } +}; + +export function SmartAlertTypeDetector({ + editingExistingRule, + rulesSourcesWithRuler, + queries, + onClickSwitch, +}: SmartAlertTypeDetectorProps) { + const { getValues } = useFormContext(); + + const [ruleFormType, dataSourceName] = getValues(['type', 'dataSourceName']); + const styles = useStyles2(getStyles); + + const canSwitch = getCanSwitch({ queries, ruleFormType, editingExistingRule, rulesSourcesWithRuler }); + + const typeTitle = + ruleFormType === RuleFormType.cloudAlerting ? 'Data source-managed alert rule' : 'Grafana-managed alert rule'; + const switchToLabel = ruleFormType !== RuleFormType.cloudAlerting ? 'data source-managed' : 'Grafana-managed'; + + const content = ruleFormType + ? getContentText(ruleFormType, editingExistingRule, dataSourceName ?? '', canSwitch) + : undefined; + + return ( +
+ + +
{content?.title}
+
+ +
+
+
+
+ ); +} + +const getStyles = (theme: GrafanaTheme2) => ({ + alertText: css` + max-width: fit-content; + flex: 1; + `, + alert: css` + margin-top: ${theme.spacing(2)}; + `, + needInfo: css` + flex: 1; + max-width: fit-content; + `, +}); diff --git a/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/reducer.ts b/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/reducer.ts index 45e9d0861cf..bead457326e 100644 --- a/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/reducer.ts +++ b/public/app/features/alerting/unified/components/rule-editor/query-and-alert-condition/reducer.ts @@ -35,6 +35,8 @@ export const setDataQueries = createAction('setDataQueries'); export const addNewExpression = createAction('addNewExpression'); export const removeExpression = createAction('removeExpression'); +export const removeExpressions = createAction('removeExpressions'); +export const addExpressions = createAction('addExpressions'); export const updateExpression = createAction('updateExpression'); export const updateExpressionRefId = createAction<{ oldRefId: string; newRefId: string }>('updateExpressionRefId'); export const rewireExpressions = createAction<{ oldRefId: string; newRefId: string }>('rewireExpressions'); @@ -111,6 +113,12 @@ export const queriesAndExpressionsReducer = createReducer(initialState, (builder .addCase(removeExpression, (state, { payload }) => { state.queries = state.queries.filter((query) => query.refId !== payload); }) + .addCase(removeExpressions, (state) => { + state.queries = state.queries.filter((query) => !isExpressionQuery(query.model)); + }) + .addCase(addExpressions, (state, { payload }) => { + state.queries = [...state.queries, ...payload]; + }) .addCase(updateExpression, (state, { payload }) => { state.queries = state.queries.map((query) => { const dataSourceAlertQuery = findDataSourceFromExpression(state.queries, payload.expression); diff --git a/public/test/helpers/alertingRuleEditor.tsx b/public/test/helpers/alertingRuleEditor.tsx index eb099bad304..544398579cc 100644 --- a/public/test/helpers/alertingRuleEditor.tsx +++ b/public/test/helpers/alertingRuleEditor.tsx @@ -28,9 +28,6 @@ export const ui = { save: byRole('button', { name: 'Save rule' }), addAnnotation: byRole('button', { name: /Add info/ }), addLabel: byRole('button', { name: /Add label/ }), - // alert type buttons - grafanaManagedAlert: byRole('button', { name: /Grafana managed/ }), - lotexAlert: byRole('button', { name: /Mimir or Loki alert/ }), }, }; From 320478760f370bc71587f79f11d9e8bdf3b9e4e1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 13 Jul 2023 18:03:05 +0300 Subject: [PATCH 09/42] Update dependency @rollup/plugin-commonjs to v25 (#71576) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- packages/grafana-data/package.json | 2 +- packages/grafana-e2e-selectors/package.json | 2 +- packages/grafana-runtime/package.json | 2 +- packages/grafana-schema/package.json | 2 +- yarn.lock | 30 ++++++++++----------- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/packages/grafana-data/package.json b/packages/grafana-data/package.json index be1a5552d7b..e102c1bc4fe 100644 --- a/packages/grafana-data/package.json +++ b/packages/grafana-data/package.json @@ -62,7 +62,7 @@ }, "devDependencies": { "@grafana/tsconfig": "^1.2.0-rc1", - "@rollup/plugin-commonjs": "23.0.2", + "@rollup/plugin-commonjs": "25.0.2", "@rollup/plugin-json": "6.0.0", "@rollup/plugin-node-resolve": "15.1.0", "@testing-library/dom": "9.3.0", diff --git a/packages/grafana-e2e-selectors/package.json b/packages/grafana-e2e-selectors/package.json index 723e29fd2ac..175f65417fb 100644 --- a/packages/grafana-e2e-selectors/package.json +++ b/packages/grafana-e2e-selectors/package.json @@ -39,7 +39,7 @@ "postpack": "mv package.json.bak package.json" }, "devDependencies": { - "@rollup/plugin-commonjs": "23.0.2", + "@rollup/plugin-commonjs": "25.0.2", "@rollup/plugin-node-resolve": "15.1.0", "@types/node": "18.16.16", "esbuild": "0.18.6", diff --git a/packages/grafana-runtime/package.json b/packages/grafana-runtime/package.json index 7c54ef32bee..262253256a6 100644 --- a/packages/grafana-runtime/package.json +++ b/packages/grafana-runtime/package.json @@ -49,7 +49,7 @@ }, "devDependencies": { "@grafana/tsconfig": "^1.2.0-rc1", - "@rollup/plugin-commonjs": "23.0.2", + "@rollup/plugin-commonjs": "25.0.2", "@rollup/plugin-node-resolve": "15.1.0", "@testing-library/dom": "9.3.0", "@testing-library/react": "14.0.0", diff --git a/packages/grafana-schema/package.json b/packages/grafana-schema/package.json index 624535944e4..f1ce5354c27 100644 --- a/packages/grafana-schema/package.json +++ b/packages/grafana-schema/package.json @@ -37,7 +37,7 @@ }, "devDependencies": { "@grafana/tsconfig": "^1.2.0-rc1", - "@rollup/plugin-commonjs": "23.0.2", + "@rollup/plugin-commonjs": "25.0.2", "@rollup/plugin-json": "6.0.0", "@rollup/plugin-node-resolve": "15.1.0", "esbuild": "0.18.6", diff --git a/yarn.lock b/yarn.lock index 8f6834d8545..708318ea0bc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3723,7 +3723,7 @@ __metadata: "@braintree/sanitize-url": 6.0.2 "@grafana/schema": 10.1.0-pre "@grafana/tsconfig": ^1.2.0-rc1 - "@rollup/plugin-commonjs": 23.0.2 + "@rollup/plugin-commonjs": 25.0.2 "@rollup/plugin-json": 6.0.0 "@rollup/plugin-node-resolve": 15.1.0 "@testing-library/dom": 9.3.0 @@ -3787,7 +3787,7 @@ __metadata: resolution: "@grafana/e2e-selectors@workspace:packages/grafana-e2e-selectors" dependencies: "@grafana/tsconfig": ^1.2.0-rc1 - "@rollup/plugin-commonjs": 23.0.2 + "@rollup/plugin-commonjs": 25.0.2 "@rollup/plugin-node-resolve": 15.1.0 "@types/node": 18.16.16 esbuild: 0.18.6 @@ -4003,7 +4003,7 @@ __metadata: "@grafana/faro-web-sdk": 1.1.0 "@grafana/tsconfig": ^1.2.0-rc1 "@grafana/ui": 10.1.0-pre - "@rollup/plugin-commonjs": 23.0.2 + "@rollup/plugin-commonjs": 25.0.2 "@rollup/plugin-node-resolve": 15.1.0 "@testing-library/dom": 9.3.0 "@testing-library/react": 14.0.0 @@ -4056,7 +4056,7 @@ __metadata: resolution: "@grafana/schema@workspace:packages/grafana-schema" dependencies: "@grafana/tsconfig": ^1.2.0-rc1 - "@rollup/plugin-commonjs": 23.0.2 + "@rollup/plugin-commonjs": 25.0.2 "@rollup/plugin-json": 6.0.0 "@rollup/plugin-node-resolve": 15.1.0 esbuild: 0.18.6 @@ -4773,7 +4773,7 @@ __metadata: languageName: node linkType: hard -"@jridgewell/sourcemap-codec@npm:^1.4.15": +"@jridgewell/sourcemap-codec@npm:^1.4.13, @jridgewell/sourcemap-codec@npm:^1.4.15": version: 1.4.15 resolution: "@jridgewell/sourcemap-codec@npm:1.4.15" checksum: b881c7e503db3fc7f3c1f35a1dd2655a188cc51a3612d76efc8a6eb74728bef5606e6758ee77423e564092b4a518aba569bbb21c9bac5ab7a35b0c6ae7e344c8 @@ -7216,22 +7216,22 @@ __metadata: languageName: node linkType: hard -"@rollup/plugin-commonjs@npm:23.0.2": - version: 23.0.2 - resolution: "@rollup/plugin-commonjs@npm:23.0.2" +"@rollup/plugin-commonjs@npm:25.0.2": + version: 25.0.2 + resolution: "@rollup/plugin-commonjs@npm:25.0.2" dependencies: "@rollup/pluginutils": ^5.0.1 commondir: ^1.0.1 estree-walker: ^2.0.2 glob: ^8.0.3 is-reference: 1.2.1 - magic-string: ^0.26.4 + magic-string: ^0.27.0 peerDependencies: rollup: ^2.68.0||^3.0.0 peerDependenciesMeta: rollup: optional: true - checksum: bd203a6e6fbcdc523f5d47a8a9e6b719f853270fbfa608c636124c213ec4b2a15026121e1e4faa820f52546425050f4c833bbf6bc58959909025cbc99c6d5df3 + checksum: d8c4e22d264c5b9286f697653c2f9288149c0fe0169d49b83b5dc8b542f96cc0b9113da3f30d241f2f277513fbf3f8c207d95def5559eb3800190f1872add794 languageName: node linkType: hard @@ -23194,12 +23194,12 @@ __metadata: languageName: node linkType: hard -"magic-string@npm:^0.26.4": - version: 0.26.7 - resolution: "magic-string@npm:0.26.7" +"magic-string@npm:^0.27.0": + version: 0.27.0 + resolution: "magic-string@npm:0.27.0" dependencies: - sourcemap-codec: ^1.4.8 - checksum: 89b0d60cbb32bbf3d1e23c46ea93db082d18a8230b972027aecb10a40bba51be519ecce0674f995571e3affe917b76b09f59d8dbc9a1b2c9c4102a2b6e8a2b01 + "@jridgewell/sourcemap-codec": ^1.4.13 + checksum: 273faaa50baadb7a2df6e442eac34ad611304fc08fe16e24fe2e472fd944bfcb73ffb50d2dc972dc04e92784222002af46868cb9698b1be181c81830fd95a13e languageName: node linkType: hard From 18b4f72c7ab756d414ed4a5a1be33493e8bfc83d Mon Sep 17 00:00:00 2001 From: Ivan Ortega Alba Date: Thu, 13 Jul 2023 17:10:38 +0200 Subject: [PATCH 10/42] DS Picker: Use trigger width as min width (#71501) --- .../components/picker/DataSourceDropdown.tsx | 1 - .../components/picker/popperModifiers.ts | 24 ++++++++----------- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/public/app/features/datasources/components/picker/DataSourceDropdown.tsx b/public/app/features/datasources/components/picker/DataSourceDropdown.tsx index a291dc625df..2604592c9b2 100644 --- a/public/app/features/datasources/components/picker/DataSourceDropdown.tsx +++ b/public/app/features/datasources/components/picker/DataSourceDropdown.tsx @@ -337,7 +337,6 @@ function getStylesPickerContent(theme: GrafanaTheme2) { container: css` display: flex; flex-direction: column; - max-width: 480px; background: ${theme.colors.background.primary}; box-shadow: ${theme.shadows.z3}; `, diff --git a/public/app/features/datasources/components/picker/popperModifiers.ts b/public/app/features/datasources/components/picker/popperModifiers.ts index 276df3227dc..733ae14649e 100644 --- a/public/app/features/datasources/components/picker/popperModifiers.ts +++ b/public/app/features/datasources/components/picker/popperModifiers.ts @@ -11,15 +11,17 @@ export const maxSize: Modifier<'maxSize', {}> = { fn({ state, name, options }: ModifierArguments<{}>) { const overflow = detectOverflow(state, options); const { x, y } = state.modifiersData.preventOverflow || { x: 0, y: 0 }; - const { width, height } = state.rects.popper; + const { width: contentW, height: contentH } = state.rects.popper; + const { width: triggerW } = state.rects.reference; const [basePlacement] = state.placement.split('-'); const widthProp = basePlacement === 'left' ? 'left' : 'right'; const heightProp = basePlacement === 'top' ? 'top' : 'bottom'; state.modifiersData[name] = { - width: width - overflow[widthProp] - x, - height: height - overflow[heightProp] - y, + maxWidth: contentW - overflow[widthProp] - x, + maxHeight: contentH - overflow[heightProp] - y, + minWidth: triggerW, }; }, }; @@ -30,17 +32,11 @@ export const applyMaxSize: Modifier<'applyMaxSize', {}> = { phase: 'beforeWrite', requires: ['maxSize'], fn({ state }: ModifierArguments<{}>) { - const { height, width } = state.modifiersData.maxSize; + const { maxHeight, maxWidth, minWidth } = state.modifiersData.maxSize; - if (!state.styles.popper.maxHeight) { - state.styles.popper.maxHeight = `${height - MODAL_MARGIN}px`; - } - if (!state.styles.popper.minHeight) { - state.styles.popper.minHeight = `${FLIP_THRESHOLD}px`; - } - - if (!state.styles.popper.maxWidth) { - state.styles.popper.maxWidth = width; - } + state.styles.popper.maxHeight ??= `${maxHeight - MODAL_MARGIN}px`; + state.styles.popper.minHeight ??= `${FLIP_THRESHOLD}px`; + state.styles.popper.maxWidth ??= maxWidth; + state.styles.popper.minWidth ??= minWidth; }, }; From 94d3fa7087df034c4990b8a7a99a43756bffeb5f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 13 Jul 2023 18:13:19 +0300 Subject: [PATCH 11/42] Update dependency selecto to v1.26.0 (#71581) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 49 +++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 40 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index d821b51eae1..e7c4dae2ab2 100644 --- a/package.json +++ b/package.json @@ -408,7 +408,7 @@ "reselect": "4.1.7", "rxjs": "7.8.0", "sass": "link:./public/sass", - "selecto": "1.22.0", + "selecto": "1.26.0", "semver": "7.5.4", "slate": "0.47.9", "slate-plain-serializer": "0.7.13", diff --git a/yarn.lock b/yarn.lock index 708318ea0bc..db40cecca4b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2624,7 +2624,7 @@ __metadata: languageName: node linkType: hard -"@daybrush/utils@npm:1.13.0": +"@daybrush/utils@npm:1.13.0, @daybrush/utils@npm:^1.13.0": version: 1.13.0 resolution: "@daybrush/utils@npm:1.13.0" checksum: 0ec0670016efc66b367fbef6581718eb5fc383b612d1290637845b9b9572e3cc19717ad63a35689f12d5a95a3dbdc9552fd1e57169077745ef0fee1a0b4e0fcd @@ -14983,6 +14983,15 @@ __metadata: languageName: node linkType: hard +"css-styled@npm:^1.0.8": + version: 1.0.8 + resolution: "css-styled@npm:1.0.8" + dependencies: + "@daybrush/utils": ^1.13.0 + checksum: ffd99f3403dff34fb682ba8a77fcc8cf0131dd3470efcd81b84c58be241904c0f877b929c54563c00994a01951c5afa45b164a56d8b7b1363c057e284f2b3061 + languageName: node + linkType: hard + "css-styled@npm:~1.0.1": version: 1.0.1 resolution: "css-styled@npm:1.0.1" @@ -15005,6 +15014,16 @@ __metadata: languageName: node linkType: hard +"css-to-mat@npm:^1.1.1": + version: 1.1.1 + resolution: "css-to-mat@npm:1.1.1" + dependencies: + "@daybrush/utils": ^1.13.0 + "@scena/matrix": ^1.0.0 + checksum: bc88b044a8b24882e06170ad6d5cedfd220119fa03a55accf54ff0e7f6450d85f9be71408900be595d8bb5c0e07346f79ab7a3de4c820869bced4de25497b3c5 + languageName: node + linkType: hard + "css-tree@npm:^1.1.2": version: 1.1.3 resolution: "css-tree@npm:1.1.3" @@ -18669,6 +18688,16 @@ __metadata: languageName: node linkType: hard +"gesto@npm:^1.19.1": + version: 1.19.1 + resolution: "gesto@npm:1.19.1" + dependencies: + "@daybrush/utils": ^1.13.0 + "@scena/event-emitter": ^1.0.2 + checksum: 3f341539cb529036d96b57855ed255a76902d6c0499fc1b193c5357604a64ef376739b3b44dd6324ab797128c8fe0a7f1ac651b6f3b51712a6fd8579601eab87 + languageName: node + linkType: hard + "get-caller-file@npm:^2.0.5": version: 2.0.5 resolution: "get-caller-file@npm:2.0.5" @@ -19473,7 +19502,7 @@ __metadata: rxjs: 7.8.0 sass: 1.63.6 sass-loader: 13.3.2 - selecto: 1.22.0 + selecto: 1.26.0 semver: 7.5.4 sinon: 15.2.0 slate: 0.47.9 @@ -29246,21 +29275,21 @@ __metadata: languageName: node linkType: hard -"selecto@npm:1.22.0": - version: 1.22.0 - resolution: "selecto@npm:1.22.0" +"selecto@npm:1.26.0": + version: 1.26.0 + resolution: "selecto@npm:1.26.0" dependencies: - "@daybrush/utils": ^1.7.1 + "@daybrush/utils": ^1.13.0 "@egjs/children-differ": ^1.0.1 "@scena/dragscroll": ^1.4.0 "@scena/event-emitter": ^1.0.5 - css-styled: ^1.0.0 - css-to-mat: ^1.0.3 + css-styled: ^1.0.8 + css-to-mat: ^1.1.1 framework-utils: ^1.1.0 - gesto: ^1.15.1 + gesto: ^1.19.1 keycon: ^1.2.0 overlap-area: ^1.1.0 - checksum: b62ac5710ff7d031f5f42745d97921642cb5b1b3ab07fcc37044fd580e0d483cb23bdb5b0631dfb1b464f02cfc5867f6acc50bf73b9873cf5b1a196df28d1329 + checksum: 401e1c2b47aa96ad2c7e9878278b70dfd4a71861fc4616f345088d3e1e20a3b33f6cb731e0015a8b9e85581c4edf896785e5cb9217802262c5a2d179d78e003d languageName: node linkType: hard From 4c3167253653974cd709b9c1fea969dc7674cefb Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 13 Jul 2023 16:27:52 +0100 Subject: [PATCH 12/42] Update dependency rudder-sdk-js to v2.37.0 (#71572) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index e7c4dae2ab2..e85bcbd6be5 100644 --- a/package.json +++ b/package.json @@ -229,7 +229,7 @@ "react-test-renderer": "18.2.0", "redux-mock-store": "1.5.4", "rimraf": "5.0.1", - "rudder-sdk-js": "2.25.0", + "rudder-sdk-js": "2.37.0", "sass": "1.63.6", "sass-loader": "13.3.2", "sinon": "15.2.0", diff --git a/yarn.lock b/yarn.lock index db40cecca4b..8996ad49e07 100644 --- a/yarn.lock +++ b/yarn.lock @@ -19498,7 +19498,7 @@ __metadata: regenerator-runtime: 0.13.11 reselect: 4.1.7 rimraf: 5.0.1 - rudder-sdk-js: 2.25.0 + rudder-sdk-js: 2.37.0 rxjs: 7.8.0 sass: 1.63.6 sass-loader: 13.3.2 @@ -29059,10 +29059,10 @@ __metadata: languageName: node linkType: hard -"rudder-sdk-js@npm:2.25.0": - version: 2.25.0 - resolution: "rudder-sdk-js@npm:2.25.0" - checksum: f4ddc07760ae234219bfc804bdd6135dacc830246584b83a418b983cee6261670795e32c3e72c920f950a4e2017ee186a768656fa286b46c97a657795d9c71c2 +"rudder-sdk-js@npm:2.37.0": + version: 2.37.0 + resolution: "rudder-sdk-js@npm:2.37.0" + checksum: df4e6a62a3c41ec9a616a2d1c3b2e0ee63aec345d6947c01b8b8e5aafa67f5ffd5cebfec0a8e8942c03070b5d7feb30f236896ef64932c30d7c8663b86d8de7a languageName: node linkType: hard From cbc44751b2bfb5668787a6c0ab32214392f98099 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 13 Jul 2023 18:52:59 +0300 Subject: [PATCH 13/42] Update dependency immer to v10 (#71583) * Update dependency immer to v10 * use named export now that the default has been removed --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Ashley Harrison --- package.json | 2 +- .../components/rule-editor/AnnotationsField.tsx | 2 +- .../unified/components/rule-viewer/RuleViewer.v1.tsx | 2 +- .../alerting/unified/hooks/useFilteredRules.ts | 2 +- public/app/features/alerting/unified/mocks.ts | 2 +- .../features/explore/Graph/exploreGraphStyleUtils.ts | 2 +- .../plugins/datasource/alertmanager/ConfigEditor.tsx | 2 +- .../azuremonitor/components/ResourcePicker/utils.ts | 2 +- .../datasource/influxdb/specs/influx_series.test.ts | 2 +- yarn.lock | 10 +++++----- 10 files changed, 14 insertions(+), 14 deletions(-) diff --git a/package.json b/package.json index e85bcbd6be5..6f816430f8c 100644 --- a/package.json +++ b/package.json @@ -337,7 +337,7 @@ "history": "4.10.1", "hoist-non-react-statics": "3.3.2", "i18next": "^22.0.0", - "immer": "9.0.19", + "immer": "10.0.2", "immutable": "4.3.0", "jquery": "3.7.0", "js-yaml": "^4.1.0", diff --git a/public/app/features/alerting/unified/components/rule-editor/AnnotationsField.tsx b/public/app/features/alerting/unified/components/rule-editor/AnnotationsField.tsx index 3c5bf22ef95..fead5d2dc60 100644 --- a/public/app/features/alerting/unified/components/rule-editor/AnnotationsField.tsx +++ b/public/app/features/alerting/unified/components/rule-editor/AnnotationsField.tsx @@ -1,5 +1,5 @@ import { css, cx } from '@emotion/css'; -import produce from 'immer'; +import { produce } from 'immer'; import React, { useEffect, useState } from 'react'; import { useFieldArray, useFormContext } from 'react-hook-form'; import { useToggle } from 'react-use'; diff --git a/public/app/features/alerting/unified/components/rule-viewer/RuleViewer.v1.tsx b/public/app/features/alerting/unified/components/rule-viewer/RuleViewer.v1.tsx index 252422d0bd8..12584fb07a1 100644 --- a/public/app/features/alerting/unified/components/rule-viewer/RuleViewer.v1.tsx +++ b/public/app/features/alerting/unified/components/rule-viewer/RuleViewer.v1.tsx @@ -1,5 +1,5 @@ import { css } from '@emotion/css'; -import produce from 'immer'; +import { produce } from 'immer'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { useObservable, useToggle } from 'react-use'; diff --git a/public/app/features/alerting/unified/hooks/useFilteredRules.ts b/public/app/features/alerting/unified/hooks/useFilteredRules.ts index 228eea3dc78..c336d065fc6 100644 --- a/public/app/features/alerting/unified/hooks/useFilteredRules.ts +++ b/public/app/features/alerting/unified/hooks/useFilteredRules.ts @@ -1,5 +1,5 @@ import uFuzzy from '@leeoniya/ufuzzy'; -import produce from 'immer'; +import { produce } from 'immer'; import { compact, isEmpty } from 'lodash'; import { useCallback, useEffect, useMemo } from 'react'; diff --git a/public/app/features/alerting/unified/mocks.ts b/public/app/features/alerting/unified/mocks.ts index 33d01764c7c..e3eac047bb1 100644 --- a/public/app/features/alerting/unified/mocks.ts +++ b/public/app/features/alerting/unified/mocks.ts @@ -1,4 +1,4 @@ -import produce from 'immer'; +import { produce } from 'immer'; import { DataSourceApi, diff --git a/public/app/features/explore/Graph/exploreGraphStyleUtils.ts b/public/app/features/explore/Graph/exploreGraphStyleUtils.ts index fc121229a76..ba72dc9365e 100644 --- a/public/app/features/explore/Graph/exploreGraphStyleUtils.ts +++ b/public/app/features/explore/Graph/exploreGraphStyleUtils.ts @@ -1,4 +1,4 @@ -import produce from 'immer'; +import { produce } from 'immer'; import { FieldConfigSource, ThresholdsConfig } from '@grafana/data'; import { GraphDrawStyle, GraphFieldConfig, GraphThresholdsStyleConfig, StackingMode } from '@grafana/schema'; diff --git a/public/app/plugins/datasource/alertmanager/ConfigEditor.tsx b/public/app/plugins/datasource/alertmanager/ConfigEditor.tsx index b37ee8ffa22..25eabbe62f2 100644 --- a/public/app/plugins/datasource/alertmanager/ConfigEditor.tsx +++ b/public/app/plugins/datasource/alertmanager/ConfigEditor.tsx @@ -1,4 +1,4 @@ -import produce from 'immer'; +import { produce } from 'immer'; import React from 'react'; import { Link } from 'react-router-dom'; diff --git a/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/utils.ts b/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/utils.ts index 33e02b5cef8..a4fa545477e 100644 --- a/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/utils.ts +++ b/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/utils.ts @@ -1,4 +1,4 @@ -import produce from 'immer'; +import { produce } from 'immer'; import { getTemplateSrv } from '@grafana/runtime'; diff --git a/public/app/plugins/datasource/influxdb/specs/influx_series.test.ts b/public/app/plugins/datasource/influxdb/specs/influx_series.test.ts index ade1587f87e..3c4d84f6cb9 100644 --- a/public/app/plugins/datasource/influxdb/specs/influx_series.test.ts +++ b/public/app/plugins/datasource/influxdb/specs/influx_series.test.ts @@ -1,4 +1,4 @@ -import produce from 'immer'; +import { produce } from 'immer'; import InfluxSeries from '../influx_series'; diff --git a/yarn.lock b/yarn.lock index 8996ad49e07..25b8ecf41b5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -19404,7 +19404,7 @@ __metadata: husky: 8.0.3 i18next: ^22.0.0 i18next-parser: 6.6.0 - immer: 9.0.19 + immer: 10.0.2 immutable: 4.3.0 jest: 29.3.1 jest-canvas-mock: 2.5.2 @@ -20382,10 +20382,10 @@ __metadata: languageName: node linkType: hard -"immer@npm:9.0.19": - version: 9.0.19 - resolution: "immer@npm:9.0.19" - checksum: f02ee53989989c287cd548a3d817fccf0bfe56db919755ee94a72ea3ae78a00363fba93ee6c010fe54a664380c29c53d44ed4091c6a86cae60957ad2cfabc010 +"immer@npm:10.0.2": + version: 10.0.2 + resolution: "immer@npm:10.0.2" + checksum: 525a3b14210d02ae420c3b9f6ca14f7e9bcf625611d1356e773e7739f14c7c8de50dac442e6c7de3a6e24a782f7b792b6b8666bc0b3f00269d21a95f8f68ca84 languageName: node linkType: hard From 6493e92932a3086ef1bffe55db7b043ee8ff7fcc Mon Sep 17 00:00:00 2001 From: Kyle Brandt Date: Thu, 13 Jul 2023 11:56:59 -0400 Subject: [PATCH 14/42] Chore: update dataplane/examples lib (#71591) Includes fix that should resolve tests using this library failing on windows --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 4d257ebf0ed..f5cc7b2d7a0 100644 --- a/go.mod +++ b/go.mod @@ -260,7 +260,7 @@ require ( github.com/alicebob/miniredis/v2 v2.30.1 github.com/dave/dst v0.27.2 github.com/go-jose/go-jose/v3 v3.0.0 - github.com/grafana/dataplane/examples v0.0.0-20230404174214-4d6fd58a18ad + github.com/grafana/dataplane/examples v0.0.1 github.com/grafana/dataplane/sdata v0.0.6 github.com/grafana/go-mssqldb v0.9.1 github.com/grafana/kindsys v0.0.0-20230508162304-452481b63482 diff --git a/go.sum b/go.sum index f89e304492b..e7a36d7c627 100644 --- a/go.sum +++ b/go.sum @@ -1364,6 +1364,8 @@ github.com/grafana/cuetsy v0.1.10 h1:+W9/7roI8LorL+D1RJhKGdhsTZ81adrK9dHS0r7qsXs github.com/grafana/cuetsy v0.1.10/go.mod h1:Ix97+CPD8ws9oSSxR3/Lf4ahU1I4Np83kjJmDVnLZvc= github.com/grafana/dataplane/examples v0.0.0-20230404174214-4d6fd58a18ad h1:bROIOQEkRlxAt+Epn9Pos8ytkVqoIAvnaUZOAb7EgEU= github.com/grafana/dataplane/examples v0.0.0-20230404174214-4d6fd58a18ad/go.mod h1:h5YwY8s407/17XF5/dS8XrUtsTVV2RnuW8+m1Mp46mg= +github.com/grafana/dataplane/examples v0.0.1 h1:K9M5glueWyLoL4//H+EtTQq16lXuHLmOhb6DjSCahzA= +github.com/grafana/dataplane/examples v0.0.1/go.mod h1:h5YwY8s407/17XF5/dS8XrUtsTVV2RnuW8+m1Mp46mg= github.com/grafana/dataplane/sdata v0.0.6 h1:Ejlj8d1Hvy/uDLeI4sOvL34Y8WLlVDd9iN270F+8aTw= github.com/grafana/dataplane/sdata v0.0.6/go.mod h1:Jvs5ddpGmn6vcxT7tCTWAZ1mgi4sbcdFt9utQx5uMAU= github.com/grafana/dskit v0.0.0-20230620150242-3dc2113b720d h1:1w9c1/z4JypJUatX+rPIiK3eTAV7+OF094UkDIPDTIs= From c4fff1c5f2cd311572c19d3ae0c707ed96d057bc Mon Sep 17 00:00:00 2001 From: David Harris Date: Thu, 13 Jul 2023 17:17:50 +0100 Subject: [PATCH 15/42] docs: update references to deprecated plugins (#71569) * docs: update plugin management 2 of the 3 panels were deprecated and should no longer be referenced. Picked two recently updated panels to replace. * docs: update create app Remove reference to deprecated worldmap panel --- docs/sources/administration/plugin-management/index.md | 2 +- .../develop-a-plugin/build-an-app-plugin.md | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/sources/administration/plugin-management/index.md b/docs/sources/administration/plugin-management/index.md index 2ae610d07cf..127e0a05a86 100644 --- a/docs/sources/administration/plugin-management/index.md +++ b/docs/sources/administration/plugin-management/index.md @@ -19,7 +19,7 @@ Grafana supports three types of plugins: [panels](/grafana/plugins?type=panel), ## Panel plugins -Add new visualizations to your dashboard with panel plugins, such as the [Worldmap Panel](/grafana/plugins/grafana-worldmap-panel), [Clock](/grafana/plugins/grafana-clock-panel), and [Pie Chart](/grafana/plugins/grafana-piechart-panel). +Add new visualizations to your dashboard with panel plugins, such as the [Clock](/grafana/plugins/grafana-clock-panel), [Mosaic](/grafana/plugins/boazreicher-mosaicplot-panel) and [Variable](/grafana/plugins/volkovlabs-variable-panel) panels. Use panel plugins when you want to: diff --git a/docs/sources/developers/plugins/create-a-grafana-plugin/develop-a-plugin/build-an-app-plugin.md b/docs/sources/developers/plugins/create-a-grafana-plugin/develop-a-plugin/build-an-app-plugin.md index cd77168132b..2ebbd79d1da 100644 --- a/docs/sources/developers/plugins/create-a-grafana-plugin/develop-a-plugin/build-an-app-plugin.md +++ b/docs/sources/developers/plugins/create-a-grafana-plugin/develop-a-plugin/build-an-app-plugin.md @@ -194,9 +194,9 @@ If you want to let users know that your app requires an existing plugin, you can "plugins": [ { "type": "panel", - "name": "Worldmap Panel", - "id": "grafana-worldmap-panel", - "version": "^0.3.2" + "name": "Clock Panel", + "id": "grafana-clock-panel", + "version": "^2.1.3" } ] } From e8b4228f8994667885936562eda1c2dac821728e Mon Sep 17 00:00:00 2001 From: Jack Baldry Date: Thu, 13 Jul 2023 18:24:23 +0100 Subject: [PATCH 16/42] Update `make docs` procedure and related workflows (#71537) * Add myself as CODEOWNER for `make docs` procedure and related workflows Signed-off-by: Jack Baldry * Update `make docs` procedure Signed-off-by: Jack Baldry * Add workflow to update `make docs` procedure Signed-off-by: Jack Baldry * Update doc-validator workflow Signed-off-by: Jack Baldry * Fix team handle Signed-off-by: Jack Baldry * Clean up CODEOWNERS Signed-off-by: Jack Baldry --------- Signed-off-by: Jack Baldry --- .github/CODEOWNERS | 43 ++++++++++++++------------ .github/workflows/doc-validator.yml | 2 +- .github/workflows/update-make-docs.yml | 27 ++++++++++++++++ docs/make-docs | 7 +++-- docs/variables.mk | 8 ++--- 5 files changed, 60 insertions(+), 27 deletions(-) create mode 100644 .github/workflows/update-make-docs.yml diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index aeb3b1e2595..709097af7a4 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -33,23 +33,25 @@ /devenv/README.md @grafana/docs-grafana # Technical documentation -/docs/ @Eve832 @jdbaldry -/docs/sources/ @Eve832 -/docs/sources/administration/ @Eve832 @GrafanaWriter -/docs/sources/alerting/ @brendamuir -/docs/sources/dashboards/ @imatwawana -/docs/sources/datasources/ @lwandz13 -/docs/sources/explore/ @Eve832 @GrafanaWriter -/docs/sources/fundamentals @chri2547 -/docs/sources/getting-started/ @chri2547 -/docs/sources/introduction/ @chri2547 -/docs/sources/old-alerting/ @brendamuir -/docs/sources/panels-visualizations/ @imatwawana -/docs/sources/release-notes/ @Eve832 @GrafanaWriter -/docs/sources/setup-grafana/ @chri2547 -/docs/sources/upgrade-guide/ @chri2547 @imatwawana -/docs/sources/whatsnew/ @chri2547 @imatwawana -/docs/sources/developers/plugins/ @Eve832 @josmperez @grafana/plugins-platform-frontend @grafana/plugins-platform-backend +# `make docs` procedure and related workflows are owned @grafana/docs-tooling. Slack #docs. +# Documentation sources might have different owners. +/docs/ @grafana/docs-tooling +/docs/sources/ @Eve832 +/docs/sources/administration/ @Eve832 @GrafanaWriter +/docs/sources/alerting/ @brendamuir +/docs/sources/dashboards/ @imatwawana +/docs/sources/datasources/ @lwandz13 +/docs/sources/explore/ @Eve832 @GrafanaWriter +/docs/sources/fundamentals @chri2547 +/docs/sources/getting-started/ @chri2547 +/docs/sources/introduction/ @chri2547 +/docs/sources/old-alerting/ @brendamuir +/docs/sources/panels-visualizations/ @imatwawana +/docs/sources/release-notes/ @Eve832 @GrafanaWriter +/docs/sources/setup-grafana/ @chri2547 +/docs/sources/upgrade-guide/ @chri2547 @imatwawana +/docs/sources/whatsnew/ @chri2547 @imatwawana +/docs/sources/developers/plugins/ @Eve832 @josmperez @grafana/plugins-platform-frontend @grafana/plugins-platform-backend /docs/sources/developers/plugins/introduction-to-plugin-development/backend/ @Eve832 @grafana/plugins-platform-backend # Backend code @@ -596,7 +598,7 @@ embed.go @grafana/grafana-as-code /.github/workflows/codeql-analysis.yml @DanCech /.github/workflows/commands.yml @torkelo /.github/workflows/detect-breaking-changes-* @grafana/plugins-platform-frontend -/.github/workflows/doc-validator.yml @grafana/docs-grafana +/.github/workflows/doc-validator.yml @grafana/docs-tooling /.github/workflows/epic-add-to-platform-ux-parent-project.yml @meanmina /.github/workflows/github-release.yml @torkelo /.github/workflows/issue-labeled.yml @armandgrillet @@ -612,14 +614,15 @@ embed.go @grafana/grafana-as-code /.github/workflows/pr-commands.yml @marefr /.github/workflows/pr-patch-check.yml @grafana/grafana-delivery /.github/workflows/pr-patch-mirror-and-apply.yml @grafana/grafana-delivery -/.github/workflows/publish-technical-documentation-next.yml @grafana/docs-grafana -/.github/workflows/publish-technical-documentation-release.yml @grafana/docs-grafana +/.github/workflows/publish-technical-documentation-next.yml @grafana/docs-tooling +/.github/workflows/publish-technical-documentation-release.yml @grafana/docs-tooling /.github/workflows/remove-milestone.yml @grafana/grafana-delivery /.github/workflows/sbom-report.yml @grafana/security-team /.github/workflows/scripts/json-file-to-job-output.js @grafana/plugins-platform-frontend /.github/workflows/scripts/pr-get-job-link.js @grafana/plugins-platform-frontend /.github/workflows/stale.yml @grafana/grafana-delivery /.github/workflows/update-changelog.yml @grafana/grafana-delivery +/.github/workflows/update-make-docs.yml @grafana/docs-tooling /.github/workflows/snyk.yml @grafana/security-team /.github/workflows/scripts/kinds/verify-kinds.go @grafana/grafana-as-code /.github/workflows/publish-kinds-next.yml @grafana/grafana-as-code diff --git a/.github/workflows/doc-validator.yml b/.github/workflows/doc-validator.yml index 792506ff46d..88a731676fc 100644 --- a/.github/workflows/doc-validator.yml +++ b/.github/workflows/doc-validator.yml @@ -7,7 +7,7 @@ jobs: doc-validator: runs-on: "ubuntu-latest" container: - image: "grafana/doc-validator:v3.0.0" + image: "grafana/doc-validator:v3.2.0" steps: - name: "Checkout code" uses: "actions/checkout@v3" diff --git a/.github/workflows/update-make-docs.yml b/.github/workflows/update-make-docs.yml new file mode 100644 index 00000000000..57d60d47c11 --- /dev/null +++ b/.github/workflows/update-make-docs.yml @@ -0,0 +1,27 @@ +name: Update `make docs` procedure +on: + schedule: + - cron: '0 7 * * 1-5' +jobs: + main: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Update procedure + if: github.repository != 'grafana/writers-toolkit' + run: | + curl -s -Lo docs/docs.mk https://raw.githubusercontent.com/grafana/writers-toolkit/main/docs/docs.mk + curl -s -Lo docs/make-docs https://raw.githubusercontent.com/grafana/writers-toolkit/main/docs/make-docs + if git diff --exit-code; then exit 0; fi + BRANCH="$(date +%Y-%m-%d)/update-make-docs" + git checkout -b "${BRANCH}" + git add . + git config --local user.email "bot@grafana.com" + git config --local user.name "grafanabot" + git commit -m "Update \`make docs\` procedure" + git push -v origin "refs/heads/${BRANCH}" + gh pr create --fill + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/docs/make-docs b/docs/make-docs index 3942bf483c3..4bb5ad79038 100755 --- a/docs/make-docs +++ b/docs/make-docs @@ -63,20 +63,23 @@ SOURCES_as_code='as-code-docs' SOURCES_enterprise_metrics='backend-enterprise' SOURCES_enterprise_metrics_='backend-enterprise' SOURCES_grafana_cloud='website' +SOURCES_grafana_cloud_alerting_and_irm_machine_learning='machine-learning' +SOURCES_grafana_cloud_alerting_and_irm_slo='slo' SOURCES_grafana_cloud_k6='k6-docs' SOURCES_grafana_cloud_data_configuration_integrations='cloud-onboarding' SOURCES_grafana_cloud_frontend_observability_faro_web_sdk='faro-web-sdk' -SOURCES_grafana_cloud_machine_learning='machine-learning' SOURCES_helm_charts_mimir_distributed='mimir' SOURCES_helm_charts_tempo_distributed='tempo' SOURCES_opentelemetry='opentelemetry-docs' +SOURCES_plugins_grafana_splunk_datasource='splunk-datasource' VERSIONS_as_code='UNVERSIONED' VERSIONS_grafana_cloud='UNVERSIONED' +VERSIONS_grafana_cloud_alerting_and_irm_machine_learning='UNVERSIONED' +VERSIONS_grafana_cloud_alerting_and_irm_slo='UNVERSIONED' VERSIONS_grafana_cloud_k6='UNVERSIONED' VERSIONS_grafana_cloud_data_configuration_integrations='UNVERSIONED' VERSIONS_grafana_cloud_frontend_observability_faro_web_sdk='UNVERSIONED' -VERSIONS_grafana_cloud_machine_learning='UNVERSIONED' VERSIONS_opentelemetry='UNVERSIONED' VERSIONS_technical_documentation='UNVERSIONED' VERSIONS_website='UNVERSIONED' diff --git a/docs/variables.mk b/docs/variables.mk index 2dfa301900c..a3302041ce5 100644 --- a/docs/variables.mk +++ b/docs/variables.mk @@ -1,11 +1,11 @@ # List of projects to provide to the make-docs script. -PROJECTS = grafana +PROJECTS := grafana # Use the doc-validator image defined in CI by default. export DOC_VALIDATOR_IMAGE := $(shell sed -En 's, *image: "(grafana/doc-validator[^"]+)",\1,p' "$(shell git rev-parse --show-toplevel)/.github/workflows/doc-validator.yml") # Skip some doc-validator checks. -export DOC_VALIDATOR_SKIP_CHECKS := ^(?:image.+|canonical-does-not-match-pretty-URL)$ +export DOC_VALIDATOR_SKIP_CHECKS := $(shell sed -En "s, *'--skip-checks=(.+)',\1,p" "$(shell git rev-parse --show-toplevel)/.github/workflows/doc-validator.yml") -# Use alternative image until make-docs 3.0.0 is rolled out. -export DOCS_IMAGE := grafana/docs-base:dbd975af06 +# Only run on sections that have been enabled in CI. +export DOC_VALIDATOR_INCLUDE := $(shell sed -En "s, *'--include=\\^docs/sources/(.+)',/hugo/content/docs/grafana/latest/\1,p" "$(shell git rev-parse --show-toplevel)/.github/workflows/doc-validator.yml") From 541bfe636daa55705a130df4004aa417c99adc09 Mon Sep 17 00:00:00 2001 From: Yuri Tseretyan Date: Thu, 13 Jul 2023 13:37:50 -0400 Subject: [PATCH 17/42] SSE: Support for ML query node (#69963) * introduce a new node-type ML and implement a command outlier that uses ML plugin as a source of data. * add feature flag mlExpressions that guards the feature --- .../feature-toggles/index.md | 1 + .../src/types/featureToggles.gen.ts | 1 + pkg/expr/graph.go | 17 +- pkg/expr/ml.go | 158 +++++++++++++ pkg/expr/ml/model.go | 83 +++++++ pkg/expr/ml/node.go | 63 +++++ pkg/expr/ml/node_test.go | 167 +++++++++++++ pkg/expr/ml/outlier.go | 116 ++++++++++ pkg/expr/ml/outlier_test.go | 194 ++++++++++++++++ pkg/expr/ml/testing.go | 44 ++++ pkg/expr/ml_test.go | 219 ++++++++++++++++++ pkg/expr/nodes.go | 1 + pkg/expr/service.go | 20 +- pkg/expr/testing.go | 84 +++++++ pkg/services/featuremgmt/registry.go | 7 + pkg/services/featuremgmt/toggles_gen.csv | 1 + pkg/services/featuremgmt/toggles_gen.go | 4 + pkg/services/ngalert/eval/eval.go | 27 ++- 18 files changed, 1196 insertions(+), 11 deletions(-) create mode 100644 pkg/expr/ml.go create mode 100644 pkg/expr/ml/model.go create mode 100644 pkg/expr/ml/node.go create mode 100644 pkg/expr/ml/node_test.go create mode 100644 pkg/expr/ml/outlier.go create mode 100644 pkg/expr/ml/outlier_test.go create mode 100644 pkg/expr/ml/testing.go create mode 100644 pkg/expr/ml_test.go create mode 100644 pkg/expr/testing.go diff --git a/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md b/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md index 61abf60d29c..df8a74dbbb2 100644 --- a/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md +++ b/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md @@ -126,6 +126,7 @@ Experimental features might be changed or removed without prior notice. | `logsExploreTableVisualisation` | A table visualisation for logs in Explore | | `awsDatasourcesTempCredentials` | Support temporary security credentials in AWS plugins for Grafana Cloud customers | | `transformationsRedesign` | Enables the transformations redesign | +| `mlExpressions` | Enable support for Machine Learning in server-side expressions | ## Development feature toggles diff --git a/packages/grafana-data/src/types/featureToggles.gen.ts b/packages/grafana-data/src/types/featureToggles.gen.ts index c7bb1c3e7d4..5012f55301a 100644 --- a/packages/grafana-data/src/types/featureToggles.gen.ts +++ b/packages/grafana-data/src/types/featureToggles.gen.ts @@ -113,4 +113,5 @@ export interface FeatureToggles { logsExploreTableVisualisation?: boolean; awsDatasourcesTempCredentials?: boolean; transformationsRedesign?: boolean; + mlExpressions?: boolean; } diff --git a/pkg/expr/graph.go b/pkg/expr/graph.go index b8b7d1bce45..eb26a87117f 100644 --- a/pkg/expr/graph.go +++ b/pkg/expr/graph.go @@ -11,6 +11,7 @@ import ( "gonum.org/v1/gonum/graph/topo" "github.com/grafana/grafana/pkg/expr/mathexp" + "github.com/grafana/grafana/pkg/services/featuremgmt" ) // NodeType is the type of a DPNode. Currently either a expression command or datasource query. @@ -21,6 +22,8 @@ const ( TypeCMDNode NodeType = iota // TypeDatasourceNode is a NodeType for datasource queries. TypeDatasourceNode + // TypeMLNode is a NodeType for Machine Learning queries. + TypeMLNode ) func (nt NodeType) String() string { @@ -29,6 +32,8 @@ func (nt NodeType) String() string { return "Expression" case TypeDatasourceNode: return "Datasource" + case TypeMLNode: + return "Machine Learning" default: return "Unknown" } @@ -159,6 +164,7 @@ func (s *Service) buildGraph(req *Request) (*simple.DirectedGraph, error) { rn := &rawNode{ Query: rawQueryProp, + QueryRaw: query.JSON, RefID: query.RefID, TimeRange: query.TimeRange, QueryType: query.QueryType, @@ -171,7 +177,16 @@ func (s *Service) buildGraph(req *Request) (*simple.DirectedGraph, error) { node, err = s.buildDSNode(dp, rn, req) case TypeCMDNode: node, err = buildCMDNode(dp, rn) - default: + case TypeMLNode: + if s.features.IsEnabled(featuremgmt.FlagMlExpressions) { + node, err = s.buildMLNode(dp, rn, req) + if err != nil { + err = fmt.Errorf("fail to parse expression with refID %v: %w", rn.RefID, err) + } + } + } + + if node == nil && err == nil { err = fmt.Errorf("unsupported node type '%s'", NodeTypeFromDatasourceUID(query.DataSource.UID)) } diff --git a/pkg/expr/ml.go b/pkg/expr/ml.go new file mode 100644 index 00000000000..902a64aef88 --- /dev/null +++ b/pkg/expr/ml.go @@ -0,0 +1,158 @@ +package expr + +import ( + "context" + "errors" + "fmt" + "net/http" + "strings" + "time" + + "github.com/grafana/grafana-plugin-sdk-go/backend" + jsoniter "github.com/json-iterator/go" + "gonum.org/v1/gonum/graph/simple" + + "github.com/grafana/grafana/pkg/api/response" + "github.com/grafana/grafana/pkg/expr/mathexp" + "github.com/grafana/grafana/pkg/expr/ml" + "github.com/grafana/grafana/pkg/plugins/httpresponsesender" + "github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext" +) + +var ( + errMLPluginDoesNotExist = fmt.Errorf("expression type Machine Learning cannot be executed. Plugin '%s' must be installed and initialized", mlPluginID) +) + +const ( + // mlDatasourceID is similar to a fake ID for CMDNode. There is no specific reason for the selection of this value. + mlDatasourceID = -200 + + // DatasourceUID is the string constant used as the datasource name in requests + // to identify it as an expression command when use in Datasource.UID. + MLDatasourceUID = "__ml__" + + // mlPluginID is a known constant and used in other places of the code + mlPluginID = "grafana-ml-app" +) + +// MLNode is a node of expression tree that evaluates the expression by sending the payload to Machine Learning back-end. +// See ml.UnmarshalCommand for supported commands. +type MLNode struct { + baseNode + command ml.Command + TimeRange TimeRange + request *Request +} + +// NodeType returns the data pipeline node type. +func (m *MLNode) NodeType() NodeType { + return TypeMLNode +} + +// Execute initializes plugin API client, executes a ml.Command and then converts the result of the execution. +// Returns non-empty mathexp.Results if evaluation was successful. Returns QueryError if command execution failed +func (m *MLNode) Execute(ctx context.Context, now time.Time, _ mathexp.Vars, s *Service) (r mathexp.Results, e error) { + logger := logger.FromContext(ctx).New("datasourceType", mlPluginID, "queryRefId", m.refID) + var result mathexp.Results + timeRange := m.TimeRange.AbsoluteTime(now) + + // get the plugin configuration that will be used by client (auth, host, etc) + pCtx, err := s.pCtxProvider.Get(ctx, mlPluginID, m.request.User, m.request.OrgId) + if err != nil { + if errors.Is(err, plugincontext.ErrPluginNotFound) { + return result, errMLPluginDoesNotExist + } + return result, fmt.Errorf("failed to get plugin settings: %w", err) + } + + // Plugin must be initialized by the admin first. That will create service account, and update plugin settings so all requests can use it. + // Fail if it is not initialized. + if pCtx.AppInstanceSettings == nil || !jsoniter.Get(pCtx.AppInstanceSettings.JSONData, "initialized").ToBool() { + return mathexp.Results{}, errMLPluginDoesNotExist + } + + // responseType and respStatus will be updated below. Use defer to ensure that debug log message is always emitted + responseType := "unknown" + respStatus := "success" + defer func() { + if e != nil { + responseType = "error" + respStatus = "failure" + } + logger.Debug("Data source queried", "responseType", responseType) + useDataplane := strings.HasPrefix("dataplane-", responseType) + s.metrics.dsRequests.WithLabelValues(respStatus, fmt.Sprintf("%t", useDataplane)).Inc() + }() + + // Execute the command and provide callback function for sending a request via plugin API. + // This lets us make commands abstracted from peculiarities of the transfer protocol. + data, err := m.command.Execute(timeRange.From, timeRange.To, func(method string, path string, payload []byte) (response.Response, error) { + crReq := &backend.CallResourceRequest{ + PluginContext: pCtx, + Path: path, + Method: method, + URL: path, + Headers: make(map[string][]string, len(m.request.Headers)), + Body: payload, + } + + // copy headers from the request to evaluate the expression pipeline. Usually this contains information from upstream, e.g. FromAlert + for key, val := range m.request.Headers { + crReq.SetHTTPHeader(key, val) + } + + resp := response.CreateNormalResponse(make(http.Header), nil, 0) + httpSender := httpresponsesender.New(resp) + err = s.pluginsClient.CallResource(ctx, crReq, httpSender) + if err != nil { + return nil, err + } + return resp, nil + }) + + if err != nil { + return result, QueryError{ + RefID: m.refID, + Err: err, + } + } + + // data is not guaranteed to be specified. In this case simulate NoData scenario + if data == nil { + data = &backend.QueryDataResponse{Responses: map[string]backend.DataResponse{}} + } + + dataFrames, err := getResponseFrame(data, m.refID) + if err != nil { + return mathexp.Results{}, QueryError{ + RefID: m.refID, + DatasourceUID: mlPluginID, + Err: err, + } + } + + // process the response the same way DSNode does. Use plugin ID as data source type. Semantically, they are the same. + responseType, result, err = convertDataFramesToResults(ctx, dataFrames, mlPluginID, s, logger) + return result, err +} + +func (s *Service) buildMLNode(dp *simple.DirectedGraph, rn *rawNode, req *Request) (Node, error) { + if rn.TimeRange == nil { + return nil, errors.New("time range must be specified") + } + + cmd, err := ml.UnmarshalCommand(rn.QueryRaw, s.cfg.AppURL) + if err != nil { + return nil, err + } + + return &MLNode{ + baseNode: baseNode{ + id: dp.NewNode().ID(), + refID: rn.RefID, + }, + TimeRange: rn.TimeRange, + command: cmd, + request: req, + }, nil +} diff --git a/pkg/expr/ml/model.go b/pkg/expr/ml/model.go new file mode 100644 index 00000000000..00ae818996b --- /dev/null +++ b/pkg/expr/ml/model.go @@ -0,0 +1,83 @@ +package ml + +import ( + "strings" + "time" + + "github.com/grafana/grafana-plugin-sdk-go/backend" + jsoniter "github.com/json-iterator/go" +) + +type CommandConfiguration struct { + Type string `json:"type"` + IntervalMs *uint `json:"intervalMs,omitempty"` + Config jsoniter.RawMessage `json:"config"` +} + +type OutlierCommandConfiguration struct { + DatasourceType string `json:"datasource_type"` + DatasourceUID string `json:"datasource_uid,omitempty"` + + // If Query is empty it should be contained in a datasource specific format + // inside of QueryParms. + Query string `json:"query,omitempty"` + QueryParams map[string]interface{} `json:"query_params,omitempty"` + + Algorithm map[string]interface{} `json:"algorithm"` + ResponseType string `json:"response_type"` +} + +// outlierAttributes is outlier command configuration that is sent to Machine learning API +type outlierAttributes struct { + OutlierCommandConfiguration + GrafanaURL string `json:"grafana_url"` + StartEndAttributes timeRangeAndInterval `json:"start_end_attributes"` +} + +type outlierData struct { + Attributes outlierAttributes `json:"attributes"` +} + +// outlierRequestBody describes a request body that is sent to Outlier API +type outlierRequestBody struct { + Data outlierData `json:"data"` +} + +type timeRangeAndInterval struct { + Start mlTime `json:"start"` + End mlTime `json:"end"` + Interval int64 `json:"interval"` // Interval is expected to be in milliseconds +} + +func newTimeRangeAndInterval(from, to time.Time, interval time.Duration) timeRangeAndInterval { + return timeRangeAndInterval{ + Start: mlTime(from), + End: mlTime(to), + Interval: interval.Milliseconds(), + } +} + +// mlTime is a time.Time that is marshalled as a string in a format is supported by Machine Learning API +type mlTime time.Time + +func (t *mlTime) UnmarshalJSON(b []byte) error { + s := strings.Trim(string(b), "\"") + parsed, err := time.Parse(timeFormat, s) + if err != nil { + return err + } + *t = mlTime(parsed) + return nil +} + +// MarshalJSON implements the Marshaler interface. +func (t mlTime) MarshalJSON() ([]byte, error) { + return []byte("\"" + time.Time(t).Format(timeFormat) + "\""), nil +} + +// outlierResponse is a model that represents a response of the outlier proxy API. +type outlierResponse struct { + Status string `json:"status"` + Data *backend.QueryDataResponse `json:"data,omitempty"` + Error string `json:"error,omitempty"` +} diff --git a/pkg/expr/ml/node.go b/pkg/expr/ml/node.go new file mode 100644 index 00000000000..096ce77d239 --- /dev/null +++ b/pkg/expr/ml/node.go @@ -0,0 +1,63 @@ +package ml + +import ( + "fmt" + "strings" + "time" + + "github.com/grafana/grafana-plugin-sdk-go/backend" + jsoniter "github.com/json-iterator/go" + + "github.com/grafana/grafana/pkg/api/response" +) + +var json = jsoniter.ConfigCompatibleWithStandardLibrary + +type CommandType string + +const ( + Outlier CommandType = "outlier" + + // format of the time used by outlier API + timeFormat = "2006-01-02T15:04:05.999999999" + + defaultInterval = 1000 * time.Millisecond +) + +// Command is an interface implemented by all Machine Learning commands that can be executed against ML API. +type Command interface { + // DatasourceUID returns UID of a data source that is used by machine learning as the source of data + DatasourceUID() string + // Execute creates a payload send request to the ML API by calling the function argument sendRequest, and then parses response. + // Function sendRequest is supposed to abstract the client configuration such creating http request, adding authorization parameters, host etc. + Execute(from, to time.Time, sendRequest func(method string, path string, payload []byte) (response.Response, error)) (*backend.QueryDataResponse, error) +} + +// UnmarshalCommand parses a config parameters and creates a command. Requires key `type` to be specified. +// Based on the value of `type` field it parses a Command +func UnmarshalCommand(query []byte, appURL string) (Command, error) { + var expr CommandConfiguration + err := json.Unmarshal(query, &expr) + if err != nil { + return nil, fmt.Errorf("failed to unmarshall Machine learning command: %w", err) + } + if len(expr.Type) == 0 { + return nil, fmt.Errorf("required field 'type' is not specified or empty. Should be one of [%s]", Outlier) + } + + if len(expr.Config) == 0 { + return nil, fmt.Errorf("required field 'config' is not specified") + } + + var cmd Command + switch mlType := strings.ToLower(expr.Type); mlType { + case string(Outlier): + cmd, err = unmarshalOutlierCommand(expr, appURL) + default: + return nil, fmt.Errorf("unsupported command type. Should be one of [%s]", Outlier) + } + if err != nil { + return nil, fmt.Errorf("failed to unmarshal Machine learning %s command: %w", expr.Type, err) + } + return cmd, nil +} diff --git a/pkg/expr/ml/node_test.go b/pkg/expr/ml/node_test.go new file mode 100644 index 00000000000..e62faff0aa3 --- /dev/null +++ b/pkg/expr/ml/node_test.go @@ -0,0 +1,167 @@ +package ml + +import ( + "testing" + "time" + + "github.com/google/uuid" + "github.com/stretchr/testify/require" +) + +func TestUnmarshalCommand(t *testing.T) { + appURL := "https://grafana.com" + + updateJson := func(cmd string, f func(m map[string]interface{})) func(t *testing.T) []byte { + return func(t *testing.T) []byte { + var d map[string]interface{} + require.NoError(t, json.UnmarshalFromString(cmd, &d)) + f(d) + data, err := json.Marshal(d) + require.NoError(t, err) + return data + } + } + t.Run("should parse outlier command", func(t *testing.T) { + cmd, err := UnmarshalCommand([]byte(outlierQuery), appURL) + require.NoError(t, err) + require.IsType(t, &OutlierCommand{}, cmd) + outlier := cmd.(*OutlierCommand) + require.Equal(t, 1234*time.Millisecond, outlier.interval) + require.Equal(t, appURL, outlier.appURL) + require.Equal(t, OutlierCommandConfiguration{ + DatasourceType: "prometheus", + DatasourceUID: "a4ce599c-4c93-44b9-be5b-76385b8c01be", + QueryParams: map[string]interface{}{ + "expr": "go_goroutines{}", + "range": true, + "refId": "A", + }, + Algorithm: map[string]interface{}{ + "name": "dbscan", + "config": map[string]interface{}{ + "epsilon": 7.667, + }, + "sensitivity": 0.83, + }, + ResponseType: "binary", + }, outlier.config) + }) + t.Run("should fallback to default if 'intervalMs' is not specified", func(t *testing.T) { + data := updateJson(outlierQuery, func(m map[string]interface{}) { + delete(m, "intervalMs") + })(t) + cmd, err := UnmarshalCommand(data, appURL) + require.NoError(t, err) + outlier := cmd.(*OutlierCommand) + require.Equal(t, defaultInterval, outlier.interval) + }) + t.Run("fails when", func(t *testing.T) { + testCases := []struct { + name string + config func(t *testing.T) []byte + err string + }{ + { + name: "field 'type' is missing", + config: updateJson(outlierQuery, func(cmd map[string]interface{}) { + delete(cmd, "type") + }), + err: "required field 'type' is not specified or empty. Should be one of [outlier]", + }, + { + name: "field 'type' is not known", + config: updateJson(outlierQuery, func(cmd map[string]interface{}) { + cmd["type"] = uuid.NewString() + }), + err: "unsupported command type. Should be one of [outlier]", + }, + { + name: "field 'type' is not string", + config: updateJson(outlierQuery, func(cmd map[string]interface{}) { + cmd["type"] = map[string]interface{}{ + "data": 1, + } + }), + err: "failed to unmarshall Machine learning command", + }, + { + name: "field 'config' is missing", + config: updateJson(outlierQuery, func(cmd map[string]interface{}) { + delete(cmd, "config") + }), + err: "required field 'config' is not specified", + }, + { + name: "field 'intervalMs' is not number", + config: updateJson(outlierQuery, func(cmd map[string]interface{}) { + cmd["intervalMs"] = "test" + }), + err: "failed to unmarshall Machine learning command", + }, + { + name: "field 'config.datasource_uid' is not specified", + config: updateJson(outlierQuery, func(cmd map[string]interface{}) { + cfg := cmd["config"].(map[string]interface{}) + delete(cfg, "datasource_uid") + }), + err: "required field `config.datasource_uid` is not specified", + }, + { + name: "field 'config.algorithm' is not specified", + config: updateJson(outlierQuery, func(cmd map[string]interface{}) { + cfg := cmd["config"].(map[string]interface{}) + delete(cfg, "algorithm") + }), + err: "required field `config.algorithm` is not specified", + }, + { + name: "field 'config.response_type' is not specified", + config: updateJson(outlierQuery, func(cmd map[string]interface{}) { + cfg := cmd["config"].(map[string]interface{}) + delete(cfg, "response_type") + }), + err: "required field `config.response_type` is not specified", + }, + { + name: "fields 'config.query' and 'config.query_params' are not specified", + config: updateJson(outlierQuery, func(cmd map[string]interface{}) { + cfg := cmd["config"].(map[string]interface{}) + delete(cfg, "query") + delete(cfg, "query_params") + }), + err: "neither of required fields `config.query_params` or `config.query` are specified", + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + _, err := UnmarshalCommand(testCase.config(t), appURL) + require.ErrorContains(t, err, testCase.err) + }) + } + }) +} + +const outlierQuery = ` +{ + "type": "outlier", + "intervalMs": 1234, + "config": { + "datasource_uid": "a4ce599c-4c93-44b9-be5b-76385b8c01be", + "datasource_type": "prometheus", + "query_params": { + "expr": "go_goroutines{}", + "range": true, + "refId": "A" + }, + "response_type": "binary", + "algorithm": { + "name": "dbscan", + "config": { + "epsilon": 7.667 + }, + "sensitivity": 0.83 + } + } +} +` diff --git a/pkg/expr/ml/outlier.go b/pkg/expr/ml/outlier.go new file mode 100644 index 00000000000..40a53446c26 --- /dev/null +++ b/pkg/expr/ml/outlier.go @@ -0,0 +1,116 @@ +package ml + +import ( + "fmt" + "net/http" + "time" + + "github.com/grafana/grafana-plugin-sdk-go/backend" + + "github.com/grafana/grafana/pkg/api/response" +) + +// OutlierCommand implements Command that sends a request to outlier proxy API and converts response to backend.QueryDataResponse +type OutlierCommand struct { + config OutlierCommandConfiguration + appURL string + interval time.Duration +} + +var _ Command = OutlierCommand{} + +func (c OutlierCommand) DatasourceUID() string { + return c.config.DatasourceUID +} + +// Execute copies the original configuration JSON and appends (overwrites) a field "start_end_attributes" and "grafana_url" to the root object. +// The value of "start_end_attributes" is JSON object that configures time range and interval. +// The value of "grafana_url" is app URL that should be used by ML to query the data source. +// After payload is generated it sends it to POST /proxy/api/v1/outlier endpoint and parses the response. +// The proxy API normally responds with a structured data. It recognizes status 200 and 204 as successful result. +// Other statuses are considered unsuccessful and result in error. Tries to extract error from the structured payload. +// Otherwise, mentions the full message in error +func (c OutlierCommand) Execute(from, to time.Time, sendRequest func(method string, path string, payload []byte) (response.Response, error)) (*backend.QueryDataResponse, error) { + payload := outlierRequestBody{ + Data: outlierData{ + Attributes: outlierAttributes{ + OutlierCommandConfiguration: c.config, + GrafanaURL: c.appURL, + StartEndAttributes: newTimeRangeAndInterval(from, to, c.interval), + }, + }, + } + requestBody, err := json.Marshal(payload) + if err != nil { + return nil, err + } + resp, err := sendRequest(http.MethodPost, "/proxy/api/v1/outlier", requestBody) + + if err != nil { + return nil, fmt.Errorf("failed to call ML API: %w", err) + } + if resp == nil { + return nil, fmt.Errorf("response is nil") + } + + // Outlier proxy API usually returns all responses with this body. + var respData outlierResponse + + respBody := resp.Body() + err = json.Unmarshal(respBody, &respData) + if err != nil { + return nil, fmt.Errorf("unexpected format of the response from ML API, status: %d, response: %s", resp.Status(), respBody) + } + + if respData.Status == "error" { + return nil, fmt.Errorf("ML API responded with error: %s", respData.Error) + } + + if resp.Status() == http.StatusNoContent { + return nil, nil + } + + if resp.Status() == http.StatusOK { + return respData.Data, nil + } + + return nil, fmt.Errorf("unexpected status %d returned by ML API, response: %s", resp.Status(), respBody) +} + +// unmarshalOutlierCommand parses the CommandConfiguration.Config, validates data and produces OutlierCommand. +func unmarshalOutlierCommand(expr CommandConfiguration, appURL string) (*OutlierCommand, error) { + var cfg OutlierCommandConfiguration + err := json.Unmarshal(expr.Config, &cfg) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal outlier command: %w", err) + } + if len(cfg.DatasourceUID) == 0 { + return nil, fmt.Errorf("required field `config.datasource_uid` is not specified") + } + + if len(cfg.Query) == 0 && len(cfg.QueryParams) == 0 { + return nil, fmt.Errorf("neither of required fields `config.query_params` or `config.query` are specified") + } + + if len(cfg.ResponseType) == 0 { + return nil, fmt.Errorf("required field `config.response_type` is not specified") + } + + if len(cfg.Algorithm) == 0 { + return nil, fmt.Errorf("required field `config.algorithm` is not specified") + } + + interval := defaultInterval + if expr.IntervalMs != nil { + i := time.Duration(*expr.IntervalMs) * time.Millisecond + if i > 0 { + interval = i + } + } + + return &OutlierCommand{ + config: cfg, + interval: interval, + appURL: appURL, + }, nil +} diff --git a/pkg/expr/ml/outlier_test.go b/pkg/expr/ml/outlier_test.go new file mode 100644 index 00000000000..f48003eeca8 --- /dev/null +++ b/pkg/expr/ml/outlier_test.go @@ -0,0 +1,194 @@ +package ml + +import ( + "errors" + "fmt" + "net/http" + "testing" + "time" + + "github.com/grafana/grafana-plugin-sdk-go/backend" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "golang.org/x/exp/slices" + + "github.com/grafana/grafana/pkg/api/response" +) + +func TestOutlierExec(t *testing.T) { + outlier := OutlierCommand{ + config: OutlierCommandConfiguration{ + DatasourceType: "prometheus", + DatasourceUID: "a4ce599c-4c93-44b9-be5b-76385b8c01be", + QueryParams: map[string]interface{}{ + "expr": "go_goroutines{}", + "range": true, + "refId": "A", + }, + Algorithm: map[string]interface{}{ + "name": "dbscan", + "config": map[string]interface{}{ + "epsilon": 7.667, + }, + "sensitivity": 0.83, + }, + ResponseType: "binary", + }, + appURL: "https://grafana.com", + interval: 1000 * time.Second, + } + + t.Run("should generate expected parameters for request", func(t *testing.T) { + to := time.Now().UTC() + from := to.Add(-10 * time.Hour) + + called := false + _, err := outlier.Execute(from, to, func(method string, path string, payload []byte) (response.Response, error) { + require.Equal(t, "POST", method) + require.Equal(t, "/proxy/api/v1/outlier", path) + + assert.JSONEq(t, fmt.Sprintf(`{ + "data": { + "attributes": { + "datasource_type": "prometheus", + "datasource_uid": "a4ce599c-4c93-44b9-be5b-76385b8c01be", + "query_params": { + "expr": "go_goroutines{}", + "range": true, + "refId": "A" + }, + "algorithm": { + "config": { + "epsilon": 7.667 + }, + "name": "dbscan", + "sensitivity": 0.83 + }, + "response_type": "binary", + "grafana_url": "https://grafana.com", + "start_end_attributes": { + "start": "%s", + "end": "%s", + "interval": 1000000 + } + } + } + }`, from.Format(timeFormat), to.Format(timeFormat)), string(payload)) + + called = true + return nil, nil + }) + require.Truef(t, called, "request function was not called") + require.ErrorContains(t, err, "response is nil") + }) + + successResponse := `{"status":"success","data":{"results":{"A":{"status":200,"frames":[{"schema":{"name":"test","fields":[{"name":"Time","type":"time","typeInfo":{"frame":"time.Time"}},{"name":"Value","type":"number","typeInfo":{"frame":"float64"},"labels":{"instance":"test"}}]},"data":{"values":[[1686945300000],[0]]}}]}}}}` + + testCases := []struct { + name string + response response.Response + assert func(t *testing.T, r *backend.QueryDataResponse, err error) + }{ + { + name: "should return parsed frames when 200", + response: response.CreateNormalResponse(nil, []byte(successResponse), http.StatusOK), + assert: func(t *testing.T, r *backend.QueryDataResponse, err error) { + require.NoError(t, err) + require.NotNil(t, r) + require.Contains(t, r.Responses, "A") + require.NoError(t, r.Responses["A"].Error) + require.Equal(t, backend.StatusOK, r.Responses["A"].Status) + require.Len(t, r.Responses["A"].Frames, 1) + }, + }, + { + name: "should return nil if 204", + response: response.CreateNormalResponse(nil, []byte(`{"status": "success"}`), http.StatusNoContent), + assert: func(t *testing.T, r *backend.QueryDataResponse, err error) { + require.NoError(t, err) + require.Nil(t, r) + }, + }, + { + name: "should return error if any status and body has status error", + response: response.CreateNormalResponse(nil, []byte(`{"status": "error"}`), 0), + assert: func(t *testing.T, r *backend.QueryDataResponse, err error) { + require.ErrorContains(t, err, "ML API responded with error") + require.Nil(t, r) + }, + }, + { + name: "should return error with explanations if any status and body has status error", + response: response.CreateNormalResponse(nil, []byte(`{"status": "error", "error": "test-error"}`), 0), + assert: func(t *testing.T, r *backend.QueryDataResponse, err error) { + require.ErrorContains(t, err, "ML API responded with error") + require.ErrorContains(t, err, "test-error") + require.Nil(t, r) + }, + }, + { + name: "should return error response is empty", + response: response.CreateNormalResponse(nil, []byte(``), 0), + assert: func(t *testing.T, r *backend.QueryDataResponse, err error) { + require.ErrorContains(t, err, "unexpected format of the response from ML API") + require.Nil(t, r) + }, + }, + { + name: "should return error response is not a valid JSON", + response: response.CreateNormalResponse(nil, []byte(`{`), 0), + assert: func(t *testing.T, r *backend.QueryDataResponse, err error) { + require.ErrorContains(t, err, "unexpected format of the response from ML API") + require.Nil(t, r) + }, + }, + { + name: "should error if response is nil and no error", + response: nil, + assert: func(t *testing.T, r *backend.QueryDataResponse, err error) { + require.ErrorContains(t, err, "response is nil") + require.Nil(t, r) + }, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + to := time.Now() + from := to.Add(-10 * time.Hour) + + resp, err := outlier.Execute(from, to, func(method string, path string, payload []byte) (response.Response, error) { + return tc.response, nil + }) + tc.assert(t, resp, err) + }) + } + + t.Run("should return error if status is not known", func(t *testing.T) { + knownStatuses := []int{http.StatusOK, http.StatusNoContent} + + for status := 100; status < 600; status++ { + if http.StatusText(status) == "" || slices.Contains(knownStatuses, status) { + continue + } + to := time.Now() + from := to.Add(-10 * time.Hour) + + resp, err := outlier.Execute(from, to, func(method string, path string, payload []byte) (response.Response, error) { + return response.CreateNormalResponse(nil, []byte(successResponse), status), nil + }) + require.ErrorContains(t, err, fmt.Sprintf("unexpected status %d returned by ML API", status)) + require.Nil(t, resp) + } + }) + + t.Run("should propagate error from request function", func(t *testing.T) { + to := time.Now() + from := to.Add(-10 * time.Hour) + + resp, err := outlier.Execute(from, to, func(method string, path string, payload []byte) (response.Response, error) { + return nil, errors.New("test-error") + }) + require.ErrorContains(t, err, "test-error") + require.Nil(t, resp) + }) +} diff --git a/pkg/expr/ml/testing.go b/pkg/expr/ml/testing.go new file mode 100644 index 00000000000..b10eeffe1a8 --- /dev/null +++ b/pkg/expr/ml/testing.go @@ -0,0 +1,44 @@ +package ml + +import ( + "time" + + "github.com/grafana/grafana-plugin-sdk-go/backend" + + "github.com/grafana/grafana/pkg/api/response" +) + +type FakeCommand struct { + Method string + Path string + Payload []byte + Response *backend.QueryDataResponse + Error error + Recordings []struct { + From time.Time + To time.Time + Response response.Response + Error error + } +} + +var _ Command = &FakeCommand{} + +func (f *FakeCommand) DatasourceUID() string { + return "fake-ml-datasource" +} + +func (f *FakeCommand) Execute(from, to time.Time, executor func(method string, path string, payload []byte) (response.Response, error)) (*backend.QueryDataResponse, error) { + r, err := executor(f.Method, f.Path, f.Payload) + f.Recordings = append(f.Recordings, struct { + From time.Time + To time.Time + Response response.Response + Error error + }{From: from, To: to, Response: r, Error: err}) + + if err != nil { + return nil, err + } + return f.Response, f.Error +} diff --git a/pkg/expr/ml_test.go b/pkg/expr/ml_test.go new file mode 100644 index 00000000000..b7f7771668c --- /dev/null +++ b/pkg/expr/ml_test.go @@ -0,0 +1,219 @@ +package expr + +import ( + "context" + "encoding/json" + "errors" + "net/http" + "testing" + "time" + + "github.com/grafana/grafana-plugin-sdk-go/backend" + "github.com/grafana/grafana-plugin-sdk-go/data" + "github.com/stretchr/testify/require" + + "github.com/grafana/grafana/pkg/expr/ml" + "github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext" + "github.com/grafana/grafana/pkg/services/user" +) + +func TestMLNodeExecute(t *testing.T) { + timeNow := time.Now() + expectedOrgID := int64(123) + timeRange := RelativeTimeRange{ + From: -10 * time.Hour, + To: 0, + } + request := &Request{ + Headers: map[string]string{ + "test": "test", + }, + Debug: false, + OrgId: expectedOrgID, + Queries: nil, + User: &user.SignedInUser{ + UserID: 1, + }, + } + + expectedResponse := &backend.CallResourceResponse{ + Status: 200, + Headers: nil, + Body: []byte("test-response"), + } + + pluginsClient := &recordingCallResourceHandler{ + response: expectedResponse, + } + + pluginCtx := &fakePluginContextProvider{ + result: map[string]*backend.AppInstanceSettings{ + mlPluginID: { + JSONData: json.RawMessage(`{ "initialized": true }`), + }, + }, + } + + s := &Service{ + cfg: nil, + dataService: nil, + pCtxProvider: pluginCtx, + features: nil, + pluginsClient: pluginsClient, + tracer: nil, + metrics: newMetrics(nil), + } + + cmdResponse := data.NewFrame("test", + data.NewField("Time", nil, []time.Time{time.Unix(1, 0)}), + data.NewField("Value", nil, []*float64{fp(1)}), + ) + + cmd := &ml.FakeCommand{ + Method: http.MethodPost, + Path: "/test/ml", + Payload: []byte(`{}`), + Response: &backend.QueryDataResponse{ + Responses: map[string]backend.DataResponse{ + "A": { + Frames: data.Frames{ + cmdResponse, + }, + Status: backend.StatusOK, + }, + }, + }, + Error: nil, + } + + node := &MLNode{ + baseNode: baseNode{}, + command: cmd, + TimeRange: timeRange, + request: request, + } + + result, err := node.Execute(context.Background(), timeNow, nil, s) + + require.NoError(t, err) + require.NotNil(t, result) + require.NotEmpty(t, result.Values) + + t.Run("should get plugin context", func(t *testing.T) { + require.NotEmpty(t, pluginCtx.recordings) + require.Equal(t, "Get", pluginCtx.recordings[0].method) + require.Equal(t, mlPluginID, pluginCtx.recordings[0].params[0]) + require.Equal(t, request.User, pluginCtx.recordings[0].params[1]) + }) + + t.Run("should call command execute with correct parameters", func(t *testing.T) { + require.NotEmpty(t, cmd.Recordings) + rec := cmd.Recordings[0] + require.Equal(t, timeRange.AbsoluteTime(timeNow).From, rec.From) + require.Equal(t, timeRange.AbsoluteTime(timeNow).To, rec.To) + require.NotNil(t, rec.Response) + require.Equal(t, expectedResponse.Status, rec.Response.Status()) + require.Equal(t, expectedResponse.Body, rec.Response.Body()) + }) + + t.Run("should call plugin API", func(t *testing.T) { + require.NotEmpty(t, pluginsClient.recordings) + req := pluginsClient.recordings[0] + require.Equal(t, cmd.Payload, req.Body) + require.Equal(t, cmd.Path, req.Path) + require.Equal(t, cmd.Method, req.Method) + + require.NotNil(t, req.PluginContext) + require.Equal(t, mlPluginID, req.PluginContext.PluginID) + + t.Run("should append request headers to API call", func(t *testing.T) { + for key, value := range request.Headers { + require.Contains(t, req.Headers, key) + require.Equal(t, value, req.Headers[key][0]) + } + }) + }) + + t.Run("should fail if plugin is not installed", func(t *testing.T) { + s := &Service{ + cfg: nil, + dataService: nil, + pCtxProvider: &fakePluginContextProvider{ + errorResult: plugincontext.ErrPluginNotFound, + }, + features: nil, + pluginsClient: nil, + tracer: nil, + metrics: nil, + } + + _, err := node.Execute(context.Background(), timeNow, nil, s) + require.ErrorIs(t, err, errMLPluginDoesNotExist) + }) + + t.Run("should fail if plugin settings cannot be retrieved", func(t *testing.T) { + expectedErr := errors.New("test-error") + s := &Service{ + cfg: nil, + dataService: nil, + pCtxProvider: &fakePluginContextProvider{ + errorResult: expectedErr, + }, + features: nil, + pluginsClient: nil, + tracer: nil, + metrics: nil, + } + + _, err := node.Execute(context.Background(), timeNow, nil, s) + require.ErrorIs(t, err, expectedErr) + }) + + t.Run("should fail if plugin is not initialized", func(t *testing.T) { + s := &Service{ + cfg: nil, + dataService: nil, + pCtxProvider: &fakePluginContextProvider{ + result: map[string]*backend.AppInstanceSettings{ + mlPluginID: { + JSONData: json.RawMessage(`{}`), + }, + }, + }, + features: nil, + pluginsClient: nil, + tracer: nil, + metrics: nil, + } + + _, err := node.Execute(context.Background(), timeNow, nil, s) + require.ErrorIs(t, err, errMLPluginDoesNotExist) + }) + + t.Run("should return QueryError if command failed", func(t *testing.T) { + s := &Service{ + cfg: nil, + dataService: nil, + pCtxProvider: pluginCtx, + features: nil, + pluginsClient: pluginsClient, + tracer: nil, + metrics: newMetrics(nil), + } + + cmd := &ml.FakeCommand{ + Error: errors.New("failed to execute command"), + } + + node := &MLNode{ + baseNode: baseNode{}, + command: cmd, + TimeRange: timeRange, + request: request, + } + + _, err := node.Execute(context.Background(), timeNow, nil, s) + require.IsType(t, err, QueryError{}) + require.ErrorIs(t, err, cmd.Error) + }) +} diff --git a/pkg/expr/nodes.go b/pkg/expr/nodes.go index e9c622c7298..0846eee6ea0 100644 --- a/pkg/expr/nodes.go +++ b/pkg/expr/nodes.go @@ -47,6 +47,7 @@ type baseNode struct { type rawNode struct { RefID string `json:"refId"` Query map[string]interface{} + QueryRaw []byte QueryType string TimeRange TimeRange DataSource *datasources.DataSource diff --git a/pkg/expr/service.go b/pkg/expr/service.go index 16d625fc9a3..678be80c093 100644 --- a/pkg/expr/service.go +++ b/pkg/expr/service.go @@ -15,6 +15,7 @@ import ( "github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext" + "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" ) @@ -47,6 +48,9 @@ func NodeTypeFromDatasourceUID(uid string) NodeType { if IsDataSource(uid) { return TypeCMDNode } + if uid == MLDatasourceUID { + return TypeMLNode + } return TypeDatasourceNode } @@ -54,7 +58,7 @@ func NodeTypeFromDatasourceUID(uid string) NodeType { type Service struct { cfg *setting.Cfg dataService backend.QueryDataHandler - pCtxProvider *plugincontext.Provider + pCtxProvider pluginContextProvider features featuremgmt.FeatureToggles pluginsClient backend.CallResourceHandler @@ -63,6 +67,11 @@ type Service struct { metrics *metrics } +type pluginContextProvider interface { + Get(ctx context.Context, pluginID string, user *user.SignedInUser, orgID int64) (backend.PluginContext, error) + GetWithDataSource(ctx context.Context, pluginID string, user *user.SignedInUser, ds *datasources.DataSource) (backend.PluginContext, error) +} + func ProvideService(cfg *setting.Cfg, pluginClient plugins.Client, pCtxProvider *plugincontext.Provider, features featuremgmt.FeatureToggles, registerer prometheus.Registerer, tracer tracing.Tracer) *Service { return &Service{ @@ -117,6 +126,15 @@ func DataSourceModelFromNodeType(kind NodeType) (*datasources.DataSource, error) JsonData: simplejson.New(), SecureJsonData: make(map[string][]byte), }, nil + case TypeMLNode: + return &datasources.DataSource{ + ID: mlDatasourceID, + UID: MLDatasourceUID, + Name: DatasourceUID, + Type: mlPluginID, + JsonData: simplejson.New(), + SecureJsonData: make(map[string][]byte), + }, nil case TypeDatasourceNode: return nil, errors.New("cannot create expression data source for data source kind") default: diff --git a/pkg/expr/testing.go b/pkg/expr/testing.go new file mode 100644 index 00000000000..38fbda4bbb1 --- /dev/null +++ b/pkg/expr/testing.go @@ -0,0 +1,84 @@ +package expr + +import ( + "context" + + "github.com/grafana/grafana-plugin-sdk-go/backend" + + "github.com/grafana/grafana/pkg/services/datasources" + "github.com/grafana/grafana/pkg/services/user" +) + +type fakePluginContextProvider struct { + recordings []struct { + method string + params []interface{} + } + result map[string]*backend.AppInstanceSettings + errorResult error +} + +var _ pluginContextProvider = &fakePluginContextProvider{} + +func (f *fakePluginContextProvider) Get(_ context.Context, pluginID string, user *user.SignedInUser, orgID int64) (backend.PluginContext, error) { + f.recordings = append(f.recordings, struct { + method string + params []interface{} + }{method: "Get", params: []interface{}{pluginID, user, orgID}}) + if f.errorResult != nil { + return backend.PluginContext{}, f.errorResult + } + var u *backend.User + if user != nil { + u = &backend.User{ + Login: user.Login, + Name: user.Name, + Email: user.Email, + } + } + return backend.PluginContext{ + OrgID: orgID, + PluginID: pluginID, + User: u, + AppInstanceSettings: f.result[pluginID], + DataSourceInstanceSettings: nil, + }, nil +} + +func (f *fakePluginContextProvider) GetWithDataSource(ctx context.Context, pluginID string, user *user.SignedInUser, ds *datasources.DataSource) (backend.PluginContext, error) { + f.recordings = append(f.recordings, struct { + method string + params []interface{} + }{method: "GetWithDataSource", params: []interface{}{pluginID, user, ds}}) + + if f.errorResult != nil { + return backend.PluginContext{}, f.errorResult + } + + orgId := int64(1) + if user != nil { + orgId = user.OrgID + } + r, err := f.Get(ctx, pluginID, user, orgId) + if ds != nil { + r.DataSourceInstanceSettings = &backend.DataSourceInstanceSettings{ + ID: ds.ID, + UID: ds.UID, + Type: ds.Type, + Name: ds.Name, + } + } + return r, err +} + +type recordingCallResourceHandler struct { + recordings []*backend.CallResourceRequest + response *backend.CallResourceResponse +} + +var _ backend.CallResourceHandler = &recordingCallResourceHandler{} + +func (f *recordingCallResourceHandler) CallResource(_ context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error { + f.recordings = append(f.recordings, req) + return sender.Send(f.response) +} diff --git a/pkg/services/featuremgmt/registry.go b/pkg/services/featuremgmt/registry.go index fccfc55ba0b..88da30310f7 100644 --- a/pkg/services/featuremgmt/registry.go +++ b/pkg/services/featuremgmt/registry.go @@ -647,5 +647,12 @@ var ( FrontendOnly: true, Owner: grafanaObservabilityMetricsSquad, }, + { + Name: "mlExpressions", + Description: "Enable support for Machine Learning in server-side expressions", + Stage: FeatureStageExperimental, + FrontendOnly: false, + Owner: grafanaAlertingSquad, + }, } ) diff --git a/pkg/services/featuremgmt/toggles_gen.csv b/pkg/services/featuremgmt/toggles_gen.csv index b9eb5966cce..abdef73a443 100644 --- a/pkg/services/featuremgmt/toggles_gen.csv +++ b/pkg/services/featuremgmt/toggles_gen.csv @@ -94,3 +94,4 @@ prometheusIncrementalQueryInstrumentation,experimental,@grafana/observability-me logsExploreTableVisualisation,experimental,@grafana/observability-logs,false,false,false,true awsDatasourcesTempCredentials,experimental,@grafana/aws-datasources,false,false,false,false transformationsRedesign,experimental,@grafana/observability-metrics,false,false,false,true +mlExpressions,experimental,@grafana/alerting-squad,false,false,false,false diff --git a/pkg/services/featuremgmt/toggles_gen.go b/pkg/services/featuremgmt/toggles_gen.go index 53d37a1667c..2b0ca030888 100644 --- a/pkg/services/featuremgmt/toggles_gen.go +++ b/pkg/services/featuremgmt/toggles_gen.go @@ -386,4 +386,8 @@ const ( // FlagTransformationsRedesign // Enables the transformations redesign FlagTransformationsRedesign = "transformationsRedesign" + + // FlagMlExpressions + // Enable support for Machine Learning in server-side expressions + FlagMlExpressions = "mlExpressions" ) diff --git a/pkg/services/ngalert/eval/eval.go b/pkg/services/ngalert/eval/eval.go index 78339b97bb0..77a3d5e6ae2 100644 --- a/pkg/services/ngalert/eval/eval.go +++ b/pkg/services/ngalert/eval/eval.go @@ -270,10 +270,10 @@ func getExprRequest(ctx EvaluationContext, data []models.AlertQuery, dsCacheServ ds, ok := datasources[q.DatasourceUID] if !ok { switch nodeType := expr.NodeTypeFromDatasourceUID(q.DatasourceUID); nodeType { - case expr.TypeCMDNode: - ds, err = expr.DataSourceModelFromNodeType(nodeType) case expr.TypeDatasourceNode: ds, err = dsCacheService.GetDatasourceByUID(ctx.Ctx, q.DatasourceUID, ctx.User, false /*skipCache*/) + default: + ds, err = expr.DataSourceModelFromNodeType(nodeType) } if err != nil { return nil, fmt.Errorf("failed to build query '%s': %w", q.RefID, err) @@ -622,15 +622,24 @@ func (e *evaluatorImpl) Validate(ctx EvaluationContext, condition models.Conditi return err } for _, query := range req.Queries { - if query.DataSource == nil || expr.NodeTypeFromDatasourceUID(query.DataSource.UID) != expr.TypeDatasourceNode { + if query.DataSource == nil { continue } - p, found := e.pluginsStore.Plugin(ctx.Ctx, query.DataSource.Type) - if !found { // technically this should fail earlier during datasource resolution phase. - return fmt.Errorf("datasource refID %s could not be found: %w", query.RefID, plugins.ErrPluginUnavailable) - } - if !p.Backend { - return fmt.Errorf("datasource refID %s is not a backend datasource", query.RefID) + switch expr.NodeTypeFromDatasourceUID(query.DataSource.UID) { + case expr.TypeDatasourceNode: + p, found := e.pluginsStore.Plugin(ctx.Ctx, query.DataSource.Type) + if !found { // technically this should fail earlier during datasource resolution phase. + return fmt.Errorf("datasource refID %s could not be found: %w", query.RefID, plugins.ErrPluginUnavailable) + } + if !p.Backend { + return fmt.Errorf("datasource refID %s is not a backend datasource", query.RefID) + } + case expr.TypeMLNode: + _, found := e.pluginsStore.Plugin(ctx.Ctx, query.DataSource.Type) + if !found { + return fmt.Errorf("datasource refID %s could not be found: %w", query.RefID, plugins.ErrPluginUnavailable) + } + case expr.TypeCMDNode: } } _, err = e.create(condition, req) From e36a9a7b9d9198aa2d4f416549eb75eb903d80a4 Mon Sep 17 00:00:00 2001 From: Kat Yang <69819079+yangkb09@users.noreply.github.com> Date: Thu, 13 Jul 2023 13:52:37 -0400 Subject: [PATCH 18/42] new go mod (#71378) * new go mod * fix * remove golang.org/x/mod from go.sum * restore go.sum for x/mod * bring back x/mod into go.mod as it is used by build pkg * Assign oauth2 to authnz Co-authored-by: Sofia Papagiannaki <1632407+papagian@users.noreply.github.com> * Assign go-kit log to backend platform Co-authored-by: Sofia Papagiannaki <1632407+papagian@users.noreply.github.com> * Assign kindsys to as-code Co-authored-by: Sofia Papagiannaki <1632407+papagian@users.noreply.github.com> * Update go.mod Co-authored-by: Artur Wierzbicki * Update go.mod Co-authored-by: Artur Wierzbicki * Update go.mod Co-authored-by: Artur Wierzbicki * implement sofia's suggestions, change ownership to BEP for some imports * Update go.mod Co-authored-by: Sofia Papagiannaki <1632407+papagian@users.noreply.github.com> * Update go.mod Co-authored-by: sam boyer * Update go.mod Co-authored-by: Sofia Papagiannaki <1632407+papagian@users.noreply.github.com> * assign grpc to plugins platform --------- Co-authored-by: Serge Zaitsev Co-authored-by: Sofia Papagiannaki <1632407+papagian@users.noreply.github.com> Co-authored-by: sam boyer Co-authored-by: Artur Wierzbicki --- go.mod | 310 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 155 insertions(+), 155 deletions(-) diff --git a/go.mod b/go.mod index f5cc7b2d7a0..afe47307222 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ replace cuelang.org/go => github.com/sdboyer/cue v0.5.0-beta.2.0.20230712135403- // hoist a replace statement. replace k8s.io/client-go => k8s.io/client-go v0.25.3 -require k8s.io/apimachinery v0.26.2 +require k8s.io/apimachinery v0.26.2 // @grafana/backend-platform // Override Prometheus version because Prometheus v2.X is tagged as v0.X for Go modules purposes and Go assumes // that v1.Y is higher than v0.X, so when we resolve dependencies if any dependency imports v1.Y we'd @@ -27,104 +27,104 @@ require k8s.io/apimachinery v0.26.2 replace github.com/prometheus/prometheus => github.com/prometheus/prometheus v0.43.0 require ( - cloud.google.com/go/storage v1.28.1 - cuelang.org/go v0.6.0-0.dev - github.com/Azure/azure-sdk-for-go v65.0.0+incompatible - github.com/Azure/go-autorest/autorest v0.11.28 - github.com/BurntSushi/toml v1.2.1 - github.com/Masterminds/semver v1.5.0 - github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f - github.com/aws/aws-sdk-go v1.44.234 - github.com/beevik/etree v1.2.0 - github.com/benbjohnson/clock v1.3.3 - github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b - github.com/centrifugal/centrifuge v0.29.1 - github.com/crewjam/saml v0.4.13 - github.com/fatih/color v1.15.0 - github.com/gchaincl/sqlhooks v1.3.0 - github.com/go-git/go-git/v5 v5.4.2 - github.com/go-ldap/ldap/v3 v3.4.4 - github.com/go-openapi/strfmt v0.21.7 - github.com/go-redis/redis/v8 v8.11.5 - github.com/go-sourcemap/sourcemap v2.1.3+incompatible - github.com/go-sql-driver/mysql v1.7.1 - github.com/go-stack/stack v1.8.1 - github.com/gobwas/glob v0.2.3 + cloud.google.com/go/storage v1.28.1 // @grafana/backend-platform + cuelang.org/go v0.6.0-0.dev // @grafana/grafana-as-code + github.com/Azure/azure-sdk-for-go v65.0.0+incompatible // @grafana/backend-platform + github.com/Azure/go-autorest/autorest v0.11.28 // @grafana/backend-platform + github.com/BurntSushi/toml v1.2.1 // @grafana/grafana-authnz-team + github.com/Masterminds/semver v1.5.0 // @grafana/backend-platform + github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f // @grafana/backend-platform + github.com/aws/aws-sdk-go v1.44.234 // @grafana/aws-datasources + github.com/beevik/etree v1.2.0 // @grafana/backend-platform + github.com/benbjohnson/clock v1.3.3 // @grafana/alerting-squad-backend + github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b // @grafana/backend-platform + github.com/centrifugal/centrifuge v0.29.1 // @grafana/grafana-app-platform-squad + github.com/crewjam/saml v0.4.13 // @grafana/backend-platform + github.com/fatih/color v1.15.0 // @grafana/backend-platform + github.com/gchaincl/sqlhooks v1.3.0 // @grafana/backend-platform + github.com/go-git/go-git/v5 v5.4.2 // @grafana/grafana-app-platform-squad + github.com/go-ldap/ldap/v3 v3.4.4 // @grafana/grafana-authnz-team + github.com/go-openapi/strfmt v0.21.7 // @grafana/alerting-squad-backend + github.com/go-redis/redis/v8 v8.11.5 // @grafana/backend-platform + github.com/go-sourcemap/sourcemap v2.1.3+incompatible // @grafana/backend-platform + github.com/go-sql-driver/mysql v1.7.1 // @grafana/backend-platform + github.com/go-stack/stack v1.8.1 // @grafana/backend-platform + github.com/gobwas/glob v0.2.3 // @grafana/backend-platform github.com/gofrs/uuid v4.4.0+incompatible // indirect - github.com/gogo/protobuf v1.3.2 - github.com/golang/mock v1.6.0 - github.com/golang/snappy v0.0.4 - github.com/google/go-cmp v0.5.9 - github.com/google/uuid v1.3.0 - github.com/google/wire v0.5.0 - github.com/gorilla/websocket v1.5.0 - github.com/grafana/alerting v0.0.0-20230606080147-55b8d71c7890 - github.com/grafana/cuetsy v0.1.10 - github.com/grafana/grafana-aws-sdk v0.15.0 - github.com/grafana/grafana-azure-sdk-go v1.7.0 - github.com/grafana/grafana-plugin-sdk-go v0.165.0 - github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 - github.com/hashicorp/go-hclog v1.5.0 - github.com/hashicorp/go-plugin v1.4.9 - github.com/hashicorp/go-version v1.3.0 - github.com/influxdata/influxdb-client-go/v2 v2.6.0 - github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 - github.com/jmespath/go-jmespath v0.4.0 - github.com/json-iterator/go v1.1.12 - github.com/jung-kurt/gofpdf v1.16.2 - github.com/lib/pq v1.10.6 - github.com/linkedin/goavro/v2 v2.10.0 - github.com/m3db/prometheus_remote_client_golang v0.4.4 - github.com/magefile/mage v1.14.0 - github.com/mattn/go-isatty v0.0.18 - github.com/mattn/go-sqlite3 v1.14.16 - github.com/matttproud/golang_protobuf_extensions v1.0.4 - github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f + github.com/gogo/protobuf v1.3.2 // @grafana/alerting-squad-backend + github.com/golang/mock v1.6.0 // @grafana/alerting-squad-backend + github.com/golang/snappy v0.0.4 // @grafana/alerting-squad-backend + github.com/google/go-cmp v0.5.9 // @grafana/backend-platform + github.com/google/uuid v1.3.0 // @grafana/backend-platform + github.com/google/wire v0.5.0 // @grafana/backend-platform + github.com/gorilla/websocket v1.5.0 // @grafana/grafana-app-platform-squad + github.com/grafana/alerting v0.0.0-20230606080147-55b8d71c7890 // @grafana/alerting-squad-backend + github.com/grafana/cuetsy v0.1.10 // @grafana/grafana-as-code + github.com/grafana/grafana-aws-sdk v0.15.0 // @grafana/aws-datasources + github.com/grafana/grafana-azure-sdk-go v1.7.0 // @grafana/backend-platform + github.com/grafana/grafana-plugin-sdk-go v0.165.0 // @grafana/alerting-squad-backend + github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // @grafana/backend-platform + github.com/hashicorp/go-hclog v1.5.0 // @grafana/plugins-platform-backend + github.com/hashicorp/go-plugin v1.4.9 // @grafana/plugins-platform-backend + github.com/hashicorp/go-version v1.3.0 // @grafana/backend-platform + github.com/influxdata/influxdb-client-go/v2 v2.6.0 // @grafana/observability-metrics + github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 // @grafana/grafana-app-platform-squad + github.com/jmespath/go-jmespath v0.4.0 // @grafana/backend-platform + github.com/json-iterator/go v1.1.12 // @grafana/backend-platform + github.com/jung-kurt/gofpdf v1.16.2 // @grafana/backend-platform + github.com/lib/pq v1.10.6 // @grafana/backend-platform + github.com/linkedin/goavro/v2 v2.10.0 // @grafana/backend-platform + github.com/m3db/prometheus_remote_client_golang v0.4.4 // @grafana/backend-platform + github.com/magefile/mage v1.14.0 // @grafana/grafana-delivery + github.com/mattn/go-isatty v0.0.18 // @grafana/backend-platform + github.com/mattn/go-sqlite3 v1.14.16 // @grafana/backend-platform + github.com/matttproud/golang_protobuf_extensions v1.0.4 // @grafana/alerting-squad-backend + github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // @grafana/grafana-operator-experience-squad github.com/opentracing/opentracing-go v1.2.0 // indirect - github.com/patrickmn/go-cache v2.1.0+incompatible + github.com/patrickmn/go-cache v2.1.0+incompatible // @grafana/alerting-squad-backend github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/prometheus/alertmanager v0.25.0 - github.com/prometheus/client_golang v1.15.1 - github.com/prometheus/client_model v0.4.0 - github.com/prometheus/common v0.43.0 - github.com/prometheus/prometheus v1.8.2-0.20210621150501-ff58416a0b02 - github.com/robfig/cron/v3 v3.0.1 - github.com/russellhaering/goxmldsig v1.4.0 - github.com/stretchr/testify v1.8.4 - github.com/teris-io/shortid v0.0.0-20171029131806-771a37caa5cf - github.com/ua-parser/uap-go v0.0.0-20211112212520-00c877edfe0f + github.com/prometheus/alertmanager v0.25.0 // @grafana/alerting-squad-backend + github.com/prometheus/client_golang v1.15.1 // @grafana/alerting-squad-backend + github.com/prometheus/client_model v0.4.0 // @grafana/backend-platform + github.com/prometheus/common v0.43.0 // @grafana/alerting-squad-backend + github.com/prometheus/prometheus v1.8.2-0.20210621150501-ff58416a0b02 // @grafana/alerting-squad-backend + github.com/robfig/cron/v3 v3.0.1 // @grafana/backend-platform + github.com/russellhaering/goxmldsig v1.4.0 // @grafana/backend-platform + github.com/stretchr/testify v1.8.4 // @grafana/backend-platform + github.com/teris-io/shortid v0.0.0-20171029131806-771a37caa5cf // @grafana/backend-platform + github.com/ua-parser/uap-go v0.0.0-20211112212520-00c877edfe0f // @grafana/backend-platform github.com/uber/jaeger-client-go v2.29.1+incompatible // indirect - github.com/urfave/cli/v2 v2.25.0 - github.com/vectordotdev/go-datemath v0.1.1-0.20220323213446-f3954d0b18ae - github.com/yalue/merged_fs v1.2.2 - github.com/yudai/gojsondiff v1.0.0 - go.opentelemetry.io/collector v0.31.0 - go.opentelemetry.io/collector/model v0.31.0 - go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.37.0 - go.opentelemetry.io/otel v1.14.0 - go.opentelemetry.io/otel/exporters/jaeger v1.0.0 - go.opentelemetry.io/otel/sdk v1.14.0 - go.opentelemetry.io/otel/trace v1.14.0 - golang.org/x/crypto v0.11.0 - golang.org/x/exp v0.0.0-20230321023759-10a507213a29 - golang.org/x/net v0.10.0 - golang.org/x/oauth2 v0.7.0 - golang.org/x/sync v0.3.0 - golang.org/x/time v0.3.0 - golang.org/x/tools v0.7.0 - gonum.org/v1/gonum v0.11.0 - google.golang.org/api v0.111.0 - google.golang.org/grpc v1.55.0 - google.golang.org/protobuf v1.30.0 + github.com/urfave/cli/v2 v2.25.0 // @grafana/backend-platform + github.com/vectordotdev/go-datemath v0.1.1-0.20220323213446-f3954d0b18ae // @grafana/backend-platform + github.com/yalue/merged_fs v1.2.2 // @grafana/grafana-as-code + github.com/yudai/gojsondiff v1.0.0 // @grafana/backend-platform + go.opentelemetry.io/collector v0.31.0 // @grafana/backend-platform + go.opentelemetry.io/collector/model v0.31.0 // @grafana/backend-platform + go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.37.0 // @grafana/grafana-operator-experience-squad + go.opentelemetry.io/otel v1.14.0 // @grafana/alerting-squad-backend + go.opentelemetry.io/otel/exporters/jaeger v1.0.0 // @grafana/backend-platform + go.opentelemetry.io/otel/sdk v1.14.0 // @grafana/backend-platform + go.opentelemetry.io/otel/trace v1.14.0 // @grafana/backend-platform + golang.org/x/crypto v0.11.0 // @grafana/backend-platform + golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // @grafana/alerting-squad-backend + golang.org/x/net v0.10.0 // @grafana/grafana-bi-squad + golang.org/x/oauth2 v0.7.0 // @grafana/grafana-authnz-team + golang.org/x/sync v0.3.0 // @grafana/alerting-squad-backend + golang.org/x/time v0.3.0 // @grafana/backend-platform + golang.org/x/tools v0.7.0 // @grafana/grafana-as-code + gonum.org/v1/gonum v0.11.0 // @grafana/observability-metrics + google.golang.org/api v0.111.0 // @grafana/backend-platform + google.golang.org/grpc v1.55.0 // @grafana/plugins-platform-backend + google.golang.org/protobuf v1.30.0 // @grafana/plugins-platform-backend gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect - gopkg.in/ini.v1 v1.67.0 - gopkg.in/mail.v2 v2.3.1 + gopkg.in/ini.v1 v1.67.0 // @grafana/alerting-squad-backend + gopkg.in/mail.v2 v2.3.1 // @grafana/backend-platform gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.1 + gopkg.in/yaml.v3 v3.0.1 // @grafana/alerting-squad-backend xorm.io/builder v0.3.6 // indirect - xorm.io/core v0.7.3 - xorm.io/xorm v0.8.2 + xorm.io/core v0.7.3 // @grafana/backend-platform + xorm.io/xorm v0.8.2 // @grafana/alerting-squad-backend ) require ( @@ -137,7 +137,7 @@ require ( github.com/Azure/go-autorest/tracing v0.6.0 // indirect github.com/FZambia/eagle v0.0.2 // indirect github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect - github.com/andybalholm/brotli v1.0.4 + github.com/andybalholm/brotli v1.0.4 // @grafana/partner-datasources github.com/apache/arrow/go/arrow v0.0.0-20211112161151-bc219186db40 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/beorn7/perks v1.0.1 // indirect @@ -152,27 +152,27 @@ require ( github.com/docker/go-units v0.5.0 // indirect github.com/edsrzf/mmap-go v1.1.0 // indirect github.com/emicklei/proto v1.10.0 // indirect - github.com/go-kit/log v0.2.1 + github.com/go-kit/log v0.2.1 // @grafana/backend-platform github.com/go-logfmt/logfmt v0.6.0 // indirect github.com/go-openapi/analysis v0.21.4 // indirect github.com/go-openapi/errors v0.20.3 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect - github.com/go-openapi/loads v0.21.2 + github.com/go-openapi/loads v0.21.2 // @grafana/alerting-squad-backend github.com/go-openapi/runtime v0.25.0 // indirect github.com/go-openapi/spec v0.20.8 // indirect github.com/go-openapi/swag v0.22.3 // indirect github.com/go-openapi/validate v0.22.1 // indirect - github.com/golang-jwt/jwt/v4 v4.5.0 + github.com/golang-jwt/jwt/v4 v4.5.0 // @grafana/backend-platform github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe // indirect github.com/golang/glog v1.0.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/protobuf v1.5.3 + github.com/golang/protobuf v1.5.3 // @grafana/backend-platform github.com/google/btree v1.1.2 // indirect github.com/google/flatbuffers v2.0.8+incompatible // indirect - github.com/googleapis/gax-go/v2 v2.7.0 + github.com/googleapis/gax-go/v2 v2.7.0 // @grafana/backend-platform github.com/gorilla/mux v1.8.0 // indirect - github.com/grafana/grafana-google-sdk-go v0.1.0 + github.com/grafana/grafana-google-sdk-go v0.1.0 // @grafana/partner-datasources github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-msgpack v0.5.5 // indirect @@ -196,7 +196,7 @@ require ( github.com/mpvl/unique v0.0.0-20150818121801-cbe035fff7de // indirect github.com/oklog/run v1.1.0 // indirect github.com/oklog/ulid v1.3.1 // indirect - github.com/olekukonko/tablewriter v0.0.5 + github.com/olekukonko/tablewriter v0.0.5 // @grafana/backend-platform github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/common/sigv4 v0.1.0 // indirect github.com/prometheus/exporter-toolkit v0.9.1 // indirect @@ -215,63 +215,64 @@ require ( github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 // indirect go.mongodb.org/mongo-driver v1.11.3 // indirect go.opencensus.io v0.24.0 // indirect - go.uber.org/atomic v1.10.0 + go.uber.org/atomic v1.10.0 // @grafana/alerting-squad-backend go.uber.org/goleak v1.2.1 // indirect golang.org/x/sys v0.10.0 // indirect - golang.org/x/text v0.11.0 + golang.org/x/text v0.11.0 // @grafana/backend-platform golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 + google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // @grafana/backend-platform ) require ( - cloud.google.com/go/kms v1.4.0 - github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.0 - github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.9.0 - github.com/Azure/azure-storage-blob-go v0.15.0 - github.com/Azure/go-autorest/autorest/adal v0.9.22 - github.com/armon/go-radix v1.0.0 - github.com/blugelabs/bluge v0.1.9 - github.com/blugelabs/bluge_segment_api v0.2.0 - github.com/bufbuild/connect-go v1.4.1 - github.com/dlmiddlecote/sqlstats v1.0.2 - github.com/drone/drone-cli v1.6.1 - github.com/getkin/kin-openapi v0.115.0 - github.com/golang-migrate/migrate/v4 v4.7.0 - github.com/google/go-github/v45 v45.2.0 - github.com/grafana/codejen v0.0.3 - github.com/grafana/dskit v0.0.0-20230620150242-3dc2113b720d - github.com/grafana/phlare/api v0.1.4-0.20230426005640-f90edba05413 - github.com/huandu/xstrings v1.3.1 - github.com/jmoiron/sqlx v1.3.5 - github.com/matryer/is v1.4.0 - github.com/urfave/cli v1.22.12 - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.40.0 - go.opentelemetry.io/contrib/propagators/jaeger v1.15.0 - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.14.0 - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.14.0 - gocloud.dev v0.25.0 + cloud.google.com/go/kms v1.4.0 // @grafana/backend-platform + github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.0 // @grafana/backend-platform + github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.9.0 // @grafana/backend-platform + github.com/Azure/azure-storage-blob-go v0.15.0 // @grafana/backend-platform + github.com/Azure/go-autorest/autorest/adal v0.9.22 // @grafana/backend-platform + github.com/armon/go-radix v1.0.0 // @grafana/grafana-app-platform-squad + github.com/blugelabs/bluge v0.1.9 // @grafana/backend-platform + github.com/blugelabs/bluge_segment_api v0.2.0 // @grafana/backend-platform + github.com/bufbuild/connect-go v1.4.1 // @grafana/observability-traces-and-profiling + github.com/dlmiddlecote/sqlstats v1.0.2 // @grafana/backend-platform + github.com/drone/drone-cli v1.6.1 // @grafana/grafana-delivery + github.com/getkin/kin-openapi v0.115.0 // @grafana/grafana-operator-experience-squad + github.com/golang-migrate/migrate/v4 v4.7.0 // @grafana/backend-platform + github.com/google/go-github/v45 v45.2.0 // @grafana/grafana-delivery + github.com/grafana/codejen v0.0.3 // @grafana/dataviz-squad + github.com/grafana/dskit v0.0.0-20230620150242-3dc2113b720d // @grafana/backend-platform + github.com/grafana/phlare/api v0.1.4-0.20230426005640-f90edba05413 // @grafana/observability-traces-and-profiling + github.com/huandu/xstrings v1.3.1 // @grafana/partner-datasources + github.com/jmoiron/sqlx v1.3.5 // @grafana/backend-platform + github.com/matryer/is v1.4.0 // @grafana/grafana-as-code + github.com/urfave/cli v1.22.12 // @grafana/backend-platform + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.40.0 // @grafana/plugins-platform-backend + go.opentelemetry.io/contrib/propagators/jaeger v1.15.0 // @grafana/backend-platform + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.14.0 // @grafana/backend-platform + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.14.0 // @grafana/backend-platform + gocloud.dev v0.25.0 // @grafana/grafana-app-platform-squad ) require ( - buf.build/gen/go/parca-dev/parca/bufbuild/connect-go v1.4.1-20221222094228-8b1d3d0f62e6.1 - buf.build/gen/go/parca-dev/parca/protocolbuffers/go v1.28.1-20221222094228-8b1d3d0f62e6.4 - github.com/Masterminds/semver/v3 v3.1.1 - github.com/alicebob/miniredis/v2 v2.30.1 - github.com/dave/dst v0.27.2 - github.com/go-jose/go-jose/v3 v3.0.0 - github.com/grafana/dataplane/examples v0.0.1 - github.com/grafana/dataplane/sdata v0.0.6 - github.com/grafana/go-mssqldb v0.9.1 - github.com/grafana/kindsys v0.0.0-20230508162304-452481b63482 - github.com/grafana/thema v0.0.0-20230712153715-375c1b45f3ed - github.com/ory/fosite v0.44.1-0.20230317114349-45a6785cc54f - github.com/redis/go-redis/v9 v9.0.2 - github.com/weaveworks/common v0.0.0-20230511094633-334485600903 - github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f - go.opentelemetry.io/contrib/samplers/jaegerremote v0.9.0 - gopkg.in/square/go-jose.v2 v2.5.2-0.20210529014059-a5c7eec3c614 - k8s.io/utils v0.0.0-20230308161112-d77c459e9343 + buf.build/gen/go/parca-dev/parca/bufbuild/connect-go v1.4.1-20221222094228-8b1d3d0f62e6.1 // @grafana/observability-traces-and-profiling + buf.build/gen/go/parca-dev/parca/protocolbuffers/go v1.28.1-20221222094228-8b1d3d0f62e6.4 // @grafana/observability-traces-and-profiling + github.com/Masterminds/semver/v3 v3.1.1 // @grafana/grafana-delivery + github.com/alicebob/miniredis/v2 v2.30.1 // @grafana/alerting-squad-backend + github.com/dave/dst v0.27.2 // @grafana/grafana-as-code + github.com/go-jose/go-jose/v3 v3.0.0 // @grafana/backend-platform + github.com/grafana/dataplane/examples v0.0.1 // @grafana/observability-metrics + github.com/grafana/dataplane/sdata v0.0.6 // @grafana/observability-metrics + github.com/grafana/go-mssqldb v0.9.1 // @grafana/grafana-bi-squad + github.com/grafana/kindsys v0.0.0-20230508162304-452481b63482 // @grafana/grafana-as-code + github.com/grafana/thema v0.0.0-20230712153715-375c1b45f3ed // @grafana/grafana-as-code + github.com/ory/fosite v0.44.1-0.20230317114349-45a6785cc54f // @grafana/grafana-authnz-team + github.com/redis/go-redis/v9 v9.0.2 // @grafana/alerting-squad-backend + github.com/weaveworks/common v0.0.0-20230511094633-334485600903 // @grafana/alerting-squad-backend + github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // @grafana/grafana-as-code + go.opentelemetry.io/contrib/samplers/jaegerremote v0.9.0 // @grafana/backend-platform + golang.org/x/mod v0.9.0 // @grafana/backend-platform + gopkg.in/square/go-jose.v2 v2.5.2-0.20210529014059-a5c7eec3c614 // @grafana/grafana-authnz-team + k8s.io/utils v0.0.0-20230308161112-d77c459e9343 // @grafana/partner-datasources ) require ( @@ -368,13 +369,13 @@ require ( require ( cloud.google.com/go/compute v1.18.0 // indirect cloud.google.com/go/iam v0.8.0 // indirect - filippo.io/age v1.1.1 + filippo.io/age v1.1.1 // @grafana/grafana-authnz-team github.com/Azure/azure-sdk-for-go/sdk/azcore v1.2.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.0 // indirect github.com/AzureAD/microsoft-authentication-library-for-go v0.7.0 // indirect - github.com/Masterminds/sprig/v3 v3.2.2 + github.com/Masterminds/sprig/v3 v3.2.2 // @grafana/backend-platform github.com/Microsoft/go-winio v0.6.0 // indirect - github.com/ProtonMail/go-crypto v0.0.0-20230426101702-58e86b294756 + github.com/ProtonMail/go-crypto v0.0.0-20230426101702-58e86b294756 // @grafana/plugins-platform-backend github.com/RoaringBitmap/roaring v0.9.4 // indirect github.com/acomagu/bufpipe v1.0.3 // indirect github.com/axiomhq/hyperloglog v0.0.0-20191112132149-a4c4c47bc57f // indirect @@ -388,7 +389,7 @@ require ( github.com/caio/go-tdigest v3.1.0+incompatible // indirect github.com/chromedp/cdproto v0.0.0-20220208224320-6efb837e6bc2 // indirect github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 // indirect - github.com/docker/docker v23.0.4+incompatible + github.com/docker/docker v23.0.4+incompatible // @grafana/grafana-delivery github.com/elazarl/goproxy v0.0.0-20220115173737-adb46da277ac // indirect github.com/emirpasic/gods v1.12.0 // indirect github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 // indirect @@ -396,9 +397,9 @@ require ( github.com/go-git/go-billy/v5 v5.3.1 // indirect github.com/go-logr/logr v1.2.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/google/go-github v17.0.0+incompatible + github.com/google/go-github v17.0.0+incompatible // @grafana/grafana-app-platform-squad github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.2 // indirect - github.com/hmarr/codeowners v1.1.2 + github.com/hmarr/codeowners v1.1.2 // @grafana/grafana-as-code github.com/imdario/mergo v0.3.13 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect @@ -411,12 +412,11 @@ require ( github.com/mschoch/smat v0.2.0 // indirect github.com/pierrec/lz4/v4 v4.1.15 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect - github.com/wk8/go-ordered-map v1.0.0 + github.com/wk8/go-ordered-map v1.0.0 // @grafana/backend-platform github.com/xanzy/ssh-agent v0.3.0 // indirect - github.com/xlab/treeprint v1.1.0 + github.com/xlab/treeprint v1.1.0 // @grafana/observability-traces-and-profiling go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.14.0 // indirect go.opentelemetry.io/proto/otlp v0.19.0 // indirect - golang.org/x/mod v0.9.0 gopkg.in/warnings.v0 v0.1.2 // indirect ) From 9b143a504318025ff9d266aac2e180db914b2a2d Mon Sep 17 00:00:00 2001 From: Ludovic Viaud Date: Thu, 13 Jul 2023 19:58:22 +0200 Subject: [PATCH 19/42] Fix e2e (#71594) --- e2e/panels-suite/panelEdit_transforms.spec.ts | 7 +- .../TransformationsEditor.tsx | 205 +++++++++--------- 2 files changed, 105 insertions(+), 107 deletions(-) diff --git a/e2e/panels-suite/panelEdit_transforms.spec.ts b/e2e/panels-suite/panelEdit_transforms.spec.ts index 6e45dd6522a..6f12a438c73 100644 --- a/e2e/panels-suite/panelEdit_transforms.spec.ts +++ b/e2e/panels-suite/panelEdit_transforms.spec.ts @@ -10,10 +10,7 @@ e2e.scenario({ e2e.flows.openDashboard({ uid: '5SdHCadmz', queryParams: { editPanel: 3 } }); e2e.components.Tab.title('Transform').should('be.visible').click(); - - // Flacky tests. Error: cy.click() failed because this element is detached from the DOM. - // The element is visible and clickable manually. - // e2e.components.TransformTab.newTransform('Reduce').scrollIntoView().should('be.visible').click(); - // e2e.components.Transforms.Reduce.calculationsLabel().should('be.visible'); + e2e.components.TransformTab.newTransform('Reduce').scrollIntoView().should('be.visible').click(); + e2e.components.Transforms.Reduce.calculationsLabel().should('be.visible'); }, }); diff --git a/public/app/features/dashboard/components/TransformationsEditor/TransformationsEditor.tsx b/public/app/features/dashboard/components/TransformationsEditor/TransformationsEditor.tsx index f3b7f49da1a..1a4506245ad 100644 --- a/public/app/features/dashboard/components/TransformationsEditor/TransformationsEditor.tsx +++ b/public/app/features/dashboard/components/TransformationsEditor/TransformationsEditor.tsx @@ -346,107 +346,6 @@ class UnThemedTransformationsEditor extends React.PureComponent ( - <> - {config.featureToggles.transformationsRedesign && ( - <> - {!noTransforms && ( - - )} -
- - Transformations{' '} - - -  allow you to manipulate your data before a visualization is applied. -
- - )} - - {!config.featureToggles.transformationsRedesign && ( - - )} - - {!config.featureToggles.transformationsRedesign && - xforms.map((t) => { - return ( - { - this.onTransformationAdd({ value: t.id }); - }} - /> - ); - })} - - {config.featureToggles.transformationsRedesign && ( -
- -
- Show images{' '} - this.setState({ showIllustrations: !this.state.showIllustrations })} - /> -
-
- )} - - {config.featureToggles.transformationsRedesign && ( -
- {filterCategoriesLabels.map(([slug, label]) => { - return ( - this.setState({ selectedFilter: slug })} - label={label} - selected={this.state.selectedFilter === slug} - /> - ); - })} -
- )} - - {config.featureToggles.transformationsRedesign && ( - { - this.onTransformationAdd({ value: id }); - }} - /> - )} -
- - ); - return ( <> {noTransforms && ( @@ -487,7 +386,109 @@ class UnThemedTransformationsEditor extends React.PureComponent )} {showPicker ? ( - + <> + {config.featureToggles.transformationsRedesign && ( + <> + {!noTransforms && ( + + )} +
+ + Transformations{' '} + + +  allow you to manipulate your data before a visualization is applied. +
+ + )} + + {!config.featureToggles.transformationsRedesign && ( + + )} + + {!config.featureToggles.transformationsRedesign && + xforms.map((t) => { + return ( + { + this.onTransformationAdd({ value: t.id }); + }} + /> + ); + })} + + {config.featureToggles.transformationsRedesign && ( +
+ +
+ Show images{' '} + this.setState({ showIllustrations: !this.state.showIllustrations })} + /> +
+
+ )} + + {config.featureToggles.transformationsRedesign && ( +
+ {filterCategoriesLabels.map(([slug, label]) => { + return ( + this.setState({ selectedFilter: slug })} + label={label} + selected={this.state.selectedFilter === slug} + /> + ); + })} +
+ )} + + {config.featureToggles.transformationsRedesign && ( + { + this.onTransformationAdd({ value: id }); + }} + /> + )} +
+ ) : (
diff --git a/public/app/features/explore/TraceView/components/TracePageHeader/SearchBar/NextPrevResult.test.tsx b/public/app/features/explore/TraceView/components/TracePageHeader/SearchBar/NextPrevResult.test.tsx index 149dbcb0616..fa042b933ab 100644 --- a/public/app/features/explore/TraceView/components/TracePageHeader/SearchBar/NextPrevResult.test.tsx +++ b/public/app/features/explore/TraceView/components/TracePageHeader/SearchBar/NextPrevResult.test.tsx @@ -19,6 +19,7 @@ import React, { useState } from 'react'; import { createTheme } from '@grafana/data'; import { defaultFilters } from '../../../useSearch'; +import { trace } from '../TracePageHeader.test'; import NextPrevResult, { getStyles } from './NextPrevResult'; @@ -37,6 +38,7 @@ describe('', () => { const NextPrevResultWithProps = (props: { matches: string[] | undefined }) => { const [focusedSpanIndexForSearch, setFocusedSpanIndexForSearch] = useState(-1); const searchBarProps = { + trace: trace, search: defaultFilters, spanFilterMatches: props.matches ? new Set(props.matches) : undefined, showSpanFilterMatchesOnly: false, @@ -46,7 +48,6 @@ describe('', () => { setFocusedSpanIndexForSearch: setFocusedSpanIndexForSearch, datasourceType: '', clear: jest.fn(), - totalSpans: 100, showSpanFilters: true, }; @@ -70,11 +71,11 @@ describe('', () => { it('renders total spans', async () => { render(); - expect(screen.getByText('100 spans')).toBeDefined(); + expect(screen.getByText('3 spans')).toBeDefined(); }); it('renders buttons that can be used to search if filters added', () => { - render(); + render(); const nextResButton = screen.queryByRole('button', { name: 'Next result button' }); const prevResButton = screen.queryByRole('button', { name: 'Prev result button' }); expect(nextResButton).toBeInTheDocument(); @@ -85,7 +86,7 @@ describe('', () => { }); it('renders correctly when moving through matches', async () => { - render(); + render(); const nextResButton = screen.queryByRole('button', { name: 'Next result button' }); const prevResButton = screen.queryByRole('button', { name: 'Prev result button' }); expect(screen.getByText('3 matches')).toBeDefined(); @@ -106,7 +107,7 @@ describe('', () => { it('renders correctly when there are no matches i.e. too many filters added', async () => { const { container } = render(); const theme = createTheme(); - const tooltip = container.querySelector('.' + getStyles(theme, true).matchesTooltip); + const tooltip = container.querySelector('.' + getStyles(theme, true).tooltip); expect(screen.getByText('0 matches')).toBeDefined(); userEvent.hover(tooltip!); jest.advanceTimersByTime(1000); @@ -114,4 +115,16 @@ describe('', () => { expect(screen.getByText(/0 span matches for the filters selected/)).toBeDefined(); }); }); + + it('renders services, depth correctly', async () => { + const { container } = render(); + const theme = createTheme(); + const tooltip = container.querySelector('.' + getStyles(theme, true).tooltip); + userEvent.hover(tooltip!); + jest.advanceTimersByTime(1000); + await waitFor(() => { + expect(screen.getByText(/Services: 2\/3/)).toBeDefined(); + expect(screen.getByText(/Depth: 1\/1/)).toBeDefined(); + }); + }); }); diff --git a/public/app/features/explore/TraceView/components/TracePageHeader/SearchBar/NextPrevResult.tsx b/public/app/features/explore/TraceView/components/TracePageHeader/SearchBar/NextPrevResult.tsx index 79230e4a76c..98c725b3918 100644 --- a/public/app/features/explore/TraceView/components/TracePageHeader/SearchBar/NextPrevResult.tsx +++ b/public/app/features/explore/TraceView/components/TracePageHeader/SearchBar/NextPrevResult.tsx @@ -13,31 +13,34 @@ // limitations under the License. import { css, cx } from '@emotion/css'; -import React, { memo, Dispatch, SetStateAction, useEffect } from 'react'; +import { get, maxBy, values } from 'lodash'; +import React, { memo, Dispatch, SetStateAction, useEffect, useCallback } from 'react'; import { GrafanaTheme2 } from '@grafana/data'; import { config, reportInteraction } from '@grafana/runtime'; -import { Icon, Tooltip, useTheme2 } from '@grafana/ui'; +import { Icon, PopoverContent, Tooltip, useTheme2 } from '@grafana/ui'; import { getButtonStyles } from '@grafana/ui/src/components/Button'; +import { Trace } from '../../types'; + export type NextPrevResultProps = { + trace: Trace; spanFilterMatches: Set | undefined; setFocusedSpanIdForSearch: Dispatch>; focusedSpanIndexForSearch: number; setFocusedSpanIndexForSearch: Dispatch>; datasourceType: string; - totalSpans: number; showSpanFilters: boolean; }; export default memo(function NextPrevResult(props: NextPrevResultProps) { const { + trace, spanFilterMatches, setFocusedSpanIdForSearch, focusedSpanIndexForSearch, setFocusedSpanIndexForSearch, datasourceType, - totalSpans, showSpanFilters, } = props; const styles = getStyles(useTheme2(), showSpanFilters); @@ -109,30 +112,88 @@ export default memo(function NextPrevResult(props: NextPrevResultProps) { }; const buttonEnabled = (spanFilterMatches && spanFilterMatches?.size > 0) ?? false; - const amountText = spanFilterMatches?.size === 1 ? 'match' : 'matches'; - const matches = - spanFilterMatches?.size === 0 ? ( - <> - 0 matches - - - + const buttonClass = buttonEnabled ? styles.button : cx(styles.button, styles.buttonDisabled); + + const getTooltip = useCallback( + (content: PopoverContent) => { + return ( + + + - - ) : focusedSpanIndexForSearch !== -1 ? ( - `${focusedSpanIndexForSearch + 1}/${spanFilterMatches?.size} ${amountText}` - ) : ( - `${spanFilterMatches?.size} ${amountText}` - ); - const buttonClass = buttonEnabled ? styles.button : cx(styles.button, styles.buttonDisabled); + ); + }, + [styles.tooltip] + ); + + const getMatchesMetadata = useCallback( + (depth: number, services: number) => { + const matchedServices: string[] = []; + const matchedDepth: number[] = []; + let metadata = ( + <> + {`${trace.spans.length} spans`} + {getTooltip( + <> +
Services: {services}
+
Depth: {depth}
+ + )} + + ); + + if (spanFilterMatches) { + spanFilterMatches.forEach((spanID) => { + matchedServices.push(trace.processes[spanID].serviceName); + matchedDepth.push(trace.spans.find((span) => span.spanID === spanID)?.depth || 0); + }); + + if (spanFilterMatches.size === 0) { + metadata = ( + <> + 0 matches + {getTooltip( + 'There are 0 span matches for the filters selected. Please try removing some of the selected filters.' + )} + + ); + } else { + const type = spanFilterMatches.size === 1 ? 'match' : 'matches'; + const text = + focusedSpanIndexForSearch !== -1 + ? `${focusedSpanIndexForSearch + 1}/${spanFilterMatches.size} ${type}` + : `${spanFilterMatches.size} ${type}`; + + metadata = ( + <> + {text} + {getTooltip( + <> +
+ Services: {new Set(matchedServices).size}/{services} +
+
+ Depth: {new Set(matchedDepth).size}/{depth} +
+ + )} + + ); + } + } + + return metadata; + }, + [focusedSpanIndexForSearch, getTooltip, spanFilterMatches, trace.processes, trace.spans] + ); + + const services = new Set(values(trace.processes).map((p) => p.serviceName)).size; + const depth = get(maxBy(trace.spans, 'depth'), 'depth', 0) + 1; return ( <> - {spanFilterMatches ? matches : `${totalSpans} spans`} + {getMatchesMetadata(depth, services)}
{ matches: css` margin-right: ${theme.spacing(2)}; `, - matchesTooltip: css` + tooltip: css` color: #aaa; - margin: -2px 0 0 10px; + margin: 0 0 0 5px; `, }; }; diff --git a/public/app/features/explore/TraceView/components/TracePageHeader/SpanFilters/SpanFilters.tsx b/public/app/features/explore/TraceView/components/TracePageHeader/SpanFilters/SpanFilters.tsx index 23681adbd37..add4cd20652 100644 --- a/public/app/features/explore/TraceView/components/TracePageHeader/SpanFilters/SpanFilters.tsx +++ b/public/app/features/explore/TraceView/components/TracePageHeader/SpanFilters/SpanFilters.tsx @@ -277,12 +277,12 @@ export const SpanFilters = memo((props: SpanFilterProps) => { {!showSpanFilters && (
@@ -448,7 +448,7 @@ export const SpanFilters = memo((props: SpanFilterProps) => { Date: Fri, 14 Jul 2023 12:11:26 +0300 Subject: [PATCH 27/42] Update react monorepo (#71552) * Update react monorepo * dedupe packages + fix type errors --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Ashley Harrison --- package.json | 4 +- packages/grafana-data/package.json | 4 +- packages/grafana-runtime/package.json | 4 +- packages/grafana-ui/package.json | 4 +- .../src/components/Dropdown/ButtonSelect.tsx | 2 +- .../src/components/Tooltip/Popover.tsx | 2 +- yarn.lock | 57 ++++++++----------- 7 files changed, 34 insertions(+), 43 deletions(-) diff --git a/package.json b/package.json index 6f816430f8c..5ea07eaf306 100644 --- a/package.json +++ b/package.json @@ -146,9 +146,9 @@ "@types/papaparse": "5.3.7", "@types/pluralize": "^0.0.29", "@types/prismjs": "1.26.0", - "@types/react": "18.0.28", + "@types/react": "18.2.15", "@types/react-beautiful-dnd": "13.1.3", - "@types/react-dom": "18.0.11", + "@types/react-dom": "18.2.7", "@types/react-grid-layout": "1.3.2", "@types/react-highlight-words": "0.16.4", "@types/react-redux": "7.1.25", diff --git a/packages/grafana-data/package.json b/packages/grafana-data/package.json index e102c1bc4fe..f9afc4726d3 100644 --- a/packages/grafana-data/package.json +++ b/packages/grafana-data/package.json @@ -77,8 +77,8 @@ "@types/marked": "4.0.8", "@types/node": "18.16.16", "@types/papaparse": "5.3.7", - "@types/react": "18.0.28", - "@types/react-dom": "18.0.11", + "@types/react": "18.2.15", + "@types/react-dom": "18.2.7", "@types/sinon": "10.0.13", "@types/testing-library__jest-dom": "5.14.5", "@types/tinycolor2": "1.4.3", diff --git a/packages/grafana-runtime/package.json b/packages/grafana-runtime/package.json index 262253256a6..4dce798898f 100644 --- a/packages/grafana-runtime/package.json +++ b/packages/grafana-runtime/package.json @@ -58,8 +58,8 @@ "@types/history": "4.7.11", "@types/jest": "29.2.3", "@types/lodash": "4.14.191", - "@types/react": "18.0.28", - "@types/react-dom": "18.0.11", + "@types/react": "18.2.15", + "@types/react-dom": "18.2.7", "@types/systemjs": "^0.20.6", "esbuild": "0.18.6", "lodash": "4.17.21", diff --git a/packages/grafana-ui/package.json b/packages/grafana-ui/package.json index daeac7c5d03..22894f04a94 100644 --- a/packages/grafana-ui/package.json +++ b/packages/grafana-ui/package.json @@ -147,11 +147,11 @@ "@types/mock-raf": "1.0.3", "@types/node": "18.16.16", "@types/prismjs": "1.26.0", - "@types/react": "18.0.28", + "@types/react": "18.2.15", "@types/react-beautiful-dnd": "13.1.3", "@types/react-calendar": "3.9.0", "@types/react-color": "3.0.6", - "@types/react-dom": "18.0.11", + "@types/react-dom": "18.2.7", "@types/react-highlight-words": "0.16.4", "@types/react-router-dom": "5.3.3", "@types/react-table": "7.7.14", diff --git a/packages/grafana-ui/src/components/Dropdown/ButtonSelect.tsx b/packages/grafana-ui/src/components/Dropdown/ButtonSelect.tsx index 131b00e920e..1cbd25e54ec 100644 --- a/packages/grafana-ui/src/components/Dropdown/ButtonSelect.tsx +++ b/packages/grafana-ui/src/components/Dropdown/ButtonSelect.tsx @@ -64,7 +64,7 @@ const ButtonSelectComponent = (props: Props) => { tabIndex=-1 is needed here to support highlighting text within the menu when using FocusScope see https://github.com/adobe/react-spectrum/issues/1604#issuecomment-781574668 */} - + {options.map((item) => ( JSX.Element; -interface Props extends React.HTMLAttributes { +interface Props extends Omit, 'content'> { show: boolean; placement?: Placement; content: PopoverContent; diff --git a/yarn.lock b/yarn.lock index 25b8ecf41b5..a1d197b7b2b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3739,8 +3739,8 @@ __metadata: "@types/marked": 4.0.8 "@types/node": 18.16.16 "@types/papaparse": 5.3.7 - "@types/react": 18.0.28 - "@types/react-dom": 18.0.11 + "@types/react": 18.2.15 + "@types/react-dom": 18.2.7 "@types/sinon": 10.0.13 "@types/string-hash": 1.1.1 "@types/testing-library__jest-dom": 5.14.5 @@ -4012,8 +4012,8 @@ __metadata: "@types/history": 4.7.11 "@types/jest": 29.2.3 "@types/lodash": 4.14.191 - "@types/react": 18.0.28 - "@types/react-dom": 18.0.11 + "@types/react": 18.2.15 + "@types/react-dom": 18.2.7 "@types/systemjs": ^0.20.6 esbuild: 0.18.6 history: 4.10.1 @@ -4154,11 +4154,11 @@ __metadata: "@types/mock-raf": 1.0.3 "@types/node": 18.16.16 "@types/prismjs": 1.26.0 - "@types/react": 18.0.28 + "@types/react": 18.2.15 "@types/react-beautiful-dnd": 13.1.3 "@types/react-calendar": 3.9.0 "@types/react-color": 3.0.6 - "@types/react-dom": 18.0.11 + "@types/react-dom": 18.2.7 "@types/react-highlight-words": 0.16.4 "@types/react-router-dom": 5.3.3 "@types/react-table": 7.7.14 @@ -10415,21 +10415,12 @@ __metadata: languageName: node linkType: hard -"@types/react-dom@npm:*": - version: 17.0.10 - resolution: "@types/react-dom@npm:17.0.10" +"@types/react-dom@npm:*, @types/react-dom@npm:18.2.7, @types/react-dom@npm:^18.0.0": + version: 18.2.7 + resolution: "@types/react-dom@npm:18.2.7" dependencies: "@types/react": "*" - checksum: cc7d8d5b77ee2f3b989c107abd8ec0f2460ba1b1ee6e6d637124e1939594b5619fa4166ef0ea7632a69b68358e0b71aa618de446ccc416dcc0017175549da601 - languageName: node - linkType: hard - -"@types/react-dom@npm:18.0.11, @types/react-dom@npm:^18.0.0": - version: 18.0.11 - resolution: "@types/react-dom@npm:18.0.11" - dependencies: - "@types/react": "*" - checksum: 579691e4d5ec09688087568037c35edf8cfb1ab3e07f6c60029280733ee7b5c06d66df6fcc90786702c93ac8cb13bc7ff16c79ddfc75d082938fbaa36e1cdbf4 + checksum: e02ea908289a7ad26053308248d2b87f6aeafd73d0e2de2a3d435947bcea0422599016ffd1c3e38ff36c42f5e1c87c7417f05b0a157e48649e4a02f21727d54f languageName: node linkType: hard @@ -10569,7 +10560,18 @@ __metadata: languageName: node linkType: hard -"@types/react@npm:*, @types/react@npm:18.0.28": +"@types/react@npm:*, @types/react@npm:18.2.15, @types/react@npm:>=16": + version: 18.2.15 + resolution: "@types/react@npm:18.2.15" + dependencies: + "@types/prop-types": "*" + "@types/scheduler": "*" + csstype: ^3.0.2 + checksum: 36989f638201bfe2f4110b06c119180f6df9c0e13d7060481e82e7a745f81745a01ae543c478a25b61e0767cb52e82da2ad5b0dedacabf99339e523d06176705 + languageName: node + linkType: hard + +"@types/react@npm:18.0.28": version: 18.0.28 resolution: "@types/react@npm:18.0.28" dependencies: @@ -10580,17 +10582,6 @@ __metadata: languageName: node linkType: hard -"@types/react@npm:>=16": - version: 18.0.33 - resolution: "@types/react@npm:18.0.33" - dependencies: - "@types/prop-types": "*" - "@types/scheduler": "*" - csstype: ^3.0.2 - checksum: 4fbd2b2b6a26378bdfde121081a6406ec2d39e4ba87ea5f6897ab7bb2198713165e6fd703ad4ed7ba1d4f23ef54a4c9f108f3105c7ed8e136411ee6bdebc5669 - languageName: node - linkType: hard - "@types/reactcss@npm:*": version: 1.2.6 resolution: "@types/reactcss@npm:1.2.6" @@ -19306,9 +19297,9 @@ __metadata: "@types/papaparse": 5.3.7 "@types/pluralize": ^0.0.29 "@types/prismjs": 1.26.0 - "@types/react": 18.0.28 + "@types/react": 18.2.15 "@types/react-beautiful-dnd": 13.1.3 - "@types/react-dom": 18.0.11 + "@types/react-dom": 18.2.7 "@types/react-grid-layout": 1.3.2 "@types/react-highlight-words": 0.16.4 "@types/react-redux": 7.1.25 From 1cacc78eda589099b389439c5885dd0d0bb01ccf Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 14 Jul 2023 10:26:58 +0100 Subject: [PATCH 28/42] Update dependency lru-cache to v10 (#71585) * Update dependency lru-cache to v10 * use named import * remove outdated type definitions and actually use named import --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Ashley Harrison --- package.json | 2 +- .../datasource/loki/LanguageProvider.ts | 6 +- .../datasource/prometheus/datasource.tsx | 4 +- .../prometheus/language_provider.ts | 6 +- public/app/types/lru-cache.d.ts | 259 ------------------ yarn.lock | 17 +- 6 files changed, 14 insertions(+), 280 deletions(-) delete mode 100644 public/app/types/lru-cache.d.ts diff --git a/package.json b/package.json index 5ea07eaf306..117d62cd744 100644 --- a/package.json +++ b/package.json @@ -347,7 +347,7 @@ "kbar": "0.1.0-beta.40", "lodash": "4.17.21", "logfmt": "^1.3.2", - "lru-cache": "7.17.0", + "lru-cache": "10.0.0", "lru-memoize": "^1.1.0", "marked": "^4.3.0", "memoize-one": "6.0.0", diff --git a/public/app/plugins/datasource/loki/LanguageProvider.ts b/public/app/plugins/datasource/loki/LanguageProvider.ts index 0021395d1f3..b10f21cb54f 100644 --- a/public/app/plugins/datasource/loki/LanguageProvider.ts +++ b/public/app/plugins/datasource/loki/LanguageProvider.ts @@ -1,5 +1,5 @@ import { chain, difference } from 'lodash'; -import LRU from 'lru-cache'; +import { LRUCache } from 'lru-cache'; import Prism, { Grammar } from 'prismjs'; import { dateTime, AbsoluteTimeRange, LanguageProvider, HistoryItem, AbstractQuery } from '@grafana/data'; @@ -79,8 +79,8 @@ export default class LokiLanguageProvider extends LanguageProvider { * not account for different size of a response. If that is needed a `length` function can be added in the options. * 10 as a max size is totally arbitrary right now. */ - private seriesCache = new LRU>({ max: 10 }); - private labelsCache = new LRU({ max: 10 }); + private seriesCache = new LRUCache>({ max: 10 }); + private labelsCache = new LRUCache({ max: 10 }); constructor(datasource: LokiDatasource, initialValues?: any) { super(); diff --git a/public/app/plugins/datasource/prometheus/datasource.tsx b/public/app/plugins/datasource/prometheus/datasource.tsx index 8f522f2fba6..ebd6f2deb4a 100644 --- a/public/app/plugins/datasource/prometheus/datasource.tsx +++ b/public/app/plugins/datasource/prometheus/datasource.tsx @@ -1,5 +1,5 @@ import { cloneDeep, defaults } from 'lodash'; -import LRU from 'lru-cache'; +import { LRUCache } from 'lru-cache'; import React from 'react'; import { forkJoin, lastValueFrom, merge, Observable, of, OperatorFunction, pipe, throwError } from 'rxjs'; import { catchError, filter, map, tap } from 'rxjs/operators'; @@ -92,7 +92,7 @@ export class PrometheusDatasource access: 'direct' | 'proxy'; basicAuth: any; withCredentials: any; - metricsNameCache = new LRU({ max: 10 }); + metricsNameCache = new LRUCache({ max: 10 }); interval: string; queryTimeout: string | undefined; httpMethod: string; diff --git a/public/app/plugins/datasource/prometheus/language_provider.ts b/public/app/plugins/datasource/prometheus/language_provider.ts index b104c0a1df6..6067cfba8d7 100644 --- a/public/app/plugins/datasource/prometheus/language_provider.ts +++ b/public/app/plugins/datasource/prometheus/language_provider.ts @@ -1,5 +1,5 @@ import { chain, difference, once } from 'lodash'; -import LRU from 'lru-cache'; +import { LRUCache } from 'lru-cache'; import Prism from 'prismjs'; import { Value } from 'slate'; @@ -121,8 +121,8 @@ export default class PromQlLanguageProvider extends LanguageProvider { * not account for different size of a response. If that is needed a `length` function can be added in the options. * 10 as a max size is totally arbitrary right now. */ - private labelsCache = new LRU>({ max: 10 }); - private labelValuesCache = new LRU({ max: 10 }); + private labelsCache = new LRUCache>({ max: 10 }); + private labelValuesCache = new LRUCache({ max: 10 }); constructor(datasource: PrometheusDatasource, initialValues?: Partial) { super(); diff --git a/public/app/types/lru-cache.d.ts b/public/app/types/lru-cache.d.ts deleted file mode 100644 index f515ec58fe6..00000000000 --- a/public/app/types/lru-cache.d.ts +++ /dev/null @@ -1,259 +0,0 @@ -// Type definitions for lru-cache 7.1.0 -// TypeScript Version: 4.5 -declare class LRUCache { - constructor(options?: LRUCache.Options); - - /** - * Return total length of objects in cache taking into account `length` options function. - */ - readonly length: number; - - /** - * Return total quantity of objects currently in cache. Note, - * that `stale` (see options) items are returned as part of this item count. - */ - readonly itemCount: number; - - /** - * Same as Options.allowStale. - */ - allowStale: boolean; - - /** - * Same as Options.length. - */ - lengthCalculator(value: V): number; - - /** - * Same as Options.max. Resizes the cache when the `max` changes. - */ - max: number; - - /** - * Same as Options.maxAge. Resizes the cache when the `maxAge` changes. - */ - maxAge: number; - - /** - * Will update the "recently used"-ness of the key. They do what you think. - * `maxAge` is optional and overrides the cache `maxAge` option if provided. - */ - set(key: K, value: V, options?: LRUCache.SetOptions): boolean; - - /** - * Will update the "recently used"-ness of the key. They do what you think. - * `maxAge` is optional and overrides the cache `maxAge` option if provided. - * - * If the key is not found, will return `undefined`. - */ - get(key: K): V | undefined; - - /** - * Returns the key value (or `undefined` if not found) without updating - * the "recently used"-ness of the key. - * - * (If you find yourself using this a lot, you might be using the wrong - * sort of data structure, but there are some use cases where it's handy.) - */ - peek(key: K): V | undefined; - - /** - * Check if a key is in the cache, without updating the recent-ness - * or deleting it for being stale. - */ - has(key: K): boolean; - - /** - * Deletes a key out of the cache. - */ - del(key: K): void; - - /** - * Clear the cache entirely, throwing away all values. - */ - reset(): void; - - /** - * Manually iterates over the entire cache proactively pruning old entries. - */ - prune(): void; - - /** - * Just like `Array.prototype.forEach`. Iterates over all the keys in the cache, - * in order of recent-ness. (Ie, more recently used items are iterated over first.) - */ - forEach(callbackFn: (this: T, value: V, key: K, cache: this) => void, thisArg?: T): void; - - /** - * The same as `cache.forEach(...)` but items are iterated over in reverse order. - * (ie, less recently used items are iterated over first.) - */ - forEach(callbackFn: (this: T, value: V, key: K, cache: this) => void, thisArg?: T): void; - - /** - * Return an array of the keys in the cache. - */ - keys(): K[]; - - /** - * Return an array of the values in the cache. - */ - values(): V[]; - - /** - * Return an array of the cache entries ready for serialization and usage with `destinationCache.load(arr)`. - */ - dump(): Array>; - - /** - * Loads another cache entries array, obtained with `sourceCache.dump()`, - * into the cache. The destination cache is reset before loading new entries - * - * @param cacheEntries Obtained from `sourceCache.dump()` - */ - load(cacheEntries: ReadonlyArray>): void; -} - -// eslint-disable-next-line no-redeclare -declare namespace LRUCache { - interface Options { - /** - * @type {number | undefined} - * the number of most recently used items to keep. - * note that we may store fewer items than this if maxSize is hit. - */ - max?: number | undefined; - - // if you wish to track item size, you must provide a maxSize - // note that we still will only keep up to max *actual items*, - // so size tracking may cause fewer than max items to be stored. - // At the extreme, a single item of maxSize size will cause everything - // else in the cache to be dropped when it is added. Use with caution! - // Note also that size tracking can negatively impact performance, - // though for most cases, only minimally. - maxSize?: number | undefined; - - // buffers or other items where memory size depends on the object itself. - // also note that oversized items do NOT immediately get dropped from - // the cache, though they will cause faster turnover in the storage. - // Return an positive integer which is the size of the item, - // if a positive integer is not returned, will use 0 as the size. - sizeCalculation?: (value, key) => number; - - // function to call when the item is removed from the cache - // Note that using this can negatively impact performance. - dispose?: (value, key) => void; - - /** - * By default, if you set a `dispose()` method, then it'll be called whenever - * a `set()` operation overwrites an existing key. If you set this option, - * `dispose()` will only be called when a key falls out of the cache, - * not when it is overwritten. - */ - noDisposeOnSet?: boolean | undefined; - - // max time to live for items before they are considered stale - // note that stale items are NOT preemptively removed by default, - // and MAY live in the cache, contributing to its LRU max, long after - // they have expired. - // Also, as this cache is optimized for LRU/MRU operations, some of - // the staleness/TTL checks will reduce performance, as they will incur - // overhead by deleting items. - // Must be a positive integer in ms, defaults to 0, which means "no TTL" - ttl?: number; - - // Minimum amount of time in ms in which to check for staleness. - // Defaults to 1, which means that the current time - // is checked at most once per millisecond. - // Set to 0 to check the current time every time staleness is tested. - // Note that setting this to a higher value - // will improve performance somewhat while using ttl tracking, - // albeit at the expense of keeping stale items - // around a bit longer than intended. - ttlResolution?: number; - - // Preemptively remove stale items from the cache. - // Note that this may significantly degrade performance, - // especially if the cache is storing a large number of items. - // It is almost always best to just leave the stale items in the cache, - // and let them fall out as new items are added. - // Note that this means that allowStale is a bit pointless, - // as stale items will be deleted almost as soon as they expire. - // Use with caution! - ttlAutopurge?: boolean; - - // By default, if you set ttl, it'll only delete stale items - // from the cache when you get(key). - // That is, it's not preemptively pruning items. - // If you set allowStale:true, it'll return the stale value - // as well as deleting it. If you don't set this, - // then it'll return undefined when you try to get a stale entry. - // Note that when a stale entry is fetched, - // even if it is returned due to allowStale being set, - // it is removed from the cache immediately. - // You can immediately put it back in the cache if you wish, - // thus resetting the TTL. - // This may be overridden by passing an options object to cache.get(). - // The cache.has() method will always return false for stale items. - // Boolean, default false, only relevant if ttl is set. - allowStale?: boolean; - - // When using time-expiring entries with ttl, - // setting this to true will make each item's - // age reset to 0 whenever it is retrieved from cache with get(), - // causing it to not expire. - // (It can still fall out of cache based on recency of use, of course.) - // This may be overridden by passing an options object to cache.get(). - // Boolean, default false, only relevant if ttl is set. - updateAgeOnGet?: boolean; - - // update the age of items on cache.has(), renewing their TTL - // boolean, default false - updateAgeOnHas?: boolean; - - // update the "recently-used"-ness of items on cache.has() - // boolean, default false - updateRecencyOnHas?: boolean; - - /** - * Function that is used to calculate the length of stored items. - * If you're storing strings or buffers, then you probably want to do - * something like `function(n, key){return n.length}`. The default - * is `function(){return 1}`, which is fine if you want to store - * `max` like-sized things. The item is passed as the first argument, - * and the key is passed as the second argument. - */ - length?(value: V, key?: K): number; - - /** - * By default, if you set a `maxAge`, it'll only actually pull stale items - * out of the cache when you `get(key)`. (That is, it's not pre-emptively - * doing a `setTimeout` or anything.) If you set `stale:true`, it'll return - * the stale value before deleting it. If you don't set this, then it'll - * return `undefined` when you try to get a stale entry, - * as if it had already been deleted. - */ - stale?: boolean | undefined; - } - - interface SetOptions { - ttl?: number; - // Will prevent calling the sizeCalculation function - // and just use the specified number if it is a positive integer - size?: number; - // Same as above - sizeCalculator?: (value: V) => number; - // Will prevent calling a dispose function in the case of overwrites - noDisposeOnSet?: boolean; - } - - interface Entry { - k: K; - v: V; - e: number; - } -} - -declare module 'lru-cache' { - export = LRUCache; -} diff --git a/yarn.lock b/yarn.lock index a1d197b7b2b..5ae8800ebf4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -19414,7 +19414,7 @@ __metadata: lint-staged: 13.2.3 lodash: 4.17.21 logfmt: ^1.3.2 - lru-cache: 7.17.0 + lru-cache: 10.0.0 lru-memoize: ^1.1.0 marked: ^4.3.0 memoize-one: 6.0.0 @@ -23159,10 +23159,10 @@ __metadata: languageName: node linkType: hard -"lru-cache@npm:7.17.0": - version: 7.17.0 - resolution: "lru-cache@npm:7.17.0" - checksum: 28c2a98ad313b8d61beac1f08257b6f0ca990e39d24a9bc831030b6e209447cfb11c6d9d1a774282189bfc9609d1dfd17ebe485228dd68f7b96b6b9b7740894e +"lru-cache@npm:10.0.0, lru-cache@npm:^9.1.1 || ^10.0.0": + version: 10.0.0 + resolution: "lru-cache@npm:10.0.0" + checksum: 18f101675fe283bc09cda0ef1e3cc83781aeb8373b439f086f758d1d91b28730950db785999cd060d3c825a8571c03073e8c14512b6655af2188d623031baf50 languageName: node linkType: hard @@ -23191,13 +23191,6 @@ __metadata: languageName: node linkType: hard -"lru-cache@npm:^9.1.1 || ^10.0.0": - version: 10.0.0 - resolution: "lru-cache@npm:10.0.0" - checksum: 18f101675fe283bc09cda0ef1e3cc83781aeb8373b439f086f758d1d91b28730950db785999cd060d3c825a8571c03073e8c14512b6655af2188d623031baf50 - languageName: node - linkType: hard - "lru-memoize@npm:^1.1.0": version: 1.1.0 resolution: "lru-memoize@npm:1.1.0" From c1f6b91ea988efeb98801eb9149769ce3ea9d4d3 Mon Sep 17 00:00:00 2001 From: Shirley <4163034+fridgepoet@users.noreply.github.com> Date: Fri, 14 Jul 2023 11:48:00 +0200 Subject: [PATCH 29/42] Elasticsearch: Fix multiple max depth flatten of multi-level objects (#70302) --- pkg/tsdb/elasticsearch/response_parser.go | 42 +++---- .../elasticsearch/response_parser_test.go | 106 +++++++++++++++++- 2 files changed, 118 insertions(+), 30 deletions(-) diff --git a/pkg/tsdb/elasticsearch/response_parser.go b/pkg/tsdb/elasticsearch/response_parser.go index 065de02c40e..c8d1f946d61 100644 --- a/pkg/tsdb/elasticsearch/response_parser.go +++ b/pkg/tsdb/elasticsearch/response_parser.go @@ -102,7 +102,7 @@ func processLogsResponse(res *es.SearchResponse, target *Query, configuredFields for hitIdx, hit := range res.Hits.Hits { var flattened map[string]interface{} if hit["_source"] != nil { - flattened = flatten(hit["_source"].(map[string]interface{})) + flattened = flatten(hit["_source"].(map[string]interface{}), 10) } doc := map[string]interface{}{ @@ -174,7 +174,7 @@ func processRawDataResponse(res *es.SearchResponse, target *Query, configuredFie for hitIdx, hit := range res.Hits.Hits { var flattened map[string]interface{} if hit["_source"] != nil { - flattened = flatten(hit["_source"].(map[string]interface{})) + flattened = flatten(hit["_source"].(map[string]interface{}), 10) } doc := map[string]interface{}{ @@ -1041,38 +1041,26 @@ func getErrorFromElasticResponse(response *es.SearchResponse) string { } // flatten flattens multi-level objects to single level objects. It uses dot notation to join keys. -func flatten(target map[string]interface{}) map[string]interface{} { +func flatten(target map[string]interface{}, maxDepth int) map[string]interface{} { // On frontend maxDepth wasn't used but as we are processing on backend // let's put a limit to avoid infinite loop. 10 was chosen arbitrary. - maxDepth := 10 - currentDepth := 0 - delimiter := "" output := make(map[string]interface{}) + step(0, maxDepth, target, "", output) + return output +} - var step func(object map[string]interface{}, prev string) +func step(currentDepth, maxDepth int, target map[string]interface{}, prev string, output map[string]interface{}) { + nextDepth := currentDepth + 1 + for key, value := range target { + newKey := strings.Trim(prev+"."+key, ".") - step = func(object map[string]interface{}, prev string) { - for key, value := range object { - if prev == "" { - delimiter = "" - } else { - delimiter = "." - } - newKey := prev + delimiter + key - - v, ok := value.(map[string]interface{}) - shouldStepInside := ok && len(v) > 0 && currentDepth < maxDepth - if shouldStepInside { - currentDepth++ - step(v, newKey) - } else { - output[newKey] = value - } + v, ok := value.(map[string]interface{}) + if ok && len(v) > 0 && currentDepth < maxDepth { + step(nextDepth, maxDepth, v, newKey, output) + } else { + output[newKey] = value } } - - step(target, "") - return output } // sortPropNames orders propNames so that timeField is first (if it exists), log message field is second diff --git a/pkg/tsdb/elasticsearch/response_parser_test.go b/pkg/tsdb/elasticsearch/response_parser_test.go index 25b09ca1d76..a54e955eee3 100644 --- a/pkg/tsdb/elasticsearch/response_parser_test.go +++ b/pkg/tsdb/elasticsearch/response_parser_test.go @@ -2481,7 +2481,6 @@ func TestProcessBuckets(t *testing.T) { } ] } - `) result, err := queryDataTest(query, response) @@ -3305,7 +3304,7 @@ func TestFlatten(t *testing.T) { }, } - flattened := flatten(obj) + flattened := flatten(obj, 10) require.Len(t, flattened, 2) require.Equal(t, "bar", flattened["foo"]) require.Equal(t, "qux", flattened["nested.bax.baz"]) @@ -3340,10 +3339,111 @@ func TestFlatten(t *testing.T) { }, } - flattened := flatten(obj) + flattened := flatten(obj, 10) require.Len(t, flattened, 1) require.Equal(t, map[string]interface{}{"nested11": map[string]interface{}{"nested12": "abc"}}, flattened["nested0.nested1.nested2.nested3.nested4.nested5.nested6.nested7.nested8.nested9.nested10"]) }) + + t.Run("does not affect any non-nested JSON", func(t *testing.T) { + target := map[string]interface{}{ + "fieldName": "", + } + + assert.Equal(t, map[string]interface{}{ + "fieldName": "", + }, flatten(target, 10)) + }) + + t.Run("flattens up to maxDepth", func(t *testing.T) { + target := map[string]interface{}{ + "fieldName2": map[string]interface{}{ + "innerFieldName2": map[string]interface{}{ + "innerFieldName3": "", + }, + }, + } + + assert.Equal(t, map[string]interface{}{ + "fieldName2.innerFieldName2": map[string]interface{}{"innerFieldName3": ""}}, flatten(target, 1)) + }) + + t.Run("flattens up to maxDepth with multiple keys in target", func(t *testing.T) { + target := map[string]interface{}{ + "fieldName": map[string]interface{}{ + "innerFieldName": "", + }, + "fieldName2": map[string]interface{}{ + "innerFieldName2": map[string]interface{}{ + "innerFieldName3": "", + }, + }, + } + + assert.Equal(t, map[string]interface{}{"fieldName.innerFieldName": "", "fieldName2.innerFieldName2": map[string]interface{}{"innerFieldName3": ""}}, flatten(target, 1)) + }) + + t.Run("flattens multiple objects of the same max depth", func(t *testing.T) { + target := map[string]interface{}{ + "fieldName": map[string]interface{}{ + "innerFieldName": "", + }, + "fieldName2": map[string]interface{}{ + "innerFieldName2": "", + }, + } + + assert.Equal(t, map[string]interface{}{ + "fieldName.innerFieldName": "", + "fieldName2.innerFieldName2": ""}, flatten(target, 1)) + }) + + t.Run("only flattens multiple entries in the same key", func(t *testing.T) { + target := map[string]interface{}{ + "fieldName": map[string]interface{}{ + "innerFieldName": "", + "innerFieldName1": "", + }, + "fieldName2": map[string]interface{}{ + "innerFieldName2": map[string]interface{}{ + "innerFieldName3": "", + }, + }, + } + + assert.Equal(t, map[string]interface{}{ + "fieldName.innerFieldName": "", + "fieldName.innerFieldName1": "", + "fieldName2.innerFieldName2": map[string]interface{}{"innerFieldName3": ""}}, flatten(target, 1)) + }) + + t.Run("combines nested field names", func(t *testing.T) { + target := map[string]interface{}{ + "fieldName": map[string]interface{}{ + "innerFieldName": "", + }, + "fieldName2": map[string]interface{}{ + "innerFieldName2": "", + }, + } + + assert.Equal(t, map[string]interface{}{"fieldName.innerFieldName": "", "fieldName2.innerFieldName2": ""}, flatten(target, 10)) + }) + + t.Run("will preserve only one key with the same name", func(t *testing.T) { + // This test documents that in the unlikely case of a collision of a flattened name and an existing key, only + // one entry's value will be preserved at random + target := map[string]interface{}{ + "fieldName": map[string]interface{}{ + "innerFieldName": "one of these values will be lost", + }, + "fieldName.innerFieldName": "this may be lost", + } + + result := flatten(target, 10) + assert.Len(t, result, 1) + _, ok := result["fieldName.innerFieldName"] + assert.True(t, ok) + }) } func TestTrimEdges(t *testing.T) { From 162dde5bdddaf3cac2444c2a52b8aebc03a71f23 Mon Sep 17 00:00:00 2001 From: Will Browne Date: Fri, 14 Jul 2023 11:49:05 +0200 Subject: [PATCH 30/42] Plugins: Use suffix for plugin directory (#71375) * plugin dir suffix * fix whitespace * fix cli * fix tests * fixup * simplify * undo uninstall changes --- pkg/api/plugin_resource_test.go | 2 +- .../grafana-cli/commands/install_command.go | 37 +++++++++----- pkg/cmd/grafana-cli/services/services.go | 15 +++++- pkg/plugins/manager/fakes/fakes.go | 6 +-- pkg/plugins/manager/installer.go | 30 ++++++----- pkg/plugins/manager/installer_test.go | 8 +-- pkg/plugins/manager/loader/finder/local.go | 6 +-- .../manager/loader/finder/local_test.go | 8 +-- pkg/plugins/manager/loader/loader_test.go | 2 +- .../manager/manager_integration_test.go | 2 +- pkg/plugins/storage/fs.go | 21 +++++--- pkg/plugins/storage/fs_test.go | 51 +++++++++---------- pkg/plugins/storage/ifaces.go | 4 +- 13 files changed, 112 insertions(+), 80 deletions(-) diff --git a/pkg/api/plugin_resource_test.go b/pkg/api/plugin_resource_test.go index b7409befb4a..97c08eaf6e0 100644 --- a/pkg/api/plugin_resource_test.go +++ b/pkg/api/plugin_resource_test.go @@ -70,7 +70,7 @@ func TestCallResource(t *testing.T) { angularInspector, err := angularinspector.NewStaticInspector() require.NoError(t, err) l := loader.ProvideService(pCfg, fakes.NewFakeLicensingService(), signature.NewUnsignedAuthorizer(pCfg), - reg, provider.ProvideService(coreRegistry), finder.NewLocalFinder(pCfg), fakes.NewFakeRoleRegistry(), + reg, provider.ProvideService(coreRegistry), finder.NewLocalFinder(pCfg.DevMode), fakes.NewFakeRoleRegistry(), assetpath.ProvideService(pluginscdn.ProvideService(pCfg)), signature.ProvideService(statickey.New()), angularInspector, &fakes.FakeOauthService{}) srcs := sources.ProvideService(cfg, pCfg) diff --git a/pkg/cmd/grafana-cli/commands/install_command.go b/pkg/cmd/grafana-cli/commands/install_command.go index a17a3769277..92969cc3335 100644 --- a/pkg/cmd/grafana-cli/commands/install_command.go +++ b/pkg/cmd/grafana-cli/commands/install_command.go @@ -5,11 +5,11 @@ import ( "errors" "fmt" "os" - "path/filepath" "runtime" "strings" "github.com/fatih/color" + "github.com/grafana/grafana/pkg/cmd/grafana-cli/logger" "github.com/grafana/grafana/pkg/cmd/grafana-cli/models" "github.com/grafana/grafana/pkg/cmd/grafana-cli/services" @@ -73,6 +73,14 @@ func installCommand(c utils.CommandLine) error { // installPlugin downloads the plugin code as a zip file from the Grafana.com API // and then extracts the zip into the plugin's directory. func installPlugin(ctx context.Context, pluginID, version string, c utils.CommandLine) error { + // If a version is specified, check if it is already installed + if version != "" { + if services.PluginVersionInstalled(pluginID, version, c.PluginDirectory()) { + services.Logger.Successf("Plugin %s v%s already installed.", pluginID, version) + return nil + } + } + repository := repo.NewManager(repo.ManagerCfg{ SkipTLSVerify: c.Bool("insecure"), BaseURL: c.PluginRepoURL(), @@ -95,7 +103,7 @@ func installPlugin(ctx context.Context, pluginID, version string, c utils.Comman } pluginFs := storage.FileSystem(services.Logger, c.PluginDirectory()) - extractedArchive, err := pluginFs.Extract(ctx, pluginID, archive.File) + extractedArchive, err := pluginFs.Extract(ctx, pluginID, storage.SimpleDirNameGeneratorFunc, archive.File) if err != nil { return err } @@ -107,7 +115,7 @@ func installPlugin(ctx context.Context, pluginID, version string, c utils.Comman return fmt.Errorf("%v: %w", fmt.Sprintf("failed to download plugin %s from repository", dep.ID), err) } - _, err = pluginFs.Extract(ctx, dep.ID, d.File) + _, err = pluginFs.Extract(ctx, dep.ID, storage.SimpleDirNameGeneratorFunc, d.File) if err != nil { return err } @@ -117,16 +125,21 @@ func installPlugin(ctx context.Context, pluginID, version string, c utils.Comman // uninstallPlugin removes the plugin directory func uninstallPlugin(_ context.Context, pluginID string, c utils.CommandLine) error { - logger.Infof("Removing plugin: %v\n", pluginID) - - pluginPath := filepath.Join(c.PluginDirectory(), pluginID) - fs := plugins.NewLocalFS(pluginPath) - - logger.Debugf("Removing directory %v\n", pluginPath) - err := fs.Remove() - if err != nil { - return err + for _, bundle := range services.GetLocalPlugins(c.PluginDirectory()) { + if bundle.Primary.JSONData.ID == pluginID { + logger.Infof("Removing plugin: %v\n", pluginID) + if remover, ok := bundle.Primary.FS.(plugins.FSRemover); ok { + logger.Debugf("Removing directory %v\n\n", bundle.Primary.FS.Base()) + if err := remover.Remove(); err != nil { + return err + } + return nil + } else { + return fmt.Errorf("plugin %v is immutable and therefore cannot be uninstalled", pluginID) + } + } } + return nil } diff --git a/pkg/cmd/grafana-cli/services/services.go b/pkg/cmd/grafana-cli/services/services.go index 46f9b4c643f..00fffc487e2 100644 --- a/pkg/cmd/grafana-cli/services/services.go +++ b/pkg/cmd/grafana-cli/services/services.go @@ -13,7 +13,6 @@ import ( "github.com/grafana/grafana/pkg/cmd/grafana-cli/logger" "github.com/grafana/grafana/pkg/cmd/grafana-cli/models" "github.com/grafana/grafana/pkg/plugins" - "github.com/grafana/grafana/pkg/plugins/config" "github.com/grafana/grafana/pkg/plugins/manager/loader/finder" "github.com/grafana/grafana/pkg/plugins/manager/sources" ) @@ -78,7 +77,7 @@ func GetLocalPlugin(pluginDir, pluginID string) (plugins.FoundPlugin, error) { } func GetLocalPlugins(pluginDir string) []*plugins.FoundBundle { - f := finder.NewLocalFinder(&config.Cfg{}) + f := finder.NewLocalFinder(true) res, err := f.Find(context.Background(), sources.NewLocalSource(plugins.ClassExternal, []string{pluginDir})) if err != nil { @@ -88,3 +87,15 @@ func GetLocalPlugins(pluginDir string) []*plugins.FoundBundle { return res } + +func PluginVersionInstalled(pluginID, version, pluginDir string) bool { + for _, bundle := range GetLocalPlugins(pluginDir) { + pJSON := bundle.Primary.JSONData + if pJSON.ID == pluginID { + if pJSON.Info.Version == version { + return true + } + } + } + return false +} diff --git a/pkg/plugins/manager/fakes/fakes.go b/pkg/plugins/manager/fakes/fakes.go index f099542360a..fd326d16f9c 100644 --- a/pkg/plugins/manager/fakes/fakes.go +++ b/pkg/plugins/manager/fakes/fakes.go @@ -233,16 +233,16 @@ func (r *FakePluginRepo) GetPluginArchiveInfo(ctx context.Context, pluginID, ver } type FakePluginStorage struct { - ExtractFunc func(_ context.Context, pluginID string, z *zip.ReadCloser) (*storage.ExtractedPluginArchive, error) + ExtractFunc func(_ context.Context, pluginID string, dirNameFunc storage.DirNameGeneratorFunc, z *zip.ReadCloser) (*storage.ExtractedPluginArchive, error) } func NewFakePluginStorage() *FakePluginStorage { return &FakePluginStorage{} } -func (s *FakePluginStorage) Extract(ctx context.Context, pluginID string, z *zip.ReadCloser) (*storage.ExtractedPluginArchive, error) { +func (s *FakePluginStorage) Extract(ctx context.Context, pluginID string, dirNameFunc storage.DirNameGeneratorFunc, z *zip.ReadCloser) (*storage.ExtractedPluginArchive, error) { if s.ExtractFunc != nil { - return s.ExtractFunc(ctx, pluginID, z) + return s.ExtractFunc(ctx, pluginID, dirNameFunc, z) } return &storage.ExtractedPluginArchive{}, nil } diff --git a/pkg/plugins/manager/installer.go b/pkg/plugins/manager/installer.go index 834beca8088..947a2f4326b 100644 --- a/pkg/plugins/manager/installer.go +++ b/pkg/plugins/manager/installer.go @@ -18,27 +18,29 @@ import ( var _ plugins.Installer = (*PluginInstaller)(nil) type PluginInstaller struct { - pluginRepo repo.Service - pluginStorage storage.ZipExtractor - pluginRegistry registry.Service - pluginLoader loader.Service - log log.Logger + pluginRepo repo.Service + pluginStorage storage.ZipExtractor + pluginStorageDirFunc storage.DirNameGeneratorFunc + pluginRegistry registry.Service + pluginLoader loader.Service + log log.Logger } func ProvideInstaller(cfg *config.Cfg, pluginRegistry registry.Service, pluginLoader loader.Service, pluginRepo repo.Service) *PluginInstaller { return New(pluginRegistry, pluginLoader, pluginRepo, - storage.FileSystem(log.NewPrettyLogger("installer.fs"), cfg.PluginsPath)) + storage.FileSystem(log.NewPrettyLogger("installer.fs"), cfg.PluginsPath), storage.SimpleDirNameGeneratorFunc) } func New(pluginRegistry registry.Service, pluginLoader loader.Service, pluginRepo repo.Service, - pluginStorage storage.ZipExtractor) *PluginInstaller { + pluginStorage storage.ZipExtractor, pluginStorageDirFunc storage.DirNameGeneratorFunc) *PluginInstaller { return &PluginInstaller{ - pluginLoader: pluginLoader, - pluginRegistry: pluginRegistry, - pluginRepo: pluginRepo, - pluginStorage: pluginStorage, - log: log.New("plugin.installer"), + pluginLoader: pluginLoader, + pluginRegistry: pluginRegistry, + pluginRepo: pluginRepo, + pluginStorage: pluginStorage, + pluginStorageDirFunc: pluginStorageDirFunc, + log: log.New("plugin.installer"), } } @@ -102,7 +104,7 @@ func (m *PluginInstaller) Add(ctx context.Context, pluginID, version string, opt } } - extractedArchive, err := m.pluginStorage.Extract(ctx, pluginID, pluginArchive.File) + extractedArchive, err := m.pluginStorage.Extract(ctx, pluginID, m.pluginStorageDirFunc, pluginArchive.File) if err != nil { return err } @@ -116,7 +118,7 @@ func (m *PluginInstaller) Add(ctx context.Context, pluginID, version string, opt return fmt.Errorf("%v: %w", fmt.Sprintf("failed to download plugin %s from repository", dep.ID), err) } - depArchive, err := m.pluginStorage.Extract(ctx, dep.ID, d.File) + depArchive, err := m.pluginStorage.Extract(ctx, dep.ID, m.pluginStorageDirFunc, d.File) if err != nil { return err } diff --git a/pkg/plugins/manager/installer_test.go b/pkg/plugins/manager/installer_test.go index a0a6043d186..a9af72e8985 100644 --- a/pkg/plugins/manager/installer_test.go +++ b/pkg/plugins/manager/installer_test.go @@ -53,7 +53,7 @@ func TestPluginManager_Add_Remove(t *testing.T) { } fs := &fakes.FakePluginStorage{ - ExtractFunc: func(_ context.Context, id string, z *zip.ReadCloser) (*storage.ExtractedPluginArchive, error) { + ExtractFunc: func(_ context.Context, id string, _ storage.DirNameGeneratorFunc, z *zip.ReadCloser) (*storage.ExtractedPluginArchive, error) { require.Equal(t, pluginID, id) require.Equal(t, mockZipV1, z) return &storage.ExtractedPluginArchive{ @@ -62,7 +62,7 @@ func TestPluginManager_Add_Remove(t *testing.T) { }, } - inst := New(fakes.NewFakePluginRegistry(), loader, pluginRepo, fs) + inst := New(fakes.NewFakePluginRegistry(), loader, pluginRepo, fs, storage.SimpleDirNameGeneratorFunc) err := inst.Add(context.Background(), pluginID, v1, testCompatOpts()) require.NoError(t, err) @@ -108,7 +108,7 @@ func TestPluginManager_Add_Remove(t *testing.T) { File: mockZipV2, }, nil } - fs.ExtractFunc = func(_ context.Context, pluginID string, z *zip.ReadCloser) (*storage.ExtractedPluginArchive, error) { + fs.ExtractFunc = func(_ context.Context, pluginID string, _ storage.DirNameGeneratorFunc, z *zip.ReadCloser) (*storage.ExtractedPluginArchive, error) { require.Equal(t, pluginV1.ID, pluginID) require.Equal(t, mockZipV2, z) return &storage.ExtractedPluginArchive{ @@ -168,7 +168,7 @@ func TestPluginManager_Add_Remove(t *testing.T) { }, } - pm := New(reg, &fakes.FakeLoader{}, &fakes.FakePluginRepo{}, &fakes.FakePluginStorage{}) + pm := New(reg, &fakes.FakeLoader{}, &fakes.FakePluginRepo{}, &fakes.FakePluginStorage{}, storage.SimpleDirNameGeneratorFunc) err := pm.Add(context.Background(), p.ID, "3.2.0", testCompatOpts()) require.ErrorIs(t, err, plugins.ErrInstallCorePlugin) diff --git a/pkg/plugins/manager/loader/finder/local.go b/pkg/plugins/manager/loader/finder/local.go index 1712d96f773..e09b96e8750 100644 --- a/pkg/plugins/manager/loader/finder/local.go +++ b/pkg/plugins/manager/loader/finder/local.go @@ -28,15 +28,15 @@ type Local struct { production bool } -func NewLocalFinder(cfg *config.Cfg) *Local { +func NewLocalFinder(devMode bool) *Local { return &Local{ - production: !cfg.DevMode, + production: !devMode, log: log.New("local.finder"), } } func ProvideLocalFinder(cfg *config.Cfg) *Local { - return NewLocalFinder(cfg) + return NewLocalFinder(cfg.DevMode) } func (l *Local) Find(ctx context.Context, src plugins.PluginSource) ([]*plugins.FoundBundle, error) { diff --git a/pkg/plugins/manager/loader/finder/local_test.go b/pkg/plugins/manager/loader/finder/local_test.go index e64dfb4434b..907920d24b2 100644 --- a/pkg/plugins/manager/loader/finder/local_test.go +++ b/pkg/plugins/manager/loader/finder/local_test.go @@ -255,7 +255,7 @@ func TestFinder_Find(t *testing.T) { } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - f := NewLocalFinder(pCfg) + f := NewLocalFinder(pCfg.DevMode) pluginBundles, err := f.Find(context.Background(), &fakes.FakePluginSource{ PluginURIsFunc: func(ctx context.Context) []string { return tc.pluginDirs @@ -292,7 +292,7 @@ func TestFinder_getAbsPluginJSONPaths(t *testing.T) { walk = origWalk }) - finder := NewLocalFinder(pCfg) + finder := NewLocalFinder(pCfg.DevMode) paths, err := finder.getAbsPluginJSONPaths("test") require.NoError(t, err) require.Empty(t, paths) @@ -307,7 +307,7 @@ func TestFinder_getAbsPluginJSONPaths(t *testing.T) { walk = origWalk }) - finder := NewLocalFinder(pCfg) + finder := NewLocalFinder(pCfg.DevMode) paths, err := finder.getAbsPluginJSONPaths("test") require.NoError(t, err) require.Empty(t, paths) @@ -322,7 +322,7 @@ func TestFinder_getAbsPluginJSONPaths(t *testing.T) { walk = origWalk }) - finder := NewLocalFinder(pCfg) + finder := NewLocalFinder(pCfg.DevMode) paths, err := finder.getAbsPluginJSONPaths("test") require.Error(t, err) require.Empty(t, paths) diff --git a/pkg/plugins/manager/loader/loader_test.go b/pkg/plugins/manager/loader/loader_test.go index 24e9b8b1cd4..b93eac7daf0 100644 --- a/pkg/plugins/manager/loader/loader_test.go +++ b/pkg/plugins/manager/loader/loader_test.go @@ -1494,7 +1494,7 @@ func newLoader(t *testing.T, cfg *config.Cfg, cbs ...func(loader *Loader)) *Load require.NoError(t, err) l := New(cfg, &fakes.FakeLicensingService{}, signature.NewUnsignedAuthorizer(cfg), fakes.NewFakePluginRegistry(), fakes.NewFakeBackendProcessProvider(), fakes.NewFakeProcessManager(), fakes.NewFakeRoleRegistry(), - assetpath.ProvideService(pluginscdn.ProvideService(cfg)), finder.NewLocalFinder(cfg), + assetpath.ProvideService(pluginscdn.ProvideService(cfg)), finder.NewLocalFinder(cfg.DevMode), signature.ProvideService(statickey.New()), angularInspector, &fakes.FakeOauthService{}) for _, cb := range cbs { diff --git a/pkg/plugins/manager/manager_integration_test.go b/pkg/plugins/manager/manager_integration_test.go index 08fc07a945f..6350640774b 100644 --- a/pkg/plugins/manager/manager_integration_test.go +++ b/pkg/plugins/manager/manager_integration_test.go @@ -121,7 +121,7 @@ func TestIntegrationPluginManager(t *testing.T) { angularInspector, err := angularinspector.NewStaticInspector() require.NoError(t, err) l := loader.ProvideService(pCfg, lic, signature.NewUnsignedAuthorizer(pCfg), - reg, provider.ProvideService(coreRegistry), finder.NewLocalFinder(pCfg), fakes.NewFakeRoleRegistry(), + reg, provider.ProvideService(coreRegistry), finder.NewLocalFinder(pCfg.DevMode), fakes.NewFakeRoleRegistry(), assetpath.ProvideService(pluginscdn.ProvideService(pCfg)), signature.ProvideService(statickey.New()), angularInspector, &fakes.FakeOauthService{}) srcs := sources.ProvideService(cfg, pCfg) diff --git a/pkg/plugins/storage/fs.go b/pkg/plugins/storage/fs.go index 445ce07c3f9..779330239cb 100644 --- a/pkg/plugins/storage/fs.go +++ b/pkg/plugins/storage/fs.go @@ -32,14 +32,18 @@ func FileSystem(logger log.PrettyLogger, pluginsDir string) *FS { } } -func (fs *FS) Extract(ctx context.Context, pluginID string, pluginArchive *zip.ReadCloser) ( +var SimpleDirNameGeneratorFunc = func(pluginID string) string { + return pluginID +} + +func (fs *FS) Extract(ctx context.Context, pluginID string, dirNameFunc DirNameGeneratorFunc, pluginArchive *zip.ReadCloser) ( *ExtractedPluginArchive, error) { - pluginDir, err := fs.extractFiles(ctx, pluginArchive, pluginID) + pluginDir, err := fs.extractFiles(ctx, pluginArchive, pluginID, dirNameFunc) if err != nil { return nil, fmt.Errorf("%v: %w", "failed to extract plugin archive", err) } - pluginJSON, err := readPluginJSON(pluginID, pluginDir) + pluginJSON, err := readPluginJSON(pluginDir) if err != nil { return nil, fmt.Errorf("%v: %w", "failed to convert to plugin DTO", err) } @@ -62,8 +66,9 @@ func (fs *FS) Extract(ctx context.Context, pluginID string, pluginArchive *zip.R }, nil } -func (fs *FS) extractFiles(_ context.Context, pluginArchive *zip.ReadCloser, pluginID string) (string, error) { - installDir := filepath.Join(fs.pluginsDir, pluginID) +func (fs *FS) extractFiles(_ context.Context, pluginArchive *zip.ReadCloser, pluginID string, dirNameFunc DirNameGeneratorFunc) (string, error) { + pluginDirName := dirNameFunc(pluginID) + installDir := filepath.Join(fs.pluginsDir, pluginDirName) if _, err := os.Stat(installDir); !os.IsNotExist(err) { fs.log.Debugf("Removing existing installation of plugin %s", installDir) err = os.RemoveAll(installDir) @@ -92,7 +97,7 @@ func (fs *FS) extractFiles(_ context.Context, pluginArchive *zip.ReadCloser, plu zf.Name, fs.pluginsDir) } - dstPath := filepath.Clean(filepath.Join(fs.pluginsDir, removeGitBuildFromName(zf.Name, pluginID))) // lgtm[go/zipslip] + dstPath := filepath.Clean(filepath.Join(fs.pluginsDir, removeGitBuildFromName(zf.Name, pluginDirName))) // lgtm[go/zipslip] if zf.FileInfo().IsDir() { // We can ignore gosec G304 here since it makes sense to give all users read access @@ -220,7 +225,7 @@ func removeGitBuildFromName(filename, pluginID string) string { return reGitBuild.ReplaceAllString(filename, pluginID+"/") } -func readPluginJSON(pluginID, pluginDir string) (plugins.JSONData, error) { +func readPluginJSON(pluginDir string) (plugins.JSONData, error) { pluginPath := filepath.Join(pluginDir, "plugin.json") // It's safe to ignore gosec warning G304 since the file path suffix is hardcoded @@ -232,7 +237,7 @@ func readPluginJSON(pluginID, pluginDir string) (plugins.JSONData, error) { // nolint:gosec data, err = os.ReadFile(pluginPath) if err != nil { - return plugins.JSONData{}, fmt.Errorf("could not find plugin.json or dist/plugin.json for %s in %s", pluginID, pluginDir) + return plugins.JSONData{}, fmt.Errorf("could not find plugin.json or dist/plugin.json for in %s", pluginDir) } } diff --git a/pkg/plugins/storage/fs_test.go b/pkg/plugins/storage/fs_test.go index 900069f5a5c..fa504248dd1 100644 --- a/pkg/plugins/storage/fs_test.go +++ b/pkg/plugins/storage/fs_test.go @@ -27,25 +27,24 @@ func TestAdd(t *testing.T) { pluginID := "test-app" fs := FileSystem(log.NewTestPrettyLogger(), testDir) - archive, err := fs.Extract(context.Background(), pluginID, zipFile(t, "./testdata/plugin-with-symlinks.zip")) + archive, err := fs.Extract(context.Background(), pluginID, SimpleDirNameGeneratorFunc, zipFile(t, "./testdata/plugin-with-symlinks.zip")) require.NotNil(t, archive) require.NoError(t, err) // verify extracted contents - files, err := os.ReadDir(filepath.Join(testDir, pluginID)) + files, err := os.ReadDir(archive.Path) require.NoError(t, err) - file2, err := files[2].Info() - require.NoError(t, err) - file4, err := files[4].Info() - require.NoError(t, err) - require.Len(t, files, 6) require.Equal(t, files[0].Name(), "MANIFEST.txt") require.Equal(t, files[1].Name(), "dashboards") require.Equal(t, files[2].Name(), "extra") + file2, err := files[2].Info() + require.NoError(t, err) require.Equal(t, os.ModeSymlink, file2.Mode()&os.ModeSymlink) require.Equal(t, files[3].Name(), "plugin.json") require.Equal(t, files[4].Name(), "symlink_to_txt") + file4, err := files[4].Info() + require.NoError(t, err) require.Equal(t, os.ModeSymlink, file4.Mode()&os.ModeSymlink) require.Equal(t, files[5].Name(), "text.txt") } @@ -59,27 +58,27 @@ func TestExtractFiles(t *testing.T) { skipWindows(t) pluginID := "grafana-simple-json-datasource" - path, err := i.extractFiles(context.Background(), zipFile(t, "testdata/grafana-simple-json-datasource-ec18fa4da8096a952608a7e4c7782b4260b41bcf.zip"), pluginID) + path, err := i.extractFiles(context.Background(), zipFile(t, "testdata/grafana-simple-json-datasource-ec18fa4da8096a952608a7e4c7782b4260b41bcf.zip"), pluginID, SimpleDirNameGeneratorFunc) require.Equal(t, filepath.Join(pluginsDir, pluginID), path) require.NoError(t, err) // File in zip has permissions 755 - fileInfo, err := os.Stat(filepath.Join(pluginsDir, "grafana-simple-json-datasource", "simple-plugin_darwin_amd64")) + fileInfo, err := os.Stat(filepath.Join(path, "simple-plugin_darwin_amd64")) require.NoError(t, err) require.Equal(t, "-rwxr-xr-x", fileInfo.Mode().String()) // File in zip has permission 755 - fileInfo, err = os.Stat(pluginsDir + "/grafana-simple-json-datasource/simple-plugin_linux_amd64") + fileInfo, err = os.Stat(filepath.Join(path, "simple-plugin_linux_amd64")) require.NoError(t, err) require.Equal(t, "-rwxr-xr-x", fileInfo.Mode().String()) // File in zip has permission 644 - fileInfo, err = os.Stat(pluginsDir + "/grafana-simple-json-datasource/simple-plugin_windows_amd64.exe") + fileInfo, err = os.Stat(filepath.Join(path, "simple-plugin_windows_amd64.exe")) require.NoError(t, err) require.Equal(t, "-rwxr-xr-x", fileInfo.Mode().String()) // File in zip has permission 755 - fileInfo, err = os.Stat(pluginsDir + "/grafana-simple-json-datasource/non-plugin-binary") + fileInfo, err = os.Stat(filepath.Join(path, "non-plugin-binary")) require.NoError(t, err) require.Equal(t, "-rwxr-xr-x", fileInfo.Mode().String()) }) @@ -88,43 +87,43 @@ func TestExtractFiles(t *testing.T) { skipWindows(t) pluginID := "plugin-with-symlink" - path, err := i.extractFiles(context.Background(), zipFile(t, "testdata/plugin-with-symlink.zip"), pluginID) + path, err := i.extractFiles(context.Background(), zipFile(t, "testdata/plugin-with-symlink.zip"), pluginID, SimpleDirNameGeneratorFunc) require.Equal(t, filepath.Join(pluginsDir, pluginID), path) require.NoError(t, err) - _, err = os.Stat(pluginsDir + "/plugin-with-symlink/symlink_to_txt") + _, err = os.Stat(filepath.Join(path, "symlink_to_txt")) require.NoError(t, err) - target, err := filepath.EvalSymlinks(pluginsDir + "/plugin-with-symlink/symlink_to_txt") + target, err := filepath.EvalSymlinks(filepath.Join(path, "symlink_to_txt")) require.NoError(t, err) - require.Equal(t, pluginsDir+"/plugin-with-symlink/text.txt", target) + require.Equal(t, filepath.Join(path, "text.txt"), target) }) t.Run("Should extract directory with relative symlink", func(t *testing.T) { skipWindows(t) pluginID := "plugin-with-symlink-dir" - path, err := i.extractFiles(context.Background(), zipFile(t, "testdata/plugin-with-symlink-dir.zip"), pluginID) + path, err := i.extractFiles(context.Background(), zipFile(t, "testdata/plugin-with-symlink-dir.zip"), pluginID, SimpleDirNameGeneratorFunc) require.Equal(t, filepath.Join(pluginsDir, pluginID), path) require.NoError(t, err) - _, err = os.Stat(pluginsDir + "/plugin-with-symlink-dir/symlink_to_dir") + _, err = os.Stat(filepath.Join(path, "symlink_to_dir")) require.NoError(t, err) - target, err := filepath.EvalSymlinks(pluginsDir + "/plugin-with-symlink-dir/symlink_to_dir") + target, err := filepath.EvalSymlinks(filepath.Join(path, "symlink_to_dir")) require.NoError(t, err) - require.Equal(t, pluginsDir+"/plugin-with-symlink-dir/dir", target) + require.Equal(t, filepath.Join(path, "dir"), target) }) t.Run("Should not extract file with absolute symlink", func(t *testing.T) { skipWindows(t) pluginID := "plugin-with-absolute-symlink" - path, err := i.extractFiles(context.Background(), zipFile(t, "testdata/plugin-with-absolute-symlink.zip"), pluginID) + path, err := i.extractFiles(context.Background(), zipFile(t, "testdata/plugin-with-absolute-symlink.zip"), pluginID, SimpleDirNameGeneratorFunc) require.Equal(t, filepath.Join(pluginsDir, pluginID), path) require.NoError(t, err) - _, err = os.Stat(pluginsDir + "/plugin-with-absolute-symlink/test.txt") + _, err = os.Stat(filepath.Join(path, "/test.txt")) require.True(t, os.IsNotExist(err)) }) @@ -132,16 +131,16 @@ func TestExtractFiles(t *testing.T) { skipWindows(t) pluginID := "plugin-with-absolute-symlink-dir" - path, err := i.extractFiles(context.Background(), zipFile(t, "testdata/plugin-with-absolute-symlink-dir.zip"), pluginID) + path, err := i.extractFiles(context.Background(), zipFile(t, "testdata/plugin-with-absolute-symlink-dir.zip"), pluginID, SimpleDirNameGeneratorFunc) require.Equal(t, filepath.Join(pluginsDir, pluginID), path) require.NoError(t, err) - _, err = os.Stat(pluginsDir + "/plugin-with-absolute-symlink-dir/target") + _, err = os.Stat(filepath.Join(path, "/plugin-with-absolute-symlink-dir/target")) require.True(t, os.IsNotExist(err)) }) t.Run("Should detect if archive members point outside of the destination directory", func(t *testing.T) { - path, err := i.extractFiles(context.Background(), zipFile(t, "testdata/plugin-with-parent-member.zip"), "plugin-with-parent-member") + path, err := i.extractFiles(context.Background(), zipFile(t, "testdata/plugin-with-parent-member.zip"), "plugin-with-parent-member", SimpleDirNameGeneratorFunc) require.Empty(t, path) require.EqualError(t, err, fmt.Sprintf( `archive member "../member.txt" tries to write outside of plugin directory: %q, this can be a security risk`, @@ -150,7 +149,7 @@ func TestExtractFiles(t *testing.T) { }) t.Run("Should detect if archive members are absolute", func(t *testing.T) { - path, err := i.extractFiles(context.Background(), zipFile(t, "testdata/plugin-with-absolute-member.zip"), "plugin-with-absolute-member") + path, err := i.extractFiles(context.Background(), zipFile(t, "testdata/plugin-with-absolute-member.zip"), "plugin-with-absolute-member", SimpleDirNameGeneratorFunc) require.Empty(t, path) require.EqualError(t, err, fmt.Sprintf( `archive member "/member.txt" tries to write outside of plugin directory: %q, this can be a security risk`, diff --git a/pkg/plugins/storage/ifaces.go b/pkg/plugins/storage/ifaces.go index 027827cf89d..eb2f2bde8c7 100644 --- a/pkg/plugins/storage/ifaces.go +++ b/pkg/plugins/storage/ifaces.go @@ -6,5 +6,7 @@ import ( ) type ZipExtractor interface { - Extract(ctx context.Context, pluginID string, rc *zip.ReadCloser) (*ExtractedPluginArchive, error) + Extract(ctx context.Context, pluginID string, destDir DirNameGeneratorFunc, rc *zip.ReadCloser) (*ExtractedPluginArchive, error) } + +type DirNameGeneratorFunc = func(pluginID string) string From 7806dbd9ad80329ca598a223750bb340a95776a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Fri, 14 Jul 2023 12:04:54 +0200 Subject: [PATCH 31/42] Alert: Change error icon to exclamation-circle (#71397) --- packages/grafana-ui/src/components/Alert/Alert.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grafana-ui/src/components/Alert/Alert.tsx b/packages/grafana-ui/src/components/Alert/Alert.tsx index e13dd28a294..42ccd327722 100644 --- a/packages/grafana-ui/src/components/Alert/Alert.tsx +++ b/packages/grafana-ui/src/components/Alert/Alert.tsx @@ -101,6 +101,7 @@ Alert.displayName = 'Alert'; export const getIconFromSeverity = (severity: AlertVariant): IconName => { switch (severity) { case 'error': + return 'exclamation-circle'; case 'warning': return 'exclamation-triangle'; case 'info': From 4b4be4006b68c8c34f1e80f59a70a0b2d6b22c06 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 14 Jul 2023 10:09:07 +0000 Subject: [PATCH 32/42] Update visx to v3.3.0 (#71625) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 12 +-- yarn.lock | 228 +++++++++++++++++++++++++++------------------------ 2 files changed, 128 insertions(+), 112 deletions(-) diff --git a/package.json b/package.json index 117d62cd744..afd14b392d3 100644 --- a/package.json +++ b/package.json @@ -300,12 +300,12 @@ "@types/react-resizable": "3.0.3", "@types/trusted-types": "2.0.3", "@types/webpack-env": "1.18.0", - "@visx/event": "3.0.1", - "@visx/gradient": "3.0.0", - "@visx/group": "3.0.0", - "@visx/scale": "3.0.0", - "@visx/shape": "3.0.0", - "@visx/tooltip": "3.1.2", + "@visx/event": "3.3.0", + "@visx/gradient": "3.3.0", + "@visx/group": "3.3.0", + "@visx/scale": "3.3.0", + "@visx/shape": "3.3.0", + "@visx/tooltip": "3.3.0", "@welldone-software/why-did-you-render": "7.0.1", "angular": "1.8.3", "angular-bindonce": "0.3.1", diff --git a/yarn.lock b/yarn.lock index 5ae8800ebf4..b8b3e68c3f5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9442,6 +9442,13 @@ __metadata: languageName: node linkType: hard +"@types/d3-array@npm:3.0.3": + version: 3.0.3 + resolution: "@types/d3-array@npm:3.0.3" + checksum: 972c8ff009c97c9093883d7597aac7185d4e8c2832d7f25420d8312aa1ebd60182f85fe768615cbc9d73d8819add52eea7ce640e57f5b1668ef389f1dc9569bc + languageName: node + linkType: hard + "@types/d3-axis@npm:*": version: 3.0.1 resolution: "@types/d3-axis@npm:3.0.1" @@ -9474,6 +9481,13 @@ __metadata: languageName: node linkType: hard +"@types/d3-color@npm:3.1.0": + version: 3.1.0 + resolution: "@types/d3-color@npm:3.1.0" + checksum: b1856f17d6366559a68eaba0164f30727e9dc5eaf1b3a6c8844354da228860240423d19fa4de65bff9da26b4ead8843eab14b1566962665412e8fd82c3810554 + languageName: node + linkType: hard + "@types/d3-contour@npm:*": version: 3.0.1 resolution: "@types/d3-contour@npm:3.0.1" @@ -9491,6 +9505,13 @@ __metadata: languageName: node linkType: hard +"@types/d3-delaunay@npm:6.0.1": + version: 6.0.1 + resolution: "@types/d3-delaunay@npm:6.0.1" + checksum: c46fd6f399ed604e9f40841851c432c936c4408af9e61b235a7f6030e93faa9b5c4f6c33a62be221e1d33f48a9162e9c4bbfa173746c0e4787483310da9a03b2 + languageName: node + linkType: hard + "@types/d3-dispatch@npm:*": version: 3.0.1 resolution: "@types/d3-dispatch@npm:3.0.1" @@ -9544,7 +9565,7 @@ __metadata: languageName: node linkType: hard -"@types/d3-format@npm:*": +"@types/d3-format@npm:*, @types/d3-format@npm:3.0.1": version: 3.0.1 resolution: "@types/d3-format@npm:3.0.1" checksum: 6819fae7e7c3fce1e44cd56e9b6d8ea5508f708cb7a42793edf82ff914b120bf6cddc35208b1b33ec82615ab82b843c284709f9cea5c3fe1ea5f012106b3d32c @@ -9567,7 +9588,7 @@ __metadata: languageName: node linkType: hard -"@types/d3-interpolate@npm:*, @types/d3-interpolate@npm:^3.0.0, @types/d3-interpolate@npm:^3.0.1": +"@types/d3-interpolate@npm:*, @types/d3-interpolate@npm:3.0.1, @types/d3-interpolate@npm:^3.0.0": version: 3.0.1 resolution: "@types/d3-interpolate@npm:3.0.1" dependencies: @@ -9618,7 +9639,7 @@ __metadata: languageName: node linkType: hard -"@types/d3-scale@npm:*": +"@types/d3-scale@npm:*, @types/d3-scale@npm:4.0.2": version: 4.0.2 resolution: "@types/d3-scale@npm:4.0.2" dependencies: @@ -9627,15 +9648,6 @@ __metadata: languageName: node linkType: hard -"@types/d3-scale@npm:^4.0.2": - version: 4.0.3 - resolution: "@types/d3-scale@npm:4.0.3" - dependencies: - "@types/d3-time": "*" - checksum: 76684da8519ab5f2210e647f74f96ece9c6816dea4ad5d76131121703a5268cc65687a8bc9ebbf4a44039482247336d98811ecc3fbfeb7f0122fdce4bb295547 - languageName: node - linkType: hard - "@types/d3-selection@npm:*": version: 3.0.1 resolution: "@types/d3-selection@npm:3.0.1" @@ -9668,17 +9680,17 @@ __metadata: languageName: node linkType: hard -"@types/d3-time@npm:*": - version: 3.0.0 - resolution: "@types/d3-time@npm:3.0.0" - checksum: e76adb056daccf80107f4db190ac6deb77e8774f00362bb6c76f178e67f2f217422fe502b654edbc9ac6451f6619045b9f6f5fe0db1ec5520e2ada377af7c72e +"@types/d3-time-format@npm:2.1.0": + version: 2.1.0 + resolution: "@types/d3-time-format@npm:2.1.0" + checksum: 8493cc4676d7656becf0c1195abb1213827e4cf42a85849c5e0159fa89b1b80c5ff6ad8af54e54d0e8c76815b866adf68a948da9b966405bd12c2070f57a7efe languageName: node linkType: hard -"@types/d3-time@npm:^2.0.0": - version: 2.1.1 - resolution: "@types/d3-time@npm:2.1.1" - checksum: 115048d0cd312a3172ef7c03615dfbdbd8b92a93fd7b6d9ca93c49c704fcdb9575f4c57955eb54eb757b9834acaaf47fc52eae103d06246c59ae120de4559cbc +"@types/d3-time@npm:*, @types/d3-time@npm:3.0.0": + version: 3.0.0 + resolution: "@types/d3-time@npm:3.0.0" + checksum: e76adb056daccf80107f4db190ac6deb77e8774f00362bb6c76f178e67f2f217422fe502b654edbc9ac6451f6619045b9f6f5fe0db1ec5520e2ada377af7c72e languageName: node linkType: hard @@ -11253,9 +11265,9 @@ __metadata: languageName: node linkType: hard -"@visx/bounds@npm:3.0.0": - version: 3.0.0 - resolution: "@visx/bounds@npm:3.0.0" +"@visx/bounds@npm:3.3.0": + version: 3.3.0 + resolution: "@visx/bounds@npm:3.3.0" dependencies: "@types/react": "*" "@types/react-dom": "*" @@ -11263,87 +11275,82 @@ __metadata: peerDependencies: react: ^16.0.0-0 || ^17.0.0-0 || ^18.0.0-0 react-dom: ^16.0.0-0 || ^17.0.0-0 || ^18.0.0-0 - checksum: 3c50dad1c78b526bebe20a690360ae5ad3dd2a31c86150553071671e49309a9fcf3bca3303eab7f7ac2e28be8d7987ac9ce5daa28b8df32c647b0aa97f118fa9 + checksum: e682b343735f53d7eed04cc9e4bc40308583724faa0577f752449d59daea57030f05cb72a9711d7e7f46db932691fea6bb7a545b204b4df24b80ffff0ed04e78 languageName: node linkType: hard -"@visx/curve@npm:3.0.0": - version: 3.0.0 - resolution: "@visx/curve@npm:3.0.0" +"@visx/curve@npm:3.3.0": + version: 3.3.0 + resolution: "@visx/curve@npm:3.3.0" dependencies: "@types/d3-shape": ^1.3.1 d3-shape: ^1.0.6 - checksum: 1707b2b0e002d35e77cec3c5fbf8a05e70f10881ffb123edf7e04e9ccfb05262e1cbbc0dfd45067e1c3ae5bc653325ef728fe880fecc7be9620ae267631f4149 + checksum: 36db95911c567408de78851eee6d98b60065c9d07b5abc7652cef072eaf5040444d8d84e73255f91bca0cfb50837f3b47db7209183211c20bc4bc1adcf13794d languageName: node linkType: hard -"@visx/event@npm:3.0.1": - version: 3.0.1 - resolution: "@visx/event@npm:3.0.1" +"@visx/event@npm:3.3.0": + version: 3.3.0 + resolution: "@visx/event@npm:3.3.0" dependencies: "@types/react": "*" - "@visx/point": 3.0.1 - checksum: 0cb4dd578bbe54bd428a0cfae9e64db141b039c2c6c1412d1cd1d04e1613d193212b031124948ca3b7eed877cdea87d161cc3a008b973c6f217e21a8a2dd27b0 + "@visx/point": 3.3.0 + checksum: 3cdb86848d9ae7cc8b6a14a0cc4efd7fc2186fca582ee374bb1f2dfe104ec5cd04dbdbbfc41ccb8c94e1885e2b6e6060a488f3a0a0554ad9e831ecc1b28339de languageName: node linkType: hard -"@visx/gradient@npm:3.0.0": - version: 3.0.0 - resolution: "@visx/gradient@npm:3.0.0" +"@visx/gradient@npm:3.3.0": + version: 3.3.0 + resolution: "@visx/gradient@npm:3.3.0" dependencies: "@types/react": "*" prop-types: ^15.5.7 peerDependencies: react: ^16.0.0-0 || ^17.0.0-0 || ^18.0.0-0 - checksum: 471b4a4e1ec329e26cedb5aeef627b7c6393b54d85f76fa2707ec4f2b75a67007c5d9e4c9ffbdf58d37853228c21e285780466ab958b22dbba41f209c5212182 + checksum: 7a371c788a09c8fc53484cfe375444332c5893f3b6fe7a86ed1bb02761deaa92e53208dab140a5a7c8d610af9396a7bcf6794d9b70d6945048fc9aeb0f4757ce languageName: node linkType: hard -"@visx/group@npm:3.0.0": - version: 3.0.0 - resolution: "@visx/group@npm:3.0.0" +"@visx/group@npm:3.3.0": + version: 3.3.0 + resolution: "@visx/group@npm:3.3.0" dependencies: "@types/react": "*" classnames: ^2.3.1 prop-types: ^15.6.2 peerDependencies: react: ^16.0.0-0 || ^17.0.0-0 || ^18.0.0-0 - checksum: f52b946fb39cfcd4798bd5c77b729ceb41b2041e0464edeef2f15955c4022d51ed9f7626f2a7ac331f8430c84037254be5dd38f8282881a63d1680b27f41d04d + checksum: a2f950664f43f1f1700a329f3a66bc3921ce8be35a93095a9ea28334ae4f9943c1082f21ba0f57f2bda913d2a40da8b7124235c2ae666c0e5d58a900c7148a8b languageName: node linkType: hard -"@visx/point@npm:3.0.1": - version: 3.0.1 - resolution: "@visx/point@npm:3.0.1" - checksum: 727f314826eb85a608b4088a9e2fedb7e6996a5f0fdddaeb40702a51aa04da07fdbc5fdcf2d595d914dfa083389c644f769fc69b3a247b4da274936dd58c7bb8 +"@visx/point@npm:3.3.0": + version: 3.3.0 + resolution: "@visx/point@npm:3.3.0" + checksum: 79950f49828d12c67c856ac0b345292df03a154b50f739aab3dbab37abb73ba40f9cbdaa46d698b50691984e81b94afdafe64dd4fa18c6d2895298cf25f1a450 languageName: node linkType: hard -"@visx/scale@npm:3.0.0": - version: 3.0.0 - resolution: "@visx/scale@npm:3.0.0" +"@visx/scale@npm:3.3.0": + version: 3.3.0 + resolution: "@visx/scale@npm:3.3.0" dependencies: - "@types/d3-interpolate": ^3.0.1 - "@types/d3-scale": ^4.0.2 - "@types/d3-time": ^2.0.0 - d3-interpolate: ^3.0.1 - d3-scale: ^4.0.2 - d3-time: ^2.1.1 - checksum: 3740fd0f6844b2297847f48f34afa9772e35d8b6faf26fb7b18c78fcd83634de57a44cd4aa9263dfb3a62bec609cf24b36db26f6db8ba36908dbdb83f359d9ed + "@visx/vendor": 3.3.0 + checksum: a6a5589fc86c72df84d8d11bab255fa3bf0481ca13ff15c66228368afae60937bb0553d942202b007a5d50b93dfc62359b06fd53c00da0eeb472db09d662440d languageName: node linkType: hard -"@visx/shape@npm:3.0.0": - version: 3.0.0 - resolution: "@visx/shape@npm:3.0.0" +"@visx/shape@npm:3.3.0": + version: 3.3.0 + resolution: "@visx/shape@npm:3.3.0" dependencies: "@types/d3-path": ^1.0.8 "@types/d3-shape": ^1.3.1 "@types/lodash": ^4.14.172 "@types/react": "*" - "@visx/curve": 3.0.0 - "@visx/group": 3.0.0 - "@visx/scale": 3.0.0 + "@visx/curve": 3.3.0 + "@visx/group": 3.3.0 + "@visx/scale": 3.3.0 classnames: ^2.3.1 d3-path: ^1.0.5 d3-shape: ^1.2.0 @@ -11351,23 +11358,48 @@ __metadata: prop-types: ^15.5.10 peerDependencies: react: ^16.3.0-0 || ^17.0.0-0 || ^18.0.0-0 - checksum: d6e71e0c5dd90957a38b1404e8357cd2192f741f8c7b4f73fac3c007e4b0af398f5cf648f5f1ecc5ca72759e729cfa58fff4f8a409f95a344219309881e58b37 + checksum: ab53910f6a2b5c2a36bfceed92ebafaf3bfa0c20272e3b86e7ec7e782628021fca4fb377edfe86b76d38df4f5ad9b846056ba358f63112988ff7346f23bad739 languageName: node linkType: hard -"@visx/tooltip@npm:3.1.2": - version: 3.1.2 - resolution: "@visx/tooltip@npm:3.1.2" +"@visx/tooltip@npm:3.3.0": + version: 3.3.0 + resolution: "@visx/tooltip@npm:3.3.0" dependencies: "@types/react": "*" - "@visx/bounds": 3.0.0 + "@visx/bounds": 3.3.0 classnames: ^2.3.1 prop-types: ^15.5.10 react-use-measure: ^2.0.4 peerDependencies: react: ^16.8.0-0 || ^17.0.0-0 || ^18.0.0-0 react-dom: ^16.8.0-0 || ^17.0.0-0 || ^18.0.0-0 - checksum: 4c2127068f22766e984ed3ed1452dcece919bacb0297b17ba862a6815bb7f04c4fc462a100d3934e0cb56a9c7962b82f7c4184748ef4b2dbef3b4b0d5b717fdd + checksum: eb525afd34bf108f9343e7998a8752e0002190afa76d2e9e7f47ec83f89139f611def8fe59ba55af4ab2d15bb7d31b836d372ef338e8aa4ca2e7e4cd68567c7f + languageName: node + linkType: hard + +"@visx/vendor@npm:3.3.0": + version: 3.3.0 + resolution: "@visx/vendor@npm:3.3.0" + dependencies: + "@types/d3-array": 3.0.3 + "@types/d3-color": 3.1.0 + "@types/d3-delaunay": 6.0.1 + "@types/d3-format": 3.0.1 + "@types/d3-interpolate": 3.0.1 + "@types/d3-scale": 4.0.2 + "@types/d3-time": 3.0.0 + "@types/d3-time-format": 2.1.0 + d3-array: 3.2.1 + d3-color: 3.1.0 + d3-delaunay: 6.0.2 + d3-format: 3.1.0 + d3-interpolate: 3.0.1 + d3-scale: 4.0.2 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + internmap: 2.0.3 + checksum: eaab876b3898d44930e75a95ea1f6f1db490822fd9c93f2806f5673875f8b63bde08f41f43ab0c2c291301796b52d612e671d3f81dfaa20c986adc90d95d09cf languageName: node linkType: hard @@ -15270,15 +15302,6 @@ __metadata: languageName: node linkType: hard -"d3-array@npm:2": - version: 2.12.1 - resolution: "d3-array@npm:2.12.1" - dependencies: - internmap: ^1.0.0 - checksum: 97853b7b523aded17078f37c67742f45d81e88dda2107ae9994c31b9e36c5fa5556c4c4cf39650436f247813602dfe31bf7ad067ff80f127a16903827f10c6eb - languageName: node - linkType: hard - "d3-array@npm:2 - 3, d3-array@npm:2.10.0 - 3, d3-array@npm:2.5.0 - 3, d3-array@npm:3, d3-array@npm:^3.2.0": version: 3.2.2 resolution: "d3-array@npm:3.2.2" @@ -15288,6 +15311,15 @@ __metadata: languageName: node linkType: hard +"d3-array@npm:3.2.1": + version: 3.2.1 + resolution: "d3-array@npm:3.2.1" + dependencies: + internmap: 1 - 2 + checksum: 0bed33cc33b70f9d48ccef3e7a5956e134862e09179bf14df0bf9c8fc0ec02b8f847d4f5e1d32729cd5e02032af1d0a32bcc968ff1333795028455a749994623 + languageName: node + linkType: hard + "d3-axis@npm:3": version: 3.0.0 resolution: "d3-axis@npm:3.0.0" @@ -15317,7 +15349,7 @@ __metadata: languageName: node linkType: hard -"d3-color@npm:1 - 3, d3-color@npm:3": +"d3-color@npm:1 - 3, d3-color@npm:3, d3-color@npm:3.1.0": version: 3.1.0 resolution: "d3-color@npm:3.1.0" checksum: 4931fbfda5d7c4b5cfa283a13c91a954f86e3b69d75ce588d06cde6c3628cebfc3af2069ccf225e982e8987c612aa7948b3932163ce15eb3c11cd7c003f3ee3b @@ -15333,7 +15365,7 @@ __metadata: languageName: node linkType: hard -"d3-delaunay@npm:6": +"d3-delaunay@npm:6, d3-delaunay@npm:6.0.2": version: 6.0.2 resolution: "d3-delaunay@npm:6.0.2" dependencies: @@ -15407,7 +15439,7 @@ __metadata: languageName: node linkType: hard -"d3-format@npm:1 - 3, d3-format@npm:3": +"d3-format@npm:1 - 3, d3-format@npm:3, d3-format@npm:3.1.0": version: 3.1.0 resolution: "d3-format@npm:3.1.0" checksum: f345ec3b8ad3cab19bff5dead395bd9f5590628eb97a389b1dd89f0b204c7c4fc1d9520f13231c2c7cf14b7c9a8cf10f8ef15bde2befbab41454a569bd706ca2 @@ -15430,7 +15462,7 @@ __metadata: languageName: node linkType: hard -"d3-interpolate@npm:1 - 3, d3-interpolate@npm:1.2.0 - 3, d3-interpolate@npm:3, d3-interpolate@npm:3.0.1, d3-interpolate@npm:^3.0.1": +"d3-interpolate@npm:1 - 3, d3-interpolate@npm:1.2.0 - 3, d3-interpolate@npm:3, d3-interpolate@npm:3.0.1": version: 3.0.1 resolution: "d3-interpolate@npm:3.0.1" dependencies: @@ -15484,7 +15516,7 @@ __metadata: languageName: node linkType: hard -"d3-scale@npm:4, d3-scale@npm:^4.0.2": +"d3-scale@npm:4, d3-scale@npm:4.0.2": version: 4.0.2 resolution: "d3-scale@npm:4.0.2" dependencies: @@ -15522,7 +15554,7 @@ __metadata: languageName: node linkType: hard -"d3-time-format@npm:2 - 4, d3-time-format@npm:4": +"d3-time-format@npm:2 - 4, d3-time-format@npm:4, d3-time-format@npm:4.1.0": version: 4.1.0 resolution: "d3-time-format@npm:4.1.0" dependencies: @@ -15531,7 +15563,7 @@ __metadata: languageName: node linkType: hard -"d3-time@npm:1 - 3, d3-time@npm:2.1.1 - 3, d3-time@npm:3": +"d3-time@npm:1 - 3, d3-time@npm:2.1.1 - 3, d3-time@npm:3, d3-time@npm:3.1.0": version: 3.1.0 resolution: "d3-time@npm:3.1.0" dependencies: @@ -15540,15 +15572,6 @@ __metadata: languageName: node linkType: hard -"d3-time@npm:^2.1.1": - version: 2.1.1 - resolution: "d3-time@npm:2.1.1" - dependencies: - d3-array: 2 - checksum: d1c7b9658c20646e46c3dd19e11c38e02dec098e8baa7d2cd868af8eb01953668f5da499fa33dc63541cf74a26e788786f8828c4381dbbf475a76b95972979a6 - languageName: node - linkType: hard - "d3-timer@npm:1 - 3, d3-timer@npm:3": version: 3.0.1 resolution: "d3-timer@npm:3.0.1" @@ -19324,12 +19347,12 @@ __metadata: "@types/yargs": 17.0.22 "@typescript-eslint/eslint-plugin": 5.42.0 "@typescript-eslint/parser": 5.42.0 - "@visx/event": 3.0.1 - "@visx/gradient": 3.0.0 - "@visx/group": 3.0.0 - "@visx/scale": 3.0.0 - "@visx/shape": 3.0.0 - "@visx/tooltip": 3.1.2 + "@visx/event": 3.3.0 + "@visx/gradient": 3.3.0 + "@visx/group": 3.3.0 + "@visx/scale": 3.3.0 + "@visx/shape": 3.3.0 + "@visx/tooltip": 3.3.0 "@welldone-software/why-did-you-render": 7.0.1 angular: 1.8.3 angular-bindonce: 0.3.1 @@ -20595,20 +20618,13 @@ __metadata: languageName: node linkType: hard -"internmap@npm:1 - 2": +"internmap@npm:1 - 2, internmap@npm:2.0.3": version: 2.0.3 resolution: "internmap@npm:2.0.3" checksum: 7ca41ec6aba8f0072fc32fa8a023450a9f44503e2d8e403583c55714b25efd6390c38a87161ec456bf42d7bc83aab62eb28f5aef34876b1ac4e60693d5e1d241 languageName: node linkType: hard -"internmap@npm:^1.0.0": - version: 1.0.1 - resolution: "internmap@npm:1.0.1" - checksum: 9d00f8c0cf873a24a53a5a937120dab634c41f383105e066bb318a61864e6292d24eb9516e8e7dccfb4420ec42ca474a0f28ac9a6cc82536898fa09bbbe53813 - languageName: node - linkType: hard - "interpret@npm:^1.0.0": version: 1.4.0 resolution: "interpret@npm:1.4.0" From 88b09213f7f89a35ca34ef3743f540ceb690cc93 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 14 Jul 2023 10:18:01 +0000 Subject: [PATCH 33/42] Update dependency centrifuge to v4 (#71626) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 41 +++++++++++++++-------------------------- 2 files changed, 16 insertions(+), 27 deletions(-) diff --git a/package.json b/package.json index afd14b392d3..4c0b7b0080e 100644 --- a/package.json +++ b/package.json @@ -316,7 +316,7 @@ "baron": "3.0.3", "brace": "0.11.1", "calculate-size": "1.1.1", - "centrifuge": "3.1.0", + "centrifuge": "4.0.1", "classnames": "2.3.2", "combokeys": "^3.0.0", "comlink": "4.4.1", diff --git a/yarn.lock b/yarn.lock index b8b3e68c3f5..de852b5e7d9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10175,13 +10175,6 @@ __metadata: languageName: node linkType: hard -"@types/long@npm:^4.0.1": - version: 4.0.2 - resolution: "@types/long@npm:4.0.2" - checksum: d16cde7240d834cf44ba1eaec49e78ae3180e724cd667052b194a372f350d024cba8dd3f37b0864931683dab09ca935d52f0c4c1687178af5ada9fc85b0635f4 - languageName: node - linkType: hard - "@types/marked@npm:4.0.8, @types/marked@npm:^4": version: 4.0.8 resolution: "@types/marked@npm:4.0.8" @@ -13705,13 +13698,13 @@ __metadata: languageName: node linkType: hard -"centrifuge@npm:3.1.0": - version: 3.1.0 - resolution: "centrifuge@npm:3.1.0" +"centrifuge@npm:4.0.1": + version: 4.0.1 + resolution: "centrifuge@npm:4.0.1" dependencies: events: ^3.3.0 - protobufjs: ^6.11.3 - checksum: 24bcf02ad896f66929b4c8f44632da708b6888c03bf09ed756940fda181e46197c28673b74680da33005ec3770725bd7f286c689bdf373cc25d1f10db4fb9fc5 + protobufjs: ^7.2.4 + checksum: 5cfa25d2688089e5c70e2a894b0f133cfc852828ff84d44a08a0ff2d60c2dceaea50f4ee5b1ffb37b1bab61ef28a25e6d803c63d03fd93566f1466e02b15262f languageName: node linkType: hard @@ -19370,7 +19363,7 @@ __metadata: brace: 0.11.1 browserslist: ^4.21.4 calculate-size: 1.1.1 - centrifuge: 3.1.0 + centrifuge: 4.0.1 chance: ^1.0.10 classnames: 2.3.2 codeowners: ^5.1.1 @@ -23138,10 +23131,10 @@ __metadata: languageName: node linkType: hard -"long@npm:^4.0.0": - version: 4.0.0 - resolution: "long@npm:4.0.0" - checksum: 16afbe8f749c7c849db1f4de4e2e6a31ac6e617cead3bdc4f9605cb703cd20e1e9fc1a7baba674ffcca57d660a6e5b53a9e236d7b25a295d3855cca79cc06744 +"long@npm:^5.0.0": + version: 5.2.3 + resolution: "long@npm:5.2.3" + checksum: 885ede7c3de4facccbd2cacc6168bae3a02c3e836159ea4252c87b6e34d40af819824b2d4edce330bfb5c4d6e8ce3ec5864bdcf9473fa1f53a4f8225860e5897 languageName: node linkType: hard @@ -26534,9 +26527,9 @@ __metadata: languageName: node linkType: hard -"protobufjs@npm:^6.11.3": - version: 6.11.3 - resolution: "protobufjs@npm:6.11.3" +"protobufjs@npm:^7.2.4": + version: 7.2.4 + resolution: "protobufjs@npm:7.2.4" dependencies: "@protobufjs/aspromise": ^1.1.2 "@protobufjs/base64": ^1.1.2 @@ -26548,13 +26541,9 @@ __metadata: "@protobufjs/path": ^1.1.2 "@protobufjs/pool": ^1.1.0 "@protobufjs/utf8": ^1.1.0 - "@types/long": ^4.0.1 "@types/node": ">=13.7.0" - long: ^4.0.0 - bin: - pbjs: bin/pbjs - pbts: bin/pbts - checksum: 4a6ce1964167e4c45c53fd8a312d7646415c777dd31b4ba346719947b88e61654912326101f927da387d6b6473ab52a7ea4f54d6f15d63b31130ce28e2e15070 + long: ^5.0.0 + checksum: a952cdf2a5e5250c16ae651b570849b6f5b20a5475c3eef63ffb290ad239aa2916adfc1cc676f7fc93c69f48113df268761c0c246f7f023118c85bdd1a170044 languageName: node linkType: hard From e7e5ae2ee010c4ce136b5a033f19baf1b9e6630c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 14 Jul 2023 10:19:07 +0000 Subject: [PATCH 34/42] Update dependency trim to v1 (#71633) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4c0b7b0080e..828365b7db5 100644 --- a/package.json +++ b/package.json @@ -433,7 +433,7 @@ "@rushstack/rig-package": "0.4.0", "@rushstack/ts-command-line": "4.15.1", "ngtemplate-loader/loader-utils": "^2.0.0", - "trim": "0.0.3", + "trim": "1.0.1", "slate-dev-environment@^0.2.2": "patch:slate-dev-environment@npm:0.2.5#.yarn/patches/slate-dev-environment-npm-0.2.5-9aeb7da7b5.patch", "react-split-pane@0.1.92": "patch:react-split-pane@npm:0.1.92#.yarn/patches/react-split-pane-npm-0.1.92-93dbf51dff.patch", "@storybook/blocks@7.0.10": "patch:@storybook/blocks@npm%3A7.0.10#./.yarn/patches/@storybook-blocks-npm-7.0.10-b101e8dcba.patch" From 565435981344fff00d105c8a358ee17dd5f8bab1 Mon Sep 17 00:00:00 2001 From: Pierre Baumard Date: Fri, 14 Jul 2023 12:24:50 +0200 Subject: [PATCH 35/42] I18n: Add server config to detect browser language (#69396) * I18N: Add browser language detector * Improve style * No new property for type check * Add dependency * Suggested doc change Co-authored-by: Christopher Moyer <35463610+chri2547@users.noreply.github.com> * Fix prettier * 'detect' as special language, no cache and only navigator detector As per PR suggestion comments * Update language configuration doc * Suggested change in doc From @chri2547 Co-authored-by: Christopher Moyer <35463610+chri2547@users.noreply.github.com> * Fix import * Revert public/app/types/explore.ts changes * Prettier write --------- Co-authored-by: Christopher Moyer <35463610+chri2547@users.noreply.github.com> Co-authored-by: joshhunt --- .../setup-grafana/configure-grafana/_index.md | 4 +- package.json | 1 + packages/grafana-ui/package.json | 1 + packages/grafana-ui/src/utils/i18n.tsx | 3 +- .../app/core/internationalization/index.tsx | 55 +++++++++++-------- yarn.lock | 13 ++++- 6 files changed, 50 insertions(+), 27 deletions(-) diff --git a/docs/sources/setup-grafana/configure-grafana/_index.md b/docs/sources/setup-grafana/configure-grafana/_index.md index 4af59af6325..97a17d8f58d 100644 --- a/docs/sources/setup-grafana/configure-grafana/_index.md +++ b/docs/sources/setup-grafana/configure-grafana/_index.md @@ -827,7 +827,9 @@ Sets the default UI theme: `dark`, `light`, or `system`. The default theme is `d ### default_language -This setting configures the default UI language, which must be a supported IETF language tag, such as `en-US`. +This option will set the default UI language if a supported IETF language tag like `en-US` is available. +If set to `detect`, the default UI language will be determined by browser preference. +The default is `en-US`. ### home_page diff --git a/package.json b/package.json index 828365b7db5..d4327aae5aa 100644 --- a/package.json +++ b/package.json @@ -337,6 +337,7 @@ "history": "4.10.1", "hoist-non-react-statics": "3.3.2", "i18next": "^22.0.0", + "i18next-browser-languagedetector": "^7.0.2", "immer": "10.0.2", "immutable": "4.3.0", "jquery": "3.7.0", diff --git a/packages/grafana-ui/package.json b/packages/grafana-ui/package.json index 22894f04a94..fa8563e1aef 100644 --- a/packages/grafana-ui/package.json +++ b/packages/grafana-ui/package.json @@ -71,6 +71,7 @@ "date-fns": "2.30.0", "hoist-non-react-statics": "3.3.2", "i18next": "^22.0.0", + "i18next-browser-languagedetector": "^7.0.2", "immutable": "4.3.0", "is-hotkey": "0.2.0", "jquery": "3.7.0", diff --git a/packages/grafana-ui/src/utils/i18n.tsx b/packages/grafana-ui/src/utils/i18n.tsx index f6777c6bad6..06cd0731653 100644 --- a/packages/grafana-ui/src/utils/i18n.tsx +++ b/packages/grafana-ui/src/utils/i18n.tsx @@ -14,7 +14,8 @@ import { Trans as I18NextTrans, initReactI18next } from 'react-i18next'; // esli // Creates a default, english i18next instance when running outside of grafana. // we don't support changing the locale of grafana ui when outside of Grafana function initI18n() { - if (!i18next.options.lng) { + // resources is undefined by default and set either by grafana app.ts or here + if (typeof i18next.options.resources !== 'object') { i18next.use(initReactI18next).init({ resources: {}, returnEmptyString: false, diff --git a/public/app/core/internationalization/index.tsx b/public/app/core/internationalization/index.tsx index 16493d8a0c9..6cf9aa881cc 100644 --- a/public/app/core/internationalization/index.tsx +++ b/public/app/core/internationalization/index.tsx @@ -1,50 +1,59 @@ -import i18n, { BackendModule } from 'i18next'; +import i18n, { BackendModule, InitOptions } from 'i18next'; +import LanguageDetector, { DetectorOptions } from 'i18next-browser-languagedetector'; import React from 'react'; import { Trans as I18NextTrans, initReactI18next } from 'react-i18next'; // eslint-disable-line no-restricted-imports -import { DEFAULT_LANGUAGE, LANGUAGES, VALID_LANGUAGES } from './constants'; +import { LANGUAGES, VALID_LANGUAGES } from './constants'; + +const getLanguagePartFromCode = (code: string) => code.split('-')[0].toLowerCase(); const loadTranslations: BackendModule = { type: 'backend', init() {}, async read(language, namespace, callback) { - const localeDef = LANGUAGES.find((v) => v.code === language); - + let localeDef = LANGUAGES.find((v) => v.code === language); + if (!localeDef) { + localeDef = LANGUAGES.find((v) => getLanguagePartFromCode(v.code) === getLanguagePartFromCode(language)); + } if (!localeDef) { return callback(new Error('No message loader available for ' + language), null); } - const messages = await localeDef.loader(); callback(null, messages); }, }; export function initializeI18n(language: string) { - const validLocale = VALID_LANGUAGES.includes(language) ? language : DEFAULT_LANGUAGE; - // This is a placeholder so we can put a 'comment' in the message json files. // Starts with an underscore so it's sorted to the top of the file. Even though it is in a comment the following line is still extracted // t('_comment', 'This file is the source of truth for English strings. Edit this to change plurals and other phrases for the UI.'); - return i18n + const options: InitOptions = { + // We don't bundle any translations, we load them async + partialBundledLanguages: true, + resources: {}, + + // If translations are empty strings (no translation), fall back to the default value in source code + returnEmptyString: false, + + pluralSeparator: '__', + }; + let init = i18n; + if (language === 'detect') { + init = init.use(LanguageDetector); + const detection: DetectorOptions = { order: ['navigator'], caches: [] }; + options.detection = detection; + } else { + options.lng = VALID_LANGUAGES.includes(language) ? language : undefined; + } + return init .use(loadTranslations) .use(initReactI18next) // passes i18n down to react-i18next - .init({ - lng: validLocale, - - // We don't bundle any translations, we load them async - partialBundledLanguages: true, - resources: {}, - - // If translations are empty strings (no translation), fall back to the default value in source code - returnEmptyString: false, - - pluralSeparator: '__', - }); + .init(options); } export function changeLanguage(locale: string) { - const validLocale = VALID_LANGUAGES.includes(locale) ? locale : DEFAULT_LANGUAGE; + const validLocale = VALID_LANGUAGES.includes(locale) ? locale : undefined; return i18n.changeLanguage(validLocale); } @@ -63,8 +72,6 @@ export const i18nDate = (value: number | Date | string, format: Intl.DateTimeFor if (typeof value === 'string') { return i18nDate(new Date(value), format); } - const locale = i18n.options.lng ?? DEFAULT_LANGUAGE; - - const dateFormatter = new Intl.DateTimeFormat(locale, format); + const dateFormatter = new Intl.DateTimeFormat(i18n.language, format); return dateFormatter.format(value); }; diff --git a/yarn.lock b/yarn.lock index de852b5e7d9..73fab7e968c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2219,7 +2219,7 @@ __metadata: languageName: node linkType: hard -"@babel/runtime@npm:7.22.3, @babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.1, @babel/runtime@npm:^7.11.1, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.0, @babel/runtime@npm:^7.12.1, @babel/runtime@npm:^7.12.13, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.13.10, @babel/runtime@npm:^7.14.0, @babel/runtime@npm:^7.14.5, @babel/runtime@npm:^7.15.4, @babel/runtime@npm:^7.17.2, @babel/runtime@npm:^7.17.8, @babel/runtime@npm:^7.18.0, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.20.0, @babel/runtime@npm:^7.20.7, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.7.2, @babel/runtime@npm:^7.7.6, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2": +"@babel/runtime@npm:7.22.3, @babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.1, @babel/runtime@npm:^7.11.1, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.0, @babel/runtime@npm:^7.12.1, @babel/runtime@npm:^7.12.13, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.13.10, @babel/runtime@npm:^7.14.0, @babel/runtime@npm:^7.14.5, @babel/runtime@npm:^7.15.4, @babel/runtime@npm:^7.17.2, @babel/runtime@npm:^7.17.8, @babel/runtime@npm:^7.18.0, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.19.4, @babel/runtime@npm:^7.20.0, @babel/runtime@npm:^7.20.7, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.7.2, @babel/runtime@npm:^7.7.6, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2": version: 7.22.3 resolution: "@babel/runtime@npm:7.22.3" dependencies: @@ -4184,6 +4184,7 @@ __metadata: expose-loader: 4.1.0 hoist-non-react-statics: 3.3.2 i18next: ^22.0.0 + i18next-browser-languagedetector: ^7.0.2 immutable: 4.3.0 is-hotkey: 0.2.0 jquery: 3.7.0 @@ -19410,6 +19411,7 @@ __metadata: http-server: 14.1.1 husky: 8.0.3 i18next: ^22.0.0 + i18next-browser-languagedetector: ^7.0.2 i18next-parser: 6.6.0 immer: 10.0.2 immutable: 4.3.0 @@ -20272,6 +20274,15 @@ __metadata: languageName: node linkType: hard +"i18next-browser-languagedetector@npm:^7.0.2": + version: 7.0.2 + resolution: "i18next-browser-languagedetector@npm:7.0.2" + dependencies: + "@babel/runtime": ^7.19.4 + checksum: ea6c5254308965ff9fe9870c16b546b67d065cc00bd3af961f1414ba73fbe323a7d1b76fe7524b1581307f7849fa6d04c36336693818a23d3690ebefc60d9071 + languageName: node + linkType: hard + "i18next-parser@npm:6.6.0": version: 6.6.0 resolution: "i18next-parser@npm:6.6.0" From 1caf3298ea2382c1391177cf1101c8f4d00ee73d Mon Sep 17 00:00:00 2001 From: Ashley Harrison Date: Fri, 14 Jul 2023 11:58:43 +0100 Subject: [PATCH 36/42] Nested folders: Empty state for nested folder picker (#71464) * add empty state to nestedfolderpicker, add translations * run i18n:extract * rename i18n key --------- Co-authored-by: joshhunt --- .../NestedFolderPicker/NestedFolderList.tsx | 32 +++++++++++++------ .../NestedFolderPicker.test.tsx | 2 +- .../NestedFolderPicker/NestedFolderPicker.tsx | 22 ++++++++----- public/locales/de-DE/grafana.json | 7 ++++ public/locales/en-US/grafana.json | 7 ++++ public/locales/es-ES/grafana.json | 7 ++++ public/locales/fr-FR/grafana.json | 7 ++++ public/locales/pseudo-LOCALE/grafana.json | 7 ++++ public/locales/zh-Hans/grafana.json | 7 ++++ 9 files changed, 79 insertions(+), 19 deletions(-) diff --git a/public/app/core/components/NestedFolderPicker/NestedFolderList.tsx b/public/app/core/components/NestedFolderPicker/NestedFolderList.tsx index 8e83126abfc..9617668e356 100644 --- a/public/app/core/components/NestedFolderPicker/NestedFolderList.tsx +++ b/public/app/core/components/NestedFolderPicker/NestedFolderList.tsx @@ -6,6 +6,7 @@ import { GrafanaTheme2 } from '@grafana/data'; import { IconButton, useStyles2 } from '@grafana/ui'; import { getSvgSize } from '@grafana/ui/src/components/Icon/utils'; import { Text } from '@grafana/ui/src/components/Text/Text'; +import { Trans } from 'app/core/internationalization'; import { Indent } from 'app/features/browse-dashboards/components/Indent'; import { DashboardsTreeItem } from 'app/features/browse-dashboards/types'; import { DashboardViewItem } from 'app/features/search/types'; @@ -39,15 +40,21 @@ export function NestedFolderList({ return (
- - {Row} - + {items.length > 0 ? ( + + {Row} + + ) : ( +
+ No folders found +
+ )}
); } @@ -132,7 +139,6 @@ function Row({ index, style: virtualStyles, data }: RowProps) { )}