From b0c336c692e9ebdbacd22d62ed334cd4ec3ecf7d Mon Sep 17 00:00:00 2001 From: David Allen Date: Mon, 15 Apr 2024 05:40:32 -0400 Subject: [PATCH 001/147] Docs: add data source type play link; cleanup (#86077) --- docs/sources/datasources/_index.md | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/docs/sources/datasources/_index.md b/docs/sources/datasources/_index.md index b738aa80a0c..8179d4388c2 100644 --- a/docs/sources/datasources/_index.md +++ b/docs/sources/datasources/_index.md @@ -76,14 +76,24 @@ For general information about querying in Grafana, and common options and user i Grafana includes three special data sources: -- **Grafana:** A built-in data source that generates random walk data and can poll the [Testdata]({{< relref "./testdata/" >}}) data source. Additionally, it can list files and get other data from a Grafana installation. This can be helpful for testing visualizations and running experiments. -- **Mixed:** An abstraction that lets you query multiple data sources in the same panel. - When you select Mixed, you can then select a different data source for each new query that you add. - - The first query uses the data source that was selected before you selected **Mixed**. - - You can't change an existing query to use the **Mixed** data source. - - Grafana Play example: [Mixed data sources](https://play.grafana.org/d/000000100/mixed-datasources?orgId=1) -- **Dashboard:** A data source that uses the result set from another panel in the same dashboard. The dashboard data source can use data either directly from the selected panel or from annotations attached to the selected panel. - - Grafana Play example: [Panel as Data source](https://play.grafana.org/d/ede8zps8ndb0gc/panel-as-data-source?orgId=1) +### Grafana + +A built-in data source that generates random walk data and can poll the [Testdata]({{< relref "./testdata/" >}}) data source. Additionally, it can list files and get other data from a Grafana installation. This can be helpful for testing visualizations and running experiments. + +### Mixed + +An abstraction that lets you query multiple data sources in the same panel. When you select Mixed, you can then select a different data source for each new query that you add. + +- The first query uses the data source that was selected before you selected **Mixed**. +- You can't change an existing query to use the **Mixed** data source. + +{{< docs/play title="Mixed Datasources Example" url="https://play.grafana.org/d/000000100/" >}} + +### Dashboard + +A data source that uses the result set from another panel in the same dashboard. The dashboard data source can use data either directly from the selected panel or from annotations attached to the selected panel. + +{{< docs/play title="Panel as a Data Source" url="https://play.grafana.org/d/ede8zps8ndb0gc/" >}} ## Built-in core data sources From fc6cad797ddcad854784ddc9792412f1a042fc9f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 15 Apr 2024 08:53:16 +0000 Subject: [PATCH 002/147] Update dependency @testing-library/react to v15.0.2 --- package.json | 2 +- packages/grafana-flamegraph/package.json | 2 +- .../grafana-o11y-ds-frontend/package.json | 2 +- packages/grafana-prometheus/package.json | 2 +- packages/grafana-runtime/package.json | 2 +- packages/grafana-sql/package.json | 2 +- packages/grafana-ui/package.json | 2 +- .../datasource/azuremonitor/package.json | 2 +- .../datasource/cloud-monitoring/package.json | 2 +- .../grafana-pyroscope-datasource/package.json | 2 +- .../grafana-testdata-datasource/package.json | 2 +- .../plugins/datasource/jaeger/package.json | 2 +- .../app/plugins/datasource/parca/package.json | 2 +- .../app/plugins/datasource/tempo/package.json | 2 +- .../plugins/datasource/zipkin/package.json | 2 +- yarn.lock | 38 +++++++++---------- 16 files changed, 34 insertions(+), 34 deletions(-) diff --git a/package.json b/package.json index 148e5422ad9..6f036ab65e3 100644 --- a/package.json +++ b/package.json @@ -92,7 +92,7 @@ "@swc/helpers": "0.5.9", "@testing-library/dom": "10.0.0", "@testing-library/jest-dom": "6.4.2", - "@testing-library/react": "15.0.1", + "@testing-library/react": "15.0.2", "@testing-library/user-event": "14.5.2", "@types/angular": "1.8.9", "@types/angular-route": "1.7.6", diff --git a/packages/grafana-flamegraph/package.json b/packages/grafana-flamegraph/package.json index 8d6860288e3..0cabbb0c100 100644 --- a/packages/grafana-flamegraph/package.json +++ b/packages/grafana-flamegraph/package.json @@ -62,7 +62,7 @@ "@grafana/tsconfig": "^1.3.0-rc1", "@rollup/plugin-node-resolve": "15.2.3", "@testing-library/jest-dom": "^6.1.2", - "@testing-library/react": "15.0.1", + "@testing-library/react": "15.0.2", "@testing-library/user-event": "14.5.2", "@types/d3": "^7", "@types/jest": "^29.5.4", diff --git a/packages/grafana-o11y-ds-frontend/package.json b/packages/grafana-o11y-ds-frontend/package.json index cc8d2a5ed92..af93e723328 100644 --- a/packages/grafana-o11y-ds-frontend/package.json +++ b/packages/grafana-o11y-ds-frontend/package.json @@ -31,7 +31,7 @@ "devDependencies": { "@grafana/tsconfig": "^1.3.0-rc1", "@testing-library/jest-dom": "^6.1.2", - "@testing-library/react": "15.0.1", + "@testing-library/react": "15.0.2", "@testing-library/user-event": "14.5.2", "@types/jest": "^29.5.4", "@types/react": "18.2.77", diff --git a/packages/grafana-prometheus/package.json b/packages/grafana-prometheus/package.json index d018aa48700..2b46078586d 100644 --- a/packages/grafana-prometheus/package.json +++ b/packages/grafana-prometheus/package.json @@ -84,7 +84,7 @@ "@swc/helpers": "0.5.9", "@testing-library/dom": "10.0.0", "@testing-library/jest-dom": "6.4.2", - "@testing-library/react": "15.0.1", + "@testing-library/react": "15.0.2", "@testing-library/user-event": "14.5.2", "@types/d3": "7.4.3", "@types/debounce-promise": "3.1.9", diff --git a/packages/grafana-runtime/package.json b/packages/grafana-runtime/package.json index f52d0a5f5bf..31294bed465 100644 --- a/packages/grafana-runtime/package.json +++ b/packages/grafana-runtime/package.json @@ -52,7 +52,7 @@ "@rollup/plugin-node-resolve": "15.2.3", "@rollup/plugin-terser": "0.4.4", "@testing-library/dom": "10.0.0", - "@testing-library/react": "15.0.1", + "@testing-library/react": "15.0.2", "@testing-library/user-event": "14.5.2", "@types/angular": "1.8.9", "@types/history": "4.7.11", diff --git a/packages/grafana-sql/package.json b/packages/grafana-sql/package.json index 7484862733f..d7db9d20084 100644 --- a/packages/grafana-sql/package.json +++ b/packages/grafana-sql/package.json @@ -35,7 +35,7 @@ "devDependencies": { "@grafana/tsconfig": "^1.3.0-rc1", "@testing-library/jest-dom": "^6.1.2", - "@testing-library/react": "15.0.1", + "@testing-library/react": "15.0.2", "@testing-library/react-hooks": "^8.0.1", "@testing-library/user-event": "14.5.2", "@types/jest": "^29.5.4", diff --git a/packages/grafana-ui/package.json b/packages/grafana-ui/package.json index 882d983f289..ee307108fed 100644 --- a/packages/grafana-ui/package.json +++ b/packages/grafana-ui/package.json @@ -129,7 +129,7 @@ "@storybook/theming": "7.4.5", "@testing-library/dom": "10.0.0", "@testing-library/jest-dom": "6.4.2", - "@testing-library/react": "15.0.1", + "@testing-library/react": "15.0.2", "@testing-library/user-event": "14.5.2", "@types/common-tags": "^1.8.0", "@types/d3": "7.4.3", diff --git a/public/app/plugins/datasource/azuremonitor/package.json b/public/app/plugins/datasource/azuremonitor/package.json index 1e5b0ad72e9..9cf5d6e1319 100644 --- a/public/app/plugins/datasource/azuremonitor/package.json +++ b/public/app/plugins/datasource/azuremonitor/package.json @@ -25,7 +25,7 @@ "devDependencies": { "@grafana/e2e-selectors": "11.1.0-pre", "@grafana/plugin-configs": "11.1.0-pre", - "@testing-library/react": "15.0.1", + "@testing-library/react": "15.0.2", "@testing-library/user-event": "14.5.2", "@types/jest": "29.5.12", "@types/lodash": "4.17.0", diff --git a/public/app/plugins/datasource/cloud-monitoring/package.json b/public/app/plugins/datasource/cloud-monitoring/package.json index b33961f36fe..6763c103839 100644 --- a/public/app/plugins/datasource/cloud-monitoring/package.json +++ b/public/app/plugins/datasource/cloud-monitoring/package.json @@ -26,7 +26,7 @@ "devDependencies": { "@grafana/e2e-selectors": "11.1.0-pre", "@grafana/plugin-configs": "11.1.0-pre", - "@testing-library/react": "15.0.1", + "@testing-library/react": "15.0.2", "@testing-library/user-event": "14.5.2", "@types/debounce-promise": "3.1.9", "@types/jest": "29.5.12", diff --git a/public/app/plugins/datasource/grafana-pyroscope-datasource/package.json b/public/app/plugins/datasource/grafana-pyroscope-datasource/package.json index 6d5d899c572..c475aacddef 100644 --- a/public/app/plugins/datasource/grafana-pyroscope-datasource/package.json +++ b/public/app/plugins/datasource/grafana-pyroscope-datasource/package.json @@ -22,7 +22,7 @@ "devDependencies": { "@grafana/plugin-configs": "11.1.0-pre", "@testing-library/jest-dom": "6.4.2", - "@testing-library/react": "15.0.1", + "@testing-library/react": "15.0.2", "@testing-library/user-event": "14.5.2", "@types/jest": "29.5.12", "@types/lodash": "4.17.0", diff --git a/public/app/plugins/datasource/grafana-testdata-datasource/package.json b/public/app/plugins/datasource/grafana-testdata-datasource/package.json index bf25c0318a2..ed12f2ef969 100644 --- a/public/app/plugins/datasource/grafana-testdata-datasource/package.json +++ b/public/app/plugins/datasource/grafana-testdata-datasource/package.json @@ -22,7 +22,7 @@ "devDependencies": { "@grafana/e2e-selectors": "11.1.0-pre", "@grafana/plugin-configs": "11.1.0-pre", - "@testing-library/react": "15.0.1", + "@testing-library/react": "15.0.2", "@testing-library/user-event": "14.5.2", "@types/d3-random": "^3.0.2", "@types/jest": "29.5.12", diff --git a/public/app/plugins/datasource/jaeger/package.json b/public/app/plugins/datasource/jaeger/package.json index 320208dda65..e7e41afe73f 100644 --- a/public/app/plugins/datasource/jaeger/package.json +++ b/public/app/plugins/datasource/jaeger/package.json @@ -21,7 +21,7 @@ "devDependencies": { "@grafana/plugin-configs": "workspace:*", "@testing-library/jest-dom": "6.4.2", - "@testing-library/react": "15.0.1", + "@testing-library/react": "15.0.2", "@testing-library/user-event": "14.5.2", "@types/jest": "29.5.12", "@types/lodash": "4.17.0", diff --git a/public/app/plugins/datasource/parca/package.json b/public/app/plugins/datasource/parca/package.json index b56c45d702c..5a5191ccf2b 100644 --- a/public/app/plugins/datasource/parca/package.json +++ b/public/app/plugins/datasource/parca/package.json @@ -18,7 +18,7 @@ }, "devDependencies": { "@grafana/plugin-configs": "11.1.0-pre", - "@testing-library/react": "15.0.1", + "@testing-library/react": "15.0.2", "@testing-library/user-event": "14.5.2", "@types/lodash": "4.17.0", "@types/react": "18.2.77", diff --git a/public/app/plugins/datasource/tempo/package.json b/public/app/plugins/datasource/tempo/package.json index 69c59a39e66..9938c4d182c 100644 --- a/public/app/plugins/datasource/tempo/package.json +++ b/public/app/plugins/datasource/tempo/package.json @@ -40,7 +40,7 @@ "devDependencies": { "@grafana/plugin-configs": "11.1.0-pre", "@testing-library/jest-dom": "6.4.2", - "@testing-library/react": "15.0.1", + "@testing-library/react": "15.0.2", "@testing-library/user-event": "14.5.2", "@types/jest": "29.5.12", "@types/lodash": "4.17.0", diff --git a/public/app/plugins/datasource/zipkin/package.json b/public/app/plugins/datasource/zipkin/package.json index 5baa6e36375..736c7f4b87a 100644 --- a/public/app/plugins/datasource/zipkin/package.json +++ b/public/app/plugins/datasource/zipkin/package.json @@ -19,7 +19,7 @@ "devDependencies": { "@grafana/plugin-configs": "workspace:*", "@testing-library/jest-dom": "6.4.2", - "@testing-library/react": "15.0.1", + "@testing-library/react": "15.0.2", "@types/jest": "29.5.12", "@types/lodash": "4.17.0", "@types/react": "18.2.77", diff --git a/yarn.lock b/yarn.lock index 9efc385f298..19fa488fc7e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3311,7 +3311,7 @@ __metadata: "@grafana/schema": "npm:11.1.0-pre" "@grafana/ui": "npm:11.1.0-pre" "@kusto/monaco-kusto": "npm:^10.0.0" - "@testing-library/react": "npm:15.0.1" + "@testing-library/react": "npm:15.0.2" "@testing-library/user-event": "npm:14.5.2" "@types/jest": "npm:29.5.12" "@types/lodash": "npm:4.17.0" @@ -3349,7 +3349,7 @@ __metadata: "@grafana/schema": "npm:11.1.0-pre" "@grafana/ui": "npm:11.1.0-pre" "@testing-library/jest-dom": "npm:6.4.2" - "@testing-library/react": "npm:15.0.1" + "@testing-library/react": "npm:15.0.2" "@testing-library/user-event": "npm:14.5.2" "@types/jest": "npm:29.5.12" "@types/lodash": "npm:4.17.0" @@ -3389,7 +3389,7 @@ __metadata: "@grafana/runtime": "npm:11.1.0-pre" "@grafana/schema": "npm:11.1.0-pre" "@grafana/ui": "npm:11.1.0-pre" - "@testing-library/react": "npm:15.0.1" + "@testing-library/react": "npm:15.0.2" "@testing-library/user-event": "npm:14.5.2" "@types/d3-random": "npm:^3.0.2" "@types/jest": "npm:29.5.12" @@ -3425,7 +3425,7 @@ __metadata: "@grafana/runtime": "workspace:*" "@grafana/ui": "workspace:*" "@testing-library/jest-dom": "npm:6.4.2" - "@testing-library/react": "npm:15.0.1" + "@testing-library/react": "npm:15.0.2" "@testing-library/user-event": "npm:14.5.2" "@types/jest": "npm:29.5.12" "@types/lodash": "npm:4.17.0" @@ -3456,7 +3456,7 @@ __metadata: "@grafana/runtime": "npm:11.1.0-pre" "@grafana/schema": "npm:11.1.0-pre" "@grafana/ui": "npm:11.1.0-pre" - "@testing-library/react": "npm:15.0.1" + "@testing-library/react": "npm:15.0.2" "@testing-library/user-event": "npm:14.5.2" "@types/lodash": "npm:4.17.0" "@types/react": "npm:18.2.77" @@ -3486,7 +3486,7 @@ __metadata: "@grafana/runtime": "npm:11.1.0-pre" "@grafana/schema": "npm:11.1.0-pre" "@grafana/ui": "npm:11.1.0-pre" - "@testing-library/react": "npm:15.0.1" + "@testing-library/react": "npm:15.0.2" "@testing-library/user-event": "npm:14.5.2" "@types/debounce-promise": "npm:3.1.9" "@types/jest": "npm:29.5.12" @@ -3539,7 +3539,7 @@ __metadata: "@opentelemetry/exporter-collector": "npm:0.25.0" "@opentelemetry/semantic-conventions": "npm:1.23.0" "@testing-library/jest-dom": "npm:6.4.2" - "@testing-library/react": "npm:15.0.1" + "@testing-library/react": "npm:15.0.2" "@testing-library/user-event": "npm:14.5.2" "@types/jest": "npm:29.5.12" "@types/lodash": "npm:4.17.0" @@ -3587,7 +3587,7 @@ __metadata: "@grafana/runtime": "workspace:*" "@grafana/ui": "workspace:*" "@testing-library/jest-dom": "npm:6.4.2" - "@testing-library/react": "npm:15.0.1" + "@testing-library/react": "npm:15.0.2" "@types/jest": "npm:29.5.12" "@types/lodash": "npm:4.17.0" "@types/react": "npm:18.2.77" @@ -3863,7 +3863,7 @@ __metadata: "@leeoniya/ufuzzy": "npm:1.0.14" "@rollup/plugin-node-resolve": "npm:15.2.3" "@testing-library/jest-dom": "npm:^6.1.2" - "@testing-library/react": "npm:15.0.1" + "@testing-library/react": "npm:15.0.2" "@testing-library/user-event": "npm:14.5.2" "@types/d3": "npm:^7" "@types/jest": "npm:^29.5.4" @@ -3946,7 +3946,7 @@ __metadata: "@grafana/tsconfig": "npm:^1.3.0-rc1" "@grafana/ui": "npm:11.1.0-pre" "@testing-library/jest-dom": "npm:^6.1.2" - "@testing-library/react": "npm:15.0.1" + "@testing-library/react": "npm:15.0.2" "@testing-library/user-event": "npm:14.5.2" "@types/jest": "npm:^29.5.4" "@types/react": "npm:18.2.77" @@ -4022,7 +4022,7 @@ __metadata: "@swc/helpers": "npm:0.5.9" "@testing-library/dom": "npm:10.0.0" "@testing-library/jest-dom": "npm:6.4.2" - "@testing-library/react": "npm:15.0.1" + "@testing-library/react": "npm:15.0.2" "@testing-library/user-event": "npm:14.5.2" "@types/d3": "npm:7.4.3" "@types/debounce-promise": "npm:3.1.9" @@ -4121,7 +4121,7 @@ __metadata: "@rollup/plugin-node-resolve": "npm:15.2.3" "@rollup/plugin-terser": "npm:0.4.4" "@testing-library/dom": "npm:10.0.0" - "@testing-library/react": "npm:15.0.1" + "@testing-library/react": "npm:15.0.2" "@testing-library/user-event": "npm:14.5.2" "@types/angular": "npm:1.8.9" "@types/history": "npm:4.7.11" @@ -4232,7 +4232,7 @@ __metadata: "@grafana/ui": "npm:11.1.0-pre" "@react-awesome-query-builder/ui": "npm:6.4.2" "@testing-library/jest-dom": "npm:^6.1.2" - "@testing-library/react": "npm:15.0.1" + "@testing-library/react": "npm:15.0.2" "@testing-library/react-hooks": "npm:^8.0.1" "@testing-library/user-event": "npm:14.5.2" "@types/jest": "npm:^29.5.4" @@ -4312,7 +4312,7 @@ __metadata: "@storybook/theming": "npm:7.4.5" "@testing-library/dom": "npm:10.0.0" "@testing-library/jest-dom": "npm:6.4.2" - "@testing-library/react": "npm:15.0.1" + "@testing-library/react": "npm:15.0.2" "@testing-library/user-event": "npm:14.5.2" "@types/common-tags": "npm:^1.8.0" "@types/d3": "npm:7.4.3" @@ -8991,9 +8991,9 @@ __metadata: languageName: node linkType: hard -"@testing-library/react@npm:15.0.1": - version: 15.0.1 - resolution: "@testing-library/react@npm:15.0.1" +"@testing-library/react@npm:15.0.2": + version: 15.0.2 + resolution: "@testing-library/react@npm:15.0.2" dependencies: "@babel/runtime": "npm:^7.12.5" "@testing-library/dom": "npm:^10.0.0" @@ -9001,7 +9001,7 @@ __metadata: peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 - checksum: 10/3f3789c01b65801fce00c5f94b21dba1f59129e9937d2632ec5c3cd68acd0da1f66a7b44199b7b700d17148c9ec9dcd909cc8c8855a604b7ce757ba29aa3796b + checksum: 10/6327e465733cec9455792acee7781d1437f7494ddbb976ca72e07446daaf8e7fe5dadd27d05690f09e8d4adce651984ed9aeca4ede9b87bf69b172f450085ede languageName: node linkType: hard @@ -18660,7 +18660,7 @@ __metadata: "@swc/helpers": "npm:0.5.9" "@testing-library/dom": "npm:10.0.0" "@testing-library/jest-dom": "npm:6.4.2" - "@testing-library/react": "npm:15.0.1" + "@testing-library/react": "npm:15.0.2" "@testing-library/react-hooks": "npm:^8.0.1" "@testing-library/user-event": "npm:14.5.2" "@types/angular": "npm:1.8.9" From d379e319d69c5938d22ea22e6006520f303df1f9 Mon Sep 17 00:00:00 2001 From: Bogdan Matei Date: Mon, 15 Apr 2024 13:43:42 +0300 Subject: [PATCH 003/147] Implement API server client in Scopes (#85266) --- .github/CODEOWNERS | 1 - packages/grafana-data/src/types/scopes.ts | 22 ++-- packages/grafana-prometheus/src/dataquery.ts | 4 +- packages/grafana-prometheus/src/datasource.ts | 2 +- public/app/features/apiserver/server.ts | 16 ++- public/app/features/apiserver/types.ts | 26 +++-- .../scene/ScopesDashboardsScene.tsx | 33 ++++-- .../scene/ScopesFiltersScene.tsx | 33 +++--- .../scene/ScopesScene.test.tsx | 104 ++++++++++-------- public/app/features/scopes/server.ts | 32 ------ .../datasource/prometheus/dataquery.ts | 4 +- .../datasource/prometheus/datasource.ts | 2 +- 12 files changed, 150 insertions(+), 129 deletions(-) delete mode 100644 public/app/features/scopes/server.ts diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index c3a77ff27cd..98d6e96c183 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -403,7 +403,6 @@ playwright.config.ts @grafana/plugins-platform-frontend /public/app/features/dashboard/ @grafana/dashboards-squad /public/app/features/dashboard/components/TransformationsEditor/ @grafana/dataviz-squad /public/app/features/dashboard-scene/ @grafana/dashboards-squad -/public/app/features/scopes/ @grafana/dashboards-squad /public/app/features/datasources/ @grafana/plugins-platform-frontend @mikkancso /public/app/features/dimensions/ @grafana/dataviz-squad /public/app/features/dataframe-import/ @grafana/dataviz-squad diff --git a/packages/grafana-data/src/types/scopes.ts b/packages/grafana-data/src/types/scopes.ts index 09dd972f98c..f0128c59cb7 100644 --- a/packages/grafana-data/src/types/scopes.ts +++ b/packages/grafana-data/src/types/scopes.ts @@ -1,20 +1,26 @@ -export interface ScopeDashboard { - uid: string; - title: string; - url: string; +export interface ScopeDashboardBindingSpec { + dashboard: string; + scope: string; } -export interface ScopeFilter { +export interface ScopeSpecFilter { key: string; value: string; operator: string; } -export interface Scope { - uid: string; +export interface ScopeSpec { title: string; type: string; description: string; category: string; - filters: ScopeFilter[]; + filters: ScopeSpecFilter[]; +} + +// TODO: Use Resource from apiserver when we export the types +export interface Scope { + metadata: { + name: string; + }; + spec: ScopeSpec; } diff --git a/packages/grafana-prometheus/src/dataquery.ts b/packages/grafana-prometheus/src/dataquery.ts index 545a32345b7..999a969c99e 100644 --- a/packages/grafana-prometheus/src/dataquery.ts +++ b/packages/grafana-prometheus/src/dataquery.ts @@ -1,4 +1,4 @@ -import { Scope } from '@grafana/data'; +import { ScopeSpec } from '@grafana/data'; import * as common from '@grafana/schema'; export enum QueryEditorMode { @@ -42,5 +42,5 @@ export interface Prometheus extends common.DataQuery { * Returns a Range vector, comprised of a set of time series containing a range of data points over time for each time series */ range?: boolean; - scope?: Scope; + scope?: ScopeSpec; } diff --git a/packages/grafana-prometheus/src/datasource.ts b/packages/grafana-prometheus/src/datasource.ts index 6c9a0c81032..7a1d6731f33 100644 --- a/packages/grafana-prometheus/src/datasource.ts +++ b/packages/grafana-prometheus/src/datasource.ts @@ -369,7 +369,7 @@ export class PrometheusDatasource }; if (config.featureToggles.promQLScope) { - processedTarget.scope = request.scope; + processedTarget.scope = request.scope?.spec; } if (target.instant && target.range) { diff --git a/public/app/features/apiserver/server.ts b/public/app/features/apiserver/server.ts index 6b75ef795c8..77fba2a006e 100644 --- a/public/app/features/apiserver/server.ts +++ b/public/app/features/apiserver/server.ts @@ -2,6 +2,7 @@ import { config, getBackendSrv } from '@grafana/runtime'; import { ListOptions, + ListOptionsFieldSelector, ListOptionsLabelSelector, MetaStatus, Resource, @@ -33,9 +34,10 @@ export class ScopedResourceServer implements ResourceSer return getBackendSrv().get>(`${this.url}/${name}`); } - public async list(opts?: ListOptions | undefined): Promise> { + public async list(opts?: ListOptions | undefined): Promise> { const finalOpts = opts || {}; - finalOpts.labelSelector = this.parseLabelSelector(finalOpts?.labelSelector); + finalOpts.labelSelector = this.parseListOptionsSelector(finalOpts?.labelSelector); + finalOpts.fieldSelector = this.parseListOptionsSelector(finalOpts?.fieldSelector); return getBackendSrv().get>(this.url, opts); } @@ -48,12 +50,14 @@ export class ScopedResourceServer implements ResourceSer return getBackendSrv().delete(`${this.url}/${name}`); } - private parseLabelSelector(labelSelector: ListOptionsLabelSelector | undefined): string | undefined { - if (!Array.isArray(labelSelector)) { - return labelSelector; + private parseListOptionsSelector( + selector: ListOptionsLabelSelector | ListOptionsFieldSelector | undefined + ): string | undefined { + if (!Array.isArray(selector)) { + return selector; } - return labelSelector + return selector .map((label) => { const key = String(label.key); const operator = label.operator; diff --git a/public/app/features/apiserver/types.ts b/public/app/features/apiserver/types.ts index 41a8cbba08a..56fbbf5ac7b 100644 --- a/public/app/features/apiserver/types.ts +++ b/public/app/features/apiserver/types.ts @@ -78,32 +78,44 @@ export interface ResourceList extends TypeMeta { items: Array>; } -export type ListOptionsLabelSelector = +export type ListOptionsLabelSelector = | string | Array< | { - key: keyof T; + key: string; operator: '=' | '!='; value: string; } | { - key: keyof T; + key: string; operator: 'in' | 'notin'; value: string[]; } | { - key: keyof T; + key: string; operator: '' | '!'; } >; -export interface ListOptions { +export type ListOptionsFieldSelector = + | string + | Array<{ + key: string; + operator: '=' | '!='; + value: string; + }>; + +export interface ListOptions { // continue the list at a given batch continue?: string; // Query by labels // https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors - labelSelector?: ListOptionsLabelSelector; + labelSelector?: ListOptionsLabelSelector; + + // Query by fields + // https://kubernetes.io/docs/concepts/overview/working-with-objects/field-selectors/ + fieldSelector?: ListOptionsFieldSelector; // Limit the response count limit?: number; @@ -129,7 +141,7 @@ export interface MetaStatus { export interface ResourceServer { create(obj: ResourceForCreate): Promise; get(name: string): Promise>; - list(opts?: ListOptions): Promise>; + list(opts?: ListOptions): Promise>; update(obj: ResourceForCreate): Promise>; delete(name: string): Promise; } diff --git a/public/app/features/dashboard-scene/scene/ScopesDashboardsScene.tsx b/public/app/features/dashboard-scene/scene/ScopesDashboardsScene.tsx index b9c60e6fd9b..ef7a56a55c8 100644 --- a/public/app/features/dashboard-scene/scene/ScopesDashboardsScene.tsx +++ b/public/app/features/dashboard-scene/scene/ScopesDashboardsScene.tsx @@ -2,11 +2,19 @@ import { css } from '@emotion/css'; import React from 'react'; import { Link } from 'react-router-dom'; -import { AppEvents, GrafanaTheme2, ScopeDashboard } from '@grafana/data'; -import { config, getAppEvents, getBackendSrv, locationService } from '@grafana/runtime'; +import { AppEvents, GrafanaTheme2, ScopeDashboardBindingSpec } from '@grafana/data'; +import { getAppEvents, getBackendSrv, locationService } from '@grafana/runtime'; import { SceneComponentProps, SceneObjectBase, SceneObjectState } from '@grafana/scenes'; import { CustomScrollbar, Icon, Input, useStyles2 } from '@grafana/ui'; +import { ScopedResourceServer } from '../../apiserver/server'; + +export interface ScopeDashboard { + uid: string; + title: string; + url: string; +} + export interface ScopesDashboardsSceneState extends SceneObjectState { dashboards: ScopeDashboard[]; filteredDashboards: ScopeDashboard[]; @@ -17,8 +25,11 @@ export interface ScopesDashboardsSceneState extends SceneObjectState { export class ScopesDashboardsScene extends SceneObjectBase { static Component = ScopesDashboardsSceneRenderer; - private _url = - config.bootData.settings.listDashboardScopesEndpoint || '/apis/scope.grafana.app/v0alpha1/scopedashboards'; + private server = new ScopedResourceServer({ + group: 'scope.grafana.app', + version: 'v0alpha1', + resource: 'scopedashboardbindings', + }); constructor() { super({ @@ -57,11 +68,17 @@ export class ScopesDashboardsScene extends SceneObjectBase { try { - const response = await getBackendSrv().get<{ - items: Array<{ spec: { dashboards: null | string[]; scope: string } }>; - }>(this._url, { scope }); + const response = await this.server.list({ + fieldSelector: [ + { + key: 'spec.scope', + operator: '=', + value: scope, + }, + ], + }); - return response.items.find((item) => !!item.spec.dashboards && item.spec.scope === scope)?.spec.dashboards ?? []; + return response.items.map((item) => item.spec.dashboard).filter((dashboardUid) => !!dashboardUid) ?? []; } catch (err) { return []; } diff --git a/public/app/features/dashboard-scene/scene/ScopesFiltersScene.tsx b/public/app/features/dashboard-scene/scene/ScopesFiltersScene.tsx index 7f2dfe5e6ad..83ba74de49f 100644 --- a/public/app/features/dashboard-scene/scene/ScopesFiltersScene.tsx +++ b/public/app/features/dashboard-scene/scene/ScopesFiltersScene.tsx @@ -1,7 +1,7 @@ import React from 'react'; -import { AppEvents, Scope, SelectableValue } from '@grafana/data'; -import { config, getAppEvents, getBackendSrv } from '@grafana/runtime'; +import { AppEvents, Scope, ScopeSpec, SelectableValue } from '@grafana/data'; +import { getAppEvents } from '@grafana/runtime'; import { SceneComponentProps, SceneObjectBase, @@ -11,6 +11,8 @@ import { } from '@grafana/scenes'; import { Select } from '@grafana/ui'; +import { ScopedResourceServer } from '../../apiserver/server'; + export interface ScopesFiltersSceneState extends SceneObjectState { isLoading: boolean; pendingValue: string | undefined; @@ -23,7 +25,11 @@ export class ScopesFiltersScene extends SceneObjectBase protected _urlSync = new SceneObjectUrlSyncConfig(this, { keys: ['scope'] }); - private _url = config.bootData.settings.listScopesEndpoint || '/apis/scope.grafana.app/v0alpha1/scopes'; + private server = new ScopedResourceServer({ + group: 'scope.grafana.app', + version: 'v0alpha1', + resource: 'scopes', + }); constructor() { super({ @@ -44,7 +50,7 @@ export class ScopesFiltersScene extends SceneObjectBase } public getSelectedScope(): Scope | undefined { - return this.state.scopes.find((scope) => scope.uid === this.state.value); + return this.state.scopes.find((scope) => scope.metadata.name === this.state.value); } public setScope(newScope: string | undefined) { @@ -52,7 +58,7 @@ export class ScopesFiltersScene extends SceneObjectBase return this.setState({ pendingValue: newScope }); } - if (!this.state.scopes.find((scope) => scope.uid === newScope)) { + if (!this.state.scopes.find((scope) => scope.metadata.name === newScope)) { newScope = undefined; } @@ -63,16 +69,9 @@ export class ScopesFiltersScene extends SceneObjectBase this.setState({ isLoading: true }); try { - const response = await getBackendSrv().get<{ - items: Array<{ metadata: { uid: string }; spec: Omit }>; - }>(this._url); + const response = await this.server.list(); - this.setScopesAfterFetch( - response.items.map(({ metadata: { uid }, spec }) => ({ - uid, - ...spec, - })) - ); + this.setScopesAfterFetch(response.items); } catch (err) { getAppEvents().publish({ type: AppEvents.alertError.name, @@ -88,7 +87,7 @@ export class ScopesFiltersScene extends SceneObjectBase private setScopesAfterFetch(scopes: Scope[]) { let value = this.state.pendingValue ?? this.state.value; - if (!scopes.find((scope) => scope.uid === value)) { + if (!scopes.find((scope) => scope.metadata.name === value)) { value = undefined; } @@ -101,9 +100,9 @@ export function ScopesFiltersSceneRenderer({ model }: SceneComponentProps> = scopes.map(({ uid, title, category }) => ({ + const options: Array> = scopes.map(({ metadata: { name }, spec: { title, category } }) => ({ label: title, - value: uid, + value: name, description: category, })); diff --git a/public/app/features/dashboard-scene/scene/ScopesScene.test.tsx b/public/app/features/dashboard-scene/scene/ScopesScene.test.tsx index 0508c762ddc..72f9c2d9ee6 100644 --- a/public/app/features/dashboard-scene/scene/ScopesScene.test.tsx +++ b/public/app/features/dashboard-scene/scene/ScopesScene.test.tsx @@ -1,5 +1,6 @@ import { waitFor } from '@testing-library/react'; +import { Scope } from '@grafana/data'; import { config } from '@grafana/runtime'; import { behaviors, @@ -13,7 +14,7 @@ import { import { DashboardControls } from './DashboardControls'; import { DashboardScene } from './DashboardScene'; -import { ScopesDashboardsScene } from './ScopesDashboardsScene'; +import { ScopeDashboard, ScopesDashboardsScene } from './ScopesDashboardsScene'; import { ScopesFiltersScene } from './ScopesFiltersScene'; import { ScopesScene } from './ScopesScene'; @@ -35,35 +36,52 @@ const dashboardsMocks = { }, }; -const scopesMocks = { +const scopesMocks: Record< + string, + Scope & { + dashboards: ScopeDashboard[]; + } +> = { scope1: { - uid: 'scope1', - title: 'Scope 1', - type: 'Type 1', - description: 'Description 1', - category: 'Category 1', - filters: [ - { key: 'a-key', operator: '=', value: 'a-value' }, - { key: 'b-key', operator: '!=', value: 'b-value' }, - ], + metadata: { + name: 'scope1', + }, + spec: { + title: 'Scope 1', + type: 'Type 1', + description: 'Description 1', + category: 'Category 1', + filters: [ + { key: 'a-key', operator: '=', value: 'a-value' }, + { key: 'b-key', operator: '!=', value: 'b-value' }, + ], + }, dashboards: [dashboardsMocks.dashboard1, dashboardsMocks.dashboard2, dashboardsMocks.dashboard3], }, scope2: { - uid: 'scope2', - title: 'Scope 2', - type: 'Type 2', - description: 'Description 2', - category: 'Category 2', - filters: [{ key: 'c-key', operator: '!=', value: 'c-value' }], + metadata: { + name: 'scope2', + }, + spec: { + title: 'Scope 2', + type: 'Type 2', + description: 'Description 2', + category: 'Category 2', + filters: [{ key: 'c-key', operator: '!=', value: 'c-value' }], + }, dashboards: [dashboardsMocks.dashboard3], }, scope3: { - uid: 'scope3', - title: 'Scope 3', - type: 'Type 1', - description: 'Description 3', - category: 'Category 1', - filters: [{ key: 'd-key', operator: '=', value: 'd-value' }], + metadata: { + name: 'scope3', + }, + spec: { + title: 'Scope 3', + type: 'Type 1', + description: 'Description 3', + category: 'Category 1', + filters: [{ key: 'd-key', operator: '=', value: 'd-value' }], + }, dashboards: [dashboardsMocks.dashboard1, dashboardsMocks.dashboard2], }, }; @@ -73,29 +91,27 @@ jest.mock('@grafana/runtime', () => ({ ...jest.requireActual('@grafana/runtime'), getBackendSrv: () => ({ get: jest.fn().mockImplementation((url: string) => { - if (url === '/apis/scope.grafana.app/v0alpha1/scopes') { + if (url.startsWith('/apis/scope.grafana.app/v0alpha1/namespaces/default/scopes')) { return { - items: Object.values(scopesMocks).map((scope) => ({ - metadata: { uid: scope.uid }, - spec: { - title: scope.title, - type: scope.type, - description: scope.description, - category: scope.category, - filters: scope.filters, - }, - })), + items: Object.values(scopesMocks).map(({ dashboards: _dashboards, ...scope }) => scope), }; } - if (url === '/apis/scope.grafana.app/v0alpha1/scopedashboards') { + if (url.startsWith('/apis/scope.grafana.app/v0alpha1/namespaces/default/scopedashboardbindings')) { + const search = new URLSearchParams(url.split('?').pop() || ''); + const scope = search.get('fieldSelector')?.replace('spec.scope=', '') ?? ''; + + if (scope in scopesMocks) { + return { + items: scopesMocks[scope].dashboards.map(({ uid }) => ({ + scope, + dashboard: uid, + })), + }; + } + return { - items: Object.values(scopesMocks).map((scope) => ({ - spec: { - dashboards: scope.dashboards.map((dashboard) => dashboard.uid), - scope: scope.uid, - }, - })), + items: [], }; } @@ -179,14 +195,14 @@ describe('ScopesScene', () => { }); it('Fetches dashboards list', () => { - filtersScene.setScope(scopesMocks.scope1.uid); + filtersScene.setScope(scopesMocks.scope1.metadata.name); waitFor(() => { expect(fetchDashboardsSpy).toHaveBeenCalled(); expect(dashboardsScene.state.dashboards).toEqual(scopesMocks.scope1.dashboards); }); - filtersScene.setScope(scopesMocks.scope2.uid); + filtersScene.setScope(scopesMocks.scope2.metadata.name); waitFor(() => { expect(fetchDashboardsSpy).toHaveBeenCalled(); @@ -197,7 +213,7 @@ describe('ScopesScene', () => { it('Enriches data requests', () => { const { dashboards: _dashboards, ...scope1 } = scopesMocks.scope1; - filtersScene.setScope(scope1.uid); + filtersScene.setScope(scope1.metadata.name); const queryRunner = sceneGraph.findObject(dashboardScene, (o) => o.state.key === 'data-query-runner')!; diff --git a/public/app/features/scopes/server.ts b/public/app/features/scopes/server.ts deleted file mode 100644 index c9ee48b346e..00000000000 --- a/public/app/features/scopes/server.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { Scope, ScopeDashboard } from '@grafana/data'; - -import { ScopedResourceServer } from '../apiserver/server'; -import { ResourceServer } from '../apiserver/types'; - -// config.bootData.settings.listDashboardScopesEndpoint || '/apis/scope.grafana.app/v0alpha1/scopedashboards'; -// config.bootData.settings.listScopesEndpoint || '/apis/scope.grafana.app/v0alpha1/scopes'; - -interface ScopeServers { - scopes: ResourceServer; - dashboards: ResourceServer; -} - -let instance: ScopeServers | undefined = undefined; - -export function getScopeServers() { - if (!instance) { - instance = { - scopes: new ScopedResourceServer({ - group: 'scope.grafana.app', - version: 'v0alpha1', - resource: 'scopes', - }), - dashboards: new ScopedResourceServer({ - group: 'scope.grafana.app', - version: 'v0alpha1', - resource: 'scopedashboards', - }), - }; - } - return instance; -} diff --git a/public/app/plugins/datasource/prometheus/dataquery.ts b/public/app/plugins/datasource/prometheus/dataquery.ts index 54f6cd7bac9..ddb8973e949 100644 --- a/public/app/plugins/datasource/prometheus/dataquery.ts +++ b/public/app/plugins/datasource/prometheus/dataquery.ts @@ -1,4 +1,4 @@ -import { Scope } from '@grafana/data'; +import { ScopeSpec } from '@grafana/data'; import * as common from '@grafana/schema'; export enum QueryEditorMode { @@ -45,5 +45,5 @@ export interface Prometheus extends common.DataQuery { /** * A scope object that will be used by Prometheus */ - scope?: Scope; + scope?: ScopeSpec; } diff --git a/public/app/plugins/datasource/prometheus/datasource.ts b/public/app/plugins/datasource/prometheus/datasource.ts index 6c8b7a1a365..e2c898658e9 100644 --- a/public/app/plugins/datasource/prometheus/datasource.ts +++ b/public/app/plugins/datasource/prometheus/datasource.ts @@ -369,7 +369,7 @@ export class PrometheusDatasource }; if (config.featureToggles.promQLScope) { - processedTarget.scope = request.scope; + processedTarget.scope = request.scope?.spec; } if (target.instant && target.range) { From 6541be39d119a58c6844aac5355a72d46ab58702 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 15 Apr 2024 09:44:27 +0000 Subject: [PATCH 004/147] Update dependency @types/react to v18.2.78 --- package.json | 2 +- packages/grafana-data/package.json | 2 +- packages/grafana-flamegraph/package.json | 2 +- packages/grafana-icons/package.json | 2 +- .../grafana-o11y-ds-frontend/package.json | 2 +- packages/grafana-prometheus/package.json | 2 +- packages/grafana-runtime/package.json | 2 +- packages/grafana-sql/package.json | 2 +- packages/grafana-ui/package.json | 2 +- .../datasource/azuremonitor/package.json | 2 +- .../datasource/cloud-monitoring/package.json | 2 +- .../grafana-pyroscope-datasource/package.json | 2 +- .../grafana-testdata-datasource/package.json | 2 +- .../app/plugins/datasource/parca/package.json | 2 +- .../app/plugins/datasource/tempo/package.json | 2 +- .../plugins/datasource/zipkin/package.json | 2 +- yarn.lock | 40 +++++++++---------- 17 files changed, 36 insertions(+), 36 deletions(-) diff --git a/package.json b/package.json index 6f036ab65e3..6376f43b912 100644 --- a/package.json +++ b/package.json @@ -126,7 +126,7 @@ "@types/papaparse": "5.3.14", "@types/pluralize": "^0.0.33", "@types/prismjs": "1.26.3", - "@types/react": "18.2.77", + "@types/react": "18.2.78", "@types/react-beautiful-dnd": "13.1.8", "@types/react-dom": "18.2.25", "@types/react-grid-layout": "1.3.5", diff --git a/packages/grafana-data/package.json b/packages/grafana-data/package.json index a57b99e299d..352c1e52f7f 100644 --- a/packages/grafana-data/package.json +++ b/packages/grafana-data/package.json @@ -69,7 +69,7 @@ "@types/marked": "5.0.2", "@types/node": "20.12.7", "@types/papaparse": "5.3.14", - "@types/react": "18.2.77", + "@types/react": "18.2.78", "@types/react-dom": "18.2.25", "@types/tinycolor2": "1.4.6", "esbuild": "0.18.12", diff --git a/packages/grafana-flamegraph/package.json b/packages/grafana-flamegraph/package.json index 0cabbb0c100..93ba6b7cdd1 100644 --- a/packages/grafana-flamegraph/package.json +++ b/packages/grafana-flamegraph/package.json @@ -67,7 +67,7 @@ "@types/d3": "^7", "@types/jest": "^29.5.4", "@types/lodash": "4.17.0", - "@types/react": "18.2.77", + "@types/react": "18.2.78", "@types/react-virtualized-auto-sizer": "1.0.4", "@types/tinycolor2": "1.4.6", "babel-jest": "29.7.0", diff --git a/packages/grafana-icons/package.json b/packages/grafana-icons/package.json index 8159cf77d98..b63c9866b9b 100644 --- a/packages/grafana-icons/package.json +++ b/packages/grafana-icons/package.json @@ -43,7 +43,7 @@ "@svgr/plugin-prettier": "^8.1.0", "@svgr/plugin-svgo": "^8.1.0", "@types/node": "20.12.7", - "@types/react": "18.2.77", + "@types/react": "18.2.78", "@types/react-dom": "18.2.25", "esbuild": "0.18.12", "prettier": "3.2.5", diff --git a/packages/grafana-o11y-ds-frontend/package.json b/packages/grafana-o11y-ds-frontend/package.json index af93e723328..82bf0ac3aec 100644 --- a/packages/grafana-o11y-ds-frontend/package.json +++ b/packages/grafana-o11y-ds-frontend/package.json @@ -34,7 +34,7 @@ "@testing-library/react": "15.0.2", "@testing-library/user-event": "14.5.2", "@types/jest": "^29.5.4", - "@types/react": "18.2.77", + "@types/react": "18.2.78", "@types/systemjs": "6.13.5", "@types/testing-library__jest-dom": "5.14.9", "jest": "^29.6.4", diff --git a/packages/grafana-prometheus/package.json b/packages/grafana-prometheus/package.json index 2b46078586d..0a1e935636d 100644 --- a/packages/grafana-prometheus/package.json +++ b/packages/grafana-prometheus/package.json @@ -96,7 +96,7 @@ "@types/node": "20.12.7", "@types/pluralize": "^0.0.33", "@types/prismjs": "1.26.3", - "@types/react": "18.2.77", + "@types/react": "18.2.78", "@types/react-beautiful-dnd": "13.1.8", "@types/react-dom": "18.2.25", "@types/react-highlight-words": "0.16.7", diff --git a/packages/grafana-runtime/package.json b/packages/grafana-runtime/package.json index 31294bed465..9b341226b25 100644 --- a/packages/grafana-runtime/package.json +++ b/packages/grafana-runtime/package.json @@ -58,7 +58,7 @@ "@types/history": "4.7.11", "@types/jest": "29.5.12", "@types/lodash": "4.17.0", - "@types/react": "18.2.77", + "@types/react": "18.2.78", "@types/react-dom": "18.2.25", "@types/systemjs": "6.13.5", "esbuild": "0.18.12", diff --git a/packages/grafana-sql/package.json b/packages/grafana-sql/package.json index d7db9d20084..39b1bfebc0d 100644 --- a/packages/grafana-sql/package.json +++ b/packages/grafana-sql/package.json @@ -39,7 +39,7 @@ "@testing-library/react-hooks": "^8.0.1", "@testing-library/user-event": "14.5.2", "@types/jest": "^29.5.4", - "@types/react": "18.2.77", + "@types/react": "18.2.78", "@types/systemjs": "6.13.5", "@types/testing-library__jest-dom": "5.14.9", "jest": "^29.6.4", diff --git a/packages/grafana-ui/package.json b/packages/grafana-ui/package.json index ee307108fed..560a234d4ab 100644 --- a/packages/grafana-ui/package.json +++ b/packages/grafana-ui/package.json @@ -141,7 +141,7 @@ "@types/mock-raf": "1.0.6", "@types/node": "20.12.7", "@types/prismjs": "1.26.3", - "@types/react": "18.2.77", + "@types/react": "18.2.78", "@types/react-beautiful-dnd": "13.1.8", "@types/react-calendar": "3.9.0", "@types/react-color": "3.0.12", diff --git a/public/app/plugins/datasource/azuremonitor/package.json b/public/app/plugins/datasource/azuremonitor/package.json index 9cf5d6e1319..61b50baf355 100644 --- a/public/app/plugins/datasource/azuremonitor/package.json +++ b/public/app/plugins/datasource/azuremonitor/package.json @@ -31,7 +31,7 @@ "@types/lodash": "4.17.0", "@types/node": "20.12.7", "@types/prismjs": "1.26.3", - "@types/react": "18.2.77", + "@types/react": "18.2.78", "@types/testing-library__jest-dom": "5.14.9", "react-select-event": "5.5.1", "ts-node": "10.9.2", diff --git a/public/app/plugins/datasource/cloud-monitoring/package.json b/public/app/plugins/datasource/cloud-monitoring/package.json index 6763c103839..b8132351603 100644 --- a/public/app/plugins/datasource/cloud-monitoring/package.json +++ b/public/app/plugins/datasource/cloud-monitoring/package.json @@ -33,7 +33,7 @@ "@types/lodash": "4.17.0", "@types/node": "20.12.7", "@types/prismjs": "1.26.3", - "@types/react": "18.2.77", + "@types/react": "18.2.78", "@types/react-test-renderer": "18.0.7", "@types/testing-library__jest-dom": "5.14.9", "react-select-event": "5.5.1", diff --git a/public/app/plugins/datasource/grafana-pyroscope-datasource/package.json b/public/app/plugins/datasource/grafana-pyroscope-datasource/package.json index c475aacddef..4d75e761386 100644 --- a/public/app/plugins/datasource/grafana-pyroscope-datasource/package.json +++ b/public/app/plugins/datasource/grafana-pyroscope-datasource/package.json @@ -27,7 +27,7 @@ "@types/jest": "29.5.12", "@types/lodash": "4.17.0", "@types/prismjs": "1.26.3", - "@types/react": "18.2.77", + "@types/react": "18.2.78", "@types/react-dom": "18.2.25", "@types/testing-library__jest-dom": "5.14.9", "css-loader": "6.10.0", diff --git a/public/app/plugins/datasource/grafana-testdata-datasource/package.json b/public/app/plugins/datasource/grafana-testdata-datasource/package.json index ed12f2ef969..2f5f5f4559d 100644 --- a/public/app/plugins/datasource/grafana-testdata-datasource/package.json +++ b/public/app/plugins/datasource/grafana-testdata-datasource/package.json @@ -28,7 +28,7 @@ "@types/jest": "29.5.12", "@types/lodash": "4.17.0", "@types/node": "20.12.7", - "@types/react": "18.2.77", + "@types/react": "18.2.78", "@types/testing-library__jest-dom": "5.14.9", "@types/uuid": "9.0.8", "ts-node": "10.9.2", diff --git a/public/app/plugins/datasource/parca/package.json b/public/app/plugins/datasource/parca/package.json index 5a5191ccf2b..70d88f8b292 100644 --- a/public/app/plugins/datasource/parca/package.json +++ b/public/app/plugins/datasource/parca/package.json @@ -21,7 +21,7 @@ "@testing-library/react": "15.0.2", "@testing-library/user-event": "14.5.2", "@types/lodash": "4.17.0", - "@types/react": "18.2.77", + "@types/react": "18.2.78", "ts-node": "10.9.2", "webpack": "5.91.0" }, diff --git a/public/app/plugins/datasource/tempo/package.json b/public/app/plugins/datasource/tempo/package.json index 9938c4d182c..7c57120a065 100644 --- a/public/app/plugins/datasource/tempo/package.json +++ b/public/app/plugins/datasource/tempo/package.json @@ -46,7 +46,7 @@ "@types/lodash": "4.17.0", "@types/node": "20.12.7", "@types/prismjs": "1.26.3", - "@types/react": "18.2.77", + "@types/react": "18.2.78", "@types/react-dom": "18.2.25", "@types/semver": "7.5.8", "@types/uuid": "9.0.8", diff --git a/public/app/plugins/datasource/zipkin/package.json b/public/app/plugins/datasource/zipkin/package.json index 736c7f4b87a..1b63941215e 100644 --- a/public/app/plugins/datasource/zipkin/package.json +++ b/public/app/plugins/datasource/zipkin/package.json @@ -22,7 +22,7 @@ "@testing-library/react": "15.0.2", "@types/jest": "29.5.12", "@types/lodash": "4.17.0", - "@types/react": "18.2.77", + "@types/react": "18.2.78", "ts-node": "10.9.2", "webpack": "5.91.0" }, diff --git a/yarn.lock b/yarn.lock index 19fa488fc7e..769978d5bc8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3317,7 +3317,7 @@ __metadata: "@types/lodash": "npm:4.17.0" "@types/node": "npm:20.12.7" "@types/prismjs": "npm:1.26.3" - "@types/react": "npm:18.2.77" + "@types/react": "npm:18.2.78" "@types/testing-library__jest-dom": "npm:5.14.9" fast-deep-equal: "npm:^3.1.3" i18next: "npm:^23.0.0" @@ -3354,7 +3354,7 @@ __metadata: "@types/jest": "npm:29.5.12" "@types/lodash": "npm:4.17.0" "@types/prismjs": "npm:1.26.3" - "@types/react": "npm:18.2.77" + "@types/react": "npm:18.2.78" "@types/react-dom": "npm:18.2.25" "@types/testing-library__jest-dom": "npm:5.14.9" css-loader: "npm:6.10.0" @@ -3395,7 +3395,7 @@ __metadata: "@types/jest": "npm:29.5.12" "@types/lodash": "npm:4.17.0" "@types/node": "npm:20.12.7" - "@types/react": "npm:18.2.77" + "@types/react": "npm:18.2.78" "@types/testing-library__jest-dom": "npm:5.14.9" "@types/uuid": "npm:9.0.8" d3-random: "npm:^3.0.1" @@ -3459,7 +3459,7 @@ __metadata: "@testing-library/react": "npm:15.0.2" "@testing-library/user-event": "npm:14.5.2" "@types/lodash": "npm:4.17.0" - "@types/react": "npm:18.2.77" + "@types/react": "npm:18.2.78" lodash: "npm:4.17.21" monaco-editor: "npm:0.34.0" react: "npm:18.2.0" @@ -3493,7 +3493,7 @@ __metadata: "@types/lodash": "npm:4.17.0" "@types/node": "npm:20.12.7" "@types/prismjs": "npm:1.26.3" - "@types/react": "npm:18.2.77" + "@types/react": "npm:18.2.78" "@types/react-test-renderer": "npm:18.0.7" "@types/testing-library__jest-dom": "npm:5.14.9" debounce-promise: "npm:3.1.2" @@ -3545,7 +3545,7 @@ __metadata: "@types/lodash": "npm:4.17.0" "@types/node": "npm:20.12.7" "@types/prismjs": "npm:1.26.3" - "@types/react": "npm:18.2.77" + "@types/react": "npm:18.2.78" "@types/react-dom": "npm:18.2.25" "@types/semver": "npm:7.5.8" "@types/uuid": "npm:9.0.8" @@ -3590,7 +3590,7 @@ __metadata: "@testing-library/react": "npm:15.0.2" "@types/jest": "npm:29.5.12" "@types/lodash": "npm:4.17.0" - "@types/react": "npm:18.2.77" + "@types/react": "npm:18.2.78" lodash: "npm:4.17.21" react: "npm:18.2.0" react-use: "npm:17.5.0" @@ -3637,7 +3637,7 @@ __metadata: "@types/marked": "npm:5.0.2" "@types/node": "npm:20.12.7" "@types/papaparse": "npm:5.3.14" - "@types/react": "npm:18.2.77" + "@types/react": "npm:18.2.78" "@types/react-dom": "npm:18.2.25" "@types/string-hash": "npm:1.1.3" "@types/tinycolor2": "npm:1.4.6" @@ -3868,7 +3868,7 @@ __metadata: "@types/d3": "npm:^7" "@types/jest": "npm:^29.5.4" "@types/lodash": "npm:4.17.0" - "@types/react": "npm:18.2.77" + "@types/react": "npm:18.2.78" "@types/react-virtualized-auto-sizer": "npm:1.0.4" "@types/tinycolor2": "npm:1.4.6" babel-jest: "npm:29.7.0" @@ -3949,7 +3949,7 @@ __metadata: "@testing-library/react": "npm:15.0.2" "@testing-library/user-event": "npm:14.5.2" "@types/jest": "npm:^29.5.4" - "@types/react": "npm:18.2.77" + "@types/react": "npm:18.2.78" "@types/systemjs": "npm:6.13.5" "@types/testing-library__jest-dom": "npm:5.14.9" jest: "npm:^29.6.4" @@ -4034,7 +4034,7 @@ __metadata: "@types/node": "npm:20.12.7" "@types/pluralize": "npm:^0.0.33" "@types/prismjs": "npm:1.26.3" - "@types/react": "npm:18.2.77" + "@types/react": "npm:18.2.78" "@types/react-beautiful-dnd": "npm:13.1.8" "@types/react-dom": "npm:18.2.25" "@types/react-highlight-words": "npm:0.16.7" @@ -4127,7 +4127,7 @@ __metadata: "@types/history": "npm:4.7.11" "@types/jest": "npm:29.5.12" "@types/lodash": "npm:4.17.0" - "@types/react": "npm:18.2.77" + "@types/react": "npm:18.2.78" "@types/react-dom": "npm:18.2.25" "@types/systemjs": "npm:6.13.5" esbuild: "npm:0.18.12" @@ -4163,7 +4163,7 @@ __metadata: "@svgr/plugin-prettier": "npm:^8.1.0" "@svgr/plugin-svgo": "npm:^8.1.0" "@types/node": "npm:20.12.7" - "@types/react": "npm:18.2.77" + "@types/react": "npm:18.2.78" "@types/react-dom": "npm:18.2.25" esbuild: "npm:0.18.12" prettier: "npm:3.2.5" @@ -4237,7 +4237,7 @@ __metadata: "@testing-library/user-event": "npm:14.5.2" "@types/jest": "npm:^29.5.4" "@types/lodash": "npm:4.17.0" - "@types/react": "npm:18.2.77" + "@types/react": "npm:18.2.78" "@types/react-virtualized-auto-sizer": "npm:1.0.4" "@types/systemjs": "npm:6.13.5" "@types/testing-library__jest-dom": "npm:5.14.9" @@ -4324,7 +4324,7 @@ __metadata: "@types/mock-raf": "npm:1.0.6" "@types/node": "npm:20.12.7" "@types/prismjs": "npm:1.26.3" - "@types/react": "npm:18.2.77" + "@types/react": "npm:18.2.78" "@types/react-beautiful-dnd": "npm:13.1.8" "@types/react-calendar": "npm:3.9.0" "@types/react-color": "npm:3.0.12" @@ -10283,13 +10283,13 @@ __metadata: languageName: node linkType: hard -"@types/react@npm:*, @types/react@npm:18.2.77, @types/react@npm:>=16": - version: 18.2.77 - resolution: "@types/react@npm:18.2.77" +"@types/react@npm:*, @types/react@npm:18.2.78, @types/react@npm:>=16": + version: 18.2.78 + resolution: "@types/react@npm:18.2.78" dependencies: "@types/prop-types": "npm:*" csstype: "npm:^3.0.2" - checksum: 10/80d7ad9cf13e15895a857c66f5b0c1ce758c1e7580a76936d8d1b19c71e4485fa4b35d762a1de98de4eb91506cbc8507582c9a979f357b6f5f75f86009d8ca07 + checksum: 10/a4bf8104c580fab40535cc6058425ac6a47c19b8dad45b566cdb38aaafa3ffa1f24e7b65ec95e391a6c18ccf4a33738a591c1f723c00300f13d61fc456a1eb8d languageName: node linkType: hard @@ -18695,7 +18695,7 @@ __metadata: "@types/papaparse": "npm:5.3.14" "@types/pluralize": "npm:^0.0.33" "@types/prismjs": "npm:1.26.3" - "@types/react": "npm:18.2.77" + "@types/react": "npm:18.2.78" "@types/react-beautiful-dnd": "npm:13.1.8" "@types/react-dom": "npm:18.2.25" "@types/react-grid-layout": "npm:1.3.5" From 06719e17561887ebde1152d4e2ec326fcbd914f9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 15 Apr 2024 10:48:21 +0000 Subject: [PATCH 005/147] Update dependency i18next to v23.11.2 --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 769978d5bc8..034e784375e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -19694,11 +19694,11 @@ __metadata: linkType: hard "i18next@npm:^23.0.0, i18next@npm:^23.5.1": - version: 23.11.1 - resolution: "i18next@npm:23.11.1" + version: 23.11.2 + resolution: "i18next@npm:23.11.2" dependencies: "@babel/runtime": "npm:^7.23.2" - checksum: 10/77ab8618a59b4c02a8c605c21b2a5680c5cb5cb8399e409c214f8ed2486dff785272f1b0682e744d1562ad443fe87913a4cbe9c7ad303e5de541736f2fc1002f + checksum: 10/f2e01ae14f1304ff6d14d29331f5645c98ccadf3aeeb23a57816735e1a606509b95f40b2425ba707a362b03a703013ce56333173fe8c895ae8e56cfa21d5e50e languageName: node linkType: hard From 6fb13842a5de6dd0cf72dfd15d77bfed81f850e3 Mon Sep 17 00:00:00 2001 From: Victor Marin <36818606+mdvictor@users.noreply.github.com> Date: Mon, 15 Apr 2024 15:13:07 +0300 Subject: [PATCH 006/147] Fix Canvas crashing in scenes dashboard (#86117) --- public/app/plugins/panel/canvas/module.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/app/plugins/panel/canvas/module.tsx b/public/app/plugins/panel/canvas/module.tsx index 75566872d8b..e6fa75a7256 100644 --- a/public/app/plugins/panel/canvas/module.tsx +++ b/public/app/plugins/panel/canvas/module.tsx @@ -66,7 +66,7 @@ export const plugin = new PanelPlugin(CanvasPanel) addStandardCanvasEditorOptions(builder); - if (state) { + if (state && state.scene) { builder.addNestedOptions(getLayerEditor(state)); const selection = state.selected; From ad8d505d81f77f3fbcb29fd7a8568c986e039ade Mon Sep 17 00:00:00 2001 From: Erik Sundell Date: Mon, 15 Apr 2024 14:19:37 +0200 Subject: [PATCH 007/147] Chore: Install Playwright deps manually (#86008) * install deps manually * use ubuntu image * regenerate drone file * use node bookworm image * get node major version from variable and wait for grafana server to be ready --- .drone.yml | 16 +++++++++------- scripts/drone/steps/lib.star | 5 +++-- scripts/drone/utils/images.star | 2 +- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/.drone.yml b/.drone.yml index 624324422f1..6f896b5526f 100644 --- a/.drone.yml +++ b/.drone.yml @@ -658,7 +658,8 @@ steps: repo: - grafana/grafana - commands: - - sleep 10s + - npx wait-on@7.0.1 http://$HOST:$PORT + - yarn playwright install --with-deps chromium - yarn e2e:playwright depends_on: - grafana-server @@ -666,7 +667,7 @@ steps: HOST: grafana-server PORT: "3001" PROV_DIR: /grafana/scripts/grafana-server/tmp/conf/provisioning - image: mcr.microsoft.com/playwright:v1.43.0-jammy + image: node:20-bookworm name: playwright-plugin-e2e - commands: - apt-get update @@ -1988,7 +1989,8 @@ steps: repo: - grafana/grafana - commands: - - sleep 10s + - npx wait-on@7.0.1 http://$HOST:$PORT + - yarn playwright install --with-deps chromium - yarn e2e:playwright depends_on: - grafana-server @@ -1996,7 +1998,7 @@ steps: HOST: grafana-server PORT: "3001" PROV_DIR: /grafana/scripts/grafana-server/tmp/conf/provisioning - image: mcr.microsoft.com/playwright:v1.43.0-jammy + image: node:20-bookworm name: playwright-plugin-e2e - commands: - apt-get update @@ -4635,6 +4637,7 @@ steps: - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM alpine/git:2.40.1 - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM golang:1.21.9-alpine - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM node:20.9.0-alpine + - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM node:20-bookworm - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM google/cloud-sdk:431.0.0 - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM grafana/grafana-ci-deploy:1.3.3 - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM alpine:3.19.1 @@ -4656,7 +4659,6 @@ steps: - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM cypress/included:13.1.0 - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM jwilder/dockerize:0.6.1 - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM koalaman/shellcheck:stable - - trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM mcr.microsoft.com/playwright:v1.43.0-jammy depends_on: - authenticate-gcr image: aquasec/trivy:0.21.0 @@ -4670,6 +4672,7 @@ steps: - trivy --exit-code 1 --severity HIGH,CRITICAL alpine/git:2.40.1 - trivy --exit-code 1 --severity HIGH,CRITICAL golang:1.21.9-alpine - trivy --exit-code 1 --severity HIGH,CRITICAL node:20.9.0-alpine + - trivy --exit-code 1 --severity HIGH,CRITICAL node:20-bookworm - trivy --exit-code 1 --severity HIGH,CRITICAL google/cloud-sdk:431.0.0 - trivy --exit-code 1 --severity HIGH,CRITICAL grafana/grafana-ci-deploy:1.3.3 - trivy --exit-code 1 --severity HIGH,CRITICAL alpine:3.19.1 @@ -4691,7 +4694,6 @@ steps: - trivy --exit-code 1 --severity HIGH,CRITICAL cypress/included:13.1.0 - trivy --exit-code 1 --severity HIGH,CRITICAL jwilder/dockerize:0.6.1 - trivy --exit-code 1 --severity HIGH,CRITICAL koalaman/shellcheck:stable - - trivy --exit-code 1 --severity HIGH,CRITICAL mcr.microsoft.com/playwright:v1.43.0-jammy depends_on: - authenticate-gcr environment: @@ -4923,6 +4925,6 @@ kind: secret name: gcr_credentials --- kind: signature -hmac: 2f4db495ad0b69ef6afd86eac7aea7101f0b8f6ec1aadea0e2860b196304a258 +hmac: fbd59890dac44eb6fb34562f2b2b2db0fc0a8a50d451f9887f815ee35757e0f6 ... diff --git a/scripts/drone/steps/lib.star b/scripts/drone/steps/lib.star index fa2d1180aa4..85d435f7f7c 100644 --- a/scripts/drone/steps/lib.star +++ b/scripts/drone/steps/lib.star @@ -853,12 +853,13 @@ def playwright_e2e_tests_step(): "PROV_DIR": "/grafana/scripts/grafana-server/tmp/conf/provisioning", }, "name": "playwright-plugin-e2e", - "image": images["playwright"], + "image": images["node_deb"], "depends_on": [ "grafana-server", ], "commands": [ - "sleep 10s", # it seems sometimes that grafana-server is not actually ready when the step starts, so waiting for a few seconds before running the tests + "npx wait-on@7.0.1 http://$HOST:$PORT", + "yarn playwright install --with-deps chromium", "yarn e2e:playwright", ], } diff --git a/scripts/drone/utils/images.star b/scripts/drone/utils/images.star index 2d70daf927d..b8946c746d3 100644 --- a/scripts/drone/utils/images.star +++ b/scripts/drone/utils/images.star @@ -12,6 +12,7 @@ images = { "git": "alpine/git:2.40.1", "go": "golang:{}-alpine".format(golang_version), "node": "node:{}-alpine".format(nodejs_version), + "node_deb": "node:{}-bookworm".format(nodejs_version[:2]), "cloudsdk": "google/cloud-sdk:431.0.0", "publish": "grafana/grafana-ci-deploy:1.3.3", "alpine": "alpine:3.19.1", @@ -33,5 +34,4 @@ images = { "cypress": "cypress/included:13.1.0", "dockerize": "jwilder/dockerize:0.6.1", "shellcheck": "koalaman/shellcheck:stable", - "playwright": "mcr.microsoft.com/playwright:v1.43.0-jammy", } From 44adfea0493fc42aa84587d1eccc8ebcb50bddf2 Mon Sep 17 00:00:00 2001 From: Dave Henderson Date: Mon, 15 Apr 2024 08:21:03 -0400 Subject: [PATCH 008/147] Server: Fix 'server' subcommand double-registration (#86083) fix 'server' subcommand double-registration Signed-off-by: Dave Henderson --- pkg/cmd/grafana/main.go | 21 ++++++++++++--------- pkg/cmd/grafana/main_test.go | 16 ++++++++++++++++ 2 files changed, 28 insertions(+), 9 deletions(-) create mode 100644 pkg/cmd/grafana/main_test.go diff --git a/pkg/cmd/grafana/main.go b/pkg/cmd/grafana/main.go index 9985f6e64e8..e9003dd078a 100644 --- a/pkg/cmd/grafana/main.go +++ b/pkg/cmd/grafana/main.go @@ -20,7 +20,18 @@ var buildBranch = "main" var buildstamp string func main() { - app := &cli.App{ + app := MainApp() + + if err := app.Run(os.Args); err != nil { + fmt.Printf("%s: %s %s\n", color.RedString("Error"), color.RedString("✗"), err) + os.Exit(1) + } + + os.Exit(0) +} + +func MainApp() *cli.App { + return &cli.App{ Name: "grafana", Usage: "Grafana server and command line interface", Authors: []*cli.Author{ @@ -52,18 +63,10 @@ func main() { return nil }, }, - gsrv.ServerCommand(version, commit, enterpriseCommit, buildBranch, buildstamp), }, CommandNotFound: cmdNotFound, EnableBashCompletion: true, } - - if err := app.Run(os.Args); err != nil { - fmt.Printf("%s: %s %s\n", color.RedString("Error"), color.RedString("✗"), err) - os.Exit(1) - } - - os.Exit(0) } func cmdNotFound(c *cli.Context, command string) { diff --git a/pkg/cmd/grafana/main_test.go b/pkg/cmd/grafana/main_test.go new file mode 100644 index 00000000000..0ec0d980643 --- /dev/null +++ b/pkg/cmd/grafana/main_test.go @@ -0,0 +1,16 @@ +package main + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestMainApp_NoDuplicateSubcommands(t *testing.T) { + app := MainApp() + found := map[string]bool{} + for _, cmd := range app.Commands { + require.False(t, found[cmd.Name], "command %q registered twice", cmd.Name) + found[cmd.Name] = true + } +} From b02317d5837a8a667b89dcf2de28c63026c1cab1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Farkas?= Date: Mon, 15 Apr 2024 14:26:15 +0200 Subject: [PATCH 009/147] mysql: decouple sqleng (#86057) --- .golangci.toml | 2 + pkg/tsdb/mysql/macros.go | 2 +- pkg/tsdb/mysql/mysql.go | 2 +- pkg/tsdb/mysql/mysql_snapshot_test.go | 2 +- pkg/tsdb/mysql/mysql_test.go | 2 +- pkg/tsdb/mysql/sqleng/sql_engine.go | 642 +++++++++++++++++++++++ pkg/tsdb/mysql/sqleng/sql_engine_test.go | 438 ++++++++++++++++ pkg/tsdb/mysql/sqleng/util/util.go | 3 + 8 files changed, 1089 insertions(+), 4 deletions(-) create mode 100644 pkg/tsdb/mysql/sqleng/sql_engine.go create mode 100644 pkg/tsdb/mysql/sqleng/sql_engine_test.go create mode 100644 pkg/tsdb/mysql/sqleng/util/util.go diff --git a/.golangci.toml b/.golangci.toml index 4429f9e6595..fd4fb00286f 100644 --- a/.golangci.toml +++ b/.golangci.toml @@ -60,6 +60,8 @@ files = [ "**/pkg/tsdb/azuremonitor/**/*", "**/pkg/tsdb/cloud-monitoring/*", "**/pkg/tsdb/cloud-monitoring/**/*", + "**/pkg/tsdb/mysql/*", + "**/pkg/tsdb/mysql/**/*", "**/pkg/tsdb/parca/*", "**/pkg/tsdb/parca/**/*", "**/pkg/tsdb/tempo/*", diff --git a/pkg/tsdb/mysql/macros.go b/pkg/tsdb/mysql/macros.go index 05e93c0aee5..15b67672968 100644 --- a/pkg/tsdb/mysql/macros.go +++ b/pkg/tsdb/mysql/macros.go @@ -8,7 +8,7 @@ import ( "github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend/gtime" "github.com/grafana/grafana-plugin-sdk-go/backend/log" - "github.com/grafana/grafana/pkg/tsdb/sqleng" + "github.com/grafana/grafana/pkg/tsdb/mysql/sqleng" ) const rsIdentifier = `([_a-zA-Z0-9]+)` diff --git a/pkg/tsdb/mysql/mysql.go b/pkg/tsdb/mysql/mysql.go index 2e908afc93d..357663f02b8 100644 --- a/pkg/tsdb/mysql/mysql.go +++ b/pkg/tsdb/mysql/mysql.go @@ -22,7 +22,7 @@ import ( "github.com/grafana/grafana-plugin-sdk-go/data/sqlutil" "github.com/grafana/grafana-plugin-sdk-go/backend/log" - "github.com/grafana/grafana/pkg/tsdb/sqleng" + "github.com/grafana/grafana/pkg/tsdb/mysql/sqleng" ) const ( diff --git a/pkg/tsdb/mysql/mysql_snapshot_test.go b/pkg/tsdb/mysql/mysql_snapshot_test.go index d2ff94f889c..c251fc23c42 100644 --- a/pkg/tsdb/mysql/mysql_snapshot_test.go +++ b/pkg/tsdb/mysql/mysql_snapshot_test.go @@ -16,7 +16,7 @@ import ( "github.com/grafana/grafana-plugin-sdk-go/experimental" "github.com/stretchr/testify/require" - "github.com/grafana/grafana/pkg/tsdb/sqleng" + "github.com/grafana/grafana/pkg/tsdb/mysql/sqleng" _ "github.com/go-sql-driver/mysql" ) diff --git a/pkg/tsdb/mysql/mysql_test.go b/pkg/tsdb/mysql/mysql_test.go index c01ec8bae6c..014c56cadf5 100644 --- a/pkg/tsdb/mysql/mysql_test.go +++ b/pkg/tsdb/mysql/mysql_test.go @@ -13,7 +13,7 @@ import ( "github.com/grafana/grafana-plugin-sdk-go/data" "github.com/stretchr/testify/require" - "github.com/grafana/grafana/pkg/tsdb/sqleng" + "github.com/grafana/grafana/pkg/tsdb/mysql/sqleng" ) // To run this test, set runMySqlTests=true diff --git a/pkg/tsdb/mysql/sqleng/sql_engine.go b/pkg/tsdb/mysql/sqleng/sql_engine.go new file mode 100644 index 00000000000..060e2bcb02e --- /dev/null +++ b/pkg/tsdb/mysql/sqleng/sql_engine.go @@ -0,0 +1,642 @@ +package sqleng + +import ( + "context" + "database/sql" + "encoding/json" + "errors" + "fmt" + "net" + "regexp" + "runtime/debug" + "strconv" + "strings" + "sync" + "time" + + "github.com/grafana/grafana-plugin-sdk-go/backend" + "github.com/grafana/grafana-plugin-sdk-go/data" + "github.com/grafana/grafana-plugin-sdk-go/data/sqlutil" + + "github.com/grafana/grafana-plugin-sdk-go/backend/gtime" + "github.com/grafana/grafana-plugin-sdk-go/backend/log" +) + +// MetaKeyExecutedQueryString is the key where the executed query should get stored +const MetaKeyExecutedQueryString = "executedQueryString" + +// SQLMacroEngine interpolates macros into sql. It takes in the Query to have access to query context and +// timeRange to be able to generate queries that use from and to. +type SQLMacroEngine interface { + Interpolate(query *backend.DataQuery, timeRange backend.TimeRange, sql string) (string, error) +} + +// SqlQueryResultTransformer transforms a query result row to RowValues with proper types. +type SqlQueryResultTransformer interface { + // TransformQueryError transforms a query error. + TransformQueryError(logger log.Logger, err error) error + GetConverterList() []sqlutil.StringConverter +} + +type JsonData struct { + MaxOpenConns int `json:"maxOpenConns"` + MaxIdleConns int `json:"maxIdleConns"` + ConnMaxLifetime int `json:"connMaxLifetime"` + ConnectionTimeout int `json:"connectionTimeout"` + Timescaledb bool `json:"timescaledb"` + Mode string `json:"sslmode"` + ConfigurationMethod string `json:"tlsConfigurationMethod"` + TlsSkipVerify bool `json:"tlsSkipVerify"` + RootCertFile string `json:"sslRootCertFile"` + CertFile string `json:"sslCertFile"` + CertKeyFile string `json:"sslKeyFile"` + Timezone string `json:"timezone"` + Encrypt string `json:"encrypt"` + Servername string `json:"servername"` + TimeInterval string `json:"timeInterval"` + Database string `json:"database"` + SecureDSProxy bool `json:"enableSecureSocksProxy"` + SecureDSProxyUsername string `json:"secureSocksProxyUsername"` + AllowCleartextPasswords bool `json:"allowCleartextPasswords"` + AuthenticationType string `json:"authenticationType"` +} + +type DataSourceInfo struct { + JsonData JsonData + URL string + User string + Database string + ID int64 + Updated time.Time + UID string + DecryptedSecureJSONData map[string]string +} + +type DataPluginConfiguration struct { + DSInfo DataSourceInfo + TimeColumnNames []string + MetricColumnTypes []string + RowLimit int64 +} + +type DataSourceHandler struct { + macroEngine SQLMacroEngine + queryResultTransformer SqlQueryResultTransformer + db *sql.DB + timeColumnNames []string + metricColumnTypes []string + log log.Logger + dsInfo DataSourceInfo + rowLimit int64 + userError string +} + +type QueryJson struct { + RawSql string `json:"rawSql"` + Fill bool `json:"fill"` + FillInterval float64 `json:"fillInterval"` + FillMode string `json:"fillMode"` + FillValue float64 `json:"fillValue"` + Format string `json:"format"` +} + +func (e *DataSourceHandler) TransformQueryError(logger log.Logger, err error) error { + // OpError is the error type usually returned by functions in the net + // package. It describes the operation, network type, and address of + // an error. We log this error rather than return it to the client + // for security purposes. + var opErr *net.OpError + if errors.As(err, &opErr) { + logger.Error("Query error", "err", err) + return fmt.Errorf("failed to connect to server - %s", e.userError) + } + + return e.queryResultTransformer.TransformQueryError(logger, err) +} + +func NewQueryDataHandler(userFacingDefaultError string, db *sql.DB, config DataPluginConfiguration, queryResultTransformer SqlQueryResultTransformer, + macroEngine SQLMacroEngine, log log.Logger) (*DataSourceHandler, error) { + queryDataHandler := DataSourceHandler{ + queryResultTransformer: queryResultTransformer, + macroEngine: macroEngine, + timeColumnNames: []string{"time"}, + log: log, + dsInfo: config.DSInfo, + rowLimit: config.RowLimit, + userError: userFacingDefaultError, + } + + if len(config.TimeColumnNames) > 0 { + queryDataHandler.timeColumnNames = config.TimeColumnNames + } + + if len(config.MetricColumnTypes) > 0 { + queryDataHandler.metricColumnTypes = config.MetricColumnTypes + } + + queryDataHandler.db = db + return &queryDataHandler, nil +} + +type DBDataResponse struct { + dataResponse backend.DataResponse + refID string +} + +func (e *DataSourceHandler) Dispose() { + e.log.Debug("Disposing DB...") + if e.db != nil { + if err := e.db.Close(); err != nil { + e.log.Error("Failed to dispose db", "error", err) + } + } + e.log.Debug("DB disposed") +} + +func (e *DataSourceHandler) Ping() error { + return e.db.Ping() +} + +func (e *DataSourceHandler) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) { + result := backend.NewQueryDataResponse() + ch := make(chan DBDataResponse, len(req.Queries)) + var wg sync.WaitGroup + // Execute each query in a goroutine and wait for them to finish afterwards + for _, query := range req.Queries { + queryjson := QueryJson{ + Fill: false, + Format: "time_series", + } + err := json.Unmarshal(query.JSON, &queryjson) + if err != nil { + return nil, fmt.Errorf("error unmarshal query json: %w", err) + } + + // the fill-params are only stored inside this function, during query-interpolation. we do not support + // sending them in "from the outside" + if queryjson.Fill || queryjson.FillInterval != 0.0 || queryjson.FillMode != "" || queryjson.FillValue != 0.0 { + return nil, fmt.Errorf("query fill-parameters not supported") + } + + if queryjson.RawSql == "" { + continue + } + + wg.Add(1) + go e.executeQuery(query, &wg, ctx, ch, queryjson) + } + + wg.Wait() + + // Read results from channels + close(ch) + result.Responses = make(map[string]backend.DataResponse) + for queryResult := range ch { + result.Responses[queryResult.refID] = queryResult.dataResponse + } + + return result, nil +} + +func (e *DataSourceHandler) executeQuery(query backend.DataQuery, wg *sync.WaitGroup, queryContext context.Context, + ch chan DBDataResponse, queryJson QueryJson) { + defer wg.Done() + queryResult := DBDataResponse{ + dataResponse: backend.DataResponse{}, + refID: query.RefID, + } + + logger := e.log.FromContext(queryContext) + + defer func() { + if r := recover(); r != nil { + logger.Error("ExecuteQuery panic", "error", r, "stack", string(debug.Stack())) + if theErr, ok := r.(error); ok { + queryResult.dataResponse.Error = theErr + } else if theErrString, ok := r.(string); ok { + queryResult.dataResponse.Error = fmt.Errorf(theErrString) + } else { + queryResult.dataResponse.Error = fmt.Errorf("unexpected error - %s", e.userError) + } + ch <- queryResult + } + }() + + if queryJson.RawSql == "" { + panic("Query model property rawSql should not be empty at this point") + } + + timeRange := query.TimeRange + + errAppendDebug := func(frameErr string, err error, query string) { + var emptyFrame data.Frame + emptyFrame.SetMeta(&data.FrameMeta{ + ExecutedQueryString: query, + }) + queryResult.dataResponse.Error = fmt.Errorf("%s: %w", frameErr, err) + queryResult.dataResponse.Frames = data.Frames{&emptyFrame} + ch <- queryResult + } + + // global substitutions + interpolatedQuery := Interpolate(query, timeRange, e.dsInfo.JsonData.TimeInterval, queryJson.RawSql) + + // data source specific substitutions + interpolatedQuery, err := e.macroEngine.Interpolate(&query, timeRange, interpolatedQuery) + if err != nil { + errAppendDebug("interpolation failed", e.TransformQueryError(logger, err), interpolatedQuery) + return + } + + rows, err := e.db.QueryContext(queryContext, interpolatedQuery) + if err != nil { + errAppendDebug("db query error", e.TransformQueryError(logger, err), interpolatedQuery) + return + } + defer func() { + if err := rows.Close(); err != nil { + logger.Warn("Failed to close rows", "err", err) + } + }() + + qm, err := e.newProcessCfg(query, queryContext, rows, interpolatedQuery) + if err != nil { + errAppendDebug("failed to get configurations", err, interpolatedQuery) + return + } + + // Convert row.Rows to dataframe + stringConverters := e.queryResultTransformer.GetConverterList() + frame, err := sqlutil.FrameFromRows(rows, e.rowLimit, sqlutil.ToConverters(stringConverters...)...) + if err != nil { + errAppendDebug("convert frame from rows error", err, interpolatedQuery) + return + } + + if frame.Meta == nil { + frame.Meta = &data.FrameMeta{} + } + + frame.Meta.ExecutedQueryString = interpolatedQuery + + // If no rows were returned, clear any previously set `Fields` with a single empty `data.Field` slice. + // Then assign `queryResult.dataResponse.Frames` the current single frame with that single empty Field. + // This assures 1) our visualization doesn't display unwanted empty fields, and also that 2) + // additionally-needed frame data stays intact and is correctly passed to our visulization. + if frame.Rows() == 0 { + frame.Fields = []*data.Field{} + queryResult.dataResponse.Frames = data.Frames{frame} + ch <- queryResult + return + } + + if err := convertSQLTimeColumnsToEpochMS(frame, qm); err != nil { + errAppendDebug("converting time columns failed", err, interpolatedQuery) + return + } + + if qm.Format == dataQueryFormatSeries { + // time series has to have time column + if qm.timeIndex == -1 { + errAppendDebug("db has no time column", errors.New("no time column found"), interpolatedQuery) + return + } + + // Make sure to name the time field 'Time' to be backward compatible with Grafana pre-v8. + frame.Fields[qm.timeIndex].Name = data.TimeSeriesTimeFieldName + + for i := range qm.columnNames { + if i == qm.timeIndex || i == qm.metricIndex { + continue + } + + if t := frame.Fields[i].Type(); t == data.FieldTypeString || t == data.FieldTypeNullableString { + continue + } + + var err error + if frame, err = convertSQLValueColumnToFloat(frame, i); err != nil { + errAppendDebug("convert value to float failed", err, interpolatedQuery) + return + } + } + + tsSchema := frame.TimeSeriesSchema() + if tsSchema.Type == data.TimeSeriesTypeLong { + var err error + originalData := frame + frame, err = data.LongToWide(frame, qm.FillMissing) + if err != nil { + errAppendDebug("failed to convert long to wide series when converting from dataframe", err, interpolatedQuery) + return + } + + // Before 8x, a special metric column was used to name time series. The LongToWide transforms that into a metric label on the value field. + // But that makes series name have both the value column name AND the metric name. So here we are removing the metric label here and moving it to the + // field name to get the same naming for the series as pre v8 + if len(originalData.Fields) == 3 { + for _, field := range frame.Fields { + if len(field.Labels) == 1 { // 7x only supported one label + name, ok := field.Labels["metric"] + if ok { + field.Name = name + field.Labels = nil + } + } + } + } + } + if qm.FillMissing != nil { + // we align the start-time + startUnixTime := qm.TimeRange.From.Unix() / int64(qm.Interval.Seconds()) * int64(qm.Interval.Seconds()) + alignedTimeRange := backend.TimeRange{ + From: time.Unix(startUnixTime, 0), + To: qm.TimeRange.To, + } + + var err error + frame, err = sqlutil.ResampleWideFrame(frame, qm.FillMissing, alignedTimeRange, qm.Interval) + if err != nil { + logger.Error("Failed to resample dataframe", "err", err) + frame.AppendNotices(data.Notice{Text: "Failed to resample dataframe", Severity: data.NoticeSeverityWarning}) + } + } + } + + queryResult.dataResponse.Frames = data.Frames{frame} + ch <- queryResult +} + +// Interpolate provides global macros/substitutions for all sql datasources. +var Interpolate = func(query backend.DataQuery, timeRange backend.TimeRange, timeInterval string, sql string) string { + interval := query.Interval + + sql = strings.ReplaceAll(sql, "$__interval_ms", strconv.FormatInt(interval.Milliseconds(), 10)) + sql = strings.ReplaceAll(sql, "$__interval", gtime.FormatInterval(interval)) + sql = strings.ReplaceAll(sql, "$__unixEpochFrom()", fmt.Sprintf("%d", timeRange.From.UTC().Unix())) + sql = strings.ReplaceAll(sql, "$__unixEpochTo()", fmt.Sprintf("%d", timeRange.To.UTC().Unix())) + + return sql +} + +func (e *DataSourceHandler) newProcessCfg(query backend.DataQuery, queryContext context.Context, + rows *sql.Rows, interpolatedQuery string) (*dataQueryModel, error) { + columnNames, err := rows.Columns() + if err != nil { + return nil, err + } + columnTypes, err := rows.ColumnTypes() + if err != nil { + return nil, err + } + + qm := &dataQueryModel{ + columnTypes: columnTypes, + columnNames: columnNames, + timeIndex: -1, + timeEndIndex: -1, + metricIndex: -1, + metricPrefix: false, + queryContext: queryContext, + } + + queryJson := QueryJson{} + err = json.Unmarshal(query.JSON, &queryJson) + if err != nil { + return nil, err + } + + if queryJson.Fill { + qm.FillMissing = &data.FillMissing{} + qm.Interval = time.Duration(queryJson.FillInterval * float64(time.Second)) + switch strings.ToLower(queryJson.FillMode) { + case "null": + qm.FillMissing.Mode = data.FillModeNull + case "previous": + qm.FillMissing.Mode = data.FillModePrevious + case "value": + qm.FillMissing.Mode = data.FillModeValue + qm.FillMissing.Value = queryJson.FillValue + default: + } + } + + qm.TimeRange.From = query.TimeRange.From.UTC() + qm.TimeRange.To = query.TimeRange.To.UTC() + + switch queryJson.Format { + case "time_series": + qm.Format = dataQueryFormatSeries + case "table": + qm.Format = dataQueryFormatTable + default: + panic(fmt.Sprintf("Unrecognized query model format: %q", queryJson.Format)) + } + + for i, col := range qm.columnNames { + for _, tc := range e.timeColumnNames { + if col == tc { + qm.timeIndex = i + break + } + } + + if qm.Format == dataQueryFormatTable && col == "timeend" { + qm.timeEndIndex = i + continue + } + + switch col { + case "metric": + qm.metricIndex = i + default: + if qm.metricIndex == -1 { + columnType := qm.columnTypes[i].DatabaseTypeName() + for _, mct := range e.metricColumnTypes { + if columnType == mct { + qm.metricIndex = i + continue + } + } + } + } + } + qm.InterpolatedQuery = interpolatedQuery + return qm, nil +} + +// dataQueryFormat is the type of query. +type dataQueryFormat string + +const ( + // dataQueryFormatTable identifies a table query (default). + dataQueryFormatTable dataQueryFormat = "table" + // dataQueryFormatSeries identifies a time series query. + dataQueryFormatSeries dataQueryFormat = "time_series" +) + +type dataQueryModel struct { + InterpolatedQuery string // property not set until after Interpolate() + Format dataQueryFormat + TimeRange backend.TimeRange + FillMissing *data.FillMissing // property not set until after Interpolate() + Interval time.Duration + columnNames []string + columnTypes []*sql.ColumnType + timeIndex int + timeEndIndex int + metricIndex int + metricPrefix bool + queryContext context.Context +} + +func convertSQLTimeColumnsToEpochMS(frame *data.Frame, qm *dataQueryModel) error { + if qm.timeIndex != -1 { + if err := convertSQLTimeColumnToEpochMS(frame, qm.timeIndex); err != nil { + return fmt.Errorf("%v: %w", "failed to convert time column", err) + } + } + + if qm.timeEndIndex != -1 { + if err := convertSQLTimeColumnToEpochMS(frame, qm.timeEndIndex); err != nil { + return fmt.Errorf("%v: %w", "failed to convert timeend column", err) + } + } + + return nil +} + +// convertSQLTimeColumnToEpochMS converts column named time to unix timestamp in milliseconds +// to make native datetime types and epoch dates work in annotation and table queries. +func convertSQLTimeColumnToEpochMS(frame *data.Frame, timeIndex int) error { + if timeIndex < 0 || timeIndex >= len(frame.Fields) { + return fmt.Errorf("timeIndex %d is out of range", timeIndex) + } + + origin := frame.Fields[timeIndex] + valueType := origin.Type() + if valueType == data.FieldTypeTime || valueType == data.FieldTypeNullableTime { + return nil + } + + newField := data.NewFieldFromFieldType(data.FieldTypeNullableTime, 0) + newField.Name = origin.Name + newField.Labels = origin.Labels + + valueLength := origin.Len() + for i := 0; i < valueLength; i++ { + v, err := origin.NullableFloatAt(i) + if err != nil { + return fmt.Errorf("unable to convert data to a time field") + } + if v == nil { + newField.Append(nil) + } else { + timestamp := time.Unix(0, int64(epochPrecisionToMS(*v))*int64(time.Millisecond)) + newField.Append(×tamp) + } + } + frame.Fields[timeIndex] = newField + + return nil +} + +// convertSQLValueColumnToFloat converts timeseries value column to float. +func convertSQLValueColumnToFloat(frame *data.Frame, Index int) (*data.Frame, error) { + if Index < 0 || Index >= len(frame.Fields) { + return frame, fmt.Errorf("metricIndex %d is out of range", Index) + } + + origin := frame.Fields[Index] + valueType := origin.Type() + if valueType == data.FieldTypeFloat64 || valueType == data.FieldTypeNullableFloat64 { + return frame, nil + } + + newField := data.NewFieldFromFieldType(data.FieldTypeNullableFloat64, origin.Len()) + newField.Name = origin.Name + newField.Labels = origin.Labels + + for i := 0; i < origin.Len(); i++ { + v, err := origin.NullableFloatAt(i) + if err != nil { + return frame, err + } + newField.Set(i, v) + } + + frame.Fields[Index] = newField + + return frame, nil +} + +func SetupFillmode(query *backend.DataQuery, interval time.Duration, fillmode string) error { + rawQueryProp := make(map[string]any) + queryBytes, err := query.JSON.MarshalJSON() + if err != nil { + return err + } + err = json.Unmarshal(queryBytes, &rawQueryProp) + if err != nil { + return err + } + rawQueryProp["fill"] = true + rawQueryProp["fillInterval"] = interval.Seconds() + + switch fillmode { + case "NULL": + rawQueryProp["fillMode"] = "null" + case "previous": + rawQueryProp["fillMode"] = "previous" + default: + rawQueryProp["fillMode"] = "value" + floatVal, err := strconv.ParseFloat(fillmode, 64) + if err != nil { + return fmt.Errorf("error parsing fill value %v", fillmode) + } + rawQueryProp["fillValue"] = floatVal + } + query.JSON, err = json.Marshal(rawQueryProp) + if err != nil { + return err + } + return nil +} + +type SQLMacroEngineBase struct{} + +func NewSQLMacroEngineBase() *SQLMacroEngineBase { + return &SQLMacroEngineBase{} +} + +func (m *SQLMacroEngineBase) ReplaceAllStringSubmatchFunc(re *regexp.Regexp, str string, repl func([]string) string) string { + result := "" + lastIndex := 0 + + for _, v := range re.FindAllStringSubmatchIndex(str, -1) { + groups := []string{} + for i := 0; i < len(v); i += 2 { + groups = append(groups, str[v[i]:v[i+1]]) + } + + result += str[lastIndex:v[0]] + repl(groups) + lastIndex = v[1] + } + + return result + str[lastIndex:] +} + +// epochPrecisionToMS converts epoch precision to millisecond, if needed. +// Only seconds to milliseconds supported right now +func epochPrecisionToMS(value float64) float64 { + s := strconv.FormatFloat(value, 'e', -1, 64) + if strings.HasSuffix(s, "e+09") { + return value * float64(1e3) + } + + if strings.HasSuffix(s, "e+18") { + return value / float64(time.Millisecond) + } + + return value +} diff --git a/pkg/tsdb/mysql/sqleng/sql_engine_test.go b/pkg/tsdb/mysql/sqleng/sql_engine_test.go new file mode 100644 index 00000000000..d8bc7c39ff5 --- /dev/null +++ b/pkg/tsdb/mysql/sqleng/sql_engine_test.go @@ -0,0 +1,438 @@ +package sqleng + +import ( + "fmt" + "net" + "testing" + "time" + + "github.com/grafana/grafana-plugin-sdk-go/backend" + "github.com/grafana/grafana-plugin-sdk-go/data" + "github.com/grafana/grafana-plugin-sdk-go/data/sqlutil" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/grafana/grafana-plugin-sdk-go/backend/log" + "github.com/grafana/grafana/pkg/tsdb/mysql/sqleng/util" +) + +func TestSQLEngine(t *testing.T) { + dt := time.Date(2018, 3, 14, 21, 20, 6, int(527345*time.Microsecond), time.UTC) + + t.Run("Handle interpolating $__interval and $__interval_ms", func(t *testing.T) { + from := time.Date(2018, 4, 12, 18, 0, 0, 0, time.UTC) + to := from.Add(5 * time.Minute) + timeRange := backend.TimeRange{From: from, To: to} + + text := "$__interval $__timeGroupAlias(time,$__interval) $__interval_ms" + + t.Run("interpolate 10 minutes $__interval", func(t *testing.T) { + query := backend.DataQuery{JSON: []byte("{}"), MaxDataPoints: 1500, Interval: time.Minute * 10} + sql := Interpolate(query, timeRange, "", text) + require.Equal(t, "10m $__timeGroupAlias(time,10m) 600000", sql) + }) + + t.Run("interpolate 4seconds $__interval", func(t *testing.T) { + query := backend.DataQuery{JSON: []byte("{}"), MaxDataPoints: 1500, Interval: time.Second * 4} + sql := Interpolate(query, timeRange, "", text) + require.Equal(t, "4s $__timeGroupAlias(time,4s) 4000", sql) + }) + + t.Run("interpolate 200 milliseconds $__interval", func(t *testing.T) { + query := backend.DataQuery{JSON: []byte("{}"), MaxDataPoints: 1500, Interval: time.Millisecond * 200} + sql := Interpolate(query, timeRange, "", text) + require.Equal(t, "200ms $__timeGroupAlias(time,200ms) 200", sql) + }) + }) + + t.Run("Given a time range between 2018-04-12 00:00 and 2018-04-12 00:05", func(t *testing.T) { + from := time.Date(2018, 4, 12, 18, 0, 0, 0, time.UTC) + to := from.Add(5 * time.Minute) + timeRange := backend.TimeRange{From: from, To: to} + query := backend.DataQuery{JSON: []byte("{}"), MaxDataPoints: 1500, Interval: time.Second * 60} + + t.Run("interpolate __unixEpochFrom function", func(t *testing.T) { + sql := Interpolate(query, timeRange, "", "select $__unixEpochFrom()") + require.Equal(t, fmt.Sprintf("select %d", from.Unix()), sql) + }) + + t.Run("interpolate __unixEpochTo function", func(t *testing.T) { + sql := Interpolate(query, timeRange, "", "select $__unixEpochTo()") + require.Equal(t, fmt.Sprintf("select %d", to.Unix()), sql) + }) + }) + + t.Run("Given row values with int64 as time columns", func(t *testing.T) { + tSeconds := dt.Unix() + tMilliseconds := dt.UnixNano() / 1e6 + tNanoSeconds := dt.UnixNano() + var nilPointer *int64 + + originFrame := data.NewFrame("", + data.NewField("time1", nil, []int64{ + tSeconds, + }), + data.NewField("time2", nil, []*int64{ + util.Pointer(tSeconds), + }), + data.NewField("time3", nil, []int64{ + tMilliseconds, + }), + data.NewField("time4", nil, []*int64{ + util.Pointer(tMilliseconds), + }), + data.NewField("time5", nil, []int64{ + tNanoSeconds, + }), + data.NewField("time6", nil, []*int64{ + util.Pointer(tNanoSeconds), + }), + data.NewField("time7", nil, []*int64{ + nilPointer, + }), + ) + + for i := 0; i < len(originFrame.Fields); i++ { + err := convertSQLTimeColumnToEpochMS(originFrame, i) + require.NoError(t, err) + } + + require.Equal(t, dt.Unix(), (*originFrame.Fields[0].At(0).(*time.Time)).Unix()) + require.Equal(t, dt.Unix(), (*originFrame.Fields[1].At(0).(*time.Time)).Unix()) + require.Equal(t, dt.Unix(), (*originFrame.Fields[2].At(0).(*time.Time)).Unix()) + require.Equal(t, dt.Unix(), (*originFrame.Fields[3].At(0).(*time.Time)).Unix()) + require.Equal(t, dt.Unix(), (*originFrame.Fields[4].At(0).(*time.Time)).Unix()) + require.Equal(t, dt.Unix(), (*originFrame.Fields[5].At(0).(*time.Time)).Unix()) + require.Nil(t, originFrame.Fields[6].At(0)) + }) + + t.Run("Given row values with uint64 as time columns", func(t *testing.T) { + tSeconds := uint64(dt.Unix()) + tMilliseconds := uint64(dt.UnixNano() / 1e6) + tNanoSeconds := uint64(dt.UnixNano()) + var nilPointer *uint64 + + originFrame := data.NewFrame("", + data.NewField("time1", nil, []uint64{ + tSeconds, + }), + data.NewField("time2", nil, []*uint64{ + util.Pointer(tSeconds), + }), + data.NewField("time3", nil, []uint64{ + tMilliseconds, + }), + data.NewField("time4", nil, []*uint64{ + util.Pointer(tMilliseconds), + }), + data.NewField("time5", nil, []uint64{ + tNanoSeconds, + }), + data.NewField("time6", nil, []*uint64{ + util.Pointer(tNanoSeconds), + }), + data.NewField("time7", nil, []*uint64{ + nilPointer, + }), + ) + + for i := 0; i < len(originFrame.Fields); i++ { + err := convertSQLTimeColumnToEpochMS(originFrame, i) + require.NoError(t, err) + } + + require.Equal(t, dt.Unix(), (*originFrame.Fields[0].At(0).(*time.Time)).Unix()) + require.Equal(t, dt.Unix(), (*originFrame.Fields[1].At(0).(*time.Time)).Unix()) + require.Equal(t, dt.Unix(), (*originFrame.Fields[2].At(0).(*time.Time)).Unix()) + require.Equal(t, dt.Unix(), (*originFrame.Fields[3].At(0).(*time.Time)).Unix()) + require.Equal(t, dt.Unix(), (*originFrame.Fields[4].At(0).(*time.Time)).Unix()) + require.Equal(t, dt.Unix(), (*originFrame.Fields[5].At(0).(*time.Time)).Unix()) + require.Nil(t, originFrame.Fields[6].At(0)) + }) + + t.Run("Given row values with int32 as time columns", func(t *testing.T) { + tSeconds := int32(dt.Unix()) + var nilInt *int32 + + originFrame := data.NewFrame("", + data.NewField("time1", nil, []int32{ + tSeconds, + }), + data.NewField("time2", nil, []*int32{ + util.Pointer(tSeconds), + }), + data.NewField("time7", nil, []*int32{ + nilInt, + }), + ) + for i := 0; i < 3; i++ { + err := convertSQLTimeColumnToEpochMS(originFrame, i) + require.NoError(t, err) + } + + require.Equal(t, dt.Unix(), (*originFrame.Fields[0].At(0).(*time.Time)).Unix()) + require.Equal(t, dt.Unix(), (*originFrame.Fields[1].At(0).(*time.Time)).Unix()) + require.Nil(t, originFrame.Fields[2].At(0)) + }) + + t.Run("Given row values with uint32 as time columns", func(t *testing.T) { + tSeconds := uint32(dt.Unix()) + var nilInt *uint32 + + originFrame := data.NewFrame("", + data.NewField("time1", nil, []uint32{ + tSeconds, + }), + data.NewField("time2", nil, []*uint32{ + util.Pointer(tSeconds), + }), + data.NewField("time7", nil, []*uint32{ + nilInt, + }), + ) + for i := 0; i < len(originFrame.Fields); i++ { + err := convertSQLTimeColumnToEpochMS(originFrame, i) + require.NoError(t, err) + } + require.Equal(t, dt.Unix(), (*originFrame.Fields[0].At(0).(*time.Time)).Unix()) + require.Equal(t, dt.Unix(), (*originFrame.Fields[1].At(0).(*time.Time)).Unix()) + require.Nil(t, originFrame.Fields[2].At(0)) + }) + + t.Run("Given row values with float64 as time columns", func(t *testing.T) { + tSeconds := float64(dt.UnixNano()) / float64(time.Second) + tMilliseconds := float64(dt.UnixNano()) / float64(time.Millisecond) + tNanoSeconds := float64(dt.UnixNano()) + var nilPointer *float64 + + originFrame := data.NewFrame("", + data.NewField("time1", nil, []float64{ + tSeconds, + }), + data.NewField("time2", nil, []*float64{ + util.Pointer(tSeconds), + }), + data.NewField("time3", nil, []float64{ + tMilliseconds, + }), + data.NewField("time4", nil, []*float64{ + util.Pointer(tMilliseconds), + }), + data.NewField("time5", nil, []float64{ + tNanoSeconds, + }), + data.NewField("time6", nil, []*float64{ + util.Pointer(tNanoSeconds), + }), + data.NewField("time7", nil, []*float64{ + nilPointer, + }), + ) + + for i := 0; i < len(originFrame.Fields); i++ { + err := convertSQLTimeColumnToEpochMS(originFrame, i) + require.NoError(t, err) + } + + require.Equal(t, dt.Unix(), (*originFrame.Fields[0].At(0).(*time.Time)).Unix()) + require.Equal(t, dt.Unix(), (*originFrame.Fields[1].At(0).(*time.Time)).Unix()) + require.Equal(t, dt.Unix(), (*originFrame.Fields[2].At(0).(*time.Time)).Unix()) + require.Equal(t, dt.Unix(), (*originFrame.Fields[3].At(0).(*time.Time)).Unix()) + require.Equal(t, dt.Unix(), (*originFrame.Fields[4].At(0).(*time.Time)).Unix()) + require.Equal(t, dt.Unix(), (*originFrame.Fields[5].At(0).(*time.Time)).Unix()) + require.Nil(t, originFrame.Fields[6].At(0)) + }) + + t.Run("Given row values with float32 as time columns", func(t *testing.T) { + tSeconds := float32(dt.Unix()) + var nilInt *float32 + + originFrame := data.NewFrame("", + data.NewField("time1", nil, []float32{ + tSeconds, + }), + data.NewField("time2", nil, []*float32{ + util.Pointer(tSeconds), + }), + data.NewField("time7", nil, []*float32{ + nilInt, + }), + ) + for i := 0; i < len(originFrame.Fields); i++ { + err := convertSQLTimeColumnToEpochMS(originFrame, i) + require.NoError(t, err) + } + require.Equal(t, int64(tSeconds), (*originFrame.Fields[0].At(0).(*time.Time)).Unix()) + require.Equal(t, int64(tSeconds), (*originFrame.Fields[1].At(0).(*time.Time)).Unix()) + require.Nil(t, originFrame.Fields[2].At(0)) + }) + + t.Run("Given row with value columns, would be converted to float64", func(t *testing.T) { + originFrame := data.NewFrame("", + data.NewField("value1", nil, []int64{ + int64(1), + }), + data.NewField("value2", nil, []*int64{ + util.Pointer(int64(1)), + }), + data.NewField("value3", nil, []int32{ + int32(1), + }), + data.NewField("value4", nil, []*int32{ + util.Pointer(int32(1)), + }), + data.NewField("value5", nil, []int16{ + int16(1), + }), + data.NewField("value6", nil, []*int16{ + util.Pointer(int16(1)), + }), + data.NewField("value7", nil, []int8{ + int8(1), + }), + data.NewField("value8", nil, []*int8{ + util.Pointer(int8(1)), + }), + data.NewField("value9", nil, []float64{ + float64(1), + }), + data.NewField("value10", nil, []*float64{ + util.Pointer(1.0), + }), + data.NewField("value11", nil, []float32{ + float32(1), + }), + data.NewField("value12", nil, []*float32{ + util.Pointer(float32(1)), + }), + data.NewField("value13", nil, []uint64{ + uint64(1), + }), + data.NewField("value14", nil, []*uint64{ + util.Pointer(uint64(1)), + }), + data.NewField("value15", nil, []uint32{ + uint32(1), + }), + data.NewField("value16", nil, []*uint32{ + util.Pointer(uint32(1)), + }), + data.NewField("value17", nil, []uint16{ + uint16(1), + }), + data.NewField("value18", nil, []*uint16{ + util.Pointer(uint16(1)), + }), + data.NewField("value19", nil, []uint8{ + uint8(1), + }), + data.NewField("value20", nil, []*uint8{ + util.Pointer(uint8(1)), + }), + ) + for i := 0; i < len(originFrame.Fields); i++ { + _, err := convertSQLValueColumnToFloat(originFrame, i) + require.NoError(t, err) + if i == 8 { + require.Equal(t, float64(1), originFrame.Fields[i].At(0).(float64)) + } else { + require.NotNil(t, originFrame.Fields[i].At(0).(*float64)) + require.Equal(t, float64(1), *originFrame.Fields[i].At(0).(*float64)) + } + } + }) + + t.Run("Given row with nil value columns", func(t *testing.T) { + var int64NilPointer *int64 + var int32NilPointer *int32 + var int16NilPointer *int16 + var int8NilPointer *int8 + var float64NilPointer *float64 + var float32NilPointer *float32 + var uint64NilPointer *uint64 + var uint32NilPointer *uint32 + var uint16NilPointer *uint16 + var uint8NilPointer *uint8 + + originFrame := data.NewFrame("", + data.NewField("value1", nil, []*int64{ + int64NilPointer, + }), + data.NewField("value2", nil, []*int32{ + int32NilPointer, + }), + data.NewField("value3", nil, []*int16{ + int16NilPointer, + }), + data.NewField("value4", nil, []*int8{ + int8NilPointer, + }), + data.NewField("value5", nil, []*float64{ + float64NilPointer, + }), + data.NewField("value6", nil, []*float32{ + float32NilPointer, + }), + data.NewField("value7", nil, []*uint64{ + uint64NilPointer, + }), + data.NewField("value8", nil, []*uint32{ + uint32NilPointer, + }), + data.NewField("value9", nil, []*uint16{ + uint16NilPointer, + }), + data.NewField("value10", nil, []*uint8{ + uint8NilPointer, + }), + ) + for i := 0; i < len(originFrame.Fields); i++ { + t.Run("", func(t *testing.T) { + _, err := convertSQLValueColumnToFloat(originFrame, i) + require.NoError(t, err) + require.Nil(t, originFrame.Fields[i].At(0)) + }) + } + }) + + t.Run("Should not return raw connection errors", func(t *testing.T) { + err := net.OpError{Op: "Dial", Err: fmt.Errorf("inner-error")} + transformer := &testQueryResultTransformer{} + dp := DataSourceHandler{ + log: backend.NewLoggerWith("logger", "test"), + queryResultTransformer: transformer, + } + resultErr := dp.TransformQueryError(dp.log, &err) + assert.False(t, transformer.transformQueryErrorWasCalled) + errorText := resultErr.Error() + assert.NotEqual(t, err, resultErr) + assert.NotContains(t, errorText, "inner-error") + assert.Contains(t, errorText, "failed to connect to server") + }) + + t.Run("Should return non-connection errors unmodified", func(t *testing.T) { + err := fmt.Errorf("normal error") + transformer := &testQueryResultTransformer{} + dp := DataSourceHandler{ + log: backend.NewLoggerWith("logger", "test"), + queryResultTransformer: transformer, + } + resultErr := dp.TransformQueryError(dp.log, err) + assert.True(t, transformer.transformQueryErrorWasCalled) + assert.Equal(t, err, resultErr) + assert.ErrorIs(t, err, resultErr) + }) +} + +type testQueryResultTransformer struct { + transformQueryErrorWasCalled bool +} + +func (t *testQueryResultTransformer) TransformQueryError(_ log.Logger, err error) error { + t.transformQueryErrorWasCalled = true + return err +} + +func (t *testQueryResultTransformer) GetConverterList() []sqlutil.StringConverter { + return nil +} diff --git a/pkg/tsdb/mysql/sqleng/util/util.go b/pkg/tsdb/mysql/sqleng/util/util.go new file mode 100644 index 00000000000..f6b5d330c17 --- /dev/null +++ b/pkg/tsdb/mysql/sqleng/util/util.go @@ -0,0 +1,3 @@ +package util + +func Pointer[T any](v T) *T { return &v } From 7ce75841515bdbed5dbd79f876c4e2206a1fb413 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Farkas?= Date: Mon, 15 Apr 2024 14:28:03 +0200 Subject: [PATCH 010/147] postgres: decouple sqleng (#86055) --- .../grafana-postgresql-datasource/macros.go | 2 +- .../grafana-postgresql-datasource/postgres.go | 2 +- .../postgres_snapshot_test.go | 2 +- .../postgres_test.go | 2 +- .../sqleng/sql_engine.go | 642 ++++++++++++++++++ .../sqleng/sql_engine_test.go | 438 ++++++++++++ .../sqleng/util/util.go | 3 + .../tlsmanager.go | 2 +- .../tlsmanager_test.go | 2 +- 9 files changed, 1089 insertions(+), 6 deletions(-) create mode 100644 pkg/tsdb/grafana-postgresql-datasource/sqleng/sql_engine.go create mode 100644 pkg/tsdb/grafana-postgresql-datasource/sqleng/sql_engine_test.go create mode 100644 pkg/tsdb/grafana-postgresql-datasource/sqleng/util/util.go diff --git a/pkg/tsdb/grafana-postgresql-datasource/macros.go b/pkg/tsdb/grafana-postgresql-datasource/macros.go index 42c7abf1de9..f6b0f893da0 100644 --- a/pkg/tsdb/grafana-postgresql-datasource/macros.go +++ b/pkg/tsdb/grafana-postgresql-datasource/macros.go @@ -9,7 +9,7 @@ import ( "github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend/gtime" - "github.com/grafana/grafana/pkg/tsdb/sqleng" + "github.com/grafana/grafana/pkg/tsdb/grafana-postgresql-datasource/sqleng" ) const rsIdentifier = `([_a-zA-Z0-9]+)` diff --git a/pkg/tsdb/grafana-postgresql-datasource/postgres.go b/pkg/tsdb/grafana-postgresql-datasource/postgres.go index 95b5ec96e1c..4f2c1ee3c90 100644 --- a/pkg/tsdb/grafana-postgresql-datasource/postgres.go +++ b/pkg/tsdb/grafana-postgresql-datasource/postgres.go @@ -19,7 +19,7 @@ import ( "github.com/grafana/grafana-plugin-sdk-go/backend/log" "github.com/grafana/grafana/pkg/setting" - "github.com/grafana/grafana/pkg/tsdb/sqleng" + "github.com/grafana/grafana/pkg/tsdb/grafana-postgresql-datasource/sqleng" ) func ProvideService(cfg *setting.Cfg) *Service { diff --git a/pkg/tsdb/grafana-postgresql-datasource/postgres_snapshot_test.go b/pkg/tsdb/grafana-postgresql-datasource/postgres_snapshot_test.go index b3c5a04aae6..e0d9e307ae0 100644 --- a/pkg/tsdb/grafana-postgresql-datasource/postgres_snapshot_test.go +++ b/pkg/tsdb/grafana-postgresql-datasource/postgres_snapshot_test.go @@ -16,7 +16,7 @@ import ( "github.com/grafana/grafana-plugin-sdk-go/experimental" "github.com/stretchr/testify/require" - "github.com/grafana/grafana/pkg/tsdb/sqleng" + "github.com/grafana/grafana/pkg/tsdb/grafana-postgresql-datasource/sqleng" ) var updateGoldenFiles = false diff --git a/pkg/tsdb/grafana-postgresql-datasource/postgres_test.go b/pkg/tsdb/grafana-postgresql-datasource/postgres_test.go index f5ccc6787f4..d16b9d53f31 100644 --- a/pkg/tsdb/grafana-postgresql-datasource/postgres_test.go +++ b/pkg/tsdb/grafana-postgresql-datasource/postgres_test.go @@ -15,7 +15,7 @@ import ( "github.com/stretchr/testify/require" "github.com/grafana/grafana/pkg/setting" - "github.com/grafana/grafana/pkg/tsdb/sqleng" + "github.com/grafana/grafana/pkg/tsdb/grafana-postgresql-datasource/sqleng" _ "github.com/lib/pq" ) diff --git a/pkg/tsdb/grafana-postgresql-datasource/sqleng/sql_engine.go b/pkg/tsdb/grafana-postgresql-datasource/sqleng/sql_engine.go new file mode 100644 index 00000000000..060e2bcb02e --- /dev/null +++ b/pkg/tsdb/grafana-postgresql-datasource/sqleng/sql_engine.go @@ -0,0 +1,642 @@ +package sqleng + +import ( + "context" + "database/sql" + "encoding/json" + "errors" + "fmt" + "net" + "regexp" + "runtime/debug" + "strconv" + "strings" + "sync" + "time" + + "github.com/grafana/grafana-plugin-sdk-go/backend" + "github.com/grafana/grafana-plugin-sdk-go/data" + "github.com/grafana/grafana-plugin-sdk-go/data/sqlutil" + + "github.com/grafana/grafana-plugin-sdk-go/backend/gtime" + "github.com/grafana/grafana-plugin-sdk-go/backend/log" +) + +// MetaKeyExecutedQueryString is the key where the executed query should get stored +const MetaKeyExecutedQueryString = "executedQueryString" + +// SQLMacroEngine interpolates macros into sql. It takes in the Query to have access to query context and +// timeRange to be able to generate queries that use from and to. +type SQLMacroEngine interface { + Interpolate(query *backend.DataQuery, timeRange backend.TimeRange, sql string) (string, error) +} + +// SqlQueryResultTransformer transforms a query result row to RowValues with proper types. +type SqlQueryResultTransformer interface { + // TransformQueryError transforms a query error. + TransformQueryError(logger log.Logger, err error) error + GetConverterList() []sqlutil.StringConverter +} + +type JsonData struct { + MaxOpenConns int `json:"maxOpenConns"` + MaxIdleConns int `json:"maxIdleConns"` + ConnMaxLifetime int `json:"connMaxLifetime"` + ConnectionTimeout int `json:"connectionTimeout"` + Timescaledb bool `json:"timescaledb"` + Mode string `json:"sslmode"` + ConfigurationMethod string `json:"tlsConfigurationMethod"` + TlsSkipVerify bool `json:"tlsSkipVerify"` + RootCertFile string `json:"sslRootCertFile"` + CertFile string `json:"sslCertFile"` + CertKeyFile string `json:"sslKeyFile"` + Timezone string `json:"timezone"` + Encrypt string `json:"encrypt"` + Servername string `json:"servername"` + TimeInterval string `json:"timeInterval"` + Database string `json:"database"` + SecureDSProxy bool `json:"enableSecureSocksProxy"` + SecureDSProxyUsername string `json:"secureSocksProxyUsername"` + AllowCleartextPasswords bool `json:"allowCleartextPasswords"` + AuthenticationType string `json:"authenticationType"` +} + +type DataSourceInfo struct { + JsonData JsonData + URL string + User string + Database string + ID int64 + Updated time.Time + UID string + DecryptedSecureJSONData map[string]string +} + +type DataPluginConfiguration struct { + DSInfo DataSourceInfo + TimeColumnNames []string + MetricColumnTypes []string + RowLimit int64 +} + +type DataSourceHandler struct { + macroEngine SQLMacroEngine + queryResultTransformer SqlQueryResultTransformer + db *sql.DB + timeColumnNames []string + metricColumnTypes []string + log log.Logger + dsInfo DataSourceInfo + rowLimit int64 + userError string +} + +type QueryJson struct { + RawSql string `json:"rawSql"` + Fill bool `json:"fill"` + FillInterval float64 `json:"fillInterval"` + FillMode string `json:"fillMode"` + FillValue float64 `json:"fillValue"` + Format string `json:"format"` +} + +func (e *DataSourceHandler) TransformQueryError(logger log.Logger, err error) error { + // OpError is the error type usually returned by functions in the net + // package. It describes the operation, network type, and address of + // an error. We log this error rather than return it to the client + // for security purposes. + var opErr *net.OpError + if errors.As(err, &opErr) { + logger.Error("Query error", "err", err) + return fmt.Errorf("failed to connect to server - %s", e.userError) + } + + return e.queryResultTransformer.TransformQueryError(logger, err) +} + +func NewQueryDataHandler(userFacingDefaultError string, db *sql.DB, config DataPluginConfiguration, queryResultTransformer SqlQueryResultTransformer, + macroEngine SQLMacroEngine, log log.Logger) (*DataSourceHandler, error) { + queryDataHandler := DataSourceHandler{ + queryResultTransformer: queryResultTransformer, + macroEngine: macroEngine, + timeColumnNames: []string{"time"}, + log: log, + dsInfo: config.DSInfo, + rowLimit: config.RowLimit, + userError: userFacingDefaultError, + } + + if len(config.TimeColumnNames) > 0 { + queryDataHandler.timeColumnNames = config.TimeColumnNames + } + + if len(config.MetricColumnTypes) > 0 { + queryDataHandler.metricColumnTypes = config.MetricColumnTypes + } + + queryDataHandler.db = db + return &queryDataHandler, nil +} + +type DBDataResponse struct { + dataResponse backend.DataResponse + refID string +} + +func (e *DataSourceHandler) Dispose() { + e.log.Debug("Disposing DB...") + if e.db != nil { + if err := e.db.Close(); err != nil { + e.log.Error("Failed to dispose db", "error", err) + } + } + e.log.Debug("DB disposed") +} + +func (e *DataSourceHandler) Ping() error { + return e.db.Ping() +} + +func (e *DataSourceHandler) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) { + result := backend.NewQueryDataResponse() + ch := make(chan DBDataResponse, len(req.Queries)) + var wg sync.WaitGroup + // Execute each query in a goroutine and wait for them to finish afterwards + for _, query := range req.Queries { + queryjson := QueryJson{ + Fill: false, + Format: "time_series", + } + err := json.Unmarshal(query.JSON, &queryjson) + if err != nil { + return nil, fmt.Errorf("error unmarshal query json: %w", err) + } + + // the fill-params are only stored inside this function, during query-interpolation. we do not support + // sending them in "from the outside" + if queryjson.Fill || queryjson.FillInterval != 0.0 || queryjson.FillMode != "" || queryjson.FillValue != 0.0 { + return nil, fmt.Errorf("query fill-parameters not supported") + } + + if queryjson.RawSql == "" { + continue + } + + wg.Add(1) + go e.executeQuery(query, &wg, ctx, ch, queryjson) + } + + wg.Wait() + + // Read results from channels + close(ch) + result.Responses = make(map[string]backend.DataResponse) + for queryResult := range ch { + result.Responses[queryResult.refID] = queryResult.dataResponse + } + + return result, nil +} + +func (e *DataSourceHandler) executeQuery(query backend.DataQuery, wg *sync.WaitGroup, queryContext context.Context, + ch chan DBDataResponse, queryJson QueryJson) { + defer wg.Done() + queryResult := DBDataResponse{ + dataResponse: backend.DataResponse{}, + refID: query.RefID, + } + + logger := e.log.FromContext(queryContext) + + defer func() { + if r := recover(); r != nil { + logger.Error("ExecuteQuery panic", "error", r, "stack", string(debug.Stack())) + if theErr, ok := r.(error); ok { + queryResult.dataResponse.Error = theErr + } else if theErrString, ok := r.(string); ok { + queryResult.dataResponse.Error = fmt.Errorf(theErrString) + } else { + queryResult.dataResponse.Error = fmt.Errorf("unexpected error - %s", e.userError) + } + ch <- queryResult + } + }() + + if queryJson.RawSql == "" { + panic("Query model property rawSql should not be empty at this point") + } + + timeRange := query.TimeRange + + errAppendDebug := func(frameErr string, err error, query string) { + var emptyFrame data.Frame + emptyFrame.SetMeta(&data.FrameMeta{ + ExecutedQueryString: query, + }) + queryResult.dataResponse.Error = fmt.Errorf("%s: %w", frameErr, err) + queryResult.dataResponse.Frames = data.Frames{&emptyFrame} + ch <- queryResult + } + + // global substitutions + interpolatedQuery := Interpolate(query, timeRange, e.dsInfo.JsonData.TimeInterval, queryJson.RawSql) + + // data source specific substitutions + interpolatedQuery, err := e.macroEngine.Interpolate(&query, timeRange, interpolatedQuery) + if err != nil { + errAppendDebug("interpolation failed", e.TransformQueryError(logger, err), interpolatedQuery) + return + } + + rows, err := e.db.QueryContext(queryContext, interpolatedQuery) + if err != nil { + errAppendDebug("db query error", e.TransformQueryError(logger, err), interpolatedQuery) + return + } + defer func() { + if err := rows.Close(); err != nil { + logger.Warn("Failed to close rows", "err", err) + } + }() + + qm, err := e.newProcessCfg(query, queryContext, rows, interpolatedQuery) + if err != nil { + errAppendDebug("failed to get configurations", err, interpolatedQuery) + return + } + + // Convert row.Rows to dataframe + stringConverters := e.queryResultTransformer.GetConverterList() + frame, err := sqlutil.FrameFromRows(rows, e.rowLimit, sqlutil.ToConverters(stringConverters...)...) + if err != nil { + errAppendDebug("convert frame from rows error", err, interpolatedQuery) + return + } + + if frame.Meta == nil { + frame.Meta = &data.FrameMeta{} + } + + frame.Meta.ExecutedQueryString = interpolatedQuery + + // If no rows were returned, clear any previously set `Fields` with a single empty `data.Field` slice. + // Then assign `queryResult.dataResponse.Frames` the current single frame with that single empty Field. + // This assures 1) our visualization doesn't display unwanted empty fields, and also that 2) + // additionally-needed frame data stays intact and is correctly passed to our visulization. + if frame.Rows() == 0 { + frame.Fields = []*data.Field{} + queryResult.dataResponse.Frames = data.Frames{frame} + ch <- queryResult + return + } + + if err := convertSQLTimeColumnsToEpochMS(frame, qm); err != nil { + errAppendDebug("converting time columns failed", err, interpolatedQuery) + return + } + + if qm.Format == dataQueryFormatSeries { + // time series has to have time column + if qm.timeIndex == -1 { + errAppendDebug("db has no time column", errors.New("no time column found"), interpolatedQuery) + return + } + + // Make sure to name the time field 'Time' to be backward compatible with Grafana pre-v8. + frame.Fields[qm.timeIndex].Name = data.TimeSeriesTimeFieldName + + for i := range qm.columnNames { + if i == qm.timeIndex || i == qm.metricIndex { + continue + } + + if t := frame.Fields[i].Type(); t == data.FieldTypeString || t == data.FieldTypeNullableString { + continue + } + + var err error + if frame, err = convertSQLValueColumnToFloat(frame, i); err != nil { + errAppendDebug("convert value to float failed", err, interpolatedQuery) + return + } + } + + tsSchema := frame.TimeSeriesSchema() + if tsSchema.Type == data.TimeSeriesTypeLong { + var err error + originalData := frame + frame, err = data.LongToWide(frame, qm.FillMissing) + if err != nil { + errAppendDebug("failed to convert long to wide series when converting from dataframe", err, interpolatedQuery) + return + } + + // Before 8x, a special metric column was used to name time series. The LongToWide transforms that into a metric label on the value field. + // But that makes series name have both the value column name AND the metric name. So here we are removing the metric label here and moving it to the + // field name to get the same naming for the series as pre v8 + if len(originalData.Fields) == 3 { + for _, field := range frame.Fields { + if len(field.Labels) == 1 { // 7x only supported one label + name, ok := field.Labels["metric"] + if ok { + field.Name = name + field.Labels = nil + } + } + } + } + } + if qm.FillMissing != nil { + // we align the start-time + startUnixTime := qm.TimeRange.From.Unix() / int64(qm.Interval.Seconds()) * int64(qm.Interval.Seconds()) + alignedTimeRange := backend.TimeRange{ + From: time.Unix(startUnixTime, 0), + To: qm.TimeRange.To, + } + + var err error + frame, err = sqlutil.ResampleWideFrame(frame, qm.FillMissing, alignedTimeRange, qm.Interval) + if err != nil { + logger.Error("Failed to resample dataframe", "err", err) + frame.AppendNotices(data.Notice{Text: "Failed to resample dataframe", Severity: data.NoticeSeverityWarning}) + } + } + } + + queryResult.dataResponse.Frames = data.Frames{frame} + ch <- queryResult +} + +// Interpolate provides global macros/substitutions for all sql datasources. +var Interpolate = func(query backend.DataQuery, timeRange backend.TimeRange, timeInterval string, sql string) string { + interval := query.Interval + + sql = strings.ReplaceAll(sql, "$__interval_ms", strconv.FormatInt(interval.Milliseconds(), 10)) + sql = strings.ReplaceAll(sql, "$__interval", gtime.FormatInterval(interval)) + sql = strings.ReplaceAll(sql, "$__unixEpochFrom()", fmt.Sprintf("%d", timeRange.From.UTC().Unix())) + sql = strings.ReplaceAll(sql, "$__unixEpochTo()", fmt.Sprintf("%d", timeRange.To.UTC().Unix())) + + return sql +} + +func (e *DataSourceHandler) newProcessCfg(query backend.DataQuery, queryContext context.Context, + rows *sql.Rows, interpolatedQuery string) (*dataQueryModel, error) { + columnNames, err := rows.Columns() + if err != nil { + return nil, err + } + columnTypes, err := rows.ColumnTypes() + if err != nil { + return nil, err + } + + qm := &dataQueryModel{ + columnTypes: columnTypes, + columnNames: columnNames, + timeIndex: -1, + timeEndIndex: -1, + metricIndex: -1, + metricPrefix: false, + queryContext: queryContext, + } + + queryJson := QueryJson{} + err = json.Unmarshal(query.JSON, &queryJson) + if err != nil { + return nil, err + } + + if queryJson.Fill { + qm.FillMissing = &data.FillMissing{} + qm.Interval = time.Duration(queryJson.FillInterval * float64(time.Second)) + switch strings.ToLower(queryJson.FillMode) { + case "null": + qm.FillMissing.Mode = data.FillModeNull + case "previous": + qm.FillMissing.Mode = data.FillModePrevious + case "value": + qm.FillMissing.Mode = data.FillModeValue + qm.FillMissing.Value = queryJson.FillValue + default: + } + } + + qm.TimeRange.From = query.TimeRange.From.UTC() + qm.TimeRange.To = query.TimeRange.To.UTC() + + switch queryJson.Format { + case "time_series": + qm.Format = dataQueryFormatSeries + case "table": + qm.Format = dataQueryFormatTable + default: + panic(fmt.Sprintf("Unrecognized query model format: %q", queryJson.Format)) + } + + for i, col := range qm.columnNames { + for _, tc := range e.timeColumnNames { + if col == tc { + qm.timeIndex = i + break + } + } + + if qm.Format == dataQueryFormatTable && col == "timeend" { + qm.timeEndIndex = i + continue + } + + switch col { + case "metric": + qm.metricIndex = i + default: + if qm.metricIndex == -1 { + columnType := qm.columnTypes[i].DatabaseTypeName() + for _, mct := range e.metricColumnTypes { + if columnType == mct { + qm.metricIndex = i + continue + } + } + } + } + } + qm.InterpolatedQuery = interpolatedQuery + return qm, nil +} + +// dataQueryFormat is the type of query. +type dataQueryFormat string + +const ( + // dataQueryFormatTable identifies a table query (default). + dataQueryFormatTable dataQueryFormat = "table" + // dataQueryFormatSeries identifies a time series query. + dataQueryFormatSeries dataQueryFormat = "time_series" +) + +type dataQueryModel struct { + InterpolatedQuery string // property not set until after Interpolate() + Format dataQueryFormat + TimeRange backend.TimeRange + FillMissing *data.FillMissing // property not set until after Interpolate() + Interval time.Duration + columnNames []string + columnTypes []*sql.ColumnType + timeIndex int + timeEndIndex int + metricIndex int + metricPrefix bool + queryContext context.Context +} + +func convertSQLTimeColumnsToEpochMS(frame *data.Frame, qm *dataQueryModel) error { + if qm.timeIndex != -1 { + if err := convertSQLTimeColumnToEpochMS(frame, qm.timeIndex); err != nil { + return fmt.Errorf("%v: %w", "failed to convert time column", err) + } + } + + if qm.timeEndIndex != -1 { + if err := convertSQLTimeColumnToEpochMS(frame, qm.timeEndIndex); err != nil { + return fmt.Errorf("%v: %w", "failed to convert timeend column", err) + } + } + + return nil +} + +// convertSQLTimeColumnToEpochMS converts column named time to unix timestamp in milliseconds +// to make native datetime types and epoch dates work in annotation and table queries. +func convertSQLTimeColumnToEpochMS(frame *data.Frame, timeIndex int) error { + if timeIndex < 0 || timeIndex >= len(frame.Fields) { + return fmt.Errorf("timeIndex %d is out of range", timeIndex) + } + + origin := frame.Fields[timeIndex] + valueType := origin.Type() + if valueType == data.FieldTypeTime || valueType == data.FieldTypeNullableTime { + return nil + } + + newField := data.NewFieldFromFieldType(data.FieldTypeNullableTime, 0) + newField.Name = origin.Name + newField.Labels = origin.Labels + + valueLength := origin.Len() + for i := 0; i < valueLength; i++ { + v, err := origin.NullableFloatAt(i) + if err != nil { + return fmt.Errorf("unable to convert data to a time field") + } + if v == nil { + newField.Append(nil) + } else { + timestamp := time.Unix(0, int64(epochPrecisionToMS(*v))*int64(time.Millisecond)) + newField.Append(×tamp) + } + } + frame.Fields[timeIndex] = newField + + return nil +} + +// convertSQLValueColumnToFloat converts timeseries value column to float. +func convertSQLValueColumnToFloat(frame *data.Frame, Index int) (*data.Frame, error) { + if Index < 0 || Index >= len(frame.Fields) { + return frame, fmt.Errorf("metricIndex %d is out of range", Index) + } + + origin := frame.Fields[Index] + valueType := origin.Type() + if valueType == data.FieldTypeFloat64 || valueType == data.FieldTypeNullableFloat64 { + return frame, nil + } + + newField := data.NewFieldFromFieldType(data.FieldTypeNullableFloat64, origin.Len()) + newField.Name = origin.Name + newField.Labels = origin.Labels + + for i := 0; i < origin.Len(); i++ { + v, err := origin.NullableFloatAt(i) + if err != nil { + return frame, err + } + newField.Set(i, v) + } + + frame.Fields[Index] = newField + + return frame, nil +} + +func SetupFillmode(query *backend.DataQuery, interval time.Duration, fillmode string) error { + rawQueryProp := make(map[string]any) + queryBytes, err := query.JSON.MarshalJSON() + if err != nil { + return err + } + err = json.Unmarshal(queryBytes, &rawQueryProp) + if err != nil { + return err + } + rawQueryProp["fill"] = true + rawQueryProp["fillInterval"] = interval.Seconds() + + switch fillmode { + case "NULL": + rawQueryProp["fillMode"] = "null" + case "previous": + rawQueryProp["fillMode"] = "previous" + default: + rawQueryProp["fillMode"] = "value" + floatVal, err := strconv.ParseFloat(fillmode, 64) + if err != nil { + return fmt.Errorf("error parsing fill value %v", fillmode) + } + rawQueryProp["fillValue"] = floatVal + } + query.JSON, err = json.Marshal(rawQueryProp) + if err != nil { + return err + } + return nil +} + +type SQLMacroEngineBase struct{} + +func NewSQLMacroEngineBase() *SQLMacroEngineBase { + return &SQLMacroEngineBase{} +} + +func (m *SQLMacroEngineBase) ReplaceAllStringSubmatchFunc(re *regexp.Regexp, str string, repl func([]string) string) string { + result := "" + lastIndex := 0 + + for _, v := range re.FindAllStringSubmatchIndex(str, -1) { + groups := []string{} + for i := 0; i < len(v); i += 2 { + groups = append(groups, str[v[i]:v[i+1]]) + } + + result += str[lastIndex:v[0]] + repl(groups) + lastIndex = v[1] + } + + return result + str[lastIndex:] +} + +// epochPrecisionToMS converts epoch precision to millisecond, if needed. +// Only seconds to milliseconds supported right now +func epochPrecisionToMS(value float64) float64 { + s := strconv.FormatFloat(value, 'e', -1, 64) + if strings.HasSuffix(s, "e+09") { + return value * float64(1e3) + } + + if strings.HasSuffix(s, "e+18") { + return value / float64(time.Millisecond) + } + + return value +} diff --git a/pkg/tsdb/grafana-postgresql-datasource/sqleng/sql_engine_test.go b/pkg/tsdb/grafana-postgresql-datasource/sqleng/sql_engine_test.go new file mode 100644 index 00000000000..b7f422327ac --- /dev/null +++ b/pkg/tsdb/grafana-postgresql-datasource/sqleng/sql_engine_test.go @@ -0,0 +1,438 @@ +package sqleng + +import ( + "fmt" + "net" + "testing" + "time" + + "github.com/grafana/grafana-plugin-sdk-go/backend" + "github.com/grafana/grafana-plugin-sdk-go/data" + "github.com/grafana/grafana-plugin-sdk-go/data/sqlutil" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/grafana/grafana-plugin-sdk-go/backend/log" + "github.com/grafana/grafana/pkg/tsdb/grafana-postgresql-datasource/sqleng/util" +) + +func TestSQLEngine(t *testing.T) { + dt := time.Date(2018, 3, 14, 21, 20, 6, int(527345*time.Microsecond), time.UTC) + + t.Run("Handle interpolating $__interval and $__interval_ms", func(t *testing.T) { + from := time.Date(2018, 4, 12, 18, 0, 0, 0, time.UTC) + to := from.Add(5 * time.Minute) + timeRange := backend.TimeRange{From: from, To: to} + + text := "$__interval $__timeGroupAlias(time,$__interval) $__interval_ms" + + t.Run("interpolate 10 minutes $__interval", func(t *testing.T) { + query := backend.DataQuery{JSON: []byte("{}"), MaxDataPoints: 1500, Interval: time.Minute * 10} + sql := Interpolate(query, timeRange, "", text) + require.Equal(t, "10m $__timeGroupAlias(time,10m) 600000", sql) + }) + + t.Run("interpolate 4seconds $__interval", func(t *testing.T) { + query := backend.DataQuery{JSON: []byte("{}"), MaxDataPoints: 1500, Interval: time.Second * 4} + sql := Interpolate(query, timeRange, "", text) + require.Equal(t, "4s $__timeGroupAlias(time,4s) 4000", sql) + }) + + t.Run("interpolate 200 milliseconds $__interval", func(t *testing.T) { + query := backend.DataQuery{JSON: []byte("{}"), MaxDataPoints: 1500, Interval: time.Millisecond * 200} + sql := Interpolate(query, timeRange, "", text) + require.Equal(t, "200ms $__timeGroupAlias(time,200ms) 200", sql) + }) + }) + + t.Run("Given a time range between 2018-04-12 00:00 and 2018-04-12 00:05", func(t *testing.T) { + from := time.Date(2018, 4, 12, 18, 0, 0, 0, time.UTC) + to := from.Add(5 * time.Minute) + timeRange := backend.TimeRange{From: from, To: to} + query := backend.DataQuery{JSON: []byte("{}"), MaxDataPoints: 1500, Interval: time.Second * 60} + + t.Run("interpolate __unixEpochFrom function", func(t *testing.T) { + sql := Interpolate(query, timeRange, "", "select $__unixEpochFrom()") + require.Equal(t, fmt.Sprintf("select %d", from.Unix()), sql) + }) + + t.Run("interpolate __unixEpochTo function", func(t *testing.T) { + sql := Interpolate(query, timeRange, "", "select $__unixEpochTo()") + require.Equal(t, fmt.Sprintf("select %d", to.Unix()), sql) + }) + }) + + t.Run("Given row values with int64 as time columns", func(t *testing.T) { + tSeconds := dt.Unix() + tMilliseconds := dt.UnixNano() / 1e6 + tNanoSeconds := dt.UnixNano() + var nilPointer *int64 + + originFrame := data.NewFrame("", + data.NewField("time1", nil, []int64{ + tSeconds, + }), + data.NewField("time2", nil, []*int64{ + util.Pointer(tSeconds), + }), + data.NewField("time3", nil, []int64{ + tMilliseconds, + }), + data.NewField("time4", nil, []*int64{ + util.Pointer(tMilliseconds), + }), + data.NewField("time5", nil, []int64{ + tNanoSeconds, + }), + data.NewField("time6", nil, []*int64{ + util.Pointer(tNanoSeconds), + }), + data.NewField("time7", nil, []*int64{ + nilPointer, + }), + ) + + for i := 0; i < len(originFrame.Fields); i++ { + err := convertSQLTimeColumnToEpochMS(originFrame, i) + require.NoError(t, err) + } + + require.Equal(t, dt.Unix(), (*originFrame.Fields[0].At(0).(*time.Time)).Unix()) + require.Equal(t, dt.Unix(), (*originFrame.Fields[1].At(0).(*time.Time)).Unix()) + require.Equal(t, dt.Unix(), (*originFrame.Fields[2].At(0).(*time.Time)).Unix()) + require.Equal(t, dt.Unix(), (*originFrame.Fields[3].At(0).(*time.Time)).Unix()) + require.Equal(t, dt.Unix(), (*originFrame.Fields[4].At(0).(*time.Time)).Unix()) + require.Equal(t, dt.Unix(), (*originFrame.Fields[5].At(0).(*time.Time)).Unix()) + require.Nil(t, originFrame.Fields[6].At(0)) + }) + + t.Run("Given row values with uint64 as time columns", func(t *testing.T) { + tSeconds := uint64(dt.Unix()) + tMilliseconds := uint64(dt.UnixNano() / 1e6) + tNanoSeconds := uint64(dt.UnixNano()) + var nilPointer *uint64 + + originFrame := data.NewFrame("", + data.NewField("time1", nil, []uint64{ + tSeconds, + }), + data.NewField("time2", nil, []*uint64{ + util.Pointer(tSeconds), + }), + data.NewField("time3", nil, []uint64{ + tMilliseconds, + }), + data.NewField("time4", nil, []*uint64{ + util.Pointer(tMilliseconds), + }), + data.NewField("time5", nil, []uint64{ + tNanoSeconds, + }), + data.NewField("time6", nil, []*uint64{ + util.Pointer(tNanoSeconds), + }), + data.NewField("time7", nil, []*uint64{ + nilPointer, + }), + ) + + for i := 0; i < len(originFrame.Fields); i++ { + err := convertSQLTimeColumnToEpochMS(originFrame, i) + require.NoError(t, err) + } + + require.Equal(t, dt.Unix(), (*originFrame.Fields[0].At(0).(*time.Time)).Unix()) + require.Equal(t, dt.Unix(), (*originFrame.Fields[1].At(0).(*time.Time)).Unix()) + require.Equal(t, dt.Unix(), (*originFrame.Fields[2].At(0).(*time.Time)).Unix()) + require.Equal(t, dt.Unix(), (*originFrame.Fields[3].At(0).(*time.Time)).Unix()) + require.Equal(t, dt.Unix(), (*originFrame.Fields[4].At(0).(*time.Time)).Unix()) + require.Equal(t, dt.Unix(), (*originFrame.Fields[5].At(0).(*time.Time)).Unix()) + require.Nil(t, originFrame.Fields[6].At(0)) + }) + + t.Run("Given row values with int32 as time columns", func(t *testing.T) { + tSeconds := int32(dt.Unix()) + var nilInt *int32 + + originFrame := data.NewFrame("", + data.NewField("time1", nil, []int32{ + tSeconds, + }), + data.NewField("time2", nil, []*int32{ + util.Pointer(tSeconds), + }), + data.NewField("time7", nil, []*int32{ + nilInt, + }), + ) + for i := 0; i < 3; i++ { + err := convertSQLTimeColumnToEpochMS(originFrame, i) + require.NoError(t, err) + } + + require.Equal(t, dt.Unix(), (*originFrame.Fields[0].At(0).(*time.Time)).Unix()) + require.Equal(t, dt.Unix(), (*originFrame.Fields[1].At(0).(*time.Time)).Unix()) + require.Nil(t, originFrame.Fields[2].At(0)) + }) + + t.Run("Given row values with uint32 as time columns", func(t *testing.T) { + tSeconds := uint32(dt.Unix()) + var nilInt *uint32 + + originFrame := data.NewFrame("", + data.NewField("time1", nil, []uint32{ + tSeconds, + }), + data.NewField("time2", nil, []*uint32{ + util.Pointer(tSeconds), + }), + data.NewField("time7", nil, []*uint32{ + nilInt, + }), + ) + for i := 0; i < len(originFrame.Fields); i++ { + err := convertSQLTimeColumnToEpochMS(originFrame, i) + require.NoError(t, err) + } + require.Equal(t, dt.Unix(), (*originFrame.Fields[0].At(0).(*time.Time)).Unix()) + require.Equal(t, dt.Unix(), (*originFrame.Fields[1].At(0).(*time.Time)).Unix()) + require.Nil(t, originFrame.Fields[2].At(0)) + }) + + t.Run("Given row values with float64 as time columns", func(t *testing.T) { + tSeconds := float64(dt.UnixNano()) / float64(time.Second) + tMilliseconds := float64(dt.UnixNano()) / float64(time.Millisecond) + tNanoSeconds := float64(dt.UnixNano()) + var nilPointer *float64 + + originFrame := data.NewFrame("", + data.NewField("time1", nil, []float64{ + tSeconds, + }), + data.NewField("time2", nil, []*float64{ + util.Pointer(tSeconds), + }), + data.NewField("time3", nil, []float64{ + tMilliseconds, + }), + data.NewField("time4", nil, []*float64{ + util.Pointer(tMilliseconds), + }), + data.NewField("time5", nil, []float64{ + tNanoSeconds, + }), + data.NewField("time6", nil, []*float64{ + util.Pointer(tNanoSeconds), + }), + data.NewField("time7", nil, []*float64{ + nilPointer, + }), + ) + + for i := 0; i < len(originFrame.Fields); i++ { + err := convertSQLTimeColumnToEpochMS(originFrame, i) + require.NoError(t, err) + } + + require.Equal(t, dt.Unix(), (*originFrame.Fields[0].At(0).(*time.Time)).Unix()) + require.Equal(t, dt.Unix(), (*originFrame.Fields[1].At(0).(*time.Time)).Unix()) + require.Equal(t, dt.Unix(), (*originFrame.Fields[2].At(0).(*time.Time)).Unix()) + require.Equal(t, dt.Unix(), (*originFrame.Fields[3].At(0).(*time.Time)).Unix()) + require.Equal(t, dt.Unix(), (*originFrame.Fields[4].At(0).(*time.Time)).Unix()) + require.Equal(t, dt.Unix(), (*originFrame.Fields[5].At(0).(*time.Time)).Unix()) + require.Nil(t, originFrame.Fields[6].At(0)) + }) + + t.Run("Given row values with float32 as time columns", func(t *testing.T) { + tSeconds := float32(dt.Unix()) + var nilInt *float32 + + originFrame := data.NewFrame("", + data.NewField("time1", nil, []float32{ + tSeconds, + }), + data.NewField("time2", nil, []*float32{ + util.Pointer(tSeconds), + }), + data.NewField("time7", nil, []*float32{ + nilInt, + }), + ) + for i := 0; i < len(originFrame.Fields); i++ { + err := convertSQLTimeColumnToEpochMS(originFrame, i) + require.NoError(t, err) + } + require.Equal(t, int64(tSeconds), (*originFrame.Fields[0].At(0).(*time.Time)).Unix()) + require.Equal(t, int64(tSeconds), (*originFrame.Fields[1].At(0).(*time.Time)).Unix()) + require.Nil(t, originFrame.Fields[2].At(0)) + }) + + t.Run("Given row with value columns, would be converted to float64", func(t *testing.T) { + originFrame := data.NewFrame("", + data.NewField("value1", nil, []int64{ + int64(1), + }), + data.NewField("value2", nil, []*int64{ + util.Pointer(int64(1)), + }), + data.NewField("value3", nil, []int32{ + int32(1), + }), + data.NewField("value4", nil, []*int32{ + util.Pointer(int32(1)), + }), + data.NewField("value5", nil, []int16{ + int16(1), + }), + data.NewField("value6", nil, []*int16{ + util.Pointer(int16(1)), + }), + data.NewField("value7", nil, []int8{ + int8(1), + }), + data.NewField("value8", nil, []*int8{ + util.Pointer(int8(1)), + }), + data.NewField("value9", nil, []float64{ + float64(1), + }), + data.NewField("value10", nil, []*float64{ + util.Pointer(1.0), + }), + data.NewField("value11", nil, []float32{ + float32(1), + }), + data.NewField("value12", nil, []*float32{ + util.Pointer(float32(1)), + }), + data.NewField("value13", nil, []uint64{ + uint64(1), + }), + data.NewField("value14", nil, []*uint64{ + util.Pointer(uint64(1)), + }), + data.NewField("value15", nil, []uint32{ + uint32(1), + }), + data.NewField("value16", nil, []*uint32{ + util.Pointer(uint32(1)), + }), + data.NewField("value17", nil, []uint16{ + uint16(1), + }), + data.NewField("value18", nil, []*uint16{ + util.Pointer(uint16(1)), + }), + data.NewField("value19", nil, []uint8{ + uint8(1), + }), + data.NewField("value20", nil, []*uint8{ + util.Pointer(uint8(1)), + }), + ) + for i := 0; i < len(originFrame.Fields); i++ { + _, err := convertSQLValueColumnToFloat(originFrame, i) + require.NoError(t, err) + if i == 8 { + require.Equal(t, float64(1), originFrame.Fields[i].At(0).(float64)) + } else { + require.NotNil(t, originFrame.Fields[i].At(0).(*float64)) + require.Equal(t, float64(1), *originFrame.Fields[i].At(0).(*float64)) + } + } + }) + + t.Run("Given row with nil value columns", func(t *testing.T) { + var int64NilPointer *int64 + var int32NilPointer *int32 + var int16NilPointer *int16 + var int8NilPointer *int8 + var float64NilPointer *float64 + var float32NilPointer *float32 + var uint64NilPointer *uint64 + var uint32NilPointer *uint32 + var uint16NilPointer *uint16 + var uint8NilPointer *uint8 + + originFrame := data.NewFrame("", + data.NewField("value1", nil, []*int64{ + int64NilPointer, + }), + data.NewField("value2", nil, []*int32{ + int32NilPointer, + }), + data.NewField("value3", nil, []*int16{ + int16NilPointer, + }), + data.NewField("value4", nil, []*int8{ + int8NilPointer, + }), + data.NewField("value5", nil, []*float64{ + float64NilPointer, + }), + data.NewField("value6", nil, []*float32{ + float32NilPointer, + }), + data.NewField("value7", nil, []*uint64{ + uint64NilPointer, + }), + data.NewField("value8", nil, []*uint32{ + uint32NilPointer, + }), + data.NewField("value9", nil, []*uint16{ + uint16NilPointer, + }), + data.NewField("value10", nil, []*uint8{ + uint8NilPointer, + }), + ) + for i := 0; i < len(originFrame.Fields); i++ { + t.Run("", func(t *testing.T) { + _, err := convertSQLValueColumnToFloat(originFrame, i) + require.NoError(t, err) + require.Nil(t, originFrame.Fields[i].At(0)) + }) + } + }) + + t.Run("Should not return raw connection errors", func(t *testing.T) { + err := net.OpError{Op: "Dial", Err: fmt.Errorf("inner-error")} + transformer := &testQueryResultTransformer{} + dp := DataSourceHandler{ + log: backend.NewLoggerWith("logger", "test"), + queryResultTransformer: transformer, + } + resultErr := dp.TransformQueryError(dp.log, &err) + assert.False(t, transformer.transformQueryErrorWasCalled) + errorText := resultErr.Error() + assert.NotEqual(t, err, resultErr) + assert.NotContains(t, errorText, "inner-error") + assert.Contains(t, errorText, "failed to connect to server") + }) + + t.Run("Should return non-connection errors unmodified", func(t *testing.T) { + err := fmt.Errorf("normal error") + transformer := &testQueryResultTransformer{} + dp := DataSourceHandler{ + log: backend.NewLoggerWith("logger", "test"), + queryResultTransformer: transformer, + } + resultErr := dp.TransformQueryError(dp.log, err) + assert.True(t, transformer.transformQueryErrorWasCalled) + assert.Equal(t, err, resultErr) + assert.ErrorIs(t, err, resultErr) + }) +} + +type testQueryResultTransformer struct { + transformQueryErrorWasCalled bool +} + +func (t *testQueryResultTransformer) TransformQueryError(_ log.Logger, err error) error { + t.transformQueryErrorWasCalled = true + return err +} + +func (t *testQueryResultTransformer) GetConverterList() []sqlutil.StringConverter { + return nil +} diff --git a/pkg/tsdb/grafana-postgresql-datasource/sqleng/util/util.go b/pkg/tsdb/grafana-postgresql-datasource/sqleng/util/util.go new file mode 100644 index 00000000000..f6b5d330c17 --- /dev/null +++ b/pkg/tsdb/grafana-postgresql-datasource/sqleng/util/util.go @@ -0,0 +1,3 @@ +package util + +func Pointer[T any](v T) *T { return &v } diff --git a/pkg/tsdb/grafana-postgresql-datasource/tlsmanager.go b/pkg/tsdb/grafana-postgresql-datasource/tlsmanager.go index 116872d0613..46e68753da3 100644 --- a/pkg/tsdb/grafana-postgresql-datasource/tlsmanager.go +++ b/pkg/tsdb/grafana-postgresql-datasource/tlsmanager.go @@ -10,7 +10,7 @@ import ( "time" "github.com/grafana/grafana-plugin-sdk-go/backend/log" - "github.com/grafana/grafana/pkg/tsdb/sqleng" + "github.com/grafana/grafana/pkg/tsdb/grafana-postgresql-datasource/sqleng" ) var validateCertFunc = validateCertFilePaths diff --git a/pkg/tsdb/grafana-postgresql-datasource/tlsmanager_test.go b/pkg/tsdb/grafana-postgresql-datasource/tlsmanager_test.go index 8e60e841cab..c8eda0a83a7 100644 --- a/pkg/tsdb/grafana-postgresql-datasource/tlsmanager_test.go +++ b/pkg/tsdb/grafana-postgresql-datasource/tlsmanager_test.go @@ -12,7 +12,7 @@ import ( "github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend/log" "github.com/grafana/grafana/pkg/setting" - "github.com/grafana/grafana/pkg/tsdb/sqleng" + "github.com/grafana/grafana/pkg/tsdb/grafana-postgresql-datasource/sqleng" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" From b07f69d1a47ed14f0c65f4a38b3bba00950ff700 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 15 Apr 2024 15:02:22 +0200 Subject: [PATCH 011/147] Update dependency @types/marked to v6 (#86123) * Update dependency @types/marked to v6 * remove @types/marked since it's no longer needed --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Ashley Harrison --- package.json | 1 - packages/grafana-data/package.json | 1 - packages/grafana-prometheus/package.json | 1 - yarn.lock | 10 ---------- 4 files changed, 13 deletions(-) diff --git a/package.json b/package.json index 6376f43b912..84ea0be4da4 100644 --- a/package.json +++ b/package.json @@ -118,7 +118,6 @@ "@types/lodash": "4.17.0", "@types/logfmt": "^1.2.3", "@types/lucene": "^2", - "@types/marked": "5.0.2", "@types/mousetrap": "1.6.15", "@types/node": "20.12.7", "@types/node-forge": "^1", diff --git a/packages/grafana-data/package.json b/packages/grafana-data/package.json index 352c1e52f7f..b720fb5e97b 100644 --- a/packages/grafana-data/package.json +++ b/packages/grafana-data/package.json @@ -66,7 +66,6 @@ "@types/dompurify": "^3.0.0", "@types/history": "4.7.11", "@types/lodash": "4.17.0", - "@types/marked": "5.0.2", "@types/node": "20.12.7", "@types/papaparse": "5.3.14", "@types/react": "18.2.78", diff --git a/packages/grafana-prometheus/package.json b/packages/grafana-prometheus/package.json index 0a1e935636d..de5d55f4fc2 100644 --- a/packages/grafana-prometheus/package.json +++ b/packages/grafana-prometheus/package.json @@ -92,7 +92,6 @@ "@types/jest": "29.5.12", "@types/jquery": "3.5.29", "@types/lodash": "4.17.0", - "@types/marked": "5.0.2", "@types/node": "20.12.7", "@types/pluralize": "^0.0.33", "@types/prismjs": "1.26.3", diff --git a/yarn.lock b/yarn.lock index 034e784375e..af257980b39 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3634,7 +3634,6 @@ __metadata: "@types/dompurify": "npm:^3.0.0" "@types/history": "npm:4.7.11" "@types/lodash": "npm:4.17.0" - "@types/marked": "npm:5.0.2" "@types/node": "npm:20.12.7" "@types/papaparse": "npm:5.3.14" "@types/react": "npm:18.2.78" @@ -4030,7 +4029,6 @@ __metadata: "@types/jest": "npm:29.5.12" "@types/jquery": "npm:3.5.29" "@types/lodash": "npm:4.17.0" - "@types/marked": "npm:5.0.2" "@types/node": "npm:20.12.7" "@types/pluralize": "npm:^0.0.33" "@types/prismjs": "npm:1.26.3" @@ -9922,13 +9920,6 @@ __metadata: languageName: node linkType: hard -"@types/marked@npm:5.0.2": - version: 5.0.2 - resolution: "@types/marked@npm:5.0.2" - checksum: 10/a22999454a193243c9ad697859ead622a578bfce48ca6b2958509aacea55601627b02e74caedba06f88fa75004273ed39235d36f94869fec528bb5bc832cdfa2 - languageName: node - linkType: hard - "@types/mdx@npm:^2.0.0": version: 2.0.4 resolution: "@types/mdx@npm:2.0.4" @@ -18687,7 +18678,6 @@ __metadata: "@types/lodash": "npm:4.17.0" "@types/logfmt": "npm:^1.2.3" "@types/lucene": "npm:^2" - "@types/marked": "npm:5.0.2" "@types/mousetrap": "npm:1.6.15" "@types/node": "npm:20.12.7" "@types/node-forge": "npm:^1" From ad3abfc695dfa42d2c8de41172178522a0f5ae1a Mon Sep 17 00:00:00 2001 From: Kristina Date: Mon, 15 Apr 2024 08:07:02 -0500 Subject: [PATCH 012/147] Explore: Query history does not save filtered queries (#85825) * Bring in datasource filterQuery in, to not save filtered queries to history * Add test --- .../app/features/explore/state/query.test.ts | 53 +++++++++++++++++++ public/app/features/explore/state/query.ts | 42 +++++++++++---- 2 files changed, 86 insertions(+), 9 deletions(-) diff --git a/public/app/features/explore/state/query.test.ts b/public/app/features/explore/state/query.test.ts index 334270c8f68..eb84d558a84 100644 --- a/public/app/features/explore/state/query.test.ts +++ b/public/app/features/explore/state/query.test.ts @@ -66,6 +66,9 @@ const datasources: DataSourceApi[] = [ getRef: () => { return { type: 'postgres', uid: 'ds1' }; }, + filterQuery: (query: DataQuery) => { + return query.key === 'true'; + }, } as DataSourceApi, { name: 'testDs2', @@ -227,6 +230,56 @@ describe('runQueries', () => { expect((richHistory.addToRichHistory as jest.Mock).mock.calls).toHaveLength(1); expect((richHistory.addToRichHistory as jest.Mock).mock.calls[0][0].localOverride).toBeTruthy(); }); + + /* the next two tests are for ensuring the query datasource's filterQuery function stops queries + from being saved to rich history. We do that by setting a fake datasource in this test (datasources[0]) + to filter queries off their key value + + datasources[1] does not have filterQuery defined + */ + it('with filterQuery defined, should not save filtered out queries to history', async () => { + const { dispatch } = configureStore({ + ...defaultInitialState, + explore: { + panes: { + left: { + ...defaultInitialState.explore.panes.left, + datasourceInstance: datasources[0], + queries: [ + { refId: 'A', key: 'false' }, + { refId: 'B', key: 'true' }, + ], + }, + }, + }, + } as unknown as Partial); + jest.spyOn(richHistory, 'addToRichHistory'); + await dispatch(runQueries({ exploreId: 'left' })); + const calls = (richHistory.addToRichHistory as jest.Mock).mock.calls; + expect(calls).toHaveLength(1); + expect(calls[0][0].queries).toHaveLength(1); + expect(calls[0][0].queries[0].refId).toEqual('B'); + }); + + it('with filterQuery not defined, all queries are saved', async () => { + const { dispatch } = configureStore({ + ...defaultInitialState, + explore: { + panes: { + left: { + ...defaultInitialState.explore.panes.left, + datasourceInstance: datasources[1], + queries: [{ refId: 'A' }, { refId: 'B' }], + }, + }, + }, + } as unknown as Partial); + jest.spyOn(richHistory, 'addToRichHistory'); + await dispatch(runQueries({ exploreId: 'left' })); + const calls = (richHistory.addToRichHistory as jest.Mock).mock.calls; + expect(calls).toHaveLength(1); + expect(calls[0][0].queries).toHaveLength(2); + }); }); describe('running queries', () => { diff --git a/public/app/features/explore/state/query.ts b/public/app/features/explore/state/query.ts index d6e2d017512..4aa94686a76 100644 --- a/public/app/features/explore/state/query.ts +++ b/public/app/features/explore/state/query.ts @@ -38,6 +38,7 @@ import { import { getShiftedTimeRange } from 'app/core/utils/timePicker'; import { getCorrelationsBySourceUIDs } from 'app/features/correlations/utils'; import { infiniteScrollRefId } from 'app/features/logs/logsModel'; +import { getDatasourceSrv } from 'app/features/plugins/datasource_srv'; import { getFiscalYearStartMonth, getTimeZone } from 'app/features/profile/state/selectors'; import { SupportingQueryType } from 'app/plugins/datasource/loki/types'; import { MIXED_DATASOURCE_NAME } from 'app/plugins/datasource/mixed/MixedDataSource'; @@ -476,25 +477,48 @@ export function modifyQueries( }; } +function filterQuery(datasource: DataSourceApi, query: DataQuery) { + if (datasource.filterQuery && !datasource.filterQuery(query)) { + return undefined; // if filterQuery is implemented and returns false, do not use query + } else { + return query; // if filterQuery is not implemented or it is and returns true, use it + } +} + async function handleHistory( dispatch: ThunkDispatch, state: ExploreState, datasource: DataSourceApi, queries: DataQuery[] ) { - /* + const filteredQueriesRes = await Promise.all( + queries.map(async (query) => { + if (query.datasource?.uid === datasource.uid) { + return filterQuery(datasource, query); + } else { + const queryDS = await getDatasourceSrv().get(query.datasource); + return filterQuery(queryDS, query); + } + }) + ); + + const filteredQueries = filteredQueriesRes.filter((query): query is DataQuery => !!query); + + if (filteredQueries.length > 0) { + /* Always write to local storage. If query history is enabled, we will use local storage for autocomplete only (and want to hide errors) If query history is disabled, we will use local storage for query history as well, and will want to show errors */ - dispatch(addHistoryItem(true, datasource.uid, datasource.name, queries, config.queryHistoryEnabled)); - if (config.queryHistoryEnabled) { - // write to remote if flag enabled - dispatch(addHistoryItem(false, datasource.uid, datasource.name, queries, false)); - } + dispatch(addHistoryItem(true, datasource.uid, datasource.name, filteredQueries, config.queryHistoryEnabled)); + if (config.queryHistoryEnabled) { + // write to remote if flag enabled + dispatch(addHistoryItem(false, datasource.uid, datasource.name, filteredQueries, false)); + } - // Because filtering happens in the backend we cannot add a new entry without checking if it matches currently - // used filters. Instead, we refresh the query history list. - await dispatch(loadRichHistory()); + // Because filtering happens in the backend we cannot add a new entry without checking if it matches currently + // used filters. Instead, we refresh the query history list. + await dispatch(loadRichHistory()); + } } interface RunQueriesOptions { From 0034e9f0445e50cae3ab3ebdcadd4d28fd9b06f7 Mon Sep 17 00:00:00 2001 From: Kristina Date: Mon, 15 Apr 2024 08:11:21 -0500 Subject: [PATCH 013/147] Explore: Change service in hook, un-skip test (#85894) Use different service, un-skip test --- public/app/features/explore/hooks/useExplorePageTitle.ts | 4 ++-- public/app/features/explore/spec/queryHistory.test.tsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/public/app/features/explore/hooks/useExplorePageTitle.ts b/public/app/features/explore/hooks/useExplorePageTitle.ts index 42fff5a5fd8..804b2cf69d9 100644 --- a/public/app/features/explore/hooks/useExplorePageTitle.ts +++ b/public/app/features/explore/hooks/useExplorePageTitle.ts @@ -1,9 +1,9 @@ import { useEffect } from 'react'; +import { getDataSourceSrv } from '@grafana/runtime'; import { Branding } from 'app/core/components/Branding/Branding'; import { useGrafana } from 'app/core/context/GrafanaContext'; import { useNavModel } from 'app/core/hooks/useNavModel'; -import { getDatasourceSrv } from 'app/features/plugins/datasource_srv'; import { ExploreQueryParams } from 'app/types'; import { isFulfilled, hasKey } from './utils'; @@ -40,7 +40,7 @@ export function useExplorePageTitle(params: ExploreQueryParams) { return Promise.reject(); } - return getDatasourceSrv().get(pane.datasource); + return getDataSourceSrv().get(pane.datasource); }) ) .then((results) => results.filter(isFulfilled).map((result) => result.value)) diff --git a/public/app/features/explore/spec/queryHistory.test.tsx b/public/app/features/explore/spec/queryHistory.test.tsx index 76fcc7a0124..66eefeea309 100644 --- a/public/app/features/explore/spec/queryHistory.test.tsx +++ b/public/app/features/explore/spec/queryHistory.test.tsx @@ -119,7 +119,7 @@ describe('Explore: Query History', () => { }); }); - it.skip('adds recently added query if the query history panel is already open', async () => { + it('adds recently added query if the query history panel is already open', async () => { const urlParams = { left: serializeStateToUrlParam({ datasource: 'loki', From 2868264360438ed489cb0bd5ab211ff341a488d4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 15 Apr 2024 15:44:12 +0200 Subject: [PATCH 014/147] Update dependency @types/react-calendar to v4 (#86132) * Update dependency @types/react-calendar to v4 * remove @types/react-calendar since it's no longer used --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Ashley Harrison --- packages/grafana-ui/package.json | 1 - yarn.lock | 10 ---------- 2 files changed, 11 deletions(-) diff --git a/packages/grafana-ui/package.json b/packages/grafana-ui/package.json index 560a234d4ab..7a7ce4a35a6 100644 --- a/packages/grafana-ui/package.json +++ b/packages/grafana-ui/package.json @@ -143,7 +143,6 @@ "@types/prismjs": "1.26.3", "@types/react": "18.2.78", "@types/react-beautiful-dnd": "13.1.8", - "@types/react-calendar": "3.9.0", "@types/react-color": "3.0.12", "@types/react-dom": "18.2.25", "@types/react-highlight-words": "0.16.7", diff --git a/yarn.lock b/yarn.lock index af257980b39..53f894f4937 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4324,7 +4324,6 @@ __metadata: "@types/prismjs": "npm:1.26.3" "@types/react": "npm:18.2.78" "@types/react-beautiful-dnd": "npm:13.1.8" - "@types/react-calendar": "npm:3.9.0" "@types/react-color": "npm:3.0.12" "@types/react-dom": "npm:18.2.25" "@types/react-highlight-words": "npm:0.16.7" @@ -10131,15 +10130,6 @@ __metadata: languageName: node linkType: hard -"@types/react-calendar@npm:3.9.0": - version: 3.9.0 - resolution: "@types/react-calendar@npm:3.9.0" - dependencies: - "@types/react": "npm:*" - checksum: 10/05acec0ec111df7f34db2d5a4b337f9b69b31ee8b8932b3257cc0ea7468973fd851dc22de028ad1a8a12729e299bfb8ee67b32bb67763ce27c33000ab0e92a88 - languageName: node - linkType: hard - "@types/react-color@npm:3.0.12": version: 3.0.12 resolution: "@types/react-color@npm:3.0.12" From b2555cfc01e9a297f8dad501cf19a08361cab2e2 Mon Sep 17 00:00:00 2001 From: antonio <45235678+tonypowa@users.noreply.github.com> Date: Mon, 15 Apr 2024 15:46:19 +0200 Subject: [PATCH 015/147] alerting>tutorial>fix (#86101) * alerting>tutorial>fix * Update index.md --- docs/sources/tutorials/alerting-get-started/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/sources/tutorials/alerting-get-started/index.md b/docs/sources/tutorials/alerting-get-started/index.md index 83827ef935e..490797e8584 100644 --- a/docs/sources/tutorials/alerting-get-started/index.md +++ b/docs/sources/tutorials/alerting-get-started/index.md @@ -152,9 +152,9 @@ In this section, we define queries, expressions (used to manipulate the data), a This [PromQL](https://prometheus.io/docs/prometheus/latest/querying/basics/) query calculates the sum of the per-second average rates of increase of the `tns_request_duration_seconds_count` metric over the last 1 minute, grouped by the HTTP method used in the requests. This can be useful for analyzing the request duration trends for different HTTP methods. -1. Keep expressions “B” and “C” as they are. These expressions (**Reduce** and **Threshold**, respectively) come by default when creating a new rule. +1. Remove expression "B" (click the bin icon). The **Reduce** expression comes by default, and in this case, it is not needed since the queried data is already reduced. - The Reduce expression “B”, selects the last value of our query “A”, while the Threshold expression “C” will check if the last value from expression “B” is above a specific value. In addition, the Threshold expression is the alert condition by default. Enter `0.2` as threshold value. You can read more about queries and conditions [here](https://grafana.com/docs/grafana/latest/alerting/fundamentals/alert-rules/queries-conditions/#expression-queries). +1. In expression "C", **Threshold**, change the **Input** to "A". By selecting the input, you're telling Grafana which data source and which specific metric within that data source the expression should evaluate. The Threshold expression is now the alert condition. Enter `0.2` as threshold value. You can read more about queries and conditions [here](https://grafana.com/docs/grafana/latest/alerting/fundamentals/alert-rules/queries-conditions/#expression-queries). 1. Click Preview to run the queries. From 499ad35a5064c6238d0fc51209f682a7369ff525 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laura=20Fern=C3=A1ndez?= Date: Mon, 15 Apr 2024 15:57:15 +0200 Subject: [PATCH 016/147] Chore: `ActionRow` - Replace `HorizontalGroup` with `Stack` (#86143) --- .betterer.results | 5 ++--- .../app/features/search/page/components/ActionRow.tsx | 10 +++++----- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/.betterer.results b/.betterer.results index aaa293b9b8b..5c68c3c61bc 100644 --- a/.betterer.results +++ b/.betterer.results @@ -4039,9 +4039,8 @@ exports[`better eslint`] = { [0, 0, 0, "\'VerticalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"] ], "public/app/features/search/page/components/ActionRow.tsx:5381": [ - [0, 0, 0, "\'HorizontalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"], - [0, 0, 0, "Styles should be written using objects.", "1"], - [0, 0, 0, "Styles should be written using objects.", "2"] + [0, 0, 0, "Styles should be written using objects.", "0"], + [0, 0, 0, "Styles should be written using objects.", "1"] ], "public/app/features/search/page/components/SearchResultsTable.tsx:5381": [ [0, 0, 0, "Styles should be written using objects.", "0"], diff --git a/public/app/features/search/page/components/ActionRow.tsx b/public/app/features/search/page/components/ActionRow.tsx index 3d9434280ee..7e1b67e7f69 100644 --- a/public/app/features/search/page/components/ActionRow.tsx +++ b/public/app/features/search/page/components/ActionRow.tsx @@ -3,7 +3,7 @@ import React, { FormEvent } from 'react'; import { GrafanaTheme2, SelectableValue } from '@grafana/data'; import { config } from '@grafana/runtime'; -import { Button, Checkbox, HorizontalGroup, RadioButtonGroup, useStyles2 } from '@grafana/ui'; +import { Button, Checkbox, Stack, RadioButtonGroup, useStyles2 } from '@grafana/ui'; import { SortPicker } from 'app/core/components/Select/SortPicker'; import { TagFilter, TermCount } from 'app/core/components/TagFilter/TagFilter'; import { t, Trans } from 'app/core/internationalization'; @@ -77,7 +77,7 @@ export const ActionRow = ({ return (
- + {config.featureToggles.panelTitleSearch && ( )} - + - + {!hideLayout && ( - +
); }; From afbd28e1600ba9dc45853de463defdcc006705dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laura=20Fern=C3=A1ndez?= Date: Mon, 15 Apr 2024 16:12:47 +0200 Subject: [PATCH 017/147] Chore: `RolePickerMenu` and `RolePickerSubmenu` - Replace `HorizontalGroup` with `Stack` (#86145) --- .betterer.results | 6 ------ public/app/core/components/RolePicker/RolePickerMenu.tsx | 6 +++--- public/app/core/components/RolePicker/RolePickerSubMenu.tsx | 6 +++--- 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/.betterer.results b/.betterer.results index 5c68c3c61bc..ec80329e2b6 100644 --- a/.betterer.results +++ b/.betterer.results @@ -1233,12 +1233,6 @@ exports[`better eslint`] = { [0, 0, 0, "Styles should be written using objects.", "5"], [0, 0, 0, "Styles should be written using objects.", "6"] ], - "public/app/core/components/RolePicker/RolePickerMenu.tsx:5381": [ - [0, 0, 0, "\'HorizontalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"] - ], - "public/app/core/components/RolePicker/RolePickerSubMenu.tsx:5381": [ - [0, 0, 0, "\'HorizontalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"] - ], "public/app/core/components/RolePicker/ValueContainer.tsx:5381": [ [0, 0, 0, "Styles should be written using objects.", "0"] ], diff --git a/public/app/core/components/RolePicker/RolePickerMenu.tsx b/public/app/core/components/RolePicker/RolePickerMenu.tsx index 1bfe1d63ce7..cb542c416ce 100644 --- a/public/app/core/components/RolePicker/RolePickerMenu.tsx +++ b/public/app/core/components/RolePicker/RolePickerMenu.tsx @@ -1,7 +1,7 @@ import { css, cx } from '@emotion/css'; import React, { useEffect, useRef, useState } from 'react'; -import { Button, CustomScrollbar, HorizontalGroup, TextLink, useStyles2, useTheme2 } from '@grafana/ui'; +import { Button, CustomScrollbar, Stack, TextLink, useStyles2, useTheme2 } from '@grafana/ui'; import { getSelectStyles } from '@grafana/ui/src/components/Select/getSelectStyles'; import { OrgRole, Role } from 'app/types'; @@ -256,14 +256,14 @@ export const RolePickerMenu = ({ ))}
- + - +
diff --git a/public/app/core/components/RolePicker/RolePickerSubMenu.tsx b/public/app/core/components/RolePicker/RolePickerSubMenu.tsx index 4f6b5aa2f9f..2c5ba1b151f 100644 --- a/public/app/core/components/RolePicker/RolePickerSubMenu.tsx +++ b/public/app/core/components/RolePicker/RolePickerSubMenu.tsx @@ -1,7 +1,7 @@ import { cx } from '@emotion/css'; import React from 'react'; -import { Button, CustomScrollbar, HorizontalGroup, useStyles2, useTheme2 } from '@grafana/ui'; +import { Button, CustomScrollbar, Stack, useStyles2, useTheme2 } from '@grafana/ui'; import { getSelectStyles } from '@grafana/ui/src/components/Select/getSelectStyles'; import { Role } from 'app/types'; @@ -65,11 +65,11 @@ export const RolePickerSubMenu = ({
- + - +
); From 5b1498f98f3e1e386381d4e8e630cea75653c5a9 Mon Sep 17 00:00:00 2001 From: Alexander Weaver Date: Mon, 15 Apr 2024 09:25:28 -0500 Subject: [PATCH 018/147] Alerting: Return a 400 and errutil error when trying to delete a contact point that is referenced by a policy (#85481) Return a 400 and errutil error when trying to delete a contact point that is referenced by a policy --- pkg/services/ngalert/api/api_provisioning.go | 2 +- pkg/services/ngalert/provisioning/contactpoints.go | 2 +- pkg/services/ngalert/provisioning/errors.go | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/pkg/services/ngalert/api/api_provisioning.go b/pkg/services/ngalert/api/api_provisioning.go index 8143a6eafa4..9d0f062d2ad 100644 --- a/pkg/services/ngalert/api/api_provisioning.go +++ b/pkg/services/ngalert/api/api_provisioning.go @@ -192,7 +192,7 @@ func (srv *ProvisioningSrv) RoutePutContactPoint(c *contextmodel.ReqContext, cp func (srv *ProvisioningSrv) RouteDeleteContactPoint(c *contextmodel.ReqContext, UID string) response.Response { err := srv.contactPointService.DeleteContactPoint(c.Req.Context(), c.SignedInUser.GetOrgID(), UID) if err != nil { - return ErrResp(http.StatusInternalServerError, err, "") + return response.ErrOrFallback(http.StatusInternalServerError, "failed to delete contact point", err) } return response.JSON(http.StatusAccepted, util.DynMap{"message": "contactpoint deleted"}) } diff --git a/pkg/services/ngalert/provisioning/contactpoints.go b/pkg/services/ngalert/provisioning/contactpoints.go index 37a3c03925a..02eeb66978d 100644 --- a/pkg/services/ngalert/provisioning/contactpoints.go +++ b/pkg/services/ngalert/provisioning/contactpoints.go @@ -338,7 +338,7 @@ func (ecp *ContactPointService) DeleteContactPoint(ctx context.Context, orgID in } } if fullRemoval && isContactPointInUse(name, []*apimodels.Route{revision.cfg.AlertmanagerConfig.Route}) { - return fmt.Errorf("contact point '%s' is currently used by a notification policy", name) + return ErrContactPointReferenced } return ecp.xact.InTransaction(ctx, func(ctx context.Context) error { diff --git a/pkg/services/ngalert/provisioning/errors.go b/pkg/services/ngalert/provisioning/errors.go index 31e50224ffe..33ab23544e6 100644 --- a/pkg/services/ngalert/provisioning/errors.go +++ b/pkg/services/ngalert/provisioning/errors.go @@ -19,6 +19,8 @@ var ( ErrTimeIntervalExists = errutil.BadRequest("alerting.notifications.time-intervals.nameExists", errutil.WithPublicMessage("Time interval with this name already exists. Use a different name or update existing one.")) ErrTimeIntervalInvalid = errutil.BadRequest("alerting.notifications.time-intervals.invalidFormat").MustTemplate("Invalid format of the submitted time interval", errutil.WithPublic("Time interval is in invalid format. Correct the payload and try again.")) ErrTimeIntervalInUse = errutil.Conflict("alerting.notifications.time-intervals.used", errutil.WithPublicMessage("Time interval is used by one or many notification policies")) + + ErrContactPointReferenced = errutil.BadRequest("alerting.notifications.contact-points.referenced", errutil.WithPublicMessage("Contact point is currently referenced by a notification policy.")) ) func makeErrBadAlertmanagerConfiguration(err error) error { From 453a75b7672aa90cd36555c82630c5f190637022 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 15 Apr 2024 15:30:26 +0100 Subject: [PATCH 019/147] Update dependency @swc/helpers to v0.5.10 (#86146) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- packages/grafana-prometheus/package.json | 2 +- yarn.lock | 12 ++++++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 84ea0be4da4..3644f896724 100644 --- a/package.json +++ b/package.json @@ -89,7 +89,7 @@ "@rtk-query/codegen-openapi": "^1.2.0", "@rtsao/plugin-proposal-class-properties": "7.0.1-patch.1", "@swc/core": "1.4.2", - "@swc/helpers": "0.5.9", + "@swc/helpers": "0.5.10", "@testing-library/dom": "10.0.0", "@testing-library/jest-dom": "6.4.2", "@testing-library/react": "15.0.2", diff --git a/packages/grafana-prometheus/package.json b/packages/grafana-prometheus/package.json index de5d55f4fc2..004fcd9764d 100644 --- a/packages/grafana-prometheus/package.json +++ b/packages/grafana-prometheus/package.json @@ -81,7 +81,7 @@ "@rollup/plugin-image": "3.0.3", "@rollup/plugin-node-resolve": "15.2.3", "@swc/core": "1.4.2", - "@swc/helpers": "0.5.9", + "@swc/helpers": "0.5.10", "@testing-library/dom": "10.0.0", "@testing-library/jest-dom": "6.4.2", "@testing-library/react": "15.0.2", diff --git a/yarn.lock b/yarn.lock index 53f894f4937..0d46f9053b6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4018,7 +4018,7 @@ __metadata: "@rollup/plugin-image": "npm:3.0.3" "@rollup/plugin-node-resolve": "npm:15.2.3" "@swc/core": "npm:1.4.2" - "@swc/helpers": "npm:0.5.9" + "@swc/helpers": "npm:0.5.10" "@testing-library/dom": "npm:10.0.0" "@testing-library/jest-dom": "npm:6.4.2" "@testing-library/react": "npm:15.0.2" @@ -8901,12 +8901,12 @@ __metadata: languageName: node linkType: hard -"@swc/helpers@npm:0.5.9, @swc/helpers@npm:^0.5.0": - version: 0.5.9 - resolution: "@swc/helpers@npm:0.5.9" +"@swc/helpers@npm:0.5.10, @swc/helpers@npm:^0.5.0": + version: 0.5.10 + resolution: "@swc/helpers@npm:0.5.10" dependencies: tslib: "npm:^2.4.0" - checksum: 10/39e75216f43474c8d2796d337f1f8425c0d0e4d51422748dc01accc2f1c1bbf309b2efbf2ce0bffa6c695b2eeb83893a3e9670a1dc15b14d57780cb7fe7754a0 + checksum: 10/840a1bbac06bfebbca1bd02a63610ee6a72e170ad9f156936d20220385624a88d900d5a668a1d0bcac57776a0aaa26a97c2503a796624a05764957a2322cc5b2 languageName: node linkType: hard @@ -18638,7 +18638,7 @@ __metadata: "@rtk-query/codegen-openapi": "npm:^1.2.0" "@rtsao/plugin-proposal-class-properties": "npm:7.0.1-patch.1" "@swc/core": "npm:1.4.2" - "@swc/helpers": "npm:0.5.9" + "@swc/helpers": "npm:0.5.10" "@testing-library/dom": "npm:10.0.0" "@testing-library/jest-dom": "npm:6.4.2" "@testing-library/react": "npm:15.0.2" From 1dfd34ee796be665bf2cf44fcffff9ac7e5d8a57 Mon Sep 17 00:00:00 2001 From: Jack Westbrook Date: Mon, 15 Apr 2024 16:36:19 +0200 Subject: [PATCH 020/147] Chore: Add codemod and betterer config to make barrel imports explicit (#80913) * chore: add codemod for highlighting barrel imports * style(frontend): add no-barrel-files plugin to betterer * chore(betterer): update betterer file * ci(frontend-metrics): track occurrences of barrel files being imported * chore: clean up explicit barrel imports codemod script * chore(codeowners): add explicit barrel imports script * Add no-barrel-files plugin to betterer configuration Co-Authored-By: LeventeBalogh --------- Co-authored-by: LeventeBalogh --- .betterer.results | 450 ++++++++++++++++++- .betterer.ts | 29 +- .eslintrc | 2 +- .github/CODEOWNERS | 2 +- package.json | 1 + scripts/ci-frontend-metrics.sh | 2 + scripts/codemods/explicit-barrel-imports.cjs | 39 ++ yarn.lock | 12 +- 8 files changed, 526 insertions(+), 11 deletions(-) create mode 100644 scripts/codemods/explicit-barrel-imports.cjs diff --git a/.betterer.results b/.betterer.results index ec80329e2b6..b39049d9b2d 100644 --- a/.betterer.results +++ b/.betterer.results @@ -1151,6 +1151,15 @@ exports[`better eslint`] = { [0, 0, 0, "Unexpected any. Specify a different type.", "5"], [0, 0, 0, "Unexpected any. Specify a different type.", "6"] ], + "public/app/core/actions/index.ts:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`updateNavIndex\`)", "0"], + [0, 0, 0, "Do not re-export imported variable (\`updateConfigurationSubtitle\`)", "1"], + [0, 0, 0, "Do not re-export imported variable (\`notifyApp\`)", "2"], + [0, 0, 0, "Do not re-export imported variable (\`hideAppNotification\`)", "3"] + ], + "public/app/core/components/AccessControl/index.ts:5381": [ + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "0"] + ], "public/app/core/components/AppChrome/TopBar/TopSearchBarCommandPaletteTrigger.tsx:5381": [ [0, 0, 0, "Styles should be written using objects.", "0"] ], @@ -1178,6 +1187,9 @@ exports[`better eslint`] = { [0, 0, 0, "Do not use any type assertions.", "8"], [0, 0, 0, "Do not use any type assertions.", "9"] ], + "public/app/core/components/LocalStorageValueProvider/index.tsx:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`./LocalStorageValueProvider\`)", "0"] + ], "public/app/core/components/Login/LoginServiceButtons.tsx:5381": [ [0, 0, 0, "\'VerticalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"] ], @@ -1282,6 +1294,19 @@ exports[`better eslint`] = { [0, 0, 0, "Unexpected any. Specify a different type.", "0"], [0, 0, 0, "Do not use any type assertions.", "1"] ], + "public/app/core/config.ts:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`config\`)", "0"] + ], + "public/app/core/core.ts:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`profiler\`)", "0"], + [0, 0, 0, "Do not re-export imported variable (\`appEvents\`)", "1"], + [0, 0, 0, "Do not re-export imported variable (\`colors\`)", "2"], + [0, 0, 0, "Do not re-export imported variable (\`assignModelProperties\`)", "3"], + [0, 0, 0, "Do not re-export imported variable (\`contextSrv\`)", "4"], + [0, 0, 0, "Do not re-export imported variable (\`JsonExplorer\`)", "5"], + [0, 0, 0, "Do not re-export imported variable (\`TimeSeries\`)", "6"], + [0, 0, 0, "Do not re-export imported variable (\`updateLegendValues\`)", "7"] + ], "public/app/core/navigation/types.ts:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"] ], @@ -1381,6 +1406,11 @@ exports[`better eslint`] = { "public/app/core/utils/richHistory.test.ts:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"] ], + "public/app/core/utils/richHistory.ts:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`RichHistorySearchFilters\`)", "0"], + [0, 0, 0, "Do not re-export imported variable (\`RichHistorySettings\`)", "1"], + [0, 0, 0, "Do not re-export imported variable (\`SortOrder\`)", "2"] + ], "public/app/core/utils/ticks.ts:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"], [0, 0, 0, "Do not use any type assertions.", "1"] @@ -1696,6 +1726,9 @@ exports[`better eslint`] = { "public/app/features/alerting/unified/components/expressions/ExpressionStatusIndicator.tsx:5381": [ [0, 0, 0, "Styles should be written using objects.", "0"] ], + "public/app/features/alerting/unified/components/extensions/AlertInstanceExtensionPointMenu.tsx:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`app/features/explore/extensions/ToolbarExtensionPointMenu\`)", "0"] + ], "public/app/features/alerting/unified/components/mute-timings/MuteTimingForm.tsx:5381": [ [0, 0, 0, "Styles should be written using objects.", "0"], [0, 0, 0, "Styles should be written using objects.", "1"] @@ -2328,9 +2361,20 @@ exports[`better eslint`] = { [0, 0, 0, "Styles should be written using objects.", "1"], [0, 0, 0, "Styles should be written using objects.", "2"] ], + "public/app/features/auth-config/index.ts:5381": [ + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "0"] + ], "public/app/features/auth-config/utils/data.ts:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"] ], + "public/app/features/browse-dashboards/api/browseDashboardsAPI.ts:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`@reduxjs/toolkit/query/react\`)", "0"] + ], + "public/app/features/browse-dashboards/state/index.ts:5381": [ + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "0"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "1"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "2"] + ], "public/app/features/canvas/element.ts:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"], [0, 0, 0, "Unexpected any. Specify a different type.", "1"], @@ -2338,6 +2382,12 @@ exports[`better eslint`] = { [0, 0, 0, "Unexpected any. Specify a different type.", "3"], [0, 0, 0, "Unexpected any. Specify a different type.", "4"] ], + "public/app/features/canvas/index.ts:5381": [ + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "0"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "1"], + [0, 0, 0, "Do not re-export imported variable (\`./frame\`)", "2"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "3"] + ], "public/app/features/canvas/runtime/element.tsx:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"], [0, 0, 0, "Do not use any type assertions.", "1"], @@ -2358,14 +2408,40 @@ exports[`better eslint`] = { [0, 0, 0, "Styles should be written using objects.", "2"], [0, 0, 0, "Styles should be written using objects.", "3"] ], + "public/app/features/canvas/types.ts:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`Placement\`)", "0"], + [0, 0, 0, "Do not re-export imported variable (\`Constraint\`)", "1"], + [0, 0, 0, "Do not re-export imported variable (\`HorizontalConstraint\`)", "2"], + [0, 0, 0, "Do not re-export imported variable (\`VerticalConstraint\`)", "3"], + [0, 0, 0, "Do not re-export imported variable (\`BackgroundImageSize\`)", "4"], + [0, 0, 0, "Do not re-export imported variable (\`LineConfig\`)", "5"], + [0, 0, 0, "Do not re-export imported variable (\`BackgroundConfig\`)", "6"] + ], "public/app/features/connections/components/ConnectionsRedirectNotice/ConnectionsRedirectNotice.tsx:5381": [ [0, 0, 0, "Styles should be written using objects.", "0"], [0, 0, 0, "Styles should be written using objects.", "1"] ], + "public/app/features/connections/components/ConnectionsRedirectNotice/index.ts:5381": [ + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "0"] + ], + "public/app/features/connections/pages/index.tsx:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`./AddNewConnectionPage\`)", "0"], + [0, 0, 0, "Do not re-export imported variable (\`./DataSourceDetailsPage\`)", "1"], + [0, 0, 0, "Do not re-export imported variable (\`./DataSourcesListPage\`)", "2"], + [0, 0, 0, "Do not re-export imported variable (\`./DataSourceDashboardsPage\`)", "3"], + [0, 0, 0, "Do not re-export imported variable (\`./EditDataSourcePage\`)", "4"], + [0, 0, 0, "Do not re-export imported variable (\`./NewDataSourcePage\`)", "5"] + ], + "public/app/features/connections/tabs/ConnectData/CardGrid/index.tsx:5381": [ + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "0"] + ], "public/app/features/connections/tabs/ConnectData/CategoryHeader/CategoryHeader.tsx:5381": [ [0, 0, 0, "Styles should be written using objects.", "0"], [0, 0, 0, "Styles should be written using objects.", "1"] ], + "public/app/features/connections/tabs/ConnectData/CategoryHeader/index.tsx:5381": [ + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "0"] + ], "public/app/features/connections/tabs/ConnectData/NoAccessModal/NoAccessModal.tsx:5381": [ [0, 0, 0, "Styles should be written using objects.", "0"], [0, 0, 0, "Styles should be written using objects.", "1"], @@ -2377,6 +2453,15 @@ exports[`better eslint`] = { [0, 0, 0, "Styles should be written using objects.", "7"], [0, 0, 0, "Styles should be written using objects.", "8"] ], + "public/app/features/connections/tabs/ConnectData/NoAccessModal/index.tsx:5381": [ + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "0"] + ], + "public/app/features/connections/tabs/ConnectData/Search/index.tsx:5381": [ + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "0"] + ], + "public/app/features/connections/tabs/ConnectData/index.tsx:5381": [ + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "0"] + ], "public/app/features/correlations/CorrelationsPage.tsx:5381": [ [0, 0, 0, "Styles should be written using objects.", "0"], [0, 0, 0, "Styles should be written using objects.", "1"], @@ -2398,6 +2483,10 @@ exports[`better eslint`] = { "public/app/features/correlations/Forms/CorrelationFormNavigation.tsx:5381": [ [0, 0, 0, "\'HorizontalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"] ], + "public/app/features/correlations/components/Wizard/index.ts:5381": [ + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "0"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "1"] + ], "public/app/features/dashboard-scene/inspect/HelpWizard/HelpWizard.tsx:5381": [ [0, 0, 0, "\'HorizontalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"] ], @@ -2469,6 +2558,10 @@ exports[`better eslint`] = { "public/app/features/dashboard-scene/settings/annotations/AnnotationSettingsList.tsx:5381": [ [0, 0, 0, "\'VerticalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"] ], + "public/app/features/dashboard-scene/settings/annotations/index.tsx:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`./AnnotationSettingsEdit\`)", "0"], + [0, 0, 0, "Do not re-export imported variable (\`./AnnotationSettingsList\`)", "1"] + ], "public/app/features/dashboard-scene/settings/links/DashboardLinkList.tsx:5381": [ [0, 0, 0, "\'HorizontalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"] ], @@ -2481,6 +2574,13 @@ exports[`better eslint`] = { "public/app/features/dashboard-scene/settings/variables/utils.ts:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"] ], + "public/app/features/dashboard-scene/settings/version-history/index.ts:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`./HistorySrv\`)", "0"], + [0, 0, 0, "Do not re-export imported variable (\`./VersionHistoryTable\`)", "1"], + [0, 0, 0, "Do not re-export imported variable (\`./VersionHistoryHeader\`)", "2"], + [0, 0, 0, "Do not re-export imported variable (\`./VersionHistoryButtons\`)", "3"], + [0, 0, 0, "Do not re-export imported variable (\`./VersionHistoryComparison\`)", "4"] + ], "public/app/features/dashboard-scene/sharing/ShareExportTab.tsx:5381": [ [0, 0, 0, "\'VerticalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"] ], @@ -2490,6 +2590,9 @@ exports[`better eslint`] = { "public/app/features/dashboard-scene/utils/PanelModelCompatibilityWrapper.ts:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"] ], + "public/app/features/dashboard/components/AddLibraryPanelWidget/index.ts:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`./AddLibraryPanelWidget\`)", "0"] + ], "public/app/features/dashboard/components/AddWidgetModal/AddWidgetModal.tsx:5381": [ [0, 0, 0, "Styles should be written using objects.", "0"], [0, 0, 0, "Styles should be written using objects.", "1"], @@ -2507,6 +2610,10 @@ exports[`better eslint`] = { [0, 0, 0, "\'VerticalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"], [0, 0, 0, "Styles should be written using objects.", "1"] ], + "public/app/features/dashboard/components/AnnotationSettings/index.tsx:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`./AnnotationSettingsEdit\`)", "0"], + [0, 0, 0, "Do not re-export imported variable (\`./AnnotationSettingsList\`)", "1"] + ], "public/app/features/dashboard/components/DashExportModal/DashboardExporter.test.ts:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"], [0, 0, 0, "Unexpected any. Specify a different type.", "1"], @@ -2527,9 +2634,15 @@ exports[`better eslint`] = { [0, 0, 0, "Do not use any type assertions.", "8"], [0, 0, 0, "Unexpected any. Specify a different type.", "9"] ], + "public/app/features/dashboard/components/DashExportModal/index.ts:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`./DashboardExporter\`)", "0"] + ], "public/app/features/dashboard/components/DashNav/DashNavButton.tsx:5381": [ [0, 0, 0, "Styles should be written using objects.", "0"] ], + "public/app/features/dashboard/components/DashNav/index.ts:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`DashNav\`)", "0"] + ], "public/app/features/dashboard/components/DashboardLoading/DashboardFailed.tsx:5381": [ [0, 0, 0, "Styles should be written using objects.", "0"] ], @@ -2556,12 +2669,18 @@ exports[`better eslint`] = { "public/app/features/dashboard/components/DashboardRow/DashboardRow.test.tsx:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"] ], + "public/app/features/dashboard/components/DashboardRow/index.ts:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`./DashboardRow\`)", "0"] + ], "public/app/features/dashboard/components/DashboardSettings/ListNewButton.tsx:5381": [ [0, 0, 0, "Styles should be written using objects.", "0"] ], "public/app/features/dashboard/components/DashboardSettings/VersionsSettings.tsx:5381": [ [0, 0, 0, "\'HorizontalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"] ], + "public/app/features/dashboard/components/DashboardSettings/index.ts:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`./DashboardSettings\`)", "0"] + ], "public/app/features/dashboard/components/DeleteDashboard/DeleteDashboardModal.tsx:5381": [ [0, 0, 0, "Styles should be written using objects.", "0"] ], @@ -2574,6 +2693,10 @@ exports[`better eslint`] = { "public/app/features/dashboard/components/Inspector/PanelInspector.tsx:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"] ], + "public/app/features/dashboard/components/LinksSettings/index.tsx:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`./LinkSettingsEdit\`)", "0"], + [0, 0, 0, "Do not re-export imported variable (\`./LinkSettingsList\`)", "1"] + ], "public/app/features/dashboard/components/PanelEditor/DynamicConfigValueEditor.tsx:5381": [ [0, 0, 0, "\'HorizontalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"], [0, 0, 0, "Styles should be written using objects.", "1"], @@ -2757,6 +2880,10 @@ exports[`better eslint`] = { "public/app/features/dashboard/components/ShareModal/SharePublicDashboard/ModalAlerts/UnsupportedDataSourcesAlert.tsx:5381": [ [0, 0, 0, "Styles should be written using objects.", "0"] ], + "public/app/features/dashboard/components/ShareModal/index.ts:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`./ShareModal\`)", "0"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "1"] + ], "public/app/features/dashboard/components/SubMenu/AnnotationPicker.tsx:5381": [ [0, 0, 0, "Styles should be written using objects.", "0"], [0, 0, 0, "Styles should be written using objects.", "1"] @@ -2937,6 +3064,10 @@ exports[`better eslint`] = { "public/app/features/dashboard/state/getPanelPluginToMigrateTo.ts:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"] ], + "public/app/features/dashboard/state/index.ts:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`./DashboardModel\`)", "0"], + [0, 0, 0, "Do not re-export imported variable (\`./PanelModel\`)", "1"] + ], "public/app/features/dashboard/state/initDashboard.test.ts:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"] ], @@ -2953,6 +3084,14 @@ exports[`better eslint`] = { [0, 0, 0, "Do not use any type assertions.", "2"], [0, 0, 0, "Unexpected any. Specify a different type.", "3"] ], + "public/app/features/dataframe-import/index.ts:5381": [ + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "0"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "1"] + ], + "public/app/features/datasources/__mocks__/index.ts:5381": [ + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "0"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "1"] + ], "public/app/features/datasources/components/BasicSettings.tsx:5381": [ [0, 0, 0, "Styles should be written using objects.", "0"] ], @@ -3006,6 +3145,15 @@ exports[`better eslint`] = { [0, 0, 0, "Unexpected any. Specify a different type.", "0"], [0, 0, 0, "Do not use any type assertions.", "1"] ], + "public/app/features/datasources/state/index.ts:5381": [ + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "0"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "1"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "2"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "3"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "4"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "5"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "6"] + ], "public/app/features/datasources/state/navModel.ts:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"], [0, 0, 0, "Unexpected any. Specify a different type.", "1"] @@ -3092,6 +3240,24 @@ exports[`better eslint`] = { "public/app/features/dimensions/editors/ValueMappingsEditor/ValueMappingsEditorModal.tsx:5381": [ [0, 0, 0, "Styles should be written using objects.", "0"] ], + "public/app/features/dimensions/editors/index.ts:5381": [ + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "0"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "1"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "2"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "3"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "4"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "5"] + ], + "public/app/features/dimensions/index.ts:5381": [ + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "0"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "1"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "2"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "3"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "4"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "5"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "6"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "7"] + ], "public/app/features/dimensions/scale.ts:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"], [0, 0, 0, "Unexpected any. Specify a different type.", "1"] @@ -3307,6 +3473,9 @@ exports[`better eslint`] = { [0, 0, 0, "Styles should be written using objects.", "7"], [0, 0, 0, "Styles should be written using objects.", "8"] ], + "public/app/features/explore/TraceView/components/TracePageHeader/index.tsx:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`./TracePageHeader\`)", "0"] + ], "public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanBarRow.tsx:5381": [ [0, 0, 0, "Styles should be written using objects.", "0"], [0, 0, 0, "Styles should be written using objects.", "1"], @@ -3444,6 +3613,9 @@ exports[`better eslint`] = { [0, 0, 0, "Styles should be written using objects.", "6"], [0, 0, 0, "Styles should be written using objects.", "7"] ], + "public/app/features/explore/TraceView/components/TraceTimelineViewer/TimelineHeaderRow/index.tsx:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`./TimelineHeaderRow\`)", "0"] + ], "public/app/features/explore/TraceView/components/TraceTimelineViewer/VirtualizedTraceView.tsx:5381": [ [0, 0, 0, "Styles should be written using objects.", "0"], [0, 0, 0, "Styles should be written using objects.", "1"], @@ -3452,6 +3624,9 @@ exports[`better eslint`] = { "public/app/features/explore/TraceView/components/TraceTimelineViewer/index.tsx:5381": [ [0, 0, 0, "Styles should be written using objects.", "0"] ], + "public/app/features/explore/TraceView/components/TraceTimelineViewer/utils.tsx:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`../utils/date\`)", "0"] + ], "public/app/features/explore/TraceView/components/common/BreakableText.tsx:5381": [ [0, 0, 0, "Styles should be written using objects.", "0"] ], @@ -3473,6 +3648,21 @@ exports[`better eslint`] = { "public/app/features/explore/TraceView/components/demo/trace-generators.ts:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"] ], + "public/app/features/explore/TraceView/components/index.ts:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`./TraceTimelineViewer\`)", "0"], + [0, 0, 0, "Do not re-export imported variable (\`./TracePageHeader\`)", "1"], + [0, 0, 0, "Do not re-export imported variable (\`./settings/SpanBarSettings\`)", "2"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "3"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "4"], + [0, 0, 0, "Do not re-export imported variable (\`./TraceTimelineViewer/SpanDetail/DetailState\`)", "5"], + [0, 0, 0, "Do not re-export imported variable (\`./model/transform-trace-data\`)", "6"], + [0, 0, 0, "Do not re-export imported variable (\`./utils/filter-spans\`)", "7"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "8"] + ], + "public/app/features/explore/TraceView/components/model/ddg/types.tsx:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`./PathElem\`)", "0"], + [0, 0, 0, "Do not re-export imported variable (\`PathElem\`)", "1"] + ], "public/app/features/explore/TraceView/components/model/link-patterns.tsx:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"], [0, 0, 0, "Unexpected any. Specify a different type.", "1"], @@ -3494,9 +3684,24 @@ exports[`better eslint`] = { [0, 0, 0, "Styles should be written using objects.", "0"], [0, 0, 0, "Styles should be written using objects.", "1"] ], + "public/app/features/explore/TraceView/components/types/index.tsx:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`./trace\`)", "0"], + [0, 0, 0, "Do not re-export imported variable (\`../settings/SpanBarSettings\`)", "1"], + [0, 0, 0, "Do not re-export imported variable (\`./TTraceTimeline\`)", "2"], + [0, 0, 0, "Do not re-export imported variable (\`./TNil\`)", "3"], + [0, 0, 0, "Do not re-export imported variable (\`./links\`)", "4"] + ], "public/app/features/explore/TraceView/components/types/trace.ts:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"] ], + "public/app/features/explore/TraceView/components/utils/DraggableManager/demo/index.tsx:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`./DraggableManagerDemo\`)", "0"] + ], + "public/app/features/explore/TraceView/components/utils/DraggableManager/index.tsx:5381": [ + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "0"], + [0, 0, 0, "Do not re-export imported variable (\`./EUpdateTypes\`)", "1"], + [0, 0, 0, "Do not re-export imported variable (\`./DraggableManager\`)", "2"] + ], "public/app/features/explore/TraceView/createSpanLink.tsx:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"], [0, 0, 0, "Do not use any type assertions.", "1"] @@ -3504,6 +3709,9 @@ exports[`better eslint`] = { "public/app/features/explore/extensions/ConfirmNavigationModal.tsx:5381": [ [0, 0, 0, "\'VerticalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"] ], + "public/app/features/explore/hooks/useStateSync/index.ts:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`./external.utils\`)", "0"] + ], "public/app/features/explore/spec/helper/setup.tsx:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"], [0, 0, 0, "Unexpected any. Specify a different type.", "1"] @@ -3790,6 +3998,9 @@ exports[`better eslint`] = { [0, 0, 0, "Unexpected any. Specify a different type.", "3"], [0, 0, 0, "Unexpected any. Specify a different type.", "4"] ], + "public/app/features/migrate-to-cloud/api/index.ts:5381": [ + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "0"] + ], "public/app/features/org/OrgDetailsPage.tsx:5381": [ [0, 0, 0, "\'VerticalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"] ], @@ -3828,18 +4039,34 @@ exports[`better eslint`] = { [0, 0, 0, "Styles should be written using objects.", "2"], [0, 0, 0, "Styles should be written using objects.", "3"] ], + "public/app/features/plugins/admin/__mocks__/index.ts:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`./remotePlugin.mock\`)", "0"], + [0, 0, 0, "Do not re-export imported variable (\`./localPlugin.mock\`)", "1"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "2"] + ], "public/app/features/plugins/admin/components/Badges/PluginEnterpriseBadge.tsx:5381": [ [0, 0, 0, "\'HorizontalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"] ], "public/app/features/plugins/admin/components/Badges/PluginUpdateAvailableBadge.tsx:5381": [ [0, 0, 0, "Styles should be written using objects.", "0"] ], + "public/app/features/plugins/admin/components/Badges/index.ts:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`./PluginDisabledBadge\`)", "0"], + [0, 0, 0, "Do not re-export imported variable (\`./PluginInstallBadge\`)", "1"], + [0, 0, 0, "Do not re-export imported variable (\`./PluginEnterpriseBadge\`)", "2"], + [0, 0, 0, "Do not re-export imported variable (\`./PluginUpdateAvailableBadge\`)", "3"], + [0, 0, 0, "Do not re-export imported variable (\`./PluginAngularBadge\`)", "4"], + [0, 0, 0, "Do not re-export imported variable (\`./PluginDeprecatedBadge\`)", "5"] + ], "public/app/features/plugins/admin/components/Badges/sharedStyles.ts:5381": [ [0, 0, 0, "Styles should be written using objects.", "0"] ], "public/app/features/plugins/admin/components/GetStartedWithPlugin/GetStartedWithDataSource.tsx:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"] ], + "public/app/features/plugins/admin/components/GetStartedWithPlugin/index.ts:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`./GetStartedWithPlugin\`)", "0"] + ], "public/app/features/plugins/admin/components/HorizontalGroup.tsx:5381": [ [0, 0, 0, "Styles should be written using objects.", "0"] ], @@ -3853,6 +4080,10 @@ exports[`better eslint`] = { [0, 0, 0, "\'HorizontalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"], [0, 0, 0, "Styles should be written using objects.", "1"] ], + "public/app/features/plugins/admin/components/InstallControls/index.tsx:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`./InstallControlsWarning\`)", "0"], + [0, 0, 0, "Do not re-export imported variable (\`./InstallControlsButton\`)", "1"] + ], "public/app/features/plugins/admin/components/PluginActions.tsx:5381": [ [0, 0, 0, "\'HorizontalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"], [0, 0, 0, "\'VerticalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "1"], @@ -4058,6 +4289,10 @@ exports[`better eslint`] = { [0, 0, 0, "Do not use any type assertions.", "0"], [0, 0, 0, "Do not use any type assertions.", "1"] ], + "public/app/features/search/service/index.ts:5381": [ + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "0"], + [0, 0, 0, "Do not re-export imported variable (\`./searcher\`)", "1"] + ], "public/app/features/search/service/sql.ts:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"] ], @@ -4228,6 +4463,10 @@ exports[`better eslint`] = { "public/app/features/transformers/editors/CalculateFieldTransformerEditor/WindowOptionsEditor.tsx:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"] ], + "public/app/features/transformers/editors/CalculateFieldTransformerEditor/index.ts:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`CalculateFieldTransformerEditor\`)", "0"], + [0, 0, 0, "Do not re-export imported variable (\`calculateFieldTransformRegistryItem\`)", "1"] + ], "public/app/features/transformers/editors/ConvertFieldTypeTransformerEditor.tsx:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"] ], @@ -4422,6 +4661,9 @@ exports[`better eslint`] = { [0, 0, 0, "Unexpected any. Specify a different type.", "0"], [0, 0, 0, "Unexpected any. Specify a different type.", "1"] ], + "public/app/features/variables/pickers/index.ts:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`./OptionsPicker/OptionsPicker\`)", "0"] + ], "public/app/features/variables/pickers/shared/VariableLink.tsx:5381": [ [0, 0, 0, "Styles should be written using objects.", "0"], [0, 0, 0, "Styles should be written using objects.", "1"] @@ -4513,11 +4755,13 @@ exports[`better eslint`] = { [0, 0, 0, "Unexpected any. Specify a different type.", "7"] ], "public/app/features/variables/types.ts:5381": [ - [0, 0, 0, "Unexpected any. Specify a different type.", "0"], - [0, 0, 0, "Unexpected any. Specify a different type.", "1"], + [0, 0, 0, "Do not re-export imported variable (\`@grafana/data\`)", "0"], + [0, 0, 0, "Do not re-export imported variable (\`VariableHide\`)", "1"], [0, 0, 0, "Unexpected any. Specify a different type.", "2"], [0, 0, 0, "Unexpected any. Specify a different type.", "3"], - [0, 0, 0, "Unexpected any. Specify a different type.", "4"] + [0, 0, 0, "Unexpected any. Specify a different type.", "4"], + [0, 0, 0, "Unexpected any. Specify a different type.", "5"], + [0, 0, 0, "Unexpected any. Specify a different type.", "6"] ], "public/app/features/variables/utils.ts:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"], @@ -4540,9 +4784,19 @@ exports[`better eslint`] = { [0, 0, 0, "Unexpected any. Specify a different type.", "1"], [0, 0, 0, "Unexpected any. Specify a different type.", "2"] ], + "public/app/plugins/datasource/azuremonitor/azureMetadata/index.ts:5381": [ + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "0"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "1"] + ], "public/app/plugins/datasource/azuremonitor/azure_monitor/azure_monitor_datasource.ts:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"] ], + "public/app/plugins/datasource/azuremonitor/components/ArgQueryEditor/index.tsx:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`./ArgQueryEditor\`)", "0"] + ], + "public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/index.tsx:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`./LogsQueryEditor\`)", "0"] + ], "public/app/plugins/datasource/azuremonitor/components/MetricsQueryEditor/DimensionFields.tsx:5381": [ [0, 0, 0, "\'HorizontalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"] ], @@ -4552,12 +4806,37 @@ exports[`better eslint`] = { "public/app/plugins/datasource/azuremonitor/components/QueryEditor/QueryEditor.tsx:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"] ], + "public/app/plugins/datasource/azuremonitor/components/QueryEditor/index.tsx:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`./QueryEditor\`)", "0"] + ], + "public/app/plugins/datasource/azuremonitor/components/ResourceField/index.tsx:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`./ResourceField\`)", "0"] + ], + "public/app/plugins/datasource/azuremonitor/components/ResourcePicker/index.tsx:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`./ResourcePicker\`)", "0"] + ], "public/app/plugins/datasource/azuremonitor/components/TracesQueryEditor/Filter.tsx:5381": [ [0, 0, 0, "\'HorizontalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"] ], + "public/app/plugins/datasource/azuremonitor/components/TracesQueryEditor/index.tsx:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`./TracesQueryEditor\`)", "0"] + ], "public/app/plugins/datasource/azuremonitor/components/VariableEditor/VariableEditor.test.tsx:5381": [ [0, 0, 0, "* import is invalid because \'Layout,HorizontalGroup,VerticalGroup\' from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"] ], + "public/app/plugins/datasource/azuremonitor/types/index.ts:5381": [ + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "0"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "1"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "2"] + ], + "public/app/plugins/datasource/azuremonitor/types/query.ts:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`AzureQueryType\`)", "0"], + [0, 0, 0, "Do not re-export imported variable (\`../dataquery.gen\`)", "1"], + [0, 0, 0, "Do not re-export imported variable (\`../dataquery.gen\`)", "2"] + ], + "public/app/plugins/datasource/azuremonitor/types/templateVariables.ts:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`../dataquery.gen\`)", "0"] + ], "public/app/plugins/datasource/azuremonitor/utils/messageFromError.ts:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"] ], @@ -4587,6 +4866,23 @@ exports[`better eslint`] = { "public/app/plugins/datasource/cloud-monitoring/components/VisualMetricQueryEditor.tsx:5381": [ [0, 0, 0, "Styles should be written using objects.", "0"] ], + "public/app/plugins/datasource/cloud-monitoring/components/index.ts:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`./Project\`)", "0"], + [0, 0, 0, "Do not re-export imported variable (\`./GroupBy\`)", "1"], + [0, 0, 0, "Do not re-export imported variable (\`./Alignment\`)", "2"], + [0, 0, 0, "Do not re-export imported variable (\`./LabelFilter\`)", "3"], + [0, 0, 0, "Do not re-export imported variable (\`./AnnotationsHelp\`)", "4"], + [0, 0, 0, "Do not re-export imported variable (\`./AlignmentFunction\`)", "5"], + [0, 0, 0, "Do not re-export imported variable (\`./AliasBy\`)", "6"], + [0, 0, 0, "Do not re-export imported variable (\`./Aggregation\`)", "7"], + [0, 0, 0, "Do not re-export imported variable (\`./MetricQueryEditor\`)", "8"], + [0, 0, 0, "Do not re-export imported variable (\`./SLOQueryEditor\`)", "9"], + [0, 0, 0, "Do not re-export imported variable (\`./MQLQueryEditor\`)", "10"], + [0, 0, 0, "Do not re-export imported variable (\`./Fields\`)", "11"], + [0, 0, 0, "Do not re-export imported variable (\`./VisualMetricQueryEditor\`)", "12"], + [0, 0, 0, "Do not re-export imported variable (\`./PeriodSelect\`)", "13"], + [0, 0, 0, "Do not re-export imported variable (\`./Preprocessor\`)", "14"] + ], "public/app/plugins/datasource/cloud-monitoring/datasource.ts:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"], [0, 0, 0, "Unexpected any. Specify a different type.", "1"], @@ -4597,9 +4893,46 @@ exports[`better eslint`] = { [0, 0, 0, "Do not use any type assertions.", "0"], [0, 0, 0, "Do not use any type assertions.", "1"] ], + "public/app/plugins/datasource/cloud-monitoring/types/query.ts:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`QueryType\`)", "0"], + [0, 0, 0, "Do not re-export imported variable (\`../dataquery.gen\`)", "1"], + [0, 0, 0, "Do not re-export imported variable (\`../dataquery.gen\`)", "2"] + ], "public/app/plugins/datasource/cloud-monitoring/types/types.ts:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"] ], + "public/app/plugins/datasource/cloud-monitoring/webpack.config.ts:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`config\`)", "0"] + ], + "public/app/plugins/datasource/cloudwatch/__mocks__/cloudwatch-logs-test-data/index.ts:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`./empty\`)", "0"], + [0, 0, 0, "Do not re-export imported variable (\`./whitespaceQuery\`)", "1"], + [0, 0, 0, "Do not re-export imported variable (\`./commentOnlyQuery\`)", "2"], + [0, 0, 0, "Do not re-export imported variable (\`./singleLineFullQuery\`)", "3"], + [0, 0, 0, "Do not re-export imported variable (\`./multiLineFullQuery\`)", "4"], + [0, 0, 0, "Do not re-export imported variable (\`./filterQuery\`)", "5"], + [0, 0, 0, "Do not re-export imported variable (\`./newCommandQuery\`)", "6"], + [0, 0, 0, "Do not re-export imported variable (\`./sortQuery\`)", "7"] + ], + "public/app/plugins/datasource/cloudwatch/__mocks__/cloudwatch-sql-test-data/index.ts:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`./multiLineFullQuery\`)", "0"], + [0, 0, 0, "Do not re-export imported variable (\`./singleLineFullQuery\`)", "1"], + [0, 0, 0, "Do not re-export imported variable (\`./singleLineEmptyQuery\`)", "2"], + [0, 0, 0, "Do not re-export imported variable (\`./singleLineTwoQueries\`)", "3"], + [0, 0, 0, "Do not re-export imported variable (\`./multiLineIncompleteQueryWithoutNamespace\`)", "4"] + ], + "public/app/plugins/datasource/cloudwatch/__mocks__/dynamic-label-test-data/index.ts:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`./afterLabelValue\`)", "0"], + [0, 0, 0, "Do not re-export imported variable (\`./insideLabelValue\`)", "1"] + ], + "public/app/plugins/datasource/cloudwatch/__mocks__/metric-math-test-data/index.ts:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`./singleLineEmptyQuery\`)", "0"], + [0, 0, 0, "Do not re-export imported variable (\`./afterFunctionQuery\`)", "1"], + [0, 0, 0, "Do not re-export imported variable (\`./secondArgQuery\`)", "2"], + [0, 0, 0, "Do not re-export imported variable (\`./secondArgAfterSearchQuery\`)", "3"], + [0, 0, 0, "Do not re-export imported variable (\`./thirdArgAfterSearchQuery\`)", "4"], + [0, 0, 0, "Do not re-export imported variable (\`./withinStringQuery\`)", "5"] + ], "public/app/plugins/datasource/cloudwatch/components/CheatSheet/LogsCheatSheet.tsx:5381": [ [0, 0, 0, "Styles should be written using objects.", "0"], [0, 0, 0, "Styles should be written using objects.", "1"] @@ -4616,12 +4949,24 @@ exports[`better eslint`] = { "public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/MetricsQueryEditor.test.tsx:5381": [ [0, 0, 0, "* import is invalid because \'Layout,HorizontalGroup,VerticalGroup\' from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"] ], + "public/app/plugins/datasource/cloudwatch/components/QueryEditor/MetricsQueryEditor/SQLBuilderEditor/index.tsx:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`./SQLBuilderEditor\`)", "0"] + ], + "public/app/plugins/datasource/cloudwatch/components/QueryEditor/QueryEditor.test.tsx:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`./MetricsQueryEditor/SQLCodeEditor\`)", "0"] + ], "public/app/plugins/datasource/cloudwatch/components/shared/LogGroups/LegacyLogGroupNamesSelection.tsx:5381": [ [0, 0, 0, "Styles should be written using objects.", "0"] ], + "public/app/plugins/datasource/cloudwatch/components/shared/MetricStatEditor/index.ts:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`./MetricStatEditor\`)", "0"] + ], "public/app/plugins/datasource/cloudwatch/datasource.ts:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"] ], + "public/app/plugins/datasource/cloudwatch/expressions.ts:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`./dataquery.gen\`)", "0"] + ], "public/app/plugins/datasource/cloudwatch/guards.ts:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"] ], @@ -4631,13 +4976,14 @@ exports[`better eslint`] = { [0, 0, 0, "Unexpected any. Specify a different type.", "2"] ], "public/app/plugins/datasource/cloudwatch/types.ts:5381": [ - [0, 0, 0, "Unexpected any. Specify a different type.", "0"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "0"], [0, 0, 0, "Unexpected any. Specify a different type.", "1"], [0, 0, 0, "Unexpected any. Specify a different type.", "2"], [0, 0, 0, "Unexpected any. Specify a different type.", "3"], [0, 0, 0, "Unexpected any. Specify a different type.", "4"], [0, 0, 0, "Unexpected any. Specify a different type.", "5"], - [0, 0, 0, "Unexpected any. Specify a different type.", "6"] + [0, 0, 0, "Unexpected any. Specify a different type.", "6"], + [0, 0, 0, "Unexpected any. Specify a different type.", "7"] ], "public/app/plugins/datasource/cloudwatch/utils/datalinks.ts:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"], @@ -4646,6 +4992,11 @@ exports[`better eslint`] = { "public/app/plugins/datasource/cloudwatch/utils/logsRetry.ts:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"] ], + "public/app/plugins/datasource/dashboard/index.ts:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`./runSharedRequest\`)", "0"], + [0, 0, 0, "Do not re-export imported variable (\`./DashboardQueryEditor\`)", "1"], + [0, 0, 0, "Do not re-export imported variable (\`./types\`)", "2"] + ], "public/app/plugins/datasource/dashboard/runSharedRequest.ts:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"], [0, 0, 0, "Do not use any type assertions.", "1"] @@ -4801,6 +5152,10 @@ exports[`better eslint`] = { "public/app/plugins/datasource/elasticsearch/test-helpers/render.tsx:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"] ], + "public/app/plugins/datasource/elasticsearch/types.ts:5381": [ + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "0"], + [0, 0, 0, "Do not re-export imported variable (\`./dataquery.gen\`)", "1"] + ], "public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/LabelsEditor.tsx:5381": [ [0, 0, 0, "Styles should be written using objects.", "0"], [0, 0, 0, "Styles should be written using objects.", "1"] @@ -4830,6 +5185,10 @@ exports[`better eslint`] = { [0, 0, 0, "Unexpected any. Specify a different type.", "1"], [0, 0, 0, "Styles should be written using objects.", "2"] ], + "public/app/plugins/datasource/grafana-testdata-datasource/components/index.ts:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`./StreamingClientEditor\`)", "0"], + [0, 0, 0, "Do not re-export imported variable (\`./RandomWalkEditor\`)", "1"] + ], "public/app/plugins/datasource/grafana-testdata-datasource/datasource.ts:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"], [0, 0, 0, "Unexpected any. Specify a different type.", "1"] @@ -4837,6 +5196,9 @@ exports[`better eslint`] = { "public/app/plugins/datasource/grafana-testdata-datasource/runStreams.ts:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"] ], + "public/app/plugins/datasource/grafana-testdata-datasource/webpack.config.ts:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`config\`)", "0"] + ], "public/app/plugins/datasource/grafana/components/AnnotationQueryEditor.tsx:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"] ], @@ -5137,6 +5499,9 @@ exports[`better eslint`] = { "public/app/plugins/datasource/jaeger/_importedDependencies/model/transform-trace-data.tsx:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"] ], + "public/app/plugins/datasource/jaeger/_importedDependencies/types/index.tsx:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`./trace\`)", "0"] + ], "public/app/plugins/datasource/jaeger/_importedDependencies/types/trace.ts:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"] ], @@ -5244,6 +5609,14 @@ exports[`better eslint`] = { "public/app/plugins/datasource/loki/streaming.ts:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"] ], + "public/app/plugins/datasource/loki/types.ts:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`LokiQueryDirection\`)", "0"], + [0, 0, 0, "Do not re-export imported variable (\`LokiQueryType\`)", "1"], + [0, 0, 0, "Do not re-export imported variable (\`SupportingQueryType\`)", "2"] + ], + "public/app/plugins/datasource/mixed/module.ts:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`MixedDatasource\`)", "0"] + ], "public/app/plugins/datasource/opentsdb/components/OpenTsdbQueryEditor.tsx:5381": [ [0, 0, 0, "Styles should be written using objects.", "0"], [0, 0, 0, "Styles should be written using objects.", "1"] @@ -5305,6 +5678,9 @@ exports[`better eslint`] = { [0, 0, 0, "Styles should be written using objects.", "0"], [0, 0, 0, "Styles should be written using objects.", "1"] ], + "public/app/plugins/datasource/parca/webpack.config.ts:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`config\`)", "0"] + ], "public/app/plugins/datasource/prometheus/components/PromExemplarField.tsx:5381": [ [0, 0, 0, "Styles should be written using objects.", "0"], [0, 0, 0, "Styles should be written using objects.", "1"], @@ -5571,6 +5947,9 @@ exports[`better eslint`] = { [0, 0, 0, "Do not use any type assertions.", "6"], [0, 0, 0, "Unexpected any. Specify a different type.", "7"] ], + "public/app/plugins/datasource/tempo/webpack.config.ts:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`config\`)", "0"] + ], "public/app/plugins/datasource/zipkin/ConfigEditor.tsx:5381": [ [0, 0, 0, "Styles should be written using objects.", "0"] ], @@ -5586,6 +5965,9 @@ exports[`better eslint`] = { "public/app/plugins/datasource/zipkin/utils/transforms.ts:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"] ], + "public/app/plugins/datasource/zipkin/webpack.config.ts:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`config\`)", "0"] + ], "public/app/plugins/panel/alertlist/AlertInstances.tsx:5381": [ [0, 0, 0, "Styles should be written using objects.", "0"], [0, 0, 0, "Styles should be written using objects.", "1"] @@ -5642,6 +6024,16 @@ exports[`better eslint`] = { [0, 0, 0, "Do not use any type assertions.", "0"], [0, 0, 0, "Unexpected any. Specify a different type.", "1"] ], + "public/app/plugins/panel/candlestick/types.ts:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`Options\`)", "0"], + [0, 0, 0, "Do not re-export imported variable (\`CandlestickColors\`)", "1"], + [0, 0, 0, "Do not re-export imported variable (\`defaultCandlestickColors\`)", "2"], + [0, 0, 0, "Do not re-export imported variable (\`CandleStyle\`)", "3"], + [0, 0, 0, "Do not re-export imported variable (\`ColorStrategy\`)", "4"], + [0, 0, 0, "Do not re-export imported variable (\`VizDisplayMode\`)", "5"], + [0, 0, 0, "Do not re-export imported variable (\`CandlestickFieldMap\`)", "6"], + [0, 0, 0, "Do not re-export imported variable (\`FieldConfig\`)", "7"] + ], "public/app/plugins/panel/canvas/components/CanvasTooltip.tsx:5381": [ [0, 0, 0, "\'VerticalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"] ], @@ -5752,6 +6144,9 @@ exports[`better eslint`] = { [0, 0, 0, "Unexpected any. Specify a different type.", "0"], [0, 0, 0, "Unexpected any. Specify a different type.", "1"] ], + "public/app/plugins/panel/geomap/types.ts:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`./panelcfg.gen\`)", "0"] + ], "public/app/plugins/panel/geomap/utils/layers.ts:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"] ], @@ -5788,7 +6183,8 @@ exports[`better eslint`] = { [0, 0, 0, "Unexpected any. Specify a different type.", "1"] ], "public/app/plugins/panel/heatmap/types.ts:5381": [ - [0, 0, 0, "Do not use any type assertions.", "0"] + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "0"], + [0, 0, 0, "Do not use any type assertions.", "1"] ], "public/app/plugins/panel/heatmap/utils.ts:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"], @@ -5829,6 +6225,9 @@ exports[`better eslint`] = { "public/app/plugins/panel/logs/LogsPanel.tsx:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"] ], + "public/app/plugins/panel/logs/types.ts:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`./panelcfg.gen\`)", "0"] + ], "public/app/plugins/panel/nodeGraph/Edge.tsx:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"] ], @@ -5883,10 +6282,16 @@ exports[`better eslint`] = { "public/app/plugins/panel/nodeGraph/editor/ArcOptionsEditor.tsx:5381": [ [0, 0, 0, "Styles should be written using objects.", "0"] ], + "public/app/plugins/panel/nodeGraph/index.ts:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`./NodeGraph\`)", "0"] + ], "public/app/plugins/panel/nodeGraph/layout.ts:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"], [0, 0, 0, "Do not use any type assertions.", "1"] ], + "public/app/plugins/panel/nodeGraph/types.ts:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`./panelcfg.gen\`)", "0"] + ], "public/app/plugins/panel/nodeGraph/useContextMenu.tsx:5381": [ [0, 0, 0, "Styles should be written using objects.", "0"], [0, 0, 0, "Styles should be written using objects.", "1"] @@ -6045,6 +6450,9 @@ exports[`better eslint`] = { "public/app/plugins/panel/xychart/v2/utils.ts:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"] ], + "public/app/plugins/sdk.ts:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`loadPluginCss\`)", "0"] + ], "public/app/store/configureStore.ts:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"] ], @@ -6052,6 +6460,9 @@ exports[`better eslint`] = { [0, 0, 0, "Do not use any type assertions.", "0"], [0, 0, 0, "Unexpected any. Specify a different type.", "1"] ], + "public/app/types/acl.ts:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`OrgRole\`)", "0"] + ], "public/app/types/alerting.ts:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"], [0, 0, 0, "Unexpected any. Specify a different type.", "1"], @@ -6086,6 +6497,30 @@ exports[`better eslint`] = { [0, 0, 0, "Unexpected any. Specify a different type.", "11"], [0, 0, 0, "Unexpected any. Specify a different type.", "12"] ], + "public/app/types/index.ts:5381": [ + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "0"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "1"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "2"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "3"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "4"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "5"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "6"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "7"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "8"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "9"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "10"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "11"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "12"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "13"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "14"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "15"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "16"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "17"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "18"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "19"], + [0, 0, 0, "Do not use export all (\`export * from ...\`)", "20"], + [0, 0, 0, "Do not re-export imported variable (\`CoreEvents\`)", "21"] + ], "public/app/types/jquery/jquery.d.ts:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"], [0, 0, 0, "Unexpected any. Specify a different type.", "1"], @@ -6101,6 +6536,9 @@ exports[`better eslint`] = { [0, 0, 0, "Unexpected any. Specify a different type.", "0"], [0, 0, 0, "Do not use any type assertions.", "1"] ], + "public/app/types/teams.ts:5381": [ + [0, 0, 0, "Do not re-export imported variable (\`TeamDTO\`)", "0"] + ], "public/app/types/unified-alerting-dto.ts:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"] ], diff --git a/.betterer.ts b/.betterer.ts index 0fd570add6b..44267d58a5a 100644 --- a/.betterer.ts +++ b/.betterer.ts @@ -105,6 +105,16 @@ function countEslintErrors() { '@typescript-eslint/consistent-type-assertions': ['error', { assertionStyle: 'never' }], }; + const grafanaRules: Partial = { + ...nonTestFilesRules, + 'no-barrel-files/no-barrel-files': 'error', + }; + + const testFilesAndGrafanaRules: Partial = { + ...baseRules, + 'no-barrel-files/no-barrel-files': 'error', + }; + // group files by eslint config file // this will create two file groups for each eslint config file // one for test files and one for non-test files @@ -117,10 +127,16 @@ function countEslintErrors() { filePath.endsWith('.test.ts') || filePath.includes('__mocks__') || filePath.includes('public/test/'); + const isGrafanaFile = filePath.includes('public/app/'); - if (isTestFile) { + if (isGrafanaFile && isTestFile) { + configPath += '-test-grafana'; + } else if (isGrafanaFile) { + configPath += '-grafana'; + } else if (isTestFile) { configPath += '-test'; } + if (!fileGroups[configPath]) { fileGroups[configPath] = []; } @@ -128,7 +144,16 @@ function countEslintErrors() { } for (const configPath of Object.keys(fileGroups)) { - const rules = configPath.endsWith('-test') ? baseRules : nonTestFilesRules; + let rules; + if (configPath.endsWith('-test-grafana')) { + rules = testFilesAndGrafanaRules; + } else if (configPath.endsWith('-test')) { + rules = baseRules; + } else if (configPath.endsWith('-grafana')) { + rules = grafanaRules; + } else { + rules = nonTestFilesRules; + } // this is by far the slowest part of this code. It takes eslint about 2 seconds just to find the config const linterOptions = (await cli.calculateConfigForFile(fileGroups[configPath][0])) as Linter.Config; const runner = new ESLint({ diff --git a/.eslintrc b/.eslintrc index b64d731e0c9..dac72ca97e0 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,7 +1,7 @@ { "extends": ["@grafana/eslint-config"], "root": true, - "plugins": ["@emotion", "lodash", "jest", "import", "jsx-a11y", "@grafana"], + "plugins": ["@emotion", "lodash", "jest", "import", "jsx-a11y", "@grafana", "no-barrel-files"], "settings": { "import/internal-regex": "^(app/)|(@grafana)", "import/external-module-folders": ["node_modules", ".yarn"] diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 98d6e96c183..4aaa6970c9c 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -376,7 +376,6 @@ /.levignore.js @grafana/plugins-platform-frontend playwright.config.ts @grafana/plugins-platform-frontend - # public folder /public/app/core/ @grafana/grafana-frontend-platform /public/app/core/components/TimePicker/ @grafana/grafana-frontend-platform @@ -536,6 +535,7 @@ playwright.config.ts @grafana/plugins-platform-frontend /scripts/generate-icon-bundle.js @grafana/plugins-platform-frontend @grafana/grafana-frontend-platform /scripts/generate-rtk-apis.ts @grafana/grafana-frontend-platform /scripts/levitate-parse-json-report.js @grafana/plugins-platform-frontend +/scripts/codemods/explicit-barrel-imports.cjs @grafana/frontend-ops /scripts/**/generate-transformations* @grafana/dataviz-squad /scripts/webpack/ @grafana/frontend-ops diff --git a/package.json b/package.json index 3644f896724..ee2b5e12b0a 100644 --- a/package.json +++ b/package.json @@ -173,6 +173,7 @@ "eslint-plugin-jsdoc": "48.2.3", "eslint-plugin-jsx-a11y": "6.8.0", "eslint-plugin-lodash": "7.4.0", + "eslint-plugin-no-barrel-files": "^1.1.0", "eslint-plugin-react": "7.34.1", "eslint-plugin-react-hooks": "4.6.0", "eslint-scope": "^8.0.0", diff --git a/scripts/ci-frontend-metrics.sh b/scripts/ci-frontend-metrics.sh index 21313cd4c43..292e2578ea5 100755 --- a/scripts/ci-frontend-metrics.sh +++ b/scripts/ci-frontend-metrics.sh @@ -11,6 +11,7 @@ ACCESSIBILITY_ERRORS="$(grep -oP '\"errors\":(\d+),' pa11y-ci-results.json | gre DIRECTIVES="$(grep -r -o directive public/app/ | wc -l)" CONTROLLERS="$(grep -r -oP 'class .*Ctrl' public/app/ | wc -l)" LEGACY_FORMS="$(grep -r -oP 'LegacyForms;' public/app | wc -l)" +BARREL_IMPORTS="$(grep -r -oP '@todo: replace barrel import path' public/app | wc -l)" CLASSNAME_PROP="$(grep -r -o -E --include="*.ts*" "\.*.className=\W.*\W.*" public/app | wc -l)" EMOTION_IMPORTS="$(grep -r -o -E --include="*.ts*" --exclude="*.test*" "\{.*css.*\} from '@emotion/css'" public/app | wc -l)" TS_FILES="$(find public/app -type f -name "*.ts*" -not -name "*.test*" | wc -l)" @@ -29,6 +30,7 @@ echo -e "Accessibility errors: $ACCESSIBILITY_ERRORS" echo -e "Directives: $DIRECTIVES" echo -e "Controllers: $CONTROLLERS" echo -e "Legacy forms: $LEGACY_FORMS" +echo -e "Barrel imports: $BARREL_IMPORTS" echo -e "Total bundle folder size: $TOTAL_BUNDLE" echo -e "Total outdated dependencies: $OUTDATED_DEPENDENCIES" echo -e "Low vulnerabilities: $LOW_VULNERABILITIES" diff --git a/scripts/codemods/explicit-barrel-imports.cjs b/scripts/codemods/explicit-barrel-imports.cjs new file mode 100644 index 00000000000..c87c26cc5d6 --- /dev/null +++ b/scripts/codemods/explicit-barrel-imports.cjs @@ -0,0 +1,39 @@ +const fs = require('fs'); +const path = require('path'); + +module.exports = function (fileInfo, api) { + const j = api.jscodeshift; + const root = j.withParser('tsx')(fileInfo.source); + const fileDir = path.dirname(fileInfo.path); + + // Function to check if the path potentially points to a barrel file + const mightBeBarrelFileImport = (importPath) => { + const fullPath = path.join(fileDir, importPath); + if (fs.existsSync(fullPath) && fs.lstatSync(fullPath).isDirectory()) { + if (fs.existsSync(path.join(fullPath, 'index.ts')) || fs.existsSync(path.join(fullPath, 'index.js'))) { + return true; + } + } + return false; + }; + + // Udpate import declarations that import from barrel files + root + .find(j.ImportDeclaration) + .filter((path) => mightBeBarrelFileImport(path.node.source.value)) + .forEach((path) => { + // Create a comment node + const comment = j.commentLine(' @todo: replace barrel import path'); + + // Attach the comment as a leading comment to the import declaration + if (!path.node.comments) { + path.node.comments = []; + } + path.node.comments.push(comment); + + // Update the import path appending '/index' + path.node.source.value = path.node.source.value + '/index'; + }); + + return root.toSource(); +}; diff --git a/yarn.lock b/yarn.lock index 0d46f9053b6..ce4f24a0fdf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10789,7 +10789,7 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/utils@npm:6.21.0, @typescript-eslint/utils@npm:^6.0.0": +"@typescript-eslint/utils@npm:6.21.0, @typescript-eslint/utils@npm:^6.0.0, @typescript-eslint/utils@npm:^6.4.1": version: 6.21.0 resolution: "@typescript-eslint/utils@npm:6.21.0" dependencies: @@ -16734,6 +16734,15 @@ __metadata: languageName: node linkType: hard +"eslint-plugin-no-barrel-files@npm:^1.1.0": + version: 1.1.0 + resolution: "eslint-plugin-no-barrel-files@npm:1.1.0" + dependencies: + "@typescript-eslint/utils": "npm:^6.4.1" + checksum: 10/f8a71fbe38e7af91a078d235b5c52d9eb06f5c0658af24714a684e3c66b60fe37f34ae984c3f23adb0916fd3271730fa149bc18ff528ec73f8bd4c3cfb55b3a1 + languageName: node + linkType: hard + "eslint-plugin-react-hooks@npm:4.6.0": version: 4.6.0 resolution: "eslint-plugin-react-hooks@npm:4.6.0" @@ -18754,6 +18763,7 @@ __metadata: eslint-plugin-jsdoc: "npm:48.2.3" eslint-plugin-jsx-a11y: "npm:6.8.0" eslint-plugin-lodash: "npm:7.4.0" + eslint-plugin-no-barrel-files: "npm:^1.1.0" eslint-plugin-react: "npm:7.34.1" eslint-plugin-react-hooks: "npm:4.6.0" eslint-scope: "npm:^8.0.0" From eb46d8582952e31f62cf72b81d51cf4a5ee27515 Mon Sep 17 00:00:00 2001 From: David Allen Date: Mon, 15 Apr 2024 10:47:58 -0400 Subject: [PATCH 021/147] Docs: add best practices Play link (#86076) --- .../sources/dashboards/build-dashboards/best-practices/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/dashboards/build-dashboards/best-practices/index.md b/docs/sources/dashboards/build-dashboards/best-practices/index.md index b0677c24b13..e50b24c62af 100644 --- a/docs/sources/dashboards/build-dashboards/best-practices/index.md +++ b/docs/sources/dashboards/build-dashboards/best-practices/index.md @@ -69,7 +69,7 @@ This method is similar to the RED method, but it includes saturation. - **Errors -** Rate of requests that are failing - **Saturation -** How "full" your system is -[Here's an example from Grafana Play](https://play.grafana.org/d/000000109/the-four-golden-signals?orgId=1). +{{< docs/play title="The Four Golden Signals" url="https://play.grafana.org/d/000000109/" >}} ## Dashboard management maturity model From 918f122433c0ee702516c9981fa600558d90be44 Mon Sep 17 00:00:00 2001 From: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> Date: Mon, 15 Apr 2024 10:49:14 -0400 Subject: [PATCH 022/147] Docs: add tags section to dashboard settings docs (#85875) Edited --- .../modify-dashboard-settings/index.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/docs/sources/dashboards/build-dashboards/modify-dashboard-settings/index.md b/docs/sources/dashboards/build-dashboards/modify-dashboard-settings/index.md index 2d2abaf6c7e..9c15dc95099 100644 --- a/docs/sources/dashboards/build-dashboards/modify-dashboard-settings/index.md +++ b/docs/sources/dashboards/build-dashboards/modify-dashboard-settings/index.md @@ -47,6 +47,24 @@ Adjust dashboard time settings when you want to change the dashboard timezone, t - **Now delay:** Override the `now` time by entering a time delay. Use this option to accommodate known delays in data aggregation to avoid null values. - **Hide time picker:** Select this option if you do not want Grafana to display the time picker. +## Add tags + +You can add metadata to your dashboards using tags. Tags also give you the ability to filter the list of dashboards. + +Tags can be up to 50 characters long, including spaces. + +To add tags to a dashboard, follow these steps: + +1. On the **Dashboard settings** page, scroll down to the **Tags** section. +1. In the field, enter a new or existing tag. + + If you're entering an existing tag, make sure that you spell it the same way or a new tag is created. + +1. Click **Add** or press the Enter key. +1. Save the dashboard. + +When you're on the **Dashboards** page, any tags you've entered show up under the **Tags** column. + ## Add an annotation query An annotation query is a query that queries for events. These events can be visualized in graphs across the dashboard as vertical lines along with a small From d9a0cedd89b439b1fbb431f092c2c04ab18d61f1 Mon Sep 17 00:00:00 2001 From: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> Date: Mon, 15 Apr 2024 10:51:00 -0400 Subject: [PATCH 023/147] Docs: add panel overview (#86075) * Added panel overview page and updated panel editor page * Finalized panel overview intro text and added links * Added add panel section to overview and removed section from editor * Fixed version interpolation syntax and updated Cloud link Co-authored-by: Jack Baldry * Fixed version interpolation syntax Co-authored-by: Jack Baldry --------- Co-authored-by: Jack Baldry --- .../panel-editor-overview/index.md | 95 +++-------- .../panel-overview/index.md | 161 ++++++++++++++++++ 2 files changed, 183 insertions(+), 73 deletions(-) create mode 100644 docs/sources/panels-visualizations/panel-overview/index.md diff --git a/docs/sources/panels-visualizations/panel-editor-overview/index.md b/docs/sources/panels-visualizations/panel-editor-overview/index.md index 54ddeda2028..7c638b18ef8 100644 --- a/docs/sources/panels-visualizations/panel-editor-overview/index.md +++ b/docs/sources/panels-visualizations/panel-editor-overview/index.md @@ -15,99 +15,54 @@ keywords: - panel - dashboard - dynamic - - rows - add labels: products: - cloud - enterprise - oss -menuTitle: Panel editor overview -title: Panel editor overview +menuTitle: Panel editor +title: Panel editor description: Learn about the features of the panel editor weight: 20 --- -# Panel editor overview +# Panel editor In the panel editor, you can update all the elements of a visualization including the data source, queries, time range, and visualization display options. ![Panel editor](/media/docs/grafana/panels-visualizations/screenshot-panel-editor-view.png) -To add a panel in a new dashboard click **+ Add visualization** in the middle of the dashboard. To add a panel to an existing dashboard, click **Add** in the dashboard header and select **Visualization** in the drop-down: +This following sections describe the areas of the Grafana panel editor. -![Add dropdown](/media/docs/grafana/dashboards/screenshot-add-dropdown-10.0.png) +## Panel header -## Panel menu +The header section lists the dashboard in which the panel appears and the following controls: -To access the panel editor, hover over the top-right corner of any panel. Click the panel menu icon that appears and select **Edit**. The panel menu gives you access to the following actions: +- **Discard:** Discards changes you have made to the panel since you last saved the dashboard. +- **Save:** Saves changes you made to the panel. +- **Apply:** Applies changes you made and closes the panel editor, returning you to the dashboard. You'll have to save the dashboard to persist the applied changes. -- **View**: View the panel in full screen. -- **Edit**: Open the panel editor to edit panel and visualization options. -- **Share**: Share the panel as a link, embed, or library panel. -- **Explore**: Open the panel in **Explore**, where you can focus on your query. -- **Inspect**: Open the **Inspect** drawer, where you can review the panel data, stats, metadata, JSON, and query. - - **Data**: Open the **Inspect** drawer in the **Data** tab. - - **Query**: Open the **Inspect** drawer in the **Query** tab. - - **Panel JSON**: Open the **Inspect** drawer in the **JSON** tab. -- **Extensions**: Access other actions provided by installed applications, such as declaring an incident. Note that this option doesn't appear unless you have app plugins installed which contribute an [extension](https://grafana.com/developers/plugin-tools/ui-extensions/) to the panel menu. -- **More**: Access other panel actions. - - **Duplicate**: Make a copy of the panel. Duplicated panels query data separately from the original panel. You can use the special `Dashboard` data source to [share the same query results across panels][] instead. - - **Copy**: Copy the panel to the clipboard. - - **Create library panel**: Create a panel that can be imported into other dashboards. - - **Create alert**: Open the alert rule configuration page in **Alerting**, where you can [create a Grafana-managed alert] based on the panel queries. - - **Hide legend**: Hide the panel legend. - - **Get help**: Send a snapshot or panel data to Grafana Labs Technical Support. -- **Remove**: Remove the panel from the dashboard. +## Visualization preview -## Panel editor +The visualization preview section contains the following options: -This section describes the areas of the Grafana panel editor. +- **Table view:** Convert any visualization to a table so you can see the data. Table views are helpful for troubleshooting. This view only contains the raw data. It doesn't include transformations you might have applied to the data or the formatting options available in the [Table][] visualization. +- **Fill:** The visualization preview fills the available space. If you change the width of the side pane or height of the bottom pane the visualization changes to fill the available space. +- **Actual:** The visualization preview has the exact size as the size on the dashboard. If not enough space is available, the visualization scales down preserving the aspect ratio. +- **Time range controls:** **Default** is either the browser local timezone or the timezone selected at a higher level. -1. Panel header: The header section lists the dashboard in which the panel appears and the following controls: +## Data section - - **Discard:** Discards changes you have made to the panel since you last saved the dashboard. - - **Save:** Saves changes you made to the panel. - - **Apply:** Applies changes you made and closes the panel editor, returning you to the dashboard. You'll have to save the dashboard to persist the applied changes. +The data section contains tabs where you enter queries, transform your data, and create alert rules (if applicable). -1. Visualization preview: The visualization preview section contains the following options: +- **Query tab:** Select your data source and enter queries here. For more information, refer to [Add a query][]. When you create a new dashboard, you'll be prompted to select a data source before you get to the panel editor. You set or update the data source in existing dashboards using the drop-down in the **Query** tab. +- **Transform tab:** Apply data transformations. For more information, refer to [Transform data][]. +- **Alert tab:** Write alert rules. For more information, refer to [the overview of Grafana Alerting][]. - - **Table view:** Convert any visualization to a table so you can see the data. Table views are helpful for troubleshooting. This view only contains the raw data. It doesn't include transformations you might have applied to the data or the formatting options available in the [Table][] visualization. - - **Fill:** The visualization preview fills the available space. If you change the width of the side pane or height of the bottom pane the visualization changes to fill the available space. - - **Actual:** The visualization preview has the exact size as the size on the dashboard. If not enough space is available, the visualization scales down preserving the aspect ratio. - - **Time range controls:** **Default** is either the browser local timezone or the timezone selected at a higher level. +## Panel display options -1. Data section: The data section contains tabs where you enter queries, transform your data, and create alert rules (if applicable). - - - **Query tab:** Select your data source and enter queries here. For more information, refer to [Add a query][]. When you create a new dashboard, you'll be prompted to select a data source before you get to the panel editor. You set or update the data source in existing dashboards using the drop-down in the **Query** tab. - - **Transform tab:** Apply data transformations. For more information, refer to [Transform data][]. - - **Alert tab:** Write alert rules. For more information, refer to [the overview of Grafana Alerting][]. - -1. Panel display options: The display options section contains tabs where you configure almost every aspect of your data visualization. - -## Panel inspect drawer - -The inspect drawer helps you understand and troubleshoot your panels. You can view the raw data for any panel, export that data to a comma-separated values (CSV) file, view query requests, and export panel and data JSON. - -To access the panel inspect drawer from the edit view, hover over any part of the panel to display the actions menu on the top right corner. Click the menu and select **Inspect**. - -{{% admonition type="note" %}} -Not all panel types include all tabs. For example, dashboard list panels don't have raw data to inspect, so they don't display the Stats, Data, or Query tabs. -{{% /admonition %}} - -The panel inspector consists of the following options: - -1. The panel inspect drawer displays opens a drawer on the right side. Click the arrow in the upper right corner to expand or reduce the drawer pane. - -1. **Data tab -** Shows the raw data returned by the query with transformations applied. Field options such as overrides and value mappings aren't applied by default. - -1. **Stats tab -** Shows how long your query takes and how much it returns. - -1. **JSON tab -** Allows you to view and copy the panel JSON, panel data JSON, and data frame structure JSON. This is useful if you are provisioning or administering Grafana. - -1. **Query tab -** Shows you the requests to the server sent when Grafana queries the data source. - -1. **Error tab -** Shows the error. Only visible when query returns error. +The display options section contains tabs where you configure almost every aspect of your data visualization. {{% docs/reference %}} [Table]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/visualizations/table" @@ -121,10 +76,4 @@ The panel inspector consists of the following options: [the overview of Grafana Alerting]: "/docs/grafana/ -> /docs/grafana//alerting" [the overview of Grafana Alerting]: "/docs/grafana-cloud/ -> /docs/grafana//alerting" - -[share the same query results across panels]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/query-transform-data/share-query" -[share the same query results across panels]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/query-transform-data/share-query" - -[create a Grafana-managed alert]: "/docs/grafana/ -> /docs/grafana//alerting/alerting-rules/create-grafana-managed-rule#create-alerts-from-panels" -[create a Grafana-managed alert]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/alerting/alerting-rules/create-grafana-managed-rule#create-alerts-from-panels" {{% /docs/reference %}} diff --git a/docs/sources/panels-visualizations/panel-overview/index.md b/docs/sources/panels-visualizations/panel-overview/index.md new file mode 100644 index 00000000000..bcdbd4f2e02 --- /dev/null +++ b/docs/sources/panels-visualizations/panel-overview/index.md @@ -0,0 +1,161 @@ +--- +keywords: + - transform + - query + - panel + - dashboard + - rows + - dynamic + - add +labels: + products: + - cloud + - enterprise + - oss +menuTitle: Panel overview +title: Panel overview +description: Learn about the features of the panel +weight: 15 +--- + +# Panel overview + +A Grafana panel is a visual representation of data composed of a [query][] and a [visualization][]. Within panels, you can apply [transformations][], which process the results of a query before they're passed on for visualization. You can also further customize a panel by formatting data and configuring visualization options. + +Each panel has a query editor specific to the data source selected in the panel. The query editor allows you to build a query that returns the data you want to visualize. + +Panels offer a wide variety of formatting and styling options, from applying colors based on field values to creating custom units. Each visualization also comes with options specific to it that give you further control over how your data is displayed. Panels can also be dragged, dropped, and resized to rearrange them on the dashboard. + +To get started adding panels, ensure that you have configured a data source: + +- For details about using data sources, refer to [Data sources][]. +- For more information about managing data sources as an administrator, refer to [Data source management][]. + + {{% admonition type="note" %}} + [Data source management](https://grafana.com/docs/grafana//administration/data-source-management/) is only available in [Grafana Enterprise](https://grafana.com/docs/grafana//introduction/grafana-enterprise/) and [Grafana Cloud](https://grafana.com/docs/grafana-cloud/). + {{% /admonition %}} + +## Panel feature overview + +The panel has the following features: + + + + + +- **Panel title** - You can create your own panel titles or have Grafana create them for you using [generative AI features][ai]. +- **Links** - Add [panel links][] to other dashboards, panels, or external sites. +- **Panel menu** - In the [panel menu](#panel-menu), access actions such as **View**, **Edit**, **Inspect**, and **Remove**. +- **Tooltips** - View [tooltips][] to get more information about data points. +- **Legend** - Change series colors, y-axis and series visibility directly from the [legend][]. + +## Panel menu + +To access the panel editor, hover over the top-right corner of any panel. Click the panel menu icon that appears and select **Edit**. The panel menu gives you access to the following actions: + +- **View**: View the panel in full screen. +- **Edit**: Open the panel editor to edit panel and visualization options. +- **Share**: Share the panel as a link, embed, or library panel. +- **Explore**: Open the panel in **Explore**, where you can focus on your query. +- **Inspect**: Open the **Inspect** drawer, where you can review the panel data, stats, metadata, JSON, and query. + - **Data**: Open the **Inspect** drawer in the **Data** tab. + - **Query**: Open the **Inspect** drawer in the **Query** tab. + - **Panel JSON**: Open the **Inspect** drawer in the **JSON** tab. +- **Extensions**: Access other actions provided by installed applications, such as declaring an incident. Note that this option doesn't appear unless you have app plugins installed which contribute an [extension](https://grafana.com/developers/plugin-tools/ui-extensions/) to the panel menu. +- **More**: Access other panel actions. + - **Duplicate**: Make a copy of the panel. Duplicated panels query data separately from the original panel. You can use the special `Dashboard` data source to [share the same query results across panels][share] instead. + - **Copy**: Copy the panel to the clipboard. + - **Create library panel**: Create a panel that can be imported into other dashboards. + - **Create alert**: Open the alert rule configuration page in **Alerting**, where you can [create a Grafana-managed alert][create] based on the panel queries. + - **Hide legend**: Hide the panel legend. + - **Get help**: Send a snapshot or panel data to Grafana Labs Technical Support. +- **Remove**: Remove the panel from the dashboard. + +## Keyboard shortcuts + +Grafana has a number of keyboard shortcuts available specifically for panels. Press `?` on your keyboard to display all keyboard shortcuts available in your version of Grafana. + +By hovering over a panel with the mouse you can use some shortcuts that will target that panel. + +- `e`: Toggle panel edit view +- `v`: Toggle panel fullscreen view +- `ps`: Open Panel Share Modal +- `pd`: Duplicate Panel +- `pr`: Remove Panel +- `pl`: Toggle panel legend + +## Add a panel + +To add a panel in a new dashboard click **+ Add visualization** in the middle of the dashboard: + +![Empty dashboard state](/media/docs/grafana/dashboards/empty-dashboard-10.2.png) + +To add a panel to an existing dashboard, click **Add** in the dashboard header and select **Visualization** in the drop-down: + +![Add dropdown](/media/docs/grafana/dashboards/screenshot-add-dropdown-10.0.png) + +## Panel configuration + +To configure panels, refer to the following subtopics: + +- [Configure panel options][] +- [Configure standard options][] +- [Configure a legend][legend] +- [Configure tooltips][tooltips] +- [Configure data links][] +- [Configure value mappings][] +- [Configure thresholds][] +- [Configure field overrides][] + +{{% docs/reference %}} +[query]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/query-transform-data" +[query]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/query-transform-data" + +[visualization]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/visualizations" +[visualization]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/visualizations" + +[transformations]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/query-transform-data/transform-data" +[transformations]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/query-transform-data/transform-data" + +[Data source management]: "/docs/grafana/ -> /docs/grafana//administration/data-source-management" +[Data source management]: "/docs/grafana-cloud/ -> /docs/grafana//administration/data-source-management" + +[Data sources]: "/docs/grafana/ -> /docs/grafana//datasources" +[Data sources]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/connect-externally-hosted/data-sources" + +[ai]: "/docs/grafana/ -> /docs/grafana//dashboards/manage-dashboards#set-up-generative-ai-features-for-dashboards" +[ai]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/dashboards/manage-dashboards#set-up-generative-ai-features-for-dashboards" + +[panel links]: "/docs/grafana/ -> /docs/grafana//dashboards/build-dashboards/manage-dashboard-links#panel-links" +[panel links]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/dashboards/build-dashboards/manage-dashboard-links#panel-links" + +[tooltips]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/configure-tooltips" +[tooltips]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/configure-tooltips" + +[legend]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/configure-legend" +[legend]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/configure-legend" + +[share]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/query-transform-data/share-query" +[share]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/query-transform-data/share-query" + +[create]: "/docs/grafana/ -> /docs/grafana//alerting/alerting-rules/create-grafana-managed-rule#create-alerts-from-panels" +[create]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/alerting-and-irm/alerting/alerting-rules/create-grafana-managed-rule#create-alerts-from-panels" + +[Configure panel options]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/configure-panel-options" +[Configure panel options]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/configure-panel-options" + +[Configure standard options]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/configure-standard-options" +[Configure standard options]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/configure-standard-options" + +[Configure data links]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/configure-data-links" +[Configure data links]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/configure-data-links" + +[Configure value mappings]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/configure-value-mappings" +[Configure value mappings]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/configure-value-mappings" + +[Configure thresholds]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/configure-thresholds" +[Configure thresholds]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/configure-thresholds" + +[Configure field overrides]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/configure-overrides" +[Configure field overrides]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/configure-overrides" +{{% /docs/reference %}} From 726cd4a8a6e73ea1039026433aed003d121f5e48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laura=20Fern=C3=A1ndez?= Date: Mon, 15 Apr 2024 16:56:28 +0200 Subject: [PATCH 024/147] Chore: Fix link in `UsersTable` (#86152) --- public/app/features/admin/Users/UsersTable.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/app/features/admin/Users/UsersTable.tsx b/public/app/features/admin/Users/UsersTable.tsx index 8043c6e061c..1c23998d5c5 100644 --- a/public/app/features/admin/Users/UsersTable.tsx +++ b/public/app/features/admin/Users/UsersTable.tsx @@ -55,7 +55,7 @@ export const UsersTable = ({ header: 'Login', cell: ({ row: { original } }: Cell<'login'>) => { return ( - + {original.login} ); From 219c2c761e4902ce8d2b405624b436664e6e35f5 Mon Sep 17 00:00:00 2001 From: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> Date: Mon, 15 Apr 2024 11:07:05 -0400 Subject: [PATCH 025/147] Docs: add dashboards landing page (#86001) * Added template from existing landing page * Added dashboards content * Fixed front matter * Referenced existing icon to test * Added test icon * Edited text * Fixed link formatting * Finalized description and overview text * Updated description' * Updated tile text * Updated docs/ref section --- docs/sources/dashboards/_index.md | 108 ++++++++++++++---------------- 1 file changed, 51 insertions(+), 57 deletions(-) diff --git a/docs/sources/dashboards/_index.md b/docs/sources/dashboards/_index.md index 0207994cd73..79ffef5454c 100644 --- a/docs/sources/dashboards/_index.md +++ b/docs/sources/dashboards/_index.md @@ -9,69 +9,63 @@ labels: title: Dashboards weight: 70 description: Create and manage dashboards +hero: + title: Dashboards + level: 1 + width: 110 + height: 110 + description: >- + Dashboards allow you to query, transform, visualize, and understand your data no matter where it’s stored. +cards: + title_class: pt-0 lh-1 + items: + - title: Build dashboards + href: ./build-dashboards/ + description: Get step-by-step directions for how to create or import your first dashboard and modify dashboard settings. Learn about reusable library panels, dashboard links, annotatations, and dashboard JSON. + height: 24 + - title: Manage dashboards + href: ./manage-dashboards/ + description: Learn about dashboard and folder management, as well as generative AI features for dashboards. + height: 24 + - title: Variables + href: ./variables/ + description: Add variables to metric queries and panel titles to create interactive and dynamic dashboards. + height: 24 + - title: Public dashboards + href: ./dashboard-public/ + description: Make your Grafana dashboards public and share them with anyone without requiring access to your Grafana organization. + height: 24 + - title: Reporting + href: ./create-reports/ + description: Automatically generate and share PDF reports from your Grafana dashboards. + height: 24 + - title: Sharing + href: ./share-dashboards-panels/ + description: Share Grafana dashboards and panels within your organization using links, snapshots, and JSON exports. + height: 24 --- -# Dashboards +{{< docs/hero-simple key="hero" >}} -A dashboard is a set of one or more [panels][] organized and arranged into one or more rows. Grafana ships with a variety of panels making it easy to construct the right queries, and customize the visualization so that you can create the perfect dashboard for your need. Each panel can interact with data from any configured Grafana [data source][]. +--- -Dashboard snapshots are static. Queries and expressions cannot be re-executed from snapshots. As a result, if you update any variables in your query or expression, it will not change your dashboard data. +## Overview -Before you begin, ensure that you have configured a data source. See also: +A Grafana dashboard is a set of one or more [panels][], organized and arranged into one or more rows, that provide an at-a-glance view of related information. These panels are created using components that query and transform raw data from a data source into charts, graphs, and other visualizations. -- [Use dashboards][] -- [Build dashboards][] -- [Create dashboard folders][] -- [Manage dashboards][] -- [Public dashboards][] -- [Annotations][] -- [Playlist][] -- [Reporting][] -- [Version history][] -- [Import][] -- [Export and share][] -- [JSON model][] +A data source can be an SQL database, Grafana Loki, Grafana Mimir, or a JSON-based API. It can even be a basic CSV file. Data source plugins take a query you want answered, retrieve the data from the data source, and reconcile the differences between the data model of the data source and the data model of Grafana dashboards. + +Queries allow you to reduce the entirety of your data to a specific dataset, providing a more manageable visualization. Since data sources have their own distinct query languages, Grafana dashboards provide you with a query editor to accommodate these differences. + +A panel is the container that displays the visualization and provides you with various controls to manipulate it. Panel options let you customize many aspects of a visualization and the options differ based on which visualization you select. When the data format in a visualization doesn’t meet your requirements, you can apply a transformation that manipulates the data returned by a query. + +With 150+ data source plugins, you can unify all your data sources into a single dashboard to streamline data monitoring and troubleshooting. With Grafana, you can translate, transform, and visualize data in flexible and versatile dashboards. + +## Explore + +{{< card-grid key="cards" type="simple" >}} {{% docs/reference %}} -[data source]: "/docs/grafana/ -> /docs/grafana//datasources" -[data source]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/connect-externally-hosted/data-sources" - -[Reporting]: "/docs/grafana/ -> /docs/grafana//dashboards/create-reports" -[Reporting]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/dashboards/create-reports" - -[Public dashboards]: "/docs/grafana/ -> /docs/grafana//dashboards/dashboard-public" -[Public dashboards]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/dashboards/dashboard-public" - -[Version history]: "/docs/grafana/ -> /docs/grafana//dashboards/build-dashboards/manage-version-history" -[Version history]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/dashboards/build-dashboards/manage-version-history" - -[panels]: "/docs/grafana/ -> /docs/grafana//panels-visualizations" -[panels]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations" - -[Annotations]: "/docs/grafana/ -> /docs/grafana//dashboards/build-dashboards/annotate-visualizations" -[Annotations]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/dashboards/build-dashboards/annotate-visualizations" - -[Create dashboard folders]: "/docs/grafana/ -> /docs/grafana//dashboards/manage-dashboards#create-a-dashboard-folder" -[Create dashboard folders]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/dashboards/manage-dashboards#create-a-dashboard-folder" - -[JSON model]: "/docs/grafana/ -> /docs/grafana//dashboards/build-dashboards/view-dashboard-json-model" -[JSON model]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/dashboards/build-dashboards/view-dashboard-json-model" - -[Import]: "/docs/grafana/ -> /docs/grafana//dashboards/build-dashboards/import-dashboards" -[Import]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/dashboards/build-dashboards/import-dashboards" - -[Export and share]: "/docs/grafana/ -> /docs/grafana//dashboards/share-dashboards-panels" -[Export and share]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/dashboards/share-dashboards-panels" - -[Manage dashboards]: "/docs/grafana/ -> /docs/grafana//dashboards/manage-dashboards" -[Manage dashboards]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/dashboards/manage-dashboards" - -[Build dashboards]: "/docs/grafana/ -> /docs/grafana//dashboards/build-dashboards" -[Build dashboards]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/dashboards/build-dashboards" - -[Use dashboards]: "/docs/grafana/ -> /docs/grafana//dashboards/use-dashboards" -[Use dashboards]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/dashboards/use-dashboards" - -[Playlist]: "/docs/grafana/ -> /docs/grafana//dashboards/create-manage-playlists" -[Playlist]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/dashboards/create-manage-playlists" +[panels]: "/docs/grafana/ -> /docs/grafana//panels-visualizations/panel-overview" +[panels]: "/docs/grafana-cloud/ -> /docs/grafana-cloud/visualizations/panels-visualizations/panel-overview" {{% /docs/reference %}} From 82f910c0c5e1c9b0c903dc40d0094e3a00b3b2f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laura=20Fern=C3=A1ndez?= Date: Mon, 15 Apr 2024 17:27:08 +0200 Subject: [PATCH 026/147] Chore: Use `handleReducedMotion` to smooth the animation in `LoadingBar` (#85808) --- .../src/components/LoadingBar/LoadingBar.tsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/grafana-ui/src/components/LoadingBar/LoadingBar.tsx b/packages/grafana-ui/src/components/LoadingBar/LoadingBar.tsx index 0084d82a550..07186be5e8c 100644 --- a/packages/grafana-ui/src/components/LoadingBar/LoadingBar.tsx +++ b/packages/grafana-ui/src/components/LoadingBar/LoadingBar.tsx @@ -4,6 +4,7 @@ import React, { CSSProperties } from 'react'; import { GrafanaTheme2 } from '@grafana/data'; import { useStyles2 } from '../../themes'; +import { handleReducedMotion } from '../../utils/handleReducedMotion'; export interface LoadingBarProps { width: number; @@ -52,10 +53,17 @@ const getStyles = (_theme: GrafanaTheme2, delay: number, duration: number) => { animationName: animation, // an initial delay to prevent the loader from showing if the response is faster than the delay animationDelay: `${delay}ms`, - animationDuration: `${duration}ms`, animationTimingFunction: 'linear', animationIterationCount: 'infinite', willChange: 'transform', + ...handleReducedMotion( + { + animationDuration: `${duration}ms`, + }, + { + animationDuration: `${4 * duration}ms`, + } + ), }), }; }; From cc87281d7153d4b6b0edd365efee94d199a4f79b Mon Sep 17 00:00:00 2001 From: ismail simsek Date: Mon, 15 Apr 2024 19:05:19 +0200 Subject: [PATCH 027/147] Prometheus: Respect dashboard queries when querying ad hoc filter labels (#85674) * use queries * extract metric name from query * unit tests --- packages/grafana-prometheus/src/datasource.ts | 2 +- .../src/language_provider.test.ts | 203 +++++++++++++++++- .../src/language_provider.ts | 26 ++- 3 files changed, 224 insertions(+), 7 deletions(-) diff --git a/packages/grafana-prometheus/src/datasource.ts b/packages/grafana-prometheus/src/datasource.ts index 7a1d6731f33..b809452bede 100644 --- a/packages/grafana-prometheus/src/datasource.ts +++ b/packages/grafana-prometheus/src/datasource.ts @@ -679,7 +679,7 @@ export class PrometheusDatasource // and in Tempo here grafana/public/app/plugins/datasource/tempo/QueryEditor/ServiceGraphSection.tsx async getTagKeys(options: DataSourceGetTagKeysOptions): Promise { if (!options || options.filters.length === 0) { - await this.languageProvider.fetchLabels(options.timeRange); + await this.languageProvider.fetchLabels(options.timeRange, options.queries); return this.languageProvider.getLabelKeys().map((k) => ({ value: k, text: k })); } diff --git a/packages/grafana-prometheus/src/language_provider.test.ts b/packages/grafana-prometheus/src/language_provider.test.ts index 574fec92ef0..91576162dd1 100644 --- a/packages/grafana-prometheus/src/language_provider.test.ts +++ b/packages/grafana-prometheus/src/language_provider.test.ts @@ -4,7 +4,7 @@ import { Label } from './components/monaco-query-field/monaco-completion-provide import { PrometheusDatasource } from './datasource'; import LanguageProvider from './language_provider'; import { getClientCacheDurationInMinutes, getPrometheusTime, getRangeSnapInterval } from './language_utils'; -import { PrometheusCacheLevel } from './types'; +import { PrometheusCacheLevel, PromQuery } from './types'; const now = new Date(1681300293392).getTime(); const timeRangeDurationSeconds = 1; @@ -306,6 +306,207 @@ describe('Language completion provider', () => { }); }); + describe('fetchLabels', () => { + const tr = getMockTimeRange(); + const getParams = (requestSpy: ReturnType) => { + // Following is equal to `URLSearchParams().toString()` + return requestSpy.mock.calls[0][2]?.toString() ?? 'undefined'; + }; + + describe('with POST', () => { + let languageProvider: LanguageProvider; + beforeEach(() => { + languageProvider = new LanguageProvider({ + ...defaultDatasource, + httpMethod: 'POST', + } as PrometheusDatasource); + }); + + it('should send query metrics to the POST request', async () => { + const mockQueries: PromQuery[] = [ + { + refId: 'C', + expr: 'go_gc_pauses_seconds_bucket', + }, + ]; + const fetchLabel = languageProvider.fetchLabels; + const requestSpy = jest.spyOn(languageProvider, 'request'); + await fetchLabel(tr, mockQueries); + expect(requestSpy).toHaveBeenCalled(); + const params = getParams(requestSpy); + expect(params).toMatch(encodeURI('match[]=go_gc_pauses_seconds_bucket')); + }); + + it('should send metrics from complex query to the POST request', async () => { + const mockQueries: PromQuery[] = [ + { + refId: 'C', + expr: 'histogram_quantile(0.95, sum(rate(go_gc_pauses_seconds_bucket[$__rate_interval])) by (le))', + }, + ]; + const fetchLabel = languageProvider.fetchLabels; + const requestSpy = jest.spyOn(languageProvider, 'request'); + await fetchLabel(tr, mockQueries); + expect(requestSpy).toHaveBeenCalled(); + const params = getParams(requestSpy); + expect(params).toMatch(encodeURI('match[]=go_gc_pauses_seconds_bucket')); + }); + + it('should send metrics from multiple queries to the POST request', async () => { + const mockQueries: PromQuery[] = [ + { + refId: 'B', + expr: 'process_cpu_seconds_total', + }, + { + refId: 'C', + expr: 'go_gc_pauses_seconds_bucket', + }, + ]; + const fetchLabel = languageProvider.fetchLabels; + const requestSpy = jest.spyOn(languageProvider, 'request'); + await fetchLabel(tr, mockQueries); + expect(requestSpy).toHaveBeenCalled(); + const params = getParams(requestSpy); + expect(params).toMatch(encodeURI('match[]=process_cpu_seconds_total&match[]=go_gc_pauses_seconds_bucket')); + }); + + it('should send metrics from a query contains multiple metrics to the POST request', async () => { + const mockQueries: PromQuery[] = [ + { + refId: 'B', + expr: 'process_cpu_seconds_total + go_gc_pauses_seconds_bucket', + }, + ]; + const fetchLabel = languageProvider.fetchLabels; + const requestSpy = jest.spyOn(languageProvider, 'request'); + await fetchLabel(tr, mockQueries); + expect(requestSpy).toHaveBeenCalled(); + const params = getParams(requestSpy); + expect(params).toMatch(encodeURI('match[]=process_cpu_seconds_total&match[]=go_gc_pauses_seconds_bucket')); + }); + + it('should send metrics from a query contains multiple metrics and queries to the POST request', async () => { + const mockQueries: PromQuery[] = [ + { + refId: 'A', + expr: 'histogram_quantile(0.95, sum(rate(process_max_fds[$__rate_interval])) by (le)) + go_gc_heap_frees_by_size_bytes_bucket', + }, + { + refId: 'B', + expr: 'process_cpu_seconds_total + go_gc_pauses_seconds_bucket', + }, + ]; + const fetchLabel = languageProvider.fetchLabels; + const requestSpy = jest.spyOn(languageProvider, 'request'); + await fetchLabel(tr, mockQueries); + expect(requestSpy).toHaveBeenCalled(); + const params = getParams(requestSpy); + expect(params).toMatch( + encodeURI( + 'match[]=process_max_fds&match[]=go_gc_heap_frees_by_size_bytes_bucket&match[]=process_cpu_seconds_total&match[]=go_gc_pauses_seconds_bucket' + ) + ); + }); + }); + + describe('with GET', () => { + let languageProvider: LanguageProvider; + beforeEach(() => { + languageProvider = new LanguageProvider({ + ...defaultDatasource, + httpMethod: 'GET', + } as PrometheusDatasource); + }); + + it('should send query metrics to the GET request', async () => { + const mockQueries: PromQuery[] = [ + { + refId: 'C', + expr: 'go_gc_pauses_seconds_bucket', + }, + ]; + const fetchLabel = languageProvider.fetchLabels; + const requestSpy = jest.spyOn(languageProvider, 'request'); + await fetchLabel(tr, mockQueries); + expect(requestSpy).toHaveBeenCalled(); + expect(requestSpy.mock.calls[0][0]).toMatch(encodeURI('match[]=go_gc_pauses_seconds_bucket')); + }); + + it('should send metrics from complex query to the GET request', async () => { + const mockQueries: PromQuery[] = [ + { + refId: 'C', + expr: 'histogram_quantile(0.95, sum(rate(go_gc_pauses_seconds_bucket[$__rate_interval])) by (le))', + }, + ]; + const fetchLabel = languageProvider.fetchLabels; + const requestSpy = jest.spyOn(languageProvider, 'request'); + await fetchLabel(tr, mockQueries); + expect(requestSpy).toHaveBeenCalled(); + expect(requestSpy.mock.calls[0][0]).toMatch(encodeURI('match[]=go_gc_pauses_seconds_bucket')); + }); + + it('should send metrics from multiple queries to the GET request', async () => { + const mockQueries: PromQuery[] = [ + { + refId: 'B', + expr: 'process_cpu_seconds_total', + }, + { + refId: 'C', + expr: 'go_gc_pauses_seconds_bucket', + }, + ]; + const fetchLabel = languageProvider.fetchLabels; + const requestSpy = jest.spyOn(languageProvider, 'request'); + await fetchLabel(tr, mockQueries); + expect(requestSpy).toHaveBeenCalled(); + expect(requestSpy.mock.calls[0][0]).toMatch( + encodeURI('match[]=process_cpu_seconds_total&match[]=go_gc_pauses_seconds_bucket') + ); + }); + + it('should send metrics from a query contains multiple metrics to the GET request', async () => { + const mockQueries: PromQuery[] = [ + { + refId: 'B', + expr: 'process_cpu_seconds_total + go_gc_pauses_seconds_bucket', + }, + ]; + const fetchLabel = languageProvider.fetchLabels; + const requestSpy = jest.spyOn(languageProvider, 'request'); + await fetchLabel(tr, mockQueries); + expect(requestSpy).toHaveBeenCalled(); + expect(requestSpy.mock.calls[0][0]).toMatch( + encodeURI('match[]=process_cpu_seconds_total&match[]=go_gc_pauses_seconds_bucket') + ); + }); + + it('should send metrics from a query contains multiple metrics and queries to the GET request', async () => { + const mockQueries: PromQuery[] = [ + { + refId: 'A', + expr: 'histogram_quantile(0.95, sum(rate(process_max_fds[$__rate_interval])) by (le)) + go_gc_heap_frees_by_size_bytes_bucket', + }, + { + refId: 'B', + expr: 'process_cpu_seconds_total + go_gc_pauses_seconds_bucket', + }, + ]; + const fetchLabel = languageProvider.fetchLabels; + const requestSpy = jest.spyOn(languageProvider, 'request'); + await fetchLabel(tr, mockQueries); + expect(requestSpy).toHaveBeenCalled(); + expect(requestSpy.mock.calls[0][0]).toMatch( + encodeURI( + 'match[]=process_max_fds&match[]=go_gc_heap_frees_by_size_bytes_bucket&match[]=process_cpu_seconds_total&match[]=go_gc_pauses_seconds_bucket' + ) + ); + }); + }); + }); + describe('fetchLabelValues', () => { it('should interpolate variable in series', () => { const languageProvider = new LanguageProvider({ diff --git a/packages/grafana-prometheus/src/language_provider.ts b/packages/grafana-prometheus/src/language_provider.ts index 9ad75e37023..7794c2d9339 100644 --- a/packages/grafana-prometheus/src/language_provider.ts +++ b/packages/grafana-prometheus/src/language_provider.ts @@ -21,6 +21,7 @@ import { toPromLikeQuery, } from './language_utils'; import PromqlSyntax from './promql'; +import { buildVisualQueryFromString } from './querybuilder/parsing'; import { PrometheusCacheLevel, PromMetricsMetadata, PromQuery } from './types'; const DEFAULT_KEYS = ['job', 'instance']; @@ -204,21 +205,36 @@ export default class PromQlLanguageProvider extends LanguageProvider { /** * Fetches all label keys */ - async fetchLabels(timeRange?: TimeRange): Promise { + fetchLabels = async (timeRange?: TimeRange, queries?: PromQuery[]): Promise => { if (timeRange) { this.timeRange = timeRange; } - const url = '/api/v1/labels'; - const params = this.datasource.getAdjustedInterval(this.timeRange); + let url = '/api/v1/labels'; + const timeParams = this.datasource.getAdjustedInterval(this.timeRange); this.labelFetchTs = Date.now().valueOf(); - const res = await this.request(url, [], params, this.getDefaultCacheHeaders()); + const searchParams = new URLSearchParams({ ...timeParams }); + queries?.forEach((q) => { + const visualQuery = buildVisualQueryFromString(q.expr); + searchParams.append('match[]', visualQuery.query.metric); + if (visualQuery.query.binaryQueries) { + visualQuery.query.binaryQueries.forEach((bq) => { + searchParams.append('match[]', bq.query.metric); + }); + } + }); + + if (this.datasource.httpMethod === 'GET') { + url += `?${searchParams.toString()}`; + } + + const res = await this.request(url, [], searchParams, this.getDefaultCacheHeaders()); if (Array.isArray(res)) { this.labelKeys = res.slice().sort(); } return []; - } + }; /** * Gets series values From 2aedd9dacf317e68280fd6635c3a07816bcc5800 Mon Sep 17 00:00:00 2001 From: Charandas Date: Mon, 15 Apr 2024 11:34:20 -0700 Subject: [PATCH 028/147] K8s: add ID token to requests outbound to new query endpoint (#86214) --- pkg/api/metrics.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkg/api/metrics.go b/pkg/api/metrics.go index df798af8ca8..010ca3cb8e2 100644 --- a/pkg/api/metrics.go +++ b/pkg/api/metrics.go @@ -7,6 +7,7 @@ import ( "net/http" "github.com/grafana/grafana-plugin-sdk-go/backend" + "github.com/grafana/grafana/pkg/util/proxyutil" "github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/api/response" @@ -50,6 +51,7 @@ func (hs *HTTPServer) getDSQueryEndpoint() web.Handler { return } r.URL.Path = "/apis/query.grafana.app/v0alpha1/namespaces/" + namespaceMapper(user.OrgID) + "/query" + r.Header.Add(proxyutil.IDHeaderName, user.GetIDToken()) hs.clientConfigProvider.DirectlyServeHTTP(w, r) } } From 7c156274cddd0b2174c7189b885f515304e2a7c2 Mon Sep 17 00:00:00 2001 From: Brendan O'Handley Date: Mon, 15 Apr 2024 14:26:51 -0500 Subject: [PATCH 029/147] Prometheus: Add native histogram functions (#86002) * add native histogram functions to code editor * add native histogram function types for query builder * add functions to query builder * add test to show parsing breaks from code to builder * add histogram_avg to code editor * add histogram_avg to builder and make parity between package and core * add functions to hard coded promql file for highlighting * remove native histogram test so that it can be added in #85942 * remove functions from core prometheus js to prevent merge conflict in #86080 * use xit for test instead of removing it --- .../components/monaco-query-field/promql.ts | 6 +++ packages/grafana-prometheus/src/promql.ts | 38 +++++++++++++++++++ .../src/querybuilder/operations.ts | 17 +++++++++ .../src/querybuilder/parsing.test.ts | 22 +++++++++++ .../src/querybuilder/types.ts | 6 +++ 5 files changed, 89 insertions(+) diff --git a/packages/grafana-prometheus/src/components/monaco-query-field/promql.ts b/packages/grafana-prometheus/src/components/monaco-query-field/promql.ts index af7ab116c95..c7697fbfb3c 100644 --- a/packages/grafana-prometheus/src/components/monaco-query-field/promql.ts +++ b/packages/grafana-prometheus/src/components/monaco-query-field/promql.ts @@ -84,6 +84,12 @@ const functions = [ 'exp', 'floor', 'histogram_quantile', + 'histogram_avg', + 'histogram_count', + 'histogram_sum', + 'histogram_fraction', + 'histogram_stddev', + 'histogram_stdvar', 'holt_winters', 'hour', 'idelta', diff --git a/packages/grafana-prometheus/src/promql.ts b/packages/grafana-prometheus/src/promql.ts index c37f52796ba..a9e89ee5f67 100644 --- a/packages/grafana-prometheus/src/promql.ts +++ b/packages/grafana-prometheus/src/promql.ts @@ -534,6 +534,44 @@ export const FUNCTIONS = [ detail: 'present_over_time(range-vector)', documentation: 'The value 1 for any series in the specified interval.', }, + { + insertText: 'histogram_avg', + label: 'histogram_avg', + detail: 'histogram_avg(v instant-vector)', + documentation: + 'Returns the arithmetic average of observed values stored in a native histogram. Samples that are not native histograms are ignored and do not show up in the returned vector.', + }, + { + insertText: 'histogram_count', + label: 'histogram_count', + detail: 'histogram_count(v instant-vector)', + documentation: 'Returns the count of observations stored in a native histogram.', + }, + { + insertText: 'histogram_sum', + label: 'histogram_sum', + detail: 'histogram_sum(v instant-vector)', + documentation: 'Returns the sum of observations stored in a native histogram.', + }, + { + insertText: 'histogram_fraction', + label: 'histogram_fraction', + detail: 'histogram_fraction(lower scalar, upper scalar, v instant-vector)', + documentation: 'Returns the estimated fraction of observations between the provided lower and upper values.', + }, + { + insertText: 'histogram_stddev', + label: 'histogram_stddev', + detail: 'histogram_stddev(v instant-vector)', + documentation: + 'Returns the estimated standard deviation of observations in a native histogram, based on the geometric mean of the buckets where the observations lie.', + }, + { + insertText: 'histogram_stdvar', + label: 'histogram_stdvar', + detail: 'histogram_stdvar(v instant-vector)', + documentation: 'Returns the estimated standard variance of observations in a native histogram.', + }, ]; export const PROM_KEYWORDS = FUNCTIONS.map((keyword) => keyword.label); diff --git a/packages/grafana-prometheus/src/querybuilder/operations.ts b/packages/grafana-prometheus/src/querybuilder/operations.ts index 3b445efa37e..e4a3dffacbd 100644 --- a/packages/grafana-prometheus/src/querybuilder/operations.ts +++ b/packages/grafana-prometheus/src/querybuilder/operations.ts @@ -28,6 +28,23 @@ export function getOperationDefinitions(): QueryBuilderOperationDef[] { renderer: functionRendererLeft, addOperationHandler: defaultAddOperationHandler, }, + createFunction({ id: PromOperationId.HistogramAvg }), + createFunction({ id: PromOperationId.HistogramCount }), + createFunction({ id: PromOperationId.HistogramSum }), + { + id: PromOperationId.HistogramFraction, + name: 'Histogram fraction', + params: [ + { name: 'Lower scalar', type: 'number' }, + { name: 'Upper scalar', type: 'number' }, + ], + defaultParams: [0.0, 0.2], + category: PromVisualQueryOperationCategory.Functions, + renderer: functionRendererLeft, + addOperationHandler: defaultAddOperationHandler, + }, + createFunction({ id: PromOperationId.HistogramStddev }), + createFunction({ id: PromOperationId.HistogramStdvar }), { id: PromOperationId.LabelReplace, name: 'Label replace', diff --git a/packages/grafana-prometheus/src/querybuilder/parsing.test.ts b/packages/grafana-prometheus/src/querybuilder/parsing.test.ts index 08fa72b7b8a..fbd094bb5ff 100644 --- a/packages/grafana-prometheus/src/querybuilder/parsing.test.ts +++ b/packages/grafana-prometheus/src/querybuilder/parsing.test.ts @@ -290,6 +290,28 @@ describe('buildVisualQueryFromString', () => { }); }); + // enable in #85942 when updated lezer parser is merged + xit('parses a native histogram function correctly', () => { + expect( + buildVisualQueryFromString('histogram_count(rate(counters_logins{app="backend"}[$__rate_interval]))') + ).toEqual({ + errors: [], + query: { + metric: 'counters_logins', + labels: [{ label: 'app', op: '=', value: 'backend' }], + operations: [ + { + id: 'rate', + params: ['$__rate_interval'], + }, + { + id: 'histogram_quantile', + }, + ], + }, + }); + }); + it('parses function with multiple arguments', () => { expect( buildVisualQueryFromString( diff --git a/packages/grafana-prometheus/src/querybuilder/types.ts b/packages/grafana-prometheus/src/querybuilder/types.ts index 24750f21a96..773b22373a4 100644 --- a/packages/grafana-prometheus/src/querybuilder/types.ts +++ b/packages/grafana-prometheus/src/querybuilder/types.ts @@ -63,6 +63,12 @@ export enum PromOperationId { Floor = 'floor', Group = 'group', HistogramQuantile = 'histogram_quantile', + HistogramAvg = 'histogram_avg', + HistogramCount = 'histogram_count', + HistogramSum = 'histogram_sum', + HistogramFraction = 'histogram_fraction', + HistogramStddev = 'histogram_stddev', + HistogramStdvar = 'histogram_stdvar', HoltWinters = 'holt_winters', Hour = 'hour', Idelta = 'idelta', From 5a57c31607addd55d9061e8f8f9cfb6d68bbdcd3 Mon Sep 17 00:00:00 2001 From: David Allen Date: Mon, 15 Apr 2024 15:32:09 -0400 Subject: [PATCH 030/147] Docs: add template var Play link; cleanup existing (#86074) * Docs: add template var Play link; cleanup existing * Update docs/sources/dashboards/variables/_index.md Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> * Update docs/sources/dashboards/variables/_index.md Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> --------- Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> --- docs/sources/dashboards/variables/_index.md | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/docs/sources/dashboards/variables/_index.md b/docs/sources/dashboards/variables/_index.md index 8b6c4a397f6..ad8eae57c86 100644 --- a/docs/sources/dashboards/variables/_index.md +++ b/docs/sources/dashboards/variables/_index.md @@ -30,7 +30,9 @@ the dashboard. These dropdowns make it easy to change the data being displayed i {{< figure src="/static/img/docs/v50/variables_dashboard.png" alt="Variable drop-down open and two values selected" >}} -These can be especially useful for administrators who want to allow Grafana viewers to quickly adjust visualizations but do not want to give them full editing permissions. Grafana Viewers can use variables. +{{< docs/play title="Templating - Global variables and interpolation" url="https://play.grafana.org/d/HYaGDGIMk/" >}} + +Variables are useful for administrators who want to allow Grafana viewers to adjust visualizations without giving them full editing permissions. Grafana viewers can use variables. Variables and templates also allow you to single-source dashboards. If you have multiple identical data sources or servers, you can make one dashboard and use variables to change what you are viewing. This simplifies maintenance and upkeep enormously. @@ -46,7 +48,7 @@ wmi_system_threads{instance=~"$server"} Variable values are always synced to the URL using the syntax `var-=value`. -## Examples +## Additional Examples Variables are listed in drop-down lists across the top of the screen. Select different variables to see how the visualizations change. @@ -56,12 +58,9 @@ Variables can be used in titles, descriptions, text panels, and queries. Queries The following dashboards in Grafana Play provide examples of template variables: -- [Graphite Templated Nested](https://play.grafana.org/d/000000056/templated-dynamic-dashboard?orgId=1&var-app=backend&var-server=backend_01&var-server=backend_02&var-server=backend_03&var-server=backend_04&var-interval=1h) - Uses query variables, chained query variables, an interval variable, and a repeated panel. -- [Global variables and interpolation](https://play.grafana.org/d/HYaGDGIMk/templating-global-variables-and-interpolation?orgId=1&var-Server=A%27A%22A&var-Server=BB%5CB) -- [Elasticsearch Dummy Flight Data](https://play.grafana.org/d/z8OZC66nk/elasticsearch-8-2-0-sample-flight-data?orgId=1&var-Filters=Carrier%7C%3D%7CLogstash%20Airways&var-query0=) - Uses ad hoc filters. -- [Templating, repeated panels](https://play.grafana.org/d/000000025/templating-repeated-panels?orgId=1) - Two sets of repeated panels use query variables. -- [Template Redux](https://play.grafana.org/d/p-k6QtkGz/template-redux?orgId=1) - Uses query variables, chained query variables, an interval variable, a text box variable, a custom variable, and a data source variable. -- [Nested Variables Drilldown](https://play.grafana.org/d/testdata-nested-variables-drilldown/templating-nested-variables-drilldown?orgId=1&var-datacenter=A&var-server=AA&var-server=AC&var-pod=All) +- [Templating, repeated panels](https://play.grafana.org/d/000000025/) - Using query variables to control how many panels appear. +- [Templated Dynamic Dashboard](https://play.grafana.org/d/000000056/) - Uses query variables, chained query variables, an interval variable, and a repeated panel. +- [Templating - Nested Variables Drilldown](https://play.grafana.org/d/testdata-nested-variables-drilldown/) ## Variable best practices From 04e127b368f45112f5c00fe1140cf81e4ce53d5e Mon Sep 17 00:00:00 2001 From: David Allen Date: Mon, 15 Apr 2024 15:50:53 -0400 Subject: [PATCH 031/147] Docs: added bar gauge play link (#86205) * docs: added bar gauge play link * Update docs/sources/panels-visualizations/visualizations/bar-gauge/index.md Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> --------- Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> --- .../panels-visualizations/visualizations/bar-gauge/index.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/sources/panels-visualizations/visualizations/bar-gauge/index.md b/docs/sources/panels-visualizations/visualizations/bar-gauge/index.md index c773210ef42..263d56c3c11 100644 --- a/docs/sources/panels-visualizations/visualizations/bar-gauge/index.md +++ b/docs/sources/panels-visualizations/visualizations/bar-gauge/index.md @@ -23,7 +23,9 @@ Bar gauges simplify your data by reducing every field to a single value. You cho This panel can show one or more bar gauges depending on how many series, rows, or columns your query returns. -{{< figure src="/static/img/docs/v66/bar_gauge_cover.png" max-width="1025px" caption="Stat panel" >}} +{{< figure src="/static/img/docs/v66/bar_gauge_cover.png" max-width="1025px" alt="Bar gauge panel" >}} + +{{< docs/play title="Bar Gauge" url="https://play.grafana.org/d/vmie2cmWz/" >}} ## Value options From c450d61d32ce6b291bbc81dd09bc68aac2be3afd Mon Sep 17 00:00:00 2001 From: David Allen Date: Mon, 15 Apr 2024 15:51:13 -0400 Subject: [PATCH 032/147] docs: query data/relative time range override play link (#86213) --- .../panels-visualizations/query-transform-data/_index.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/sources/panels-visualizations/query-transform-data/_index.md b/docs/sources/panels-visualizations/query-transform-data/_index.md index 356fca6533c..be31482eaab 100644 --- a/docs/sources/panels-visualizations/query-transform-data/_index.md +++ b/docs/sources/panels-visualizations/query-transform-data/_index.md @@ -190,6 +190,8 @@ Panel data source query options include: | This week so far | `now/w` | | Last 2 years | `now-2y/y` | +{{< docs/play title="Time range override" url="https://play.grafana.org/d/000000041/" >}} + - **Time shift:** Overrides the time range for individual panels by shifting its start and end relative to the time picker. For example, you can shift the time range for the panel to be two hours earlier than the dashboard time picker. From 19ae9377b906f6f7ec7c629622f42cef65ffc55e Mon Sep 17 00:00:00 2001 From: David Allen Date: Mon, 15 Apr 2024 17:08:06 -0400 Subject: [PATCH 033/147] docs: added logs panel play link; added dedup options, reformatted fig (#86209) * docs: added logs panel play link; added dedup options, reformatted fig * Update docs/sources/panels-visualizations/visualizations/logs/index.md Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> * Update docs/sources/panels-visualizations/visualizations/logs/index.md Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> --------- Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> --- .../panels-visualizations/visualizations/logs/index.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/sources/panels-visualizations/visualizations/logs/index.md b/docs/sources/panels-visualizations/visualizations/logs/index.md index 17739cafdef..418a9a51b94 100644 --- a/docs/sources/panels-visualizations/visualizations/logs/index.md +++ b/docs/sources/panels-visualizations/visualizations/logs/index.md @@ -24,7 +24,9 @@ weight: 100 The logs visualization shows log lines from data sources that support logs, such as Elastic, Influx, and Loki. Typically you would use this visualization next to a graph visualization to display the log output of a related process. - +{{< figure src="/static/img/docs/v64/logs-panel.png" max-width="1025px" alt="Logs panel" >}} + +{{< docs/play title="Logs Panel" url="https://play.grafana.org/d/6NmftOxZz/" >}} The logs visualization shows the result of queries that were entered in the Query tab. The results of multiple queries are merged and sorted by time. You can scroll inside the panel if the data source returns more lines than can be displayed at any one time. @@ -56,6 +58,7 @@ Use these settings to refine your visualization: - **Wrap lines -** Toggle line wrapping. - **Prettify JSON -** Set this to `true` to pretty print all JSON logs. This setting does not affect logs in any format other than JSON. - **Enable log details -** Toggle option to see the log details view for each log row. The default setting is true. +- **Deduplication -** Hides log messages that are duplicates of others shown according to criteria such as exact match, or those that only differ by numbers such as IPs or latencies. - **Order -** Display results in descending or ascending time order. The default is **Descending**, showing the newest logs first. Set to **Ascending** to show the oldest log lines first. {{% docs/reference %}} From f50e29e00420e90827fc2aaef1fdf8dda43444c3 Mon Sep 17 00:00:00 2001 From: David Allen Date: Mon, 15 Apr 2024 17:16:04 -0400 Subject: [PATCH 034/147] docs: add thresholds play link (#86212) * docs: add thresholds play link * PR review --- .../sources/panels-visualizations/configure-thresholds/index.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/sources/panels-visualizations/configure-thresholds/index.md b/docs/sources/panels-visualizations/configure-thresholds/index.md index fe6e7a5bd5c..92557208917 100644 --- a/docs/sources/panels-visualizations/configure-thresholds/index.md +++ b/docs/sources/panels-visualizations/configure-thresholds/index.md @@ -38,6 +38,8 @@ You can also use thresholds to: - Color markers in a geomap - Color cell text or background in a table +{{< docs/play title="Threshold example" url="https://play.grafana.org/d/000000167/" >}} + ## Supported visualizations You can set thresholds in the following visualizations: From 63aa8a60355ca1f0220dc6968f541be89242ca93 Mon Sep 17 00:00:00 2001 From: Nick Richmond <5732000+NWRichmond@users.noreply.github.com> Date: Mon, 15 Apr 2024 17:17:15 -0400 Subject: [PATCH 035/147] Chore: add missing modowner (#86234) * chore: add modowner * fix: modowner --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 17ac82f1891..099b49df2db 100644 --- a/go.mod +++ b/go.mod @@ -199,7 +199,7 @@ require ( go.mongodb.org/mongo-driver v1.13.1 // indirect go.opencensus.io v0.24.0 // indirect go.uber.org/atomic v1.11.0 // @grafana/alerting-squad-backend - go.uber.org/goleak v1.3.0 // indirect + go.uber.org/goleak v1.3.0 // @grafana/grafana-search-and-storage golang.org/x/sys v0.18.0 // indirect golang.org/x/text v0.14.0 // @grafana/backend-platform golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect From c9350a25c4898cfcfb6aa0336174b089e4c5b69b Mon Sep 17 00:00:00 2001 From: David Allen Date: Mon, 15 Apr 2024 17:30:48 -0400 Subject: [PATCH 036/147] docs: add annotations play link (#86206) * docs: add annotations play link * PR feedback --- .../build-dashboards/annotate-visualizations/index.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/sources/dashboards/build-dashboards/annotate-visualizations/index.md b/docs/sources/dashboards/build-dashboards/annotate-visualizations/index.md index d9711ffffab..5948d8f9f15 100644 --- a/docs/sources/dashboards/build-dashboards/annotate-visualizations/index.md +++ b/docs/sources/dashboards/build-dashboards/annotate-visualizations/index.md @@ -24,6 +24,8 @@ Annotations provide a way to mark points on a visualization with rich events. Th {{< figure src="/static/img/docs/v46/annotations.png" max-width="800px" alt="Annotated visualization with annotation context menu open" >}} +{{< docs/play title="Annotations" url="https://play.grafana.org/d/000000010/" >}} + You can annotate visualizations in three ways: - Directly in the panel, using the [built-in annotations query](#built-in-query) From f85470d6523a6d086176686cd47ef0a2177ff9e7 Mon Sep 17 00:00:00 2001 From: Brendan O'Handley Date: Mon, 15 Apr 2024 16:45:23 -0500 Subject: [PATCH 037/147] Prometheus: Use the frontend package in Prometheus and remove feature toggle (#86080) * add history links for monaco completion provider folder * add history links for monaco query field folder * add history links for components folder * add history links for configuration folder * add history links for dashboard json folder * add history links for gcopypaste folder * add history link for variableMigration * add history link for querybuilder/components/metrics-modal folder * add history link for querybuilder/components/promqail folder * add history links for querybuilder/components folder * add history links for querybuilder/hooks folder * add history links for querybuilder/shared folder * add history links for querybuilder folder * add history links for querycache folder * add history links for src folder * use frontend package and custom auth in module.ts * remove files and fix import issues * remove usePrometheusFrontendPackage * remove extra files * update betterer * remove extra files after rebase * fix betterer for rebase * fix e2e flakiness --- .betterer.results | 247 ---- .../feature-toggles/index.md | 1 - e2e/various-suite/query-editor.spec.ts | 2 +- .../src/types/featureToggles.gen.ts | 1 - .../src/add_label_to_query.test.ts | 1 + .../src/add_label_to_query.ts | 1 + .../src/components/AnnotationQueryEditor.tsx | 1 + .../src/components/PromCheatSheet.tsx | 1 + .../src/components/PromExemplarField.tsx | 1 + .../components/PromExploreExtraField.test.tsx | 1 + .../src/components/PromExploreExtraField.tsx | 1 + .../components/PromQueryEditorByApp.test.tsx | 1 + .../src/components/PromQueryEditorByApp.tsx | 1 + .../components/PromQueryEditorForAlerting.tsx | 1 + .../src/components/PromQueryField.test.tsx | 1 + .../src/components/PromQueryField.tsx | 1 + .../PrometheusMetricsBrowser.test.tsx | 1 + .../components/PrometheusMetricsBrowser.tsx | 1 + .../components/VariableQueryEditor.test.tsx | 1 + .../src/components/VariableQueryEditor.tsx | 1 + .../monaco-query-field/MonacoQueryField.tsx | 1 + .../MonacoQueryFieldLazy.tsx | 1 + .../MonacoQueryFieldProps.ts | 1 + .../MonacoQueryFieldWrapper.tsx | 1 + .../monaco-query-field/getOverrideServices.ts | 1 + .../monaco-completion-provider/completions.ts | 1 + .../monaco-completion-provider/index.ts | 1 + .../situation.test.ts | 1 + .../monaco-completion-provider/situation.ts | 1 + .../monaco-completion-provider/util.ts | 2 + .../validation.test.ts | 1 + .../monaco-completion-provider/validation.ts | 1 + .../src/components/types.ts | 1 + .../AlertingSettingsOverhaul.tsx | 1 + .../src/configuration/ConfigEditor.test.tsx | 1 + .../src/configuration/ConfigEditor.tsx | 1 + .../DataSourceHttpSettingsOverhaul.tsx | 1 + .../src/configuration/ExemplarSetting.tsx | 1 + .../src/configuration/ExemplarsSettings.tsx | 1 + .../src/configuration/PromFlavorVersions.ts | 1 + .../src/configuration/PromSettings.test.tsx | 1 + .../src/configuration/PromSettings.tsx | 1 + .../src/configuration/mocks.ts | 1 + .../src/dashboards/grafana_stats.json | 1 + .../src/dashboards/prometheus_2_stats.json | 1 + .../src/dashboards/prometheus_stats.json | 1 + packages/grafana-prometheus/src/dataquery.ts | 1 + .../grafana-prometheus/src/datasource.test.ts | 1 + packages/grafana-prometheus/src/datasource.ts | 1 + .../LocalStorageValueProvider.tsx | 1 + .../LocalStorageValueProvider/index.tsx | 1 + .../src/gcopypaste/app/core/store.ts | 1 + .../app/core/utils/CancelablePromise.ts | 1 + .../src/gcopypaste/app/core/utils/query.ts | 1 + .../datasources/__mocks__/dataSourcesMocks.ts | 1 + .../app/features/live/data/amendTimeSeries.ts | 1 + .../src/components/Select/SelectBase.tsx | 1 + .../gcopypaste/public/test/matchers/index.ts | 1 + .../public/test/matchers/toEmitValues.test.ts | 1 + .../public/test/matchers/toEmitValues.ts | 1 + .../test/matchers/toEmitValuesWith.test.ts | 1 + .../public/test/matchers/toEmitValuesWith.ts | 1 + .../gcopypaste/public/test/matchers/types.ts | 1 + .../gcopypaste/public/test/matchers/utils.ts | 1 + .../test/helpers/selectOptionInTest.ts | 1 + packages/grafana-prometheus/src/index.ts | 4 +- .../src/language_provider.mock.ts | 1 + .../src/language_provider.test.ts | 1 + .../src/language_provider.ts | 1 + .../src/language_utils.test.ts | 1 + .../grafana-prometheus/src/language_utils.ts | 1 + .../src/metric_find_query.test.ts | 1 + .../src/metric_find_query.ts | 1 + .../src/migrations/variableMigration.ts | 1 + .../grafana-prometheus/src/module.test.ts | 1 + packages/grafana-prometheus/src/module.ts | 1 + .../grafana-prometheus/src/promql.test.ts | 1 + packages/grafana-prometheus/src/promql.ts | 1 + .../src/query_hints.test.ts | 1 + .../grafana-prometheus/src/query_hints.ts | 1 + .../querybuilder/PromQueryModeller.test.ts | 1 + .../src/querybuilder/PromQueryModeller.ts | 1 + .../src/querybuilder/QueryPattern.tsx | 1 + .../querybuilder/QueryPatternsModal.test.tsx | 1 + .../src/querybuilder/QueryPatternsModal.tsx | 1 + .../src/querybuilder/aggregations.ts | 1 + .../querybuilder/binaryScalarOperations.ts | 1 + .../components/LabelFilterItem.tsx | 1 + .../components/LabelFilters.test.tsx | 1 + .../querybuilder/components/LabelFilters.tsx | 1 + .../components/LabelParamEditor.tsx | 1 + .../components/MetricSelect.test.tsx | 1 + .../querybuilder/components/MetricSelect.tsx | 1 + .../components/MetricsLabelsSection.tsx | 1 + .../querybuilder/components/NestedQuery.tsx | 1 + .../components/NestedQueryList.tsx | 1 + .../components/PromQueryBuilder.test.tsx | 1 + .../components/PromQueryBuilder.tsx | 1 + .../PromQueryBuilderContainer.test.tsx | 1 + .../components/PromQueryBuilderContainer.tsx | 1 + .../components/PromQueryBuilderExplained.tsx | 1 + .../PromQueryBuilderOptions.test.tsx | 1 + .../components/PromQueryBuilderOptions.tsx | 1 + .../components/PromQueryCodeEditor.test.tsx | 1 + .../components/PromQueryCodeEditor.tsx | 1 + .../PromQueryEditorSelector.test.tsx | 1 + .../components/PromQueryEditorSelector.tsx | 1 + .../components/PromQueryLegendEditor.tsx | 1 + .../querybuilder/components/QueryPreview.tsx | 1 + .../metrics-modal/AdditionalSettings.tsx | 1 + .../components/metrics-modal/FeedbackLink.tsx | 1 + .../metrics-modal/MetricsModal.test.tsx | 1 + .../components/metrics-modal/MetricsModal.tsx | 1 + .../components/metrics-modal/ResultsTable.tsx | 1 + .../components/metrics-modal/state/helpers.ts | 1 + .../components/metrics-modal/state/state.ts | 1 + .../components/metrics-modal/styles.ts | 1 + .../components/metrics-modal/types.ts | 1 + .../components/metrics-modal/uFuzzy.ts | 1 + .../components/promQail/PromQail.test.tsx | 1 + .../components/promQail/PromQail.tsx | 1 + .../promQail/QueryAssistantButton.test.tsx | 1 + .../promQail/QueryAssistantButton.tsx | 1 + .../promQail/QuerySuggestionContainer.tsx | 1 + .../promQail/QuerySuggestionItem.tsx | 1 + .../components/promQail/prompts.ts | 1 + .../components/promQail/state/helpers.test.ts | 1 + .../components/promQail/state/helpers.ts | 1 + .../components/promQail/state/state.ts | 1 + .../components/promQail/state/templates.ts | 1 + .../querybuilder/components/promQail/types.ts | 1 + .../src/querybuilder/hooks/useFlag.test.ts | 1 + .../src/querybuilder/hooks/useFlag.ts | 1 + .../src/querybuilder/operationUtils.test.ts | 1 + .../src/querybuilder/operationUtils.ts | 1 + .../src/querybuilder/operations.ts | 1 + .../src/querybuilder/parsing.test.ts | 1 + .../src/querybuilder/parsing.ts | 1 + .../src/querybuilder/parsingUtils.test.ts | 1 + .../src/querybuilder/parsingUtils.ts | 1 + .../shared/LokiAndPromQueryModellerBase.ts | 1 + .../querybuilder/shared/OperationEditor.tsx | 1 + .../shared/OperationExplainedBox.tsx | 1 + .../querybuilder/shared/OperationHeader.tsx | 1 + .../shared/OperationInfoButton.tsx | 1 + .../shared/OperationList.test.tsx | 1 + .../src/querybuilder/shared/OperationList.tsx | 1 + .../shared/OperationListExplained.tsx | 1 + .../shared/OperationParamEditor.tsx | 1 + .../shared/OperationsEditorRow.tsx | 1 + .../querybuilder/shared/QueryBuilderHints.tsx | 1 + .../shared/QueryEditorModeToggle.tsx | 1 + .../querybuilder/shared/QueryHeaderSwitch.tsx | 1 + .../querybuilder/shared/QueryOptionGroup.tsx | 1 + .../src/querybuilder/shared/RawQuery.tsx | 1 + .../src/querybuilder/shared/types.ts | 1 + .../src/querybuilder/state.test.ts | 1 + .../src/querybuilder/state.ts | 1 + .../src/querybuilder/testUtils.ts | 1 + .../src/querybuilder/types.ts | 1 + .../src/querycache/QueryCache.test.ts | 1 + .../src/querycache/QueryCache.ts | 1 + .../src/querycache/QueryCacheTestData.ts | 1 + .../src/result_transformer.test.ts | 1 + .../src/result_transformer.ts | 1 + packages/grafana-prometheus/src/tracking.ts | 1 + packages/grafana-prometheus/src/types.ts | 1 + packages/grafana-prometheus/src/variables.ts | 1 + pkg/services/featuremgmt/registry.go | 7 - pkg/services/featuremgmt/toggles_gen.csv | 1 - pkg/services/featuremgmt/toggles_gen.go | 4 - pkg/services/featuremgmt/toggles_gen.json | 1 + .../unified/PanelAlertTabContent.test.tsx | 3 +- .../unified/components/Expression.tsx | 4 +- .../rule-editor/ExpressionEditor.tsx | 2 +- .../features/alerting/unified/utils/query.ts | 2 +- .../alerting/unified/utils/rule-form.test.ts | 2 +- .../alerting/unified/utils/rule-form.ts | 2 +- .../PanelDataAlertingTab.test.tsx | 3 +- .../dashboard/state/DashboardModel.ts | 2 +- .../explore/PrometheusListView/ItemLabels.tsx | 3 +- .../explore/TraceView/createSpanLink.tsx | 2 +- .../trails/ActionTabs/MetricOverviewScene.tsx | 2 +- .../AutomaticMetricQueries/previewPanel.ts | 2 +- .../query-generators/histogram.ts | 2 +- .../trails/AutomaticMetricQueries/types.ts | 2 +- .../trails/helpers/MetricDatasourceHelper.ts | 4 +- .../dashboard/DashboardQueryEditor.tsx | 3 +- .../prometheus/add_label_to_query.test.ts | 114 -- .../prometheus/add_label_to_query.ts | 100 -- .../components/AnnotationQueryEditor.tsx | 139 -- .../prometheus/components/PromCheatSheet.tsx | 52 - .../components/PromExemplarField.tsx | 79 - .../components/PromExploreExtraField.test.tsx | 37 - .../components/PromExploreExtraField.tsx | 141 -- .../components/PromQueryEditorByApp.test.tsx | 83 -- .../components/PromQueryEditorByApp.tsx | 21 - .../components/PromQueryEditorForAlerting.tsx | 25 - .../components/PromQueryField.test.tsx | 183 --- .../prometheus/components/PromQueryField.tsx | 290 ---- .../PrometheusMetricsBrowser.test.tsx | 324 ---- .../components/PrometheusMetricsBrowser.tsx | 684 --------- .../components/VariableQueryEditor.test.tsx | 392 ----- .../components/VariableQueryEditor.tsx | 437 ------ .../monaco-query-field/MonacoQueryField.tsx | 296 ---- .../MonacoQueryFieldLazy.tsx | 13 - .../MonacoQueryFieldProps.ts | 21 - .../MonacoQueryFieldWrapper.tsx | 34 - .../monaco-query-field/getOverrideServices.ts | 116 -- .../completions.test.ts | 118 -- .../monaco-completion-provider/completions.ts | 217 --- .../data_provider.ts | 116 -- .../monaco-completion-provider/index.ts | 116 -- .../situation.test.ts | 185 --- .../monaco-completion-provider/situation.ts | 567 ------- .../monaco-completion-provider/util.ts | 25 - .../validation.test.ts | 85 -- .../datasource/prometheus/components/types.ts | 6 - .../AlertingSettingsOverhaul.tsx | 65 - .../configuration/ConfigEditor.test.tsx | 93 -- .../prometheus/configuration/ConfigEditor.tsx | 195 --- .../DataSourceHttpSettingsOverhaul.tsx | 168 --- .../configuration/ExemplarSetting.tsx | 150 -- .../configuration/ExemplarsSettings.tsx | 67 - .../configuration/PromFlavorVersions.ts | 99 -- .../configuration/PromSettings.test.tsx | 142 -- .../prometheus/configuration/PromSettings.tsx | 638 -------- .../prometheus/configuration/mocks.ts | 14 - .../overhaul/AdvancedHttpSettings.tsx | 93 -- .../overhaul/ConnectionSettings.tsx | 90 -- .../configuration/overhaul/types.ts | 11 - .../datasource/prometheus/dataquery.ts | 49 - .../datasource/prometheus/datasource.test.ts | 1297 ----------------- .../datasource/prometheus/datasource.ts | 1023 ------------- .../prometheus/language_provider.mock.ts | 18 - .../prometheus/language_provider.test.ts | 393 ----- .../prometheus/language_provider.ts | 378 ----- .../prometheus/language_utils.test.ts | 515 ------- .../datasource/prometheus/language_utils.ts | 533 ------- .../prometheus/metric_find_query.test.ts | 413 ------ .../prometheus/metric_find_query.ts | 203 --- .../migrations/variableMigration.ts | 137 -- .../plugins/datasource/prometheus/module.ts | 30 +- .../datasource/prometheus/promql.test.ts | 23 - .../plugins/datasource/prometheus/promql.ts | 607 -------- .../datasource/prometheus/query_hints.test.ts | 192 --- .../datasource/prometheus/query_hints.ts | 151 -- .../querybuilder/PromQueryModeller.test.ts | 335 ----- .../querybuilder/PromQueryModeller.ts | 93 -- .../prometheus/querybuilder/QueryPattern.tsx | 118 -- .../querybuilder/QueryPatternsModal.test.tsx | 143 -- .../querybuilder/QueryPatternsModal.tsx | 132 -- .../prometheus/querybuilder/aggregations.ts | 62 - .../querybuilder/binaryScalarOperations.ts | 120 -- .../components/LabelFilterItem.tsx | 195 --- .../components/LabelFilters.test.tsx | 162 -- .../querybuilder/components/LabelFilters.tsx | 114 -- .../components/LabelParamEditor.tsx | 60 - .../components/MetricSelect.test.tsx | 191 --- .../querybuilder/components/MetricSelect.tsx | 423 ------ .../components/MetricsLabelsSection.tsx | 252 ---- .../querybuilder/components/NestedQuery.tsx | 129 -- .../components/NestedQueryList.tsx | 49 - .../components/PromQueryBuilder.test.tsx | 392 ----- .../components/PromQueryBuilder.tsx | 149 -- .../PromQueryBuilderContainer.test.tsx | 64 - .../components/PromQueryBuilderContainer.tsx | 120 -- .../components/PromQueryBuilderExplained.tsx | 41 - .../PromQueryBuilderOptions.test.tsx | 134 -- .../components/PromQueryBuilderOptions.tsx | 162 -- .../components/PromQueryCodeEditor.test.tsx | 64 - .../components/PromQueryCodeEditor.tsx | 52 - ...omQueryCodeEditorAutocompleteInfo.test.tsx | 161 -- .../PromQueryCodeEditorAutocompleteInfo.tsx | 69 - .../PromQueryEditorSelector.test.tsx | 255 ---- .../components/PromQueryEditorSelector.tsx | 168 --- .../components/PromQueryLegendEditor.tsx | 119 -- .../querybuilder/components/QueryPreview.tsx | 24 - .../metrics-modal/AdditionalSettings.tsx | 81 - .../components/metrics-modal/FeedbackLink.tsx | 40 - .../metrics-modal/MetricsModal.test.tsx | 261 ---- .../components/metrics-modal/MetricsModal.tsx | 337 ----- .../components/metrics-modal/ResultsTable.tsx | 252 ---- .../components/metrics-modal/state/helpers.ts | 259 ---- .../components/metrics-modal/state/state.ts | 193 --- .../components/metrics-modal/styles.ts | 101 -- .../components/metrics-modal/types.ts | 30 - .../components/metrics-modal/uFuzzy.ts | 45 - .../components/promQail/PromQail.test.tsx | 148 -- .../components/promQail/PromQail.tsx | 567 ------- .../promQail/QueryAssistantButton.test.tsx | 51 - .../promQail/QueryAssistantButton.tsx | 87 -- .../promQail/QuerySuggestionContainer.tsx | 101 -- .../promQail/QuerySuggestionItem.tsx | 321 ---- .../components/promQail/prompts.ts | 114 -- .../promQail/resources/AI_Logo_bw.svg | 4 - .../promQail/resources/AI_Logo_color.svg | 11 - .../components/promQail/state/helpers.test.ts | 74 - .../components/promQail/state/helpers.ts | 419 ------ .../components/promQail/state/state.ts | 93 -- .../components/promQail/state/templates.ts | 337 ----- .../querybuilder/components/promQail/types.ts | 17 - .../querybuilder/hooks/useFlag.test.ts | 23 - .../prometheus/querybuilder/hooks/useFlag.ts | 36 - .../querybuilder/operationUtils.test.ts | 208 --- .../prometheus/querybuilder/operationUtils.ts | 353 ----- .../prometheus/querybuilder/operations.ts | 376 ----- .../prometheus/querybuilder/parsing.test.ts | 720 --------- .../prometheus/querybuilder/parsing.ts | 468 ------ .../querybuilder/parsingUtils.test.ts | 42 - .../prometheus/querybuilder/parsingUtils.ts | 140 -- .../querybuilder/shared/LabelFilterItem.tsx | 184 --- .../querybuilder/shared/LabelFilters.test.tsx | 121 -- .../querybuilder/shared/LabelFilters.tsx | 79 - .../shared/LokiAndPromQueryModellerBase.ts | 122 -- .../querybuilder/shared/OperationEditor.tsx | 332 ----- .../shared/OperationExplainedBox.tsx | 77 - .../querybuilder/shared/OperationHeader.tsx | 121 -- .../shared/OperationInfoButton.tsx | 120 -- .../shared/OperationList.test.tsx | 85 -- .../querybuilder/shared/OperationList.tsx | 204 --- .../shared/OperationListExplained.tsx | 55 - .../shared/OperationParamEditor.tsx | 129 -- .../shared/OperationsEditorRow.tsx | 29 - .../querybuilder/shared/QueryBuilderHints.tsx | 88 -- .../shared/QueryEditorModeToggle.tsx | 23 - .../querybuilder/shared/QueryHeaderSwitch.tsx | 39 - .../shared/QueryOptionGroup.test.tsx | 48 - .../querybuilder/shared/QueryOptionGroup.tsx | 114 -- .../querybuilder/shared/RawQuery.tsx | 37 - .../prometheus/querybuilder/shared/types.ts | 110 -- .../prometheus/querybuilder/state.test.ts | 64 - .../prometheus/querybuilder/state.ts | 72 - .../prometheus/querybuilder/testUtils.ts | 27 - .../prometheus/querybuilder/types.ts | 139 -- .../prometheus/querycache/QueryCache.test.ts | 521 ------- .../prometheus/querycache/QueryCache.ts | 441 ------ .../querycache/QueryCacheTestData.ts | 862 ----------- .../prometheus/result_transformer.test.ts | 1159 --------------- .../prometheus/result_transformer.ts | 422 ------ .../plugins/datasource/prometheus/tracking.ts | 46 - .../plugins/datasource/prometheus/types.ts | 142 -- .../datasource/prometheus/variables.ts | 58 - public/app/plugins/panel/heatmap/fields.ts | 2 +- 344 files changed, 193 insertions(+), 30015 deletions(-) delete mode 100644 public/app/plugins/datasource/prometheus/add_label_to_query.test.ts delete mode 100644 public/app/plugins/datasource/prometheus/add_label_to_query.ts delete mode 100644 public/app/plugins/datasource/prometheus/components/AnnotationQueryEditor.tsx delete mode 100644 public/app/plugins/datasource/prometheus/components/PromCheatSheet.tsx delete mode 100644 public/app/plugins/datasource/prometheus/components/PromExemplarField.tsx delete mode 100644 public/app/plugins/datasource/prometheus/components/PromExploreExtraField.test.tsx delete mode 100644 public/app/plugins/datasource/prometheus/components/PromExploreExtraField.tsx delete mode 100644 public/app/plugins/datasource/prometheus/components/PromQueryEditorByApp.test.tsx delete mode 100644 public/app/plugins/datasource/prometheus/components/PromQueryEditorByApp.tsx delete mode 100644 public/app/plugins/datasource/prometheus/components/PromQueryEditorForAlerting.tsx delete mode 100644 public/app/plugins/datasource/prometheus/components/PromQueryField.test.tsx delete mode 100644 public/app/plugins/datasource/prometheus/components/PromQueryField.tsx delete mode 100644 public/app/plugins/datasource/prometheus/components/PrometheusMetricsBrowser.test.tsx delete mode 100644 public/app/plugins/datasource/prometheus/components/PrometheusMetricsBrowser.tsx delete mode 100644 public/app/plugins/datasource/prometheus/components/VariableQueryEditor.test.tsx delete mode 100644 public/app/plugins/datasource/prometheus/components/VariableQueryEditor.tsx delete mode 100644 public/app/plugins/datasource/prometheus/components/monaco-query-field/MonacoQueryField.tsx delete mode 100644 public/app/plugins/datasource/prometheus/components/monaco-query-field/MonacoQueryFieldLazy.tsx delete mode 100644 public/app/plugins/datasource/prometheus/components/monaco-query-field/MonacoQueryFieldProps.ts delete mode 100644 public/app/plugins/datasource/prometheus/components/monaco-query-field/MonacoQueryFieldWrapper.tsx delete mode 100644 public/app/plugins/datasource/prometheus/components/monaco-query-field/getOverrideServices.ts delete mode 100644 public/app/plugins/datasource/prometheus/components/monaco-query-field/monaco-completion-provider/completions.test.ts delete mode 100644 public/app/plugins/datasource/prometheus/components/monaco-query-field/monaco-completion-provider/completions.ts delete mode 100644 public/app/plugins/datasource/prometheus/components/monaco-query-field/monaco-completion-provider/data_provider.ts delete mode 100644 public/app/plugins/datasource/prometheus/components/monaco-query-field/monaco-completion-provider/index.ts delete mode 100644 public/app/plugins/datasource/prometheus/components/monaco-query-field/monaco-completion-provider/situation.test.ts delete mode 100644 public/app/plugins/datasource/prometheus/components/monaco-query-field/monaco-completion-provider/situation.ts delete mode 100644 public/app/plugins/datasource/prometheus/components/monaco-query-field/monaco-completion-provider/util.ts delete mode 100644 public/app/plugins/datasource/prometheus/components/monaco-query-field/monaco-completion-provider/validation.test.ts delete mode 100644 public/app/plugins/datasource/prometheus/components/types.ts delete mode 100644 public/app/plugins/datasource/prometheus/configuration/AlertingSettingsOverhaul.tsx delete mode 100644 public/app/plugins/datasource/prometheus/configuration/ConfigEditor.test.tsx delete mode 100644 public/app/plugins/datasource/prometheus/configuration/ConfigEditor.tsx delete mode 100644 public/app/plugins/datasource/prometheus/configuration/DataSourceHttpSettingsOverhaul.tsx delete mode 100644 public/app/plugins/datasource/prometheus/configuration/ExemplarSetting.tsx delete mode 100644 public/app/plugins/datasource/prometheus/configuration/ExemplarsSettings.tsx delete mode 100644 public/app/plugins/datasource/prometheus/configuration/PromFlavorVersions.ts delete mode 100644 public/app/plugins/datasource/prometheus/configuration/PromSettings.test.tsx delete mode 100644 public/app/plugins/datasource/prometheus/configuration/PromSettings.tsx delete mode 100644 public/app/plugins/datasource/prometheus/configuration/mocks.ts delete mode 100644 public/app/plugins/datasource/prometheus/configuration/overhaul/AdvancedHttpSettings.tsx delete mode 100644 public/app/plugins/datasource/prometheus/configuration/overhaul/ConnectionSettings.tsx delete mode 100644 public/app/plugins/datasource/prometheus/configuration/overhaul/types.ts delete mode 100644 public/app/plugins/datasource/prometheus/dataquery.ts delete mode 100644 public/app/plugins/datasource/prometheus/datasource.test.ts delete mode 100644 public/app/plugins/datasource/prometheus/datasource.ts delete mode 100644 public/app/plugins/datasource/prometheus/language_provider.mock.ts delete mode 100644 public/app/plugins/datasource/prometheus/language_provider.test.ts delete mode 100644 public/app/plugins/datasource/prometheus/language_provider.ts delete mode 100644 public/app/plugins/datasource/prometheus/language_utils.test.ts delete mode 100644 public/app/plugins/datasource/prometheus/language_utils.ts delete mode 100644 public/app/plugins/datasource/prometheus/metric_find_query.test.ts delete mode 100644 public/app/plugins/datasource/prometheus/metric_find_query.ts delete mode 100644 public/app/plugins/datasource/prometheus/migrations/variableMigration.ts delete mode 100644 public/app/plugins/datasource/prometheus/promql.test.ts delete mode 100644 public/app/plugins/datasource/prometheus/promql.ts delete mode 100644 public/app/plugins/datasource/prometheus/query_hints.test.ts delete mode 100644 public/app/plugins/datasource/prometheus/query_hints.ts delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/PromQueryModeller.test.ts delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/PromQueryModeller.ts delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/QueryPattern.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/QueryPatternsModal.test.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/QueryPatternsModal.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/aggregations.ts delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/binaryScalarOperations.ts delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/components/LabelFilterItem.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/components/LabelFilters.test.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/components/LabelFilters.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/components/LabelParamEditor.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/components/MetricSelect.test.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/components/MetricSelect.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/components/MetricsLabelsSection.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/components/NestedQuery.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/components/NestedQueryList.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryBuilder.test.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryBuilder.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryBuilderContainer.test.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryBuilderContainer.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryBuilderExplained.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryBuilderOptions.test.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryBuilderOptions.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryCodeEditor.test.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryCodeEditor.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryCodeEditorAutocompleteInfo.test.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryCodeEditorAutocompleteInfo.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryEditorSelector.test.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryEditorSelector.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryLegendEditor.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/components/QueryPreview.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/components/metrics-modal/AdditionalSettings.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/components/metrics-modal/FeedbackLink.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/components/metrics-modal/MetricsModal.test.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/components/metrics-modal/MetricsModal.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/components/metrics-modal/ResultsTable.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/components/metrics-modal/state/helpers.ts delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/components/metrics-modal/state/state.ts delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/components/metrics-modal/styles.ts delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/components/metrics-modal/types.ts delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/components/metrics-modal/uFuzzy.ts delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/components/promQail/PromQail.test.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/components/promQail/PromQail.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/components/promQail/QueryAssistantButton.test.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/components/promQail/QueryAssistantButton.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/components/promQail/QuerySuggestionContainer.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/components/promQail/QuerySuggestionItem.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/components/promQail/prompts.ts delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/components/promQail/resources/AI_Logo_bw.svg delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/components/promQail/resources/AI_Logo_color.svg delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/components/promQail/state/helpers.test.ts delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/components/promQail/state/helpers.ts delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/components/promQail/state/state.ts delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/components/promQail/state/templates.ts delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/components/promQail/types.ts delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/hooks/useFlag.test.ts delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/hooks/useFlag.ts delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/operationUtils.test.ts delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/operationUtils.ts delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/operations.ts delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/parsing.test.ts delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/parsing.ts delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/parsingUtils.test.ts delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/parsingUtils.ts delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/shared/LabelFilterItem.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/shared/LabelFilters.test.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/shared/LabelFilters.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/shared/LokiAndPromQueryModellerBase.ts delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/shared/OperationEditor.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/shared/OperationExplainedBox.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/shared/OperationHeader.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/shared/OperationInfoButton.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/shared/OperationList.test.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/shared/OperationList.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/shared/OperationListExplained.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/shared/OperationParamEditor.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/shared/OperationsEditorRow.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/shared/QueryBuilderHints.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/shared/QueryEditorModeToggle.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/shared/QueryHeaderSwitch.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/shared/QueryOptionGroup.test.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/shared/QueryOptionGroup.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/shared/RawQuery.tsx delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/shared/types.ts delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/state.test.ts delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/state.ts delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/testUtils.ts delete mode 100644 public/app/plugins/datasource/prometheus/querybuilder/types.ts delete mode 100644 public/app/plugins/datasource/prometheus/querycache/QueryCache.test.ts delete mode 100644 public/app/plugins/datasource/prometheus/querycache/QueryCache.ts delete mode 100644 public/app/plugins/datasource/prometheus/querycache/QueryCacheTestData.ts delete mode 100644 public/app/plugins/datasource/prometheus/result_transformer.test.ts delete mode 100644 public/app/plugins/datasource/prometheus/result_transformer.ts delete mode 100644 public/app/plugins/datasource/prometheus/tracking.ts delete mode 100644 public/app/plugins/datasource/prometheus/types.ts delete mode 100644 public/app/plugins/datasource/prometheus/variables.ts diff --git a/.betterer.results b/.betterer.results index b39049d9b2d..d9cef880441 100644 --- a/.betterer.results +++ b/.betterer.results @@ -5681,40 +5681,6 @@ exports[`better eslint`] = { "public/app/plugins/datasource/parca/webpack.config.ts:5381": [ [0, 0, 0, "Do not re-export imported variable (\`config\`)", "0"] ], - "public/app/plugins/datasource/prometheus/components/PromExemplarField.tsx:5381": [ - [0, 0, 0, "Styles should be written using objects.", "0"], - [0, 0, 0, "Styles should be written using objects.", "1"], - [0, 0, 0, "Styles should be written using objects.", "2"] - ], - "public/app/plugins/datasource/prometheus/components/PromExploreExtraField.tsx:5381": [ - [0, 0, 0, "Styles should be written using objects.", "0"], - [0, 0, 0, "Styles should be written using objects.", "1"] - ], - "public/app/plugins/datasource/prometheus/components/PromQueryField.test.tsx:5381": [ - [0, 0, 0, "Unexpected any. Specify a different type.", "0"] - ], - "public/app/plugins/datasource/prometheus/components/PromQueryField.tsx:5381": [ - [0, 0, 0, "Unexpected any. Specify a different type.", "0"] - ], - "public/app/plugins/datasource/prometheus/components/PrometheusMetricsBrowser.tsx:5381": [ - [0, 0, 0, "\'HorizontalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"], - [0, 0, 0, "Styles should be written using objects.", "1"], - [0, 0, 0, "Styles should be written using objects.", "2"], - [0, 0, 0, "Styles should be written using objects.", "3"], - [0, 0, 0, "Styles should be written using objects.", "4"], - [0, 0, 0, "Styles should be written using objects.", "5"], - [0, 0, 0, "Styles should be written using objects.", "6"], - [0, 0, 0, "Styles should be written using objects.", "7"], - [0, 0, 0, "Styles should be written using objects.", "8"], - [0, 0, 0, "Styles should be written using objects.", "9"], - [0, 0, 0, "Styles should be written using objects.", "10"], - [0, 0, 0, "Styles should be written using objects.", "11"], - [0, 0, 0, "Styles should be written using objects.", "12"] - ], - "public/app/plugins/datasource/prometheus/components/monaco-query-field/MonacoQueryField.tsx:5381": [ - [0, 0, 0, "Styles should be written using objects.", "0"], - [0, 0, 0, "Styles should be written using objects.", "1"] - ], "public/app/plugins/datasource/prometheus/configuration/AzureCredentialsConfig.ts:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"], [0, 0, 0, "Unexpected any. Specify a different type.", "1"], @@ -5736,165 +5702,6 @@ exports[`better eslint`] = { [0, 0, 0, "Unexpected any. Specify a different type.", "17"], [0, 0, 0, "Unexpected any. Specify a different type.", "18"] ], - "public/app/plugins/datasource/prometheus/configuration/ConfigEditor.tsx:5381": [ - [0, 0, 0, "Styles should be written using objects.", "0"], - [0, 0, 0, "Styles should be written using objects.", "1"], - [0, 0, 0, "Styles should be written using objects.", "2"], - [0, 0, 0, "Styles should be written using objects.", "3"], - [0, 0, 0, "Styles should be written using objects.", "4"], - [0, 0, 0, "Styles should be written using objects.", "5"], - [0, 0, 0, "Styles should be written using objects.", "6"], - [0, 0, 0, "Styles should be written using objects.", "7"], - [0, 0, 0, "Styles should be written using objects.", "8"], - [0, 0, 0, "Styles should be written using objects.", "9"], - [0, 0, 0, "Styles should be written using objects.", "10"], - [0, 0, 0, "Styles should be written using objects.", "11"], - [0, 0, 0, "Styles should be written using objects.", "12"], - [0, 0, 0, "Styles should be written using objects.", "13"], - [0, 0, 0, "Styles should be written using objects.", "14"], - [0, 0, 0, "Styles should be written using objects.", "15"] - ], - "public/app/plugins/datasource/prometheus/configuration/ExemplarsSettings.tsx:5381": [ - [0, 0, 0, "Styles should be written using objects.", "0"] - ], - "public/app/plugins/datasource/prometheus/datasource.ts:5381": [ - [0, 0, 0, "Unexpected any. Specify a different type.", "0"], - [0, 0, 0, "Unexpected any. Specify a different type.", "1"], - [0, 0, 0, "Unexpected any. Specify a different type.", "2"], - [0, 0, 0, "Unexpected any. Specify a different type.", "3"], - [0, 0, 0, "Unexpected any. Specify a different type.", "4"], - [0, 0, 0, "Unexpected any. Specify a different type.", "5"], - [0, 0, 0, "Unexpected any. Specify a different type.", "6"], - [0, 0, 0, "Unexpected any. Specify a different type.", "7"], - [0, 0, 0, "Unexpected any. Specify a different type.", "8"] - ], - "public/app/plugins/datasource/prometheus/language_provider.ts:5381": [ - [0, 0, 0, "Unexpected any. Specify a different type.", "0"], - [0, 0, 0, "Unexpected any. Specify a different type.", "1"], - [0, 0, 0, "Unexpected any. Specify a different type.", "2"] - ], - "public/app/plugins/datasource/prometheus/language_utils.ts:5381": [ - [0, 0, 0, "Do not use any type assertions.", "0"] - ], - "public/app/plugins/datasource/prometheus/querybuilder/QueryPattern.tsx:5381": [ - [0, 0, 0, "Styles should be written using objects.", "0"], - [0, 0, 0, "Styles should be written using objects.", "1"], - [0, 0, 0, "Styles should be written using objects.", "2"], - [0, 0, 0, "Styles should be written using objects.", "3"] - ], - "public/app/plugins/datasource/prometheus/querybuilder/QueryPatternsModal.tsx:5381": [ - [0, 0, 0, "Styles should be written using objects.", "0"], - [0, 0, 0, "Styles should be written using objects.", "1"] - ], - "public/app/plugins/datasource/prometheus/querybuilder/binaryScalarOperations.ts:5381": [ - [0, 0, 0, "Unexpected any. Specify a different type.", "0"] - ], - "public/app/plugins/datasource/prometheus/querybuilder/components/LabelFilterItem.tsx:5381": [ - [0, 0, 0, "Do not use any type assertions.", "0"], - [0, 0, 0, "Do not use any type assertions.", "1"], - [0, 0, 0, "Do not use any type assertions.", "2"], - [0, 0, 0, "Do not use any type assertions.", "3"] - ], - "public/app/plugins/datasource/prometheus/querybuilder/components/LabelFilters.tsx:5381": [ - [0, 0, 0, "Styles should be written using objects.", "0"] - ], - "public/app/plugins/datasource/prometheus/querybuilder/components/LabelParamEditor.tsx:5381": [ - [0, 0, 0, "Do not use any type assertions.", "0"] - ], - "public/app/plugins/datasource/prometheus/querybuilder/components/MetricSelect.tsx:5381": [ - [0, 0, 0, "Unexpected any. Specify a different type.", "0"], - [0, 0, 0, "Styles should be written using objects.", "1"], - [0, 0, 0, "Styles should be written using objects.", "2"], - [0, 0, 0, "Styles should be written using objects.", "3"], - [0, 0, 0, "Styles should be written using objects.", "4"], - [0, 0, 0, "Styles should be written using objects.", "5"], - [0, 0, 0, "Styles should be written using objects.", "6"], - [0, 0, 0, "Styles should be written using objects.", "7"], - [0, 0, 0, "Styles should be written using objects.", "8"], - [0, 0, 0, "Styles should be written using objects.", "9"] - ], - "public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryBuilder.tsx:5381": [ - [0, 0, 0, "Do not use any type assertions.", "0"] - ], - "public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryCodeEditor.tsx:5381": [ - [0, 0, 0, "Styles should be written using objects.", "0"] - ], - "public/app/plugins/datasource/prometheus/querybuilder/components/metrics-modal/AdditionalSettings.tsx:5381": [ - [0, 0, 0, "Styles should be written using objects.", "0"], - [0, 0, 0, "Styles should be written using objects.", "1"], - [0, 0, 0, "Styles should be written using objects.", "2"] - ], - "public/app/plugins/datasource/prometheus/querybuilder/components/metrics-modal/ResultsTable.tsx:5381": [ - [0, 0, 0, "Styles should be written using objects.", "0"], - [0, 0, 0, "Styles should be written using objects.", "1"], - [0, 0, 0, "Styles should be written using objects.", "2"], - [0, 0, 0, "Styles should be written using objects.", "3"], - [0, 0, 0, "Styles should be written using objects.", "4"], - [0, 0, 0, "Styles should be written using objects.", "5"], - [0, 0, 0, "Styles should be written using objects.", "6"], - [0, 0, 0, "Styles should be written using objects.", "7"], - [0, 0, 0, "Styles should be written using objects.", "8"], - [0, 0, 0, "Styles should be written using objects.", "9"], - [0, 0, 0, "Styles should be written using objects.", "10"], - [0, 0, 0, "Styles should be written using objects.", "11"], - [0, 0, 0, "Styles should be written using objects.", "12"] - ], - "public/app/plugins/datasource/prometheus/querybuilder/components/metrics-modal/styles.ts:5381": [ - [0, 0, 0, "Styles should be written using objects.", "0"], - [0, 0, 0, "Styles should be written using objects.", "1"], - [0, 0, 0, "Styles should be written using objects.", "2"], - [0, 0, 0, "Styles should be written using objects.", "3"], - [0, 0, 0, "Styles should be written using objects.", "4"], - [0, 0, 0, "Styles should be written using objects.", "5"], - [0, 0, 0, "Styles should be written using objects.", "6"], - [0, 0, 0, "Styles should be written using objects.", "7"], - [0, 0, 0, "Styles should be written using objects.", "8"], - [0, 0, 0, "Styles should be written using objects.", "9"], - [0, 0, 0, "Styles should be written using objects.", "10"], - [0, 0, 0, "Styles should be written using objects.", "11"], - [0, 0, 0, "Styles should be written using objects.", "12"], - [0, 0, 0, "Styles should be written using objects.", "13"], - [0, 0, 0, "Styles should be written using objects.", "14"], - [0, 0, 0, "Styles should be written using objects.", "15"], - [0, 0, 0, "Styles should be written using objects.", "16"], - [0, 0, 0, "Styles should be written using objects.", "17"], - [0, 0, 0, "Styles should be written using objects.", "18"] - ], - "public/app/plugins/datasource/prometheus/querybuilder/shared/LabelFilterItem.tsx:5381": [ - [0, 0, 0, "Do not use any type assertions.", "0"], - [0, 0, 0, "Do not use any type assertions.", "1"], - [0, 0, 0, "Do not use any type assertions.", "2"], - [0, 0, 0, "Do not use any type assertions.", "3"], - [0, 0, 0, "Do not use any type assertions.", "4"], - [0, 0, 0, "Do not use any type assertions.", "5"], - [0, 0, 0, "Unexpected any. Specify a different type.", "6"], - [0, 0, 0, "Do not use any type assertions.", "7"], - [0, 0, 0, "Do not use any type assertions.", "8"] - ], - "public/app/plugins/datasource/prometheus/querybuilder/shared/LabelFilters.tsx:5381": [ - [0, 0, 0, "Do not use any type assertions.", "0"] - ], - "public/app/plugins/datasource/prometheus/querybuilder/shared/OperationEditor.tsx:5381": [ - [0, 0, 0, "Unexpected any. Specify a different type.", "0"] - ], - "public/app/plugins/datasource/prometheus/querybuilder/shared/OperationParamEditor.tsx:5381": [ - [0, 0, 0, "Do not use any type assertions.", "0"], - [0, 0, 0, "Do not use any type assertions.", "1"] - ], - "public/app/plugins/datasource/prometheus/querybuilder/shared/QueryBuilderHints.tsx:5381": [ - [0, 0, 0, "Styles should be written using objects.", "0"], - [0, 0, 0, "Styles should be written using objects.", "1"] - ], - "public/app/plugins/datasource/prometheus/querybuilder/shared/types.ts:5381": [ - [0, 0, 0, "Unexpected any. Specify a different type.", "0"], - [0, 0, 0, "Unexpected any. Specify a different type.", "1"], - [0, 0, 0, "Unexpected any. Specify a different type.", "2"] - ], - "public/app/plugins/datasource/prometheus/types.ts:5381": [ - [0, 0, 0, "Unexpected any. Specify a different type.", "0"], - [0, 0, 0, "Unexpected any. Specify a different type.", "1"], - [0, 0, 0, "Unexpected any. Specify a different type.", "2"] - ], "public/app/plugins/datasource/tempo/QueryField.tsx:5381": [ [0, 0, 0, "\'HorizontalGroup\' import from \'@grafana/ui\' is restricted from being used by a pattern. Use Stack component instead.", "0"] ], @@ -7163,25 +6970,6 @@ exports[`no gf-form usage`] = { [0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"], [0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"] ], - "public/app/plugins/datasource/prometheus/components/PromExploreExtraField.tsx:5381": [ - [0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"], - [0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"], - [0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"], - [0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"] - ], - "public/app/plugins/datasource/prometheus/components/PromQueryField.tsx:5381": [ - [0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"], - [0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"], - [0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"], - [0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"], - [0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"], - [0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"] - ], - "public/app/plugins/datasource/prometheus/configuration/AlertingSettingsOverhaul.tsx:5381": [ - [0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"], - [0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"], - [0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"] - ], "public/app/plugins/datasource/prometheus/configuration/AzureAuthSettings.tsx:5381": [ [0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"] ], @@ -7208,41 +6996,6 @@ exports[`no gf-form usage`] = { [0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"], [0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"] ], - "public/app/plugins/datasource/prometheus/configuration/ExemplarSetting.tsx:5381": [ - [0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"] - ], - "public/app/plugins/datasource/prometheus/configuration/PromSettings.tsx:5381": [ - [0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"], - [0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"], - [0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"], - [0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"], - [0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"], - [0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"], - [0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"], - [0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"], - [0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"], - [0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"], - [0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"], - [0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"], - [0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"], - [0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"], - [0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"], - [0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"], - [0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"], - [0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"], - [0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"], - [0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"], - [0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"], - [0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"], - [0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"], - [0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"], - [0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"], - [0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"], - [0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"] - ], - "public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryCodeEditor.tsx:5381": [ - [0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"] - ], "public/app/plugins/datasource/tempo/_importedDependencies/components/AdHocFilter/AdHocFilter.tsx:5381": [ [0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"] ], 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 0d755b205e1..c17980df319 100644 --- a/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md +++ b/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md @@ -59,7 +59,6 @@ Some features are enabled by default. You can disable these feature by setting t | `lokiQueryHints` | Enables query hints for Loki | Yes | | `alertingQueryOptimization` | Optimizes eligible queries in order to reduce load on datasources | | | `betterPageScrolling` | Removes CustomScrollbar from the UI, relying on native browser scrollbars | Yes | -| `usePrometheusFrontendPackage` | Use the @grafana/prometheus frontend package in core Prometheus. | | | `cloudWatchNewLabelParsing` | Updates CloudWatch label parsing to be more accurate | Yes | ## Preview feature toggles diff --git a/e2e/various-suite/query-editor.spec.ts b/e2e/various-suite/query-editor.spec.ts index 3441f2b4c0d..4a4b8b249c5 100644 --- a/e2e/various-suite/query-editor.spec.ts +++ b/e2e/various-suite/query-editor.spec.ts @@ -13,7 +13,7 @@ describe('Query editor', () => { cy.contains('gdev-prometheus').scrollIntoView().should('be.visible').click(); const queryText = `rate(http_requests_total{job="grafana"}[5m])`; - e2e.components.RadioButton.container().filter(':contains("Code")').click(); + e2e.components.RadioButton.container().filter(':contains("Code")').should('be.visible').click(); waitForMonacoToLoad(); diff --git a/packages/grafana-data/src/types/featureToggles.gen.ts b/packages/grafana-data/src/types/featureToggles.gen.ts index a751590217f..a070155a704 100644 --- a/packages/grafana-data/src/types/featureToggles.gen.ts +++ b/packages/grafana-data/src/types/featureToggles.gen.ts @@ -174,7 +174,6 @@ export interface FeatureToggles { authAPIAccessTokenAuth?: boolean; scopeFilters?: boolean; ssoSettingsSAML?: boolean; - usePrometheusFrontendPackage?: boolean; oauthRequireSubClaim?: boolean; newDashboardWithFiltersAndGroupBy?: boolean; cloudWatchNewLabelParsing?: boolean; diff --git a/packages/grafana-prometheus/src/add_label_to_query.test.ts b/packages/grafana-prometheus/src/add_label_to_query.test.ts index 08c32e3c398..0936da9f726 100644 --- a/packages/grafana-prometheus/src/add_label_to_query.test.ts +++ b/packages/grafana-prometheus/src/add_label_to_query.test.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/add_label_to_query.test.ts import { addLabelToQuery } from './add_label_to_query'; describe('addLabelToQuery()', () => { diff --git a/packages/grafana-prometheus/src/add_label_to_query.ts b/packages/grafana-prometheus/src/add_label_to_query.ts index 696e0cbb8dc..690a5c3aaff 100644 --- a/packages/grafana-prometheus/src/add_label_to_query.ts +++ b/packages/grafana-prometheus/src/add_label_to_query.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/add_label_to_query.ts import { parser, VectorSelector } from '@prometheus-io/lezer-promql'; import { PromQueryModeller } from './querybuilder/PromQueryModeller'; diff --git a/packages/grafana-prometheus/src/components/AnnotationQueryEditor.tsx b/packages/grafana-prometheus/src/components/AnnotationQueryEditor.tsx index 0cbaf5978cd..2c22905e99e 100644 --- a/packages/grafana-prometheus/src/components/AnnotationQueryEditor.tsx +++ b/packages/grafana-prometheus/src/components/AnnotationQueryEditor.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/components/AnnotationQueryEditor.tsx import React from 'react'; import { AnnotationQuery } from '@grafana/data'; diff --git a/packages/grafana-prometheus/src/components/PromCheatSheet.tsx b/packages/grafana-prometheus/src/components/PromCheatSheet.tsx index 347d6547301..7eaee0b0782 100644 --- a/packages/grafana-prometheus/src/components/PromCheatSheet.tsx +++ b/packages/grafana-prometheus/src/components/PromCheatSheet.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/components/PromCheatSheet.tsx import React from 'react'; import { QueryEditorHelpProps } from '@grafana/data'; diff --git a/packages/grafana-prometheus/src/components/PromExemplarField.tsx b/packages/grafana-prometheus/src/components/PromExemplarField.tsx index e09a6260c98..8b300687dad 100644 --- a/packages/grafana-prometheus/src/components/PromExemplarField.tsx +++ b/packages/grafana-prometheus/src/components/PromExemplarField.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/components/PromExemplarField.tsx import { css, cx } from '@emotion/css'; import React, { useEffect, useState } from 'react'; import { usePrevious } from 'react-use'; diff --git a/packages/grafana-prometheus/src/components/PromExploreExtraField.test.tsx b/packages/grafana-prometheus/src/components/PromExploreExtraField.test.tsx index 4c22e2f16f2..75cc778f7f0 100644 --- a/packages/grafana-prometheus/src/components/PromExploreExtraField.test.tsx +++ b/packages/grafana-prometheus/src/components/PromExploreExtraField.test.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/components/PromExploreExtraField.test.tsx import { render, screen } from '@testing-library/react'; import React from 'react'; diff --git a/packages/grafana-prometheus/src/components/PromExploreExtraField.tsx b/packages/grafana-prometheus/src/components/PromExploreExtraField.tsx index c9ad0a79e36..0d3fa86a1b4 100644 --- a/packages/grafana-prometheus/src/components/PromExploreExtraField.tsx +++ b/packages/grafana-prometheus/src/components/PromExploreExtraField.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/components/PromExploreExtraField.tsx import { css, cx } from '@emotion/css'; import { isEqual } from 'lodash'; import React, { memo, useCallback } from 'react'; diff --git a/packages/grafana-prometheus/src/components/PromQueryEditorByApp.test.tsx b/packages/grafana-prometheus/src/components/PromQueryEditorByApp.test.tsx index 832cc37355f..6909409f810 100644 --- a/packages/grafana-prometheus/src/components/PromQueryEditorByApp.test.tsx +++ b/packages/grafana-prometheus/src/components/PromQueryEditorByApp.test.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/components/PromQueryEditorByApp.test.tsx import { render, screen } from '@testing-library/react'; import { noop } from 'lodash'; import React from 'react'; diff --git a/packages/grafana-prometheus/src/components/PromQueryEditorByApp.tsx b/packages/grafana-prometheus/src/components/PromQueryEditorByApp.tsx index 843bb30284a..82b095322bf 100644 --- a/packages/grafana-prometheus/src/components/PromQueryEditorByApp.tsx +++ b/packages/grafana-prometheus/src/components/PromQueryEditorByApp.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/components/PromQueryEditorByApp.tsx import React, { memo } from 'react'; import { CoreApp } from '@grafana/data'; diff --git a/packages/grafana-prometheus/src/components/PromQueryEditorForAlerting.tsx b/packages/grafana-prometheus/src/components/PromQueryEditorForAlerting.tsx index 5adac3afeb5..5f5f2da7bfc 100644 --- a/packages/grafana-prometheus/src/components/PromQueryEditorForAlerting.tsx +++ b/packages/grafana-prometheus/src/components/PromQueryEditorForAlerting.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/components/PromQueryEditorForAlerting.tsx import React from 'react'; import { PromQueryField } from './PromQueryField'; diff --git a/packages/grafana-prometheus/src/components/PromQueryField.test.tsx b/packages/grafana-prometheus/src/components/PromQueryField.test.tsx index 700f73574d5..46c56efc381 100644 --- a/packages/grafana-prometheus/src/components/PromQueryField.test.tsx +++ b/packages/grafana-prometheus/src/components/PromQueryField.test.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/components/PromQueryField.test.tsx import { getByTestId, render, screen, waitFor } from '@testing-library/react'; // @ts-ignore import userEvent from '@testing-library/user-event'; diff --git a/packages/grafana-prometheus/src/components/PromQueryField.tsx b/packages/grafana-prometheus/src/components/PromQueryField.tsx index 3ceab631609..623092b648c 100644 --- a/packages/grafana-prometheus/src/components/PromQueryField.tsx +++ b/packages/grafana-prometheus/src/components/PromQueryField.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/components/PromQueryField.tsx import { cx } from '@emotion/css'; import React, { ReactNode } from 'react'; diff --git a/packages/grafana-prometheus/src/components/PrometheusMetricsBrowser.test.tsx b/packages/grafana-prometheus/src/components/PrometheusMetricsBrowser.test.tsx index e3ba496356b..393a15b3d00 100644 --- a/packages/grafana-prometheus/src/components/PrometheusMetricsBrowser.test.tsx +++ b/packages/grafana-prometheus/src/components/PrometheusMetricsBrowser.test.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/components/PrometheusMetricsBrowser.test.tsx import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; diff --git a/packages/grafana-prometheus/src/components/PrometheusMetricsBrowser.tsx b/packages/grafana-prometheus/src/components/PrometheusMetricsBrowser.tsx index 79ae235574e..e58a57c9323 100644 --- a/packages/grafana-prometheus/src/components/PrometheusMetricsBrowser.tsx +++ b/packages/grafana-prometheus/src/components/PrometheusMetricsBrowser.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/components/PrometheusMetricsBrowser.tsx import { css, cx } from '@emotion/css'; import React, { ChangeEvent } from 'react'; import { FixedSizeList } from 'react-window'; diff --git a/packages/grafana-prometheus/src/components/VariableQueryEditor.test.tsx b/packages/grafana-prometheus/src/components/VariableQueryEditor.test.tsx index 0d3a877069d..427066e9c41 100644 --- a/packages/grafana-prometheus/src/components/VariableQueryEditor.test.tsx +++ b/packages/grafana-prometheus/src/components/VariableQueryEditor.test.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/components/VariableQueryEditor.test.tsx import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; diff --git a/packages/grafana-prometheus/src/components/VariableQueryEditor.tsx b/packages/grafana-prometheus/src/components/VariableQueryEditor.tsx index fce9bf1e1df..cd81e5fc6c8 100644 --- a/packages/grafana-prometheus/src/components/VariableQueryEditor.tsx +++ b/packages/grafana-prometheus/src/components/VariableQueryEditor.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/components/VariableQueryEditor.tsx import React, { FormEvent, useCallback, useEffect, useState } from 'react'; import { QueryEditorProps, SelectableValue } from '@grafana/data'; diff --git a/packages/grafana-prometheus/src/components/monaco-query-field/MonacoQueryField.tsx b/packages/grafana-prometheus/src/components/monaco-query-field/MonacoQueryField.tsx index 2e5dbb1f52e..9b554db003b 100644 --- a/packages/grafana-prometheus/src/components/monaco-query-field/MonacoQueryField.tsx +++ b/packages/grafana-prometheus/src/components/monaco-query-field/MonacoQueryField.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/components/monaco-query-field/MonacoQueryField.tsx import { css } from '@emotion/css'; import { parser } from '@prometheus-io/lezer-promql'; import { debounce } from 'lodash'; diff --git a/packages/grafana-prometheus/src/components/monaco-query-field/MonacoQueryFieldLazy.tsx b/packages/grafana-prometheus/src/components/monaco-query-field/MonacoQueryFieldLazy.tsx index 797d48b6c2b..ea2fb3576e9 100644 --- a/packages/grafana-prometheus/src/components/monaco-query-field/MonacoQueryFieldLazy.tsx +++ b/packages/grafana-prometheus/src/components/monaco-query-field/MonacoQueryFieldLazy.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/components/monaco-query-field/MonacoQueryFieldLazy.tsx import React, { Suspense } from 'react'; import MonacoQueryField from './MonacoQueryField'; diff --git a/packages/grafana-prometheus/src/components/monaco-query-field/MonacoQueryFieldProps.ts b/packages/grafana-prometheus/src/components/monaco-query-field/MonacoQueryFieldProps.ts index 1383b565828..a0d21761f2c 100644 --- a/packages/grafana-prometheus/src/components/monaco-query-field/MonacoQueryFieldProps.ts +++ b/packages/grafana-prometheus/src/components/monaco-query-field/MonacoQueryFieldProps.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/components/monaco-query-field/MonacoQueryFieldProps.ts import { HistoryItem } from '@grafana/data'; import { PrometheusDatasource } from '../../datasource'; diff --git a/packages/grafana-prometheus/src/components/monaco-query-field/MonacoQueryFieldWrapper.tsx b/packages/grafana-prometheus/src/components/monaco-query-field/MonacoQueryFieldWrapper.tsx index 7f69ce54758..2fafe41a1cc 100644 --- a/packages/grafana-prometheus/src/components/monaco-query-field/MonacoQueryFieldWrapper.tsx +++ b/packages/grafana-prometheus/src/components/monaco-query-field/MonacoQueryFieldWrapper.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/components/monaco-query-field/MonacoQueryFieldWrapper.tsx import React, { useRef } from 'react'; import { MonacoQueryFieldLazy } from './MonacoQueryFieldLazy'; diff --git a/packages/grafana-prometheus/src/components/monaco-query-field/getOverrideServices.ts b/packages/grafana-prometheus/src/components/monaco-query-field/getOverrideServices.ts index b3bc45a3f57..c7a3192ddb6 100644 --- a/packages/grafana-prometheus/src/components/monaco-query-field/getOverrideServices.ts +++ b/packages/grafana-prometheus/src/components/monaco-query-field/getOverrideServices.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/components/monaco-query-field/getOverrideServices.ts import { monacoTypes } from '@grafana/ui'; // this thing here is a workaround in a way. diff --git a/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/completions.ts b/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/completions.ts index a092beac588..d93338c5ea5 100644 --- a/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/completions.ts +++ b/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/completions.ts @@ -1,3 +1,4 @@ +// Core grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/components/monaco-query-field/monaco-completion-provider/completions.ts import UFuzzy from '@leeoniya/ufuzzy'; import { config } from '@grafana/runtime'; diff --git a/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/index.ts b/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/index.ts index 6c1037df321..abc97de27ce 100644 --- a/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/index.ts +++ b/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/index.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/components/monaco-query-field/monaco-completion-provider/index.ts import type { Monaco, monacoTypes } from '@grafana/ui'; import { CompletionType, getCompletions } from './completions'; diff --git a/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/situation.test.ts b/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/situation.test.ts index 8c7be6b592b..605d9658174 100644 --- a/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/situation.test.ts +++ b/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/situation.test.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/components/monaco-query-field/monaco-completion-provider/situation.test.ts import { getSituation, Situation } from './situation'; // we use the `^` character as the cursor-marker in the string. diff --git a/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/situation.ts b/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/situation.ts index e6f569fe806..f633922d298 100644 --- a/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/situation.ts +++ b/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/situation.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/components/monaco-query-field/monaco-completion-provider/situation.ts import type { SyntaxNode, Tree } from '@lezer/common'; import { AggregateExpr, diff --git a/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/util.ts b/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/util.ts index 35babca0d09..84ee27c8e94 100644 --- a/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/util.ts +++ b/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/util.ts @@ -1,3 +1,5 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/components/monaco-query-field/monaco-completion-provider/util.ts + // this helper class is used to make typescript warn you when you forget // a case-block in a switch statement. // example code that triggers the typescript-error: diff --git a/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/validation.test.ts b/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/validation.test.ts index c51c764e8fa..e467257e23d 100644 --- a/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/validation.test.ts +++ b/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/validation.test.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/components/monaco-query-field/monaco-completion-provider/validation.test.ts import { parser } from '@prometheus-io/lezer-promql'; import { validateQuery } from './validation'; diff --git a/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/validation.ts b/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/validation.ts index 8b9cb8e6766..34ce38c060b 100644 --- a/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/validation.ts +++ b/packages/grafana-prometheus/src/components/monaco-query-field/monaco-completion-provider/validation.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/loki/components/monaco-query-field/monaco-completion-provider/validation.ts import { SyntaxNode } from '@lezer/common'; import { LRParser } from '@lezer/lr'; diff --git a/packages/grafana-prometheus/src/components/types.ts b/packages/grafana-prometheus/src/components/types.ts index 419b86ea5bd..4f453b0a947 100644 --- a/packages/grafana-prometheus/src/components/types.ts +++ b/packages/grafana-prometheus/src/components/types.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/components/types.ts import { QueryEditorProps } from '@grafana/data'; import { PrometheusDatasource } from '../datasource'; diff --git a/packages/grafana-prometheus/src/configuration/AlertingSettingsOverhaul.tsx b/packages/grafana-prometheus/src/configuration/AlertingSettingsOverhaul.tsx index 11bbe3d2361..4cd5a13b85a 100644 --- a/packages/grafana-prometheus/src/configuration/AlertingSettingsOverhaul.tsx +++ b/packages/grafana-prometheus/src/configuration/AlertingSettingsOverhaul.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/configuration/AlertingSettingsOverhaul.tsx import { cx } from '@emotion/css'; import React from 'react'; diff --git a/packages/grafana-prometheus/src/configuration/ConfigEditor.test.tsx b/packages/grafana-prometheus/src/configuration/ConfigEditor.test.tsx index 9ce9e66c563..12878c69435 100644 --- a/packages/grafana-prometheus/src/configuration/ConfigEditor.test.tsx +++ b/packages/grafana-prometheus/src/configuration/ConfigEditor.test.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/configuration/ConfigEditor.test.tsx import React from 'react'; import { FieldValidationMessage } from '@grafana/ui'; diff --git a/packages/grafana-prometheus/src/configuration/ConfigEditor.tsx b/packages/grafana-prometheus/src/configuration/ConfigEditor.tsx index 86a6f687253..28355af85be 100644 --- a/packages/grafana-prometheus/src/configuration/ConfigEditor.tsx +++ b/packages/grafana-prometheus/src/configuration/ConfigEditor.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/configuration/ConfigEditor.tsx import { css } from '@emotion/css'; import React from 'react'; diff --git a/packages/grafana-prometheus/src/configuration/DataSourceHttpSettingsOverhaul.tsx b/packages/grafana-prometheus/src/configuration/DataSourceHttpSettingsOverhaul.tsx index 86af4461740..035e513c6a3 100644 --- a/packages/grafana-prometheus/src/configuration/DataSourceHttpSettingsOverhaul.tsx +++ b/packages/grafana-prometheus/src/configuration/DataSourceHttpSettingsOverhaul.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/configuration/DataSourceHttpSettingsOverhaul.tsx import React from 'react'; import { DataSourceSettings } from '@grafana/data'; diff --git a/packages/grafana-prometheus/src/configuration/ExemplarSetting.tsx b/packages/grafana-prometheus/src/configuration/ExemplarSetting.tsx index 75614934cf5..acb9c35cbe6 100644 --- a/packages/grafana-prometheus/src/configuration/ExemplarSetting.tsx +++ b/packages/grafana-prometheus/src/configuration/ExemplarSetting.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/configuration/ExemplarSetting.tsx import React, { useState } from 'react'; import { DataSourceInstanceSettings } from '@grafana/data'; diff --git a/packages/grafana-prometheus/src/configuration/ExemplarsSettings.tsx b/packages/grafana-prometheus/src/configuration/ExemplarsSettings.tsx index 6ffece606a0..24ad9a5d1ad 100644 --- a/packages/grafana-prometheus/src/configuration/ExemplarsSettings.tsx +++ b/packages/grafana-prometheus/src/configuration/ExemplarsSettings.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/configuration/ExemplarsSettings.tsx import { css } from '@emotion/css'; import React from 'react'; diff --git a/packages/grafana-prometheus/src/configuration/PromFlavorVersions.ts b/packages/grafana-prometheus/src/configuration/PromFlavorVersions.ts index bce2dd88a87..71381bd73c0 100644 --- a/packages/grafana-prometheus/src/configuration/PromFlavorVersions.ts +++ b/packages/grafana-prometheus/src/configuration/PromFlavorVersions.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/configuration/PromFlavorVersions.ts export const PromFlavorVersions: { [index: string]: Array<{ value?: string; label: string }> } = { Prometheus: [ { value: undefined, label: 'Please select' }, diff --git a/packages/grafana-prometheus/src/configuration/PromSettings.test.tsx b/packages/grafana-prometheus/src/configuration/PromSettings.test.tsx index af9b99bd4da..2deae5f94dd 100644 --- a/packages/grafana-prometheus/src/configuration/PromSettings.test.tsx +++ b/packages/grafana-prometheus/src/configuration/PromSettings.test.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/configuration/PromSettings.test.tsx import { render, screen, fireEvent } from '@testing-library/react'; import React, { SyntheticEvent } from 'react'; diff --git a/packages/grafana-prometheus/src/configuration/PromSettings.tsx b/packages/grafana-prometheus/src/configuration/PromSettings.tsx index d9a0b7abc64..5e41aaac5e9 100644 --- a/packages/grafana-prometheus/src/configuration/PromSettings.tsx +++ b/packages/grafana-prometheus/src/configuration/PromSettings.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/configuration/PromSettings.tsx import React, { SyntheticEvent, useState } from 'react'; import { diff --git a/packages/grafana-prometheus/src/configuration/mocks.ts b/packages/grafana-prometheus/src/configuration/mocks.ts index dc52090298b..3c1d7e29762 100644 --- a/packages/grafana-prometheus/src/configuration/mocks.ts +++ b/packages/grafana-prometheus/src/configuration/mocks.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/configuration/mocks.ts import { DataSourceSettings } from '@grafana/data'; import { getMockDataSource } from '../gcopypaste/app/features/datasources/__mocks__/dataSourcesMocks'; diff --git a/packages/grafana-prometheus/src/dashboards/grafana_stats.json b/packages/grafana-prometheus/src/dashboards/grafana_stats.json index a121de7fe5a..0131aa9bc40 100644 --- a/packages/grafana-prometheus/src/dashboards/grafana_stats.json +++ b/packages/grafana-prometheus/src/dashboards/grafana_stats.json @@ -1,4 +1,5 @@ { + "_comment": "Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/dashboards/grafana_stats.json", "__inputs": [ { "name": "DS_PROMETHEUS", diff --git a/packages/grafana-prometheus/src/dashboards/prometheus_2_stats.json b/packages/grafana-prometheus/src/dashboards/prometheus_2_stats.json index 3d4cea64f05..034663fe6f4 100644 --- a/packages/grafana-prometheus/src/dashboards/prometheus_2_stats.json +++ b/packages/grafana-prometheus/src/dashboards/prometheus_2_stats.json @@ -1,4 +1,5 @@ { + "_comment": "Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/dashboards/prometheus_2_stats.json", "__inputs": [ { "name": "DS_GDEV-PROMETHEUS", diff --git a/packages/grafana-prometheus/src/dashboards/prometheus_stats.json b/packages/grafana-prometheus/src/dashboards/prometheus_stats.json index 9169006b895..8a2764c5cb7 100644 --- a/packages/grafana-prometheus/src/dashboards/prometheus_stats.json +++ b/packages/grafana-prometheus/src/dashboards/prometheus_stats.json @@ -1,4 +1,5 @@ { + "_comment": "Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/dashboards/prometheus_stats.json", "__inputs": [ { "name": "DS_GDEV-PROMETHEUS", diff --git a/packages/grafana-prometheus/src/dataquery.ts b/packages/grafana-prometheus/src/dataquery.ts index 999a969c99e..6601b7ac8ab 100644 --- a/packages/grafana-prometheus/src/dataquery.ts +++ b/packages/grafana-prometheus/src/dataquery.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/dataquery.ts import { ScopeSpec } from '@grafana/data'; import * as common from '@grafana/schema'; diff --git a/packages/grafana-prometheus/src/datasource.test.ts b/packages/grafana-prometheus/src/datasource.test.ts index 72f9c4572d8..a8ae4298ef1 100644 --- a/packages/grafana-prometheus/src/datasource.test.ts +++ b/packages/grafana-prometheus/src/datasource.test.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/datasource.test.ts import { cloneDeep } from 'lodash'; import { lastValueFrom, of } from 'rxjs'; diff --git a/packages/grafana-prometheus/src/datasource.ts b/packages/grafana-prometheus/src/datasource.ts index b809452bede..ea36501aea5 100644 --- a/packages/grafana-prometheus/src/datasource.ts +++ b/packages/grafana-prometheus/src/datasource.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/datasource.ts import { defaults } from 'lodash'; import { lastValueFrom, Observable, throwError } from 'rxjs'; import { map, tap } from 'rxjs/operators'; diff --git a/packages/grafana-prometheus/src/gcopypaste/app/core/components/LocalStorageValueProvider/LocalStorageValueProvider.tsx b/packages/grafana-prometheus/src/gcopypaste/app/core/components/LocalStorageValueProvider/LocalStorageValueProvider.tsx index d0558fe43ee..c71e11ec749 100644 --- a/packages/grafana-prometheus/src/gcopypaste/app/core/components/LocalStorageValueProvider/LocalStorageValueProvider.tsx +++ b/packages/grafana-prometheus/src/gcopypaste/app/core/components/LocalStorageValueProvider/LocalStorageValueProvider.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/core/components/LocalStorageValueProvider/LocalStorageValueProvider.tsx import React, { useEffect, useState } from 'react'; import store from '../../store'; diff --git a/packages/grafana-prometheus/src/gcopypaste/app/core/components/LocalStorageValueProvider/index.tsx b/packages/grafana-prometheus/src/gcopypaste/app/core/components/LocalStorageValueProvider/index.tsx index e4bde7ccaea..e3df7a01194 100644 --- a/packages/grafana-prometheus/src/gcopypaste/app/core/components/LocalStorageValueProvider/index.tsx +++ b/packages/grafana-prometheus/src/gcopypaste/app/core/components/LocalStorageValueProvider/index.tsx @@ -1 +1,2 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/core/components/LocalStorageValueProvider/index.tsx export { LocalStorageValueProvider } from './LocalStorageValueProvider'; diff --git a/packages/grafana-prometheus/src/gcopypaste/app/core/store.ts b/packages/grafana-prometheus/src/gcopypaste/app/core/store.ts index 28587a7d428..a23d14c93cc 100644 --- a/packages/grafana-prometheus/src/gcopypaste/app/core/store.ts +++ b/packages/grafana-prometheus/src/gcopypaste/app/core/store.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/core/store.ts type StoreValue = string | number | boolean | null; export class Store { diff --git a/packages/grafana-prometheus/src/gcopypaste/app/core/utils/CancelablePromise.ts b/packages/grafana-prometheus/src/gcopypaste/app/core/utils/CancelablePromise.ts index 221e5ef2bb6..0256922cbbb 100644 --- a/packages/grafana-prometheus/src/gcopypaste/app/core/utils/CancelablePromise.ts +++ b/packages/grafana-prometheus/src/gcopypaste/app/core/utils/CancelablePromise.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/core/utils/CancelablePromise.ts // https://github.com/facebook/react/issues/5465 export interface CancelablePromise { diff --git a/packages/grafana-prometheus/src/gcopypaste/app/core/utils/query.ts b/packages/grafana-prometheus/src/gcopypaste/app/core/utils/query.ts index 4084e418f18..28b4af48c0b 100644 --- a/packages/grafana-prometheus/src/gcopypaste/app/core/utils/query.ts +++ b/packages/grafana-prometheus/src/gcopypaste/app/core/utils/query.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/core/utils/query.ts import { DataQuery } from '@grafana/data'; export const getNextRefIdChar = (queries: DataQuery[]): string => { diff --git a/packages/grafana-prometheus/src/gcopypaste/app/features/datasources/__mocks__/dataSourcesMocks.ts b/packages/grafana-prometheus/src/gcopypaste/app/features/datasources/__mocks__/dataSourcesMocks.ts index db78a03b289..15ebe4229a9 100644 --- a/packages/grafana-prometheus/src/gcopypaste/app/features/datasources/__mocks__/dataSourcesMocks.ts +++ b/packages/grafana-prometheus/src/gcopypaste/app/features/datasources/__mocks__/dataSourcesMocks.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/features/datasources/__mocks__/dataSourcesMocks.ts import { merge } from 'lodash'; import { DataSourceJsonData, DataSourceSettings } from '@grafana/data'; diff --git a/packages/grafana-prometheus/src/gcopypaste/app/features/live/data/amendTimeSeries.ts b/packages/grafana-prometheus/src/gcopypaste/app/features/live/data/amendTimeSeries.ts index 39b01600d46..a2d00ad34f4 100644 --- a/packages/grafana-prometheus/src/gcopypaste/app/features/live/data/amendTimeSeries.ts +++ b/packages/grafana-prometheus/src/gcopypaste/app/features/live/data/amendTimeSeries.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/features/live/data/amendTimeSeries.ts import { closestIdx } from '@grafana/data'; export type Table = [times: number[], ...values: any[][]]; diff --git a/packages/grafana-prometheus/src/gcopypaste/packages/grafana-ui/src/components/Select/SelectBase.tsx b/packages/grafana-prometheus/src/gcopypaste/packages/grafana-ui/src/components/Select/SelectBase.tsx index 9c6e81eec9f..f252ee11767 100644 --- a/packages/grafana-prometheus/src/gcopypaste/packages/grafana-ui/src/components/Select/SelectBase.tsx +++ b/packages/grafana-prometheus/src/gcopypaste/packages/grafana-ui/src/components/Select/SelectBase.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/packages/grafana-ui/src/components/Select/SelectBase.tsx import { cx } from '@emotion/css'; import { max } from 'lodash'; import React, { RefCallback } from 'react'; diff --git a/packages/grafana-prometheus/src/gcopypaste/public/test/matchers/index.ts b/packages/grafana-prometheus/src/gcopypaste/public/test/matchers/index.ts index b6f8a091aaa..ea1578a7482 100644 --- a/packages/grafana-prometheus/src/gcopypaste/public/test/matchers/index.ts +++ b/packages/grafana-prometheus/src/gcopypaste/public/test/matchers/index.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/test/matchers/index.ts import { Observable } from 'rxjs'; import { toEmitValues } from './toEmitValues'; diff --git a/packages/grafana-prometheus/src/gcopypaste/public/test/matchers/toEmitValues.test.ts b/packages/grafana-prometheus/src/gcopypaste/public/test/matchers/toEmitValues.test.ts index 71edff27e8d..bb0d9aa3c63 100644 --- a/packages/grafana-prometheus/src/gcopypaste/public/test/matchers/toEmitValues.test.ts +++ b/packages/grafana-prometheus/src/gcopypaste/public/test/matchers/toEmitValues.test.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/test/matchers/toEmitValues.test.ts import { interval, Observable, of, throwError } from 'rxjs'; import { map, mergeMap, take } from 'rxjs/operators'; diff --git a/packages/grafana-prometheus/src/gcopypaste/public/test/matchers/toEmitValues.ts b/packages/grafana-prometheus/src/gcopypaste/public/test/matchers/toEmitValues.ts index d2987471a38..5d87c1f342d 100644 --- a/packages/grafana-prometheus/src/gcopypaste/public/test/matchers/toEmitValues.ts +++ b/packages/grafana-prometheus/src/gcopypaste/public/test/matchers/toEmitValues.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/test/matchers/toEmitValues.ts import { matcherHint, printExpected, printReceived } from 'jest-matcher-utils'; import { isEqual } from 'lodash'; import { Observable, Subscription } from 'rxjs'; diff --git a/packages/grafana-prometheus/src/gcopypaste/public/test/matchers/toEmitValuesWith.test.ts b/packages/grafana-prometheus/src/gcopypaste/public/test/matchers/toEmitValuesWith.test.ts index 7ca3eed1c57..352c8237665 100644 --- a/packages/grafana-prometheus/src/gcopypaste/public/test/matchers/toEmitValuesWith.test.ts +++ b/packages/grafana-prometheus/src/gcopypaste/public/test/matchers/toEmitValuesWith.test.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/test/matchers/toEmitValuesWith.test.ts import { interval, Observable, of, throwError } from 'rxjs'; import { map, mergeMap, take } from 'rxjs/operators'; diff --git a/packages/grafana-prometheus/src/gcopypaste/public/test/matchers/toEmitValuesWith.ts b/packages/grafana-prometheus/src/gcopypaste/public/test/matchers/toEmitValuesWith.ts index d9a53e965a0..2c647baea5b 100644 --- a/packages/grafana-prometheus/src/gcopypaste/public/test/matchers/toEmitValuesWith.ts +++ b/packages/grafana-prometheus/src/gcopypaste/public/test/matchers/toEmitValuesWith.ts @@ -1,3 +1,4 @@ +// Core Grafana history import { matcherHint, printReceived } from 'jest-matcher-utils'; import { Observable, Subscription } from 'rxjs'; diff --git a/packages/grafana-prometheus/src/gcopypaste/public/test/matchers/types.ts b/packages/grafana-prometheus/src/gcopypaste/public/test/matchers/types.ts index c67b32897f5..953b5ff86da 100644 --- a/packages/grafana-prometheus/src/gcopypaste/public/test/matchers/types.ts +++ b/packages/grafana-prometheus/src/gcopypaste/public/test/matchers/types.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/test/matchers/toEmitValuesWith.ts import { Observable } from 'rxjs'; export const OBSERVABLE_TEST_TIMEOUT_IN_MS = 1000; diff --git a/packages/grafana-prometheus/src/gcopypaste/public/test/matchers/utils.ts b/packages/grafana-prometheus/src/gcopypaste/public/test/matchers/utils.ts index e7758bb9177..3915cc13a4f 100644 --- a/packages/grafana-prometheus/src/gcopypaste/public/test/matchers/utils.ts +++ b/packages/grafana-prometheus/src/gcopypaste/public/test/matchers/utils.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/test/matchers/utils.ts import { matcherHint, printExpected, printReceived } from 'jest-matcher-utils'; import { asapScheduler, Subscription, timer, isObservable } from 'rxjs'; diff --git a/packages/grafana-prometheus/src/gcopypaste/test/helpers/selectOptionInTest.ts b/packages/grafana-prometheus/src/gcopypaste/test/helpers/selectOptionInTest.ts index c1ff432dacc..f8d333d2c2e 100644 --- a/packages/grafana-prometheus/src/gcopypaste/test/helpers/selectOptionInTest.ts +++ b/packages/grafana-prometheus/src/gcopypaste/test/helpers/selectOptionInTest.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/packages/grafana-ui/src/components/Select/SelectBase.tsx import { Matcher, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { select } from 'react-select-event'; diff --git a/packages/grafana-prometheus/src/index.ts b/packages/grafana-prometheus/src/index.ts index 76302ec9570..acf324f7e92 100644 --- a/packages/grafana-prometheus/src/index.ts +++ b/packages/grafana-prometheus/src/index.ts @@ -59,14 +59,14 @@ export { PromQail } from './querybuilder/components/promQail/PromQail'; // SRC/ // Main export -export { PrometheusDatasource } from './datasource'; +export { PrometheusDatasource, InstantQueryRefIdIndex } from './datasource'; // The parts export { addLabelToQuery } from './add_label_to_query'; export { type QueryEditorMode, type PromQueryFormat, type Prometheus } from './dataquery'; export { PrometheusMetricFindQuery } from './metric_find_query'; export { promqlGrammar } from './promql'; export { getQueryHints, getInitHints } from './query_hints'; -export { transformV2, transformDFToTable } from './result_transformer'; +export { transformV2, transformDFToTable, parseSampleValue, sortSeriesByLabel } from './result_transformer'; export { type PromQuery, type PrometheusCacheLevel, diff --git a/packages/grafana-prometheus/src/language_provider.mock.ts b/packages/grafana-prometheus/src/language_provider.mock.ts index 731a1977ca9..e10c2844b19 100644 --- a/packages/grafana-prometheus/src/language_provider.mock.ts +++ b/packages/grafana-prometheus/src/language_provider.mock.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/language_provider.mock.ts export class EmptyLanguageProviderMock { metrics = []; constructor() {} diff --git a/packages/grafana-prometheus/src/language_provider.test.ts b/packages/grafana-prometheus/src/language_provider.test.ts index 91576162dd1..dd7dec7ce71 100644 --- a/packages/grafana-prometheus/src/language_provider.test.ts +++ b/packages/grafana-prometheus/src/language_provider.test.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/language_provider.test.ts import { AbstractLabelOperator, dateTime, TimeRange } from '@grafana/data'; import { Label } from './components/monaco-query-field/monaco-completion-provider/situation'; diff --git a/packages/grafana-prometheus/src/language_provider.ts b/packages/grafana-prometheus/src/language_provider.ts index 7794c2d9339..e5c85a9316f 100644 --- a/packages/grafana-prometheus/src/language_provider.ts +++ b/packages/grafana-prometheus/src/language_provider.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/language_provider.ts import { once } from 'lodash'; import Prism from 'prismjs'; diff --git a/packages/grafana-prometheus/src/language_utils.test.ts b/packages/grafana-prometheus/src/language_utils.test.ts index fe6d1dd02c9..949e6489af1 100644 --- a/packages/grafana-prometheus/src/language_utils.test.ts +++ b/packages/grafana-prometheus/src/language_utils.test.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/language_utils.test.ts import { Moment } from 'moment'; import { AbstractLabelOperator, AbstractQuery, DateTime, dateTime, TimeRange } from '@grafana/data'; diff --git a/packages/grafana-prometheus/src/language_utils.ts b/packages/grafana-prometheus/src/language_utils.ts index eeb699f6739..ed96e929702 100644 --- a/packages/grafana-prometheus/src/language_utils.ts +++ b/packages/grafana-prometheus/src/language_utils.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/language_utils.ts import { invert } from 'lodash'; import { Token } from 'prismjs'; diff --git a/packages/grafana-prometheus/src/metric_find_query.test.ts b/packages/grafana-prometheus/src/metric_find_query.test.ts index a410189fc42..c21fd8f8353 100644 --- a/packages/grafana-prometheus/src/metric_find_query.test.ts +++ b/packages/grafana-prometheus/src/metric_find_query.test.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/metric_find_query.test.ts import { Observable, of } from 'rxjs'; import 'whatwg-fetch'; // fetch polyfill needed backendSrv diff --git a/packages/grafana-prometheus/src/metric_find_query.ts b/packages/grafana-prometheus/src/metric_find_query.ts index 9390f32373c..8be41c06364 100644 --- a/packages/grafana-prometheus/src/metric_find_query.ts +++ b/packages/grafana-prometheus/src/metric_find_query.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/metric_find_query.ts import { chain, map as _map, uniq } from 'lodash'; import { getDefaultTimeRange, MetricFindValue, TimeRange } from '@grafana/data'; diff --git a/packages/grafana-prometheus/src/migrations/variableMigration.ts b/packages/grafana-prometheus/src/migrations/variableMigration.ts index 302191f98fb..08476c2f4b6 100644 --- a/packages/grafana-prometheus/src/migrations/variableMigration.ts +++ b/packages/grafana-prometheus/src/migrations/variableMigration.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/migrations/variableMigration.ts import { promQueryModeller } from '../querybuilder/PromQueryModeller'; import { buildVisualQueryFromString } from '../querybuilder/parsing'; import { PromVariableQuery, PromVariableQueryType as QueryType } from '../types'; diff --git a/packages/grafana-prometheus/src/module.test.ts b/packages/grafana-prometheus/src/module.test.ts index 171fd491637..0fb7bb592a8 100644 --- a/packages/grafana-prometheus/src/module.test.ts +++ b/packages/grafana-prometheus/src/module.test.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/module.test.ts import { plugin as PrometheusDatasourcePlugin } from './module'; describe('module', () => { diff --git a/packages/grafana-prometheus/src/module.ts b/packages/grafana-prometheus/src/module.ts index 8fdb90c8bd9..0bbabf50383 100644 --- a/packages/grafana-prometheus/src/module.ts +++ b/packages/grafana-prometheus/src/module.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/module.ts // DONT NEED THIS BUT MAYBE EXPORT THIS TO CORE PROM import { DataSourcePlugin } from '@grafana/data'; diff --git a/packages/grafana-prometheus/src/promql.test.ts b/packages/grafana-prometheus/src/promql.test.ts index ff78a805ef2..8ce99e175fc 100644 --- a/packages/grafana-prometheus/src/promql.test.ts +++ b/packages/grafana-prometheus/src/promql.test.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/promql.test.ts import Prism from 'prismjs'; import promql from './promql'; diff --git a/packages/grafana-prometheus/src/promql.ts b/packages/grafana-prometheus/src/promql.ts index a9e89ee5f67..58893206b09 100644 --- a/packages/grafana-prometheus/src/promql.ts +++ b/packages/grafana-prometheus/src/promql.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/promql.ts import { Grammar } from 'prismjs'; import { CompletionItem } from '@grafana/ui'; diff --git a/packages/grafana-prometheus/src/query_hints.test.ts b/packages/grafana-prometheus/src/query_hints.test.ts index 7089ea3e2e1..aa425a22f28 100644 --- a/packages/grafana-prometheus/src/query_hints.test.ts +++ b/packages/grafana-prometheus/src/query_hints.test.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/query_hints.test.ts import { PrometheusDatasource } from './datasource'; import { getQueryHints, SUM_HINT_THRESHOLD_COUNT } from './query_hints'; diff --git a/packages/grafana-prometheus/src/query_hints.ts b/packages/grafana-prometheus/src/query_hints.ts index 12c8bdfbbaf..10ec829f364 100644 --- a/packages/grafana-prometheus/src/query_hints.ts +++ b/packages/grafana-prometheus/src/query_hints.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/query_hints.ts import { size } from 'lodash'; import { QueryFix, QueryHint } from '@grafana/data'; diff --git a/packages/grafana-prometheus/src/querybuilder/PromQueryModeller.test.ts b/packages/grafana-prometheus/src/querybuilder/PromQueryModeller.test.ts index f81ab15cbc9..432adeb59d4 100644 --- a/packages/grafana-prometheus/src/querybuilder/PromQueryModeller.test.ts +++ b/packages/grafana-prometheus/src/querybuilder/PromQueryModeller.test.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/PromQueryModeller.test.ts import { PromQueryModeller } from './PromQueryModeller'; import { PromOperationId } from './types'; diff --git a/packages/grafana-prometheus/src/querybuilder/PromQueryModeller.ts b/packages/grafana-prometheus/src/querybuilder/PromQueryModeller.ts index 894ba907ed1..cef7b53e6d6 100644 --- a/packages/grafana-prometheus/src/querybuilder/PromQueryModeller.ts +++ b/packages/grafana-prometheus/src/querybuilder/PromQueryModeller.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/PromQueryModeller.ts import { FUNCTIONS } from '../promql'; import { getAggregationOperations } from './aggregations'; diff --git a/packages/grafana-prometheus/src/querybuilder/QueryPattern.tsx b/packages/grafana-prometheus/src/querybuilder/QueryPattern.tsx index 083396cda39..a332a7f2da4 100644 --- a/packages/grafana-prometheus/src/querybuilder/QueryPattern.tsx +++ b/packages/grafana-prometheus/src/querybuilder/QueryPattern.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/QueryPattern.tsx import { css } from '@emotion/css'; import React from 'react'; diff --git a/packages/grafana-prometheus/src/querybuilder/QueryPatternsModal.test.tsx b/packages/grafana-prometheus/src/querybuilder/QueryPatternsModal.test.tsx index a8a2b3c9e02..8cc19b9cbe9 100644 --- a/packages/grafana-prometheus/src/querybuilder/QueryPatternsModal.test.tsx +++ b/packages/grafana-prometheus/src/querybuilder/QueryPatternsModal.test.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/QueryPatternsModal.test.tsx import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; diff --git a/packages/grafana-prometheus/src/querybuilder/QueryPatternsModal.tsx b/packages/grafana-prometheus/src/querybuilder/QueryPatternsModal.tsx index f98a778e778..404b0b7a502 100644 --- a/packages/grafana-prometheus/src/querybuilder/QueryPatternsModal.tsx +++ b/packages/grafana-prometheus/src/querybuilder/QueryPatternsModal.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/QueryPatternsModal.tsx import { css } from '@emotion/css'; import { capitalize } from 'lodash'; import React, { useMemo, useState } from 'react'; diff --git a/packages/grafana-prometheus/src/querybuilder/aggregations.ts b/packages/grafana-prometheus/src/querybuilder/aggregations.ts index 18a2f72b687..d4129c3665e 100644 --- a/packages/grafana-prometheus/src/querybuilder/aggregations.ts +++ b/packages/grafana-prometheus/src/querybuilder/aggregations.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/aggregations.ts import { createAggregationOperation, createAggregationOperationWithParam, diff --git a/packages/grafana-prometheus/src/querybuilder/binaryScalarOperations.ts b/packages/grafana-prometheus/src/querybuilder/binaryScalarOperations.ts index 523f85e99a7..b1fc45e849a 100644 --- a/packages/grafana-prometheus/src/querybuilder/binaryScalarOperations.ts +++ b/packages/grafana-prometheus/src/querybuilder/binaryScalarOperations.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/binaryScalarOperations.ts import { defaultAddOperationHandler } from './operationUtils'; import { QueryBuilderOperation, QueryBuilderOperationDef, QueryBuilderOperationParamDef } from './shared/types'; import { PromOperationId, PromVisualQueryOperationCategory } from './types'; diff --git a/packages/grafana-prometheus/src/querybuilder/components/LabelFilterItem.tsx b/packages/grafana-prometheus/src/querybuilder/components/LabelFilterItem.tsx index c1a28d8f96f..c8075933f3b 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/LabelFilterItem.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/LabelFilterItem.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/LabelFilterItem.tsx import debounce from 'debounce-promise'; import React, { useState } from 'react'; diff --git a/packages/grafana-prometheus/src/querybuilder/components/LabelFilters.test.tsx b/packages/grafana-prometheus/src/querybuilder/components/LabelFilters.test.tsx index fcd1b06b72a..b1e21da0096 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/LabelFilters.test.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/LabelFilters.test.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/LabelFilters.test.tsx import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React, { ComponentProps } from 'react'; diff --git a/packages/grafana-prometheus/src/querybuilder/components/LabelFilters.tsx b/packages/grafana-prometheus/src/querybuilder/components/LabelFilters.tsx index 09f5fd1d822..9364dd83f28 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/LabelFilters.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/LabelFilters.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/LabelFilters.tsx import { css, cx } from '@emotion/css'; import { isEqual } from 'lodash'; import React, { useEffect, useState } from 'react'; diff --git a/packages/grafana-prometheus/src/querybuilder/components/LabelParamEditor.tsx b/packages/grafana-prometheus/src/querybuilder/components/LabelParamEditor.tsx index 6cf4e9a9b74..0c1c4a8e35c 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/LabelParamEditor.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/LabelParamEditor.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/LabelParamEditor.tsx import React, { useState } from 'react'; import { DataSourceApi, SelectableValue, toOption } from '@grafana/data'; diff --git a/packages/grafana-prometheus/src/querybuilder/components/MetricSelect.test.tsx b/packages/grafana-prometheus/src/querybuilder/components/MetricSelect.test.tsx index a0561768837..cb115f389c0 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/MetricSelect.test.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/MetricSelect.test.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/MetricSelect.test.tsx import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; diff --git a/packages/grafana-prometheus/src/querybuilder/components/MetricSelect.tsx b/packages/grafana-prometheus/src/querybuilder/components/MetricSelect.tsx index 3e0ab156c2e..35a10f7064c 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/MetricSelect.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/MetricSelect.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/MetricSelect.tsx import { css } from '@emotion/css'; import debounce from 'debounce-promise'; import React, { RefCallback, useCallback, useState } from 'react'; diff --git a/packages/grafana-prometheus/src/querybuilder/components/MetricsLabelsSection.tsx b/packages/grafana-prometheus/src/querybuilder/components/MetricsLabelsSection.tsx index b27af15c168..60d0f4fbcca 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/MetricsLabelsSection.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/MetricsLabelsSection.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/MetricsLabelsSection.tsx import React, { useCallback } from 'react'; import { SelectableValue } from '@grafana/data'; diff --git a/packages/grafana-prometheus/src/querybuilder/components/NestedQuery.tsx b/packages/grafana-prometheus/src/querybuilder/components/NestedQuery.tsx index ecba5898454..efdffc73023 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/NestedQuery.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/NestedQuery.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/NestedQuery.tsx import { css } from '@emotion/css'; import React from 'react'; diff --git a/packages/grafana-prometheus/src/querybuilder/components/NestedQueryList.tsx b/packages/grafana-prometheus/src/querybuilder/components/NestedQueryList.tsx index fb9e60229fe..7d36bec9919 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/NestedQueryList.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/NestedQueryList.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/NestedQueryList.tsx import React from 'react'; import { Stack } from '@grafana/ui'; diff --git a/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilder.test.tsx b/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilder.test.tsx index 54f44c46f13..fdbb2779a4f 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilder.test.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilder.test.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryBuilder.test.tsx import { getByText, render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; diff --git a/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilder.tsx b/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilder.tsx index e05b1c2caa2..90e4d46f8c7 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilder.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilder.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryBuilder.tsx import { css } from '@emotion/css'; import React, { useEffect, useState } from 'react'; diff --git a/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderContainer.test.tsx b/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderContainer.test.tsx index 5172172fd32..e55b4f2d3f4 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderContainer.test.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderContainer.test.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryBuilderContainer.test.tsx import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; diff --git a/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderContainer.tsx b/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderContainer.tsx index 46d3dc05625..a960fc3a58e 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderContainer.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderContainer.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryBuilderContainer.tsx import { createSlice, PayloadAction } from '@reduxjs/toolkit'; import React, { useEffect, useReducer } from 'react'; diff --git a/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderExplained.tsx b/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderExplained.tsx index 38389fbc6e4..c3de6c3808e 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderExplained.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderExplained.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryBuilderExplained.tsx import React from 'react'; import { Stack } from '@grafana/ui'; diff --git a/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderOptions.test.tsx b/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderOptions.test.tsx index 331092c1962..9b9531a28ed 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderOptions.test.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderOptions.test.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryBuilderOptions.test.tsx import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; diff --git a/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderOptions.tsx b/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderOptions.tsx index 79f93db2fe7..7a554d9be45 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderOptions.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/PromQueryBuilderOptions.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryBuilderOptions.tsx import React, { SyntheticEvent } from 'react'; import { CoreApp, SelectableValue } from '@grafana/data'; diff --git a/packages/grafana-prometheus/src/querybuilder/components/PromQueryCodeEditor.test.tsx b/packages/grafana-prometheus/src/querybuilder/components/PromQueryCodeEditor.test.tsx index 5554f33997d..c907e604576 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/PromQueryCodeEditor.test.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/PromQueryCodeEditor.test.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryCodeEditor.test.tsx import { render, screen } from '@testing-library/react'; import React from 'react'; diff --git a/packages/grafana-prometheus/src/querybuilder/components/PromQueryCodeEditor.tsx b/packages/grafana-prometheus/src/querybuilder/components/PromQueryCodeEditor.tsx index 75bc63055e6..84e5805a4f3 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/PromQueryCodeEditor.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/PromQueryCodeEditor.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryCodeEditor.tsx import { css } from '@emotion/css'; import React from 'react'; diff --git a/packages/grafana-prometheus/src/querybuilder/components/PromQueryEditorSelector.test.tsx b/packages/grafana-prometheus/src/querybuilder/components/PromQueryEditorSelector.test.tsx index 9e9079188f3..2dbc49535a7 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/PromQueryEditorSelector.test.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/PromQueryEditorSelector.test.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryEditorSelector.test.tsx import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { cloneDeep, defaultsDeep } from 'lodash'; diff --git a/packages/grafana-prometheus/src/querybuilder/components/PromQueryEditorSelector.tsx b/packages/grafana-prometheus/src/querybuilder/components/PromQueryEditorSelector.tsx index b46ef45c6f0..30c5502bacb 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/PromQueryEditorSelector.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/PromQueryEditorSelector.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryEditorSelector.tsx import { isEqual, map } from 'lodash'; import React, { SyntheticEvent, useCallback, useEffect, useState } from 'react'; diff --git a/packages/grafana-prometheus/src/querybuilder/components/PromQueryLegendEditor.tsx b/packages/grafana-prometheus/src/querybuilder/components/PromQueryLegendEditor.tsx index 440278b4c50..5be07dee6be 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/PromQueryLegendEditor.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/PromQueryLegendEditor.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/PromQueryLegendEditor.tsx import React, { useRef } from 'react'; import { SelectableValue } from '@grafana/data'; diff --git a/packages/grafana-prometheus/src/querybuilder/components/QueryPreview.tsx b/packages/grafana-prometheus/src/querybuilder/components/QueryPreview.tsx index 0f731ec0b3d..2bd0e252672 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/QueryPreview.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/QueryPreview.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/QueryPreview.tsx import React from 'react'; import { EditorFieldGroup, EditorRow } from '@grafana/experimental'; diff --git a/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/AdditionalSettings.tsx b/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/AdditionalSettings.tsx index c5a7d104849..38caa6e6f49 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/AdditionalSettings.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/AdditionalSettings.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/metrics-modal/AdditionalSettings.tsx import { css } from '@emotion/css'; import React from 'react'; diff --git a/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/FeedbackLink.tsx b/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/FeedbackLink.tsx index 4ba1d881147..954efbd61e1 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/FeedbackLink.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/FeedbackLink.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/metrics-modal/FeedbackLink.tsx import { css } from '@emotion/css'; import React from 'react'; diff --git a/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/MetricsModal.test.tsx b/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/MetricsModal.test.tsx index f12d7c67080..ca0c28916c3 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/MetricsModal.test.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/MetricsModal.test.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/metrics-modal/MetricsModal.test.tsx import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; diff --git a/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/MetricsModal.tsx b/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/MetricsModal.tsx index 6e02715a804..4d6aab8dc0d 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/MetricsModal.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/MetricsModal.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/metrics-modal/MetricsModal.tsx import { cx } from '@emotion/css'; import { PayloadAction, createSlice } from '@reduxjs/toolkit'; import debounce from 'debounce-promise'; diff --git a/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/ResultsTable.tsx b/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/ResultsTable.tsx index a474098bbc0..ef396c58e21 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/ResultsTable.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/ResultsTable.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/metrics-modal/ResultsTable.tsx import { css } from '@emotion/css'; import React, { ReactElement } from 'react'; import Highlighter from 'react-highlight-words'; diff --git a/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/state/helpers.ts b/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/state/helpers.ts index e8a40d02b0c..19d016eafd0 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/state/helpers.ts +++ b/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/state/helpers.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/metrics-modal/state/helpers.ts import { AnyAction } from '@reduxjs/toolkit'; import { reportInteraction } from '@grafana/runtime'; diff --git a/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/state/state.ts b/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/state/state.ts index f22bd73ea4b..fa29ba2450e 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/state/state.ts +++ b/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/state/state.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/metrics-modal/state/state.ts import { SelectableValue } from '@grafana/data'; import { PromVisualQuery } from '../../../types'; diff --git a/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/styles.ts b/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/styles.ts index e8eb2fe86dd..e105530602c 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/styles.ts +++ b/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/styles.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/metrics-modal/styles.ts import { css } from '@emotion/css'; import { GrafanaTheme2 } from '@grafana/data'; diff --git a/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/types.ts b/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/types.ts index d4be9a48638..233f3765e8a 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/types.ts +++ b/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/types.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/metrics-modal/types.ts export type MetricsData = MetricData[]; export type MetricData = { diff --git a/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/uFuzzy.ts b/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/uFuzzy.ts index 7c7e5eb44ea..7b070b9ab58 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/uFuzzy.ts +++ b/packages/grafana-prometheus/src/querybuilder/components/metrics-modal/uFuzzy.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/metrics-modal/uFuzzy.ts import uFuzzy from '@leeoniya/ufuzzy'; import { debounce as debounceLodash } from 'lodash'; diff --git a/packages/grafana-prometheus/src/querybuilder/components/promQail/PromQail.test.tsx b/packages/grafana-prometheus/src/querybuilder/components/promQail/PromQail.test.tsx index b4056fb8bca..0874258cc87 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/promQail/PromQail.test.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/promQail/PromQail.test.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/promQail/PromQail.test.tsx import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; diff --git a/packages/grafana-prometheus/src/querybuilder/components/promQail/PromQail.tsx b/packages/grafana-prometheus/src/querybuilder/components/promQail/PromQail.tsx index 8777f8c48ab..638d3f53b93 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/promQail/PromQail.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/promQail/PromQail.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/promQail/PromQail.tsx import { css, cx } from '@emotion/css'; import { PayloadAction, createSlice } from '@reduxjs/toolkit'; import React, { useEffect, useReducer, useRef, useState } from 'react'; diff --git a/packages/grafana-prometheus/src/querybuilder/components/promQail/QueryAssistantButton.test.tsx b/packages/grafana-prometheus/src/querybuilder/components/promQail/QueryAssistantButton.test.tsx index 2b64277c22c..3bfabc4bf60 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/promQail/QueryAssistantButton.test.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/promQail/QueryAssistantButton.test.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/promQail/QueryAssistantButton.test.tsx import { fireEvent, render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; diff --git a/packages/grafana-prometheus/src/querybuilder/components/promQail/QueryAssistantButton.tsx b/packages/grafana-prometheus/src/querybuilder/components/promQail/QueryAssistantButton.tsx index 5445134b64b..577d330691e 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/promQail/QueryAssistantButton.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/promQail/QueryAssistantButton.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/promQail/QueryAssistantButton.tsx import React from 'react'; import { selectors } from '@grafana/e2e-selectors'; diff --git a/packages/grafana-prometheus/src/querybuilder/components/promQail/QuerySuggestionContainer.tsx b/packages/grafana-prometheus/src/querybuilder/components/promQail/QuerySuggestionContainer.tsx index 1a52194b9cb..469811e72e2 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/promQail/QuerySuggestionContainer.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/promQail/QuerySuggestionContainer.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/promQail/QuerySuggestionContainer.tsx import { cx } from '@emotion/css'; import React, { useState } from 'react'; diff --git a/packages/grafana-prometheus/src/querybuilder/components/promQail/QuerySuggestionItem.tsx b/packages/grafana-prometheus/src/querybuilder/components/promQail/QuerySuggestionItem.tsx index 9076faae6bc..09a5b1c3fce 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/promQail/QuerySuggestionItem.tsx +++ b/packages/grafana-prometheus/src/querybuilder/components/promQail/QuerySuggestionItem.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/promQail/QuerySuggestionItem.tsx import { cx } from '@emotion/css'; import React, { FormEvent, useState } from 'react'; diff --git a/packages/grafana-prometheus/src/querybuilder/components/promQail/prompts.ts b/packages/grafana-prometheus/src/querybuilder/components/promQail/prompts.ts index b92bd2d2f14..3a62b1c7b72 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/promQail/prompts.ts +++ b/packages/grafana-prometheus/src/querybuilder/components/promQail/prompts.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/promQail/prompts.ts export const ExplainSystemPrompt = `You are an expert in Prometheus, the event monitoring and alerting application. You are given relevant PromQL documentation, a type and description for a Prometheus metric, and a PromQL query on that metric. Using the provided information for reference, please explain what the output of a given query is in 1 sentences. Do not walk through what the functions do separately, make your answer concise. diff --git a/packages/grafana-prometheus/src/querybuilder/components/promQail/state/helpers.test.ts b/packages/grafana-prometheus/src/querybuilder/components/promQail/state/helpers.test.ts index 323848bebdc..90da7dbadd5 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/promQail/state/helpers.test.ts +++ b/packages/grafana-prometheus/src/querybuilder/components/promQail/state/helpers.test.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/promQail/state/helpers.test.ts import { llms } from '@grafana/experimental'; import { guessMetricType, isLLMPluginEnabled } from './helpers'; diff --git a/packages/grafana-prometheus/src/querybuilder/components/promQail/state/helpers.ts b/packages/grafana-prometheus/src/querybuilder/components/promQail/state/helpers.ts index 8bf207da75e..ea94d6da2a7 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/promQail/state/helpers.ts +++ b/packages/grafana-prometheus/src/querybuilder/components/promQail/state/helpers.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/promQail/state/helpers.ts import { AnyAction } from 'redux'; import { llms } from '@grafana/experimental'; diff --git a/packages/grafana-prometheus/src/querybuilder/components/promQail/state/state.ts b/packages/grafana-prometheus/src/querybuilder/components/promQail/state/state.ts index 2c00053f1dc..a33d0a227ee 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/promQail/state/state.ts +++ b/packages/grafana-prometheus/src/querybuilder/components/promQail/state/state.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/promQail/state/state.ts import { PromVisualQuery } from '../../../types'; import { Interaction, SuggestionType } from '../types'; diff --git a/packages/grafana-prometheus/src/querybuilder/components/promQail/state/templates.ts b/packages/grafana-prometheus/src/querybuilder/components/promQail/state/templates.ts index 2a56e9f4fbb..330de01da2f 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/promQail/state/templates.ts +++ b/packages/grafana-prometheus/src/querybuilder/components/promQail/state/templates.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/promQail/state/templates.ts import { QuerySuggestion } from '../types'; interface TemplateData { diff --git a/packages/grafana-prometheus/src/querybuilder/components/promQail/types.ts b/packages/grafana-prometheus/src/querybuilder/components/promQail/types.ts index e8c5005cfac..09f4a3988f5 100644 --- a/packages/grafana-prometheus/src/querybuilder/components/promQail/types.ts +++ b/packages/grafana-prometheus/src/querybuilder/components/promQail/types.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/components/promQail/types.ts export type QuerySuggestion = { query: string; explanation: string; diff --git a/packages/grafana-prometheus/src/querybuilder/hooks/useFlag.test.ts b/packages/grafana-prometheus/src/querybuilder/hooks/useFlag.test.ts index 4c7ca4e6393..a3c95b17a52 100644 --- a/packages/grafana-prometheus/src/querybuilder/hooks/useFlag.test.ts +++ b/packages/grafana-prometheus/src/querybuilder/hooks/useFlag.test.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/hooks/useFlag.test.ts import { act, renderHook } from '@testing-library/react'; import { promQueryEditorExplainKey, useFlag } from './useFlag'; diff --git a/packages/grafana-prometheus/src/querybuilder/hooks/useFlag.ts b/packages/grafana-prometheus/src/querybuilder/hooks/useFlag.ts index 183a956d45a..7dfc732b025 100644 --- a/packages/grafana-prometheus/src/querybuilder/hooks/useFlag.ts +++ b/packages/grafana-prometheus/src/querybuilder/hooks/useFlag.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/hooks/useFlag.ts import { useCallback, useState } from 'react'; import store from '../../gcopypaste/app/core/store'; diff --git a/packages/grafana-prometheus/src/querybuilder/operationUtils.test.ts b/packages/grafana-prometheus/src/querybuilder/operationUtils.test.ts index da1aabe924e..d1e690bc807 100644 --- a/packages/grafana-prometheus/src/querybuilder/operationUtils.test.ts +++ b/packages/grafana-prometheus/src/querybuilder/operationUtils.test.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/operationUtils.test.ts import { createAggregationOperation, createAggregationOperationWithParam, diff --git a/packages/grafana-prometheus/src/querybuilder/operationUtils.ts b/packages/grafana-prometheus/src/querybuilder/operationUtils.ts index 9be994d73da..a0bda0d598f 100644 --- a/packages/grafana-prometheus/src/querybuilder/operationUtils.ts +++ b/packages/grafana-prometheus/src/querybuilder/operationUtils.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/operationUtils.ts import { capitalize } from 'lodash'; import pluralize from 'pluralize'; diff --git a/packages/grafana-prometheus/src/querybuilder/operations.ts b/packages/grafana-prometheus/src/querybuilder/operations.ts index e4a3dffacbd..afecda0ab31 100644 --- a/packages/grafana-prometheus/src/querybuilder/operations.ts +++ b/packages/grafana-prometheus/src/querybuilder/operations.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/operations.ts import { binaryScalarOperations } from './binaryScalarOperations'; import { LabelParamEditor } from './components/LabelParamEditor'; import { diff --git a/packages/grafana-prometheus/src/querybuilder/parsing.test.ts b/packages/grafana-prometheus/src/querybuilder/parsing.test.ts index fbd094bb5ff..1522aff295f 100644 --- a/packages/grafana-prometheus/src/querybuilder/parsing.test.ts +++ b/packages/grafana-prometheus/src/querybuilder/parsing.test.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/parsing.test.ts import { buildVisualQueryFromString } from './parsing'; import { PromOperationId, PromVisualQuery } from './types'; diff --git a/packages/grafana-prometheus/src/querybuilder/parsing.ts b/packages/grafana-prometheus/src/querybuilder/parsing.ts index de1486efc2a..af31365c564 100644 --- a/packages/grafana-prometheus/src/querybuilder/parsing.ts +++ b/packages/grafana-prometheus/src/querybuilder/parsing.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/parsing.ts import { SyntaxNode } from '@lezer/common'; import { AggregateExpr, diff --git a/packages/grafana-prometheus/src/querybuilder/parsingUtils.test.ts b/packages/grafana-prometheus/src/querybuilder/parsingUtils.test.ts index 81c8d255ca6..3bef72e1fd0 100644 --- a/packages/grafana-prometheus/src/querybuilder/parsingUtils.test.ts +++ b/packages/grafana-prometheus/src/querybuilder/parsingUtils.test.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/parsingUtils.test.ts import { parser } from '@prometheus-io/lezer-promql'; import { getLeftMostChild, getString, replaceVariables } from './parsingUtils'; diff --git a/packages/grafana-prometheus/src/querybuilder/parsingUtils.ts b/packages/grafana-prometheus/src/querybuilder/parsingUtils.ts index 10be8692ebc..bc19084122f 100644 --- a/packages/grafana-prometheus/src/querybuilder/parsingUtils.ts +++ b/packages/grafana-prometheus/src/querybuilder/parsingUtils.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/parsingUtils.ts import { SyntaxNode, TreeCursor } from '@lezer/common'; import { QueryBuilderOperation, QueryBuilderOperationParamValue } from './shared/types'; diff --git a/packages/grafana-prometheus/src/querybuilder/shared/LokiAndPromQueryModellerBase.ts b/packages/grafana-prometheus/src/querybuilder/shared/LokiAndPromQueryModellerBase.ts index 81afc5a2762..872973b4887 100644 --- a/packages/grafana-prometheus/src/querybuilder/shared/LokiAndPromQueryModellerBase.ts +++ b/packages/grafana-prometheus/src/querybuilder/shared/LokiAndPromQueryModellerBase.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/shared/LokiAndPromQueryModellerBase.ts import { Registry } from '@grafana/data'; import { PromVisualQueryOperationCategory } from '../types'; diff --git a/packages/grafana-prometheus/src/querybuilder/shared/OperationEditor.tsx b/packages/grafana-prometheus/src/querybuilder/shared/OperationEditor.tsx index cd4dd77ff72..405b40b7cd2 100644 --- a/packages/grafana-prometheus/src/querybuilder/shared/OperationEditor.tsx +++ b/packages/grafana-prometheus/src/querybuilder/shared/OperationEditor.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/shared/OperationEditor.tsx import { css, cx } from '@emotion/css'; import React, { useEffect, useId, useState } from 'react'; import { Draggable } from 'react-beautiful-dnd'; diff --git a/packages/grafana-prometheus/src/querybuilder/shared/OperationExplainedBox.tsx b/packages/grafana-prometheus/src/querybuilder/shared/OperationExplainedBox.tsx index f38597c3c10..d5e5f753997 100644 --- a/packages/grafana-prometheus/src/querybuilder/shared/OperationExplainedBox.tsx +++ b/packages/grafana-prometheus/src/querybuilder/shared/OperationExplainedBox.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/shared/OperationExplainedBox.tsx import { css } from '@emotion/css'; import React from 'react'; diff --git a/packages/grafana-prometheus/src/querybuilder/shared/OperationHeader.tsx b/packages/grafana-prometheus/src/querybuilder/shared/OperationHeader.tsx index a47c747c9d5..757befe40ec 100644 --- a/packages/grafana-prometheus/src/querybuilder/shared/OperationHeader.tsx +++ b/packages/grafana-prometheus/src/querybuilder/shared/OperationHeader.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/shared/OperationHeader.tsx import { css } from '@emotion/css'; import React, { useState } from 'react'; import { DraggableProvided } from 'react-beautiful-dnd'; diff --git a/packages/grafana-prometheus/src/querybuilder/shared/OperationInfoButton.tsx b/packages/grafana-prometheus/src/querybuilder/shared/OperationInfoButton.tsx index 56f12509390..c5149c16ef9 100644 --- a/packages/grafana-prometheus/src/querybuilder/shared/OperationInfoButton.tsx +++ b/packages/grafana-prometheus/src/querybuilder/shared/OperationInfoButton.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/shared/OperationInfoButton.tsx import { css } from '@emotion/css'; import { autoUpdate, diff --git a/packages/grafana-prometheus/src/querybuilder/shared/OperationList.test.tsx b/packages/grafana-prometheus/src/querybuilder/shared/OperationList.test.tsx index 02d95b87236..912bc4e4952 100644 --- a/packages/grafana-prometheus/src/querybuilder/shared/OperationList.test.tsx +++ b/packages/grafana-prometheus/src/querybuilder/shared/OperationList.test.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/shared/OperationList.test.tsx import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; diff --git a/packages/grafana-prometheus/src/querybuilder/shared/OperationList.tsx b/packages/grafana-prometheus/src/querybuilder/shared/OperationList.tsx index 6e104e2675f..875eb166730 100644 --- a/packages/grafana-prometheus/src/querybuilder/shared/OperationList.tsx +++ b/packages/grafana-prometheus/src/querybuilder/shared/OperationList.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/shared/OperationList.tsx import { css } from '@emotion/css'; import React, { useState } from 'react'; import { DragDropContext, Droppable, DropResult } from 'react-beautiful-dnd'; diff --git a/packages/grafana-prometheus/src/querybuilder/shared/OperationListExplained.tsx b/packages/grafana-prometheus/src/querybuilder/shared/OperationListExplained.tsx index bfc7fba3808..bde7203584c 100644 --- a/packages/grafana-prometheus/src/querybuilder/shared/OperationListExplained.tsx +++ b/packages/grafana-prometheus/src/querybuilder/shared/OperationListExplained.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/shared/OperationListExplained.tsx import { Grammar } from 'prismjs'; import React from 'react'; diff --git a/packages/grafana-prometheus/src/querybuilder/shared/OperationParamEditor.tsx b/packages/grafana-prometheus/src/querybuilder/shared/OperationParamEditor.tsx index e9bbbff644b..d4f8694c4a6 100644 --- a/packages/grafana-prometheus/src/querybuilder/shared/OperationParamEditor.tsx +++ b/packages/grafana-prometheus/src/querybuilder/shared/OperationParamEditor.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/shared/OperationParamEditor.tsx import { css } from '@emotion/css'; import React, { ComponentType } from 'react'; diff --git a/packages/grafana-prometheus/src/querybuilder/shared/OperationsEditorRow.tsx b/packages/grafana-prometheus/src/querybuilder/shared/OperationsEditorRow.tsx index 00ebc654f06..696d034b5a9 100644 --- a/packages/grafana-prometheus/src/querybuilder/shared/OperationsEditorRow.tsx +++ b/packages/grafana-prometheus/src/querybuilder/shared/OperationsEditorRow.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/shared/OperationsEditorRow.tsx import { css } from '@emotion/css'; import React from 'react'; diff --git a/packages/grafana-prometheus/src/querybuilder/shared/QueryBuilderHints.tsx b/packages/grafana-prometheus/src/querybuilder/shared/QueryBuilderHints.tsx index 91389eb495b..25ed6b8e271 100644 --- a/packages/grafana-prometheus/src/querybuilder/shared/QueryBuilderHints.tsx +++ b/packages/grafana-prometheus/src/querybuilder/shared/QueryBuilderHints.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/shared/QueryBuilderHints.tsx import { css } from '@emotion/css'; import React, { useEffect, useState } from 'react'; diff --git a/packages/grafana-prometheus/src/querybuilder/shared/QueryEditorModeToggle.tsx b/packages/grafana-prometheus/src/querybuilder/shared/QueryEditorModeToggle.tsx index b47d89b6301..f5541dde1c8 100644 --- a/packages/grafana-prometheus/src/querybuilder/shared/QueryEditorModeToggle.tsx +++ b/packages/grafana-prometheus/src/querybuilder/shared/QueryEditorModeToggle.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/shared/QueryEditorModeToggle.tsx import React from 'react'; import { RadioButtonGroup } from '@grafana/ui'; diff --git a/packages/grafana-prometheus/src/querybuilder/shared/QueryHeaderSwitch.tsx b/packages/grafana-prometheus/src/querybuilder/shared/QueryHeaderSwitch.tsx index b7088bb3f8b..f92f2accd44 100644 --- a/packages/grafana-prometheus/src/querybuilder/shared/QueryHeaderSwitch.tsx +++ b/packages/grafana-prometheus/src/querybuilder/shared/QueryHeaderSwitch.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/shared/QueryHeaderSwitch.tsx import { css } from '@emotion/css'; import { uniqueId } from 'lodash'; import React, { HTMLProps, useRef } from 'react'; diff --git a/packages/grafana-prometheus/src/querybuilder/shared/QueryOptionGroup.tsx b/packages/grafana-prometheus/src/querybuilder/shared/QueryOptionGroup.tsx index b0c6951b092..7d8df70545b 100644 --- a/packages/grafana-prometheus/src/querybuilder/shared/QueryOptionGroup.tsx +++ b/packages/grafana-prometheus/src/querybuilder/shared/QueryOptionGroup.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/shared/QueryOptionGroup.tsx import { css } from '@emotion/css'; import React from 'react'; import { useToggle } from 'react-use'; diff --git a/packages/grafana-prometheus/src/querybuilder/shared/RawQuery.tsx b/packages/grafana-prometheus/src/querybuilder/shared/RawQuery.tsx index b2cc3d8a372..da7ec8c0f79 100644 --- a/packages/grafana-prometheus/src/querybuilder/shared/RawQuery.tsx +++ b/packages/grafana-prometheus/src/querybuilder/shared/RawQuery.tsx @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/shared/RawQuery.tsx import { css, cx } from '@emotion/css'; import Prism, { Grammar } from 'prismjs'; import React from 'react'; diff --git a/packages/grafana-prometheus/src/querybuilder/shared/types.ts b/packages/grafana-prometheus/src/querybuilder/shared/types.ts index 73d46de0a74..e8764866c43 100644 --- a/packages/grafana-prometheus/src/querybuilder/shared/types.ts +++ b/packages/grafana-prometheus/src/querybuilder/shared/types.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/shared/types.ts /** * Shared types that can be reused by Loki and other data sources */ diff --git a/packages/grafana-prometheus/src/querybuilder/state.test.ts b/packages/grafana-prometheus/src/querybuilder/state.test.ts index a96f876ada1..04293ec686c 100644 --- a/packages/grafana-prometheus/src/querybuilder/state.test.ts +++ b/packages/grafana-prometheus/src/querybuilder/state.test.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/state.test.ts import { CoreApp } from '@grafana/data'; import { PromQuery } from '../types'; diff --git a/packages/grafana-prometheus/src/querybuilder/state.ts b/packages/grafana-prometheus/src/querybuilder/state.ts index 06ef89c33fc..fddda52c406 100644 --- a/packages/grafana-prometheus/src/querybuilder/state.ts +++ b/packages/grafana-prometheus/src/querybuilder/state.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/state.ts import { CoreApp } from '@grafana/data'; import store from '../gcopypaste/app/core/store'; diff --git a/packages/grafana-prometheus/src/querybuilder/testUtils.ts b/packages/grafana-prometheus/src/querybuilder/testUtils.ts index 818d05756b4..04ef4c911e7 100644 --- a/packages/grafana-prometheus/src/querybuilder/testUtils.ts +++ b/packages/grafana-prometheus/src/querybuilder/testUtils.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/testUtils.ts import { getAllByRole, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; diff --git a/packages/grafana-prometheus/src/querybuilder/types.ts b/packages/grafana-prometheus/src/querybuilder/types.ts index 773b22373a4..c846adff8a5 100644 --- a/packages/grafana-prometheus/src/querybuilder/types.ts +++ b/packages/grafana-prometheus/src/querybuilder/types.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querybuilder/types.ts import { VisualQueryBinary } from './shared/LokiAndPromQueryModellerBase'; import { QueryBuilderLabelFilter, QueryBuilderOperation } from './shared/types'; diff --git a/packages/grafana-prometheus/src/querycache/QueryCache.test.ts b/packages/grafana-prometheus/src/querycache/QueryCache.test.ts index d0f385a7516..78ff585ec20 100644 --- a/packages/grafana-prometheus/src/querycache/QueryCache.test.ts +++ b/packages/grafana-prometheus/src/querycache/QueryCache.test.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querycache/QueryCache.test.ts import moment from 'moment'; import { DataFrame, DataQueryRequest, DateTime, dateTime, TimeRange } from '@grafana/data'; diff --git a/packages/grafana-prometheus/src/querycache/QueryCache.ts b/packages/grafana-prometheus/src/querycache/QueryCache.ts index 0cf5f84c2f5..05ad2c3f1d3 100644 --- a/packages/grafana-prometheus/src/querycache/QueryCache.ts +++ b/packages/grafana-prometheus/src/querycache/QueryCache.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querycache/QueryCache.ts import { DataFrame, DataQueryRequest, diff --git a/packages/grafana-prometheus/src/querycache/QueryCacheTestData.ts b/packages/grafana-prometheus/src/querycache/QueryCacheTestData.ts index ec4d5154bf2..a066f3107e4 100644 --- a/packages/grafana-prometheus/src/querycache/QueryCacheTestData.ts +++ b/packages/grafana-prometheus/src/querycache/QueryCacheTestData.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/querycache/QueryCacheTestData.ts import { clone } from 'lodash'; /** diff --git a/packages/grafana-prometheus/src/result_transformer.test.ts b/packages/grafana-prometheus/src/result_transformer.test.ts index bc2f251767f..b530babd4f5 100644 --- a/packages/grafana-prometheus/src/result_transformer.test.ts +++ b/packages/grafana-prometheus/src/result_transformer.test.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/result_transformer.test.ts import { cacheFieldDisplayNames, createDataFrame, diff --git a/packages/grafana-prometheus/src/result_transformer.ts b/packages/grafana-prometheus/src/result_transformer.ts index ac93f7955a8..a3f11c39087 100644 --- a/packages/grafana-prometheus/src/result_transformer.ts +++ b/packages/grafana-prometheus/src/result_transformer.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/result_transformer.ts import { flatten, forOwn, groupBy, partition } from 'lodash'; import { diff --git a/packages/grafana-prometheus/src/tracking.ts b/packages/grafana-prometheus/src/tracking.ts index 76706984df3..a39c02882f5 100644 --- a/packages/grafana-prometheus/src/tracking.ts +++ b/packages/grafana-prometheus/src/tracking.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/tracking.ts import { CoreApp, DataQueryRequest, DataQueryResponse } from '@grafana/data'; import { config, reportInteraction } from '@grafana/runtime'; diff --git a/packages/grafana-prometheus/src/types.ts b/packages/grafana-prometheus/src/types.ts index f6837388e05..beb9fb07a63 100644 --- a/packages/grafana-prometheus/src/types.ts +++ b/packages/grafana-prometheus/src/types.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/types.ts import { DataSourceJsonData } from '@grafana/data'; import { DataQuery } from '@grafana/schema'; diff --git a/packages/grafana-prometheus/src/variables.ts b/packages/grafana-prometheus/src/variables.ts index fcf545e0d1c..cf3ac7c5f63 100644 --- a/packages/grafana-prometheus/src/variables.ts +++ b/packages/grafana-prometheus/src/variables.ts @@ -1,3 +1,4 @@ +// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/variables.ts import { from, Observable, of } from 'rxjs'; import { map } from 'rxjs/operators'; diff --git a/pkg/services/featuremgmt/registry.go b/pkg/services/featuremgmt/registry.go index daef6b36959..16327d02e5a 100644 --- a/pkg/services/featuremgmt/registry.go +++ b/pkg/services/featuremgmt/registry.go @@ -1164,13 +1164,6 @@ var ( HideFromDocs: true, HideFromAdminPage: true, }, - { - Name: "usePrometheusFrontendPackage", - Description: "Use the @grafana/prometheus frontend package in core Prometheus.", - Stage: FeatureStageGeneralAvailability, - FrontendOnly: true, - Owner: grafanaObservabilityMetricsSquad, - }, { Name: "oauthRequireSubClaim", Description: "Require that sub claims is present in oauth tokens.", diff --git a/pkg/services/featuremgmt/toggles_gen.csv b/pkg/services/featuremgmt/toggles_gen.csv index bc4043f1f78..9c99387368a 100644 --- a/pkg/services/featuremgmt/toggles_gen.csv +++ b/pkg/services/featuremgmt/toggles_gen.csv @@ -155,7 +155,6 @@ betterPageScrolling,GA,@grafana/grafana-frontend-platform,false,false,true authAPIAccessTokenAuth,experimental,@grafana/identity-access-team,false,false,false scopeFilters,experimental,@grafana/dashboards-squad,false,false,false ssoSettingsSAML,experimental,@grafana/identity-access-team,false,false,false -usePrometheusFrontendPackage,GA,@grafana/observability-metrics,false,false,true oauthRequireSubClaim,experimental,@grafana/identity-access-team,false,false,false newDashboardWithFiltersAndGroupBy,experimental,@grafana/dashboards-squad,false,false,false cloudWatchNewLabelParsing,GA,@grafana/aws-datasources,false,false,false diff --git a/pkg/services/featuremgmt/toggles_gen.go b/pkg/services/featuremgmt/toggles_gen.go index 753ab0885a4..80c0dc9dc0c 100644 --- a/pkg/services/featuremgmt/toggles_gen.go +++ b/pkg/services/featuremgmt/toggles_gen.go @@ -631,10 +631,6 @@ const ( // Use the new SSO Settings API to configure the SAML connector FlagSsoSettingsSAML = "ssoSettingsSAML" - // FlagUsePrometheusFrontendPackage - // Use the @grafana/prometheus frontend package in core Prometheus. - FlagUsePrometheusFrontendPackage = "usePrometheusFrontendPackage" - // FlagOauthRequireSubClaim // Require that sub claims is present in oauth tokens. FlagOauthRequireSubClaim = "oauthRequireSubClaim" diff --git a/pkg/services/featuremgmt/toggles_gen.json b/pkg/services/featuremgmt/toggles_gen.json index 78ab30dc6e6..3479f58e6d1 100644 --- a/pkg/services/featuremgmt/toggles_gen.json +++ b/pkg/services/featuremgmt/toggles_gen.json @@ -1468,6 +1468,7 @@ "name": "usePrometheusFrontendPackage", "resourceVersion": "1712841379965", "creationTimestamp": "2024-04-09T05:07:41Z", + "deletionTimestamp": "2024-04-12T23:12:45Z", "annotations": { "grafana.app/updatedTimestamp": "2024-04-11 13:16:19.965312 +0000 UTC" } diff --git a/public/app/features/alerting/unified/PanelAlertTabContent.test.tsx b/public/app/features/alerting/unified/PanelAlertTabContent.test.tsx index a1df6a1be3e..9c70f018da8 100644 --- a/public/app/features/alerting/unified/PanelAlertTabContent.test.tsx +++ b/public/app/features/alerting/unified/PanelAlertTabContent.test.tsx @@ -4,14 +4,13 @@ import { TestProvider } from 'test/helpers/TestProvider'; import { byTestId } from 'testing-library-selector'; import { DataSourceApi } from '@grafana/data'; +import { PromOptions, PrometheusDatasource } from '@grafana/prometheus'; import { setDataSourceSrv } from '@grafana/runtime'; import * as ruleActionButtons from 'app/features/alerting/unified/components/rules/RuleActionsButtons'; import { DashboardModel, PanelModel } from 'app/features/dashboard/state'; import { getDatasourceSrv } from 'app/features/plugins/datasource_srv'; import { toggleOption } from 'app/features/variables/pickers/OptionsPicker/reducer'; import { toKeyedAction } from 'app/features/variables/state/keyedVariablesReducer'; -import { PrometheusDatasource } from 'app/plugins/datasource/prometheus/datasource'; -import { PromOptions } from 'app/plugins/datasource/prometheus/types'; import { configureStore } from 'app/store/configureStore'; import { AccessControlAction } from 'app/types'; import { AlertQuery } from 'app/types/unified-alerting-dto'; diff --git a/public/app/features/alerting/unified/components/Expression.tsx b/public/app/features/alerting/unified/components/Expression.tsx index dce352a0f92..ec11e41a58f 100644 --- a/public/app/features/alerting/unified/components/Expression.tsx +++ b/public/app/features/alerting/unified/components/Expression.tsx @@ -4,9 +4,9 @@ import React, { FC, useMemo } from 'react'; import { Editor } from 'slate-react'; import { GrafanaTheme2 } from '@grafana/data'; +import { promqlGrammar } from '@grafana/prometheus'; import { makeValue, SlatePrism, useStyles2 } from '@grafana/ui'; import LogqlSyntax from 'app/plugins/datasource/loki/syntax'; -import PromqlSyntax from 'app/plugins/datasource/prometheus/promql'; import { RulesSource } from 'app/types/unified-alerting'; import { DataSourceType, isCloudRulesSource } from '../utils/datasource'; @@ -26,7 +26,7 @@ export const HighlightedQuery: FC<{ language: 'promql' | 'logql'; expr: string } onlyIn: (node) => 'type' in node && node.type === 'code_block', getSyntax: () => language, }, - { ...prismLanguages, [language]: language === 'logql' ? LogqlSyntax : PromqlSyntax } + { ...prismLanguages, [language]: language === 'logql' ? LogqlSyntax : promqlGrammar } ), ], [language] diff --git a/public/app/features/alerting/unified/components/rule-editor/ExpressionEditor.tsx b/public/app/features/alerting/unified/components/rule-editor/ExpressionEditor.tsx index 4c2f5892908..58caf640fe4 100644 --- a/public/app/features/alerting/unified/components/rule-editor/ExpressionEditor.tsx +++ b/public/app/features/alerting/unified/components/rule-editor/ExpressionEditor.tsx @@ -4,10 +4,10 @@ import React, { useCallback, useMemo } from 'react'; import { useAsync } from 'react-use'; import { CoreApp, DataQuery, DataSourcePluginContextProvider, GrafanaTheme2, LoadingState } from '@grafana/data'; +import { PromQuery } from '@grafana/prometheus'; import { getDataSourceSrv } from '@grafana/runtime'; import { Alert, Button, useStyles2 } from '@grafana/ui'; import { LokiQuery } from 'app/plugins/datasource/loki/types'; -import { PromQuery } from 'app/plugins/datasource/prometheus/types'; import { CloudAlertPreview } from './CloudAlertPreview'; import { usePreview } from './PreviewRule'; diff --git a/public/app/features/alerting/unified/utils/query.ts b/public/app/features/alerting/unified/utils/query.ts index 950c7340956..49ec1464a93 100644 --- a/public/app/features/alerting/unified/utils/query.ts +++ b/public/app/features/alerting/unified/utils/query.ts @@ -1,9 +1,9 @@ import { produce } from 'immer'; import { DataSourceInstanceSettings } from '@grafana/data'; +import { PromQuery } from '@grafana/prometheus'; import { DataQuery } from '@grafana/schema'; import { LokiQuery } from 'app/plugins/datasource/loki/types'; -import { PromQuery } from 'app/plugins/datasource/prometheus/types'; import { CombinedRule } from 'app/types/unified-alerting'; import { AlertQuery } from 'app/types/unified-alerting-dto'; diff --git a/public/app/features/alerting/unified/utils/rule-form.test.ts b/public/app/features/alerting/unified/utils/rule-form.test.ts index 735a8f7087b..164720b2f4a 100644 --- a/public/app/features/alerting/unified/utils/rule-form.test.ts +++ b/public/app/features/alerting/unified/utils/rule-form.test.ts @@ -1,5 +1,5 @@ +import { PromQuery } from '@grafana/prometheus'; import { config } from '@grafana/runtime'; -import { PromQuery } from 'app/plugins/datasource/prometheus/types'; import { GrafanaAlertStateDecision, GrafanaRuleDefinition, RulerAlertingRuleDTO } from 'app/types/unified-alerting-dto'; import { AlertManagerManualRouting, RuleFormType, RuleFormValues } from '../types/rule-form'; diff --git a/public/app/features/alerting/unified/utils/rule-form.ts b/public/app/features/alerting/unified/utils/rule-form.ts index 1b664dfbfb4..8efbb441727 100644 --- a/public/app/features/alerting/unified/utils/rule-form.ts +++ b/public/app/features/alerting/unified/utils/rule-form.ts @@ -11,6 +11,7 @@ import { ScopedVars, TimeRange, } from '@grafana/data'; +import { PromQuery } from '@grafana/prometheus'; import { config, getDataSourceSrv } from '@grafana/runtime'; import { ExpressionDatasourceRef } from '@grafana/runtime/src/utils/DataSourceWithBackend'; import { sceneGraph, VizPanel } from '@grafana/scenes'; @@ -24,7 +25,6 @@ import { } from 'app/features/dashboard-scene/utils/utils'; import { ExpressionDatasourceUID, ExpressionQuery, ExpressionQueryType } from 'app/features/expressions/types'; import { LokiQuery } from 'app/plugins/datasource/loki/types'; -import { PromQuery } from 'app/plugins/datasource/prometheus/types'; import { RuleWithLocation } from 'app/types/unified-alerting'; import { AlertDataQuery, diff --git a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataAlertingTab.test.tsx b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataAlertingTab.test.tsx index a261687ea1c..7a3ccdd4f4c 100644 --- a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataAlertingTab.test.tsx +++ b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataAlertingTab.test.tsx @@ -5,6 +5,7 @@ import { TestProvider } from 'test/helpers/TestProvider'; import { byTestId } from 'testing-library-selector'; import { DataSourceApi } from '@grafana/data'; +import { PromOptions, PrometheusDatasource } from '@grafana/prometheus'; import { locationService, setDataSourceSrv } from '@grafana/runtime'; import { fetchRules } from 'app/features/alerting/unified/api/prometheus'; import { fetchRulerRules } from 'app/features/alerting/unified/api/ruler'; @@ -24,8 +25,6 @@ import { Annotation } from 'app/features/alerting/unified/utils/constants'; import { DataSourceType, GRAFANA_RULES_SOURCE_NAME } from 'app/features/alerting/unified/utils/datasource'; import { DashboardModel, PanelModel } from 'app/features/dashboard/state'; import { getDatasourceSrv } from 'app/features/plugins/datasource_srv'; -import { PrometheusDatasource } from 'app/plugins/datasource/prometheus/datasource'; -import { PromOptions } from 'app/plugins/datasource/prometheus/types'; import { configureStore } from 'app/store/configureStore'; import { AccessControlAction } from 'app/types'; import { AlertQuery } from 'app/types/unified-alerting-dto'; diff --git a/public/app/features/dashboard/state/DashboardModel.ts b/public/app/features/dashboard/state/DashboardModel.ts index a4b2600dc5f..e8f75cd8262 100644 --- a/public/app/features/dashboard/state/DashboardModel.ts +++ b/public/app/features/dashboard/state/DashboardModel.ts @@ -17,6 +17,7 @@ import { TypedVariableModel, UrlQueryValue, } from '@grafana/data'; +import { PromQuery } from '@grafana/prometheus'; import { RefreshEvent, TimeRangeUpdatedEvent, config } from '@grafana/runtime'; import { Dashboard, DashboardLink } from '@grafana/schema'; import { DEFAULT_ANNOTATION_COLOR } from '@grafana/ui'; @@ -27,7 +28,6 @@ import { isAngularDatasourcePluginAndNotHidden } from 'app/features/plugins/angu import { variableAdapters } from 'app/features/variables/adapters'; import { onTimeRangeUpdated } from 'app/features/variables/state/actions'; import { GetVariables, getVariablesByKey } from 'app/features/variables/state/selectors'; -import { PromQuery } from 'app/plugins/datasource/prometheus/types'; import { CoreEvents, DashboardMeta, KioskMode } from 'app/types'; import { DashboardMetaChangedEvent, DashboardPanelsChangedEvent, RenderEvent } from 'app/types/events'; diff --git a/public/app/features/explore/PrometheusListView/ItemLabels.tsx b/public/app/features/explore/PrometheusListView/ItemLabels.tsx index a3630f2e650..453edc18e4c 100644 --- a/public/app/features/explore/PrometheusListView/ItemLabels.tsx +++ b/public/app/features/explore/PrometheusListView/ItemLabels.tsx @@ -2,10 +2,9 @@ import { css } from '@emotion/css'; import React from 'react'; import { Field, GrafanaTheme2 } from '@grafana/data/'; +import { InstantQueryRefIdIndex } from '@grafana/prometheus'; import { useStyles2 } from '@grafana/ui/'; -import { InstantQueryRefIdIndex } from '../../../plugins/datasource/prometheus/datasource'; - import { rawListItemColumnWidth } from './RawListItem'; const getItemLabelsStyles = (theme: GrafanaTheme2, expanded: boolean) => { diff --git a/public/app/features/explore/TraceView/createSpanLink.tsx b/public/app/features/explore/TraceView/createSpanLink.tsx index 7b9cdd06c76..c7b840d683a 100644 --- a/public/app/features/explore/TraceView/createSpanLink.tsx +++ b/public/app/features/explore/TraceView/createSpanLink.tsx @@ -20,11 +20,11 @@ import { TraceToLogsOptionsV2, TraceToLogsTag, } from '@grafana/o11y-ds-frontend'; +import { PromQuery } from '@grafana/prometheus'; import { getTemplateSrv } from '@grafana/runtime'; import { DataQuery } from '@grafana/schema'; import { Icon } from '@grafana/ui'; import { getDatasourceSrv } from 'app/features/plugins/datasource_srv'; -import { PromQuery } from 'app/plugins/datasource/prometheus/types'; import { LokiQuery } from '../../../plugins/datasource/loki/types'; import { ExploreFieldLinkModel, getFieldLinksForExplore, getVariableUsageInfo } from '../utils/links'; diff --git a/public/app/features/trails/ActionTabs/MetricOverviewScene.tsx b/public/app/features/trails/ActionTabs/MetricOverviewScene.tsx index 799ee2c2b13..8803de661a6 100644 --- a/public/app/features/trails/ActionTabs/MetricOverviewScene.tsx +++ b/public/app/features/trails/ActionTabs/MetricOverviewScene.tsx @@ -1,5 +1,6 @@ import React from 'react'; +import { PromMetricsMetadataItem } from '@grafana/prometheus'; import { QueryVariable, SceneComponentProps, @@ -10,7 +11,6 @@ import { } from '@grafana/scenes'; import { Stack, Text, TextLink } from '@grafana/ui'; -import { PromMetricsMetadataItem } from '../../../plugins/datasource/prometheus/types'; import { ALL_VARIABLE_VALUE } from '../../variables/constants'; import { MetricScene } from '../MetricScene'; import { StatusWrapper } from '../StatusWrapper'; diff --git a/public/app/features/trails/AutomaticMetricQueries/previewPanel.ts b/public/app/features/trails/AutomaticMetricQueries/previewPanel.ts index 7b77811f2c5..e6561ba26aa 100644 --- a/public/app/features/trails/AutomaticMetricQueries/previewPanel.ts +++ b/public/app/features/trails/AutomaticMetricQueries/previewPanel.ts @@ -1,5 +1,5 @@ +import { PromQuery } from '@grafana/prometheus'; import { SceneCSSGridItem, SceneQueryRunner, SceneVariableSet } from '@grafana/scenes'; -import { PromQuery } from 'app/plugins/datasource/prometheus/types'; import { SelectMetricAction } from '../SelectMetricAction'; import { hideEmptyPreviews } from '../hideEmptyPreviews'; diff --git a/public/app/features/trails/AutomaticMetricQueries/query-generators/histogram.ts b/public/app/features/trails/AutomaticMetricQueries/query-generators/histogram.ts index 6f51f6270e2..b6fc3903c1f 100644 --- a/public/app/features/trails/AutomaticMetricQueries/query-generators/histogram.ts +++ b/public/app/features/trails/AutomaticMetricQueries/query-generators/histogram.ts @@ -1,4 +1,4 @@ -import { PromQuery } from 'app/plugins/datasource/prometheus/types'; +import { PromQuery } from '@grafana/prometheus'; import { VAR_FILTERS_EXPR, VAR_GROUP_BY_EXP, VAR_METRIC_EXPR } from '../../shared'; import { heatmapGraphBuilder } from '../graph-builders/heatmap'; diff --git a/public/app/features/trails/AutomaticMetricQueries/types.ts b/public/app/features/trails/AutomaticMetricQueries/types.ts index 0737f3bcbe0..e104dd6dab2 100644 --- a/public/app/features/trails/AutomaticMetricQueries/types.ts +++ b/public/app/features/trails/AutomaticMetricQueries/types.ts @@ -1,5 +1,5 @@ +import { PromQuery } from '@grafana/prometheus'; import { VizPanelBuilder } from '@grafana/scenes'; -import { PromQuery } from 'app/plugins/datasource/prometheus/types'; export interface AutoQueryDef { variant: string; diff --git a/public/app/features/trails/helpers/MetricDatasourceHelper.ts b/public/app/features/trails/helpers/MetricDatasourceHelper.ts index 48aa4f9c3d1..c89b4ab990d 100644 --- a/public/app/features/trails/helpers/MetricDatasourceHelper.ts +++ b/public/app/features/trails/helpers/MetricDatasourceHelper.ts @@ -1,8 +1,8 @@ import { DataSourceApi } from '@grafana/data'; import { PromMetricsMetadata, PromMetricsMetadataItem } from '@grafana/prometheus'; +import PromQlLanguageProvider from '@grafana/prometheus/src/language_provider'; import { getDataSourceSrv } from '@grafana/runtime'; -import PrometheusLanguageProvider from '../../../plugins/datasource/prometheus/language_provider'; import { DataTrail } from '../DataTrail'; import { VAR_DATASOURCE_EXPR } from '../shared'; @@ -34,7 +34,7 @@ export class MetricDatasourceHelper { private async _getMetricsMetadata() { const ds = await this.getDatasource(); - if (ds.languageProvider instanceof PrometheusLanguageProvider) { + if (ds.languageProvider instanceof PromQlLanguageProvider) { if (!ds.languageProvider.metricsMetadata) { await ds.languageProvider.start(); } diff --git a/public/app/plugins/datasource/dashboard/DashboardQueryEditor.tsx b/public/app/plugins/datasource/dashboard/DashboardQueryEditor.tsx index b43d0363169..589a532f349 100644 --- a/public/app/plugins/datasource/dashboard/DashboardQueryEditor.tsx +++ b/public/app/plugins/datasource/dashboard/DashboardQueryEditor.tsx @@ -5,6 +5,7 @@ import React, { useCallback, useMemo } from 'react'; import { useAsync } from 'react-use'; import { DataQuery, GrafanaTheme2, SelectableValue, DataTopic, QueryEditorProps } from '@grafana/data'; +import { OperationsEditorRow } from '@grafana/experimental'; import { Field, Select, useStyles2, Spinner, RadioButtonGroup, Stack, InlineSwitch } from '@grafana/ui'; import config from 'app/core/config'; import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv'; @@ -12,8 +13,6 @@ import { PanelModel } from 'app/features/dashboard/state'; import { getDatasourceSrv } from 'app/features/plugins/datasource_srv'; import { filterPanelDataToQuery } from 'app/features/query/components/QueryEditorRow'; -import { OperationsEditorRow } from '../prometheus/querybuilder/shared/OperationsEditorRow'; - import { DashboardDatasource } from './datasource'; import { DashboardQuery, ResultInfo, SHARED_DASHBOARD_QUERY } from './types'; diff --git a/public/app/plugins/datasource/prometheus/add_label_to_query.test.ts b/public/app/plugins/datasource/prometheus/add_label_to_query.test.ts deleted file mode 100644 index 08c32e3c398..00000000000 --- a/public/app/plugins/datasource/prometheus/add_label_to_query.test.ts +++ /dev/null @@ -1,114 +0,0 @@ -import { addLabelToQuery } from './add_label_to_query'; - -describe('addLabelToQuery()', () => { - it('should add label to simple query', () => { - expect(() => { - addLabelToQuery('foo', '', ''); - }).toThrow(); - expect(addLabelToQuery('foo', 'bar', 'baz')).toBe('foo{bar="baz"}'); - expect(addLabelToQuery('foo{}', 'bar', 'baz')).toBe('foo{bar="baz"}'); - expect(addLabelToQuery('foo{x="yy"}', 'bar', 'baz')).toBe('foo{x="yy", bar="baz"}'); - expect(addLabelToQuery('metric > 0.001', 'foo', 'bar')).toBe('metric{foo="bar"} > 0.001'); - }); - - it('should add custom operator', () => { - expect(addLabelToQuery('foo{}', 'bar', 'baz', '!=')).toBe('foo{bar!="baz"}'); - expect(addLabelToQuery('foo{x="yy"}', 'bar', 'baz', '!=')).toBe('foo{x="yy", bar!="baz"}'); - }); - - it('should not modify ranges', () => { - expect(addLabelToQuery('rate(metric[1m])', 'foo', 'bar')).toBe('rate(metric{foo="bar"}[1m])'); - }); - - it('should detect in-order function use', () => { - expect(addLabelToQuery('sum by (xx) (foo)', 'bar', 'baz')).toBe('sum by (xx) (foo{bar="baz"})'); - }); - - it('should convert number Infinity to +Inf', () => { - expect( - addLabelToQuery('sum(rate(prometheus_tsdb_compaction_chunk_size_bytes_bucket[5m])) by (le)', 'le', Infinity) - ).toBe('sum(rate(prometheus_tsdb_compaction_chunk_size_bytes_bucket{le="+Inf"}[5m])) by (le)'); - }); - - it('should handle selectors with punctuation', () => { - expect(addLabelToQuery('foo{instance="my-host.com:9100"}', 'bar', 'baz')).toBe( - 'foo{instance="my-host.com:9100", bar="baz"}' - ); - expect(addLabelToQuery('foo:metric:rate1m', 'bar', 'baz')).toBe('foo:metric:rate1m{bar="baz"}'); - expect(addLabelToQuery('avg(foo:metric:rate1m{a="b"})', 'bar', 'baz')).toBe( - 'avg(foo:metric:rate1m{a="b", bar="baz"})' - ); - expect(addLabelToQuery('foo{list="a,b,c"}', 'bar', 'baz')).toBe('foo{list="a,b,c", bar="baz"}'); - }); - - it('should work on arithmetical expressions', () => { - expect(addLabelToQuery('foo + foo', 'bar', 'baz')).toBe('foo{bar="baz"} + foo{bar="baz"}'); - expect(addLabelToQuery('foo{x="yy"} + metric', 'bar', 'baz')).toBe('foo{x="yy", bar="baz"} + metric{bar="baz"}'); - expect(addLabelToQuery('avg(foo) + sum(xx_yy)', 'bar', 'baz')).toBe('avg(foo{bar="baz"}) + sum(xx_yy{bar="baz"})'); - expect(addLabelToQuery('foo{x="yy"} * metric{y="zz",a="bb"} * metric2', 'bar', 'baz')).toBe( - 'foo{x="yy", bar="baz"} * metric{y="zz", a="bb", bar="baz"} * metric2{bar="baz"}' - ); - }); - - it('should not add duplicate labels to a query', () => { - expect(addLabelToQuery(addLabelToQuery('foo{x="yy"}', 'bar', 'baz', '!='), 'bar', 'baz', '!=')).toBe( - 'foo{x="yy", bar!="baz"}' - ); - expect(addLabelToQuery(addLabelToQuery('rate(metric[1m])', 'foo', 'bar'), 'foo', 'bar')).toBe( - 'rate(metric{foo="bar"}[1m])' - ); - expect(addLabelToQuery(addLabelToQuery('foo{list="a,b,c"}', 'bar', 'baz'), 'bar', 'baz')).toBe( - 'foo{list="a,b,c", bar="baz"}' - ); - expect(addLabelToQuery(addLabelToQuery('avg(foo) + sum(xx_yy)', 'bar', 'baz'), 'bar', 'baz')).toBe( - 'avg(foo{bar="baz"}) + sum(xx_yy{bar="baz"})' - ); - }); - - it('should not remove filters', () => { - expect(addLabelToQuery('{x="y"} |="yy"', 'bar', 'baz')).toBe('{x="y", bar="baz"} |="yy"'); - expect(addLabelToQuery('{x="y"} |="yy" !~"xx"', 'bar', 'baz')).toBe('{x="y", bar="baz"} |="yy" !~"xx"'); - }); - - it('should add labels to metrics with logical operators', () => { - expect(addLabelToQuery('foo_info or bar_info', 'bar', 'baz')).toBe('foo_info{bar="baz"} or bar_info{bar="baz"}'); - expect(addLabelToQuery('foo_info and bar_info', 'bar', 'baz')).toBe('foo_info{bar="baz"} and bar_info{bar="baz"}'); - }); - - it('should not add ad-hoc filter to template variables', () => { - expect(addLabelToQuery('sum(rate({job="foo"}[2m])) by (value $variable)', 'bar', 'baz')).toBe( - 'sum(rate({job="foo", bar="baz"}[2m])) by (value $variable)' - ); - }); - - it('should not add ad-hoc filter to range', () => { - expect(addLabelToQuery('avg(rate((my_metric{job="foo"} > 0)[3h:])) by (label)', 'bar', 'baz')).toBe( - 'avg(rate((my_metric{job="foo", bar="baz"} > 0)[3h:])) by (label)' - ); - }); - it('should not add ad-hoc filter to labels in label list provided with the group modifier', () => { - expect( - addLabelToQuery( - 'max by (id, name, type) (my_metric{type=~"foo|bar|baz-test"}) * on(id) group_right(id, type, name) sum by (id) (my_metric) * 1000', - 'bar', - 'baz' - ) - ).toBe( - 'max by (id, name, type) (my_metric{type=~"foo|bar|baz-test", bar="baz"}) * on(id) group_right(id, type, name) sum by (id) (my_metric{bar="baz"}) * 1000' - ); - }); - it('should not add ad-hoc filter to labels in label list provided with the group modifier', () => { - expect(addLabelToQuery('rate(my_metric[${__range_s}s])', 'bar', 'baz')).toBe( - 'rate(my_metric{bar="baz"}[${__range_s}s])' - ); - }); - it('should not add ad-hoc filter to labels to math operations', () => { - expect(addLabelToQuery('count(my_metric{job!="foo"} < (5*1024*1024*1024) or vector(0)) - 1', 'bar', 'baz')).toBe( - 'count(my_metric{job!="foo", bar="baz"} < (5*1024*1024*1024) or vector(0)) - 1' - ); - }); - - it('should not add ad-hoc filter bool operator', () => { - expect(addLabelToQuery('ALERTS < bool 1', 'bar', 'baz')).toBe('ALERTS{bar="baz"} < bool 1'); - }); -}); diff --git a/public/app/plugins/datasource/prometheus/add_label_to_query.ts b/public/app/plugins/datasource/prometheus/add_label_to_query.ts deleted file mode 100644 index 696e0cbb8dc..00000000000 --- a/public/app/plugins/datasource/prometheus/add_label_to_query.ts +++ /dev/null @@ -1,100 +0,0 @@ -import { parser, VectorSelector } from '@prometheus-io/lezer-promql'; - -import { PromQueryModeller } from './querybuilder/PromQueryModeller'; -import { buildVisualQueryFromString } from './querybuilder/parsing'; -import { QueryBuilderLabelFilter } from './querybuilder/shared/types'; -import { PromVisualQuery } from './querybuilder/types'; - -/** - * Adds label filter to existing query. Useful for query modification for example for ad hoc filters. - * - * It uses PromQL parser to find instances of metric and labels, alters them and then splices them back into the query. - * Ideally we could use the parse -> change -> render is a simple 3 steps but right now building the visual query - * object does not support all possible queries. - * - * So instead this just operates on substrings of the query with labels and operates just on those. This makes this - * more robust and can alter even invalid queries, and preserves in general the query structure and whitespace. - * @param query - * @param key - * @param value - * @param operator - */ -export function addLabelToQuery(query: string, key: string, value: string | number, operator = '='): string { - if (!key || !value) { - throw new Error('Need label to add to query.'); - } - - const vectorSelectorPositions = getVectorSelectorPositions(query); - if (!vectorSelectorPositions.length) { - return query; - } - - const filter = toLabelFilter(key, value, operator); - return addFilter(query, vectorSelectorPositions, filter); -} - -type VectorSelectorPosition = { from: number; to: number; query: PromVisualQuery }; - -/** - * Parse the string and get all VectorSelector positions in the query together with parsed representation of the vector - * selector. - * @param query - */ -function getVectorSelectorPositions(query: string): VectorSelectorPosition[] { - const tree = parser.parse(query); - const positions: VectorSelectorPosition[] = []; - tree.iterate({ - enter: ({ to, from, type }): false | void => { - if (type.id === VectorSelector) { - const visQuery = buildVisualQueryFromString(query.substring(from, to)); - positions.push({ query: visQuery.query, from, to }); - return false; - } - }, - }); - return positions; -} - -function toLabelFilter(key: string, value: string | number, operator: string): QueryBuilderLabelFilter { - // We need to make sure that we convert the value back to string because it may be a number - const transformedValue = value === Infinity ? '+Inf' : value.toString(); - return { label: key, op: operator, value: transformedValue }; -} - -function addFilter( - query: string, - vectorSelectorPositions: VectorSelectorPosition[], - filter: QueryBuilderLabelFilter -): string { - const modeller = new PromQueryModeller(); - let newQuery = ''; - let prev = 0; - - for (let i = 0; i < vectorSelectorPositions.length; i++) { - // This is basically just doing splice on a string for each matched vector selector. - - const match = vectorSelectorPositions[i]; - const isLast = i === vectorSelectorPositions.length - 1; - - const start = query.substring(prev, match.from); - const end = isLast ? query.substring(match.to) : ''; - - if (!labelExists(match.query.labels, filter)) { - // We don't want to add duplicate labels. - match.query.labels.push(filter); - } - const newLabels = modeller.renderQuery(match.query); - newQuery += start + newLabels + end; - prev = match.to; - } - return newQuery; -} - -/** - * Check if label exists in the list of labels but ignore the operator. - * @param labels - * @param filter - */ -function labelExists(labels: QueryBuilderLabelFilter[], filter: QueryBuilderLabelFilter) { - return labels.find((label) => label.label === filter.label && label.value === filter.value); -} diff --git a/public/app/plugins/datasource/prometheus/components/AnnotationQueryEditor.tsx b/public/app/plugins/datasource/prometheus/components/AnnotationQueryEditor.tsx deleted file mode 100644 index 0cbaf5978cd..00000000000 --- a/public/app/plugins/datasource/prometheus/components/AnnotationQueryEditor.tsx +++ /dev/null @@ -1,139 +0,0 @@ -import React from 'react'; - -import { AnnotationQuery } from '@grafana/data'; -import { selectors } from '@grafana/e2e-selectors'; -import { EditorField, EditorRow, EditorRows, EditorSwitch } from '@grafana/experimental'; -import { AutoSizeInput, Input, Space } from '@grafana/ui'; - -import { PromQueryCodeEditor } from '../querybuilder/components/PromQueryCodeEditor'; -import { PromQuery } from '../types'; - -import { PromQueryEditorProps } from './types'; - -type Props = PromQueryEditorProps & { - annotation?: AnnotationQuery; - onAnnotationChange?: (annotation: AnnotationQuery) => void; -}; - -export function AnnotationQueryEditor(props: Props) { - // This is because of problematic typing. See AnnotationQueryEditorProps in grafana-data/annotations.ts. - const annotation = props.annotation!; - const onAnnotationChange = props.onAnnotationChange!; - const query = { expr: annotation.expr, refId: annotation.name, interval: annotation.step }; - - return ( - <> - - { - onAnnotationChange({ - ...annotation, - expr: query.expr, - }); - }} - /> - - - An additional lower limit for the step parameter of the Prometheus query and for the{' '} - $__interval and $__rate_interval variables. - - } - > - { - onAnnotationChange({ - ...annotation, - step: ev.currentTarget.value, - }); - }} - defaultValue={query.interval} - id={selectors.components.DataSource.Prometheus.annotations.minStep} - /> - - - - - - - { - onAnnotationChange({ - ...annotation, - titleFormat: event.currentTarget.value, - }); - }} - data-testid={selectors.components.DataSource.Prometheus.annotations.title} - /> - - - { - onAnnotationChange({ - ...annotation, - tagKeys: event.currentTarget.value, - }); - }} - data-testid={selectors.components.DataSource.Prometheus.annotations.tags} - /> - - - { - onAnnotationChange({ - ...annotation, - textFormat: event.currentTarget.value, - }); - }} - data-testid={selectors.components.DataSource.Prometheus.annotations.text} - /> - - - { - onAnnotationChange({ - ...annotation, - useValueForTime: event.currentTarget.value, - }); - }} - data-testid={selectors.components.DataSource.Prometheus.annotations.seriesValueAsTimestamp} - /> - - - - ); -} diff --git a/public/app/plugins/datasource/prometheus/components/PromCheatSheet.tsx b/public/app/plugins/datasource/prometheus/components/PromCheatSheet.tsx deleted file mode 100644 index 9142be3e1f7..00000000000 --- a/public/app/plugins/datasource/prometheus/components/PromCheatSheet.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import React from 'react'; - -import { QueryEditorHelpProps } from '@grafana/data'; - -import { PromQuery } from '../types'; - -const CHEAT_SHEET_ITEMS = [ - { - title: 'Request Rate', - expression: 'rate(http_request_total[5m])', - label: - 'Given an HTTP request counter, this query calculates the per-second average request rate over the last 5 minutes.', - }, - { - title: '95th Percentile of Request Latencies', - expression: 'histogram_quantile(0.95, sum(rate(prometheus_http_request_duration_seconds_bucket[5m])) by (le))', - label: 'Calculates the 95th percentile of HTTP request rate over 5 minute windows.', - }, - { - title: 'Alerts Firing', - expression: 'sort_desc(sum(sum_over_time(ALERTS{alertstate="firing"}[24h])) by (alertname))', - label: 'Sums up the alerts that have been firing over the last 24 hours.', - }, - { - title: 'Step', - label: - 'Defines the graph resolution using a duration format (15s, 1m, 3h, ...). Small steps create high-resolution graphs but can be slow over larger time ranges. Using a longer step lowers the resolution and smooths the graph by producing fewer datapoints. If no step is given the resolution is calculated automatically.', - }, -]; - -const PromCheatSheet = (props: QueryEditorHelpProps) => ( -
-

PromQL Cheat Sheet

- {CHEAT_SHEET_ITEMS.map((item, index) => ( -
-
{item.title}
- {item.expression ? ( - - ) : null} -
{item.label}
-
- ))} -
-); - -export default PromCheatSheet; diff --git a/public/app/plugins/datasource/prometheus/components/PromExemplarField.tsx b/public/app/plugins/datasource/prometheus/components/PromExemplarField.tsx deleted file mode 100644 index e09a6260c98..00000000000 --- a/public/app/plugins/datasource/prometheus/components/PromExemplarField.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import { css, cx } from '@emotion/css'; -import React, { useEffect, useState } from 'react'; -import { usePrevious } from 'react-use'; - -import { GrafanaTheme2 } from '@grafana/data'; -import { IconButton, InlineLabel, Tooltip, useStyles2 } from '@grafana/ui'; - -import { PrometheusDatasource } from '../datasource'; -import { PromQuery } from '../types'; - -interface Props { - onChange: (exemplar: boolean) => void; - datasource: PrometheusDatasource; - query: PromQuery; - 'data-testid'?: string; -} - -export function PromExemplarField({ datasource, onChange, query, ...rest }: Props) { - const [error, setError] = useState(null); - const styles = useStyles2(getStyles); - const prevError = usePrevious(error); - - useEffect(() => { - if (!datasource.exemplarsAvailable) { - setError('Exemplars for this query are not available'); - onChange(false); - } else if (query.instant && !query.range) { - setError('Exemplars are not available for instant queries'); - onChange(false); - } else { - setError(null); - // If error is cleared, we want to change exemplar to true - if (prevError && !error) { - onChange(true); - } - } - }, [datasource.exemplarsAvailable, query.instant, query.range, onChange, prevError, error]); - - const iconButtonStyles = cx( - { - [styles.activeIcon]: !!query.exemplar, - }, - styles.eyeIcon - ); - - return ( - - -
- Exemplars - { - onChange(!query.exemplar); - }} - /> -
-
-
- ); -} - -function getStyles(theme: GrafanaTheme2) { - return { - eyeIcon: css` - margin-left: ${theme.spacing(2)}; - `, - activeIcon: css` - color: ${theme.colors.primary.main}; - `, - iconWrapper: css` - display: flex; - align-items: center; - `, - }; -} diff --git a/public/app/plugins/datasource/prometheus/components/PromExploreExtraField.test.tsx b/public/app/plugins/datasource/prometheus/components/PromExploreExtraField.test.tsx deleted file mode 100644 index 44fcd65b7a8..00000000000 --- a/public/app/plugins/datasource/prometheus/components/PromExploreExtraField.test.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { render, screen } from '@testing-library/react'; -import React from 'react'; - -import { PrometheusDatasource } from '../datasource'; -import { PromQuery } from '../types'; - -import { PromExploreExtraFieldProps, PromExploreExtraField, testIds } from './PromExploreExtraField'; - -const setup = (propOverrides?: PromExploreExtraFieldProps) => { - const query = { exemplar: false } as PromQuery; - const datasource = {} as PrometheusDatasource; - const onChange = jest.fn(); - const onRunQuery = jest.fn(); - - const props: PromExploreExtraFieldProps = { - onChange, - onRunQuery, - query, - datasource, - }; - - Object.assign(props, propOverrides); - - return render(); -}; - -describe('PromExploreExtraField', () => { - it('should render step field', () => { - setup(); - expect(screen.getByTestId(testIds.stepField)).toBeInTheDocument(); - }); - - it('should render query type field', () => { - setup(); - expect(screen.getByTestId(testIds.queryTypeField)).toBeInTheDocument(); - }); -}); diff --git a/public/app/plugins/datasource/prometheus/components/PromExploreExtraField.tsx b/public/app/plugins/datasource/prometheus/components/PromExploreExtraField.tsx deleted file mode 100644 index f4bc23d0e4d..00000000000 --- a/public/app/plugins/datasource/prometheus/components/PromExploreExtraField.tsx +++ /dev/null @@ -1,141 +0,0 @@ -import { css, cx } from '@emotion/css'; -import { isEqual } from 'lodash'; -import React, { memo, useCallback } from 'react'; -import { usePrevious } from 'react-use'; - -import { InlineFormLabel, RadioButtonGroup } from '@grafana/ui'; - -import { PrometheusDatasource } from '../datasource'; -import { PromQuery } from '../types'; - -import { PromExemplarField } from './PromExemplarField'; - -export interface PromExploreExtraFieldProps { - query: PromQuery; - onChange: (value: PromQuery) => void; - onRunQuery: () => void; - datasource: PrometheusDatasource; -} - -export const PromExploreExtraField = memo(({ query, datasource, onChange, onRunQuery }: PromExploreExtraFieldProps) => { - const rangeOptions = getQueryTypeOptions(true); - const prevQuery = usePrevious(query); - - const onExemplarChange = useCallback( - (exemplar: boolean) => { - if (!isEqual(query, prevQuery) || exemplar !== query.exemplar) { - onChange({ ...query, exemplar }); - } - }, - [prevQuery, query, onChange] - ); - - function onChangeQueryStep(interval: string) { - onChange({ ...query, interval }); - } - - function onStepChange(e: React.SyntheticEvent) { - if (e.currentTarget.value !== query.interval) { - onChangeQueryStep(e.currentTarget.value); - } - } - - function onReturnKeyDown(e: React.KeyboardEvent) { - if (e.key === 'Enter' && e.shiftKey) { - onRunQuery(); - } - } - - const onQueryTypeChange = getQueryTypeChangeHandler(query, onChange); - - return ( -
- {/*Query type field*/} -
- Query type - - -
- {/*Step field*/} -
- - Min step - - -
- - -
- ); -}); - -PromExploreExtraField.displayName = 'PromExploreExtraField'; - -export function getQueryTypeOptions(includeBoth: boolean) { - const rangeOptions = [ - { value: 'range', label: 'Range', description: 'Run query over a range of time' }, - { - value: 'instant', - label: 'Instant', - description: 'Run query against a single point in time. For this query, the "To" time is used', - }, - ]; - - if (includeBoth) { - rangeOptions.push({ value: 'both', label: 'Both', description: 'Run an Instant query and a Range query' }); - } - - return rangeOptions; -} - -export function getQueryTypeChangeHandler(query: PromQuery, onChange: (update: PromQuery) => void) { - return (queryType: string) => { - if (queryType === 'instant') { - onChange({ ...query, instant: true, range: false, exemplar: false }); - } else if (queryType === 'range') { - onChange({ ...query, instant: false, range: true }); - } else { - onChange({ ...query, instant: true, range: true }); - } - }; -} - -export const testIds = { - extraFieldEditor: 'prom-editor-extra-field', - stepField: 'prom-editor-extra-field-step', - queryTypeField: 'prom-editor-extra-field-query-type', -}; diff --git a/public/app/plugins/datasource/prometheus/components/PromQueryEditorByApp.test.tsx b/public/app/plugins/datasource/prometheus/components/PromQueryEditorByApp.test.tsx deleted file mode 100644 index e8da197c087..00000000000 --- a/public/app/plugins/datasource/prometheus/components/PromQueryEditorByApp.test.tsx +++ /dev/null @@ -1,83 +0,0 @@ -import { render, screen } from '@testing-library/react'; -import { noop } from 'lodash'; -import React from 'react'; - -import { CoreApp } from '@grafana/data'; - -import { PrometheusDatasource } from '../datasource'; - -import { PromQueryEditorByApp } from './PromQueryEditorByApp'; -import { testIds as alertingTestIds } from './PromQueryEditorForAlerting'; -import { Props } from './monaco-query-field/MonacoQueryFieldProps'; - -// the monaco-based editor uses lazy-loading and that does not work -// well with this test, and we do not need the monaco-related -// functionality in this test anyway, so we mock it out. -jest.mock('./monaco-query-field/MonacoQueryFieldLazy', () => { - const fakeQueryField = (props: Props) => { - return props.onBlur(e.currentTarget.value)} data-testid={'dummy-code-input'} type={'text'} />; - }; - return { - MonacoQueryFieldLazy: fakeQueryField, - }; -}); - -function setup(app: CoreApp): { onRunQuery: jest.Mock } { - const dataSource = { - createQuery: jest.fn((q) => q), - getInitHints: () => [], - getPrometheusTime: jest.fn((date, roundup) => 123), - getQueryHints: jest.fn(() => []), - getDebounceTimeInMilliseconds: jest.fn(() => 300), - languageProvider: { - start: () => Promise.resolve([]), - syntax: () => {}, - getLabelKeys: () => [], - metrics: [], - }, - } as unknown as PrometheusDatasource; - const onRunQuery = jest.fn(); - - render( - - ); - - return { - onRunQuery, - }; -} - -describe('PromQueryEditorByApp', () => { - it('should render simplified query editor for cloud alerting', async () => { - setup(CoreApp.CloudAlerting); - - expect(await screen.findByTestId(alertingTestIds.editor)).toBeInTheDocument(); - }); - - it('should render editor selector for unkown apps', () => { - setup(CoreApp.Unknown); - - expect(screen.getByTestId('QueryEditorModeToggle')).toBeInTheDocument(); - expect(screen.queryByTestId(alertingTestIds.editor)).toBeNull(); - }); - - it('should render editor selector for explore', () => { - setup(CoreApp.Explore); - - expect(screen.getByTestId('QueryEditorModeToggle')).toBeInTheDocument(); - expect(screen.queryByTestId(alertingTestIds.editor)).toBeNull(); - }); - - it('should render editor selector for dashboard', () => { - setup(CoreApp.Dashboard); - - expect(screen.getByTestId('QueryEditorModeToggle')).toBeInTheDocument(); - expect(screen.queryByTestId(alertingTestIds.editor)).toBeNull(); - }); -}); diff --git a/public/app/plugins/datasource/prometheus/components/PromQueryEditorByApp.tsx b/public/app/plugins/datasource/prometheus/components/PromQueryEditorByApp.tsx deleted file mode 100644 index f10a6e3279a..00000000000 --- a/public/app/plugins/datasource/prometheus/components/PromQueryEditorByApp.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import React, { memo } from 'react'; - -import { CoreApp } from '@grafana/data'; - -import { PromQueryEditorSelector } from '../querybuilder/components/PromQueryEditorSelector'; - -import { PromQueryEditorForAlerting } from './PromQueryEditorForAlerting'; -import { PromQueryEditorProps } from './types'; - -export function PromQueryEditorByApp(props: PromQueryEditorProps) { - const { app } = props; - - switch (app) { - case CoreApp.CloudAlerting: - return ; - default: - return ; - } -} - -export default memo(PromQueryEditorByApp); diff --git a/public/app/plugins/datasource/prometheus/components/PromQueryEditorForAlerting.tsx b/public/app/plugins/datasource/prometheus/components/PromQueryEditorForAlerting.tsx deleted file mode 100644 index b7b57071d8e..00000000000 --- a/public/app/plugins/datasource/prometheus/components/PromQueryEditorForAlerting.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import React from 'react'; - -import PromQueryField from './PromQueryField'; -import { PromQueryEditorProps } from './types'; - -export function PromQueryEditorForAlerting(props: PromQueryEditorProps) { - const { datasource, query, range, data, onChange, onRunQuery } = props; - - return ( - - ); -} - -export const testIds = { - editor: 'prom-editor-cloud-alerting', -}; diff --git a/public/app/plugins/datasource/prometheus/components/PromQueryField.test.tsx b/public/app/plugins/datasource/prometheus/components/PromQueryField.test.tsx deleted file mode 100644 index 5c8393649a0..00000000000 --- a/public/app/plugins/datasource/prometheus/components/PromQueryField.test.tsx +++ /dev/null @@ -1,183 +0,0 @@ -import { getByTestId, render, screen, waitFor } from '@testing-library/react'; -// @ts-ignore -import userEvent from '@testing-library/user-event'; -import React from 'react'; - -import { PanelData, LoadingState, DataFrame, CoreApp } from '@grafana/data'; - -import { PrometheusDatasource } from '../datasource'; -import PromQlLanguageProvider from '../language_provider'; - -import PromQueryField from './PromQueryField'; -import { Props } from './monaco-query-field/MonacoQueryFieldProps'; - -// the monaco-based editor uses lazy-loading and that does not work -// well with this test, and we do not need the monaco-related -// functionality in this test anyway, so we mock it out. -jest.mock('./monaco-query-field/MonacoQueryFieldLazy', () => { - const fakeQueryField = (props: Props) => { - return props.onBlur(e.currentTarget.value)} data-testid={'dummy-code-input'} type={'text'} />; - }; - return { - MonacoQueryFieldLazy: fakeQueryField, - }; -}); - -const defaultProps = { - datasource: { - languageProvider: { - start: () => Promise.resolve([]), - syntax: () => {}, - getLabelKeys: () => [], - metrics: [], - }, - getInitHints: () => [], - } as unknown as PrometheusDatasource, - query: { - expr: '', - refId: '', - }, - onRunQuery: () => {}, - onChange: () => {}, - history: [], -}; - -describe('PromQueryField', () => { - beforeAll(() => { - // @ts-ignore - window.getSelection = () => {}; - }); - - it('renders metrics chooser regularly if lookups are not disabled in the datasource settings', async () => { - const queryField = render(); - - // wait for component to render - await screen.findByRole('button'); - - expect(queryField.getAllByRole('button')).toHaveLength(1); - }); - - it('renders a disabled metrics chooser if lookups are disabled in datasource settings', async () => { - const props = defaultProps; - props.datasource.lookupsDisabled = true; - const queryField = render(); - - // wait for component to render - await screen.findByRole('button'); - - const bcButton = queryField.getByRole('button'); - expect(bcButton).toBeDisabled(); - }); - - it('renders an initial hint if no data and initial hint provided', async () => { - const props = defaultProps; - props.datasource.lookupsDisabled = true; - props.datasource.getInitHints = () => [{ label: 'Initial hint', type: 'INFO' }]; - render(); - - // wait for component to render - await screen.findByRole('button'); - - expect(screen.getByText('Initial hint')).toBeInTheDocument(); - }); - - it('renders query hint if data, query hint and initial hint provided', async () => { - const props = defaultProps; - props.datasource.lookupsDisabled = true; - props.datasource.getInitHints = () => [{ label: 'Initial hint', type: 'INFO' }]; - props.datasource.getQueryHints = () => [{ label: 'Query hint', type: 'INFO' }]; - render( - - ); - - // wait for component to render - await screen.findByRole('button'); - - expect(screen.getByText('Query hint')).toBeInTheDocument(); - expect(screen.queryByText('Initial hint')).not.toBeInTheDocument(); - }); - - it('refreshes metrics when the data source changes', async () => { - const defaultProps = { - query: { expr: '', refId: '' }, - onRunQuery: () => {}, - onChange: () => {}, - history: [], - }; - const metrics = ['foo', 'bar']; - const queryField = render( - [], - } as unknown as PrometheusDatasource - } - {...defaultProps} - /> - ); - - // wait for component to render - await screen.findByRole('button'); - - const changedMetrics = ['baz', 'moo']; - queryField.rerender( - - ); - - // If we check the label browser right away it should be in loading state - let labelBrowser = screen.getByRole('button'); - expect(labelBrowser).toHaveTextContent('Loading'); - - // wait for component to rerender - labelBrowser = await screen.findByRole('button'); - await waitFor(() => { - expect(labelBrowser).toHaveTextContent('Metrics browser'); - }); - }); - - it('should not run query onBlur', async () => { - const onRunQuery = jest.fn(); - const { container } = render(); - - // wait for component to rerender - await screen.findByRole('button'); - - const input = getByTestId(container, 'dummy-code-input'); - expect(input).toBeInTheDocument(); - await userEvent.type(input, 'metric'); - - // blur element - await userEvent.click(document.body); - expect(onRunQuery).not.toHaveBeenCalled(); - }); -}); - -function makeLanguageProvider(options: { metrics: string[][] }) { - const metricsStack = [...options.metrics]; - return { - histogramMetrics: [], - metrics: [], - metricsMetadata: {}, - lookupsDisabled: false, - getLabelKeys: () => [], - start() { - this.metrics = metricsStack.shift(); - return Promise.resolve([]); - }, - } as any as PromQlLanguageProvider; -} diff --git a/public/app/plugins/datasource/prometheus/components/PromQueryField.tsx b/public/app/plugins/datasource/prometheus/components/PromQueryField.tsx deleted file mode 100644 index 496322a5a7d..00000000000 --- a/public/app/plugins/datasource/prometheus/components/PromQueryField.tsx +++ /dev/null @@ -1,290 +0,0 @@ -import { cx } from '@emotion/css'; -import React, { ReactNode } from 'react'; - -import { isDataFrame, QueryEditorProps, QueryHint, TimeRange, toLegacyResponseData } from '@grafana/data'; -import { selectors } from '@grafana/e2e-selectors'; -import { reportInteraction } from '@grafana/runtime'; -import { Icon, Themeable2, withTheme2, clearButtonStyles } from '@grafana/ui'; -import { LocalStorageValueProvider } from 'app/core/components/LocalStorageValueProvider'; -import { - CancelablePromise, - isCancelablePromiseRejection, - makePromiseCancelable, -} from 'app/core/utils/CancelablePromise'; - -import { PrometheusDatasource } from '../datasource'; -import { roundMsToMin } from '../language_utils'; -import { PromOptions, PromQuery } from '../types'; - -import { PrometheusMetricsBrowser } from './PrometheusMetricsBrowser'; -import { MonacoQueryFieldWrapper } from './monaco-query-field/MonacoQueryFieldWrapper'; - -const LAST_USED_LABELS_KEY = 'grafana.datasources.prometheus.browser.labels'; - -function getChooserText(metricsLookupDisabled: boolean, hasSyntax: boolean, hasMetrics: boolean) { - if (metricsLookupDisabled) { - return '(Disabled)'; - } - - if (!hasSyntax) { - return 'Loading metrics...'; - } - - if (!hasMetrics) { - return '(No metrics found)'; - } - - return 'Metrics browser'; -} - -interface PromQueryFieldProps extends QueryEditorProps, Themeable2 { - ExtraFieldElement?: ReactNode; - 'data-testid'?: string; -} - -interface PromQueryFieldState { - labelBrowserVisible: boolean; - syntaxLoaded: boolean; - hint: QueryHint | null; -} - -class PromQueryField extends React.PureComponent { - declare languageProviderInitializationPromise: CancelablePromise; - - constructor(props: PromQueryFieldProps) { - super(props); - - this.state = { - labelBrowserVisible: false, - syntaxLoaded: false, - hint: null, - }; - } - - componentDidMount() { - if (this.props.datasource.languageProvider) { - this.refreshMetrics(); - } - this.refreshHint(); - } - - componentWillUnmount() { - if (this.languageProviderInitializationPromise) { - this.languageProviderInitializationPromise.cancel(); - } - } - - componentDidUpdate(prevProps: PromQueryFieldProps) { - const { - data, - datasource: { languageProvider }, - range, - } = this.props; - - if (languageProvider !== prevProps.datasource.languageProvider) { - // We reset this only on DS change so we do not flesh loading state on every rangeChange which happens on every - // query run if using relative range. - this.setState({ - syntaxLoaded: false, - }); - } - - const changedRangeToRefresh = this.rangeChangedToRefresh(range, prevProps.range); - // We want to refresh metrics when language provider changes and/or when range changes (we round up intervals to a minute) - if (languageProvider !== prevProps.datasource.languageProvider || changedRangeToRefresh) { - this.refreshMetrics(); - } - - if (data && prevProps.data && prevProps.data.series !== data.series) { - this.refreshHint(); - } - } - - refreshHint = () => { - const { datasource, query, data } = this.props; - const initHints = datasource.getInitHints(); - const initHint = initHints.length > 0 ? initHints[0] : null; - - if (!data || data.series.length === 0) { - this.setState({ - hint: initHint, - }); - return; - } - - const result = isDataFrame(data.series[0]) ? data.series.map(toLegacyResponseData) : data.series; - const queryHints = datasource.getQueryHints(query, result); - let queryHint = queryHints.length > 0 ? queryHints[0] : null; - - this.setState({ hint: queryHint ?? initHint }); - }; - - refreshMetrics = async () => { - const { - range, - datasource: { languageProvider }, - } = this.props; - - this.languageProviderInitializationPromise = makePromiseCancelable(languageProvider.start(range)); - - try { - const remainingTasks = await this.languageProviderInitializationPromise.promise; - await Promise.all(remainingTasks); - this.onUpdateLanguage(); - } catch (err) { - if (isCancelablePromiseRejection(err) && err.isCanceled) { - // do nothing, promise was canceled - } else { - throw err; - } - } - }; - - rangeChangedToRefresh(range?: TimeRange, prevRange?: TimeRange): boolean { - if (range && prevRange) { - const sameMinuteFrom = roundMsToMin(range.from.valueOf()) === roundMsToMin(prevRange.from.valueOf()); - const sameMinuteTo = roundMsToMin(range.to.valueOf()) === roundMsToMin(prevRange.to.valueOf()); - // If both are same, don't need to refresh. - return !(sameMinuteFrom && sameMinuteTo); - } - return false; - } - - /** - * TODO #33976: Remove this, add histogram group (query = `histogram_quantile(0.95, sum(rate(${metric}[5m])) by (le))`;) - */ - onChangeLabelBrowser = (selector: string) => { - this.onChangeQuery(selector, true); - this.setState({ labelBrowserVisible: false }); - }; - - onChangeQuery = (value: string, override?: boolean) => { - // Send text change to parent - const { query, onChange, onRunQuery } = this.props; - if (onChange) { - const nextQuery: PromQuery = { ...query, expr: value }; - onChange(nextQuery); - - if (override && onRunQuery) { - onRunQuery(); - } - } - }; - - onClickChooserButton = () => { - this.setState((state) => ({ labelBrowserVisible: !state.labelBrowserVisible })); - - reportInteraction('user_grafana_prometheus_metrics_browser_clicked', { - editorMode: this.state.labelBrowserVisible ? 'metricViewClosed' : 'metricViewOpen', - app: this.props?.app ?? '', - }); - }; - - onClickHintFix = () => { - const { datasource, query, onChange, onRunQuery } = this.props; - const { hint } = this.state; - if (hint?.fix?.action) { - onChange(datasource.modifyQuery(query, hint.fix.action)); - } - onRunQuery(); - }; - - onUpdateLanguage = () => { - const { - datasource: { languageProvider }, - } = this.props; - const { metrics } = languageProvider; - - if (!metrics) { - return; - } - - this.setState({ syntaxLoaded: true }); - }; - - render() { - const { - datasource, - datasource: { languageProvider }, - query, - ExtraFieldElement, - history = [], - theme, - } = this.props; - - const { labelBrowserVisible, syntaxLoaded, hint } = this.state; - const hasMetrics = languageProvider.metrics.length > 0; - const chooserText = getChooserText(datasource.lookupsDisabled, syntaxLoaded, hasMetrics); - const buttonDisabled = !(syntaxLoaded && hasMetrics); - - return ( - storageKey={LAST_USED_LABELS_KEY} defaultValue={[]}> - {(lastUsedLabels, onLastUsedLabelsSave, onLastUsedLabelsDelete) => { - return ( - <> -
- - -
- -
-
- {labelBrowserVisible && ( -
- -
- )} - - {ExtraFieldElement} - {hint ? ( -
-
- {hint.label}{' '} - {hint.fix ? ( - - ) : null} -
-
- ) : null} - - ); - }} - - ); - } -} - -export default withTheme2(PromQueryField); diff --git a/public/app/plugins/datasource/prometheus/components/PrometheusMetricsBrowser.test.tsx b/public/app/plugins/datasource/prometheus/components/PrometheusMetricsBrowser.test.tsx deleted file mode 100644 index b5cc16744a8..00000000000 --- a/public/app/plugins/datasource/prometheus/components/PrometheusMetricsBrowser.test.tsx +++ /dev/null @@ -1,324 +0,0 @@ -import { render, screen, waitFor } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; -import React from 'react'; - -import { createTheme } from '@grafana/data'; - -import PromQlLanguageProvider from '../language_provider'; - -import { - buildSelector, - facetLabels, - SelectableLabel, - UnthemedPrometheusMetricsBrowser, - BrowserProps, -} from './PrometheusMetricsBrowser'; - -describe('buildSelector()', () => { - it('returns an empty selector for no labels', () => { - expect(buildSelector([])).toEqual('{}'); - }); - it('returns an empty selector for selected labels with no values', () => { - const labels: SelectableLabel[] = [{ name: 'foo', selected: true }]; - expect(buildSelector(labels)).toEqual('{}'); - }); - it('returns an empty selector for one selected label with no selected values', () => { - const labels: SelectableLabel[] = [{ name: 'foo', selected: true, values: [{ name: 'bar' }] }]; - expect(buildSelector(labels)).toEqual('{}'); - }); - it('returns a simple selector from a selected label with a selected value', () => { - const labels: SelectableLabel[] = [{ name: 'foo', selected: true, values: [{ name: 'bar', selected: true }] }]; - expect(buildSelector(labels)).toEqual('{foo="bar"}'); - }); - it('metric selector without labels', () => { - const labels: SelectableLabel[] = [{ name: '__name__', selected: true, values: [{ name: 'foo', selected: true }] }]; - expect(buildSelector(labels)).toEqual('foo{}'); - }); - it('selector with multiple metrics', () => { - const labels: SelectableLabel[] = [ - { - name: '__name__', - selected: true, - values: [ - { name: 'foo', selected: true }, - { name: 'bar', selected: true }, - ], - }, - ]; - expect(buildSelector(labels)).toEqual('{__name__=~"foo|bar"}'); - }); - it('metric selector with labels', () => { - const labels: SelectableLabel[] = [ - { name: '__name__', selected: true, values: [{ name: 'foo', selected: true }] }, - { name: 'bar', selected: true, values: [{ name: 'baz', selected: true }] }, - ]; - expect(buildSelector(labels)).toEqual('foo{bar="baz"}'); - }); -}); - -describe('facetLabels()', () => { - const possibleLabels = { - cluster: ['dev'], - namespace: ['alertmanager'], - }; - const labels: SelectableLabel[] = [ - { name: 'foo', selected: true, values: [{ name: 'bar' }] }, - { name: 'cluster', values: [{ name: 'dev' }, { name: 'ops' }, { name: 'prod' }] }, - { name: 'namespace', values: [{ name: 'alertmanager' }] }, - ]; - - it('returns no labels given an empty label set', () => { - expect(facetLabels([], {})).toEqual([]); - }); - - it('marks all labels as hidden when no labels are possible', () => { - const result = facetLabels(labels, {}); - expect(result.length).toEqual(labels.length); - expect(result[0].hidden).toBeTruthy(); - expect(result[0].values).toBeUndefined(); - }); - - it('keeps values as facetted when they are possible', () => { - const result = facetLabels(labels, possibleLabels); - expect(result.length).toEqual(labels.length); - expect(result[0].hidden).toBeTruthy(); - expect(result[0].values).toBeUndefined(); - expect(result[1].hidden).toBeFalsy(); - expect(result[1].values!.length).toBe(1); - expect(result[1].values![0].name).toBe('dev'); - }); - - it('does not facet out label values that are currently being facetted', () => { - const result = facetLabels(labels, possibleLabels, 'cluster'); - expect(result.length).toEqual(labels.length); - expect(result[0].hidden).toBeTruthy(); - expect(result[1].hidden).toBeFalsy(); - // 'cluster' is being facetted, should show all 3 options even though only 1 is possible - expect(result[1].values!.length).toBe(3); - expect(result[2].values!.length).toBe(1); - }); -}); - -describe('PrometheusMetricsBrowser', () => { - const setupProps = (): BrowserProps => { - const mockLanguageProvider = { - start: () => Promise.resolve(), - getLabelValues: (name: string) => { - switch (name) { - case 'label1': - return ['value1-1', 'value1-2']; - case 'label2': - return ['value2-1', 'value2-2']; - case 'label3': - return ['value3-1', 'value3-2']; - } - return []; - }, - // This must always call the series endpoint - // until we refactor all of the metrics browser - // to never use the series endpoint. - // The metrics browser expects both label names and label values. - // The labels endpoint with match does not supply label values - // and so using it breaks the metrics browser. - fetchSeriesLabels: (selector: string) => { - switch (selector) { - case '{label1="value1-1"}': - return { label1: ['value1-1'], label2: ['value2-1'], label3: ['value3-1'] }; - case '{label1=~"value1-1|value1-2"}': - return { label1: ['value1-1', 'value1-2'], label2: ['value2-1'], label3: ['value3-1', 'value3-2'] }; - } - // Allow full set by default - return { - label1: ['value1-1', 'value1-2'], - label2: ['value2-1', 'value2-2'], - }; - }, - getLabelKeys: () => ['label1', 'label2', 'label3'], - }; - - const defaults: BrowserProps = { - theme: createTheme({ colors: { mode: 'dark' } }), - onChange: () => {}, - autoSelect: 0, - languageProvider: mockLanguageProvider as unknown as PromQlLanguageProvider, - lastUsedLabels: [], - storeLastUsedLabels: () => {}, - deleteLastUsedLabels: () => {}, - }; - - return defaults; - }; - - // Clear label selection manually because it's saved in localStorage - afterEach(async () => { - const clearBtn = screen.getByLabelText('Selector clear button'); - await userEvent.click(clearBtn); - }); - - it('renders and loader shows when empty, and then first set of labels', async () => { - const props = setupProps(); - render(); - // Loading appears and dissappears - screen.getByText(/Loading labels/); - await waitFor(() => { - expect(screen.queryByText(/Loading labels/)).not.toBeInTheDocument(); - }); - // Initial set of labels is available and not selected - expect(screen.queryByRole('option', { name: 'label1' })).toBeInTheDocument(); - expect(screen.queryByRole('option', { name: 'label1', selected: true })).not.toBeInTheDocument(); - expect(screen.queryByRole('option', { name: 'label2' })).toBeInTheDocument(); - expect(screen.queryByRole('option', { name: 'label2', selected: true })).not.toBeInTheDocument(); - expect(screen.queryByLabelText('selector')).toHaveTextContent('{}'); - }); - - it('allows label and value selection/deselection', async () => { - const props = setupProps(); - render(); - // Selecting label2 - const label2 = await screen.findByRole('option', { name: 'label2', selected: false }); - expect(screen.queryByRole('list', { name: /Values/ })).not.toBeInTheDocument(); - await userEvent.click(label2); - expect(screen.queryByRole('option', { name: 'label2', selected: true })).toBeInTheDocument(); - // List of values for label2 appears - expect(screen.queryByLabelText(/Values for/)).toHaveTextContent('label2'); - expect(screen.queryByRole('option', { name: 'value2-1' })).toBeInTheDocument(); - expect(screen.queryByRole('option', { name: 'value2-2' })).toBeInTheDocument(); - expect(screen.queryByLabelText('selector')).toHaveTextContent('{}'); - // Selecting label1, list for its values appears - const label1 = await screen.findByRole('option', { name: 'label1', selected: false }); - await userEvent.click(label1); - expect(screen.queryByRole('option', { name: 'label1', selected: true })).toBeInTheDocument(); - await screen.findByLabelText('Values for label1'); - expect(await screen.findAllByRole('list', { name: /Values/ })).toHaveLength(2); - // Selecting value2-2 of label2 - const value = await screen.findByRole('option', { name: 'value2-2', selected: false }); - await userEvent.click(value); - await screen.findByRole('option', { name: 'value2-2', selected: true }); - expect(screen.queryByLabelText('selector')).toHaveTextContent('{label2="value2-2"}'); - // Selecting value2-1 of label2, both values now selected - const value2 = await screen.findByRole('option', { name: 'value2-1', selected: false }); - await userEvent.click(value2); - // await screen.findByRole('option', {name: 'value2-1', selected: true}); - await screen.findByText('{label2=~"value2-1|value2-2"}'); - // Deselecting value2-2, one value should remain - const selectedValue = await screen.findByRole('option', { name: 'value2-2', selected: true }); - await userEvent.click(selectedValue); - await screen.findByRole('option', { name: 'value2-1', selected: true }); - await screen.findByRole('option', { name: 'value2-2', selected: false }); - expect(screen.queryByLabelText('selector')).toHaveTextContent('{label2="value2-1"}'); - }); - - it('allows label selection from multiple labels', async () => { - const props = setupProps(); - render(); - - // Selecting label2 - const label2 = await screen.findByRole('option', { name: 'label2', selected: false }); - await userEvent.click(label2); - // List of values for label2 appears - expect(screen.queryByLabelText(/Values for/)).toHaveTextContent('label2'); - expect(screen.queryByRole('option', { name: 'value2-1' })).toBeInTheDocument(); - expect(screen.queryByRole('option', { name: 'value2-2' })).toBeInTheDocument(); - expect(screen.queryByLabelText('selector')).toHaveTextContent('{}'); - // Selecting label1, list for its values appears - const label1 = await screen.findByRole('option', { name: 'label1', selected: false }); - await userEvent.click(label1); - await screen.findByLabelText('Values for label1'); - expect(await screen.findAllByRole('list', { name: /Values/ })).toHaveLength(2); - // Selecting value2-1 of label2 - const value2 = await screen.findByRole('option', { name: 'value2-1', selected: false }); - await userEvent.click(value2); - await screen.findByText('{label2="value2-1"}'); - - // Selecting value from label1 for combined selector - const value1 = await screen.findByRole('option', { name: 'value1-2', selected: false }); - await userEvent.click(value1); - await screen.findByRole('option', { name: 'value1-2', selected: true }); - await screen.findByText('{label1="value1-2",label2="value2-1"}'); - // Deselect label1 should remove label and value - const selectedLabel = (await screen.findAllByRole('option', { name: /label1/, selected: true }))[0]; - await userEvent.click(selectedLabel); - await screen.findByRole('option', { name: /label1/, selected: false }); - expect(await screen.findAllByRole('list', { name: /Values/ })).toHaveLength(1); - expect(screen.queryByLabelText('selector')).toHaveTextContent('{label2="value2-1"}'); - }); - - it('allows clearing the label selection', async () => { - const props = setupProps(); - render(); - - // Selecting label2 - const label2 = await screen.findByRole('option', { name: 'label2', selected: false }); - await userEvent.click(label2); - // List of values for label2 appears - expect(screen.queryByLabelText(/Values for/)).toHaveTextContent('label2'); - expect(screen.queryByRole('option', { name: 'value2-1' })).toBeInTheDocument(); - expect(screen.queryByRole('option', { name: 'value2-2' })).toBeInTheDocument(); - expect(screen.queryByLabelText('selector')).toHaveTextContent('{}'); - // Selecting label1, list for its values appears - const label1 = await screen.findByRole('option', { name: 'label1', selected: false }); - await userEvent.click(label1); - await screen.findByLabelText('Values for label1'); - expect(await screen.findAllByRole('list', { name: /Values/ })).toHaveLength(2); - // Selecting value2-1 of label2 - const value2 = await screen.findByRole('option', { name: 'value2-1', selected: false }); - await userEvent.click(value2); - await screen.findByText('{label2="value2-1"}'); - - // Clear selector - const clearBtn = screen.getByLabelText('Selector clear button'); - await userEvent.click(clearBtn); - await screen.findByRole('option', { name: 'label2', selected: false }); - expect(screen.queryByLabelText('selector')).toHaveTextContent('{}'); - }); - - it('filters values by input text', async () => { - const props = setupProps(); - render(); - // Selecting label2 and label1 - const label2 = await screen.findByRole('option', { name: /label2/, selected: false }); - await userEvent.click(label2); - const label1 = await screen.findByRole('option', { name: /label1/, selected: false }); - await userEvent.click(label1); - await screen.findByLabelText('Values for label1'); - await screen.findByLabelText('Values for label2'); - expect(await screen.findAllByRole('option', { name: /value/ })).toHaveLength(4); - // Typing '1' to filter for values - await userEvent.type(screen.getByLabelText('Filter expression for label values'), '1'); - expect(screen.getByLabelText('Filter expression for label values')).toHaveValue('1'); - expect(await screen.findAllByRole('option', { name: /value/ })).toHaveLength(3); - expect(screen.queryByRole('option', { name: 'value2-2' })).not.toBeInTheDocument(); - }); - - it('facets labels', async () => { - const props = setupProps(); - render(); - // Selecting label2 and label1 - const label2 = await screen.findByRole('option', { name: /label2/, selected: false }); - await userEvent.click(label2); - const label1 = await screen.findByRole('option', { name: /label1/, selected: false }); - await userEvent.click(label1); - await screen.findByLabelText('Values for label1'); - await screen.findByLabelText('Values for label2'); - expect(await screen.findAllByRole('option', { name: /value/ })).toHaveLength(4); - expect(screen.queryByRole('option', { name: /label3/ })).toHaveTextContent('label3'); - // Click value1-1 which triggers facetting for value3-x, and still show all value1-x - const value1 = await screen.findByRole('option', { name: 'value1-1', selected: false }); - await userEvent.click(value1); - await waitFor(() => expect(screen.queryByRole('option', { name: 'value2-2' })).not.toBeInTheDocument()); - expect(screen.queryByRole('option', { name: 'value1-2' })).toBeInTheDocument(); - expect(screen.queryByLabelText('selector')).toHaveTextContent('{label1="value1-1"}'); - expect(screen.queryByRole('option', { name: /label3/ })).toHaveTextContent('label3 (1)'); - // Click value1-2 for which facetting will allow more values for value3-x - const value12 = await screen.findByRole('option', { name: 'value1-2', selected: false }); - await userEvent.click(value12); - await screen.findByRole('option', { name: 'value1-2', selected: true }); - await screen.findByRole('option', { name: /label3/, selected: false }); - await userEvent.click(screen.getByRole('option', { name: /label3/ })); - await screen.findByLabelText('Values for label3'); - expect(screen.queryByRole('option', { name: 'value1-1', selected: true })).toBeInTheDocument(); - expect(screen.queryByRole('option', { name: 'value1-2', selected: true })).toBeInTheDocument(); - expect(screen.queryByLabelText('selector')).toHaveTextContent('{label1=~"value1-1|value1-2"}'); - expect(screen.queryAllByRole('option', { name: /label3/ })[0]).toHaveTextContent('label3 (2)'); - }); -}); diff --git a/public/app/plugins/datasource/prometheus/components/PrometheusMetricsBrowser.tsx b/public/app/plugins/datasource/prometheus/components/PrometheusMetricsBrowser.tsx deleted file mode 100644 index b877843cddb..00000000000 --- a/public/app/plugins/datasource/prometheus/components/PrometheusMetricsBrowser.tsx +++ /dev/null @@ -1,684 +0,0 @@ -import { css, cx } from '@emotion/css'; -import React, { ChangeEvent } from 'react'; -import { FixedSizeList } from 'react-window'; - -import { GrafanaTheme2, TimeRange } from '@grafana/data'; -import { selectors } from '@grafana/e2e-selectors'; -import { - Button, - HorizontalGroup, - Input, - Label, - LoadingPlaceholder, - stylesFactory, - BrowserLabel as PromLabel, - withTheme2, -} from '@grafana/ui'; - -import PromQlLanguageProvider from '../language_provider'; -import { escapeLabelValueInExactSelector, escapeLabelValueInRegexSelector } from '../language_utils'; - -// Hard limit on labels to render -const EMPTY_SELECTOR = '{}'; -const METRIC_LABEL = '__name__'; -const LIST_ITEM_SIZE = 25; - -export interface BrowserProps { - languageProvider: PromQlLanguageProvider; - onChange: (selector: string) => void; - theme: GrafanaTheme2; - autoSelect?: number; - hide?: () => void; - lastUsedLabels: string[]; - storeLastUsedLabels: (labels: string[]) => void; - deleteLastUsedLabels: () => void; - timeRange?: TimeRange; -} - -interface BrowserState { - labels: SelectableLabel[]; - labelSearchTerm: string; - metricSearchTerm: string; - status: string; - error: string; - validationStatus: string; - valueSearchTerm: string; -} - -interface FacettableValue { - name: string; - selected?: boolean; - details?: string; -} - -export interface SelectableLabel { - name: string; - selected?: boolean; - loading?: boolean; - values?: FacettableValue[]; - hidden?: boolean; - facets?: number; -} - -export function buildSelector(labels: SelectableLabel[]): string { - let singleMetric = ''; - const selectedLabels = []; - for (const label of labels) { - if ((label.name === METRIC_LABEL || label.selected) && label.values && label.values.length > 0) { - const selectedValues = label.values.filter((value) => value.selected).map((value) => value.name); - if (selectedValues.length > 1) { - selectedLabels.push(`${label.name}=~"${selectedValues.map(escapeLabelValueInRegexSelector).join('|')}"`); - } else if (selectedValues.length === 1) { - if (label.name === METRIC_LABEL) { - singleMetric = selectedValues[0]; - } else { - selectedLabels.push(`${label.name}="${escapeLabelValueInExactSelector(selectedValues[0])}"`); - } - } - } - } - return [singleMetric, '{', selectedLabels.join(','), '}'].join(''); -} - -export function facetLabels( - labels: SelectableLabel[], - possibleLabels: Record, - lastFacetted?: string -): SelectableLabel[] { - return labels.map((label) => { - const possibleValues = possibleLabels[label.name]; - if (possibleValues) { - let existingValues: FacettableValue[]; - if (label.name === lastFacetted && label.values) { - // Facetting this label, show all values - existingValues = label.values; - } else { - // Keep selection in other facets - const selectedValues: Set = new Set( - label.values?.filter((value) => value.selected).map((value) => value.name) || [] - ); - // Values for this label have not been requested yet, let's use the facetted ones as the initial values - existingValues = possibleValues.map((value) => ({ name: value, selected: selectedValues.has(value) })); - } - return { - ...label, - loading: false, - values: existingValues, - hidden: !possibleValues, - facets: existingValues.length, - }; - } - - // Label is facetted out, hide all values - return { ...label, loading: false, hidden: !possibleValues, values: undefined, facets: 0 }; - }); -} - -const getStyles = stylesFactory((theme: GrafanaTheme2) => ({ - wrapper: css` - background-color: ${theme.colors.background.secondary}; - padding: ${theme.spacing(1)}; - width: 100%; - `, - list: css` - margin-top: ${theme.spacing(1)}; - display: flex; - flex-wrap: wrap; - max-height: 200px; - overflow: auto; - align-content: flex-start; - `, - section: css` - & + & { - margin: ${theme.spacing(2)} 0; - } - position: relative; - `, - selector: css` - font-family: ${theme.typography.fontFamilyMonospace}; - margin-bottom: ${theme.spacing(1)}; - `, - status: css` - padding: ${theme.spacing(0.5)}; - color: ${theme.colors.text.secondary}; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - /* using absolute positioning because flex interferes with ellipsis */ - position: absolute; - width: 50%; - right: 0; - text-align: right; - transition: opacity 100ms linear; - opacity: 0; - `, - statusShowing: css` - opacity: 1; - `, - error: css` - color: ${theme.colors.error.main}; - `, - valueList: css` - margin-right: ${theme.spacing(1)}; - resize: horizontal; - `, - valueListWrapper: css` - border-left: 1px solid ${theme.colors.border.medium}; - margin: ${theme.spacing(1)} 0; - padding: ${theme.spacing(1)} 0 ${theme.spacing(1)} ${theme.spacing(1)}; - `, - valueListArea: css` - display: flex; - flex-wrap: wrap; - margin-top: ${theme.spacing(1)}; - `, - valueTitle: css` - margin-left: -${theme.spacing(0.5)}; - margin-bottom: ${theme.spacing(1)}; - `, - validationStatus: css` - padding: ${theme.spacing(0.5)}; - margin-bottom: ${theme.spacing(1)}; - color: ${theme.colors.text.maxContrast}; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - `, -})); - -/** - * TODO #33976: Remove duplicated code. The component is very similar to LokiLabelBrowser.tsx. Check if it's possible - * to create a single, generic component. - */ -export class UnthemedPrometheusMetricsBrowser extends React.Component { - valueListsRef = React.createRef(); - state: BrowserState = { - labels: [], - labelSearchTerm: '', - metricSearchTerm: '', - status: 'Ready', - error: '', - validationStatus: '', - valueSearchTerm: '', - }; - - onChangeLabelSearch = (event: ChangeEvent) => { - this.setState({ labelSearchTerm: event.target.value }); - }; - - onChangeMetricSearch = (event: ChangeEvent) => { - this.setState({ metricSearchTerm: event.target.value }); - }; - - onChangeValueSearch = (event: ChangeEvent) => { - this.setState({ valueSearchTerm: event.target.value }); - }; - - onClickRunQuery = () => { - const selector = buildSelector(this.state.labels); - this.props.onChange(selector); - }; - - onClickRunRateQuery = () => { - const selector = buildSelector(this.state.labels); - const query = `rate(${selector}[$__rate_interval])`; - this.props.onChange(query); - }; - - onClickClear = () => { - this.setState((state) => { - const labels: SelectableLabel[] = state.labels.map((label) => ({ - ...label, - values: undefined, - selected: false, - loading: false, - hidden: false, - facets: undefined, - })); - return { - labels, - labelSearchTerm: '', - metricSearchTerm: '', - status: '', - error: '', - validationStatus: '', - valueSearchTerm: '', - }; - }); - this.props.deleteLastUsedLabels(); - // Get metrics - this.fetchValues(METRIC_LABEL, EMPTY_SELECTOR); - }; - - onClickLabel = (name: string, value: string | undefined, event: React.MouseEvent) => { - const label = this.state.labels.find((l) => l.name === name); - if (!label) { - return; - } - // Toggle selected state - const selected = !label.selected; - let nextValue: Partial = { selected }; - if (label.values && !selected) { - // Deselect all values if label was deselected - const values = label.values.map((value) => ({ ...value, selected: false })); - nextValue = { ...nextValue, facets: 0, values }; - } - // Resetting search to prevent empty results - this.setState({ labelSearchTerm: '' }); - this.updateLabelState(name, nextValue, '', () => this.doFacettingForLabel(name)); - }; - - onClickValue = (name: string, value: string | undefined, event: React.MouseEvent) => { - const label = this.state.labels.find((l) => l.name === name); - if (!label || !label.values) { - return; - } - // Resetting search to prevent empty results - this.setState({ labelSearchTerm: '' }); - // Toggling value for selected label, leaving other values intact - const values = label.values.map((v) => ({ ...v, selected: v.name === value ? !v.selected : v.selected })); - this.updateLabelState(name, { values }, '', () => this.doFacetting(name)); - }; - - onClickMetric = (name: string, value: string | undefined, event: React.MouseEvent) => { - // Finding special metric label - const label = this.state.labels.find((l) => l.name === name); - if (!label || !label.values) { - return; - } - // Resetting search to prevent empty results - this.setState({ metricSearchTerm: '' }); - // Toggling value for selected label, leaving other values intact - const values = label.values.map((v) => ({ - ...v, - selected: v.name === value || v.selected ? !v.selected : v.selected, - })); - // Toggle selected state of special metrics label - const selected = values.some((v) => v.selected); - this.updateLabelState(name, { selected, values }, '', () => this.doFacetting(name)); - }; - - onClickValidate = () => { - const selector = buildSelector(this.state.labels); - this.validateSelector(selector); - }; - - updateLabelState(name: string, updatedFields: Partial, status = '', cb?: () => void) { - this.setState((state) => { - const labels: SelectableLabel[] = state.labels.map((label) => { - if (label.name === name) { - return { ...label, ...updatedFields }; - } - return label; - }); - // New status overrides errors - const error = status ? '' : state.error; - return { labels, status, error, validationStatus: '' }; - }, cb); - } - - componentDidMount() { - const { languageProvider, lastUsedLabels } = this.props; - if (languageProvider) { - const selectedLabels: string[] = lastUsedLabels; - languageProvider.start(this.props.timeRange).then(() => { - let rawLabels: string[] = languageProvider.getLabelKeys(); - // Get metrics - this.fetchValues(METRIC_LABEL, EMPTY_SELECTOR); - // Auto-select previously selected labels - const labels: SelectableLabel[] = rawLabels.map((label, i, arr) => ({ - name: label, - selected: selectedLabels.includes(label), - loading: false, - })); - // Pre-fetch values for selected labels - this.setState({ labels }, () => { - this.state.labels.forEach((label) => { - if (label.selected) { - this.fetchValues(label.name, EMPTY_SELECTOR); - } - }); - }); - }); - } - } - - doFacettingForLabel(name: string) { - const label = this.state.labels.find((l) => l.name === name); - if (!label) { - return; - } - const selectedLabels = this.state.labels.filter((label) => label.selected).map((label) => label.name); - this.props.storeLastUsedLabels(selectedLabels); - if (label.selected) { - // Refetch values for newly selected label... - if (!label.values) { - this.fetchValues(name, buildSelector(this.state.labels)); - } - } else { - // Only need to facet when deselecting labels - this.doFacetting(); - } - } - - doFacetting = (lastFacetted?: string) => { - const selector = buildSelector(this.state.labels); - if (selector === EMPTY_SELECTOR) { - // Clear up facetting - const labels: SelectableLabel[] = this.state.labels.map((label) => { - return { ...label, facets: 0, values: undefined, hidden: false }; - }); - this.setState({ labels }, () => { - // Get fresh set of values - this.state.labels.forEach( - (label) => (label.selected || label.name === METRIC_LABEL) && this.fetchValues(label.name, selector) - ); - }); - } else { - // Do facetting - this.fetchSeries(selector, lastFacetted); - } - }; - - async fetchValues(name: string, selector: string) { - const { languageProvider } = this.props; - this.updateLabelState(name, { loading: true }, `Fetching values for ${name}`); - try { - let rawValues = await languageProvider.getLabelValues(name); - // If selector changed, clear loading state and discard result by returning early - if (selector !== buildSelector(this.state.labels)) { - this.updateLabelState(name, { loading: false }); - return; - } - const values: FacettableValue[] = []; - const { metricsMetadata } = languageProvider; - for (const labelValue of rawValues) { - const value: FacettableValue = { name: labelValue }; - // Adding type/help text to metrics - if (name === METRIC_LABEL && metricsMetadata) { - const meta = metricsMetadata[labelValue]; - if (meta) { - value.details = `(${meta.type}) ${meta.help}`; - } - } - values.push(value); - } - this.updateLabelState(name, { values, loading: false }); - } catch (error) { - console.error(error); - } - } - - async fetchSeries(selector: string, lastFacetted?: string) { - const { languageProvider } = this.props; - if (lastFacetted) { - this.updateLabelState(lastFacetted, { loading: true }, `Facetting labels for ${selector}`); - } - try { - const possibleLabels = await languageProvider.fetchSeriesLabels(selector, true); - // If selector changed, clear loading state and discard result by returning early - if (selector !== buildSelector(this.state.labels)) { - if (lastFacetted) { - this.updateLabelState(lastFacetted, { loading: false }); - } - return; - } - if (Object.keys(possibleLabels).length === 0) { - this.setState({ error: `Empty results, no matching label for ${selector}` }); - return; - } - const labels: SelectableLabel[] = facetLabels(this.state.labels, possibleLabels, lastFacetted); - this.setState({ labels, error: '' }); - if (lastFacetted) { - this.updateLabelState(lastFacetted, { loading: false }); - } - } catch (error) { - console.error(error); - } - } - - async validateSelector(selector: string) { - const { languageProvider } = this.props; - this.setState({ validationStatus: `Validating selector ${selector}`, error: '' }); - const streams = await languageProvider.fetchSeries(selector); - this.setState({ validationStatus: `Selector is valid (${streams.length} series found)` }); - } - - render() { - const { theme } = this.props; - const { labels, labelSearchTerm, metricSearchTerm, status, error, validationStatus, valueSearchTerm } = this.state; - const styles = getStyles(theme); - if (labels.length === 0) { - return ( -
- -
- ); - } - - // Filter metrics - let metrics = labels.find((label) => label.name === METRIC_LABEL); - if (metrics && metricSearchTerm) { - metrics = { - ...metrics, - values: metrics.values?.filter((value) => value.selected || value.name.includes(metricSearchTerm)), - }; - } - - // Filter labels - let nonMetricLabels = labels.filter((label) => !label.hidden && label.name !== METRIC_LABEL); - if (labelSearchTerm) { - nonMetricLabels = nonMetricLabels.filter((label) => label.selected || label.name.includes(labelSearchTerm)); - } - - // Filter non-metric label values - let selectedLabels = nonMetricLabels.filter((label) => label.selected && label.values); - if (valueSearchTerm) { - selectedLabels = selectedLabels.map((label) => ({ - ...label, - values: label.values?.filter((value) => value.selected || value.name.includes(valueSearchTerm)), - })); - } - const selector = buildSelector(this.state.labels); - const empty = selector === EMPTY_SELECTOR; - const metricCount = metrics?.values?.length || 0; - - return ( -
- -
-
- -
- -
-
- metrics!.values![i].name} - width={300} - className={styles.valueList} - > - {({ index, style }) => { - const value = metrics?.values?.[index]; - if (!value) { - return null; - } - return ( -
- -
- ); - }} -
-
-
-
- -
-
- -
- -
- {/* Using fixed height here to prevent jumpy layout */} -
- {nonMetricLabels.map((label) => ( -
-
-
- -
- -
-
- {selectedLabels.map((label) => ( -
-
-
- label.values![i].name} - width={200} - className={styles.valueList} - > - {({ index, style }) => { - const value = label.values?.[index]; - if (!value) { - return null; - } - return ( -
- -
- ); - }} -
-
- ))} -
-
-
-
- -
- -
- {selector} -
- {validationStatus &&
{validationStatus}
} - - - - - -
- {error || status} -
-
-
-
- ); - } -} - -export const PrometheusMetricsBrowser = withTheme2(UnthemedPrometheusMetricsBrowser); diff --git a/public/app/plugins/datasource/prometheus/components/VariableQueryEditor.test.tsx b/public/app/plugins/datasource/prometheus/components/VariableQueryEditor.test.tsx deleted file mode 100644 index 1804f3efff1..00000000000 --- a/public/app/plugins/datasource/prometheus/components/VariableQueryEditor.test.tsx +++ /dev/null @@ -1,392 +0,0 @@ -import { render, screen, waitFor } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; -import React from 'react'; -import { selectOptionInTest } from 'test/helpers/selectOptionInTest'; - -import { dateTime, TimeRange } from '@grafana/data'; - -import { PrometheusDatasource } from '../datasource'; -import PrometheusLanguageProvider from '../language_provider'; -import { migrateVariableEditorBackToVariableSupport } from '../migrations/variableMigration'; -import { PromVariableQuery, PromVariableQueryType, StandardPromVariableQuery } from '../types'; - -import { PromVariableQueryEditor, Props, variableMigration } from './VariableQueryEditor'; - -const refId = 'PrometheusVariableQueryEditor-VariableQuery'; - -describe('PromVariableQueryEditor', () => { - let props: Props; - - test('Migrates from standard variable support to custom variable query', () => { - const query: StandardPromVariableQuery = { - query: 'label_names()', - refId: 'StandardVariableQuery', - }; - - const migration: PromVariableQuery = variableMigration(query); - - const expected: PromVariableQuery = { - qryType: PromVariableQueryType.LabelNames, - refId: 'PrometheusDatasource-VariableQuery', - }; - - expect(migration).toEqual(expected); - }); - - test('Allows for use of variables to interpolate label names in the label values query type.', () => { - const query: StandardPromVariableQuery = { - query: 'label_values($label_name)', - refId: 'StandardVariableQuery', - }; - - const migration: PromVariableQuery = variableMigration(query); - - const expected: PromVariableQuery = { - qryType: PromVariableQueryType.LabelValues, - label: '$label_name', - refId: 'PrometheusDatasource-VariableQuery', - }; - - expect(migration).toEqual(expected); - }); - - test('Migrates from jsonnet grafana as code variable to custom variable query', () => { - const query = 'label_names()'; - - const migration: PromVariableQuery = variableMigration(query); - - const expected: PromVariableQuery = { - qryType: PromVariableQueryType.LabelNames, - refId: 'PrometheusDatasource-VariableQuery', - }; - - expect(migration).toEqual(expected); - }); - - test('Migrates label filters to the query object for label_values()', () => { - const query: StandardPromVariableQuery = { - query: 'label_values(metric{label="value"},name)', - refId: 'StandardVariableQuery', - }; - - const migration: PromVariableQuery = variableMigration(query); - - const expected: PromVariableQuery = { - qryType: PromVariableQueryType.LabelValues, - label: 'name', - metric: 'metric', - labelFilters: [ - { - label: 'label', - op: '=', - value: 'value', - }, - ], - refId: 'PrometheusDatasource-VariableQuery', - }; - - expect(migration).toEqual(expected); - }); - - test('Migrates a query object with label filters to an expression correctly', () => { - const query: PromVariableQuery = { - qryType: PromVariableQueryType.LabelValues, - label: 'name', - metric: 'metric', - labelFilters: [ - { - label: 'label', - op: '=', - value: 'value', - }, - ], - refId: 'PrometheusDatasource-VariableQuery', - }; - - const migration: string = migrateVariableEditorBackToVariableSupport(query); - - const expected = 'label_values(metric{label="value"},name)'; - - expect(migration).toEqual(expected); - }); - - test('Migrates a query object with no metric and only label filters to an expression correctly', () => { - const query: PromVariableQuery = { - qryType: PromVariableQueryType.LabelValues, - label: 'name', - labelFilters: [ - { - label: 'label', - op: '=', - value: 'value', - }, - ], - refId: 'PrometheusDatasource-VariableQuery', - }; - - const migration: string = migrateVariableEditorBackToVariableSupport(query); - - const expected = 'label_values({label="value"},name)'; - - expect(migration).toEqual(expected); - }); - - beforeEach(() => { - props = { - datasource: { - hasLabelsMatchAPISupport: () => true, - languageProvider: { - start: () => Promise.resolve([]), - syntax: () => {}, - getLabelKeys: () => [], - metrics: [], - metricsMetadata: {}, - getLabelValues: jest.fn().mockImplementation(() => ['that']), - fetchLabelsWithMatch: jest.fn().mockImplementation(() => Promise.resolve({ those: 'those' })), - } as Partial as PrometheusLanguageProvider, - getInitHints: () => [], - getDebounceTimeInMilliseconds: jest.fn(), - getTagKeys: jest.fn().mockImplementation(() => Promise.resolve(['this'])), - getVariables: jest.fn().mockImplementation(() => []), - metricFindQuery: jest.fn().mockImplementation(() => Promise.resolve(['that'])), - getSeriesLabels: jest.fn().mockImplementation(() => Promise.resolve(['that'])), - } as Partial as PrometheusDatasource, - query: { - refId: 'test', - query: 'label_names()', - }, - onRunQuery: () => {}, - onChange: () => {}, - history: [], - }; - }); - - test('Displays a group of function options', async () => { - render(); - - const select = screen.getByLabelText('Query type').parentElement!; - await userEvent.click(select); - - await waitFor(() => expect(screen.getAllByText('Label names')).toHaveLength(2)); - await waitFor(() => expect(screen.getByText('Label values')).toBeInTheDocument()); - await waitFor(() => expect(screen.getByText('Metrics')).toBeInTheDocument()); - await waitFor(() => expect(screen.getByText('Query result')).toBeInTheDocument()); - await waitFor(() => expect(screen.getByText('Series query')).toBeInTheDocument()); - await waitFor(() => expect(screen.getByText('Classic query')).toBeInTheDocument()); - }); - - test('Calls onChange for label_names(match) query', async () => { - const onChange = jest.fn(); - - props.query = { - refId: 'test', - query: '', - match: 'that', - }; - - render(); - - await selectOptionInTest(screen.getByLabelText('Query type'), 'Label names'); - - expect(onChange).toHaveBeenCalledWith({ - query: 'label_names(that)', - refId, - qryType: 0, - }); - }); - - test('Calls onChange for label_names, label_values, metrics, query result and and classic query.', async () => { - const onChange = jest.fn(); - - props.query = { - refId: 'test', - query: '', - }; - - render(); - - await selectOptionInTest(screen.getByLabelText('Query type'), 'Label names'); - await selectOptionInTest(screen.getByLabelText('Query type'), 'Label values'); - await selectOptionInTest(screen.getByLabelText('Query type'), 'Metrics'); - await selectOptionInTest(screen.getByLabelText('Query type'), 'Query result'); - await selectOptionInTest(screen.getByLabelText('Query type'), 'Classic query'); - - expect(onChange).toHaveBeenCalledTimes(5); - }); - - test('Does not call onChange for series query', async () => { - const onChange = jest.fn(); - - render(); - - await selectOptionInTest(screen.getByLabelText('Query type'), 'Series query'); - - expect(onChange).not.toHaveBeenCalled(); - }); - - test('Calls onChange for metrics() after input', async () => { - const onChange = jest.fn(); - - props.query = { - refId: 'test', - query: 'label_names()', - }; - - render(); - - await selectOptionInTest(screen.getByLabelText('Query type'), 'Metrics'); - const metricInput = screen.getByLabelText('Metric selector'); - await userEvent.type(metricInput, 'a'); - const queryType = screen.getByLabelText('Query type'); - // click elsewhere to trigger the onBlur - await userEvent.click(queryType); - - await waitFor(() => - expect(onChange).toHaveBeenCalledWith({ - query: 'metrics(a)', - refId, - qryType: 2, - }) - ); - }); - - test('Calls onChange for label_values() after selecting label', async () => { - const onChange = jest.fn(); - - props.query = { - refId: 'test', - query: 'label_names()', - qryType: 0, - }; - - render(); - - await selectOptionInTest(screen.getByLabelText('Query type'), 'Label values'); - const labelSelect = screen.getByLabelText('label-select'); - await userEvent.type(labelSelect, 'this'); - await selectOptionInTest(labelSelect, 'this'); - - await waitFor(() => - expect(onChange).toHaveBeenCalledWith({ - query: 'label_values(this)', - refId, - qryType: 1, - }) - ); - }); - - test('Calls onChange for label_values() after selecting metric', async () => { - const onChange = jest.fn(); - - props.query = { - refId: 'test', - query: 'label_names()', - }; - - render(); - - await selectOptionInTest(screen.getByLabelText('Query type'), 'Label values'); - const labelSelect = screen.getByLabelText('label-select'); - await userEvent.type(labelSelect, 'this'); - await selectOptionInTest(labelSelect, 'this'); - - const metricSelect = screen.getByLabelText('Metric'); - await userEvent.type(metricSelect, 'that'); - await selectOptionInTest(metricSelect, 'that'); - - await waitFor(() => - expect(onChange).toHaveBeenCalledWith({ - query: 'label_values(that,this)', - refId, - qryType: 1, - }) - ); - }); - - test('Calls onChange for query_result() with argument onBlur', async () => { - const onChange = jest.fn(); - - props.query = { - refId: 'test', - query: 'query_result(a)', - }; - - render(); - - const labelSelect = screen.getByLabelText('Prometheus Query'); - await userEvent.click(labelSelect); - const functionSelect = screen.getByLabelText('Query type').parentElement!; - await userEvent.click(functionSelect); - - expect(onChange).toHaveBeenCalledWith({ - query: 'query_result(a)', - refId, - qryType: 3, - }); - }); - - test('Calls onChange for Match[] series with argument onBlur', async () => { - const onChange = jest.fn(); - - props.query = { - refId: 'test', - query: '{a: "example"}', - }; - - render(); - - const labelSelect = screen.getByLabelText('Series Query'); - await userEvent.click(labelSelect); - const functionSelect = screen.getByLabelText('Query type').parentElement!; - await userEvent.click(functionSelect); - - expect(onChange).toHaveBeenCalledWith({ - query: '{a: "example"}', - refId, - qryType: 4, - }); - }); - - test('Calls onChange for classic query onBlur', async () => { - const onChange = jest.fn(); - - props.query = { - refId: 'test', - qryType: 5, - query: 'label_values(instance)', - }; - - render(); - - const labelSelect = screen.getByLabelText('Classic Query'); - await userEvent.click(labelSelect); - const functionSelect = screen.getByLabelText('Query type').parentElement!; - await userEvent.click(functionSelect); - - expect(onChange).toHaveBeenCalledWith({ - query: 'label_values(instance)', - refId, - qryType: 5, - }); - }); - - test('Calls language provider with the time range received in props', async () => { - const now = dateTime('2023-09-16T21:26:00Z'); - const range: TimeRange = { - from: dateTime(now).subtract(2, 'days'), - to: now, - raw: { - from: 'now-2d', - to: 'now', - }, - }; - props.range = range; - - const languageProviderStartMock = jest.fn(); - props.datasource.languageProvider.start = languageProviderStartMock; - - render(); - - expect(languageProviderStartMock).toHaveBeenCalledWith(range); - }); -}); diff --git a/public/app/plugins/datasource/prometheus/components/VariableQueryEditor.tsx b/public/app/plugins/datasource/prometheus/components/VariableQueryEditor.tsx deleted file mode 100644 index fce9bf1e1df..00000000000 --- a/public/app/plugins/datasource/prometheus/components/VariableQueryEditor.tsx +++ /dev/null @@ -1,437 +0,0 @@ -import React, { FormEvent, useCallback, useEffect, useState } from 'react'; - -import { QueryEditorProps, SelectableValue } from '@grafana/data'; -import { selectors } from '@grafana/e2e-selectors'; -import { InlineField, InlineFieldRow, Input, Select, TextArea } from '@grafana/ui'; - -import { PrometheusDatasource } from '../datasource'; -import { - migrateVariableEditorBackToVariableSupport, - migrateVariableQueryToEditor, -} from '../migrations/variableMigration'; -import { promQueryModeller } from '../querybuilder/PromQueryModeller'; -import { MetricsLabelsSection } from '../querybuilder/components/MetricsLabelsSection'; -import { QueryBuilderLabelFilter } from '../querybuilder/shared/types'; -import { PromVisualQuery } from '../querybuilder/types'; -import { - PromOptions, - PromQuery, - PromVariableQuery, - PromVariableQueryType as QueryType, - StandardPromVariableQuery, -} from '../types'; - -export const variableOptions = [ - { label: 'Label names', value: QueryType.LabelNames }, - { label: 'Label values', value: QueryType.LabelValues }, - { label: 'Metrics', value: QueryType.MetricNames }, - { label: 'Query result', value: QueryType.VarQueryResult }, - { label: 'Series query', value: QueryType.SeriesQuery }, - { label: 'Classic query', value: QueryType.ClassicQuery }, -]; - -export type Props = QueryEditorProps; - -const refId = 'PrometheusVariableQueryEditor-VariableQuery'; - -export const PromVariableQueryEditor = ({ onChange, query, datasource, range }: Props) => { - // to select the query type, i.e. label_names, label_values, etc. - const [qryType, setQryType] = useState(undefined); - // list of variables for each function - const [label, setLabel] = useState(''); - - const [labelNamesMatch, setLabelNamesMatch] = useState(''); - - // metric is used for both label_values() and metric() - // label_values() metric requires a whole/complete metric - // metric() is expected to be a part of a metric string - const [metric, setMetric] = useState(''); - // varQuery is a whole query, can include math/rates/etc - const [varQuery, setVarQuery] = useState(''); - // seriesQuery is only a whole - const [seriesQuery, setSeriesQuery] = useState(''); - - // the original variable query implementation, e.g. label_value(metric, label_name) - const [classicQuery, setClassicQuery] = useState(''); - - // list of label names for label_values(), /api/v1/labels, contains the same results as label_names() function - const [labelOptions, setLabelOptions] = useState>>([]); - - // label filters have been added as a filter for metrics in label values query type - const [labelFilters, setLabelFilters] = useState([]); - - useEffect(() => { - datasource.languageProvider.start(range); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - useEffect(() => { - if (!query) { - return; - } - - if (query.qryType === QueryType.ClassicQuery) { - setQryType(query.qryType); - setClassicQuery(query.query ?? ''); - } else { - // 1. Changing from standard to custom variable editor changes the string attr from expr to query - // 2. jsonnet grafana as code passes a variable as a string - const variableQuery = variableMigration(query); - - setLabelNamesMatch(variableQuery.match ?? ''); - setQryType(variableQuery.qryType); - setLabel(variableQuery.label ?? ''); - setMetric(variableQuery.metric ?? ''); - setLabelFilters(variableQuery.labelFilters ?? []); - setVarQuery(variableQuery.varQuery ?? ''); - setSeriesQuery(variableQuery.seriesQuery ?? ''); - setClassicQuery(variableQuery.classicQuery ?? ''); - } - }, [query]); - - // set the label names options for the label values var query - useEffect(() => { - if (qryType !== QueryType.LabelValues) { - return; - } - const variables = datasource.getVariables().map((variable: string) => ({ label: variable, value: variable })); - if (!metric) { - // get all the labels - datasource.getTagKeys({ filters: [] }).then((labelNames: Array<{ text: string }>) => { - const names = labelNames.map(({ text }) => ({ label: text, value: text })); - setLabelOptions([...variables, ...names]); - }); - } else { - // fetch the labels filtered by the metric - const labelToConsider = [{ label: '__name__', op: '=', value: metric }]; - const expr = promQueryModeller.renderLabels(labelToConsider); - - datasource.languageProvider.fetchLabelsWithMatch(expr).then((labelsIndex: Record) => { - const labelNames = Object.keys(labelsIndex); - const names = labelNames.map((value) => ({ label: value, value: value })); - setLabelOptions([...variables, ...names]); - }); - } - }, [datasource, qryType, metric]); - - const onChangeWithVariableString = ( - updateVar: { [key: string]: QueryType | string }, - updLabelFilters?: QueryBuilderLabelFilter[] - ) => { - const queryVar = { - qryType, - label, - metric, - match: labelNamesMatch, - varQuery, - seriesQuery, - classicQuery, - refId: 'PrometheusVariableQueryEditor-VariableQuery', - }; - - let updateLabelFilters = updLabelFilters ? { labelFilters: updLabelFilters } : { labelFilters: labelFilters }; - - const updatedVar = { ...queryVar, ...updateVar, ...updateLabelFilters }; - - const queryString = migrateVariableEditorBackToVariableSupport(updatedVar); - - // setting query.query property allows for update of variable definition - onChange({ - query: queryString, - qryType: updatedVar.qryType, - refId, - }); - }; - - /** Call onchange for label names query type change */ - const onQueryTypeChange = (newType: SelectableValue) => { - setQryType(newType.value); - if (newType.value !== QueryType.SeriesQuery) { - onChangeWithVariableString({ qryType: newType.value ?? 0 }); - } - }; - - /** Call onchange for label select when query type is label values */ - const onLabelChange = (newLabel: SelectableValue) => { - const newLabelvalue = newLabel && newLabel.value ? newLabel.value : ''; - setLabel(newLabelvalue); - if (qryType === QueryType.LabelValues && newLabelvalue) { - onChangeWithVariableString({ label: newLabelvalue }); - } - }; - - /** - * Call onChange for MetricsLabels component change for label values query type - * if there is a label (required) and - * if the labels or metric are updated. - */ - const metricsLabelsChange = (update: PromVisualQuery) => { - setMetric(update.metric); - setLabelFilters(update.labels); - - const updMetric = update.metric; - const updLabelFilters = update.labels ?? []; - - if (qryType === QueryType.LabelValues && label && (updMetric || updLabelFilters)) { - onChangeWithVariableString({ qryType, metric: updMetric }, updLabelFilters); - } - }; - - const onLabelNamesMatchChange = (regex: string) => { - if (qryType === QueryType.LabelNames) { - onChangeWithVariableString({ qryType, match: regex }); - } - }; - - /** - * Call onchange for metric change if metrics names (regex) query type - * Debounce this because to not call the API for every keystroke. - */ - const onMetricChange = (value: string) => { - if (qryType === QueryType.MetricNames && value) { - onChangeWithVariableString({ metric: value }); - } - }; - - /** - * Do not call onchange for variable query result when query type is var query result - * because the query may not be finished typing and an error is returned - * for incorrectly formatted series. Call onchange for blur instead. - */ - const onVarQueryChange = (e: FormEvent) => { - setVarQuery(e.currentTarget.value); - }; - - /** - * Do not call onchange for seriesQuery when query type is series query - * because the series may not be finished typing and an error is returned - * for incorrectly formatted series. Call onchange for blur instead. - */ - const onSeriesQueryChange = (e: FormEvent) => { - setSeriesQuery(e.currentTarget.value); - }; - - const onClassicQueryChange = (e: FormEvent) => { - setClassicQuery(e.currentTarget.value); - }; - - const promVisualQuery = useCallback(() => { - return { metric: metric, labels: labelFilters, operations: [] }; - }, [metric, labelFilters]); - - return ( - <> - - The Prometheus data source plugin provides the following query types for template variables. - } - > - - - - {/* Used to select an optional metric with optional label filters */} - - - )} - - {qryType === QueryType.LabelNames && ( - - Returns a list of label names, optionally filtering by specified metric regex.} - > - { - setLabelNamesMatch(event.currentTarget.value); - onLabelNamesMatchChange(event.currentTarget.value); - }} - onChange={(e) => { - setLabelNamesMatch(e.currentTarget.value); - }} - width={25} - data-testid={selectors.components.DataSource.Prometheus.variableQueryEditor.labelnames.metricRegex} - /> - - - )} - - {qryType === QueryType.MetricNames && ( - - Returns a list of metrics matching the specified metric regex.} - > - { - setMetric(e.currentTarget.value); - }} - onBlur={(e) => { - setMetric(e.currentTarget.value); - onMetricChange(e.currentTarget.value); - }} - width={25} - data-testid={selectors.components.DataSource.Prometheus.variableQueryEditor.metricNames.metricRegex} - /> - - - )} - - {qryType === QueryType.VarQueryResult && ( - - - Returns a list of Prometheus query results for the query. This can include Prometheus functions, i.e. - sum(go_goroutines). - - } - > -