Compare commits
44 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ceff188b35 | |||
| 10ea008462 | |||
| f5a2695590 | |||
| bffd24a35c | |||
| b9574d6698 | |||
| c03cd22431 | |||
| 62201abe1b | |||
| b7118163f2 | |||
| ecda40e78a | |||
| f88f9199a5 | |||
| 0de3ec2903 | |||
| db354f2d71 | |||
| 225b47165d | |||
| dbc1b646cb | |||
| 3adcf92c1e | |||
| 6a9f1532ea | |||
| 84f806b573 | |||
| 8801d0a781 | |||
| d859de6a9a | |||
| 01a7e5dc9a | |||
| 2520d54e25 | |||
| 5c51966ac6 | |||
| f435ea0f72 | |||
| 355161aac7 | |||
| be023a10fd | |||
| 12dd28d04d | |||
| f107b0db60 | |||
| 0acbcd2c81 | |||
| 3aa9ed274a | |||
| 400178ec3c | |||
| dade7bfaaf | |||
| cb1b4ab8aa | |||
| f1e99d1806 | |||
| e055768434 | |||
| 662120de9c | |||
| 64161f72c6 | |||
| 68a0a02844 | |||
| 56853cf796 | |||
| 417b9e0c70 | |||
| c8b7546e6b | |||
| 10c7ae6056 | |||
| 664b933026 | |||
| 87f5bf1914 | |||
| c60816ff6e |
+48
-184
@@ -495,7 +495,7 @@ steps:
|
||||
name: identify-runner
|
||||
- commands:
|
||||
- mkdir -p bin
|
||||
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v3.0.53/grabpl
|
||||
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v3.0.56/grabpl
|
||||
- chmod +x bin/grabpl
|
||||
image: byrnedo/alpine-curl:0.1.8
|
||||
name: grabpl
|
||||
@@ -902,7 +902,7 @@ steps:
|
||||
name: clone-enterprise
|
||||
- commands:
|
||||
- mkdir -p bin
|
||||
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v3.0.53/grabpl
|
||||
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v3.0.56/grabpl
|
||||
- chmod +x bin/grabpl
|
||||
image: byrnedo/alpine-curl:0.1.8
|
||||
name: grabpl
|
||||
@@ -1819,7 +1819,7 @@ steps:
|
||||
name: identify-runner
|
||||
- commands:
|
||||
- mkdir -p bin
|
||||
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v3.0.53/grabpl
|
||||
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v3.0.56/grabpl
|
||||
- chmod +x bin/grabpl
|
||||
image: byrnedo/alpine-curl:0.1.8
|
||||
name: grabpl
|
||||
@@ -2323,7 +2323,7 @@ services:
|
||||
steps:
|
||||
- commands:
|
||||
- mkdir -p bin
|
||||
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v3.0.53/grabpl
|
||||
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v3.0.56/grabpl
|
||||
- chmod +x bin/grabpl
|
||||
image: byrnedo/alpine-curl:0.1.8
|
||||
name: grabpl
|
||||
@@ -2527,7 +2527,7 @@ steps:
|
||||
name: identify-runner
|
||||
- commands:
|
||||
- $$ProgressPreference = "SilentlyContinue"
|
||||
- Invoke-WebRequest https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v3.0.53/windows/grabpl.exe
|
||||
- Invoke-WebRequest https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v3.0.56/windows/grabpl.exe
|
||||
-OutFile grabpl.exe
|
||||
image: grafana/ci-wix:0.1.1
|
||||
name: windows-init
|
||||
@@ -2657,7 +2657,7 @@ steps:
|
||||
name: identify-runner
|
||||
- commands:
|
||||
- mkdir -p bin
|
||||
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v3.0.53/grabpl
|
||||
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v3.0.56/grabpl
|
||||
- chmod +x bin/grabpl
|
||||
image: byrnedo/alpine-curl:0.1.8
|
||||
name: grabpl
|
||||
@@ -2703,9 +2703,9 @@ steps:
|
||||
$$debug docker push grafana/grafana-image-tags:$${IMAGE_TAG}-ubuntu-armv7
|
||||
|
||||
# Create the grafana manifests
|
||||
$$debug docker manifest create grafana/grafana:${TAG} grafana/grafana-image-tags:$${IMAGE_TAG}-amd64 grafana/grafana-image-tags:$${IMAGE_TAG}-arm64 grafana/grafana-image-tags:$${IMAGE_TAG}-armv7
|
||||
$$debug docker manifest create grafana/grafana:$${IMAGE_TAG} grafana/grafana-image-tags:$${IMAGE_TAG}-amd64 grafana/grafana-image-tags:$${IMAGE_TAG}-arm64 grafana/grafana-image-tags:$${IMAGE_TAG}-armv7
|
||||
|
||||
$$debug docker manifest create grafana/grafana:${TAG}-ubuntu grafana/grafana-image-tags:$${IMAGE_TAG}-ubuntu-amd64 grafana/grafana-image-tags:$${IMAGE_TAG}-ubuntu-arm64 grafana/grafana-image-tags:$${IMAGE_TAG}-ubuntu-armv7
|
||||
$$debug docker manifest create grafana/grafana:$${IMAGE_TAG}-ubuntu grafana/grafana-image-tags:$${IMAGE_TAG}-ubuntu-amd64 grafana/grafana-image-tags:$${IMAGE_TAG}-ubuntu-arm64 grafana/grafana-image-tags:$${IMAGE_TAG}-ubuntu-armv7
|
||||
|
||||
# Push the grafana manifests
|
||||
$$debug docker manifest push grafana/grafana:$${IMAGE_TAG}
|
||||
@@ -2789,7 +2789,7 @@ steps:
|
||||
name: identify-runner
|
||||
- commands:
|
||||
- mkdir -p bin
|
||||
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v3.0.53/grabpl
|
||||
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v3.0.56/grabpl
|
||||
- chmod +x bin/grabpl
|
||||
image: byrnedo/alpine-curl:0.1.8
|
||||
name: grabpl
|
||||
@@ -2835,9 +2835,9 @@ steps:
|
||||
$$debug docker push grafana/grafana-image-tags:$${IMAGE_TAG}-ubuntu-armv7
|
||||
|
||||
# Create the grafana manifests
|
||||
$$debug docker manifest create grafana/grafana:${TAG} grafana/grafana-image-tags:$${IMAGE_TAG}-amd64 grafana/grafana-image-tags:$${IMAGE_TAG}-arm64 grafana/grafana-image-tags:$${IMAGE_TAG}-armv7
|
||||
$$debug docker manifest create grafana/grafana:$${IMAGE_TAG} grafana/grafana-image-tags:$${IMAGE_TAG}-amd64 grafana/grafana-image-tags:$${IMAGE_TAG}-arm64 grafana/grafana-image-tags:$${IMAGE_TAG}-armv7
|
||||
|
||||
$$debug docker manifest create grafana/grafana:${TAG}-ubuntu grafana/grafana-image-tags:$${IMAGE_TAG}-ubuntu-amd64 grafana/grafana-image-tags:$${IMAGE_TAG}-ubuntu-arm64 grafana/grafana-image-tags:$${IMAGE_TAG}-ubuntu-armv7
|
||||
$$debug docker manifest create grafana/grafana:$${IMAGE_TAG}-ubuntu grafana/grafana-image-tags:$${IMAGE_TAG}-ubuntu-amd64 grafana/grafana-image-tags:$${IMAGE_TAG}-ubuntu-arm64 grafana/grafana-image-tags:$${IMAGE_TAG}-ubuntu-armv7
|
||||
|
||||
# Push the grafana manifests
|
||||
$$debug docker manifest push grafana/grafana:$${IMAGE_TAG}
|
||||
@@ -3100,6 +3100,7 @@ platform:
|
||||
services: []
|
||||
steps:
|
||||
- commands:
|
||||
- export version=$(echo ${TAG} | sed -e "s/+security-/-/g")
|
||||
- 'echo "Step 1: Updating package lists..."'
|
||||
- apt-get update >/dev/null 2>&1
|
||||
- 'echo "Step 2: Installing prerequisites..."'
|
||||
@@ -3113,14 +3114,14 @@ steps:
|
||||
- echo "deb [signed-by=/etc/apt/keyrings/grafana.gpg] https://apt.grafana.com stable
|
||||
main" | tee -a /etc/apt/sources.list.d/grafana.list
|
||||
- 'echo "Step 5: Installing Grafana..."'
|
||||
- for i in $(seq 1 10); do
|
||||
- for i in $(seq 1 60); do
|
||||
- ' if apt-get update >/dev/null 2>&1 && DEBIAN_FRONTEND=noninteractive apt-get
|
||||
install -yq grafana=${TAG} >/dev/null 2>&1; then'
|
||||
install -yq grafana=$version >/dev/null 2>&1; then'
|
||||
- ' echo "Command succeeded on attempt $i"'
|
||||
- ' break'
|
||||
- ' else'
|
||||
- ' echo "Attempt $i failed"'
|
||||
- ' if [ $i -eq 10 ]; then'
|
||||
- ' if [ $i -eq 60 ]; then'
|
||||
- ' echo ''All attempts failed'''
|
||||
- ' exit 1'
|
||||
- ' fi'
|
||||
@@ -3129,10 +3130,10 @@ steps:
|
||||
- ' fi'
|
||||
- done
|
||||
- 'echo "Step 6: Verifying Grafana installation..."'
|
||||
- 'if dpkg -s grafana | grep -q "Version: ${TAG}"; then'
|
||||
- ' echo "Successfully verified Grafana version ${TAG}"'
|
||||
- 'if dpkg -s grafana | grep -q "Version: $version"; then'
|
||||
- ' echo "Successfully verified Grafana version $version"'
|
||||
- else
|
||||
- ' echo "Failed to verify Grafana version ${TAG}"'
|
||||
- ' echo "Failed to verify Grafana version $version"'
|
||||
- ' exit 1'
|
||||
- fi
|
||||
- echo "Verification complete."
|
||||
@@ -3160,16 +3161,17 @@ steps:
|
||||
sslcacert=/etc/pki/tls/certs/ca-bundle.crt
|
||||
' > /etc/yum.repos.d/grafana.repo
|
||||
- 'echo "Step 5: Checking RPM repository..."'
|
||||
- dnf list available grafana-${TAG}
|
||||
- export version=$(echo "${TAG}" | sed -e "s/+security-/^security_/g")
|
||||
- dnf list available grafana-$version
|
||||
- if [ $? -eq 0 ]; then
|
||||
- ' echo "Grafana package found in repository. Installing from repo..."'
|
||||
- for i in $(seq 1 5); do
|
||||
- ' if dnf install -y --nogpgcheck grafana-${TAG} >/dev/null 2>&1; then'
|
||||
- for i in $(seq 1 60); do
|
||||
- ' if dnf install -y --nogpgcheck grafana-$version >/dev/null 2>&1; then'
|
||||
- ' echo "Command succeeded on attempt $i"'
|
||||
- ' break'
|
||||
- ' else'
|
||||
- ' echo "Attempt $i failed"'
|
||||
- ' if [ $i -eq 5 ]; then'
|
||||
- ' if [ $i -eq 60 ]; then'
|
||||
- ' echo ''All attempts failed'''
|
||||
- ' exit 1'
|
||||
- ' fi'
|
||||
@@ -3181,16 +3183,16 @@ steps:
|
||||
- ' rpm --import https://rpm.grafana.com/gpg.key'
|
||||
- ' rpm -qa gpg-pubkey* | xargs rpm -qi | grep -i grafana'
|
||||
- else
|
||||
- ' echo "Grafana package version ${TAG} not found in repository."'
|
||||
- ' echo "Grafana package version $version not found in repository."'
|
||||
- ' dnf repolist'
|
||||
- ' dnf list available grafana*'
|
||||
- ' exit 1'
|
||||
- fi
|
||||
- 'echo "Step 6: Verifying Grafana installation..."'
|
||||
- if rpm -q grafana | grep -q "${TAG}"; then
|
||||
- ' echo "Successfully verified Grafana version ${TAG}"'
|
||||
- if rpm -q grafana | grep -q "$verison"; then
|
||||
- ' echo "Successfully verified Grafana version $version"'
|
||||
- else
|
||||
- ' echo "Failed to verify Grafana version ${TAG}"'
|
||||
- ' echo "Failed to verify Grafana version $version"'
|
||||
- ' exit 1'
|
||||
- fi
|
||||
- echo "Verification complete."
|
||||
@@ -3277,6 +3279,7 @@ steps:
|
||||
from_secret: packages_service_account
|
||||
target_bucket: grafana-packages
|
||||
- commands:
|
||||
- export version=$(echo ${TAG} | sed -e "s/+security-/-/g")
|
||||
- 'echo "Step 1: Updating package lists..."'
|
||||
- apt-get update >/dev/null 2>&1
|
||||
- 'echo "Step 2: Installing prerequisites..."'
|
||||
@@ -3290,14 +3293,14 @@ steps:
|
||||
- echo "deb [signed-by=/etc/apt/keyrings/grafana.gpg] https://apt.grafana.com stable
|
||||
main" | tee -a /etc/apt/sources.list.d/grafana.list
|
||||
- 'echo "Step 5: Installing Grafana..."'
|
||||
- for i in $(seq 1 10); do
|
||||
- for i in $(seq 1 60); do
|
||||
- ' if apt-get update >/dev/null 2>&1 && DEBIAN_FRONTEND=noninteractive apt-get
|
||||
install -yq grafana=${TAG} >/dev/null 2>&1; then'
|
||||
install -yq grafana=$version >/dev/null 2>&1; then'
|
||||
- ' echo "Command succeeded on attempt $i"'
|
||||
- ' break'
|
||||
- ' else'
|
||||
- ' echo "Attempt $i failed"'
|
||||
- ' if [ $i -eq 10 ]; then'
|
||||
- ' if [ $i -eq 60 ]; then'
|
||||
- ' echo ''All attempts failed'''
|
||||
- ' exit 1'
|
||||
- ' fi'
|
||||
@@ -3306,10 +3309,10 @@ steps:
|
||||
- ' fi'
|
||||
- done
|
||||
- 'echo "Step 6: Verifying Grafana installation..."'
|
||||
- 'if dpkg -s grafana | grep -q "Version: ${TAG}"; then'
|
||||
- ' echo "Successfully verified Grafana version ${TAG}"'
|
||||
- 'if dpkg -s grafana | grep -q "Version: $version"; then'
|
||||
- ' echo "Successfully verified Grafana version $version"'
|
||||
- else
|
||||
- ' echo "Failed to verify Grafana version ${TAG}"'
|
||||
- ' echo "Failed to verify Grafana version $version"'
|
||||
- ' exit 1'
|
||||
- fi
|
||||
- echo "Verification complete."
|
||||
@@ -3338,16 +3341,17 @@ steps:
|
||||
sslcacert=/etc/pki/tls/certs/ca-bundle.crt
|
||||
' > /etc/yum.repos.d/grafana.repo
|
||||
- 'echo "Step 5: Checking RPM repository..."'
|
||||
- dnf list available grafana-${TAG}
|
||||
- export version=$(echo "${TAG}" | sed -e "s/+security-/^security_/g")
|
||||
- dnf list available grafana-$version
|
||||
- if [ $? -eq 0 ]; then
|
||||
- ' echo "Grafana package found in repository. Installing from repo..."'
|
||||
- for i in $(seq 1 5); do
|
||||
- ' if dnf install -y --nogpgcheck grafana-${TAG} >/dev/null 2>&1; then'
|
||||
- for i in $(seq 1 60); do
|
||||
- ' if dnf install -y --nogpgcheck grafana-$version >/dev/null 2>&1; then'
|
||||
- ' echo "Command succeeded on attempt $i"'
|
||||
- ' break'
|
||||
- ' else'
|
||||
- ' echo "Attempt $i failed"'
|
||||
- ' if [ $i -eq 5 ]; then'
|
||||
- ' if [ $i -eq 60 ]; then'
|
||||
- ' echo ''All attempts failed'''
|
||||
- ' exit 1'
|
||||
- ' fi'
|
||||
@@ -3359,16 +3363,16 @@ steps:
|
||||
- ' rpm --import https://rpm.grafana.com/gpg.key'
|
||||
- ' rpm -qa gpg-pubkey* | xargs rpm -qi | grep -i grafana'
|
||||
- else
|
||||
- ' echo "Grafana package version ${TAG} not found in repository."'
|
||||
- ' echo "Grafana package version $version not found in repository."'
|
||||
- ' dnf repolist'
|
||||
- ' dnf list available grafana*'
|
||||
- ' exit 1'
|
||||
- fi
|
||||
- 'echo "Step 6: Verifying Grafana installation..."'
|
||||
- if rpm -q grafana | grep -q "${TAG}"; then
|
||||
- ' echo "Successfully verified Grafana version ${TAG}"'
|
||||
- if rpm -q grafana | grep -q "$verison"; then
|
||||
- ' echo "Successfully verified Grafana version $version"'
|
||||
- else
|
||||
- ' echo "Failed to verify Grafana version ${TAG}"'
|
||||
- ' echo "Failed to verify Grafana version $version"'
|
||||
- ' exit 1'
|
||||
- fi
|
||||
- echo "Verification complete."
|
||||
@@ -3534,144 +3538,6 @@ volumes:
|
||||
clone:
|
||||
retries: 3
|
||||
depends_on: []
|
||||
environment:
|
||||
EDITION: oss
|
||||
image_pull_secrets:
|
||||
- gcr
|
||||
- gar
|
||||
kind: pipeline
|
||||
name: release-test-frontend
|
||||
node:
|
||||
type: no-parallel
|
||||
platform:
|
||||
arch: amd64
|
||||
os: linux
|
||||
services: []
|
||||
steps:
|
||||
- commands:
|
||||
- echo $DRONE_RUNNER_NAME
|
||||
image: alpine:3.20.3
|
||||
name: identify-runner
|
||||
- commands:
|
||||
- apk add --update g++ make python3 && ln -sf /usr/bin/python3 /usr/bin/python
|
||||
- yarn install --immutable || yarn install --immutable
|
||||
depends_on: []
|
||||
image: node:20.9.0-alpine
|
||||
name: yarn-install
|
||||
- commands:
|
||||
- apk add --update git bash
|
||||
- yarn betterer ci
|
||||
depends_on:
|
||||
- yarn-install
|
||||
image: node:20.9.0-alpine
|
||||
name: betterer-frontend
|
||||
- commands:
|
||||
- yarn run ci:test-frontend
|
||||
depends_on:
|
||||
- yarn-install
|
||||
environment:
|
||||
TEST_MAX_WORKERS: 50%
|
||||
image: node:20.9.0-alpine
|
||||
name: test-frontend
|
||||
trigger:
|
||||
event:
|
||||
exclude:
|
||||
- promote
|
||||
ref:
|
||||
exclude:
|
||||
- refs/tags/*-cloud*
|
||||
include:
|
||||
- refs/tags/v*
|
||||
type: docker
|
||||
volumes:
|
||||
- host:
|
||||
path: /var/run/docker.sock
|
||||
name: docker
|
||||
---
|
||||
clone:
|
||||
retries: 3
|
||||
depends_on: []
|
||||
environment:
|
||||
EDITION: oss
|
||||
image_pull_secrets:
|
||||
- gcr
|
||||
- gar
|
||||
kind: pipeline
|
||||
name: release-test-backend
|
||||
node:
|
||||
type: no-parallel
|
||||
platform:
|
||||
arch: amd64
|
||||
os: linux
|
||||
services: []
|
||||
steps:
|
||||
- commands:
|
||||
- echo $DRONE_RUNNER_NAME
|
||||
image: alpine:3.20.3
|
||||
name: identify-runner
|
||||
- commands:
|
||||
- '# It is required that code generated from Thema/CUE be committed and in sync
|
||||
with its inputs.'
|
||||
- '# The following command will fail if running code generators produces any diff
|
||||
in output.'
|
||||
- apk add --update make
|
||||
- CODEGEN_VERIFY=1 make gen-cue
|
||||
depends_on: []
|
||||
image: golang:1.22.7-alpine
|
||||
name: verify-gen-cue
|
||||
- commands:
|
||||
- '# It is required that generated jsonnet is committed and in sync with its inputs.'
|
||||
- '# The following command will fail if running code generators produces any diff
|
||||
in output.'
|
||||
- apk add --update make
|
||||
- CODEGEN_VERIFY=1 make gen-jsonnet
|
||||
depends_on: []
|
||||
image: golang:1.22.7-alpine
|
||||
name: verify-gen-jsonnet
|
||||
- commands:
|
||||
- apk add --update make
|
||||
- make gen-go
|
||||
depends_on:
|
||||
- verify-gen-cue
|
||||
image: golang:1.22.7-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 -tags requires_buildifer -short -covermode=atomic
|
||||
-timeout=5m
|
||||
depends_on:
|
||||
- wire-install
|
||||
image: golang:1.22.7-alpine
|
||||
name: test-backend
|
||||
- commands:
|
||||
- apk add --update build-base
|
||||
- go test -count=1 -covermode=atomic -timeout=5m -run '^TestIntegration' $(find
|
||||
./pkg -type f -name '*_test.go' -exec grep -l '^func TestIntegration' '{}' '+'
|
||||
| grep -o '\(.*\)/' | sort -u)
|
||||
depends_on:
|
||||
- wire-install
|
||||
image: golang:1.22.7-alpine
|
||||
name: test-backend-integration
|
||||
trigger:
|
||||
event:
|
||||
exclude:
|
||||
- promote
|
||||
ref:
|
||||
exclude:
|
||||
- refs/tags/*-cloud*
|
||||
include:
|
||||
- refs/tags/v*
|
||||
type: docker
|
||||
volumes:
|
||||
- host:
|
||||
path: /var/run/docker.sock
|
||||
name: docker
|
||||
---
|
||||
clone:
|
||||
retries: 3
|
||||
depends_on:
|
||||
- release-test-backend
|
||||
- release-test-frontend
|
||||
image_pull_secrets:
|
||||
- gcr
|
||||
- gar
|
||||
@@ -3761,7 +3627,7 @@ steps:
|
||||
name: identify-runner
|
||||
- commands:
|
||||
- $$ProgressPreference = "SilentlyContinue"
|
||||
- Invoke-WebRequest https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v3.0.53/windows/grabpl.exe
|
||||
- Invoke-WebRequest https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v3.0.56/windows/grabpl.exe
|
||||
-OutFile grabpl.exe
|
||||
image: grafana/ci-wix:0.1.1
|
||||
name: windows-init
|
||||
@@ -3852,9 +3718,7 @@ volumes:
|
||||
---
|
||||
clone:
|
||||
retries: 3
|
||||
depends_on:
|
||||
- release-test-backend
|
||||
- release-test-frontend
|
||||
depends_on: []
|
||||
image_pull_secrets:
|
||||
- gcr
|
||||
- gar
|
||||
@@ -4564,7 +4428,7 @@ services:
|
||||
steps:
|
||||
- commands:
|
||||
- mkdir -p bin
|
||||
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v3.0.53/grabpl
|
||||
- curl -fL -o bin/grabpl https://grafana-downloads.storage.googleapis.com/grafana-build-pipeline/v3.0.56/grabpl
|
||||
- chmod +x bin/grabpl
|
||||
image: byrnedo/alpine-curl:0.1.8
|
||||
name: grabpl
|
||||
@@ -5188,7 +5052,7 @@ name: gar
|
||||
---
|
||||
get:
|
||||
name: pat
|
||||
path: infra/data/ci/github/grafanabot
|
||||
path: ci/data/repo/grafana/grafana/grafanabot
|
||||
kind: secret
|
||||
name: github_token
|
||||
---
|
||||
@@ -5355,6 +5219,6 @@ kind: secret
|
||||
name: gcr_credentials
|
||||
---
|
||||
kind: signature
|
||||
hmac: 7e3291db6cd7067117554911aa9a0f6e4e8e5e154a716ca662eae036d8c1ac82
|
||||
hmac: b590c18e0ab745e48f2b56eb5004c9c351fca29b164f338c7ebf6a71054b82e1
|
||||
|
||||
...
|
||||
|
||||
+4
-4
@@ -43,12 +43,12 @@
|
||||
/docs/sources/dashboards/ @imatwawana
|
||||
/docs/sources/datasources/ @jdbaldry
|
||||
/docs/sources/explore/ @grafana/explore-squad @lwandz13
|
||||
/docs/sources/fundamentals @chri2547
|
||||
/docs/sources/getting-started/ @chri2547
|
||||
/docs/sources/introduction/ @chri2547
|
||||
/docs/sources/fundamentals @irenerl24
|
||||
/docs/sources/getting-started/ @irenerl24
|
||||
/docs/sources/introduction/ @irenerl24
|
||||
/docs/sources/panels-visualizations/ @imatwawana
|
||||
/docs/sources/release-notes/ @Eve832 @GrafanaWriter
|
||||
/docs/sources/setup-grafana/ @chri2547
|
||||
/docs/sources/setup-grafana/ @irenerl24
|
||||
/docs/sources/upgrade-guide/ @imatwawana
|
||||
/docs/sources/whatsnew/ @imatwawana
|
||||
|
||||
|
||||
@@ -1,38 +1,21 @@
|
||||
name: "publish-technical-documentation-next"
|
||||
name: publish-technical-documentation-next
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "main"
|
||||
- main
|
||||
paths:
|
||||
- "docs/sources/**"
|
||||
workflow_dispatch:
|
||||
jobs:
|
||||
sync:
|
||||
if: github.repository == 'grafana/grafana'
|
||||
runs-on: "ubuntu-latest"
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: "Checkout Grafana repo"
|
||||
uses: "actions/checkout@v4"
|
||||
|
||||
- name: "Clone website-sync Action"
|
||||
# WEBSITE_SYNC_TOKEN is a fine-grained GitHub Personal Access Token that expires.
|
||||
# It must be regenerated in the grafanabot GitHub account and requires a Grafana organization
|
||||
# GitHub administrator to update the organization secret.
|
||||
# The IT helpdesk can update the organization secret.
|
||||
run: "git clone --single-branch --no-tags --depth 1 -b master https://grafanabot:${{ secrets.WEBSITE_SYNC_TOKEN }}@github.com/grafana/website-sync ./.github/actions/website-sync"
|
||||
|
||||
- name: "Publish to website repository (next)"
|
||||
uses: "./.github/actions/website-sync"
|
||||
id: "publish-next"
|
||||
- uses: actions/checkout@v4
|
||||
- uses: grafana/writers-toolkit/publish-technical-documentation@publish-technical-documentation/v1
|
||||
with:
|
||||
repository: "grafana/website"
|
||||
branch: "master"
|
||||
host: "github.com"
|
||||
# PUBLISH_TO_WEBSITE_TOKEN is a fine-grained GitHub Personal Access Token that expires.
|
||||
# It must be regenerated in the grafanabot GitHub account and requires a Grafana organization
|
||||
# GitHub administrator to update the organization secret.
|
||||
# The IT helpdesk can update the organization secret.
|
||||
github_pat: "grafanabot:${{ secrets.PUBLISH_TO_WEBSITE_TOKEN }}"
|
||||
source_folder: "docs/sources"
|
||||
target_folder: "content/docs/grafana/next"
|
||||
website_directory: content/docs/grafana/next
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
name: "publish-technical-documentation-release"
|
||||
name: publish-technical-documentation-release
|
||||
|
||||
on:
|
||||
push:
|
||||
@@ -12,63 +12,18 @@ on:
|
||||
jobs:
|
||||
sync:
|
||||
if: github.repository == 'grafana/grafana'
|
||||
runs-on: "ubuntu-latest"
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: "Checkout Grafana repo"
|
||||
uses: "actions/checkout@v4"
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: "Checkout Actions library"
|
||||
uses: "actions/checkout@v4"
|
||||
- uses: grafana/writers-toolkit/publish-technical-documentation-release@publish-technical-documentation-release/v1
|
||||
with:
|
||||
repository: "grafana/grafana-github-actions"
|
||||
path: "./actions"
|
||||
|
||||
- name: "Install Actions from library"
|
||||
run: "npm install --production --prefix ./actions"
|
||||
|
||||
- name: "Determine if there is a matching release tag"
|
||||
id: "has-matching-release-tag"
|
||||
uses: "./actions/has-matching-release-tag"
|
||||
with:
|
||||
ref_name: "${{ github.ref_name }}"
|
||||
release_tag_regexp: "^v(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)$"
|
||||
release_branch_regexp: "^v(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.x$"
|
||||
|
||||
- name: "Determine technical documentation version"
|
||||
if: "steps.has-matching-release-tag.outputs.bool == 'true'"
|
||||
uses: "./actions/docs-target"
|
||||
id: "target"
|
||||
with:
|
||||
ref_name: "${{ github.ref_name }}"
|
||||
|
||||
- name: "Clone website-sync Action"
|
||||
if: "steps.has-matching-release-tag.outputs.bool == 'true'"
|
||||
# WEBSITE_SYNC_TOKEN is a fine-grained GitHub Personal Access Token that expires.
|
||||
# It must be regenerated in the grafanabot GitHub account and requires a Grafana organization
|
||||
# GitHub administrator to update the organization secret.
|
||||
# The IT helpdesk can update the organization secret.
|
||||
run: "git clone --single-branch --no-tags --depth 1 -b master https://grafanabot:${{ secrets.WEBSITE_SYNC_TOKEN }}@github.com/grafana/website-sync ./.github/actions/website-sync"
|
||||
|
||||
- name: "Switch to HEAD of version branch for tags"
|
||||
# Tags aren't necessarily made to the HEAD of the version branch.
|
||||
# The documentation to be published is always on the HEAD of the version branch.
|
||||
if: "steps.has-matching-release-tag.outputs.bool == 'true' && github.ref_type == 'tag'"
|
||||
run: "git switch --detach origin/${{ steps.target.outputs.target }}.x"
|
||||
|
||||
- name: "Publish to website repository (release)"
|
||||
if: "steps.has-matching-release-tag.outputs.bool == 'true'"
|
||||
uses: "./.github/actions/website-sync"
|
||||
id: "publish-release"
|
||||
with:
|
||||
repository: "grafana/website"
|
||||
branch: "master"
|
||||
host: "github.com"
|
||||
# PUBLISH_TO_WEBSITE_TOKEN is a fine-grained GitHub Personal Access Token that expires.
|
||||
# It must be regenerated in the grafanabot GitHub account and requires a Grafana organization
|
||||
# GitHub administrator to update the organization secret.
|
||||
# The IT helpdesk can update the organization secret.
|
||||
github_pat: "grafanabot:${{ secrets.PUBLISH_TO_WEBSITE_TOKEN }}"
|
||||
source_folder: "docs/sources"
|
||||
target_folder: "content/docs/grafana/${{ steps.target.outputs.target }}"
|
||||
release_branch_with_patch_regexp: "^v(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)$"
|
||||
website_directory: content/docs/grafana
|
||||
version_suffix: ""
|
||||
|
||||
@@ -1,3 +1,70 @@
|
||||
<!-- 11.0.6+security-01 START -->
|
||||
|
||||
# 11.0.6+security-01 (2024-10-17)
|
||||
|
||||
### Features and enhancements
|
||||
|
||||
- **Chore:** Bump Go to 1.22.7 [#93358](https://github.com/grafana/grafana/pull/93358), [@hairyhenderson](https://github.com/hairyhenderson)
|
||||
- **Chore:** Bump Go to 1.22.7 (Enterprise)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- **AzureMonitor:** Deduplicate resource picker rows [#93703](https://github.com/grafana/grafana/pull/93703), [@aangelisc](https://github.com/aangelisc)
|
||||
- **AzureMonitor:** Improve resource picker efficiency [#93438](https://github.com/grafana/grafana/pull/93438), [@aangelisc](https://github.com/aangelisc)
|
||||
- **Correlations:** Limit access to correlations page to users who can access Explore [#93674](https://github.com/grafana/grafana/pull/93674), [@ifrost](https://github.com/ifrost)
|
||||
- **Plugins:** Avoid returning 404 for `AutoEnabled` apps [#93486](https://github.com/grafana/grafana/pull/93486), [@wbrowne](https://github.com/wbrowne)
|
||||
- **SQL Expressions**: Fixes CVE-2024-9264
|
||||
|
||||
<!-- 11.0.6+security-01 END -->
|
||||
|
||||
<!-- 11.0.5+security-01 START -->
|
||||
|
||||
# 11.0.5+security-01 (2024-10-17)
|
||||
|
||||
### Features and enhancements
|
||||
|
||||
- **Chore:** Update swagger ui (4.3.0 to 5.17.14) [#92345](https://github.com/grafana/grafana/pull/92345), [@ryantxu](https://github.com/ryantxu)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- **Provisioning:** Prevent provisioning folder errors from failing startup [#92588](https://github.com/grafana/grafana/pull/92588), [@suntala](https://github.com/suntala)
|
||||
- **TutorialCard:** Fix link to tutorial not opening [#92645](https://github.com/grafana/grafana/pull/92645), [@eledobleefe](https://github.com/eledobleefe)
|
||||
- **SQL Expressions**: Fixes CVE-2024-9264
|
||||
|
||||
<!-- 11.0.5+security-01 END -->
|
||||
|
||||
<!-- 11.0.6 START -->
|
||||
|
||||
# 11.0.6 (2024-10-01)
|
||||
|
||||
### Features and enhancements
|
||||
|
||||
- **Chore:** Bump Go to 1.22.7 [#93358](https://github.com/grafana/grafana/pull/93358), [@hairyhenderson](https://github.com/hairyhenderson)
|
||||
- **Chore:** Bump Go to 1.22.7 (Enterprise)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- **AzureMonitor:** Deduplicate resource picker rows [#93703](https://github.com/grafana/grafana/pull/93703), [@aangelisc](https://github.com/aangelisc)
|
||||
- **AzureMonitor:** Improve resource picker efficiency [#93438](https://github.com/grafana/grafana/pull/93438), [@aangelisc](https://github.com/aangelisc)
|
||||
- **Correlations:** Limit access to correlations page to users who can access Explore [#93674](https://github.com/grafana/grafana/pull/93674), [@ifrost](https://github.com/ifrost)
|
||||
- **Plugins:** Avoid returning 404 for `AutoEnabled` apps [#93486](https://github.com/grafana/grafana/pull/93486), [@wbrowne](https://github.com/wbrowne)
|
||||
|
||||
<!-- 11.0.6 END -->
|
||||
<!-- 11.0.5 START -->
|
||||
|
||||
# 11.0.5 (2024-09-26)
|
||||
|
||||
### Features and enhancements
|
||||
|
||||
- **Chore:** Update swagger ui (4.3.0 to 5.17.14) [#92345](https://github.com/grafana/grafana/pull/92345), [@ryantxu](https://github.com/ryantxu)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- **Provisioning:** Prevent provisioning folder errors from failing startup [#92588](https://github.com/grafana/grafana/pull/92588), [@suntala](https://github.com/suntala)
|
||||
- **TutorialCard:** Fix link to tutorial not opening [#92645](https://github.com/grafana/grafana/pull/92645), [@eledobleefe](https://github.com/eledobleefe)
|
||||
- **Alerting:** Fixed CVE-2024-8118.
|
||||
|
||||
<!-- 11.0.5 END -->
|
||||
<!-- 11.0.4 START -->
|
||||
|
||||
# 11.0.4 (2024-08-27)
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
ARG BASE_IMAGE=alpine:3.19.1
|
||||
ARG JS_IMAGE=node:20-alpine
|
||||
ARG JS_PLATFORM=linux/amd64
|
||||
ARG GO_IMAGE=golang:1.22.4-alpine
|
||||
ARG GO_IMAGE=golang:1.22.7-alpine
|
||||
|
||||
ARG GO_SRC=go-builder
|
||||
ARG JS_SRC=js-builder
|
||||
|
||||
@@ -266,7 +266,7 @@ build-docker-full-ubuntu: ## Build Docker image based on Ubuntu for development.
|
||||
--build-arg COMMIT_SHA=$$(git rev-parse HEAD) \
|
||||
--build-arg BUILD_BRANCH=$$(git rev-parse --abbrev-ref HEAD) \
|
||||
--build-arg BASE_IMAGE=ubuntu:22.04 \
|
||||
--build-arg GO_IMAGE=golang:1.22.4 \
|
||||
--build-arg GO_IMAGE=golang:1.22.7 \
|
||||
--tag grafana/grafana$(TAG_SUFFIX):dev-ubuntu \
|
||||
$(DOCKER_BUILD_ARGS)
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
# workaround for grafana-build quirk
|
||||
|
||||
@@ -1628,6 +1628,9 @@ ha_engine_address = "127.0.0.1:6379"
|
||||
# ha_engine_password allows setting an optional password to authenticate with the engine
|
||||
ha_engine_password = ""
|
||||
|
||||
# ha_prefix is a prefix for keys in the HA engine. It's used to separate keys for different Grafana instances.
|
||||
ha_prefix =
|
||||
|
||||
#################################### Grafana Image Renderer Plugin ##########################
|
||||
[plugin.grafana-image-renderer]
|
||||
# Instruct headless browser instance to use a default timezone when not provided by Grafana, e.g. when rendering panel image of alert.
|
||||
|
||||
@@ -1480,6 +1480,9 @@ max_annotations_to_keep =
|
||||
# ha_engine_password allows setting an optional password to authenticate with the engine
|
||||
;ha_engine_password = ""
|
||||
|
||||
# ha_prefix is a prefix for keys in the HA engine. It's used to separate keys for different Grafana instances.
|
||||
;ha_prefix =
|
||||
|
||||
#################################### Grafana Image Renderer Plugin ##########################
|
||||
[plugin.grafana-image-renderer]
|
||||
# Instruct headless browser instance to use a default timezone when not provided by Grafana, e.g. when rendering panel image of alert.
|
||||
|
||||
+82
-2
@@ -53,7 +53,7 @@ To create a notification template that contains more than one template:
|
||||
|
||||
## Preview notification templates
|
||||
|
||||
Preview how your notification templates will look before using them in your contact points, helping you understand the result of the template you are creating as well as enabling you to fix any errors before saving it.
|
||||
Preview how your notification templates should look before using them in your contact points, helping you understand the result of the template you are creating as well as enabling you to fix any errors before saving it.
|
||||
|
||||
**Note:** This feature is only for Grafana Alertmanager.
|
||||
|
||||
@@ -81,7 +81,7 @@ To preview your notification templates:
|
||||
|
||||
c. Click **Add alert data**.
|
||||
|
||||
d. Click **Refresh preview** to see what your template content will look like and the corresponding payload data.
|
||||
d. Click **Refresh preview** to see what your template content should look like and the corresponding payload data.
|
||||
|
||||
If there are any errors in your template, they are displayed in the Preview and you can correct them before saving.
|
||||
|
||||
@@ -162,6 +162,86 @@ Resolved alerts:
|
||||
{{ template "email.message" . }}
|
||||
```
|
||||
|
||||
## Group multiple alert instances into one email notification
|
||||
|
||||
To make alerts more concise, you can group multiple instances of a firing alert into a single email notification in a table format. This way, you avoid long, repetitive emails and make alerts easier to digest.
|
||||
|
||||
Follow these steps to create a custom notification template that consolidates alert instances into a table.
|
||||
|
||||
1. Modify the alert rule to include an annotation that is referenced in the notification template later on.
|
||||
1. Enter a name for the **custom annotation**: In this example, _ServerInfo_.
|
||||
1. Enter the following code as the value for the annotation. It retrieves the server's instance name and a corresponding metric value, formatted as a table row:
|
||||
|
||||
```
|
||||
{{ index $labels "instance" }}{{- "\t" -}}{{ index $values "A"}}{{- "\n" -}}
|
||||
```
|
||||
|
||||
This line of code returns the labels and their values in the form of a table. Assuming $labels has `{"instance": "node1"}` and $values has `{"A": "123"}`, the output would be:
|
||||
|
||||
```
|
||||
node1 123
|
||||
```
|
||||
|
||||
1. Create a notification template that references the _ServerInfo_ annotation.
|
||||
|
||||
```go
|
||||
{{ define "Table" }}
|
||||
{{- "\nHost\t\tValue\n" -}}
|
||||
{{ range .Alerts -}}
|
||||
{{ range .Annotations.SortedPairs -}}
|
||||
{{ if (eq .Name "ServerInfo") -}}
|
||||
{{ .Value -}}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{ end }}
|
||||
```
|
||||
|
||||
The notification template outputs a list of server information from the "ServerInfo" annotation for each alert instance.
|
||||
|
||||
1. Navigate to your contact point in Grafana
|
||||
1. In the **Message** field, reference the template by name (see **Optional Email settings** section):
|
||||
|
||||
```
|
||||
{{ template "Table" . }}
|
||||
```
|
||||
|
||||
This generates a neatly formatted table in the email, grouping information for all affected servers into a single notification.
|
||||
|
||||
## Conditional notification template
|
||||
|
||||
Template alert notifications based on a label. In this example the label represents a namespace.
|
||||
|
||||
1. Use the following code in your notification template to display different messages based on the namespace:
|
||||
|
||||
```go
|
||||
{{ define "my_conditional_notification" }}
|
||||
{{ if eq .CommonLabels.namespace "namespace-a" }}
|
||||
Alert: CPU limits have reached 80% in namespace-a.
|
||||
{{ else if eq .CommonLabels.namespace "namespace-b" }}
|
||||
Alert: CPU limits have reached 80% in namespace-b.
|
||||
{{ else if eq .CommonLabels.namespace "namespace-c" }}
|
||||
Alert: CPU limits have reached 80% in namespace-c.
|
||||
{{ else }}
|
||||
Alert: CPU limits have reached 80% for {{ .CommonLabels.namespace }} namespace.
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
```
|
||||
|
||||
`.CommonLabels` is a map containing the labels that are common to all the alerts firing.
|
||||
|
||||
Make sure to replace the `.namespace` label with a label that exists in your alert rule.
|
||||
|
||||
1. Replace `namespace-a`, `namespace-b`, and `namespace-c` with your specific namespace values.
|
||||
1. Navigate to your contact point in Grafana
|
||||
1. In the **Message** field, reference the template by name (see **Optional settings** section):
|
||||
|
||||
```
|
||||
{{ template "my_conditional_notification" . }}
|
||||
```
|
||||
|
||||
This template alters the content of alert notifications depending on the namespace value.
|
||||
|
||||
## Template the title of a Slack message
|
||||
|
||||
Template the title of a Slack message to contain the number of firing and resolved alerts:
|
||||
|
||||
@@ -171,6 +171,8 @@ The following options are the same for both **Builder** and **Code** mode:
|
||||
|
||||
- **Line limit** -Defines the upper limit for the number of log lines returned by a query. The default is `1000`
|
||||
|
||||
- **Direction** - Determines the search order. **Backward** is a backward search starting at the end of the time range. **Forward** is a forward search starting at the beginning of the time range. The default is **Backward**
|
||||
|
||||
- **Step** Sets the step parameter of Loki metrics queries. The default value equals to the value of `$__interval` variable, which is calculated using the time range and the width of the graph (the number of pixels).
|
||||
|
||||
- **Resolution** Deprecated. Sets the step parameter of Loki metrics range queries. With a resolution of `1/1`, each pixel corresponds to one data point. `1/2` retrieves one data point for every other pixel, `1/10` retrieves one data point per 10 pixels, and so on. Lower resolutions perform better.
|
||||
|
||||
@@ -155,7 +155,7 @@ We also bundle a dashboard within Grafana so you can start viewing your metrics
|
||||
1. Navigate to the data source's [configuration page](ref:configure-prometheus-data-source).
|
||||
1. Select the **Dashboards** tab.
|
||||
|
||||
This displays dashboards for Grafana and Prometheus.
|
||||
This displays dashboards for Grafana and Prometheus.
|
||||
|
||||
1. Select **Import** for the dashboard to import.
|
||||
|
||||
|
||||
@@ -39,6 +39,12 @@ You can use a bar gauge visualization when you need to show:
|
||||
- Attendance
|
||||
- Process completion rates
|
||||
|
||||
## Configure a bar gauge visualization
|
||||
|
||||
The following video shows you how to create and configure a bar gauge visualization:
|
||||
|
||||
{{< youtube id="7PhDysObEXA" >}}
|
||||
|
||||
{{< docs/play title="Bar Gauge" url="https://play.grafana.org/d/vmie2cmWz/" >}}
|
||||
|
||||
## Supported data formats
|
||||
|
||||
@@ -25,16 +25,94 @@ refs:
|
||||
|
||||
# Gauge
|
||||
|
||||
Gauges are single-value visualizations that can repeat a gauge for every series, column or row.
|
||||
Gauges are single-value visualizations that allow you to quickly visualize where a value falls within a defined or calculated min and max range. With repeat options, you can display multiple gauges, each corresponding to a different series, column, or row.
|
||||
|
||||
{{< figure src="/static/img/docs/v66/gauge_panel_cover.png" max-width="1025px" alt="A gauge visualization">}}
|
||||
|
||||
{{< docs/play title="Grafana Gauge Visualization" url="https://play.grafana.org/d/KIhkVD6Gk/" >}}
|
||||
You can use gauges if you need to track:
|
||||
|
||||
- Service level objectives (SLOs)
|
||||
- How full a piece of equipment is
|
||||
- How fast a vehicle is moving within a set of limits
|
||||
- Network latency
|
||||
- Equipment state with setpoint and alarm thresholds
|
||||
- CPU consumption (0-100%)
|
||||
- RAM availability
|
||||
|
||||
## Configure a time series visualization
|
||||
|
||||
The following video provides beginner steps for creating gauge panels. You'll learn the data requirements and caveats, special customizations, and much more:
|
||||
|
||||
{{< youtube id="QwXj3y_YpnE" >}}
|
||||
|
||||
{{< docs/play title="Grafana Gauge Visualization" url="https://play.grafana.org/d/KIhkVD6Gk/" >}}
|
||||
|
||||
## Supported data formats
|
||||
|
||||
To create a gauge visualization you need a dataset containing at least one numeric field. These values are identified by the field name. Additional text fields aren’t required but can be used for identification and labeling.
|
||||
|
||||
### Example - One value
|
||||
|
||||
| GaugeName | GaugeValue |
|
||||
| --------- | ---------- |
|
||||
| MyGauge | 5 |
|
||||
|
||||

|
||||
|
||||
This dataset generates a visualization with one empty gauge showing the numeric value. This is because the gauge visualization automatically defines the upper and lower range from the minimum and maximum values in the dataset. This dataset has only one value, so it’s set as both minimum and maximum.
|
||||
|
||||
If you only have one value, but you want to define a different minimum and maximum, you can set them manually in the [Standard options](#standard-options) settings to generate a more typical looking gauge.
|
||||
|
||||

|
||||
|
||||
### Example - One row, multiple values
|
||||
|
||||
The gauge visualization can support multiple fields in a dataset. <!-- In this case, multiple gauges are displayed. -->
|
||||
|
||||
| Identifier | value1 | value2 | value3 |
|
||||
| ---------- | ------ | ------ | ------ |
|
||||
| Gauges | 5 | 3 | 10 |
|
||||
|
||||

|
||||
|
||||
When there are multiple values in the dataset, the visualization displays multiple gauges and automatically defines the minimum and maximum. In this case, those are 3 and 10. Because the minimum and maximum values are defined, each gauge is shaded in to show that value in relation to the minimum and maximum.
|
||||
|
||||
### Example - Multiple rows and values
|
||||
|
||||
The gauge visualization can display datasets with multiple rows of data or even multiple datasets.
|
||||
|
||||
| Identifier | value1 | value2 | value3 |
|
||||
| ---------- | ------ | ------ | ------ |
|
||||
| Gauges | 5 | 3 | 10 |
|
||||
| Indicators | 6 | 9 | 15 |
|
||||
| Defaults | 1 | 4 | 8 |
|
||||
|
||||

|
||||
|
||||
By default, the visualization is configured to [calculate](#value-options) a single value per column or series and to display only the last row of data. However, it derives the minimum and maximum from the full dataset, even if those values aren’t visible.
|
||||
|
||||
In this example, that means only the last row of data is displayed in the gauges and the minimum and maximum values are 1 and 10. The value 1 is displayed because it’s in the last row, while 10 is not.
|
||||
|
||||
If you want to show one gauge per table cell, you can change the **Show** setting from **Calculate** to **All values**, and each gauge is labeled by concatenating the text column with each value's column name.
|
||||
|
||||

|
||||
|
||||
### Example - Defined min and max
|
||||
|
||||
You can also define minimum and maximum values as part of the dataset.
|
||||
|
||||
| Identifier | value | max | min |
|
||||
| ---------- | ----- | --- | --- |
|
||||
| Gauges | 5 | 10 | 2 |
|
||||
|
||||

|
||||
|
||||
If you don’t want to display gauges for the `min` and `max` values, you can configure only one field to be displayed as described in the [value options](#value-options) section.
|
||||
|
||||

|
||||
|
||||
Even when minimum and maximum values aren’t displayed, the visualization still pulls the range from them.
|
||||
|
||||
## Panel options
|
||||
|
||||
{{< docs/shared lookup="visualizations/panel-options.md" source="grafana" version="<GRAFANA_VERSION>" >}}
|
||||
@@ -135,6 +213,10 @@ Adjust the sizes of the gauge text.
|
||||
|
||||
{{< docs/shared lookup="visualizations/thresholds-options-2.md" source="grafana" version="<GRAFANA_VERSION>" >}}
|
||||
|
||||
Last, gauge colors and thresholds (the outer bar markers) of the gauge can be configured as described above.
|
||||
|
||||

|
||||
|
||||
## Field overrides
|
||||
|
||||
{{< docs/shared lookup="visualizations/overrides-options.md" source="grafana" version="<GRAFANA_VERSION>" >}}
|
||||
|
||||
@@ -51,7 +51,7 @@ refs:
|
||||
|
||||
Geomaps allow you to view and customize the world map using geospatial data. It's the ideal visualization if you have data that includes location information and you want to see it displayed in a map.
|
||||
|
||||
You can configure and overlay [map layers](#types), like heatmaps and networks, and blend included basemaps or your own custom maps. This helps you to easily focus on the important location-based characteristics of the data.
|
||||
You can configure and overlay [map layers](#layer-type), like heatmaps and networks, and blend included basemaps or your own custom maps. This helps you to easily focus on the important location-based characteristics of the data.
|
||||
|
||||
{{< figure src="/static/img/docs/geomap-panel/geomap-example-8-1-0.png" max-width="1200px" alt="Geomap visualization" >}}
|
||||
|
||||
@@ -141,42 +141,42 @@ The other location types— airport codes or US state codes—aren't aut
|
||||
|
||||
If you want to use other codes or give the field a custom name, you can follow the steps in the [Location mode](#location-mode) section.
|
||||
|
||||
## Panel options
|
||||
## Configuration options
|
||||
|
||||
### Panel options
|
||||
|
||||
{{< docs/shared lookup="visualizations/panel-options.md" source="grafana" version="<GRAFANA_VERSION>" >}}
|
||||
|
||||
## Map View
|
||||
### Map view options
|
||||
|
||||
The map view controls the initial view of the map when the dashboard loads.
|
||||
|
||||
### Initial View
|
||||
#### Initial View
|
||||
|
||||
The initial view configures how the geomap renders when the panel is first loaded.
|
||||
|
||||
- **View** sets the center for the map when the panel first loads.
|
||||
- **Fit to data** fits the map view based on the data extents of Map layers and updates when data changes.
|
||||
- **Data** option allows selection of extent based on data from "All layers", a single "Layer", or the "Last value" from a selected layer.
|
||||
- **Layer** can be selected if fitting data from a single "Layer" or the "Last value" of a layer.
|
||||
- **Padding** sets padding in relative percent beyond data extent (not available when looking at "Last value" only).
|
||||
- **Max Zoom** sets the maximum zoom level when fitting data.
|
||||
- **Coordinates** sets the map view based on:
|
||||
- **Latitude**
|
||||
- **Longitude**
|
||||
- Default Views are also available including:
|
||||
- **(0°, 0°)**
|
||||
- **North America**
|
||||
- **South America**
|
||||
- **Europe**
|
||||
- **Africa**
|
||||
- **West Asia**
|
||||
- **South Asia**
|
||||
- **South-East Asia**
|
||||
- **East Asia**
|
||||
- **Australia**
|
||||
- **Oceania**
|
||||
- **Zoom** sets the initial zoom level.
|
||||
- **View** - Sets the center for the map when the panel first loads. Refer to the table following this list for view selections.
|
||||
- **Zoom** - Sets the initial zoom level.
|
||||
- **Use current map settings** - Use the settings of the current map to set the center.
|
||||
|
||||
### Share view
|
||||
<!-- prettier-ignore-start -->
|
||||
| View selection | Description |
|
||||
|---|---|
|
||||
| Fit to data | fits the map view based on the data extents of Map layers and updates when data changes.<ul><li>**Data** - option allows selection of extent based on data from "All layers", a single "Layer", or the "Last value" from a selected layer.</li><li>**Layer** - can be selected if fitting data from a single "Layer" or the "Last value" of a layer.</li><li>**Padding** - sets padding in relative percent beyond data extent (not available when looking at "Last value" only).</li><li>**Max zoom** - sets the maximum zoom level when fitting data.</li> |
|
||||
| (0°, 0°) | |
|
||||
| Coordinates | sets the map view based on: **Latitude** and **Longitude**. |
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
Default Views are also available including:
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
| | | | | |
|
||||
| ------------- | ------------- | ------ | ------ | --------- |
|
||||
| North America | South America | Europe | Africa | West Asia |
|
||||
| South Asia | South-East Asia | East Asia | Australia | Oceania |
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
#### Share view
|
||||
|
||||
The **Share view** option allows you to link the movement and zoom actions of multiple map visualizations within the same dashboard. The map visualizations that have this option enabled act in tandem when one of them is moved or zoomed, leaving the other ones independent.
|
||||
|
||||
@@ -184,11 +184,28 @@ The **Share view** option allows you to link the movement and zoom actions of mu
|
||||
You might need to reload the dashboard for this feature to work.
|
||||
{{< /admonition >}}
|
||||
|
||||
## Map layers
|
||||
### Map layers options
|
||||
|
||||
Geomaps support showing multiple layers. Each layer determines how you visualize geospatial data on top of the base map.
|
||||
|
||||
### Types
|
||||
There are three options that you need to set for all maps:
|
||||
|
||||
- [Layer type](#layer-type)
|
||||
- [Data](#data)
|
||||
- [Location mode](#location-mode)
|
||||
|
||||
Other options are dependent on your map layer type and are described within the layer type section.
|
||||
|
||||
The layer controls allow you to create layers, change their name, reorder and delete layers.
|
||||
|
||||
- **Add layer** creates an additional, configurable data layer for the geomap. When you add a layer, you are prompted to select a layer type. You can change the layer type at any point during panel configuration. See the **Layer Types** section above for details on each layer type.
|
||||
- **Edit layer name (pencil icon)** renames the layer.
|
||||
- **Trash Bin** deletes the layer.
|
||||
- **Reorder (six dots/grab handle)** allows you to change the layer order. Data on higher layers will appear above data on lower layers. The visualization will update the layer order as you drag and drop to help simplify choosing a layer order.
|
||||
|
||||
You can add multiple layers of data to a single geomap in order to create rich, detailed visualizations.
|
||||
|
||||
#### Layer type
|
||||
|
||||
There are seven map layer types to choose from in a geomap.
|
||||
|
||||
@@ -199,6 +216,10 @@ There are seven map layer types to choose from in a geomap.
|
||||
- [Route (Beta)](#route-layer-beta) render data points as a route.
|
||||
- [Photos (Beta)](#photos-layer-beta) renders a photo at each data point.
|
||||
- [Network (Beta)](#network-layer-beta) visualizes a network graph from the data.
|
||||
- [Open Street Map](#open-street-map-layer) adds a map from a collaborative free geographic world database.
|
||||
- [CARTO basemap](#carto-basemap-layer) adds a layer from CARTO Raster basemaps.
|
||||
- [ArcGIS MapServer](#arcgis-mapserver-layer) adds a layer from an ESRI ArcGIS MapServer.
|
||||
- [XYZ Tile layer](#xyz-tile-layer) adds a map from a generic tile layer.
|
||||
|
||||
{{% admonition type="note" %}}
|
||||
Beta is equivalent to the [public preview](/docs/release-life-cycle/) release stage.
|
||||
@@ -209,9 +230,7 @@ There are also two experimental (or alpha) layer types.
|
||||
- **Icon at last point (alpha)** renders an icon at the last data point.
|
||||
- **Dynamic GeoJSON (alpha)** styles a GeoJSON file based on query results.
|
||||
|
||||
{{% admonition type="note" %}}
|
||||
To enable experimental layers:
|
||||
Set `enable_alpha` to `true` in your configuration file:
|
||||
To enable experimental layers. Set `enable_alpha` to `true` in your configuration file:
|
||||
|
||||
```
|
||||
[panels]
|
||||
@@ -224,29 +243,11 @@ To enable the experimental layers using Docker, run the following command:
|
||||
docker run -p 3000:3000 -e "GF_PANELS_ENABLE_ALPHA=true" grafana/grafana:<VERSION>
|
||||
```
|
||||
|
||||
{{% /admonition %}}
|
||||
|
||||
{{% admonition type="note" %}}
|
||||
[Basemap layer types](#types-1) can also be added as layers. You can specify an opacity.
|
||||
{{% /admonition %}}
|
||||
|
||||
### Layer Controls
|
||||
|
||||
The layer controls allow you to create layers, change their name, reorder and delete layers.
|
||||
|
||||
- **Add layer** creates an additional, configurable data layer for the geomap. When you add a layer, you are prompted to select a layer type. You can change the layer type at any point during panel configuration. See the **Layer Types** section above for details on each layer type.
|
||||
- The layer controls allow you to rename, delete, and reorder the layers of the visualization.
|
||||
- **Edit layer name (pencil icon)** renames the layer.
|
||||
- **Trash Bin** deletes the layer.
|
||||
- **Reorder (six dots/grab handle)** allows you to change the layer order. Data on higher layers will appear above data on lower layers. The visualization will update the layer order as you drag and drop to help simplify choosing a layer order.
|
||||
|
||||
You can add multiple layers of data to a single geomap in order to create rich, detailed visualizations.
|
||||
|
||||
### Data
|
||||
#### Data
|
||||
|
||||
Geomaps need a source of geographical data gathered from a data source query which can return multiple datasets. By default Grafana picks the first dataset, but this drop-down allows you to pick other datasets if the query returns more than one.
|
||||
|
||||
### Location mode
|
||||
#### Location mode
|
||||
|
||||
There are four options to map the data returned by the selected query:
|
||||
|
||||
@@ -259,23 +260,290 @@ There are four options to map the data returned by the selected query:
|
||||
- **Geohash** specifies that your query holds geohash data. You will be prompted to select a string data field for the geohash from your database query.
|
||||
- **Lookup** specifies that your query holds location name data that needs to be mapped to a value. You will be prompted to select the lookup field from your database query and a gazetteer. The gazetteer is the directory that is used to map your queried data to a geographical point.
|
||||
|
||||
## Basemap layer
|
||||
#### Markers layer
|
||||
|
||||
The markers layer allows you to display data points as different marker shapes such as circles, squares, triangles, stars, and more.
|
||||
|
||||

|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
| Option | Description |
|
||||
| ------ | ----------- |
|
||||
| Data | Configure the data settings for the layer. For more information, refer to [Data](#data). |
|
||||
| Location | Configure the data settings for the layer. For more information, refer to [Location mode](#location-mode). |
|
||||
| Size | Configures the size of the markers. The default is `Fixed size`, which makes all marker sizes the same regardless of the data; however, there is also an option to size the markers based on data corresponding to a selected field. `Min` and `Max` marker sizes have to be set such that the markers can scale within this range. |
|
||||
| Symbol | Allows you to choose the symbol, icon, or graphic to aid in providing additional visual context to your data. Choose from assets that are included with Grafana such as simple symbols or the Unicon library. You can also specify a URL containing an image asset. The image must be a scalable vector graphic (SVG). |
|
||||
| Symbol Vertical Align | Configures the vertical alignment of the symbol relative to the data point. Note that the symbol's rotation angle is applied first around the data point, then the vertical alignment is applied relative to the rotation of the symbol. |
|
||||
| Symbol Horizontal Align | Configures the horizontal alignment of the symbol relative to the data point. Note that the symbol's rotation angle is applied first around the data point, then the horizontal alignment is applied relative to the rotation of the symbol. |
|
||||
| Color | Configures the color of the markers. The default `Fixed color` sets all markers to a specific color. There is also an option to have conditional colors depending on the selected field data point values and the color scheme set in the `Standard options` section. |
|
||||
| Fill opacity | Configures the transparency of each marker. |
|
||||
| Rotation angle | Configures the rotation angle of each marker. The default is `Fixed value`, which makes all markers rotate to the same angle regardless of the data; however, there is also an option to set the rotation of the markers based on data corresponding to a selected field. |
|
||||
| Text label | Configures a text label for each marker. |
|
||||
| Show legend | Allows you to toggle the legend for the layer. |
|
||||
| Display tooltip | Allows you to toggle tooltips for the layer. |
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
#### Heatmap layer
|
||||
|
||||
The heatmap layer clusters various data points to visualize locations with different densities.
|
||||
To add a heatmap layer:
|
||||
|
||||
Click on the drop-down menu under Data Layer and choose `Heatmap`.
|
||||
|
||||
Similar to `Markers`, you are prompted with various options to determine which data points to visualize and how you want to visualize them.
|
||||
|
||||

|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
| Option | Description |
|
||||
| ------ | ----------- |
|
||||
| Data | Configure the data settings for the layer. For more information, refer to [Data](#data). |
|
||||
| Location | Configure the data settings for the layer. For more information, refer to [Location mode](#location-mode). |
|
||||
| Weight values | Configures the size of the markers. The default is `Fixed size`, which makes all marker sizes the same regardless of the data; however, there is also an option to size the markers based on data corresponding to a selected field. `Min` and `Max` marker sizes have to be set such that the markers can scale within this range. |
|
||||
| Radius | Configures the size of the heatmap clusters. |
|
||||
| Blur | Configures the amount of blur on each cluster. |
|
||||
| Opacity | Configures the opacity of each cluster. |
|
||||
| Display tooltip | Allows you to toggle tooltips for the layer. |
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
#### GeoJSON layer
|
||||
|
||||
The GeoJSON layer allows you to select and load a static GeoJSON file from the filesystem.
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
| Option | Description |
|
||||
| ------ | ----------- |
|
||||
| GeoJSON URL | Provides a choice of GeoJSON files that ship with Grafana. |
|
||||
| Default Style | Controls which styles to apply when no rules above match.<ul><li>**Color** - configures the color of the default style</li><li>**Opacity** - configures the default opacity</li></ul> |
|
||||
| Style Rules | Apply styles based on feature properties <ul><li>**Rule** - allows you to select a _feature_, _condition_, and _value_ from the GeoJSON file in order to define a rule. The trash bin icon can be used to delete the current rule.</li><li>**Color** - configures the color of the style for the current rule</li><li>**Opacity** - configures the transparency level for the current rule</li> |
|
||||
| Display tooltip | Allows you to toggle tooltips for the layer. |
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
Styles can be set within the "properties" object of the GeoJSON with support for the following geometries:
|
||||
|
||||
**Polygon, MultiPolygon**
|
||||
|
||||
- **"fill"** - The color of the interior of the polygon(s)
|
||||
- **"fill-opacity"** - The opacity of the interior of the polygon(s)
|
||||
- **"stroke-width"** - The width of the line component of the polygon(s)
|
||||
|
||||
**Point, MultiPoint**
|
||||
|
||||
- **"marker-color"** - The color of the point(s)
|
||||
- **"marker-size"** - The size of the point(s)
|
||||
|
||||
**LineString, MultiLineString**
|
||||
|
||||
- **"stroke"** - The color of the line(s)
|
||||
- **"stroke-width"** - The width of the line(s)
|
||||
|
||||
#### Night / Day layer
|
||||
|
||||
The Night / Day layer displays night and day regions based on the current time range.
|
||||
|
||||
{{< figure src="/static/img/docs/geomap-panel/geomap-day-night-9-1-0.png" max-width="1200px" alt="Geomap panel Night / Day" >}}
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
| Option | Description |
|
||||
| ------ | ----------- |
|
||||
| Data | Configures the data set for the layer. For more information, refer to [Data](#data). |
|
||||
| Show | Toggles the time source from panel time range. |
|
||||
| Night region color | Picks the color for the night region. |
|
||||
| Display sun | Toggles the sun icon. |
|
||||
| Opacity | Set the opacity from `0` (transparent) to `1` (opaque). |
|
||||
| Display tooltip | Allows you to toggle tooltips for the layer. |
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
[Extensions for OpenLayers - DayNight](https://viglino.github.io/ol-ext/examples/layer/map.daynight.html)
|
||||
|
||||
#### Route layer (Beta)
|
||||
|
||||
{{% admonition type="caution" %}}
|
||||
The Route layer is currently in [public preview](/docs/release-life-cycle/). Grafana Labs offers limited support, and breaking changes might occur prior to the feature being made generally available.
|
||||
{{% /admonition %}}
|
||||
|
||||
The Route layer renders data points as a route.
|
||||
|
||||
{{< figure src="/media/docs/grafana/geomap-route-layer-basic-9-4-0.png" max-width="1200px" alt="Geomap panel Route" >}}
|
||||
|
||||
The layer can also render a route with arrows.
|
||||
|
||||
{{< figure src="/media/docs/grafana/geomap-route-layer-arrow-size-9-4-0.png" max-width="1200px" alt="Geomap panel Route arrows with size" >}}
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
| Option | Description |
|
||||
| ------ | ----------- |
|
||||
| Data | configure the data settings for the layer. For more information, refer to [Data](#data). |
|
||||
| Location | configure the data settings for the layer. For more information, refer to [Location mode](#location-mode). |
|
||||
| Size | sets the route thickness. Fixed value by default. When field data is selected you can set the Min and Max range in which field data can scale. |
|
||||
| Color | sets the route color. Set to `Fixed color` by default. You can also tie the color to field data. |
|
||||
| Fill opacity | configures the opacity of the route. |
|
||||
| Text label | configures a text label for each route. |
|
||||
| Arrow | sets the arrow styling to display along route, in order of data. Choose from: **None**, **Forward**, and **Reverse** |
|
||||
| Display tooltip | allows you to toggle tooltips for the layer. |
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
[Extensions for OpenLayers - Flow Line Style](http://viglino.github.io/ol-ext/examples/style/map.style.gpxline.html)
|
||||
|
||||
#### Photos layer (Beta)
|
||||
|
||||
{{% admonition type="caution" %}}
|
||||
The Photos layer is currently in [public preview](/docs/release-life-cycle/). Grafana Labs offers limited support, and breaking changes might occur prior to the feature being made generally available.
|
||||
{{% /admonition %}}
|
||||
|
||||
The Photos layer renders a photo at each data point.
|
||||
|
||||
{{< figure src="/static/img/docs/geomap-panel/geomap-photos-9-3-0.png" max-width="1200px" alt="Geomap panel Photos" >}}
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
| Option | Description |
|
||||
| ------ | ----------- |
|
||||
| Data | Configure the data settings for the layer. For more information, refer to [Data](#data). |
|
||||
| Location | Configure the data settings for the layer. For more information, refer to [Location mode](#location-mode). |
|
||||
| Image Source field | Allows you to select a string field containing image data in either of the following formats:<ul><li>**Image URLs**</li><li>**Base64 encoded** - Image binary ("data:image/png;base64,...")</li></ul> |
|
||||
| Kind | Sets the frame style around the images. Choose from: **Square**, **Circle**, **Anchored**, and **Folio**. |
|
||||
| Crop | Toggles whether the images are cropped to fit. |
|
||||
| Shadow | Toggles a box shadow behind the images. |
|
||||
| Border | Sets the border size around images. |
|
||||
| Border color | Sets the border color around images. |
|
||||
| Radius | Sets the overall size of images in pixels. |
|
||||
| Display tooltip | Allows you to toggle tooltips for the layer. |
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
[Extensions for OpenLayers - Image Photo Style](http://viglino.github.io/ol-ext/examples/style/map.style.photo.html)
|
||||
|
||||
#### Network layer (Beta)
|
||||
|
||||
{{% admonition type="caution" %}}
|
||||
The Network layer is currently in [public preview](/docs/release-life-cycle/). Grafana Labs offers limited support, and breaking changes might occur prior to the feature being made generally available.
|
||||
{{% /admonition %}}
|
||||
|
||||
The Network layer renders a network graph. This layer supports the same [data format supported by the node graph visualization](ref:data-format) with the addition of [geospatial data](#location-mode) included in the nodes data. The geospatial data is used to locate and render the nodes on the map.
|
||||
|
||||
{{< figure src="/media/docs/grafana/screenshot-grafana-10-1-geomap-network-layer-v2.png" max-width="750px" alt="Geomap network layer" >}}
|
||||
|
||||
You can convert node graph data to a network layer:
|
||||
{{< video-embed src="/media/docs/grafana/screen-recording-10-1-geomap-network-layer-from-node-graph.mp4" max-width="750px" alt="Node graph to Geomap network layer" >}}
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
| Option | Description |
|
||||
| ------ | ----------- |
|
||||
| Data | Configure the data settings for the layer. For more information, refer to [Data](#data). |
|
||||
| Location | Configure the data settings for the layer. For more information, refer to [Location mode](#location-mode). |
|
||||
| Arrow | Sets the arrow direction to display for each edge, with forward meaning source to target. Choose from: **None**, **Forward**, **Reverse** and **Both**. |
|
||||
| Show legend | Allows you to toggle the legend for the layer. **Note:** The legend currently only supports node data. |
|
||||
| Display tooltip | Allows you to toggle tooltips for the layer. |
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
##### Node styles options
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
| Option | Description |
|
||||
| ------ | ----------- |
|
||||
| Size | Configures the size of the nodes. The default is `Fixed size`, which makes all node sizes the same regardless of the data; however, there is also an option to size the nodes based on data corresponding to a selected field. `Min` and `Max` node sizes have to be set such that the nodes can scale within this range. |
|
||||
| Symbol | Allows you to choose the symbol, icon, or graphic to aid in providing additional visual context to your data. Choose from assets that are included with Grafana such as simple symbols or the Unicon library. You can also specify a URL containing an image asset. The image must be a scalable vector graphic (SVG). |
|
||||
| Color | Configures the color of the nodes. The default `Fixed color` sets all nodes to a specific color. There is also an option to have conditional colors depending on the selected field data point values and the color scheme set in the `Standard options` section. |
|
||||
| Fill opacity | Configures the transparency of each node. |
|
||||
| Rotation angle | Configures the rotation angle of each node. The default is `Fixed value`, which makes all nodes rotate to the same angle regardless of the data; however, there is also an option to set the rotation of the nodes based on data corresponding to a selected field. |
|
||||
| Text label | Configures a text label for each node. |
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
##### Edge styles options
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
| Option | Description |
|
||||
| ------ | ----------- |
|
||||
| Size | Configures the line width of the edges. The default is `Fixed size`, which makes all edge line widths the same regardless of the data; however, there is also an option to size the edges based on data corresponding to a selected field. `Min` and `Max` eges sizes have to be set such that the edges can scale within this range. |
|
||||
| Color | Configures the color of the edges. The default `Fixed color` sets all edges to a specific color. There is also an option to have conditional colors depending on the selected field data point values and the color scheme set in the `Standard options` section. |
|
||||
| Fill opacity | Configures the transparency of each edge. |
|
||||
| Text label | Configures a text label for each edge. |
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
#### Open Street Map layer
|
||||
|
||||
A map from a collaborative free geographic world database.
|
||||
|
||||
{{< figure src="/static/img/docs/geomap-panel/geomap-osm-9-1-0.png" max-width="1200px" alt="Geomap panel Open Street Map" >}}
|
||||
|
||||
- **Opacity** from 0 (transparent) to 1 (opaque)
|
||||
- **Display tooltip** - allows you to toggle tooltips for the layer.
|
||||
|
||||
[About Open Street Map](https://www.openstreetmap.org/about)
|
||||
|
||||
#### CARTO basemap layer
|
||||
|
||||
A CARTO layer is from CARTO Raster basemaps.
|
||||
|
||||
- **Theme**
|
||||
- Auto
|
||||
- Light
|
||||
{{< figure src="/static/img/docs/geomap-panel/geomap-carto-light-9-1-0.png" max-width="1200px" alt="Geomap panel CARTO light example" >}}
|
||||
- Dark
|
||||
{{< figure src="/static/img/docs/geomap-panel/geomap-carto-dark-9-1-0.png" max-width="1200px" alt="Geomap panel CARTO dark example" >}}
|
||||
- **Show labels** shows the Country details on top of the map.
|
||||
- **Opacity** from 0 (transparent) to 1 (opaque)
|
||||
- **Display tooltip** - allows you to toggle tooltips for the layer.
|
||||
|
||||
[About CARTO](https://carto.com/about-us/)
|
||||
|
||||
#### ArcGIS MapServer layer
|
||||
|
||||
An ArcGIS layer is a layer from an ESRI ArcGIS MapServer.
|
||||
|
||||
- **Server Instance** to select the map type.
|
||||
- World Street Map
|
||||
{{< figure src="/static/img/docs/geomap-panel/geomap-arcgis-wsm-9-1-0.png" max-width="1200px" alt="Geomap panel ArcGIS World Street Map" >}}
|
||||
- World Imagery
|
||||
{{< figure src="/static/img/docs/geomap-panel/geomap-arcgis-wi-9-1-0.png" max-width="1200px" alt="Geomap panel ArcGIS World Imagery" >}}
|
||||
- World Physical
|
||||
{{< figure src="/static/img/docs/geomap-panel/geomap-arcgis-wp-9-1-0.png" max-width="1200px" alt="Geomap panel ArcGIS World Physical" >}}
|
||||
- Topographic
|
||||
{{< figure src="/static/img/docs/geomap-panel/geomap-arcgis-topographic-9-1-0.png" max-width="1200px" alt="Geomap panel ArcGIS Topographic" >}}
|
||||
- USA Topographic
|
||||
{{< figure src="/static/img/docs/geomap-panel/geomap-arcgis-usa-topographic-9-1-0.png" max-width="1200px" alt="Geomap panel ArcGIS USA Topographic" >}}
|
||||
- World Ocean
|
||||
{{< figure src="/static/img/docs/geomap-panel/geomap-arcgis-ocean-9-1-0.png" max-width="1200px" alt="Geomap panel ArcGIS World Ocean" >}}
|
||||
- Custom MapServer (see [XYZ](#xyz-tile-layer) for formatting)
|
||||
- URL template
|
||||
- Attribution
|
||||
- **Opacity** from 0 (transparent) to 1 (opaque)
|
||||
- **Display tooltip** - allows you to toggle tooltips for the layer.
|
||||
|
||||
##### More Information
|
||||
|
||||
- [ArcGIS Services](https://services.arcgisonline.com/arcgis/rest/services)
|
||||
- [About ESRI](https://www.esri.com/en-us/about/about-esri/overview)
|
||||
|
||||
#### XYZ Tile layer
|
||||
|
||||
The XYZ Tile layer is a map from a generic tile layer.
|
||||
|
||||
{{< figure src="/static/img/docs/geomap-panel/geomap-xyz-9-1-0.png" max-width="1200px" alt="Geomap panel xyz example" >}}
|
||||
|
||||
- **URL template** - Set a valid tile server url, with {z}/{x}/{y} for example: https://tile.openstreetmap.org/{z}/{x}/{y}.png
|
||||
- **Attribution** sets the reference string for the layer if displayed in [map controls](#show-attribution)
|
||||
- **Opacity** from 0 (transparent) to 1 (opaque)
|
||||
|
||||
##### More information
|
||||
|
||||
- [Tiled Web Map Wikipedia](https://en.wikipedia.org/wiki/Tiled_web_map)
|
||||
- [List of Open Street Map Tile Servers](https://wiki.openstreetmap.org/wiki/Tile_servers)
|
||||
|
||||
### Basemap layer options
|
||||
|
||||
A basemap layer provides the visual foundation for a mapping application. It typically contains data with global coverage. Several base layer options
|
||||
are available each with specific configuration options to style the base map.
|
||||
|
||||
### Types
|
||||
Basemap layer types can also be added as layers. You can specify an opacity.
|
||||
|
||||
There are four basemap layer types to choose from in a geomap.
|
||||
|
||||
- [Open Street Map](#open-street-map-layer) adds a map from a collaborative free geographic world database.
|
||||
- [CARTO](#carto-layer) adds a layer from CARTO Raster basemaps.
|
||||
- [ArcGIS](#arcgis-layer) adds a layer from an ESRI ArcGIS MapServer.
|
||||
- [XYZ](#xyz-tile-layer) adds a map from a generic tile layer.
|
||||
- [CARTO basemap](#carto-basemap-layer) adds a layer from CARTO Raster basemaps.
|
||||
- [ArcGIS MapServer](#arcgis-mapserver-layer) adds a layer from an ESRI ArcGIS MapServer.
|
||||
- [XYZ Tile layer](#xyz-tile-layer) adds a map from a generic tile layer.
|
||||
|
||||
### Default
|
||||
|
||||
The default base layer uses the [CARTO](#carto-layer) map. You can define custom default base layers in the `.ini` configuration file.
|
||||
The default basemap layer uses the CARTO map. You can define custom default base layers in the `.ini` configuration file.
|
||||
|
||||

|
||||
|
||||
@@ -299,6 +567,9 @@ geomap_default_baselayer = `{
|
||||
|
||||
- **esri-xyz** loads the ESRI tile server. There are already multiple server instances implemented to show the various map styles: `world-imagery`, `world-physical`, `topo`, `usa-topo`, and `ocean`. The `custom` server option allows you to configure your own ArcGIS map server. Here are some examples:
|
||||
|
||||
{{< tabs >}}
|
||||
{{< tab-content name="World imagery" >}}
|
||||
|
||||
```ini
|
||||
geomap_default_baselayer = `{
|
||||
"type": "esri-xyz",
|
||||
@@ -308,6 +579,9 @@ geomap_default_baselayer = `{
|
||||
}`
|
||||
```
|
||||
|
||||
{{< /tab-content >}}
|
||||
{{< tab-content name="Custom" >}}
|
||||
|
||||
```ini
|
||||
geomap_default_baselayer = `{
|
||||
"type": "esri-xyz",
|
||||
@@ -319,6 +593,9 @@ geomap_default_baselayer = `{
|
||||
}`
|
||||
```
|
||||
|
||||
{{< /tab-content >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
- **osm-standard** loads the OpenStreetMap tile server. There are no additional configurations needed and the `config` fields can be left blank. Here is an example:
|
||||
|
||||
```ini
|
||||
@@ -342,343 +619,57 @@ default_baselayer_config = `{
|
||||
|
||||
`enable_custom_baselayers` allows you to enable or disable custom open source base maps that are already implemented. The default is `true`.
|
||||
|
||||
## Markers layer
|
||||
|
||||
The markers layer allows you to display data points as different marker shapes such as circles, squares, triangles, stars, and more.
|
||||
|
||||

|
||||
|
||||
{{< figure src="/media/docs/grafana/panels-visualizations/geomap-markers-options-11-1-0.png" max-width="350px" alt="Markers layer options" >}}
|
||||
|
||||
- **Data** and **Location mode** configure the data settings for the layer. For more information, refer to [Data](#data) and [Location mode](#location-mode).
|
||||
- **Size** configures the size of the markers. The default is `Fixed size`, which makes all marker sizes the same regardless of the data; however, there is also an option to size the markers based on data corresponding to a selected field. `Min` and `Max` marker sizes have to be set such that the markers can scale within this range.
|
||||
- **Symbol** allows you to choose the symbol, icon, or graphic to aid in providing additional visual context to your data. Choose from assets that are included with Grafana such as simple symbols or the Unicon library. You can also specify a URL containing an image asset. The image must be a scalable vector graphic (SVG).
|
||||
- **Symbol Vertical Align** configures the vertical alignment of the symbol relative to the data point. Note that the symbol's rotation angle is applied first around the data point, then the vertical alignment is applied relative to the rotation of the symbol.
|
||||
- **Symbol Horizontal Align** configures the horizontal alignment of the symbol relative to the data point. Note that the symbol's rotation angle is applied first around the data point, then the horizontal alignment is applied relative to the rotation of the symbol.
|
||||
- **Color** configures the color of the markers. The default `Fixed color` sets all markers to a specific color. There is also an option to have conditional colors depending on the selected field data point values and the color scheme set in the `Standard options` section.
|
||||
- **Fill opacity** configures the transparency of each marker.
|
||||
- **Rotation angle** configures the rotation angle of each marker. The default is `Fixed value`, which makes all markers rotate to the same angle regardless of the data; however, there is also an option to set the rotation of the markers based on data corresponding to a selected field.
|
||||
- **Text label** configures a text label for each marker.
|
||||
- **Show legend** allows you to toggle the legend for the layer.
|
||||
- **Display tooltip** allows you to toggle tooltips for the layer.
|
||||
|
||||
## Heatmap layer
|
||||
|
||||
The heatmap layer clusters various data points to visualize locations with different densities.
|
||||
To add a heatmap layer:
|
||||
|
||||
Click on the drop-down menu under Data Layer and choose `Heatmap`.
|
||||
|
||||
Similar to `Markers`, you are prompted with various options to determine which data points to visualize and how you want to visualize them.
|
||||
|
||||

|
||||
|
||||
{{< figure src="/media/docs/grafana/panels-visualizations/geomap-heatmap-options-11-1-0.png" max-width="350px" alt="Heatmap layer options" >}}
|
||||
|
||||
- **Data** and **Location mode** configure the data settings for the layer. For more information, refer to [Data](#data) and [Location mode](#location-mode).
|
||||
- **Weight values** configure the intensity of the heatmap clusters. `Fixed value` keeps a constant weight value throughout all data points. This value should be in the range of 0~1. Similar to Markers, there is an alternate option in the drop-down to automatically scale the weight values depending on data values.
|
||||
- **Radius** configures the size of the heatmap clusters.
|
||||
- **Blur** configures the amount of blur on each cluster.
|
||||
- **Opacity** configures the opacity of each cluster.
|
||||
- **Display tooltip** allows you to toggle tooltips for the layer.
|
||||
|
||||
## GeoJSON layer
|
||||
|
||||
The GeoJSON layer allows you to select and load a static GeoJSON file from the filesystem.
|
||||
|
||||
- **GeoJSON URL** provides a choice of GeoJSON files that ship with Grafana.
|
||||
- **Default Style** controls which styles to apply when no rules above match.
|
||||
- **Color** configures the color of the default style
|
||||
- **Opacity** configures the default opacity
|
||||
- **Style Rules** apply styles based on feature properties
|
||||
- **Rule** allows you to select a _feature_, _condition_, and _value_ from the GeoJSON file in order to define a rule. The trash bin icon can be used to delete the current rule.
|
||||
- **Color** configures the color of the style for the current rule
|
||||
- **Opacity** configures the transparency level for the current rule
|
||||
- **Add style rule** creates additional style rules.
|
||||
- **Display tooltip** allows you to toggle tooltips for the layer.
|
||||
|
||||
{{% admonition type="note" %}}
|
||||
Styles can be set within the "properties" object of the GeoJSON with support for the following geometries:
|
||||
|
||||
- Polygon, MultiPolygon
|
||||
|
||||
- **"fill"** - The color of the interior of the polygon(s)
|
||||
- **"fill-opacity"** - The opacity of the interior of the polygon(s)
|
||||
- **"stroke-width"** - The width of the line component of the polygon(s)
|
||||
|
||||
- Point, MultiPoint
|
||||
|
||||
- **"marker-color"** - The color of the point(s)
|
||||
- **"marker-size"** - The size of the point(s)
|
||||
|
||||
- LineString, MultiLineString
|
||||
- **"stroke"** - The color of the line(s)
|
||||
- **"stroke-width"** - The width of the line(s)
|
||||
|
||||
{{% /admonition %}}
|
||||
|
||||
## Night / Day layer
|
||||
|
||||
The Night / Day layer displays night and day regions based on the current time range.
|
||||
|
||||
{{< figure src="/static/img/docs/geomap-panel/geomap-day-night-9-1-0.png" max-width="1200px" caption="Geomap panel Night / Day" >}}
|
||||
|
||||
### Options
|
||||
|
||||
- **Data** configures the data set for the layer. For more information, refer to [Data](#data).
|
||||
- **Show** toggles the time source from panel time range.
|
||||
- **Night region color** picks the color for the night region.
|
||||
- **Display sun** toggles the sun icon.
|
||||
- **Opacity** set the opacity from `0` (transparent) to `1` (opaque).
|
||||
- **Display tooltip** allows you to toggle tooltips for the layer.
|
||||
|
||||
{{< figure src="/static/img/docs/geomap-panel/geomap-day-night-options-9-1-0.png" max-width="1200px" caption="Geomap panel Night / Day options" >}}
|
||||
|
||||
### More information
|
||||
|
||||
- [**Extensions for OpenLayers - DayNight**](https://viglino.github.io/ol-ext/examples/layer/map.daynight.html)
|
||||
|
||||
## Route layer (Beta)
|
||||
|
||||
{{% admonition type="caution" %}}
|
||||
The Route layer is currently in [public preview](/docs/release-life-cycle/). Grafana Labs offers limited support, and breaking changes might occur prior to the feature being made generally available.
|
||||
{{% /admonition %}}
|
||||
|
||||
The Route layer renders data points as a route.
|
||||
|
||||
{{< figure src="/media/docs/grafana/geomap-route-layer-basic-9-4-0.png" max-width="1200px" caption="Geomap panel Route" >}}
|
||||
|
||||
### Options
|
||||
|
||||
- **Data** and **Location mode** configure the data settings for the layer. For more information, refer to [Data](#data) and [Location mode](#location-mode).
|
||||
- **Size** sets the route thickness. Fixed value by default. When field data is selected you can set the Min and Max range in which field data can scale.
|
||||
- **Color** sets the route color. Set to `Fixed color` by default. You can also tie the color to field data.
|
||||
- **Fill opacity** configures the opacity of the route.
|
||||
- **Text label** configures a text label for each route.
|
||||
- **Arrow** sets the arrow styling to display along route, in order of data.
|
||||
- **None**
|
||||
- **Forward**
|
||||
- **Reverse**
|
||||
- **Display tooltip** allows you to toggle tooltips for the layer.
|
||||
|
||||
{{< figure src="/media/docs/grafana/geomap-route-layer-arrow-size-9-4-0.png" max-width="1200px" caption="Geomap panel Route arrows with size" >}}
|
||||
|
||||
### More information
|
||||
|
||||
- [**Extensions for OpenLayers - Flow Line Style**](http://viglino.github.io/ol-ext/examples/style/map.style.gpxline.html)
|
||||
|
||||
## Photos layer (Beta)
|
||||
|
||||
{{% admonition type="caution" %}}
|
||||
The Photos layer is currently in [public preview](/docs/release-life-cycle/). Grafana Labs offers limited support, and breaking changes might occur prior to the feature being made generally available.
|
||||
{{% /admonition %}}
|
||||
|
||||
The Photos layer renders a photo at each data point.
|
||||
|
||||
{{< figure src="/static/img/docs/geomap-panel/geomap-photos-9-3-0.png" max-width="1200px" caption="Geomap panel Photos" >}}
|
||||
|
||||
### Options
|
||||
|
||||
- **Data** and **Location mode** configure the data settings for the layer. For more information, refer to [Data](#data) and [Location mode](#location-mode).
|
||||
- **Image Source field** allows you to select a string field containing image data in either of the following formats:
|
||||
- **Image URLs**
|
||||
- **Base64 encoded** - Image binary ("data:image/png;base64,...")
|
||||
- **Kind** sets the frame style around the images. Choose from:
|
||||
- **Square**
|
||||
- **Circle**
|
||||
- **Anchored**
|
||||
- **Folio**
|
||||
- **Crop** toggles whether the images are cropped to fit.
|
||||
- **Shadow** toggles a box shadow behind the images.
|
||||
- **Border** sets the border size around images.
|
||||
- **Border color** sets the border color around images.
|
||||
- **Radius** sets the overall size of images in pixels.
|
||||
- **Display tooltip** allows you to toggle tooltips for the layer.
|
||||
|
||||
{{< figure src="/static/img/docs/geomap-panel/geomap-photos-options-9-3-0.png" max-width="1200px" caption="Geomap panel Photos options" >}}
|
||||
|
||||
### More information
|
||||
|
||||
- [**Extensions for OpenLayers - Image Photo Style**](http://viglino.github.io/ol-ext/examples/style/map.style.photo.html)
|
||||
|
||||
## Network layer (Beta)
|
||||
|
||||
{{% admonition type="caution" %}}
|
||||
The Network layer is currently in [public preview](/docs/release-life-cycle/). Grafana Labs offers limited support, and breaking changes might occur prior to the feature being made generally available.
|
||||
{{% /admonition %}}
|
||||
|
||||
The Network layer renders a network graph. This layer supports the same [data format supported by the node graph visualization](ref:data-format) with the addition of [geospatial data](#location-mode) included in the nodes data. The geospatial data is used to locate and render the nodes on the map.
|
||||
|
||||
{{< figure src="/media/docs/grafana/screenshot-grafana-10-1-geomap-network-layer-v2.png" max-width="750px" caption="Geomap network layer" >}}
|
||||
{{< video-embed src="/media/docs/grafana/screen-recording-10-1-geomap-network-layer-from-node-graph.mp4" max-width="750px" caption="Node graph to Geomap network layer" >}}
|
||||
|
||||
### Options
|
||||
|
||||
- **Data** and **Location mode** configure the data settings for the layer. For more information, refer to [Data](#data) and [Location mode](#location-mode).
|
||||
- **Arrow** sets the arrow direction to display for each edge, with forward meaning source to target. Choose from:
|
||||
- **None**
|
||||
- **Forward**
|
||||
- **Reverse**
|
||||
- **Both**
|
||||
- **Show legend** allows you to toggle the legend for the layer. **Note:** The legend currently only supports node data.
|
||||
- **Display tooltip** allows you to toggle tooltips for the layer.
|
||||
|
||||
#### Node styles
|
||||
|
||||
- **Size** configures the size of the nodes. The default is `Fixed size`, which makes all node sizes the same regardless of the data; however, there is also an option to size the nodes based on data corresponding to a selected field. `Min` and `Max` node sizes have to be set such that the nodes can scale within this range.
|
||||
- **Symbol** allows you to choose the symbol, icon, or graphic to aid in providing additional visual context to your data. Choose from assets that are included with Grafana such as simple symbols or the Unicon library. You can also specify a URL containing an image asset. The image must be a scalable vector graphic (SVG).
|
||||
- **Color** configures the color of the nodes. The default `Fixed color` sets all nodes to a specific color. There is also an option to have conditional colors depending on the selected field data point values and the color scheme set in the `Standard options` section.
|
||||
- **Fill opacity** configures the transparency of each node.
|
||||
- **Rotation angle** configures the rotation angle of each node. The default is `Fixed value`, which makes all nodes rotate to the same angle regardless of the data; however, there is also an option to set the rotation of the nodes based on data corresponding to a selected field.
|
||||
- **Text label** configures a text label for each node.
|
||||
|
||||
#### Edge styles
|
||||
|
||||
- **Size** configures the line width of the edges. The default is `Fixed size`, which makes all edge line widths the same regardless of the data; however, there is also an option to size the edges based on data corresponding to a selected field. `Min` and `Max` eges sizes have to be set such that the edges can scale within this range.
|
||||
- **Color** configures the color of the edges. The default `Fixed color` sets all edges to a specific color. There is also an option to have conditional colors depending on the selected field data point values and the color scheme set in the `Standard options` section.
|
||||
- **Fill opacity** configures the transparency of each edge.
|
||||
- **Text label** configures a text label for each edge.
|
||||
|
||||
## CARTO layer
|
||||
|
||||
A CARTO layer is from CARTO Raster basemaps.
|
||||
|
||||
### Options
|
||||
|
||||
- **Theme**
|
||||
- Auto
|
||||
- Light
|
||||
{{< figure src="/static/img/docs/geomap-panel/geomap-carto-light-9-1-0.png" max-width="1200px" caption="Geomap panel CARTO light example" >}}
|
||||
- Dark
|
||||
{{< figure src="/static/img/docs/geomap-panel/geomap-carto-dark-9-1-0.png" max-width="1200px" caption="Geomap panel CARTO dark example" >}}
|
||||
- **Show labels** shows the Country details on top of the map.
|
||||
- **Opacity** from 0 (transparent) to 1 (opaque)
|
||||
|
||||
{{< figure src="/static/img/docs/geomap-panel/geomap-carto-options-9-1-0.png" max-width="1200px" caption="Geomap panel CARTO options" >}}
|
||||
|
||||
### More Information
|
||||
|
||||
- [**About CARTO**](https://carto.com/about-us/)
|
||||
|
||||
## XYZ tile layer
|
||||
|
||||
The XYZ tile layer is a map from a generic tile layer.
|
||||
|
||||
{{< figure src="/static/img/docs/geomap-panel/geomap-xyz-9-1-0.png" max-width="1200px" caption="Geomap panel xyz example" >}}
|
||||
|
||||
### Options
|
||||
|
||||
- **URL template**
|
||||
|
||||
> **Note:** Set a valid tile server url, with {z}/{x}/{y} for example: https://tile.openstreetmap.org/{z}/{x}/{y}.png
|
||||
|
||||
- **Attribution** sets the reference string for the layer if displayed in [map controls](#show-attribution)
|
||||
- **Opacity** from 0 (transparent) to 1 (opaque)
|
||||
|
||||
{{< figure src="/static/img/docs/geomap-panel/geomap-xyz-options-9-1-0.png" max-width="1200px" caption="Geomap panel xyz options" >}}
|
||||
|
||||
### More information
|
||||
|
||||
- [**Tiled Web Map Wikipedia**](https://en.wikipedia.org/wiki/Tiled_web_map)
|
||||
- [**List of Open Street Map Tile Servers**](https://wiki.openstreetmap.org/wiki/Tile_servers)
|
||||
|
||||
## Open Street Map layer
|
||||
|
||||
A map from a collaborative free geographic world database.
|
||||
|
||||
{{< figure src="/static/img/docs/geomap-panel/geomap-osm-9-1-0.png" max-width="1200px" caption="Geomap panel Open Street Map" >}}
|
||||
|
||||
### Options
|
||||
|
||||
- **Opacity** from 0 (transparent) to 1 (opaque)
|
||||
|
||||
{{< figure src="/static/img/docs/geomap-panel/geomap-osm-options-9-1-0.png" max-width="1200px" caption="Geomap panel Open Street Map options" >}}
|
||||
|
||||
### More Information
|
||||
|
||||
- [**About Open Street Map**](https://www.openstreetmap.org/about)
|
||||
|
||||
## ArcGIS layer
|
||||
|
||||
An ArcGIS layer is a layer from an ESRI ArcGIS MapServer.
|
||||
|
||||
### Options
|
||||
|
||||
- **Server Instance** to select the map type.
|
||||
- World Street Map
|
||||
{{< figure src="/static/img/docs/geomap-panel/geomap-arcgis-wsm-9-1-0.png" max-width="1200px" caption="Geomap panel ArcGIS World Street Map" >}}
|
||||
- World Imagery
|
||||
{{< figure src="/static/img/docs/geomap-panel/geomap-arcgis-wi-9-1-0.png" max-width="1200px" caption="Geomap panel ArcGIS World Imagery" >}}
|
||||
- World Physical
|
||||
{{< figure src="/static/img/docs/geomap-panel/geomap-arcgis-wp-9-1-0.png" max-width="1200px" caption="Geomap panel ArcGIS World Physical" >}}
|
||||
- Topographic
|
||||
{{< figure src="/static/img/docs/geomap-panel/geomap-arcgis-topographic-9-1-0.png" max-width="1200px" caption="Geomap panel ArcGIS Topographic" >}}
|
||||
- USA Topographic
|
||||
{{< figure src="/static/img/docs/geomap-panel/geomap-arcgis-usa-topographic-9-1-0.png" max-width="1200px" caption="Geomap panel ArcGIS USA Topographic" >}}
|
||||
- World Ocean
|
||||
{{< figure src="/static/img/docs/geomap-panel/geomap-arcgis-ocean-9-1-0.png" max-width="1200px" caption="Geomap panel ArcGIS World Ocean" >}}
|
||||
- Custom MapServer (see [XYZ](#xyz-tile-layer) for formatting)
|
||||
- URL template
|
||||
- Attribution
|
||||
- **Opacity** from 0 (transparent) to 1 (opaque)
|
||||
|
||||
{{< figure src="/static/img/docs/geomap-panel/geomap-arcgis-options-9-1-0.png" max-width="1200px" caption="Geomap panel ArcGIS options" >}}
|
||||
|
||||
### More Information
|
||||
|
||||
- [**ArcGIS Services**](https://services.arcgisonline.com/arcgis/rest/services)
|
||||
- [**About ESRI**](https://www.esri.com/en-us/about/about-esri/overview)
|
||||
|
||||
## Map Controls
|
||||
### Map controls options
|
||||
|
||||
The map controls section contains various options for map information and tool overlays.
|
||||
{{< figure src="/static/img/docs/geomap-panel/geomap-map-controls-9-1-0.png" max-width="1200px" caption="Geomap panel map controls" >}}
|
||||
|
||||
### Zoom
|
||||
|
||||
This section describes each of the zoom controls.
|
||||
<!-- prettier-ignore-start -->
|
||||
| Option | Description |
|
||||
| ------ | ----------- |
|
||||
| [Show zoom control](#show-zoom-control) | Displays zoom controls in the upper left corner. |
|
||||
| [Mouse wheel zoom](#mouse-wheel-zoom) | Enables the mouse wheel to be used for zooming in or out. |
|
||||
| [Show attribution](#show-attribution) | Displays attribution for basemap layers. |
|
||||
| [Show scale](#show-scale) | Displays scale information in the bottom left corner in meters (m) or kilometers (km). |
|
||||
| [Show measure tools](#show-measure-tools) | Displays measure tools in the upper right corner. This includes the [Length](#length) and [Area](#area) options. |
|
||||
| [Show debug](#show-debug) | Displays debug information in the upper right corner. |
|
||||
| [Tooltip](#tooltip) | Controls display of tooltips. |
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
#### Show zoom control
|
||||
|
||||
Displays zoom controls in the upper left corner. This control can be useful when using systems that don't have a mouse.
|
||||
|
||||
{{< figure src="/static/img/docs/geomap-panel/geomap-map-controls-zoom-9-1-0.png" max-width="1200px" caption="Geomap panel zoom" >}}
|
||||
{{< figure src="/static/img/docs/geomap-panel/geomap-map-controls-zoom-9-1-0.png" max-width="1200px" alt="Geomap panel zoom" >}}
|
||||
|
||||
#### Mouse wheel zoom
|
||||
|
||||
Enables the mouse wheel to be used for zooming in or out.
|
||||
|
||||
### Show attribution
|
||||
#### Show attribution
|
||||
|
||||
Displays attribution for basemap layers.
|
||||
|
||||
{{< figure src="/static/img/docs/geomap-panel/geomap-map-controls-attribution-9-1-0.png" max-width="1200px" caption="Geomap panel attribution" >}}
|
||||
{{< figure src="/static/img/docs/geomap-panel/geomap-map-controls-attribution-9-1-0.png" max-width="1200px" alt="Geomap panel attribution" >}}
|
||||
|
||||
### Show scale
|
||||
#### Show scale
|
||||
|
||||
Displays scale information in the bottom left corner.
|
||||
Displays scale information in the bottom left corner in meters (m) or kilometers (km).
|
||||
|
||||
{{< figure src="/static/img/docs/geomap-panel/geomap-map-controls-scale-9-1-0.png" max-width="1200px" caption="Geomap panel scale" >}}
|
||||
{{< figure src="/static/img/docs/geomap-panel/geomap-map-controls-scale-9-1-0.png" max-width="1200px" alt="Geomap panel scale" >}}
|
||||
|
||||
{{% admonition type="note" %}}
|
||||
Currently only displays units in [m]/[km].
|
||||
{{% /admonition %}}
|
||||
|
||||
### Show measure tools
|
||||
#### Show measure tools
|
||||
|
||||
Displays measure tools in the upper right corner. Measurements appear only when this control is open.
|
||||
|
||||
{{< figure src="/static/img/docs/geomap-panel/geomap-map-controls-measure-9-1-0.png" max-width="1200px" caption="Geomap panel measure" >}}
|
||||
{{< figure src="/static/img/docs/geomap-panel/geomap-map-controls-measure-9-1-0.png" max-width="1200px" alt="Geomap panel measure" >}}
|
||||
|
||||
- **Click** to start measuring
|
||||
- **Continue clicking** to continue measurement
|
||||
- **Double-click** to end measurement
|
||||
|
||||
{{% admonition type="note" %}}
|
||||
When you change measurement type or units, the previous measurement is removed from the map. If the control is closed and then re-opened, the most recent measurement is displayed. A measurement can be modified by clicking and dragging on it.
|
||||
{{% /admonition %}}
|
||||
|
||||
#### Length
|
||||
##### Length
|
||||
|
||||
Get the spherical length of a geometry. This length is the sum of the great circle distances between coordinates. For multi-part geometries, the length is the sum of the length of each part. Geometries are assumed to be in 'EPSG:3857'.
|
||||
|
||||
@@ -687,9 +678,9 @@ Get the spherical length of a geometry. This length is the sum of the great circ
|
||||
- **Miles (mi)**
|
||||
- **Nautical miles (nmi)**
|
||||
|
||||
{{< figure src="/static/img/docs/geomap-panel/geomap-map-controls-measure-length-9-1-0.png" max-width="1200px" caption="Geomap panel measure length" >}}
|
||||
{{< figure src="/static/img/docs/geomap-panel/geomap-map-controls-measure-length-9-1-0.png" max-width="1200px" alt="Geomap panel measure length" >}}
|
||||
|
||||
#### Area
|
||||
##### Area
|
||||
|
||||
Get the spherical area of a geometry. This area is calculated assuming that polygon edges are segments of great circles on a sphere. Geometries are assumed to be in 'EPSG:3857'.
|
||||
|
||||
@@ -700,38 +691,38 @@ Get the spherical area of a geometry. This area is calculated assuming that poly
|
||||
- **Acres (acre)**
|
||||
- **Hectare (ha)**
|
||||
|
||||
{{< figure src="/static/img/docs/geomap-panel/geomap-map-controls-measure-area-9-1-0.png" max-width="1200px" caption="Geomap panel measure area" >}}
|
||||
{{< figure src="/static/img/docs/geomap-panel/geomap-map-controls-measure-area-9-1-0.png" max-width="1200px" alt="Geomap panel measure area" >}}
|
||||
|
||||
### Show debug
|
||||
#### Show debug
|
||||
|
||||
Displays debug information in the upper right corner. This can be useful for debugging or validating a data source.
|
||||
|
||||
- **Zoom** displays current zoom level of the map.
|
||||
- **Center** displays the current **longitude**, **latitude** of the map center.
|
||||
|
||||
{{< figure src="/static/img/docs/geomap-panel/geomap-map-controls-debug-9-1-0.png" max-width="1200px" caption="Geomap panel debug" >}}
|
||||
{{< figure src="/static/img/docs/geomap-panel/geomap-map-controls-debug-9-1-0.png" max-width="1200px" alt="Geomap panel debug" >}}
|
||||
|
||||
### Tooltip
|
||||
#### Tooltip
|
||||
|
||||
- **None** displays tooltips only when a data point is clicked.
|
||||
- **Details** displays tooltips when a mouse pointer hovers over a data point.
|
||||
|
||||
## Standard options
|
||||
### Standard options
|
||||
|
||||
{{< docs/shared lookup="visualizations/standard-options.md" source="grafana" version="<GRAFANA_VERSION>" >}}
|
||||
|
||||
## Data links
|
||||
### Data links
|
||||
|
||||
{{< docs/shared lookup="visualizations/datalink-options.md" source="grafana" version="<GRAFANA_VERSION>" >}}
|
||||
|
||||
## Value mappings
|
||||
### Value mappings
|
||||
|
||||
{{< docs/shared lookup="visualizations/value-mappings-options.md" source="grafana" version="<GRAFANA_VERSION>" >}}
|
||||
|
||||
## Thresholds
|
||||
### Thresholds
|
||||
|
||||
{{< docs/shared lookup="visualizations/thresholds-options-2.md" source="grafana" version="<GRAFANA_VERSION>" >}}
|
||||
|
||||
## Field overrides
|
||||
### Field overrides
|
||||
|
||||
{{< docs/shared lookup="visualizations/overrides-options.md" source="grafana" version="<GRAFANA_VERSION>" >}}
|
||||
|
||||
@@ -127,183 +127,22 @@ The table visualization helps with debugging when you need to know exactly what
|
||||
|
||||

|
||||
|
||||
## Sort column
|
||||
|
||||
Click a column title to change the sort order from default to descending to ascending. Each time you click, the sort order changes to the next option in the cycle. You can sort multiple columns by holding the `shift` key and clicking the column name.
|
||||
|
||||

|
||||
|
||||
## Data set selector
|
||||
|
||||
If the data queried contains multiple data sets, a table displays a drop-down list at the bottom, so you can select the data set you want to visualize.
|
||||
|
||||

|
||||
|
||||
## Panel options
|
||||
|
||||
{{< docs/shared lookup="visualizations/panel-options.md" source="grafana" version="<GRAFANA_VERSION>" >}}
|
||||
|
||||
## Table options
|
||||
|
||||
{{% admonition type="note" %}}
|
||||
If you are using a table created before Grafana 7.0, then you need to migrate to the new table version in order to see these options. To migrate, on the Panel tab, click **Table** visualization. Grafana updates the table version and you can then access all table options.
|
||||
{{% /admonition %}}
|
||||
|
||||
### Show header
|
||||
|
||||
Show or hide column names imported from your data source.
|
||||
|
||||
## Column width
|
||||
|
||||
By default, Grafana automatically calculates the column width based on the table size and the minimum column width. This field option can override the setting and define the width for all columns in pixels.
|
||||
|
||||
For example, if you enter `100` in the field, then when you click outside the field, all the columns will be set to 100 pixels wide.
|
||||
|
||||
## Minimum column width
|
||||
|
||||
By default, the minimum width of the table column is 150 pixels. This field option can override that default and will define the new minimum column width for the table in pixels.
|
||||
|
||||
For example, if you enter `75` in the field, then when you click outside the field, all the columns will scale to no smaller than 75 pixels wide.
|
||||
|
||||
For small-screen devices, such as smartphones or tablets, reduce the default `150` pixel value to`50` to allow table-based panels to render correctly in dashboards.
|
||||
|
||||
## Column alignment
|
||||
|
||||
Choose how Grafana should align cell contents:
|
||||
|
||||
- Auto (default)
|
||||
- Left
|
||||
- Center
|
||||
- Right
|
||||
|
||||
## Cell type
|
||||
|
||||
By default, Grafana automatically chooses display settings. You can override the settings by choosing one of the following options to set the default for all fields. Additional configuration is available for some cell types.
|
||||
|
||||
{{% admonition type="note" %}}
|
||||
If you set these in the Field tab, then the type will apply to all fields, including the time field. Many options will work best if you set them in the Override tab so that they can be restricted to one or more fields.
|
||||
{{% /admonition %}}
|
||||
|
||||
### Color text
|
||||
|
||||
If thresholds are set, then the field text is displayed in the appropriate threshold color.
|
||||
|
||||
{{< figure src="/static/img/docs/tables/color-text.png" max-width="500px" caption="Color text" class="docs-image--no-shadow" >}}
|
||||
|
||||
### Color background (gradient or solid)
|
||||
|
||||
If thresholds are set, then the field background is displayed in the appropriate threshold color.
|
||||
|
||||
{{< figure src="/static/img/docs/tables/color-background.png" max-width="500px" caption="Color background" class="docs-image--no-shadow" >}}
|
||||
|
||||
Toggle the **Apply to entire row** switch, to apply the background color that's configured for the cell to the whole row.
|
||||
|
||||
{{< figure src="/static/img/docs/tables/colored-rows.png" max-width="500px" alt="Colored row background" class="docs-image--no-shadow" >}}
|
||||
|
||||
### Gauge
|
||||
|
||||
Cells can be displayed as a graphical gauge, with several different presentation types.
|
||||
|
||||
{{< admonition type="note" >}}
|
||||
The maximum and minimum values of the gauges are configured automatically from the smallest and largest values in your whole data set. If you don't want the max/min values to be pulled from the whole data set, you can configure them for each column with field overrides.
|
||||
{{< /admonition >}}
|
||||
|
||||
##### Basic
|
||||
|
||||
The basic mode will show a simple gauge with the threshold levels defining the color of gauge.
|
||||
|
||||
{{< figure src="/static/img/docs/tables/basic-gauge.png" max-width="500px" caption="Gradient gauge" class="docs-image--no-shadow" >}}
|
||||
|
||||
#### Gradient
|
||||
|
||||
The threshold levels define a gradient.
|
||||
|
||||
{{< figure src="/static/img/docs/tables/gradient-gauge.png" max-width="500px" caption="Gradient gauge" class="docs-image--no-shadow" >}}
|
||||
|
||||
#### LCD
|
||||
|
||||
The gauge is split up in small cells that are lit or unlit.
|
||||
|
||||
{{< figure src="/static/img/docs/tables/lcd-gauge.png" max-width="500px" caption="LCD gauge" class="docs-image--no-shadow" >}}
|
||||
|
||||
#### Label Options
|
||||
|
||||
Additionally, labels displayed alongside of the gauges can be set to be colored by value, match the theme text color, or be hidden.
|
||||
|
||||
**Value Color**
|
||||
|
||||
{{< figure src="/static/img/docs/tables/value-color-mode.png" max-width="500px" caption="Color Label by Value" class="docs-image--no-shadow" >}}
|
||||
|
||||
**Text Color**
|
||||
|
||||
{{< figure src="/static/img/docs/tables/text-color-mode.png" max-width="500px" caption="Color Label by theme color" class="docs-image--no-shadow" >}}
|
||||
|
||||
**Hidden**
|
||||
|
||||
{{< figure src="/static/img/docs/tables/hidden-mode.png" max-width="500px" caption="Hide Label" class="docs-image--no-shadow" >}}
|
||||
|
||||
### Data links
|
||||
|
||||
If you've configured data links, when the cell type is **Auto** mode, the cell text becomes clickable. If you change the cell type to **Data links**, the cell text reflects the titles of the configured data links. To control the application of data link text more granularly use a **Cell option > Cell type > Data links** field override.
|
||||
|
||||
### JSON view
|
||||
|
||||
Shows value formatted as code. If a value is an object the JSON view allowing browsing the JSON object will appear on hover.
|
||||
|
||||
{{< figure src="/static/img/docs/tables/json-view.png" max-width="500px" caption="JSON view" class="docs-image--no-shadow" >}}
|
||||
|
||||
### Image
|
||||
|
||||
> Only available in Grafana 7.3+
|
||||
|
||||
If you have a field value that is an image URL or a base64 encoded image you can configure the table to display it as an image.
|
||||
|
||||
{{< figure src="/static/img/docs/v73/table_hover.gif" max-width="900px" caption="Table hover" >}}
|
||||
|
||||
### Sparkline
|
||||
|
||||
Shows values rendered as a sparkline. You can show sparklines using the [Time series to table transformation](ref:time-series-to-table-transformation) on data with multiple time series to process it into a format the table can show.
|
||||
|
||||
{{< figure src="/static/img/docs/tables/sparkline2.png" max-width="500px" caption="Sparkline" class="docs-image--no-shadow" >}}
|
||||
|
||||
You can be customize sparklines with many of the same options as the [Time series panel](ref:time-series-panel) including line width, fill opacity, and more. You can also change the color of the sparkline by updating the [color scheme](ref:color-scheme) in the _Standard options_ section of the panel configuration.
|
||||
|
||||
## Cell value inspect
|
||||
|
||||
Enables value inspection from table cell. The raw value is presented in a modal window.
|
||||
|
||||
{{% admonition type="note" %}}
|
||||
Cell value inspection is only available when cell display mode is set to Auto, Color text, Color background or JSON View.
|
||||
{{% /admonition %}}
|
||||
|
||||
## Column filter
|
||||
|
||||
You can temporarily change how column data is displayed. For example, you can order values from highest to lowest or hide specific values. For more information, refer to [Filter table columns](#filter-table-columns).
|
||||
|
||||
## Pagination
|
||||
|
||||
Use this option to enable or disable pagination. It is a front-end option that does not affect queries. When enabled, the page size automatically adjusts to the height of the table.
|
||||
|
||||
## Filter table columns
|
||||
|
||||
If you turn on the **Column filter**, then you can filter table options.
|
||||
|
||||
### Turn on column filtering
|
||||
## Turn on column filtering
|
||||
|
||||
1. In Grafana, navigate to the dashboard with the table with the columns that you want to filter.
|
||||
1. On the table panel you want to filter, open the panel editor.
|
||||
1. Click the **Field** tab.
|
||||
1. In Table options, turn on the **Column filter** option.
|
||||
1. Expand the the **Table** options section.
|
||||
1. Toggle on the [**Column filter** switch](#table-options).
|
||||
|
||||
A filter icon appears next to each column title.
|
||||
|
||||
{{< figure src="/static/img/docs/tables/column-filter-with-icon.png" max-width="500px" caption="Column filtering turned on" class="docs-image--no-shadow" >}}
|
||||
{{< figure src="/static/img/docs/tables/column-filter-with-icon.png" max-width="350px" alt="Column filtering turned on" class="docs-image--no-shadow" >}}
|
||||
|
||||
### Filter column values
|
||||
|
||||
To filter column values, click the filter (funnel) icon next to a column title. Grafana displays the filter options for that column.
|
||||
|
||||
{{< figure src="/static/img/docs/tables/filter-column-values.png" max-width="500px" caption="Filter column values" class="docs-image--no-shadow" >}}
|
||||
{{< figure src="/static/img/docs/tables/filter-column-values.png" max-width="300px" alt="Filter column values" class="docs-image--no-shadow" >}}
|
||||
|
||||
Click the check box next to the values that you want to display. Enter text in the search field at the top to show those values in the display so that you can select them rather than scroll to find them.
|
||||
|
||||
@@ -319,41 +158,202 @@ Click the check box above the **Ok** and **Cancel** buttons to add or remove all
|
||||
|
||||
Columns with filters applied have a blue funnel displayed next to the title.
|
||||
|
||||
{{< figure src="/static/img/docs/tables/filtered-column.png" max-width="500px" caption="Filtered column" class="docs-image--no-shadow" >}}
|
||||
{{< figure src="/static/img/docs/tables/filtered-column.png" max-width="100px" alt="Filtered column" class="docs-image--no-shadow" >}}
|
||||
|
||||
To remove the filter, click the blue funnel icon and then click **Clear filter**.
|
||||
|
||||
## Table footer
|
||||
## Sort columns
|
||||
|
||||
You can use the table footer to show [calculations](ref:calculations) on fields.
|
||||
Click a column title to change the sort order from default to descending to ascending. Each time you click, the sort order changes to the next option in the cycle. You can sort multiple columns by holding the `shift` key and clicking the column name.
|
||||
|
||||
After you enable the table footer:
|
||||
{{< figure src="/static/img/docs/tables/sort-descending.png" max-width="350px" alt="Sort descending" class="docs-image--no-shadow" >}}
|
||||
|
||||
1. Select the **Calculation**
|
||||
2. Select the **Fields** that you want to calculate
|
||||
## Dataset selector
|
||||
|
||||
The system applies the calculation to all numeric fields if you do not select a field.
|
||||
If the data queried contains multiple datasets, a table displays a drop-down list at the bottom, so you can select the dataset you want to visualize.
|
||||
|
||||
### Count rows
|
||||
{{< figure src="/media/docs/grafana/panels-visualizations/TablePanelMultiSet.png" max-width="650px" alt="Table visualization with multiple datasets" class="docs-image--no-shadow" >}}
|
||||
|
||||
If you want to show the number of rows in the dataset instead of the number of values in the selected fields, select the **Count** calculation and enable **Count rows**.
|
||||
## Configuration options
|
||||
|
||||
## Standard options
|
||||
### Panel options
|
||||
|
||||
{{< docs/shared lookup="visualizations/panel-options.md" source="grafana" version="<GRAFANA_VERSION>" >}}
|
||||
|
||||
### Table options
|
||||
|
||||
{{% admonition type="note" %}}
|
||||
If you are using a table created before Grafana 7.0, then you need to migrate to the new table version in order to see these options. To migrate, on the Panel tab, click **Table** visualization. Grafana updates the table version and you can then access all table options.
|
||||
{{% /admonition %}}
|
||||
|
||||
| Option | Description |
|
||||
| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Show table header | Show or hide column names imported from your data source. |
|
||||
| Cell height | Set the height of the cell. Choose from **Small**, **Medium**, and **Large**. |
|
||||
| Enable pagination | Toggle the switch to control how many table rows are visible at once. When switched on, the page size automatically adjusts to the height of the table. This option doesn't affect queries. |
|
||||
| Minimum column width | Define the lower limit of the column width, in pixels. By default, the minimum width of the table column is 150 pixels. For small-screen devices, such as smartphones or tablets, reduce the default `150` pixel value to `50` to allow table-based panels to render correctly in dashboards. |
|
||||
| Column width | Define a column width, in pixels, rather than allowing the width to be set automatically. By default, Grafana calculates the column width based on the table size and the minimum column width. |
|
||||
| Column alignment | Set how Grafana should align cell contents. Choose from: **Auto** (default), **Left**, **Center**, and **Right**. |
|
||||
| Column filter | Temporarily change how column data is displayed. For example, you can order values from highest to lowest or hide specific values. For more information, refer to [Filter table columns](#filter-table-columns). |
|
||||
|
||||
### Table footer options
|
||||
|
||||
Toggle the **Show table footer** switch on and off to control the display of the footer. When the toggle is switched on, you can use the table footer to show [calculations](ref:calculations) on fields.
|
||||
|
||||
After you activate the table footer, make selections in the following options:
|
||||
|
||||
- **Calculation** - The calculation that you want to apply.
|
||||
- **Fields** - The fields to which you want to apply the calculations. The system applies the calculation to all numeric fields if you do not select a field.
|
||||
- **Count rows** - This options is displayed if you select the **Count** calculation. If you want to show the number of rows in the dataset instead of the number of values in the selected fields, toggle on the **Count rows** switch.
|
||||
|
||||
### Cell options
|
||||
|
||||
Cell options allow you to control how data is displayed in a table.
|
||||
|
||||
#### Cell type
|
||||
|
||||
By default, Grafana automatically chooses display settings. You can override the settings by choosing one of the following options to set the default for all fields. Additional configuration is available for some cell types.
|
||||
|
||||
{{% admonition type="note" %}}
|
||||
If you set these in the Field tab, then the type will apply to all fields, including the time field. Many options will work best if you set them in the Override tab so that they can be restricted to one or more fields.
|
||||
{{% /admonition %}}
|
||||
|
||||
| Cell type | Description |
|
||||
| ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Auto | The **Auto** cell type automatically displays values, with sensible defaults applied. |
|
||||
| [Sparkline](#sparkline) | Shows values rendered as a sparkline. |
|
||||
| [Colored text](#colored-text) | If thresholds are set, then the field text is displayed in the appropriate threshold color. |
|
||||
| [Colored background](#colored-background) | If thresholds are set, then the field background is displayed in the appropriate threshold color. |
|
||||
| [Gauge](#gauge) | Cells can be displayed as a graphical gauge, with several different presentation types. You can set the [Gauge display mode](#gauge-display-mode) and the [Value display](#value-display) options. |
|
||||
| Data links | If you've configured data links, when the cell type is **Auto** mode, the cell text becomes clickable. If you change the cell type to **Data links**, the cell text reflects the titles of the configured data links. To control the application of data link text more granularly use a **Cell option > Cell type > Data links** field override. |
|
||||
| [JSON View](#json-view) | Shows value formatted as code. |
|
||||
| [Image](#image) | If you have a field value that is an image URL or a base64 encoded image you can configure the table to display it as an image. |
|
||||
|
||||
##### Sparkline
|
||||
|
||||
Shows values rendered as a sparkline. You can show sparklines using the [Time series to table transformation](ref:time-series-to-table-transformation) on data with multiple time series to process it into a format the table can show.
|
||||
|
||||
{{< figure src="/static/img/docs/tables/sparkline2.png" max-width="500px" alt="Sparkline" class="docs-image--no-shadow" >}}
|
||||
|
||||
You can customize sparklines with many of the same options as the [time series visualization](ref:time-series-panel) including line style and width, fill opacity, gradient mode, and more. You can also change the color of the sparkline by updating the [color scheme](ref:color-scheme) in the **Standard options** section of the panel configuration.
|
||||
|
||||
##### Colored text
|
||||
|
||||
If thresholds are set, then the field text is displayed in the appropriate threshold color.
|
||||
|
||||
{{< figure src="/static/img/docs/tables/color-text.png" max-width="500px" alt="Color text" class="docs-image--no-shadow" >}}
|
||||
|
||||
{{< admonition type="note" >}}
|
||||
This is an experimental feature.
|
||||
{{< /admonition >}}
|
||||
|
||||
##### Colored background
|
||||
|
||||
If thresholds are set, then the field background is displayed in the appropriate threshold color.
|
||||
|
||||
{{< figure src="/static/img/docs/tables/color-background.png" max-width="500px" alt="Color background" class="docs-image--no-shadow" >}}
|
||||
|
||||
Choose between **Basic** and **Gradient** to set the **Background display mode**.
|
||||
|
||||
Toggle the **Apply to entire row** switch, to apply the background color that's configured for the cell to the whole row.
|
||||
|
||||
{{< figure src="/static/img/docs/tables/colored-rows.png" max-width="500px" alt="Colored row background" class="docs-image--no-shadow" >}}
|
||||
|
||||
##### Gauge
|
||||
|
||||
Cells can be displayed as a graphical gauge, with several different presentation types controlled by the gauge display mode and the value display.
|
||||
|
||||
{{< admonition type="note" >}}
|
||||
The maximum and minimum values of the gauges are configured automatically from the smallest and largest values in your whole data set. If you don't want the max/min values to be pulled from the whole data set, you can configure them for each column with field overrides.
|
||||
{{< /admonition >}}
|
||||
|
||||
###### Gauge display mode
|
||||
|
||||
You can set three gauge display modes.
|
||||
|
||||
- **Basic** - Shows a simple gauge with the threshold levels defining the color of gauge.
|
||||
|
||||
{{< figure src="/static/img/docs/tables/basic-gauge.png" max-width="500px" alt="Gradient gauge" class="docs-image--no-shadow" >}}
|
||||
|
||||
- **Gradient** - The threshold levels define a gradient.
|
||||
|
||||
{{< figure src="/static/img/docs/tables/gradient-gauge.png" max-width="500px" alt="Gradient gauge" class="docs-image--no-shadow" >}}
|
||||
|
||||
- **Retro LCD** - The gauge is split up in small cells that are lit or unlit.
|
||||
|
||||
{{< figure src="/static/img/docs/tables/lcd-gauge.png" max-width="500px" alt="LCD gauge" class="docs-image--no-shadow" >}}
|
||||
|
||||
###### Value display
|
||||
|
||||
Labels displayed alongside of the gauges can be set to be colored by value, match the theme text color, or be hidden.
|
||||
|
||||
- **Value color**
|
||||
|
||||
{{< figure src="/static/img/docs/tables/value-color-mode.png" max-width="500px" alt="Color Label by Value" class="docs-image--no-shadow" >}}
|
||||
|
||||
- **Text color**
|
||||
|
||||
{{< figure src="/static/img/docs/tables/text-color-mode.png" max-width="500px" alt="Color Label by theme color" class="docs-image--no-shadow" >}}
|
||||
|
||||
- **Hidden**
|
||||
|
||||
{{< figure src="/static/img/docs/tables/hidden-mode.png" max-width="500px" alt="Hide Label" class="docs-image--no-shadow" >}}
|
||||
|
||||
##### JSON View
|
||||
|
||||
Shows value formatted as code. If a value is an object the JSON view allowing browsing the JSON object will appear on hover.
|
||||
|
||||
{{< figure src="/static/img/docs/tables/json-view.png" max-width="350px" alt="JSON view" class="docs-image--no-shadow" >}}
|
||||
|
||||
##### Image
|
||||
|
||||
{{< admonition type="note" >}}
|
||||
Only available in Grafana 7.3+
|
||||
{{< /admonition >}}
|
||||
|
||||
If you have a field value that is an image URL or a base64 encoded image you can configure the table to display it as an image.
|
||||
|
||||
{{< figure src="/static/img/docs/v73/table_hover.gif" max-width="900px" alt="Table hover" >}}
|
||||
|
||||
- **Alt text** - Set the alternative text of an image. The text will be available for screen readers and in cases when images can't be loaded.
|
||||
- **Title text** - Set the text that's displayed when the image is hovered over with a cursor.
|
||||
|
||||
#### Wrap text
|
||||
|
||||
{{< admonition type="note" >}}
|
||||
Text wrapping is in [public preview](https://grafana.com/docs/release-life-cycle/#public-preview), however, it’s available to use by default. We’d love hear from you about how this new feature is working. To provide feedback, you can open an issue in the [Grafana GitHub repository](https://github.com/grafana/grafana).
|
||||
{{< /admonition >}}
|
||||
|
||||
Toggle the **Wrap text** switch to wrap text in the cell with the longest content in your table. To wrap the text in a specific column only, use the Wrap Text option in a [field override](ref:field-override).
|
||||
|
||||
This option isn't available when you set the cell type to **Gauge** or Data links,JSON View, Image.
|
||||
|
||||
#### Cell value inspect
|
||||
|
||||
Enables value inspection from table cells. When the **Cell inspect value** switch is toggled on, clicking the inspect icon in a cell opens the **Inspect value** drawer.
|
||||
|
||||
The **Inspect value** drawer has two tabs, **Plain text** and **Code editor**. Grafana attempts to automatically detect the type of data in the cell and opens the drawer with the associated tab showing. However, you can switch back and forth between tabs.
|
||||
|
||||
Cell value inspection is only available when the **Cell type** selection is **Auto**, **Colored text**, **Colored background**, or **JSON View**.
|
||||
|
||||
This option isn't available when you set the cell type to **Gauge** or Data links, Image, .
|
||||
|
||||
### Standard options
|
||||
|
||||
{{< docs/shared lookup="visualizations/standard-options.md" source="grafana" version="<GRAFANA_VERSION>" >}}
|
||||
|
||||
## Data links
|
||||
### Data links
|
||||
|
||||
{{< docs/shared lookup="visualizations/datalink-options.md" source="grafana" version="<GRAFANA_VERSION>" >}}
|
||||
|
||||
## Value mappings
|
||||
### Value mappings
|
||||
|
||||
{{< docs/shared lookup="visualizations/value-mappings-options.md" source="grafana" version="<GRAFANA_VERSION>" >}}
|
||||
|
||||
## Thresholds
|
||||
### Thresholds
|
||||
|
||||
{{< docs/shared lookup="visualizations/thresholds-options-2.md" source="grafana" version="<GRAFANA_VERSION>" >}}
|
||||
|
||||
## Field overrides
|
||||
### Field overrides
|
||||
|
||||
{{< docs/shared lookup="visualizations/overrides-options.md" source="grafana" version="<GRAFANA_VERSION>" >}}
|
||||
|
||||
+6
-6
@@ -154,13 +154,13 @@ Grafana supports user authentication through Okta, which is useful when you want
|
||||
- In the **Single sign on URL** field, use the `/saml/acs` endpoint URL of your Grafana instance, for example, `https://grafana.example.com/saml/acs`.
|
||||
- In the **Audience URI (SP Entity ID)** field, use the `/saml/metadata` endpoint URL, for example, `https://grafana.example.com/saml/metadata`.
|
||||
- Leave the default values for **Name ID format** and **Application username**.
|
||||
- In the **ATTRIBUTE STATEMENTS (OPTIONAL)** section, enter the SAML attributes to be shared with Grafana, for example:
|
||||
- In the **ATTRIBUTE STATEMENTS (OPTIONAL)** section, enter the SAML attributes to be shared with Grafana. The attribute names in Okta need to match exactly what is defined within Grafana, for example:
|
||||
|
||||
| Attribute name (in Grafana) | Value (in Okta profile) |
|
||||
| --------------------------- | -------------------------------------- |
|
||||
| Login | `user.login` |
|
||||
| Email | `user.email` |
|
||||
| DisplayName | `user.firstName + " " + user.lastName` |
|
||||
| Attribute name (in Grafana) | Name and value (in Okta profile) |
|
||||
| --------------------------- | -------------------------------------------------- |
|
||||
| Login | Login `user.login` |
|
||||
| Email | Email `user.email` |
|
||||
| DisplayName | DisplayName `user.firstName + " " + user.lastName` |
|
||||
|
||||
- In the **GROUP ATTRIBUTE STATEMENTS (OPTIONAL)** section, enter a group attribute name (for example, `Group`) and set filter to `Matches regex .*` to return all user groups.
|
||||
|
||||
|
||||
@@ -97,6 +97,14 @@ On a minimal CentOS 8 installation, the following dependencies are required for
|
||||
libXcomposite libXdamage libXtst cups libXScrnSaver pango atk adwaita-cursor-theme adwaita-icon-theme at at-spi2-atk at-spi2-core cairo-gobject colord-libs dconf desktop-file-utils ed emacs-filesystem gdk-pixbuf2 glib-networking gnutls gsettings-desktop-schemas gtk-update-icon-cache gtk3 hicolor-icon-theme jasper-libs json-glib libappindicator-gtk3 libdbusmenu libdbusmenu-gtk3 libepoxy liberation-fonts liberation-narrow-fonts liberation-sans-fonts liberation-serif-fonts libgusb libindicator-gtk3 libmodman libproxy libsoup libwayland-cursor libwayland-egl libxkbcommon m4 mailx nettle patch psmisc redhat-lsb-core redhat-lsb-submod-security rest spax time trousers xdg-utils xkeyboard-config alsa-lib libX11-xcb
|
||||
```
|
||||
|
||||
**RHEL:**
|
||||
|
||||
On a minimal RHEL 8 installation, the following dependencies are required for the image rendering to function:
|
||||
|
||||
```bash
|
||||
linux-vdso.so.1 libdl.so.2 libpthread.so.0 libgobject-2.0.so.0 libglib-2.0.so.0 libnss3.so libnssutil3.so libsmime3.so libnspr4.so libatk-1.0.so.0 libatk-bridge-2.0.so.0 libcups.so.2 libgio-2.0.so.0 libdrm.so.2 libdbus-1.so.3 libexpat.so.1 libxcb.so.1 libxkbcommon.so.0 libm.so.6 libX11.so.6 libXcomposite.so.1 libXdamage.so.1 libXext.so.6 libXfixes.so.3 libXrandr.so.2 libgbm.so.1 libpango-1.0.so.0 libcairo.so.2 libasound.so.2 libatspi.so.0 libgcc_s.so.1 libc.so.6 /lib64/ld-linux-x86-64.so.2 libgnutls.so.30 libpcre.so.1 libffi.so.6 libplc4.so libplds4.so librt.so.1 libgmodule-2.0.so.0 libgssapi_krb5.so.2 libkrb5.so.3 libk5crypto.so.3 libcom_err.so.2 libavahi-common.so.3 libavahi-client.so.3 libcrypt.so.1 libz.so.1 libselinux.so.1 libresolv.so.2 libmount.so.1 libsystemd.so.0 libXau.so.6 libXrender.so.1 libthai.so.0 libfribidi.so.0 libpixman-1.so.0 libfontconfig.so.1 libpng16.so.16 libxcb-render.so.0 libidn2.so.0 libunistring.so.2 libtasn1.so.6 libnettle.so.6 libhogweed.so.4 libgmp.so.10 libkrb5support.so.0 libkeyutils.so.1 libpcre2-8.so.0 libuuid.so.1 liblz4.so.1 libgcrypt.so.20 libbz2.so.1
|
||||
```
|
||||
|
||||
## Certificate signed by internal certificate authorities
|
||||
|
||||
In many cases, Grafana runs on internal servers and uses certificates that have not been signed by a CA ([Certificate Authority](https://en.wikipedia.org/wiki/Certificate_authority)) known to Chrome, and therefore cannot be validated. Chrome internally uses NSS ([Network Security Services](https://en.wikipedia.org/wiki/Network_Security_Services)) for cryptographic operations such as the validation of certificates.
|
||||
|
||||
@@ -61,7 +61,7 @@ Grafana requires a database to store its configuration data, such as users, data
|
||||
Grafana supports the following databases:
|
||||
|
||||
- [SQLite 3](https://www.sqlite.org/index.html)
|
||||
- [MySQL 5.7+](https://www.mysql.com/support/supportedplatforms/database.html)
|
||||
- [MySQL 8.0+](https://www.mysql.com/support/supportedplatforms/database.html)
|
||||
- [PostgreSQL 12+](https://www.postgresql.org/support/versioning/)
|
||||
|
||||
By default Grafana uses an embedded SQLite database, which is stored in the Grafana installation location.
|
||||
|
||||
@@ -1448,9 +1448,9 @@ Status: Accepted
|
||||
|
||||
### <span id="duration"></span> Duration
|
||||
|
||||
| Name | Type | Go type | Default | Description | Example |
|
||||
| -------- | ------------------------- | ------- | ------- | ----------- | ------- |
|
||||
| Duration | int64 (formatted integer) | int64 | | | |
|
||||
| Name | Type | Go type | Default | Description | Example |
|
||||
| -------- | ------ | ------- | ------- | ----------- | ------- |
|
||||
| Duration | string | int64 | | | |
|
||||
|
||||
### <span id="embedded-contact-point"></span> EmbeddedContactPoint
|
||||
|
||||
|
||||
@@ -8,11 +8,11 @@ comments: |
|
||||
|
||||
A threshold is a value or limit you set for a metric that’s reflected visually when it’s met or exceeded. Thresholds are one way you can conditionally style and color your visualizations based on query results.
|
||||
|
||||
Set the following options:
|
||||
For each threshold, set the following options:
|
||||
|
||||
- **Value** - Set the value for each threshold.
|
||||
- **Thresholds mode** - Choose from:
|
||||
- **Absolute**
|
||||
- **Percentage**
|
||||
| Option | Description |
|
||||
| --------------- | -------------------------------------------- |
|
||||
| Value | Set the value for each threshold. |
|
||||
| Thresholds mode | Choose from **Absolute** and **Percentage**. |
|
||||
|
||||
To learn more, refer to [Configure thresholds](../../configure-thresholds/).
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
module github.com/grafana/grafana
|
||||
|
||||
go 1.22
|
||||
|
||||
toolchain go1.22.4
|
||||
go 1.22.7
|
||||
|
||||
// Override docker/docker to avoid:
|
||||
// go: github.com/drone-runners/drone-runner-docker@v1.8.2 requires
|
||||
@@ -83,7 +81,6 @@ require (
|
||||
github.com/redis/go-redis/v9 v9.1.0 // @grafana/alerting-squad-backend
|
||||
github.com/robfig/cron/v3 v3.0.1 // @grafana/grafana-backend-group
|
||||
github.com/russellhaering/goxmldsig v1.4.0 // @grafana/grafana-backend-group
|
||||
github.com/scottlepp/go-duck v0.0.20 // @grafana/grafana-app-platform-squad
|
||||
github.com/spf13/cobra v1.8.0 // @grafana/grafana-app-platform-squad
|
||||
github.com/spf13/pflag v1.0.5 // @grafana-app-platform-squad
|
||||
github.com/spyzhov/ajson v0.9.0 // @grafana/grafana-app-platform-squad
|
||||
@@ -426,9 +423,6 @@ require github.com/fullstorydev/grpchan v1.1.1 // @grafana/backend-platform
|
||||
require github.com/grafana/grafana/pkg/promlib v0.0.4 // @grafana/observability-metrics
|
||||
|
||||
require (
|
||||
github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c // indirect
|
||||
github.com/apache/arrow/go/arrow v0.0.0-20211112161151-bc219186db40 // indirect
|
||||
github.com/apache/thrift v0.18.1 // indirect
|
||||
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20240226124929-648abdbd0ea4 // @grafana/grafana-app-platform-squad
|
||||
github.com/grafana/grafana/pkg/apiserver v0.0.0-20240226124929-648abdbd0ea4 // @grafana/grafana-app-platform-squad
|
||||
)
|
||||
@@ -438,9 +432,6 @@ require (
|
||||
github.com/grafana/sqlds/v3 v3.2.0 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
|
||||
github.com/jhump/protoreflect v1.15.1 // indirect
|
||||
github.com/klauspost/asmfmt v1.3.2 // indirect
|
||||
github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8 // indirect
|
||||
github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/mithrandie/csvq v1.17.10 // indirect
|
||||
github.com/mithrandie/csvq-driver v1.6.8 // indirect
|
||||
|
||||
@@ -1194,16 +1194,12 @@ github.com/Azure/azure-sdk-for-go/sdk/azcore v1.0.0/go.mod h1:uGG2W01BaETf0Ozp+Q
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.4.0/go.mod h1:ON4tFdPTwRcgWEaVDrN3584Ef+b7GgSJaXxe5fW9t4M=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.8.0/go.mod h1:3Ug6Qzto9anB6mGlEdgYMDF5zHQ+wwhEaYR4s17PHMw=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.0/go.mod h1:uReU2sSxZExRPBAg3qKzmAucSi51+SP1OhohieR821Q=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.10.0 h1:n1DH8TPV4qqPTje2RcUBYwtrTWlabVp4n46+74X2pn4=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.10.0/go.mod h1:HDcZnuGbiyppErN6lB+idp4CKhjbc8gwjto6OPpyggM=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1 h1:E+OJmp2tPvt1W+amx48v1eqbjDYsgN+RzP4q16yV5eM=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1/go.mod h1:a6xsAQUZg+VsS3TJ05SRp524Hs4pZ/AeFSr5ENf0Yjo=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.11.0/go.mod h1:HcM1YX14R7CJcghJGOYCgdezslRSVzqwLf/q+4Y2r/0=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.0.0/go.mod h1:+6sju8gk8FRmSajX3Oz4G5Gm7P+mbqE9FVaXXFYTkCM=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.0/go.mod h1:NBanQUfSWiWn3QEpWDTCU0IjBECKOYvl2R8xdRtMtiM=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0/go.mod h1:1fXstnBMas5kzG+S3q8UoJcmyU6nUeunJcMDHcRYHhs=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 h1:sO0/P7g68FrryJzljemN+6GTssUXdANk6aJ7T1ZxnsQ=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1/go.mod h1:h8hyGFDsU5HMivxiS2iYFZsgDbU9OnnJ163x5UGVKYo=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 h1:tfLQ34V6F7tVSwoTf/4lH5sE0o6eCJuNDTmH09nDpbc=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0/go.mod h1:9kIvujWAA58nmPmWB1m23fyWic1kYZMxD9CxaWn4Qpg=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0/go.mod h1:yqy467j36fJxcRV2TzfVZ1pCb5vxm4BtZPUdYWe/Xo8=
|
||||
@@ -1212,8 +1208,6 @@ github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.2/go.mod h1:eWRD7oawr1Mu1sLC
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.2.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.0/go.mod h1:s4kgfzA0covAXNicZHDMN58jExvcng2mC/DepXiF1EI=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 h1:LqbJ/WzJUwBf8UiaSzgX7aMclParm9/5Vgp+TY51uBQ=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2/go.mod h1:yInRyqWXAuaPrgI7p70+lDDgh3mlBohis29jGMISnmc=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.8.0 h1:jBQA3cKT4L2rWMpgE7Yt3Hwh2aUj8KXjIGLxjHeYNNo=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.8.0/go.mod h1:4OG6tQ9EOP/MT0NMjDlRzWoVFxfu9rN9B2X+tlSVktg=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.9.0 h1:TOFrNxfjslms5nLLIMjW7N0+zSALX4KiGsptmpb16AA=
|
||||
@@ -1276,8 +1270,6 @@ github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e/go.mod h1:chxPXzS
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v0.4.0/go.mod h1:Vt9sXTKwMyGcOxSmLDMnGPgqsUg7m8pe215qMLrDXw4=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v0.7.0/go.mod h1:BDJ5qMFKx9DugEg3+uQSDCdbYPr5s9vBTrL9P8TpqOU=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1 h1:DzHpqpoJVaCgOUdVHxE8QB52S6NiVdDQvGlny1qvPqA=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
@@ -1293,7 +1285,6 @@ github.com/GoogleCloudPlatform/cloudsql-proxy v1.29.0/go.mod h1:spvB9eLJH9dutlbP
|
||||
github.com/HdrHistogram/hdrhistogram-go v1.1.0/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
|
||||
github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM=
|
||||
github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
|
||||
github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c h1:RGWPOewvKIROun94nF7v2cua9qP+thov/7M50KEoeSU=
|
||||
github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk=
|
||||
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
|
||||
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
|
||||
@@ -1357,8 +1348,6 @@ github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kd
|
||||
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df h1:7RFfzj4SSt6nnvCPbCqijJi1nWCd+TqAT3bYCStRC18=
|
||||
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM=
|
||||
github.com/apache/arrow/go/arrow v0.0.0-20210223225224-5bea62493d91/go.mod h1:c9sxoIT3YgLxH4UhLOCKaBlEojuMhVYpk4Ntv3opUTQ=
|
||||
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/go.mod h1:YvhnlEePVnBS4+0z3fhPfUy7W1Ikj0Ih0vcRo/gZ1M0=
|
||||
github.com/apache/arrow/go/v11 v11.0.0/go.mod h1:Eg5OsL5H+e299f7u5ssuXsuHQVEGC4xei5aX110hRiI=
|
||||
github.com/apache/arrow/go/v12 v12.0.0/go.mod h1:d+tV/eHZZ7Dz7RPrFKtPK02tpr+c9/PEd/zm8mDS9Vg=
|
||||
@@ -1367,14 +1356,10 @@ github.com/apache/arrow/go/v15 v15.0.2/go.mod h1:DGXsR3ajT524njufqf95822i+KTh+ye
|
||||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU=
|
||||
github.com/apache/thrift v0.18.1 h1:lNhK/1nqjbwbiOPDBPFJVKxgDEGSepKuTh6OLiXW8kg=
|
||||
github.com/apache/thrift v0.18.1/go.mod h1:rdQn/dCcDKEWjjylUeueum4vQEjG2v8v2PqriUnbr+I=
|
||||
github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ=
|
||||
github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk=
|
||||
github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw=
|
||||
github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo=
|
||||
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de h1:FxWPpzIjnTlhPwqqXc4/vE0f7GvRjuAsbW+HOIe8KnA=
|
||||
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de/go.mod h1:DCaWoUhZrYW9p1lxo/cm8EmUOOzAPSEZNGF2DK1dJgw=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||
@@ -1636,7 +1621,6 @@ github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/
|
||||
github.com/dlmiddlecote/sqlstats v1.0.2 h1:gSU11YN23D/iY50A2zVYwgXgy072khatTsIW6UPjUtI=
|
||||
github.com/dlmiddlecote/sqlstats v1.0.2/go.mod h1:0CWaIh/Th+z2aI6Q9Jpfg/o21zmGxWhbByHgQSCUQvY=
|
||||
github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko=
|
||||
github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI=
|
||||
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
|
||||
github.com/docker/distribution v2.7.0+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8=
|
||||
@@ -2014,7 +1998,6 @@ github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl76
|
||||
github.com/google/cel-go v0.17.7 h1:6ebJFzu1xO2n7TLtN+UBqShGBhlD85bhvglh5DpcfqQ=
|
||||
github.com/google/cel-go v0.17.7/go.mod h1:HXZKzB0LXqer5lHHgfWAnlYwJaQBDKMjxjulNQzhwhY=
|
||||
github.com/google/flatbuffers v1.11.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
|
||||
github.com/google/flatbuffers v2.0.0+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
|
||||
github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
|
||||
github.com/google/flatbuffers v23.5.26+incompatible h1:M9dgRyhJemaM4Sw8+66GHBu8ioaQmyPLg1b8VwK5WJg=
|
||||
github.com/google/flatbuffers v23.5.26+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
|
||||
@@ -2441,10 +2424,8 @@ github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:C
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/asmfmt v1.3.2 h1:4Ri7ox3EwapiOjCki+hw14RyKk201CN4rzyCJRFLpK4=
|
||||
github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE=
|
||||
github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.13.1/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
|
||||
github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
|
||||
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/klauspost/compress v1.15.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
@@ -2575,9 +2556,7 @@ github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJys
|
||||
github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
|
||||
github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM=
|
||||
github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk=
|
||||
github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8 h1:AMFGa4R4MiIpspGNG7Z948v4n35fFGB3RR3G/ry4FWs=
|
||||
github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY=
|
||||
github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3 h1:+n/aFZefKZp7spd8DFdX7uMikMLXX4oubIzJF4kv/wI=
|
||||
github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE=
|
||||
github.com/minio/highwayhash v1.0.1/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY=
|
||||
github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY=
|
||||
@@ -2766,7 +2745,6 @@ github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk
|
||||
github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=
|
||||
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
|
||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
github.com/pierrec/lz4/v4 v4.1.8/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/pierrec/lz4/v4 v4.1.18 h1:xaKrnTkyoqfh1YItXl56+6KJNVYWlEEPuAQW9xsplYQ=
|
||||
github.com/pierrec/lz4/v4 v4.1.18/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
@@ -2904,8 +2882,6 @@ github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.21 h1:yWfiTPwYxB0l5fGMhl/G+liULugVIHD9AU77iNLrURQ=
|
||||
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.21/go.mod h1:fCa7OJZ/9DRTnOKmxvT6pn+LPWUptQAmHF/SBJUGEcg=
|
||||
github.com/scottlepp/go-duck v0.0.20 h1:SrDrLuwouDh50QB2eaEEhfWvRpdAbnejgqn/3aHBspY=
|
||||
github.com/scottlepp/go-duck v0.0.20/go.mod h1:GL+hHuKdueJRrFCduwBc7A7TQk+Tetc5BPXPVtduihY=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/segmentio/asm v1.1.3/go.mod h1:Ld3L4ZXGNcSLRg4JBsZ3//1+f/TjYl0Mzen/DQy1EJg=
|
||||
@@ -3273,8 +3249,6 @@ golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72
|
||||
golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
|
||||
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
|
||||
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
@@ -3346,8 +3320,7 @@ golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8=
|
||||
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -3446,8 +3419,6 @@ golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
|
||||
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
|
||||
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
||||
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
|
||||
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
@@ -3665,8 +3636,6 @@ golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
|
||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
@@ -3689,8 +3658,7 @@ golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww=
|
||||
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
|
||||
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA=
|
||||
golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -3713,8 +3681,6 @@ 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.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@@ -3823,8 +3789,7 @@ golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846/go.mod h1:Sc0INKfu04Tlq
|
||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||
golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0=
|
||||
golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
|
||||
golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ=
|
||||
golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -3993,7 +3958,6 @@ google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxH
|
||||
google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||
google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||
google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24=
|
||||
google.golang.org/genproto v0.0.0-20210630183607-d20f26d13c79/go.mod h1:yiaVoXHpRzHGyxV3o4DktVWY4mSUErTKaeEOq6C3t3U=
|
||||
google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=
|
||||
google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=
|
||||
google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
|
||||
|
||||
@@ -1035,6 +1035,8 @@ 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/telemetry v0.0.0-20240208230135-b75ee8823808 h1:+Kc94D8UVEVxJnLXp/+FMfqQARZtWHfVrcRtcG8aT3g=
|
||||
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=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM=
|
||||
golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg=
|
||||
golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0=
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"$schema": "node_modules/lerna/schemas/lerna-schema.json",
|
||||
"npmClient": "yarn",
|
||||
"version": "11.0.5"
|
||||
"version": "11.0.7"
|
||||
}
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
"license": "AGPL-3.0-only",
|
||||
"private": true,
|
||||
"name": "grafana",
|
||||
"version": "11.0.5",
|
||||
"version": "11.0.7",
|
||||
"repository": "github:grafana/grafana",
|
||||
"scripts": {
|
||||
"build": "NODE_ENV=production nx exec --verbose -- webpack --config scripts/webpack/webpack.prod.js",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"author": "Grafana Labs",
|
||||
"license": "Apache-2.0",
|
||||
"name": "@grafana/data",
|
||||
"version": "11.0.5",
|
||||
"version": "11.0.7",
|
||||
"description": "Grafana Data Library",
|
||||
"keywords": [
|
||||
"typescript"
|
||||
@@ -36,7 +36,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@braintree/sanitize-url": "7.0.1",
|
||||
"@grafana/schema": "11.0.5",
|
||||
"@grafana/schema": "11.0.7",
|
||||
"@types/d3-interpolate": "^3.0.0",
|
||||
"@types/string-hash": "1.1.3",
|
||||
"d3-interpolate": "3.0.1",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"author": "Grafana Labs",
|
||||
"license": "Apache-2.0",
|
||||
"name": "@grafana/e2e-selectors",
|
||||
"version": "11.0.5",
|
||||
"version": "11.0.7",
|
||||
"description": "Grafana End-to-End Test Selectors Library",
|
||||
"keywords": [
|
||||
"cli",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"author": "Grafana Labs",
|
||||
"license": "Apache-2.0",
|
||||
"name": "@grafana/e2e",
|
||||
"version": "11.0.5",
|
||||
"version": "11.0.7",
|
||||
"description": "Grafana End-to-End Test Library",
|
||||
"keywords": [
|
||||
"cli",
|
||||
@@ -63,8 +63,8 @@
|
||||
"@babel/core": "7.23.2",
|
||||
"@babel/preset-env": "7.23.2",
|
||||
"@cypress/webpack-preprocessor": "5.17.1",
|
||||
"@grafana/e2e-selectors": "11.0.5",
|
||||
"@grafana/schema": "11.0.5",
|
||||
"@grafana/e2e-selectors": "11.0.7",
|
||||
"@grafana/schema": "11.0.7",
|
||||
"@grafana/tsconfig": "^1.3.0-rc1",
|
||||
"@mochajs/json-file-reporter": "^1.2.0",
|
||||
"babel-loader": "9.1.3",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@grafana/eslint-plugin",
|
||||
"description": "ESLint rules for use within the Grafana repo. Not suitable (or supported) for external use.",
|
||||
"version": "11.0.5",
|
||||
"version": "11.0.7",
|
||||
"main": "./index.cjs",
|
||||
"author": "Grafana Labs",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"author": "Grafana Labs",
|
||||
"license": "Apache-2.0",
|
||||
"name": "@grafana/flamegraph",
|
||||
"version": "11.0.5",
|
||||
"version": "11.0.7",
|
||||
"description": "Grafana flamegraph visualization component",
|
||||
"keywords": [
|
||||
"grafana",
|
||||
@@ -44,8 +44,8 @@
|
||||
],
|
||||
"dependencies": {
|
||||
"@emotion/css": "11.11.2",
|
||||
"@grafana/data": "11.0.5",
|
||||
"@grafana/ui": "11.0.5",
|
||||
"@grafana/data": "11.0.7",
|
||||
"@grafana/ui": "11.0.7",
|
||||
"@leeoniya/ufuzzy": "1.0.14",
|
||||
"d3": "^7.8.5",
|
||||
"lodash": "4.17.21",
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"license": "AGPL-3.0-only",
|
||||
"name": "@grafana/o11y-ds-frontend",
|
||||
"private": true,
|
||||
"version": "11.0.5",
|
||||
"version": "11.0.7",
|
||||
"description": "Library to manage traces in Grafana.",
|
||||
"sideEffects": false,
|
||||
"repository": {
|
||||
@@ -18,12 +18,12 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@emotion/css": "11.11.2",
|
||||
"@grafana/data": "11.0.5",
|
||||
"@grafana/e2e-selectors": "11.0.5",
|
||||
"@grafana/data": "11.0.7",
|
||||
"@grafana/e2e-selectors": "11.0.7",
|
||||
"@grafana/experimental": "1.7.10",
|
||||
"@grafana/runtime": "11.0.5",
|
||||
"@grafana/schema": "11.0.5",
|
||||
"@grafana/ui": "11.0.5",
|
||||
"@grafana/runtime": "11.0.7",
|
||||
"@grafana/schema": "11.0.7",
|
||||
"@grafana/ui": "11.0.7",
|
||||
"react-use": "17.5.0",
|
||||
"rxjs": "7.8.1",
|
||||
"tslib": "2.6.2"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "@grafana/plugin-configs",
|
||||
"description": "Shared dependencies and files for core plugins",
|
||||
"private": true,
|
||||
"version": "11.0.5",
|
||||
"version": "11.0.7",
|
||||
"dependencies": {
|
||||
"tslib": "2.6.2"
|
||||
},
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"author": "Grafana Labs",
|
||||
"license": "AGPL-3.0-only",
|
||||
"name": "@grafana/prometheus",
|
||||
"version": "11.0.5",
|
||||
"version": "11.0.7",
|
||||
"description": "Grafana Prometheus Library",
|
||||
"keywords": [
|
||||
"typescript"
|
||||
@@ -38,12 +38,12 @@
|
||||
"dependencies": {
|
||||
"@emotion/css": "11.11.2",
|
||||
"@floating-ui/react": "0.26.10",
|
||||
"@grafana/data": "11.0.5",
|
||||
"@grafana/data": "11.0.7",
|
||||
"@grafana/experimental": "1.7.10",
|
||||
"@grafana/faro-web-sdk": "1.5.0",
|
||||
"@grafana/runtime": "11.0.5",
|
||||
"@grafana/schema": "11.0.5",
|
||||
"@grafana/ui": "11.0.5",
|
||||
"@grafana/runtime": "11.0.7",
|
||||
"@grafana/schema": "11.0.7",
|
||||
"@grafana/ui": "11.0.7",
|
||||
"@leeoniya/ufuzzy": "1.0.14",
|
||||
"@lezer/common": "1.2.1",
|
||||
"@lezer/highlight": "1.2.0",
|
||||
@@ -76,8 +76,8 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@emotion/eslint-plugin": "11.11.0",
|
||||
"@grafana/e2e": "11.0.5",
|
||||
"@grafana/e2e-selectors": "11.0.5",
|
||||
"@grafana/e2e": "11.0.7",
|
||||
"@grafana/e2e-selectors": "11.0.7",
|
||||
"@grafana/tsconfig": "^1.3.0-rc1",
|
||||
"@rollup/plugin-image": "3.0.3",
|
||||
"@rollup/plugin-node-resolve": "15.2.3",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"author": "Grafana Labs",
|
||||
"license": "Apache-2.0",
|
||||
"name": "@grafana/runtime",
|
||||
"version": "11.0.5",
|
||||
"version": "11.0.7",
|
||||
"description": "Grafana Runtime Library",
|
||||
"keywords": [
|
||||
"grafana",
|
||||
@@ -37,11 +37,11 @@
|
||||
"postpack": "mv package.json.bak package.json"
|
||||
},
|
||||
"dependencies": {
|
||||
"@grafana/data": "11.0.5",
|
||||
"@grafana/e2e-selectors": "11.0.5",
|
||||
"@grafana/data": "11.0.7",
|
||||
"@grafana/e2e-selectors": "11.0.7",
|
||||
"@grafana/faro-web-sdk": "^1.3.6",
|
||||
"@grafana/schema": "11.0.5",
|
||||
"@grafana/ui": "11.0.5",
|
||||
"@grafana/schema": "11.0.7",
|
||||
"@grafana/ui": "11.0.7",
|
||||
"history": "4.10.1",
|
||||
"lodash": "4.17.21",
|
||||
"rxjs": "7.8.1",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"author": "Grafana Labs",
|
||||
"license": "Apache-2.0",
|
||||
"name": "@grafana/schema",
|
||||
"version": "11.0.5",
|
||||
"version": "11.0.7",
|
||||
"description": "Grafana Schema Library",
|
||||
"keywords": [
|
||||
"typescript"
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
//
|
||||
// Run 'make gen-cue' from repository root to regenerate.
|
||||
|
||||
export const pluginVersion = "11.0.5";
|
||||
export const pluginVersion = "11.0.7";
|
||||
|
||||
export interface Options {
|
||||
limit: number;
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
|
||||
import * as common from '@grafana/schema';
|
||||
|
||||
export const pluginVersion = "11.0.5";
|
||||
export const pluginVersion = "11.0.7";
|
||||
|
||||
export interface Options extends common.OptionsWithLegend, common.OptionsWithTooltip, common.OptionsWithTextFormatting {
|
||||
/**
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
|
||||
import * as common from '@grafana/schema';
|
||||
|
||||
export const pluginVersion = "11.0.5";
|
||||
export const pluginVersion = "11.0.7";
|
||||
|
||||
export interface Options extends common.SingleStatBaseOptions {
|
||||
displayMode: common.BarGaugeDisplayMode;
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
|
||||
import * as common from '@grafana/schema';
|
||||
|
||||
export const pluginVersion = "11.0.5";
|
||||
export const pluginVersion = "11.0.7";
|
||||
|
||||
export enum VizDisplayMode {
|
||||
Candles = 'candles',
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
|
||||
import * as ui from '@grafana/schema';
|
||||
|
||||
export const pluginVersion = "11.0.5";
|
||||
export const pluginVersion = "11.0.7";
|
||||
|
||||
export enum HorizontalConstraint {
|
||||
Center = 'center',
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
|
||||
import * as common from '@grafana/schema';
|
||||
|
||||
export const pluginVersion = "11.0.5";
|
||||
export const pluginVersion = "11.0.7";
|
||||
|
||||
export interface MetricStat {
|
||||
/**
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
//
|
||||
// Run 'make gen-cue' from repository root to regenerate.
|
||||
|
||||
export const pluginVersion = "11.0.5";
|
||||
export const pluginVersion = "11.0.7";
|
||||
|
||||
export interface Options {
|
||||
/**
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
//
|
||||
// Run 'make gen-cue' from repository root to regenerate.
|
||||
|
||||
export const pluginVersion = "11.0.5";
|
||||
export const pluginVersion = "11.0.7";
|
||||
|
||||
export interface Options {
|
||||
selectedSeries: number;
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
//
|
||||
// Run 'make gen-cue' from repository root to regenerate.
|
||||
|
||||
export const pluginVersion = "11.0.5";
|
||||
export const pluginVersion = "11.0.7";
|
||||
|
||||
export type UpdateConfig = {
|
||||
render: boolean,
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
|
||||
import * as common from '@grafana/schema';
|
||||
|
||||
export const pluginVersion = "11.0.5";
|
||||
export const pluginVersion = "11.0.7";
|
||||
|
||||
export type BucketAggregation = (DateHistogram | Histogram | Terms | Filters | GeoHashGrid | Nested);
|
||||
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
|
||||
import * as common from '@grafana/schema';
|
||||
|
||||
export const pluginVersion = "11.0.5";
|
||||
export const pluginVersion = "11.0.7";
|
||||
|
||||
export interface Options extends common.SingleStatBaseOptions {
|
||||
minVizHeight: number;
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
|
||||
import * as ui from '@grafana/schema';
|
||||
|
||||
export const pluginVersion = "11.0.5";
|
||||
export const pluginVersion = "11.0.7";
|
||||
|
||||
export interface Options {
|
||||
basemap: ui.MapLayerOptions;
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
|
||||
import * as ui from '@grafana/schema';
|
||||
|
||||
export const pluginVersion = "11.0.5";
|
||||
export const pluginVersion = "11.0.7";
|
||||
|
||||
/**
|
||||
* Controls the color mode of the heatmap
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
|
||||
import * as common from '@grafana/schema';
|
||||
|
||||
export const pluginVersion = "11.0.5";
|
||||
export const pluginVersion = "11.0.7";
|
||||
|
||||
export interface Options extends common.OptionsWithLegend, common.OptionsWithTooltip {
|
||||
/**
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
|
||||
import * as common from '@grafana/schema';
|
||||
|
||||
export const pluginVersion = "11.0.5";
|
||||
export const pluginVersion = "11.0.7";
|
||||
|
||||
export interface Options {
|
||||
dedupStrategy: common.LogsDedupStrategy;
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
|
||||
import * as common from '@grafana/schema';
|
||||
|
||||
export const pluginVersion = "11.0.5";
|
||||
export const pluginVersion = "11.0.7";
|
||||
|
||||
export enum QueryEditorMode {
|
||||
Builder = 'builder',
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
//
|
||||
// Run 'make gen-cue' from repository root to regenerate.
|
||||
|
||||
export const pluginVersion = "11.0.5";
|
||||
export const pluginVersion = "11.0.7";
|
||||
|
||||
export interface Options {
|
||||
/**
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
//
|
||||
// Run 'make gen-cue' from repository root to regenerate.
|
||||
|
||||
export const pluginVersion = "11.0.5";
|
||||
export const pluginVersion = "11.0.7";
|
||||
|
||||
export interface ArcOption {
|
||||
/**
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
|
||||
import * as common from '@grafana/schema';
|
||||
|
||||
export const pluginVersion = "11.0.5";
|
||||
export const pluginVersion = "11.0.7";
|
||||
|
||||
/**
|
||||
* Select the pie chart display style.
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
|
||||
import * as common from '@grafana/schema';
|
||||
|
||||
export const pluginVersion = "11.0.5";
|
||||
export const pluginVersion = "11.0.7";
|
||||
|
||||
export interface Options extends common.SingleStatBaseOptions {
|
||||
colorMode: common.BigValueColorMode;
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
|
||||
import * as ui from '@grafana/schema';
|
||||
|
||||
export const pluginVersion = "11.0.5";
|
||||
export const pluginVersion = "11.0.7";
|
||||
|
||||
export interface Options extends ui.OptionsWithLegend, ui.OptionsWithTooltip, ui.OptionsWithTimezones {
|
||||
/**
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
|
||||
import * as ui from '@grafana/schema';
|
||||
|
||||
export const pluginVersion = "11.0.5";
|
||||
export const pluginVersion = "11.0.7";
|
||||
|
||||
export interface Options extends ui.OptionsWithLegend, ui.OptionsWithTooltip, ui.OptionsWithTimezones {
|
||||
/**
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
|
||||
import * as ui from '@grafana/schema';
|
||||
|
||||
export const pluginVersion = "11.0.5";
|
||||
export const pluginVersion = "11.0.7";
|
||||
|
||||
export interface Options {
|
||||
/**
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
//
|
||||
// Run 'make gen-cue' from repository root to regenerate.
|
||||
|
||||
export const pluginVersion = "11.0.5";
|
||||
export const pluginVersion = "11.0.7";
|
||||
|
||||
export enum TextMode {
|
||||
Code = 'code',
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
|
||||
import * as common from '@grafana/schema';
|
||||
|
||||
export const pluginVersion = "11.0.5";
|
||||
export const pluginVersion = "11.0.7";
|
||||
|
||||
export interface Options extends common.OptionsWithTimezones {
|
||||
legend: common.VizLegendOptions;
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
|
||||
import * as common from '@grafana/schema';
|
||||
|
||||
export const pluginVersion = "11.0.5";
|
||||
export const pluginVersion = "11.0.7";
|
||||
|
||||
/**
|
||||
* Identical to timeseries... except it does not have timezone settings
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
|
||||
import * as common from '@grafana/schema';
|
||||
|
||||
export const pluginVersion = "11.0.5";
|
||||
export const pluginVersion = "11.0.7";
|
||||
|
||||
/**
|
||||
* Auto is "table" in the UI
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"license": "AGPL-3.0-only",
|
||||
"private": true,
|
||||
"name": "@grafana/sql",
|
||||
"version": "11.0.5",
|
||||
"version": "11.0.7",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "http://github.com/grafana/grafana.git",
|
||||
@@ -15,10 +15,10 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@emotion/css": "11.11.2",
|
||||
"@grafana/data": "11.0.5",
|
||||
"@grafana/data": "11.0.7",
|
||||
"@grafana/experimental": "1.7.10",
|
||||
"@grafana/runtime": "11.0.5",
|
||||
"@grafana/ui": "11.0.5",
|
||||
"@grafana/runtime": "11.0.7",
|
||||
"@grafana/ui": "11.0.7",
|
||||
"@react-awesome-query-builder/ui": "6.4.2",
|
||||
"@types/lodash": "4.17.0",
|
||||
"@types/react-virtualized-auto-sizer": "1.0.4",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"author": "Grafana Labs",
|
||||
"license": "Apache-2.0",
|
||||
"name": "@grafana/ui",
|
||||
"version": "11.0.5",
|
||||
"version": "11.0.7",
|
||||
"description": "Grafana Components Library",
|
||||
"keywords": [
|
||||
"grafana",
|
||||
@@ -50,10 +50,10 @@
|
||||
"@emotion/css": "11.11.2",
|
||||
"@emotion/react": "11.11.4",
|
||||
"@floating-ui/react": "0.26.10",
|
||||
"@grafana/data": "11.0.5",
|
||||
"@grafana/e2e-selectors": "11.0.5",
|
||||
"@grafana/data": "11.0.7",
|
||||
"@grafana/e2e-selectors": "11.0.7",
|
||||
"@grafana/faro-web-sdk": "^1.3.6",
|
||||
"@grafana/schema": "11.0.5",
|
||||
"@grafana/schema": "11.0.7",
|
||||
"@leeoniya/ufuzzy": "1.0.14",
|
||||
"@monaco-editor/react": "4.6.0",
|
||||
"@popperjs/core": "2.11.8",
|
||||
|
||||
@@ -22,6 +22,8 @@ import (
|
||||
"github.com/grafana/grafana/pkg/web"
|
||||
)
|
||||
|
||||
const defaultAnnotationsLimit = 100
|
||||
|
||||
// swagger:route GET /annotations annotations getAnnotations
|
||||
//
|
||||
// Find Annotations.
|
||||
@@ -48,6 +50,9 @@ func (hs *HTTPServer) GetAnnotations(c *contextmodel.ReqContext) response.Respon
|
||||
MatchAny: c.QueryBool("matchAny"),
|
||||
SignedInUser: c.SignedInUser,
|
||||
}
|
||||
if query.Limit == 0 {
|
||||
query.Limit = defaultAnnotationsLimit
|
||||
}
|
||||
|
||||
// When dashboard UID present in the request, we ignore dashboard ID
|
||||
if query.DashboardUID != "" {
|
||||
|
||||
@@ -28,7 +28,13 @@ func checkAppEnabled(pluginStore pluginstore.Store, pluginSettings pluginsetting
|
||||
})
|
||||
if err != nil {
|
||||
if errors.Is(err, pluginsettings.ErrPluginSettingNotFound) {
|
||||
c.JsonApiErr(http.StatusNotFound, "Plugin not found", nil)
|
||||
// If the plugin is auto enabled, we don't want to return an error because auto enabling allows us
|
||||
// to enable plugins that are not explicitly configured.
|
||||
if p.AutoEnabled {
|
||||
return
|
||||
}
|
||||
|
||||
c.JsonApiErr(http.StatusNotFound, "Plugin setting not found", nil)
|
||||
return
|
||||
}
|
||||
c.JsonApiErr(http.StatusInternalServerError, "Failed to get plugin settings", err)
|
||||
|
||||
@@ -41,6 +41,11 @@ func TestHTTPServer_CheckEnabled(t *testing.T) {
|
||||
pluginID: "grafana-test-app_disabled",
|
||||
expectedCode: 404,
|
||||
},
|
||||
{
|
||||
name: "should not set an error code if the plugin is auto enabled, without a saved plugin setting",
|
||||
pluginID: "grafana-test-app_autoEnabled",
|
||||
expectedCode: 0,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
@@ -50,6 +55,7 @@ func TestHTTPServer_CheckEnabled(t *testing.T) {
|
||||
{JSONData: plugins.JSONData{ID: "mysql"}},
|
||||
{JSONData: plugins.JSONData{Type: plugins.TypeApp, ID: "grafana-test-app"}},
|
||||
{JSONData: plugins.JSONData{Type: plugins.TypeApp, ID: "grafana-test-app_disabled"}},
|
||||
{JSONData: plugins.JSONData{Type: plugins.TypeApp, ID: "grafana-test-app_autoEnabled", AutoEnabled: true}},
|
||||
},
|
||||
}
|
||||
hs.PluginSettings = &pluginsettings.FakePluginSettings{Plugins: map[string]*pluginsettings.DTO{
|
||||
|
||||
@@ -145,6 +145,9 @@ func Builds(baseURL *url.URL, grafana, version string, packages []packaging.Buil
|
||||
if arch == "aarch64" {
|
||||
arch = "arm64"
|
||||
}
|
||||
if arch == "x86_64" {
|
||||
arch = "amd64"
|
||||
}
|
||||
}
|
||||
|
||||
if v.Distro == "deb" {
|
||||
|
||||
@@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
@@ -23,6 +24,11 @@ func NpmRetrieveAction(c *cli.Context) error {
|
||||
return fmt.Errorf("no tag version specified, exitting")
|
||||
}
|
||||
|
||||
if strings.Contains(tag, "security") {
|
||||
log.Printf("skipping npm publish because version '%s' has 'security'", tag)
|
||||
return nil
|
||||
}
|
||||
|
||||
prereleaseBucket := strings.TrimSpace(os.Getenv("PRERELEASE_BUCKET"))
|
||||
if prereleaseBucket == "" {
|
||||
return cli.Exit("the environment variable PRERELEASE_BUCKET must be set", 1)
|
||||
@@ -48,6 +54,11 @@ func NpmStoreAction(c *cli.Context) error {
|
||||
return fmt.Errorf("no tag version specified, exiting")
|
||||
}
|
||||
|
||||
if strings.Contains(tag, "security") {
|
||||
log.Printf("skipping npm publish because version '%s' has 'security'", tag)
|
||||
return nil
|
||||
}
|
||||
|
||||
prereleaseBucket := strings.TrimSpace(os.Getenv("PRERELEASE_BUCKET"))
|
||||
if prereleaseBucket == "" {
|
||||
return cli.Exit("the environment variable PRERELEASE_BUCKET must be set", 1)
|
||||
@@ -73,6 +84,11 @@ func NpmReleaseAction(c *cli.Context) error {
|
||||
return fmt.Errorf("no tag version specified, exitting")
|
||||
}
|
||||
|
||||
if strings.Contains(tag, "security") {
|
||||
log.Printf("skipping npm publish because version '%s' has 'security'", tag)
|
||||
return nil
|
||||
}
|
||||
|
||||
err := npm.PublishNpmPackages(c.Context, tag)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
+1
-3
@@ -1,8 +1,6 @@
|
||||
module github.com/grafana/grafana/pkg/build
|
||||
|
||||
go 1.22
|
||||
|
||||
toolchain go1.22.4
|
||||
go 1.22.7
|
||||
|
||||
// Override docker/docker to avoid:
|
||||
// go: github.com/drone-runners/drone-runner-docker@v1.8.2 requires
|
||||
|
||||
@@ -113,6 +113,16 @@ var ARMArtifacts = []BuildArtifact{
|
||||
Arch: "armv7",
|
||||
Ext: "tar.gz",
|
||||
},
|
||||
{
|
||||
Distro: "linux",
|
||||
Arch: "arm64",
|
||||
Ext: "tar.gz",
|
||||
},
|
||||
{
|
||||
Distro: "linux",
|
||||
Arch: "amd64",
|
||||
Ext: "tar.gz",
|
||||
},
|
||||
}
|
||||
|
||||
func join(a []BuildArtifact, b ...[]BuildArtifact) []BuildArtifact {
|
||||
|
||||
@@ -13,15 +13,17 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
reGrafanaTag = regexp.MustCompile(`^v(\d+\.\d+\.\d+$)`)
|
||||
reGrafanaTagPreview = regexp.MustCompile(`^v(\d+\.\d+\.\d+-preview)`)
|
||||
reGrafanaTagCustom = regexp.MustCompile(`^v(\d+\.\d+\.\d+-\w+)`)
|
||||
reGrafanaTag = regexp.MustCompile(`^v(\d+\.\d+\.\d+$)`)
|
||||
reGrafanaTagPreview = regexp.MustCompile(`^v(\d+\.\d+\.\d+-preview)`)
|
||||
reGrafanaTagCustom = regexp.MustCompile(`^v(\d+\.\d+\.\d+-\w+)`)
|
||||
reGrafanaTagSecurity = regexp.MustCompile(`^v(\d+\.\d+\.\d+\+\w+\-\d+)`)
|
||||
)
|
||||
|
||||
const (
|
||||
Latest = "latest"
|
||||
Next = "next"
|
||||
Test = "test"
|
||||
Latest = "latest"
|
||||
Next = "next"
|
||||
Test = "test"
|
||||
Security = "security"
|
||||
)
|
||||
|
||||
type Version struct {
|
||||
@@ -152,6 +154,11 @@ func GetVersion(tag string) (*Version, error) {
|
||||
Version: reGrafanaTagCustom.FindStringSubmatch(tag)[1],
|
||||
Channel: Test,
|
||||
}
|
||||
case reGrafanaTagSecurity.MatchString(tag):
|
||||
version = Version{
|
||||
Version: reGrafanaTagSecurity.FindStringSubmatch(tag)[1],
|
||||
Channel: Security,
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("%s not a supported Grafana version, exitting", tag)
|
||||
}
|
||||
|
||||
@@ -125,6 +125,10 @@ func (h *ExpressionQueryReader) ReadQuery(
|
||||
}
|
||||
|
||||
case QueryTypeSQL:
|
||||
enabled := enableSqlExpressions(h)
|
||||
if !enabled {
|
||||
return eq, fmt.Errorf("sqlExpressions is not implemented")
|
||||
}
|
||||
q := &SQLExpression{}
|
||||
err = iter.ReadVal(q)
|
||||
if err == nil {
|
||||
@@ -192,3 +196,11 @@ func getReferenceVar(exp string, refId string) (string, error) {
|
||||
}
|
||||
return exp, nil
|
||||
}
|
||||
|
||||
func enableSqlExpressions(h *ExpressionQueryReader) bool {
|
||||
enabled := !h.features.IsEnabledGlobally(featuremgmt.FlagSqlExpressions)
|
||||
if enabled {
|
||||
return false
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -84,9 +84,9 @@ func (gr *SQLCommand) Execute(ctx context.Context, now time.Time, vars mathexp.V
|
||||
|
||||
rsp := mathexp.Results{}
|
||||
|
||||
duckDB := sql.NewInMemoryDB()
|
||||
db := sql.NewInMemoryDB()
|
||||
var frame = &data.Frame{}
|
||||
err := duckDB.QueryFramesInto(gr.refID, gr.query, allFrames, frame)
|
||||
err := db.QueryFramesInto(gr.refID, gr.query, allFrames, frame)
|
||||
if err != nil {
|
||||
rsp.Error = err
|
||||
return rsp, nil
|
||||
|
||||
@@ -39,7 +39,7 @@ func NewAuthService(db db.DB, features featuremgmt.FeatureToggles) *AuthService
|
||||
}
|
||||
|
||||
// Authorize checks if the user has permission to read annotations, then returns a struct containing dashboards and scope types that the user has access to.
|
||||
func (authz *AuthService) Authorize(ctx context.Context, orgID int64, query *annotations.ItemQuery) (*AccessResources, error) {
|
||||
func (authz *AuthService) Authorize(ctx context.Context, query annotations.ItemQuery) (*AccessResources, error) {
|
||||
user := query.SignedInUser
|
||||
if user == nil || user.IsNil() {
|
||||
return nil, ErrReadForbidden.Errorf("missing user")
|
||||
@@ -60,14 +60,14 @@ func (authz *AuthService) Authorize(ctx context.Context, orgID int64, query *ann
|
||||
var err error
|
||||
if canAccessDashAnnotations {
|
||||
if query.AnnotationID != 0 {
|
||||
annotationDashboardID, err := authz.getAnnotationDashboard(ctx, query, orgID)
|
||||
annotationDashboardID, err := authz.getAnnotationDashboard(ctx, query)
|
||||
if err != nil {
|
||||
return nil, ErrAccessControlInternal.Errorf("failed to fetch annotations: %w", err)
|
||||
}
|
||||
query.DashboardID = annotationDashboardID
|
||||
}
|
||||
|
||||
visibleDashboards, err = authz.dashboardsWithVisibleAnnotations(ctx, query, orgID)
|
||||
visibleDashboards, err = authz.dashboardsWithVisibleAnnotations(ctx, query)
|
||||
if err != nil {
|
||||
return nil, ErrAccessControlInternal.Errorf("failed to fetch dashboards: %w", err)
|
||||
}
|
||||
@@ -80,7 +80,7 @@ func (authz *AuthService) Authorize(ctx context.Context, orgID int64, query *ann
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (authz *AuthService) getAnnotationDashboard(ctx context.Context, query *annotations.ItemQuery, orgID int64) (int64, error) {
|
||||
func (authz *AuthService) getAnnotationDashboard(ctx context.Context, query annotations.ItemQuery) (int64, error) {
|
||||
var items []annotations.Item
|
||||
params := make([]any, 0)
|
||||
err := authz.db.WithDbSession(ctx, func(sess *db.Session) error {
|
||||
@@ -92,7 +92,7 @@ func (authz *AuthService) getAnnotationDashboard(ctx context.Context, query *ann
|
||||
FROM annotation as a
|
||||
WHERE a.org_id = ? AND a.id = ?
|
||||
`
|
||||
params = append(params, orgID, query.AnnotationID)
|
||||
params = append(params, query.OrgID, query.AnnotationID)
|
||||
|
||||
return sess.SQL(sql, params...).Find(&items)
|
||||
})
|
||||
@@ -106,7 +106,7 @@ func (authz *AuthService) getAnnotationDashboard(ctx context.Context, query *ann
|
||||
return items[0].DashboardID, nil
|
||||
}
|
||||
|
||||
func (authz *AuthService) dashboardsWithVisibleAnnotations(ctx context.Context, query *annotations.ItemQuery, orgID int64) (map[string]int64, error) {
|
||||
func (authz *AuthService) dashboardsWithVisibleAnnotations(ctx context.Context, query annotations.ItemQuery) (map[string]int64, error) {
|
||||
recursiveQueriesSupported, err := authz.db.RecursiveQueriesAreSupported()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -119,7 +119,7 @@ func (authz *AuthService) dashboardsWithVisibleAnnotations(ctx context.Context,
|
||||
|
||||
filters := []any{
|
||||
permissions.NewAccessControlDashboardPermissionFilter(query.SignedInUser, dashboardaccess.PERMISSION_VIEW, filterType, authz.features, recursiveQueriesSupported),
|
||||
searchstore.OrgFilter{OrgId: orgID},
|
||||
searchstore.OrgFilter{OrgId: query.OrgID},
|
||||
}
|
||||
|
||||
if query.DashboardUID != "" {
|
||||
@@ -134,32 +134,25 @@ func (authz *AuthService) dashboardsWithVisibleAnnotations(ctx context.Context,
|
||||
}
|
||||
|
||||
sb := &searchstore.Builder{Dialect: authz.db.GetDialect(), Filters: filters, Features: authz.features}
|
||||
// This is a limit for a batch size, not for the end query result.
|
||||
var limit int64 = 1000
|
||||
if query.Page == 0 {
|
||||
query.Page = 1
|
||||
}
|
||||
sql, params := sb.ToSQL(limit, query.Page)
|
||||
|
||||
visibleDashboards := make(map[string]int64)
|
||||
var res []dashboardProjection
|
||||
|
||||
var page int64 = 1
|
||||
var limit int64 = 1000
|
||||
for {
|
||||
var res []dashboardProjection
|
||||
sql, params := sb.ToSQL(limit, page)
|
||||
err = authz.db.WithDbSession(ctx, func(sess *db.Session) error {
|
||||
return sess.SQL(sql, params...).Find(&res)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = authz.db.WithDbSession(ctx, func(sess *db.Session) error {
|
||||
return sess.SQL(sql, params...).Find(&res)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, p := range res {
|
||||
visibleDashboards[p.UID] = p.ID
|
||||
}
|
||||
|
||||
// if the result is less than the limit, we have reached the end
|
||||
if len(res) < int(limit) {
|
||||
break
|
||||
}
|
||||
|
||||
page++
|
||||
for _, p := range res {
|
||||
visibleDashboards[p.UID] = p.ID
|
||||
}
|
||||
|
||||
return visibleDashboards, nil
|
||||
|
||||
@@ -175,8 +175,8 @@ func TestIntegrationAuthorize(t *testing.T) {
|
||||
|
||||
authz := NewAuthService(sql, featuremgmt.WithFeatures(tc.featureToggle))
|
||||
|
||||
query := &annotations.ItemQuery{SignedInUser: u}
|
||||
resources, err := authz.Authorize(context.Background(), 1, query)
|
||||
query := annotations.ItemQuery{SignedInUser: u, OrgID: 1}
|
||||
resources, err := authz.Authorize(context.Background(), query)
|
||||
require.NoError(t, err)
|
||||
|
||||
if tc.expectedResources.Dashboards != nil {
|
||||
|
||||
@@ -8,6 +8,8 @@ type AccessResources struct {
|
||||
CanAccessDashAnnotations bool
|
||||
// CanAccessOrgAnnotations true if the user is allowed to access organization annotations
|
||||
CanAccessOrgAnnotations bool
|
||||
// Skip filtering
|
||||
SkipAccessControlFilter bool
|
||||
}
|
||||
|
||||
type dashboardProjection struct {
|
||||
|
||||
@@ -68,12 +68,50 @@ func (r *RepositoryImpl) Update(ctx context.Context, item *annotations.Item) err
|
||||
}
|
||||
|
||||
func (r *RepositoryImpl) Find(ctx context.Context, query *annotations.ItemQuery) ([]*annotations.ItemDTO, error) {
|
||||
resources, err := r.authZ.Authorize(ctx, query.OrgID, query)
|
||||
if err != nil {
|
||||
return make([]*annotations.ItemDTO, 0), err
|
||||
if query.Limit == 0 {
|
||||
query.Limit = 100
|
||||
}
|
||||
|
||||
return r.reader.Get(ctx, query, resources)
|
||||
// Search without dashboard UID filter is expensive, so check without access control first
|
||||
if query.DashboardID == 0 && query.DashboardUID == "" {
|
||||
// Return early if no annotations found, it's not necessary to perform expensive access control filtering
|
||||
res, err := r.reader.Get(ctx, *query, &accesscontrol.AccessResources{
|
||||
SkipAccessControlFilter: true,
|
||||
})
|
||||
if err != nil || len(res) == 0 {
|
||||
return []*annotations.ItemDTO{}, err
|
||||
}
|
||||
// If number of resources is less than limit, it makes sense to set query limit to this
|
||||
// value, otherwise query will be iterating over all user's dashboards since original
|
||||
// query limit is never reached.
|
||||
query.Limit = int64(len(res))
|
||||
}
|
||||
|
||||
results := make([]*annotations.ItemDTO, 0, query.Limit)
|
||||
query.Page = 1
|
||||
|
||||
// Iterate over available annotations until query limit is reached
|
||||
// or all available dashboards are checked
|
||||
for len(results) < int(query.Limit) {
|
||||
resources, err := r.authZ.Authorize(ctx, *query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res, err := r.reader.Get(ctx, *query, resources)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
results = append(results, res...)
|
||||
query.Page++
|
||||
// All user's dashboards are fetched
|
||||
if len(resources.Dashboards) < int(query.Limit) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func (r *RepositoryImpl) Delete(ctx context.Context, params *annotations.DeleteParams) error {
|
||||
@@ -81,5 +119,5 @@ func (r *RepositoryImpl) Delete(ctx context.Context, params *annotations.DeleteP
|
||||
}
|
||||
|
||||
func (r *RepositoryImpl) FindTags(ctx context.Context, query *annotations.TagsQuery) (annotations.FindTagsResult, error) {
|
||||
return r.reader.GetTags(ctx, query)
|
||||
return r.reader.GetTags(ctx, *query)
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ func (c *CompositeStore) Type() string {
|
||||
}
|
||||
|
||||
// Get returns annotations from all stores, and combines the results.
|
||||
func (c *CompositeStore) Get(ctx context.Context, query *annotations.ItemQuery, accessResources *accesscontrol.AccessResources) ([]*annotations.ItemDTO, error) {
|
||||
func (c *CompositeStore) Get(ctx context.Context, query annotations.ItemQuery, accessResources *accesscontrol.AccessResources) ([]*annotations.ItemDTO, error) {
|
||||
itemCh := make(chan []*annotations.ItemDTO, len(c.readers))
|
||||
|
||||
err := concurrency.ForEachJob(ctx, len(c.readers), len(c.readers), func(ctx context.Context, i int) (err error) {
|
||||
@@ -56,7 +56,7 @@ func (c *CompositeStore) Get(ctx context.Context, query *annotations.ItemQuery,
|
||||
}
|
||||
|
||||
// GetTags returns tags from all stores, and combines the results.
|
||||
func (c *CompositeStore) GetTags(ctx context.Context, query *annotations.TagsQuery) (annotations.FindTagsResult, error) {
|
||||
func (c *CompositeStore) GetTags(ctx context.Context, query annotations.TagsQuery) (annotations.FindTagsResult, error) {
|
||||
resCh := make(chan annotations.FindTagsResult, len(c.readers))
|
||||
|
||||
err := concurrency.ForEachJob(ctx, len(c.readers), len(c.readers), func(ctx context.Context, i int) (err error) {
|
||||
|
||||
@@ -7,10 +7,11 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/services/annotations"
|
||||
"github.com/grafana/grafana/pkg/services/annotations/accesscontrol"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -21,7 +22,7 @@ var (
|
||||
func TestCompositeStore(t *testing.T) {
|
||||
t.Run("should handle panic", func(t *testing.T) {
|
||||
r1 := newFakeReader()
|
||||
getPanic := func(context.Context, *annotations.ItemQuery, *accesscontrol.AccessResources) ([]*annotations.ItemDTO, error) {
|
||||
getPanic := func(context.Context, annotations.ItemQuery, *accesscontrol.AccessResources) ([]*annotations.ItemDTO, error) {
|
||||
panic("ohno")
|
||||
}
|
||||
r2 := newFakeReader(withGetFn(getPanic))
|
||||
@@ -30,7 +31,7 @@ func TestCompositeStore(t *testing.T) {
|
||||
[]readStore{r1, r2},
|
||||
}
|
||||
|
||||
_, err := store.Get(context.Background(), nil, nil)
|
||||
_, err := store.Get(context.Background(), annotations.ItemQuery{}, nil)
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), "concurrent job panic")
|
||||
})
|
||||
@@ -51,11 +52,11 @@ func TestCompositeStore(t *testing.T) {
|
||||
err error
|
||||
}{
|
||||
{
|
||||
f: func() (any, error) { return store.Get(context.Background(), nil, nil) },
|
||||
f: func() (any, error) { return store.Get(context.Background(), annotations.ItemQuery{}, nil) },
|
||||
err: errGet,
|
||||
},
|
||||
{
|
||||
f: func() (any, error) { return store.GetTags(context.Background(), nil) },
|
||||
f: func() (any, error) { return store.GetTags(context.Background(), annotations.TagsQuery{}) },
|
||||
err: errGetTags,
|
||||
},
|
||||
}
|
||||
@@ -93,7 +94,7 @@ func TestCompositeStore(t *testing.T) {
|
||||
{TimeEnd: 1, Time: 1},
|
||||
}
|
||||
|
||||
items, _ := store.Get(context.Background(), nil, nil)
|
||||
items, _ := store.Get(context.Background(), annotations.ItemQuery{}, nil)
|
||||
require.Equal(t, expected, items)
|
||||
})
|
||||
|
||||
@@ -122,16 +123,40 @@ func TestCompositeStore(t *testing.T) {
|
||||
{Tag: "key2:val2"},
|
||||
}
|
||||
|
||||
res, _ := store.GetTags(context.Background(), nil)
|
||||
res, _ := store.GetTags(context.Background(), annotations.TagsQuery{})
|
||||
require.Equal(t, expected, res.Tags)
|
||||
})
|
||||
|
||||
// Check if reader is not modifying query since it might cause a race condition in case of composite store
|
||||
t.Run("should not modify query", func(t *testing.T) {
|
||||
getFn1 := func(ctx context.Context, query annotations.ItemQuery, resources *accesscontrol.AccessResources) ([]*annotations.ItemDTO, error) {
|
||||
query.From = 1
|
||||
return []*annotations.ItemDTO{}, nil
|
||||
}
|
||||
getFn2 := func(ctx context.Context, query annotations.ItemQuery, resources *accesscontrol.AccessResources) ([]*annotations.ItemDTO, error) {
|
||||
return []*annotations.ItemDTO{}, nil
|
||||
}
|
||||
|
||||
r1 := newFakeReader(withGetFn(getFn1))
|
||||
r2 := newFakeReader(withGetFn(getFn2))
|
||||
|
||||
store := &CompositeStore{
|
||||
log.NewNopLogger(),
|
||||
[]readStore{r1, r2},
|
||||
}
|
||||
|
||||
query := annotations.ItemQuery{}
|
||||
_, err := store.Get(context.Background(), query, nil)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, int64(0), query.From)
|
||||
})
|
||||
}
|
||||
|
||||
type fakeReader struct {
|
||||
items []*annotations.ItemDTO
|
||||
tagRes annotations.FindTagsResult
|
||||
getFn func(context.Context, *annotations.ItemQuery, *accesscontrol.AccessResources) ([]*annotations.ItemDTO, error)
|
||||
getTagFn func(context.Context, *annotations.TagsQuery) (annotations.FindTagsResult, error)
|
||||
getFn func(context.Context, annotations.ItemQuery, *accesscontrol.AccessResources) ([]*annotations.ItemDTO, error)
|
||||
getTagFn func(context.Context, annotations.TagsQuery) (annotations.FindTagsResult, error)
|
||||
wait time.Duration
|
||||
err error
|
||||
}
|
||||
@@ -140,7 +165,7 @@ func (f *fakeReader) Type() string {
|
||||
return "fake"
|
||||
}
|
||||
|
||||
func (f *fakeReader) Get(ctx context.Context, query *annotations.ItemQuery, accessResources *accesscontrol.AccessResources) ([]*annotations.ItemDTO, error) {
|
||||
func (f *fakeReader) Get(ctx context.Context, query annotations.ItemQuery, accessResources *accesscontrol.AccessResources) ([]*annotations.ItemDTO, error) {
|
||||
if f.getFn != nil {
|
||||
return f.getFn(ctx, query, accessResources)
|
||||
}
|
||||
@@ -157,7 +182,7 @@ func (f *fakeReader) Get(ctx context.Context, query *annotations.ItemQuery, acce
|
||||
return f.items, nil
|
||||
}
|
||||
|
||||
func (f *fakeReader) GetTags(ctx context.Context, query *annotations.TagsQuery) (annotations.FindTagsResult, error) {
|
||||
func (f *fakeReader) GetTags(ctx context.Context, query annotations.TagsQuery) (annotations.FindTagsResult, error) {
|
||||
if f.getTagFn != nil {
|
||||
return f.getTagFn(ctx, query)
|
||||
}
|
||||
@@ -198,7 +223,7 @@ func withTags(tags []*annotations.TagsDTO) func(*fakeReader) {
|
||||
}
|
||||
}
|
||||
|
||||
func withGetFn(fn func(context.Context, *annotations.ItemQuery, *accesscontrol.AccessResources) ([]*annotations.ItemDTO, error)) func(*fakeReader) {
|
||||
func withGetFn(fn func(context.Context, annotations.ItemQuery, *accesscontrol.AccessResources) ([]*annotations.ItemDTO, error)) func(*fakeReader) {
|
||||
return func(f *fakeReader) {
|
||||
f.getFn = fn
|
||||
}
|
||||
|
||||
@@ -8,23 +8,21 @@ import (
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"golang.org/x/exp/constraints"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/infra/db"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/services/annotations"
|
||||
"github.com/grafana/grafana/pkg/services/annotations/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert"
|
||||
"golang.org/x/exp/constraints"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/db"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
ngmetrics "github.com/grafana/grafana/pkg/services/ngalert/metrics"
|
||||
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/state"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/state/historian"
|
||||
historymodel "github.com/grafana/grafana/pkg/services/ngalert/state/historian/model"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/annotations"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/util/errutil"
|
||||
)
|
||||
@@ -73,7 +71,7 @@ func (r *LokiHistorianStore) Type() string {
|
||||
return "loki"
|
||||
}
|
||||
|
||||
func (r *LokiHistorianStore) Get(ctx context.Context, query *annotations.ItemQuery, accessResources *accesscontrol.AccessResources) ([]*annotations.ItemDTO, error) {
|
||||
func (r *LokiHistorianStore) Get(ctx context.Context, query annotations.ItemQuery, accessResources *accesscontrol.AccessResources) ([]*annotations.ItemDTO, error) {
|
||||
if query.Type == "annotation" {
|
||||
return make([]*annotations.ItemDTO, 0), nil
|
||||
}
|
||||
@@ -96,7 +94,7 @@ func (r *LokiHistorianStore) Get(ctx context.Context, query *annotations.ItemQue
|
||||
}
|
||||
}
|
||||
|
||||
logQL, err := historian.BuildLogQuery(buildHistoryQuery(query, accessResources.Dashboards, rule.UID))
|
||||
logQL, err := historian.BuildLogQuery(buildHistoryQuery(&query, accessResources.Dashboards, rule.UID))
|
||||
if err != nil {
|
||||
return make([]*annotations.ItemDTO, 0), ErrLokiStoreInternal.Errorf("failed to build loki query: %w", err)
|
||||
}
|
||||
@@ -178,7 +176,7 @@ func (r *LokiHistorianStore) annotationsFromStream(stream historian.Stream, ac a
|
||||
return items
|
||||
}
|
||||
|
||||
func (r *LokiHistorianStore) GetTags(ctx context.Context, query *annotations.TagsQuery) (annotations.FindTagsResult, error) {
|
||||
func (r *LokiHistorianStore) GetTags(ctx context.Context, query annotations.TagsQuery) (annotations.FindTagsResult, error) {
|
||||
return annotations.FindTagsResult{Tags: []*annotations.TagsDTO{}}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,9 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/infra/db"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
@@ -28,9 +31,6 @@ import (
|
||||
historymodel "github.com/grafana/grafana/pkg/services/ngalert/state/historian/model"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/tests/testsuite"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
@@ -100,7 +100,7 @@ func TestIntegrationAlertStateHistoryStore(t *testing.T) {
|
||||
}
|
||||
res, err := store.Get(
|
||||
context.Background(),
|
||||
&query,
|
||||
query,
|
||||
&annotation_ac.AccessResources{
|
||||
Dashboards: map[string]int64{
|
||||
dashboard1.UID: dashboard1.ID,
|
||||
@@ -126,7 +126,7 @@ func TestIntegrationAlertStateHistoryStore(t *testing.T) {
|
||||
}
|
||||
res, err := store.Get(
|
||||
context.Background(),
|
||||
&query,
|
||||
query,
|
||||
&annotation_ac.AccessResources{
|
||||
Dashboards: map[string]int64{
|
||||
dashboard1.UID: dashboard1.ID,
|
||||
@@ -150,7 +150,7 @@ func TestIntegrationAlertStateHistoryStore(t *testing.T) {
|
||||
}
|
||||
res, err := store.Get(
|
||||
context.Background(),
|
||||
&query,
|
||||
query,
|
||||
&annotation_ac.AccessResources{
|
||||
Dashboards: map[string]int64{
|
||||
dashboard1.UID: dashboard1.ID,
|
||||
@@ -176,7 +176,7 @@ func TestIntegrationAlertStateHistoryStore(t *testing.T) {
|
||||
}
|
||||
res, err := store.Get(
|
||||
context.Background(),
|
||||
&query,
|
||||
query,
|
||||
&annotation_ac.AccessResources{
|
||||
Dashboards: map[string]int64{
|
||||
dashboard1.UID: dashboard1.ID,
|
||||
@@ -206,7 +206,7 @@ func TestIntegrationAlertStateHistoryStore(t *testing.T) {
|
||||
}
|
||||
res, err := store.Get(
|
||||
context.Background(),
|
||||
&query,
|
||||
query,
|
||||
&annotation_ac.AccessResources{
|
||||
Dashboards: map[string]int64{
|
||||
dashboard1.UID: dashboard1.ID,
|
||||
@@ -235,7 +235,7 @@ func TestIntegrationAlertStateHistoryStore(t *testing.T) {
|
||||
}
|
||||
res, err := store.Get(
|
||||
context.Background(),
|
||||
&query,
|
||||
query,
|
||||
&annotation_ac.AccessResources{
|
||||
Dashboards: map[string]int64{
|
||||
dashboard1.UID: dashboard1.ID,
|
||||
@@ -269,7 +269,7 @@ func TestIntegrationAlertStateHistoryStore(t *testing.T) {
|
||||
}
|
||||
res, err := store.Get(
|
||||
context.Background(),
|
||||
&query,
|
||||
query,
|
||||
&annotation_ac.AccessResources{
|
||||
Dashboards: map[string]int64{
|
||||
dashboard1.UID: dashboard1.ID,
|
||||
|
||||
@@ -20,8 +20,8 @@ type commonStore interface {
|
||||
|
||||
type readStore interface {
|
||||
commonStore
|
||||
Get(ctx context.Context, query *annotations.ItemQuery, accessResources *accesscontrol.AccessResources) ([]*annotations.ItemDTO, error)
|
||||
GetTags(ctx context.Context, query *annotations.TagsQuery) (annotations.FindTagsResult, error)
|
||||
Get(ctx context.Context, query annotations.ItemQuery, accessResources *accesscontrol.AccessResources) ([]*annotations.ItemDTO, error)
|
||||
GetTags(ctx context.Context, query annotations.TagsQuery) (annotations.FindTagsResult, error)
|
||||
}
|
||||
|
||||
type writeStore interface {
|
||||
|
||||
@@ -245,7 +245,7 @@ func tagSet[T any](fn func(T) int64, list []T) map[int64]struct{} {
|
||||
return set
|
||||
}
|
||||
|
||||
func (r *xormRepositoryImpl) Get(ctx context.Context, query *annotations.ItemQuery, accessResources *accesscontrol.AccessResources) ([]*annotations.ItemDTO, error) {
|
||||
func (r *xormRepositoryImpl) Get(ctx context.Context, query annotations.ItemQuery, accessResources *accesscontrol.AccessResources) ([]*annotations.ItemDTO, error) {
|
||||
var sql bytes.Buffer
|
||||
params := make([]interface{}, 0)
|
||||
items := make([]*annotations.ItemDTO, 0)
|
||||
@@ -351,14 +351,16 @@ func (r *xormRepositoryImpl) Get(ctx context.Context, query *annotations.ItemQue
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sql.WriteString(fmt.Sprintf(" AND (%s)", acFilter))
|
||||
|
||||
if query.Limit == 0 {
|
||||
query.Limit = 100
|
||||
if acFilter != "" {
|
||||
sql.WriteString(fmt.Sprintf(" AND (%s)", acFilter))
|
||||
}
|
||||
|
||||
// order of ORDER BY arguments match the order of a sql index for performance
|
||||
sql.WriteString(" ORDER BY a.org_id, a.epoch_end DESC, a.epoch DESC" + r.db.GetDialect().Limit(query.Limit) + " ) dt on dt.id = annotation.id")
|
||||
orderBy := " ORDER BY a.org_id, a.epoch_end DESC, a.epoch DESC"
|
||||
if query.Limit > 0 {
|
||||
orderBy += r.db.GetDialect().Limit(query.Limit)
|
||||
}
|
||||
sql.WriteString(orderBy + " ) dt on dt.id = annotation.id")
|
||||
|
||||
if err := sess.SQL(sql.String(), params...).Find(&items); err != nil {
|
||||
items = nil
|
||||
@@ -372,6 +374,10 @@ func (r *xormRepositoryImpl) Get(ctx context.Context, query *annotations.ItemQue
|
||||
}
|
||||
|
||||
func (r *xormRepositoryImpl) getAccessControlFilter(user identity.Requester, accessResources *accesscontrol.AccessResources) (string, error) {
|
||||
if accessResources.SkipAccessControlFilter {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
var filters []string
|
||||
|
||||
if accessResources.CanAccessOrgAnnotations {
|
||||
@@ -440,7 +446,7 @@ func (r *xormRepositoryImpl) Delete(ctx context.Context, params *annotations.Del
|
||||
})
|
||||
}
|
||||
|
||||
func (r *xormRepositoryImpl) GetTags(ctx context.Context, query *annotations.TagsQuery) (annotations.FindTagsResult, error) {
|
||||
func (r *xormRepositoryImpl) GetTags(ctx context.Context, query annotations.TagsQuery) (annotations.FindTagsResult, error) {
|
||||
var items []*annotations.Tag
|
||||
err := r.db.WithDbSession(ctx, func(dbSession *db.Session) error {
|
||||
if query.Limit == 0 {
|
||||
|
||||
@@ -133,7 +133,7 @@ func TestIntegrationAnnotations(t *testing.T) {
|
||||
assert.Greater(t, organizationAnnotation2.ID, int64(0))
|
||||
|
||||
t.Run("Can query for annotation by dashboard id", func(t *testing.T) {
|
||||
items, err := store.Get(context.Background(), &annotations.ItemQuery{
|
||||
items, err := store.Get(context.Background(), annotations.ItemQuery{
|
||||
OrgID: 1,
|
||||
DashboardID: dashboard.ID,
|
||||
From: 0,
|
||||
@@ -182,7 +182,7 @@ func TestIntegrationAnnotations(t *testing.T) {
|
||||
err := store.AddMany(context.Background(), items)
|
||||
|
||||
require.NoError(t, err)
|
||||
query := &annotations.ItemQuery{OrgID: 100, SignedInUser: testUser}
|
||||
query := annotations.ItemQuery{OrgID: 100, SignedInUser: testUser}
|
||||
accRes := &annotation_ac.AccessResources{CanAccessOrgAnnotations: true}
|
||||
inserted, err := store.Get(context.Background(), query, accRes)
|
||||
require.NoError(t, err)
|
||||
@@ -209,7 +209,7 @@ func TestIntegrationAnnotations(t *testing.T) {
|
||||
err := store.AddMany(context.Background(), items)
|
||||
|
||||
require.NoError(t, err)
|
||||
query := &annotations.ItemQuery{OrgID: 101, SignedInUser: testUser}
|
||||
query := annotations.ItemQuery{OrgID: 101, SignedInUser: testUser}
|
||||
accRes := &annotation_ac.AccessResources{CanAccessOrgAnnotations: true}
|
||||
inserted, err := store.Get(context.Background(), query, accRes)
|
||||
require.NoError(t, err)
|
||||
@@ -217,7 +217,7 @@ func TestIntegrationAnnotations(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("Can query for annotation by id", func(t *testing.T) {
|
||||
items, err := store.Get(context.Background(), &annotations.ItemQuery{
|
||||
items, err := store.Get(context.Background(), annotations.ItemQuery{
|
||||
OrgID: 1,
|
||||
AnnotationID: annotation2.ID,
|
||||
SignedInUser: testUser,
|
||||
@@ -237,7 +237,7 @@ func TestIntegrationAnnotations(t *testing.T) {
|
||||
Dashboards: map[string]int64{"foo": 1},
|
||||
CanAccessDashAnnotations: true,
|
||||
}
|
||||
items, err := store.Get(context.Background(), &annotations.ItemQuery{
|
||||
items, err := store.Get(context.Background(), annotations.ItemQuery{
|
||||
OrgID: 1,
|
||||
DashboardID: 1,
|
||||
From: 12,
|
||||
@@ -253,7 +253,7 @@ func TestIntegrationAnnotations(t *testing.T) {
|
||||
Dashboards: map[string]int64{"foo": 1},
|
||||
CanAccessDashAnnotations: true,
|
||||
}
|
||||
items, err := store.Get(context.Background(), &annotations.ItemQuery{
|
||||
items, err := store.Get(context.Background(), annotations.ItemQuery{
|
||||
OrgID: 1,
|
||||
DashboardID: 1,
|
||||
From: 1,
|
||||
@@ -270,7 +270,7 @@ func TestIntegrationAnnotations(t *testing.T) {
|
||||
Dashboards: map[string]int64{"foo": 1},
|
||||
CanAccessDashAnnotations: true,
|
||||
}
|
||||
items, err := store.Get(context.Background(), &annotations.ItemQuery{
|
||||
items, err := store.Get(context.Background(), annotations.ItemQuery{
|
||||
OrgID: 1,
|
||||
DashboardID: 1,
|
||||
From: 1,
|
||||
@@ -287,7 +287,7 @@ func TestIntegrationAnnotations(t *testing.T) {
|
||||
Dashboards: map[string]int64{"foo": 1},
|
||||
CanAccessDashAnnotations: true,
|
||||
}
|
||||
items, err := store.Get(context.Background(), &annotations.ItemQuery{
|
||||
items, err := store.Get(context.Background(), annotations.ItemQuery{
|
||||
OrgID: 1,
|
||||
DashboardID: 1,
|
||||
From: 1,
|
||||
@@ -301,7 +301,7 @@ func TestIntegrationAnnotations(t *testing.T) {
|
||||
|
||||
t.Run("Should find two annotations using partial match", func(t *testing.T) {
|
||||
accRes := &annotation_ac.AccessResources{CanAccessOrgAnnotations: true}
|
||||
items, err := store.Get(context.Background(), &annotations.ItemQuery{
|
||||
items, err := store.Get(context.Background(), annotations.ItemQuery{
|
||||
OrgID: 1,
|
||||
From: 1,
|
||||
To: 25,
|
||||
@@ -318,7 +318,7 @@ func TestIntegrationAnnotations(t *testing.T) {
|
||||
Dashboards: map[string]int64{"foo": 1},
|
||||
CanAccessDashAnnotations: true,
|
||||
}
|
||||
items, err := store.Get(context.Background(), &annotations.ItemQuery{
|
||||
items, err := store.Get(context.Background(), annotations.ItemQuery{
|
||||
OrgID: 1,
|
||||
DashboardID: 1,
|
||||
From: 1,
|
||||
@@ -331,7 +331,7 @@ func TestIntegrationAnnotations(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("Can update annotation and remove all tags", func(t *testing.T) {
|
||||
query := &annotations.ItemQuery{
|
||||
query := annotations.ItemQuery{
|
||||
OrgID: 1,
|
||||
DashboardID: 1,
|
||||
From: 0,
|
||||
@@ -366,7 +366,7 @@ func TestIntegrationAnnotations(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("Can update annotation with new tags", func(t *testing.T) {
|
||||
query := &annotations.ItemQuery{
|
||||
query := annotations.ItemQuery{
|
||||
OrgID: 1,
|
||||
DashboardID: 1,
|
||||
From: 0,
|
||||
@@ -399,7 +399,7 @@ func TestIntegrationAnnotations(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("Can update annotation with additional tags", func(t *testing.T) {
|
||||
query := &annotations.ItemQuery{
|
||||
query := annotations.ItemQuery{
|
||||
OrgID: 1,
|
||||
DashboardID: 1,
|
||||
From: 0,
|
||||
@@ -432,7 +432,7 @@ func TestIntegrationAnnotations(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("Can update annotations with data", func(t *testing.T) {
|
||||
query := &annotations.ItemQuery{
|
||||
query := annotations.ItemQuery{
|
||||
OrgID: 1,
|
||||
DashboardID: 1,
|
||||
From: 0,
|
||||
@@ -468,7 +468,7 @@ func TestIntegrationAnnotations(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("Can delete annotation", func(t *testing.T) {
|
||||
query := &annotations.ItemQuery{
|
||||
query := annotations.ItemQuery{
|
||||
OrgID: 1,
|
||||
DashboardID: 1,
|
||||
From: 0,
|
||||
@@ -512,7 +512,7 @@ func TestIntegrationAnnotations(t *testing.T) {
|
||||
CanAccessDashAnnotations: true,
|
||||
}
|
||||
|
||||
query := &annotations.ItemQuery{
|
||||
query := annotations.ItemQuery{
|
||||
OrgID: 1,
|
||||
AnnotationID: annotation3.ID,
|
||||
SignedInUser: testUser,
|
||||
@@ -531,7 +531,7 @@ func TestIntegrationAnnotations(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("Should find tags by key", func(t *testing.T) {
|
||||
result, err := store.GetTags(context.Background(), &annotations.TagsQuery{
|
||||
result, err := store.GetTags(context.Background(), annotations.TagsQuery{
|
||||
OrgID: 1,
|
||||
Tag: "server",
|
||||
})
|
||||
@@ -542,7 +542,7 @@ func TestIntegrationAnnotations(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("Should find tags by value", func(t *testing.T) {
|
||||
result, err := store.GetTags(context.Background(), &annotations.TagsQuery{
|
||||
result, err := store.GetTags(context.Background(), annotations.TagsQuery{
|
||||
OrgID: 1,
|
||||
Tag: "outage",
|
||||
})
|
||||
@@ -555,7 +555,7 @@ func TestIntegrationAnnotations(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("Should not find tags in other org", func(t *testing.T) {
|
||||
result, err := store.GetTags(context.Background(), &annotations.TagsQuery{
|
||||
result, err := store.GetTags(context.Background(), annotations.TagsQuery{
|
||||
OrgID: 0,
|
||||
Tag: "server-1",
|
||||
})
|
||||
@@ -564,7 +564,7 @@ func TestIntegrationAnnotations(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("Should not find tags that do not exist", func(t *testing.T) {
|
||||
result, err := store.GetTags(context.Background(), &annotations.TagsQuery{
|
||||
result, err := store.GetTags(context.Background(), annotations.TagsQuery{
|
||||
OrgID: 0,
|
||||
Tag: "unknown:tag",
|
||||
})
|
||||
@@ -650,7 +650,7 @@ func benchmarkFindTags(b *testing.B, numAnnotations int) {
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
result, err := store.GetTags(context.Background(), &annotations.TagsQuery{
|
||||
result, err := store.GetTags(context.Background(), annotations.TagsQuery{
|
||||
OrgID: 1,
|
||||
Tag: "outage",
|
||||
})
|
||||
|
||||
@@ -21,6 +21,7 @@ type ItemQuery struct {
|
||||
SignedInUser identity.Requester
|
||||
|
||||
Limit int64 `json:"limit"`
|
||||
Page int64
|
||||
}
|
||||
|
||||
// TagsQuery is the query for a tags search.
|
||||
|
||||
@@ -84,18 +84,25 @@ func (s *OrgSync) SyncOrgRolesHook(ctx context.Context, id *authn.Identity, _ *a
|
||||
orgIDs := make([]int64, 0, len(id.OrgRoles))
|
||||
// add any new org roles
|
||||
for orgId, orgRole := range id.OrgRoles {
|
||||
orgIDs = append(orgIDs, orgId)
|
||||
if _, exists := handledOrgIds[orgId]; exists {
|
||||
orgIDs = append(orgIDs, orgId)
|
||||
continue
|
||||
}
|
||||
|
||||
// add role
|
||||
cmd := &org.AddOrgUserCommand{UserID: userID, Role: orgRole, OrgID: orgId}
|
||||
err := s.orgService.AddOrgUser(ctx, cmd)
|
||||
if err != nil && !errors.Is(err, org.ErrOrgNotFound) {
|
||||
|
||||
if errors.Is(err, org.ErrOrgNotFound) {
|
||||
continue
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
ctxLogger.Error("Failed to update active org for user", "error", err)
|
||||
return err
|
||||
}
|
||||
|
||||
orgIDs = append(orgIDs, orgId)
|
||||
}
|
||||
|
||||
// delete any removed org roles
|
||||
|
||||
@@ -22,7 +22,8 @@ import (
|
||||
)
|
||||
|
||||
func TestOrgSync_SyncOrgRolesHook(t *testing.T) {
|
||||
orgService := &orgtest.FakeOrgService{ExpectedUserOrgDTO: []*org.UserOrgDTO{
|
||||
orgService := &orgtest.MockService{}
|
||||
orgService.On("GetUserOrgList", mock.Anything, mock.Anything).Return([]*org.UserOrgDTO{
|
||||
{
|
||||
OrgID: 1,
|
||||
Role: org.RoleEditor,
|
||||
@@ -31,14 +32,16 @@ func TestOrgSync_SyncOrgRolesHook(t *testing.T) {
|
||||
OrgID: 3,
|
||||
Role: org.RoleViewer,
|
||||
},
|
||||
},
|
||||
ExpectedOrgListResponse: orgtest.OrgListResponse{
|
||||
{
|
||||
OrgID: 3,
|
||||
Response: nil,
|
||||
},
|
||||
},
|
||||
}
|
||||
}, nil)
|
||||
orgService.On("RemoveOrgUser", mock.Anything, mock.MatchedBy(func(cmd *org.RemoveOrgUserCommand) bool {
|
||||
return cmd.OrgID == 3 && cmd.UserID == 1
|
||||
})).Return(nil)
|
||||
orgService.On("UpdateOrgUser", mock.Anything, mock.MatchedBy(func(cmd *org.UpdateOrgUserCommand) bool {
|
||||
return cmd.OrgID == 1 && cmd.UserID == 1 && cmd.Role == org.RoleAdmin
|
||||
})).Return(nil)
|
||||
orgService.On("AddOrgUser", mock.Anything, mock.MatchedBy(func(cmd *org.AddOrgUserCommand) bool {
|
||||
return cmd.OrgID == 2 && cmd.UserID == 1 && cmd.Role == org.RoleEditor
|
||||
})).Return(org.ErrOrgNotFound)
|
||||
acService := &actest.FakeService{}
|
||||
userService := &usertest.FakeUserService{ExpectedUser: &user.User{
|
||||
ID: 1,
|
||||
@@ -65,7 +68,7 @@ func TestOrgSync_SyncOrgRolesHook(t *testing.T) {
|
||||
wantID *authn.Identity
|
||||
}{
|
||||
{
|
||||
name: "add user to multiple orgs",
|
||||
name: "add user to multiple orgs, should not set the user's default orgID to an org that does not exist",
|
||||
fields: fields{
|
||||
userService: userService,
|
||||
orgService: orgService,
|
||||
@@ -96,7 +99,7 @@ func TestOrgSync_SyncOrgRolesHook(t *testing.T) {
|
||||
Name: "test",
|
||||
Email: "test",
|
||||
OrgRoles: map[int64]roletype.RoleType{1: org.RoleAdmin, 2: org.RoleEditor},
|
||||
OrgID: 1, //set using org
|
||||
OrgID: 1, // set using org
|
||||
IsGrafanaAdmin: ptrBool(false),
|
||||
ClientParams: authn.ClientParams{
|
||||
SyncOrgRoles: true,
|
||||
|
||||
@@ -2,10 +2,9 @@ package correlations
|
||||
|
||||
import (
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
)
|
||||
|
||||
var (
|
||||
// ConfigurationPageAccess is used to protect the "Configure > correlations" tab access
|
||||
ConfigurationPageAccess = accesscontrol.EvalPermission(datasources.ActionRead)
|
||||
ConfigurationPageAccess = accesscontrol.EvalPermission(accesscontrol.ActionDatasourcesExplore)
|
||||
)
|
||||
|
||||
@@ -751,9 +751,7 @@ func (d *dashboardStore) FindDashboards(ctx context.Context, query *dashboards.F
|
||||
return nil, err
|
||||
}
|
||||
|
||||
filters := []any{
|
||||
permissions.NewAccessControlDashboardPermissionFilter(query.SignedInUser, query.Permission, query.Type, d.features, recursiveQueriesAreSupported),
|
||||
}
|
||||
filters := []any{}
|
||||
|
||||
for _, filter := range query.Sort.Filter {
|
||||
filters = append(filters, filter)
|
||||
@@ -802,6 +800,8 @@ func (d *dashboardStore) FindDashboards(ctx context.Context, query *dashboards.F
|
||||
})
|
||||
}
|
||||
|
||||
filters = append(filters, permissions.NewAccessControlDashboardPermissionFilter(query.SignedInUser, query.Permission, query.Type, d.features, recursiveQueriesAreSupported))
|
||||
|
||||
var res []dashboards.DashboardSearchProjection
|
||||
sb := &searchstore.Builder{Dialect: d.store.GetDialect(), Filters: filters, Features: d.features}
|
||||
|
||||
|
||||
@@ -98,6 +98,11 @@ func ProvideService(plugCtxProvider *plugincontext.Provider, cfg *setting.Cfg, r
|
||||
},
|
||||
usageStatsService: usageStatsService,
|
||||
orgService: orgService,
|
||||
keyPrefix: "gf_live",
|
||||
}
|
||||
|
||||
if cfg.LiveHAPrefix != "" {
|
||||
g.keyPrefix = cfg.LiveHAPrefix + ".gf_live"
|
||||
}
|
||||
|
||||
logger.Debug("GrafanaLive initialization", "ha", g.IsHA())
|
||||
@@ -153,7 +158,7 @@ func ProvideService(plugCtxProvider *plugincontext.Provider, cfg *setting.Cfg, r
|
||||
managedStreamRunner = managedstream.NewRunner(
|
||||
g.Publish,
|
||||
channelLocalPublisher,
|
||||
managedstream.NewRedisFrameCache(redisClient),
|
||||
managedstream.NewRedisFrameCache(redisClient, g.keyPrefix),
|
||||
)
|
||||
} else {
|
||||
managedStreamRunner = managedstream.NewRunner(
|
||||
@@ -343,7 +348,7 @@ func setupRedisLiveEngine(g *GrafanaLive, node *centrifuge.Node) error {
|
||||
}
|
||||
|
||||
broker, err := centrifuge.NewRedisBroker(node, centrifuge.RedisBrokerConfig{
|
||||
Prefix: "gf_live",
|
||||
Prefix: g.keyPrefix,
|
||||
Shards: redisShards,
|
||||
})
|
||||
if err != nil {
|
||||
@@ -352,7 +357,7 @@ func setupRedisLiveEngine(g *GrafanaLive, node *centrifuge.Node) error {
|
||||
node.SetBroker(broker)
|
||||
|
||||
presenceManager, err := centrifuge.NewRedisPresenceManager(node, centrifuge.RedisPresenceManagerConfig{
|
||||
Prefix: "gf_live",
|
||||
Prefix: g.keyPrefix,
|
||||
Shards: redisShards,
|
||||
})
|
||||
if err != nil {
|
||||
@@ -381,6 +386,8 @@ type GrafanaLive struct {
|
||||
queryDataService query.Service
|
||||
orgService org.Service
|
||||
|
||||
keyPrefix string
|
||||
|
||||
node *centrifuge.Node
|
||||
surveyCaller *survey.Caller
|
||||
|
||||
|
||||
@@ -18,11 +18,13 @@ type RedisFrameCache struct {
|
||||
mu sync.RWMutex
|
||||
redisClient *redis.Client
|
||||
frames map[int64]map[string]data.FrameJSONCache
|
||||
keyPrefix string
|
||||
}
|
||||
|
||||
// NewRedisFrameCache ...
|
||||
func NewRedisFrameCache(redisClient *redis.Client) *RedisFrameCache {
|
||||
func NewRedisFrameCache(redisClient *redis.Client, keyPrefix string) *RedisFrameCache {
|
||||
return &RedisFrameCache{
|
||||
keyPrefix: keyPrefix,
|
||||
frames: map[int64]map[string]data.FrameJSONCache{},
|
||||
redisClient: redisClient,
|
||||
}
|
||||
@@ -43,7 +45,7 @@ func (c *RedisFrameCache) GetActiveChannels(orgID int64) (map[string]json.RawMes
|
||||
}
|
||||
|
||||
func (c *RedisFrameCache) GetFrame(ctx context.Context, orgID int64, channel string) (json.RawMessage, bool, error) {
|
||||
key := getCacheKey(orgchannel.PrependOrgID(orgID, channel))
|
||||
key := c.getCacheKey(orgchannel.PrependOrgID(orgID, channel))
|
||||
cmd := c.redisClient.HGetAll(ctx, key)
|
||||
result, err := cmd.Result()
|
||||
if err != nil {
|
||||
@@ -69,7 +71,7 @@ func (c *RedisFrameCache) Update(ctx context.Context, orgID int64, channel strin
|
||||
|
||||
stringSchema := string(jsonFrame.Bytes(data.IncludeSchemaOnly))
|
||||
|
||||
key := getCacheKey(orgchannel.PrependOrgID(orgID, channel))
|
||||
key := c.getCacheKey(orgchannel.PrependOrgID(orgID, channel))
|
||||
|
||||
pipe := c.redisClient.TxPipeline()
|
||||
defer func() { _ = pipe.Close() }()
|
||||
@@ -107,6 +109,6 @@ func (c *RedisFrameCache) Update(ctx context.Context, orgID int64, channel strin
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func getCacheKey(channelID string) string {
|
||||
return "gf_live.managed_stream." + channelID
|
||||
func (c *RedisFrameCache) getCacheKey(channelID string) string {
|
||||
return c.keyPrefix + ".managed_stream." + channelID
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/google/uuid"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
@@ -30,7 +31,25 @@ func TestIntegrationRedisCacheStorage(t *testing.T) {
|
||||
Addr: addr,
|
||||
DB: db,
|
||||
})
|
||||
c := NewRedisFrameCache(redisClient)
|
||||
prefix := uuid.New().String()
|
||||
|
||||
t.Cleanup(redisCleanup(t, redisClient, prefix))
|
||||
|
||||
c := NewRedisFrameCache(redisClient, prefix)
|
||||
require.NotNil(t, c)
|
||||
testFrameCache(t, c)
|
||||
}
|
||||
|
||||
func redisCleanup(t *testing.T, redisClient *redis.Client, prefix string) func() {
|
||||
return func() {
|
||||
keys, err := redisClient.Keys(redisClient.Context(), prefix+"*").Result()
|
||||
if err != nil {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
for _, key := range keys {
|
||||
_, err := redisClient.Del(redisClient.Context(), key).Result()
|
||||
require.NoError(t, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
)
|
||||
|
||||
//go:generate mockery --name Service --structname MockService --outpkg orgtest --filename mock.go --output ./orgtest/
|
||||
type Service interface {
|
||||
GetIDForNewUser(context.Context, GetOrgIDForNewUserCommand) (int64, error)
|
||||
InsertOrgUser(context.Context, *OrgUser) (int64, error)
|
||||
|
||||
@@ -0,0 +1,454 @@
|
||||
// Code generated by mockery v2.42.1. DO NOT EDIT.
|
||||
|
||||
package orgtest
|
||||
|
||||
import (
|
||||
context "context"
|
||||
|
||||
org "github.com/grafana/grafana/pkg/services/org"
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
// MockService is an autogenerated mock type for the Service type
|
||||
type MockService struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// AddOrgUser provides a mock function with given fields: _a0, _a1
|
||||
func (_m *MockService) AddOrgUser(_a0 context.Context, _a1 *org.AddOrgUserCommand) error {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for AddOrgUser")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *org.AddOrgUserCommand) error); ok {
|
||||
r0 = rf(_a0, _a1)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// CreateWithMember provides a mock function with given fields: _a0, _a1
|
||||
func (_m *MockService) CreateWithMember(_a0 context.Context, _a1 *org.CreateOrgCommand) (*org.Org, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for CreateWithMember")
|
||||
}
|
||||
|
||||
var r0 *org.Org
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *org.CreateOrgCommand) (*org.Org, error)); ok {
|
||||
return rf(_a0, _a1)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *org.CreateOrgCommand) *org.Org); ok {
|
||||
r0 = rf(_a0, _a1)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*org.Org)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *org.CreateOrgCommand) error); ok {
|
||||
r1 = rf(_a0, _a1)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Delete provides a mock function with given fields: _a0, _a1
|
||||
func (_m *MockService) Delete(_a0 context.Context, _a1 *org.DeleteOrgCommand) error {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for Delete")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *org.DeleteOrgCommand) error); ok {
|
||||
r0 = rf(_a0, _a1)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// DeleteUserFromAll provides a mock function with given fields: _a0, _a1
|
||||
func (_m *MockService) DeleteUserFromAll(_a0 context.Context, _a1 int64) error {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for DeleteUserFromAll")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok {
|
||||
r0 = rf(_a0, _a1)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// GetByID provides a mock function with given fields: _a0, _a1
|
||||
func (_m *MockService) GetByID(_a0 context.Context, _a1 *org.GetOrgByIDQuery) (*org.Org, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetByID")
|
||||
}
|
||||
|
||||
var r0 *org.Org
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *org.GetOrgByIDQuery) (*org.Org, error)); ok {
|
||||
return rf(_a0, _a1)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *org.GetOrgByIDQuery) *org.Org); ok {
|
||||
r0 = rf(_a0, _a1)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*org.Org)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *org.GetOrgByIDQuery) error); ok {
|
||||
r1 = rf(_a0, _a1)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetByName provides a mock function with given fields: _a0, _a1
|
||||
func (_m *MockService) GetByName(_a0 context.Context, _a1 *org.GetOrgByNameQuery) (*org.Org, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetByName")
|
||||
}
|
||||
|
||||
var r0 *org.Org
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *org.GetOrgByNameQuery) (*org.Org, error)); ok {
|
||||
return rf(_a0, _a1)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *org.GetOrgByNameQuery) *org.Org); ok {
|
||||
r0 = rf(_a0, _a1)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*org.Org)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *org.GetOrgByNameQuery) error); ok {
|
||||
r1 = rf(_a0, _a1)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetIDForNewUser provides a mock function with given fields: _a0, _a1
|
||||
func (_m *MockService) GetIDForNewUser(_a0 context.Context, _a1 org.GetOrgIDForNewUserCommand) (int64, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetIDForNewUser")
|
||||
}
|
||||
|
||||
var r0 int64
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, org.GetOrgIDForNewUserCommand) (int64, error)); ok {
|
||||
return rf(_a0, _a1)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, org.GetOrgIDForNewUserCommand) int64); ok {
|
||||
r0 = rf(_a0, _a1)
|
||||
} else {
|
||||
r0 = ret.Get(0).(int64)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, org.GetOrgIDForNewUserCommand) error); ok {
|
||||
r1 = rf(_a0, _a1)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetOrCreate provides a mock function with given fields: _a0, _a1
|
||||
func (_m *MockService) GetOrCreate(_a0 context.Context, _a1 string) (int64, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetOrCreate")
|
||||
}
|
||||
|
||||
var r0 int64
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string) (int64, error)); ok {
|
||||
return rf(_a0, _a1)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string) int64); ok {
|
||||
r0 = rf(_a0, _a1)
|
||||
} else {
|
||||
r0 = ret.Get(0).(int64)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
|
||||
r1 = rf(_a0, _a1)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetOrgUsers provides a mock function with given fields: _a0, _a1
|
||||
func (_m *MockService) GetOrgUsers(_a0 context.Context, _a1 *org.GetOrgUsersQuery) ([]*org.OrgUserDTO, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetOrgUsers")
|
||||
}
|
||||
|
||||
var r0 []*org.OrgUserDTO
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *org.GetOrgUsersQuery) ([]*org.OrgUserDTO, error)); ok {
|
||||
return rf(_a0, _a1)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *org.GetOrgUsersQuery) []*org.OrgUserDTO); ok {
|
||||
r0 = rf(_a0, _a1)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*org.OrgUserDTO)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *org.GetOrgUsersQuery) error); ok {
|
||||
r1 = rf(_a0, _a1)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetUserOrgList provides a mock function with given fields: _a0, _a1
|
||||
func (_m *MockService) GetUserOrgList(_a0 context.Context, _a1 *org.GetUserOrgListQuery) ([]*org.UserOrgDTO, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetUserOrgList")
|
||||
}
|
||||
|
||||
var r0 []*org.UserOrgDTO
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *org.GetUserOrgListQuery) ([]*org.UserOrgDTO, error)); ok {
|
||||
return rf(_a0, _a1)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *org.GetUserOrgListQuery) []*org.UserOrgDTO); ok {
|
||||
r0 = rf(_a0, _a1)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*org.UserOrgDTO)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *org.GetUserOrgListQuery) error); ok {
|
||||
r1 = rf(_a0, _a1)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// InsertOrgUser provides a mock function with given fields: _a0, _a1
|
||||
func (_m *MockService) InsertOrgUser(_a0 context.Context, _a1 *org.OrgUser) (int64, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for InsertOrgUser")
|
||||
}
|
||||
|
||||
var r0 int64
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *org.OrgUser) (int64, error)); ok {
|
||||
return rf(_a0, _a1)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *org.OrgUser) int64); ok {
|
||||
r0 = rf(_a0, _a1)
|
||||
} else {
|
||||
r0 = ret.Get(0).(int64)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *org.OrgUser) error); ok {
|
||||
r1 = rf(_a0, _a1)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// RegisterDelete provides a mock function with given fields: query
|
||||
func (_m *MockService) RegisterDelete(query string) {
|
||||
_m.Called(query)
|
||||
}
|
||||
|
||||
// RemoveOrgUser provides a mock function with given fields: _a0, _a1
|
||||
func (_m *MockService) RemoveOrgUser(_a0 context.Context, _a1 *org.RemoveOrgUserCommand) error {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for RemoveOrgUser")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *org.RemoveOrgUserCommand) error); ok {
|
||||
r0 = rf(_a0, _a1)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// Search provides a mock function with given fields: _a0, _a1
|
||||
func (_m *MockService) Search(_a0 context.Context, _a1 *org.SearchOrgsQuery) ([]*org.OrgDTO, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for Search")
|
||||
}
|
||||
|
||||
var r0 []*org.OrgDTO
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *org.SearchOrgsQuery) ([]*org.OrgDTO, error)); ok {
|
||||
return rf(_a0, _a1)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *org.SearchOrgsQuery) []*org.OrgDTO); ok {
|
||||
r0 = rf(_a0, _a1)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*org.OrgDTO)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *org.SearchOrgsQuery) error); ok {
|
||||
r1 = rf(_a0, _a1)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// SearchOrgUsers provides a mock function with given fields: _a0, _a1
|
||||
func (_m *MockService) SearchOrgUsers(_a0 context.Context, _a1 *org.SearchOrgUsersQuery) (*org.SearchOrgUsersQueryResult, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for SearchOrgUsers")
|
||||
}
|
||||
|
||||
var r0 *org.SearchOrgUsersQueryResult
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *org.SearchOrgUsersQuery) (*org.SearchOrgUsersQueryResult, error)); ok {
|
||||
return rf(_a0, _a1)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *org.SearchOrgUsersQuery) *org.SearchOrgUsersQueryResult); ok {
|
||||
r0 = rf(_a0, _a1)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*org.SearchOrgUsersQueryResult)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *org.SearchOrgUsersQuery) error); ok {
|
||||
r1 = rf(_a0, _a1)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// UpdateAddress provides a mock function with given fields: _a0, _a1
|
||||
func (_m *MockService) UpdateAddress(_a0 context.Context, _a1 *org.UpdateOrgAddressCommand) error {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for UpdateAddress")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *org.UpdateOrgAddressCommand) error); ok {
|
||||
r0 = rf(_a0, _a1)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// UpdateOrg provides a mock function with given fields: _a0, _a1
|
||||
func (_m *MockService) UpdateOrg(_a0 context.Context, _a1 *org.UpdateOrgCommand) error {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for UpdateOrg")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *org.UpdateOrgCommand) error); ok {
|
||||
r0 = rf(_a0, _a1)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// UpdateOrgUser provides a mock function with given fields: _a0, _a1
|
||||
func (_m *MockService) UpdateOrgUser(_a0 context.Context, _a1 *org.UpdateOrgUserCommand) error {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for UpdateOrgUser")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *org.UpdateOrgUserCommand) error); ok {
|
||||
r0 = rf(_a0, _a1)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// NewMockService creates a new instance of MockService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
// The first argument is typically a *testing.T value.
|
||||
func NewMockService(t interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}) *MockService {
|
||||
mock := &MockService{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
||||
@@ -26,7 +26,9 @@ const (
|
||||
)
|
||||
|
||||
type ServiceAccountsService struct {
|
||||
acService accesscontrol.Service
|
||||
acService accesscontrol.Service
|
||||
permissions accesscontrol.ServiceAccountPermissionsService
|
||||
|
||||
store store
|
||||
log log.Logger
|
||||
backgroundLog log.Logger
|
||||
@@ -44,7 +46,8 @@ func ProvideServiceAccountsService(
|
||||
kvStore kvstore.KVStore,
|
||||
userService user.Service,
|
||||
orgService org.Service,
|
||||
accesscontrolService accesscontrol.Service,
|
||||
acService accesscontrol.Service,
|
||||
permissions accesscontrol.ServiceAccountPermissionsService,
|
||||
) (*ServiceAccountsService, error) {
|
||||
serviceAccountsStore := database.ProvideServiceAccountsStore(
|
||||
cfg,
|
||||
@@ -55,13 +58,14 @@ func ProvideServiceAccountsService(
|
||||
orgService,
|
||||
)
|
||||
s := &ServiceAccountsService{
|
||||
acService: accesscontrolService,
|
||||
acService: acService,
|
||||
permissions: permissions,
|
||||
store: serviceAccountsStore,
|
||||
log: log.New("serviceaccounts"),
|
||||
backgroundLog: log.New("serviceaccounts.background"),
|
||||
}
|
||||
|
||||
if err := RegisterRoles(accesscontrolService); err != nil {
|
||||
if err := RegisterRoles(acService); err != nil {
|
||||
s.log.Error("Failed to register roles", "error", err)
|
||||
}
|
||||
|
||||
@@ -179,7 +183,10 @@ func (sa *ServiceAccountsService) DeleteServiceAccount(ctx context.Context, orgI
|
||||
if err := sa.store.DeleteServiceAccount(ctx, orgID, serviceAccountID); err != nil {
|
||||
return err
|
||||
}
|
||||
return sa.acService.DeleteUserPermissions(ctx, orgID, serviceAccountID)
|
||||
if err := sa.acService.DeleteUserPermissions(ctx, orgID, serviceAccountID); err != nil {
|
||||
return err
|
||||
}
|
||||
return sa.permissions.DeleteResourcePermissions(ctx, orgID, fmt.Sprintf("%d", serviceAccountID))
|
||||
}
|
||||
|
||||
func (sa *ServiceAccountsService) EnableServiceAccount(ctx context.Context, orgID, serviceAccountID int64, enable bool) error {
|
||||
|
||||
@@ -119,7 +119,8 @@ func (f *SecretsCheckerFake) CheckTokens(ctx context.Context) error {
|
||||
func TestProvideServiceAccount_DeleteServiceAccount(t *testing.T) {
|
||||
storeMock := newServiceAccountStoreFake()
|
||||
acSvc := actest.FakeService{}
|
||||
svc := ServiceAccountsService{acSvc, storeMock, log.New("test"), log.New("background.test"), &SecretsCheckerFake{}, false, 0}
|
||||
pSvc := &actest.FakePermissionsService{}
|
||||
svc := ServiceAccountsService{acSvc, pSvc, storeMock, log.NewNopLogger(), log.NewNopLogger(), &SecretsCheckerFake{}, false, 0}
|
||||
testOrgId := 1
|
||||
|
||||
t.Run("should create service account", func(t *testing.T) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user