Merge remote-tracking branch 'origin/main' into grafana-git-ui-sync

This commit is contained in:
Mariell Hoversholm committed 2025-01-17 10:26:39 +01:00
commit f06b5a5933
150 files changed
+3478 -1498

No files matched your search

+5 -6
View File
@@ -830,7 +830,8 @@ exports[`better eslint`] = {
],
"packages/grafana-ui/src/components/Table/types.ts:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
[0, 0, 0, "Unexpected any. Specify a different type.", "1"]
[0, 0, 0, "Unexpected any. Specify a different type.", "1"],
[0, 0, 0, "Unexpected any. Specify a different type.", "2"]
],
"packages/grafana-ui/src/components/Table/utils.ts:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
@@ -4827,7 +4828,9 @@ exports[`better eslint`] = {
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "2"]
],
"public/app/features/explore/PrometheusListView/RawListItem.tsx:5381": [
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"]
[0, 0, 0, "No untranslated strings in text props. Wrap text with <Trans /> or use t()", "0"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "1"],
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "2"]
],
"public/app/features/explore/PrometheusListView/RawListItemAttributes.tsx:5381": [
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "0"],
@@ -7480,10 +7483,6 @@ exports[`better eslint`] = {
[0, 0, 0, "Do not use any type assertions.", "1"],
[0, 0, 0, "Unexpected any. Specify a different type.", "2"]
],
"public/app/plugins/datasource/grafana/components/TimePickerInput.tsx:5381": [
[0, 0, 0, "\'@grafana/ui/src/components/Forms/commonStyles\' import is restricted from being used by a pattern. Import from the public export instead.", "0"],
[0, 0, 0, "\'@grafana/ui/src/themes/mixins\' import is restricted from being used by a pattern. Import from the public export instead.", "1"]
],
"public/app/plugins/datasource/grafana/components/TimeRegionEditor.tsx:5381": [
[0, 0, 0, "\'@grafana/ui/src/components/DateTimePickers/TimeZonePicker/TimeZoneOffset\' import is restricted from being used by a pattern. Import from the public export instead.", "0"],
[0, 0, 0, "\'@grafana/ui/src/components/DateTimePickers/TimeZonePicker/TimeZoneTitle\' import is restricted from being used by a pattern. Import from the public export instead.", "1"]
+105 -105
View File
@@ -25,7 +25,7 @@ steps:
depends_on: []
environment:
CGO_ENABLED: 0
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: compile-build-cmd
- commands:
- ./bin/build verify-drone
@@ -75,7 +75,7 @@ steps:
- go install github.com/bazelbuild/buildtools/buildifier@latest
- buildifier --lint=warn -mode=check -r .
depends_on: []
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: lint-starlark
trigger:
event:
@@ -427,7 +427,7 @@ steps:
- apk add --update make
- CODEGEN_VERIFY=1 make gen-cue
depends_on: []
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: verify-gen-cue
- commands:
- '# It is required that generated jsonnet is committed and in sync with its inputs.'
@@ -436,21 +436,21 @@ steps:
- apk add --update make
- CODEGEN_VERIFY=1 make gen-jsonnet
depends_on: []
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: verify-gen-jsonnet
- commands:
- apk add --update make
- make gen-go
depends_on:
- verify-gen-cue
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: wire-install
- commands:
- apk add --update build-base shared-mime-info shared-mime-info-lang
- go list -f '{{.Dir}}/...' -m | xargs go test -short -covermode=atomic -timeout=5m
depends_on:
- wire-install
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: test-backend
- commands:
- apk add --update build-base
@@ -459,7 +459,7 @@ steps:
| grep -o '\(.*\)/' | sort -u)
depends_on:
- wire-install
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: test-backend-integration
trigger:
event:
@@ -513,7 +513,7 @@ steps:
depends_on: []
environment:
CGO_ENABLED: 0
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: compile-build-cmd
- commands:
- echo $(/usr/bin/github-app-external-token) > /github-app/token
@@ -558,16 +558,16 @@ steps:
- apk add --update make
- make gen-go
depends_on: []
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: wire-install
- commands:
- go run scripts/modowners/modowners.go check go.mod
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: validate-modfile
- commands:
- apk add --update make
- make swagger-validate
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: validate-openapi-spec
trigger:
event:
@@ -643,7 +643,7 @@ steps:
depends_on: []
environment:
CGO_ENABLED: 0
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: compile-build-cmd
- commands:
- '# It is required that code generated from Thema/CUE be committed and in sync
@@ -653,7 +653,7 @@ steps:
- apk add --update make
- CODEGEN_VERIFY=1 make gen-cue
depends_on: []
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: verify-gen-cue
- commands:
- '# It is required that generated jsonnet is committed and in sync with its inputs.'
@@ -662,7 +662,7 @@ steps:
- apk add --update make
- CODEGEN_VERIFY=1 make gen-jsonnet
depends_on: []
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: verify-gen-jsonnet
- commands:
- yarn install --immutable || yarn install --immutable
@@ -698,7 +698,7 @@ steps:
- /src/grafana-build artifacts -a targz:grafana:linux/amd64 -a targz:grafana:linux/arm64
-a targz:grafana:linux/arm/v7 -a docker:grafana:linux/amd64 -a docker:grafana:linux/amd64:ubuntu
-a docker:grafana:linux/arm64 -a docker:grafana:linux/arm64:ubuntu -a docker:grafana:linux/arm/v7
-a docker:grafana:linux/arm/v7:ubuntu --go-version=1.23.4 --yarn-cache=$$YARN_CACHE_FOLDER
-a docker:grafana:linux/arm/v7:ubuntu --go-version=1.23.5 --yarn-cache=$$YARN_CACHE_FOLDER
--build-id=$$DRONE_BUILD_NUMBER --ubuntu-base=ubuntu:22.04 --alpine-base=alpine:3.20.3
--tag-format='{{ .version_base }}-{{ .buildID }}-{{ .arch }}' --ubuntu-tag-format='{{
.version_base }}-{{ .buildID }}-ubuntu-{{ .arch }}' --verify='false' --grafana-dir=$$PWD
@@ -1096,7 +1096,7 @@ steps:
depends_on: []
environment:
CGO_ENABLED: 0
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: compile-build-cmd
- commands:
- echo $DRONE_RUNNER_NAME
@@ -1110,7 +1110,7 @@ steps:
- apk add --update make
- CODEGEN_VERIFY=1 make gen-cue
depends_on: []
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: verify-gen-cue
- commands:
- '# It is required that generated jsonnet is committed and in sync with its inputs.'
@@ -1119,14 +1119,14 @@ steps:
- apk add --update make
- CODEGEN_VERIFY=1 make gen-jsonnet
depends_on: []
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: verify-gen-jsonnet
- commands:
- apk add --update make
- make gen-go
depends_on:
- verify-gen-cue
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: wire-install
- commands:
- dockerize -wait tcp://postgres:5432 -timeout 120s
@@ -1147,7 +1147,7 @@ steps:
GRAFANA_TEST_DB: postgres
PGPASSWORD: grafanatest
POSTGRES_HOST: postgres
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: postgres-integration-tests
- commands:
- dockerize -wait tcp://mysql80:3306 -timeout 120s
@@ -1168,7 +1168,7 @@ steps:
environment:
GRAFANA_TEST_DB: mysql
MYSQL_HOST: mysql80
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: mysql-8.0-integration-tests
- commands:
- dockerize -wait tcp://redis:6379 -timeout 120s
@@ -1184,7 +1184,7 @@ steps:
- wait-for-redis
environment:
REDIS_URL: redis://redis:6379/0
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: redis-integration-tests
- commands:
- dockerize -wait tcp://memcached:11211 -timeout 120s
@@ -1200,7 +1200,7 @@ steps:
- wait-for-memcached
environment:
MEMCACHED_HOSTS: memcached:11211
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: memcached-integration-tests
- commands:
- dockerize -wait tcp://mimir_backend:8080 -timeout 120s
@@ -1216,7 +1216,7 @@ steps:
environment:
AM_TENANT_ID: test
AM_URL: http://mimir_backend:8080
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: remote-alertmanager-integration-tests
trigger:
event:
@@ -1298,7 +1298,7 @@ steps:
- apk add --update make
- CODEGEN_VERIFY=1 make gen-cue
depends_on: []
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: verify-gen-cue
trigger:
event:
@@ -1419,7 +1419,7 @@ steps:
&& return 1; fi
depends_on:
- clone-enterprise
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: swagger-gen
trigger:
event:
@@ -1524,7 +1524,7 @@ steps:
depends_on: []
environment:
CGO_ENABLED: 0
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: compile-build-cmd
- commands:
- '# It is required that code generated from Thema/CUE be committed and in sync
@@ -1535,7 +1535,7 @@ steps:
- CODEGEN_VERIFY=1 make gen-cue
depends_on:
- clone-enterprise
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: verify-gen-cue
- commands:
- '# It is required that generated jsonnet is committed and in sync with its inputs.'
@@ -1545,14 +1545,14 @@ steps:
- CODEGEN_VERIFY=1 make gen-jsonnet
depends_on:
- clone-enterprise
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: verify-gen-jsonnet
- commands:
- apk add --update make
- make gen-go
depends_on:
- verify-gen-cue
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: wire-install
- commands:
- apk add --update build-base
@@ -1560,7 +1560,7 @@ steps:
- go test -v -run=^$ -benchmem -timeout=1h -count=8 -bench=. ${GO_PACKAGES}
depends_on:
- wire-install
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: sqlite-benchmark-integration-tests
- commands:
- apk add --update build-base
@@ -1572,7 +1572,7 @@ steps:
GRAFANA_TEST_DB: postgres
PGPASSWORD: grafanatest
POSTGRES_HOST: postgres
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: postgres-benchmark-integration-tests
- commands:
- apk add --update build-base
@@ -1583,7 +1583,7 @@ steps:
environment:
GRAFANA_TEST_DB: mysql
MYSQL_HOST: mysql80
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: mysql-8.0-benchmark-integration-tests
trigger:
event:
@@ -1655,7 +1655,7 @@ steps:
- apk add --update make
- CODEGEN_VERIFY=1 make gen-cue
depends_on: []
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: verify-gen-cue
trigger:
branch: main
@@ -1828,7 +1828,7 @@ steps:
- apk add --update make
- CODEGEN_VERIFY=1 make gen-cue
depends_on: []
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: verify-gen-cue
- commands:
- '# It is required that generated jsonnet is committed and in sync with its inputs.'
@@ -1837,21 +1837,21 @@ steps:
- apk add --update make
- CODEGEN_VERIFY=1 make gen-jsonnet
depends_on: []
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: verify-gen-jsonnet
- commands:
- apk add --update make
- make gen-go
depends_on:
- verify-gen-cue
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: wire-install
- commands:
- apk add --update build-base shared-mime-info shared-mime-info-lang
- go list -f '{{.Dir}}/...' -m | xargs go test -short -covermode=atomic -timeout=5m
depends_on:
- wire-install
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: test-backend
- commands:
- apk add --update build-base
@@ -1860,7 +1860,7 @@ steps:
| grep -o '\(.*\)/' | sort -u)
depends_on:
- wire-install
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: test-backend-integration
trigger:
branch: main
@@ -1905,22 +1905,22 @@ steps:
depends_on: []
environment:
CGO_ENABLED: 0
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: compile-build-cmd
- commands:
- apk add --update make
- make gen-go
depends_on: []
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: wire-install
- commands:
- go run scripts/modowners/modowners.go check go.mod
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: validate-modfile
- commands:
- apk add --update make
- make swagger-validate
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: validate-openapi-spec
- commands:
- ./bin/build verify-drone
@@ -2052,7 +2052,7 @@ steps:
depends_on: []
environment:
CGO_ENABLED: 0
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: compile-build-cmd
- commands:
- '# It is required that code generated from Thema/CUE be committed and in sync
@@ -2062,7 +2062,7 @@ steps:
- apk add --update make
- CODEGEN_VERIFY=1 make gen-cue
depends_on: []
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: verify-gen-cue
- commands:
- '# It is required that generated jsonnet is committed and in sync with its inputs.'
@@ -2071,7 +2071,7 @@ steps:
- apk add --update make
- CODEGEN_VERIFY=1 make gen-jsonnet
depends_on: []
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: verify-gen-jsonnet
- commands:
- yarn install --immutable || yarn install --immutable
@@ -2106,7 +2106,7 @@ steps:
- /src/grafana-build artifacts -a targz:grafana:linux/amd64 -a targz:grafana:linux/arm64
-a targz:grafana:linux/arm/v7 -a docker:grafana:linux/amd64 -a docker:grafana:linux/amd64:ubuntu
-a docker:grafana:linux/arm64 -a docker:grafana:linux/arm64:ubuntu -a docker:grafana:linux/arm/v7
-a docker:grafana:linux/arm/v7:ubuntu --go-version=1.23.4 --yarn-cache=$$YARN_CACHE_FOLDER
-a docker:grafana:linux/arm/v7:ubuntu --go-version=1.23.5 --yarn-cache=$$YARN_CACHE_FOLDER
--build-id=$$DRONE_BUILD_NUMBER --ubuntu-base=ubuntu:22.04 --alpine-base=alpine:3.20.3
--tag-format='{{ .version_base }}-{{ .buildID }}-{{ .arch }}' --ubuntu-tag-format='{{
.version_base }}-{{ .buildID }}-ubuntu-{{ .arch }}' --verify='false' --grafana-dir=$$PWD
@@ -2581,7 +2581,7 @@ steps:
depends_on: []
environment:
CGO_ENABLED: 0
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: compile-build-cmd
- commands:
- echo $DRONE_RUNNER_NAME
@@ -2595,7 +2595,7 @@ steps:
- apk add --update make
- CODEGEN_VERIFY=1 make gen-cue
depends_on: []
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: verify-gen-cue
- commands:
- '# It is required that generated jsonnet is committed and in sync with its inputs.'
@@ -2604,14 +2604,14 @@ steps:
- apk add --update make
- CODEGEN_VERIFY=1 make gen-jsonnet
depends_on: []
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: verify-gen-jsonnet
- commands:
- apk add --update make
- make gen-go
depends_on:
- verify-gen-cue
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: wire-install
- commands:
- dockerize -wait tcp://postgres:5432 -timeout 120s
@@ -2632,7 +2632,7 @@ steps:
GRAFANA_TEST_DB: postgres
PGPASSWORD: grafanatest
POSTGRES_HOST: postgres
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: postgres-integration-tests
- commands:
- dockerize -wait tcp://mysql80:3306 -timeout 120s
@@ -2653,7 +2653,7 @@ steps:
environment:
GRAFANA_TEST_DB: mysql
MYSQL_HOST: mysql80
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: mysql-8.0-integration-tests
- commands:
- dockerize -wait tcp://redis:6379 -timeout 120s
@@ -2669,7 +2669,7 @@ steps:
- wait-for-redis
environment:
REDIS_URL: redis://redis:6379/0
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: redis-integration-tests
- commands:
- dockerize -wait tcp://memcached:11211 -timeout 120s
@@ -2685,7 +2685,7 @@ steps:
- wait-for-memcached
environment:
MEMCACHED_HOSTS: memcached:11211
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: memcached-integration-tests
- commands:
- dockerize -wait tcp://mimir_backend:8080 -timeout 120s
@@ -2701,7 +2701,7 @@ steps:
environment:
AM_TENANT_ID: test
AM_URL: http://mimir_backend:8080
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: remote-alertmanager-integration-tests
trigger:
branch: main
@@ -2960,7 +2960,7 @@ steps:
- apk add --update make
- CODEGEN_VERIFY=1 make gen-cue
depends_on: []
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: verify-gen-cue
- commands:
- '# It is required that generated jsonnet is committed and in sync with its inputs.'
@@ -2969,21 +2969,21 @@ steps:
- apk add --update make
- CODEGEN_VERIFY=1 make gen-jsonnet
depends_on: []
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: verify-gen-jsonnet
- commands:
- apk add --update make
- make gen-go
depends_on:
- verify-gen-cue
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: wire-install
- commands:
- apk add --update build-base shared-mime-info shared-mime-info-lang
- go list -f '{{.Dir}}/...' -m | xargs go test -short -covermode=atomic -timeout=5m
depends_on:
- wire-install
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: test-backend
- commands:
- apk add --update build-base
@@ -2992,7 +2992,7 @@ steps:
| grep -o '\(.*\)/' | sort -u)
depends_on:
- wire-install
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: test-backend-integration
trigger:
branch:
@@ -3035,22 +3035,22 @@ steps:
depends_on: []
environment:
CGO_ENABLED: 0
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: compile-build-cmd
- commands:
- apk add --update make
- make gen-go
depends_on: []
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: wire-install
- commands:
- go run scripts/modowners/modowners.go check go.mod
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: validate-modfile
- commands:
- apk add --update make
- make swagger-validate
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: validate-openapi-spec
trigger:
branch:
@@ -3129,7 +3129,7 @@ steps:
depends_on: []
environment:
CGO_ENABLED: 0
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: compile-build-cmd
- commands:
- echo $DRONE_RUNNER_NAME
@@ -3143,7 +3143,7 @@ steps:
- apk add --update make
- CODEGEN_VERIFY=1 make gen-cue
depends_on: []
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: verify-gen-cue
- commands:
- '# It is required that generated jsonnet is committed and in sync with its inputs.'
@@ -3152,14 +3152,14 @@ steps:
- apk add --update make
- CODEGEN_VERIFY=1 make gen-jsonnet
depends_on: []
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: verify-gen-jsonnet
- commands:
- apk add --update make
- make gen-go
depends_on:
- verify-gen-cue
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: wire-install
- commands:
- dockerize -wait tcp://postgres:5432 -timeout 120s
@@ -3180,7 +3180,7 @@ steps:
GRAFANA_TEST_DB: postgres
PGPASSWORD: grafanatest
POSTGRES_HOST: postgres
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: postgres-integration-tests
- commands:
- dockerize -wait tcp://mysql80:3306 -timeout 120s
@@ -3201,7 +3201,7 @@ steps:
environment:
GRAFANA_TEST_DB: mysql
MYSQL_HOST: mysql80
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: mysql-8.0-integration-tests
- commands:
- dockerize -wait tcp://redis:6379 -timeout 120s
@@ -3217,7 +3217,7 @@ steps:
- wait-for-redis
environment:
REDIS_URL: redis://redis:6379/0
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: redis-integration-tests
- commands:
- dockerize -wait tcp://memcached:11211 -timeout 120s
@@ -3233,7 +3233,7 @@ steps:
- wait-for-memcached
environment:
MEMCACHED_HOSTS: memcached:11211
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: memcached-integration-tests
- commands:
- dockerize -wait tcp://mimir_backend:8080 -timeout 120s
@@ -3249,7 +3249,7 @@ steps:
environment:
AM_TENANT_ID: test
AM_URL: http://mimir_backend:8080
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: remote-alertmanager-integration-tests
trigger:
branch:
@@ -3349,7 +3349,7 @@ steps:
depends_on: []
environment:
CGO_ENABLED: 0
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: compile-build-cmd
- commands:
- ./bin/build artifacts docker fetch --edition oss
@@ -3481,7 +3481,7 @@ steps:
depends_on: []
environment:
CGO_ENABLED: 0
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: compile-build-cmd
- commands:
- ./bin/build artifacts docker fetch --edition oss
@@ -3622,7 +3622,7 @@ steps:
depends_on: []
environment:
CGO_ENABLED: 0
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: compile-build-cmd
- commands:
- ./bin/build artifacts packages --artifacts-editions=oss --tag $${DRONE_TAG} --src-bucket
@@ -3714,7 +3714,7 @@ steps:
depends_on: []
environment:
CGO_ENABLED: 0
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: compile-build-cmd
- commands:
- yarn install --immutable || yarn install --immutable
@@ -3814,7 +3814,7 @@ steps:
depends_on: []
environment:
CGO_ENABLED: 0
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: compile-build-cmd
- depends_on:
- compile-build-cmd
@@ -3911,7 +3911,7 @@ steps:
depends_on: []
environment:
CGO_ENABLED: 0
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: compile-build-cmd
- commands:
- ./bin/build publish grafana-com --edition oss ${DRONE_TAG}
@@ -3973,7 +3973,7 @@ steps:
from_secret: grafana_api_key
GCP_KEY_BASE64:
from_secret: gcp_key_base64
GO_VERSION: 1.23.4
GO_VERSION: 1.23.5
GPG_PASSPHRASE:
from_secret: packages_gpg_passphrase
GPG_PRIVATE_KEY:
@@ -4048,7 +4048,7 @@ steps:
from_secret: grafana_api_key
GCP_KEY_BASE64:
from_secret: gcp_key_base64
GO_VERSION: 1.23.4
GO_VERSION: 1.23.5
GPG_PASSPHRASE:
from_secret: packages_gpg_passphrase
GPG_PRIVATE_KEY:
@@ -4105,13 +4105,13 @@ steps:
depends_on: []
environment:
CGO_ENABLED: 0
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: compile-build-cmd
- commands:
- ./bin/build whatsnew-checker
depends_on:
- compile-build-cmd
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: whats-new-checker
trigger:
event:
@@ -4210,7 +4210,7 @@ steps:
from_secret: grafana_api_key
GCP_KEY_BASE64:
from_secret: gcp_key_base64
GO_VERSION: 1.23.4
GO_VERSION: 1.23.5
GPG_PASSPHRASE:
from_secret: packages_gpg_passphrase
GPG_PRIVATE_KEY:
@@ -4361,7 +4361,7 @@ steps:
- apk add --update make
- CODEGEN_VERIFY=1 make gen-cue
depends_on: []
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: verify-gen-cue
- commands:
- '# It is required that generated jsonnet is committed and in sync with its inputs.'
@@ -4370,21 +4370,21 @@ steps:
- apk add --update make
- CODEGEN_VERIFY=1 make gen-jsonnet
depends_on: []
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: verify-gen-jsonnet
- commands:
- apk add --update make
- make gen-go
depends_on:
- verify-gen-cue
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: wire-install
- commands:
- apk add --update build-base shared-mime-info shared-mime-info-lang
- go list -f '{{.Dir}}/...' -m | xargs go test -short -covermode=atomic -timeout=5m
depends_on:
- wire-install
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: test-backend
- commands:
- apk add --update build-base
@@ -4393,7 +4393,7 @@ steps:
| grep -o '\(.*\)/' | sort -u)
depends_on:
- wire-install
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: test-backend-integration
trigger:
cron:
@@ -4447,7 +4447,7 @@ steps:
from_secret: grafana_api_key
GCP_KEY_BASE64:
from_secret: gcp_key_base64
GO_VERSION: 1.23.4
GO_VERSION: 1.23.5
GPG_PASSPHRASE:
from_secret: packages_gpg_passphrase
GPG_PRIVATE_KEY:
@@ -4591,7 +4591,7 @@ steps:
from_secret: grafana_api_key
GCP_KEY_BASE64:
from_secret: gcp_key_base64
GO_VERSION: 1.23.4
GO_VERSION: 1.23.5
GPG_PASSPHRASE:
from_secret: packages_gpg_passphrase
GPG_PRIVATE_KEY:
@@ -4698,7 +4698,7 @@ steps:
- export GITHUB_TOKEN=$(cat /github-app/token)
- 'dagger run --silent /src/grafana-build artifacts -a $${ARTIFACTS} --grafana-ref=$${GRAFANA_REF}
--enterprise-ref=$${ENTERPRISE_REF} --grafana-repo=$${GRAFANA_REPO} --version=$${VERSION} '
- --go-version=1.23.4
- --go-version=1.23.5
depends_on:
- github-app-generate-token
environment:
@@ -4719,7 +4719,7 @@ steps:
from_secret: grafana_api_key
GCP_KEY_BASE64:
from_secret: gcp_key_base64
GO_VERSION: 1.23.4
GO_VERSION: 1.23.5
GPG_PASSPHRASE:
from_secret: packages_gpg_passphrase
GPG_PRIVATE_KEY:
@@ -4853,7 +4853,7 @@ steps:
- apk add --update make
- CODEGEN_VERIFY=1 make gen-cue
depends_on: []
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: verify-gen-cue
- commands:
- '# It is required that generated jsonnet is committed and in sync with its inputs.'
@@ -4862,14 +4862,14 @@ steps:
- apk add --update make
- CODEGEN_VERIFY=1 make gen-jsonnet
depends_on: []
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: verify-gen-jsonnet
- commands:
- apk add --update make
- make gen-go
depends_on:
- verify-gen-cue
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: wire-install
- commands:
- dockerize -wait tcp://postgres:5432 -timeout 120s
@@ -4890,7 +4890,7 @@ steps:
GRAFANA_TEST_DB: postgres
PGPASSWORD: grafanatest
POSTGRES_HOST: postgres
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: postgres-integration-tests
- commands:
- dockerize -wait tcp://mysql80:3306 -timeout 120s
@@ -4911,7 +4911,7 @@ steps:
environment:
GRAFANA_TEST_DB: mysql
MYSQL_HOST: mysql80
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: mysql-8.0-integration-tests
- commands:
- dockerize -wait tcp://redis:6379 -timeout 120s
@@ -4927,7 +4927,7 @@ steps:
- wait-for-redis
environment:
REDIS_URL: redis://redis:6379/0
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: redis-integration-tests
- commands:
- dockerize -wait tcp://memcached:11211 -timeout 120s
@@ -4943,7 +4943,7 @@ steps:
- wait-for-memcached
environment:
MEMCACHED_HOSTS: memcached:11211
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: memcached-integration-tests
- commands:
- dockerize -wait tcp://mimir_backend:8080 -timeout 120s
@@ -4959,7 +4959,7 @@ steps:
environment:
AM_TENANT_ID: test
AM_URL: http://mimir_backend:8080
image: golang:1.23.4-alpine
image: golang:1.23.5-alpine
name: remote-alertmanager-integration-tests
trigger:
event:
@@ -5262,7 +5262,7 @@ steps:
- commands:
- trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM docker:27-cli
- trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM alpine/git:2.40.1
- trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM golang:1.23.4-alpine
- trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM golang:1.23.5-alpine
- trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM node:22.11.0-alpine
- trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM node:22-bookworm
- trivy --exit-code 0 --severity UNKNOWN,LOW,MEDIUM google/cloud-sdk:431.0.0
@@ -5300,7 +5300,7 @@ steps:
- commands:
- trivy --exit-code 1 --severity HIGH,CRITICAL docker:27-cli
- trivy --exit-code 1 --severity HIGH,CRITICAL alpine/git:2.40.1
- trivy --exit-code 1 --severity HIGH,CRITICAL golang:1.23.4-alpine
- trivy --exit-code 1 --severity HIGH,CRITICAL golang:1.23.5-alpine
- trivy --exit-code 1 --severity HIGH,CRITICAL node:22.11.0-alpine
- trivy --exit-code 1 --severity HIGH,CRITICAL node:22-bookworm
- trivy --exit-code 1 --severity HIGH,CRITICAL google/cloud-sdk:431.0.0
@@ -5569,6 +5569,6 @@ kind: secret
name: gcr_credentials
---
kind: signature
hmac: be82e983dfa15f85f82935674ec109056f519ff99c7ab1f4be71f9ce62b571a7
hmac: 154c1f072294cef09ba4f579eed30b1e29bc5c263897c862f4574432d321502c
...
-4
View File
@@ -13,10 +13,6 @@ packageExtensions:
doctrine@3.0.0:
dependencies:
assert: 2.0.0
rc-time-picker@3.7.3:
peerDependencies:
react: 17.0.1
react-dom: 17.0.1
rc-trigger@2.6.5:
peerDependencies:
react: 17.0.1
+1 -1
View File
@@ -2,7 +2,7 @@
ARG BASE_IMAGE=alpine:3.20
ARG JS_IMAGE=node:22-alpine
ARG JS_PLATFORM=linux/amd64
ARG GO_IMAGE=golang:1.23.4-alpine
ARG GO_IMAGE=golang:1.23.5-alpine
ARG GO_SRC=go-builder
ARG JS_SRC=js-builder
+1 -1
View File
@@ -8,7 +8,7 @@ WIRE_TAGS = "oss"
include .bingo/Variables.mk
GO = go
GO_VERSION = 1.23.4
GO_VERSION = 1.23.5
GO_LINT_FILES ?= $(shell ./scripts/go-workspace/golangci-lint-includes.sh)
GO_TEST_FILES ?= $(shell ./scripts/go-workspace/test-includes.sh)
SH_FILES ?= $(shell find ./scripts -name *.sh)
+4 -4
View File
@@ -1,6 +1,6 @@
module github.com/grafana/grafana/apps/alerting/notifications
go 1.23.4
go 1.23.5
replace github.com/grafana/grafana => ../../..
@@ -38,7 +38,7 @@ require (
github.com/google/uuid v1.6.0 // indirect
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20240821155123-6891eb1d35da // indirect
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jmespath-community/go-jmespath v1.1.1 // indirect
github.com/josharian/intern v1.0.0 // indirect
@@ -69,7 +69,7 @@ require (
go.opentelemetry.io/otel/metric v1.33.0 // indirect
go.opentelemetry.io/otel/sdk v1.33.0 // indirect
go.opentelemetry.io/otel/trace v1.33.0 // indirect
go.opentelemetry.io/proto/otlp v1.4.0 // indirect
go.opentelemetry.io/proto/otlp v1.5.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/crypto v0.32.0 // indirect
@@ -80,7 +80,7 @@ require (
golang.org/x/term v0.28.0 // indirect
golang.org/x/text v0.21.0 // indirect
golang.org/x/time v0.9.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d // indirect
google.golang.org/grpc v1.69.2 // indirect
google.golang.org/protobuf v1.36.1 // indirect
+6 -6
View File
@@ -81,8 +81,8 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a534
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340/go.mod h1:3bDW6wMZJB7tiONtC/1Xpicra6Wp5GgbTbQWCbI5fkc=
github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 h1:TmHmbvxPmaegwhDubVz0lICL0J5Ka2vwTzhoePEXsGE=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0/go.mod h1:qztMSjm835F2bXf+5HKAPIS5qsmQDqZna/PgVt4rWtI=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 h1:VNqngBF40hVlDloBruUehVYC3ArSgIyScOAyMRqBxRg=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1/go.mod h1:RBRO7fro65R6tjKzYgLAFo0t1QEXY1Dp+i/bvpRiqiQ=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jmespath-community/go-jmespath v1.1.1 h1:bFikPhsi/FdmlZhVgSCd2jj1e7G/rw+zyQfyg5UF+L4=
@@ -196,8 +196,8 @@ go.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4Jjx
go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8=
go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s=
go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck=
go.opentelemetry.io/proto/otlp v1.4.0 h1:TA9WRvW6zMwP+Ssb6fLoUIuirti1gGbP28GcKG1jgeg=
go.opentelemetry.io/proto/otlp v1.4.0/go.mod h1:PPBWZIP98o2ElSqI35IHfu7hIhSwvc5N38Jw8pXuGFY=
go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4=
go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
@@ -262,8 +262,8 @@ google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9Ywl
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 h1:Q3nlH8iSQSRUwOskjbcSMcF2jiYMNiQYZ0c2KEJLKKU=
google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38/go.mod h1:xBI+tzfqGGN2JBeSebfKXFSdBpWVQ7sLW40PTupVRm4=
google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484 h1:ChAdCYNQFDk5fYvFZMywKLIijG7TC2m1C2CMEu11G3o=
google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484/go.mod h1:KRUmxRI4JmbpAm8gcZM4Jsffi859fo5LQjILwuqj9z8=
google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d h1:H8tOf8XM88HvKqLTxe755haY6r1fqqzLbEnfrmLXlSA=
google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d/go.mod h1:2v7Z7gP2ZUOGsaFyxATQSRoBnKygqVq2Cwnvom7QiqY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d h1:xJJRGY7TJcvIlpSrN3K6LAWgNFUILlO+OMAqtg9aqnw=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d/go.mod h1:3ENsm/5D1mzDyhpzeRi1NR784I0BcofWBoSc5QqqMK4=
google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
+3 -3
View File
@@ -32,7 +32,7 @@ require (
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/grafana/grafana-app-sdk/logging v0.29.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/invopop/yaml v0.3.1 // indirect
@@ -60,7 +60,7 @@ require (
go.opentelemetry.io/otel/metric v1.33.0 // indirect
go.opentelemetry.io/otel/sdk v1.33.0 // indirect
go.opentelemetry.io/otel/trace v1.33.0 // indirect
go.opentelemetry.io/proto/otlp v1.4.0 // indirect
go.opentelemetry.io/proto/otlp v1.5.0 // indirect
golang.org/x/net v0.34.0 // indirect
golang.org/x/oauth2 v0.25.0 // indirect
golang.org/x/sync v0.10.0 // indirect
@@ -70,7 +70,7 @@ require (
golang.org/x/time v0.9.0 // indirect
golang.org/x/tools v0.29.0 // indirect
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d // indirect
google.golang.org/grpc v1.69.2 // indirect
google.golang.org/protobuf v1.36.1 // indirect
+6 -6
View File
@@ -53,8 +53,8 @@ github.com/grafana/grafana-app-sdk v0.29.0 h1:LMSm/+0LOBPd13fe1bs/4sKJmuLiixYUX9
github.com/grafana/grafana-app-sdk v0.29.0/go.mod h1:XLt308EmK6kvqPlzjUyXxbwZKEk2vur/eiypUNDay5I=
github.com/grafana/grafana-app-sdk/logging v0.29.0 h1:mgbXaAf33aFwqwGVeaX30l8rkeAJH0iACgX5Rn6YkN4=
github.com/grafana/grafana-app-sdk/logging v0.29.0/go.mod h1:xy6ZyVXl50Z3DBDLybvBPphbykPhuVNed/VNmen9DQM=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 h1:TmHmbvxPmaegwhDubVz0lICL0J5Ka2vwTzhoePEXsGE=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0/go.mod h1:qztMSjm835F2bXf+5HKAPIS5qsmQDqZna/PgVt4rWtI=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 h1:VNqngBF40hVlDloBruUehVYC3ArSgIyScOAyMRqBxRg=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1/go.mod h1:RBRO7fro65R6tjKzYgLAFo0t1QEXY1Dp+i/bvpRiqiQ=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
@@ -140,8 +140,8 @@ go.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4Jjx
go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8=
go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s=
go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck=
go.opentelemetry.io/proto/otlp v1.4.0 h1:TA9WRvW6zMwP+Ssb6fLoUIuirti1gGbP28GcKG1jgeg=
go.opentelemetry.io/proto/otlp v1.4.0/go.mod h1:PPBWZIP98o2ElSqI35IHfu7hIhSwvc5N38Jw8pXuGFY=
go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4=
go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
@@ -187,8 +187,8 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw=
gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484 h1:ChAdCYNQFDk5fYvFZMywKLIijG7TC2m1C2CMEu11G3o=
google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484/go.mod h1:KRUmxRI4JmbpAm8gcZM4Jsffi859fo5LQjILwuqj9z8=
google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d h1:H8tOf8XM88HvKqLTxe755haY6r1fqqzLbEnfrmLXlSA=
google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d/go.mod h1:2v7Z7gP2ZUOGsaFyxATQSRoBnKygqVq2Cwnvom7QiqY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d h1:xJJRGY7TJcvIlpSrN3K6LAWgNFUILlO+OMAqtg9aqnw=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d/go.mod h1:3ENsm/5D1mzDyhpzeRi1NR784I0BcofWBoSc5QqqMK4=
google.golang.org/grpc v1.69.2 h1:U3S9QEtbXC0bYNvRtcoklF3xGtLViumSYxWykJS+7AU=
+3 -3
View File
@@ -33,7 +33,7 @@ require (
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/grafana/grafana-app-sdk/logging v0.29.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/invopop/yaml v0.3.1 // indirect
@@ -61,7 +61,7 @@ require (
go.opentelemetry.io/otel/metric v1.33.0 // indirect
go.opentelemetry.io/otel/sdk v1.33.0 // indirect
go.opentelemetry.io/otel/trace v1.33.0 // indirect
go.opentelemetry.io/proto/otlp v1.4.0 // indirect
go.opentelemetry.io/proto/otlp v1.5.0 // indirect
golang.org/x/net v0.34.0 // indirect
golang.org/x/oauth2 v0.25.0 // indirect
golang.org/x/sync v0.10.0 // indirect
@@ -71,7 +71,7 @@ require (
golang.org/x/time v0.9.0 // indirect
golang.org/x/tools v0.29.0 // indirect
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d // indirect
google.golang.org/grpc v1.69.2 // indirect
google.golang.org/protobuf v1.36.1 // indirect
+6 -6
View File
@@ -53,8 +53,8 @@ github.com/grafana/grafana-app-sdk v0.29.0 h1:LMSm/+0LOBPd13fe1bs/4sKJmuLiixYUX9
github.com/grafana/grafana-app-sdk v0.29.0/go.mod h1:XLt308EmK6kvqPlzjUyXxbwZKEk2vur/eiypUNDay5I=
github.com/grafana/grafana-app-sdk/logging v0.29.0 h1:mgbXaAf33aFwqwGVeaX30l8rkeAJH0iACgX5Rn6YkN4=
github.com/grafana/grafana-app-sdk/logging v0.29.0/go.mod h1:xy6ZyVXl50Z3DBDLybvBPphbykPhuVNed/VNmen9DQM=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 h1:TmHmbvxPmaegwhDubVz0lICL0J5Ka2vwTzhoePEXsGE=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0/go.mod h1:qztMSjm835F2bXf+5HKAPIS5qsmQDqZna/PgVt4rWtI=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 h1:VNqngBF40hVlDloBruUehVYC3ArSgIyScOAyMRqBxRg=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1/go.mod h1:RBRO7fro65R6tjKzYgLAFo0t1QEXY1Dp+i/bvpRiqiQ=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
@@ -140,8 +140,8 @@ go.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4Jjx
go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8=
go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s=
go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck=
go.opentelemetry.io/proto/otlp v1.4.0 h1:TA9WRvW6zMwP+Ssb6fLoUIuirti1gGbP28GcKG1jgeg=
go.opentelemetry.io/proto/otlp v1.4.0/go.mod h1:PPBWZIP98o2ElSqI35IHfu7hIhSwvc5N38Jw8pXuGFY=
go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4=
go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
@@ -187,8 +187,8 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw=
gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484 h1:ChAdCYNQFDk5fYvFZMywKLIijG7TC2m1C2CMEu11G3o=
google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484/go.mod h1:KRUmxRI4JmbpAm8gcZM4Jsffi859fo5LQjILwuqj9z8=
google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d h1:H8tOf8XM88HvKqLTxe755haY6r1fqqzLbEnfrmLXlSA=
google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d/go.mod h1:2v7Z7gP2ZUOGsaFyxATQSRoBnKygqVq2Cwnvom7QiqY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d h1:xJJRGY7TJcvIlpSrN3K6LAWgNFUILlO+OMAqtg9aqnw=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d/go.mod h1:3ENsm/5D1mzDyhpzeRi1NR784I0BcofWBoSc5QqqMK4=
google.golang.org/grpc v1.69.2 h1:U3S9QEtbXC0bYNvRtcoklF3xGtLViumSYxWykJS+7AU=
@@ -60,6 +60,14 @@ func main() {
label: "label.with.spaß",
getNextValue: staticList([]string{"this_is_fun"}),
},
{
label: "instance",
getNextValue: staticList([]string{"instance"}),
},
{
label: "job",
getNextValue: staticList([]string{"job"}),
},
{
label: "site",
getNextValue: staticList([]string{"LA-EPI"}),
@@ -85,6 +93,12 @@ func main() {
Help: "a metric with utf8 labels",
}, dimensions)
target_info := promauto.NewGauge(prometheus.GaugeOpts{
Name: "target_info",
Help: "an info metric model for otel",
ConstLabels: map[string]string{"job": "job", "instance": "instance", "resource 1": "1", "resource 2": "2", "resource ę": "e", "deployment_environment": "prod"},
})
http.Handle("/metrics", promhttp.Handler())
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
@@ -101,6 +115,7 @@ func main() {
utf8Metric.WithLabelValues(labels...).Inc()
opsProcessed.WithLabelValues(labels...).Inc()
target_info.Set(1)
time.Sleep(time.Second * 5)
}
@@ -266,6 +266,7 @@ guaranteed because plugin developers can override this functionality. The follow
- Datadog
- Dataset
- Druid
- DynamoDB
- GitHub
- Google BigQuery
- Grafana for YNAB
+13 -13
View File
@@ -1,6 +1,6 @@
module github.com/grafana/grafana
go 1.23.4
go 1.23.5
require (
buf.build/gen/go/parca-dev/parca/connectrpc/go v1.17.0-20240902100956-02fd72488966.1 // @grafana/observability-traces-and-profiling
@@ -94,7 +94,7 @@ require (
github.com/grafana/tempo v1.5.1-0.20241001135150-ed943d7a56b2 // @grafana/observability-traces-and-profiling
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 // @grafana/plugins-platform-backend
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.2.0 // @grafana/grafana-backend-group
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 // @grafana/identity-access-team
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 // @grafana/identity-access-team
github.com/hashicorp/go-hclog v1.6.3 // @grafana/plugins-platform-backend
github.com/hashicorp/go-multierror v1.1.1 // @grafana/alerting-squad
github.com/hashicorp/go-plugin v1.6.2 // @grafana/plugins-platform-backend
@@ -125,9 +125,9 @@ require (
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // @grafana/alerting-backend
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // @grafana/grafana-operator-experience-squad
github.com/olekukonko/tablewriter v0.0.5 // @grafana/grafana-backend-group
github.com/openfga/api/proto v0.0.0-20240906203051-102620ef2a66 // @grafana/identity-access-team
github.com/openfga/language/pkg/go v0.2.0-beta.2.0.20240926131254-992b301a003f // @grafana/identity-access-team
github.com/openfga/openfga v1.6.2 // @grafana/identity-access-team
github.com/openfga/api/proto v0.0.0-20250107154247-c22e6db5c4f5 // @grafana/identity-access-team
github.com/openfga/language/pkg/go v0.2.0-beta.2.0.20241115164311-10e575c8e47c // @grafana/identity-access-team
github.com/openfga/openfga v1.8.4 // @grafana/identity-access-team
github.com/openzipkin/zipkin-go v0.4.3 // @grafana/oss-big-tent
github.com/patrickmn/go-cache v2.1.0+incompatible // @grafana/alerting-backend
github.com/phpdave11/gofpdi v1.0.13 // @grafana/sharing-squad
@@ -241,6 +241,7 @@ require (
github.com/Masterminds/squirrel v1.5.4 // indirect
github.com/NYTimes/gziphandler v1.1.1 // indirect
github.com/RoaringBitmap/roaring v1.9.3 // indirect
github.com/Yiling-J/theine-go v0.6.0 // indirect
github.com/agext/levenshtein v1.2.1 // indirect
github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b // indirect
github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a // indirect
@@ -327,7 +328,7 @@ require (
github.com/golang/geo v0.0.0-20210211234256-740aa86cb551 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/google/btree v1.1.3 // indirect
github.com/google/cel-go v0.22.0 // indirect
github.com/google/cel-go v0.22.1 // indirect
github.com/google/flatbuffers v24.3.25+incompatible // indirect
github.com/google/gnostic-models v0.6.8 // indirect
github.com/google/gofuzz v1.2.0 // indirect
@@ -358,7 +359,7 @@ require (
github.com/invopop/yaml v0.3.1 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/pgx/v5 v5.7.1 // indirect
github.com/jackc/pgx/v5 v5.7.2 // indirect
github.com/jackc/puddle/v2 v2.2.2 // indirect
github.com/jcmturner/aescts/v2 v2.0.0 // indirect
github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect
@@ -373,7 +374,6 @@ require (
github.com/jpillora/backoff v1.0.0 // indirect
github.com/jszwedko/go-datemath v0.1.1-0.20230526204004-640a500621d6 // indirect
github.com/jtolds/gls v4.20.0+incompatible // indirect
github.com/karlseguin/ccache/v3 v3.0.5 // indirect
github.com/klauspost/compress v1.17.11 // indirect
github.com/klauspost/cpuid/v2 v2.2.9 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
@@ -424,7 +424,7 @@ require (
github.com/pkg/errors v0.9.1 // indirect
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/pressly/goose/v3 v3.22.1 // indirect
github.com/pressly/goose/v3 v3.24.0 // indirect
github.com/prometheus/common/sigv4 v0.1.0 // indirect
github.com/prometheus/exporter-toolkit v0.13.2 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
@@ -480,8 +480,8 @@ require (
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.33.0 // indirect
go.opentelemetry.io/otel/metric v1.33.0 // indirect
go.opentelemetry.io/proto/otlp v1.4.0 // indirect
go.uber.org/mock v0.4.0 // indirect
go.opentelemetry.io/proto/otlp v1.5.0 // indirect
go.uber.org/mock v0.5.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go4.org/netipx v0.0.0-20230125063823-8449b0a6169f // indirect
golang.org/x/sys v0.29.0 // indirect
@@ -489,7 +489,7 @@ require (
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
@@ -503,7 +503,7 @@ require (
modernc.org/libc v1.55.3 // indirect
modernc.org/mathutil v1.6.0 // indirect
modernc.org/memory v1.8.0 // indirect
modernc.org/sqlite v1.33.1 // indirect
modernc.org/sqlite v1.34.4 // indirect
modernc.org/strutil v1.2.0 // indirect
modernc.org/token v1.1.0 // indirect
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.0 // indirect
+24 -24
View File
@@ -747,6 +747,8 @@ github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f h1:HR5nRmUQgX
github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f/go.mod h1:f3HiCrHjHBdcm6E83vGaXh1KomZMA2P6aeo3hKx/wg0=
github.com/Workiva/go-datastructures v1.1.5 h1:5YfhQ4ry7bZc2Mc7R0YZyYwpf5c6t1cEFvdAhd6Mkf4=
github.com/Workiva/go-datastructures v1.1.5/go.mod h1:1yZL+zfsztete+ePzZz/Zb1/t5BnDuE2Ya2MMGhzP6A=
github.com/Yiling-J/theine-go v0.6.0 h1:jv7V/tcD6ijL0T4kfbJDKP81TCZBkoriNTPSqwivWuY=
github.com/Yiling-J/theine-go v0.6.0/go.mod h1:mdch1vjgGWd7s3rWKvY+MF5InRLfRv/CWVI9RVNQ8wY=
github.com/agext/levenshtein v1.2.1 h1:QmvMAjj2aEICytGiWzmxoE0x2KZvE0fvmqMOfy2tjT8=
github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY=
@@ -1369,8 +1371,8 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Z
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
github.com/google/cel-go v0.22.0 h1:b3FJZxpiv1vTMo2/5RDUqAHPxkT8mmMfJIrq1llbf7g=
github.com/google/cel-go v0.22.0/go.mod h1:BuznPXXfQDpXKWQ9sPW3TzlAJN5zzFe+i9tIs0yC4s8=
github.com/google/cel-go v0.22.1 h1:AfVXx3chM2qwoSbM7Da8g8hX8OVSkBFwX+rz2+PcK40=
github.com/google/cel-go v0.22.1/go.mod h1:BuznPXXfQDpXKWQ9sPW3TzlAJN5zzFe+i9tIs0yC4s8=
github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
github.com/google/flatbuffers v24.3.25+incompatible h1:CX395cjN9Kke9mmalRoL3d81AtFUxJM+yDthflgJGkI=
github.com/google/flatbuffers v24.3.25+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
@@ -1588,8 +1590,8 @@ github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 h1:TmHmbvxPmaegwhDubVz0lICL0J5Ka2vwTzhoePEXsGE=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0/go.mod h1:qztMSjm835F2bXf+5HKAPIS5qsmQDqZna/PgVt4rWtI=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 h1:VNqngBF40hVlDloBruUehVYC3ArSgIyScOAyMRqBxRg=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1/go.mod h1:RBRO7fro65R6tjKzYgLAFo0t1QEXY1Dp+i/bvpRiqiQ=
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/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
@@ -1710,8 +1712,8 @@ github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5ey
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx v3.2.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
github.com/jackc/pgx/v5 v5.7.1 h1:x7SYsPBYDkHDksogeSmZZ5xzThcTgRz++I5E+ePFUcs=
github.com/jackc/pgx/v5 v5.7.1/go.mod h1:e7O26IywZZ+naJtWWos6i6fvWK+29etgITqrqHLfoZA=
github.com/jackc/pgx/v5 v5.7.2 h1:mLoDLV6sonKlvjIEsV56SkWNCnuNv531l94GaIzO+XI=
github.com/jackc/pgx/v5 v5.7.2/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ=
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8=
@@ -1775,8 +1777,6 @@ github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8
github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
github.com/karlseguin/ccache/v3 v3.0.5 h1:hFX25+fxzNjsRlREYsoGNa2LoVEw5mPF8wkWq/UnevQ=
github.com/karlseguin/ccache/v3 v3.0.5/go.mod h1:qxC372+Qn+IBj8Pe3KvGjHPj0sWwEF7AeZVhsNPZ6uY=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6 h1:IsMZxCuZqKuao2vNdfD82fjjgPLfyHLpR41Z88viRWs=
github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6/go.mod h1:3VeWNIJaW+O5xpRQbPp0Ybqu1vJd/pm7s2F473HRrkw=
@@ -2010,12 +2010,12 @@ github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3I
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
github.com/openfga/api/proto v0.0.0-20240906203051-102620ef2a66 h1:pAYrdyIKxPsMs/nRcTEnS9za2io11g7Rt7ng7HK82hk=
github.com/openfga/api/proto v0.0.0-20240906203051-102620ef2a66/go.mod h1:gil5LBD8tSdFQbUkCQdnXsoeU9kDJdJgbGdHkgJfcd0=
github.com/openfga/language/pkg/go v0.2.0-beta.2.0.20240926131254-992b301a003f h1:ZMZ7ntMnaHIPZxvVQv/aqC4ctzLqH+9Fqn4uw35kQpk=
github.com/openfga/language/pkg/go v0.2.0-beta.2.0.20240926131254-992b301a003f/go.mod h1:ll/hN6kS4EE6B/7J/PbZqac9Nuv7ZHpI+Jfh36JLrbs=
github.com/openfga/openfga v1.6.2 h1:tHBAgiCPomCZb3IH0CFqOpTDVDA/Xb8kG87oX4JCbXc=
github.com/openfga/openfga v1.6.2/go.mod h1:jzbEpheazf6MFjtanQt1rpxexSRzfa9057F7JlkMv2I=
github.com/openfga/api/proto v0.0.0-20250107154247-c22e6db5c4f5 h1:z9jaRoo+NIN1AB0ogjtrjx1316TTuq6IbqpEg3UJycA=
github.com/openfga/api/proto v0.0.0-20250107154247-c22e6db5c4f5/go.mod h1:m74TNgnAAIJ03gfHcx+xaRWnr+IbQy3y/AVNwwCFrC0=
github.com/openfga/language/pkg/go v0.2.0-beta.2.0.20241115164311-10e575c8e47c h1:1y84C0V4NRfPtRi4MqQ7+gnFtYgeBKPIeIAPLdVJ7j4=
github.com/openfga/language/pkg/go v0.2.0-beta.2.0.20241115164311-10e575c8e47c/go.mod h1:12RMe/HuRNyOzS33RQa53jwdcxE2znr8ycXMlVbgQN4=
github.com/openfga/openfga v1.8.4 h1:OqyRpuxMCxcS7irTFYFkhAIYzmAnczNwxUqjnuZOQyo=
github.com/openfga/openfga v1.8.4/go.mod h1:9Ax9VMMySV2JMsCT8MTePeYt4OrTnPAy1XUV1y9RyuU=
github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e h1:4cPxUYdgaGzZIT5/j0IfqOrrXmq6bG8AwvwisMXpdrg=
github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e/go.mod h1:DYR5Eij8rJl8h7gblRrOZ8g0kW1umSpKqYIBTgeDtLo=
github.com/opentracing-contrib/go-stdlib v0.0.0-20190519235532-cf7a6c988dc9/go.mod h1:PLldrQSroqzH70Xl+1DQcGnefIbqsKR7UDaiux3zV+w=
@@ -2071,8 +2071,8 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
github.com/pressly/goose/v3 v3.22.1 h1:2zICEfr1O3yTP9BRZMGPj7qFxQ+ik6yeo+z1LMuioLc=
github.com/pressly/goose/v3 v3.22.1/go.mod h1:xtMpbstWyCpyH+0cxLTMCENWBG+0CSxvTsXhW95d5eo=
github.com/pressly/goose/v3 v3.24.0 h1:sFbNms7Bd++2VMq6HSgDHDLWa7kHz1qXzPb3ZIU72VU=
github.com/pressly/goose/v3 v3.24.0/go.mod h1:rEWreU9uVtt0DHCyLzF9gRcWiiTF/V+528DV+4DORug=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
@@ -2466,16 +2466,16 @@ go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37Cb
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
go.opentelemetry.io/proto/otlp v1.4.0 h1:TA9WRvW6zMwP+Ssb6fLoUIuirti1gGbP28GcKG1jgeg=
go.opentelemetry.io/proto/otlp v1.4.0/go.mod h1:PPBWZIP98o2ElSqI35IHfu7hIhSwvc5N38Jw8pXuGFY=
go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4=
go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
@@ -3234,8 +3234,8 @@ google.golang.org/genproto/googleapis/api v0.0.0-20230525234020-1aefcd67740a/go.
google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig=
google.golang.org/genproto/googleapis/api v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig=
google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig=
google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484 h1:ChAdCYNQFDk5fYvFZMywKLIijG7TC2m1C2CMEu11G3o=
google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484/go.mod h1:KRUmxRI4JmbpAm8gcZM4Jsffi859fo5LQjILwuqj9z8=
google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d h1:H8tOf8XM88HvKqLTxe755haY6r1fqqzLbEnfrmLXlSA=
google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d/go.mod h1:2v7Z7gP2ZUOGsaFyxATQSRoBnKygqVq2Cwnvom7QiqY=
google.golang.org/genproto/googleapis/bytestream v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:ylj+BE99M198VPbBh6A8d9n3w8fChvyLK3wwBOjXBFA=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234015-3fc162c6f38a/go.mod h1:xURIpW9ES5+/GZhnV6beoEtxQrnkRGIfP5VQG2tCBLc=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA=
@@ -3447,8 +3447,8 @@ modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc=
modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss=
modernc.org/sqlite v1.18.1/go.mod h1:6ho+Gow7oX5V+OiOQ6Tr4xeqbx13UZ6t+Fw9IRUG4d4=
modernc.org/sqlite v1.33.1 h1:trb6Z3YYoeM9eDL1O8do81kP+0ejv+YzgyFo+Gwy0nM=
modernc.org/sqlite v1.33.1/go.mod h1:pXV2xHxhzXZsgT/RtTFAPY6JJDEvOTcTdwADQCCWD4k=
modernc.org/sqlite v1.34.4 h1:sjdARozcL5KJBvYQvLlZEmctRgW9xqIZc2ncN7PU0P8=
modernc.org/sqlite v1.34.4/go.mod h1:3QQFCG2SEMtc2nv+Wq4cQCH7Hjcg+p/RMlS1XK+zwbk=
modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw=
modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw=
modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA=
+1 -1
View File
@@ -1,4 +1,4 @@
go 1.23.4
go 1.23.5
// The `skip:golangci-lint` comment tag is used to exclude the package from the `golangci-lint` GitHub Action.
// The module at the root of the repo (`.`) is excluded because ./pkg/... is included manually in the `golangci-lint` configuration.
+146
View File
@@ -1,5 +1,6 @@
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.31.0-20230802163732-1c33ebd9ecfa.1 h1:tdpHgTbmbvEIARu+bixzmleMi14+3imnpoFXz+Qzjp4=
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.31.0-20230802163732-1c33ebd9ecfa.1/go.mod h1:xafc+XIsTxTy76GJQ1TKgvJWsSugFBqMaN27WhUblew=
cel.dev/expr v0.16.2/go.mod h1:gXngZQMkWJoSbE8mOzehJlXQyubn/Vg0vR9/F3W7iw8=
cloud.google.com/go v0.110.4/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI=
cloud.google.com/go v0.110.6/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI=
cloud.google.com/go v0.110.7/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI=
@@ -8,6 +9,9 @@ cloud.google.com/go v0.110.9/go.mod h1:rpxevX/0Lqvlbc88b7Sc1SPNdyK1riNBTUU6JXhYN
cloud.google.com/go v0.110.10/go.mod h1:v1OoFqYxiBkUrruItNM3eT4lLByNjxmJSV/xDKJNnic=
cloud.google.com/go v0.111.0/go.mod h1:0mibmpKP1TyOOFYQY5izo0LnT+ecvOQ0Sg3OdmMiNRU=
cloud.google.com/go v0.112.0/go.mod h1:3jEEVwZ/MHU4djK5t5RHuKOA/GbLddgTdVubX1qnPD4=
cloud.google.com/go v0.112.2/go.mod h1:iEqjp//KquGIJV/m+Pk3xecgKNhV+ry+vVTsy4TbDms=
cloud.google.com/go v0.115.0/go.mod h1:8jIM5vVgoAEoiVxQ/O4BFTfHqulPZgs/ufEzMcFMdWU=
cloud.google.com/go v0.115.1/go.mod h1:DuujITeaufu3gL68/lOFIirVNJwQeyf5UXyi+Wbgknc=
cloud.google.com/go/accessapproval v1.7.1/go.mod h1:JYczztsHRMK7NTXb6Xw+dwbs/WnOJxbo/2mTI+Kgg68=
cloud.google.com/go/accessapproval v1.7.2/go.mod h1:/gShiq9/kK/h8T/eEn1BTzalDvk0mZxJlhfw0p+Xuc0=
cloud.google.com/go/accessapproval v1.7.3/go.mod h1:4l8+pwIxGTNqSf4T3ds8nLO94NQf0W/KnMNuQ9PbnP8=
@@ -109,7 +113,13 @@ cloud.google.com/go/assuredworkloads v1.11.5/go.mod h1:FKJ3g3ZvkL2D7qtqIGnDufFkH
cloud.google.com/go/assuredworkloads v1.12.1 h1:B+hWc62fYL8NdntPjx0rzJJ67qx99w6dCeIVDpHf7QE=
cloud.google.com/go/assuredworkloads v1.12.1/go.mod h1:nBnkK2GZNSdtjU3ER75oC5fikub5/+QchbolKgnMI/I=
cloud.google.com/go/auth v0.2.0/go.mod h1:+yb+oy3/P0geX6DLKlqiGHARGR6EX2GRtYCzWOCQSbU=
cloud.google.com/go/auth v0.3.0/go.mod h1:lBv6NKTWp8E3LPzmO1TbiiRKc4drLOfHsgmlH9ogv5w=
cloud.google.com/go/auth v0.6.1/go.mod h1:eFHG7zDzbXHKmjJddFG/rBlcGp6t25SwRUiEQSlO4x4=
cloud.google.com/go/auth v0.9.3/go.mod h1:7z6VY+7h3KUdRov5F1i8NDP5ZzWKYmEPO842BgCsmTk=
cloud.google.com/go/auth v0.9.4/go.mod h1:SHia8n6//Ya940F1rLimhJCjjx7KE17t0ctFEci3HkA=
cloud.google.com/go/auth/oauth2adapt v0.2.0/go.mod h1:AfqujpDAlTfLfeCIl/HJZZlIxD8+nJoZ5e0x1IxGq5k=
cloud.google.com/go/auth/oauth2adapt v0.2.2/go.mod h1:wcYjgpZI9+Yu7LyYBg4pqSiaRkfEK3GQcpb7C/uyF1Q=
cloud.google.com/go/auth/oauth2adapt v0.2.4/go.mod h1:jC/jOpwFP6JBxhB3P5Rr0a9HLMC/Pe3eaL4NmdvqPtc=
cloud.google.com/go/automl v1.13.1/go.mod h1:1aowgAHWYZU27MybSCFiukPO7xnyawv7pt3zK4bheQE=
cloud.google.com/go/automl v1.13.2/go.mod h1:gNY/fUmDEN40sP8amAX3MaXkxcqPIn7F1UIIPZpy4Mg=
cloud.google.com/go/automl v1.13.3/go.mod h1:Y8KwvyAZFOsMAPqUCfNu1AyclbC6ivCUF/MTwORymyY=
@@ -226,6 +236,8 @@ cloud.google.com/go/compute v1.24.0/go.mod h1:kw1/T+h/+tK2LJK0wiPPx1intgdAM3j/g3
cloud.google.com/go/compute v1.28.1 h1:XwPcZjgMCnU2tkwY10VleUjSAfpTj9RDn+kGrbYsi8o=
cloud.google.com/go/compute v1.28.1/go.mod h1:b72iXMY4FucVry3NR3Li4kVyyTvbMDE7x5WsqvxjsYk=
cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY=
cloud.google.com/go/compute/metadata v0.5.2/go.mod h1:C66sj2AluDcIqakBq/M8lw8/ybHgOZqin2obFxa/E5k=
cloud.google.com/go/contactcenterinsights v1.9.1/go.mod h1:bsg/R7zGLYMVxFFzfh9ooLTruLRCG9fnzhH9KznHhbM=
cloud.google.com/go/contactcenterinsights v1.10.0/go.mod h1:bsg/R7zGLYMVxFFzfh9ooLTruLRCG9fnzhH9KznHhbM=
cloud.google.com/go/contactcenterinsights v1.11.0/go.mod h1:hutBdImE4XNZ1NV4vbPJKSFOnQruhC5Lj9bZqWMTKiU=
@@ -493,6 +505,8 @@ cloud.google.com/go/iam v1.1.3/go.mod h1:3khUlaBXfPKKe7huYgEpDn6FtgRyMEqbkvBxrQy
cloud.google.com/go/iam v1.1.4/go.mod h1:l/rg8l1AaA+VFMho/HYx2Vv6xinPSLMF8qfhRPIZ0L8=
cloud.google.com/go/iam v1.1.5/go.mod h1:rB6P/Ic3mykPbFio+vo7403drjlgvoWfYpJhMXEbzv8=
cloud.google.com/go/iam v1.1.6/go.mod h1:O0zxdPeGBoFdWW3HWmBxJsk0pfvNM/p/qa82rWOGTwI=
cloud.google.com/go/iam v1.1.8/go.mod h1:GvE6lyMmfxXauzNq8NbgJbeVQNspG+tcdL/W8QO1+zE=
cloud.google.com/go/iam v1.2.0/go.mod h1:zITGuWgsLZxd8OwAlX+eMFgZDXzBm7icj1PVTYG766Q=
cloud.google.com/go/iap v1.8.1/go.mod h1:sJCbeqg3mvWLqjZNsI6dfAtbbV1DL2Rl7e1mTyXYREQ=
cloud.google.com/go/iap v1.9.0/go.mod h1:01OFxd1R+NFrg78S+hoPV5PxEzv22HXaNqUUlmNHFuY=
cloud.google.com/go/iap v1.9.1/go.mod h1:SIAkY7cGMLohLSdBR25BuIxO+I4fXJiL06IBL7cy/5Q=
@@ -550,6 +564,9 @@ cloud.google.com/go/longrunning v0.5.2/go.mod h1:nqo6DQbNV2pXhGDbDMoN2bWz68MjZUz
cloud.google.com/go/longrunning v0.5.3/go.mod h1:y/0ga59EYu58J6SHmmQOvekvND2qODbu8ywBBW7EK7Y=
cloud.google.com/go/longrunning v0.5.4/go.mod h1:zqNVncI0BOP8ST6XQD1+VcvuShMmq7+xFSzOL++V0dI=
cloud.google.com/go/longrunning v0.5.5/go.mod h1:WV2LAxD8/rg5Z1cNW6FJ/ZpX4E4VnDnoTk0yawPBB7s=
cloud.google.com/go/longrunning v0.5.6/go.mod h1:vUaDrWYOMKRuhiv6JBnn49YxCPz2Ayn9GqyjaBT8/mA=
cloud.google.com/go/longrunning v0.5.7/go.mod h1:8GClkudohy1Fxm3owmBGid8W0pSgodEMwEAztp38Xng=
cloud.google.com/go/longrunning v0.6.0/go.mod h1:uHzSZqW89h7/pasCWNYdUpwGz3PcVWhrWupreVPYLts=
cloud.google.com/go/managedidentities v1.6.1/go.mod h1:h/irGhTN2SkZ64F43tfGPMbHnypMbu4RB3yl8YcuEak=
cloud.google.com/go/managedidentities v1.6.2/go.mod h1:5c2VG66eCa0WIq6IylRk3TBW83l161zkFvCj28X7jn8=
cloud.google.com/go/managedidentities v1.6.3/go.mod h1:tewiat9WLyFN0Fi7q1fDD5+0N4VUoL0SCX0OTCthZq4=
@@ -839,6 +856,7 @@ cloud.google.com/go/speech v1.21.1/go.mod h1:E5GHZXYQlkqWQwY5xRSLHw2ci5NMQNG52Ff
cloud.google.com/go/speech v1.25.1 h1:iGZJS3wrdkje/Vqiacx1+r+zVwUZoXVMdklYIVsvfNw=
cloud.google.com/go/speech v1.25.1/go.mod h1:WgQghvghkZ1htG6BhYn98mP7Tg0mti8dBFDLMVXH/vM=
cloud.google.com/go/storage v1.30.1/go.mod h1:NfxhC0UJE1aXSx7CIIbCf7y9HKT7BiccwkR7+P7gN8E=
cloud.google.com/go/storage v1.35.1/go.mod h1:M6M/3V/D3KpzMTJyPOR/HU6n2Si5QdaXYEsng2xgOs8=
cloud.google.com/go/storage v1.36.0/go.mod h1:M6M/3V/D3KpzMTJyPOR/HU6n2Si5QdaXYEsng2xgOs8=
cloud.google.com/go/storage v1.37.0/go.mod h1:i34TiT2IhiNDmcj65PqwCjcoUX7Z5pLzS8DEmoiFq1k=
cloud.google.com/go/storagetransfer v1.10.0/go.mod h1:DM4sTlSmGiNczmV6iZyceIh2dbs+7z2Ayg6YAiQlYfA=
@@ -884,6 +902,7 @@ cloud.google.com/go/translate v1.9.2/go.mod h1:E3Tc6rUTsQkVrXW6avbUhKJSr7ZE3j7zN
cloud.google.com/go/translate v1.9.3/go.mod h1:Kbq9RggWsbqZ9W5YpM94Q1Xv4dshw/gr/SHfsl5yCZ0=
cloud.google.com/go/translate v1.10.0/go.mod h1:Kbq9RggWsbqZ9W5YpM94Q1Xv4dshw/gr/SHfsl5yCZ0=
cloud.google.com/go/translate v1.10.1/go.mod h1:adGZcQNom/3ogU65N9UXHOnnSvjPwA/jKQUMnsYXOyk=
cloud.google.com/go/translate v1.10.3/go.mod h1:GW0vC1qvPtd3pgtypCv4k4U8B7EdgK9/QEF2aJEUovs=
cloud.google.com/go/translate v1.12.1 h1:Vws9BGpVcaOeI6HodyWdvysUzHUBFvk7ymHu1tzFvuM=
cloud.google.com/go/translate v1.12.1/go.mod h1:5f4RvC7/hh76qSl6LYuqOJaKbIzEpR1Sj+CMA6gSgIk=
cloud.google.com/go/video v1.17.1/go.mod h1:9qmqPqw/Ib2tLqaeHgtakU+l5TcJxCJbhFXM7UJjVzU=
@@ -1016,6 +1035,8 @@ github.com/ClickHouse/ch-go v0.61.5 h1:zwR8QbYI0tsMiEcze/uIMK+Tz1D3XZXLdNrlaOpeE
github.com/ClickHouse/ch-go v0.61.5/go.mod h1:s1LJW/F/LcFs5HJnuogFMta50kKDO0lf9zzfrbl0RQg=
github.com/ClickHouse/clickhouse-go/v2 v2.28.3 h1:SkFzPULX6nzgfNZd1YD1XTECivjTMrCtD09ZPKcVLFQ=
github.com/ClickHouse/clickhouse-go/v2 v2.28.3/go.mod h1:vzn73hp+3JwxtFU4RjPCQ7r6fP2pMKVwdi8E1/Tkua8=
github.com/ClickHouse/clickhouse-go/v2 v2.30.0 h1:AG4D/hW39qa58+JHQIFOSnxyL46H6h2lrmGGk17dhFo=
github.com/ClickHouse/clickhouse-go/v2 v2.30.0/go.mod h1:i9ZQAojcayW3RsdCb3YR+n+wC2h65eJsZCscZ1Z1wyo=
github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53 h1:sR+/8Yb4slttB4vD+b9btVEnWgL3Q00OBTzVT8B9C0c=
github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno=
github.com/CloudyKit/jet/v6 v6.2.0 h1:EpcZ6SR9n28BUGtNJSvlBqf90IpjeFr36Tizxhn/oME=
@@ -1101,6 +1122,7 @@ github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEq
github.com/antihax/optional v1.0.0 h1:xK2lYat7ZLaVVcIuj82J8kIro4V6kDe0AUDFboUCwcg=
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230512164433-5d1fd1a340c9 h1:goHVqTbFX3AIo0tzGr14pgfAW2ZfPChKO21Z9MGf/gk=
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230512164433-5d1fd1a340c9/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM=
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=
@@ -1302,8 +1324,10 @@ github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc=
github.com/edsrzf/mmap-go v1.1.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8EIth78Q=
github.com/efficientgo/tools/core v0.0.0-20220225185207-fe763185946b h1:ZHiD4/yE4idlbqvAO6iYCOYRzOMRpxkW+FKasRA3tsQ=
github.com/efficientgo/tools/core v0.0.0-20220225185207-fe763185946b/go.mod h1:OmVcnJopJL8d3X3sSXTiypGoUSgFq1aDGmlrdi9dn/M=
github.com/elastic/go-sysinfo v1.8.1/go.mod h1:JfllUnzoQV/JRYymbH3dO1yggI3mV2oTKSXsDHM+uIM=
github.com/elastic/go-sysinfo v1.11.2 h1:mcm4OSYVMyws6+n2HIVMGkln5HOpo5Ie1ZmbbNn0jg4=
github.com/elastic/go-sysinfo v1.11.2/go.mod h1:GKqR8bbMK/1ITnez9NIsIfXQr25aLhRJa7AfT8HpBFQ=
github.com/elastic/go-windows v1.0.0/go.mod h1:TsU0Nrp7/y3+VwE82FoZF8gC/XFg/Elz6CcloAxnPgU=
github.com/elastic/go-windows v1.0.1 h1:AlYZOldA+UJ0/2nBuqWdo90GFCgG9xuyw9SYzGUtJm0=
github.com/elastic/go-windows v1.0.1/go.mod h1:FoVvqWSun28vaDQPbj2Elfc0JahhPB7WQEGa3c814Ss=
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633 h1:H2pdYOb3KQ1/YsqVWoWNLQO+fusocsw354rqGTZtAgw=
@@ -1432,6 +1456,7 @@ github.com/google/go-pkcs11 v0.3.0/go.mod h1:6eQoGcuNJpa7jnd5pMGdkSaQpNDYvPlXWMc
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
github.com/google/pprof v0.0.0-20240416155748-26353dc0451f/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA=
github.com/google/renameio/v2 v2.0.0 h1:UifI23ZTGY8Tt29JbYFiuyIU3eX+RNFtUwefq9qAhxg=
@@ -1443,9 +1468,13 @@ github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
github.com/googleapis/enterprise-certificate-proxy v0.2.4/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k=
github.com/googleapis/enterprise-certificate-proxy v0.2.5/go.mod h1:RxW0N9901Cko1VOCW3SXCpWP+mlIEkk2tP7jnHy9a3w=
github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0=
github.com/googleapis/enterprise-certificate-proxy v0.3.3/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA=
github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU=
github.com/googleapis/gax-go/v2 v2.12.2/go.mod h1:61M8vcyyXR2kqKFxKrfA22jaA8JGF7Dc8App1U3H6jc=
github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4=
github.com/googleapis/gax-go/v2 v2.12.5/go.mod h1:BUDKcWo+RaKq5SC9vVYL0wLADa3VcfswbOMMRmB9H3E=
github.com/googleapis/gax-go/v2 v2.13.0/go.mod h1:Z/fvTZXF8/uw7Xu5GuslPw+bplx6SS338j1Is2S+B7A=
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-20210719221736-1c9a4c676720 h1:zC34cGQu69FG7qzJ3WiKW244WfhDC3xxYMeNOX2gtUQ=
@@ -1472,6 +1501,8 @@ github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJr
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0/go.mod h1:qmOFXW2epJhM0qSnUUYpldc7gVz2KMQwJ/QYCDIa7XU=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1/go.mod h1:5SN9VR2LTsRFsrEC6FHgRbTWrTHu6tqPeKxEQv15giM=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I=
github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 h1:MJG/KsmcqMwFAkh8mTnAwhyKoB+sTAnY4CACC110tbU=
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8=
github.com/hamba/avro/v2 v2.27.0 h1:IAM4lQ0VzUIKBuo4qlAiLKfqALSrFC+zi1iseTtbBKU=
@@ -1542,6 +1573,7 @@ github.com/jarcoal/httpmock v1.3.1 h1:iUx3whfZWVf3jT01hQTO/Eo5sAYtB2/rqaUuOtpInw
github.com/jarcoal/httpmock v1.3.1/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg=
github.com/jedib0t/go-pretty/v6 v6.2.4 h1:wdaj2KHD2W+mz8JgJ/Q6L/T5dB7kyqEFI16eLq7GEmk=
github.com/jedib0t/go-pretty/v6 v6.2.4/go.mod h1:+nE9fyyHGil+PuISTCrp7avEdo6bqoMwqZnuiK2r2a0=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jessevdk/go-flags v1.4.1-0.20181029123624-5de817a9aa20/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jhump/gopoet v0.1.0 h1:gYjOPnzHd2nzB37xYQZxj4EIQNpBrBskRqQQ3q4ZgSg=
github.com/jhump/goprotoc v0.5.0 h1:Y1UgUX+txUznfqcGdDef8ZOVlyQvnV0pKWZH08RmZuo=
@@ -1583,7 +1615,9 @@ github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg=
github.com/kisielk/sqlstruct v0.0.0-20201105191214-5f3e10d3ab46 h1:veS9QfglfvqAw2e+eeNT/SbGySq8ajECXJ9e4fPoLhY=
github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/klauspost/cpuid v1.3.1 h1:5JNjFYYQrZeKRJ0734q51WCEEn2huer72Dc7K+R/b6s=
github.com/klauspost/cpuid v1.3.1/go.mod h1:bYW4mA6ZgKPob1/Dlai2LviZJO7KGI3uoWLd42rAQw4=
github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
@@ -1635,6 +1669,8 @@ github.com/maxatome/go-testdeep v1.12.0 h1:Ql7Go8Tg0C1D/uMMX59LAoYK7LffeJQ6X2T04
github.com/maxatome/go-testdeep v1.12.0/go.mod h1:lPZc/HAcJMP92l7yI6TRz1aZN5URwUBUAfUNvrclaNM=
github.com/mfridman/xflag v0.0.0-20240825232106-efb77353e578 h1:CRrqlUmLebb/QjzRDWE0E66+YyN/v95+w6WyH9ju8/Y=
github.com/mfridman/xflag v0.0.0-20240825232106-efb77353e578/go.mod h1:/483ywM5ZO5SuMVjrIGquYNE5CzLrj5Ux/LxWWnjRaE=
github.com/mfridman/xflag v0.1.0 h1:TWZrZwG1QklFX5S4j1vxfF1sZbZeZSGofMwPMLAF29M=
github.com/mfridman/xflag v0.1.0/go.mod h1:/483ywM5ZO5SuMVjrIGquYNE5CzLrj5Ux/LxWWnjRaE=
github.com/microcosm-cc/bluemonday v1.0.25 h1:4NEwSfiJ+Wva0VxN5B8OwMicaJvD8r9tlJWm9rtloEg=
github.com/microcosm-cc/bluemonday v1.0.25/go.mod h1:ZIOjCQp1OrzBBPIJmfX4qDYFuhU02nx4bn030ixfHLE=
github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
@@ -1772,6 +1808,7 @@ github.com/open-telemetry/opentelemetry-collector-contrib/receiver/zipkinreceive
github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
github.com/opencontainers/runtime-spec v1.0.2 h1:UfAcuLBJB9Coz72x1hgl8O5RVzTdNiaglX6v2DM6FI0=
github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/openfga/api/proto v0.0.0-20240905181937-3583905f61a6/go.mod h1:gil5LBD8tSdFQbUkCQdnXsoeU9kDJdJgbGdHkgJfcd0=
github.com/openzipkin/zipkin-go v0.2.5/go.mod h1:KpXfKdgRDnnhsxw4pNIH9Md5lyFqKUa4YDFlwRYAMyE=
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde h1:x0TT0RDC7UhAVbbWWBzr41ElhJx5tXPWkIHA2HWPRuw=
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=
@@ -1785,11 +1822,13 @@ github.com/parquet-go/parquet-go v0.23.0 h1:dyEU5oiHCtbASyItMCD2tXtT2nPmoPbKpqf0
github.com/parquet-go/parquet-go v0.23.0/go.mod h1:MnwbUcFHU6uBYMymKAlPPAw9yh3kE1wWl6Gl1uLdkNk=
github.com/paulmach/orb v0.11.1 h1:3koVegMC4X/WeiXYz9iswopaTwMem53NzTJuTF20JzU=
github.com/paulmach/orb v0.11.1/go.mod h1:5mULz1xQfs3bmQm63QEJA6lNGujuRafwA5S/EnuLaLU=
github.com/paulmach/protoscan v0.2.1/go.mod h1:SpcSwydNLrxUGSDvXvO0P7g7AuhJ7lcKfDlhJCDw2gY=
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0=
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y=
github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30 h1:BHT1/DKsYDGkUgQ2jmMaozVcdk+sVfz0+1ZJq4zkWgw=
github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g=
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/performancecopilot/speed/v4 v4.0.0 h1:VxEDCmdkfbQYDlcr/GC9YoN9PQ6p8ulk9xVsepYy9ZY=
github.com/performancecopilot/speed/v4 v4.0.0/go.mod h1:qxrSyuDGrTOWfV+uKRFhfxw6h/4HXRGUiZiufxo49BM=
github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
@@ -1812,10 +1851,13 @@ github.com/pquerna/cachecontrol v0.1.0 h1:yJMy84ti9h/+OEWa752kBTKv4XC30OtVVHYv/8
github.com/pquerna/cachecontrol v0.1.0/go.mod h1:NrUG3Z7Rdu85UNR3vm7SOsl1nFIeSiQnrHV5K9mBcUI=
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
github.com/prometheus/client_golang v1.20.4/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8=
github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
github.com/prometheus/common v0.53.0/go.mod h1:BrxBKv3FWBIGXw89Mg1AeBq7FSyRzXWI3l3e7W3RN5U=
github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
github.com/prometheus/common/assets v0.2.0 h1:0P5OrzoHrYBOSM1OigWL3mY8ZvV2N4zIE/5AahrSrfM=
github.com/prometheus/procfs v0.0.0-20190425082905-87a4384529e0/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/prometheus v0.52.0 h1:f7kHJgr7+zShpWdTCeKqbCWR7nKTScgLYQwRux9h1V0=
github.com/prometheus/prometheus v0.52.0/go.mod h1:3z74cVsmVH0iXOR5QBjB7Pa6A0KJeEAK5A6UsmAFb1g=
github.com/prometheus/statsd_exporter v0.26.0 h1:SQl3M6suC6NWQYEzOvIv+EF6dAMYEqIuZy+o4H9F5Ig=
@@ -1859,8 +1901,10 @@ github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
github.com/spf13/afero v1.10.0/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ=
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
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/stoewer/parquet-cli v0.0.7 h1:rhdZODIbyMS3twr4OM3am8BPPT5pbfMcHLH93whDM5o=
github.com/stoewer/parquet-cli v0.0.7/go.mod h1:bskxHdj8q3H1EmfuCqjViFoeO3NEvs5lzZAQvI8Nfjk=
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
@@ -1880,6 +1924,8 @@ github.com/tdewolff/parse/v2 v2.6.8 h1:mhNZXYCx//xG7Yq2e/kVLNZw4YfYmeHbhx+Zc0OvF
github.com/tdewolff/parse/v2 v2.6.8/go.mod h1:XHDhaU6IBgsryfdnpzUXBlT6leW/l25yrFBTEb4eIyM=
github.com/tidwall/gjson v1.17.3 h1:bwWLZU7icoKRG+C+0PNwIKC6FCJO/Q3p2pZvuP0jN94=
github.com/tidwall/gjson v1.17.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
@@ -1919,7 +1965,9 @@ github.com/willf/bloom v2.0.3+incompatible h1:QDacWdqcAUI1MPOwIQZRy9kOR7yxfyEmxX
github.com/willf/bloom v2.0.3+incompatible/go.mod h1:MmAltL9pDMNTrvUkxdg0k0q5I0suxmuwp3KbyrZLOZ8=
github.com/xanzy/go-gitlab v0.15.0 h1:rWtwKTgEnXyNUGrOArN7yyc3THRkpYcKXIXia9abywQ=
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g=
github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8=
github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c h1:u40Z8hqBAAQyv+vATcGgV0YCnDjqSL7/q/JyPhhJSPk=
github.com/xdg/stringprep v1.0.0 h1:d9X0esnoa3dFsV0FG35rAT0RIhYFlPq7MiP+DW89La0=
@@ -1936,8 +1984,12 @@ github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77 h1:ESFSdwYZvkeru3RtdrYueztKhOBCSAAzS4Gf+k0tEow=
github.com/ydb-platform/ydb-go-genproto v0.0.0-20240528144234-5d5a685e41f7 h1:nL8XwD6fSst7xFUirkaWJmE7kM0CdWRYgu6+YQer1d4=
github.com/ydb-platform/ydb-go-genproto v0.0.0-20240528144234-5d5a685e41f7/go.mod h1:Er+FePu1dNUieD+XTMDduGpQuCPssK5Q4BjF+IIXJ3I=
github.com/ydb-platform/ydb-go-genproto v0.0.0-20241112172322-ea1f63298f77 h1:LY6cI8cP4B9rrpTleZk95+08kl2gF4rixG7+V/dwL6Q=
github.com/ydb-platform/ydb-go-genproto v0.0.0-20241112172322-ea1f63298f77/go.mod h1:Er+FePu1dNUieD+XTMDduGpQuCPssK5Q4BjF+IIXJ3I=
github.com/ydb-platform/ydb-go-sdk/v3 v3.80.2 h1:qmZGJQCNx09/r0HDIT2cDDogiOvWikELy13ubM2CFS8=
github.com/ydb-platform/ydb-go-sdk/v3 v3.80.2/go.mod h1:IHwuXyolaAmGK2Dp7+dlhsnXphG1pwCoaP/OITT3+tU=
github.com/ydb-platform/ydb-go-sdk/v3 v3.95.3 h1:pgsQPKSFfRFy3JSZMUReCF4CSEwgxA+a5GymvtyRJO0=
github.com/ydb-platform/ydb-go-sdk/v3 v3.95.3/go.mod h1:WiezFS4YCi2vHqbYGQkeu/2MDBYFLix6dIs/pd87Yck=
github.com/yosssi/ace v0.0.5 h1:tUkIP/BLdKqrlrPwcmH0shwEEhTRHoGnc1wFIWmaBUA=
github.com/yosssi/ace v0.0.5/go.mod h1:ALfIzm2vT7t5ZE7uoIZqF3TQ7SAOyupFZnkrF5id+K0=
github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE=
@@ -1958,6 +2010,7 @@ go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsX
go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0=
go.etcd.io/gofail v0.1.0 h1:XItAMIhOojXFQMgrxjnd2EIIHun/d5qL0Pf7FzVTkFg=
go.etcd.io/gofail v0.1.0/go.mod h1:VZBCXYGZhHAinaBiiqYvuDynvahNsAyLFwB3kEHKz1M=
go.mongodb.org/mongo-driver v1.11.4/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g=
go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c=
go.opentelemetry.io/collector v0.102.1 h1:M/ciCcReQsSDYG9bJ2Qwqk7pQILDJ2bM/l0MdeCAvJE=
go.opentelemetry.io/collector v0.102.1/go.mod h1:yF1lDRgL/Eksb4/LUnkMjvLvHHpi6wqBVlzp+dACnPM=
@@ -2039,10 +2092,12 @@ go.opentelemetry.io/contrib/exporters/autoexport v0.53.0/go.mod h1:lyQF6xQ4iDnMg
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1/go.mod h1:4UoMYEZOC0yN/sPGH76KPkkU7zgiEWYWL9vwmbnTJPE=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0/go.mod h1:r9vWsPS/3AQItv3OSlEJ/E4mbrhUbbw18meOjArPtKQ=
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/net/http/otelhttp v0.46.1/go.mod h1:sEGXWArGqc3tVa+ekntsN65DmVbVeW+7lTKTjZF3/Fo=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0/go.mod h1:SK2UL73Zy1quvRPonmOmRDiWk1KBV3LyIeeIxcEApWw=
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.50.0/go.mod h1:DKdbWcT4GH1D0Y3Sqt/PFXt2naRKDWtU+eE6oLdFNA8=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8=
go.opentelemetry.io/contrib/propagators/b3 v1.27.0 h1:IjgxbomVrV9za6bRi8fWCNXENs0co37SZedQilP2hm0=
go.opentelemetry.io/contrib/propagators/b3 v1.27.0/go.mod h1:Dv9obQz25lCisDvvs4dy28UPh974CxkahRDUPsY7y9E=
go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY=
@@ -2050,6 +2105,9 @@ go.opentelemetry.io/otel v1.22.0/go.mod h1:eoV4iAi3Ea8LkAEI9+GFT44O6T/D0GWAVFyZV
go.opentelemetry.io/otel v1.23.0/go.mod h1:YCycw9ZeKhcJFrb34iVSkyT0iczq/zYDtZYFufObyB0=
go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo=
go.opentelemetry.io/otel v1.25.0/go.mod h1:Wa2ds5NOXEMkCmUou1WA7ZBfLTHWIsp034OVD7AO+Vg=
go.opentelemetry.io/otel v1.26.0/go.mod h1:UmLkJHUAidDval2EICqBMbnAd0/m2vmpf/dAM+fvFs4=
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.27.0 h1:ao9aGGHd+G4YfjBpGs6vbkvt5hoC67STlJA9fCnOAcs=
go.opentelemetry.io/otel/bridge/opencensus v1.27.0/go.mod h1:uRvWtAAXzyVOST0WMPX5JHGBaAvBws+2F8PcC5gMnTk=
go.opentelemetry.io/otel/bridge/opentracing v1.26.0 h1:Q/dHj0DOhfLMAs5u5ucAbC7gy66x9xxsZRLpHCJ4XhI=
@@ -2060,6 +2118,7 @@ go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.28.0 h1:aLm
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.28.0/go.mod h1:TC1pyCt6G9Sjb4bQpShH+P5R53pO6ZuGnHuuln9xMeE=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.25.0/go.mod h1:h95q0LBGh7hlAC08X2DhSeyIG02YQ0UyioTCVAqRPmc=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.25.0/go.mod h1:8GlBGcDk8KKi7n+2S4BT/CPZQYH3erLu0/k64r1MYgo=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.22.0/go.mod h1:hYwym2nDEeZfG/motx0p7L7J1N1vyzIThemQsb4g2qY=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.25.0/go.mod h1:e7ciERRhZaOZXVjx5MiL8TK5+Xv7G5Gv5PA2ZDEJdL8=
go.opentelemetry.io/otel/exporters/prometheus v0.50.0 h1:2Ewsda6hejmbhGFyUvWZjUThC98Cf8Zy6g0zkIimOng=
go.opentelemetry.io/otel/exporters/prometheus v0.50.0/go.mod h1:pMm5PkUo5YwbLiuEf7t2xg4wbP0/eSJrMxIMxKosynY=
@@ -2074,13 +2133,21 @@ go.opentelemetry.io/otel/metric v1.22.0/go.mod h1:evJGjVpZv0mQ5QBRJoBF64yMuOf4xC
go.opentelemetry.io/otel/metric v1.23.0/go.mod h1:MqUW2X2a6Q8RN96E2/nqNoT+z9BSms20Jb7Bbp+HiTo=
go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco=
go.opentelemetry.io/otel/metric v1.25.0/go.mod h1:rkDLUSd2lC5lq2dFNrX9LGAbINP5B7WBkC78RXCpH5s=
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.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A=
go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg=
go.opentelemetry.io/otel/sdk v1.25.0/go.mod h1:oFgzCM2zdsxKzz6zwpTZYLLQsFwc+K0daArPdIhuxkw=
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/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo=
go.opentelemetry.io/otel/trace v1.22.0/go.mod h1:RbbHXVqKES9QhzZq/fE5UnOSILqRt40a21sPw2He1xo=
go.opentelemetry.io/otel/trace v1.23.0/go.mod h1:GSGTbIClEsuZrGIzoEHqsVfxgn5UkggkflQwDScNUsk=
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
go.opentelemetry.io/otel/trace v1.25.0/go.mod h1:hCCs70XM/ljO+BeQkyFnbK28SBIJ/Emuha+ccrCRT7I=
go.opentelemetry.io/otel/trace v1.26.0/go.mod h1:4iDxvGDQuUkHve82hJJ8UqrwswHYsZuWCBllGV2U2y0=
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.1.0/go.mod h1:GpBHCBWiqvVLDqmHZsoMM3C5ySeKTC7ej/RNTae6MdY=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
@@ -2106,13 +2173,21 @@ golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98y
golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/exp v0.0.0-20220328175248-053ad81199eb/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
golang.org/x/exp v0.0.0-20230206171751-46f607a40771/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08=
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ=
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
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.14.0 h1:tNgSxAFe3jC4uYqvZdTr84SZoM1KfwdC9SKIFrLjFn4=
@@ -2128,6 +2203,9 @@ golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
@@ -2144,6 +2222,12 @@ golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI=
golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk=
golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0=
@@ -2152,8 +2236,12 @@ golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCA
golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA=
golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8=
golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8=
golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -2170,6 +2258,12 @@ golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.25.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/telemetry v0.0.0-20240208230135-b75ee8823808/go.mod h1:KG1lNk5ZFNssSZLrpVb4sMXKMpGwGXOxSG3rnu2gZQQ=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
@@ -2184,9 +2278,14 @@ golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
@@ -2198,6 +2297,7 @@ golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4=
golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM=
golang.org/x/tools v0.11.0/go.mod h1:anzJrxPjNtfgiYQYirP2CPGzGLxrH2u2QBhn6Bf3qY8=
golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM=
golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM=
golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg=
@@ -2205,6 +2305,10 @@ golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0
golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg=
golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc=
golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg=
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
gonum.org/v1/gonum v0.12.0/go.mod h1:73TDxJfAAHeA8Mk9mf8NlIppyhQNo5GLTcYeqgo2lvY=
gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0 h1:OE9mWmgKkjJyEmDAAtGMPjXu+YNeGvK9VTSHY6+Qihc=
@@ -2215,6 +2319,7 @@ google.golang.org/api v0.128.0/go.mod h1:Y611qgqaE92On/7g65MQgxYul3c0rEB894kniWL
google.golang.org/api v0.139.0/go.mod h1:CVagp6Eekz9CjGZ718Z+sloknzkDJE7Vc1Ckj9+viBk=
google.golang.org/api v0.149.0/go.mod h1:Mwn1B7JTXrzXtnvmzQE2BD6bYZQ8DShKZDZbeN9I7qI=
google.golang.org/api v0.150.0/go.mod h1:ccy+MJ6nrYFgE3WgRx/AMXOxOmU8Q4hSa+jjibzhxcg=
google.golang.org/api v0.152.0/go.mod h1:3qNJX5eOmhiWYc67jRA/3GsDw97UFb5ivv7Y2PrriAY=
google.golang.org/api v0.155.0/go.mod h1:GI5qK5f40kCpHfPn6+YzGAByIKWv8ujFnmoWm7Igduk=
google.golang.org/api v0.157.0/go.mod h1:+z4v4ufbZ1WEpld6yMGHyggs+PmAHiaLNj5ytP3N01g=
google.golang.org/api v0.160.0/go.mod h1:0mu0TpK33qnydLvWqbImq2b1eQ5FHRSDCBzAxX9ZHyw=
@@ -2222,6 +2327,11 @@ google.golang.org/api v0.162.0/go.mod h1:6SulDkfoBIg4NFmCuZ39XeeAgSHCPecfSUuDyYl
google.golang.org/api v0.164.0/go.mod h1:2OatzO7ZDQsoS7IFf3rvsE17/TldiU3F/zxFHeqUB5o=
google.golang.org/api v0.169.0/go.mod h1:gpNOiMA2tZ4mf5R9Iwf4rK/Dcz0fbdIgWYWVoxmsyLg=
google.golang.org/api v0.174.0/go.mod h1:aC7tB6j0HR1Nl0ni5ghpx6iLasmAX78Zkh/wgxAAjLg=
google.golang.org/api v0.177.0/go.mod h1:srbhue4MLjkjbkux5p3dw/ocYOSZTaIEvf7bCOnFQDw=
google.golang.org/api v0.187.0/go.mod h1:KIHlTc4x7N7gKKuVsdmfBXN13yEEWXWFURWY6SBp2gk=
google.golang.org/api v0.196.0/go.mod h1:g9IL21uGkYgvQ5BZg6BAtoGJQIm8r6EgaAbpNey5wBE=
google.golang.org/api v0.197.0/go.mod h1:AuOuo20GoQ331nq7DquGHlU6d+2wN2fZ8O0ta60nRNw=
google.golang.org/api v0.211.0/go.mod h1:XOloB4MXFH4UTlQSGuNUxw0UT74qdENK8d6JNsXKLi0=
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-20210917145530-b395a37504d4/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
@@ -2251,6 +2361,8 @@ google.golang.org/genproto v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:cc8bqMqt
google.golang.org/genproto v0.0.0-20240205150955-31a09d347014/go.mod h1:xEgQu1e4stdSSsxPDK8Azkrk/ECl5HvdPf6nbZrTS5M=
google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:mqHbVIp48Muh7Ywss/AD6I5kNVKZMmAa/QEW58Gxp2s=
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo=
google.golang.org/genproto v0.0.0-20240624140628-dc46fd24d27d/go.mod h1:s7iA721uChleev562UJO2OYB0PPT9CMFjV+Ce7VJH5M=
google.golang.org/genproto v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:hL97c3SYopEHblzpxRL4lSs523++l8DYxGM1FQiYmb4=
google.golang.org/genproto/googleapis/api v0.0.0-20230629202037-9506855d4529/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig=
google.golang.org/genproto/googleapis/api v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:mPBs5jNgx2GuQGvFwUvVKqtn6HsUw9nP64BedgvqEsQ=
google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ=
@@ -2277,6 +2389,14 @@ google.golang.org/genproto/googleapis/api v0.0.0-20240213162025-012b6fc9bca9/go.
google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:5iCWqnniDlqZHrd3neWVTOwvh/v6s3232omMecelax8=
google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2/go.mod h1:O1cOfN1Cy6QEYr7VxtjOyP5AdAuR0aJ/MYZaaof623Y=
google.golang.org/genproto/googleapis/api v0.0.0-20240415180920-8c6c420018be/go.mod h1:dvdCTIoAGbkWbcIKBniID56/7XHTt6WfxXNMxuziJ+w=
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-20240528184218-531527333157/go.mod h1:99sLkeliLXfdj2J75X3Ho+rrVCaJze0uwN7zDDkjPVU=
google.golang.org/genproto/googleapis/api v0.0.0-20240617180043-68d350f18fd4/go.mod h1:px9SlOOZBg1wM1zdnr8jEL4CNGUBZ+ZKYtNPApNQc4c=
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-20240903143218-8af14fe29dc1/go.mod h1:qpvKtACPCQhAdu3PyQgV4l3LMXZEtft7y8QcarRsp9I=
google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53/go.mod h1:riSXTwQ4+nqmPGtobMFyW5FqVAmIs0St6VPp4Ug7CE4=
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-20241219192143-6b3ec007d9bb/go.mod h1:E5//3O5ZIG2l71Xnt+P/CYUY8Bxs8E7WMoZ9tlcMbAY=
google.golang.org/genproto/googleapis/bytestream v0.0.0-20230807174057-1744710a1577/go.mod h1:NjCQG/D8JandXxM57PZbAJL1DCNL6EypA0vPPwfsc7c=
google.golang.org/genproto/googleapis/bytestream v0.0.0-20231030173426-d783a09b4405/go.mod h1:GRUCuLdzVqZte8+Dl/D4N25yLzcGqqWaYkeVOwulFqw=
google.golang.org/genproto/googleapis/bytestream v0.0.0-20231212172506-995d672761c0/go.mod h1:guYXGPwC6jwxgWKW5Y405fKWOFNwlvUlUnzyp9i0uqo=
@@ -2315,9 +2435,20 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20240228201840-1f18d85a4ec2/go.
google.golang.org/genproto/googleapis/rpc v0.0.0-20240228224816-df926f6c8641/go.mod h1:UCOku4NytXMJuLQE5VuqA5lX3PcHCBo8pxNyvkf4xBs=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240304161311-37d4d3c04a78/go.mod h1:UCOku4NytXMJuLQE5VuqA5lX3PcHCBo8pxNyvkf4xBs=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240311132316-a219d84964c2/go.mod h1:UCOku4NytXMJuLQE5VuqA5lX3PcHCBo8pxNyvkf4xBs=
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-20240401170217-c3f982113cda/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240415141817-7cd4c1c1f9ec/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be/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-20240528184218-531527333157/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240624140628-dc46fd24d27d/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240826202546-f6391c0de4c7/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241206012308-a4fef0638583/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-20241219192143-6b3ec007d9bb/go.mod h1:lcTa1sDdWEIHMWlITnIczmw5w60CF9ffkb8Z+DVmmjA=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8/go.mod h1:lcTa1sDdWEIHMWlITnIczmw5w60CF9ffkb8Z+DVmmjA=
google.golang.org/grpc v1.52.3/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY=
google.golang.org/grpc v1.56.1/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s=
google.golang.org/grpc v1.56.2/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s=
@@ -2333,8 +2464,19 @@ google.golang.org/grpc v1.62.0/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJai
google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE=
google.golang.org/grpc v1.63.0/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA=
google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA=
google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg=
google.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0=
google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
google.golang.org/grpc v1.66.2/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA=
google.golang.org/grpc v1.68.1/go.mod h1:+q1XYFJjShcqn0QZHvCyeR4CXPA+llXIeUIfIe00waw=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 h1:M1YKkFIboKNieVO5DLUEVzQfGwJD30Nv2jfUgzb5UcE=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
google.golang.org/protobuf v1.36.0/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=
@@ -2349,10 +2491,13 @@ gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzE
gopkg.in/telebot.v3 v3.2.1 h1:3I4LohaAyJBiivGmkfB+CiVu7QFOWkuZ4+KHgO/G3rs=
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg=
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
gotest.tools/v3 v3.5.0/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
honnef.co/go/tools v0.3.2 h1:ytYb4rOqyp1TSa2EPvNVwtPQJctSELKaMyLfqNP4+34=
honnef.co/go/tools v0.3.2/go.mod h1:jzwdWgg7Jdq75wlfblQxO4neNaFFSvgc1tD5Wv8U0Yw=
howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0=
howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM=
howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g=
k8s.io/api v0.29.3/go.mod h1:y2yg2NTyHUUkIoTC+phinTnEa3KFM6RZ3szxt014a80=
@@ -2406,6 +2551,7 @@ modernc.org/memory v1.4.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
modernc.org/sqlite v1.18.2/go.mod h1:kvrTLEWgxUcHa2GfHBQtanR1H9ht3hTJNtKpzH9k1u0=
modernc.org/sqlite v1.21.2/go.mod h1:cxbLkB5WS32DnQqeH4h4o1B0eMr8W/y8/RGuxQ3JsC0=
modernc.org/sqlite v1.34.1/go.mod h1:pXV2xHxhzXZsgT/RtTFAPY6JJDEvOTcTdwADQCCWD4k=
modernc.org/tcl v1.13.1 h1:npxzTwFTZYM8ghWicVIX1cRWzj7Nd8i6AqqX2p+IYao=
modernc.org/tcl v1.13.2/go.mod h1:7CLiGIPo1M8Rv1Mitpv5akc2+8fxUd2y2UzC/MfMzy0=
modernc.org/tcl v1.15.1 h1:mOQwiEK4p7HruMZcwKTZPw/aqtGM4aY00uzWhlKKYws=
+4 -5
View File
@@ -291,10 +291,10 @@
"@opentelemetry/exporter-collector": "0.25.0",
"@opentelemetry/semantic-conventions": "1.28.0",
"@popperjs/core": "2.11.8",
"@react-aria/dialog": "3.5.20",
"@react-aria/focus": "3.19.0",
"@react-aria/overlays": "3.24.0",
"@react-aria/utils": "3.26.0",
"@react-aria/dialog": "3.5.21",
"@react-aria/focus": "3.19.1",
"@react-aria/overlays": "3.25.0",
"@react-aria/utils": "3.27.0",
"@react-awesome-query-builder/ui": "6.6.4",
"@reduxjs/toolkit": "2.5.0",
"@visx/event": "3.12.0",
@@ -359,7 +359,6 @@
"pluralize": "^8.0.0",
"prismjs": "1.29.0",
"rc-slider": "11.1.8",
"rc-time-picker": "3.7.3",
"rc-tree": "5.13.0",
"re-resizable": "6.10.3",
"react": "18.2.0",
@@ -42,7 +42,10 @@ describe('ensureColumns transformer', () => {
options: {},
};
const data = [seriesA, seriesBC];
const data = [
{ refId: 'A', ...seriesA },
{ refId: 'B', ...seriesBC },
];
await expect(transformDataFrame([cfg], data)).toEmitValuesWith((received) => {
const filtered = received[0];
@@ -109,6 +112,7 @@ describe('ensureColumns transformer', () => {
},
],
"length": 2,
"refId": "joinByField-A-B",
}
`);
});
@@ -592,5 +592,6 @@ export function histogramFieldsToFrame(info: HistogramFields, theme?: GrafanaThe
type: DataFrameType.Histogram,
},
fields: [info.xMin, info.xMax, ...info.counts],
refId: `${DataTransformerID.histogram}`,
};
}
@@ -42,6 +42,7 @@ export const joinByFieldTransformer: SynchronousDataTransformerInfo<JoinByFieldO
}
const joined = joinDataFrames({ frames: data, joinBy, mode: options.mode });
if (joined) {
joined.refId = `${DataTransformerID.joinByField}-${data.map((frame) => frame.refId).join('-')}`;
return [joined];
}
}
@@ -43,7 +43,10 @@ export const mergeTransformer: DataTransformerInfo<MergeTransformerOptions> = {
const fieldNames = new Set<string>();
const fieldIndexByName: Record<string, Record<number, number>> = {};
const fieldNamesForKey: string[] = [];
const dataFrame = new MutableDataFrame();
const dataFrame = new MutableDataFrame({
refId: `${DataTransformerID.merge}-${data.map((frame) => frame.refId).join('-')}`,
fields: [],
});
for (let frameIndex = 0; frameIndex < data.length; frameIndex++) {
const frame = data[frameIndex];
@@ -56,7 +56,9 @@ export const reduceTransformer: DataTransformerInfo<ReduceTransformerOptions> =
// Add a row for each series
const res = reduceSeriesToRows(data, matcher, options.reducers, options.labelsToFields);
return res ? [res] : [];
return res
? [{ ...res, refId: `${DataTransformerID.reduce}-${data.map((frame) => frame.refId).join('-')}` }]
: [];
})
),
};
@@ -37,7 +37,10 @@ export const seriesToRowsTransformer: DataTransformerInfo<SeriesToRowsTransforme
const timeFieldByIndex: Record<number, number> = {};
const targetFields = new Set<string>();
const dataFrame = new MutableDataFrame();
const dataFrame = new MutableDataFrame({
refId: `${DataTransformerID.seriesToRows}-${data.map((frame) => frame.refId).join('-')}`,
fields: [],
});
const metricField: Field = {
name: TIME_SERIES_METRIC_FIELD_NAME,
values: [],
@@ -80,6 +80,7 @@ function transposeDataFrame(options: TransposeTransformerOptions, data: DataFram
...frame,
fields: newFields,
length: Math.max(...newFields.map((field) => field.values.length)),
refId: `${DataTransformerID.transpose}-${frame.refId}`,
};
});
}
@@ -112,4 +112,24 @@ describe('addLabelToQuery()', () => {
it('should not add ad-hoc filter bool operator', () => {
expect(addLabelToQuery('ALERTS < bool 1', 'bar', 'baz')).toBe('ALERTS{bar="baz"} < bool 1');
});
it('should add a utf8 label', () => {
expect(addLabelToQuery('{"metric.name"}', 'cenk.erdem', 'muhabbet')).toBe(
'{"metric.name", "cenk.erdem"="muhabbet"}'
);
expect(addLabelToQuery('metric{label="val"}', 'cenk.erdem', 'muhabbet')).toBe(
'metric{label="val", "cenk.erdem"="muhabbet"}'
);
});
it('should not add a utf8 label when it is already applied', () => {
expect(addLabelToQuery('{"metric.name", "cenk.erdem"="muhabbet"}', 'cenk.erdem', 'muhabbet')).toBe(
'{"metric.name", "cenk.erdem"="muhabbet"}'
);
expect(addLabelToQuery('metric{label="val", "cenk.erdem"="muhabbet"}', 'cenk.erdem', 'muhabbet')).toBe(
'metric{label="val", "cenk.erdem"="muhabbet"}'
);
});
});
@@ -54,6 +54,49 @@ describe('buildSelector()', () => {
];
expect(buildSelector(labels)).toEqual('foo{bar="baz"}');
});
describe('utf8 support', () => {
it('metric selector with utf8 metric', () => {
const labels: SelectableLabel[] = [
{ name: '__name__', selected: true, values: [{ name: 'utf8.metric', selected: true }] },
];
expect(buildSelector(labels)).toEqual('{"utf8.metric"}');
});
it('metric selector with utf8 labels', () => {
const labels: SelectableLabel[] = [
{ name: '__name__', selected: true, values: [{ name: 'foo', selected: true }] },
{ name: 'utf8.label', selected: true, values: [{ name: 'baz', selected: true }] },
];
expect(buildSelector(labels)).toEqual('foo{"utf8.label"="baz"}');
});
it('metric selector with utf8 labels and metrics', () => {
const labels: SelectableLabel[] = [
{ name: '__name__', selected: true, values: [{ name: 'utf8.metric', selected: true }] },
{ name: 'utf8.label', selected: true, values: [{ name: 'baz', selected: true }] },
];
expect(buildSelector(labels)).toEqual('{"utf8.metric","utf8.label"="baz"}');
});
it('metric selector with utf8 metric and with utf8/non-utf8 labels', () => {
const labels: SelectableLabel[] = [
{ name: '__name__', selected: true, values: [{ name: 'utf8.metric', selected: true }] },
{ name: 'utf8.label', selected: true, values: [{ name: 'uuu', selected: true }] },
{ name: 'bar', selected: true, values: [{ name: 'baz', selected: true }] },
];
expect(buildSelector(labels)).toEqual('{"utf8.metric","utf8.label"="uuu",bar="baz"}');
});
it('metric selector with non-utf8 metric with utf8/non-utf8 labels', () => {
const labels: SelectableLabel[] = [
{ name: '__name__', selected: true, values: [{ name: 'foo', selected: true }] },
{ name: 'utf8.label', selected: true, values: [{ name: 'uuu', selected: true }] },
{ name: 'bar', selected: true, values: [{ name: 'baz', selected: true }] },
];
expect(buildSelector(labels)).toEqual('foo{"utf8.label"="uuu",bar="baz"}');
});
});
});
describe('facetLabels()', () => {
@@ -19,6 +19,7 @@ import {
import PromQlLanguageProvider from '../language_provider';
import { escapeLabelValueInExactSelector, escapeLabelValueInRegexSelector } from '../language_utils';
import { isValidLegacyName, utf8Support } from '../utf8_support';
// Hard limit on labels to render
const EMPTY_SELECTOR = '{}';
@@ -68,22 +69,38 @@ export interface SelectableLabel {
export function buildSelector(labels: SelectableLabel[]): string {
let singleMetric = '';
const selectedLabels = [];
const selectedLabels: string[] = [];
for (const label of labels) {
if ((label.name === METRIC_LABEL || label.selected) && label.values && label.values.length > 0) {
const selectedValues = label.values.filter((value) => value.selected).map((value) => value.name);
if (selectedValues.length > 1) {
selectedLabels.push(`${label.name}=~"${selectedValues.map(escapeLabelValueInRegexSelector).join('|')}"`);
selectedLabels.push(
`${utf8Support(label.name)}=~"${selectedValues.map(escapeLabelValueInRegexSelector).join('|')}"`
);
} else if (selectedValues.length === 1) {
if (label.name === METRIC_LABEL) {
singleMetric = selectedValues[0];
} else {
selectedLabels.push(`${label.name}="${escapeLabelValueInExactSelector(selectedValues[0])}"`);
selectedLabels.push(`${utf8Support(label.name)}="${escapeLabelValueInExactSelector(selectedValues[0])}"`);
}
}
}
}
return [singleMetric, '{', selectedLabels.join(','), '}'].join('');
const selectorParts: string[] = [];
const isLegacyName = singleMetric === '' || isValidLegacyName(singleMetric);
if (isLegacyName) {
selectorParts.push(singleMetric, '{');
} else {
selectorParts.push('{', `"${singleMetric}"`);
if (selectedLabels.length > 0) {
selectorParts.push(',');
}
}
selectorParts.push(selectedLabels.join(','), '}');
return selectorParts.join('');
}
export function facetLabels(
@@ -1,11 +1,13 @@
// Core grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/prometheus/components/monaco-query-field/monaco-completion-provider/completions.ts
import UFuzzy from '@leeoniya/ufuzzy';
import { languages } from 'monaco-editor';
import { config } from '@grafana/runtime';
import { prometheusRegularEscape } from '../../../datasource';
import { escapeLabelValueInExactSelector } from '../../../language_utils';
import { FUNCTIONS } from '../../../promql';
import { isValidLegacyName } from '../../../utf8_support';
import { DataProvider } from './data_provider';
import type { Label, Situation } from './situation';
@@ -14,10 +16,16 @@ import { NeverCaseError } from './util';
export type CompletionType = 'HISTORY' | 'FUNCTION' | 'METRIC_NAME' | 'DURATION' | 'LABEL_NAME' | 'LABEL_VALUE';
// We cannot use languages.CompletionItemInsertTextRule.InsertAsSnippet because grafana-prometheus package isn't compatible
// It should first change the moduleResolution to bundler for TS to correctly resolve the types
// https://github.com/grafana/grafana/pull/96450
const InsertAsSnippet = 4;
type Completion = {
type: CompletionType;
label: string;
insertText: string;
insertTextRules?: languages.CompletionItemInsertTextRule;
detail?: string;
documentation?: string;
triggerOnInsert?: boolean;
@@ -29,6 +37,11 @@ const metricNamesSearch = {
singleError: new UFuzzy({ intraMode: 1 }),
};
// Snippet Marker is telling monaco where to show the cursor and maybe a help text
// With help text example: ${1:labelName}
// labelName will be shown as selected. So user would know what to type next
const snippetMarker = '${1:}';
interface MetricFilterOptions {
metricNames: string[];
inputText: string;
@@ -74,9 +87,16 @@ function getAllMetricNamesCompletions(dataProvider: DataProvider): Completion[]
return dataProvider.metricNamesToMetrics(metricNames).map((metric) => ({
type: 'METRIC_NAME',
label: metric.name,
insertText: metric.name,
detail: `${metric.name} : ${metric.type}`,
documentation: metric.help,
...(metric.isUtf8
? {
insertText: `{"${metric.name}"${snippetMarker}}`,
insertTextRules: InsertAsSnippet,
}
: {
insertText: metric.name,
}),
}));
}
@@ -159,12 +179,22 @@ async function getLabelNamesForCompletions(
dataProvider: DataProvider
): Promise<Completion[]> {
const labelNames = await getLabelNames(metric, otherLabels, dataProvider);
return labelNames.map((text) => ({
type: 'LABEL_NAME',
label: text,
insertText: `${text}${suffix}`,
triggerOnInsert,
}));
return labelNames.map((text) => {
const isUtf8 = !isValidLegacyName(text);
return {
type: 'LABEL_NAME',
label: text,
...(isUtf8
? {
insertText: `"${text}"${suffix}`,
insertTextRules: InsertAsSnippet,
}
: {
insertText: `${text}${suffix}`,
}),
triggerOnInsert,
};
});
}
async function getLabelNamesForSelectorCompletions(
@@ -3,6 +3,7 @@ import type { Monaco } from '@grafana/ui'; // used in TSDoc `@link` below
import PromQlLanguageProvider from '../../../language_provider';
import { PromQuery } from '../../../types';
import { isValidLegacyName } from '../../../utf8_support';
export const CODE_MODE_SUGGESTIONS_INCOMPLETE_EVENT = 'codeModeSuggestionsIncomplete';
@@ -26,6 +27,7 @@ interface Metric {
name: string;
help: string;
type: string;
isUtf8?: boolean;
}
export interface DataProviderParams {
@@ -78,6 +80,7 @@ export class DataProvider {
name: m,
help: metaItem?.help ?? '',
type: metaItem?.type ?? '',
isUtf8: !isValidLegacyName(m),
};
});
@@ -95,6 +95,7 @@ export function getCompletionProvider(
kind: getMonacoCompletionItemKind(item.type, monaco),
label: item.label,
insertText: item.insertText,
insertTextRules: item.insertTextRules,
detail: item.detail,
documentation: item.documentation,
sortText: index.toString().padStart(maxIndexDigits, '0'), // to force the order we have
@@ -56,6 +56,7 @@ describe('situation', () => {
type: 'IN_LABEL_SELECTOR_NO_LABEL_NAME',
metricName: 'something',
otherLabels: [],
betweenQuotes: false,
});
assertSituation('sum(something) by (^)', {
@@ -79,34 +80,157 @@ describe('situation', () => {
{ name: 'three', value: 'val3', op: '=~' },
{ name: 'four', value: 'val4', op: '!~' },
],
betweenQuotes: false,
});
assertSituation('{^}', {
type: 'IN_LABEL_SELECTOR_NO_LABEL_NAME',
otherLabels: [],
betweenQuotes: false,
});
assertSituation('{one="val1",^}', {
type: 'IN_LABEL_SELECTOR_NO_LABEL_NAME',
otherLabels: [{ name: 'one', value: 'val1', op: '=' }],
betweenQuotes: false,
});
// single-quoted label-values with escape
assertSituation("{one='val\\'1',^}", {
type: 'IN_LABEL_SELECTOR_NO_LABEL_NAME',
otherLabels: [{ name: 'one', value: "val'1", op: '=' }],
betweenQuotes: false,
});
// double-quoted label-values with escape
assertSituation('{one="val\\"1",^}', {
type: 'IN_LABEL_SELECTOR_NO_LABEL_NAME',
otherLabels: [{ name: 'one', value: 'val"1', op: '=' }],
betweenQuotes: false,
});
// backticked label-values with escape (the escape should not be interpreted)
assertSituation('{one=`val\\"1`,^}', {
type: 'IN_LABEL_SELECTOR_NO_LABEL_NAME',
otherLabels: [{ name: 'one', value: 'val\\"1', op: '=' }],
betweenQuotes: false,
});
});
describe('utf-8 metric name support', () => {
it('with utf8 metric name no label and no comma', () => {
assertSituation(`{"metric.name"^}`, null);
});
it('with utf8 metric name no label', () => {
assertSituation(`{"metric.name", ^}`, {
type: 'IN_LABEL_SELECTOR_NO_LABEL_NAME',
metricName: 'metric.name',
otherLabels: [],
betweenQuotes: false,
});
});
it('with utf8 metric name requesting utf8 labels in quotes', () => {
assertSituation(`{"metric.name", "^"}`, {
type: 'IN_LABEL_SELECTOR_NO_LABEL_NAME',
metricName: 'metric.name',
otherLabels: [],
betweenQuotes: true,
});
});
it('with utf8 metric name with a legacy label', () => {
assertSituation(`{"metric.name", label1="val", ^}`, {
type: 'IN_LABEL_SELECTOR_NO_LABEL_NAME',
metricName: 'metric.name',
otherLabels: [{ name: 'label1', value: 'val', op: '=' }],
betweenQuotes: false,
});
});
it('with utf8 metric name with a legacy label and no value', () => {
assertSituation(`{"metric.name", label1="^"}`, {
type: 'IN_LABEL_SELECTOR_WITH_LABEL_NAME',
metricName: 'metric.name',
labelName: 'label1',
betweenQuotes: true,
otherLabels: [],
});
});
it('with utf8 metric name with a utf8 label and no value', () => {
assertSituation(`{"metric.name", "utf8.label"="^"}`, {
type: 'IN_LABEL_SELECTOR_WITH_LABEL_NAME',
metricName: 'metric.name',
labelName: '"utf8.label"',
betweenQuotes: true,
otherLabels: [],
});
});
it('with utf8 metric name with a legacy label and utf8 label', () => {
assertSituation(`{"metric.name", label1="val", "utf8.label"="^"}`, {
type: 'IN_LABEL_SELECTOR_WITH_LABEL_NAME',
metricName: 'metric.name',
labelName: `"utf8.label"`,
betweenQuotes: true,
otherLabels: [{ name: 'label1', value: 'val', op: '=' }],
});
});
it('with utf8 metric name with a utf8 label and legacy label', () => {
assertSituation(`{"metric.name", "utf8.label"="val", label1="^"}`, {
type: 'IN_LABEL_SELECTOR_WITH_LABEL_NAME',
metricName: 'metric.name',
labelName: `label1`,
betweenQuotes: true,
otherLabels: [{ name: '"utf8.label"', value: 'val', op: '=' }],
});
});
it('with utf8 metric name with grouping', () => {
assertSituation(`sum by (^)(rate({"metric.name", label1="val"}[1m]))`, {
type: 'IN_GROUPING',
metricName: 'metric.name',
otherLabels: [],
});
});
});
it('utf-8 label support', () => {
assertSituation(`metric{"label": "^"}`, null);
assertSituation(`metric{"label with space": "^"}`, null);
assertSituation(`metric{"label_🤖": "^"}`, null);
assertSituation(`metric{"Spaß": "^"}`, null);
assertSituation(`{"metric", "Spaß": "^"}`, null);
assertSituation('something{"job"=^}', {
type: 'IN_LABEL_SELECTOR_WITH_LABEL_NAME',
metricName: 'something',
labelName: '"job"',
betweenQuotes: false,
otherLabels: [],
});
assertSituation('something{"job📈"=^}', {
type: 'IN_LABEL_SELECTOR_WITH_LABEL_NAME',
metricName: 'something',
labelName: '"job📈"',
betweenQuotes: false,
otherLabels: [],
});
assertSituation('something{"job with space"=^,host="h1"}', {
type: 'IN_LABEL_SELECTOR_WITH_LABEL_NAME',
metricName: 'something',
labelName: '"job with space"',
betweenQuotes: false,
otherLabels: [{ name: 'host', value: 'h1', op: '=' }],
});
});
@@ -194,6 +318,7 @@ describe('situation', () => {
{ name: 'three', value: 'val3', op: '=~' },
{ name: 'four', value: 'val4', op: '!~' },
],
betweenQuotes: false,
});
});
});
@@ -18,6 +18,8 @@ import {
NumberDurationLiteralInDurationContext,
parser,
PromQL,
QuotedLabelMatcher,
QuotedLabelName,
StringLiteral,
UnquotedLabelMatcher,
VectorSelector,
@@ -35,8 +37,10 @@ type NodeTypeId =
| typeof GroupingLabels
| typeof Identifier
| typeof UnquotedLabelMatcher
| typeof QuotedLabelMatcher
| typeof LabelMatchers
| typeof LabelName
| typeof QuotedLabelName
| typeof PromQL
| typeof StringLiteral
| typeof VectorSelector
@@ -80,8 +84,10 @@ function walk(node: SyntaxNode, path: Path): SyntaxNode | null {
return current;
}
function getNodeText(node: SyntaxNode, text: string): string {
return text.slice(node.from, node.to);
function getNodeText(node: SyntaxNode, text: string, utf8?: boolean): string {
const nodeFrom = utf8 ? node.from + 1 : node.from;
const nodeTo = utf8 ? node.to - 1 : node.to;
return text.slice(nodeFrom, nodeTo);
}
function parsePromQLStringLiteral(text: string): string {
@@ -140,6 +146,8 @@ export type Situation =
type: 'IN_LABEL_SELECTOR_NO_LABEL_NAME';
metricName?: string;
otherLabels: Label[];
// utf8 labels must be in quotes
betweenQuotes: boolean;
}
| {
type: 'IN_GROUPING';
@@ -170,6 +178,10 @@ const RESOLVERS: Resolver[] = [
path: [LabelMatchers, VectorSelector],
fun: resolveLabelKeysWithEquals,
},
{
path: [StringLiteral, QuotedLabelName, LabelMatchers, VectorSelector],
fun: resolveUtf8LabelKeysWithEquals,
},
{
path: [PromQL],
fun: resolveTopLevel,
@@ -182,6 +194,10 @@ const RESOLVERS: Resolver[] = [
path: [StringLiteral, UnquotedLabelMatcher],
fun: resolveLabelMatcher,
},
{
path: [StringLiteral, QuotedLabelMatcher],
fun: resolveQuotedLabelMatcher,
},
{
path: [ERROR_NODE_NAME, BinaryExpr, PromQL],
fun: resolveTopLevel,
@@ -190,6 +206,10 @@ const RESOLVERS: Resolver[] = [
path: [ERROR_NODE_NAME, UnquotedLabelMatcher],
fun: resolveLabelMatcher,
},
{
path: [ERROR_NODE_NAME, QuotedLabelMatcher],
fun: resolveQuotedLabelMatcher,
},
{
path: [ERROR_NODE_NAME, NumberDurationLiteralInDurationContext, MatrixSelector],
fun: resolveDurations,
@@ -217,11 +237,13 @@ function getLabelOp(opNode: SyntaxNode): LabelOperator | null {
}
function getLabel(labelMatcherNode: SyntaxNode, text: string): Label | null {
if (labelMatcherNode.type.id !== UnquotedLabelMatcher) {
const allowedMatchers = new Set([UnquotedLabelMatcher, QuotedLabelMatcher]);
if (!allowedMatchers.has(labelMatcherNode.type.id)) {
return null;
}
const nameNode = walk(labelMatcherNode, [['firstChild', LabelName]]);
const nameNode =
walk(labelMatcherNode, [['firstChild', LabelName]]) ?? walk(labelMatcherNode, [['firstChild', QuotedLabelName]]);
if (nameNode === null) {
return null;
@@ -254,8 +276,17 @@ function getLabels(labelMatchersNode: SyntaxNode, text: string): Label[] {
return [];
}
const labelNodes = labelMatchersNode.getChildren(UnquotedLabelMatcher);
return labelNodes.map((ln) => getLabel(ln, text)).filter(notEmpty);
const matchers = [UnquotedLabelMatcher, QuotedLabelMatcher];
return matchers.reduce<Label[]>((acc, matcher) => {
labelMatchersNode.getChildren(matcher).forEach((ln) => {
const label = getLabel(ln, text);
if (notEmpty(label)) {
acc.push(label);
}
});
return acc;
}, []);
}
function getNodeChildren(node: SyntaxNode): SyntaxNode[] {
@@ -299,12 +330,20 @@ function resolveLabelsForGrouping(node: SyntaxNode, text: string, pos: number):
return null;
}
const metricIdNode = getNodeInSubtree(bodyNode, Identifier);
if (metricIdNode === null) {
const metricIdNode = getNodeInSubtree(bodyNode, Identifier) ?? getNodeInSubtree(bodyNode, StringLiteral);
if (!metricIdNode) {
return null;
}
const metricName = getNodeText(metricIdNode, text);
// Let's check whether it's a utf8 metric.
// A utf8 metric must be a StringLiteral and its parent must be a QuotedLabelName
if (metricIdNode.type.id === StringLiteral && metricIdNode.parent?.type.id !== QuotedLabelName) {
return null;
}
const metricName = getNodeText(metricIdNode, text, metricIdNode.type.id === StringLiteral);
return {
type: 'IN_GROUPING',
metricName,
@@ -341,29 +380,54 @@ function resolveLabelMatcher(node: SyntaxNode, text: string, pos: number): Situa
// we need to remove "our" label from all-labels, if it is in there
const otherLabels = allLabels.filter((label) => label.name !== labelName);
const metricNameNode = walk(labelMatchersNode, [
['parent', VectorSelector],
['firstChild', Identifier],
]);
if (metricNameNode === null) {
// we are probably in a situation without a metric name
return {
type: 'IN_LABEL_SELECTOR_WITH_LABEL_NAME',
labelName,
betweenQuotes: inStringNode,
otherLabels,
};
}
const metricName = getNodeText(metricNameNode, text);
const metricName = getMetricName(labelMatchersNode, text);
// we are probably in a situation without a metric name
return {
type: 'IN_LABEL_SELECTOR_WITH_LABEL_NAME',
metricName,
labelName,
betweenQuotes: inStringNode,
otherLabels,
...(metricName ? { metricName } : {}),
};
}
function resolveQuotedLabelMatcher(node: SyntaxNode, text: string, pos: number): Situation | null {
// we can arrive here in two situation. `node` is either:
// - a StringNode (like in `{"job"="^"}`)
// - or an error node (like in `{"job"=^}`)
const inStringNode = !node.type.isError;
const parent = walk(node, [['parent', QuotedLabelMatcher]]);
if (parent === null) {
return null;
}
const labelNameNode = walk(parent, [['firstChild', QuotedLabelName]]);
if (labelNameNode === null) {
return null;
}
const labelName = getNodeText(labelNameNode, text);
const labelMatchersNode = walk(parent, [['parent', LabelMatchers]]);
if (labelMatchersNode === null) {
return null;
}
// now we need to find the other names
const allLabels = getLabels(labelMatchersNode, text);
// we need to remove "our" label from all-labels, if it is in there
const otherLabels = allLabels.filter((label) => label.name !== labelName);
const metricName = getMetricName(parent.parent!, text);
return {
type: 'IN_LABEL_SELECTOR_WITH_LABEL_NAME',
labelName,
betweenQuotes: inStringNode,
otherLabels,
...(metricName ? { metricName } : {}),
};
}
@@ -388,7 +452,7 @@ function resolveDurations(node: SyntaxNode, text: string, pos: number): Situatio
function resolveLabelKeysWithEquals(node: SyntaxNode, text: string, pos: number): Situation | null {
// next false positive:
// `something{a="1"^}`
const child = walk(node, [['firstChild', UnquotedLabelMatcher]]);
let child = walk(node, [['firstChild', UnquotedLabelMatcher]]);
if (child !== null) {
// means the label-matching part contains at least one label already.
//
@@ -403,28 +467,72 @@ function resolveLabelKeysWithEquals(node: SyntaxNode, text: string, pos: number)
}
}
const metricNameNode = walk(node, [
// next false positive:
// `{"utf8.metric"^}`
child = walk(node, [['firstChild', QuotedLabelName]]);
if (child !== null) {
// means the label-matching part contains a utf8 metric.
//
// in this case, we will need to have a `,` character at the end,
// to be able to suggest adding the next label.
// the area between the end-of-the-child-node and the cursor-pos
// must contain a `,` in this case.
const textToCheck = text.slice(child.to, pos);
if (!textToCheck.includes(',')) {
return null;
}
}
const otherLabels = getLabels(node, text);
const metricName = getMetricName(node, text);
return {
type: 'IN_LABEL_SELECTOR_NO_LABEL_NAME',
otherLabels,
betweenQuotes: false,
...(metricName ? { metricName } : {}),
};
}
function resolveUtf8LabelKeysWithEquals(node: SyntaxNode, text: string, pos: number): Situation | null {
const otherLabels = getLabels(node, text);
const metricName = node.parent?.parent ? getMetricName(node.parent.parent, text) : null;
return {
type: 'IN_LABEL_SELECTOR_NO_LABEL_NAME',
otherLabels,
betweenQuotes: true,
...(metricName ? { metricName } : {}),
};
}
function getMetricName(node: SyntaxNode, text: string): string | null {
// Legacy Metric metric_name{label="value"}
const legacyMetricNameNode = walk(node, [
['parent', VectorSelector],
['firstChild', Identifier],
]);
const otherLabels = getLabels(node, text);
if (metricNameNode === null) {
// we are probably in a situation without a metric name.
return {
type: 'IN_LABEL_SELECTOR_NO_LABEL_NAME',
otherLabels,
};
if (legacyMetricNameNode) {
return getNodeText(legacyMetricNameNode, text);
}
const metricName = getNodeText(metricNameNode, text);
// check for a utf-8 metric
// utf-8 metric {"metric.name", label="value"}
const utf8MetricNameNode = walk(node, [
['parent', VectorSelector],
['firstChild', LabelMatchers],
['firstChild', QuotedLabelName],
['firstChild', StringLiteral],
]);
return {
type: 'IN_LABEL_SELECTOR_NO_LABEL_NAME',
metricName,
otherLabels,
};
if (utf8MetricNameNode) {
return getNodeText(utf8MetricNameNode, text, true);
}
// no metric name
return null;
}
// we find the first error-node in the tree that is at the cursor-position.
@@ -461,10 +569,10 @@ export function getSituation(text: string, pos: number): Situation | null {
}
/**
PromQL
Expr
VectorSelector
LabelMatchers
PromQL
Expr
VectorSelector
LabelMatchers
*/
const tree = parser.parse(text);
+16 -1
View File
@@ -71,6 +71,7 @@ import {
RawRecordingRules,
RuleQueryMapping,
} from './types';
import { utf8Support, wrapUtf8Filters } from './utf8_support';
import { PrometheusVariableSupport } from './variables';
const ANNOTATION_QUERY_STEP_DEFAULT = '60s';
@@ -925,7 +926,21 @@ export class PrometheusDatasource
// We need a first replace to evaluate variables before applying adhoc filters
// This is required for an expression like `metric > $VAR` where $VAR is a float to which we must not add adhoc filters
const expr = this.templateSrv.replace(target.expr, variables, this.interpolateQueryExpr);
const expr = this.templateSrv.replace(
target.expr,
variables,
(value: string | string[] = [], variable: QueryVariableModel | CustomVariableModel) => {
if (typeof value === 'string' && target.fromExploreMetrics) {
if (variable.name === 'filters') {
return wrapUtf8Filters(value);
}
if (variable.name === 'groupby') {
return utf8Support(value);
}
}
return this.interpolateQueryExpr(value, variable);
}
);
// Apply ad-hoc filters
// When ad-hoc filters are applied, we replace again the variables in case the ad-hoc filters also reference a variable
+8
View File
@@ -85,3 +85,11 @@ export {
type StandardPromVariableQuery,
} from './types';
export { PrometheusVariableSupport } from './variables';
// For explore metrics
export { default as PromQlLanguageProvider } from './language_provider';
export { getPrometheusTime } from './language_utils';
export { isValidLegacyName, utf8Support, wrapUtf8Filters } from './utf8_support';
export { buildVisualQueryFromString } from './querybuilder/parsing';
export { PromQueryModeller } from './querybuilder/PromQueryModeller';
export { type QueryBuilderLabelFilter } from './querybuilder/shared/types';
@@ -4,7 +4,7 @@ import { AbstractLabelOperator, dateTime, TimeRange } from '@grafana/data';
import { DEFAULT_SERIES_LIMIT } from './components/PrometheusMetricsBrowser';
import { Label } from './components/monaco-query-field/monaco-completion-provider/situation';
import { PrometheusDatasource } from './datasource';
import LanguageProvider from './language_provider';
import LanguageProvider, { removeQuotesIfExist } from './language_provider';
import { getClientCacheDurationInMinutes, getPrometheusTime, getRangeSnapInterval } from './language_utils';
import { PrometheusCacheLevel, PromQuery } from './types';
@@ -120,7 +120,13 @@ describe('Language completion provider', () => {
const labelName = 'job';
const labelValue = 'grafana';
getSeriesLabels(`{${labelName}="${labelValue}"}`, [{ name: labelName, value: labelValue, op: '=' }] as Label[]);
getSeriesLabels(`{${labelName}="${labelValue}"}`, [
{
name: labelName,
value: labelValue,
op: '=',
},
] as Label[]);
expect(requestSpy).toHaveBeenCalled();
expect(requestSpy).toHaveBeenCalledWith(
`/api/v1/labels`,
@@ -145,7 +151,13 @@ describe('Language completion provider', () => {
const labelName = 'job';
const labelValue = 'grafana';
getSeriesLabels(`{${labelName}="${labelValue}"}`, [{ name: labelName, value: labelValue, op: '=' }] as Label[]);
getSeriesLabels(`{${labelName}="${labelValue}"}`, [
{
name: labelName,
value: labelValue,
op: '=',
},
] as Label[]);
expect(requestSpy).toHaveBeenCalled();
expect(requestSpy).toHaveBeenCalledWith(
'/api/v1/series',
@@ -174,7 +186,13 @@ describe('Language completion provider', () => {
const labelName = 'job';
const labelValue = 'grafana';
getSeriesLabels(`{${labelName}="${labelValue}"}`, [{ name: labelName, value: labelValue, op: '=' }] as Label[]);
getSeriesLabels(`{${labelName}="${labelValue}"}`, [
{
name: labelName,
value: labelValue,
op: '=',
},
] as Label[]);
expect(requestSpy).toHaveBeenCalled();
expect(requestSpy).toHaveBeenCalledWith(
`/api/v1/labels`,
@@ -569,14 +587,14 @@ describe('Language completion provider', () => {
it('should interpolate variable in series', () => {
const languageProvider = new LanguageProvider({
...defaultDatasource,
interpolateString: (string: string) => string.replace(/\$/, 'interpolated-'),
interpolateString: (string: string) => string.replace(/\$/g, 'interpolated_'),
} as PrometheusDatasource);
const fetchLabelValues = languageProvider.fetchLabelValues;
const requestSpy = jest.spyOn(languageProvider, 'request');
fetchLabelValues('$job');
expect(requestSpy).toHaveBeenCalled();
expect(requestSpy).toHaveBeenCalledWith(
'/api/v1/label/interpolated-job/values',
'/api/v1/label/interpolated_job/values',
[],
{
end: toPrometheusTimeString,
@@ -585,6 +603,69 @@ describe('Language completion provider', () => {
undefined
);
});
it('should fetch with encoded utf8 label', () => {
const languageProvider = new LanguageProvider({
...defaultDatasource,
interpolateString: (string: string) => string.replace(/\$/g, 'http.status:sum'),
} as PrometheusDatasource);
const fetchLabelValues = languageProvider.fetchLabelValues;
const requestSpy = jest.spyOn(languageProvider, 'request');
fetchLabelValues('"http.status:sum"');
expect(requestSpy).toHaveBeenCalled();
expect(requestSpy).toHaveBeenCalledWith(
'/api/v1/label/U__http_2e_status:sum/values',
[],
{
end: toPrometheusTimeString,
start: fromPrometheusTimeString,
},
undefined
);
});
});
describe('fetchSeriesValuesWithMatch', () => {
it('should fetch with encoded utf8 label', () => {
const languageProvider = new LanguageProvider({
...defaultDatasource,
interpolateString: (string: string) => string.replace(/\$/g, 'http.status:sum'),
} as PrometheusDatasource);
const fetchSeriesValuesWithMatch = languageProvider.fetchSeriesValuesWithMatch;
const requestSpy = jest.spyOn(languageProvider, 'request');
fetchSeriesValuesWithMatch('"http.status:sum"', '{__name__="a_utf8_http_requests_total"}');
expect(requestSpy).toHaveBeenCalled();
expect(requestSpy).toHaveBeenCalledWith(
'/api/v1/label/U__http_2e_status:sum/values',
[],
{
end: toPrometheusTimeString,
start: fromPrometheusTimeString,
'match[]': '{__name__="a_utf8_http_requests_total"}',
},
undefined
);
});
it('should fetch without encoding for standard prometheus labels', () => {
const languageProvider = new LanguageProvider({
...defaultDatasource,
} as PrometheusDatasource);
const fetchSeriesValuesWithMatch = languageProvider.fetchSeriesValuesWithMatch;
const requestSpy = jest.spyOn(languageProvider, 'request');
fetchSeriesValuesWithMatch('"http_status_sum"', '{__name__="a_utf8_http_requests_total"}');
expect(requestSpy).toHaveBeenCalled();
expect(requestSpy).toHaveBeenCalledWith(
'/api/v1/label/http_status_sum/values',
[],
{
end: toPrometheusTimeString,
start: fromPrometheusTimeString,
'match[]': '{__name__="a_utf8_http_requests_total"}',
},
undefined
);
});
});
describe('disabled metrics lookup', () => {
@@ -650,3 +731,59 @@ describe('Language completion provider', () => {
});
});
});
describe('removeQuotesIfExist', () => {
it('removes quotes from a string with double quotes', () => {
const input = '"hello"';
const result = removeQuotesIfExist(input);
expect(result).toBe('hello');
});
it('returns the original string if it does not start and end with quotes', () => {
const input = 'hello';
const result = removeQuotesIfExist(input);
expect(result).toBe('hello');
});
it('returns the original string if it has mismatched quotes', () => {
const input = '"hello';
const result = removeQuotesIfExist(input);
expect(result).toBe('"hello');
});
it('removes quotes for strings with special characters inside quotes', () => {
const input = '"hello, world!"';
const result = removeQuotesIfExist(input);
expect(result).toBe('hello, world!');
});
it('removes quotes for strings with spaces inside quotes', () => {
const input = '" "';
const result = removeQuotesIfExist(input);
expect(result).toBe(' ');
});
it('returns the original string for an empty string', () => {
const input = '';
const result = removeQuotesIfExist(input);
expect(result).toBe('');
});
it('returns the original string if the string only has a single quote character', () => {
const input = '"';
const result = removeQuotesIfExist(input);
expect(result).toBe('"');
});
it('handles strings with nested quotes correctly', () => {
const input = '"nested \"quotes\""';
const result = removeQuotesIfExist(input);
expect(result).toBe('nested \"quotes\"');
});
it('removes quotes from a numeric string wrapped in quotes', () => {
const input = '"12345"';
const result = removeQuotesIfExist(input);
expect(result).toBe('12345');
});
});
@@ -29,6 +29,7 @@ import {
import PromqlSyntax from './promql';
import { buildVisualQueryFromString } from './querybuilder/parsing';
import { PrometheusCacheLevel, PromMetricsMetadata, PromQuery } from './types';
import { escapeForUtf8Support, isValidLegacyName } from './utf8_support';
const DEFAULT_KEYS = ['job', 'instance'];
const EMPTY_SELECTOR = '{}';
@@ -208,7 +209,8 @@ export default class PromQlLanguageProvider extends LanguageProvider {
fetchLabelValues = async (key: string): Promise<string[]> => {
const params = this.datasource.getAdjustedInterval(this.timeRange);
const interpolatedName = this.datasource.interpolateString(key);
const url = `/api/v1/label/${interpolatedName}/values`;
const interpolatedAndEscapedName = escapeForUtf8Support(removeQuotesIfExist(interpolatedName));
const url = `/api/v1/label/${interpolatedAndEscapedName}/values`;
const value = await this.request(url, [], params, this.getDefaultCacheHeaders());
return value ?? [];
};
@@ -232,10 +234,11 @@ export default class PromQlLanguageProvider extends LanguageProvider {
queries?.forEach((q) => {
const visualQuery = buildVisualQueryFromString(q.expr);
if (visualQuery.query.metric !== '') {
searchParams.append('match[]', visualQuery.query.metric);
const isUtf8Metric = !isValidLegacyName(visualQuery.query.metric);
searchParams.append('match[]', isUtf8Metric ? `{"${visualQuery.query.metric}"}` : visualQuery.query.metric);
if (visualQuery.query.binaryQueries) {
visualQuery.query.binaryQueries.forEach((bq) => {
searchParams.append('match[]', bq.query.metric);
searchParams.append('match[]', isUtf8Metric ? `{"${bq.query.metric}"}` : bq.query.metric);
});
}
}
@@ -263,7 +266,7 @@ export default class PromQlLanguageProvider extends LanguageProvider {
getSeriesValues = async (labelName: string, selector: string): Promise<string[]> => {
if (!this.datasource.hasLabelsMatchAPISupport()) {
const data = await this.getSeries(selector);
return data[labelName] ?? [];
return data[removeQuotesIfExist(labelName)] ?? [];
}
return await this.fetchSeriesValuesWithMatch(labelName, selector);
};
@@ -297,7 +300,14 @@ export default class PromQlLanguageProvider extends LanguageProvider {
requestOptions = undefined;
}
const value = await this.request(`/api/v1/label/${interpolatedName}/values`, [], urlParams, requestOptions);
const interpolatedAndEscapedName = escapeForUtf8Support(removeQuotesIfExist(interpolatedName ?? ''));
const value = await this.request(
`/api/v1/label/${interpolatedAndEscapedName}/values`,
[],
urlParams,
requestOptions
);
return value ?? [];
};
@@ -493,3 +503,10 @@ function isCancelledError(error: unknown): error is {
} {
return typeof error === 'object' && error !== null && 'cancelled' in error && error.cancelled === true;
}
// For utf8 labels we use quotes around the label
// While requesting the label values we must remove the quotes
export function removeQuotesIfExist(input: string): string {
const match = input.match(/^"(.*)"$/); // extract the content inside the quotes
return match?.[1] ?? input;
}
@@ -11,6 +11,7 @@ import {
getPrometheusTime,
getRangeSnapInterval,
parseSelector,
processLabels,
toPromLikeQuery,
truncateResult,
} from './language_utils';
@@ -565,3 +566,54 @@ describe('truncateResult', () => {
expect(array[999]).toBe(999);
});
});
describe('processLabels', () => {
it('export abstract query to expr', () => {
const labels: Array<{ [key: string]: string }> = [
{ label1: 'value1' },
{ label2: 'value2' },
{ label3: 'value3' },
{ label1: 'value1' },
{ label1: 'value1b' },
];
expect(processLabels(labels)).toEqual({
keys: ['label1', 'label2', 'label3'],
values: { label1: ['value1', 'value1b'], label2: ['value2'], label3: ['value3'] },
});
});
it('dont wrap utf8 label values with quotes', () => {
const labels: Array<{ [key: string]: string }> = [
{ label1: 'value1' },
{ label2: 'value2' },
{ label3: 'value3 with space' },
{ label4: 'value4.with.dot' },
];
expect(processLabels(labels)).toEqual({
keys: ['label1', 'label2', 'label3', 'label4'],
values: {
label1: ['value1'],
label2: ['value2'],
label3: [`value3 with space`],
label4: [`value4.with.dot`],
},
});
});
it('dont wrap utf8 labels with quotes', () => {
const labels: Array<{ [key: string]: string }> = [
{ 'label1 with space': 'value1' },
{ 'label2.with.dot': 'value2' },
];
expect(processLabels(labels)).toEqual({
keys: ['label1 with space', 'label2.with.dot'],
values: {
'label1 with space': ['value1'],
'label2.with.dot': ['value2'],
},
});
});
});
@@ -478,7 +478,10 @@ export function extractLabelMatchers(tokens: Array<string | Token>): AbstractLab
export function getRangeSnapInterval(
cacheLevel: PrometheusCacheLevel,
range: TimeRange
): { start: string; end: string } {
): {
start: string;
end: string;
} {
// Don't round the range if we're not caching
if (cacheLevel === PrometheusCacheLevel.None) {
return {
@@ -8,6 +8,7 @@ import { PrometheusDatasource } from './datasource';
import { getPrometheusTime } from './language_utils';
import { PrometheusMetricFindQuery } from './metric_find_query';
import { PromApplication, PromOptions } from './types';
import { escapeForUtf8Support } from './utf8_support';
const fetchMock = jest.fn((options: BackendSrvRequest): Observable<FetchResponse<BackendDataSourceResponse>> => {
return of({} as unknown as FetchResponse);
@@ -413,5 +414,51 @@ describe('PrometheusMetricFindQuery', () => {
});
});
// </ ModernPrometheus>
describe('utf8 metric and label support', () => {
it('utf8 label - label_values(a_utf8_http_requests_total,instance.test) should generate label values query', () => {
const metricName = 'a_utf8_http_requests_total';
const label = 'instance.test';
const query = `label_values(${metricName},${label})`;
const metricFindQuery = new PrometheusMetricFindQuery(prometheusDatasource, query);
metricFindQuery.process(raw);
expect(fetchMock).toHaveBeenCalledTimes(1);
expect(fetchMock).toHaveBeenCalledWith({
method: 'GET',
url: `/api/datasources/uid/ABCDEF/resources/api/v1/label/${escapeForUtf8Support(label)}/values?match%5B%5D=${metricName}&start=1524650400&end=1524654000`,
hideFromInspector: true,
headers: {},
});
});
it('utf8 metric - label_values(utf8.http_requests_total,instance_test) should generate label values query', () => {
const metricName = 'utf8.http_requests_total';
const label = 'instance_test';
const query = `label_values(${metricName},${label})`;
const metricFindQuery = new PrometheusMetricFindQuery(prometheusDatasource, query);
metricFindQuery.process(raw);
expect(fetchMock).toHaveBeenCalledTimes(1);
expect(fetchMock).toHaveBeenCalledWith({
method: 'GET',
url: `/api/datasources/uid/ABCDEF/resources/api/v1/label/${label}/values?match%5B%5D=${metricName}&start=1524650400&end=1524654000`,
hideFromInspector: true,
headers: {},
});
});
it('utf8 metric and label - label_values(utf8.http_requests_total,instance.test) should generate label values query', () => {
const metricName = 'utf8.http_requests_total';
const label = 'instance.test';
const query = `label_values(${metricName},${label})`;
const metricFindQuery = new PrometheusMetricFindQuery(prometheusDatasource, query);
metricFindQuery.process(raw);
expect(fetchMock).toHaveBeenCalledTimes(1);
expect(fetchMock).toHaveBeenCalledWith({
method: 'GET',
url: `/api/datasources/uid/ABCDEF/resources/api/v1/label/${escapeForUtf8Support(label)}/values?match%5B%5D=${metricName}&start=1524650400&end=1524654000`,
hideFromInspector: true,
headers: {},
});
});
});
});
});
@@ -8,9 +8,11 @@ import { getPrometheusTime } from './language_utils';
import {
PrometheusLabelNamesRegex,
PrometheusLabelNamesRegexWithMatch,
PrometheusLabelValuesRegex,
PrometheusMetricNamesRegex,
PrometheusQueryResultRegex,
} from './migrations/variableMigration';
import { escapeForUtf8Support, isValidLegacyName } from './utf8_support';
export class PrometheusMetricFindQuery {
range: TimeRange;
@@ -28,7 +30,7 @@ export class PrometheusMetricFindQuery {
this.range = timeRange;
const labelNamesRegex = PrometheusLabelNamesRegex;
const labelNamesRegexWithMatch = PrometheusLabelNamesRegexWithMatch;
const labelValuesRegex = /^label_values\((?:(.+),\s*)?([a-zA-Z_][a-zA-Z0-9_]*)\)\s*$/;
const labelValuesRegex = PrometheusLabelValuesRegex;
const metricNamesRegex = PrometheusMetricNamesRegex;
const queryResultRegex = PrometheusQueryResultRegex;
const labelNamesQuery = this.query.match(labelNamesRegex);
@@ -83,8 +85,13 @@ export class PrometheusMetricFindQuery {
const end = getPrometheusTime(this.range.to, true);
const params = { ...(metric && { 'match[]': metric }), start: start.toString(), end: end.toString() };
let escapedLabel = label;
if (!isValidLegacyName(label)) {
escapedLabel = escapeForUtf8Support(label);
}
if (!metric || this.datasource.hasLabelsMatchAPISupport()) {
const url = `/api/v1/label/${label}/values`;
const url = `/api/v1/label/${escapedLabel}/values`;
return this.datasource.metadataRequest(url, params).then((result) => {
return _map(result.data.data, (value) => {
@@ -4,8 +4,7 @@ import { buildVisualQueryFromString } from '../querybuilder/parsing';
import { PromVariableQuery, PromVariableQueryType as QueryType } from '../types';
export const PrometheusLabelNamesRegex = /^label_names\(\)\s*$/;
// Note that this regex is different from the one in metric_find_query.ts because this is used pre-interpolation
export const PrometheusLabelValuesRegex = /^label_values\((?:(.+),\s*)?([a-zA-Z_$][a-zA-Z0-9_]*)\)\s*$/;
export const PrometheusLabelValuesRegex = /^label_values\((?:(.+),\s*)?(.+)\)\s*$/;
export const PrometheusMetricNamesRegex = /^metrics\((.+)\)\s*$/;
export const PrometheusQueryResultRegex = /^query_result\((.+)\)\s*$/;
export const PrometheusLabelNamesRegexWithMatch = /^label_names\((.+)\)\s*$/;
@@ -97,7 +96,7 @@ export function migrateVariableQueryToEditor(rawQuery: string | PromVariableQuer
return queryBase;
}
// migrate it back to a string with the correct varialbes in place
// migrate it back to a string with the correct variables in place
export function migrateVariableEditorBackToVariableSupport(QueryVariable: PromVariableQuery): string {
switch (QueryVariable.qryType) {
case QueryType.LabelNames:
@@ -334,3 +334,82 @@ describe('PromQueryModeller', () => {
).toBe('cluster_namespace_slug_dialer_name <= bool 2');
});
});
describe('PromQueryModeller with utf8 support', () => {
const modeller = new PromQueryModeller();
it('should render nothing if there is nothing', () => {
expect(
modeller.renderQuery({
metric: undefined,
labels: [],
operations: [],
})
).toBe('');
expect(
modeller.renderQuery({
metric: '',
labels: [],
operations: [],
})
).toBe('');
});
it('should render legacy metric name as usual', () => {
expect(
modeller.renderQuery({
metric: 'not_a_utf8_metric',
labels: [],
operations: [],
})
).toBe('not_a_utf8_metric');
});
it('can render utf8 metric name in curly braces', () => {
expect(
modeller.renderQuery({
metric: 'a.utf8.metric',
labels: [],
operations: [],
})
).toBe('{"a.utf8.metric"}');
});
it('can render utf8 metric name in curly braces with legacy labels', () => {
expect(
modeller.renderQuery({
metric: 'a.utf8.metric',
labels: [
{
label: 'label',
value: 'value',
op: '=',
},
],
operations: [],
})
).toBe('{"a.utf8.metric", label="value"}');
});
it('can render utf8 metric name in curly braces with legacy and utf8 labels', () => {
expect(
modeller.renderQuery({
metric: 'a.utf8.metric',
labels: [
{
label: 'label',
value: 'value',
op: '=',
},
{
label: 'utf8.label',
value: 'value',
op: '=',
},
],
operations: [],
})
).toBe('{"a.utf8.metric", label="value", "utf8.label"="value"}');
});
});
@@ -93,7 +93,7 @@ export const PromQueryBuilder = memo<PromQueryBuilderProps>((props) => {
{showExplain && (
<OperationExplainedBox
stepNumber={1}
title={<RawQuery query={`${query.metric} ${promQueryModeller.renderLabels(query.labels)}`} lang={lang} />}
title={<RawQuery query={`${promQueryModeller.renderQuery(query)}`} lang={lang} />}
>
{EXPLAIN_LABEL_FILTER_CONTENT}
</OperationExplainedBox>
@@ -25,7 +25,7 @@ export const PromQueryBuilderExplained = memo<PromQueryBuilderExplainedProps>(({
<Stack gap={0.5} direction="column">
<OperationExplainedBox
stepNumber={1}
title={<RawQuery query={`${visQuery.metric} ${promQueryModeller.renderLabels(visQuery.labels)}`} lang={lang} />}
title={<RawQuery query={`${promQueryModeller.renderQuery(visQuery)}`} lang={lang} />}
>
{EXPLAIN_LABEL_FILTER_CONTENT}
</OperationExplainedBox>
@@ -3,6 +3,80 @@ import { buildVisualQueryFromString } from './parsing';
import { PromOperationId, PromVisualQuery } from './types';
describe('buildVisualQueryFromString', () => {
describe('utf8 support', () => {
it('supports uts-8 label names', () => {
expect(buildVisualQueryFromString('{"glück:🍀.dot"="luck"} == 11')).toEqual({
query: {
labels: [
{
label: 'glück:🍀.dot',
op: '=',
value: 'luck',
},
],
metric: '',
operations: [
{
id: PromOperationId.EqualTo,
params: [11, false],
},
],
},
errors: [],
});
});
it('supports uts-8 metric names', () => {
expect(buildVisualQueryFromString('{"I am a metric"}')).toEqual({
query: {
labels: [],
metric: 'I am a metric',
operations: [],
},
errors: [],
});
});
it('supports uts-8 metric names with labels', () => {
expect(buildVisualQueryFromString('{"metric.name", label_field="label value"}')).toEqual({
query: {
labels: [
{
label: 'label_field',
op: '=',
value: 'label value',
},
],
metric: 'metric.name',
operations: [],
},
errors: [],
});
});
it('supports uts-8 metric names with utf8 labels', () => {
expect(buildVisualQueryFromString('{"metric.name", "glück:🍀.dot"="luck"} == 11')).toEqual({
query: {
labels: [
{
label: 'glück:🍀.dot',
op: '=',
value: 'luck',
},
],
metric: 'metric.name',
operations: [
{
id: PromOperationId.EqualTo,
params: [11, false],
},
],
},
errors: [],
});
});
});
it('creates no errors for empty query', () => {
expect(buildVisualQueryFromString('')).toEqual(
noErrors({
@@ -246,6 +320,31 @@ describe('buildVisualQueryFromString', () => {
);
});
it('parses query with aggregation by utf8 labels', () => {
const visQuery = {
metric: 'metric_name',
labels: [
{
label: 'instance',
op: '=',
value: 'internal:3000',
},
],
operations: [
{
id: '__sum_by',
params: ['cluster', '"app.version"'],
},
],
};
expect(
buildVisualQueryFromString('sum(metric_name{instance="internal:3000"}) by ("app.version", cluster)')
).toEqual(noErrors(visQuery));
expect(
buildVisualQueryFromString('sum by ("app.version", cluster)(metric_name{instance="internal:3000"})')
).toEqual(noErrors(visQuery));
});
it('parses aggregation with params', () => {
expect(buildVisualQueryFromString('topk(5, http_requests_total)')).toEqual(
noErrors({
@@ -12,6 +12,7 @@ import {
GroupingLabels,
Identifier,
LabelName,
QuotedLabelName,
MatchingModifierClause,
MatchOp,
NumberDurationLiteral,
@@ -19,6 +20,7 @@ import {
ParenExpr,
parser,
StringLiteral,
QuotedLabelMatcher,
UnquotedLabelMatcher,
VectorSelector,
Without,
@@ -145,9 +147,33 @@ export function handleExpression(expr: string, node: SyntaxNode, context: Contex
break;
}
case QuotedLabelName: {
// Usually we got the metric name above in the Identifier case.
// If we didn't get the name that's potentially we have it in curly braces as quoted string.
// It must be quoted because that's how utf8 metric names should be defined
// See proposal https://github.com/prometheus/proposals/blob/main/proposals/2023-08-21-utf8.md
if (visQuery.metric === '') {
const strLiteral = node.getChild(StringLiteral);
const quotedMetric = getString(expr, strLiteral);
visQuery.metric = quotedMetric.slice(1, -1);
}
break;
}
case QuotedLabelMatcher: {
const quotedLabel = getLabel(expr, node, QuotedLabelName);
quotedLabel.label = quotedLabel.label.slice(1, -1);
visQuery.labels.push(quotedLabel);
const err = node.getChild(ErrorId);
if (err) {
context.errors.push(makeError(expr, err));
}
break;
}
case UnquotedLabelMatcher: {
// Same as MetricIdentifier should be just one per query.
visQuery.labels.push(getLabel(expr, node));
visQuery.labels.push(getLabel(expr, node, LabelName));
const err = node.getChild(ErrorId);
if (err) {
context.errors.push(makeError(expr, err));
@@ -202,8 +228,12 @@ function isIntervalVariableError(node: SyntaxNode) {
return node.prevSibling?.firstChild?.type.id === VectorSelector;
}
function getLabel(expr: string, node: SyntaxNode): QueryBuilderLabelFilter {
const label = getString(expr, node.getChild(LabelName));
function getLabel(
expr: string,
node: SyntaxNode,
labelType: typeof LabelName | typeof QuotedLabelName
): QueryBuilderLabelFilter {
const label = getString(expr, node.getChild(labelType));
const op = getString(expr, node.getChild(MatchOp));
const value = getString(expr, node.getChild(StringLiteral)).replace(/^["'`]|["'`]$/g, '');
return {
@@ -281,7 +311,7 @@ function handleAggregation(expr: string, node: SyntaxNode, context: Context) {
funcName = `__${funcName}_without`;
}
labels.push(...getAllByType(expr, modifier, LabelName));
labels.push(...getAllByType(expr, modifier, LabelName), ...getAllByType(expr, modifier, QuotedLabelName));
}
const body = node.getChild(FunctionCallBody);
@@ -3,6 +3,7 @@ import { Registry } from '@grafana/data';
import { config } from '@grafana/runtime';
import { prometheusRegularEscape } from '../../datasource';
import { isValidLegacyName, utf8Support } from '../../utf8_support';
import { PromVisualQueryOperationCategory } from '../types';
import { QueryBuilderLabelFilter, QueryBuilderOperation, QueryBuilderOperationDef, VisualQueryModeller } from './types';
@@ -97,14 +98,28 @@ export abstract class LokiAndPromQueryModellerBase implements VisualQueryModelle
if (config.featureToggles.prometheusSpecialCharsInLabelValues && !usingRegexOperator) {
labelValue = prometheusRegularEscape(labelValue);
}
expr += `${filter.label}${filter.op}"${labelValue}"`;
expr += `${utf8Support(filter.label)}${filter.op}"${labelValue}"`;
}
return expr + `}`;
}
renderQuery(query: PromLokiVisualQuery, nested?: boolean) {
let queryString = `${query.metric ?? ''}${this.renderLabels(query.labels)}`;
let queryString = '';
const labels = this.renderLabels(query.labels);
if (query.metric) {
if (isValidLegacyName(query.metric)) {
// This is a legacy metric, put outside the curl legacy_query{label="value"}
queryString = `${query.metric}${labels}`;
} else {
// This is a utf8 metric, put inside the curly and quotes {"utf8.metric", label="value"}
queryString = `{"${query.metric}"${labels.length > 0 ? `, ${labels.substring(1)}` : `}`}`;
}
} else {
// No metric just use labels {label="value"}
queryString = labels;
}
queryString = this.renderOperations(queryString, query.operations);
if (!nested && this.hasBinaryOp(query) && Boolean(query.binaryQueries?.length)) {
+1
View File
@@ -20,6 +20,7 @@ export interface PromQuery extends GenPromQuery, DataQuery {
disableTextWrap?: boolean;
fullMetaSearch?: boolean;
includeNullMetadata?: boolean;
fromExploreMetrics?: boolean;
}
export enum PrometheusCacheLevel {
@@ -0,0 +1,127 @@
import { escapeForUtf8Support, utf8Support, wrapUtf8Filters } from './utf8_support';
describe('utf8 support', () => {
it('should return utf8 labels wrapped in quotes', () => {
const labels = ['valid:label', 'metric_label', 'utf8 label with space 🤘', ''];
const expected = ['valid:label', 'metric_label', `"utf8 label with space 🤘"`, ''];
const supportedLabels = labels.map(utf8Support);
expect(supportedLabels).toEqual(expected);
});
});
describe('applyValueEncodingEscaping', () => {
it('should return utf8 labels wrapped in quotes', () => {
const labels = [
'no:escaping_required',
'mysystem.prod.west.cpu.load',
'mysystem.prod.west.cpu.load_total',
'http.status:sum',
'my lovely_http.status:sum',
'花火',
'label with 😱',
];
const expected = [
'no:escaping_required',
'U__mysystem_2e_prod_2e_west_2e_cpu_2e_load',
'U__mysystem_2e_prod_2e_west_2e_cpu_2e_load__total',
'U__http_2e_status:sum',
'U__my_20_lovely__http_2e_status:sum',
'U___82b1__706b_',
'U__label_20_with_20__1f631_',
];
const excapedLabels = labels.map(escapeForUtf8Support);
expect(excapedLabels).toEqual(expected);
});
});
describe('wrapUtf8Filters', () => {
it('should correctly wrap UTF-8 labels and values for multiple key-value pairs', () => {
const result = wrapUtf8Filters('label.with.spaß="this_is_fun",instance="localhost:9112"');
const expected = '"label.with.spaß"="this_is_fun",instance="localhost:9112"';
expect(result).toEqual(expected);
});
it('should correctly wrap UTF-8 labels and values for a single key-value pair', () => {
const result = wrapUtf8Filters('label.with.spaß="this_is_fun"');
const expected = '"label.with.spaß"="this_is_fun"';
expect(result).toEqual(expected);
});
it('should correctly handle commas within values', () => {
const result = wrapUtf8Filters('label.with.spaß="this,is,fun",instance="localhost:9112"');
const expected = '"label.with.spaß"="this,is,fun",instance="localhost:9112"';
expect(result).toEqual(expected);
});
it('should correctly handle escaped quotes within values', () => {
const result = wrapUtf8Filters(`label.with.spaß="this_is_\\"fun\\"",instance="localhost:9112"`);
const expected = `"label.with.spaß"="this_is_\\"fun\\"",instance="localhost:9112"`;
expect(result).toEqual(expected);
});
it('should correctly handle spaces within keys', () => {
const result = wrapUtf8Filters('label with space="value with space",instance="localhost:9112"');
const expected = '"label with space"="value with space",instance="localhost:9112"';
expect(result).toEqual(expected);
});
it('should correctly process mixed inputs with various formats', () => {
const result = wrapUtf8Filters('key1="value1",key2="value,with,comma",key3="val3"');
const expected = 'key1="value1",key2="value,with,comma",key3="val3"';
expect(result).toEqual(expected);
});
it('should correctly handle empty values', () => {
const result = wrapUtf8Filters('key1="",key2="value2"');
const expected = 'key1="",key2="value2"';
expect(result).toEqual(expected);
});
it('should handle an empty input string', () => {
const result = wrapUtf8Filters('');
const expected = '';
expect(result).toEqual(expected);
});
it('should handle a single key with an empty value', () => {
const result = wrapUtf8Filters('key1=""');
const expected = 'key1=""';
expect(result).toEqual(expected);
});
it('should handle multiple consecutive commas in a value', () => {
const result = wrapUtf8Filters('key1="value1,,value2",key2="value3"');
const expected = 'key1="value1,,value2",key2="value3"';
expect(result).toEqual(expected);
});
it('should handle a key-value pair with special characters in the key', () => {
const result = wrapUtf8Filters('special@key#="value1",key2="value2"');
const expected = '"special@key#"="value1",key2="value2"';
expect(result).toEqual(expected);
});
it('should handle a key-value pair with special characters in the value', () => {
const result = wrapUtf8Filters('key1="value@#&*",key2="value2"');
const expected = 'key1="value@#&*",key2="value2"';
expect(result).toEqual(expected);
});
it('should correctly process keys without special characters', () => {
const result = wrapUtf8Filters('key1="value1",key2="value2"');
const expected = 'key1="value1",key2="value2"';
expect(result).toEqual(expected);
});
it('should handle nested escaped quotes correctly', () => {
const result = wrapUtf8Filters('key1="nested \\"escaped\\" quotes",key2="value2"');
const expected = 'key1="nested \\"escaped\\" quotes",key2="value2"';
expect(result).toEqual(expected);
});
it('should handle escaped quotes correctly', () => {
const result = wrapUtf8Filters('key1="nested \\"escaped\\" quotes",key2="value with \\"escaped\\" quotes"');
const expected = 'key1="nested \\"escaped\\" quotes",key2="value with \\"escaped\\" quotes"';
expect(result).toEqual(expected);
});
});
@@ -0,0 +1,113 @@
export const utf8Support = (value: string) => {
if (value === '') {
return value;
}
const isLegacyLabel = isValidLegacyName(value);
if (isLegacyLabel) {
return value;
}
return `"${value}"`;
};
export const escapeForUtf8Support = (value: string) => {
const isLegacyLabel = isValidLegacyName(value);
if (isLegacyLabel) {
return value;
}
let escaped = 'U__';
for (let i = 0; i < value.length; i++) {
const char = value[i];
const codePoint = value.codePointAt(i);
if (char === '_') {
escaped += '__';
} else if (codePoint !== undefined && isValidLegacyRune(char, i)) {
escaped += char;
} else if (codePoint === undefined || !isValidCodePoint(codePoint)) {
escaped += '_FFFD_';
} else {
escaped += '_';
escaped += codePoint.toString(16); // Convert code point to hexadecimal
escaped += '_';
}
// Handle surrogate pairs for characters outside the Basic Multilingual Plane
if (codePoint !== undefined && codePoint > 0xffff) {
i++; // Skip the second half of the surrogate pair
}
}
return escaped;
};
export const isValidLegacyName = (name: string): boolean => {
if (name.length === 0) {
return false;
}
for (let i = 0; i < name.length; i++) {
const char = name[i];
if (!isValidLegacyRune(char, i)) {
return false;
}
}
return true;
};
// const labelNamePriorToUtf8Support = /^[a-zA-Z_:][a-zA-Z0-9_:]*$/;
// instead of regex we use rune check (converted from prometheus code)
// https://github.com/prometheus/common/blob/main/model/metric.go#L426-L428
const isValidLegacyRune = (char: string, index: number): boolean => {
const codePoint = char.codePointAt(0);
if (codePoint === undefined) {
return false;
}
return (
(codePoint >= 97 && codePoint <= 122) || // 'a' to 'z'
(codePoint >= 65 && codePoint <= 90) || // 'A' to 'Z'
codePoint === 95 || // '_'
codePoint === 58 || // ':'
(codePoint >= 48 && codePoint <= 57 && index > 0) // '0' to '9', but not at the start
);
};
const isValidCodePoint = (codePoint: number): boolean => {
// Validate the code point for UTF-8 compliance if needed.
return codePoint >= 0 && codePoint <= 0x10ffff;
};
export const wrapUtf8Filters = (filterStr: string): string => {
const resultArray: string[] = [];
let currentKey = '';
let currentValue = '';
let inQuotes = false;
let temp = '';
for (const char of filterStr) {
if (char === '"' && temp[temp.length - 1] !== '\\') {
// Toggle inQuotes when an unescaped quote is found
inQuotes = !inQuotes;
temp += char;
} else if (char === ',' && !inQuotes) {
// When outside quotes and encountering ',', finalize the current pair
[currentKey, currentValue] = temp.split('=');
resultArray.push(`${utf8Support(currentKey.trim())}="${currentValue.slice(1, -1)}"`);
temp = ''; // Reset for the next pair
} else {
// Collect characters
temp += char;
}
}
// Handle the last key-value pair
if (temp) {
[currentKey, currentValue] = temp.split('=');
resultArray.push(`${utf8Support(currentKey.trim())}="${currentValue.slice(1, -1)}"`);
}
return resultArray.join(',');
};
+5 -5
View File
@@ -58,10 +58,10 @@
"@leeoniya/ufuzzy": "1.0.18",
"@monaco-editor/react": "4.6.0",
"@popperjs/core": "2.11.8",
"@react-aria/dialog": "3.5.20",
"@react-aria/focus": "3.19.0",
"@react-aria/overlays": "3.24.0",
"@react-aria/utils": "3.26.0",
"@react-aria/dialog": "3.5.21",
"@react-aria/focus": "3.19.1",
"@react-aria/overlays": "3.25.0",
"@react-aria/utils": "3.27.0",
"@tanstack/react-virtual": "^3.5.1",
"@types/jquery": "3.5.32",
"@types/lodash": "4.17.14",
@@ -85,8 +85,8 @@
"prismjs": "1.29.0",
"rc-cascader": "3.33.0",
"rc-drawer": "7.2.0",
"rc-picker": "4.9.2",
"rc-slider": "11.1.8",
"rc-time-picker": "^3.7.3",
"rc-tooltip": "6.4.0",
"react-calendar": "^5.1.0",
"react-colorful": "5.6.1",
@@ -1,4 +1,4 @@
import { render, screen } from '@testing-library/react';
import { render, screen, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { dateTime, dateTimeAsMoment, dateTimeForTimeZone, getTimeZone, setTimeZoneResolver } from '@grafana/data';
@@ -86,23 +86,16 @@ describe('Date time picker', () => {
// open the time of day overlay
await userEvent.click(screen.getAllByRole('textbox')[1]);
const hourList = screen.getAllByRole('list')[0];
// change the hour
await userEvent.click(
screen.getAllByRole('button', {
name: '00',
})[0]
);
await userEvent.click(within(hourList).getByText('00'));
// Check the active day is the 5th
expect(screen.getByRole('button', { name: 'May 5, 2021' })).toHaveClass('react-calendar__tile--active');
// change the hour
await userEvent.click(
screen.getAllByRole('button', {
name: '23',
})[0]
);
await userEvent.click(within(hourList).getByText('23'));
// Check the active day is the 5th
expect(screen.getByRole('button', { name: 'May 5, 2021' })).toHaveClass('react-calendar__tile--active');
@@ -123,7 +116,6 @@ describe('Date time picker', () => {
await userEvent.click(screen.getByRole('button', { name: 'May 15, 2021' }));
const timeInput = screen.getAllByRole('textbox')[1];
expect(timeInput).toHaveClass('rc-time-picker-input');
expect(timeInput).not.toHaveDisplayValue('00:00:00');
}
);
@@ -216,9 +208,7 @@ describe('Date time picker', () => {
await userEvent.click(screen.getAllByRole('textbox')[1]);
// check the hour element is visible
const hourElement = screen.getAllByRole('button', {
name: '00',
})[0];
const hourElement = screen.getAllByText('00')[0];
expect(hourElement).toBeVisible();
// select the hour value and check it's still visible
@@ -227,11 +217,7 @@ describe('Date time picker', () => {
// click outside the overlay and check the hour element is no longer visible
await userEvent.click(document.body);
expect(
screen.queryByRole('button', {
name: '00',
})
).not.toBeInTheDocument();
expect(screen.queryByText('00')).not.toBeInTheDocument();
}
);
@@ -24,7 +24,7 @@ export const Basic: StoryFn<typeof TimeOfDayPicker> = (args) => {
return (
<TimeOfDayPicker
{...args}
onChange={(newValue) => {
onChange={(newValue?) => {
action('on selected')(newValue);
updateArgs({ value: newValue });
}}
@@ -1,5 +1,8 @@
import { css, cx } from '@emotion/css';
import RcTimePicker from 'rc-time-picker';
import { Moment } from 'moment';
import RcPicker, { PickerProps } from 'rc-picker';
import generateConfig from 'rc-picker/lib/generate/moment';
import locale from 'rc-picker/lib/locale/en_US';
import { dateTime, DateTime, dateTimeAsMoment, GrafanaTheme2, isDateTimeInput } from '@grafana/data';
@@ -8,62 +11,102 @@ import { getFocusStyles } from '../../themes/mixins';
import { inputSizes } from '../Forms/commonStyles';
import { FormInputSize } from '../Forms/types';
import { Icon } from '../Icon/Icon';
import 'rc-picker/assets/index.css';
import 'rc-time-picker/assets/index.css';
export interface Props {
onChange: (value: DateTime) => void;
interface BaseProps {
onChange: (value: DateTime) => void | ((value?: DateTime) => void);
value?: DateTime;
showHour?: boolean;
showSeconds?: boolean;
minuteStep?: number;
minuteStep?: PickerProps['minuteStep'];
size?: FormInputSize;
disabled?: boolean;
disabledHours?: () => number[];
disabledMinutes?: () => number[];
disabledSeconds?: () => number[];
placeholder?: string;
allowEmpty?: boolean;
}
interface AllowEmptyProps extends BaseProps {
allowEmpty: true;
onChange: (value?: DateTime) => void;
}
interface NoAllowEmptyProps extends BaseProps {
allowEmpty?: false;
onChange: (value: DateTime) => void;
}
export type Props = AllowEmptyProps | NoAllowEmptyProps;
export const POPUP_CLASS_NAME = 'time-of-day-picker-panel';
export const TimeOfDayPicker = ({
minuteStep = 1,
showHour = true,
showSeconds = false,
onChange,
value,
size = 'auto',
disabled,
disabledHours,
disabledMinutes,
disabledSeconds,
placeholder,
// note: we can't destructure allowEmpty/onChange here
// in order to discriminate the types properly later in the onChange handler
...restProps
}: Props) => {
const styles = useStyles2(getStyles);
const allowClear = restProps.allowEmpty ?? false;
return (
<RcTimePicker
<RcPicker<Moment>
generateConfig={generateConfig}
locale={locale}
allowClear={
allowClear && {
clearIcon: <Icon name="times" className={styles.clearIcon} />,
}
}
className={cx(inputSizes()[size], styles.input)}
popupClassName={cx(styles.picker, POPUP_CLASS_NAME)}
defaultValue={dateTimeAsMoment()}
classNames={{
popup: cx(styles.picker, POPUP_CLASS_NAME),
}}
defaultValue={restProps.allowEmpty ? undefined : dateTimeAsMoment()}
disabled={disabled}
disabledTime={() => ({
disabledHours,
disabledMinutes,
disabledSeconds,
})}
format={generateFormat(showHour, showSeconds)}
minuteStep={minuteStep}
onChange={(value) => {
if (isDateTimeInput(value)) {
return onChange(dateTime(value));
if (restProps.allowEmpty) {
return restProps.onChange(value ? dateTime(value) : undefined);
} else {
return restProps.onChange(dateTime(value));
}
}
}}
allowEmpty={false}
showSecond={showSeconds}
value={dateTimeAsMoment(value)}
showHour={showHour}
minuteStep={minuteStep}
inputIcon={<Caret wrapperStyle={styles.caretWrapper} />}
disabled={disabled}
disabledHours={disabledHours}
disabledMinutes={disabledMinutes}
disabledSeconds={disabledSeconds}
picker="time"
placeholder={placeholder}
showNow={false}
needConfirm={false}
suffixIcon={<Caret wrapperStyle={styles.caretWrapper} />}
value={value ? dateTimeAsMoment(value) : value}
/>
);
};
function generateFormat(showHour = true, showSeconds = false) {
const maybeHour = showHour ? 'HH:' : '';
const maybeSecond = showSeconds ? ':ss' : '';
return maybeHour + 'mm' + maybeSecond;
}
interface CaretProps {
wrapperStyle?: string;
}
@@ -78,31 +121,44 @@ const Caret = ({ wrapperStyle = '' }: CaretProps) => {
const getStyles = (theme: GrafanaTheme2) => {
const bgColor = theme.components.input.background;
const menuShadowColor = theme.v1.palette.black;
const optionBgHover = theme.colors.background.secondary;
const optionBgHover = theme.colors.action.hover;
const borderRadius = theme.shape.radius.default;
const borderColor = theme.components.input.borderColor;
return {
caretWrapper: css({
position: 'absolute',
right: '8px',
position: 'relative',
top: '50%',
transform: 'translateY(-50%)',
display: 'inline-block',
textAlign: 'right',
color: theme.colors.text.secondary,
}),
clearIcon: css({
color: theme.colors.text.secondary,
'&:hover': {
color: theme.colors.text.maxContrast,
},
}),
picker: css({
'.rc-time-picker-panel-select': {
fontSize: '14px',
'&.rc-picker-dropdown': {
boxShadow: 'none',
zIndex: theme.zIndex.portal,
},
'.rc-picker-time-panel-column': {
fontSize: theme.typography.htmlFontSize,
backgroundColor: bgColor,
color: theme.colors.text.secondary,
borderColor,
padding: 'unset',
overflowY: 'auto',
scrollbarWidth: 'thin',
width: theme.spacing(8),
li: {
outlineWidth: '2px',
'&.rc-time-picker-panel-select-option-selected': {
paddingRight: theme.spacing(2),
width: 'auto',
'&.rc-picker-time-panel-cell-selected': {
backgroundColor: 'inherit',
border: `1px solid ${theme.v1.palette.orange}`,
border: `1px solid ${theme.colors.action.selectedBorder}`,
borderRadius,
color: theme.colors.text.primary,
},
@@ -112,44 +168,37 @@ const getStyles = (theme: GrafanaTheme2) => {
color: theme.colors.text.primary,
},
'&.rc-time-picker-panel-select-option-disabled': {
'&.rc-picker-time-panel-cell-disabled': {
color: theme.colors.action.disabledText,
},
},
'.rc-picker-time-panel-cell-inner': {
color: 'inherit',
},
'&:not(:last-of-type)': {
borderRight: `1px solid ${borderColor}`,
},
},
'.rc-time-picker-panel-inner': {
boxShadow: `0px 4px 4px ${menuShadowColor}`,
'.rc-picker-panel': {
boxShadow: theme.shadows.z3,
backgroundColor: bgColor,
borderColor,
borderRadius,
marginTop: '3px',
'.rc-time-picker-panel-input-wrap': {
marginRight: '2px',
'&, .rc-time-picker-panel-input': {
backgroundColor: bgColor,
paddingTop: '2px',
},
},
'.rc-time-picker-panel-combobox': {
display: 'flex',
},
overflow: 'hidden',
},
}),
input: css({
'.rc-time-picker-input': {
backgroundColor: bgColor,
borderRadius,
borderColor,
color: theme.colors.text.primary,
height: theme.spacing(4),
'&.rc-picker-focused': {
border: 'none',
'&:focus': getFocusStyles(theme),
'.rc-picker-input': getFocusStyles(theme),
},
'&:disabled': {
'&.rc-picker-disabled': {
'.rc-picker-input': {
backgroundColor: theme.colors.action.disabledBackground,
color: theme.colors.action.disabledText,
border: `1px solid ${theme.colors.action.disabledBackground}`,
@@ -158,6 +207,36 @@ const getStyles = (theme: GrafanaTheme2) => {
},
},
},
'.rc-picker-input': {
backgroundColor: bgColor,
borderRadius,
borderColor,
borderStyle: 'solid',
borderWidth: '1px',
color: theme.colors.text.primary,
height: theme.spacing(4),
padding: theme.spacing(0, 1),
input: {
color: 'unset',
backgroundColor: 'unset',
'&:focus': {
outline: 'none',
},
'&::placeholder': {
color: theme.colors.text.disabled,
},
},
},
'.rc-picker-clear': {
alignItems: 'center',
display: 'flex',
insetInlineEnd: 'unset',
position: 'relative',
},
}),
};
};
@@ -11,7 +11,7 @@ import type { ReactMonacoEditorProps } from './types';
monacoEditorLoader.config({ monaco });
export const ReactMonacoEditor = (props: ReactMonacoEditorProps) => {
const { beforeMount, options, ...restProps } = props;
const { beforeMount, onMount, options, ...restProps } = props;
const theme = useTheme2();
const onMonacoBeforeMount = useCallback(
@@ -31,6 +31,15 @@ export const ReactMonacoEditor = (props: ReactMonacoEditorProps) => {
}}
theme={theme.isDark ? 'grafana-dark' : 'grafana-light'}
beforeMount={onMonacoBeforeMount}
onMount={(editor, monaco) => {
// we use a custom font in our monaco editor
// we need monaco to remeasure the fonts after they are loaded to prevent alignment issues
// see https://github.com/microsoft/monaco-editor/issues/648#issuecomment-564978560
document.fonts.ready.then(() => {
monaco.editor.remeasureFonts();
});
onMount?.(editor, monaco);
}}
/>
);
};
@@ -1,4 +1,4 @@
import { useCallback, useState } from 'react';
import { useCallback } from 'react';
import * as React from 'react';
import { IconSize } from '../../types/icon';
@@ -6,7 +6,7 @@ import { IconButton } from '../IconButton/IconButton';
import { Stack } from '../Layout/Stack/Stack';
import { TooltipPlacement } from '../Tooltip';
import { TableCellInspector, TableCellInspectorMode } from './TableCellInspector';
import { TableCellInspectorMode } from './TableCellInspector';
import { FILTER_FOR_OPERATOR, FILTER_OUT_OPERATOR, TableCellProps } from './types';
import { getTextAlign } from './utils';
@@ -20,9 +20,14 @@ interface CommonButtonProps {
tooltipPlacement: TooltipPlacement;
}
export function CellActions({ field, cell, previewMode, showFilters, onCellFilterAdded }: CellActionProps) {
const [isInspecting, setIsInspecting] = useState(false);
export function CellActions({
field,
cell,
previewMode,
showFilters,
onCellFilterAdded,
setInspectCell,
}: CellActionProps) {
const isRightAligned = getTextAlign(field) === 'flex-end';
const inspectEnabled = Boolean(field.config.custom?.inspect);
const commonButtonProps: CommonButtonProps = {
@@ -48,37 +53,27 @@ export function CellActions({ field, cell, previewMode, showFilters, onCellFilte
);
return (
<>
<div className={`cellActions${isRightAligned ? ' cellActionsLeft' : ''}`}>
<Stack gap={0.5}>
{inspectEnabled && (
<IconButton
name="eye"
tooltip="Inspect value"
onClick={() => {
setIsInspecting(true);
}}
{...commonButtonProps}
/>
)}
{showFilters && (
<IconButton name={'search-plus'} onClick={onFilterFor} tooltip="Filter for value" {...commonButtonProps} />
)}
{showFilters && (
<IconButton name={'search-minus'} onClick={onFilterOut} tooltip="Filter out value" {...commonButtonProps} />
)}
</Stack>
</div>
{isInspecting && (
<TableCellInspector
mode={previewMode}
value={cell.value}
onDismiss={() => {
setIsInspecting(false);
}}
/>
)}
</>
<div className={`cellActions${isRightAligned ? ' cellActionsLeft' : ''}`}>
<Stack gap={0.5}>
{inspectEnabled && (
<IconButton
name="eye"
tooltip="Inspect value"
onClick={() => {
if (setInspectCell) {
setInspectCell({ value: cell.value, mode: previewMode });
}
}}
{...commonButtonProps}
/>
)}
{showFilters && (
<IconButton name={'search-plus'} onClick={onFilterFor} tooltip="Filter for value" {...commonButtonProps} />
)}
{showFilters && (
<IconButton name={'search-minus'} onClick={onFilterOut} tooltip="Filter out value" {...commonButtonProps} />
)}
</Stack>
</div>
);
}
@@ -1,5 +1,5 @@
import { cx } from '@emotion/css';
import { ReactElement, useState } from 'react';
import { ReactElement } from 'react';
import * as React from 'react';
import { DisplayValue, formattedValueToString } from '@grafana/data';
@@ -28,18 +28,10 @@ export const DefaultCell = (props: TableCellProps) => {
const hasLinks = Boolean(getCellLinks(field, row)?.length);
const hasActions = Boolean(actions?.length);
const clearButtonStyle = useStyles2(clearLinkButtonStyles);
const [hover, setHover] = useState(false);
let value: string | ReactElement;
const OG_TWEET_LENGTH = 140; // 🙏
const onMouseLeave = () => {
setHover(false);
};
const onMouseEnter = () => {
setHover(true);
};
if (cellOptions.type === TableCellDisplayMode.Custom) {
const CustomCellComponent: React.ComponentType<CustomCellRendererProps> = cellOptions.cellComponent;
value = <CustomCellComponent field={field} value={cell.value} rowIndex={row.index} frame={frame} />;
@@ -88,13 +80,7 @@ export const DefaultCell = (props: TableCellProps) => {
const { key, ...rest } = cellProps;
return (
<div
key={key}
{...rest}
onMouseEnter={showActions ? onMouseEnter : undefined}
onMouseLeave={showActions ? onMouseLeave : undefined}
className={cellStyle}
>
<div key={key} {...rest} className={cellStyle}>
{hasLinks || hasActions ? (
<DataLinksContextMenu links={() => getCellLinks(field, row) || []} actions={actions}>
{(api) => {
@@ -118,9 +104,7 @@ export const DefaultCell = (props: TableCellProps) => {
<div className={tableStyles.cellText}>{value}</div>
)}
{hover && showActions && (
<CellActions {...props} previewMode={TableCellInspectorMode.text} showFilters={showFilters} />
)}
{showActions && <CellActions {...props} previewMode={TableCellInspectorMode.text} showFilters={showFilters} />}
</div>
);
};
@@ -24,7 +24,13 @@ import { usePanelContext } from '../PanelChrome';
import { ExpandedRow, getExpandedRowHeight } from './ExpandedRow';
import { TableCell } from './TableCell';
import { TableStyles } from './styles';
import { CellColors, GetActionsFunction, TableFieldOptions, TableFilterActionCallback } from './types';
import {
CellColors,
GetActionsFunction,
TableFieldOptions,
TableFilterActionCallback,
TableInspectCellCallback,
} from './types';
import {
calculateAroundPointThreshold,
getCellColors,
@@ -57,6 +63,7 @@ interface RowsListProps {
textWrapField?: Field;
getActions?: GetActionsFunction;
replaceVariables?: InterpolateFunction;
setInspectCell?: TableInspectCellCallback;
}
export const RowsList = (props: RowsListProps) => {
@@ -85,6 +92,7 @@ export const RowsList = (props: RowsListProps) => {
textWrapField,
getActions,
replaceVariables,
setInspectCell,
} = props;
const [rowHighlightIndex, setRowHighlightIndex] = useState<number | undefined>(initialRowIndex);
@@ -346,6 +354,7 @@ export const RowsList = (props: RowsListProps) => {
height={Number(style.height)}
getActions={getActions}
replaceVariables={replaceVariables}
setInspectCell={setInspectCell}
/>
))}
</div>
@@ -374,6 +383,7 @@ export const RowsList = (props: RowsListProps) => {
timeRange,
getActions,
replaceVariables,
setInspectCell,
]
);
@@ -22,10 +22,11 @@ import { Pagination } from '../Pagination/Pagination';
import { FooterRow } from './FooterRow';
import { HeaderRow } from './HeaderRow';
import { RowsList } from './RowsList';
import { TableCellInspector } from './TableCellInspector';
import { useFixScrollbarContainer, useResetVariableListSizeCache } from './hooks';
import { getInitialState, useTableStateReducer } from './reducer';
import { useTableStyles } from './styles';
import { FooterItem, GrafanaTableState, Props } from './types';
import { FooterItem, GrafanaTableState, InspectCell, Props } from './types';
import {
getColumns,
sortCaseInsensitive,
@@ -72,6 +73,7 @@ export const Table = memo((props: Props) => {
const headerHeight = noHeader ? 0 : tableStyles.rowHeight;
const [footerItems, setFooterItems] = useState<FooterItem[] | undefined>(footerValues);
const noValuesDisplayText = fieldConfig?.defaults?.noValue ?? NO_DATA_TEXT;
const [inspectCell, setInspectCell] = useState<InspectCell | null>(null);
const footerHeight = useMemo(() => {
const EXTENDED_ROW_HEIGHT = FOOTER_ROW_HEIGHT;
@@ -324,66 +326,82 @@ export const Table = memo((props: Props) => {
}
return (
<div
{...getTableProps()}
className={tableStyles.table}
aria-label={ariaLabel}
role="table"
ref={tableDivRef}
style={{ width, height }}
>
<CustomScrollbar hideVerticalTrack={true}>
<div className={tableStyles.tableContentWrapper(totalColumnsWidth)}>
{!noHeader && (
<HeaderRow headerGroups={headerGroups} showTypeIcons={showTypeIcons} tableStyles={tableStyles} />
)}
{itemCount > 0 ? (
<div data-testid={selectors.components.Panels.Visualization.Table.body} ref={variableSizeListScrollbarRef}>
<RowsList
headerGroups={headerGroups}
data={data}
rows={rows}
width={width}
cellHeight={cellHeight}
headerHeight={headerHeight}
rowHeight={tableStyles.rowHeight}
itemCount={itemCount}
pageIndex={state.pageIndex}
listHeight={listHeight}
listRef={listRef}
tableState={state}
prepareRow={prepareRow}
timeRange={timeRange}
onCellFilterAdded={onCellFilterAdded}
nestedDataField={nestedDataField}
<>
<div
{...getTableProps()}
className={tableStyles.table}
aria-label={ariaLabel}
role="table"
ref={tableDivRef}
style={{ width, height }}
>
<CustomScrollbar hideVerticalTrack={true}>
<div className={tableStyles.tableContentWrapper(totalColumnsWidth)}>
{!noHeader && (
<HeaderRow headerGroups={headerGroups} showTypeIcons={showTypeIcons} tableStyles={tableStyles} />
)}
{itemCount > 0 ? (
<div
data-testid={selectors.components.Panels.Visualization.Table.body}
ref={variableSizeListScrollbarRef}
>
<RowsList
headerGroups={headerGroups}
data={data}
rows={rows}
width={width}
cellHeight={cellHeight}
headerHeight={headerHeight}
rowHeight={tableStyles.rowHeight}
itemCount={itemCount}
pageIndex={state.pageIndex}
listHeight={listHeight}
listRef={listRef}
tableState={state}
prepareRow={prepareRow}
timeRange={timeRange}
onCellFilterAdded={onCellFilterAdded}
nestedDataField={nestedDataField}
tableStyles={tableStyles}
footerPaginationEnabled={Boolean(enablePagination)}
enableSharedCrosshair={enableSharedCrosshair}
initialRowIndex={initialRowIndex}
longestField={longestField}
textWrapField={textWrapField}
getActions={getActions}
replaceVariables={replaceVariables}
setInspectCell={setInspectCell}
/>
</div>
) : (
<div style={{ height: height - headerHeight, width }} className={tableStyles.noData}>
{noValuesDisplayText}
</div>
)}
{footerItems && (
<FooterRow
isPaginationVisible={Boolean(enablePagination)}
footerValues={footerItems}
footerGroups={footerGroups}
totalColumnsWidth={totalColumnsWidth}
tableStyles={tableStyles}
footerPaginationEnabled={Boolean(enablePagination)}
enableSharedCrosshair={enableSharedCrosshair}
initialRowIndex={initialRowIndex}
longestField={longestField}
textWrapField={textWrapField}
getActions={getActions}
replaceVariables={replaceVariables}
/>
</div>
) : (
<div style={{ height: height - headerHeight, width }} className={tableStyles.noData}>
{noValuesDisplayText}
</div>
)}
{footerItems && (
<FooterRow
isPaginationVisible={Boolean(enablePagination)}
footerValues={footerItems}
footerGroups={footerGroups}
totalColumnsWidth={totalColumnsWidth}
tableStyles={tableStyles}
/>
)}
</div>
</CustomScrollbar>
{paginationEl}
</div>
)}
</div>
</CustomScrollbar>
{paginationEl}
</div>
{inspectCell !== null && (
<TableCellInspector
mode={inspectCell.mode}
value={inspectCell.value}
onDismiss={() => {
setInspectCell(null);
}}
/>
)}
</>
);
});
@@ -3,7 +3,7 @@ import { Cell } from 'react-table';
import { TimeRange, DataFrame, InterpolateFunction } from '@grafana/data';
import { TableStyles } from './styles';
import { GetActionsFunction, GrafanaTableColumn, TableFilterActionCallback } from './types';
import { GetActionsFunction, GrafanaTableColumn, TableFilterActionCallback, TableInspectCellCallback } from './types';
export interface Props {
cell: Cell;
@@ -20,6 +20,7 @@ export interface Props {
height?: number;
getActions?: GetActionsFunction;
replaceVariables?: InterpolateFunction;
setInspectCell?: TableInspectCellCallback;
}
export const TableCell = ({
@@ -35,6 +36,7 @@ export const TableCell = ({
height,
getActions,
replaceVariables,
setInspectCell,
}: Props) => {
const cellProps = cell.getCellProps();
const field = (cell.column as unknown as GrafanaTableColumn).field;
@@ -78,6 +80,7 @@ export const TableCell = ({
textWrapped,
height,
actions,
setInspectCell,
})}
</>
);
@@ -14,6 +14,7 @@ import {
} from '@grafana/data';
import * as schema from '@grafana/schema';
import { TableCellInspectorMode } from './TableCellInspector';
import { TableStyles } from './styles';
export {
@@ -33,6 +34,8 @@ export interface TableRow {
[x: string]: any;
}
export type InspectCell = { value: any; mode: TableCellInspectorMode };
export const FILTER_FOR_OPERATOR = '=';
export const FILTER_OUT_OPERATOR = '!=';
export type AdHocFilterOperator = typeof FILTER_FOR_OPERATOR | typeof FILTER_OUT_OPERATOR;
@@ -40,6 +43,7 @@ export type AdHocFilterItem = { key: string; value: string; operator: AdHocFilte
export type TableFilterActionCallback = (item: AdHocFilterItem) => void;
export type TableColumnResizeActionCallback = (fieldDisplayName: string, width: number) => void;
export type TableSortByActionCallback = (state: TableSortByFieldState[]) => void;
export type TableInspectCellCallback = (state: InspectCell) => void;
export interface TableSortByFieldState {
displayName: string;
@@ -54,6 +58,7 @@ export interface TableCellProps extends CellProps<any> {
innerWidth: number;
frame: DataFrame;
actions?: ActionModel[];
setInspectCell?: TableInspectCellCallback;
}
export type CellComponent = FC<TableCellProps>;
@@ -19,7 +19,6 @@ import { getLegacySelectStyles } from './legacySelect';
import { getMarkdownStyles } from './markdownStyles';
import { getPageStyles } from './page';
import { getQueryEditorStyles } from './queryEditor';
import { getRcTimePickerStyles } from './rcTimePicker';
import { getSkeletonStyles } from './skeletonStyles';
import { getSlateStyles } from './slate';
import { getUplotStyles } from './uPlot';
@@ -48,7 +47,6 @@ export function GlobalStyles() {
getMarkdownStyles(theme),
getPageStyles(theme),
getQueryEditorStyles(theme),
getRcTimePickerStyles(theme),
getSkeletonStyles(theme),
getSlateStyles(theme),
getUplotStyles(theme),
@@ -1,43 +0,0 @@
import { css } from '@emotion/react';
import { GrafanaTheme2 } from '@grafana/data';
export function getRcTimePickerStyles(theme: GrafanaTheme2) {
return css({
'.rc-time-picker-input,.rc-time-picker-panel-input-wrap,.rc-time-picker-panel-inner': {
backgroundColor: theme.components.input.background,
color: theme.colors.text.secondary,
borderColor: theme.components.input.borderColor,
fontSize: theme.typography.body.fontSize,
},
'.rc-time-picker-input': {
padding: theme.spacing(0, 1),
height: theme.spacing(4),
},
'.rc-time-picker-panel': {
width: '176px',
},
'.rc-time-picker-panel-select': {
width: '50%',
'&:only-child': {
width: '100%',
},
'.rc-time-picker-panel-select-option-selected': {
backgroundColor: theme.colors.background.secondary,
},
'li:hover': {
backgroundColor: theme.colors.background.secondary,
},
},
'.rc-time-picker-panel-narrow': {
maxWidth: 'none',
},
});
}
+4 -4
View File
@@ -54,7 +54,7 @@ require (
github.com/golang-jwt/jwt/v4 v4.5.1 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/btree v1.1.3 // indirect
github.com/google/cel-go v0.22.0 // indirect
github.com/google/cel-go v0.22.1 // indirect
github.com/google/flatbuffers v24.3.25+incompatible // indirect
github.com/google/gnostic-models v0.6.8 // indirect
github.com/google/go-cmp v0.6.0 // indirect
@@ -69,7 +69,7 @@ require (
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 // indirect
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.2.0 // indirect
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 // indirect
github.com/hashicorp/go-hclog v1.6.3 // indirect
github.com/hashicorp/go-plugin v1.6.2 // indirect
github.com/hashicorp/yamux v0.1.1 // indirect
@@ -128,7 +128,7 @@ require (
go.opentelemetry.io/otel/metric v1.33.0 // indirect
go.opentelemetry.io/otel/sdk v1.33.0 // indirect
go.opentelemetry.io/otel/trace v1.33.0 // indirect
go.opentelemetry.io/proto/otlp v1.4.0 // indirect
go.opentelemetry.io/proto/otlp v1.5.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/crypto v0.32.0 // indirect
@@ -144,7 +144,7 @@ require (
golang.org/x/tools v0.29.0 // indirect
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect
google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d // indirect
google.golang.org/grpc v1.69.2 // indirect
google.golang.org/protobuf v1.36.1 // indirect
+8 -8
View File
@@ -110,8 +110,8 @@ github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
github.com/google/cel-go v0.22.0 h1:b3FJZxpiv1vTMo2/5RDUqAHPxkT8mmMfJIrq1llbf7g=
github.com/google/cel-go v0.22.0/go.mod h1:BuznPXXfQDpXKWQ9sPW3TzlAJN5zzFe+i9tIs0yC4s8=
github.com/google/cel-go v0.22.1 h1:AfVXx3chM2qwoSbM7Da8g8hX8OVSkBFwX+rz2+PcK40=
github.com/google/cel-go v0.22.1/go.mod h1:BuznPXXfQDpXKWQ9sPW3TzlAJN5zzFe+i9tIs0yC4s8=
github.com/google/flatbuffers v24.3.25+incompatible h1:CX395cjN9Kke9mmalRoL3d81AtFUxJM+yDthflgJGkI=
github.com/google/flatbuffers v24.3.25+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
@@ -154,8 +154,8 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a534
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340/go.mod h1:3bDW6wMZJB7tiONtC/1Xpicra6Wp5GgbTbQWCbI5fkc=
github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 h1:TmHmbvxPmaegwhDubVz0lICL0J5Ka2vwTzhoePEXsGE=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0/go.mod h1:qztMSjm835F2bXf+5HKAPIS5qsmQDqZna/PgVt4rWtI=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 h1:VNqngBF40hVlDloBruUehVYC3ArSgIyScOAyMRqBxRg=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1/go.mod h1:RBRO7fro65R6tjKzYgLAFo0t1QEXY1Dp+i/bvpRiqiQ=
github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
github.com/hashicorp/go-plugin v1.6.2 h1:zdGAEd0V1lCaU0u+MxWQhtSDQmahpkwOun8U8EiRVog=
@@ -379,8 +379,8 @@ go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC
go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ=
go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s=
go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck=
go.opentelemetry.io/proto/otlp v1.4.0 h1:TA9WRvW6zMwP+Ssb6fLoUIuirti1gGbP28GcKG1jgeg=
go.opentelemetry.io/proto/otlp v1.4.0/go.mod h1:PPBWZIP98o2ElSqI35IHfu7hIhSwvc5N38Jw8pXuGFY=
go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4=
go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
@@ -481,8 +481,8 @@ google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98
google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 h1:Q3nlH8iSQSRUwOskjbcSMcF2jiYMNiQYZ0c2KEJLKKU=
google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38/go.mod h1:xBI+tzfqGGN2JBeSebfKXFSdBpWVQ7sLW40PTupVRm4=
google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484 h1:ChAdCYNQFDk5fYvFZMywKLIijG7TC2m1C2CMEu11G3o=
google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484/go.mod h1:KRUmxRI4JmbpAm8gcZM4Jsffi859fo5LQjILwuqj9z8=
google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d h1:H8tOf8XM88HvKqLTxe755haY6r1fqqzLbEnfrmLXlSA=
google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d/go.mod h1:2v7Z7gP2ZUOGsaFyxATQSRoBnKygqVq2Cwnvom7QiqY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d h1:xJJRGY7TJcvIlpSrN3K6LAWgNFUILlO+OMAqtg9aqnw=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d/go.mod h1:3ENsm/5D1mzDyhpzeRi1NR784I0BcofWBoSc5QqqMK4=
google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
+3 -3
View File
@@ -46,7 +46,7 @@ require (
github.com/gorilla/websocket v1.5.3 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
@@ -75,7 +75,7 @@ require (
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.33.0 // indirect
go.opentelemetry.io/otel/metric v1.33.0 // indirect
go.opentelemetry.io/otel/sdk v1.33.0 // indirect
go.opentelemetry.io/proto/otlp v1.4.0 // indirect
go.opentelemetry.io/proto/otlp v1.5.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/net v0.34.0 // indirect
@@ -86,7 +86,7 @@ require (
golang.org/x/time v0.9.0 // indirect
golang.org/x/tools v0.29.0 // indirect
google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d // indirect
google.golang.org/grpc v1.69.2 // indirect
google.golang.org/protobuf v1.36.1 // indirect
+6 -6
View File
@@ -89,8 +89,8 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a534
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340/go.mod h1:3bDW6wMZJB7tiONtC/1Xpicra6Wp5GgbTbQWCbI5fkc=
github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 h1:TmHmbvxPmaegwhDubVz0lICL0J5Ka2vwTzhoePEXsGE=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0/go.mod h1:qztMSjm835F2bXf+5HKAPIS5qsmQDqZna/PgVt4rWtI=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 h1:VNqngBF40hVlDloBruUehVYC3ArSgIyScOAyMRqBxRg=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1/go.mod h1:RBRO7fro65R6tjKzYgLAFo0t1QEXY1Dp+i/bvpRiqiQ=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4=
@@ -216,8 +216,8 @@ go.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4Jjx
go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8=
go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s=
go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck=
go.opentelemetry.io/proto/otlp v1.4.0 h1:TA9WRvW6zMwP+Ssb6fLoUIuirti1gGbP28GcKG1jgeg=
go.opentelemetry.io/proto/otlp v1.4.0/go.mod h1:PPBWZIP98o2ElSqI35IHfu7hIhSwvc5N38Jw8pXuGFY=
go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4=
go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
@@ -298,8 +298,8 @@ google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98
google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 h1:Q3nlH8iSQSRUwOskjbcSMcF2jiYMNiQYZ0c2KEJLKKU=
google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38/go.mod h1:xBI+tzfqGGN2JBeSebfKXFSdBpWVQ7sLW40PTupVRm4=
google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484 h1:ChAdCYNQFDk5fYvFZMywKLIijG7TC2m1C2CMEu11G3o=
google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484/go.mod h1:KRUmxRI4JmbpAm8gcZM4Jsffi859fo5LQjILwuqj9z8=
google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d h1:H8tOf8XM88HvKqLTxe755haY6r1fqqzLbEnfrmLXlSA=
google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d/go.mod h1:2v7Z7gP2ZUOGsaFyxATQSRoBnKygqVq2Cwnvom7QiqY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d h1:xJJRGY7TJcvIlpSrN3K6LAWgNFUILlO+OMAqtg9aqnw=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d/go.mod h1:3ENsm/5D1mzDyhpzeRi1NR784I0BcofWBoSc5QqqMK4=
google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
+3 -3
View File
@@ -77,7 +77,7 @@ require (
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect
golang.org/x/sys v0.29.0 // indirect
google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 // indirect; @grafana/grafana-backend-group
google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)
@@ -92,7 +92,7 @@ require (
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/distribution/reference v0.6.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect
github.com/moby/term v0.5.0 // indirect
@@ -106,7 +106,7 @@ require (
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.33.0 // indirect
go.opentelemetry.io/otel/log v0.4.0 // indirect
go.opentelemetry.io/otel/sdk/log v0.4.0 // indirect
go.opentelemetry.io/proto/otlp v1.4.0 // indirect
go.opentelemetry.io/proto/otlp v1.5.0 // indirect
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect
gotest.tools/v3 v3.5.1 // indirect
)
+6 -6
View File
@@ -146,8 +146,8 @@ github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKG
github.com/googleapis/gax-go/v2 v2.14.1 h1:hb0FFeiPaQskmvakKu5EbCbpntQn48jyHuvrkurSS/Q=
github.com/googleapis/gax-go/v2 v2.14.1/go.mod h1:Hb/NubMaVM88SrNkvl8X/o8XWwDJEPqouaLeN2IUxoA=
github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 h1:TmHmbvxPmaegwhDubVz0lICL0J5Ka2vwTzhoePEXsGE=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0/go.mod h1:qztMSjm835F2bXf+5HKAPIS5qsmQDqZna/PgVt4rWtI=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 h1:VNqngBF40hVlDloBruUehVYC3ArSgIyScOAyMRqBxRg=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1/go.mod h1:RBRO7fro65R6tjKzYgLAFo0t1QEXY1Dp+i/bvpRiqiQ=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
@@ -259,8 +259,8 @@ go.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4Jjx
go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8=
go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s=
go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck=
go.opentelemetry.io/proto/otlp v1.4.0 h1:TA9WRvW6zMwP+Ssb6fLoUIuirti1gGbP28GcKG1jgeg=
go.opentelemetry.io/proto/otlp v1.4.0/go.mod h1:PPBWZIP98o2ElSqI35IHfu7hIhSwvc5N38Jw8pXuGFY=
go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4=
go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4=
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca h1:VdD38733bfYv5tUZwEIskMM93VanwNIi5bIKnDrJdEY=
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
@@ -343,8 +343,8 @@ google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 h1:Q3nlH8iSQSRUwOskjbcSMcF2jiYMNiQYZ0c2KEJLKKU=
google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38/go.mod h1:xBI+tzfqGGN2JBeSebfKXFSdBpWVQ7sLW40PTupVRm4=
google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484 h1:ChAdCYNQFDk5fYvFZMywKLIijG7TC2m1C2CMEu11G3o=
google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484/go.mod h1:KRUmxRI4JmbpAm8gcZM4Jsffi859fo5LQjILwuqj9z8=
google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d h1:H8tOf8XM88HvKqLTxe755haY6r1fqqzLbEnfrmLXlSA=
google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d/go.mod h1:2v7Z7gP2ZUOGsaFyxATQSRoBnKygqVq2Cwnvom7QiqY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d h1:xJJRGY7TJcvIlpSrN3K6LAWgNFUILlO+OMAqtg9aqnw=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d/go.mod h1:3ENsm/5D1mzDyhpzeRi1NR784I0BcofWBoSc5QqqMK4=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
@@ -13,6 +13,7 @@ import (
"github.com/grafana/grafana/pkg/infra/db"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/folder/foldertest"
"github.com/grafana/grafana/pkg/services/org/orgtest"
"github.com/grafana/grafana/pkg/services/stats/statsimpl"
@@ -28,7 +29,7 @@ func TestMain(m *testing.M) {
func TestConcurrentUsersMetrics(t *testing.T) {
sqlStore, cfg := db.InitTestDBWithCfg(t)
statsService := statsimpl.ProvideService(&setting.Cfg{}, sqlStore, &dashboards.FakeDashboardService{}, &foldertest.FakeService{}, &orgtest.FakeOrgService{})
statsService := statsimpl.ProvideService(&setting.Cfg{}, sqlStore, &dashboards.FakeDashboardService{}, &foldertest.FakeService{}, &orgtest.FakeOrgService{}, featuremgmt.WithFeatures())
s := createService(t, cfg, sqlStore, statsService)
createConcurrentTokens(t, sqlStore)
@@ -46,7 +47,7 @@ func TestConcurrentUsersMetrics(t *testing.T) {
func TestConcurrentUsersStats(t *testing.T) {
sqlStore, cfg := db.InitTestDBWithCfg(t)
statsService := statsimpl.ProvideService(&setting.Cfg{}, sqlStore, &dashboards.FakeDashboardService{}, &foldertest.FakeService{}, &orgtest.FakeOrgService{})
statsService := statsimpl.ProvideService(&setting.Cfg{}, sqlStore, &dashboards.FakeDashboardService{}, &foldertest.FakeService{}, &orgtest.FakeOrgService{}, featuremgmt.WithFeatures())
s := createService(t, cfg, sqlStore, statsService)
createConcurrentTokens(t, sqlStore)
+3 -3
View File
@@ -53,7 +53,7 @@ require (
github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc // indirect
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 // indirect
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.2.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 // indirect
github.com/hashicorp/go-hclog v1.6.3 // indirect
github.com/hashicorp/go-plugin v1.6.2 // indirect
github.com/hashicorp/yamux v0.1.1 // indirect
@@ -100,7 +100,7 @@ require (
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.33.0 // indirect
go.opentelemetry.io/otel/metric v1.33.0 // indirect
go.opentelemetry.io/otel/sdk v1.33.0 // indirect
go.opentelemetry.io/proto/otlp v1.4.0 // indirect
go.opentelemetry.io/proto/otlp v1.5.0 // indirect
go.uber.org/atomic v1.11.0 // indirect
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect
golang.org/x/mod v0.22.0 // indirect
@@ -112,7 +112,7 @@ require (
golang.org/x/tools v0.29.0 // indirect
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect
google.golang.org/api v0.216.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d // indirect
google.golang.org/grpc v1.69.2 // indirect
google.golang.org/protobuf v1.36.1 // indirect
+6 -6
View File
@@ -132,8 +132,8 @@ github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 h1:qnpS
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1/go.mod h1:lXGCsh6c22WGtjr+qGHj1otzZpV/1kwTMAqkwZsnWRU=
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.2.0 h1:kQ0NI7W1B3HwiN5gAYtY+XFItDPbLBwYRxAqbFTyDes=
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.2.0/go.mod h1:zrT2dxOAjNFPRGjTUe2Xmb4q4YdUwVvQFV6xiCSf+z0=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 h1:TmHmbvxPmaegwhDubVz0lICL0J5Ka2vwTzhoePEXsGE=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0/go.mod h1:qztMSjm835F2bXf+5HKAPIS5qsmQDqZna/PgVt4rWtI=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 h1:VNqngBF40hVlDloBruUehVYC3ArSgIyScOAyMRqBxRg=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1/go.mod h1:RBRO7fro65R6tjKzYgLAFo0t1QEXY1Dp+i/bvpRiqiQ=
github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
github.com/hashicorp/go-plugin v1.6.2 h1:zdGAEd0V1lCaU0u+MxWQhtSDQmahpkwOun8U8EiRVog=
@@ -318,8 +318,8 @@ go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC
go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ=
go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s=
go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck=
go.opentelemetry.io/proto/otlp v1.4.0 h1:TA9WRvW6zMwP+Ssb6fLoUIuirti1gGbP28GcKG1jgeg=
go.opentelemetry.io/proto/otlp v1.4.0/go.mod h1:PPBWZIP98o2ElSqI35IHfu7hIhSwvc5N38Jw8pXuGFY=
go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4=
go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4=
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
@@ -386,8 +386,8 @@ gonum.org/v1/gonum v0.15.1 h1:FNy7N6OUZVUaWG9pTiD+jlhdQ3lMP+/LcTpJ6+a8sQ0=
gonum.org/v1/gonum v0.15.1/go.mod h1:eZTZuRFrzu5pcyjN5wJhcIhnUdNijYxX1T2IcrOGY0o=
google.golang.org/api v0.216.0 h1:xnEHy+xWFrtYInWPy8OdGFsyIfWJjtVnO39g7pz2BFY=
google.golang.org/api v0.216.0/go.mod h1:K9wzQMvWi47Z9IU7OgdOofvZuw75Ge3PPITImZR/UyI=
google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484 h1:ChAdCYNQFDk5fYvFZMywKLIijG7TC2m1C2CMEu11G3o=
google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484/go.mod h1:KRUmxRI4JmbpAm8gcZM4Jsffi859fo5LQjILwuqj9z8=
google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d h1:H8tOf8XM88HvKqLTxe755haY6r1fqqzLbEnfrmLXlSA=
google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d/go.mod h1:2v7Z7gP2ZUOGsaFyxATQSRoBnKygqVq2Cwnvom7QiqY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d h1:xJJRGY7TJcvIlpSrN3K6LAWgNFUILlO+OMAqtg9aqnw=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d/go.mod h1:3ENsm/5D1mzDyhpzeRi1NR784I0BcofWBoSc5QqqMK4=
google.golang.org/grpc v1.69.2 h1:U3S9QEtbXC0bYNvRtcoklF3xGtLViumSYxWykJS+7AU=
+5
View File
@@ -4,10 +4,15 @@ import (
"fmt"
"strings"
"github.com/prometheus/common/model"
"github.com/prometheus/prometheus/model/labels"
"github.com/prometheus/prometheus/promql/parser"
)
func init() {
model.NameValidationScheme = model.UTF8Validation
}
// ApplyFiltersAndGroupBy takes a raw promQL expression, converts the filters into PromQL matchers, and applies these matchers to the parsed expression. It also applies the group by clause to any aggregate expressions in the parsed expression.
func ApplyFiltersAndGroupBy(rawExpr string, scopeFilters, adHocFilters []ScopeFilter, groupBy []string) (string, error) {
expr, err := parser.ParseExpr(rawExpr)
+136 -2
View File
@@ -145,6 +145,37 @@ func TestApplyQueryFiltersAndGroupBy_Filters(t *testing.T) {
}
}
func TestApplyQueryFiltersAndGroupBy_Filters_utf8(t *testing.T) {
tests := []struct {
name string
query string
adhocFilters []ScopeFilter
scopeFilters []ScopeFilter
expected string
expectErr bool
}{
{
name: "No filters with existing utf8 filter",
query: `http_requests_total{"job.name"="prometheus"}`,
expected: `http_requests_total{"job.name"="prometheus"}`,
expectErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
expr, err := ApplyFiltersAndGroupBy(tt.query, tt.scopeFilters, tt.adhocFilters, nil)
if tt.expectErr {
require.Error(t, err)
} else {
require.NoError(t, err)
require.Equal(t, tt.expected, expr, tt.name)
}
})
}
}
func TestApplyQueryFiltersAndGroupBy_GroupBy(t *testing.T) {
tests := []struct {
name string
@@ -197,7 +228,45 @@ func TestApplyQueryFiltersAndGroupBy_GroupBy(t *testing.T) {
require.Error(t, err)
} else {
require.NoError(t, err)
require.Equal(t, expr, tt.expected)
require.Equal(t, tt.expected, expr)
}
})
}
}
func TestApplyQueryFiltersAndGroupBy_GroupBy_utf8(t *testing.T) {
tests := []struct {
name string
query string
groupBy []string
expected string
expectErr bool
}{
{
name: "GroupBy with no aggregate expression and utf8 metric",
groupBy: []string{"job"},
query: `{"http.requests_total"}`,
expected: `{__name__="http.requests_total"}`,
expectErr: false,
},
{
name: "GroupBy with aggregate expression with existing utf8 group by",
groupBy: []string{"status"},
query: `sum by ("utf8.job") (http_requests_total)`,
expected: `sum by ("utf8.job", status) (http_requests_total)`,
expectErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
expr, err := ApplyFiltersAndGroupBy(tt.query, nil, nil, tt.groupBy)
if tt.expectErr {
require.Error(t, err)
} else {
require.NoError(t, err)
require.Equal(t, tt.expected, expr)
}
})
}
@@ -237,7 +306,72 @@ func TestApplyQueryFiltersAndGroupBy(t *testing.T) {
require.Error(t, err)
} else {
require.NoError(t, err)
require.Equal(t, expr, tt.expected)
require.Equal(t, tt.expected, expr)
}
})
}
}
func TestApplyQueryFiltersAndGroupBy_utf8(t *testing.T) {
tests := []struct {
name string
query string
adhocFilters []ScopeFilter
scopeFilters []ScopeFilter
groupby []string
expected string
expectErr bool
}{
{
name: "Adhoc filters with more complex expression and utf8 metric name",
query: `sum({"capacity_bytes", job="prometheus"} + {"available_bytes", job="grafana"}) / 1024`,
adhocFilters: []ScopeFilter{
{Key: "job", Value: "alloy", Operator: FilterOperatorEquals},
},
scopeFilters: []ScopeFilter{
{Key: "vol", Value: "/", Operator: FilterOperatorEquals},
},
groupby: []string{"job"},
expected: `sum by (job) ({__name__="capacity_bytes",job="alloy",vol="/"} + {__name__="available_bytes",job="alloy",vol="/"}) / 1024`,
expectErr: false,
},
{
name: "Adhoc filters with more complex expression with utf8 label",
query: `sum(capacity_bytes{job="prometheus", "utf8.label"="value"} + available_bytes{job="grafana"}) / 1024`,
adhocFilters: []ScopeFilter{
{Key: "job", Value: "alloy", Operator: FilterOperatorEquals},
},
scopeFilters: []ScopeFilter{
{Key: "vol", Value: "/", Operator: FilterOperatorEquals},
},
groupby: []string{"job"},
expected: `sum by (job) (capacity_bytes{"utf8.label"="value",job="alloy",vol="/"} + available_bytes{job="alloy",vol="/"}) / 1024`,
expectErr: false,
},
{
name: "Adhoc filters with more complex expression with utf8 metric and label",
query: `sum({"capacity_bytes", job="prometheus", "utf8.label"="value"} + available_bytes{job="grafana"}) / 1024`,
adhocFilters: []ScopeFilter{
{Key: "job", Value: "alloy", Operator: FilterOperatorEquals},
},
scopeFilters: []ScopeFilter{
{Key: "vol", Value: "/", Operator: FilterOperatorEquals},
},
groupby: []string{"job"},
expected: `sum by (job) ({"utf8.label"="value",__name__="capacity_bytes",job="alloy",vol="/"} + available_bytes{job="alloy",vol="/"}) / 1024`,
expectErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
expr, err := ApplyFiltersAndGroupBy(tt.query, tt.scopeFilters, tt.adhocFilters, tt.groupby)
if tt.expectErr {
require.Error(t, err)
} else {
require.NoError(t, err)
require.Equal(t, tt.expected, expr)
}
})
}
+32 -1
View File
@@ -5,6 +5,7 @@ import (
"encoding/json"
"fmt"
"net/http"
"strings"
"time"
"github.com/grafana/authlib/claims"
@@ -340,5 +341,35 @@ func (a *dashboardSqlAccess) CountRepositoryObjects(context.Context, *resource.C
// GetStats implements ResourceServer.
func (a *dashboardSqlAccess) GetStats(ctx context.Context, req *resource.ResourceStatsRequest) (*resource.ResourceStatsResponse, error) {
return nil, fmt.Errorf("not yet (GetStats)")
info, err := claims.ParseNamespace(req.Namespace)
if err != nil {
return nil, fmt.Errorf("unable to read namespace")
}
if info.OrgID == 0 {
return nil, fmt.Errorf("invalid OrgID found in namespace")
}
if len(req.Kinds) != 1 {
return nil, fmt.Errorf("only can query for dashboard kind in legacy fallback")
}
parts := strings.SplitN(req.Kinds[0], "/", 2)
if len(parts) != 2 {
return nil, fmt.Errorf("invalid kind")
}
count, err := a.dashStore.CountInOrg(ctx, info.OrgID)
if err != nil {
return nil, err
}
return &resource.ResourceStatsResponse{
Stats: []*resource.ResourceStatsResponse_Stats{
{
Group: parts[0],
Resource: parts[1],
Count: count,
},
},
}, nil
}
+3 -22
View File
@@ -3,7 +3,6 @@ package folders
import (
"fmt"
"regexp"
"strconv"
"time"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -80,10 +79,7 @@ func UnstructuredToLegacyFolder(item unstructured.Unstructured, orgID int64) (*f
return nil, ""
}
id, err := getLegacyID(meta)
if err != nil {
return nil, ""
}
id := meta.GetDeprecatedInternalID() // nolint:staticcheck
created, err := getCreated(meta)
if err != nil {
@@ -161,6 +157,8 @@ func convertToK8sResource(v *folder.Folder, namespacer request.NamespaceMapper)
meta.SetUpdatedTimestamp(&v.Updated)
if v.ID > 0 { // nolint:staticcheck
meta.SetDeprecatedInternalID(v.ID) // nolint:staticcheck
meta.SetRepositoryInfo(&utils.ResourceRepositoryInfo{
Name: "SQL",
Path: fmt.Sprintf("%d", v.ID), // nolint:staticcheck
@@ -201,23 +199,6 @@ func setParentUID(u *unstructured.Unstructured, parentUid string) error {
return nil
}
func getLegacyID(meta utils.GrafanaMetaAccessor) (int64, error) {
var i int64
repo, err := meta.GetRepositoryInfo()
if err != nil {
return i, err
}
if repo != nil && repo.Name == "SQL" {
i, err = strconv.ParseInt(repo.Path, 10, 64)
if err != nil {
return i, err
}
}
return i, nil
}
func getURL(meta utils.GrafanaMetaAccessor, title string) string {
slug := slugify.Slugify(title)
uid := meta.GetName()
+6 -3
View File
@@ -18,13 +18,11 @@ import (
common "k8s.io/kube-openapi/pkg/common"
"k8s.io/kube-openapi/pkg/spec3"
grafanarest "github.com/grafana/grafana/pkg/apiserver/rest"
"github.com/grafana/grafana/pkg/storage/unified/resource"
"github.com/grafana/grafana/pkg/apimachinery/identity"
"github.com/grafana/grafana/pkg/apimachinery/utils"
"github.com/grafana/grafana/pkg/apis/folder/v0alpha1"
grafanaregistry "github.com/grafana/grafana/pkg/apiserver/registry/generic"
grafanarest "github.com/grafana/grafana/pkg/apiserver/rest"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/apiserver/builder"
"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request"
@@ -32,6 +30,8 @@ import (
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/folder"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/storage/unified/apistore"
"github.com/grafana/grafana/pkg/storage/unified/resource"
)
var _ builder.APIGroupBuilder = (*FolderAPIBuilder)(nil)
@@ -134,6 +134,9 @@ func (b *FolderAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver.API
cfg: b.cfg,
}
opts.StorageOptions(resourceInfo.GroupResource(), apistore.StorageOptions{
RequireDeprecatedInternalID: true})
storage := map[string]rest.Storage{}
storage[resourceInfo.StoragePath()] = legacyStore
if optsGetter != nil && dualWriteBuilder != nil {
+2
View File
@@ -36,6 +36,7 @@ type DashboardService interface {
RestoreDashboard(ctx context.Context, dashboard *Dashboard, user identity.Requester, optionalFolderUID string) error
CleanUpDeletedDashboards(ctx context.Context) (int64, error)
GetSoftDeletedDashboard(ctx context.Context, orgID int64, uid string) (*Dashboard, error)
CountDashboardsInOrg(ctx context.Context, orgID int64) (int64, error)
}
// PluginService is a service for operating on plugin dashboards.
@@ -82,6 +83,7 @@ type Store interface {
ValidateDashboardBeforeSave(ctx context.Context, dashboard *Dashboard, overwrite bool) (bool, error)
Count(context.Context, *quota.ScopeParameters) (*quota.Map, error)
CountInOrg(ctx context.Context, orgID int64) (int64, error)
// CountDashboardsInFolder returns the number of dashboards associated with
// the given parent folder ID.
CountDashboardsInFolders(ctx context.Context, request *CountDashboardsInFolderRequest) (int64, error)
@@ -168,6 +168,36 @@ func (_m *FakeDashboardService) FindDashboards(ctx context.Context, query *FindP
return r0, r1
}
// CountDashboardsInOrg provides a mock function with given fields: ctx, orgID
func (_m *FakeDashboardService) CountDashboardsInOrg(ctx context.Context, orgID int64) (int64, error) {
ret := _m.Called(ctx, orgID)
if len(ret) == 0 {
panic("no return value specified for CountDashboardsInOrg")
}
var r0 int64
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, int64) (int64, error)); ok {
return rf(ctx, orgID)
}
if rf, ok := ret.Get(0).(func(context.Context, int64) int64); ok {
r0 = rf(ctx, orgID)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(int64)
}
}
if rf, ok := ret.Get(1).(func(context.Context, int64) error); ok {
r1 = rf(ctx, orgID)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// GetAllDashboards provides a mock function with given fields: ctx
func (_m *FakeDashboardService) GetAllDashboards(ctx context.Context) ([]*Dashboard, error) {
ret := _m.Called(ctx)
@@ -266,6 +266,24 @@ func (d *dashboardStore) Count(ctx context.Context, scopeParams *quota.ScopePara
return u, nil
}
func (d *dashboardStore) CountInOrg(ctx context.Context, orgID int64) (int64, error) {
type result struct {
Count int64
}
r := result{}
if err := d.store.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
rawSQL := fmt.Sprintf("SELECT COUNT(*) AS count FROM dashboard WHERE org_id=? AND is_folder=%s", d.store.GetDialect().BooleanStr(false))
if _, err := sess.SQL(rawSQL, orgID).Get(&r); err != nil {
return err
}
return nil
}); err != nil {
return 0, err
}
return r.Count, nil
}
func getExistingDashboardByIDOrUIDForUpdate(sess *db.Session, dash *dashboards.Dashboard, overwrite bool) (bool, error) {
dashWithIdExists := false
isParentFolderChanged := false
@@ -61,6 +61,7 @@ func TestIntegrationDashboardDataAccess(t *testing.T) {
savedDash = insertTestDashboard(t, dashboardStore, "test dash 23", 1, savedFolder.ID, savedFolder.UID, false, "prod", "webapp")
insertTestDashboard(t, dashboardStore, "test dash 45", 1, savedFolder.ID, savedFolder.UID, false, "prod")
savedDash2 = insertTestDashboard(t, dashboardStore, "test dash 67", 1, 0, "", false, "prod")
insertTestDashboard(t, dashboardStore, "test dash org2", 2, 0, "", false, "")
insertTestRule(t, sqlStore, savedFolder.OrgID, savedFolder.UID)
}
@@ -81,6 +82,17 @@ func TestIntegrationDashboardDataAccess(t *testing.T) {
require.Positive(t, len(savedFolder.UID))
})
t.Run("Should be able to get dashboard counts per org", func(t *testing.T) {
setup()
count, err := dashboardStore.CountInOrg(context.Background(), 1)
require.NoError(t, err)
require.Equal(t, int64(3), count)
count, err = dashboardStore.CountInOrg(context.Background(), 2)
require.NoError(t, err)
require.Equal(t, int64(1), count)
})
t.Run("Should be able to get dashboard by id", func(t *testing.T) {
setup()
query := dashboards.GetDashboardQuery{
@@ -52,6 +52,7 @@ import (
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/storage/unified/resource"
"github.com/grafana/grafana/pkg/storage/unified/search"
"github.com/grafana/grafana/pkg/util"
)
@@ -179,11 +180,10 @@ func (dr *DashboardServiceImpl) Count(ctx context.Context, scopeParams *quota.Sc
total := int64(0)
for _, org := range orgs {
ctx = identity.WithRequester(ctx, getDashboardBackgroundRequester(org.ID))
dashs, err := dr.listDashboardsThroughK8s(ctx, org.ID)
orgDashboards, err := dr.CountDashboardsInOrg(ctx, org.ID)
if err != nil {
return u, err
return nil, err
}
orgDashboards := int64(len(dashs))
total += orgDashboards
tag, err := quota.NewTag(dashboards.QuotaTargetSrv, dashboards.QuotaTarget, quota.OrgScope)
@@ -205,6 +205,28 @@ func (dr *DashboardServiceImpl) Count(ctx context.Context, scopeParams *quota.Sc
return dr.dashboardStore.Count(ctx, scopeParams)
}
func (dr *DashboardServiceImpl) CountDashboardsInOrg(ctx context.Context, orgID int64) (int64, error) {
if dr.features.IsEnabledGlobally(featuremgmt.FlagKubernetesCliDashboards) {
resp, err := dr.k8sclient.getSearcher().GetStats(ctx, &resource.ResourceStatsRequest{
Namespace: dr.k8sclient.getNamespace(orgID),
Kinds: []string{
v0alpha1.GROUP + "/" + v0alpha1.DashboardResourceInfo.GetName(),
},
})
if err != nil {
return 0, err
}
if len(resp.Stats) != 1 {
return 0, fmt.Errorf("expected 1 stat, got %d", len(resp.Stats))
}
return resp.Stats[0].Count, nil
}
return dr.dashboardStore.CountInOrg(ctx, orgID)
}
func readQuotaConfig(cfg *setting.Cfg) (*quota.Map, error) {
limits := &quota.Map{}
@@ -1215,6 +1237,7 @@ func (dr *DashboardServiceImpl) FindDashboards(ctx context.Context, query *dashb
finalResults := make([]dashboards.DashboardSearchProjection, len(response.Hits))
for i, hit := range response.Hits {
finalResults[i] = dashboards.DashboardSearchProjection{
ID: hit.Field.GetNestedInt64(search.DASHBOARD_LEGACY_ID),
UID: hit.Name,
OrgID: query.OrgId,
Title: hit.Title,
@@ -1980,7 +2003,7 @@ func ParseResults(result *resource.ResourceSearchResponse, offset int64) (*v0alp
for i, row := range result.Results.Rows {
fields := &common.Unstructured{}
for colIndex, col := range result.Results.Columns {
if _, ok := excludedFields[col.Name]; ok {
if _, ok := excludedFields[col.Name]; !ok {
val, err := resource.DecodeCell(col, colIndex, row.Cells[colIndex])
if err != nil {
return nil, err
@@ -271,6 +271,11 @@ func (m *mockResourceIndexClient) Search(ctx context.Context, req *resource.Reso
return args.Get(0).(*resource.ResourceSearchResponse), args.Error(1)
}
func (m *mockResourceIndexClient) GetStats(ctx context.Context, in *resource.ResourceStatsRequest, opts ...grpc.CallOption) (*resource.ResourceStatsResponse, error) {
args := m.Called(in)
return args.Get(0).(*resource.ResourceStatsResponse), args.Error(1)
}
type mockResourceInterface struct {
mock.Mock
dynamic.ResourceInterface
@@ -1779,44 +1784,17 @@ func TestQuotaCount(t *testing.T) {
},
}
dashboardUnstructuredOrg1 := unstructured.UnstructuredList{
Items: []unstructured.Unstructured{{
Object: map[string]any{
"metadata": map[string]any{
"name": "uid",
},
"spec": map[string]any{
"test": "test",
"version": int64(1),
"title": "testing slugify",
},
},
}},
}
dashboardUnstructuredOrg2 := unstructured.UnstructuredList{
Items: []unstructured.Unstructured{{
Object: map[string]any{
"metadata": map[string]any{
"name": "uid",
},
"spec": map[string]any{
"test": "test",
"version": int64(1),
"title": "testing slugify",
},
countOrg1 := resource.ResourceStatsResponse{
Stats: []*resource.ResourceStatsResponse_Stats{
{
Count: 1,
},
},
}
countOrg2 := resource.ResourceStatsResponse{
Stats: []*resource.ResourceStatsResponse_Stats{
{
Object: map[string]any{
"metadata": map[string]any{
"name": "uid2",
},
"spec": map[string]any{
"test": "test2",
"version": int64(1),
"title": "testing slugify2",
},
},
Count: 2,
},
},
}
@@ -1833,13 +1811,11 @@ func TestQuotaCount(t *testing.T) {
})
t.Run("Should use Kubernetes client if feature flags are enabled", func(t *testing.T) {
ctx, k8sClientMock, k8sResourceMock := setupK8sDashboardTests(service)
ctx, k8sClientMock, _ := setupK8sDashboardTests(service)
orgSvc := orgtest.FakeOrgService{ExpectedOrgs: orgs}
service.orgService = &orgSvc
k8sClientMock.On("getClient", mock.Anything, int64(1)).Return(k8sResourceMock, true).Once()
k8sClientMock.On("getClient", mock.Anything, int64(2)).Return(k8sResourceMock, true).Once()
k8sResourceMock.On("List", mock.Anything, mock.Anything).Return(&dashboardUnstructuredOrg2, nil).Once()
k8sResourceMock.On("List", mock.Anything, mock.Anything).Return(&dashboardUnstructuredOrg1, nil).Once()
k8sClientMock.searcher.On("GetStats", mock.Anything).Return(&countOrg2, nil).Once()
k8sClientMock.searcher.On("GetStats", mock.Anything).Return(&countOrg1, nil).Once()
result, err := service.Count(ctx, query)
require.NoError(t, err)
@@ -1858,6 +1834,38 @@ func TestQuotaCount(t *testing.T) {
})
}
func TestCountDashboardsInOrg(t *testing.T) {
fakeStore := dashboards.FakeDashboardStore{}
defer fakeStore.AssertExpectations(t)
service := &DashboardServiceImpl{
cfg: setting.NewCfg(),
dashboardStore: &fakeStore,
}
count := resource.ResourceStatsResponse{
Stats: []*resource.ResourceStatsResponse_Stats{
{
Count: 3,
},
},
}
t.Run("Should fallback to dashboard store if Kubernetes feature flags are not enabled", func(t *testing.T) {
service.features = featuremgmt.WithFeatures()
fakeStore.On("CountInOrg", mock.Anything, mock.Anything).Return(nil, nil).Once()
_, err := service.CountDashboardsInOrg(context.Background(), 1)
require.NoError(t, err)
fakeStore.AssertExpectations(t)
})
t.Run("Should use Kubernetes client if feature flags are enabled", func(t *testing.T) {
ctx, k8sClientMock, _ := setupK8sDashboardTests(service)
k8sClientMock.searcher.On("GetStats", mock.Anything).Return(&count, nil).Once()
result, err := service.CountDashboardsInOrg(ctx, 1)
require.NoError(t, err)
require.Equal(t, result, int64(3))
})
}
func TestLegacySaveCommandToUnstructured(t *testing.T) {
namespace := "test-namespace"
t.Run("successfully converts save command to unstructured", func(t *testing.T) {
+31
View File
@@ -48,6 +48,37 @@ func (_m *FakeDashboardStore) Count(_a0 context.Context, _a1 *quota.ScopeParamet
return r0, r1
}
// CountInOrg provides a mock function with given fields: _a0, _a1
func (_m *FakeDashboardStore) CountInOrg(_a0 context.Context, _a1 int64) (int64, error) {
ret := _m.Called(_a0, _a1)
if len(ret) == 0 {
panic("no return value specified for Count")
}
var r0 int64
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, int64) (int64, error)); ok {
return rf(_a0, _a1)
}
if rf, ok := ret.Get(0).(func(context.Context, int64) int64); ok {
r0 = rf(_a0, _a1)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(int64)
}
}
if rf, ok := ret.Get(1).(func(context.Context, int64) error); ok {
r1 = rf(_a0, _a1)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// CountDashboardsInFolders provides a mock function with given fields: ctx, request
func (_m *FakeDashboardStore) CountDashboardsInFolders(ctx context.Context, request *CountDashboardsInFolderRequest) (int64, error) {
ret := _m.Called(ctx, request)
@@ -785,15 +785,6 @@ func TestIntegrationInsertAlertRules(t *testing.T) {
require.ErrorIs(t, err, models.ErrAlertRuleFailedValidation)
require.ErrorContains(t, err, "metric name for recording rule must be a valid utf8 string")
})
t.Run("invalid metric name", func(t *testing.T) {
invalidMetric := "with-dashes"
invalidRule := recordingRulesGen.Generate()
invalidRule.Record.Metric = invalidMetric
_, err := store.InsertAlertRules(context.Background(), []models.AlertRule{invalidRule})
require.ErrorIs(t, err, models.ErrAlertRuleFailedValidation)
require.ErrorContains(t, err, "metric name for recording rule must be a valid Prometheus metric name")
})
})
t.Run("clears fields that should not exist on recording rules", func(t *testing.T) {
+19 -40
View File
@@ -10,6 +10,7 @@ import (
"github.com/grafana/grafana/pkg/apimachinery/identity"
"github.com/grafana/grafana/pkg/infra/db"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/folder"
"github.com/grafana/grafana/pkg/services/libraryelements/model"
"github.com/grafana/grafana/pkg/services/org"
@@ -21,13 +22,14 @@ import (
const activeUserTimeLimit = time.Hour * 24 * 30
const dailyActiveUserTimeLimit = time.Hour * 24
func ProvideService(cfg *setting.Cfg, db db.DB, dashSvc dashboards.DashboardService, folderSvc folder.Service, orgSvc org.Service) stats.Service {
func ProvideService(cfg *setting.Cfg, db db.DB, dashSvc dashboards.DashboardService, folderSvc folder.Service, orgSvc org.Service, features featuremgmt.FeatureToggles) stats.Service {
return &sqlStatsService{
cfg: cfg,
db: db,
folderSvc: folderSvc,
dashSvc: dashSvc,
orgSvc: orgSvc,
features: features,
}
}
@@ -35,48 +37,23 @@ type sqlStatsService struct {
db db.DB
cfg *setting.Cfg
dashSvc dashboards.DashboardService
features featuremgmt.FeatureToggles
folderSvc folder.Service
orgSvc org.Service
}
type dashboardStats struct {
count int
bytesTotal int
bytesMax int
}
func (ss *sqlStatsService) collectDashboardStats(ctx context.Context, orgs []*org.OrgDTO, calculateByteSize bool) (dashboardStats, error) {
stats := dashboardStats{
count: 0,
bytesTotal: 0,
bytesMax: 0,
}
func (ss *sqlStatsService) getDashboardCount(ctx context.Context, orgs []*org.OrgDTO) (int64, error) {
count := int64(0)
for _, org := range orgs {
ctx = identity.WithRequester(ctx, getStatsRequester(org.ID))
dashs, err := ss.dashSvc.GetAllDashboardsByOrgId(ctx, org.ID)
dashsCount, err := ss.dashSvc.CountDashboardsInOrg(ctx, org.ID)
if err != nil {
return stats, err
}
stats.count += len(dashs)
// only calculate bytes if needed
if calculateByteSize {
for _, dash := range dashs {
b, err := dash.Data.ToDB()
if err != nil {
return stats, err
}
stats.bytesTotal += len(b)
if len(b) > stats.bytesMax {
stats.bytesMax = len(b)
}
}
return 0, err
}
count += dashsCount
}
return stats, nil
return count, nil
}
func (ss *sqlStatsService) getTagCount(ctx context.Context, orgs []*org.OrgDTO) (int64, error) {
@@ -172,7 +149,6 @@ func (ss *sqlStatsService) GetSystemStats(ctx context.Context, query *stats.GetS
monthlyActiveUserDeadlineDate := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location())
sb.Write(`(SELECT COUNT(*) FROM `+dialect.Quote("user")+` WHERE `+
notServiceAccount(dialect)+` AND last_seen_at > ?) AS monthly_active_users,`, monthlyActiveUserDeadlineDate)
sb.Write(`(SELECT COUNT(id) FROM ` + dialect.Quote("dashboard_provisioning") + `) AS provisioned_dashboards,`)
sb.Write(`(SELECT COUNT(id) FROM ` + dialect.Quote("dashboard_snapshot") + `) AS snapshots,`)
sb.Write(`(SELECT COUNT(id) FROM ` + dialect.Quote("dashboard_version") + `) AS dashboard_versions,`)
@@ -190,6 +166,11 @@ func (ss *sqlStatsService) GetSystemStats(ctx context.Context, query *stats.GetS
if ss.IsUnifiedAlertingEnabled() {
sb.Write(`(SELECT COUNT(DISTINCT (` + dialect.Quote("rule_group") + `)) FROM ` + dialect.Quote("alert_rule") + `) AS rule_groups,`)
}
// currently not supported when dashboards are in unified storage
if !ss.features.IsEnabledGlobally(featuremgmt.FlagKubernetesCliDashboards) {
sb.Write(`(SELECT SUM(LENGTH(data)) FROM `+dialect.Quote("dashboard")+` WHERE is_folder = ?) AS dashboard_bytes_total,`, dialect.BooleanStr(false))
sb.Write(`(SELECT MAX(LENGTH(data)) FROM `+dialect.Quote("dashboard")+` WHERE is_folder = ?) AS dashboard_bytes_max,`, dialect.BooleanStr(false))
}
sb.Write(ss.roleCounterSQL(ctx))
@@ -216,13 +197,11 @@ func (ss *sqlStatsService) GetSystemStats(ctx context.Context, query *stats.GetS
result.Orgs = int64(len(orgs))
// for services in unified storage, get the stats through the service rather than the db directly
dashStats, err := ss.collectDashboardStats(ctx, orgs, true)
dashCount, err := ss.getDashboardCount(ctx, orgs)
if err != nil {
return result, err
}
result.DashboardBytesMax = int64(dashStats.bytesMax)
result.DashboardBytesTotal = int64(dashStats.bytesTotal)
result.Dashboards = int64(dashStats.count)
result.Dashboards = dashCount
folderCount, err := ss.getFolderCount(ctx, orgs)
if err != nil {
@@ -329,11 +308,11 @@ func (ss *sqlStatsService) GetAdminStats(ctx context.Context, query *stats.GetAd
result.Orgs = int64(len(orgs))
// for services in unified storage, get the stats through the service rather than the db directly
dashStats, err := ss.collectDashboardStats(ctx, orgs, false)
dashCount, err := ss.getDashboardCount(ctx, orgs)
if err != nil {
return result, err
}
result.Dashboards = int64(dashStats.count)
result.Dashboards = dashCount
tagCount, err := ss.getTagCount(ctx, orgs)
if err != nil {
+7 -14
View File
@@ -10,12 +10,12 @@ import (
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/db"
"github.com/grafana/grafana/pkg/infra/tracing"
"github.com/grafana/grafana/pkg/services/correlations"
"github.com/grafana/grafana/pkg/services/correlations/correlationstest"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/folder"
"github.com/grafana/grafana/pkg/services/folder/foldertest"
"github.com/grafana/grafana/pkg/services/org"
@@ -40,15 +40,9 @@ func TestIntegrationStatsDataAccess(t *testing.T) {
db, cfg := db.InitTestDBWithCfg(t)
orgSvc := populateDB(t, db, cfg)
dashSvc := &dashboards.FakeDashboardService{}
emptyJson := simplejson.New()
emptyJsonBytes, err := emptyJson.ToDB()
require.NoError(t, err)
largerJson := simplejson.NewFromAny(map[string]string{"key": "value"})
largerJsonBytes, err := largerJson.ToDB()
require.NoError(t, err)
dashSvc.On("GetAllDashboardsByOrgId", mock.Anything, int64(1)).Return([]*dashboards.Dashboard{{Data: largerJson}, {Data: emptyJson}}, nil)
dashSvc.On("GetAllDashboardsByOrgId", mock.Anything, int64(2)).Return([]*dashboards.Dashboard{}, nil)
dashSvc.On("GetAllDashboardsByOrgId", mock.Anything, int64(3)).Return([]*dashboards.Dashboard{}, nil)
dashSvc.On("CountDashboardsInOrg", mock.Anything, int64(1)).Return(int64(2), nil)
dashSvc.On("CountDashboardsInOrg", mock.Anything, int64(2)).Return(int64(1), nil)
dashSvc.On("CountDashboardsInOrg", mock.Anything, int64(3)).Return(int64(0), nil)
dashSvc.On("GetDashboardTags", mock.Anything, &dashboards.GetDashboardTagsQuery{OrgID: 1}).Return([]*dashboards.DashboardTagCloudItem{{Term: "test"}}, nil)
dashSvc.On("GetDashboardTags", mock.Anything, &dashboards.GetDashboardTagsQuery{OrgID: 2}).Return([]*dashboards.DashboardTagCloudItem{}, nil)
dashSvc.On("GetDashboardTags", mock.Anything, &dashboards.GetDashboardTagsQuery{OrgID: 3}).Return([]*dashboards.DashboardTagCloudItem{}, nil)
@@ -61,6 +55,7 @@ func TestIntegrationStatsDataAccess(t *testing.T) {
dashSvc: dashSvc,
orgSvc: orgSvc,
folderSvc: folderService,
features: featuremgmt.WithFeatures(),
}
t.Run("Get system stats should not results in error", func(t *testing.T) {
@@ -76,10 +71,8 @@ func TestIntegrationStatsDataAccess(t *testing.T) {
assert.Equal(t, int64(0), result.APIKeys)
assert.Equal(t, int64(2), result.Correlations)
assert.Equal(t, int64(3), result.Orgs)
assert.Equal(t, int64(2), result.Dashboards)
assert.Equal(t, int64(3), result.Dashboards)
assert.Equal(t, int64(9), result.Folders) // will return 3 folders for each org
assert.Equal(t, int64(len(largerJsonBytes)+len(emptyJsonBytes)), result.DashboardBytesTotal)
assert.Equal(t, int64(len(largerJsonBytes)), result.DashboardBytesMax)
assert.NotNil(t, result.DatabaseCreatedTime)
assert.Equal(t, db.GetDialect().DriverName(), result.DatabaseDriver)
})
@@ -113,7 +106,7 @@ func TestIntegrationStatsDataAccess(t *testing.T) {
stats, err := statsService.GetAdminStats(context.Background(), &query)
assert.NoError(t, err)
assert.Equal(t, int64(1), stats.Tags)
assert.Equal(t, int64(2), stats.Dashboards)
assert.Equal(t, int64(3), stats.Dashboards)
assert.Equal(t, int64(3), stats.Orgs)
})
}
+13 -14
View File
@@ -1,6 +1,6 @@
module github.com/grafana/grafana/pkg/storage/unified/apistore
go 1.23.4
go 1.23.5
replace (
github.com/grafana/grafana => ../../../..
@@ -55,6 +55,7 @@ require (
github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // indirect
github.com/RoaringBitmap/roaring v1.9.3 // indirect
github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f // indirect
github.com/Yiling-J/theine-go v0.6.0 // indirect
github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b // indirect
github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
github.com/apache/arrow-go/v18 v18.0.1-0.20241212180703-82be143d7c30 // indirect
@@ -115,7 +116,6 @@ require (
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/distribution/reference v0.6.0 // indirect
github.com/dlmiddlecote/sqlstats v1.0.2 // indirect
github.com/docker/docker v27.4.1+incompatible // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/elazarl/goproxy v1.3.0 // indirect
@@ -159,7 +159,7 @@ require (
github.com/golang/protobuf v1.5.4 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/btree v1.1.3 // indirect
github.com/google/cel-go v0.22.0 // indirect
github.com/google/cel-go v0.22.1 // indirect
github.com/google/flatbuffers v24.3.25+incompatible // indirect
github.com/google/gnostic-models v0.6.8 // indirect
github.com/google/go-cmp v0.6.0 // indirect
@@ -185,7 +185,7 @@ require (
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 // indirect
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.2.0 // indirect
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-hclog v1.6.3 // indirect
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
@@ -203,7 +203,7 @@ require (
github.com/invopop/yaml v0.3.1 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/pgx/v5 v5.7.1 // indirect
github.com/jackc/pgx/v5 v5.7.2 // indirect
github.com/jackc/puddle/v2 v2.2.2 // indirect
github.com/jeremywohl/flatten v1.0.1 // indirect
github.com/jessevdk/go-flags v1.5.0 // indirect
@@ -215,7 +215,6 @@ require (
github.com/jpillora/backoff v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/jszwedko/go-datemath v0.1.1-0.20230526204004-640a500621d6 // indirect
github.com/karlseguin/ccache/v3 v3.0.5 // indirect
github.com/klauspost/compress v1.17.11 // indirect
github.com/klauspost/cpuid/v2 v2.2.9 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
@@ -256,9 +255,9 @@ require (
github.com/oklog/ulid v1.3.1 // indirect
github.com/oklog/ulid/v2 v2.1.0 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/openfga/api/proto v0.0.0-20240906203051-102620ef2a66 // indirect
github.com/openfga/language/pkg/go v0.2.0-beta.2.0.20240926131254-992b301a003f // indirect
github.com/openfga/openfga v1.6.2 // indirect
github.com/openfga/api/proto v0.0.0-20250107154247-c22e6db5c4f5 // indirect
github.com/openfga/language/pkg/go v0.2.0-beta.2.0.20241115164311-10e575c8e47c // indirect
github.com/openfga/openfga v1.8.4 // indirect
github.com/opentracing-contrib/go-stdlib v1.0.0 // indirect
github.com/opentracing/opentracing-go v1.2.0 // indirect
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
@@ -268,7 +267,7 @@ require (
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/pressly/goose/v3 v3.22.1 // indirect
github.com/pressly/goose/v3 v3.24.0 // indirect
github.com/prometheus/alertmanager v0.27.0 // indirect
github.com/prometheus/client_golang v1.20.5 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
@@ -324,9 +323,9 @@ require (
go.opentelemetry.io/otel/metric v1.33.0 // indirect
go.opentelemetry.io/otel/sdk v1.33.0 // indirect
go.opentelemetry.io/otel/trace v1.33.0 // indirect
go.opentelemetry.io/proto/otlp v1.4.0 // indirect
go.opentelemetry.io/proto/otlp v1.5.0 // indirect
go.uber.org/atomic v1.11.0 // indirect
go.uber.org/mock v0.4.0 // indirect
go.uber.org/mock v0.5.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/crypto v0.32.0 // indirect
@@ -343,7 +342,7 @@ require (
gonum.org/v1/gonum v0.15.1 // indirect
google.golang.org/api v0.216.0 // indirect
google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d // indirect
google.golang.org/protobuf v1.36.1 // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
@@ -362,7 +361,7 @@ require (
modernc.org/libc v1.55.3 // indirect
modernc.org/mathutil v1.6.0 // indirect
modernc.org/memory v1.8.0 // indirect
modernc.org/sqlite v1.33.1 // indirect
modernc.org/sqlite v1.34.4 // indirect
modernc.org/strutil v1.2.0 // indirect
modernc.org/token v1.1.0 // indirect
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.0 // indirect
+24 -24
View File
@@ -111,6 +111,8 @@ github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWX
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f h1:HR5nRmUQgXrwqZOwZ2DAc/aCi3Bu3xENpspW935vxu0=
github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f/go.mod h1:f3HiCrHjHBdcm6E83vGaXh1KomZMA2P6aeo3hKx/wg0=
github.com/Yiling-J/theine-go v0.6.0 h1:jv7V/tcD6ijL0T4kfbJDKP81TCZBkoriNTPSqwivWuY=
github.com/Yiling-J/theine-go v0.6.0/go.mod h1:mdch1vjgGWd7s3rWKvY+MF5InRLfRv/CWVI9RVNQ8wY=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
@@ -473,8 +475,8 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Z
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
github.com/google/cel-go v0.22.0 h1:b3FJZxpiv1vTMo2/5RDUqAHPxkT8mmMfJIrq1llbf7g=
github.com/google/cel-go v0.22.0/go.mod h1:BuznPXXfQDpXKWQ9sPW3TzlAJN5zzFe+i9tIs0yC4s8=
github.com/google/cel-go v0.22.1 h1:AfVXx3chM2qwoSbM7Da8g8hX8OVSkBFwX+rz2+PcK40=
github.com/google/cel-go v0.22.1/go.mod h1:BuznPXXfQDpXKWQ9sPW3TzlAJN5zzFe+i9tIs0yC4s8=
github.com/google/flatbuffers v24.3.25+incompatible h1:CX395cjN9Kke9mmalRoL3d81AtFUxJM+yDthflgJGkI=
github.com/google/flatbuffers v24.3.25+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
@@ -583,8 +585,8 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a534
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340/go.mod h1:3bDW6wMZJB7tiONtC/1Xpicra6Wp5GgbTbQWCbI5fkc=
github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 h1:TmHmbvxPmaegwhDubVz0lICL0J5Ka2vwTzhoePEXsGE=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0/go.mod h1:qztMSjm835F2bXf+5HKAPIS5qsmQDqZna/PgVt4rWtI=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 h1:VNqngBF40hVlDloBruUehVYC3ArSgIyScOAyMRqBxRg=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1/go.mod h1:RBRO7fro65R6tjKzYgLAFo0t1QEXY1Dp+i/bvpRiqiQ=
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
@@ -642,8 +644,8 @@ github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5ey
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx v3.2.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
github.com/jackc/pgx/v5 v5.7.1 h1:x7SYsPBYDkHDksogeSmZZ5xzThcTgRz++I5E+ePFUcs=
github.com/jackc/pgx/v5 v5.7.1/go.mod h1:e7O26IywZZ+naJtWWos6i6fvWK+29etgITqrqHLfoZA=
github.com/jackc/pgx/v5 v5.7.2 h1:mLoDLV6sonKlvjIEsV56SkWNCnuNv531l94GaIzO+XI=
github.com/jackc/pgx/v5 v5.7.2/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ=
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/jeremywohl/flatten v1.0.1 h1:LrsxmB3hfwJuE+ptGOijix1PIfOoKLJ3Uee/mzbgtrs=
@@ -688,8 +690,6 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
github.com/karlseguin/ccache/v3 v3.0.5 h1:hFX25+fxzNjsRlREYsoGNa2LoVEw5mPF8wkWq/UnevQ=
github.com/karlseguin/ccache/v3 v3.0.5/go.mod h1:qxC372+Qn+IBj8Pe3KvGjHPj0sWwEF7AeZVhsNPZ6uY=
github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6 h1:IsMZxCuZqKuao2vNdfD82fjjgPLfyHLpR41Z88viRWs=
github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6/go.mod h1:3VeWNIJaW+O5xpRQbPp0Ybqu1vJd/pm7s2F473HRrkw=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
@@ -831,12 +831,12 @@ github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3I
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
github.com/openfga/api/proto v0.0.0-20240906203051-102620ef2a66 h1:pAYrdyIKxPsMs/nRcTEnS9za2io11g7Rt7ng7HK82hk=
github.com/openfga/api/proto v0.0.0-20240906203051-102620ef2a66/go.mod h1:gil5LBD8tSdFQbUkCQdnXsoeU9kDJdJgbGdHkgJfcd0=
github.com/openfga/language/pkg/go v0.2.0-beta.2.0.20240926131254-992b301a003f h1:ZMZ7ntMnaHIPZxvVQv/aqC4ctzLqH+9Fqn4uw35kQpk=
github.com/openfga/language/pkg/go v0.2.0-beta.2.0.20240926131254-992b301a003f/go.mod h1:ll/hN6kS4EE6B/7J/PbZqac9Nuv7ZHpI+Jfh36JLrbs=
github.com/openfga/openfga v1.6.2 h1:tHBAgiCPomCZb3IH0CFqOpTDVDA/Xb8kG87oX4JCbXc=
github.com/openfga/openfga v1.6.2/go.mod h1:jzbEpheazf6MFjtanQt1rpxexSRzfa9057F7JlkMv2I=
github.com/openfga/api/proto v0.0.0-20250107154247-c22e6db5c4f5 h1:z9jaRoo+NIN1AB0ogjtrjx1316TTuq6IbqpEg3UJycA=
github.com/openfga/api/proto v0.0.0-20250107154247-c22e6db5c4f5/go.mod h1:m74TNgnAAIJ03gfHcx+xaRWnr+IbQy3y/AVNwwCFrC0=
github.com/openfga/language/pkg/go v0.2.0-beta.2.0.20241115164311-10e575c8e47c h1:1y84C0V4NRfPtRi4MqQ7+gnFtYgeBKPIeIAPLdVJ7j4=
github.com/openfga/language/pkg/go v0.2.0-beta.2.0.20241115164311-10e575c8e47c/go.mod h1:12RMe/HuRNyOzS33RQa53jwdcxE2znr8ycXMlVbgQN4=
github.com/openfga/openfga v1.8.4 h1:OqyRpuxMCxcS7irTFYFkhAIYzmAnczNwxUqjnuZOQyo=
github.com/openfga/openfga v1.8.4/go.mod h1:9Ax9VMMySV2JMsCT8MTePeYt4OrTnPAy1XUV1y9RyuU=
github.com/opentracing-contrib/go-stdlib v1.0.0 h1:TBS7YuVotp8myLon4Pv7BtCBzOTo1DeZCld0Z63mW2w=
github.com/opentracing-contrib/go-stdlib v1.0.0/go.mod h1:qtI1ogk+2JhVPIXVc6q+NHziSmy2W5GbdQZFUHADCBU=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
@@ -865,8 +865,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pressly/goose/v3 v3.22.1 h1:2zICEfr1O3yTP9BRZMGPj7qFxQ+ik6yeo+z1LMuioLc=
github.com/pressly/goose/v3 v3.22.1/go.mod h1:xtMpbstWyCpyH+0cxLTMCENWBG+0CSxvTsXhW95d5eo=
github.com/pressly/goose/v3 v3.24.0 h1:sFbNms7Bd++2VMq6HSgDHDLWa7kHz1qXzPb3ZIU72VU=
github.com/pressly/goose/v3 v3.24.0/go.mod h1:rEWreU9uVtt0DHCyLzF9gRcWiiTF/V+528DV+4DORug=
github.com/prometheus/alertmanager v0.27.0 h1:V6nTa2J5V4s8TG4C4HtrBP/WNSebCCTYGGv4qecA/+I=
github.com/prometheus/alertmanager v0.27.0/go.mod h1:8Ia/R3urPmbzJ8OsdvmZvIprDwvwmYCmUbwBL+jlPOE=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
@@ -1095,16 +1095,16 @@ go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC
go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ=
go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s=
go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck=
go.opentelemetry.io/proto/otlp v1.4.0 h1:TA9WRvW6zMwP+Ssb6fLoUIuirti1gGbP28GcKG1jgeg=
go.opentelemetry.io/proto/otlp v1.4.0/go.mod h1:PPBWZIP98o2ElSqI35IHfu7hIhSwvc5N38Jw8pXuGFY=
go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4=
go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
@@ -1465,8 +1465,8 @@ google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6D
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 h1:Q3nlH8iSQSRUwOskjbcSMcF2jiYMNiQYZ0c2KEJLKKU=
google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38/go.mod h1:xBI+tzfqGGN2JBeSebfKXFSdBpWVQ7sLW40PTupVRm4=
google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484 h1:ChAdCYNQFDk5fYvFZMywKLIijG7TC2m1C2CMEu11G3o=
google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484/go.mod h1:KRUmxRI4JmbpAm8gcZM4Jsffi859fo5LQjILwuqj9z8=
google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d h1:H8tOf8XM88HvKqLTxe755haY6r1fqqzLbEnfrmLXlSA=
google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d/go.mod h1:2v7Z7gP2ZUOGsaFyxATQSRoBnKygqVq2Cwnvom7QiqY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d h1:xJJRGY7TJcvIlpSrN3K6LAWgNFUILlO+OMAqtg9aqnw=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d/go.mod h1:3ENsm/5D1mzDyhpzeRi1NR784I0BcofWBoSc5QqqMK4=
google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
@@ -1586,8 +1586,8 @@ modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc=
modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss=
modernc.org/sqlite v1.33.1 h1:trb6Z3YYoeM9eDL1O8do81kP+0ejv+YzgyFo+Gwy0nM=
modernc.org/sqlite v1.33.1/go.mod h1:pXV2xHxhzXZsgT/RtTFAPY6JJDEvOTcTdwADQCCWD4k=
modernc.org/sqlite v1.34.4 h1:sjdARozcL5KJBvYQvLlZEmctRgW9xqIZc2ncN7PU0P8=
modernc.org/sqlite v1.34.4/go.mod h1:3QQFCG2SEMtc2nv+Wq4cQCH7Hjcg+p/RMlS1XK+zwbk=
modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA=
modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0=
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
+4 -4
View File
@@ -1,6 +1,6 @@
module github.com/grafana/grafana/pkg/storage/unified/resource
go 1.23.4
go 1.23.5
replace (
github.com/grafana/grafana => ../../../..
@@ -127,7 +127,7 @@ require (
github.com/grafana/pyroscope-go/godeltaprof v0.1.8 // indirect
github.com/grafana/sqlds/v4 v4.1.3 // indirect
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-hclog v1.6.3 // indirect
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
@@ -215,7 +215,7 @@ require (
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.33.0 // indirect
go.opentelemetry.io/otel/metric v1.33.0 // indirect
go.opentelemetry.io/otel/sdk v1.33.0 // indirect
go.opentelemetry.io/proto/otlp v1.4.0 // indirect
go.opentelemetry.io/proto/otlp v1.5.0 // indirect
go.uber.org/atomic v1.11.0 // indirect
golang.org/x/crypto v0.32.0 // indirect
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect
@@ -230,7 +230,7 @@ require (
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect
google.golang.org/api v0.216.0 // indirect
google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d // indirect
gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
+24 -25
View File
@@ -73,7 +73,8 @@ github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWX
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f h1:HR5nRmUQgXrwqZOwZ2DAc/aCi3Bu3xENpspW935vxu0=
github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f/go.mod h1:f3HiCrHjHBdcm6E83vGaXh1KomZMA2P6aeo3hKx/wg0=
github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
github.com/Yiling-J/theine-go v0.6.0 h1:jv7V/tcD6ijL0T4kfbJDKP81TCZBkoriNTPSqwivWuY=
github.com/Yiling-J/theine-go v0.6.0/go.mod h1:mdch1vjgGWd7s3rWKvY+MF5InRLfRv/CWVI9RVNQ8wY=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
@@ -358,8 +359,8 @@ github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
github.com/google/cel-go v0.22.0 h1:b3FJZxpiv1vTMo2/5RDUqAHPxkT8mmMfJIrq1llbf7g=
github.com/google/cel-go v0.22.0/go.mod h1:BuznPXXfQDpXKWQ9sPW3TzlAJN5zzFe+i9tIs0yC4s8=
github.com/google/cel-go v0.22.1 h1:AfVXx3chM2qwoSbM7Da8g8hX8OVSkBFwX+rz2+PcK40=
github.com/google/cel-go v0.22.1/go.mod h1:BuznPXXfQDpXKWQ9sPW3TzlAJN5zzFe+i9tIs0yC4s8=
github.com/google/flatbuffers v24.3.25+incompatible h1:CX395cjN9Kke9mmalRoL3d81AtFUxJM+yDthflgJGkI=
github.com/google/flatbuffers v24.3.25+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
@@ -442,8 +443,8 @@ github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 h1:qnpS
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1/go.mod h1:lXGCsh6c22WGtjr+qGHj1otzZpV/1kwTMAqkwZsnWRU=
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.2.0 h1:kQ0NI7W1B3HwiN5gAYtY+XFItDPbLBwYRxAqbFTyDes=
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.2.0/go.mod h1:zrT2dxOAjNFPRGjTUe2Xmb4q4YdUwVvQFV6xiCSf+z0=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 h1:TmHmbvxPmaegwhDubVz0lICL0J5Ka2vwTzhoePEXsGE=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0/go.mod h1:qztMSjm835F2bXf+5HKAPIS5qsmQDqZna/PgVt4rWtI=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 h1:VNqngBF40hVlDloBruUehVYC3ArSgIyScOAyMRqBxRg=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1/go.mod h1:RBRO7fro65R6tjKzYgLAFo0t1QEXY1Dp+i/bvpRiqiQ=
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
@@ -495,8 +496,8 @@ github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7Ulw
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx v3.2.0+incompatible h1:0Vihzu20St42/UDsvZGdNE6jak7oi/UOeMzwMPHkgFY=
github.com/jackc/pgx v3.2.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
github.com/jackc/pgx/v5 v5.7.1 h1:x7SYsPBYDkHDksogeSmZZ5xzThcTgRz++I5E+ePFUcs=
github.com/jackc/pgx/v5 v5.7.1/go.mod h1:e7O26IywZZ+naJtWWos6i6fvWK+29etgITqrqHLfoZA=
github.com/jackc/pgx/v5 v5.7.2 h1:mLoDLV6sonKlvjIEsV56SkWNCnuNv531l94GaIzO+XI=
github.com/jackc/pgx/v5 v5.7.2/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ=
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/jeremywohl/flatten v1.0.1 h1:LrsxmB3hfwJuE+ptGOijix1PIfOoKLJ3Uee/mzbgtrs=
@@ -535,8 +536,6 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
github.com/karlseguin/ccache/v3 v3.0.5 h1:hFX25+fxzNjsRlREYsoGNa2LoVEw5mPF8wkWq/UnevQ=
github.com/karlseguin/ccache/v3 v3.0.5/go.mod h1:qxC372+Qn+IBj8Pe3KvGjHPj0sWwEF7AeZVhsNPZ6uY=
github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6 h1:IsMZxCuZqKuao2vNdfD82fjjgPLfyHLpR41Z88viRWs=
github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6/go.mod h1:3VeWNIJaW+O5xpRQbPp0Ybqu1vJd/pm7s2F473HRrkw=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
@@ -661,12 +660,12 @@ github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
github.com/openfga/api/proto v0.0.0-20240906203051-102620ef2a66 h1:pAYrdyIKxPsMs/nRcTEnS9za2io11g7Rt7ng7HK82hk=
github.com/openfga/api/proto v0.0.0-20240906203051-102620ef2a66/go.mod h1:gil5LBD8tSdFQbUkCQdnXsoeU9kDJdJgbGdHkgJfcd0=
github.com/openfga/language/pkg/go v0.2.0-beta.2.0.20240926131254-992b301a003f h1:ZMZ7ntMnaHIPZxvVQv/aqC4ctzLqH+9Fqn4uw35kQpk=
github.com/openfga/language/pkg/go v0.2.0-beta.2.0.20240926131254-992b301a003f/go.mod h1:ll/hN6kS4EE6B/7J/PbZqac9Nuv7ZHpI+Jfh36JLrbs=
github.com/openfga/openfga v1.6.2 h1:tHBAgiCPomCZb3IH0CFqOpTDVDA/Xb8kG87oX4JCbXc=
github.com/openfga/openfga v1.6.2/go.mod h1:jzbEpheazf6MFjtanQt1rpxexSRzfa9057F7JlkMv2I=
github.com/openfga/api/proto v0.0.0-20250107154247-c22e6db5c4f5 h1:z9jaRoo+NIN1AB0ogjtrjx1316TTuq6IbqpEg3UJycA=
github.com/openfga/api/proto v0.0.0-20250107154247-c22e6db5c4f5/go.mod h1:m74TNgnAAIJ03gfHcx+xaRWnr+IbQy3y/AVNwwCFrC0=
github.com/openfga/language/pkg/go v0.2.0-beta.2.0.20241115164311-10e575c8e47c h1:1y84C0V4NRfPtRi4MqQ7+gnFtYgeBKPIeIAPLdVJ7j4=
github.com/openfga/language/pkg/go v0.2.0-beta.2.0.20241115164311-10e575c8e47c/go.mod h1:12RMe/HuRNyOzS33RQa53jwdcxE2znr8ycXMlVbgQN4=
github.com/openfga/openfga v1.8.4 h1:OqyRpuxMCxcS7irTFYFkhAIYzmAnczNwxUqjnuZOQyo=
github.com/openfga/openfga v1.8.4/go.mod h1:9Ax9VMMySV2JMsCT8MTePeYt4OrTnPAy1XUV1y9RyuU=
github.com/opentracing-contrib/go-stdlib v1.0.0 h1:TBS7YuVotp8myLon4Pv7BtCBzOTo1DeZCld0Z63mW2w=
github.com/opentracing-contrib/go-stdlib v1.0.0/go.mod h1:qtI1ogk+2JhVPIXVc6q+NHziSmy2W5GbdQZFUHADCBU=
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
@@ -693,8 +692,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pressly/goose/v3 v3.22.1 h1:2zICEfr1O3yTP9BRZMGPj7qFxQ+ik6yeo+z1LMuioLc=
github.com/pressly/goose/v3 v3.22.1/go.mod h1:xtMpbstWyCpyH+0cxLTMCENWBG+0CSxvTsXhW95d5eo=
github.com/pressly/goose/v3 v3.24.0 h1:sFbNms7Bd++2VMq6HSgDHDLWa7kHz1qXzPb3ZIU72VU=
github.com/pressly/goose/v3 v3.24.0/go.mod h1:rEWreU9uVtt0DHCyLzF9gRcWiiTF/V+528DV+4DORug=
github.com/prometheus/alertmanager v0.27.0 h1:V6nTa2J5V4s8TG4C4HtrBP/WNSebCCTYGGv4qecA/+I=
github.com/prometheus/alertmanager v0.27.0/go.mod h1:8Ia/R3urPmbzJ8OsdvmZvIprDwvwmYCmUbwBL+jlPOE=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
@@ -873,14 +872,14 @@ go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC
go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ=
go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s=
go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck=
go.opentelemetry.io/proto/otlp v1.4.0 h1:TA9WRvW6zMwP+Ssb6fLoUIuirti1gGbP28GcKG1jgeg=
go.opentelemetry.io/proto/otlp v1.4.0/go.mod h1:PPBWZIP98o2ElSqI35IHfu7hIhSwvc5N38Jw8pXuGFY=
go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4=
go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4=
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
@@ -1088,8 +1087,8 @@ google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 h1:Q3nlH8iSQSRUwOskjbcSMcF2jiYMNiQYZ0c2KEJLKKU=
google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38/go.mod h1:xBI+tzfqGGN2JBeSebfKXFSdBpWVQ7sLW40PTupVRm4=
google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484 h1:ChAdCYNQFDk5fYvFZMywKLIijG7TC2m1C2CMEu11G3o=
google.golang.org/genproto/googleapis/api v0.0.0-20241216192217-9240e9c98484/go.mod h1:KRUmxRI4JmbpAm8gcZM4Jsffi859fo5LQjILwuqj9z8=
google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d h1:H8tOf8XM88HvKqLTxe755haY6r1fqqzLbEnfrmLXlSA=
google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d/go.mod h1:2v7Z7gP2ZUOGsaFyxATQSRoBnKygqVq2Cwnvom7QiqY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d h1:xJJRGY7TJcvIlpSrN3K6LAWgNFUILlO+OMAqtg9aqnw=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d/go.mod h1:3ENsm/5D1mzDyhpzeRi1NR784I0BcofWBoSc5QqqMK4=
google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
@@ -1172,8 +1171,8 @@ modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=
modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E=
modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU=
modernc.org/sqlite v1.33.1 h1:trb6Z3YYoeM9eDL1O8do81kP+0ejv+YzgyFo+Gwy0nM=
modernc.org/sqlite v1.33.1/go.mod h1:pXV2xHxhzXZsgT/RtTFAPY6JJDEvOTcTdwADQCCWD4k=
modernc.org/sqlite v1.34.4 h1:sjdARozcL5KJBvYQvLlZEmctRgW9xqIZc2ncN7PU0P8=
modernc.org/sqlite v1.34.4/go.mod h1:3QQFCG2SEMtc2nv+Wq4cQCH7Hjcg+p/RMlS1XK+zwbk=
modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA=
modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0=
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
@@ -2,16 +2,17 @@ package grpc
import (
"context"
"fmt"
"strconv"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
"github.com/grafana/authlib/authn"
authClaims "github.com/grafana/authlib/claims"
"github.com/grafana/grafana/pkg/apimachinery/identity"
"github.com/grafana/grafana/pkg/infra/tracing"
)
const (
@@ -27,10 +28,13 @@ const (
// var _ interceptors.Authenticator = (*Authenticator)(nil)
type Authenticator struct {
IDTokenVerifier authn.Verifier[authn.IDTokenClaims]
Tracer tracing.Tracer
}
func (f *Authenticator) Authenticate(ctx context.Context) (context.Context, error) {
ctx, span := f.Tracer.Start(ctx, "legacy.grpc.Authenticator.Authenticate")
defer span.End()
r, err := identity.GetRequester(ctx)
if err == nil && r != nil {
return ctx, nil // noop, requester exists
@@ -38,16 +42,19 @@ func (f *Authenticator) Authenticate(ctx context.Context) (context.Context, erro
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
return nil, fmt.Errorf("no metadata found")
err := status.Error(codes.Unauthenticated, "no metadata found in grpc context")
span.RecordError(err)
return nil, err
}
user, err := f.decodeMetadata(ctx, md)
user, err := f.decodeMetadata(md)
if err != nil {
span.RecordError(err)
return nil, err
}
return identity.WithRequester(ctx, user), nil
}
func (f *Authenticator) decodeMetadata(ctx context.Context, meta metadata.MD) (identity.Requester, error) {
func (f *Authenticator) decodeMetadata(meta metadata.MD) (identity.Requester, error) {
// Avoid NPE/panic with getting keys
getter := func(key string) string {
v := meta.Get(key)
@@ -57,20 +64,10 @@ func (f *Authenticator) decodeMetadata(ctx context.Context, meta metadata.MD) (i
return ""
}
// First try the token
token := getter(mdToken)
if token != "" && f.IDTokenVerifier != nil {
claims, err := f.IDTokenVerifier.Verify(ctx, token)
if err != nil {
return nil, err
}
fmt.Printf("TODO, convert CLAIMS to an identity %+v\n", claims)
}
user := &identity.StaticRequester{}
user.Login = getter(mdLogin)
if user.Login == "" {
return nil, fmt.Errorf("no login found in grpc metadata")
return nil, status.Error(codes.Unauthenticated, "no login found in grpc metadata")
}
// The namespaced versions have a "-" in the key
@@ -80,34 +77,34 @@ func (f *Authenticator) decodeMetadata(ctx context.Context, meta metadata.MD) (i
user.Type = authClaims.TypeUser
user.UserID, err = strconv.ParseInt(getter("grafana-userid"), 10, 64)
if err != nil {
return nil, fmt.Errorf("invalid user id: %w", err)
return nil, status.Error(codes.Unauthenticated, "invalid user id")
}
user.OrgID, err = strconv.ParseInt(getter("grafana-orgid"), 10, 64)
if err != nil {
return nil, fmt.Errorf("invalid org id: %w", err)
return nil, status.Error(codes.Unauthenticated, "invalid org id")
}
return user, nil
}
typ, id, err := authClaims.ParseTypeID(getter(mdUserID))
if err != nil {
return nil, fmt.Errorf("invalid user id: %w", err)
return nil, status.Error(codes.Unauthenticated, "invalid user id")
}
user.Type = typ
user.UserID, err = strconv.ParseInt(id, 10, 64)
if err != nil {
return nil, fmt.Errorf("invalid user id: %w", err)
return nil, status.Error(codes.Unauthenticated, "invalid user id")
}
_, id, err = authClaims.ParseTypeID(getter(mdUserUID))
_, uid, err := authClaims.ParseTypeID(getter(mdUserUID))
if err != nil {
return nil, fmt.Errorf("invalid user id: %w", err)
return nil, status.Error(codes.Unauthenticated, "invalid user uid")
}
user.UserUID = id
user.UserUID = uid
user.OrgID, err = strconv.ParseInt(getter(mdOrgID), 10, 64)
if err != nil {
return nil, fmt.Errorf("invalid org id: %w", err)
return nil, status.Error(codes.Unauthenticated, "invalid org id")
}
user.OrgRole = identity.RoleType(getter(mdOrgRole))
return user, nil
@@ -1,13 +1,13 @@
package grpc
import (
"context"
"testing"
"github.com/stretchr/testify/require"
"github.com/grafana/authlib/claims"
"github.com/grafana/grafana/pkg/apimachinery/identity"
"github.com/grafana/grafana/pkg/infra/tracing"
)
func TestBasicEncodeDecode(t *testing.T) {
@@ -20,10 +20,10 @@ func TestBasicEncodeDecode(t *testing.T) {
OrgRole: identity.RoleAdmin,
}
auth := &Authenticator{}
auth := &Authenticator{Tracer: tracing.NewNoopTracerService()}
md := encodeIdentityInMetadata(before)
after, err := auth.decodeMetadata(context.Background(), md)
after, err := auth.decodeMetadata(md)
require.NoError(t, err)
require.Equal(t, before.GetID(), after.GetID())
require.Equal(t, before.GetUID(), after.GetUID())
+7 -3
View File
@@ -189,6 +189,11 @@ func DashboardBuilder(namespaced resource.NamespacedDocumentSupplier) (resource.
Filterable: true,
},
},
{
Name: DASHBOARD_LEGACY_ID,
Type: resource.ResourceTableColumnDefinition_INT64,
Description: "Deprecated legacy id of the dashboard",
},
})
if namespaced == nil {
namespaced = func(ctx context.Context, namespace string, blob resource.BlobSupport) (resource.DocumentBuilder, error) {
@@ -267,6 +272,7 @@ func (s *DashboardDocumentBuilder) BuildDocument(ctx context.Context, key *resou
// metadata name is the dashboard uid
summary.UID = obj.GetName()
summary.ID = obj.GetDeprecatedInternalID() // nolint:staticcheck
doc := resource.NewIndexableDocument(key, rv, obj)
doc.Title = summary.Title
@@ -310,11 +316,9 @@ func (s *DashboardDocumentBuilder) BuildDocument(ctx context.Context, key *resou
doc.Fields = map[string]any{
DASHBOARD_SCHEMA_VERSION: summary.SchemaVersion,
DASHBOARD_LINK_COUNT: summary.LinkCount,
DASHBOARD_LEGACY_ID: summary.ID,
}
if summary.ID > 0 {
doc.Fields[DASHBOARD_LEGACY_ID] = summary.ID
}
if len(panelTypes) > 0 {
sort.Strings(panelTypes)
doc.Fields[DASHBOARD_PANEL_TYPES] = panelTypes
@@ -16,6 +16,7 @@
"c"
],
"labels": {
"grafana.app/deprecatedInternalID": "141",
"host": "abc",
"region": "xyz"
},
+2 -1
View File
@@ -13,7 +13,8 @@
},
"labels": {
"host": "abc",
"region": "xyz"
"region": "xyz",
"grafana.app/deprecatedInternalID": "141"
}
},
"spec": {
@@ -168,6 +168,13 @@
"format": "int64",
"description": "Total number of views",
"priority": 0
},
{
"name": "legacy_id",
"type": "number",
"format": "int64",
"description": "Deprecated legacy id of the dashboard",
"priority": 0
}
],
"rows": [
@@ -198,6 +205,7 @@
null,
null,
null,
null,
null
],
"object": {
@@ -239,6 +247,7 @@
100,
null,
null,
null,
null
],
"object": {
@@ -282,6 +291,7 @@
50,
null,
null,
null,
null
],
"object": {
+2 -1
View File
@@ -80,7 +80,8 @@ func ProvideUnifiedStorageGrpcService(
// FIXME: This is a temporary solution while we are migrating to the new authn interceptor
// grpcutils.NewGrpcAuthenticator should be used instead.
authn, err := grpcutils.NewGrpcAuthenticatorWithFallback(cfg, reg, tracing, &grpc.Authenticator{})
fallback := &grpc.Authenticator{Tracer: tracing}
authn, err := grpcutils.NewGrpcAuthenticatorWithFallback(cfg, reg, tracing, fallback)
if err != nil {
return nil, err
}
+1
View File
@@ -398,6 +398,7 @@ func doFolderTests(t *testing.T, helper *apis.K8sTestHelper) *apis.K8sTestHelper
"kind": "Folder",
"metadata": {
"creationTimestamp": "${creationTimestamp}",
"labels": {"grafana.app/deprecatedInternalID":"1"},
"name": "` + uid + `",
"namespace": "default",
"resourceVersion": "${resourceVersion}",
Loaded 100 of 150 files, more files were not shown because too many files have changed in this diff. Show more