Merge remote-tracking branch 'origin' into sriram/postgres-config-page-tls-regrouping

This commit is contained in:
yesoreyeram
2025-07-07 16:27:12 +01:00
114 changed files with 3413 additions and 1045 deletions
+1 -4
View File
@@ -19,9 +19,6 @@ update-app-sdk: ## Update the Grafana App SDK dependency in go.mod
go mod tidy
.PHONY: generate
generate: do-generate ## Run Grafana App SDK code generation
.PHONY: do-generate
do-generate: install-app-sdk update-app-sdk
generate: install-app-sdk update-app-sdk
## --defencoding=none and noschemasinmanifest are needed to avoid infinite loop while generating recursive models (see routingtree.cue)
@$(APP_SDK_BIN) generate --grouping=group --gogenpath=./pkg/apis --defencoding=none --postprocess --noschemasinmanifest
+8 -8
View File
@@ -3,10 +3,10 @@ module github.com/grafana/grafana/apps/alerting/notifications
go 1.24.4
require (
github.com/grafana/grafana-app-sdk v0.39.0
github.com/grafana/grafana-app-sdk/logging v0.38.2
k8s.io/apimachinery v0.33.1
k8s.io/apiserver v0.33.1
github.com/grafana/grafana-app-sdk v0.39.2
github.com/grafana/grafana-app-sdk/logging v0.39.1
k8s.io/apimachinery v0.33.2
k8s.io/apiserver v0.33.2
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff
)
@@ -97,10 +97,10 @@ require (
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/api v0.33.1 // indirect
k8s.io/apiextensions-apiserver v0.33.1 // indirect
k8s.io/client-go v0.33.1 // indirect
k8s.io/component-base v0.33.1 // indirect
k8s.io/api v0.33.2 // indirect
k8s.io/apiextensions-apiserver v0.33.2 // indirect
k8s.io/client-go v0.33.2 // indirect
k8s.io/component-base v0.33.2 // indirect
k8s.io/klog/v2 v2.130.1 // indirect
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 // indirect
+16 -16
View File
@@ -84,10 +84,10 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo=
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA=
github.com/grafana/grafana-app-sdk v0.39.0 h1:WC2E9BKXWDX/e2bajdAFjQEyyWf9BFp7Yzbjm6T1T1w=
github.com/grafana/grafana-app-sdk v0.39.0/go.mod h1:xRyBQOttgWTc3tGe9pI0upnpEPVhzALf7Mh/61O4zyY=
github.com/grafana/grafana-app-sdk/logging v0.38.2 h1:EdQTRxbbH72zdqJ09Z76zcSjfALJXkpPLgvKEPPnloc=
github.com/grafana/grafana-app-sdk/logging v0.38.2/go.mod h1:Y/bvbDhBiV/tkIle9RW49pgfSPIPSON8Q4qjx3pyqDk=
github.com/grafana/grafana-app-sdk v0.39.2 h1:ymfr+1318t+JC9U2OYrzVpGmNG/aJONUmFFu/G98Xh8=
github.com/grafana/grafana-app-sdk v0.39.2/go.mod h1:t0m6q561lpoHQCixS9LUHFUhUzDClzNtm7BH60gHVSY=
github.com/grafana/grafana-app-sdk/logging v0.39.1 h1:lI5rbrheuwVPuyIM6LIuEYOCSpgmXahfKtqeMyhbGPU=
github.com/grafana/grafana-app-sdk/logging v0.39.1/go.mod h1:WhDENSnaGHtyVVwZGVnAR7YLvh2xlLDYR3D7E6h7XVk=
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI=
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340 h1:uGoIog/wiQHI9GAxXO5TJbT0wWKH3O9HhOJW1F9c3fY=
@@ -352,18 +352,18 @@ gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
k8s.io/api v0.33.1 h1:tA6Cf3bHnLIrUK4IqEgb2v++/GYUtqiu9sRVk3iBXyw=
k8s.io/api v0.33.1/go.mod h1:87esjTn9DRSRTD4fWMXamiXxJhpOIREjWOSjsW1kEHw=
k8s.io/apiextensions-apiserver v0.33.1 h1:N7ccbSlRN6I2QBcXevB73PixX2dQNIW0ZRuguEE91zI=
k8s.io/apiextensions-apiserver v0.33.1/go.mod h1:uNQ52z1A1Gu75QSa+pFK5bcXc4hq7lpOXbweZgi4dqA=
k8s.io/apimachinery v0.33.1 h1:mzqXWV8tW9Rw4VeW9rEkqvnxj59k1ezDUl20tFK/oM4=
k8s.io/apimachinery v0.33.1/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
k8s.io/apiserver v0.33.1 h1:yLgLUPDVC6tHbNcw5uE9mo1T6ELhJj7B0geifra3Qdo=
k8s.io/apiserver v0.33.1/go.mod h1:VMbE4ArWYLO01omz+k8hFjAdYfc3GVAYPrhP2tTKccs=
k8s.io/client-go v0.33.1 h1:ZZV/Ks2g92cyxWkRRnfUDsnhNn28eFpt26aGc8KbXF4=
k8s.io/client-go v0.33.1/go.mod h1:JAsUrl1ArO7uRVFWfcj6kOomSlCv+JpvIsp6usAGefA=
k8s.io/component-base v0.33.1 h1:EoJ0xA+wr77T+G8p6T3l4efT2oNwbqBVKR71E0tBIaI=
k8s.io/component-base v0.33.1/go.mod h1:guT/w/6piyPfTgq7gfvgetyXMIh10zuXA6cRRm3rDuY=
k8s.io/api v0.33.2 h1:YgwIS5jKfA+BZg//OQhkJNIfie/kmRsO0BmNaVSimvY=
k8s.io/api v0.33.2/go.mod h1:fhrbphQJSM2cXzCWgqU29xLDuks4mu7ti9vveEnpSXs=
k8s.io/apiextensions-apiserver v0.33.2 h1:6gnkIbngnaUflR3XwE1mCefN3YS8yTD631JXQhsU6M8=
k8s.io/apiextensions-apiserver v0.33.2/go.mod h1:IvVanieYsEHJImTKXGP6XCOjTwv2LUMos0YWc9O+QP8=
k8s.io/apimachinery v0.33.2 h1:IHFVhqg59mb8PJWTLi8m1mAoepkUNYmptHsV+Z1m5jY=
k8s.io/apimachinery v0.33.2/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
k8s.io/apiserver v0.33.2 h1:KGTRbxn2wJagJowo29kKBp4TchpO1DRO3g+dB/KOJN4=
k8s.io/apiserver v0.33.2/go.mod h1:9qday04wEAMLPWWo9AwqCZSiIn3OYSZacDyu/AcoM/M=
k8s.io/client-go v0.33.2 h1:z8CIcc0P581x/J1ZYf4CNzRKxRvQAwoAolYPbtQes+E=
k8s.io/client-go v0.33.2/go.mod h1:9mCgT4wROvL948w6f6ArJNb7yQd7QsvqavDeZHvNmHo=
k8s.io/component-base v0.33.2 h1:sCCsn9s/dG3ZrQTX/Us0/Sx2R0G5kwa0wbZFYoVp/+0=
k8s.io/component-base v0.33.2/go.mod h1:/41uw9wKzuelhN+u+/C59ixxf4tYQKW7p32ddkYNe2k=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4=
@@ -14,6 +14,8 @@ import (
v0alpha1 "github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/alerting/v0alpha1"
)
var ()
var appManifestData = app.ManifestData{
AppName: "alerting",
Group: "notifications.alerting.grafana.app",
+1 -1
View File
@@ -1,4 +1,4 @@
APP_SDK_VERSION := v0.39.0
APP_SDK_VERSION := v0.39.2
APP_SDK_DIR := $(shell go env GOPATH)/bin/app-sdk-$(APP_SDK_VERSION)
APP_SDK_BIN := $(APP_SDK_DIR)/grafana-app-sdk
+4 -4
View File
@@ -4,11 +4,11 @@ go 1.24.4
require (
cuelang.org/go v0.11.1
github.com/grafana/grafana-app-sdk v0.39.0
github.com/grafana/grafana-app-sdk v0.39.2
github.com/grafana/grafana-plugin-sdk-go v0.278.0
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250514132646-acbc7b54ed9e
github.com/stretchr/testify v1.10.0
k8s.io/apimachinery v0.33.1
k8s.io/apimachinery v0.33.2
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff
)
@@ -44,7 +44,7 @@ require (
github.com/google/go-cmp v0.7.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gorilla/mux v1.8.1 // indirect
github.com/grafana/grafana-app-sdk/logging v0.38.2 // indirect
github.com/grafana/grafana-app-sdk/logging v0.39.1 // indirect
github.com/grafana/otel-profiling-go v0.5.1 // indirect
github.com/grafana/pyroscope-go/godeltaprof v0.1.8 // indirect
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 // indirect
@@ -123,7 +123,7 @@ require (
gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/client-go v0.33.1 // indirect
k8s.io/client-go v0.33.2 // indirect
k8s.io/klog/v2 v2.130.1 // indirect
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
+10 -10
View File
@@ -94,10 +94,10 @@ github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
github.com/grafana/grafana-app-sdk v0.39.0 h1:WC2E9BKXWDX/e2bajdAFjQEyyWf9BFp7Yzbjm6T1T1w=
github.com/grafana/grafana-app-sdk v0.39.0/go.mod h1:xRyBQOttgWTc3tGe9pI0upnpEPVhzALf7Mh/61O4zyY=
github.com/grafana/grafana-app-sdk/logging v0.38.2 h1:EdQTRxbbH72zdqJ09Z76zcSjfALJXkpPLgvKEPPnloc=
github.com/grafana/grafana-app-sdk/logging v0.38.2/go.mod h1:Y/bvbDhBiV/tkIle9RW49pgfSPIPSON8Q4qjx3pyqDk=
github.com/grafana/grafana-app-sdk v0.39.2 h1:ymfr+1318t+JC9U2OYrzVpGmNG/aJONUmFFu/G98Xh8=
github.com/grafana/grafana-app-sdk v0.39.2/go.mod h1:t0m6q561lpoHQCixS9LUHFUhUzDClzNtm7BH60gHVSY=
github.com/grafana/grafana-app-sdk/logging v0.39.1 h1:lI5rbrheuwVPuyIM6LIuEYOCSpgmXahfKtqeMyhbGPU=
github.com/grafana/grafana-app-sdk/logging v0.39.1/go.mod h1:WhDENSnaGHtyVVwZGVnAR7YLvh2xlLDYR3D7E6h7XVk=
github.com/grafana/grafana-plugin-sdk-go v0.278.0 h1:5/rIYparLi02pofdaag8wnjspMMVNCi8cZhC4cdC3Ho=
github.com/grafana/grafana-plugin-sdk-go v0.278.0/go.mod h1:+8NXT/XUJ/89GV6FxGQ366NZ3nU+cAXDMd0OUESF9H4=
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250514132646-acbc7b54ed9e h1:BTKk7LHuG1kmAkucwTA7DuMbKpKvJTKrGdBmUNO4dfQ=
@@ -379,12 +379,12 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
k8s.io/api v0.33.1 h1:tA6Cf3bHnLIrUK4IqEgb2v++/GYUtqiu9sRVk3iBXyw=
k8s.io/api v0.33.1/go.mod h1:87esjTn9DRSRTD4fWMXamiXxJhpOIREjWOSjsW1kEHw=
k8s.io/apimachinery v0.33.1 h1:mzqXWV8tW9Rw4VeW9rEkqvnxj59k1ezDUl20tFK/oM4=
k8s.io/apimachinery v0.33.1/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
k8s.io/client-go v0.33.1 h1:ZZV/Ks2g92cyxWkRRnfUDsnhNn28eFpt26aGc8KbXF4=
k8s.io/client-go v0.33.1/go.mod h1:JAsUrl1ArO7uRVFWfcj6kOomSlCv+JpvIsp6usAGefA=
k8s.io/api v0.33.2 h1:YgwIS5jKfA+BZg//OQhkJNIfie/kmRsO0BmNaVSimvY=
k8s.io/api v0.33.2/go.mod h1:fhrbphQJSM2cXzCWgqU29xLDuks4mu7ti9vveEnpSXs=
k8s.io/apimachinery v0.33.2 h1:IHFVhqg59mb8PJWTLi8m1mAoepkUNYmptHsV+Z1m5jY=
k8s.io/apimachinery v0.33.2/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
k8s.io/client-go v0.33.2 h1:z8CIcc0P581x/J1ZYf4CNzRKxRvQAwoAolYPbtQes+E=
k8s.io/client-go v0.33.2/go.mod h1:9mCgT4wROvL948w6f6ArJNb7yQd7QsvqavDeZHvNmHo=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4=
@@ -111,6 +111,8 @@ DashboardLink: {
keepTime: bool | *false
}
// Keeping this for backwards compatibility for GroupByVariableSpec and AdhocVariableSpec
// This type is widely used in the codebase and changing it will have a big impact
DataSourceRef: {
// The plugin type-id
type?: string
@@ -385,8 +387,7 @@ VizConfigKind: {
}
AnnotationQuerySpec: {
datasource?: DataSourceRef
query?: DataQueryKind
query: DataQueryKind
enable: bool
hide: bool
iconColor: string
@@ -412,15 +413,19 @@ QueryOptionsSpec: {
}
DataQueryKind: {
// The kind of a DataQueryKind is the datasource type
kind: string
kind: "DataQuery"
group: string
version: string | *"v0"
// New type for datasource reference
// Not creating a new type until we figure out how to handle DS refs for group by, adhoc, and every place that uses DataSourceRef in TS.
datasource?: {
name?: string
}
spec: [string]: _
}
PanelQuerySpec: {
query: DataQueryKind
datasource?: DataSourceRef
refId: string
hidden: bool
}
@@ -723,7 +728,6 @@ QueryVariableSpec: {
refresh: VariableRefresh
skipUrlSync: bool | *false
description?: string
datasource?: DataSourceRef
query: DataQueryKind
regex: string | *""
sort: VariableSort
@@ -115,6 +115,8 @@ DashboardLink: {
keepTime: bool | *false
}
// Keeping this for backwards compatibility for GroupByVariableSpec and AdhocVariableSpec
// This type is widely used in the codebase and changing it will have a big impact
DataSourceRef: {
// The plugin type-id
type?: string
@@ -389,8 +391,7 @@ VizConfigKind: {
}
AnnotationQuerySpec: {
datasource?: DataSourceRef
query?: DataQueryKind
query: DataQueryKind
enable: bool
hide: bool
iconColor: string
@@ -416,15 +417,19 @@ QueryOptionsSpec: {
}
DataQueryKind: {
// The kind of a DataQueryKind is the datasource type
kind: string
kind: "DataQuery"
group: string
version: string | *"v0"
// New type for datasource reference
// Not creating a new type until we figure out how to handle DS refs for group by, adhoc, and every place that uses DataSourceRef in TS.
datasource?: {
name?: string
}
spec: [string]: _
}
PanelQuerySpec: {
query: DataQueryKind
datasource?: DataSourceRef
refId: string
hidden: bool
}
@@ -727,7 +732,6 @@ QueryVariableSpec: {
refresh: VariableRefresh
skipUrlSync: bool | *false
description?: string
datasource?: DataSourceRef
query: DataQueryKind
regex: string | *""
sort: VariableSort
@@ -23,14 +23,13 @@ func NewDashboardAnnotationQueryKind() *DashboardAnnotationQueryKind {
// +k8s:openapi-gen=true
type DashboardAnnotationQuerySpec struct {
Datasource *DashboardDataSourceRef `json:"datasource,omitempty"`
Query *DashboardDataQueryKind `json:"query,omitempty"`
Enable bool `json:"enable"`
Hide bool `json:"hide"`
IconColor string `json:"iconColor"`
Name string `json:"name"`
BuiltIn *bool `json:"builtIn,omitempty"`
Filter *DashboardAnnotationPanelFilter `json:"filter,omitempty"`
Query DashboardDataQueryKind `json:"query"`
Enable bool `json:"enable"`
Hide bool `json:"hide"`
IconColor string `json:"iconColor"`
Name string `json:"name"`
BuiltIn *bool `json:"builtIn,omitempty"`
Filter *DashboardAnnotationPanelFilter `json:"filter,omitempty"`
// Catch-all field for datasource-specific properties
LegacyOptions map[string]interface{} `json:"legacyOptions,omitempty"`
}
@@ -38,34 +37,28 @@ type DashboardAnnotationQuerySpec struct {
// NewDashboardAnnotationQuerySpec creates a new DashboardAnnotationQuerySpec object.
func NewDashboardAnnotationQuerySpec() *DashboardAnnotationQuerySpec {
return &DashboardAnnotationQuerySpec{
Query: *NewDashboardDataQueryKind(),
BuiltIn: (func(input bool) *bool { return &input })(false),
}
}
// +k8s:openapi-gen=true
type DashboardDataSourceRef struct {
// The plugin type-id
Type *string `json:"type,omitempty"`
// Specific datasource instance
Uid *string `json:"uid,omitempty"`
}
// NewDashboardDataSourceRef creates a new DashboardDataSourceRef object.
func NewDashboardDataSourceRef() *DashboardDataSourceRef {
return &DashboardDataSourceRef{}
}
// +k8s:openapi-gen=true
type DashboardDataQueryKind struct {
// The kind of a DataQueryKind is the datasource type
Kind string `json:"kind"`
Spec map[string]interface{} `json:"spec"`
Kind string `json:"kind"`
Group string `json:"group"`
Version string `json:"version"`
// New type for datasource reference
// Not creating a new type until we figure out how to handle DS refs for group by, adhoc, and every place that uses DataSourceRef in TS.
Datasource *DashboardV2alpha1DataQueryKindDatasource `json:"datasource,omitempty"`
Spec map[string]interface{} `json:"spec"`
}
// NewDashboardDataQueryKind creates a new DashboardDataQueryKind object.
func NewDashboardDataQueryKind() *DashboardDataQueryKind {
return &DashboardDataQueryKind{
Spec: map[string]interface{}{},
Kind: "DataQuery",
Version: "v0",
Spec: map[string]interface{}{},
}
}
@@ -199,10 +192,9 @@ func NewDashboardPanelQueryKind() *DashboardPanelQueryKind {
// +k8s:openapi-gen=true
type DashboardPanelQuerySpec struct {
Query DashboardDataQueryKind `json:"query"`
Datasource *DashboardDataSourceRef `json:"datasource,omitempty"`
RefId string `json:"refId"`
Hidden bool `json:"hidden"`
Query DashboardDataQueryKind `json:"query"`
RefId string `json:"refId"`
Hidden bool `json:"hidden"`
}
// NewDashboardPanelQuerySpec creates a new DashboardPanelQuerySpec object.
@@ -763,7 +755,9 @@ type DashboardRepeatOptions struct {
// NewDashboardRepeatOptions creates a new DashboardRepeatOptions object.
func NewDashboardRepeatOptions() *DashboardRepeatOptions {
return &DashboardRepeatOptions{}
return &DashboardRepeatOptions{
Mode: DashboardRepeatMode,
}
}
// other repeat modes will be added in the future: label, frame
@@ -938,7 +932,9 @@ type DashboardRowRepeatOptions struct {
// NewDashboardRowRepeatOptions creates a new DashboardRowRepeatOptions object.
func NewDashboardRowRepeatOptions() *DashboardRowRepeatOptions {
return &DashboardRowRepeatOptions{}
return &DashboardRowRepeatOptions{
Mode: DashboardRepeatMode,
}
}
// +k8s:openapi-gen=true
@@ -1011,7 +1007,9 @@ type DashboardAutoGridRepeatOptions struct {
// NewDashboardAutoGridRepeatOptions creates a new DashboardAutoGridRepeatOptions object.
func NewDashboardAutoGridRepeatOptions() *DashboardAutoGridRepeatOptions {
return &DashboardAutoGridRepeatOptions{}
return &DashboardAutoGridRepeatOptions{
Mode: DashboardRepeatMode,
}
}
// +k8s:openapi-gen=true
@@ -1077,7 +1075,9 @@ type DashboardTabRepeatOptions struct {
// NewDashboardTabRepeatOptions creates a new DashboardTabRepeatOptions object.
func NewDashboardTabRepeatOptions() *DashboardTabRepeatOptions {
return &DashboardTabRepeatOptions{}
return &DashboardTabRepeatOptions{
Mode: DashboardRepeatMode,
}
}
// Links with references to other dashboards or external resources
@@ -1221,7 +1221,6 @@ type DashboardQueryVariableSpec struct {
Refresh DashboardVariableRefresh `json:"refresh"`
SkipUrlSync bool `json:"skipUrlSync"`
Description *string `json:"description,omitempty"`
Datasource *DashboardDataSourceRef `json:"datasource,omitempty"`
Query DashboardDataQueryKind `json:"query"`
Regex string `json:"regex"`
Sort DashboardVariableSort `json:"sort"`
@@ -1627,6 +1626,21 @@ func NewDashboardGroupByVariableSpec() *DashboardGroupByVariableSpec {
}
}
// Keeping this for backwards compatibility for GroupByVariableSpec and AdhocVariableSpec
// This type is widely used in the codebase and changing it will have a big impact
// +k8s:openapi-gen=true
type DashboardDataSourceRef struct {
// The plugin type-id
Type *string `json:"type,omitempty"`
// Specific datasource instance
Uid *string `json:"uid,omitempty"`
}
// NewDashboardDataSourceRef creates a new DashboardDataSourceRef object.
func NewDashboardDataSourceRef() *DashboardDataSourceRef {
return &DashboardDataSourceRef{}
}
// Adhoc variable kind
// +k8s:openapi-gen=true
type DashboardAdhocVariableKind struct {
@@ -1687,7 +1701,9 @@ type DashboardAdHocFilterWithLabels struct {
// NewDashboardAdHocFilterWithLabels creates a new DashboardAdHocFilterWithLabels object.
func NewDashboardAdHocFilterWithLabels() *DashboardAdHocFilterWithLabels {
return &DashboardAdHocFilterWithLabels{}
return &DashboardAdHocFilterWithLabels{
Origin: DashboardFilterOrigin,
}
}
// Determine the origin of the adhoc variable filter
@@ -1758,6 +1774,16 @@ func NewDashboardSpec() *DashboardSpec {
}
}
// +k8s:openapi-gen=true
type DashboardV2alpha1DataQueryKindDatasource struct {
Name *string `json:"name,omitempty"`
}
// NewDashboardV2alpha1DataQueryKindDatasource creates a new DashboardV2alpha1DataQueryKindDatasource object.
func NewDashboardV2alpha1DataQueryKindDatasource() *DashboardV2alpha1DataQueryKindDatasource {
return &DashboardV2alpha1DataQueryKindDatasource{}
}
// +k8s:openapi-gen=true
type DashboardV2alpha1FieldConfigSourceOverrides struct {
Matcher DashboardMatcherConfig `json:"matcher"`
@@ -109,6 +109,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardTimeRangeOption": schema_pkg_apis_dashboard_v2alpha1_DashboardTimeRangeOption(ref),
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardTimeSettingsSpec": schema_pkg_apis_dashboard_v2alpha1_DashboardTimeSettingsSpec(ref),
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardTransformationKind": schema_pkg_apis_dashboard_v2alpha1_DashboardTransformationKind(ref),
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardV2alpha1DataQueryKindDatasource": schema_pkg_apis_dashboard_v2alpha1_DashboardV2alpha1DataQueryKindDatasource(ref),
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardV2alpha1FieldConfigSourceOverrides": schema_pkg_apis_dashboard_v2alpha1_DashboardV2alpha1FieldConfigSourceOverrides(ref),
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardV2alpha1RangeMapOptions": schema_pkg_apis_dashboard_v2alpha1_DashboardV2alpha1RangeMapOptions(ref),
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardV2alpha1RegexMapOptions": schema_pkg_apis_dashboard_v2alpha1_DashboardV2alpha1RegexMapOptions(ref),
@@ -595,14 +596,10 @@ func schema_pkg_apis_dashboard_v2alpha1_DashboardAnnotationQuerySpec(ref common.
SchemaProps: spec.SchemaProps{
Type: []string{"object"},
Properties: map[string]spec.Schema{
"datasource": {
SchemaProps: spec.SchemaProps{
Ref: ref("github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardDataSourceRef"),
},
},
"query": {
SchemaProps: spec.SchemaProps{
Ref: ref("github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardDataQueryKind"),
Default: map[string]interface{}{},
Ref: ref("github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardDataQueryKind"),
},
},
"enable": {
@@ -660,11 +657,11 @@ func schema_pkg_apis_dashboard_v2alpha1_DashboardAnnotationQuerySpec(ref common.
},
},
},
Required: []string{"enable", "hide", "iconColor", "name"},
Required: []string{"query", "enable", "hide", "iconColor", "name"},
},
},
Dependencies: []string{
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardAnnotationPanelFilter", "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardDataQueryKind", "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardDataSourceRef"},
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardAnnotationPanelFilter", "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardDataQueryKind"},
}
}
@@ -1505,10 +1502,29 @@ func schema_pkg_apis_dashboard_v2alpha1_DashboardDataQueryKind(ref common.Refere
Properties: map[string]spec.Schema{
"kind": {
SchemaProps: spec.SchemaProps{
Description: "The kind of a DataQueryKind is the datasource type",
Default: "",
Type: []string{"string"},
Format: "",
Default: "",
Type: []string{"string"},
Format: "",
},
},
"group": {
SchemaProps: spec.SchemaProps{
Default: "",
Type: []string{"string"},
Format: "",
},
},
"version": {
SchemaProps: spec.SchemaProps{
Default: "",
Type: []string{"string"},
Format: "",
},
},
"datasource": {
SchemaProps: spec.SchemaProps{
Description: "New type for datasource reference Not creating a new type until we figure out how to handle DS refs for group by, adhoc, and every place that uses DataSourceRef in TS.",
Ref: ref("github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardV2alpha1DataQueryKindDatasource"),
},
},
"spec": {
@@ -1526,9 +1542,11 @@ func schema_pkg_apis_dashboard_v2alpha1_DashboardDataQueryKind(ref common.Refere
},
},
},
Required: []string{"kind", "spec"},
Required: []string{"kind", "group", "version", "spec"},
},
},
Dependencies: []string{
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardV2alpha1DataQueryKindDatasource"},
}
}
@@ -1536,7 +1554,8 @@ func schema_pkg_apis_dashboard_v2alpha1_DashboardDataSourceRef(ref common.Refere
return common.OpenAPIDefinition{
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
Type: []string{"object"},
Description: "Keeping this for backwards compatibility for GroupByVariableSpec and AdhocVariableSpec This type is widely used in the codebase and changing it will have a big impact",
Type: []string{"object"},
Properties: map[string]spec.Schema{
"type": {
SchemaProps: spec.SchemaProps{
@@ -2890,11 +2909,6 @@ func schema_pkg_apis_dashboard_v2alpha1_DashboardPanelQuerySpec(ref common.Refer
Ref: ref("github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardDataQueryKind"),
},
},
"datasource": {
SchemaProps: spec.SchemaProps{
Ref: ref("github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardDataSourceRef"),
},
},
"refId": {
SchemaProps: spec.SchemaProps{
Default: "",
@@ -2914,7 +2928,7 @@ func schema_pkg_apis_dashboard_v2alpha1_DashboardPanelQuerySpec(ref common.Refer
},
},
Dependencies: []string{
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardDataQueryKind", "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardDataSourceRef"},
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardDataQueryKind"},
}
}
@@ -3250,11 +3264,6 @@ func schema_pkg_apis_dashboard_v2alpha1_DashboardQueryVariableSpec(ref common.Re
Format: "",
},
},
"datasource": {
SchemaProps: spec.SchemaProps{
Ref: ref("github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardDataSourceRef"),
},
},
"query": {
SchemaProps: spec.SchemaProps{
Default: map[string]interface{}{},
@@ -3332,7 +3341,7 @@ func schema_pkg_apis_dashboard_v2alpha1_DashboardQueryVariableSpec(ref common.Re
},
},
Dependencies: []string{
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardDataQueryKind", "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardDataSourceRef", "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardVariableOption"},
"github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardDataQueryKind", "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1.DashboardVariableOption"},
}
}
@@ -4320,6 +4329,24 @@ func schema_pkg_apis_dashboard_v2alpha1_DashboardTransformationKind(ref common.R
}
}
func schema_pkg_apis_dashboard_v2alpha1_DashboardV2alpha1DataQueryKindDatasource(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
Type: []string{"object"},
Properties: map[string]spec.Schema{
"name": {
SchemaProps: spec.SchemaProps{
Type: []string{"string"},
Format: "",
},
},
},
},
},
}
}
func schema_pkg_apis_dashboard_v2alpha1_DashboardV2alpha1FieldConfigSourceOverrides(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
+4 -4
View File
@@ -3,9 +3,9 @@ module github.com/grafana/grafana/apps/folder
go 1.24.4
require (
github.com/grafana/grafana-app-sdk v0.39.0
github.com/grafana/grafana-app-sdk v0.39.2
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250514132646-acbc7b54ed9e
k8s.io/apimachinery v0.33.1
k8s.io/apimachinery v0.33.2
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff
)
@@ -23,7 +23,7 @@ require (
github.com/go-test/deep v1.1.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/google/gnostic-models v0.6.9 // indirect
github.com/grafana/grafana-app-sdk/logging v0.38.2 // indirect
github.com/grafana/grafana-app-sdk/logging v0.39.1 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
@@ -53,7 +53,7 @@ require (
google.golang.org/protobuf v1.36.6 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/client-go v0.33.1 // indirect
k8s.io/client-go v0.33.2 // indirect
k8s.io/klog/v2 v2.130.1 // indirect
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
+10 -10
View File
@@ -32,10 +32,10 @@ github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/grafana/grafana-app-sdk v0.39.0 h1:WC2E9BKXWDX/e2bajdAFjQEyyWf9BFp7Yzbjm6T1T1w=
github.com/grafana/grafana-app-sdk v0.39.0/go.mod h1:xRyBQOttgWTc3tGe9pI0upnpEPVhzALf7Mh/61O4zyY=
github.com/grafana/grafana-app-sdk/logging v0.38.2 h1:EdQTRxbbH72zdqJ09Z76zcSjfALJXkpPLgvKEPPnloc=
github.com/grafana/grafana-app-sdk/logging v0.38.2/go.mod h1:Y/bvbDhBiV/tkIle9RW49pgfSPIPSON8Q4qjx3pyqDk=
github.com/grafana/grafana-app-sdk v0.39.2 h1:ymfr+1318t+JC9U2OYrzVpGmNG/aJONUmFFu/G98Xh8=
github.com/grafana/grafana-app-sdk v0.39.2/go.mod h1:t0m6q561lpoHQCixS9LUHFUhUzDClzNtm7BH60gHVSY=
github.com/grafana/grafana-app-sdk/logging v0.39.1 h1:lI5rbrheuwVPuyIM6LIuEYOCSpgmXahfKtqeMyhbGPU=
github.com/grafana/grafana-app-sdk/logging v0.39.1/go.mod h1:WhDENSnaGHtyVVwZGVnAR7YLvh2xlLDYR3D7E6h7XVk=
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250514132646-acbc7b54ed9e h1:BTKk7LHuG1kmAkucwTA7DuMbKpKvJTKrGdBmUNO4dfQ=
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250514132646-acbc7b54ed9e/go.mod h1:IA4SOwun8QyST9c5UNs/fN37XL6boXXDvRYFcFwbipg=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
@@ -150,12 +150,12 @@ gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
k8s.io/api v0.33.1 h1:tA6Cf3bHnLIrUK4IqEgb2v++/GYUtqiu9sRVk3iBXyw=
k8s.io/api v0.33.1/go.mod h1:87esjTn9DRSRTD4fWMXamiXxJhpOIREjWOSjsW1kEHw=
k8s.io/apimachinery v0.33.1 h1:mzqXWV8tW9Rw4VeW9rEkqvnxj59k1ezDUl20tFK/oM4=
k8s.io/apimachinery v0.33.1/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
k8s.io/client-go v0.33.1 h1:ZZV/Ks2g92cyxWkRRnfUDsnhNn28eFpt26aGc8KbXF4=
k8s.io/client-go v0.33.1/go.mod h1:JAsUrl1ArO7uRVFWfcj6kOomSlCv+JpvIsp6usAGefA=
k8s.io/api v0.33.2 h1:YgwIS5jKfA+BZg//OQhkJNIfie/kmRsO0BmNaVSimvY=
k8s.io/api v0.33.2/go.mod h1:fhrbphQJSM2cXzCWgqU29xLDuks4mu7ti9vveEnpSXs=
k8s.io/apimachinery v0.33.2 h1:IHFVhqg59mb8PJWTLi8m1mAoepkUNYmptHsV+Z1m5jY=
k8s.io/apimachinery v0.33.2/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
k8s.io/client-go v0.33.2 h1:z8CIcc0P581x/J1ZYf4CNzRKxRvQAwoAolYPbtQes+E=
k8s.io/client-go v0.33.2/go.mod h1:9mCgT4wROvL948w6f6ArJNb7yQd7QsvqavDeZHvNmHo=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4=
+2
View File
@@ -14,6 +14,8 @@ import (
v1beta1 "github.com/grafana/grafana/apps/folder/pkg/apis/folder/v1beta1"
)
var ()
var appManifestData = app.ManifestData{
AppName: "folder",
Group: "folder.grafana.app",
+4 -4
View File
@@ -3,9 +3,9 @@ module github.com/grafana/grafana/apps/iam
go 1.24.4
require (
github.com/grafana/grafana-app-sdk v0.39.0
github.com/grafana/grafana-app-sdk v0.39.2
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250514132646-acbc7b54ed9e
k8s.io/apimachinery v0.33.1
k8s.io/apimachinery v0.33.2
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff
)
@@ -23,7 +23,7 @@ require (
github.com/go-test/deep v1.1.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/google/gnostic-models v0.6.9 // indirect
github.com/grafana/grafana-app-sdk/logging v0.38.2 // indirect
github.com/grafana/grafana-app-sdk/logging v0.39.1 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
@@ -53,7 +53,7 @@ require (
google.golang.org/protobuf v1.36.6 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/client-go v0.33.1 // indirect
k8s.io/client-go v0.33.2 // indirect
k8s.io/klog/v2 v2.130.1 // indirect
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
+10 -10
View File
@@ -32,10 +32,10 @@ github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/grafana/grafana-app-sdk v0.39.0 h1:WC2E9BKXWDX/e2bajdAFjQEyyWf9BFp7Yzbjm6T1T1w=
github.com/grafana/grafana-app-sdk v0.39.0/go.mod h1:xRyBQOttgWTc3tGe9pI0upnpEPVhzALf7Mh/61O4zyY=
github.com/grafana/grafana-app-sdk/logging v0.38.2 h1:EdQTRxbbH72zdqJ09Z76zcSjfALJXkpPLgvKEPPnloc=
github.com/grafana/grafana-app-sdk/logging v0.38.2/go.mod h1:Y/bvbDhBiV/tkIle9RW49pgfSPIPSON8Q4qjx3pyqDk=
github.com/grafana/grafana-app-sdk v0.39.2 h1:ymfr+1318t+JC9U2OYrzVpGmNG/aJONUmFFu/G98Xh8=
github.com/grafana/grafana-app-sdk v0.39.2/go.mod h1:t0m6q561lpoHQCixS9LUHFUhUzDClzNtm7BH60gHVSY=
github.com/grafana/grafana-app-sdk/logging v0.39.1 h1:lI5rbrheuwVPuyIM6LIuEYOCSpgmXahfKtqeMyhbGPU=
github.com/grafana/grafana-app-sdk/logging v0.39.1/go.mod h1:WhDENSnaGHtyVVwZGVnAR7YLvh2xlLDYR3D7E6h7XVk=
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250514132646-acbc7b54ed9e h1:BTKk7LHuG1kmAkucwTA7DuMbKpKvJTKrGdBmUNO4dfQ=
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250514132646-acbc7b54ed9e/go.mod h1:IA4SOwun8QyST9c5UNs/fN37XL6boXXDvRYFcFwbipg=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
@@ -150,12 +150,12 @@ gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
k8s.io/api v0.33.1 h1:tA6Cf3bHnLIrUK4IqEgb2v++/GYUtqiu9sRVk3iBXyw=
k8s.io/api v0.33.1/go.mod h1:87esjTn9DRSRTD4fWMXamiXxJhpOIREjWOSjsW1kEHw=
k8s.io/apimachinery v0.33.1 h1:mzqXWV8tW9Rw4VeW9rEkqvnxj59k1ezDUl20tFK/oM4=
k8s.io/apimachinery v0.33.1/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
k8s.io/client-go v0.33.1 h1:ZZV/Ks2g92cyxWkRRnfUDsnhNn28eFpt26aGc8KbXF4=
k8s.io/client-go v0.33.1/go.mod h1:JAsUrl1ArO7uRVFWfcj6kOomSlCv+JpvIsp6usAGefA=
k8s.io/api v0.33.2 h1:YgwIS5jKfA+BZg//OQhkJNIfie/kmRsO0BmNaVSimvY=
k8s.io/api v0.33.2/go.mod h1:fhrbphQJSM2cXzCWgqU29xLDuks4mu7ti9vveEnpSXs=
k8s.io/apimachinery v0.33.2 h1:IHFVhqg59mb8PJWTLi8m1mAoepkUNYmptHsV+Z1m5jY=
k8s.io/apimachinery v0.33.2/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
k8s.io/client-go v0.33.2 h1:z8CIcc0P581x/J1ZYf4CNzRKxRvQAwoAolYPbtQes+E=
k8s.io/client-go v0.33.2/go.mod h1:9mCgT4wROvL948w6f6ArJNb7yQd7QsvqavDeZHvNmHo=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4=
-2
View File
@@ -14,8 +14,6 @@ import (
v0alpha1 "github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1"
)
var ()
var appManifestData = app.ManifestData{
AppName: "iam",
Group: "iam.grafana.app",
+6 -6
View File
@@ -3,9 +3,9 @@ module github.com/grafana/grafana/apps/playlist
go 1.24.4
require (
github.com/grafana/grafana-app-sdk v0.39.0
k8s.io/apimachinery v0.33.1
k8s.io/client-go v0.33.1
github.com/grafana/grafana-app-sdk v0.39.2
k8s.io/apimachinery v0.33.2
k8s.io/client-go v0.33.2
k8s.io/klog/v2 v2.130.1
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff
)
@@ -31,7 +31,7 @@ require (
github.com/google/go-cmp v0.7.0 // indirect
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/grafana/grafana-app-sdk/logging v0.38.2 // indirect
github.com/grafana/grafana-app-sdk/logging v0.39.1 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
@@ -79,8 +79,8 @@ require (
google.golang.org/protobuf v1.36.6 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/api v0.33.1 // indirect
k8s.io/apiextensions-apiserver v0.33.1 // indirect
k8s.io/api v0.33.2 // indirect
k8s.io/apiextensions-apiserver v0.33.2 // indirect
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
sigs.k8s.io/randfill v1.0.0 // indirect
+12 -12
View File
@@ -47,10 +47,10 @@ github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/grafana/grafana-app-sdk v0.39.0 h1:WC2E9BKXWDX/e2bajdAFjQEyyWf9BFp7Yzbjm6T1T1w=
github.com/grafana/grafana-app-sdk v0.39.0/go.mod h1:xRyBQOttgWTc3tGe9pI0upnpEPVhzALf7Mh/61O4zyY=
github.com/grafana/grafana-app-sdk/logging v0.38.2 h1:EdQTRxbbH72zdqJ09Z76zcSjfALJXkpPLgvKEPPnloc=
github.com/grafana/grafana-app-sdk/logging v0.38.2/go.mod h1:Y/bvbDhBiV/tkIle9RW49pgfSPIPSON8Q4qjx3pyqDk=
github.com/grafana/grafana-app-sdk v0.39.2 h1:ymfr+1318t+JC9U2OYrzVpGmNG/aJONUmFFu/G98Xh8=
github.com/grafana/grafana-app-sdk v0.39.2/go.mod h1:t0m6q561lpoHQCixS9LUHFUhUzDClzNtm7BH60gHVSY=
github.com/grafana/grafana-app-sdk/logging v0.39.1 h1:lI5rbrheuwVPuyIM6LIuEYOCSpgmXahfKtqeMyhbGPU=
github.com/grafana/grafana-app-sdk/logging v0.39.1/go.mod h1:WhDENSnaGHtyVVwZGVnAR7YLvh2xlLDYR3D7E6h7XVk=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
@@ -206,14 +206,14 @@ gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
k8s.io/api v0.33.1 h1:tA6Cf3bHnLIrUK4IqEgb2v++/GYUtqiu9sRVk3iBXyw=
k8s.io/api v0.33.1/go.mod h1:87esjTn9DRSRTD4fWMXamiXxJhpOIREjWOSjsW1kEHw=
k8s.io/apiextensions-apiserver v0.33.1 h1:N7ccbSlRN6I2QBcXevB73PixX2dQNIW0ZRuguEE91zI=
k8s.io/apiextensions-apiserver v0.33.1/go.mod h1:uNQ52z1A1Gu75QSa+pFK5bcXc4hq7lpOXbweZgi4dqA=
k8s.io/apimachinery v0.33.1 h1:mzqXWV8tW9Rw4VeW9rEkqvnxj59k1ezDUl20tFK/oM4=
k8s.io/apimachinery v0.33.1/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
k8s.io/client-go v0.33.1 h1:ZZV/Ks2g92cyxWkRRnfUDsnhNn28eFpt26aGc8KbXF4=
k8s.io/client-go v0.33.1/go.mod h1:JAsUrl1ArO7uRVFWfcj6kOomSlCv+JpvIsp6usAGefA=
k8s.io/api v0.33.2 h1:YgwIS5jKfA+BZg//OQhkJNIfie/kmRsO0BmNaVSimvY=
k8s.io/api v0.33.2/go.mod h1:fhrbphQJSM2cXzCWgqU29xLDuks4mu7ti9vveEnpSXs=
k8s.io/apiextensions-apiserver v0.33.2 h1:6gnkIbngnaUflR3XwE1mCefN3YS8yTD631JXQhsU6M8=
k8s.io/apiextensions-apiserver v0.33.2/go.mod h1:IvVanieYsEHJImTKXGP6XCOjTwv2LUMos0YWc9O+QP8=
k8s.io/apimachinery v0.33.2 h1:IHFVhqg59mb8PJWTLi8m1mAoepkUNYmptHsV+Z1m5jY=
k8s.io/apimachinery v0.33.2/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
k8s.io/client-go v0.33.2 h1:z8CIcc0P581x/J1ZYf4CNzRKxRvQAwoAolYPbtQes+E=
k8s.io/client-go v0.33.2/go.mod h1:9mCgT4wROvL948w6f6ArJNb7yQd7QsvqavDeZHvNmHo=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4=
+586 -18
View File
@@ -10,14 +10,44 @@
"kind": "AnnotationQuery",
"spec": {
"builtIn": true,
"datasource": {
"type": "grafana",
"uid": "-- Grafana --"
},
"enable": true,
"filter": {
"exclude": false,
"ids": [1]
},
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations \u0026 Alerts"
"name": "Annotations \u0026 Alerts",
"query": {
"group": "grafana",
"kind": "DataQuery",
"spec": {},
"version": "v0"
}
}
},
{
"kind": "AnnotationQuery",
"spec": {
"query": {
"kind": "DataQuery",
"group": "grafana-testdata-datasource",
"version": "v0",
"spec": {
"lines": 10,
"refId": "Anno",
"scenarioId": "annotations"
}
},
"enable": true,
"hide": false,
"iconColor": "red",
"name": "Test data annotations",
"builtIn": false,
"filter": {
"exclude": false,
"ids": [1]
}
}
}
],
@@ -37,8 +67,16 @@
"spec": {
"hidden": false,
"query": {
"kind": "grafana-testdata-datasource",
"spec": {}
"datasource": {
"name": "gdev-testdata"
},
"group": "grafana-testdata-datasource",
"kind": "DataQuery",
"spec": {
"scenarioId": "random_walk",
"seriesCount": 3
},
"version": "v0"
},
"refId": "A"
}
@@ -51,7 +89,7 @@
"description": "",
"id": 1,
"links": [],
"title": "Simle timeseries",
"title": "Simple timeseries (WITH DS REF)",
"vizConfig": {
"kind": "timeseries",
"spec": {
@@ -93,12 +131,12 @@
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green"
"color": "green",
"value": 0
},
{
"color": "red",
@@ -122,7 +160,7 @@
"sort": "none"
}
},
"pluginVersion": "12.0.0-pre"
"pluginVersion": "12.1.0-pre"
}
}
}
@@ -139,8 +177,13 @@
"spec": {
"hidden": false,
"query": {
"kind": "grafana-testdata-datasource",
"spec": {}
"group": "grafana-testdata-datasource",
"kind": "DataQuery",
"spec": {
"scenarioId": "random_walk",
"seriesCount": 4
},
"version": "v0"
},
"refId": "A"
}
@@ -153,7 +196,7 @@
"description": "",
"id": 2,
"links": [],
"title": "Simple stat",
"title": "Simple stat (NO DS REF)",
"vizConfig": {
"kind": "stat",
"spec": {
@@ -162,12 +205,12 @@
"color": {
"mode": "thresholds"
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green"
"color": "green",
"value": 0
},
{
"color": "red",
@@ -193,7 +236,496 @@
"textMode": "auto",
"wideLayout": true
},
"pluginVersion": "12.0.0-pre"
"pluginVersion": "12.1.0-pre"
}
}
}
},
"panel-3": {
"kind": "Panel",
"spec": {
"data": {
"kind": "QueryGroup",
"spec": {
"queries": [
{
"kind": "PanelQuery",
"spec": {
"hidden": false,
"query": {
"group": "prometheus",
"kind": "DataQuery",
"spec": {
"disableTextWrap": false,
"editorMode": "builder",
"expr": "rate(counters_requests[$__rate_interval])",
"fullMetaSearch": false,
"includeNullMetadata": false,
"instant": false,
"legendFormat": "__auto",
"range": true,
"useBackend": false
},
"version": "v0"
},
"refId": "A"
}
}
],
"queryOptions": {},
"transformations": []
}
},
"description": "",
"id": 3,
"links": [],
"title": "Panel with NO REF to gdev-prometheus",
"vizConfig": {
"kind": "timeseries",
"spec": {
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"barWidthFactor": 0.6,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": 0
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"hideZeros": false,
"mode": "single",
"sort": "none"
}
},
"pluginVersion": "12.1.0-pre"
}
}
}
},
"panel-4": {
"kind": "Panel",
"spec": {
"data": {
"kind": "QueryGroup",
"spec": {
"queries": [
{
"kind": "PanelQuery",
"spec": {
"hidden": false,
"query": {
"datasource": {
"name": "gdev-prometheus"
},
"group": "prometheus",
"kind": "DataQuery",
"spec": {
"disableTextWrap": false,
"editorMode": "builder",
"expr": "rate(counters_requests[$__rate_interval])",
"fullMetaSearch": false,
"includeNullMetadata": false,
"instant": false,
"legendFormat": "__auto",
"range": true,
"useBackend": false
},
"version": "v0"
},
"refId": "A"
}
}
],
"queryOptions": {},
"transformations": []
}
},
"description": "",
"id": 4,
"links": [],
"title": "Panel with ref to gdev-prometheus",
"vizConfig": {
"kind": "timeseries",
"spec": {
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"barWidthFactor": 0.6,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": 0
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"hideZeros": false,
"mode": "single",
"sort": "none"
}
},
"pluginVersion": "12.1.0-pre"
}
}
}
},
"panel-5": {
"kind": "Panel",
"spec": {
"data": {
"kind": "QueryGroup",
"spec": {
"queries": [
{
"kind": "PanelQuery",
"spec": {
"hidden": false,
"query": {
"datasource": {
"name": "gdev-prometheus"
},
"group": "prometheus",
"kind": "DataQuery",
"spec": {
"disableTextWrap": false,
"editorMode": "builder",
"expr": "rate(counters_requests{server=\"backend-01\"}[$__rate_interval])",
"fullMetaSearch": false,
"includeNullMetadata": false,
"legendFormat": "__auto",
"range": true,
"useBackend": false
},
"version": "v0"
},
"refId": "A"
}
},
{
"kind": "PanelQuery",
"spec": {
"hidden": false,
"query": {
"datasource": {
"name": "gdev-testdata"
},
"group": "grafana-testdata-datasource",
"kind": "DataQuery",
"spec": {},
"version": "v0"
},
"refId": "B"
}
}
],
"queryOptions": {},
"transformations": []
}
},
"description": "",
"id": 5,
"links": [],
"title": "Mixed DS WITH REFS",
"vizConfig": {
"kind": "timeseries",
"spec": {
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"barWidthFactor": 0.6,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": 0
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"hideZeros": false,
"mode": "single",
"sort": "none"
}
},
"pluginVersion": "12.1.0-pre"
}
}
}
},
"panel-6": {
"kind": "Panel",
"spec": {
"data": {
"kind": "QueryGroup",
"spec": {
"queries": [
{
"kind": "PanelQuery",
"spec": {
"hidden": false,
"query": {
"group": "prometheus",
"kind": "DataQuery",
"spec": {
"disableTextWrap": false,
"editorMode": "builder",
"expr": "rate(counters_requests{server=\"backend-01\"}[$__rate_interval])",
"fullMetaSearch": false,
"includeNullMetadata": false,
"legendFormat": "__auto",
"range": true,
"useBackend": false
},
"version": "v0"
},
"refId": "A"
}
},
{
"kind": "PanelQuery",
"spec": {
"hidden": false,
"query": {
"group": "grafana-testdata-datasource",
"kind": "DataQuery",
"spec": {},
"version": "v0"
},
"refId": "B"
}
}
],
"queryOptions": {},
"transformations": []
}
},
"description": "",
"id": 6,
"links": [],
"title": "Mixed DS WITHOUT REFS",
"vizConfig": {
"kind": "timeseries",
"spec": {
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisBorderShow": false,
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"barWidthFactor": 0.6,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"insertNulls": false,
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": 0
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"hideZeros": false,
"mode": "single",
"sort": "none"
}
},
"pluginVersion": "12.1.0-pre"
}
}
}
@@ -204,6 +736,24 @@
"spec": {
"columnWidthMode": "standard",
"items": [
{
"kind": "AutoGridLayoutItem",
"spec": {
"element": {
"kind": "ElementReference",
"name": "panel-3"
}
}
},
{
"kind": "AutoGridLayoutItem",
"spec": {
"element": {
"kind": "ElementReference",
"name": "panel-4"
}
}
},
{
"kind": "AutoGridLayoutItem",
"spec": {
@@ -221,6 +771,24 @@
"name": "panel-1"
}
}
},
{
"kind": "AutoGridLayoutItem",
"spec": {
"element": {
"kind": "ElementReference",
"name": "panel-5"
}
}
},
{
"kind": "AutoGridLayoutItem",
"spec": {
"element": {
"kind": "ElementReference",
"name": "panel-6"
}
}
}
],
"maxColumnCount": 3,
@@ -235,7 +803,7 @@
"autoRefresh": "",
"autoRefreshIntervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"],
"fiscalYearStartMonth": 0,
"from": "now-6h",
"from": "now-5m",
"hideTimepicker": false,
"timezone": "browser",
"to": "now"
@@ -90,6 +90,12 @@ This collapsible section provides more details about which checks have been perf
Click the cogwheel in this section to access Grafana Advisor settings, where you can enable or disable checks according to your preferences.
{{< /admonition >}}
### Enable LLM suggestions
If the [Grafana LLM app](https://grafana.com/grafana/plugins/grafana-llm-app/) is installed, the Advisor can use it to generate suggestions for issues. Enable the LLM app and click the magic (✨) button to generate a suggestion for an issue.
![<Grafana Advisor - LLM suggestions>](/media/docs/grafana-advisor/llm-suggestions.png)
## Address issues
To resolve issues flagged by Grafana Advisor and maintain system reliability, follow the best practices below. Regularly check the Advisor to keep your Grafana instance secure and up to date.
+26 -41
View File
@@ -2,21 +2,11 @@
"apiVersion": "dashboard.grafana.app/v2alpha1",
"kind": "Dashboard",
"metadata": {
"name": "admjzp8",
"namespace": "default",
"uid": "hrbekBWXeM7nC7GtouIbcngFyuqt8Xx7KlE4AnTwV7AX",
"resourceVersion": "1",
"name": "fa400625-2a44-4add-a369-e6c972eb4bd6",
"generation": 1,
"creationTimestamp": "2025-05-16T09:41:56Z",
"labels": {
"grafana.app/deprecatedInternalID": "182"
},
"annotations": {
"grafana.app/createdBy": "user:cejvsh18uudxcf",
"grafana.app/updatedBy": "user:cejvsh18uudxcf",
"grafana.app/updatedTimestamp": "2025-05-16T09:41:56Z",
"grafana.app/folder": ""
}
"creationTimestamp": "2025-05-27T11:40:22Z",
"labels": {},
"annotations": {}
},
"spec": {
"annotations": [
@@ -24,19 +14,20 @@
"kind": "AnnotationQuery",
"spec": {
"builtIn": true,
"datasource": {
"type": "grafana",
"uid": "-- Grafana --"
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts"
"name": "Annotations & Alerts",
"query": {
"group": "grafana",
"kind": "DataQuery",
"spec": {},
"version": "v0"
}
}
}
],
"cursorSync": "Off",
"description": "",
"editable": true,
"elements": {
"panel-1": {
@@ -49,14 +40,12 @@
{
"kind": "PanelQuery",
"spec": {
"datasource": {
"type": "grafana-testdata-datasource",
"uid": "PD8C576611E62080A"
},
"hidden": false,
"query": {
"kind": "grafana-testdata-datasource",
"spec": {}
"group": "grafana-testdata-datasource",
"kind": "DataQuery",
"spec": {},
"version": "v0"
},
"refId": "A"
}
@@ -155,14 +144,12 @@
{
"kind": "PanelQuery",
"spec": {
"datasource": {
"type": "grafana-testdata-datasource",
"uid": "PD8C576611E62080A"
},
"hidden": false,
"query": {
"kind": "grafana-testdata-datasource",
"spec": {}
"group": "grafana-testdata-datasource",
"kind": "DataQuery",
"spec": {},
"version": "v0"
},
"refId": "A"
}
@@ -261,14 +248,12 @@
{
"kind": "PanelQuery",
"spec": {
"datasource": {
"type": "grafana-testdata-datasource",
"uid": "PD8C576611E62080A"
},
"hidden": false,
"query": {
"kind": "grafana-testdata-datasource",
"spec": {}
"group": "grafana-testdata-datasource",
"kind": "DataQuery",
"spec": {},
"version": "v0"
},
"refId": "A"
}
@@ -380,7 +365,7 @@
"spec": {
"element": {
"kind": "ElementReference",
"name": "panel-2"
"name": "panel-3"
},
"height": 8,
"width": 12,
@@ -393,7 +378,7 @@
"spec": {
"element": {
"kind": "ElementReference",
"name": "panel-3"
"name": "panel-2"
},
"height": 8,
"width": 12,
@@ -417,7 +402,7 @@
"timezone": "browser",
"to": "now"
},
"title": "New Test V2 Dashboard",
"title": "Test V2 Dashboard",
"variables": []
},
"status": {}
@@ -17,5 +17,9 @@ export const importV2Dashboard = ({ title }: ImportDashboardConfig) => {
if (title) {
e2e.components.ImportDashboardForm.name().clear().type(title);
}
e2e.components.DataSourcePicker.inputV2().click();
cy.get('div[data-testid="data-source-card"]').first().click();
e2e.components.ImportDashboardForm.submit().click();
};
+9 -9
View File
@@ -97,8 +97,8 @@ require (
github.com/grafana/gofpdf v0.0.0-20250307124105-3b9c5d35577f // @grafana/sharing-squad
github.com/grafana/gomemcache v0.0.0-20250318131618-74242eea118d // @grafana/grafana-operator-experience-squad
github.com/grafana/grafana-api-golang-client v0.27.0 // @grafana/alerting-backend
github.com/grafana/grafana-app-sdk v0.39.0 // @grafana/grafana-app-platform-squad
github.com/grafana/grafana-app-sdk/logging v0.38.2 // @grafana/grafana-app-platform-squad
github.com/grafana/grafana-app-sdk v0.39.2 // @grafana/grafana-app-platform-squad
github.com/grafana/grafana-app-sdk/logging v0.39.1 // @grafana/grafana-app-platform-squad
github.com/grafana/grafana-aws-sdk v1.0.2 // @grafana/aws-datasources
github.com/grafana/grafana-azure-sdk-go/v2 v2.1.6 // @grafana/partner-datasources
github.com/grafana/grafana-cloud-migration-snapshot v1.6.0 // @grafana/grafana-operator-experience-squad
@@ -212,11 +212,11 @@ require (
gopkg.in/mail.v2 v2.3.1 // @grafana/grafana-backend-group
gopkg.in/yaml.v2 v2.4.0 // @grafana/alerting-backend
gopkg.in/yaml.v3 v3.0.1 // @grafana/alerting-backend
k8s.io/api v0.33.1 // @grafana/grafana-app-platform-squad
k8s.io/apimachinery v0.33.1 // @grafana/grafana-app-platform-squad
k8s.io/apiserver v0.33.1 // @grafana/grafana-app-platform-squad
k8s.io/client-go v0.33.1 // @grafana/grafana-app-platform-squad
k8s.io/component-base v0.33.1 // @grafana/grafana-app-platform-squad
k8s.io/api v0.33.2 // @grafana/grafana-app-platform-squad
k8s.io/apimachinery v0.33.2 // @grafana/grafana-app-platform-squad
k8s.io/apiserver v0.33.2 // @grafana/grafana-app-platform-squad
k8s.io/client-go v0.33.2 // @grafana/grafana-app-platform-squad
k8s.io/component-base v0.33.2 // @grafana/grafana-app-platform-squad
k8s.io/klog/v2 v2.130.1 // @grafana/grafana-app-platform-squad
k8s.io/kube-aggregator v0.33.1 // @grafana/grafana-app-platform-squad
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // @grafana/grafana-app-platform-squad
@@ -587,8 +587,8 @@ require (
gopkg.in/src-d/go-errors.v1 v1.0.0 // indirect
gopkg.in/telebot.v3 v3.2.1 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
k8s.io/apiextensions-apiserver v0.33.1 // indirect
k8s.io/kms v0.33.1 // indirect
k8s.io/apiextensions-apiserver v0.33.2 // indirect
k8s.io/kms v0.33.2 // indirect
modernc.org/libc v1.65.0 // indirect
modernc.org/mathutil v1.7.1 // indirect
modernc.org/memory v1.10.0 // indirect
+18 -18
View File
@@ -1606,10 +1606,10 @@ github.com/grafana/gomemcache v0.0.0-20250318131618-74242eea118d h1:oXRJlb9UjVsl
github.com/grafana/gomemcache v0.0.0-20250318131618-74242eea118d/go.mod h1:j/s0jkda4UXTemDs7Pgw/vMT06alWc42CHisvYac0qw=
github.com/grafana/grafana-api-golang-client v0.27.0 h1:zIwMXcbCB4n588i3O2N6HfNcQogCNTd/vPkEXTr7zX8=
github.com/grafana/grafana-api-golang-client v0.27.0/go.mod h1:uNLZEmgKtTjHBtCQMwNn3qsx2mpMb8zU+7T4Xv3NR9Y=
github.com/grafana/grafana-app-sdk v0.39.0 h1:WC2E9BKXWDX/e2bajdAFjQEyyWf9BFp7Yzbjm6T1T1w=
github.com/grafana/grafana-app-sdk v0.39.0/go.mod h1:xRyBQOttgWTc3tGe9pI0upnpEPVhzALf7Mh/61O4zyY=
github.com/grafana/grafana-app-sdk/logging v0.38.2 h1:EdQTRxbbH72zdqJ09Z76zcSjfALJXkpPLgvKEPPnloc=
github.com/grafana/grafana-app-sdk/logging v0.38.2/go.mod h1:Y/bvbDhBiV/tkIle9RW49pgfSPIPSON8Q4qjx3pyqDk=
github.com/grafana/grafana-app-sdk v0.39.2 h1:ymfr+1318t+JC9U2OYrzVpGmNG/aJONUmFFu/G98Xh8=
github.com/grafana/grafana-app-sdk v0.39.2/go.mod h1:t0m6q561lpoHQCixS9LUHFUhUzDClzNtm7BH60gHVSY=
github.com/grafana/grafana-app-sdk/logging v0.39.1 h1:lI5rbrheuwVPuyIM6LIuEYOCSpgmXahfKtqeMyhbGPU=
github.com/grafana/grafana-app-sdk/logging v0.39.1/go.mod h1:WhDENSnaGHtyVVwZGVnAR7YLvh2xlLDYR3D7E6h7XVk=
github.com/grafana/grafana-aws-sdk v1.0.2 h1:98eBuHYFmgvH0xO9kKf4RBsEsgQRp8EOA/9yhDIpkss=
github.com/grafana/grafana-aws-sdk v1.0.2/go.mod h1:hO7q7yWV+t6dmiyJjMa3IbuYnYkBua+G/IAlOPVIYKE=
github.com/grafana/grafana-azure-sdk-go/v2 v2.1.6 h1:OfCkitCuomzZKW1WYHrG8MxKwtMhALb7jqoj+487eTg=
@@ -3571,19 +3571,19 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las=
k8s.io/api v0.0.0-20190813020757-36bff7324fb7/go.mod h1:3Iy+myeAORNCLgjd/Xu9ebwN7Vh59Bw0vh9jhoX+V58=
k8s.io/api v0.33.1 h1:tA6Cf3bHnLIrUK4IqEgb2v++/GYUtqiu9sRVk3iBXyw=
k8s.io/api v0.33.1/go.mod h1:87esjTn9DRSRTD4fWMXamiXxJhpOIREjWOSjsW1kEHw=
k8s.io/apiextensions-apiserver v0.33.1 h1:N7ccbSlRN6I2QBcXevB73PixX2dQNIW0ZRuguEE91zI=
k8s.io/apiextensions-apiserver v0.33.1/go.mod h1:uNQ52z1A1Gu75QSa+pFK5bcXc4hq7lpOXbweZgi4dqA=
k8s.io/api v0.33.2 h1:YgwIS5jKfA+BZg//OQhkJNIfie/kmRsO0BmNaVSimvY=
k8s.io/api v0.33.2/go.mod h1:fhrbphQJSM2cXzCWgqU29xLDuks4mu7ti9vveEnpSXs=
k8s.io/apiextensions-apiserver v0.33.2 h1:6gnkIbngnaUflR3XwE1mCefN3YS8yTD631JXQhsU6M8=
k8s.io/apiextensions-apiserver v0.33.2/go.mod h1:IvVanieYsEHJImTKXGP6XCOjTwv2LUMos0YWc9O+QP8=
k8s.io/apimachinery v0.0.0-20190809020650-423f5d784010/go.mod h1:Waf/xTS2FGRrgXCkO5FP3XxTOWh0qLf2QhL1qFZZ/R8=
k8s.io/apimachinery v0.33.1 h1:mzqXWV8tW9Rw4VeW9rEkqvnxj59k1ezDUl20tFK/oM4=
k8s.io/apimachinery v0.33.1/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
k8s.io/apiserver v0.33.1 h1:yLgLUPDVC6tHbNcw5uE9mo1T6ELhJj7B0geifra3Qdo=
k8s.io/apiserver v0.33.1/go.mod h1:VMbE4ArWYLO01omz+k8hFjAdYfc3GVAYPrhP2tTKccs=
k8s.io/client-go v0.33.1 h1:ZZV/Ks2g92cyxWkRRnfUDsnhNn28eFpt26aGc8KbXF4=
k8s.io/client-go v0.33.1/go.mod h1:JAsUrl1ArO7uRVFWfcj6kOomSlCv+JpvIsp6usAGefA=
k8s.io/component-base v0.33.1 h1:EoJ0xA+wr77T+G8p6T3l4efT2oNwbqBVKR71E0tBIaI=
k8s.io/component-base v0.33.1/go.mod h1:guT/w/6piyPfTgq7gfvgetyXMIh10zuXA6cRRm3rDuY=
k8s.io/apimachinery v0.33.2 h1:IHFVhqg59mb8PJWTLi8m1mAoepkUNYmptHsV+Z1m5jY=
k8s.io/apimachinery v0.33.2/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
k8s.io/apiserver v0.33.2 h1:KGTRbxn2wJagJowo29kKBp4TchpO1DRO3g+dB/KOJN4=
k8s.io/apiserver v0.33.2/go.mod h1:9qday04wEAMLPWWo9AwqCZSiIn3OYSZacDyu/AcoM/M=
k8s.io/client-go v0.33.2 h1:z8CIcc0P581x/J1ZYf4CNzRKxRvQAwoAolYPbtQes+E=
k8s.io/client-go v0.33.2/go.mod h1:9mCgT4wROvL948w6f6ArJNb7yQd7QsvqavDeZHvNmHo=
k8s.io/component-base v0.33.2 h1:sCCsn9s/dG3ZrQTX/Us0/Sx2R0G5kwa0wbZFYoVp/+0=
k8s.io/component-base v0.33.2/go.mod h1:/41uw9wKzuelhN+u+/C59ixxf4tYQKW7p32ddkYNe2k=
k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
@@ -3591,8 +3591,8 @@ k8s.io/klog v0.3.1/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
k8s.io/klog v0.4.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kms v0.33.1 h1:jJKrFhsbVofpyLF+G8k+drwOAF9CMQpxilHa5Uilb8Q=
k8s.io/kms v0.33.1/go.mod h1:C1I8mjFFBNzfUZXYt9FZVJ8MJl7ynFbGgZFbBzkBJ3E=
k8s.io/kms v0.33.2 h1:GFwNXX4CZGQCg9DPOaJi1/+iKidCtB9/OIAGdzRo8FI=
k8s.io/kms v0.33.2/go.mod h1:C1I8mjFFBNzfUZXYt9FZVJ8MJl7ynFbGgZFbBzkBJ3E=
k8s.io/kube-aggregator v0.33.1 h1:PigQUqAvd6Y4hBjQAqhKz3lEJC2VHLL4bSOEuS06a40=
k8s.io/kube-aggregator v0.33.1/go.mod h1:16/wlU5Lj7hNJSv7JSu5FLvxyrgiJVLCHzfVoECAsuI=
k8s.io/kube-openapi v0.0.0-20190709113604-33be087ad058/go.mod h1:nfDlWeOsu3pUf4yWGL+ERqohP4YsZcBJXWMK+gkzOA4=
+184 -23
View File
@@ -6,13 +6,19 @@ atomicgo.dev/schedule v0.1.0 h1:nTthAbhZS5YZmgYbb2+DH8uQIZcTlIrd4eYr3UQxEjs=
atomicgo.dev/schedule v0.1.0/go.mod h1:xeUa3oAkiuHYh8bKiQBRojqAMq3PXXbJujjb0hw8pEU=
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.6-20250425153114-8976f5be98c1.1 h1:YhMSc48s25kr7kv31Z8vf7sPUIq5YJva9z1mn/hAt0M=
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.6-20250425153114-8976f5be98c1.1/go.mod h1:avRlCjnFzl98VPaeCtJ24RrV/wwHFzB8sWXhj26+n/U=
buf.build/gen/go/parca-dev/parca/connectrpc/go v1.18.1-20250703125925-3f0fcf4bff96.1 h1:MXQkdpJwbCwskYLQ3dUv/5gmk8fSsUwu78u+kXebbek=
buf.build/gen/go/parca-dev/parca/connectrpc/go v1.18.1-20250703125925-3f0fcf4bff96.1/go.mod h1:pjl83IqpNF7Lm/lOPMLQ5IIfCg+yTu2A9OgYTcEncCs=
buf.build/gen/go/parca-dev/parca/protocolbuffers/go v1.36.2-20250703125925-3f0fcf4bff96.1 h1:9nqE/pDc/HXAXiD5pZncPywjAzWgKuBkFFYgdK2lVU8=
buf.build/gen/go/parca-dev/parca/protocolbuffers/go v1.36.2-20250703125925-3f0fcf4bff96.1/go.mod h1:1M7nlq2ljfzb95x9LaA2j1gYIvDkVZii58mGvTa9ExM=
buf.build/go/protovalidate v0.12.0 h1:4GKJotbspQjRCcqZMGVSuC8SjwZ/FmgtSuKDpKUTZew=
buf.build/go/protovalidate v0.12.0/go.mod h1:q3PFfbzI05LeqxSwq+begW2syjy2Z6hLxZSkP1OH/D0=
cel.dev/expr v0.15.0/go.mod h1:TRSuuV7DlVCE/uwv5QbAiW/v8l5O8C4eEPHeu7gf7Sg=
cel.dev/expr v0.16.0/go.mod h1:TRSuuV7DlVCE/uwv5QbAiW/v8l5O8C4eEPHeu7gf7Sg=
cel.dev/expr v0.16.1/go.mod h1:AsGA5zb3WruAEQeQng1RZdGEXmBj0jvMWh6l5SnNuC8=
cel.dev/expr v0.19.0/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw=
cel.dev/expr v0.19.1/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw=
cel.dev/expr v0.19.2/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw=
cel.dev/expr v0.23.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw=
cloud.google.com/go v0.112.2/go.mod h1:iEqjp//KquGIJV/m+Pk3xecgKNhV+ry+vVTsy4TbDms=
cloud.google.com/go v0.116.0/go.mod h1:cEPSRWPzZEswwdr9BxE6ChEn01dWlTaF05LiC2Xs70U=
cloud.google.com/go v0.118.1/go.mod h1:CFO4UPEPi8oV21xoezZCrd3d81K4fFkDTEJu4R8K+9M=
cloud.google.com/go v0.118.3/go.mod h1:Lhs3YLnBlwJ4KA6nuObNMZ/fCbOQBPuWKPoE0Wa/9Vc=
cloud.google.com/go/accessapproval v1.8.3 h1:axlU03FRiXDNupsmPG7LKzuS4Enk1gf598M62lWVB74=
cloud.google.com/go/accessapproval v1.8.3/go.mod h1:3speETyAv63TDrDmo5lIkpVueFkQcQchkiw/TAMbBo4=
cloud.google.com/go/accesscontextmanager v1.9.3 h1:8zVoeiBa4erMCLEXltOcqVEsZhS26JZ5/Vrgs59eQiI=
@@ -38,6 +44,14 @@ cloud.google.com/go/asset v1.20.4 h1:6oNgjcs5KCPGBD71G0IccK6TfeFsEtBTyQ3Q+Dn09bs
cloud.google.com/go/asset v1.20.4/go.mod h1:DP09pZ+SoFWUZyPZx26xVroHk+6+9umnQv+01yfJxbM=
cloud.google.com/go/assuredworkloads v1.12.3 h1:RU1WhF1zMggdXAZ+ezYTn4Eh/FdiX7sz8lLXGERn4Po=
cloud.google.com/go/assuredworkloads v1.12.3/go.mod h1:iGBkyMGdtlsxhCi4Ys5SeuvIrPTeI6HeuEJt7qJgJT8=
cloud.google.com/go/auth v0.3.0/go.mod h1:lBv6NKTWp8E3LPzmO1TbiiRKc4drLOfHsgmlH9ogv5w=
cloud.google.com/go/auth v0.13.0/go.mod h1:COOjD9gwfKNKz+IIduatIhYJQIc0mG3H102r/EMxX6Q=
cloud.google.com/go/auth v0.14.0/go.mod h1:CYsoRL1PdiDuqeQpZE0bP2pnPrGqFcOkI0nldEQis+A=
cloud.google.com/go/auth v0.15.0/go.mod h1:WJDGqZ1o9E9wKIL+IwStfyn/+s59zl4Bi+1KQNVXLZ8=
cloud.google.com/go/auth v0.16.0/go.mod h1:1howDHJ5IETh/LwYs3ZxvlkXF48aSqqJUM+5o02dNOI=
cloud.google.com/go/auth/oauth2adapt v0.2.2/go.mod h1:wcYjgpZI9+Yu7LyYBg4pqSiaRkfEK3GQcpb7C/uyF1Q=
cloud.google.com/go/auth/oauth2adapt v0.2.6/go.mod h1:AlmsELtlEBnaNTL7jCj8VQFLy6mbZv0s4Q7NGBeQ5E8=
cloud.google.com/go/auth/oauth2adapt v0.2.7/go.mod h1:NTbTTzfvPl1Y3V1nPpOgl2w6d/FjO7NNUQaWSox6ZMc=
cloud.google.com/go/automl v1.14.4 h1:vkD+hQ75SMINMgJBT/KDpFYvfQLzJbtIQZdw0AWq8Rs=
cloud.google.com/go/automl v1.14.4/go.mod h1:sVfsJ+g46y7QiQXpVs9nZ/h8ntdujHm5xhjHW32b3n4=
cloud.google.com/go/baremetalsolution v1.3.3 h1:OL+KT+wCumdDhG44aeqGAdkwdT8Wa4Lh+o4INM+CQjw=
@@ -127,8 +141,12 @@ cloud.google.com/go/gkehub v0.15.3/go.mod h1:nzFT/Q+4HdQES/F+FP1QACEEWR9Hd+Sh00q
cloud.google.com/go/gkemulticloud v1.5.1 h1:JWe6PDNpNU88ZYvQkTd7w28fgeIs/gg6i0hcjUkgZ3M=
cloud.google.com/go/gkemulticloud v1.5.1/go.mod h1:OdmhfSPXuJ0Kn9dQ2I3Ou7XZ3QK8caV4XVOJZwrIa3s=
cloud.google.com/go/grafeas v0.2.0 h1:CYjC+xzdPvbV65gi6Dr4YowKcmLo045pm18L0DhdELM=
cloud.google.com/go/grafeas v0.3.11 h1:CobnwnyeY1j1Defi5vbEircI+jfrk3ci5m004ZjiFP4=
cloud.google.com/go/grafeas v0.3.11/go.mod h1:dcQyG2+T4tBgG0MvJAh7g2wl/xHV2w+RZIqivwuLjNg=
cloud.google.com/go/gsuiteaddons v1.7.4 h1:f3eMYsCDdg2AeldIPdKmBRxN1WoiTpE3RvX5orcm/I8=
cloud.google.com/go/gsuiteaddons v1.7.4/go.mod h1:gpE2RUok+HUhuK7RPE/fCOEgnTffS0lCHRaAZLxAMeE=
cloud.google.com/go/iam v1.2.2/go.mod h1:0Ys8ccaZHdI1dEUilwzqng/6ps2YB6vRsjIe00/+6JY=
cloud.google.com/go/iam v1.4.0/go.mod h1:gMBgqPaERlriaOV0CUl//XUzDhSfXevn4OEUbg6VRs4=
cloud.google.com/go/iap v1.10.3 h1:OWNYFHPyIBNHEAEFdVKOltYWe0g3izSrpFJW6Iidovk=
cloud.google.com/go/iap v1.10.3/go.mod h1:xKgn7bocMuCFYhzRizRWP635E2LNPnIXT7DW0TlyPJ8=
cloud.google.com/go/ids v1.5.3 h1:wbFF7twu0XScFr+dtsVxTTttbFIRYt/SJjZiHFidtYE=
@@ -139,6 +157,9 @@ cloud.google.com/go/language v1.14.3 h1:8hmFMiS3wjjj3TX/U1zZYTgzwZoUjDbo9PaqcYEm
cloud.google.com/go/language v1.14.3/go.mod h1:hjamj+KH//QzF561ZuU2J+82DdMlFUjmiGVWpovGGSA=
cloud.google.com/go/lifesciences v0.10.3 h1:Z05C+Ui953f0EQx9hJ1la6+QQl8ADrIs3iNwP5Elkpg=
cloud.google.com/go/lifesciences v0.10.3/go.mod h1:hnUUFht+KcZcliixAg+iOh88FUwAzDQQt5tWd7iIpNg=
cloud.google.com/go/longrunning v0.5.6/go.mod h1:vUaDrWYOMKRuhiv6JBnn49YxCPz2Ayn9GqyjaBT8/mA=
cloud.google.com/go/longrunning v0.6.2/go.mod h1:k/vIs83RN4bE3YCswdXC5PFfWVILjm3hpEUlSko4PiI=
cloud.google.com/go/longrunning v0.6.4/go.mod h1:ttZpLCe6e7EXvn9OxpBRx7kZEB0efv8yBO6YnVMfhJs=
cloud.google.com/go/managedidentities v1.7.3 h1:b9xGs24BIjfyvLgCtJoClOZpPi8d8owPgWe5JEINgaY=
cloud.google.com/go/managedidentities v1.7.3/go.mod h1:H9hO2aMkjlpY+CNnKWRh+WoQiUIDO8457wWzUGsdtLA=
cloud.google.com/go/maps v1.19.0 h1:deVm1ZFyCrUwxG11CdvtBz350VG5JUQ/LHTLnQrBgrM=
@@ -149,6 +170,8 @@ cloud.google.com/go/memcache v1.11.3 h1:XH/qT3GbbSH//R0JTqR77lRpBxaa0N9sHgAzfwbT
cloud.google.com/go/memcache v1.11.3/go.mod h1:UeWI9cmY7hvjU1EU6dwJcQb6EFG4GaM3KNXOO2OFsbI=
cloud.google.com/go/metastore v1.14.3 h1:jDqeCw6NGDRAPT9+2Y/EjnWAB0BfCcUfmPLOyhB0eHs=
cloud.google.com/go/metastore v1.14.3/go.mod h1:HlbGVOvg0ubBLVFRk3Otj3gtuzInuzO/TImOBwsKlG4=
cloud.google.com/go/monitoring v1.21.2/go.mod h1:hS3pXvaG8KgWTSz+dAdyzPrGUYmi2Q+WFX8g2hqVEZU=
cloud.google.com/go/monitoring v1.22.1/go.mod h1:AuZZXAoN0WWWfsSvET1Cpc4/1D8LXq8KRDU87fMS6XY=
cloud.google.com/go/networkconnectivity v1.16.1 h1:YsVhG71ZC4FkqCP2oCI55x/JeGFyd7738Lt8iNTrzJw=
cloud.google.com/go/networkconnectivity v1.16.1/go.mod h1:GBC1iOLkblcnhcnfRV92j4KzqGBrEI6tT7LP52nZCTk=
cloud.google.com/go/networkmanagement v1.18.0 h1:oEoFGPYxTBsY47h0zdoE2ojV5aU/541D83UmxfjHWaE=
@@ -213,6 +236,8 @@ cloud.google.com/go/spanner v1.76.1 h1:vYbVZuXfnFwvNcvH3lhI2PeUA+kHyqKmLC7mJWaC4
cloud.google.com/go/spanner v1.76.1/go.mod h1:YtwoE+zObKY7+ZeDCBtZ2ukM+1/iPaMfUM+KnTh/sx0=
cloud.google.com/go/speech v1.26.0 h1:qvURtJs7BQzQhbxWxwai0pT79S8KLVKJ/4W8igVkt1Y=
cloud.google.com/go/speech v1.26.0/go.mod h1:78bqDV2SgwFlP/M4n3i3PwLthFq6ta7qmyG6lUV7UCA=
cloud.google.com/go/storage v1.49.0/go.mod h1:k1eHhhpLvrPjVGfo0mOUPEJ4Y2+a/Hv5PiwehZI9qGU=
cloud.google.com/go/storage v1.50.0/go.mod h1:l7XeiD//vx5lfqE3RavfmU9yvk5Pp0Zhcv482poyafY=
cloud.google.com/go/storagetransfer v1.12.1 h1:W3v9A7MGBN7H9sAFstyciwP/1XEQhUhZfrjclmDnpMs=
cloud.google.com/go/storagetransfer v1.12.1/go.mod h1:hQqbfs8/LTmObJyCC0KrlBw8yBJ2bSFlaGila0qBMk4=
cloud.google.com/go/talent v1.8.0 h1:olv+s2g+LGXeJi+MYF1wI44/TwHaVnO0N7PiucVf5ZQ=
@@ -221,6 +246,7 @@ cloud.google.com/go/texttospeech v1.11.0 h1:YF/RdNb+jUEp22cIZCvqiFjfA5OxGE+Dxss3
cloud.google.com/go/texttospeech v1.11.0/go.mod h1:7M2ro3I2QfIEvArFk1TJ+pqXJqhszDtxUpnIv/150As=
cloud.google.com/go/tpu v1.8.0 h1:BvMNijOb6Vd46Rr/SR5jWv1MPosOhVsi0UaeAGNjeds=
cloud.google.com/go/tpu v1.8.0/go.mod h1:XyNzyK1xc55WvL5rZEML0Z9/TUHDfnq0uICkQw6rWMo=
cloud.google.com/go/translate v1.10.3/go.mod h1:GW0vC1qvPtd3pgtypCv4k4U8B7EdgK9/QEF2aJEUovs=
cloud.google.com/go/translate v1.12.3 h1:XJ7LipYJi80BCgVk2lx1fwc7DIYM6oV2qx1G4IAGQ5w=
cloud.google.com/go/translate v1.12.3/go.mod h1:qINOVpgmgBnY4YTFHdfVO4nLrSBlpvlIyosqpGEgyEg=
cloud.google.com/go/video v1.23.3 h1:C2FH+6yr6LCZC4fP0gm9FwJB/SRh5Ul88O5Sc/bL83I=
@@ -293,6 +319,13 @@ github.com/DmitriyVTitov/size v1.5.0 h1:/PzqxYrOyOUX1BXj6J9OuVRVGe+66VL4D9FlUaW5
github.com/DmitriyVTitov/size v1.5.0/go.mod h1:le6rNI4CoLQV1b9gzp1+3d7hMAD/uu2QcJ+aYbNgiU0=
github.com/GoogleCloudPlatform/cloudsql-proxy v1.36.0 h1:kAtNAWwvTt5+iew6baV0kbOrtjYTXPtWNSyOFlcxkBU=
github.com/GoogleCloudPlatform/cloudsql-proxy v1.36.0/go.mod h1:VRKXU8C7Y/aUKjRBTGfw0Ndv4YqNxlB8zAPJJDxbASE=
github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp v1.5.2 h1:DBjmt6/otSdULyJdVg2BlG0qGZO5tKL4VzOs0jpvw5Q=
github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp v1.5.2/go.mod h1:dppbR7CwXD4pgtV9t3wD1812RaLDcBjtblcDF5f1vI0=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0/go.mod h1:obipzmGjfSjam60XLwGfqUkJsfiheAl+TUjG+4yzyPM=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.48.1/go.mod h1:jyqM3eLpJ3IbIFDTKVz2rF9T/xWGW0rIriGwnz8l9Tk=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.50.0/go.mod h1:ZV4VOm0/eHR06JLrXWe09068dHpr3TRpY9Uo7T+anuA=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.48.1/go.mod h1:viRWSEhtMZqz1rhwmOVKkWl6SwmVowfL9O2YR5gI2PE=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.50.0/go.mod h1:otE2jQekW/PqXk1Awf5lmfokJx4uwuqcj1ab5SpGeW0=
github.com/IBM/go-sdk-core/v5 v5.17.4 h1:VGb9+mRrnS2HpHZFM5hy4J6ppIWnwNrw0G+tLSgcJLc=
github.com/IBM/go-sdk-core/v5 v5.17.4/go.mod h1:KsAAI7eStAWwQa4F96MLy+whYSh39JzNjklZRbN/8ns=
github.com/IBM/ibm-cos-sdk-go v1.11.0 h1:Jp55NLN3OvBwucMGpP5wNybyjncsmTZ9+GPHai/1cE8=
@@ -314,7 +347,6 @@ github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV
github.com/RaveNoX/go-jsoncommentstrip v1.0.0 h1:t527LHHE3HmiHrq74QMpNPZpGCIJzTx+apLkMKt4HC0=
github.com/RoaringBitmap/gocroaring v0.4.0 h1:5nufXUgWpBEUNEJXw7926YAA58ZAQRpWPrQV1xCoSjc=
github.com/RoaringBitmap/real-roaring-datasets v0.0.0-20190726190000-eb7c87156f76 h1:ZYlhPbqQFU+AHfgtCdHGDTtRW1a8geZyiE8c6Q+Sl1s=
github.com/RoaringBitmap/real-roaring-datasets v0.0.0-20190726190000-eb7c87156f76/go.mod h1:oM0MHmQ3nDsq609SS36p+oYbRi16+oVvU2Bw4Ipv0SE=
github.com/Sereal/Sereal/Go/sereal v0.0.0-20231009093132-b9187f1a92c6 h1:5kUcJJAKWWI82Xnp/CaU0eu5hLlHkmm9acjowSkwCd0=
github.com/Sereal/Sereal/Go/sereal v0.0.0-20231009093132-b9187f1a92c6/go.mod h1:JwrycNnC8+sZPDyzM3MQ86LvaGzSpfxg885KOOwFRW4=
github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 h1:KkH3I3sJuOLP3TjA/dfr4NAY8bghDwnXiU7cTKxQqo0=
@@ -350,22 +382,19 @@ github.com/antchfx/xmlquery v1.4.4/go.mod h1:AEPEEPYE9GnA2mj5Ur2L5Q5/2PycJ0N9Fus
github.com/antchfx/xpath v1.3.4 h1:1ixrW1VnXd4HurCj7qnqnR0jo14g8JMe20Fshg1Vgz4=
github.com/antchfx/xpath v1.3.4/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs=
github.com/antihax/optional v1.0.0 h1:xK2lYat7ZLaVVcIuj82J8kIro4V6kDe0AUDFboUCwcg=
github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g=
github.com/apache/arrow/go/arrow v0.0.0-20211112161151-bc219186db40 h1:q4dksr6ICHXqG5hm0ZW5IHyeEJXoIJSOZeBLmWPNeIQ=
github.com/apache/arrow/go/arrow v0.0.0-20211112161151-bc219186db40/go.mod h1:Q7yQnSMnLvcXlZ8RV+jwz/6y1rQTqbX6C82SndT52Zs=
github.com/apache/arrow/go/v10 v10.0.1 h1:n9dERvixoC/1JjDmBcs9FPaEryoANa2sCgVFo6ez9cI=
github.com/apache/arrow/go/v11 v11.0.0 h1:hqauxvFQxww+0mEU/2XHG6LT7eZternCZq+A5Yly2uM=
github.com/apache/arrow/go/v15 v15.0.2 h1:60IliRbiyTWCWjERBCkO1W4Qun9svcYoZrSLcyOsMLE=
github.com/apache/arrow/go/v15 v15.0.2/go.mod h1:DGXsR3ajT524njufqf95822i+KTh+yea1jass9YXgjA=
github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3 h1:ZSTrOEhiM5J5RFxEaFvMZVEAM1KvT1YzbEOwB2EAGjA=
github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e h1:QEF07wC0T1rKkctt1RINW/+RMTVmiwxETico2l3gxJA=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6 h1:G1bPvciwNyF7IUmKXNt9Ak3m6u9DE1rF+RmtIkBpVdA=
github.com/aws/aws-msk-iam-sasl-signer-go v1.0.1 h1:nMp7diZObd4XEVUR0pEvn7/E13JIgManMX79Q6quV6E=
github.com/aws/aws-msk-iam-sasl-signer-go v1.0.1/go.mod h1:MVYeeOhILFFemC/XlYTClvBjYZrg/EPd3ts885KrNTI=
github.com/aws/aws-sdk-go-v2/config v1.29.17 h1:jSuiQ5jEe4SAMH6lLRMY9OVC+TqJLP5655pBGjmnjr0=
github.com/aws/aws-sdk-go-v2/config v1.29.17/go.mod h1:9P4wwACpbeXs9Pm9w1QTh6BwWwJjwYvJ1iCt5QbCXh8=
github.com/aws/aws-sdk-go-v2/credentials v1.17.70 h1:ONnH5CM16RTXRkS8Z1qg7/s2eDOhHhaXVd72mmyv4/0=
github.com/aws/aws-sdk-go-v2/credentials v1.17.70/go.mod h1:M+lWhhmomVGgtuPOhO85u4pEa3SmssPTdcYpP/5J/xc=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.32 h1:KAXP9JSHO1vKGCr5f4O6WmlVKLFFXgWYAGoJosorxzU=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.32/go.mod h1:h4Sg6FQdexC1yYG9RDnOvLbW1a/P986++/Y/a+GyEM8=
github.com/aws/aws-sdk-go-v2/service/kms v1.35.3 h1:UPTdlTOwWUX49fVi7cymEN6hDqCwe3LNv1vi7TXUutk=
github.com/aws/aws-sdk-go-v2/service/kms v1.35.3/go.mod h1:gjDP16zn+WWalyaUqwCCioQ8gU8lzttCCc9jYsiQI/8=
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.32.4 h1:NgRFYyFpiMD62y4VPXh4DosPFbZd4vdMVBWKk0VmWXc=
@@ -376,16 +405,12 @@ github.com/aws/aws-sdk-go-v2/service/sqs v1.34.3 h1:Vjqy5BZCOIsn4Pj8xzyqgGmsSqzz
github.com/aws/aws-sdk-go-v2/service/sqs v1.34.3/go.mod h1:L0enV3GCRd5iG9B64W35C4/hwsCB00Ib+DKVGTadKHI=
github.com/aws/aws-sdk-go-v2/service/ssm v1.52.4 h1:hgSBvRT7JEWx2+vEGI9/Ld5rZtl7M5lu8PqdvOmbRHw=
github.com/aws/aws-sdk-go-v2/service/ssm v1.52.4/go.mod h1:v7NIzEFIHBiicOMaMTuEmbnzGnqW0d+6ulNALul6fYE=
github.com/aws/aws-sdk-go-v2/service/sso v1.25.5 h1:AIRJ3lfb2w/1/8wOOSqYb9fUKGwQbtysJ2H1MofRUPg=
github.com/aws/aws-sdk-go-v2/service/sso v1.25.5/go.mod h1:b7SiVprpU+iGazDUqvRSLf5XmCdn+JtT1on7uNL6Ipc=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3 h1:BpOxT3yhLwSJ77qIY3DoHAQjZsc4HEGfMCE4NGy3uFg=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3/go.mod h1:vq/GQR1gOFLquZMSrxUK/cpvKCNVYibNyJ1m7JrU88E=
github.com/aws/aws-sdk-go-v2/service/sts v1.34.0 h1:NFOJ/NXEGV4Rq//71Hs1jC/NvPs1ezajK+yQmkwnPV0=
github.com/aws/aws-sdk-go-v2/service/sts v1.34.0/go.mod h1:7ph2tGpfQvwzgistp2+zga9f+bCjlQJPkPUmMgDSD7w=
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
github.com/baidubce/bce-sdk-go v0.9.188 h1:8MA7ewe4VpX01uYl7Kic6ZvfIReUFdSKbY46ZqlQM7U=
github.com/baidubce/bce-sdk-go v0.9.188/go.mod h1:zbYJMQwE4IZuyrJiFO8tO8NbtYiKTFTbwh4eIsqjVdg=
github.com/bazelbuild/rules_go v0.49.0 h1:5vCbuvy8Q11g41lseGJDc5vxhDjJtfxr6nM/IC4VmqM=
github.com/bazelbuild/rules_go v0.49.0/go.mod h1:Dhcz716Kqg1RHNWos+N6MlXNkjNP2EwZQ0LukRKJfMs=
github.com/benbjohnson/immutable v0.4.0 h1:CTqXbEerYso8YzVPxmWxh2gnoRQbbB9X1quUC8+vGZA=
github.com/benbjohnson/immutable v0.4.0/go.mod h1:iAr8OjJGLnLmVUr9MZ/rz4PWUy6Ouc2JLYuMArmvAJM=
github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY=
@@ -427,8 +452,13 @@ github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible h1:C29Ae4G5GtYyY
github.com/circonus-labs/circonusllhist v0.1.3 h1:TJH+oke8D16535+jHExHj4nQvzlZrj7ug5D7I/orNUA=
github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI=
github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe h1:QQ3GSy+MqSHxm/d8nCtnAiZdYFd45cYZPs8vOOIYKfk=
github.com/cncf/xds/go v0.0.0-20240723142845-024c85f92f20/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c h1:2zRrJWIt/f9c9HhNHAgrRgq0San5gRRUJTBXLkchal0=
github.com/cockroachdb/datadriven v1.0.2 h1:H9MtNqVoVhvd9nCBwOyDjUEdZCREqbIdCJD93PBm/jA=
github.com/cockroachdb/datadriven v1.0.2/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU=
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w=
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
github.com/coder/quartz v0.1.0 h1:cLL+0g5l7xTf6ordRnUMMiZtRE8Sq5LxpghS63vEXrQ=
@@ -459,6 +489,8 @@ github.com/couchbase/moss v0.2.0/go.mod h1:9MaHIaRuy9pvLPUJxB8sh8OrLfyDczECVL37g
github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA=
github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc=
github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk=
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/creasty/defaults v1.8.0 h1:z27FJxCAa0JKt3utc0sCImAEb+spPucmKoOdLHvHYKk=
@@ -533,6 +565,12 @@ github.com/elastic/go-windows v1.0.2/go.mod h1:bGcDpBzXgYSqM0Gx3DM4+UxFj300SZLix
github.com/elastic/lunes v0.1.0 h1:amRtLPjwkWtzDF/RKzcEPMvSsSseLDLW+bnhfNSLRe4=
github.com/elastic/lunes v0.1.0/go.mod h1:xGphYIt3XdZRtyWosHQTErsQTd4OP1p9wsbVoHelrd4=
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633 h1:H2pdYOb3KQ1/YsqVWoWNLQO+fusocsw354rqGTZtAgw=
github.com/emicklei/proto v1.10.0/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A=
github.com/envoyproxy/go-control-plane v0.13.1/go.mod h1:X45hY0mufo6Fd0KW3rqsGvQMw58jvjymeCzBU3mWyHw=
github.com/envoyproxy/go-control-plane/envoy v1.32.3/go.mod h1:F6hWupPfh75TBXGKA++MCT/CZHFq5r9/uwt/kQYkZfE=
github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew=
github.com/envoyproxy/protoc-gen-validate v1.1.0/go.mod h1:sXRDRVmzEbkM7CVcM06s9shE/m23dg3wzjl0UWqJ2q4=
github.com/expr-lang/expr v1.17.0/go.mod h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40VO/1IT4=
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/felixge/fgprof v0.9.4 h1:ocDNwMFlnA0NU0zSB3I52xkO4sFXk80VK9lXjLClu88=
@@ -543,6 +581,7 @@ github.com/fluent/fluent-bit-go v0.0.0-20230731091245-a7a013e2473c h1:yKN46XJHYC
github.com/fluent/fluent-bit-go v0.0.0-20230731091245-a7a013e2473c/go.mod h1:L92h+dgwElEyUuShEwjbiHjseW410WIcNz+Bjutc8YQ=
github.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8=
github.com/form3tech-oss/jwt-go v3.2.2+incompatible h1:TcekIExNqud5crz4xD2pavyTgWiPvpYe4Xau31I0PRk=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/fsouza/fake-gcs-server v1.7.0 h1:Un0BXUXrRWYSmYyC1Rqm2e2WJfTPyDy/HGMz31emTi8=
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
@@ -567,8 +606,12 @@ github.com/go-json-experiment/json v0.0.0-20250211171154-1ae217ad3535/go.mod h1:
github.com/go-kit/kit v0.12.0 h1:e4o3o3IsBfAKQh5Qbbiqyfu97Ku7jrO/JbohvztANh4=
github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEaizzs=
github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81 h1:6zl3BbBhdnMkpSj2YY30qV3gDcVBGtFgVsV3+/i+mKQ=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
github.com/go-pdf/fpdf v0.6.0 h1:MlgtGIfsdMEEQJr2le6b/HNr1ZlQwxyWr77r2aj2U/8=
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
@@ -594,16 +637,26 @@ github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzq
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
github.com/gomarkdown/markdown v0.0.0-20230716120725-531d2d74bc12 h1:uK3X/2mt4tbSGoHvbLBHUny7CKiuwUip3MArtukol4E=
github.com/gomarkdown/markdown v0.0.0-20230716120725-531d2d74bc12/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA=
github.com/google/cel-go v0.23.2/go.mod h1:52Pb6QsDbC5kvgxvZhiL9QX1oZEkcUF/ZqaPx1J5Wwo=
github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
github.com/google/go-jsonnet v0.18.0 h1:/6pTy6g+Jh1a1I2UMoAODkqELFiVIdOxbNwv0DDzoOg=
github.com/google/go-jsonnet v0.18.0/go.mod h1:C3fTzyVJDslXdiTqw/bTFk7vSGyCtH3MGRbDfvEwGd0=
github.com/google/go-pkcs11 v0.3.0 h1:PVRnTgtArZ3QQqTGtbtjtnIkzl2iY2kt24yqbrf7td8=
github.com/google/go-pkcs11 v0.3.0/go.mod h1:6eQoGcuNJpa7jnd5pMGdkSaQpNDYvPlXWMcjXXThLlY=
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA=
github.com/google/renameio/v2 v2.0.0 h1:UifI23ZTGY8Tt29JbYFiuyIU3eX+RNFtUwefq9qAhxg=
github.com/google/renameio/v2 v2.0.0/go.mod h1:BtmJXm5YlszgC+TD4HOEEUFgkJP3nLxehU6hfe7jRt4=
github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
github.com/googleapis/cloud-bigtable-clients-test v0.0.3 h1:afMKTvA/jc6jSTMkeHBZGFDTt8Cc+kb1ATFzqMK85hw=
github.com/googleapis/cloud-bigtable-clients-test v0.0.3/go.mod h1:TWtDzrrAI70C3dNLDY+nZN3gxHtFdZIbpL9rCTFyxE0=
github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0=
github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA=
github.com/googleapis/enterprise-certificate-proxy v0.3.5/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA=
github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4=
github.com/googleapis/gax-go/v2 v2.14.0/go.mod h1:lhBCnjdLrWRaPvLWhmc8IS24m9mr07qSYnHncrgo+zk=
github.com/googleapis/gnostic v0.3.0 h1:CcQijm0XKekKjP/YCz28LXVSpgguuB+nCxaSjCe09y0=
github.com/googleapis/go-type-adapters v1.0.0 h1:9XdMn+d/G57qq1s8dNc5IesGCXHf6V2HZ2JwRxfA2tA=
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8 h1:tlyzajkF3030q6M8SvmJSemC9DTHL/xaMa18b65+JM4=
@@ -626,8 +679,6 @@ github.com/grafana/alerting v0.0.0-20250403153742-418bc7118d05 h1:hMzOzI/S0nkZt0
github.com/grafana/alerting v0.0.0-20250403153742-418bc7118d05/go.mod h1:K3YAJumchx5EEZItGv4D3pCv/Ux796hmoOibP/p/eYk=
github.com/grafana/alerting v0.0.0-20250429131604-de176b4a0309 h1:H2p3XKDHnTBGkMXLCgXiqb2dFnHbQ4zPDXOwKK4Ne3Y=
github.com/grafana/alerting v0.0.0-20250429131604-de176b4a0309/go.mod h1:pMfhRxL2LZ3Pm8iy7VcVsb9CLYuBtjFYbf1oxgx7yFA=
github.com/grafana/alerting v0.0.0-20250701210250-cea2d1683945 h1:3imTbxFpZSVI6IBIB9mn+Xc40lUweWjfMaBSgXR7rLs=
github.com/grafana/alerting v0.0.0-20250701210250-cea2d1683945/go.mod h1:gtR7agmxVfJOmNKV/n2ZULgOYTYNL+PDKYB5N48tQ7Q=
github.com/grafana/authlib v0.0.0-20250123104008-e99947858901/go.mod h1:/gYfphsNu9v1qYWXxpv1NSvMEMSwvdf8qb8YlgwIRl8=
github.com/grafana/authlib/types v0.0.0-20250120144156-d6737a7dc8f5/go.mod h1:qYjSd1tmJiuVoSICp7Py9/zD54O9uQQA3wuM6Gg4DFM=
github.com/grafana/authlib/types v0.0.0-20250120145936-5f0e28e7a87c/go.mod h1:qYjSd1tmJiuVoSICp7Py9/zD54O9uQQA3wuM6Gg4DFM=
@@ -642,8 +693,6 @@ github.com/grafana/grafana-app-sdk/logging v0.39.0 h1:3GgN5+dUZYqq74Q+GT9/ET+yo+
github.com/grafana/grafana-app-sdk/logging v0.39.0/go.mod h1:WhDENSnaGHtyVVwZGVnAR7YLvh2xlLDYR3D7E6h7XVk=
github.com/grafana/grafana-aws-sdk v0.38.2 h1:TzQD0OpWsNjtldi5G5TLDlBRk8OyDf+B5ujcoAu4Dp0=
github.com/grafana/grafana-aws-sdk v0.38.2/go.mod h1:j3vi+cXYHEFqjhBGrI6/lw1TNM+dl0Y3f0cSnDOPy+s=
github.com/grafana/grafana-aws-sdk v1.0.2 h1:98eBuHYFmgvH0xO9kKf4RBsEsgQRp8EOA/9yhDIpkss=
github.com/grafana/grafana-aws-sdk v1.0.2/go.mod h1:hO7q7yWV+t6dmiyJjMa3IbuYnYkBua+G/IAlOPVIYKE=
github.com/grafana/grafana-plugin-sdk-go v0.263.0/go.mod h1:U43Cnrj/9DNYyvFcNdeUWNjMXTKNB0jcTcQGpWKd2gw=
github.com/grafana/grafana-plugin-sdk-go v0.267.0/go.mod h1:OuwS4c/JYgn0rr/w5zhJBpLo4gKm/vw15RsfpYAvK9Q=
github.com/grafana/grafana-plugin-sdk-go v0.269.1/go.mod h1:yv2KbO4mlr9WuDK2f+2gHAMTwwLmLuqaEnrPXTRU+OI=
@@ -672,12 +721,12 @@ github.com/grafana/prometheus-alertmanager v0.25.1-0.20250331083058-4563aec7a975
github.com/grafana/prometheus-alertmanager v0.25.1-0.20250331083058-4563aec7a975/go.mod h1:FGdGvhI40Dq+CTQaSzK9evuve774cgOUdGfVO04OXkw=
github.com/grafana/prometheus-alertmanager v0.25.1-0.20250604130045-92c8f6389b36 h1:AjZ58JRw1ZieFH/SdsddF5BXtsDKt5kSrKNPWrzYz3Y=
github.com/grafana/prometheus-alertmanager v0.25.1-0.20250604130045-92c8f6389b36/go.mod h1:O/QP1BCm0HHIzbKvgMzqb5sSyH88rzkFk84F4TfJjBU=
github.com/grafana/sqlds/v4 v4.2.3 h1:9ibD1c5O5u9fifEkBSig+jAc41TUEz+M+bWQqDsofP4=
github.com/grafana/sqlds/v4 v4.2.3/go.mod h1:bv+XHabfUF4xkgg4y+nYFCK8rpMHZsMaQk56qNaJcAM=
github.com/grafana/tail v0.0.0-20230510142333-77b18831edf0 h1:bjh0PVYSVVFxzINqPFYJmAmJNrWPgnVjuSdYJGHmtFU=
github.com/grafana/tail v0.0.0-20230510142333-77b18831edf0/go.mod h1:7t5XR+2IA8P2qggOAHTj/GCZfoLBle3OvNSYh1VkRBU=
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA=
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0/go.mod h1:qztMSjm835F2bXf+5HKAPIS5qsmQDqZna/PgVt4rWtI=
github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 h1:MJG/KsmcqMwFAkh8mTnAwhyKoB+sTAnY4CACC110tbU=
github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw=
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8=
@@ -727,6 +776,7 @@ github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/jon-whit/go-grpc-prometheus v1.4.0 h1:/wmpGDJcLXuEjXryWhVYEGt9YBRhtLwFEN7T+Flr8sw=
github.com/jon-whit/go-grpc-prometheus v1.4.0/go.mod h1:iTPm+Iuhh3IIqR0iGZ91JJEg5ax6YQEe1I0f6vtBuao=
github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc=
github.com/joncrlsn/dque v0.0.0-20211108142734-c2ef48c5192a h1:sfe532Ipn7GX0V6mHdynBk393rDmqgI0QmjLK7ct7TU=
github.com/joncrlsn/dque v0.0.0-20211108142734-c2ef48c5192a/go.mod h1:dNKs71rs2VJGBAmttu7fouEsRQlRjxy0p1Sx+T5wbpY=
github.com/jstemmer/go-junit-report v0.9.1 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o=
@@ -837,6 +887,7 @@ github.com/ncw/swift/v2 v2.0.2/go.mod h1:z0A9RVdYPjNjXVo2pDOPxZ4eu3oarO1P91fTItc
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/nsf/jsondiff v0.0.0-20230430225905-43f6cf3098c1 h1:dOYG7LS/WK00RWZc8XGgcUTlTxpp3mKhdR2Q9z9HbXM=
github.com/nsf/jsondiff v0.0.0-20230430225905-43f6cf3098c1/go.mod h1:mpRZBD8SJ55OIICQ3iWH0Yz3cjzA61JdqMLoWXeB2+8=
github.com/onsi/ginkgo/v2 v2.22.1/go.mod h1:S6aTpoRsSq2cZOd+pssHAlKW/Q/jZt6cPrPlnj4a1xM=
github.com/open-telemetry/opentelemetry-collector-contrib/exporter/zipkinexporter v0.124.1 h1:+aiMrDR6xiaDM7xN4ByrBYI0Craqt68nZicmpYpt0co=
github.com/open-telemetry/opentelemetry-collector-contrib/exporter/zipkinexporter v0.124.1/go.mod h1:H/TEWN4jgExt0McrtrBK2VFK6r9LRsWtqhEZrH690rs=
github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal v0.124.1 h1:NrjsoVPxI6lmV8jPImDcMeqYh+97Y71f/HB5Sfpfe3I=
@@ -941,8 +992,13 @@ github.com/shirou/gopsutil/v4 v4.25.3/go.mod h1:xbuxyoZj+UsgnZrENu3lQivsngRR5Bdj
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/spf13/afero v1.10.0/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ=
github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g=
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad h1:fiWzISvDn0Csy5H0iwgAuJGQTUpVfEMJJd4nRFXogbc=
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
github.com/substrait-io/substrait v0.66.1-0.20250205013839-a30b3e2d7ec6 h1:XqtxwYFCjS4L0o1QD4ipGHCuFG94U0f6BeldbilGQjU=
github.com/substrait-io/substrait v0.66.1-0.20250205013839-a30b3e2d7ec6/go.mod h1:MPFNw6sToJgpD5Z2rj0rQrdP/Oq8HG7Z2t3CAEHtkHw=
github.com/substrait-io/substrait-go/v3 v3.9.1 h1:2yfHDHpK6KMcvLd0bJVzUJoeXO+K98yS+ciBruxD9po=
@@ -1034,6 +1090,9 @@ github.com/zenazn/goji v1.0.1/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxt
github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs=
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b h1:7gd+rd8P3bqcn/96gOZa3F5dpJr/vEiDQYlNb/y2uNs=
go.einride.tech/aip v0.68.1 h1:16/AfSxcQISGN5z9C5lM+0mLYXihrHbQ1onvYTr93aQ=
go.einride.tech/aip v0.68.1/go.mod h1:XaFtaj4HuA3Zwk9xoBtTWgNubZ0ZZXv9BZJCkuKuWbg=
go.etcd.io/bbolt v1.3.11/go.mod h1:dksAq7YMXoljX0xu6VF5DMZGbhYYoLUalEiSySYAS4I=
go.etcd.io/gofail v0.2.0 h1:p19drv16FKK345a09a1iubchlw/vmRuksmRzgBIGjcA=
go.etcd.io/gofail v0.2.0/go.mod h1:nL3ILMGfkXTekKI3clMBNazKnjUZjYLKmBHzsVAnC1o=
go.opentelemetry.io/collector v0.124.0 h1:g/dfdGFhBcQI0ggGxTmGlJnJ6Yl6T2gVxQoIj4UfXCc=
@@ -1150,54 +1209,154 @@ go.opentelemetry.io/collector/service/hostcapabilities v0.124.0 h1:ArxbARF7+bnzK
go.opentelemetry.io/collector/service/hostcapabilities v0.124.0/go.mod h1:vifQsB+lkeCsjBCRPVHca9lJ3pLpLPZKCGrG77nkxFQ=
go.opentelemetry.io/contrib/bridges/otelzap v0.10.0 h1:ojdSRDvjrnm30beHOmwsSvLpoRF40MlwNCA+Oo93kXU=
go.opentelemetry.io/contrib/bridges/otelzap v0.10.0/go.mod h1:oTTm4g7NEtHSV2i/0FeVdPaPgUIZPfQkFbq0vbzqnv0=
go.opentelemetry.io/contrib/detectors/gcp v1.29.0/go.mod h1:GW2aWZNwR2ZxDLdv8OyC2G8zkRoQBuURgV7RPQgcPoU=
go.opentelemetry.io/contrib/detectors/gcp v1.34.0/go.mod h1:cV4BMFcscUR/ckqLkbfQmF0PRsq8w/lMGzdbCSveBHo=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0/go.mod h1:B9yO6b04uB80CzjedvewuqDhxJxi11s7/GtiGa8bAjI=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.58.0/go.mod h1:HDBUsEjOuRC0EzKZ1bSaRGZWUBAzo+MhAcUUORSr4D0=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0/go.mod h1:ijPqXp5P6IRRByFVVg9DY8P5HkxkHE5ARIa+86aXPf4=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0/go.mod h1:umTcuxiv1n/s/S6/c2AT/g2CQ7u5C59sHDNmfSwgz7Q=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0/go.mod h1:FRmFuRJfag1IZ2dPkHnEoSFVgTVPUd2qf5Vi69hLb8I=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ=
go.opentelemetry.io/contrib/otelconf v0.15.0 h1:BLNiIUsrNcqhSKpsa6CnhE6LdrpY1A8X0szMVsu99eo=
go.opentelemetry.io/contrib/otelconf v0.15.0/go.mod h1:OPH1seO5z9dp1P26gnLtoM9ht7JDvh3Ws6XRHuXqImY=
go.opentelemetry.io/contrib/propagators/b3 v1.35.0 h1:DpwKW04LkdFRFCIgM3sqwTJA/QREHMeMHYPWP1WeaPQ=
go.opentelemetry.io/contrib/propagators/b3 v1.35.0/go.mod h1:9+SNxwqvCWo1qQwUpACBY5YKNVxFJn5mlbXg/4+uKBg=
go.opentelemetry.io/contrib/zpages v0.60.0 h1:wOM9ie1Hz4H88L9KE6GrGbKJhfm+8F1NfW/Y3q9Xt+8=
go.opentelemetry.io/contrib/zpages v0.60.0/go.mod h1:xqfToSRGh2MYUsfyErNz8jnNDPlnpZqWM/y6Z2Cx7xw=
go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo=
go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8=
go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE=
go.opentelemetry.io/otel/bridge/opencensus v1.35.0 h1:4nJfffRbozhqnuukfRkiahA94mnpryCLJLiduMIDJKI=
go.opentelemetry.io/otel/bridge/opencensus v1.35.0/go.mod h1:359S30saRYNsB4A46EDx91SpXsQFNgkma7ftg2/L5/M=
go.opentelemetry.io/otel/bridge/opentracing v1.35.0 h1:qT4jl1fYl0hHuRopNcwS94QosLFhGYcS0HacPUeXmT4=
go.opentelemetry.io/otel/bridge/opentracing v1.35.0/go.mod h1:p5CbIL4v7uQz7mnQD6T/AZc1pPUzwz+2wZ1zrGY9Kgs=
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.35.0/go.mod h1:U2R3XyVPzn0WX7wOIypPuptulsMcPDPs/oiSVOMVnHY=
go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco=
go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8=
go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY=
go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok=
go.opentelemetry.io/otel/sdk v1.31.0/go.mod h1:TfRbMdhvxIIr/B2N2LQW2S5v9m3gOQ/08KsbbO5BPT0=
go.opentelemetry.io/otel/sdk/metric v1.29.0/go.mod h1:6zZLdCl2fkauYoZIOn/soQIDSWFmNSRcICarHfuhNJQ=
go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w=
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ=
go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A=
go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM=
go.opentelemetry.io/proto/otlp v1.4.0/go.mod h1:PPBWZIP98o2ElSqI35IHfu7hIhSwvc5N38Jw8pXuGFY=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
golang.org/x/arch v0.4.0 h1:A8WCeEWhLwPBKNbFi5Wv5UTCBx5zzubnXDlMOFAzFMc=
golang.org/x/arch v0.4.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ=
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e h1:qyrTQ++p1afMkO4DPEeLGq/3oTsdlvdH4vqZUBWzUKM=
golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
golang.org/x/image v0.25.0 h1:Y6uW6rH1y5y/LK1J8BPWZtr6yZ7hrsy6hFrXjgsc2fQ=
golang.org/x/image v0.25.0/go.mod h1:tCAmOEGthTtkalusGp1g3xa2gke8J6c2N565dTyl9Rs=
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028 h1:4+4C/Iv2U4fMZBiMCc98MG1In4gJY5YRhtpDNeDeHWs=
golang.org/x/mod v0.6.0-dev.0.20220818022119-ed83ed61efb9/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20211123203042-d83791d6bcd9/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8=
golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457 h1:zf5N6UOrA487eEFacMePxjXAJctxKmyjKUsjA11Uzuk=
golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457/go.mod h1:pRgIJT+bRLFKnoM1ldnzKoxTIn14Yxz928LQRYYgIN0=
golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g=
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/time v0.10.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw=
gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0 h1:OE9mWmgKkjJyEmDAAtGMPjXu+YNeGvK9VTSHY6+Qihc=
gonum.org/v1/plot v0.15.2 h1:Tlfh/jBk2tqjLZ4/P8ZIwGrLEWQSPDLRm/SNWKNXiGI=
gonum.org/v1/plot v0.15.2/go.mod h1:DX+x+DWso3LTha+AdkJEv5Txvi+Tql3KAGkehP0/Ubg=
google.golang.org/api v0.177.0/go.mod h1:srbhue4MLjkjbkux5p3dw/ocYOSZTaIEvf7bCOnFQDw=
google.golang.org/api v0.211.0/go.mod h1:XOloB4MXFH4UTlQSGuNUxw0UT74qdENK8d6JNsXKLi0=
google.golang.org/api v0.214.0/go.mod h1:bYPpLG8AyeMWwDU6NXoB00xC0DFkikVvd5MfwoxjLqE=
google.golang.org/api v0.215.0/go.mod h1:fta3CVtuJYOEdugLNWm6WodzOS8KdFckABwN4I40hzY=
google.golang.org/api v0.216.0/go.mod h1:K9wzQMvWi47Z9IU7OgdOofvZuw75Ge3PPITImZR/UyI=
google.golang.org/api v0.218.0/go.mod h1:5VGHBAkxrA/8EFjLVEYmMUJ8/8+gWWQ3s4cFH0FxG2M=
google.golang.org/api v0.224.0/go.mod h1:3V39my2xAGkodXy0vEqcEtkqgw2GtrFL5WuBZlCTCOQ=
google.golang.org/api v0.227.0/go.mod h1:EIpaG6MbTgQarWF5xJvX0eOJPK9n/5D4Bynb9j2HXvQ=
google.golang.org/api v0.229.0/go.mod h1:wyDfmq5g1wYJWn29O22FDWN48P7Xcz0xz+LBpptYvB0=
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro=
google.golang.org/genproto v0.0.0-20241118233622-e639e219e697/go.mod h1:JJrvXBWRZaFMxBufik1a4RpFw4HhgVtBBWQeQgUj2cc=
google.golang.org/genproto v0.0.0-20250106144421-5f5ef82da422/go.mod h1:1NPAxoesyw/SgLPqaUp9u1f9PWCLAk/jVmhx7gJZStg=
google.golang.org/genproto v0.0.0-20250122153221-138b5a5a4fd4/go.mod h1:qbZzneIOXSq+KFAFut9krLfRLZiFLzZL5u2t8SV83EE=
google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk=
google.golang.org/genproto/googleapis/api v0.0.0-20240429193739-8cf5692501f6/go.mod h1:10yRODfgim2/T8csjQsMPgZOMvtytXKTDRzH6HRGzRw=
google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142/go.mod h1:d6be+8HhtEtucleCbxpPW9PA9XwISACu8nvpPqF0BVo=
google.golang.org/genproto/googleapis/api v0.0.0-20240826202546-f6391c0de4c7/go.mod h1:OCdP9MfskevB/rbYvHTsXTtKC+3bHWajPdoKgjcYkfo=
google.golang.org/genproto/googleapis/api v0.0.0-20241118233622-e639e219e697/go.mod h1:+D9ySVjN8nY8YCVjc5O7PZDIdZporIDY3KaGfJunh88=
google.golang.org/genproto/googleapis/api v0.0.0-20241202173237-19429a94021a/go.mod h1:jehYqy3+AhJU9ve55aNOaSml7wUXjF9x6z2LcCfpAhY=
google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576/go.mod h1:1R3kvZ1dtP3+4p4d3G8uJ8rFk/fWlScl38vanWACI08=
google.golang.org/genproto/googleapis/api v0.0.0-20250106144421-5f5ef82da422/go.mod h1:b6h1vNKhxaSoEI+5jc3PJUCustfli/mRab7295pY7rw=
google.golang.org/genproto/googleapis/api v0.0.0-20250124145028-65684f501c47/go.mod h1:AfA77qWLcidQWywD0YgqfpJzf50w2VjzBml3TybHeJU=
google.golang.org/genproto/googleapis/api v0.0.0-20250227231956-55c901821b1e/go.mod h1:Xsh8gBVxGCcbV8ZeTB9wI5XPyZ5RvC6V3CTeeplHbiA=
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:jbe3Bkdp+Dh2IrslsFCklNhweNTBgSYanP1UXhJDhKg=
google.golang.org/genproto/googleapis/api v0.0.0-20250313205543-e70fdf4c4cb4/go.mod h1:c8q6Z6OCqnfVIqUFJkCzKcrj8eCvUrz+K4KRzSTuANg=
google.golang.org/genproto/googleapis/api v0.0.0-20250414145226-207652e42e2e/go.mod h1:085qFyf2+XaZlRdCgKNCIZ3afY2p4HHZdoIRpId8F4A=
google.golang.org/genproto/googleapis/bytestream v0.0.0-20250505200425-f936aa4a68b2 h1:DbpkGFGRkd4GORg+IWQW2EhxUaa/My/PM8d1CGyTDMY=
google.golang.org/genproto/googleapis/bytestream v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:h6yxum/C2qRb4txaZRLDHK8RyS0H/o2oEDeKY4onY/Y=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240429193739-8cf5692501f6/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240826202546-f6391c0de4c7/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8/go.mod h1:lcTa1sDdWEIHMWlITnIczmw5w60CF9ffkb8Z+DVmmjA=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250106144421-5f5ef82da422/go.mod h1:3ENsm/5D1mzDyhpzeRi1NR784I0BcofWBoSc5QqqMK4=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250124145028-65684f501c47/go.mod h1:+2Yz8+CLJbIfL9z73EW45avw8Lmge3xVElCP9zEKi50=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250227231956-55c901821b1e/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250414145226-207652e42e2e/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250512202823-5a2f75b736a9/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98=
google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA=
google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA=
google.golang.org/grpc v1.67.3/go.mod h1:YGaHCc6Oap+FzBJTZLBzkGSYt/cvGPFTPxkn7QfSU8s=
google.golang.org/grpc v1.68.1/go.mod h1:+q1XYFJjShcqn0QZHvCyeR4CXPA+llXIeUIfIe00waw=
google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 h1:M1YKkFIboKNieVO5DLUEVzQfGwJD30Nv2jfUgzb5UcE=
google.golang.org/grpc/examples v0.0.0-20230224211313-3775f633ce20 h1:MLBCGN1O7GzIx+cBiwfYPwtmZ41U3Mn/cotLJciaArI=
google.golang.org/grpc/examples v0.0.0-20230224211313-3775f633ce20/go.mod h1:Nr5H8+MlGWr5+xX/STzdoEqJrO+YteqFbMyCsrb6mH0=
google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
google.golang.org/protobuf v1.36.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
@@ -1216,6 +1375,8 @@ howett.net/plist v1.0.1 h1:37GdZ8tP09Q35o9ych3ehygcsL+HqKSwzctveSlarvM=
howett.net/plist v1.0.1/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g=
k8s.io/code-generator v0.33.1 h1:ZLzIRdMsh3Myfnx9BaooX6iQry29UJjVfVG+BuS+UMw=
k8s.io/code-generator v0.33.1/go.mod h1:HUKT7Ubp6bOgIbbaPIs9lpd2Q02uqkMCMx9/GjDrWpY=
k8s.io/code-generator v0.33.2 h1:PCJ0Y6viTCxxJHMOyGqYwWEteM4q6y1Hqo2rNpl6jF4=
k8s.io/code-generator v0.33.2/go.mod h1:hBjCA9kPMpjLWwxcr75ReaQfFXY8u+9bEJJ7kRw3J8c=
k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6 h1:4s3/R4+OYYYUKptXPhZKjQ04WJ6EhQQVFdjOFvCazDk=
k8s.io/gengo/v2 v2.0.0-20250207200755-1244d31929d7 h1:2OX19X59HxDprNCVrWi6jb7LW1PoqTlYqEq5H2oetog=
k8s.io/gengo/v2 v2.0.0-20250207200755-1244d31929d7/go.mod h1:EJykeLsmFC60UQbYJezXkEsG2FLrt0GPNkU5iK5GWxU=
+2 -3
View File
@@ -118,7 +118,6 @@
"@types/d3-force": "^3.0.0",
"@types/d3-scale-chromatic": "3.1.0",
"@types/debounce-promise": "3.1.9",
"@types/diff": "^7.0.0",
"@types/eslint": "9.6.1",
"@types/eslint-scope": "^3.7.7",
"@types/file-saver": "2.0.7",
@@ -336,7 +335,7 @@
"dangerously-set-html-content": "1.1.0",
"date-fns": "4.1.0",
"debounce-promise": "3.1.2",
"diff": "^7.0.0",
"diff": "^8.0.0",
"fast-deep-equal": "^3.1.3",
"fast-json-patch": "3.1.1",
"file-saver": "2.0.5",
@@ -416,7 +415,7 @@
"slate": "0.47.9",
"slate-plain-serializer": "0.7.13",
"slate-react": "0.22.10",
"swagger-ui-react": "5.26.1",
"swagger-ui-react": "5.26.2",
"symbol-observable": "4.0.0",
"systemjs": "6.15.1",
"tinycolor2": "1.6.0",
+5 -1
View File
@@ -432,7 +432,11 @@ export {
export { createFieldConfigRegistry } from './panel/registryFactories';
export { type QueryRunner, type QueryRunnerOptions } from './types/queryRunner';
export { type GroupingToMatrixTransformerOptions } from './transformations/transformers/groupingToMatrix';
export { type PluginContextType, type DataSourcePluginContextType } from './context/plugins/PluginContext';
export {
type PluginContextType,
type DataSourcePluginContextType,
Context as PluginContext,
} from './context/plugins/PluginContext';
export { type PluginContextProviderProps, PluginContextProvider } from './context/plugins/PluginContextProvider';
export {
type DataSourcePluginContextProviderProps,
@@ -257,23 +257,30 @@ const MonacoQueryField = (props: Props) => {
return;
}
const query = model.getValue();
const errors =
validateQuery(
query,
datasource.interpolateString(query, placeHolderScopedVars),
model.getLinesContent(),
parser
) || [];
const { errors, warnings } = validateQuery(
query,
datasource.interpolateString(query, placeHolderScopedVars),
model.getLinesContent(),
parser
);
const markers = errors.map(({ error, ...boundary }) => ({
message: `${
error ? `Error parsing "${error}"` : 'Parse error'
}. The query appears to be incorrect and could fail to be executed.`,
severity: monaco.MarkerSeverity.Error,
...boundary,
}));
const errorMarkers = errors.map(({ issue, ...boundary }) => {
return {
message: `${issue ? `Error parsing "${issue}"` : 'Parse error'}. The query appears to be incorrect and could fail to be executed.`,
severity: monaco.MarkerSeverity.Error,
...boundary,
};
});
monaco.editor.setModelMarkers(model, 'owner', markers);
const warningMarkers = warnings.map(({ issue, ...boundary }) => {
return {
message: `Warning: ${issue}`,
severity: monaco.MarkerSeverity.Warning,
...boundary,
};
});
monaco.editor.setModelMarkers(model, 'owner', [...errorMarkers, ...warningMarkers]);
});
}
}}
@@ -1,11 +1,11 @@
// 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';
import { validateQuery, warningTypes } from './validation';
describe('Monaco Query Validation', () => {
test('Identifies empty queries as valid', () => {
expect(validateQuery('', '', [], parser)).toBeFalsy();
expect(validateQuery('', '', [], parser)).toEqual({ errors: [], warnings: [] });
});
test.each([
@@ -17,45 +17,30 @@ describe('Monaco Query Validation', () => {
'rate(http_requests_total[5m])',
'topk(3, sum by (app, proc) (rate(instance_cpu_time_ns[5m])))',
])('Identifies valid queries', (query: string) => {
expect(validateQuery(query, query, [], parser)).toBeFalsy();
expect(validateQuery(query, query, [], parser).errors).toEqual([]);
});
test('Identifies invalid queries', () => {
// Missing } at the end
let query = 'access_evaluation_duration_sum{job="grafana"';
expect(validateQuery(query, query, [query], parser)).toEqual([
{
endColumn: 45,
endLineNumber: 1,
error: '{job="grafana"',
startColumn: 31,
startLineNumber: 1,
},
]);
expect(validateQuery(query, query, [query], parser)).toEqual({
errors: [{ endColumn: 45, endLineNumber: 1, issue: '{job="grafana"', startColumn: 31, startLineNumber: 1 }],
warnings: [],
});
// Missing handler="value"
query = 'http_requests_total{job="apiserver", handler}[5m]';
expect(validateQuery(query, query, [query], parser)).toEqual([
{
endColumn: 45,
endLineNumber: 1,
error: 'handler',
startColumn: 38,
startLineNumber: 1,
},
]);
expect(validateQuery(query, query, [query], parser)).toEqual({
errors: [{ endColumn: 45, endLineNumber: 1, issue: 'handler', startColumn: 38, startLineNumber: 1 }],
warnings: [],
});
// Missing : in [30s:5s]
query = 'max_over_time(deriv(rate(distance_covered_total[5s])[30s5s])[10m:])';
expect(validateQuery(query, query, [query], parser)).toEqual([
{
endColumn: 59,
endLineNumber: 1,
error: '5s',
startColumn: 57,
startLineNumber: 1,
},
]);
expect(validateQuery(query, query, [query], parser)).toEqual({
errors: [{ endColumn: 59, endLineNumber: 1, issue: '5s', startColumn: 57, startLineNumber: 1 }],
warnings: [],
});
});
test('Identifies valid multi-line queries', () => {
@@ -64,7 +49,7 @@ sum by (job) (
rate(http_requests_total[5m])
)`;
const queryLines = query.split('\n');
expect(validateQuery(query, query, queryLines, parser)).toBeFalsy();
expect(validateQuery(query, query, queryLines, parser)).toEqual({ errors: [], warnings: [] });
});
test('Identifies invalid multi-line queries', () => {
@@ -73,14 +58,32 @@ sum by (job) (
rate(http_requests_total[])
)`;
const queryLines = query.split('\n');
expect(validateQuery(query, query, queryLines, parser)).toEqual([
{
endColumn: 30,
endLineNumber: 3,
error: '',
startColumn: 30,
startLineNumber: 3,
},
]);
expect(validateQuery(query, query, queryLines, parser)).toEqual({
errors: [{ endColumn: 30, endLineNumber: 3, issue: '', startColumn: 30, startLineNumber: 3 }],
warnings: [],
});
});
test('Warns agains subqueries with same duration and step', () => {
const query = 'rate(http_requests_total[5m:5m])';
const queryLines = query.split('\n');
expect(validateQuery(query, query, queryLines, parser)).toEqual({
errors: [],
warnings: [
{ endColumn: 32, endLineNumber: 1, issue: warningTypes.SubqueryExpr, startColumn: 6, startLineNumber: 1 },
],
});
});
test('Warns agains queries with multiple subqueries', () => {
const query = 'quantile_over_time(0.5, rate(http_requests_total[1m:1m]) [1m:1m])';
const queryLines = query.split('\n');
expect(validateQuery(query, query, queryLines, parser)).toEqual({
errors: [],
warnings: [
{ issue: warningTypes.SubqueryExpr, startColumn: 25, endColumn: 65, startLineNumber: 1, endLineNumber: 1 },
{ issue: warningTypes.SubqueryExpr, startColumn: 30, endColumn: 56, startLineNumber: 1, endLineNumber: 1 },
],
});
});
});
@@ -5,15 +5,25 @@ import { LRParser } from '@lezer/lr';
// Although 0 isn't explicitly provided in the @grafana/lezer-logql library as the error node ID, it does appear to be the ID of error nodes within lezer.
export const ErrorId = 0;
interface ParserErrorBoundary {
export const warningTypes: Record<string, string> = {
SubqueryExpr:
'This subquery may return only one data point, preventing rate/increase/delta calculations. Use a range at least twice the step size (e.g., [2x:x]).',
};
enum NodeType {
SubqueryExpr = 'SubqueryExpr',
Duration = 'NumberDurationLiteralInDurationContext',
}
interface ParserIssueBoundary {
startLineNumber: number;
startColumn: number;
endLineNumber: number;
endColumn: number;
error: string;
issue: string;
}
interface ParseError {
interface ParseIssue {
text: string;
node: SyntaxNode;
}
@@ -30,9 +40,9 @@ export function validateQuery(
interpolatedQuery: string,
queryLines: string[],
parser: LRParser
): ParserErrorBoundary[] | false {
): { errors: ParserIssueBoundary[]; warnings: ParserIssueBoundary[] } {
if (!query) {
return false;
return { errors: [], warnings: [] };
}
/**
@@ -42,51 +52,93 @@ export function validateQuery(
* have different lengths. With this, we also exclude irrelevant parser errors that are produced by
* lezer not understanding $variables and $__variables, which usually generate 2 or 3 error SyntaxNode.
*/
const interpolatedErrors: ParseError[] = parseQuery(interpolatedQuery, parser);
if (!interpolatedErrors.length) {
return false;
const { errors: interpolatedErrors, warnings: interpolatedWarnings } = parseQuery(interpolatedQuery, parser);
if (!interpolatedErrors.length && !interpolatedWarnings.length) {
return { errors: [], warnings: [] };
}
let parseErrors: ParseError[] = interpolatedErrors;
let parseErrors: ParseIssue[] = interpolatedErrors;
let parseWarnings: ParseIssue[] = interpolatedWarnings;
if (query !== interpolatedQuery) {
const queryErrors: ParseError[] = parseQuery(query, parser);
const { errors: queryErrors, warnings: queryWarnings } = parseQuery(query, parser);
parseErrors = interpolatedErrors.flatMap(
(interpolatedError) =>
queryErrors.filter((queryError) => interpolatedError.text === queryError.text) || interpolatedError
);
parseWarnings = interpolatedWarnings.flatMap(
(interpolatedWarning) =>
queryWarnings.filter((queryWarning) => interpolatedWarning.node.from === queryWarning.node.from) ||
interpolatedWarning
);
}
return parseErrors.map((parseError) => findErrorBoundary(query, queryLines, parseError)).filter(isErrorBoundary);
const errorBoundaries = parseErrors
.map((parseError) => findIssueBoundary(query, queryLines, parseError, 'error'))
.filter(isValidIssueBoundary);
const warningBoundaries = parseWarnings
.map((parseWarning) => findIssueBoundary(query, queryLines, parseWarning, 'warning'))
.filter(isValidIssueBoundary);
return {
errors: errorBoundaries,
warnings: warningBoundaries,
};
}
function parseQuery(query: string, parser: LRParser) {
const parseErrors: ParseError[] = [];
const parseErrors: ParseIssue[] = [];
const parseWarnings: ParseIssue[] = [];
const tree = parser.parse(query);
tree.iterate({
enter: (nodeRef): false | void => {
if (nodeRef.type.id === ErrorId) {
const node = nodeRef.node;
parseErrors.push({
node: node,
text: query.substring(node.from, node.to),
});
parseErrors.push({ node: node, text: query.substring(node.from, node.to) });
}
if (nodeRef.type.name === NodeType.SubqueryExpr) {
const node = nodeRef.node;
const durations: string[] = [];
const children = node.getChildren(NodeType.Duration);
for (const child of children) {
durations.push(query.substring(child.from, child.to));
}
if (durations.length === 2 && durations[0] === durations[1]) {
parseWarnings.push({ node: node, text: query.substring(node.from, node.to) });
}
}
},
});
return parseErrors;
return { errors: parseErrors, warnings: parseWarnings };
}
function findErrorBoundary(query: string, queryLines: string[], parseError: ParseError): ParserErrorBoundary | null {
function findIssueBoundary(
query: string,
queryLines: string[],
parseError: ParseIssue,
issueType: 'error' | 'warning'
): ParserIssueBoundary | null {
if (queryLines.length === 1) {
const isEmptyString = parseError.node.from === parseError.node.to;
const errorNode = isEmptyString && parseError.node.parent ? parseError.node.parent : parseError.node;
const error = isEmptyString ? query.substring(errorNode.from, errorNode.to) : parseError.text;
let issue: string;
if (issueType === 'error') {
issue = isEmptyString ? query.substring(errorNode.from, errorNode.to) : parseError.text;
} else {
issue = warningTypes[parseError.node.type.name];
}
return {
startLineNumber: 1,
startColumn: errorNode.from + 1,
endLineNumber: 1,
endColumn: errorNode.to + 1,
error,
issue,
};
}
@@ -105,14 +157,14 @@ function findErrorBoundary(query: string, queryLines: string[], parseError: Pars
startColumn: parseError.node.from - startPos + 1,
endLineNumber: line + 1,
endColumn: parseError.node.to - startPos + 1,
error: parseError.text,
issue: issueType === 'error' ? parseError.text : warningTypes[parseError.node.type.name],
};
}
return null;
}
function isErrorBoundary(boundary: ParserErrorBoundary | null): boundary is ParserErrorBoundary {
function isValidIssueBoundary(boundary: ParserIssueBoundary | null): boundary is ParserIssueBoundary {
return boundary !== null;
}
@@ -1,4 +1,4 @@
import { Spec } from './v2alpha1/types.spec.gen';
import { defaultDataQueryKind, Spec } from './v2alpha1/types.spec.gen';
export const handyTestingSchema: Spec = {
title: 'Default Dashboard',
@@ -37,15 +37,16 @@ export const handyTestingSchema: Spec = {
spec: {
builtIn: false,
query: {
kind: 'prometheus',
kind: 'DataQuery',
version: defaultDataQueryKind().version,
group: 'prometheus',
datasource: {
name: 'uid',
},
spec: {
expr: 'test-query',
},
},
datasource: {
type: 'prometheus',
uid: 'uid',
},
filter: { ids: [1] },
enable: true,
hide: false,
@@ -57,15 +58,16 @@ export const handyTestingSchema: Spec = {
kind: 'AnnotationQuery',
spec: {
builtIn: false,
datasource: {
type: 'grafana-testdata-datasource',
uid: 'uid',
},
enable: true,
iconColor: 'red',
name: 'Enabled',
query: {
kind: 'grafana-testdata-datasource',
kind: 'DataQuery',
version: defaultDataQueryKind().version,
group: 'grafana-testdata-datasource',
datasource: {
name: 'uid',
},
spec: {
lines: 4,
refId: 'Anno',
@@ -79,15 +81,16 @@ export const handyTestingSchema: Spec = {
kind: 'AnnotationQuery',
spec: {
builtIn: false,
datasource: {
type: 'grafana-testdata-datasource',
uid: 'uid',
},
enable: false,
iconColor: 'yellow',
name: 'Disabled',
query: {
kind: 'grafana-testdata-datasource',
kind: 'DataQuery',
version: defaultDataQueryKind().version,
group: 'grafana-testdata-datasource',
datasource: {
name: 'uid',
},
spec: { lines: 5, refId: 'Anno', scenarioId: 'annotations' },
},
hide: false,
@@ -97,16 +100,17 @@ export const handyTestingSchema: Spec = {
kind: 'AnnotationQuery',
spec: {
builtIn: false,
datasource: {
type: 'grafana-testdata-datasource',
uid: 'uid',
},
enable: true,
hide: true,
iconColor: 'dark-purple',
name: 'Hidden',
query: {
kind: 'grafana-testdata-datasource',
kind: 'DataQuery',
version: defaultDataQueryKind().version,
group: 'grafana-testdata-datasource',
datasource: {
name: 'uid',
},
spec: {
lines: 6,
refId: 'Anno',
@@ -128,12 +132,13 @@ export const handyTestingSchema: Spec = {
kind: 'PanelQuery',
spec: {
refId: 'A',
datasource: {
type: 'prometheus',
uid: 'datasource1',
},
query: {
kind: 'prometheus',
kind: 'DataQuery',
version: defaultDataQueryKind().version,
group: 'prometheus',
datasource: {
name: 'datasource1',
},
spec: {
expr: 'test-query',
},
@@ -265,10 +270,6 @@ export const handyTestingSchema: Spec = {
text: 'text1',
value: 'value1',
},
datasource: {
type: 'prometheus',
uid: 'datasource1',
},
definition: 'definition1',
description: 'A query variable',
hide: 'dontHide',
@@ -278,7 +279,12 @@ export const handyTestingSchema: Spec = {
name: 'queryVar',
options: [],
query: {
kind: 'prometheus',
kind: 'DataQuery',
version: defaultDataQueryKind().version,
group: 'prometheus',
datasource: {
name: 'datasource1',
},
spec: {
expr: 'test-query',
refId: 'A',
@@ -11,8 +11,7 @@ export const defaultAnnotationQueryKind = (): AnnotationQueryKind => ({
});
export interface AnnotationQuerySpec {
datasource?: DataSourceRef;
query?: DataQueryKind;
query: DataQueryKind;
enable: boolean;
hide: boolean;
iconColor: string;
@@ -24,6 +23,7 @@ export interface AnnotationQuerySpec {
}
export const defaultAnnotationQuerySpec = (): AnnotationQuerySpec => ({
query: defaultDataQueryKind(),
enable: false,
hide: false,
iconColor: "",
@@ -31,24 +31,22 @@ export const defaultAnnotationQuerySpec = (): AnnotationQuerySpec => ({
builtIn: false,
});
export interface DataSourceRef {
// The plugin type-id
type?: string;
// Specific datasource instance
uid?: string;
}
export const defaultDataSourceRef = (): DataSourceRef => ({
});
export interface DataQueryKind {
// The kind of a DataQueryKind is the datasource type
kind: string;
kind: "DataQuery";
group: string;
version: string;
// New type for datasource reference
// Not creating a new type until we figure out how to handle DS refs for group by, adhoc, and every place that uses DataSourceRef in TS.
datasource?: {
name?: string;
};
spec: Record<string, any>;
}
export const defaultDataQueryKind = (): DataQueryKind => ({
kind: "",
kind: "DataQuery",
group: "",
version: "v0",
spec: {},
});
@@ -151,7 +149,6 @@ export const defaultPanelQueryKind = (): PanelQueryKind => ({
export interface PanelQuerySpec {
query: DataQueryKind;
datasource?: DataSourceRef;
refId: string;
hidden: boolean;
}
@@ -994,7 +991,6 @@ export interface QueryVariableSpec {
refresh: VariableRefresh;
skipUrlSync: boolean;
description?: string;
datasource?: DataSourceRef;
query: DataQueryKind;
regex: string;
sort: VariableSort;
@@ -1283,6 +1279,18 @@ export const defaultGroupByVariableSpec = (): GroupByVariableSpec => ({
skipUrlSync: false,
});
// Keeping this for backwards compatibility for GroupByVariableSpec and AdhocVariableSpec
// This type is widely used in the codebase and changing it will have a big impact
export interface DataSourceRef {
// The plugin type-id
type?: string;
// Specific datasource instance
uid?: string;
}
export const defaultDataSourceRef = (): DataSourceRef => ({
});
// Adhoc variable kind
export interface AdhocVariableKind {
kind: "AdhocVariable";
+5 -5
View File
@@ -10,11 +10,11 @@ require (
github.com/mattbaird/jsonpatch v0.0.0-20240118010651-0ba75a80ca38
github.com/stretchr/testify v1.10.0
go.opentelemetry.io/otel v1.36.0
k8s.io/api v0.33.1
k8s.io/apimachinery v0.33.1
k8s.io/apiserver v0.33.1
k8s.io/client-go v0.33.1
k8s.io/component-base v0.33.1
k8s.io/api v0.33.2
k8s.io/apimachinery v0.33.2
k8s.io/apiserver v0.33.2
k8s.io/client-go v0.33.2
k8s.io/component-base v0.33.2
k8s.io/klog/v2 v2.130.1
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff
sigs.k8s.io/structured-merge-diff/v4 v4.6.0
+10 -10
View File
@@ -520,16 +520,16 @@ gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
k8s.io/api v0.33.1 h1:tA6Cf3bHnLIrUK4IqEgb2v++/GYUtqiu9sRVk3iBXyw=
k8s.io/api v0.33.1/go.mod h1:87esjTn9DRSRTD4fWMXamiXxJhpOIREjWOSjsW1kEHw=
k8s.io/apimachinery v0.33.1 h1:mzqXWV8tW9Rw4VeW9rEkqvnxj59k1ezDUl20tFK/oM4=
k8s.io/apimachinery v0.33.1/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
k8s.io/apiserver v0.33.1 h1:yLgLUPDVC6tHbNcw5uE9mo1T6ELhJj7B0geifra3Qdo=
k8s.io/apiserver v0.33.1/go.mod h1:VMbE4ArWYLO01omz+k8hFjAdYfc3GVAYPrhP2tTKccs=
k8s.io/client-go v0.33.1 h1:ZZV/Ks2g92cyxWkRRnfUDsnhNn28eFpt26aGc8KbXF4=
k8s.io/client-go v0.33.1/go.mod h1:JAsUrl1ArO7uRVFWfcj6kOomSlCv+JpvIsp6usAGefA=
k8s.io/component-base v0.33.1 h1:EoJ0xA+wr77T+G8p6T3l4efT2oNwbqBVKR71E0tBIaI=
k8s.io/component-base v0.33.1/go.mod h1:guT/w/6piyPfTgq7gfvgetyXMIh10zuXA6cRRm3rDuY=
k8s.io/api v0.33.2 h1:YgwIS5jKfA+BZg//OQhkJNIfie/kmRsO0BmNaVSimvY=
k8s.io/api v0.33.2/go.mod h1:fhrbphQJSM2cXzCWgqU29xLDuks4mu7ti9vveEnpSXs=
k8s.io/apimachinery v0.33.2 h1:IHFVhqg59mb8PJWTLi8m1mAoepkUNYmptHsV+Z1m5jY=
k8s.io/apimachinery v0.33.2/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
k8s.io/apiserver v0.33.2 h1:KGTRbxn2wJagJowo29kKBp4TchpO1DRO3g+dB/KOJN4=
k8s.io/apiserver v0.33.2/go.mod h1:9qday04wEAMLPWWo9AwqCZSiIn3OYSZacDyu/AcoM/M=
k8s.io/client-go v0.33.2 h1:z8CIcc0P581x/J1ZYf4CNzRKxRvQAwoAolYPbtQes+E=
k8s.io/client-go v0.33.2/go.mod h1:9mCgT4wROvL948w6f6ArJNb7yQd7QsvqavDeZHvNmHo=
k8s.io/component-base v0.33.2 h1:sCCsn9s/dG3ZrQTX/Us0/Sx2R0G5kwa0wbZFYoVp/+0=
k8s.io/component-base v0.33.2/go.mod h1:/41uw9wKzuelhN+u+/C59ixxf4tYQKW7p32ddkYNe2k=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4=
+2 -2
View File
@@ -7,8 +7,8 @@ require (
github.com/grafana/authlib v0.0.0-20250618124654-54543efcfeed // @grafana/identity-access-team
github.com/grafana/authlib/types v0.0.0-20250325095148-d6da9c164a7d // @grafana/identity-access-team
github.com/stretchr/testify v1.10.0
k8s.io/apimachinery v0.33.1
k8s.io/apiserver v0.33.1
k8s.io/apimachinery v0.33.2
k8s.io/apiserver v0.33.2
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff
)
+4 -4
View File
@@ -166,10 +166,10 @@ gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
k8s.io/apimachinery v0.33.1 h1:mzqXWV8tW9Rw4VeW9rEkqvnxj59k1ezDUl20tFK/oM4=
k8s.io/apimachinery v0.33.1/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
k8s.io/apiserver v0.33.1 h1:yLgLUPDVC6tHbNcw5uE9mo1T6ELhJj7B0geifra3Qdo=
k8s.io/apiserver v0.33.1/go.mod h1:VMbE4ArWYLO01omz+k8hFjAdYfc3GVAYPrhP2tTKccs=
k8s.io/apimachinery v0.33.2 h1:IHFVhqg59mb8PJWTLi8m1mAoepkUNYmptHsV+Z1m5jY=
k8s.io/apimachinery v0.33.2/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
k8s.io/apiserver v0.33.2 h1:KGTRbxn2wJagJowo29kKBp4TchpO1DRO3g+dB/KOJN4=
k8s.io/apiserver v0.33.2/go.mod h1:9qday04wEAMLPWWo9AwqCZSiIn3OYSZacDyu/AcoM/M=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4=
+5 -5
View File
@@ -8,8 +8,8 @@ require (
google.golang.org/grpc v1.73.0
google.golang.org/protobuf v1.36.6
gopkg.in/yaml.v3 v3.0.1
k8s.io/apimachinery v0.33.1
k8s.io/apiserver v0.33.1
k8s.io/apimachinery v0.33.2
k8s.io/apiserver v0.33.2
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738
)
@@ -86,9 +86,9 @@ require (
google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237 // indirect
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
k8s.io/api v0.33.1 // indirect
k8s.io/client-go v0.33.1 // indirect
k8s.io/component-base v0.33.1 // indirect
k8s.io/api v0.33.2 // indirect
k8s.io/client-go v0.33.2 // indirect
k8s.io/component-base v0.33.2 // indirect
k8s.io/klog/v2 v2.130.1 // indirect
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 // indirect
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
+10 -10
View File
@@ -319,16 +319,16 @@ gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
k8s.io/api v0.33.1 h1:tA6Cf3bHnLIrUK4IqEgb2v++/GYUtqiu9sRVk3iBXyw=
k8s.io/api v0.33.1/go.mod h1:87esjTn9DRSRTD4fWMXamiXxJhpOIREjWOSjsW1kEHw=
k8s.io/apimachinery v0.33.1 h1:mzqXWV8tW9Rw4VeW9rEkqvnxj59k1ezDUl20tFK/oM4=
k8s.io/apimachinery v0.33.1/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
k8s.io/apiserver v0.33.1 h1:yLgLUPDVC6tHbNcw5uE9mo1T6ELhJj7B0geifra3Qdo=
k8s.io/apiserver v0.33.1/go.mod h1:VMbE4ArWYLO01omz+k8hFjAdYfc3GVAYPrhP2tTKccs=
k8s.io/client-go v0.33.1 h1:ZZV/Ks2g92cyxWkRRnfUDsnhNn28eFpt26aGc8KbXF4=
k8s.io/client-go v0.33.1/go.mod h1:JAsUrl1ArO7uRVFWfcj6kOomSlCv+JpvIsp6usAGefA=
k8s.io/component-base v0.33.1 h1:EoJ0xA+wr77T+G8p6T3l4efT2oNwbqBVKR71E0tBIaI=
k8s.io/component-base v0.33.1/go.mod h1:guT/w/6piyPfTgq7gfvgetyXMIh10zuXA6cRRm3rDuY=
k8s.io/api v0.33.2 h1:YgwIS5jKfA+BZg//OQhkJNIfie/kmRsO0BmNaVSimvY=
k8s.io/api v0.33.2/go.mod h1:fhrbphQJSM2cXzCWgqU29xLDuks4mu7ti9vveEnpSXs=
k8s.io/apimachinery v0.33.2 h1:IHFVhqg59mb8PJWTLi8m1mAoepkUNYmptHsV+Z1m5jY=
k8s.io/apimachinery v0.33.2/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
k8s.io/apiserver v0.33.2 h1:KGTRbxn2wJagJowo29kKBp4TchpO1DRO3g+dB/KOJN4=
k8s.io/apiserver v0.33.2/go.mod h1:9qday04wEAMLPWWo9AwqCZSiIn3OYSZacDyu/AcoM/M=
k8s.io/client-go v0.33.2 h1:z8CIcc0P581x/J1ZYf4CNzRKxRvQAwoAolYPbtQes+E=
k8s.io/client-go v0.33.2/go.mod h1:9mCgT4wROvL948w6f6ArJNb7yQd7QsvqavDeZHvNmHo=
k8s.io/component-base v0.33.2 h1:sCCsn9s/dG3ZrQTX/Us0/Sx2R0G5kwa0wbZFYoVp/+0=
k8s.io/component-base v0.33.2/go.mod h1:/41uw9wKzuelhN+u+/C59ixxf4tYQKW7p32ddkYNe2k=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4=
+6 -6
View File
@@ -5,16 +5,16 @@ go 1.24.4
require (
github.com/google/go-cmp v0.7.0
github.com/grafana/authlib/types v0.0.0-20250325095148-d6da9c164a7d
github.com/grafana/grafana-app-sdk/logging v0.38.2
github.com/grafana/grafana-app-sdk/logging v0.39.1
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250514132646-acbc7b54ed9e
github.com/prometheus/client_golang v1.22.0
github.com/stretchr/testify v1.10.0
go.opentelemetry.io/contrib/propagators/jaeger v1.36.0
go.opentelemetry.io/otel v1.36.0
go.opentelemetry.io/otel/trace v1.36.0
k8s.io/apimachinery v0.33.1
k8s.io/apiserver v0.33.1
k8s.io/component-base v0.33.1
k8s.io/apimachinery v0.33.2
k8s.io/apiserver v0.33.2
k8s.io/component-base v0.33.2
k8s.io/klog/v2 v2.130.1
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738
sigs.k8s.io/structured-merge-diff/v4 v4.6.0
@@ -98,8 +98,8 @@ require (
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/api v0.33.1 // indirect
k8s.io/client-go v0.33.1 // indirect
k8s.io/api v0.33.2 // indirect
k8s.io/client-go v0.33.2 // indirect
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 // indirect
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
+12 -12
View File
@@ -84,8 +84,8 @@ github.com/grafana/authlib/types v0.0.0-20250325095148-d6da9c164a7d h1:34E6btDAh
github.com/grafana/authlib/types v0.0.0-20250325095148-d6da9c164a7d/go.mod h1:qeWYbnWzaYGl88JlL9+DsP1GT2Cudm58rLtx13fKZdw=
github.com/grafana/dskit v0.0.0-20250611075409-46f51e1ce914 h1:qcSGhr691f1mmPHwg2svGyO40Ex92G02aOyHzP6XHCE=
github.com/grafana/dskit v0.0.0-20250611075409-46f51e1ce914/go.mod h1:OiN4P4aC6LwLzLbEupH3Ue83VfQoNMfG48rsna8jI/E=
github.com/grafana/grafana-app-sdk/logging v0.38.2 h1:EdQTRxbbH72zdqJ09Z76zcSjfALJXkpPLgvKEPPnloc=
github.com/grafana/grafana-app-sdk/logging v0.38.2/go.mod h1:Y/bvbDhBiV/tkIle9RW49pgfSPIPSON8Q4qjx3pyqDk=
github.com/grafana/grafana-app-sdk/logging v0.39.1 h1:lI5rbrheuwVPuyIM6LIuEYOCSpgmXahfKtqeMyhbGPU=
github.com/grafana/grafana-app-sdk/logging v0.39.1/go.mod h1:WhDENSnaGHtyVVwZGVnAR7YLvh2xlLDYR3D7E6h7XVk=
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250514132646-acbc7b54ed9e h1:BTKk7LHuG1kmAkucwTA7DuMbKpKvJTKrGdBmUNO4dfQ=
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250514132646-acbc7b54ed9e/go.mod h1:IA4SOwun8QyST9c5UNs/fN37XL6boXXDvRYFcFwbipg=
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI=
@@ -364,16 +364,16 @@ gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
k8s.io/api v0.33.1 h1:tA6Cf3bHnLIrUK4IqEgb2v++/GYUtqiu9sRVk3iBXyw=
k8s.io/api v0.33.1/go.mod h1:87esjTn9DRSRTD4fWMXamiXxJhpOIREjWOSjsW1kEHw=
k8s.io/apimachinery v0.33.1 h1:mzqXWV8tW9Rw4VeW9rEkqvnxj59k1ezDUl20tFK/oM4=
k8s.io/apimachinery v0.33.1/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
k8s.io/apiserver v0.33.1 h1:yLgLUPDVC6tHbNcw5uE9mo1T6ELhJj7B0geifra3Qdo=
k8s.io/apiserver v0.33.1/go.mod h1:VMbE4ArWYLO01omz+k8hFjAdYfc3GVAYPrhP2tTKccs=
k8s.io/client-go v0.33.1 h1:ZZV/Ks2g92cyxWkRRnfUDsnhNn28eFpt26aGc8KbXF4=
k8s.io/client-go v0.33.1/go.mod h1:JAsUrl1ArO7uRVFWfcj6kOomSlCv+JpvIsp6usAGefA=
k8s.io/component-base v0.33.1 h1:EoJ0xA+wr77T+G8p6T3l4efT2oNwbqBVKR71E0tBIaI=
k8s.io/component-base v0.33.1/go.mod h1:guT/w/6piyPfTgq7gfvgetyXMIh10zuXA6cRRm3rDuY=
k8s.io/api v0.33.2 h1:YgwIS5jKfA+BZg//OQhkJNIfie/kmRsO0BmNaVSimvY=
k8s.io/api v0.33.2/go.mod h1:fhrbphQJSM2cXzCWgqU29xLDuks4mu7ti9vveEnpSXs=
k8s.io/apimachinery v0.33.2 h1:IHFVhqg59mb8PJWTLi8m1mAoepkUNYmptHsV+Z1m5jY=
k8s.io/apimachinery v0.33.2/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
k8s.io/apiserver v0.33.2 h1:KGTRbxn2wJagJowo29kKBp4TchpO1DRO3g+dB/KOJN4=
k8s.io/apiserver v0.33.2/go.mod h1:9qday04wEAMLPWWo9AwqCZSiIn3OYSZacDyu/AcoM/M=
k8s.io/client-go v0.33.2 h1:z8CIcc0P581x/J1ZYf4CNzRKxRvQAwoAolYPbtQes+E=
k8s.io/client-go v0.33.2/go.mod h1:9mCgT4wROvL948w6f6ArJNb7yQd7QsvqavDeZHvNmHo=
k8s.io/component-base v0.33.2 h1:sCCsn9s/dG3ZrQTX/Us0/Sx2R0G5kwa0wbZFYoVp/+0=
k8s.io/component-base v0.33.2/go.mod h1:/41uw9wKzuelhN+u+/C59ixxf4tYQKW7p32ddkYNe2k=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4=
+1 -1
View File
@@ -6,7 +6,7 @@ require (
cuelang.org/go v0.11.1
github.com/dave/dst v0.27.3
github.com/grafana/codejen v0.0.4-0.20230321061741-77f656893a3d
github.com/grafana/cog v0.0.35
github.com/grafana/cog v0.0.36
github.com/grafana/cuetsy v0.1.11
github.com/matryer/is v1.4.1
golang.org/x/tools v0.34.0
+2 -2
View File
@@ -31,8 +31,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/grafana/codejen v0.0.4-0.20230321061741-77f656893a3d h1:hrXbGJ5jgp6yNITzs5o+zXq0V5yT3siNJ+uM8LGwWKk=
github.com/grafana/codejen v0.0.4-0.20230321061741-77f656893a3d/go.mod h1:zmwwM/DRyQB7pfuBjTWII3CWtxcXh8LTwAYGfDfpR6s=
github.com/grafana/cog v0.0.35 h1:ZrGca+X17lczqhuXVCxHbLyGszP8VHGh1eAQLxbplkY=
github.com/grafana/cog v0.0.35/go.mod h1:UDstzYqMdgIROmbfkHL8fB9XWQO2lnf5z+4W/eJo4Dc=
github.com/grafana/cog v0.0.36 h1:5kijtkHRzabhCG+ck4sCAEtYp2luaBK8v1CrUHcQ0Es=
github.com/grafana/cog v0.0.36/go.mod h1:UDstzYqMdgIROmbfkHL8fB9XWQO2lnf5z+4W/eJo4Dc=
github.com/grafana/cue v0.0.0-20230926092038-971951014e3f h1:TmYAMnqg3d5KYEAaT6PtTguL2GjLfvr6wnAX8Azw6tQ=
github.com/grafana/cue v0.0.0-20230926092038-971951014e3f/go.mod h1:okjJBHFQFer+a41sAe2SaGm1glWS8oEb6CmJvn5Zdws=
github.com/grafana/cuetsy v0.1.11 h1:I3IwBhF+UaQxRM79HnImtrAn8REGdb5M3+C4QrYHoWk=
+1 -1
View File
@@ -7,7 +7,7 @@ replace github.com/grafana/grafana/pkg/codegen => ../../codegen
require (
cuelang.org/go v0.11.1
github.com/grafana/codejen v0.0.4-0.20230321061741-77f656893a3d
github.com/grafana/cog v0.0.35
github.com/grafana/cog v0.0.36
github.com/grafana/cuetsy v0.1.11
github.com/grafana/grafana/pkg/codegen v0.0.0-20250514132646-acbc7b54ed9e
)
+2 -2
View File
@@ -30,8 +30,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/grafana/codejen v0.0.4-0.20230321061741-77f656893a3d h1:hrXbGJ5jgp6yNITzs5o+zXq0V5yT3siNJ+uM8LGwWKk=
github.com/grafana/codejen v0.0.4-0.20230321061741-77f656893a3d/go.mod h1:zmwwM/DRyQB7pfuBjTWII3CWtxcXh8LTwAYGfDfpR6s=
github.com/grafana/cog v0.0.35 h1:ZrGca+X17lczqhuXVCxHbLyGszP8VHGh1eAQLxbplkY=
github.com/grafana/cog v0.0.35/go.mod h1:UDstzYqMdgIROmbfkHL8fB9XWQO2lnf5z+4W/eJo4Dc=
github.com/grafana/cog v0.0.36 h1:5kijtkHRzabhCG+ck4sCAEtYp2luaBK8v1CrUHcQ0Es=
github.com/grafana/cog v0.0.36/go.mod h1:UDstzYqMdgIROmbfkHL8fB9XWQO2lnf5z+4W/eJo4Dc=
github.com/grafana/cuetsy v0.1.11 h1:I3IwBhF+UaQxRM79HnImtrAn8REGdb5M3+C4QrYHoWk=
github.com/grafana/cuetsy v0.1.11/go.mod h1:Ix97+CPD8ws9oSSxR3/Lf4ahU1I4Np83kjJmDVnLZvc=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+2 -2
View File
@@ -13,7 +13,7 @@ require (
go.opentelemetry.io/otel v1.36.0
go.opentelemetry.io/otel/trace v1.36.0
google.golang.org/protobuf v1.36.6
k8s.io/apimachinery v0.33.1
k8s.io/apimachinery v0.33.2
)
require (
@@ -128,7 +128,7 @@ require (
gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/client-go v0.33.1 // indirect
k8s.io/client-go v0.33.2 // indirect
k8s.io/klog/v2 v2.130.1 // indirect
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect
+4 -4
View File
@@ -430,10 +430,10 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
k8s.io/apimachinery v0.33.1 h1:mzqXWV8tW9Rw4VeW9rEkqvnxj59k1ezDUl20tFK/oM4=
k8s.io/apimachinery v0.33.1/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
k8s.io/client-go v0.33.1 h1:ZZV/Ks2g92cyxWkRRnfUDsnhNn28eFpt26aGc8KbXF4=
k8s.io/client-go v0.33.1/go.mod h1:JAsUrl1ArO7uRVFWfcj6kOomSlCv+JpvIsp6usAGefA=
k8s.io/apimachinery v0.33.2 h1:IHFVhqg59mb8PJWTLi8m1mAoepkUNYmptHsV+Z1m5jY=
k8s.io/apimachinery v0.33.2/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
k8s.io/client-go v0.33.2 h1:z8CIcc0P581x/J1ZYf4CNzRKxRvQAwoAolYPbtQes+E=
k8s.io/client-go v0.33.2/go.mod h1:9mCgT4wROvL948w6f6ArJNb7yQd7QsvqavDeZHvNmHo=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4=
@@ -61,8 +61,10 @@ func (a *decryptAuthorizer) Authorize(ctx context.Context, secureValueName strin
// TEMPORARY: while we can't onboard every app into secrets, we can block them from decrypting
// securevalues preemptively here before even reaching out to the database.
// This check can be removed once we open the gates for any service to use secrets.
if _, exists := a.allowList[serviceIdentity]; !exists || serviceIdentity == "" {
return serviceIdentity, false
if len(a.allowList) > 0 {
if _, exists := a.allowList[serviceIdentity]; !exists || serviceIdentity == "" {
return serviceIdentity, false
}
}
// Checks whether the token has the permission to decrypt secure values.
@@ -108,6 +108,15 @@ func TestDecryptAuthorizer(t *testing.T) {
require.False(t, allowed)
})
t.Run("when the allow list is empty, it allows all identities", func(t *testing.T) {
ctx := createAuthContext(context.Background(), "identity", []string{"secret.grafana.app/securevalues:decrypt"})
authorizer := ProvideDecryptAuthorizer(tracer, nil)
identity, allowed := authorizer.Authorize(ctx, "", []string{"identity"})
require.NotEmpty(t, identity)
require.True(t, allowed)
})
t.Run("when the identity is not in the allow list, it returns false", func(t *testing.T) {
ctx := createAuthContext(context.Background(), "identity", []string{"secret.grafana.app/securevalues:decrypt"})
authorizer := ProvideDecryptAuthorizer(tracer, map[string]struct{}{"allowed1": {}})
@@ -83,6 +83,7 @@ func (ss *SqlStore) getDataSource(_ context.Context, query *datasources.GetDataS
ss.logger.Error("Failed getting data source", "err", err, "uid", query.UID, "id", query.ID, "name", query.Name, "orgId", query.OrgID) // nolint:staticcheck
return nil, err
} else if !has {
ss.logger.Debug("Data source not found", "uid", query.UID, "id", query.ID, "name", query.Name, "orgId", query.OrgID) // nolint:staticcheck
return nil, datasources.ErrDataSourceNotFound
}
@@ -281,7 +281,10 @@ func TestIntegrationDataAccess(t *testing.T) {
t.Run("Can not delete datasource with wrong orgID", func(t *testing.T) {
db := db.InitTestDB(t)
ds := initDatasource(db)
ss := SqlStore{db: db}
ss := SqlStore{
db: db,
logger: log.NewNopLogger(),
}
err := ss.DeleteDataSource(context.Background(),
&datasources.DeleteDataSourceCommand{ID: ds.ID, OrgID: 123123})
@@ -322,7 +325,10 @@ func TestIntegrationDataAccess(t *testing.T) {
t.Run("does not fire an event when the datasource is not deleted", func(t *testing.T) {
db := db.InitTestDB(t)
ss := SqlStore{db: db}
ss := SqlStore{
db: db,
logger: log.NewNopLogger(),
}
var called bool
db.Bus().AddEventListener(func(ctx context.Context, e *events.DataSourceDeleted) error {
+31
View File
@@ -179,6 +179,24 @@ func runTestKVSave(t *testing.T, kv resource.KV, nsPrefix string) {
err = obj.Value.Close()
require.NoError(t, err)
})
t.Run("save key with no data", func(t *testing.T) {
// Save a key with empty data
err := kv.Save(ctx, section, "empty-key", strings.NewReader(""))
require.NoError(t, err)
// Verify it was saved with empty data
obj, err := kv.Get(ctx, section, "empty-key")
require.NoError(t, err)
assert.Equal(t, "empty-key", obj.Key)
value, err := io.ReadAll(obj.Value)
require.NoError(t, err)
assert.Equal(t, "", string(value))
assert.Len(t, value, 0)
err = obj.Value.Close()
require.NoError(t, err)
})
}
func runTestKVDelete(t *testing.T, kv resource.KV, nsPrefix string) {
@@ -251,6 +269,19 @@ func runTestKVKeys(t *testing.T, kv resource.KV, nsPrefix string) {
assert.Contains(t, errors[0].Error(), "section is required")
assert.Empty(t, keys)
})
t.Run("list keys returns 0 keys", func(t *testing.T) {
// Use a different section with no keys
emptySection := nsPrefix + "-empty-keys"
var keys []string
for k, err := range kv.Keys(ctx, emptySection, resource.ListOptions{}) {
require.NoError(t, err)
keys = append(keys, k)
}
assert.Empty(t, keys)
assert.Len(t, keys, 0)
})
}
func runTestKVKeysWithLimits(t *testing.T, kv resource.KV, nsPrefix string) {
@@ -1250,6 +1250,7 @@
"com.github.grafana.grafana.apps.dashboard.pkg.apis.dashboard.v2alpha1.DashboardAnnotationQuerySpec": {
"type": "object",
"required": [
"query",
"enable",
"hide",
"iconColor",
@@ -1259,9 +1260,6 @@
"builtIn": {
"type": "boolean"
},
"datasource": {
"$ref": "#/components/schemas/com.github.grafana.grafana.apps.dashboard.pkg.apis.dashboard.v2alpha1.DashboardDataSourceRef"
},
"enable": {
"type": "boolean",
"default": false
@@ -1289,7 +1287,12 @@
"default": ""
},
"query": {
"$ref": "#/components/schemas/com.github.grafana.grafana.apps.dashboard.pkg.apis.dashboard.v2alpha1.DashboardDataQueryKind"
"default": {},
"allOf": [
{
"$ref": "#/components/schemas/com.github.grafana.grafana.apps.dashboard.pkg.apis.dashboard.v2alpha1.DashboardDataQueryKind"
}
]
}
}
},
@@ -1865,11 +1868,24 @@
"type": "object",
"required": [
"kind",
"group",
"version",
"spec"
],
"properties": {
"datasource": {
"description": "New type for datasource reference Not creating a new type until we figure out how to handle DS refs for group by, adhoc, and every place that uses DataSourceRef in TS.",
"allOf": [
{
"$ref": "#/components/schemas/com.github.grafana.grafana.apps.dashboard.pkg.apis.dashboard.v2alpha1.DashboardV2alpha1DataQueryKindDatasource"
}
]
},
"group": {
"type": "string",
"default": ""
},
"kind": {
"description": "The kind of a DataQueryKind is the datasource type",
"type": "string",
"default": ""
},
@@ -1878,10 +1894,15 @@
"additionalProperties": {
"type": "object"
}
},
"version": {
"type": "string",
"default": ""
}
}
},
"com.github.grafana.grafana.apps.dashboard.pkg.apis.dashboard.v2alpha1.DashboardDataSourceRef": {
"description": "Keeping this for backwards compatibility for GroupByVariableSpec and AdhocVariableSpec This type is widely used in the codebase and changing it will have a big impact",
"type": "object",
"properties": {
"type": {
@@ -2743,9 +2764,6 @@
"hidden"
],
"properties": {
"datasource": {
"$ref": "#/components/schemas/com.github.grafana.grafana.apps.dashboard.pkg.apis.dashboard.v2alpha1.DashboardDataSourceRef"
},
"hidden": {
"type": "boolean",
"default": false
@@ -2993,9 +3011,6 @@
}
]
},
"datasource": {
"$ref": "#/components/schemas/com.github.grafana.grafana.apps.dashboard.pkg.apis.dashboard.v2alpha1.DashboardDataSourceRef"
},
"definition": {
"type": "string"
},
@@ -3725,6 +3740,14 @@
}
}
},
"com.github.grafana.grafana.apps.dashboard.pkg.apis.dashboard.v2alpha1.DashboardV2alpha1DataQueryKindDatasource": {
"type": "object",
"properties": {
"name": {
"type": "string"
}
}
},
"com.github.grafana.grafana.apps.dashboard.pkg.apis.dashboard.v2alpha1.DashboardV2alpha1FieldConfigSourceOverrides": {
"type": "object",
"required": [
@@ -13,6 +13,7 @@ package dataquery
import (
json "encoding/json"
fmt "fmt"
)
type AzureMonitorQuery struct {
@@ -835,3 +836,58 @@ type StringOrBoolOrFloat64OrSelectableValue struct {
func NewStringOrBoolOrFloat64OrSelectableValue() *StringOrBoolOrFloat64OrSelectableValue {
return &StringOrBoolOrFloat64OrSelectableValue{}
}
// MarshalJSON implements a custom JSON marshalling logic to encode `StringOrBoolOrFloat64OrSelectableValue` as JSON.
func (resource StringOrBoolOrFloat64OrSelectableValue) MarshalJSON() ([]byte, error) {
if resource.String != nil {
return json.Marshal(resource.String)
}
if resource.Bool != nil {
return json.Marshal(resource.Bool)
}
if resource.Float64 != nil {
return json.Marshal(resource.Float64)
}
if resource.SelectableValue != nil {
return json.Marshal(resource.SelectableValue)
}
return []byte("null"), nil
}
// UnmarshalJSON implements a custom JSON unmarshalling logic to decode StringOrBoolOrFloat64OrSelectableValue from JSON.
func (resource *StringOrBoolOrFloat64OrSelectableValue) UnmarshalJSON(raw []byte) error {
if raw == nil {
return nil
}
fields := make(map[string]json.RawMessage)
if err := json.Unmarshal(raw, &fields); err != nil {
return err
}
if fields["String"] != nil {
if err := json.Unmarshal(fields["String"], &resource.String); err != nil {
return fmt.Errorf("error decoding field 'String': %w", err)
}
}
if fields["Bool"] != nil {
if err := json.Unmarshal(fields["Bool"], &resource.Bool); err != nil {
return fmt.Errorf("error decoding field 'Bool': %w", err)
}
}
if fields["Float64"] != nil {
if err := json.Unmarshal(fields["Float64"], &resource.Float64); err != nil {
return fmt.Errorf("error decoding field 'Float64': %w", err)
}
}
if fields["SelectableValue"] != nil {
if err := json.Unmarshal(fields["SelectableValue"], &resource.SelectableValue); err != nil {
return fmt.Errorf("error decoding field 'SelectableValue': %w", err)
}
}
return nil
}
@@ -211,6 +211,12 @@ func NewQueryEditorProperty() *QueryEditorProperty {
}
}
type QueryEditorPropertyType string
const (
QueryEditorPropertyTypeString QueryEditorPropertyType = "string"
)
type QueryEditorArrayExpression struct {
Type QueryEditorArrayExpressionType `json:"type"`
Expressions ArrayOfQueryEditorExpressionOrArrayOfQueryEditorArrayExpression `json:"expressions"`
@@ -279,12 +285,6 @@ func NewQueryEditorOperatorValueType() *QueryEditorOperatorValueType {
return NewStringOrBoolOrInt64OrArrayOfQueryEditorOperatorType()
}
type QueryEditorPropertyType string
const (
QueryEditorPropertyTypeString QueryEditorPropertyType = "string"
)
type LogsQueryLanguage string
const (
@@ -13,6 +13,7 @@ package dataquery
import (
json "encoding/json"
fmt "fmt"
)
type BucketAggregation = DateHistogramOrHistogramOrTermsOrFiltersOrGeoHashGridOrNested
@@ -1549,6 +1550,43 @@ func NewStringOrDataqueryInlineScript() *StringOrDataqueryInlineScript {
return &StringOrDataqueryInlineScript{}
}
// MarshalJSON implements a custom JSON marshalling logic to encode `StringOrDataqueryInlineScript` as JSON.
func (resource StringOrDataqueryInlineScript) MarshalJSON() ([]byte, error) {
if resource.String != nil {
return json.Marshal(resource.String)
}
if resource.DataqueryInlineScript != nil {
return json.Marshal(resource.DataqueryInlineScript)
}
return []byte("null"), nil
}
// UnmarshalJSON implements a custom JSON unmarshalling logic to decode StringOrDataqueryInlineScript from JSON.
func (resource *StringOrDataqueryInlineScript) UnmarshalJSON(raw []byte) error {
if raw == nil {
return nil
}
fields := make(map[string]json.RawMessage)
if err := json.Unmarshal(raw, &fields); err != nil {
return err
}
if fields["String"] != nil {
if err := json.Unmarshal(fields["String"], &resource.String); err != nil {
return fmt.Errorf("error decoding field 'String': %w", err)
}
}
if fields["DataqueryInlineScript"] != nil {
if err := json.Unmarshal(fields["DataqueryInlineScript"], &resource.DataqueryInlineScript); err != nil {
return fmt.Errorf("error decoding field 'DataqueryInlineScript': %w", err)
}
}
return nil
}
type BucketScriptOrCumulativeSumOrDerivativeOrSerialDiffOrRawDataOrRawDocumentOrUniqueCountOrPercentilesOrExtendedStatsOrMinOrMaxOrSumOrAverageOrMovingAverageOrMovingFunctionOrLogsOrRateOrTopMetrics struct {
BucketScript *BucketScript `json:"BucketScript,omitempty"`
CumulativeSum *CumulativeSum `json:"CumulativeSum,omitempty"`
@@ -4,6 +4,7 @@ import (
"context"
"database/sql"
"encoding/json"
"errors"
"fmt"
"reflect"
"strconv"
@@ -172,6 +173,26 @@ func escape(input string) string {
func (s *Service) generateConnectionString(dsInfo sqleng.DataSourceInfo) (string, error) {
logger := s.logger
connStr, err := getInitialConnectionString(dsInfo, logger)
if err != nil {
return connStr, err
}
connStr, err = getTLSIncludedConnectionString(connStr, s.tlsManager, dsInfo, logger)
if err != nil {
return connStr, err
}
logger.Debug("Generated Postgres connection string successfully")
return connStr, nil
}
func getInitialConnectionString(dsInfo sqleng.DataSourceInfo, logger log.Logger) (string, error) {
if dsInfo.JsonData.ConnectionType == sqleng.ConnectionTypeConnectionString {
connStr := dsInfo.DecryptedSecureJSONData["connectionString"]
if connStr == "" {
return connStr, errors.New("Invalid/Empty connection string")
}
return connStr, nil
}
var host string
var port int
if strings.HasPrefix(dsInfo.URL, "/") {
@@ -216,8 +237,11 @@ func (s *Service) generateConnectionString(dsInfo sqleng.DataSourceInfo) (string
if port > 0 {
connStr += fmt.Sprintf(" port=%d", port)
}
return connStr, nil
}
tlsSettings, err := s.tlsManager.getTLSSettings(dsInfo)
func getTLSIncludedConnectionString(connStr string, tlsManager tlsSettingsProvider, dsInfo sqleng.DataSourceInfo, logger log.Logger) (string, error) {
tlsSettings, err := tlsManager.getTLSSettings(dsInfo)
if err != nil {
return "", err
}
@@ -246,7 +270,6 @@ func (s *Service) generateConnectionString(dsInfo sqleng.DataSourceInfo) (string
return "", fmt.Errorf("TLS/SSL client certificate and key must both be specified")
}
logger.Debug("Generated Postgres connection string successfully")
return connStr, nil
}
@@ -37,7 +37,16 @@ type SqlQueryResultTransformer interface {
GetConverterList() []sqlutil.StringConverter
}
type ConnectionType string
const (
ConnectionTypeDefault ConnectionType = "default"
ConnectionTypeConnectionString ConnectionType = "connectionString"
)
type JsonData struct {
ConnectionType ConnectionType `json:"connectionType"`
MaxOpenConns int `json:"maxOpenConns"`
MaxIdleConns int `json:"maxIdleConns"`
ConnMaxLifetime int `json:"connMaxLifetime"`
@@ -2,7 +2,6 @@ import { useLocation } from 'react-router-dom';
import { PluginExtensionPoints } from '@grafana/data';
import { config, renderLimitedComponents, usePluginComponents } from '@grafana/runtime';
import { ErrorBoundaryAlert } from '@grafana/ui';
const excludedRoutes: Record<string, boolean> = {
'/login': true,
@@ -24,13 +23,10 @@ export function AppChromeExtensionPoint(): JSX.Element | null {
return null;
}
return (
<ErrorBoundaryAlert>
<InternalAppChromeExtensionPoint />
</ErrorBoundaryAlert>
);
return <InternalAppChromeExtensionPoint />;
}
// We have this "internal" component so we can prevent pre-loading the plugins associated with the extension-point if the feature is not enabled.
function InternalAppChromeExtensionPoint(): JSX.Element | null {
const { components, isLoading } = usePluginComponents({
extensionPointId: PluginExtensionPoints.AppChrome,
@@ -0,0 +1,167 @@
import { render, screen } from '@testing-library/react';
import { ExtensionInfo, PluginExtensionTypes } from '@grafana/data';
import { config, usePluginComponents } from '@grafana/runtime';
import { AddedComponentRegistryItem } from 'app/features/plugins/extensions/registry/AddedComponentsRegistry';
import { createComponentWithMeta } from 'app/features/plugins/extensions/usePluginComponents';
import { ExtensionSidebar } from './ExtensionSidebar';
import {
ExtensionSidebarContextType,
getComponentIdFromComponentMeta,
useExtensionSidebarContext,
} from './ExtensionSidebarProvider';
jest.mock('@grafana/runtime', () => ({
...jest.requireActual('@grafana/runtime'),
usePluginComponents: jest.fn(),
}));
jest.mock('./ExtensionSidebarProvider', () => ({
...jest.requireActual('./ExtensionSidebarProvider'),
useExtensionSidebarContext: jest.fn(),
}));
const mockUsePluginComponents = jest.mocked(usePluginComponents);
const mockUseExtensionSidebarContext = jest.mocked(useExtensionSidebarContext);
const MockComponent = () => <div data-testid="working-component">Mock Component</div>;
const pluginId = 'test-plugin';
const extensionPointId = 'grafana/extension-sidebar/v0-alpha';
MockComponent.meta = {
pluginId,
title: 'Test Component',
id: 'test-component-id',
type: PluginExtensionTypes.component,
description: 'Test Component',
};
const addedComponentConfigMock: ExtensionInfo = {
targets: extensionPointId,
title: 'Test Component',
};
const extensionSidebarContextMock: ExtensionSidebarContextType = {
dockedComponentId: getComponentIdFromComponentMeta(pluginId, addedComponentConfigMock),
isEnabled: true,
props: {},
isOpen: true,
setDockedComponentId: jest.fn(),
availableComponents: new Map(),
extensionSidebarWidth: 300,
setExtensionSidebarWidth: jest.fn(),
};
const addedComponentRegistryItemMock: AddedComponentRegistryItem = {
pluginId,
title: addedComponentConfigMock.title,
component: MockComponent,
};
describe('ExtensionSidebar', () => {
const originalEnv = config.buildInfo.env;
beforeEach(() => {
jest.clearAllMocks();
config.buildInfo.env = 'development';
});
afterEach(() => {
config.buildInfo.env = originalEnv;
});
it('should render nothing when the extension sidebar is not enabled', () => {
mockUseExtensionSidebarContext.mockReturnValue({
...extensionSidebarContextMock,
isEnabled: false,
});
mockUsePluginComponents.mockReturnValue({
components: [createComponentWithMeta(addedComponentRegistryItemMock, extensionPointId)],
isLoading: false,
});
const { container } = render(<ExtensionSidebar />);
expect(container.firstChild).toBeNull();
});
it('should render nothing when the extension sidebar is enabled but no component is docked', () => {
mockUseExtensionSidebarContext.mockReturnValue({
...extensionSidebarContextMock,
isEnabled: true,
dockedComponentId: undefined,
});
mockUsePluginComponents.mockReturnValue({
components: [createComponentWithMeta(addedComponentRegistryItemMock, extensionPointId)],
isLoading: false,
});
const { container } = render(<ExtensionSidebar />);
expect(container.firstChild).toBeNull();
});
it('should render nothing when the extension sidebar is enabled but the component docked is not found in the available components', () => {
mockUseExtensionSidebarContext.mockReturnValue({
...extensionSidebarContextMock,
isEnabled: true,
dockedComponentId: 'test-component-id-not-found',
});
mockUsePluginComponents.mockReturnValue({
components: [createComponentWithMeta(addedComponentRegistryItemMock, extensionPointId)],
isLoading: false,
});
const { container } = render(<ExtensionSidebar />);
expect(container.firstChild).toBeNull();
});
it('should render nothing when the extension sidebar is enabled but the component docked is not found in the available components', () => {
mockUseExtensionSidebarContext.mockReturnValue({
...extensionSidebarContextMock,
isEnabled: true,
dockedComponentId: 'test-component-id-not-found',
});
mockUsePluginComponents.mockReturnValue({
components: [createComponentWithMeta(addedComponentRegistryItemMock, extensionPointId)],
isLoading: false,
});
const { container } = render(<ExtensionSidebar />);
expect(container.firstChild).toBeNull();
});
it('should render nothing when components are loading', () => {
mockUseExtensionSidebarContext.mockReturnValue({
...extensionSidebarContextMock,
isEnabled: true,
});
mockUsePluginComponents.mockReturnValue({
components: [createComponentWithMeta(addedComponentRegistryItemMock, extensionPointId)],
isLoading: true,
});
const { container } = render(<ExtensionSidebar />);
expect(container.firstChild).toBeNull();
});
it('should render the component when all conditions are met', () => {
mockUseExtensionSidebarContext.mockReturnValue({
...extensionSidebarContextMock,
isEnabled: true,
});
mockUsePluginComponents.mockReturnValue({
components: [createComponentWithMeta(addedComponentRegistryItemMock, extensionPointId)],
isLoading: false,
});
const { container } = render(<ExtensionSidebar />);
expect(container.firstChild).toBeInTheDocument();
expect(screen.getByText('Mock Component')).toBeInTheDocument();
});
});
@@ -2,7 +2,7 @@ import { css } from '@emotion/css';
import { GrafanaTheme2 } from '@grafana/data';
import { usePluginComponents } from '@grafana/runtime';
import { ErrorBoundaryAlert, useTheme2 } from '@grafana/ui';
import { useTheme2 } from '@grafana/ui';
import {
EXTENSION_SIDEBAR_EXTENSION_POINT_ID,
@@ -45,9 +45,7 @@ export function ExtensionSidebar() {
return (
<div className={styles.sidebarWrapper}>
<div className={styles.content}>
<ErrorBoundaryAlert>
<ExtensionComponent {...props} />
</ErrorBoundaryAlert>
<ExtensionComponent {...props} />
</div>
</div>
);
@@ -18,7 +18,7 @@ const PERMITTED_EXTENSION_SIDEBAR_PLUGINS = [
'grafana-grafanadocsplugin-app',
];
type ExtensionSidebarContextType = {
export type ExtensionSidebarContextType = {
/**
* Whether the extension sidebar is enabled.
*/
@@ -4,23 +4,12 @@ import { Alert } from '@grafana/ui';
import { stringifyErrorLike } from '../../utils/misc';
export const NotificationPoliciesErrorAlert = ({ error }: { error: unknown }) => {
const title = t('alerting.policies.update-errors.title', 'Error saving notification policy');
const title = t('alerting.policies.update-errors.title', 'Failed to add or update notification policy');
const errMessage = stringifyErrorLike(error);
return (
<Alert title={title} severity="error">
<div>
<Trans i18nKey="alerting.policies.update-errors.fallback">
Something went wrong when updating your notification policies.
</Trans>
</div>
<div>
{errMessage || (
<Trans i18nKey="alerting.policies.update-errors.error-code" values={{ error }}>
Error message: "{{ error }}"
</Trans>
)}
</div>
<div>{errMessage}</div>
<Trans i18nKey="alerting.policies.update-errors.suffix">Please refresh the page and try again.</Trans>
</Alert>
@@ -0,0 +1,45 @@
import {
ApiMachineryErrorResponse,
ERROR_ROUTES_MATCHER_CONFLICT,
getErrorMessageFromApiMachineryErrorResponse,
} from './errors';
describe('getErrorMessageFromCode', () => {
it(`should handle ${ERROR_ROUTES_MATCHER_CONFLICT}`, () => {
const error: ApiMachineryErrorResponse = {
status: 400,
config: { url: '' },
data: {
kind: 'Status',
apiVersion: 'v1',
metadata: {},
status: 'Failure',
message: 'this is ignored',
reason: 'BadRequest',
details: {
uid: 'alerting.notifications.routes.conflictingMatchers',
causes: [
{
message: '"[foo=\\"bar\\" baz=\\"qux\\"]"',
field: 'Matchers',
},
{
message: '"[foo2=\\"bar2\\" baz2=\\"qux2\\"]"',
field: 'Matchers',
},
],
},
code: 400,
},
};
expect(getErrorMessageFromApiMachineryErrorResponse(error)).toBe(
'Cannot add or update route: matchers conflict with an external routing tree if we merged matchers \"[foo=\\\"bar\\\" baz=\\\"qux\\\"]\", \"[foo2=\\\"bar2\\\" baz2=\\\"qux2\\\"]\". This would make the route unreachable.'
);
delete error.data.details?.causes;
expect(getErrorMessageFromApiMachineryErrorResponse(error)).toBe(
'Cannot add or update route: matchers conflict with an external routing tree if we merged matchers <unknown matchers>. This would make the route unreachable.'
);
});
});
@@ -3,19 +3,56 @@ import { get } from 'lodash';
import { t } from '@grafana/i18n';
import { FetchError, isFetchError } from '@grafana/runtime';
export type SupportedErrors = 'alerting.notifications.conflict' | string;
import { getErrorCode } from '../misc';
export const ERROR_NEWER_CONFIGURATION = 'alerting.notifications.conflict';
export const ERROR_NEWER_CONFIGURATION = 'alerting.notifications.conflict' as const;
export const ERROR_ROUTES_MATCHER_CONFLICT = 'alerting.notifications.routes.conflictingMatchers' as const;
/** This function gives us the opportunity to translate or transform error codes that are returned from the Kubernetes APIs */
export type ApiMachineryErrorResponse = FetchError<ApiMachineryError>;
// these are known error IDs, used by both Kubernetes API and the front-end (using error `cause`).
export type KnownErrorCodes = typeof ERROR_NEWER_CONFIGURATION;
// Kubernetes API Machinery errors are a superset of supported errors codes.
export type KnownMachineryErrorCodes = KnownErrorCodes | typeof ERROR_ROUTES_MATCHER_CONFLICT;
/**
* This function gives us the opportunity to translate or transform error codes that are returned from the Kubernetes APIs
*/
export function getErrorMessageFromApiMachineryErrorResponse(error: ApiMachineryErrorResponse): string | undefined {
const code = getErrorCode(error);
if (!code) {
return error.data.message;
}
const errorMessageMap: Record<KnownMachineryErrorCodes, string | undefined> = {
[ERROR_NEWER_CONFIGURATION]: getErrorMessageFromCode(code),
[ERROR_ROUTES_MATCHER_CONFLICT]: t(
'alerting.policies.update-errors.routes.conflictingMatchers',
'Cannot add or update route: matchers conflict with an external routing tree if we merged matchers {{-matchers}}. This would make the route unreachable.',
{
matchers:
error.data.details?.causes?.map((cause) => cause.message).join(', ') ??
t('alerting.policies.update-errors.routes.unknownMatchers', '<unknown matchers>'),
}
),
};
// @ts-expect-error this allows the typechecker to warn us about forgetting to handle some KnownMachineryErrors and still return "undefined" for unknown codes;
return errorMessageMap[code];
}
/**
* This function gives us the opportunity to translate or transform error codes
*/
export function getErrorMessageFromCode(code: string): string | undefined {
const errorMessageMap: Record<SupportedErrors, string> = {
const errorMessageMap: Record<KnownErrorCodes, string> = {
[ERROR_NEWER_CONFIGURATION]: t(
'alerting.policies.update-errors.conflict',
'The notification policy tree has been updated by another user.'
),
};
// @ts-expect-error this allows the typechecker to warn us about forgetting to handle some KnownErrors and still return "undefined" for unknown codes;
return errorMessageMap[code];
}
@@ -29,7 +66,12 @@ export type ApiMachineryError = {
group?: string;
kind?: string;
retryAfterSeconds?: number;
causes?: []; // @TODO type this, see apimachinery@v0.31.1/pkg/apis/meta/v1/types.go
// https://github.com/kubernetes/apimachinery/blob/v0.33.2/pkg/apis/meta/v1/types.go#L1020-L1040
causes?: Array<{
message?: string;
field?: string;
reason?: string;
}>;
};
status: 'Failure';
metadata?: Record<string, unknown>;
@@ -37,6 +79,6 @@ export type ApiMachineryError = {
reason: string;
};
export function isApiMachineryError(error: unknown): error is FetchError<ApiMachineryError> {
export function isApiMachineryError(error: unknown): error is ApiMachineryErrorResponse {
return isFetchError(error) && get(error.data, 'kind') === 'Status' && get(error.data, 'status') === 'Failure';
}
@@ -125,12 +125,12 @@ describe('create links', () => {
describe('stringifyErrorLike', () => {
it('should stringify error with cause', () => {
const error = new Error('Something went strong', { cause: new Error('database did not respond') });
expect(stringifyErrorLike(error)).toBe('Something went strong, cause: database did not respond');
const error = new Error('Something went wrong', { cause: new Error('database did not respond') });
expect(stringifyErrorLike(error)).toBe('Something went wrong, cause: database did not respond');
});
it('should stringify error with cause being a code', () => {
const error = new Error('Something went strong', { cause: ERROR_NEWER_CONFIGURATION });
const error = new Error('Something went wrong', { cause: ERROR_NEWER_CONFIGURATION });
expect(stringifyErrorLike(error)).toBe(getErrorMessageFromCode(ERROR_NEWER_CONFIGURATION));
});
@@ -1,4 +1,4 @@
import { sortBy } from 'lodash';
import { isString, sortBy } from 'lodash';
import { Labels, UrlQueryMap } from '@grafana/data';
import { GrafanaEdition } from '@grafana/data/internal';
@@ -34,7 +34,12 @@ import {
import { ALERTMANAGER_NAME_QUERY_KEY } from './constants';
import { getRulesSourceName } from './datasource';
import { SupportedErrors, getErrorMessageFromCode, isApiMachineryError } from './k8s/errors';
import {
KnownErrorCodes,
getErrorMessageFromApiMachineryErrorResponse,
getErrorMessageFromCode,
isApiMachineryError,
} from './k8s/errors';
import { getMatcherQueryParams } from './matchers';
import { rulesNav } from './navigation';
import * as ruleId from './rule-id';
@@ -282,15 +287,20 @@ export function isErrorLike(error: unknown): error is Error {
return Boolean(error && typeof error === 'object' && 'message' in error);
}
export function getErrorCode(error: Error): unknown {
export function getErrorCode(error: unknown): string | undefined {
if (isApiMachineryError(error) && error.data.details) {
return error.data.details.uid;
}
return error.cause;
if (isErrorLike(error) && isString(error.cause)) {
return error.cause;
}
return;
}
/* this function will check if the error passed as the first argument contains an error code */
export function isErrorMatchingCode(error: Error | undefined, code: SupportedErrors): boolean {
export function isErrorMatchingCode(error: Error | undefined, code: KnownErrorCodes): boolean {
if (!error) {
return false;
}
@@ -301,8 +311,8 @@ export function isErrorMatchingCode(error: Error | undefined, code: SupportedErr
export function stringifyErrorLike(error: unknown): string {
const fetchError = isFetchError(error);
if (fetchError) {
if (isApiMachineryError(error) && error.data.details) {
const message = getErrorMessageFromCode(error.data.details.uid);
if (isApiMachineryError(error)) {
const message = getErrorMessageFromApiMachineryErrorResponse(error);
if (message) {
return message;
}
@@ -37,6 +37,39 @@ jest.mock('@grafana/runtime', () => {
...original.config.featureToggles,
dashboardNewLayouts: false, // Default value
},
bootData: {
...original.config.bootData,
settings: {
...original.config.bootData.settings,
datasources: {
'gdev-testdata': {
id: 7,
uid: 'abc',
type: 'grafana-testdata-datasource',
name: 'gdev-testdata',
meta: {
id: 'grafana-testdata-datasource',
type: 'datasource',
name: 'TestData',
aliasIDs: ['testdata'],
},
},
'-- Grafana --': {
id: -1,
uid: 'grafana',
type: 'datasource',
name: '-- Grafana --',
meta: {
id: 'grafana',
type: 'datasource',
name: '-- Grafana --',
},
},
},
defaultDatasource: 'gdev-testdata',
},
},
},
};
});
@@ -218,6 +251,39 @@ describe('DashboardScenePageStateManager v1', () => {
});
describe('caching', () => {
it('should return cached scene if updated_at matches', async () => {
const loader = new DashboardScenePageStateManager({});
// set cache
loader.setSceneCache(
'fake-dash',
new DashboardScene({ title: 'Dashboard 1', uid: 'fake-dash', meta: { created: '1' }, version: 0 }, 'v1')
);
// should return cached scene
expect(
loader.transformResponseToScene(
{
meta: { created: '1' },
dashboard: { title: 'Dashboard 1', uid: 'fake-dash', schemaVersion: 1, version: 0 },
},
{ uid: 'fake-dash', route: DashboardRoutes.Normal }
)?.state.title
).toBe('Dashboard 1');
// try loading new scene
loader.transformResponseToScene(
{
meta: { created: '2' },
dashboard: { title: 'Dashboard 2', uid: 'fake-dash', schemaVersion: 1, version: 0 },
},
{ uid: 'fake-dash', route: DashboardRoutes.Normal }
);
// should update cache with new scene
expect(loader.getSceneFromCache('fake-dash').state.title).toBe('Dashboard 2');
});
it('should take scene from cache if it exists', async () => {
setupLoadDashboardMock({ dashboard: { uid: 'fake-dash', version: 10 }, meta: {} });
@@ -1555,9 +1621,11 @@ const v2ProvisionedDashboardResource = {
kind: 'AnnotationQuery',
spec: {
builtIn: true,
datasource: {
type: 'grafana',
uid: '-- Grafana --',
query: {
kind: 'DataQuery',
group: 'grafana',
spec: {},
version: 'v0',
},
enable: true,
hide: true,
@@ -1580,13 +1648,14 @@ const v2ProvisionedDashboardResource = {
{
kind: 'PanelQuery',
spec: {
datasource: {
type: 'grafana-testdata-datasource',
uid: 'PD8C576611E62080A',
},
hidden: false,
query: {
kind: 'grafana-testdata-datasource',
kind: 'DataQuery',
group: 'grafana-testdata-datasource',
version: 'v0',
datasource: {
name: 'PD8C576611E62080A',
},
spec: {
scenarioId: 'random_walk',
seriesCount: 2,
@@ -371,7 +371,11 @@ export class DashboardScenePageStateManager extends DashboardScenePageStateManag
transformResponseToScene(rsp: DashboardDTO | null, options: LoadDashboardOptions): DashboardScene | null {
const fromCache = this.getSceneFromCache(options.uid);
if (fromCache && fromCache.state.version === rsp?.dashboard.version) {
if (
fromCache &&
fromCache.state.version === rsp?.dashboard.version &&
fromCache.state.meta.created === rsp?.meta.created
) {
return fromCache;
}
@@ -549,13 +549,12 @@ describe('dashboard exporter v2', () => {
{
kind: 'PanelQuery',
spec: {
datasource: {
type: 'prometheus',
uid: '${datasourceVar}',
},
hidden: false,
query: {
kind: 'prometheus',
datasource: {
name: '${datasourceVar}',
},
group: 'prometheus',
spec: {
editorMode: 'builder',
expr: 'go_goroutines{job="prometheus"}',
@@ -583,7 +582,7 @@ describe('dashboard exporter v2', () => {
it('should replace datasource in a query variable', async () => {
const { dashboard } = await setup();
const variable = dashboard.variables[0] as QueryVariableKind;
expect(variable.spec.datasource?.uid).toBeUndefined();
expect(variable.spec.query.datasource?.name).toBeUndefined();
});
it('do not expose datasource name and id in datasource variable', async () => {
@@ -597,7 +596,7 @@ describe('dashboard exporter v2', () => {
const { dashboard } = await setup();
const annotationQuery = dashboard.annotations[0];
expect(annotationQuery.spec.datasource?.uid).toBeUndefined();
expect(annotationQuery.spec.query?.datasource?.name).toBeUndefined();
});
it('should remove library panels from layout', async () => {
@@ -616,11 +615,8 @@ describe('dashboard exporter v2', () => {
if (panel.kind !== 'Panel') {
throw new Error('Panel should be a Panel');
}
expect(panel.spec.data.spec.queries[0].spec.datasource).toEqual({
type: 'prometheus',
uid: '${datasourceVar}',
});
expect(panel.spec.data.spec.queries[0].spec.query.datasource?.name).toBe('${datasourceVar}');
expect(panel.spec.data.spec.queries[0].spec.query.group).toBe('prometheus');
});
});
@@ -344,7 +344,8 @@ export async function makeExportableV2(dashboard: DashboardV2Spec) {
const removeDataSourceRefs = (
obj: AnnotationQueryKind['spec'] | QueryVariableKind['spec'] | PanelQueryKind['spec']
) => {
const datasourceUid = obj.datasource?.uid;
const datasourceUid = obj.query?.datasource?.name;
if (datasourceUid?.startsWith('${') && datasourceUid?.endsWith('}')) {
const varName = datasourceUid.slice(2, -1);
// if there's a match we don't want to remove the datasource ref
@@ -354,7 +355,7 @@ export async function makeExportableV2(dashboard: DashboardV2Spec) {
}
}
obj.datasource = undefined;
obj.query && (obj.query.datasource = undefined);
};
const processPanel = (panel: PanelKind) => {
@@ -10,6 +10,7 @@ import { Dashboard, VariableModel } from '@grafana/schema';
import {
Spec as DashboardV2Spec,
defaultSpec as defaultDashboardV2Spec,
defaultDataQueryKind,
defaultPanelSpec,
defaultTimeSettingsSpec,
GridLayoutKind,
@@ -723,9 +724,14 @@ describe('DashboardSceneSerializer', () => {
spec: {
builtIn: true,
name: 'Annotations & Alerts',
datasource: {
uid: '-- Grafana --',
type: 'grafana',
query: {
kind: 'DataQuery',
version: defaultDataQueryKind().version,
group: 'grafana',
datasource: {
name: '-- Grafana --',
},
spec: {},
},
enable: true,
hide: true,
@@ -1014,7 +1020,7 @@ describe('DashboardSceneSerializer', () => {
refId: 'A',
hidden: false,
// No datasource defined
query: { kind: 'sql', spec: {} },
query: { kind: 'DataQuery', version: defaultDataQueryKind().version, group: 'sql', spec: {} },
},
},
{
@@ -1022,8 +1028,15 @@ describe('DashboardSceneSerializer', () => {
spec: {
refId: 'B',
hidden: false,
datasource: { uid: 'datasource-1', type: 'prometheus' },
query: { kind: 'prometheus', spec: {} },
query: {
kind: 'DataQuery',
version: defaultDataQueryKind().version,
group: 'prometheus',
datasource: {
name: 'datasource-1',
},
spec: {},
},
},
},
],
@@ -1058,7 +1071,7 @@ describe('DashboardSceneSerializer', () => {
refId: 'C',
hidden: false,
// No datasource defined
query: { kind: 'sql', spec: {} },
query: { kind: 'DataQuery', version: defaultDataQueryKind().version, group: 'sql', spec: {} },
},
},
],
@@ -1106,7 +1119,7 @@ describe('DashboardSceneSerializer', () => {
kind: 'AnnotationQuery',
spec: {
name: 'Annotation 1',
query: { kind: 'prometheus', spec: {} },
query: { kind: 'DataQuery', version: defaultDataQueryKind().version, group: 'prometheus', spec: {} },
enable: true,
hide: false,
iconColor: 'red',
@@ -288,7 +288,7 @@ export class V2DashboardSerializer
const panelQueries = elementPanel.spec.data.spec.queries;
for (const query of panelQueries) {
if (!query.spec.datasource) {
if (!query.spec.query.datasource?.name) {
const elementId = this.getElementIdForPanel(elementPanel.spec.id);
if (!this.defaultDsReferencesMap.panels.has(elementId)) {
this.defaultDsReferencesMap.panels.set(elementId, new Set());
@@ -306,7 +306,7 @@ export class V2DashboardSerializer
if (saveModel?.variables) {
for (const variable of saveModel.variables) {
// for query variables that dont have a ds defined add them to the list
if (variable.kind === 'QueryVariable' && !variable.spec.datasource) {
if (variable.kind === 'QueryVariable' && !variable.spec.query.datasource?.name) {
this.defaultDsReferencesMap.variables.add(variable.spec.name);
}
}
@@ -315,7 +315,7 @@ export class V2DashboardSerializer
// initialize annotations ds references map
if (saveModel?.annotations) {
for (const annotation of saveModel.annotations) {
if (!annotation.spec.datasource) {
if (!annotation.spec.query?.datasource?.name) {
this.defaultDsReferencesMap.annotations.add(annotation.spec.name);
}
}
@@ -7,38 +7,38 @@ exports[`transformSceneToSaveModelSchemaV2 should transform scene to save model
"kind": "AnnotationQuery",
"spec": {
"builtIn": false,
"datasource": {
"type": "grafana",
"uid": "-- Grafana --",
},
"enable": true,
"hide": false,
"iconColor": "red",
"name": "query1",
"query": {
"datasource": {
"name": "-- Grafana --",
},
"group": "grafana",
"kind": "DataQuery",
"spec": {},
"version": "v0",
},
},
},
{
"kind": "AnnotationQuery",
"spec": {
"builtIn": false,
"datasource": {
"type": "prometheus",
"uid": "abcdef",
},
"enable": true,
"hide": true,
"iconColor": "blue",
"name": "query2",
},
},
{
"kind": "AnnotationQuery",
"spec": {
"builtIn": false,
"enable": true,
"hide": true,
"iconColor": "green",
"name": "query3",
"query": {
"datasource": {
"name": "abcdef",
},
"group": "prometheus",
"kind": "DataQuery",
"spec": {},
"version": "v0",
},
},
},
],
@@ -152,10 +152,6 @@ exports[`transformSceneToSaveModelSchemaV2 should transform scene to save model
"text": "text1",
"value": "value1",
},
"datasource": {
"type": "prometheus",
"uid": "datasource1",
},
"definition": "definition1",
"description": "A query variable",
"hide": "hideLabel",
@@ -165,11 +161,16 @@ exports[`transformSceneToSaveModelSchemaV2 should transform scene to save model
"name": "queryVar",
"options": [],
"query": {
"kind": "prometheus",
"datasource": {
"name": "datasource1",
},
"group": "prometheus",
"kind": "DataQuery",
"spec": {
"expr": "label_values(node_boot_time_seconds)",
"refId": "A",
},
"version": "v0",
},
"refresh": "onDashboardLoad",
"regex": "regex1",
@@ -1,4 +1,7 @@
import { PanelQueryKind } from '@grafana/schema/dist/esm/schema/dashboard/v2alpha1/types.spec.gen';
import {
defaultDataQueryKind,
PanelQueryKind,
} from '@grafana/schema/dist/esm/schema/dashboard/v2alpha1/types.spec.gen';
import { getRuntimePanelDataSource } from './utils';
@@ -29,6 +32,12 @@ jest.mock('@grafana/runtime', () => ({
meta: { id: 'loki' },
type: 'datasource',
},
'-- Grafana --': {
uid: 'grafana',
name: 'Grafana',
meta: { id: 'grafana' },
type: 'datasource',
},
},
},
},
@@ -42,22 +51,23 @@ describe('getRuntimePanelDataSource', () => {
spec: {
refId: 'A',
hidden: false,
datasource: {
uid: 'test-ds-uid',
type: 'test-ds-type',
},
query: {
kind: 'prometheus',
kind: 'DataQuery',
version: defaultDataQueryKind().version,
group: 'prometheus',
datasource: {
name: 'prometheus-uid',
},
spec: {},
},
},
};
const result = getRuntimePanelDataSource(query);
const result = getRuntimePanelDataSource(query.spec.query);
expect(result).toEqual({
uid: 'test-ds-uid',
type: 'test-ds-type',
uid: 'prometheus-uid',
type: 'prometheus',
});
});
@@ -67,15 +77,16 @@ describe('getRuntimePanelDataSource', () => {
spec: {
refId: 'A',
hidden: false,
datasource: undefined,
query: {
kind: 'prometheus',
kind: 'DataQuery',
version: defaultDataQueryKind().version,
group: 'prometheus',
spec: {},
},
},
};
const result = getRuntimePanelDataSource(query);
const result = getRuntimePanelDataSource(query.spec.query);
expect(result).toEqual({
uid: 'default-prometheus-uid',
@@ -89,15 +100,16 @@ describe('getRuntimePanelDataSource', () => {
spec: {
refId: 'A',
hidden: false,
datasource: undefined,
query: {
kind: 'loki',
kind: 'DataQuery',
version: defaultDataQueryKind().version,
group: 'loki',
spec: {},
},
},
};
const result = getRuntimePanelDataSource(query);
const result = getRuntimePanelDataSource(query.spec.query);
expect(result).toEqual({
uid: 'loki-uid',
@@ -112,15 +124,16 @@ describe('getRuntimePanelDataSource', () => {
spec: {
refId: 'A',
hidden: false,
datasource: undefined,
query: {
kind: 'unknown-type',
kind: 'DataQuery',
version: defaultDataQueryKind().version,
group: 'unknown-type',
spec: {},
},
},
};
const result = getRuntimePanelDataSource(query);
const result = getRuntimePanelDataSource(query.spec.query);
expect(result).toEqual({
uid: 'default-prometheus-uid',
@@ -138,18 +151,19 @@ describe('getRuntimePanelDataSource', () => {
spec: {
refId: 'A',
hidden: false,
datasource: {
uid: '',
type: 'test-ds-type',
},
query: {
kind: 'prometheus',
kind: 'DataQuery',
version: defaultDataQueryKind().version,
group: 'prometheus',
datasource: {
name: '',
},
spec: {},
},
},
};
const result = getRuntimePanelDataSource(query);
const result = getRuntimePanelDataSource(query.spec.query);
expect(result).toEqual({
uid: 'default-prometheus-uid',
@@ -19,6 +19,7 @@ import {
PanelQueryKind,
QueryVariableKind,
TabsLayoutTabKind,
DataQueryKind,
} from '@grafana/schema/dist/esm/schema/dashboard/v2alpha1/types.spec.gen';
import { MIXED_DATASOURCE_NAME } from 'app/plugins/datasource/mixed/MixedDataSource';
@@ -185,12 +186,15 @@ function getPanelDataSource(panel: PanelKind): DataSourceRef | undefined {
panel.spec.data.spec.queries.forEach((query) => {
if (!datasource) {
if (!query.spec.datasource?.uid) {
datasource = getRuntimePanelDataSource(query);
if (!query.spec.query.datasource?.name) {
datasource = getRuntimePanelDataSource(query.spec.query);
} else {
datasource = query.spec.datasource;
datasource = {
uid: query.spec.query.datasource?.name,
type: query.spec.query.group,
};
}
} else if (datasource.uid !== query.spec.datasource?.uid || datasource.type !== query.spec.datasource?.type) {
} else if (datasource.uid !== query.spec.query.datasource?.name || datasource.type !== query.spec.query.group) {
isMixedDatasource = true;
}
});
@@ -199,11 +203,19 @@ function getPanelDataSource(panel: PanelKind): DataSourceRef | undefined {
}
export function getRuntimeVariableDataSource(variable: QueryVariableKind): DataSourceRef | undefined {
return getDataSourceForQuery(variable.spec.datasource, variable.spec.query.kind);
const ds: DataSourceRef = {
uid: variable.spec.query.datasource?.name,
type: variable.spec.query.group,
};
return getDataSourceForQuery(ds, variable.spec.query.group);
}
export function getRuntimePanelDataSource(query: PanelQueryKind): DataSourceRef | undefined {
return getDataSourceForQuery(query.spec.datasource, query.spec.query.kind);
export function getRuntimePanelDataSource(query: DataQueryKind): DataSourceRef {
const ds: DataSourceRef = {
uid: query.datasource?.name,
type: query.group,
};
return getDataSourceForQuery(ds, query.group);
}
/**
@@ -211,10 +223,7 @@ export function getRuntimePanelDataSource(query: PanelQueryKind): DataSourceRef
* @param queryKind - The kind of query being performed
* @returns The resolved DataSourceRef
*/
function getDataSourceForQuery(
querySpecDS: DataSourceRef | undefined | null,
queryKind: string
): DataSourceRef | undefined {
function getDataSourceForQuery(querySpecDS: DataSourceRef | undefined | null, queryKind: string): DataSourceRef {
// If datasource is specified and has a uid, use it
if (querySpecDS?.uid) {
return querySpecDS;
@@ -253,14 +262,22 @@ function getDataSourceForQuery(
};
}
// If we don't find a default datasource, return undefined
return undefined;
if (dsList && !dsList[defaultDatasource]) {
throw new Error(`Default datasource ${defaultDatasource} not found in datasource list`);
}
// In the datasource list from bootData "id" is the type and the uid could be uid or the name
// in cases like grafana, dashboard or mixed datasource
return {
uid: dsList[defaultDatasource].uid || dsList[defaultDatasource].name,
type: dsList[defaultDatasource].meta.id,
};
}
function panelQueryKindToSceneQuery(query: PanelQueryKind): SceneDataQuery {
return {
refId: query.spec.refId,
datasource: getRuntimePanelDataSource(query),
datasource: getRuntimePanelDataSource(query.spec.query),
hide: query.spec.hidden,
...query.spec.query.spec,
};
@@ -45,8 +45,8 @@ const getDataSourceMock = jest.fn();
const fakeDsMock: DataSourceApi = {
name: 'fake-std',
type: 'fake-std',
getRef: () => ({ type: 'fake-std', uid: 'fake-std' }),
type: 'fake-type',
getRef: () => ({ type: 'fake-type', uid: 'fake-uid' }),
query: () =>
Promise.resolve({
data: [],
@@ -74,7 +74,7 @@ const fakeDsMock: DataSourceApi = {
toDataQuery: (q) => ({ ...q, refId: 'FakeDataSource-refId' }),
},
id: 1,
uid: 'fake-std',
uid: 'fake-uid',
};
jest.mock('@grafana/runtime', () => ({
@@ -95,7 +95,7 @@ describe('sceneVariablesSetToVariables', () => {
description: 'test-desc',
value: ['selected-value'],
text: ['selected-value-text'],
datasource: { uid: 'fake-std', type: 'fake-std' },
datasource: { uid: 'fake-uid', type: 'fake-type' },
query: 'query',
includeAll: true,
allowCustomValue: true,
@@ -123,8 +123,8 @@ describe('sceneVariablesSetToVariables', () => {
],
},
"datasource": {
"type": "fake-std",
"uid": "fake-std",
"type": "fake-type",
"uid": "fake-uid",
},
"definition": undefined,
"description": "test-desc",
@@ -148,7 +148,7 @@ describe('sceneVariablesSetToVariables', () => {
description: 'test-desc',
value: ['selected-value'],
text: ['selected-value-text'],
datasource: { uid: 'fake-std', type: 'fake-std' },
datasource: { uid: 'fake-uid', type: 'fake-type' },
query: 'query',
definition: 'query',
includeAll: true,
@@ -176,8 +176,8 @@ describe('sceneVariablesSetToVariables', () => {
],
},
"datasource": {
"type": "fake-std",
"uid": "fake-std",
"type": "fake-type",
"uid": "fake-uid",
},
"definition": "query",
"description": "test-desc",
@@ -201,7 +201,7 @@ describe('sceneVariablesSetToVariables', () => {
description: 'test-desc',
value: ['selected-value'],
text: ['selected-value-text'],
datasource: { uid: 'fake-std', type: 'fake-std' },
datasource: { uid: 'fake-uid', type: 'fake-type' },
query: 'query',
options: [
{ label: 'test', value: 'test' },
@@ -228,7 +228,7 @@ describe('sceneVariablesSetToVariables', () => {
description: 'test-desc',
value: ['test'],
text: ['test'],
datasource: { uid: 'fake-std', type: 'fake-std' },
datasource: { uid: 'fake-uid', type: 'fake-type' },
query: 'query',
options: [
{ label: 'test', value: 'test' },
@@ -499,7 +499,7 @@ describe('sceneVariablesSetToVariables', () => {
allowCustomValue: true,
label: 'test-label',
description: 'test-desc',
datasource: { uid: 'fake-std', type: 'fake-std' },
datasource: { uid: 'fake-uid', type: 'fake-type' },
filters: [
{
key: 'filterTest',
@@ -533,8 +533,8 @@ describe('sceneVariablesSetToVariables', () => {
},
],
"datasource": {
"type": "fake-std",
"uid": "fake-std",
"type": "fake-type",
"uid": "fake-uid",
},
"defaultKeys": undefined,
"description": "test-desc",
@@ -662,7 +662,7 @@ describe('sceneVariablesSetToVariables', () => {
allowCustomValue: true,
label: 'test-label',
description: 'test-desc',
datasource: { uid: 'fake-std', type: 'fake-std' },
datasource: { uid: 'fake-uid', type: 'fake-type' },
defaultKeys: [
{
text: 'some',
@@ -710,8 +710,8 @@ describe('sceneVariablesSetToVariables', () => {
},
],
"datasource": {
"type": "fake-std",
"uid": "fake-std",
"type": "fake-type",
"uid": "fake-uid",
},
"defaultKeys": [
{
@@ -757,7 +757,7 @@ describe('sceneVariablesSetToVariables', () => {
label: 'test-label',
description: 'test-desc',
allowCustomValue: true,
datasource: { uid: 'fake-std', type: 'fake-std' },
datasource: { uid: 'fake-uid', type: 'fake-type' },
defaultOptions: [
{
text: 'Foo',
@@ -784,8 +784,8 @@ describe('sceneVariablesSetToVariables', () => {
"value": [],
},
"datasource": {
"type": "fake-std",
"uid": "fake-std",
"type": "fake-type",
"uid": "fake-uid",
},
"defaultValue": undefined,
"description": "test-desc",
@@ -813,7 +813,7 @@ describe('sceneVariablesSetToVariables', () => {
name: 'test',
label: 'test-label',
description: 'test-desc',
datasource: { uid: 'fake-std', type: 'fake-std' },
datasource: { uid: 'fake-uid', type: 'fake-type' },
defaultOptions: [
{
text: 'Foo',
@@ -841,7 +841,7 @@ describe('sceneVariablesSetToVariables', () => {
description: 'test-desc',
value: ['selected-value'],
text: ['selected-value-text'],
datasource: { uid: 'fake-std', type: 'fake-std' },
datasource: { uid: 'fake-uid', type: 'fake-type' },
query: 'query',
includeAll: true,
allValue: 'test-all',
@@ -856,44 +856,45 @@ describe('sceneVariablesSetToVariables', () => {
expect(result).toHaveLength(1);
expect(result[0]).toMatchInlineSnapshot(`
{
"kind": "QueryVariable",
"spec": {
"allValue": "test-all",
"allowCustomValue": true,
"current": {
"text": [
"selected-value-text",
],
"value": [
"selected-value",
],
},
"datasource": {
"type": "fake-std",
"uid": "fake-std",
},
"definition": undefined,
"description": "test-desc",
"hide": "dontHide",
"includeAll": true,
"label": "test-label",
"multi": true,
"name": "test",
"options": [],
"query": {
"kind": "fake-std",
{
"kind": "QueryVariable",
"spec": {
"__legacyStringValue": "query",
"allValue": "test-all",
"allowCustomValue": true,
"current": {
"text": [
"selected-value-text",
],
"value": [
"selected-value",
],
},
"definition": undefined,
"description": "test-desc",
"hide": "dontHide",
"includeAll": true,
"label": "test-label",
"multi": true,
"name": "test",
"options": [],
"query": {
"datasource": {
"name": "fake-uid",
},
"group": "fake-type",
"kind": "DataQuery",
"spec": {
"__legacyStringValue": "query",
},
"version": "v0",
},
"refresh": "onDashboardLoad",
"regex": "",
"skipUrlSync": false,
"sort": "disabled",
},
},
"refresh": "onDashboardLoad",
"regex": "",
"skipUrlSync": false,
"sort": "disabled",
},
}
`);
}
`);
});
it('should handle CustomVariable', () => {
@@ -1152,7 +1153,7 @@ describe('sceneVariablesSetToVariables', () => {
name: 'test',
label: 'test-label',
description: 'test-desc',
datasource: { uid: 'fake-std', type: 'fake-std' },
datasource: { uid: 'fake-uid', type: 'fake-type' },
filters: [
{
key: 'filterTest',
@@ -1188,8 +1189,8 @@ describe('sceneVariablesSetToVariables', () => {
},
],
"datasource": {
"type": "fake-std",
"uid": "fake-std",
"type": "fake-type",
"uid": "fake-uid",
},
"defaultKeys": [],
"description": "test-desc",
@@ -1214,7 +1215,7 @@ describe('sceneVariablesSetToVariables', () => {
name: 'test',
label: 'test-label',
description: 'test-desc',
datasource: { uid: 'fake-std', type: 'fake-std' },
datasource: { uid: 'fake-uid', type: 'fake-type' },
defaultKeys: [
{
text: 'some',
@@ -1264,8 +1265,8 @@ describe('sceneVariablesSetToVariables', () => {
},
],
"datasource": {
"type": "fake-std",
"uid": "fake-std",
"type": "fake-type",
"uid": "fake-uid",
},
"defaultKeys": [
{
@@ -1312,7 +1313,7 @@ describe('sceneVariablesSetToVariables', () => {
name: 'test',
label: 'test-label',
description: 'test-desc',
datasource: { uid: 'fake-std', type: 'fake-std' },
datasource: { uid: 'fake-uid', type: 'fake-type' },
defaultOptions: [
{
text: 'Foo',
@@ -1340,8 +1341,8 @@ describe('sceneVariablesSetToVariables', () => {
"value": [],
},
"datasource": {
"type": "fake-std",
"uid": "fake-std",
"type": "fake-type",
"uid": "fake-uid",
},
"defaultValue": undefined,
"description": "test-desc",
@@ -1372,7 +1373,7 @@ describe('sceneVariablesSetToVariables', () => {
name: 'test',
label: 'test-label',
description: 'test-desc',
datasource: { uid: 'fake-std', type: 'fake-std' },
datasource: { uid: 'fake-uid', type: 'fake-type' },
defaultOptions: [
{
text: 'Foo',
@@ -24,6 +24,7 @@ import {
GroupByVariableKind,
defaultVariableHide,
VariableOption,
defaultDataQueryKind,
AdHocFilterWithLabels,
} from '@grafana/schema/dist/esm/schema/dashboard/v2alpha1/types.spec.gen';
@@ -294,14 +295,30 @@ export function sceneVariablesSetToSchemaV2Variables(
}
const query = variable.state.query;
let dataQuery: DataQueryKind | string;
const datasource = getElementDatasource(set, variable, 'variable', undefined, dsReferencesMapping);
if (typeof query !== 'string') {
dataQuery = {
kind: variable.state.datasource?.type ?? getDataQueryKind(query),
kind: 'DataQuery',
version: defaultDataQueryKind().version,
group: datasource?.type ?? getDataQueryKind(query),
...(datasource?.uid && {
datasource: {
name: datasource.uid,
},
}),
spec: getDataQuerySpec(query),
};
} else {
dataQuery = {
kind: variable.state.datasource?.type ?? getDataQueryKind(query),
kind: 'DataQuery',
version: defaultDataQueryKind().version,
group: datasource?.type ?? getDataQueryKind(query),
...(datasource?.uid && {
datasource: {
name: datasource.uid,
},
}),
spec: {
[LEGACY_STRING_VALUE_KEY]: query,
},
@@ -315,7 +332,6 @@ export function sceneVariablesSetToSchemaV2Variables(
options,
query: dataQuery,
definition: variable.state.definition,
datasource: getElementDatasource(set, variable, 'variable', undefined, dsReferencesMapping),
sort: transformSortVariableToEnum(variable.state.sort),
refresh: transformVariableRefreshToEnum(variable.state.refresh),
regex: variable.state.regex,
@@ -22,6 +22,7 @@ import {
CustomVariableKind,
Spec as DashboardV2Spec,
DatasourceVariableKind,
defaultDataQueryKind,
GridLayoutItemSpec,
GridLayoutSpec,
GroupByVariableKind,
@@ -138,6 +139,7 @@ describe('transformSaveModelSchemaV2ToScene', () => {
// Variables
const variables = scene.state?.$variables;
expect(variables?.state.variables).toHaveLength(dash.variables.length);
validateVariable({
sceneVariable: variables?.state.variables[0],
variableKind: dash.variables[0] as QueryVariableKind,
@@ -206,36 +208,26 @@ describe('transformSaveModelSchemaV2ToScene', () => {
// Annotations
expect(scene.state.$data).toBeInstanceOf(DashboardDataLayerSet);
const dataLayers = scene.state.$data as DashboardDataLayerSet;
// we should get two annotations, Grafana built-in and the custom ones
expect(dataLayers.state.annotationLayers).toHaveLength(dash.annotations.length);
expect(dataLayers.state.annotationLayers).toHaveLength(5);
// Built-in
const builtInAnnotation = dataLayers.state.annotationLayers[0] as unknown as DashboardAnnotationsDataLayer;
expect(builtInAnnotation.state.name).toBe('Annotations & Alerts');
expect(builtInAnnotation.state.isEnabled).toBe(true);
expect(builtInAnnotation.state.isHidden).toBe(true);
expect(builtInAnnotation.state?.query.builtIn).toBe(1);
expect(dataLayers.state.annotationLayers[0].state.name).toBe(dash.annotations[0].spec.name);
expect(dataLayers.state.annotationLayers[0].state.isEnabled).toBe(dash.annotations[0].spec.enable);
expect(dataLayers.state.annotationLayers[0].state.isHidden).toBe(dash.annotations[0].spec.hide);
// Enabled
expect(dataLayers.state.annotationLayers[1].state.name).toBe(dash.annotations[1].spec.name);
expect(dataLayers.state.annotationLayers[1].state.isEnabled).toBe(dash.annotations[1].spec.enable);
expect(dataLayers.state.annotationLayers[1].state.isHidden).toBe(dash.annotations[1].spec.hide);
// Disabled
expect(dataLayers.state.annotationLayers[2].state.name).toBe(dash.annotations[2].spec.name);
expect(dataLayers.state.annotationLayers[2].state.isEnabled).toBe(dash.annotations[2].spec.enable);
expect(dataLayers.state.annotationLayers[2].state.isHidden).toBe(dash.annotations[2].spec.hide);
// Disabled
// Hidden
expect(dataLayers.state.annotationLayers[3].state.name).toBe(dash.annotations[3].spec.name);
expect(dataLayers.state.annotationLayers[3].state.isEnabled).toBe(dash.annotations[3].spec.enable);
expect(dataLayers.state.annotationLayers[3].state.isHidden).toBe(dash.annotations[3].spec.hide);
// Hidden
expect(dataLayers.state.annotationLayers[4].state.name).toBe(dash.annotations[4].spec.name);
expect(dataLayers.state.annotationLayers[4].state.isEnabled).toBe(dash.annotations[4].spec.enable);
expect(dataLayers.state.annotationLayers[4].state.isHidden).toBe(dash.annotations[4].spec.hide);
// VizPanel
const vizPanels = (scene.state.body as DashboardLayoutManager).getVizPanels();
expect(vizPanels).toHaveLength(2);
@@ -279,13 +271,14 @@ describe('transformSaveModelSchemaV2ToScene', () => {
kind: 'PanelQuery',
spec: {
refId: 'A',
datasource: {
type: 'graphite',
uid: 'datasource1',
},
hidden: false,
query: {
kind: 'prometheus',
kind: 'DataQuery',
version: defaultDataQueryKind().version,
group: 'graphite',
datasource: {
name: 'datasource1',
},
spec: {
expr: 'test-query',
},
@@ -307,13 +300,14 @@ describe('transformSaveModelSchemaV2ToScene', () => {
kind: 'PanelQuery',
spec: {
refId: 'A',
datasource: {
type: 'prometheus',
uid: 'datasource1',
},
hidden: false,
query: {
kind: 'prometheus',
kind: 'DataQuery',
version: defaultDataQueryKind().version,
group: 'prometheus',
datasource: {
name: 'datasource1',
},
spec: {
expr: 'test-query',
},
@@ -340,7 +334,12 @@ describe('transformSaveModelSchemaV2ToScene', () => {
refId: 'A',
hidden: false,
query: {
kind: 'prometheus',
kind: 'DataQuery',
version: defaultDataQueryKind().version,
group: 'prometheus',
datasource: {
name: 'abc123',
},
spec: {
expr: 'test-query',
},
@@ -722,10 +721,6 @@ describe('transformSaveModelSchemaV2ToScene', () => {
enable: true,
hide: false,
iconColor: 'purple',
datasource: {
type: 'prometheus',
uid: 'abc123',
},
legacyOptions: {
expr: 'rate(http_requests_total[5m])',
queryType: 'range',
@@ -733,6 +728,15 @@ describe('transformSaveModelSchemaV2ToScene', () => {
useValueAsTime: true,
step: '1m',
},
query: {
kind: 'DataQuery',
version: defaultDataQueryKind().version,
group: 'prometheus',
datasource: {
name: 'abc123',
},
spec: {},
},
},
},
],
@@ -764,14 +768,36 @@ describe('transformSaveModelSchemaV2ToScene', () => {
// Get the annotation layers
const dataLayerSet = scene.state.$data as DashboardDataLayerSet;
expect(dataLayerSet).toBeDefined();
// it should have two annotation layers, built-in and custom
expect(dataLayerSet.state.annotationLayers.length).toBe(2);
const defaultAnnotationLayer = dataLayerSet.state.annotationLayers[0] as DashboardAnnotationsDataLayer;
// Verify that the default annotation layer has been correctly initialized
expect(defaultAnnotationLayer.state.query).toEqual({
datasource: {
uid: '-- Grafana --',
type: 'grafana',
},
builtIn: 1,
enable: true,
iconColor: 'rgba(0, 211, 255, 1)',
name: 'Annotations & Alerts',
filter: undefined,
hide: true,
});
const annotationLayer = dataLayerSet.state.annotationLayers[1] as DashboardAnnotationsDataLayer;
// Verify that the legacyOptions have been merged into the query object
expect(annotationLayer.state.query).toMatchObject({
datasource: {
uid: 'abc123',
type: 'prometheus',
},
name: 'Annotation with legacy options',
builtIn: 0,
enable: true,
hide: false,
iconColor: 'purple',
expr: 'rate(http_requests_total[5m])',
queryType: 'range',
legendFormat: '{{method}} {{endpoint}}',
@@ -1,5 +1,6 @@
import { uniqueId } from 'lodash';
import { AnnotationQuery } from '@grafana/data';
import { config, getDataSourceSrv } from '@grafana/runtime';
import {
AdHocFiltersVariable,
@@ -28,6 +29,7 @@ import {
defaultAdhocVariableKind,
defaultConstantVariableKind,
defaultCustomVariableKind,
defaultDataQueryKind,
defaultDatasourceVariableKind,
defaultGroupByVariableKind,
defaultIntervalVariableKind,
@@ -64,7 +66,7 @@ import { getIntervalsFromQueryString } from '../utils/utils';
import { SnapshotVariable } from './custom-variables/SnapshotVariable';
import { layoutDeserializerRegistry } from './layoutSerializers/layoutSerializerRegistry';
import { getRuntimeVariableDataSource } from './layoutSerializers/utils';
import { getRuntimePanelDataSource, getRuntimeVariableDataSource } from './layoutSerializers/utils';
import { registerPanelInteractionsReporter } from './transformSaveModelToScene';
import {
transformCursorSyncV2ToV1,
@@ -97,25 +99,46 @@ export function transformSaveModelSchemaV2ToScene(dto: DashboardWithAccessInfo<D
}
const annotationLayers = dashboard.annotations.map((annotation) => {
let annoQuerySpec = annotation.spec;
let { query: dataQuery, ...annotationQuery } = annotation.spec;
// Mapping from AnnotationQueryKind to AnnotationQuery used by scenes.
let annoQuerySpec: AnnotationQuery = {
builtIn: annotation.spec.builtIn ? 1 : 0,
enable: annotation.spec.enable,
iconColor: annotation.spec.iconColor,
name: annotation.spec.name,
filter: annotation.spec.filter,
hide: annotation.spec.hide,
...dataQuery?.spec,
};
// some annotations will contain in the legacyOptions properties that need to be
// added to the root level annotation spec
if (annoQuerySpec?.legacyOptions) {
if (annotationQuery.legacyOptions) {
annoQuerySpec = {
...annoQuerySpec,
...annoQuerySpec.legacyOptions,
...annotationQuery.legacyOptions,
legacyOptions: {
...annotationQuery.legacyOptions,
},
};
}
return new DashboardAnnotationsDataLayer({
// get data source from annotation query
const datasource = getRuntimePanelDataSource(dataQuery);
const layerState = {
key: uniqueId('annotations-'),
query: {
...annoQuerySpec,
builtIn: annotation.spec.builtIn ? 1 : 0,
datasource,
},
name: annotation.spec.name,
isEnabled: Boolean(annotation.spec.enable),
isHidden: Boolean(annotation.spec.hide),
});
};
return new DashboardAnnotationsDataLayer(layerState);
});
const isDashboardEditable = Boolean(dashboard.editable);
@@ -514,7 +537,15 @@ function getGrafanaBuiltInAnnotationDataLayer(dashboard: DashboardV2Spec) {
const grafanaBuiltAnnotation: AnnotationQueryKind = {
kind: 'AnnotationQuery',
spec: {
datasource: { uid: '-- Grafana --', type: 'grafana' },
query: {
kind: 'DataQuery',
version: defaultDataQueryKind().version,
group: 'grafana',
datasource: {
name: '-- Grafana --',
},
spec: {},
},
name: 'Annotations & Alerts',
iconColor: DEFAULT_ANNOTATION_COLOR,
enable: true,
@@ -57,6 +57,7 @@ import {
validateDashboardSchemaV2,
getDataQueryKind,
getAutoAssignedDSRef,
getVizPanelQueries,
} from './transformSceneToSaveModelSchemaV2';
// Mock dependencies
@@ -410,9 +411,7 @@ describe('transformSceneToSaveModelSchemaV2', () => {
expect(result).toMatchSnapshot();
// Check that the annotation layers are correctly transformed
expect(result.annotations).toHaveLength(3);
// Check annotation layer 3 without initial data source isn't updated with runtime default
expect(result.annotations?.[2].spec.datasource?.type).toBe(undefined);
expect(result.annotations).toHaveLength(2);
});
it('should transform the minimum scene to save model schema v2', () => {
@@ -834,6 +833,50 @@ describe('getElementDatasource', () => {
});
});
describe('getVizPanelQueries', () => {
it('should handle panel query datasources correctly', () => {
const queryWithDS: SceneDataQuery = {
refId: 'B',
datasource: { uid: 'prometheus-uid', type: 'prometheus' },
};
const queryWithoutDS: SceneDataQuery = {
refId: 'A',
};
// Mock query runner
const queryRunner = new SceneQueryRunner({
queries: [queryWithoutDS, queryWithDS],
datasource: { uid: 'default-ds', type: 'default' },
});
// Create test elements
const vizPanel = new VizPanel({
key: 'panel-1',
pluginId: 'timeseries',
$data: queryRunner,
});
// Mock dsReferencesMapping
const dsReferencesMapping = {
panels: new Map(new Set([['panel-1', new Set<string>(['A'])]])),
variables: new Set<string>(),
annotations: new Set<string>(),
};
const result = getVizPanelQueries(vizPanel, dsReferencesMapping);
expect(result.length).toBe(2);
expect(result[0].spec.query.kind).toBe('DataQuery');
expect(result[0].spec.query.datasource).toBeUndefined(); // ignore datasource if it wasn't provided
expect(result[0].spec.query.group).toBe('default');
expect(result[0].spec.query.version).toBe('v0');
expect(result[1].spec.query.kind).toBe('DataQuery');
expect(result[1].spec.query.datasource?.name).toBe('prometheus-uid');
expect(result[1].spec.query.group).toBe('prometheus');
expect(result[1].spec.query.version).toBe('v0');
});
});
function getMinimalSceneState(body: DashboardLayoutManager): Partial<DashboardSceneState> {
return {
id: 1,
@@ -1065,18 +1108,6 @@ function createAnnotationLayers() {
isEnabled: true,
isHidden: true,
}),
// this could happen if a dahboard was created from code and the datasource was not defined
new DashboardAnnotationsDataLayer({
key: 'layer3',
query: {
name: 'query3',
enable: true,
iconColor: 'green',
},
name: 'layer3',
isEnabled: true,
isHidden: true,
}),
];
}
@@ -43,6 +43,7 @@ import {
DashboardCursorSync,
FieldConfig,
FieldColor,
defaultDataQueryKind,
} from '../../../../../packages/grafana-schema/src/schema/dashboard/v2alpha1/types.spec.gen';
import { DashboardDataLayerSet } from '../scene/DashboardDataLayerSet';
import { DashboardScene, DashboardSceneState } from '../scene/DashboardScene';
@@ -250,7 +251,7 @@ function getPanelLinks(panel: VizPanel): DataLink[] {
return [];
}
function getVizPanelQueries(vizPanel: VizPanel, dsReferencesMapping?: DSReferencesMapping): PanelQueryKind[] {
export function getVizPanelQueries(vizPanel: VizPanel, dsReferencesMapping?: DSReferencesMapping): PanelQueryKind[] {
const queries: PanelQueryKind[] = [];
const queryRunner = getQueryRunnerFor(vizPanel);
const vizPanelQueries = queryRunner?.state.queries;
@@ -258,12 +259,22 @@ function getVizPanelQueries(vizPanel: VizPanel, dsReferencesMapping?: DSReferenc
if (vizPanelQueries) {
vizPanelQueries.forEach((query) => {
const queryDatasource = getElementDatasource(vizPanel, query, 'panel', queryRunner, dsReferencesMapping);
const dataQuery: DataQueryKind = {
kind: getDataQueryKind(query, queryRunner),
kind: 'DataQuery',
version: defaultDataQueryKind().version,
group: getDataQueryKind(query, queryRunner),
datasource: {
name: queryDatasource?.uid,
},
spec: omit(query, 'datasource', 'refId', 'hide'),
};
if (!dataQuery.datasource?.name) {
delete dataQuery.datasource;
}
const querySpec: PanelQuerySpec = {
datasource: queryDatasource,
query: dataQuery,
refId: query.refId,
hidden: Boolean(query.hide),
@@ -407,18 +418,36 @@ function getAnnotations(state: DashboardSceneState, dsReferencesMapping?: DSRefe
if (!(layer instanceof dataLayers.AnnotationsDataLayer)) {
continue;
}
const datasource = getElementDatasource(layer, layer.state.query, 'annotation', undefined, dsReferencesMapping);
const layerDs = layer.state.query.datasource;
if (!layerDs) {
throw new Error('Misconfigured AnnotationsDataLayer: Datasource is required for annotations');
}
const result: AnnotationQueryKind = {
kind: 'AnnotationQuery',
spec: {
builtIn: Boolean(layer.state.query.builtIn),
name: layer.state.query.name,
datasource: getElementDatasource(layer, layer.state.query, 'annotation', undefined, dsReferencesMapping),
enable: Boolean(layer.state.isEnabled),
hide: Boolean(layer.state.isHidden),
iconColor: layer.state.query.iconColor,
query: {
kind: 'DataQuery',
version: defaultDataQueryKind().version,
group: layerDs.type!, // Annotation layer has a datasource type provided in runtime.
spec: {},
},
},
};
if (datasource) {
result.spec.query!.datasource = {
name: datasource.uid,
};
}
// Transform v1 dashboard (using target) to v2 structure
// adds extra condition to prioritize query over target
// if query is defined, use it
@@ -426,24 +455,37 @@ function getAnnotations(state: DashboardSceneState, dsReferencesMapping?: DSRefe
// Handle built-in annotations
if (layer.state.query.builtIn) {
result.spec.query = {
kind: 'grafana', // built-in annotations are always of type grafana
kind: 'DataQuery',
version: defaultDataQueryKind().version,
group: 'grafana', // built-in annotations are always of type grafana
spec: {
...layer.state.query.target,
},
};
} else {
result.spec.query = {
kind: getAnnotationQueryKind(layer.state.query),
kind: 'DataQuery',
version: defaultDataQueryKind().version,
group: datasource?.type!,
spec: {
...layer.state.query.target,
},
};
if (layer.state.query.datasource?.uid) {
result.spec.query.datasource = {
name: layer.state.query.datasource?.uid,
};
}
}
}
// For annotations without query.query defined (e.g., grafana annotations without tags)
else if (layer.state.query.query?.kind) {
result.spec.query = {
kind: layer.state.query.query.kind,
kind: 'DataQuery',
version: defaultDataQueryKind().version,
group: layer.state.query.query.group || getAnnotationQueryKind(layer.state.query),
datasource: layer.state.query.query.datasource,
spec: {
...layer.state.query.query.spec,
},
@@ -466,10 +508,15 @@ function getAnnotations(state: DashboardSceneState, dsReferencesMapping?: DSRefe
// Store extra properties in the legacyOptions field instead of directly in the spec
if (Object.keys(otherProps).length > 0) {
// Extract options property and get the rest of the properties
// // Extract options property and get the rest of the properties
const { legacyOptions, ...restProps } = otherProps;
// Merge options with the rest of the properties
result.spec.legacyOptions = { ...legacyOptions, ...restProps };
if (legacyOptions) {
// Merge options with the rest of the properties
result.spec.legacyOptions = { ...legacyOptions, ...restProps };
}
result.spec.query!.spec = {
...otherProps,
};
}
// If filter is an empty array, don't save it
@@ -5,6 +5,7 @@ import { locationService, reportInteraction } from '@grafana/runtime';
import {
AnnotationQueryKind,
Spec as DashboardV2Spec,
defaultDataQueryKind,
} from '@grafana/schema/dist/esm/schema/dashboard/v2alpha1/types.spec.gen';
import { Form } from 'app/core/components/Form/Form';
import { getDashboardAPI } from 'app/features/dashboard/api/dashboard_api';
@@ -16,6 +17,8 @@ import { ImportDashboardFormV2 } from './ImportDashboardFormV2';
const IMPORT_FINISHED_EVENT_NAME = 'dashboard_import_imported';
type FormData = SaveDashboardCommand<DashboardV2Spec> & { [key: `datasource-${string}`]: string };
export function ImportDashboardOverviewV2() {
const [uidReset, setUidReset] = useState(false);
const dispatch = useDispatch();
@@ -34,24 +37,29 @@ export function ImportDashboardOverviewV2() {
dispatch(clearLoadedDashboard());
}
async function onSubmit(form: SaveDashboardCommand<DashboardV2Spec>) {
async function onSubmit(form: FormData) {
reportInteraction(IMPORT_FINISHED_EVENT_NAME);
const dashboardWithDataSources: DashboardV2Spec = {
...dashboard,
title: form.dashboard.title,
annotations: dashboard.annotations?.map((annotation: AnnotationQueryKind) => {
if (annotation.spec.query?.kind) {
const dsType = annotation.spec.query.kind;
const dsType = annotation.spec.query?.spec.group;
if (dsType) {
if (form[`datasource-${dsType}` as keyof typeof form]) {
const ds = form[`datasource-${dsType}` as keyof typeof form] as { uid: string; type: string };
return {
...annotation,
spec: {
...annotation.spec,
datasource: {
uid: ds.uid,
type: ds.type,
query: {
kind: 'DataQuery',
group: dsType,
version: defaultDataQueryKind().version,
datasource: { name: ds.uid },
spec: {
...annotation.spec.query?.spec,
},
},
},
};
@@ -61,18 +69,23 @@ export function ImportDashboardOverviewV2() {
}),
variables: dashboard.variables?.map((variable) => {
if (variable.kind === 'QueryVariable') {
if (variable.spec.query?.kind) {
const dsType = variable.spec.query.kind;
const dsType = variable.spec.query?.spec.group;
if (dsType) {
if (form[`datasource-${dsType}` as keyof typeof form]) {
const ds = form[`datasource-${dsType}` as keyof typeof form] as { uid: string; type: string };
return {
...variable,
spec: {
...variable.spec,
datasource: {
...variable.spec.datasource,
uid: ds.uid,
type: ds.type,
query: {
...variable.spec.query,
spec: {
...variable.spec.query.spec,
group: ds.type,
datasource: {
name: ds.uid,
},
},
},
options: [],
current: {
@@ -157,7 +170,7 @@ export function ImportDashboardOverviewV2() {
return (
<>
<Form<SaveDashboardCommand<DashboardV2Spec> & { [key: `datasource-${string}`]: string }>
<Form<FormData>
onSubmit={onSubmit}
defaultValues={{ dashboard, k8s: { annotations: { 'grafana.app/folder': folder.uid } } }}
validateOnMount
@@ -52,7 +52,8 @@ export function validateVariable<
expect(sceneVariable?.state.pluginId).toBe(variableKind.spec.pluginId);
}
if (sceneVariable instanceof QueryVariable && variableKind.kind === 'QueryVariable') {
expect(sceneVariable?.state.datasource).toBe(variableKind.spec.datasource);
expect(sceneVariable?.state.datasource?.type).toBe(variableKind.spec.query?.group);
expect(sceneVariable?.state.datasource?.uid).toBe(variableKind.spec.query?.datasource?.name);
expect(sceneVariable?.state.query).toEqual(variableKind.spec.query.spec);
}
if (sceneVariable instanceof CustomVariable && variableKind.kind === 'CustomVariable') {
@@ -2,6 +2,7 @@ import { AnnotationQuery, DataQuery, VariableModel, VariableRefresh, Panel } fro
import { handyTestingSchema } from '@grafana/schema/dist/esm/schema/dashboard/v2_examples';
import {
Spec as DashboardV2Spec,
defaultDataQueryKind,
GridLayoutItemKind,
GridLayoutKind,
PanelKind,
@@ -466,10 +467,14 @@ describe('ResponseTransformers', () => {
{
kind: 'PanelQuery',
spec: {
datasource: 'datasource1',
hidden: false,
query: {
kind: 'prometheus',
kind: 'DataQuery',
version: defaultDataQueryKind().version,
group: 'prometheus',
datasource: {
name: 'datasource1',
},
spec: {
expr: 'test-query',
},
@@ -973,11 +978,9 @@ describe('ResponseTransformers', () => {
result.forEach((query) => {
expect(query.kind).toBe('PanelQuery');
expect(query.spec.datasource).toEqual({
type: 'theoretical-ds',
uid: 'theoretical-uid',
});
expect(query.spec.query.kind).toBe('theoretical-ds');
expect(query.spec.query.group).toEqual('theoretical-ds');
expect(query.spec.query.datasource?.name).toEqual('theoretical-uid');
expect(query.spec.query.kind).toBe('DataQuery');
});
});
@@ -1003,11 +1006,9 @@ describe('ResponseTransformers', () => {
result.forEach((query) => {
expect(query.kind).toBe('PanelQuery');
expect(query.spec.datasource).toEqual({
type: 'theoretical-ds',
uid: 'theoretical-uid',
});
expect(query.spec.query.kind).toBe('theoretical-ds');
expect(query.spec.query.group).toEqual('theoretical-ds');
expect(query.spec.query.datasource?.name).toEqual('theoretical-uid');
expect(query.spec.query.kind).toBe('DataQuery');
});
});
});
@@ -1017,7 +1018,8 @@ describe('ResponseTransformers', () => {
const { spec: v2Spec } = v2;
expect(v1.name).toBe(v2Spec.name);
expect(v1.datasource).toBe(v2Spec.datasource);
expect(v1.datasource?.type).toBe(v2Spec.query?.spec.group);
expect(v1.datasource?.uid).toBe(v2Spec.query?.spec.datasource?.name);
expect(v1.enable).toBe(v2Spec.enable);
expect(v1.hide).toBe(v2Spec.hide);
expect(v1.iconColor).toBe(v2Spec.iconColor);
@@ -1043,7 +1045,10 @@ describe('ResponseTransformers', () => {
return {
refId: q.spec.refId,
hide: q.spec.hidden,
datasource: q.spec.datasource,
datasource: {
type: q.spec.query.spec.group,
uid: q.spec.query.spec.datasource?.uid,
},
...q.spec.query.spec,
};
})
@@ -1093,18 +1098,24 @@ describe('ResponseTransformers', () => {
};
expect(v2Common).toEqual(v1Common);
if (v2.kind === 'QueryVariable') {
expect(v2.spec.datasource).toEqual(v1.datasource);
if (typeof v1.query === 'string') {
expect(v2.spec.query.spec[LEGACY_STRING_VALUE_KEY]).toEqual(v1.query);
} else {
expect(v2.spec.query).toEqual({
kind: v1.datasource?.type,
spec: {
...(typeof v1.query === 'object' ? v1.query : {}),
expect(v2.spec.query).toMatchObject({
kind: 'DataQuery',
version: defaultDataQueryKind().version,
group: (v1.datasource?.type || getDefaultDataSourceRef()?.type) ?? 'grafana',
...(v1.datasource?.uid && {
datasource: {
name: v1.datasource?.uid,
},
}),
});
if (typeof v1.query === 'string') {
expect(v2.spec.query.spec).toEqual({
[LEGACY_STRING_VALUE_KEY]: v1.query,
});
} else {
expect(v2.spec.query.spec).toEqual({
...(typeof v1.query === 'object' ? v1.query : {}),
});
}
}
@@ -38,6 +38,7 @@ import {
LibraryPanelKind,
PanelKind,
GridLayoutItemKind,
defaultDataQueryKind,
RowsLayoutRowKind,
GridLayoutKind,
} from '@grafana/schema/dist/esm/schema/dashboard/v2alpha1/types.spec.gen';
@@ -502,9 +503,13 @@ export function getPanelQueries(targets: DataQuery[], panelDatasource: DataSourc
spec: {
refId: t.refId,
hidden: t.hide ?? false,
datasource: t.datasource ? t.datasource : panelDatasource,
query: {
kind: t.datasource?.type || panelDatasource.type!,
kind: 'DataQuery',
version: defaultDataQueryKind().version,
group: t.datasource?.type || panelDatasource.type!,
datasource: {
name: t.datasource?.uid || panelDatasource.uid!,
},
spec: {
...query,
},
@@ -568,7 +573,12 @@ function getVariables(vars: TypedVariableModel[]): DashboardV2Spec['variables']
regex: v.regex || '',
sort: transformSortVariableToEnum(v.sort),
query: {
kind: v.datasource?.type || getDefaultDatasourceType(),
kind: 'DataQuery',
version: defaultDataQueryKind().version,
group: v.datasource?.type ?? getDefaultDatasourceType(),
datasource: {
name: v.datasource?.uid,
},
spec: query,
},
allowCustomValue: v.allowCustomValue ?? true,
@@ -722,7 +732,12 @@ function getAnnotations(annotations: AnnotationQuery[]): DashboardV2Spec['annota
iconColor: a.iconColor,
builtIn: Boolean(a.builtIn),
query: {
kind: a.datasource?.type || getDefaultDatasourceType(),
kind: 'DataQuery',
version: defaultDataQueryKind().version,
group: a.datasource?.type || getDefaultDatasourceType(),
datasource: {
name: a.datasource?.uid,
},
spec: {
...a.target,
},
@@ -757,7 +772,10 @@ function getVariablesV1(vars: DashboardV2Spec['variables']): VariableModel[] {
LEGACY_STRING_VALUE_KEY in v.spec.query.spec
? v.spec.query.spec[LEGACY_STRING_VALUE_KEY]
: v.spec.query.spec,
datasource: v.spec.datasource,
datasource: {
type: v.spec.query?.spec.group,
uid: v.spec.query?.spec.datasource?.name,
},
sort: transformSortVariableToEnumV1(v.spec.sort),
refresh: transformVariableRefreshToEnumV1(v.spec.refresh),
regex: v.spec.regex,
@@ -879,7 +897,10 @@ function getAnnotationsV1(annotations: DashboardV2Spec['annotations']): Annotati
return annotations.map((a) => {
return {
name: a.spec.name,
datasource: a.spec.datasource,
datasource: {
type: a.spec.query?.spec.group,
uid: a.spec.query?.spec.datasource?.name,
},
enable: a.spec.enable,
hide: a.spec.hide,
iconColor: a.spec.iconColor,
@@ -950,7 +971,10 @@ function transformV2PanelToV1Panel(
return {
refId: q.spec.refId,
hide: q.spec.hidden,
datasource: q.spec.datasource,
datasource: {
uid: q.spec.query.spec.datasource?.uid,
type: q.spec.query.spec.group,
},
...q.spec.query.spec,
};
}),
+1
View File
@@ -128,6 +128,7 @@ export class K8sDashboardAPI implements DashboardAPI<DashboardDTO, Dashboard> {
uid: dash.metadata.name,
k8s: dash.metadata,
version: dash.metadata.generation,
created: dash.metadata.creationTimestamp,
},
dashboard: {
...dash.spec,
@@ -33,6 +33,7 @@ const dashMock: DashboardDTO = {
},
meta: {
canEdit: false,
created: 'Friday, 4 July 2025 07:56:41 GMT+05:30',
},
};
@@ -11,16 +11,19 @@ import { NumberInput } from 'app/core/components/OptionsUI/NumberInput';
import { validateScaleOptions, validateScaleConfig } from '../scale';
import { ScaleDimensionOptions } from '../types';
const fixedValueOption: SelectableValue<string> = {
label: 'Fixed value',
value: '_____fixed_____',
};
export const ScaleDimensionEditor = (props: StandardEditorProps<ScaleDimensionConfig, ScaleDimensionOptions>) => {
const { value, context, onChange, item } = props;
const { settings } = item;
const styles = useStyles2(getStyles);
const fixedValueOption: SelectableValue<string> = useMemo(
() => ({
label: t('dimensions.scale-dimension-editor.fixed-value-option.label.fixed-value', 'Fixed value'),
value: '_____fixed_____',
}),
[]
);
const fieldName = value?.field;
const isFixed = Boolean(!fieldName);
const names = useFieldDisplayNames(context.data);
@@ -53,7 +56,7 @@ export const ScaleDimensionEditor = (props: StandardEditorProps<ScaleDimensionCo
});
}
},
[validateAndDoChange, value]
[validateAndDoChange, value, fixedValueOption.value]
);
const onMinChange = useCallback(
@@ -1,4 +1,5 @@
import { Field, FieldType, PanelOptionsEditorBuilder, DataFrame } from '@grafana/data';
import { t } from '@grafana/i18n';
import { FrameGeometrySource, FrameGeometrySourceMode } from '@grafana/schema';
import { GazetteerPathEditor } from 'app/features/geo/editor/GazetteerPathEditor';
@@ -14,7 +15,7 @@ export function addLocationFields<TOptions>(
builder.addCustomEditor({
id: 'modeEditor',
path: `${prefix}mode`,
name: 'Location Mode',
name: t('geo.location-editor.name-location-mode', 'Location Mode'),
editor: LocationModeEditor,
settings: { data, source },
});
@@ -25,18 +26,18 @@ export function addLocationFields<TOptions>(
builder
.addFieldNamePicker({
path: `${prefix}latitude`,
name: 'Latitude field',
name: t('geo.location-editor.name-latitude-field', 'Latitude field'),
settings: {
filter: (f: Field) => f.type === FieldType.number,
noFieldsMessage: 'No numeric fields found',
noFieldsMessage: t('geo.location-editor.latitude-field.no-fields-message', 'No numeric fields found'),
},
})
.addFieldNamePicker({
path: `${prefix}longitude`,
name: 'Longitude field',
name: t('geo.location-editor.name-longitude-field', 'Longitude field'),
settings: {
filter: (f: Field) => f.type === FieldType.number,
noFieldsMessage: 'No numeric fields found',
noFieldsMessage: t('geo.location-editor.longitude-field.no-fields-message', 'No numeric fields found'),
},
});
break;
@@ -44,10 +45,10 @@ export function addLocationFields<TOptions>(
case FrameGeometrySourceMode.Geohash:
builder.addFieldNamePicker({
path: `${prefix}geohash`,
name: 'Geohash field',
name: t('geo.location-editor.name-geohash-field', 'Geohash field'),
settings: {
filter: (f: Field) => f.type === FieldType.string,
noFieldsMessage: 'No strings fields found',
noFieldsMessage: t('geo.location-editor.geohash-field.no-fields-message', 'No strings fields found'),
},
});
break;
@@ -56,16 +57,16 @@ export function addLocationFields<TOptions>(
builder
.addFieldNamePicker({
path: `${prefix}lookup`,
name: 'Lookup field',
name: t('geo.location-editor.name-lookup-field', 'Lookup field'),
settings: {
filter: (f: Field) => f.type === FieldType.string,
noFieldsMessage: 'No strings fields found',
noFieldsMessage: t('geo.location-editor.lookup-field.no-fields-message', 'No strings fields found'),
},
})
.addCustomEditor({
id: 'gazetteer',
path: `${prefix}gazetteer`,
name: 'Gazetteer',
name: t('geo.location-editor.name-gazetteer', 'Gazetteer'),
editor: GazetteerPathEditor,
});
}
@@ -3,38 +3,12 @@ import { useEffect, useState } from 'react';
import { StandardEditorProps, DataFrame, GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { t } from '@grafana/i18n';
import { FrameGeometrySource, FrameGeometrySourceMode } from '@grafana/schema';
import { Alert, HorizontalGroup, Icon, Select, useStyles2 } from '@grafana/ui';
import { FrameGeometryField, getGeometryField, getLocationMatchers } from '../utils/location';
const MODE_OPTIONS = [
{
value: FrameGeometrySourceMode.Auto,
label: 'Auto',
ariaLabel: selectors.components.Transforms.SpatialOperations.location.autoOption,
description: 'Automatically identify location data based on default field names',
},
{
value: FrameGeometrySourceMode.Coords,
label: 'Coords',
ariaLabel: selectors.components.Transforms.SpatialOperations.location.coords.option,
description: 'Specify latitude and longitude fields',
},
{
value: FrameGeometrySourceMode.Geohash,
label: 'Geohash',
ariaLabel: selectors.components.Transforms.SpatialOperations.location.geohash.option,
description: 'Specify geohash field',
},
{
value: FrameGeometrySourceMode.Lookup,
label: 'Lookup',
ariaLabel: selectors.components.Transforms.SpatialOperations.location.lookup.option,
description: 'Specify Gazetteer and lookup field',
},
];
interface ModeEditorSettings {
data?: DataFrame[];
source?: FrameGeometrySource;
@@ -50,6 +24,39 @@ export const LocationModeEditor = ({
}: StandardEditorProps<string, ModeEditorSettings, unknown, unknown>) => {
const [info, setInfo] = useState<FrameGeometryField>();
const MODE_OPTIONS = [
{
value: FrameGeometrySourceMode.Auto,
label: t('geo.location-more-editor.mode-options.label-auto', 'Auto'),
ariaLabel: selectors.components.Transforms.SpatialOperations.location.autoOption,
description: t(
'geo.location-more-editor.mode-options.description-auto',
'Automatically identify location data based on default field names'
),
},
{
value: FrameGeometrySourceMode.Coords,
label: t('geo.location-more-editor.mode-options.label-coords', 'Coords'),
ariaLabel: selectors.components.Transforms.SpatialOperations.location.coords.option,
description: t(
'geo.location-more-editor.mode-options.description-coords',
'Specify latitude and longitude fields'
),
},
{
value: FrameGeometrySourceMode.Geohash,
label: t('geo.location-more-editor.mode-options.label-geohash', 'Geohash'),
ariaLabel: selectors.components.Transforms.SpatialOperations.location.geohash.option,
description: t('geo.location-more-editor.mode-options.description-geohash', 'Specify geohash field'),
},
{
value: FrameGeometrySourceMode.Lookup,
label: t('geo.location-more-editor.mode-options.label-lookup', 'Lookup'),
ariaLabel: selectors.components.Transforms.SpatialOperations.location.lookup.option,
description: t('geo.location-more-editor.mode-options.description-lookup', 'Specify Gazetteer and lookup field'),
},
];
useEffect(() => {
if (item.settings?.source && item.settings?.data?.length && item.settings.data[0]) {
getLocationMatchers(item.settings.source).then((location) => {
+7 -6
View File
@@ -9,6 +9,7 @@ import {
getFieldDisplayName,
FieldType,
} from '@grafana/data';
import { t } from '@grafana/i18n';
import { FrameGeometrySource, FrameGeometrySourceMode } from '@grafana/schema';
import { getGeoFieldFromGazetteer, pointFieldFromGeohash, pointFieldFromLonLat } from '../format/utils';
@@ -178,7 +179,7 @@ export function getGeometryField(frame: DataFrame, location: LocationFieldMatche
};
}
return {
warning: 'Unable to find location fields',
warning: t('geo.get-geometry-field.warning-unable-to-find', 'Unable to find location fields'),
};
case FrameGeometrySourceMode.Coords:
@@ -190,7 +191,7 @@ export function getGeometryField(frame: DataFrame, location: LocationFieldMatche
};
}
return {
warning: 'Select latitude/longitude fields',
warning: t('geo.get-geometry-field.warning-select-lat-long', 'Select latitude/longitude fields'),
};
case FrameGeometrySourceMode.Geohash:
@@ -202,7 +203,7 @@ export function getGeometryField(frame: DataFrame, location: LocationFieldMatche
};
}
return {
warning: 'Select geohash field',
warning: t('geo.get-geometry-field.warning-select-geohash', 'Select geohash field'),
};
case FrameGeometrySourceMode.Lookup:
@@ -215,13 +216,13 @@ export function getGeometryField(frame: DataFrame, location: LocationFieldMatche
};
}
return {
warning: 'Gazetteer not found',
warning: t('geo.get-geometry-field.warning-gazetteer-not-found', 'Gazetteer not found'),
};
}
return {
warning: 'Select lookup field',
warning: t('geo.get-geometry-field.warning-select-lookup', 'Select lookup field'),
};
}
return { warning: 'unable to find geometry' };
return { warning: t('geo.get-geometry-field.warning-no-geometry', 'unable to find geometry') };
}
@@ -7,6 +7,7 @@ import {
defaultSpec as defaultDashboardV2Spec,
defaultPanelSpec,
defaultQueryVariableSpec,
defaultDataQueryKind,
} from '@grafana/schema/dist/esm/schema/dashboard/v2alpha1/types.spec.gen';
import { browseDashboardsAPI } from 'app/features/browse-dashboards/api/browseDashboardsAPI';
import { getLibraryPanel } from 'app/features/library-panels/state/api';
@@ -836,7 +837,9 @@ describe('processV2Datasources', () => {
refId: 'A',
hidden: false,
query: {
kind: 'prometheus',
kind: 'DataQuery',
version: defaultDataQueryKind().version,
group: 'prometheus',
spec: {
expr: 'access_evaluation_duration_count',
range: true,
@@ -862,7 +865,9 @@ describe('processV2Datasources', () => {
...defaultQueryVariableSpec(),
name: 'var1',
query: {
kind: 'loki',
kind: 'DataQuery',
version: defaultDataQueryKind().version,
group: 'loki',
spec: {
expr: 'access_evaluation_duration_count',
range: true,
@@ -880,7 +885,9 @@ describe('processV2Datasources', () => {
hide: false,
iconColor: 'red',
query: {
kind: 'loki',
kind: 'DataQuery',
version: defaultDataQueryKind().version,
group: 'loki',
spec: {
expr: 'access_evaluation_duration_count',
range: true,
@@ -982,13 +989,17 @@ describe('processV2DatasourceInput', () => {
...defaultQueryVariableSpec(),
name: 'var2WithGrafanaDs',
query: {
kind: 'grafana',
kind: 'DataQuery' as const,
version: defaultDataQueryKind().version,
group: 'grafana',
spec: {
panelId: 2,
expr: 'access_evaluation_duration_count',
range: true,
},
},
},
};
const result = await processV2DatasourceInput(queryVariable.spec, {});
expect(result).toEqual({});
});
@@ -1001,7 +1012,9 @@ describe('processV2DatasourceInput', () => {
refId: 'A',
hidden: false,
query: {
kind: 'datasource',
kind: 'DataQuery' as const,
version: defaultDataQueryKind().version,
group: 'datasource',
spec: {
panelId: 2,
},
@@ -167,6 +167,7 @@ export function processV2Datasources(dashboard: DashboardV2Spec): ThunkResult<vo
if (element.kind !== 'Panel') {
throw new Error('Only panels are currenlty supported in v2 dashboards');
}
if (element.spec.data.spec.queries.length > 0) {
for (const query of element.spec.data.spec.queries) {
inputs = await processV2DatasourceInput(query.spec, inputs);
@@ -331,43 +332,43 @@ export function getFolderByUid(uid: string): Promise<{ uid: string; title: strin
}
export async function processV2DatasourceInput(
obj: PanelQueryKind['spec'] | QueryVariableKind['spec'] | AnnotationQueryKind['spec'],
spec: PanelQueryKind['spec'] | QueryVariableKind['spec'] | AnnotationQueryKind['spec'],
inputs: Record<string, DataSourceInput> = {}
) {
const datasourceRef = obj?.datasource;
if (!datasourceRef && obj?.query) {
const dsType = obj.query.kind;
const datasourceRef = spec.query.datasource;
let dataSourceInput: DataSourceInput | undefined;
const dsType = spec.query.group;
if (!datasourceRef) {
// if dsType is grafana, it means we are using a built-in annotation or default grafana datasource, in those
// cases we don't need to map it
// "datasource" type is what we call "--Dashboard--" datasource <.-.>
if (dsType === 'grafana' || dsType === 'datasource') {
return inputs;
}
const datasource = await getDatasourceSrv().get({ type: dsType });
let dataSourceInput: DataSourceInput | undefined;
if (datasource) {
dataSourceInput = {
name: datasource.name,
label: datasource.name,
info: `Select a ${datasource.name} data source`,
value: datasource.uid,
type: InputType.DataSource,
pluginId: datasource.meta?.id,
};
}
inputs[datasource.meta?.id] = dataSourceInput;
} else {
dataSourceInput = {
name: dsType,
label: dsType,
info: `No data sources of type ${dsType} found`,
value: '',
type: InputType.DataSource,
pluginId: dsType,
};
inputs[dsType] = dataSourceInput;
}
const datasource = await getDatasourceSrv().get({ type: dsType });
if (datasource) {
dataSourceInput = {
name: datasource.name,
label: datasource.name,
info: `Select a ${datasource.name} data source`,
value: datasource.uid,
type: InputType.DataSource,
pluginId: datasource.meta?.id,
};
inputs[datasource.meta?.id] = dataSourceInput;
} else {
dataSourceInput = {
name: dsType,
label: dsType,
info: `No data sources of type ${dsType} found`,
value: '',
type: InputType.DataSource,
pluginId: dsType,
};
inputs[dsType] = dataSourceInput;
}
return inputs;
}
@@ -16,7 +16,7 @@ import {
} from '@grafana/data';
import { Trans, t } from '@grafana/i18n';
import { config, locationSearchToObject } from '@grafana/runtime';
import { Alert } from '@grafana/ui';
import { Alert, ErrorWithStack } from '@grafana/ui';
import { Page } from 'app/core/components/Page/Page';
import PageLoader from 'app/core/components/PageLoader/PageLoader';
import { EntityNotFound } from 'app/core/components/PageNotFound/EntityNotFound';
@@ -36,6 +36,7 @@ import { getPluginSettings } from '../pluginSettings';
import { importAppPlugin } from '../plugin_loader';
import { buildPluginSectionNav, pluginsLogger } from '../utils';
import { PluginErrorBoundary } from './PluginErrorBoundary';
import { buildPluginPageContext, PluginPageContext } from './PluginPageContext';
interface Props {
@@ -106,22 +107,32 @@ export function AppRootPage({ pluginId, pluginNavSection }: Props) {
const pluginRoot = plugin.root && (
<PluginContextProvider meta={plugin.meta}>
<ExtensionRegistriesProvider
registries={{
addedLinksRegistry: addedLinksRegistry.readOnly(),
addedComponentsRegistry: addedComponentsRegistry.readOnly(),
exposedComponentsRegistry: exposedComponentsRegistry.readOnly(),
addedFunctionsRegistry: addedFunctionsRegistry.readOnly(),
}}
<PluginErrorBoundary
fallback={({ error, errorInfo }) => (
<ErrorWithStack
title={t('plugins.app-root-page.error-loading-plugin', 'Plugin failed to load')}
error={error}
errorInfo={errorInfo}
/>
)}
>
<plugin.root
meta={plugin.meta}
basename={location.pathname}
onNavChanged={onNavChanged}
query={queryParams}
path={location.pathname}
/>
</ExtensionRegistriesProvider>
<ExtensionRegistriesProvider
registries={{
addedLinksRegistry: addedLinksRegistry.readOnly(),
addedComponentsRegistry: addedComponentsRegistry.readOnly(),
exposedComponentsRegistry: exposedComponentsRegistry.readOnly(),
addedFunctionsRegistry: addedFunctionsRegistry.readOnly(),
}}
>
<plugin.root
meta={plugin.meta}
basename={location.pathname}
onNavChanged={onNavChanged}
query={queryParams}
path={location.pathname}
/>
</ExtensionRegistriesProvider>
</PluginErrorBoundary>
</PluginContextProvider>
);
@@ -0,0 +1,184 @@
import { render, screen } from '@testing-library/react';
import * as React from 'react';
import { PluginMeta, PluginType, PluginContext } from '@grafana/data';
import { getMockPlugin } from '@grafana/data/test';
import { PluginErrorBoundary } from './PluginErrorBoundary';
const ThrowingComponent = ({ shouldThrow }: { shouldThrow: boolean }) => {
if (shouldThrow) {
throw new Error('Test error message');
}
return <div>Working component</div>;
};
const TestFallback = ({ error, errorInfo }: { error: Error | null; errorInfo: React.ErrorInfo | null }) => (
<div>
<div>Fallback rendered</div>
<div>Error: {error?.message}</div>
{errorInfo && <div>Error info available</div>}
</div>
);
const renderWithPluginContext = ({
children,
pluginMeta,
fallback,
onError,
}: {
children: React.ReactNode;
pluginMeta?: PluginMeta;
fallback?: React.ComponentType<{ error: Error | null; errorInfo: React.ErrorInfo | null }>;
onError?: (error: Error, info: React.ErrorInfo) => void;
}) => {
const mockPluginMeta = pluginMeta || getMockPlugin({ id: 'test-plugin', type: PluginType.panel });
return render(
<PluginContext.Provider value={{ meta: mockPluginMeta }}>
<PluginErrorBoundary fallback={fallback} onError={onError}>
{children}
</PluginErrorBoundary>
</PluginContext.Provider>
);
};
describe('PluginErrorBoundary', () => {
let consoleErrorSpy: jest.SpyInstance;
beforeEach(() => {
consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
});
afterEach(() => {
consoleErrorSpy.mockRestore();
});
it('should render children normally when no error occurs', () => {
renderWithPluginContext({ children: <ThrowingComponent shouldThrow={false} /> });
expect(screen.getByText('Working component')).toBeInTheDocument();
});
it('should render null when an error occurs and no fallback is provided', () => {
const { container } = renderWithPluginContext({ children: <ThrowingComponent shouldThrow={true} /> });
expect(container.firstChild).toBeNull();
});
it('should render custom fallback component when an error occurs', () => {
renderWithPluginContext({ children: <ThrowingComponent shouldThrow={true} />, fallback: TestFallback });
expect(screen.getByText('Fallback rendered')).toBeInTheDocument();
expect(screen.getByText('Error: Test error message')).toBeInTheDocument();
expect(screen.getByText('Error info available')).toBeInTheDocument();
});
it('should call onError callback when an error occurs', () => {
const onErrorMock = jest.fn();
renderWithPluginContext({ children: <ThrowingComponent shouldThrow={true} />, onError: onErrorMock });
expect(onErrorMock).toHaveBeenCalledTimes(1);
expect(onErrorMock).toHaveBeenCalledWith(
expect.objectContaining({ message: 'Test error message' }),
expect.objectContaining({
componentStack: expect.any(String),
})
);
});
it('should log error to console with plugin ID when no onError callback is provided', () => {
const mockPluginMeta = getMockPlugin({ id: 'my-test-plugin', type: PluginType.datasource });
renderWithPluginContext({ children: <ThrowingComponent shouldThrow={true} />, pluginMeta: mockPluginMeta });
expect(consoleErrorSpy).toHaveBeenCalledWith(
'Plugin "my-test-plugin" failed to load:',
expect.objectContaining({ message: 'Test error message' }),
expect.objectContaining({
componentStack: expect.any(String),
})
);
});
it('should handle error when plugin context is not available', () => {
render(
<PluginErrorBoundary>
<ThrowingComponent shouldThrow={true} />
</PluginErrorBoundary>
);
expect(consoleErrorSpy).toHaveBeenCalledWith(
'Plugin "undefined" failed to load:',
expect.objectContaining({ message: 'Test error message' }),
expect.objectContaining({
componentStack: expect.any(String),
})
);
});
it('should update state correctly when error occurs', () => {
renderWithPluginContext({ children: <ThrowingComponent shouldThrow={true} />, fallback: TestFallback });
// Verify that both error and errorInfo are available in the fallback
expect(screen.getByText('Error: Test error message')).toBeInTheDocument();
expect(screen.getByText('Error info available')).toBeInTheDocument();
});
it('should reset error state when children change to non-throwing component', () => {
const { rerender } = renderWithPluginContext({
children: <ThrowingComponent shouldThrow={true} />,
fallback: TestFallback,
});
// Initially should show fallback
expect(screen.getByText('Fallback rendered')).toBeInTheDocument();
// Re-render with non-throwing component
rerender(
<PluginContext.Provider value={{ meta: getMockPlugin({ id: 'test-plugin', type: PluginType.panel }) }}>
<PluginErrorBoundary fallback={TestFallback}>
<ThrowingComponent shouldThrow={false} />
</PluginErrorBoundary>
</PluginContext.Provider>
);
// Should still show fallback since error boundary doesn't reset automatically
expect(screen.getByText('Fallback rendered')).toBeInTheDocument();
});
it('should handle multiple children correctly', () => {
renderWithPluginContext({
children: (
<>
<div>First child</div>
<ThrowingComponent shouldThrow={false} />
<div>Third child</div>
</>
),
});
expect(screen.getByText('First child')).toBeInTheDocument();
expect(screen.getByText('Working component')).toBeInTheDocument();
expect(screen.getByText('Third child')).toBeInTheDocument();
});
it('should handle error in one of multiple children', () => {
renderWithPluginContext({
children: (
<>
<div>First child</div>
<ThrowingComponent shouldThrow={true} />
<div>Third child</div>
</>
),
fallback: TestFallback,
});
// Should show fallback and not render any of the children
expect(screen.getByText('Fallback rendered')).toBeInTheDocument();
expect(screen.queryByText('First child')).not.toBeInTheDocument();
expect(screen.queryByText('Third child')).not.toBeInTheDocument();
});
});
@@ -0,0 +1,49 @@
import * as React from 'react';
import { PluginContext } from '@grafana/data';
interface PluginErrorBoundaryProps {
children: React.ReactNode;
fallback?: React.ComponentType<{ error: Error | null; errorInfo: React.ErrorInfo | null }>;
onError?: (error: Error, info: React.ErrorInfo) => void;
}
interface PluginErrorBoundaryState {
hasError: boolean;
error: Error | null;
errorInfo: React.ErrorInfo | null;
}
export class PluginErrorBoundary extends React.Component<PluginErrorBoundaryProps, PluginErrorBoundaryState> {
static contextType = PluginContext;
declare context: React.ContextType<typeof PluginContext>;
constructor(props: PluginErrorBoundaryProps) {
super(props);
this.state = { hasError: false, error: null, errorInfo: null };
}
static getDerivedStateFromError(error: Error): PluginErrorBoundaryState {
return { hasError: true, error: error, errorInfo: null };
}
componentDidCatch(error: Error, info: React.ErrorInfo) {
if (this.props.onError) {
this.props.onError(error, info);
} else {
console.error(`Plugin "${this.context?.meta.id}" failed to load:`, error, info);
}
this.setState({ error, errorInfo: info });
}
render() {
const Fallback = this.props.fallback;
if (this.state.hasError) {
return Fallback ? <Fallback error={this.state.error} errorInfo={this.state.errorInfo} /> : null;
}
return this.props.children;
}
}
@@ -0,0 +1,20 @@
import { t } from '@grafana/i18n';
import { Alert } from '@grafana/ui';
export const ExtensionErrorAlert = ({ pluginId, extensionTitle }: { pluginId: string; extensionTitle: string }) => {
return (
<Alert
title={t(
'plugins.extensions.extension-error-alert-title',
'Extension failed to load: "{{pluginId}}/{{extensionTitle}}"',
{
pluginId,
extensionTitle,
}
)}
severity="error"
>
{t('plugins.extensions.extension-error-alert-description', 'Check the console for more details on the error.')}
</Alert>
);
};
@@ -0,0 +1,42 @@
import * as React from 'react';
import { PluginErrorBoundary } from '../components/PluginErrorBoundary';
import { ExtensionErrorAlert } from './ExtensionErrorAlert';
import { ExtensionsLog, log as baseLog } from './logs/log';
import { isGrafanaDevMode } from './utils';
export const ExtensionErrorBoundary = ({
children,
pluginId,
extensionTitle,
log = baseLog,
fallbackAlwaysVisible = false,
}: {
children: React.ReactNode;
pluginId: string;
extensionTitle: string;
log?: ExtensionsLog;
fallbackAlwaysVisible?: boolean;
}) => {
return (
<PluginErrorBoundary
onError={(error, errorInfo) => {
log.error(`Extension "${pluginId}/${extensionTitle}" failed to load.`, {
message: error.message,
componentStack: errorInfo.componentStack ?? '',
digest: errorInfo.digest ?? '',
});
}}
fallback={() => {
if (isGrafanaDevMode() || fallbackAlwaysVisible) {
return <ExtensionErrorAlert pluginId={pluginId} extensionTitle={extensionTitle} />;
}
return null;
}}
>
{children}
</PluginErrorBoundary>
);
};
@@ -172,7 +172,12 @@ export const getPluginExtensions: GetExtensions = ({
pluginId: addedComponent.pluginId,
title: addedComponent.title,
description: addedComponent.description ?? '',
component: wrapWithPluginContext(addedComponent.pluginId, addedComponent.component, componentLog),
component: wrapWithPluginContext({
pluginId: addedComponent.pluginId,
extensionTitle: addedComponent.title,
Component: addedComponent.component,
log: componentLog,
}),
};
extensions.push(extension);

Some files were not shown because too many files have changed in this diff Show More