Merge branch 'main' into 20230331_add_kerberos_support
This commit is contained in:
+16
-9
@@ -200,9 +200,6 @@ exports[`better eslint`] = {
|
|||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "6"],
|
[0, 0, 0, "Unexpected any. Specify a different type.", "6"],
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "7"]
|
[0, 0, 0, "Unexpected any. Specify a different type.", "7"]
|
||||||
],
|
],
|
||||||
"packages/grafana-data/src/field/templateProxies.ts:5381": [
|
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
|
||||||
],
|
|
||||||
"packages/grafana-data/src/geo/layer.ts:5381": [
|
"packages/grafana-data/src/geo/layer.ts:5381": [
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||||
],
|
],
|
||||||
@@ -2523,8 +2520,7 @@ exports[`better eslint`] = {
|
|||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "3"],
|
[0, 0, 0, "Unexpected any. Specify a different type.", "3"],
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "4"],
|
[0, 0, 0, "Unexpected any. Specify a different type.", "4"],
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "5"],
|
[0, 0, 0, "Unexpected any. Specify a different type.", "5"],
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "6"],
|
[0, 0, 0, "Unexpected any. Specify a different type.", "6"]
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "7"]
|
|
||||||
],
|
],
|
||||||
"public/app/features/dashboard/state/DashboardModel.test.ts:5381": [
|
"public/app/features/dashboard/state/DashboardModel.test.ts:5381": [
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||||
@@ -3353,6 +3349,9 @@ exports[`better eslint`] = {
|
|||||||
"public/app/features/teams/state/selectors.ts:5381": [
|
"public/app/features/teams/state/selectors.ts:5381": [
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||||
],
|
],
|
||||||
|
"public/app/features/templating/fieldAccessorCache.ts:5381": [
|
||||||
|
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||||
|
],
|
||||||
"public/app/features/templating/formatVariableValue.ts:5381": [
|
"public/app/features/templating/formatVariableValue.ts:5381": [
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
|
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "1"],
|
[0, 0, 0, "Unexpected any. Specify a different type.", "1"],
|
||||||
@@ -3361,6 +3360,9 @@ exports[`better eslint`] = {
|
|||||||
"public/app/features/templating/macroRegistry.test.ts:5381": [
|
"public/app/features/templating/macroRegistry.test.ts:5381": [
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||||
],
|
],
|
||||||
|
"public/app/features/templating/templateProxies.ts:5381": [
|
||||||
|
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||||
|
],
|
||||||
"public/app/features/templating/template_srv.mock.ts:5381": [
|
"public/app/features/templating/template_srv.mock.ts:5381": [
|
||||||
[0, 0, 0, "Do not use any type assertions.", "0"]
|
[0, 0, 0, "Do not use any type assertions.", "0"]
|
||||||
],
|
],
|
||||||
@@ -3377,11 +3379,9 @@ exports[`better eslint`] = {
|
|||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "9"],
|
[0, 0, 0, "Unexpected any. Specify a different type.", "9"],
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "10"],
|
[0, 0, 0, "Unexpected any. Specify a different type.", "10"],
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "11"],
|
[0, 0, 0, "Unexpected any. Specify a different type.", "11"],
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "12"],
|
[0, 0, 0, "Do not use any type assertions.", "12"],
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "13"],
|
[0, 0, 0, "Unexpected any. Specify a different type.", "13"],
|
||||||
[0, 0, 0, "Do not use any type assertions.", "14"],
|
[0, 0, 0, "Do not use any type assertions.", "14"]
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "15"],
|
|
||||||
[0, 0, 0, "Do not use any type assertions.", "16"]
|
|
||||||
],
|
],
|
||||||
"public/app/features/transformers/FilterByValueTransformer/ValueMatchers/BasicMatcherEditor.tsx:5381": [
|
"public/app/features/transformers/FilterByValueTransformer/ValueMatchers/BasicMatcherEditor.tsx:5381": [
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
|
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
|
||||||
@@ -5264,6 +5264,9 @@ exports[`better eslint`] = {
|
|||||||
[0, 0, 0, "Do not use any type assertions.", "1"],
|
[0, 0, 0, "Do not use any type assertions.", "1"],
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "2"]
|
[0, 0, 0, "Unexpected any. Specify a different type.", "2"]
|
||||||
],
|
],
|
||||||
|
"public/app/plugins/panel/flamegraph/components/FlameGraphTopWrapper.tsx:5381": [
|
||||||
|
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||||
|
],
|
||||||
"public/app/plugins/panel/gauge/GaugeMigrations.ts:5381": [
|
"public/app/plugins/panel/gauge/GaugeMigrations.ts:5381": [
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||||
],
|
],
|
||||||
@@ -6010,6 +6013,10 @@ exports[`better eslint`] = {
|
|||||||
[0, 0, 0, "Do not use any type assertions.", "0"],
|
[0, 0, 0, "Do not use any type assertions.", "0"],
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "1"]
|
[0, 0, 0, "Unexpected any. Specify a different type.", "1"]
|
||||||
],
|
],
|
||||||
|
"public/app/plugins/panel/trend/suggestions.ts:5381": [
|
||||||
|
[0, 0, 0, "Do not use any type assertions.", "0"],
|
||||||
|
[0, 0, 0, "Unexpected any. Specify a different type.", "1"]
|
||||||
|
],
|
||||||
"public/app/plugins/panel/xychart/AutoEditor.tsx:5381": [
|
"public/app/plugins/panel/xychart/AutoEditor.tsx:5381": [
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||||
],
|
],
|
||||||
|
|||||||
+111
-11
@@ -797,6 +797,12 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- name: mysql
|
- name: mysql
|
||||||
path: /var/lib/mysql
|
path: /var/lib/mysql
|
||||||
|
- environment: {}
|
||||||
|
image: redis:6.2.11-alpine
|
||||||
|
name: redis
|
||||||
|
- environment: {}
|
||||||
|
image: memcached:1.6.9-alpine
|
||||||
|
name: memcached
|
||||||
steps:
|
steps:
|
||||||
- commands:
|
- commands:
|
||||||
- is_fork=$(curl "https://$GITHUB_TOKEN@api.github.com/repos/grafana/grafana/pulls/$DRONE_PULL_REQUEST"
|
- is_fork=$(curl "https://$GITHUB_TOKEN@api.github.com/repos/grafana/grafana/pulls/$DRONE_PULL_REQUEST"
|
||||||
@@ -892,6 +898,26 @@ steps:
|
|||||||
MYSQL_HOST: mysql
|
MYSQL_HOST: mysql
|
||||||
image: grafana/build-container:1.7.2
|
image: grafana/build-container:1.7.2
|
||||||
name: mysql-integration-tests
|
name: mysql-integration-tests
|
||||||
|
- commands:
|
||||||
|
- dockerize -wait tcp://redis:6379/0 -timeout 120s
|
||||||
|
- go clean -testcache
|
||||||
|
- go test -run IntegrationRedis -covermode=atomic -timeout=2m ./pkg/...
|
||||||
|
depends_on:
|
||||||
|
- wire-install
|
||||||
|
environment:
|
||||||
|
REDIS_URL: redis://redis:6379/0
|
||||||
|
image: grafana/build-container:1.7.2
|
||||||
|
name: redis-integration-tests
|
||||||
|
- commands:
|
||||||
|
- dockerize -wait tcp://memcached:11211 -timeout 120s
|
||||||
|
- go clean -testcache
|
||||||
|
- go test -run IntegrationMemcached -covermode=atomic -timeout=2m ./pkg/...
|
||||||
|
depends_on:
|
||||||
|
- wire-install
|
||||||
|
environment:
|
||||||
|
MEMCACHED_HOSTS: memcached:11211
|
||||||
|
image: grafana/build-container:1.7.2
|
||||||
|
name: memcached-integration-tests
|
||||||
trigger:
|
trigger:
|
||||||
event:
|
event:
|
||||||
- pull_request
|
- pull_request
|
||||||
@@ -1797,6 +1823,12 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- name: mysql
|
- name: mysql
|
||||||
path: /var/lib/mysql
|
path: /var/lib/mysql
|
||||||
|
- environment: {}
|
||||||
|
image: redis:6.2.11-alpine
|
||||||
|
name: redis
|
||||||
|
- environment: {}
|
||||||
|
image: memcached:1.6.9-alpine
|
||||||
|
name: memcached
|
||||||
steps:
|
steps:
|
||||||
- commands:
|
- commands:
|
||||||
- mkdir -p bin
|
- mkdir -p bin
|
||||||
@@ -1870,6 +1902,26 @@ steps:
|
|||||||
MYSQL_HOST: mysql
|
MYSQL_HOST: mysql
|
||||||
image: grafana/build-container:1.7.2
|
image: grafana/build-container:1.7.2
|
||||||
name: mysql-integration-tests
|
name: mysql-integration-tests
|
||||||
|
- commands:
|
||||||
|
- dockerize -wait tcp://redis:6379/0 -timeout 120s
|
||||||
|
- go clean -testcache
|
||||||
|
- go test -run IntegrationRedis -covermode=atomic -timeout=2m ./pkg/...
|
||||||
|
depends_on:
|
||||||
|
- wire-install
|
||||||
|
environment:
|
||||||
|
REDIS_URL: redis://redis:6379/0
|
||||||
|
image: grafana/build-container:1.7.2
|
||||||
|
name: redis-integration-tests
|
||||||
|
- commands:
|
||||||
|
- dockerize -wait tcp://memcached:11211 -timeout 120s
|
||||||
|
- go clean -testcache
|
||||||
|
- go test -run IntegrationMemcached -covermode=atomic -timeout=2m ./pkg/...
|
||||||
|
depends_on:
|
||||||
|
- wire-install
|
||||||
|
environment:
|
||||||
|
MEMCACHED_HOSTS: memcached:11211
|
||||||
|
image: grafana/build-container:1.7.2
|
||||||
|
name: memcached-integration-tests
|
||||||
trigger:
|
trigger:
|
||||||
branch: main
|
branch: main
|
||||||
event:
|
event:
|
||||||
@@ -4956,6 +5008,12 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- name: mysql
|
- name: mysql
|
||||||
path: /var/lib/mysql
|
path: /var/lib/mysql
|
||||||
|
- environment: {}
|
||||||
|
image: redis:6.2.11-alpine
|
||||||
|
name: redis
|
||||||
|
- environment: {}
|
||||||
|
image: memcached:1.6.9-alpine
|
||||||
|
name: memcached
|
||||||
steps:
|
steps:
|
||||||
- commands:
|
- commands:
|
||||||
- mkdir -p bin
|
- mkdir -p bin
|
||||||
@@ -5022,6 +5080,26 @@ steps:
|
|||||||
MYSQL_HOST: mysql
|
MYSQL_HOST: mysql
|
||||||
image: grafana/build-container:1.7.2
|
image: grafana/build-container:1.7.2
|
||||||
name: mysql-integration-tests
|
name: mysql-integration-tests
|
||||||
|
- commands:
|
||||||
|
- dockerize -wait tcp://redis:6379/0 -timeout 120s
|
||||||
|
- go clean -testcache
|
||||||
|
- go test -run IntegrationRedis -covermode=atomic -timeout=2m ./pkg/...
|
||||||
|
depends_on:
|
||||||
|
- wire-install
|
||||||
|
environment:
|
||||||
|
REDIS_URL: redis://redis:6379/0
|
||||||
|
image: grafana/build-container:1.7.2
|
||||||
|
name: redis-integration-tests
|
||||||
|
- commands:
|
||||||
|
- dockerize -wait tcp://memcached:11211 -timeout 120s
|
||||||
|
- go clean -testcache
|
||||||
|
- go test -run IntegrationMemcached -covermode=atomic -timeout=2m ./pkg/...
|
||||||
|
depends_on:
|
||||||
|
- wire-install
|
||||||
|
environment:
|
||||||
|
MEMCACHED_HOSTS: memcached:11211
|
||||||
|
image: grafana/build-container:1.7.2
|
||||||
|
name: memcached-integration-tests
|
||||||
trigger:
|
trigger:
|
||||||
ref:
|
ref:
|
||||||
- refs/heads/v[0-9]*
|
- refs/heads/v[0-9]*
|
||||||
@@ -5617,7 +5695,7 @@ services:
|
|||||||
- name: mysql
|
- name: mysql
|
||||||
path: /var/lib/mysql
|
path: /var/lib/mysql
|
||||||
- environment: {}
|
- environment: {}
|
||||||
image: redis:6.2.1-alpine
|
image: redis:6.2.11-alpine
|
||||||
name: redis
|
name: redis
|
||||||
- environment: {}
|
- environment: {}
|
||||||
image: memcached:1.6.9-alpine
|
image: memcached:1.6.9-alpine
|
||||||
@@ -5718,8 +5796,7 @@ steps:
|
|||||||
- commands:
|
- commands:
|
||||||
- dockerize -wait tcp://redis:6379/0 -timeout 120s
|
- dockerize -wait tcp://redis:6379/0 -timeout 120s
|
||||||
- go clean -testcache
|
- go clean -testcache
|
||||||
- go list './pkg/...' | xargs -I {} sh -c 'go test -run Integration -covermode=atomic
|
- go test -run IntegrationRedis -covermode=atomic -timeout=2m ./pkg/...
|
||||||
-timeout=5m {}'
|
|
||||||
depends_on:
|
depends_on:
|
||||||
- wire-install
|
- wire-install
|
||||||
environment:
|
environment:
|
||||||
@@ -5729,8 +5806,7 @@ steps:
|
|||||||
- commands:
|
- commands:
|
||||||
- dockerize -wait tcp://memcached:11211 -timeout 120s
|
- dockerize -wait tcp://memcached:11211 -timeout 120s
|
||||||
- go clean -testcache
|
- go clean -testcache
|
||||||
- go list './pkg/...' | xargs -I {} sh -c 'go test -run Integration -covermode=atomic
|
- go test -run IntegrationMemcached -covermode=atomic -timeout=2m ./pkg/...
|
||||||
-timeout=5m {}'
|
|
||||||
depends_on:
|
depends_on:
|
||||||
- wire-install
|
- wire-install
|
||||||
environment:
|
environment:
|
||||||
@@ -6112,6 +6188,12 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- name: mysql
|
- name: mysql
|
||||||
path: /var/lib/mysql
|
path: /var/lib/mysql
|
||||||
|
- environment: {}
|
||||||
|
image: redis:6.2.11-alpine
|
||||||
|
name: redis
|
||||||
|
- environment: {}
|
||||||
|
image: memcached:1.6.9-alpine
|
||||||
|
name: memcached
|
||||||
steps:
|
steps:
|
||||||
- commands:
|
- commands:
|
||||||
- mkdir -p bin
|
- mkdir -p bin
|
||||||
@@ -6178,6 +6260,26 @@ steps:
|
|||||||
MYSQL_HOST: mysql
|
MYSQL_HOST: mysql
|
||||||
image: grafana/build-container:1.7.2
|
image: grafana/build-container:1.7.2
|
||||||
name: mysql-integration-tests
|
name: mysql-integration-tests
|
||||||
|
- commands:
|
||||||
|
- dockerize -wait tcp://redis:6379/0 -timeout 120s
|
||||||
|
- go clean -testcache
|
||||||
|
- go test -run IntegrationRedis -covermode=atomic -timeout=2m ./pkg/...
|
||||||
|
depends_on:
|
||||||
|
- wire-install
|
||||||
|
environment:
|
||||||
|
REDIS_URL: redis://redis:6379/0
|
||||||
|
image: grafana/build-container:1.7.2
|
||||||
|
name: redis-integration-tests
|
||||||
|
- commands:
|
||||||
|
- dockerize -wait tcp://memcached:11211 -timeout 120s
|
||||||
|
- go clean -testcache
|
||||||
|
- go test -run IntegrationMemcached -covermode=atomic -timeout=2m ./pkg/...
|
||||||
|
depends_on:
|
||||||
|
- wire-install
|
||||||
|
environment:
|
||||||
|
MEMCACHED_HOSTS: memcached:11211
|
||||||
|
image: grafana/build-container:1.7.2
|
||||||
|
name: memcached-integration-tests
|
||||||
trigger:
|
trigger:
|
||||||
event:
|
event:
|
||||||
- promote
|
- promote
|
||||||
@@ -6230,7 +6332,7 @@ services:
|
|||||||
- name: mysql
|
- name: mysql
|
||||||
path: /var/lib/mysql
|
path: /var/lib/mysql
|
||||||
- environment: {}
|
- environment: {}
|
||||||
image: redis:6.2.1-alpine
|
image: redis:6.2.11-alpine
|
||||||
name: redis
|
name: redis
|
||||||
- environment: {}
|
- environment: {}
|
||||||
image: memcached:1.6.9-alpine
|
image: memcached:1.6.9-alpine
|
||||||
@@ -6332,8 +6434,7 @@ steps:
|
|||||||
- commands:
|
- commands:
|
||||||
- dockerize -wait tcp://redis:6379/0 -timeout 120s
|
- dockerize -wait tcp://redis:6379/0 -timeout 120s
|
||||||
- go clean -testcache
|
- go clean -testcache
|
||||||
- go list './pkg/...' | xargs -I {} sh -c 'go test -run Integration -covermode=atomic
|
- go test -run IntegrationRedis -covermode=atomic -timeout=2m ./pkg/...
|
||||||
-timeout=5m {}'
|
|
||||||
depends_on:
|
depends_on:
|
||||||
- wire-install
|
- wire-install
|
||||||
environment:
|
environment:
|
||||||
@@ -6343,8 +6444,7 @@ steps:
|
|||||||
- commands:
|
- commands:
|
||||||
- dockerize -wait tcp://memcached:11211 -timeout 120s
|
- dockerize -wait tcp://memcached:11211 -timeout 120s
|
||||||
- go clean -testcache
|
- go clean -testcache
|
||||||
- go list './pkg/...' | xargs -I {} sh -c 'go test -run Integration -covermode=atomic
|
- go test -run IntegrationMemcached -covermode=atomic -timeout=2m ./pkg/...
|
||||||
-timeout=5m {}'
|
|
||||||
depends_on:
|
depends_on:
|
||||||
- wire-install
|
- wire-install
|
||||||
environment:
|
environment:
|
||||||
@@ -6653,6 +6753,6 @@ kind: secret
|
|||||||
name: enterprise2_security_prefix
|
name: enterprise2_security_prefix
|
||||||
---
|
---
|
||||||
kind: signature
|
kind: signature
|
||||||
hmac: 675c90070f9b68e15f349d079fbafa5288c3e5c30c345a4c9678d69afd1cc5a7
|
hmac: 54bded4dc7c3ffbbf3859a4f8f6364f59f3b6e0696152a0b835211eca7119e50
|
||||||
|
|
||||||
...
|
...
|
||||||
|
|||||||
@@ -407,6 +407,7 @@ lerna.json @grafana/frontend-ops
|
|||||||
/public/app/plugins/panel/table/ @grafana/grafana-bi-squad
|
/public/app/plugins/panel/table/ @grafana/grafana-bi-squad
|
||||||
/public/app/plugins/panel/table-old/ @grafana/grafana-bi-squad
|
/public/app/plugins/panel/table-old/ @grafana/grafana-bi-squad
|
||||||
/public/app/plugins/panel/timeseries/ @grafana/dataviz-squad
|
/public/app/plugins/panel/timeseries/ @grafana/dataviz-squad
|
||||||
|
/public/app/plugins/panel/trend/ @grafana/dataviz-squad
|
||||||
/public/app/plugins/panel/geomap/ @grafana/dataviz-squad
|
/public/app/plugins/panel/geomap/ @grafana/dataviz-squad
|
||||||
/public/app/plugins/panel/canvas/ @grafana/dataviz-squad
|
/public/app/plugins/panel/canvas/ @grafana/dataviz-squad
|
||||||
/public/app/plugins/panel/candlestick/ @grafana/dataviz-squad
|
/public/app/plugins/panel/candlestick/ @grafana/dataviz-squad
|
||||||
|
|||||||
@@ -322,5 +322,157 @@
|
|||||||
"addToProject": {
|
"addToProject": {
|
||||||
"url": "https://github.com/orgs/grafana/projects/78"
|
"url": "https://github.com/orgs/grafana/projects/78"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "label",
|
||||||
|
"name": "area/panel/candlestick",
|
||||||
|
"action": "addToProject",
|
||||||
|
"addToProject": {
|
||||||
|
"url": "https://github.com/orgs/grafana/projects/56"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "label",
|
||||||
|
"name": "area/panel/canvas",
|
||||||
|
"action": "addToProject",
|
||||||
|
"addToProject": {
|
||||||
|
"url": "https://github.com/orgs/grafana/projects/56"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "label",
|
||||||
|
"name": "area/panel/barchart",
|
||||||
|
"action": "addToProject",
|
||||||
|
"addToProject": {
|
||||||
|
"url": "https://github.com/orgs/grafana/projects/56"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "label",
|
||||||
|
"name": "area/panel/bargauge",
|
||||||
|
"action": "addToProject",
|
||||||
|
"addToProject": {
|
||||||
|
"url": "https://github.com/orgs/grafana/projects/72"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "label",
|
||||||
|
"name": "area/panel/gauge",
|
||||||
|
"action": "addToProject",
|
||||||
|
"addToProject": {
|
||||||
|
"url": "https://github.com/orgs/grafana/projects/72"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "label",
|
||||||
|
"name": "area/panel/geomap",
|
||||||
|
"action": "addToProject",
|
||||||
|
"addToProject": {
|
||||||
|
"url": "https://github.com/orgs/grafana/projects/56"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "label",
|
||||||
|
"name": "area/panel/graph",
|
||||||
|
"action": "addToProject",
|
||||||
|
"addToProject": {
|
||||||
|
"url": "https://github.com/orgs/grafana/projects/56"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "label",
|
||||||
|
"name": "area/panel/heatmap",
|
||||||
|
"action": "addToProject",
|
||||||
|
"addToProject": {
|
||||||
|
"url": "https://github.com/orgs/grafana/projects/56"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "label",
|
||||||
|
"name": "area/panel/histogram",
|
||||||
|
"action": "addToProject",
|
||||||
|
"addToProject": {
|
||||||
|
"url": "https://github.com/orgs/grafana/projects/56"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "label",
|
||||||
|
"name": "area/panel/icon",
|
||||||
|
"action": "addToProject",
|
||||||
|
"addToProject": {
|
||||||
|
"url": "https://github.com/orgs/grafana/projects/56"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "label",
|
||||||
|
"name": "area/panel/piechart",
|
||||||
|
"action": "addToProject",
|
||||||
|
"addToProject": {
|
||||||
|
"url": "https://github.com/orgs/grafana/projects/72"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "label",
|
||||||
|
"name": "area/panel/stat",
|
||||||
|
"action": "addToProject",
|
||||||
|
"addToProject": {
|
||||||
|
"url": "https://github.com/orgs/grafana/projects/72"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "label",
|
||||||
|
"name": "area/panel/state-timeline",
|
||||||
|
"action": "addToProject",
|
||||||
|
"addToProject": {
|
||||||
|
"url": "https://github.com/orgs/grafana/projects/56"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "label",
|
||||||
|
"name": "area/panel/status-history",
|
||||||
|
"action": "addToProject",
|
||||||
|
"addToProject": {
|
||||||
|
"url": "https://github.com/orgs/grafana/projects/56"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "label",
|
||||||
|
"name": "area/panel/timeseries",
|
||||||
|
"action": "addToProject",
|
||||||
|
"addToProject": {
|
||||||
|
"url": "https://github.com/orgs/grafana/projects/56"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "label",
|
||||||
|
"name": "area/panel/xychart",
|
||||||
|
"action": "addToProject",
|
||||||
|
"addToProject": {
|
||||||
|
"url": "https://github.com/orgs/grafana/projects/56"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "label",
|
||||||
|
"name": "area/panel/oss-dataviz",
|
||||||
|
"action": "addToProject",
|
||||||
|
"addToProject": {
|
||||||
|
"url": "https://github.com/orgs/grafana/projects/56"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "label",
|
||||||
|
"name": "area/panel/oss-bi",
|
||||||
|
"action": "addToProject",
|
||||||
|
"addToProject": {
|
||||||
|
"url": "https://github.com/orgs/grafana/projects/72"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "label",
|
||||||
|
"name": "area/panel/table",
|
||||||
|
"action": "addToProject",
|
||||||
|
"addToProject": {
|
||||||
|
"url": "https://github.com/orgs/grafana/projects/72"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -17,13 +17,13 @@ jobs:
|
|||||||
id: regex-match
|
id: regex-match
|
||||||
with:
|
with:
|
||||||
text: ${{ github.event.inputs.version }}
|
text: ${{ github.event.inputs.version }}
|
||||||
regex: '^(\d+.\d+).\d+(?:-beta\d+)?$'
|
regex: '^(\d+.\d+).\d+(?:-(?:(beta\d+)|(pre)))?$'
|
||||||
- uses: actions-ecosystem/action-regex-match@v2.0.2
|
- uses: actions-ecosystem/action-regex-match@v2.0.2
|
||||||
if: ${{ inputs.version_call != '' }}
|
if: ${{ inputs.version_call != '' }}
|
||||||
id: regex-match-version-call
|
id: regex-match-version-call
|
||||||
with:
|
with:
|
||||||
text: ${{ inputs.version_call }}
|
text: ${{ inputs.version_call }}
|
||||||
regex: '^(\d+.\d+).\d+(?:-beta\d+)?$'
|
regex: '^(\d+.\d+).\d+(?:-(?:(beta\d+)|(pre)))?$'
|
||||||
- name: Validate input version
|
- name: Validate input version
|
||||||
if: ${{ steps.regex-match.outputs.match == '' && github.event.inputs.version != '' }}
|
if: ${{ steps.regex-match.outputs.match == '' && github.event.inputs.version != '' }}
|
||||||
run: |
|
run: |
|
||||||
@@ -50,7 +50,7 @@ jobs:
|
|||||||
echo "branch_exist=$(git ls-remote --heads https://github.com/grafana/grafana.git v${{ steps.regex-match.outputs.group1 }}.x | wc -l)" >> $GITHUB_OUTPUT
|
echo "branch_exist=$(git ls-remote --heads https://github.com/grafana/grafana.git v${{ steps.regex-match.outputs.group1 }}.x | wc -l)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Check input version is aligned with branch(main)
|
- name: Check input version is aligned with branch(main)
|
||||||
if: ${{ github.event.inputs.version != '' && steps.intermedia.outputs.branch_exist == '0' && !contains(steps.intermedia.outputs.short_ref, 'main') }}
|
if: ${{ github.event.inputs.version != '' && steps.intermedia.outputs.branch_exist == '0' && !contains(github.event.inputs.version, 'pre') && !contains(steps.intermedia.outputs.short_ref, 'main') }}
|
||||||
run: |
|
run: |
|
||||||
echo "When you want to deliver a new new minor version, you might want to create a new branch first \
|
echo "When you want to deliver a new new minor version, you might want to create a new branch first \
|
||||||
with naming convention v[major].[minor].x, and just run the workflow on that branch. \
|
with naming convention v[major].[minor].x, and just run the workflow on that branch. \
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ jobs:
|
|||||||
doc-validator:
|
doc-validator:
|
||||||
runs-on: "ubuntu-latest"
|
runs-on: "ubuntu-latest"
|
||||||
container:
|
container:
|
||||||
image: "grafana/doc-validator:v1.9.0"
|
image: "grafana/doc-validator:v1.10.0"
|
||||||
steps:
|
steps:
|
||||||
- name: "Checkout code"
|
- name: "Checkout code"
|
||||||
uses: "actions/checkout@v3"
|
uses: "actions/checkout@v3"
|
||||||
|
|||||||
+1
-1
@@ -15,7 +15,7 @@ You can contribute to Grafana in several ways. Here are some examples:
|
|||||||
- Organize meetups and user groups in your local area.
|
- Organize meetups and user groups in your local area.
|
||||||
- Help others by answering questions about Grafana.
|
- Help others by answering questions about Grafana.
|
||||||
|
|
||||||
**Please note:** We do not currently accept contributions for translations. Please do not submit pull requests for messages.po files - they will be rejected.
|
**Please note:** We do not currently accept contributions for translations. Please do not submit pull requests translating grafana.json files - they will be rejected. We do accept contributions to mark up phrases for translation. See [Internationalization](contribute/internationalization.md).
|
||||||
|
|
||||||
For more ways to contribute, check out the [Open Source Guides](https://opensource.guide/how-to-contribute/).
|
For more ways to contribute, check out the [Open Source Guides](https://opensource.guide/how-to-contribute/).
|
||||||
|
|
||||||
|
|||||||
@@ -143,6 +143,18 @@ test-go-integration-mysql: devenv-mysql ## Run integration tests for mysql backe
|
|||||||
$(GO) clean -testcache
|
$(GO) clean -testcache
|
||||||
$(GO) list './pkg/...' | xargs -I {} sh -c 'GRAFANA_TEST_DB=mysql go test -run Integration -covermode=atomic -timeout=2m {}'
|
$(GO) list './pkg/...' | xargs -I {} sh -c 'GRAFANA_TEST_DB=mysql go test -run Integration -covermode=atomic -timeout=2m {}'
|
||||||
|
|
||||||
|
.PHONY: test-go-integration-redis
|
||||||
|
test-go-integration-redis: ## Run integration tests for redis cache.
|
||||||
|
@echo "test backend integration redis tests"
|
||||||
|
$(GO) clean -testcache
|
||||||
|
REDIS_URL=localhost:6379 $(GO) test -run IntegrationRedis -covermode=atomic -timeout=2m ./pkg/...
|
||||||
|
|
||||||
|
.PHONY: test-go-integration-memcached
|
||||||
|
test-go-integration-memcached: ## Run integration tests for memcached cache.
|
||||||
|
@echo "test backend integration memcached tests"
|
||||||
|
$(GO) clean -testcache
|
||||||
|
MEMCACHED_HOSTS=localhost:11211 $(GO) test -run IntegrationMemcached -covermode=atomic -timeout=2m ./pkg/...
|
||||||
|
|
||||||
test-js: ## Run tests for frontend.
|
test-js: ## Run tests for frontend.
|
||||||
@echo "test frontend"
|
@echo "test frontend"
|
||||||
yarn test
|
yarn test
|
||||||
|
|||||||
@@ -124,6 +124,7 @@ datasources:
|
|||||||
|
|
||||||
- name: gdev-elasticsearch
|
- name: gdev-elasticsearch
|
||||||
type: elasticsearch
|
type: elasticsearch
|
||||||
|
uid: gdev-elasticsearch
|
||||||
access: proxy
|
access: proxy
|
||||||
database: "[logs-]YYYY.MM.DD"
|
database: "[logs-]YYYY.MM.DD"
|
||||||
url: http://localhost:9200
|
url: http://localhost:9200
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,736 +0,0 @@
|
|||||||
{
|
|
||||||
"annotations": {
|
|
||||||
"list": [
|
|
||||||
{
|
|
||||||
"builtIn": 1,
|
|
||||||
"datasource": "-- Grafana --",
|
|
||||||
"enable": false,
|
|
||||||
"hide": true,
|
|
||||||
"iconColor": "rgba(0, 211, 255, 1)",
|
|
||||||
"limit": 100,
|
|
||||||
"name": "Annotations & Alerts",
|
|
||||||
"showIn": 0,
|
|
||||||
"type": "dashboard"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"datasource": "gdev-elasticsearch-v7-logs",
|
|
||||||
"enable": false,
|
|
||||||
"iconColor": "rgba(255, 96, 96, 1)",
|
|
||||||
"limit": 100,
|
|
||||||
"name": "test",
|
|
||||||
"query": "",
|
|
||||||
"showIn": 0,
|
|
||||||
"textField": "description",
|
|
||||||
"type": "alert"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"editable": true,
|
|
||||||
"gnetId": null,
|
|
||||||
"graphTooltip": 0,
|
|
||||||
"iteration": 1591027717495,
|
|
||||||
"links": [
|
|
||||||
{
|
|
||||||
"asDropdown": true,
|
|
||||||
"icon": "external link",
|
|
||||||
"tags": ["gdev", "elasticsearch", "datasource-test"],
|
|
||||||
"title": "Dashboards",
|
|
||||||
"type": "dashboards"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"panels": [
|
|
||||||
{
|
|
||||||
"aliasColors": {},
|
|
||||||
"bars": false,
|
|
||||||
"dashLength": 10,
|
|
||||||
"dashes": false,
|
|
||||||
"datasource": "gdev-elasticsearch-v7-metrics",
|
|
||||||
"editable": true,
|
|
||||||
"error": false,
|
|
||||||
"fieldConfig": {
|
|
||||||
"defaults": {
|
|
||||||
"custom": {}
|
|
||||||
},
|
|
||||||
"overrides": []
|
|
||||||
},
|
|
||||||
"fill": 1,
|
|
||||||
"fillGradient": 0,
|
|
||||||
"grid": {},
|
|
||||||
"gridPos": {
|
|
||||||
"h": 7,
|
|
||||||
"w": 24,
|
|
||||||
"x": 0,
|
|
||||||
"y": 0
|
|
||||||
},
|
|
||||||
"hiddenSeries": false,
|
|
||||||
"id": 1,
|
|
||||||
"legend": {
|
|
||||||
"alignAsTable": true,
|
|
||||||
"avg": false,
|
|
||||||
"current": false,
|
|
||||||
"max": true,
|
|
||||||
"min": false,
|
|
||||||
"rightSide": true,
|
|
||||||
"show": true,
|
|
||||||
"total": false,
|
|
||||||
"values": true
|
|
||||||
},
|
|
||||||
"lines": true,
|
|
||||||
"linewidth": 2,
|
|
||||||
"links": [],
|
|
||||||
"nullPointMode": "connected",
|
|
||||||
"options": {
|
|
||||||
"dataLinks": []
|
|
||||||
},
|
|
||||||
"percentage": false,
|
|
||||||
"pointradius": 5,
|
|
||||||
"points": false,
|
|
||||||
"renderer": "flot",
|
|
||||||
"seriesOverrides": [],
|
|
||||||
"spaceLength": 10,
|
|
||||||
"stack": false,
|
|
||||||
"steppedLine": false,
|
|
||||||
"targets": [
|
|
||||||
{
|
|
||||||
"bucketAggs": [
|
|
||||||
{
|
|
||||||
"field": "@hostname",
|
|
||||||
"id": "3",
|
|
||||||
"settings": {
|
|
||||||
"min_doc_count": 1,
|
|
||||||
"order": "asc",
|
|
||||||
"orderBy": "1",
|
|
||||||
"size": "5"
|
|
||||||
},
|
|
||||||
"type": "terms"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"field": "@timestamp",
|
|
||||||
"id": "2",
|
|
||||||
"settings": {
|
|
||||||
"interval": "auto",
|
|
||||||
"min_doc_count": 0,
|
|
||||||
"trimEdges": 0
|
|
||||||
},
|
|
||||||
"type": "date_histogram"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"dsType": "elasticsearch",
|
|
||||||
"metrics": [
|
|
||||||
{
|
|
||||||
"field": "@value",
|
|
||||||
"id": "1",
|
|
||||||
"meta": {},
|
|
||||||
"settings": {},
|
|
||||||
"type": "max"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"query": "*",
|
|
||||||
"refId": "A",
|
|
||||||
"target": "",
|
|
||||||
"timeField": "@timestamp"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"thresholds": [],
|
|
||||||
"timeFrom": null,
|
|
||||||
"timeRegions": [],
|
|
||||||
"timeShift": null,
|
|
||||||
"title": "Top 5 servers",
|
|
||||||
"tooltip": {
|
|
||||||
"msResolution": true,
|
|
||||||
"shared": true,
|
|
||||||
"sort": 0,
|
|
||||||
"value_type": "cumulative"
|
|
||||||
},
|
|
||||||
"type": "graph",
|
|
||||||
"xaxis": {
|
|
||||||
"buckets": null,
|
|
||||||
"mode": "time",
|
|
||||||
"name": null,
|
|
||||||
"show": true,
|
|
||||||
"values": []
|
|
||||||
},
|
|
||||||
"yaxes": [
|
|
||||||
{
|
|
||||||
"format": "short",
|
|
||||||
"logBase": 1,
|
|
||||||
"max": null,
|
|
||||||
"min": null,
|
|
||||||
"show": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"format": "short",
|
|
||||||
"logBase": 1,
|
|
||||||
"max": null,
|
|
||||||
"min": null,
|
|
||||||
"show": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"yaxis": {
|
|
||||||
"align": false,
|
|
||||||
"alignLevel": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"aliasColors": {
|
|
||||||
"Count": "#6ED0E0"
|
|
||||||
},
|
|
||||||
"bars": false,
|
|
||||||
"dashLength": 10,
|
|
||||||
"dashes": false,
|
|
||||||
"datasource": "gdev-elasticsearch-v7-metrics",
|
|
||||||
"editable": true,
|
|
||||||
"error": false,
|
|
||||||
"fieldConfig": {
|
|
||||||
"defaults": {
|
|
||||||
"custom": {}
|
|
||||||
},
|
|
||||||
"overrides": []
|
|
||||||
},
|
|
||||||
"fill": 1,
|
|
||||||
"fillGradient": 0,
|
|
||||||
"grid": {},
|
|
||||||
"gridPos": {
|
|
||||||
"h": 6,
|
|
||||||
"w": 12,
|
|
||||||
"x": 0,
|
|
||||||
"y": 7
|
|
||||||
},
|
|
||||||
"hiddenSeries": false,
|
|
||||||
"id": 2,
|
|
||||||
"legend": {
|
|
||||||
"alignAsTable": true,
|
|
||||||
"avg": true,
|
|
||||||
"current": false,
|
|
||||||
"max": false,
|
|
||||||
"min": false,
|
|
||||||
"rightSide": true,
|
|
||||||
"show": true,
|
|
||||||
"total": false,
|
|
||||||
"values": true
|
|
||||||
},
|
|
||||||
"lines": true,
|
|
||||||
"linewidth": 2,
|
|
||||||
"links": [],
|
|
||||||
"nullPointMode": "connected",
|
|
||||||
"options": {
|
|
||||||
"dataLinks": []
|
|
||||||
},
|
|
||||||
"percentage": false,
|
|
||||||
"pointradius": 5,
|
|
||||||
"points": false,
|
|
||||||
"renderer": "flot",
|
|
||||||
"seriesOverrides": [
|
|
||||||
{
|
|
||||||
"alias": "Count",
|
|
||||||
"lines": false,
|
|
||||||
"yaxis": 2,
|
|
||||||
"zindex": -1
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"spaceLength": 10,
|
|
||||||
"stack": false,
|
|
||||||
"steppedLine": false,
|
|
||||||
"targets": [
|
|
||||||
{
|
|
||||||
"alias": "{{metric}}",
|
|
||||||
"bucketAggs": [
|
|
||||||
{
|
|
||||||
"field": "@timestamp",
|
|
||||||
"id": "2",
|
|
||||||
"settings": {
|
|
||||||
"interval": "5m",
|
|
||||||
"min_doc_count": 0,
|
|
||||||
"trimEdges": 0
|
|
||||||
},
|
|
||||||
"type": "date_histogram"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"dsType": "elasticsearch",
|
|
||||||
"metrics": [
|
|
||||||
{
|
|
||||||
"field": "@value",
|
|
||||||
"id": "1",
|
|
||||||
"meta": {},
|
|
||||||
"settings": {
|
|
||||||
"percents": [25, 50, 75, 95, 99]
|
|
||||||
},
|
|
||||||
"type": "percentiles"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"query": "@metric:cpu",
|
|
||||||
"refId": "A",
|
|
||||||
"target": "",
|
|
||||||
"timeField": "@timestamp"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"thresholds": [],
|
|
||||||
"timeFrom": null,
|
|
||||||
"timeRegions": [],
|
|
||||||
"timeShift": null,
|
|
||||||
"title": "Percentiles & Metric filter",
|
|
||||||
"tooltip": {
|
|
||||||
"msResolution": false,
|
|
||||||
"shared": true,
|
|
||||||
"sort": 0,
|
|
||||||
"value_type": "cumulative"
|
|
||||||
},
|
|
||||||
"type": "graph",
|
|
||||||
"xaxis": {
|
|
||||||
"buckets": null,
|
|
||||||
"mode": "time",
|
|
||||||
"name": null,
|
|
||||||
"show": true,
|
|
||||||
"values": []
|
|
||||||
},
|
|
||||||
"yaxes": [
|
|
||||||
{
|
|
||||||
"format": "short",
|
|
||||||
"logBase": 1,
|
|
||||||
"max": null,
|
|
||||||
"min": null,
|
|
||||||
"show": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"format": "short",
|
|
||||||
"logBase": 1,
|
|
||||||
"max": null,
|
|
||||||
"min": null,
|
|
||||||
"show": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"yaxis": {
|
|
||||||
"align": false,
|
|
||||||
"alignLevel": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"aliasColors": {
|
|
||||||
"Count": "#6ED0E0"
|
|
||||||
},
|
|
||||||
"bars": false,
|
|
||||||
"dashLength": 10,
|
|
||||||
"dashes": false,
|
|
||||||
"datasource": "gdev-elasticsearch-v7-metrics",
|
|
||||||
"editable": true,
|
|
||||||
"error": false,
|
|
||||||
"fieldConfig": {
|
|
||||||
"defaults": {
|
|
||||||
"custom": {}
|
|
||||||
},
|
|
||||||
"overrides": []
|
|
||||||
},
|
|
||||||
"fill": 1,
|
|
||||||
"fillGradient": 0,
|
|
||||||
"grid": {},
|
|
||||||
"gridPos": {
|
|
||||||
"h": 6,
|
|
||||||
"w": 12,
|
|
||||||
"x": 12,
|
|
||||||
"y": 7
|
|
||||||
},
|
|
||||||
"hiddenSeries": false,
|
|
||||||
"id": 3,
|
|
||||||
"legend": {
|
|
||||||
"alignAsTable": true,
|
|
||||||
"avg": true,
|
|
||||||
"current": false,
|
|
||||||
"max": false,
|
|
||||||
"min": false,
|
|
||||||
"rightSide": true,
|
|
||||||
"show": true,
|
|
||||||
"total": false,
|
|
||||||
"values": true
|
|
||||||
},
|
|
||||||
"lines": true,
|
|
||||||
"linewidth": 2,
|
|
||||||
"links": [],
|
|
||||||
"nullPointMode": "connected",
|
|
||||||
"options": {
|
|
||||||
"dataLinks": []
|
|
||||||
},
|
|
||||||
"percentage": false,
|
|
||||||
"pointradius": 5,
|
|
||||||
"points": false,
|
|
||||||
"renderer": "flot",
|
|
||||||
"seriesOverrides": [
|
|
||||||
{
|
|
||||||
"alias": "Count",
|
|
||||||
"lines": false,
|
|
||||||
"yaxis": 2,
|
|
||||||
"zindex": -1
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"spaceLength": 10,
|
|
||||||
"stack": false,
|
|
||||||
"steppedLine": false,
|
|
||||||
"targets": [
|
|
||||||
{
|
|
||||||
"alias": "{{metric}}",
|
|
||||||
"bucketAggs": [
|
|
||||||
{
|
|
||||||
"field": "@timestamp",
|
|
||||||
"id": "2",
|
|
||||||
"settings": {
|
|
||||||
"interval": "auto",
|
|
||||||
"min_doc_count": 0,
|
|
||||||
"trimEdges": 0
|
|
||||||
},
|
|
||||||
"type": "date_histogram"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"dsType": "elasticsearch",
|
|
||||||
"metrics": [
|
|
||||||
{
|
|
||||||
"field": "@value",
|
|
||||||
"id": "1",
|
|
||||||
"meta": {
|
|
||||||
"std_deviation_bounds_lower": true,
|
|
||||||
"std_deviation_bounds_upper": true
|
|
||||||
},
|
|
||||||
"settings": {},
|
|
||||||
"type": "extended_stats"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"query": "@metric:cpu",
|
|
||||||
"refId": "A",
|
|
||||||
"target": "",
|
|
||||||
"timeField": "@timestamp"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"thresholds": [],
|
|
||||||
"timeFrom": null,
|
|
||||||
"timeRegions": [],
|
|
||||||
"timeShift": null,
|
|
||||||
"title": "Standard dev",
|
|
||||||
"tooltip": {
|
|
||||||
"msResolution": true,
|
|
||||||
"shared": true,
|
|
||||||
"sort": 0,
|
|
||||||
"value_type": "cumulative"
|
|
||||||
},
|
|
||||||
"type": "graph",
|
|
||||||
"xaxis": {
|
|
||||||
"buckets": null,
|
|
||||||
"mode": "time",
|
|
||||||
"name": null,
|
|
||||||
"show": true,
|
|
||||||
"values": []
|
|
||||||
},
|
|
||||||
"yaxes": [
|
|
||||||
{
|
|
||||||
"format": "short",
|
|
||||||
"logBase": 1,
|
|
||||||
"max": null,
|
|
||||||
"min": null,
|
|
||||||
"show": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"format": "short",
|
|
||||||
"logBase": 1,
|
|
||||||
"max": null,
|
|
||||||
"min": null,
|
|
||||||
"show": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"yaxis": {
|
|
||||||
"align": false,
|
|
||||||
"alignLevel": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"columns": [
|
|
||||||
{
|
|
||||||
"text": "@hostname",
|
|
||||||
"value": "@hostname"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"text": "Average",
|
|
||||||
"value": "Average"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"text": "Max",
|
|
||||||
"value": "Max"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"text": "Sum",
|
|
||||||
"value": "Sum"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"datasource": "gdev-elasticsearch-v7-metrics",
|
|
||||||
"editable": true,
|
|
||||||
"error": false,
|
|
||||||
"fieldConfig": {
|
|
||||||
"defaults": {
|
|
||||||
"custom": {}
|
|
||||||
},
|
|
||||||
"overrides": []
|
|
||||||
},
|
|
||||||
"fontSize": "100%",
|
|
||||||
"gridPos": {
|
|
||||||
"h": 7,
|
|
||||||
"w": 24,
|
|
||||||
"x": 0,
|
|
||||||
"y": 13
|
|
||||||
},
|
|
||||||
"id": 6,
|
|
||||||
"links": [],
|
|
||||||
"pageSize": null,
|
|
||||||
"scroll": true,
|
|
||||||
"showHeader": true,
|
|
||||||
"sort": {
|
|
||||||
"col": 0,
|
|
||||||
"desc": true
|
|
||||||
},
|
|
||||||
"styles": [
|
|
||||||
{
|
|
||||||
"align": "auto",
|
|
||||||
"dateFormat": "YYYY-MM-DD HH:mm:ss",
|
|
||||||
"pattern": "@timestamp",
|
|
||||||
"type": "date"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"align": "auto",
|
|
||||||
"colorMode": null,
|
|
||||||
"colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"],
|
|
||||||
"dateFormat": "YYYY-MM-DD HH:mm:ss",
|
|
||||||
"decimals": 2,
|
|
||||||
"pattern": "/.*/",
|
|
||||||
"thresholds": [],
|
|
||||||
"type": "number",
|
|
||||||
"unit": "short"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"targets": [
|
|
||||||
{
|
|
||||||
"bucketAggs": [
|
|
||||||
{
|
|
||||||
"field": "@hostname",
|
|
||||||
"id": "2",
|
|
||||||
"settings": {
|
|
||||||
"min_doc_count": 1,
|
|
||||||
"order": "asc",
|
|
||||||
"orderBy": "_term",
|
|
||||||
"size": "0"
|
|
||||||
},
|
|
||||||
"type": "terms"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"dsType": "elasticsearch",
|
|
||||||
"metrics": [
|
|
||||||
{
|
|
||||||
"field": "@value",
|
|
||||||
"id": "1",
|
|
||||||
"meta": {},
|
|
||||||
"settings": {},
|
|
||||||
"type": "avg"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"field": "@value",
|
|
||||||
"id": "3",
|
|
||||||
"meta": {},
|
|
||||||
"settings": {},
|
|
||||||
"type": "max"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"field": "@value",
|
|
||||||
"id": "4",
|
|
||||||
"meta": {},
|
|
||||||
"settings": {},
|
|
||||||
"type": "sum"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"refId": "B",
|
|
||||||
"timeField": "@timestamp"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"title": "ES Metrics",
|
|
||||||
"transform": "table",
|
|
||||||
"type": "table-old"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"columns": [
|
|
||||||
{
|
|
||||||
"text": "@timestamp",
|
|
||||||
"value": "@timestamp"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"text": "@message",
|
|
||||||
"value": "@message"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"text": "tags",
|
|
||||||
"value": "tags"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"text": "description",
|
|
||||||
"value": "description"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"datasource": "gdev-elasticsearch-v7-logs",
|
|
||||||
"editable": true,
|
|
||||||
"error": false,
|
|
||||||
"fieldConfig": {
|
|
||||||
"defaults": {
|
|
||||||
"custom": {}
|
|
||||||
},
|
|
||||||
"overrides": []
|
|
||||||
},
|
|
||||||
"fontSize": "100%",
|
|
||||||
"gridPos": {
|
|
||||||
"h": 7,
|
|
||||||
"w": 24,
|
|
||||||
"x": 0,
|
|
||||||
"y": 20
|
|
||||||
},
|
|
||||||
"id": 5,
|
|
||||||
"links": [],
|
|
||||||
"pageSize": null,
|
|
||||||
"scroll": true,
|
|
||||||
"showHeader": true,
|
|
||||||
"sort": {
|
|
||||||
"col": 0,
|
|
||||||
"desc": true
|
|
||||||
},
|
|
||||||
"styles": [
|
|
||||||
{
|
|
||||||
"align": "auto",
|
|
||||||
"dateFormat": "YYYY-MM-DD HH:mm:ss",
|
|
||||||
"pattern": "@timestamp",
|
|
||||||
"type": "date"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"targets": [
|
|
||||||
{
|
|
||||||
"bucketAggs": [],
|
|
||||||
"dsType": "elasticsearch",
|
|
||||||
"metrics": [
|
|
||||||
{
|
|
||||||
"field": "select field",
|
|
||||||
"id": "1",
|
|
||||||
"meta": {},
|
|
||||||
"settings": {
|
|
||||||
"size": 500
|
|
||||||
},
|
|
||||||
"type": "raw_document"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"refId": "A",
|
|
||||||
"target": "",
|
|
||||||
"timeField": "@timestamp"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"title": "ES Log query",
|
|
||||||
"transform": "json",
|
|
||||||
"type": "table-old"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"circleMaxSize": 30,
|
|
||||||
"circleMinSize": 2,
|
|
||||||
"colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"],
|
|
||||||
"datasource": "gdev-elasticsearch-v7-metrics",
|
|
||||||
"decimals": 0,
|
|
||||||
"esGeoPoint": "@location",
|
|
||||||
"esMetric": "Average",
|
|
||||||
"fieldConfig": {
|
|
||||||
"defaults": {
|
|
||||||
"custom": {}
|
|
||||||
},
|
|
||||||
"overrides": []
|
|
||||||
},
|
|
||||||
"gridPos": {
|
|
||||||
"h": 12,
|
|
||||||
"w": 24,
|
|
||||||
"x": 0,
|
|
||||||
"y": 27
|
|
||||||
},
|
|
||||||
"hideEmpty": false,
|
|
||||||
"hideZero": false,
|
|
||||||
"id": 8,
|
|
||||||
"initialZoom": "1",
|
|
||||||
"links": [],
|
|
||||||
"locationData": "geohash",
|
|
||||||
"mapCenter": "(0°, 0°)",
|
|
||||||
"mapCenterLatitude": 0,
|
|
||||||
"mapCenterLongitude": 0,
|
|
||||||
"maxDataPoints": 1,
|
|
||||||
"mouseWheelZoom": false,
|
|
||||||
"showLegend": true,
|
|
||||||
"stickyLabels": false,
|
|
||||||
"tableQueryOptions": {
|
|
||||||
"geohashField": "geohash",
|
|
||||||
"latitudeField": "latitude",
|
|
||||||
"longitudeField": "longitude",
|
|
||||||
"metricField": "metric",
|
|
||||||
"queryType": "geohash"
|
|
||||||
},
|
|
||||||
"targets": [
|
|
||||||
{
|
|
||||||
"bucketAggs": [
|
|
||||||
{
|
|
||||||
"fake": true,
|
|
||||||
"field": "@location",
|
|
||||||
"id": "3",
|
|
||||||
"settings": {
|
|
||||||
"precision": 2
|
|
||||||
},
|
|
||||||
"type": "geohash_grid"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metrics": [
|
|
||||||
{
|
|
||||||
"field": "@value",
|
|
||||||
"id": "1",
|
|
||||||
"meta": {},
|
|
||||||
"settings": {},
|
|
||||||
"type": "avg"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"refId": "A",
|
|
||||||
"target": "",
|
|
||||||
"timeField": "@timestamp"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"thresholds": "0,10",
|
|
||||||
"title": "World map panel",
|
|
||||||
"type": "grafana-worldmap-panel",
|
|
||||||
"unitPlural": "",
|
|
||||||
"unitSingle": "",
|
|
||||||
"valueName": "total"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"schemaVersion": 25,
|
|
||||||
"style": "dark",
|
|
||||||
"tags": ["elasticsearch", "gdev", "datasource-test"],
|
|
||||||
"templating": {
|
|
||||||
"list": [
|
|
||||||
{
|
|
||||||
"datasource": "gdev-elasticsearch-v7-metrics",
|
|
||||||
"filters": [],
|
|
||||||
"hide": 0,
|
|
||||||
"label": "",
|
|
||||||
"name": "Filters",
|
|
||||||
"skipUrlSync": false,
|
|
||||||
"type": "adhoc"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"time": {
|
|
||||||
"from": "now-30m",
|
|
||||||
"to": "now"
|
|
||||||
},
|
|
||||||
"timepicker": {
|
|
||||||
"collapse": false,
|
|
||||||
"enable": true,
|
|
||||||
"notice": false,
|
|
||||||
"now": true,
|
|
||||||
"refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"],
|
|
||||||
"status": "Stable",
|
|
||||||
"time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"],
|
|
||||||
"type": "timepicker"
|
|
||||||
},
|
|
||||||
"timezone": "browser",
|
|
||||||
"title": "Datasource tests - Elasticsearch v7",
|
|
||||||
"uid": "Y-RvmuRWk",
|
|
||||||
"version": 1
|
|
||||||
}
|
|
||||||
@@ -1,241 +0,0 @@
|
|||||||
{
|
|
||||||
"annotations": {
|
|
||||||
"list": [
|
|
||||||
{
|
|
||||||
"builtIn": 1,
|
|
||||||
"datasource": "-- Grafana --",
|
|
||||||
"enable": true,
|
|
||||||
"hide": true,
|
|
||||||
"iconColor": "rgba(0, 211, 255, 1)",
|
|
||||||
"name": "Annotations & Alerts",
|
|
||||||
"type": "dashboard"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"editable": true,
|
|
||||||
"gnetId": null,
|
|
||||||
"graphTooltip": 0,
|
|
||||||
"iteration": 1591027736516,
|
|
||||||
"links": [
|
|
||||||
{
|
|
||||||
"asDropdown": true,
|
|
||||||
"icon": "external link",
|
|
||||||
"tags": ["gdev", "elasticsearch", "datasource-test"],
|
|
||||||
"title": "Dashboards",
|
|
||||||
"type": "dashboards"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"panels": [
|
|
||||||
{
|
|
||||||
"aliasColors": {
|
|
||||||
"error": "red"
|
|
||||||
},
|
|
||||||
"bars": true,
|
|
||||||
"dashLength": 10,
|
|
||||||
"dashes": false,
|
|
||||||
"datasource": "gdev-elasticsearch-v7-filebeat",
|
|
||||||
"fieldConfig": {
|
|
||||||
"defaults": {
|
|
||||||
"custom": {}
|
|
||||||
},
|
|
||||||
"overrides": []
|
|
||||||
},
|
|
||||||
"fill": 1,
|
|
||||||
"fillGradient": 0,
|
|
||||||
"gridPos": {
|
|
||||||
"h": 5,
|
|
||||||
"w": 24,
|
|
||||||
"x": 0,
|
|
||||||
"y": 0
|
|
||||||
},
|
|
||||||
"hiddenSeries": false,
|
|
||||||
"id": 4,
|
|
||||||
"legend": {
|
|
||||||
"avg": false,
|
|
||||||
"current": false,
|
|
||||||
"max": false,
|
|
||||||
"min": false,
|
|
||||||
"show": true,
|
|
||||||
"total": false,
|
|
||||||
"values": false
|
|
||||||
},
|
|
||||||
"lines": false,
|
|
||||||
"linewidth": 1,
|
|
||||||
"nullPointMode": "null",
|
|
||||||
"options": {
|
|
||||||
"dataLinks": []
|
|
||||||
},
|
|
||||||
"percentage": false,
|
|
||||||
"pointradius": 2,
|
|
||||||
"points": false,
|
|
||||||
"renderer": "flot",
|
|
||||||
"seriesOverrides": [],
|
|
||||||
"spaceLength": 10,
|
|
||||||
"stack": true,
|
|
||||||
"steppedLine": false,
|
|
||||||
"targets": [
|
|
||||||
{
|
|
||||||
"bucketAggs": [
|
|
||||||
{
|
|
||||||
"fake": true,
|
|
||||||
"field": "fields.level",
|
|
||||||
"id": "3",
|
|
||||||
"settings": {
|
|
||||||
"min_doc_count": 1,
|
|
||||||
"order": "desc",
|
|
||||||
"orderBy": "_term",
|
|
||||||
"size": "10"
|
|
||||||
},
|
|
||||||
"type": "terms"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"field": "@timestamp",
|
|
||||||
"id": "2",
|
|
||||||
"settings": {
|
|
||||||
"interval": "5m",
|
|
||||||
"min_doc_count": 1,
|
|
||||||
"trimEdges": 0
|
|
||||||
},
|
|
||||||
"type": "date_histogram"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metrics": [
|
|
||||||
{
|
|
||||||
"field": "select field",
|
|
||||||
"id": "1",
|
|
||||||
"type": "count"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"query": "fields.app:grafana",
|
|
||||||
"refId": "A",
|
|
||||||
"timeField": "@timestamp"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"thresholds": [],
|
|
||||||
"timeFrom": null,
|
|
||||||
"timeRegions": [],
|
|
||||||
"timeShift": null,
|
|
||||||
"title": "Panel Title",
|
|
||||||
"tooltip": {
|
|
||||||
"shared": true,
|
|
||||||
"sort": 0,
|
|
||||||
"value_type": "individual"
|
|
||||||
},
|
|
||||||
"type": "graph",
|
|
||||||
"xaxis": {
|
|
||||||
"buckets": null,
|
|
||||||
"mode": "time",
|
|
||||||
"name": null,
|
|
||||||
"show": true,
|
|
||||||
"values": []
|
|
||||||
},
|
|
||||||
"yaxes": [
|
|
||||||
{
|
|
||||||
"format": "short",
|
|
||||||
"label": null,
|
|
||||||
"logBase": 1,
|
|
||||||
"max": null,
|
|
||||||
"min": null,
|
|
||||||
"show": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"format": "short",
|
|
||||||
"label": null,
|
|
||||||
"logBase": 1,
|
|
||||||
"max": null,
|
|
||||||
"min": null,
|
|
||||||
"show": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"yaxis": {
|
|
||||||
"align": false,
|
|
||||||
"alignLevel": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"datasource": "gdev-elasticsearch-v7-filebeat",
|
|
||||||
"fieldConfig": {
|
|
||||||
"defaults": {
|
|
||||||
"custom": {}
|
|
||||||
},
|
|
||||||
"overrides": []
|
|
||||||
},
|
|
||||||
"gridPos": {
|
|
||||||
"h": 22,
|
|
||||||
"w": 24,
|
|
||||||
"x": 0,
|
|
||||||
"y": 5
|
|
||||||
},
|
|
||||||
"id": 2,
|
|
||||||
"links": [],
|
|
||||||
"options": {
|
|
||||||
"showLabels": false,
|
|
||||||
"showTime": true,
|
|
||||||
"sortOrder": "Descending",
|
|
||||||
"wrapLogMessage": true
|
|
||||||
},
|
|
||||||
"targets": [
|
|
||||||
{
|
|
||||||
"bucketAggs": [
|
|
||||||
{
|
|
||||||
"$$hashKey": "object:522",
|
|
||||||
"field": "@timestamp",
|
|
||||||
"id": "2",
|
|
||||||
"settings": {
|
|
||||||
"interval": "auto",
|
|
||||||
"min_doc_count": 0,
|
|
||||||
"trimEdges": 0
|
|
||||||
},
|
|
||||||
"type": "date_histogram"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metrics": [
|
|
||||||
{
|
|
||||||
"$$hashKey": "object:484",
|
|
||||||
"field": "select field",
|
|
||||||
"id": "1",
|
|
||||||
"meta": {},
|
|
||||||
"settings": {},
|
|
||||||
"type": "logs"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"query": "fields.app:grafana",
|
|
||||||
"refId": "A",
|
|
||||||
"timeField": "@timestamp"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"timeFrom": null,
|
|
||||||
"timeShift": null,
|
|
||||||
"title": "Panel Title",
|
|
||||||
"type": "logs"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"schemaVersion": 25,
|
|
||||||
"style": "dark",
|
|
||||||
"tags": ["elasticsearch", "gdev", "datasource-test"],
|
|
||||||
"templating": {
|
|
||||||
"list": [
|
|
||||||
{
|
|
||||||
"datasource": "gdev-elasticsearch-v7-filebeat",
|
|
||||||
"filters": [],
|
|
||||||
"hide": 0,
|
|
||||||
"label": "",
|
|
||||||
"name": "Filters",
|
|
||||||
"skipUrlSync": false,
|
|
||||||
"type": "adhoc"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"time": {
|
|
||||||
"from": "now-1h",
|
|
||||||
"to": "now"
|
|
||||||
},
|
|
||||||
"timepicker": {
|
|
||||||
"refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"],
|
|
||||||
"time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"]
|
|
||||||
},
|
|
||||||
"timezone": "",
|
|
||||||
"title": "Datasource tests - Elasticsearch v7 Filebeat",
|
|
||||||
"uid": "M94gguRWz",
|
|
||||||
"version": 1
|
|
||||||
}
|
|
||||||
@@ -3,7 +3,10 @@
|
|||||||
"list": [
|
"list": [
|
||||||
{
|
{
|
||||||
"builtIn": 1,
|
"builtIn": 1,
|
||||||
"datasource": "-- Grafana --",
|
"datasource": {
|
||||||
|
"type": "datasource",
|
||||||
|
"uid": "grafana"
|
||||||
|
},
|
||||||
"enable": true,
|
"enable": true,
|
||||||
"hide": true,
|
"hide": true,
|
||||||
"iconColor": "rgba(0, 211, 255, 1)",
|
"iconColor": "rgba(0, 211, 255, 1)",
|
||||||
@@ -13,17 +16,69 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"editable": true,
|
"editable": true,
|
||||||
"gnetId": null,
|
"fiscalYearStartMonth": 0,
|
||||||
"graphTooltip": 0,
|
"graphTooltip": 0,
|
||||||
"links": [],
|
"links": [],
|
||||||
|
"liveNow": false,
|
||||||
"panels": [
|
"panels": [
|
||||||
{
|
{
|
||||||
"aliasColors": {},
|
"datasource": {
|
||||||
"bars": false,
|
"type": "testdata",
|
||||||
"dashLength": 10,
|
"uid": "PD8C576611E62080A"
|
||||||
"dashes": false,
|
},
|
||||||
"fill": 0,
|
"fieldConfig": {
|
||||||
"fillGradient": 6,
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "palette-classic"
|
||||||
|
},
|
||||||
|
"custom": {
|
||||||
|
"axisCenteredZero": false,
|
||||||
|
"axisColorMode": "text",
|
||||||
|
"axisLabel": "",
|
||||||
|
"axisPlacement": "auto",
|
||||||
|
"barAlignment": 0,
|
||||||
|
"drawStyle": "line",
|
||||||
|
"fillOpacity": 60,
|
||||||
|
"gradientMode": "opacity",
|
||||||
|
"hideFrom": {
|
||||||
|
"legend": false,
|
||||||
|
"tooltip": false,
|
||||||
|
"viz": false
|
||||||
|
},
|
||||||
|
"lineInterpolation": "linear",
|
||||||
|
"lineWidth": 1,
|
||||||
|
"pointSize": 6,
|
||||||
|
"scaleDistribution": {
|
||||||
|
"type": "linear"
|
||||||
|
},
|
||||||
|
"showPoints": "always",
|
||||||
|
"spanNulls": false,
|
||||||
|
"stacking": {
|
||||||
|
"group": "A",
|
||||||
|
"mode": "none"
|
||||||
|
},
|
||||||
|
"thresholdsStyle": {
|
||||||
|
"mode": "off"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"links": [],
|
||||||
|
"mappings": [],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "red",
|
||||||
|
"value": 80
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"unit": "short"
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
"gridPos": {
|
"gridPos": {
|
||||||
"h": 15,
|
"h": 15,
|
||||||
"w": 12,
|
"w": 12,
|
||||||
@@ -31,89 +86,79 @@
|
|||||||
"y": 0
|
"y": 0
|
||||||
},
|
},
|
||||||
"id": 2,
|
"id": 2,
|
||||||
"legend": {
|
|
||||||
"avg": false,
|
|
||||||
"current": false,
|
|
||||||
"max": false,
|
|
||||||
"min": false,
|
|
||||||
"show": true,
|
|
||||||
"total": false,
|
|
||||||
"values": false
|
|
||||||
},
|
|
||||||
"lines": true,
|
|
||||||
"linewidth": 1,
|
|
||||||
"nullPointMode": "null",
|
|
||||||
"options": {
|
"options": {
|
||||||
"dataLinks": []
|
"legend": {
|
||||||
|
"calcs": [],
|
||||||
|
"displayMode": "list",
|
||||||
|
"placement": "bottom",
|
||||||
|
"showLegend": true
|
||||||
|
},
|
||||||
|
"tooltip": {
|
||||||
|
"mode": "multi",
|
||||||
|
"sort": "none"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"percentage": false,
|
"pluginVersion": "9.5.0-pre",
|
||||||
"pointradius": 2,
|
|
||||||
"points": true,
|
|
||||||
"renderer": "flot",
|
|
||||||
"seriesOverrides": [],
|
|
||||||
"spaceLength": 10,
|
|
||||||
"stack": false,
|
|
||||||
"steppedLine": false,
|
|
||||||
"targets": [
|
"targets": [
|
||||||
{
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "testdata",
|
||||||
|
"uid": "PD8C576611E62080A"
|
||||||
|
},
|
||||||
"refId": "A",
|
"refId": "A",
|
||||||
"scenarioId": "csv_metric_values",
|
"scenarioId": "csv_metric_values",
|
||||||
"stringInput": "1,20,90,30,5,0,100"
|
"stringInput": "1,20,90,30,5,0,100"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "testdata",
|
||||||
|
"uid": "PD8C576611E62080A"
|
||||||
|
},
|
||||||
"refId": "B",
|
"refId": "B",
|
||||||
"scenarioId": "csv_metric_values",
|
"scenarioId": "csv_metric_values",
|
||||||
"stringInput": "1,20,90,30,5,-100,200"
|
"stringInput": "1,20,90,30,5,-100,200"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "testdata",
|
||||||
|
"uid": "PD8C576611E62080A"
|
||||||
|
},
|
||||||
"refId": "C",
|
"refId": "C",
|
||||||
"scenarioId": "csv_metric_values",
|
"scenarioId": "csv_metric_values",
|
||||||
"stringInput": "2.5,3.5,4.5,10.5,20.5,21.5,19.5"
|
"stringInput": "2.5,3.5,4.5,10.5,20.5,21.5,19.5"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"thresholds": [],
|
|
||||||
"timeFrom": null,
|
|
||||||
"timeRegions": [],
|
|
||||||
"timeShift": null,
|
|
||||||
"title": "Raw Data Graph",
|
"title": "Raw Data Graph",
|
||||||
"tooltip": {
|
"type": "timeseries"
|
||||||
"shared": true,
|
|
||||||
"sort": 0,
|
|
||||||
"value_type": "individual"
|
|
||||||
},
|
|
||||||
"type": "graph",
|
|
||||||
"xaxis": {
|
|
||||||
"buckets": null,
|
|
||||||
"mode": "time",
|
|
||||||
"name": null,
|
|
||||||
"show": true,
|
|
||||||
"values": []
|
|
||||||
},
|
|
||||||
"yaxes": [
|
|
||||||
{
|
|
||||||
"format": "short",
|
|
||||||
"label": null,
|
|
||||||
"logBase": 1,
|
|
||||||
"max": null,
|
|
||||||
"min": null,
|
|
||||||
"show": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"format": "short",
|
|
||||||
"label": null,
|
|
||||||
"logBase": 1,
|
|
||||||
"max": null,
|
|
||||||
"min": null,
|
|
||||||
"show": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"yaxis": {
|
|
||||||
"align": false,
|
|
||||||
"alignLevel": null
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"datasource": "-- Dashboard --",
|
"datasource": {
|
||||||
|
"type": "datasource",
|
||||||
|
"uid": "-- Dashboard --"
|
||||||
|
},
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "thresholds"
|
||||||
|
},
|
||||||
|
"mappings": [],
|
||||||
|
"max": 100,
|
||||||
|
"min": 0,
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "red",
|
||||||
|
"value": 80
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
"gridPos": {
|
"gridPos": {
|
||||||
"h": 5,
|
"h": 5,
|
||||||
"w": 12,
|
"w": 12,
|
||||||
@@ -122,44 +167,59 @@
|
|||||||
},
|
},
|
||||||
"id": 4,
|
"id": 4,
|
||||||
"options": {
|
"options": {
|
||||||
"fieldOptions": {
|
"orientation": "auto",
|
||||||
"calcs": ["lastNotNull"],
|
"reduceOptions": {
|
||||||
"defaults": {
|
"calcs": [
|
||||||
"mappings": [],
|
"lastNotNull"
|
||||||
"max": 100,
|
],
|
||||||
"min": 0,
|
"fields": "",
|
||||||
"thresholds": [
|
"values": false
|
||||||
|
},
|
||||||
|
"showThresholdLabels": false,
|
||||||
|
"showThresholdMarkers": true
|
||||||
|
},
|
||||||
|
"pluginVersion": "9.5.0-pre",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "datasource",
|
||||||
|
"uid": "-- Dashboard --"
|
||||||
|
},
|
||||||
|
"panelId": 2,
|
||||||
|
"refId": "A"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Last non-null",
|
||||||
|
"type": "gauge"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "datasource",
|
||||||
|
"uid": "-- Dashboard --"
|
||||||
|
},
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "thresholds"
|
||||||
|
},
|
||||||
|
"mappings": [],
|
||||||
|
"max": 100,
|
||||||
|
"min": 0,
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
{
|
{
|
||||||
"color": "green",
|
"color": "green"
|
||||||
"value": null
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"color": "red",
|
"color": "red",
|
||||||
"value": 80
|
"value": 80
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
}
|
||||||
"override": {},
|
|
||||||
"values": false
|
|
||||||
},
|
},
|
||||||
"orientation": "auto",
|
"overrides": []
|
||||||
"showThresholdLabels": false,
|
|
||||||
"showThresholdMarkers": true
|
|
||||||
},
|
},
|
||||||
"pluginVersion": "6.4.0-pre",
|
|
||||||
"targets": [
|
|
||||||
{
|
|
||||||
"panelId": 2,
|
|
||||||
"refId": "A"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"timeFrom": null,
|
|
||||||
"timeShift": null,
|
|
||||||
"title": "Last non-null",
|
|
||||||
"type": "gauge"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"datasource": "-- Dashboard --",
|
|
||||||
"gridPos": {
|
"gridPos": {
|
||||||
"h": 5,
|
"h": 5,
|
||||||
"w": 12,
|
"w": 12,
|
||||||
@@ -168,63 +228,49 @@
|
|||||||
},
|
},
|
||||||
"id": 6,
|
"id": 6,
|
||||||
"options": {
|
"options": {
|
||||||
"fieldOptions": {
|
"orientation": "auto",
|
||||||
"calcs": ["min"],
|
"reduceOptions": {
|
||||||
"defaults": {
|
"calcs": [
|
||||||
"mappings": [],
|
"min"
|
||||||
"max": 100,
|
],
|
||||||
"min": 0,
|
"fields": "",
|
||||||
"thresholds": [
|
|
||||||
{
|
|
||||||
"color": "green",
|
|
||||||
"value": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"color": "red",
|
|
||||||
"value": 80
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"override": {},
|
|
||||||
"values": false
|
"values": false
|
||||||
},
|
},
|
||||||
"orientation": "auto",
|
|
||||||
"showThresholdLabels": false,
|
"showThresholdLabels": false,
|
||||||
"showThresholdMarkers": true
|
"showThresholdMarkers": true
|
||||||
},
|
},
|
||||||
"pluginVersion": "6.4.0-pre",
|
"pluginVersion": "9.5.0-pre",
|
||||||
"targets": [
|
"targets": [
|
||||||
{
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "datasource",
|
||||||
|
"uid": "-- Dashboard --"
|
||||||
|
},
|
||||||
"panelId": 2,
|
"panelId": 2,
|
||||||
"refId": "A"
|
"refId": "A"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"timeFrom": null,
|
|
||||||
"timeShift": null,
|
|
||||||
"title": "min",
|
"title": "min",
|
||||||
"type": "gauge"
|
"type": "gauge"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"datasource": "-- Dashboard --",
|
"datasource": {
|
||||||
"gridPos": {
|
"type": "datasource",
|
||||||
"h": 5,
|
"uid": "-- Dashboard --"
|
||||||
"w": 12,
|
|
||||||
"x": 12,
|
|
||||||
"y": 10
|
|
||||||
},
|
},
|
||||||
"id": 5,
|
"fieldConfig": {
|
||||||
"options": {
|
"defaults": {
|
||||||
"displayMode": "basic",
|
"color": {
|
||||||
"fieldOptions": {
|
"mode": "thresholds"
|
||||||
"calcs": ["max"],
|
},
|
||||||
"defaults": {
|
"mappings": [],
|
||||||
"mappings": [],
|
"max": 200,
|
||||||
"max": 200,
|
"min": 0,
|
||||||
"min": 0,
|
"thresholds": {
|
||||||
"thresholds": [
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
{
|
{
|
||||||
"color": "green",
|
"color": "green"
|
||||||
"value": null
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"color": "blue",
|
"color": "blue",
|
||||||
@@ -235,28 +281,102 @@
|
|||||||
"value": 120
|
"value": 120
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
}
|
||||||
"override": {},
|
},
|
||||||
|
"overrides": []
|
||||||
|
},
|
||||||
|
"gridPos": {
|
||||||
|
"h": 5,
|
||||||
|
"w": 12,
|
||||||
|
"x": 12,
|
||||||
|
"y": 10
|
||||||
|
},
|
||||||
|
"id": 5,
|
||||||
|
"options": {
|
||||||
|
"displayMode": "basic",
|
||||||
|
"minVizHeight": 10,
|
||||||
|
"minVizWidth": 0,
|
||||||
|
"orientation": "vertical",
|
||||||
|
"reduceOptions": {
|
||||||
|
"calcs": [
|
||||||
|
"max"
|
||||||
|
],
|
||||||
|
"fields": "",
|
||||||
"values": false
|
"values": false
|
||||||
},
|
},
|
||||||
"orientation": "vertical"
|
"showUnfilled": true,
|
||||||
|
"valueMode": "color"
|
||||||
},
|
},
|
||||||
"pluginVersion": "6.4.0-pre",
|
"pluginVersion": "9.5.0-pre",
|
||||||
"targets": [
|
"targets": [
|
||||||
{
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "datasource",
|
||||||
|
"uid": "-- Dashboard --"
|
||||||
|
},
|
||||||
"panelId": 2,
|
"panelId": 2,
|
||||||
"refId": "A"
|
"refId": "A"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"timeFrom": null,
|
|
||||||
"timeShift": null,
|
|
||||||
"title": "Max",
|
"title": "Max",
|
||||||
"type": "bargauge"
|
"type": "bargauge"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"columns": [],
|
"datasource": {
|
||||||
"datasource": "-- Dashboard --",
|
"type": "datasource",
|
||||||
"fontSize": "100%",
|
"uid": "-- Dashboard --"
|
||||||
|
},
|
||||||
|
"fieldConfig": {
|
||||||
|
"defaults": {
|
||||||
|
"color": {
|
||||||
|
"mode": "thresholds"
|
||||||
|
},
|
||||||
|
"custom": {
|
||||||
|
"align": "auto",
|
||||||
|
"cellOptions": {
|
||||||
|
"type": "auto"
|
||||||
|
},
|
||||||
|
"inspect": false
|
||||||
|
},
|
||||||
|
"decimals": 2,
|
||||||
|
"displayName": "",
|
||||||
|
"mappings": [],
|
||||||
|
"thresholds": {
|
||||||
|
"mode": "absolute",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"color": "green"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"color": "red",
|
||||||
|
"value": 80
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"unit": "short"
|
||||||
|
},
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"matcher": {
|
||||||
|
"id": "byName",
|
||||||
|
"options": "Time"
|
||||||
|
},
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"id": "displayName",
|
||||||
|
"value": "Time"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "unit",
|
||||||
|
"value": "time: YYYY-MM-DD HH:mm:ss"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "custom.align"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"gridPos": {
|
"gridPos": {
|
||||||
"h": 10,
|
"h": 10,
|
||||||
"w": 24,
|
"w": 24,
|
||||||
@@ -264,47 +384,49 @@
|
|||||||
"y": 15
|
"y": 15
|
||||||
},
|
},
|
||||||
"id": 8,
|
"id": 8,
|
||||||
"options": {},
|
"options": {
|
||||||
"pageSize": null,
|
"cellHeight": "sm",
|
||||||
"showHeader": true,
|
"footer": {
|
||||||
"sort": {
|
"countRows": false,
|
||||||
"col": 0,
|
"fields": "",
|
||||||
"desc": true
|
"reducer": [
|
||||||
},
|
"sum"
|
||||||
"styles": [
|
],
|
||||||
{
|
"show": false
|
||||||
"alias": "Time",
|
|
||||||
"dateFormat": "YYYY-MM-DD HH:mm:ss",
|
|
||||||
"pattern": "Time",
|
|
||||||
"type": "date"
|
|
||||||
},
|
},
|
||||||
{
|
"showHeader": true,
|
||||||
"alias": "",
|
"showRowNums": false
|
||||||
"colorMode": null,
|
},
|
||||||
"colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"],
|
"pluginVersion": "9.5.0-pre",
|
||||||
"decimals": 2,
|
|
||||||
"pattern": "/.*/",
|
|
||||||
"thresholds": [],
|
|
||||||
"type": "number",
|
|
||||||
"unit": "short"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"targets": [
|
"targets": [
|
||||||
{
|
{
|
||||||
|
"datasource": {
|
||||||
|
"type": "datasource",
|
||||||
|
"uid": "-- Dashboard --"
|
||||||
|
},
|
||||||
"panelId": 2,
|
"panelId": 2,
|
||||||
"refId": "A"
|
"refId": "A"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"timeFrom": null,
|
"title": "The data from graph above with seriesToColumns transform",
|
||||||
"timeShift": null,
|
"transformations": [
|
||||||
"title": "Panel Title",
|
{
|
||||||
"transform": "timeseries_to_columns",
|
"id": "seriesToColumns",
|
||||||
|
"options": {
|
||||||
|
"reducers": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
"type": "table"
|
"type": "table"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"schemaVersion": 19,
|
"refresh": "",
|
||||||
|
"schemaVersion": 38,
|
||||||
"style": "dark",
|
"style": "dark",
|
||||||
"tags": ["gdev", "datasource-test"],
|
"tags": [
|
||||||
|
"gdev",
|
||||||
|
"datasource-test"
|
||||||
|
],
|
||||||
"templating": {
|
"templating": {
|
||||||
"list": []
|
"list": []
|
||||||
},
|
},
|
||||||
@@ -313,10 +435,22 @@
|
|||||||
"to": "now"
|
"to": "now"
|
||||||
},
|
},
|
||||||
"timepicker": {
|
"timepicker": {
|
||||||
"refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"]
|
"refresh_intervals": [
|
||||||
|
"5s",
|
||||||
|
"10s",
|
||||||
|
"30s",
|
||||||
|
"1m",
|
||||||
|
"5m",
|
||||||
|
"15m",
|
||||||
|
"30m",
|
||||||
|
"1h",
|
||||||
|
"2h",
|
||||||
|
"1d"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"timezone": "",
|
"timezone": "",
|
||||||
"title": "Datasource tests - Shared Queries",
|
"title": "Datasource tests - Shared Queries",
|
||||||
"uid": "ZqZnVvFZz",
|
"uid": "ZqZnVvFZz",
|
||||||
"version": 10
|
"version": 8,
|
||||||
}
|
"weekStart": ""
|
||||||
|
}
|
||||||
@@ -81,6 +81,18 @@ async function elasticSetupIndexTemplate() {
|
|||||||
},
|
},
|
||||||
shapes: {
|
shapes: {
|
||||||
type: 'nested',
|
type: 'nested',
|
||||||
|
},
|
||||||
|
hostname: {
|
||||||
|
type: 'keyword',
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: 'integer',
|
||||||
|
},
|
||||||
|
metric: {
|
||||||
|
type: 'keyword',
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
type: 'text',
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -119,6 +131,10 @@ function getRandomLogItem(counter, timestamp) {
|
|||||||
{"type": "triangle"},
|
{"type": "triangle"},
|
||||||
{"type": "square"},
|
{"type": "square"},
|
||||||
],
|
],
|
||||||
|
hostname: chooseRandomElement(['hostname1', 'hostname2', 'hostname3', 'hostname4', 'hostname5', 'hostname6']),
|
||||||
|
value: counter,
|
||||||
|
metric: chooseRandomElement(['cpu', 'memory', 'latency']),
|
||||||
|
description: "this is description"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -163,21 +163,21 @@ local dashboard = grafana.dashboard;
|
|||||||
id: 0,
|
id: 0,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
dashboard.new('elasticsearch_compare', import '../dev-dashboards/datasource-elasticsearch/elasticsearch_compare.json') +
|
dashboard.new('elasticsearch_complex', import '../dev-dashboards/datasource-elasticsearch/elasticsearch_complex.json') +
|
||||||
resource.addMetadata('folder', 'dev-dashboards') +
|
resource.addMetadata('folder', 'dev-dashboards') +
|
||||||
{
|
{
|
||||||
spec+: {
|
spec+: {
|
||||||
id: 0,
|
id: 0,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
dashboard.new('elasticsearch_v7', import '../dev-dashboards/datasource-elasticsearch/elasticsearch_v7.json') +
|
dashboard.new('elasticsearch_migration', import '../dev-dashboards/datasource-elasticsearch/elasticsearch_migration.json') +
|
||||||
resource.addMetadata('folder', 'dev-dashboards') +
|
resource.addMetadata('folder', 'dev-dashboards') +
|
||||||
{
|
{
|
||||||
spec+: {
|
spec+: {
|
||||||
id: 0,
|
id: 0,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
dashboard.new('elasticsearch_v7_filebeat', import '../dev-dashboards/datasource-elasticsearch/elasticsearch_v7_filebeat.json') +
|
dashboard.new('elasticsearch_simple', import '../dev-dashboards/datasource-elasticsearch/elasticsearch_simple.json') +
|
||||||
resource.addMetadata('folder', 'dev-dashboards') +
|
resource.addMetadata('folder', 'dev-dashboards') +
|
||||||
{
|
{
|
||||||
spec+: {
|
spec+: {
|
||||||
|
|||||||
@@ -46,7 +46,8 @@ By default, data sources in an organization can be queried by any user in that o
|
|||||||
|
|
||||||
You can assign data source permissions to users, teams, and roles which will allow access to query or edit the data source.
|
You can assign data source permissions to users, teams, and roles which will allow access to query or edit the data source.
|
||||||
|
|
||||||
1. Navigate to **Administration > Data sources**.
|
1. Click **Connections** in the left-side menu.
|
||||||
|
1. Under Your connections, click **Data sources**.
|
||||||
1. Select the data source to which you want to assign permissions.
|
1. Select the data source to which you want to assign permissions.
|
||||||
1. On the Permissions tab, click **Add a permission**.
|
1. On the Permissions tab, click **Add a permission**.
|
||||||
1. Select **User**, **Team**, or **Role**.
|
1. Select **User**, **Team**, or **Role**.
|
||||||
@@ -58,7 +59,8 @@ You can assign data source permissions to users, teams, and roles which will all
|
|||||||
|
|
||||||
### Edit data source permissions for users, teams, or roles
|
### Edit data source permissions for users, teams, or roles
|
||||||
|
|
||||||
1. Navigate to **Administration > Data sources**.
|
1. Click **Connections** in the left-side menu.
|
||||||
|
1. Under Your connections, click **Data sources**.
|
||||||
1. Select the data source for which you want to edit permissions.
|
1. Select the data source for which you want to edit permissions.
|
||||||
1. On the Permissions tab, find the user, team, or role permission you want to update.
|
1. On the Permissions tab, find the user, team, or role permission you want to update.
|
||||||
1. Select a different option in the **Permission** dropdown.
|
1. Select a different option in the **Permission** dropdown.
|
||||||
@@ -67,7 +69,8 @@ You can assign data source permissions to users, teams, and roles which will all
|
|||||||
|
|
||||||
### Remove data source permissions for users, teams, or roles
|
### Remove data source permissions for users, teams, or roles
|
||||||
|
|
||||||
1. Navigate to **Administration > Data sources**.
|
1. Click **Connections** in the left-side menu.
|
||||||
|
1. Under Your connections, click **Data sources**.
|
||||||
1. Select the data source from which you want to remove permissions.
|
1. Select the data source from which you want to remove permissions.
|
||||||
1. On the Permissions tab, find the user, team, or role permission you want to remove.
|
1. On the Permissions tab, find the user, team, or role permission you want to remove.
|
||||||
1. Click the **X** next to the permission.
|
1. Click the **X** next to the permission.
|
||||||
@@ -122,9 +125,10 @@ You must be an Org admin or Grafana admin to enable query caching for a data sou
|
|||||||
|
|
||||||
By default, data source queries are not cached. To enable query caching for a single data source:
|
By default, data source queries are not cached. To enable query caching for a single data source:
|
||||||
|
|
||||||
1. On the left-side menu, click **Administration > Data sources**.
|
1. Click **Connections** in the left-side menu.
|
||||||
|
1. Under Your Connections, click **Data sources**.
|
||||||
1. In the data source list, click the data source that you want to turn on caching for.
|
1. In the data source list, click the data source that you want to turn on caching for.
|
||||||
1. Open the Cache tab.
|
1. Go to the Cache tab.
|
||||||
1. Click **Enable**.
|
1. Click **Enable**.
|
||||||
1. (Optional) Choose custom TTLs for the data source's queries and resources caching. If you skip this step, then Grafana uses the default TTL.
|
1. (Optional) Choose custom TTLs for the data source's queries and resources caching. If you skip this step, then Grafana uses the default TTL.
|
||||||
|
|
||||||
@@ -140,9 +144,10 @@ To configure global settings for query caching, refer to the [Query caching sect
|
|||||||
|
|
||||||
To disable query caching for a single data source:
|
To disable query caching for a single data source:
|
||||||
|
|
||||||
1. On the left-side menu, click **Administration > Data sources**.
|
1. Click **Connections** in the left-side menu.
|
||||||
|
1. Under Your Connections, click **Data sources**.
|
||||||
1. In the data source list, click the data source that you want to turn off caching for.
|
1. In the data source list, click the data source that you want to turn off caching for.
|
||||||
1. In the Cache tab, click **Disable**.
|
1. On the Cache tab, click **Disable**.
|
||||||
|
|
||||||
To disable query caching for an entire Grafana instance, set the `enabled` flag to `false` in the [Query caching section of Enterprise Configuration]({{< relref "../../setup-grafana/configure-grafana/enterprise-configuration/#caching" >}}). You will no longer see the Cache tab on any data sources, and no data source queries will be cached.
|
To disable query caching for an entire Grafana instance, set the `enabled` flag to `false` in the [Query caching section of Enterprise Configuration]({{< relref "../../setup-grafana/configure-grafana/enterprise-configuration/#caching" >}}). You will no longer see the Cache tab on any data sources, and no data source queries will be cached.
|
||||||
|
|
||||||
@@ -152,7 +157,8 @@ If you experience performance issues or repeated queries become slower to execut
|
|||||||
|
|
||||||
> **Note:** This action impacts all cache-enabled data sources. If you are using Memcached, the system clears all data from the Memcached instance.
|
> **Note:** This action impacts all cache-enabled data sources. If you are using Memcached, the system clears all data from the Memcached instance.
|
||||||
|
|
||||||
1. On the left-side menu, click **Administration > Data sources**.
|
1. Click **Connections** in the left-side menu.
|
||||||
|
1. Under Your Connections, click **Data sources**.
|
||||||
1. In the data source list, click the data source that you want to clear the cache for.
|
1. In the data source list, click the data source that you want to clear the cache for.
|
||||||
1. In the Cache tab, click **Clear cache**.
|
1. In the Cache tab, click **Clear cache**.
|
||||||
|
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ Before following the steps below, make sure you are logged in as a Grafana admin
|
|||||||
|
|
||||||
<a id="#plugin-catalog-entry"></a>
|
<a id="#plugin-catalog-entry"></a>
|
||||||
|
|
||||||
- Administrators can find the Plugin catalog at **Configuration > Plugins**.
|
- Administrators can find the Plugin catalog at **Administration > Plugins**.
|
||||||
|
|
||||||
### Browse plugins
|
### Browse plugins
|
||||||
|
|
||||||
|
|||||||
+1
@@ -207,3 +207,4 @@ The following list contains role-based access control scopes.
|
|||||||
| `settings:*` | Restrict an action to a subset of settings. For example, `settings:*` matches all settings, `settings:auth.saml:*` matches all SAML settings, and `settings:auth.saml:enabled` matches the enable property on the SAML settings. |
|
| `settings:*` | Restrict an action to a subset of settings. For example, `settings:*` matches all settings, `settings:auth.saml:*` matches all SAML settings, and `settings:auth.saml:enabled` matches the enable property on the SAML settings. |
|
||||||
| `teams:*` <br> `teams:id:*` | Restrict an action to a set of teams from an organization. For example, `teams:*` matches any team and `teams:id:1` matches the team whose ID is `1`. |
|
| `teams:*` <br> `teams:id:*` | Restrict an action to a set of teams from an organization. For example, `teams:*` matches any team and `teams:id:1` matches the team whose ID is `1`. |
|
||||||
| `users:*` <br> `users:id:*` | Restrict an action to a set of users from an organization. For example, `users:*` matches any user and `users:id:1` matches the user whose ID is `1`. |
|
| `users:*` <br> `users:id:*` | Restrict an action to a set of users from an organization. For example, `users:*` matches any user and `users:id:1` matches the user whose ID is `1`. |
|
||||||
|
| `n/a` | `n/a` means not applicable. If an action has `n/a` specified for the scope, then the action does not require a scope. For example, the `teams:create` action does not require a scope and allows users to create teams. |
|
||||||
|
|||||||
+10
@@ -71,6 +71,16 @@ The name of the annotation is {{ .Name }}, and the value is {{ .Value }}
|
|||||||
{{ end }}
|
{{ end }}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## The index function
|
||||||
|
|
||||||
|
To print a specific annotation or label use the `index` function.
|
||||||
|
|
||||||
|
```
|
||||||
|
{{ range .Alerts }}
|
||||||
|
The name of the alert is {{ index .Labels "alertname" }}
|
||||||
|
{{ end }}
|
||||||
|
```
|
||||||
|
|
||||||
## If statements
|
## If statements
|
||||||
|
|
||||||
You can use if statements in templates. For example, to print `There are no alerts` if there are no alerts in `.Alerts` you would write the following:
|
You can use if statements in templates. For example, to print `There are no alerts` if there are no alerts in `.Alerts` you would write the following:
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ When you create a library panel, the panel on the source dashboard is converted
|
|||||||
|
|
||||||
1. Open a panel in edit mode.
|
1. Open a panel in edit mode.
|
||||||
1. In the panel display options, click the down arrow option to bring changes to the visualization.
|
1. In the panel display options, click the down arrow option to bring changes to the visualization.
|
||||||
{{< figure src="/static/img/docs/library-panels/create-lib-panel-from-edit-8-0.png" class="docs-image--no-shadow" max-width= "800px" caption="Screenshot of the edit panel" >}}
|
{{< figure src="/media/docs/grafana/panels-visualizations/screenshot-create-lib-panel-from-edit-9-5.png" class="docs-image--no-shadow" max-width= "800px" >}}
|
||||||
1. Click the **Library panels** option, and then click **Create library panel** to open the create dialog.
|
1. Click **Library panels**, and then click **+ Create library panel** to open the create dialog.
|
||||||
1. In **Library panel name**, enter the name.
|
1. In **Library panel name**, enter the name.
|
||||||
1. In **Save in folder**, select the folder to save the library panel.
|
1. In **Save in folder**, select the folder to save the library panel.
|
||||||
1. Click **Create library panel** to save your changes.
|
1. Click **Create library panel** to save your changes.
|
||||||
@@ -34,14 +34,16 @@ When you create a library panel, the panel on the source dashboard is converted
|
|||||||
|
|
||||||
Once created, you can modify the library panel using any dashboard on which it appears. After you save the changes, all instances of the library panel reflect these modifications.
|
Once created, you can modify the library panel using any dashboard on which it appears. After you save the changes, all instances of the library panel reflect these modifications.
|
||||||
|
|
||||||
{{< figure src="/static/img/docs/library-panels/create-from-more-8-0.png" class="docs-image--no-shadow" max-width= "900px" caption="Screenshot of the edit panel" >}}
|
You can also create a library panel directly from the edit menu of any panel.
|
||||||
|
|
||||||
|
{{< figure src="/media/docs/grafana/panels-visualizations/screenshot-create-from-more-9-5.png" class="docs-image--no-shadow" max-width= "900px" >}}
|
||||||
|
|
||||||
## Add a library panel to a dashboard
|
## Add a library panel to a dashboard
|
||||||
|
|
||||||
Add a Grafana library panel to a dashboard when you want to provide visualizations to other dashboard users.
|
Add a Grafana library panel to a dashboard when you want to provide visualizations to other dashboard users.
|
||||||
|
|
||||||
1. Click **Dashboards** in the left-side menu.
|
1. Click **Dashboards** in the left-side menu.
|
||||||
1. Click **New** and select **New Dashboard**.
|
1. Click **New** and select **New Dashboard** in the dropdown.
|
||||||
1. On the empty dashboard, click **+ Import library panel**.
|
1. On the empty dashboard, click **+ Import library panel**.
|
||||||
|
|
||||||
You will see a list of your library panels.
|
You will see a list of your library panels.
|
||||||
@@ -60,6 +62,7 @@ Unlink a library panel when you want to make a change to the panel and not affec
|
|||||||
1. Hover over any part of the panel to display the actions menu on the top right corner.
|
1. Hover over any part of the panel to display the actions menu on the top right corner.
|
||||||
1. Click the menu and select **Edit**.
|
1. Click the menu and select **Edit**.
|
||||||
1. Click **Unlink** on the top right corner of the page.
|
1. Click **Unlink** on the top right corner of the page.
|
||||||
|
1. Click **Yes, unlink**.
|
||||||
|
|
||||||
## View a list of library panels
|
## View a list of library panels
|
||||||
|
|
||||||
@@ -69,7 +72,7 @@ You can view a list of available library panels and search for a library panel.
|
|||||||
1. Click **Library panels**.
|
1. Click **Library panels**.
|
||||||
|
|
||||||
You can see a list of previously defined library panels.
|
You can see a list of previously defined library panels.
|
||||||
{{< figure src="/static/img/docs/library-panels/library-panel-list-8-0.png" class="docs-image--no-shadow" max-width= "900px" caption="Screenshot of the edit panel" >}}
|
{{< figure src="/media/docs/grafana/panels-visualizations/screenshot-library-panel-list-9-5.png" class="docs-image--no-shadow" max-width= "900px" >}}
|
||||||
|
|
||||||
1. Search for a specific library panel if you know its name.
|
1. Search for a specific library panel if you know its name.
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ weight: 400
|
|||||||
|
|
||||||
Whenever you save a version of your dashboard, a copy of that version is saved so that previous versions of your dashboard are never lost. A list of these versions is available by entering the dashboard settings and then selecting "Versions" in the left side menu.
|
Whenever you save a version of your dashboard, a copy of that version is saved so that previous versions of your dashboard are never lost. A list of these versions is available by entering the dashboard settings and then selecting "Versions" in the left side menu.
|
||||||
|
|
||||||
<img class="no-shadow" src="/static/img/docs/v50/dashboard_versions_list.png">
|

|
||||||
|
|
||||||
The dashboard version history feature lets you compare and restore to previously saved dashboard versions.
|
The dashboard version history feature lets you compare and restore to previously saved dashboard versions.
|
||||||
|
|
||||||
@@ -25,20 +25,18 @@ The dashboard version history feature lets you compare and restore to previously
|
|||||||
|
|
||||||
To compare two dashboard versions, select the two versions from the list that you wish to compare. Once selected, the "Compare versions" button will become clickable. Click the button to view the diff between the two versions.
|
To compare two dashboard versions, select the two versions from the list that you wish to compare. Once selected, the "Compare versions" button will become clickable. Click the button to view the diff between the two versions.
|
||||||
|
|
||||||
<img class="no-shadow" src="/static/img/docs/v50/dashboard_versions_select.png">
|

|
||||||
|
|
||||||
Upon clicking the button, you'll be brought to the diff view. By default, you'll see a textual summary of the changes, like in the image below.
|
Upon clicking the button, you'll be brought to the diff view. By default, you'll see a textual summary of the changes, like in the image below.
|
||||||
|
|
||||||
<img class="no-shadow" src="/static/img/docs/v50/dashboard_versions_diff_basic.png">
|

|
||||||
|
|
||||||
If you want to view the diff of the raw JSON that represents your dashboard, you can do that as well by clicking the "View JSON Diff" button at the bottom.
|
If you want to view the diff of the raw JSON that represents your dashboard, you can do that as well by clicking the expand icon for the View JSON Diff section at the bottom.
|
||||||
|
|
||||||
If you want to restore to the version you are diffing against, you can do so by clicking the "Restore to version \<x\>" button in the top right.
|
|
||||||
|
|
||||||
## Restoring to a previously saved dashboard version
|
## Restoring to a previously saved dashboard version
|
||||||
|
|
||||||
If you need to restore to a previously saved dashboard version, you can do so by either clicking the "Restore" button on the right of a row in the dashboard version list, or by clicking the "Restore to version \<x\>" button appearing in the diff view. Clicking the button will bring up the following popup prompting you to confirm the restoration.
|
If you need to restore to a previously saved dashboard version, you can do so by either clicking the "Restore" button on the right of a row in the dashboard version list, or by clicking the **Restore to version \<x\>** button appearing in the diff view. Clicking the button will bring up the following popup prompting you to confirm the restoration.
|
||||||
|
|
||||||
<img class="no-shadow" src="/static/img/docs/v50/dashboard_versions_restore.png">
|

|
||||||
|
|
||||||
After restoring to a previous version, a new version will be created containing the same exact data as the previous version, only with a different version number. This is indicated in the "Notes column" for the row in the new dashboard version. This is done simply to ensure your previous dashboard versions are not affected by the change.
|
After restoring to a previous version, a new version will be created containing the same exact data as the previous version, only with a different version number. This is indicated in the "Notes column" for the row in the new dashboard version. This is done simply to ensure your previous dashboard versions are not affected by the change.
|
||||||
|
|||||||
@@ -26,21 +26,22 @@ Use the information in this section to access existing playlists. Start and cont
|
|||||||
|
|
||||||
### Access a playlist
|
### Access a playlist
|
||||||
|
|
||||||
1. Hover your cursor over Grafana’s side menu.
|
1. Click **Dashboards** in the left-side menu.
|
||||||
1. Click **Playlists**. You will see a list of existing playlists.
|
1. Click **Playlists** to see a list of existing playlists.
|
||||||
|
|
||||||
### Start a playlist
|
### Start a playlist
|
||||||
|
|
||||||
You can start a playlist in five different view modes. View mode determine how the menus and navigation bar appear on the dashboards.
|
You can start a playlist in five different view modes. View modes determine how the menus and navigation bar appear on the dashboards.
|
||||||
|
|
||||||
By default, each dashboard is displayed for the amount of time entered in the Interval field, which you set when you create or edit a playlist. After you start a playlist, you can control it with the navbar at the top of the page.
|
By default, each dashboard is displayed for the amount of time entered in the Interval field, which you set when you create or edit a playlist. After you start a playlist, you can control it with the navbar at the top of the page.
|
||||||
|
|
||||||
1. [Access](#access-playlist) the playlist page to see a list of existing playlists.
|
1. Click **Dashboards** in the left-side menu.
|
||||||
1. Find the playlist you want to start, then click **Start playlist**. The start playlist dialog opens.
|
1. Click **Playlists** to see a list of existing playlists.
|
||||||
1. Select one of the five playlist modes available based on the information in the following table.
|
1. Find the playlist you want to start, then click **Start playlist**.
|
||||||
1. Click **Start <playlist name>**.
|
1. In the modal that opens, select one of the five playlist modes available, based on the information in the table below.
|
||||||
|
1. Click **Start \<playlist name\>**.
|
||||||
|
|
||||||
The playlist displays each dashboard for the time specified in the `Interval` field, set when creating or editing a playlist. Once a playlist starts, you can [control](#control-a-playlist) it using the navbar at the top of your screen.
|
The playlist displays each dashboard for the time specified in the **Interval** field, set when creating or editing a playlist. Once a playlist starts, you can [control](#control-a-playlist) it using the navbar at the top of your screen.
|
||||||
|
|
||||||
| Mode | Description |
|
| Mode | Description |
|
||||||
| --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
@@ -67,7 +68,9 @@ You can control a playlist in **Normal** or **TV** mode after it's started, usin
|
|||||||
|
|
||||||
You can create a playlist to present dashboards in a sequence, with a set order and time interval between dashboards.
|
You can create a playlist to present dashboards in a sequence, with a set order and time interval between dashboards.
|
||||||
|
|
||||||
1. In the playlist page, click **New playlist**. The New playlist page opens.
|
1. Click **Dashboards** in the left-side menu.
|
||||||
|
1. Click **Playlists** to see a list of existing playlists.
|
||||||
|
1. Click **New playlist**. The New playlist page opens.
|
||||||
1. In the **Name** text box, enter a descriptive name.
|
1. In the **Name** text box, enter a descriptive name.
|
||||||
1. In the **Interval** text box, enter a time interval. Grafana displays a particular dashboard for the interval of time specified here before moving on to the next dashboard.
|
1. In the **Interval** text box, enter a time interval. Grafana displays a particular dashboard for the interval of time specified here before moving on to the next dashboard.
|
||||||
1. In Dashboards, add existing dashboards to the playlist using **Add by title** and **Add by tag** drop-down options. The dashboards you add are listed in a sequential order.
|
1. In Dashboards, add existing dashboards to the playlist using **Add by title** and **Add by tag** drop-down options. The dashboards you add are listed in a sequential order.
|
||||||
@@ -82,8 +85,8 @@ You can create a playlist to present dashboards in a sequence, with a set order
|
|||||||
|
|
||||||
You can save a playlist and add it to your **Playlists** page, where you can start it. Be sure that all the dashboards you want to appear in your playlist are added when creating or editing the playlist before saving it.
|
You can save a playlist and add it to your **Playlists** page, where you can start it. Be sure that all the dashboards you want to appear in your playlist are added when creating or editing the playlist before saving it.
|
||||||
|
|
||||||
1. To access the Playlist feature, hover your cursor over Grafana's side menu.
|
1. Click **Dashboards** in the left-side menu.
|
||||||
1. Click **Playlists**.
|
1. Click **Playlists** to see a list of existing playlists.
|
||||||
1. Click on the playlist.
|
1. Click on the playlist.
|
||||||
1. Edit the playlist.
|
1. Edit the playlist.
|
||||||
1. Ensure that your playlist has a **Name**, **Interval**, and at least one **Dashboard** added to it.
|
1. Ensure that your playlist has a **Name**, **Interval**, and at least one **Dashboard** added to it.
|
||||||
@@ -95,36 +98,47 @@ You can edit a playlist by updating its name, interval time, and by adding, remo
|
|||||||
|
|
||||||
### Edit a playlist
|
### Edit a playlist
|
||||||
|
|
||||||
1. In the playlist page, click **Edit playlist**. The Edit playlist page opens.
|
1. Click **Dashboards** in the left-side menu.
|
||||||
|
1. Click **Playlists** to see a list of existing playlists.
|
||||||
|
1. Find the playlist you want to update and click **Edit playlist**.
|
||||||
1. Update the name and time interval, then add or remove dashboards from the playlist using instructions in [Create a playlist](#create-a-playlist).
|
1. Update the name and time interval, then add or remove dashboards from the playlist using instructions in [Create a playlist](#create-a-playlist).
|
||||||
1. Click **Save** to save your changes.
|
1. Click **Save** to save your changes.
|
||||||
|
|
||||||
### Delete a playlist
|
### Delete a playlist
|
||||||
|
|
||||||
1. Click **Playlists**.
|
1. Click **Dashboards** in the left-side menu.
|
||||||
1. Next to the Playlist you want to delete, click **Remove[x]**.
|
1. Click **Playlists** to see a list of existing playlists.
|
||||||
|
1. Find the playlist you want to remove.
|
||||||
|
1. Click **Delete playlist**.
|
||||||
|
|
||||||
### Rearrange dashboard order
|
### Rearrange dashboard order
|
||||||
|
|
||||||
1. Next to the dashboard you want to move, click the up or down arrow.
|
1. Click **Dashboards** in the left-side menu.
|
||||||
|
1. Click **Playlists** to see a list of existing playlists.
|
||||||
|
1. Find the playlist you want to update and click **Edit playlist**.
|
||||||
|
1. Click and drag the dashboards into your desired order.
|
||||||
1. Click **Save** to save your changes.
|
1. Click **Save** to save your changes.
|
||||||
|
|
||||||
### Remove a dashboard
|
### Remove a dashboard
|
||||||
|
|
||||||
1. Click **Remove[x]** to remove a dashboard from the playlist.
|
1. Click **Dashboards** in the left-side menu.
|
||||||
|
1. Click **Playlists** to see a list of existing playlists.
|
||||||
|
1. Find the playlist you want to update and click **Edit playlist**.
|
||||||
|
1. Click **\[x\]** on the name of the dashboard you want to remove from the playlist.
|
||||||
1. Click **Save** to save your changes.
|
1. Click **Save** to save your changes.
|
||||||
|
|
||||||
## Share a playlist in a view mode
|
## Share a playlist in a view mode
|
||||||
|
|
||||||
You can share a playlist by copying the link address on the view mode you prefer, and pasting the URL to your destination.
|
You can share a playlist by copying the link address on the view mode you prefer, and pasting the URL to your destination.
|
||||||
|
|
||||||
1. From the Dashboards submenu, click **Playlists**.
|
1. Click **Dashboards** in the left-side menu.
|
||||||
1. Next to the playlist you want to share, click **Start playlist**.
|
1. Click **Playlists** to see a list of existing playlists.
|
||||||
1. In the dropdown, right click the view mode you prefer.
|
1. Click the share icon of the playlist you want to share.
|
||||||
1. Click **Copy Link Address** to copy the URL to your clipboard.
|
1. Select the view mode you prefer.
|
||||||
|
1. Click **Copy** next to the Link URL to copy it to your clipboard.
|
||||||
|
|
||||||
Example: The URL for the first playlist on the Grafana Play site in Kiosk mode will look like this:
|
For example, the URL for the first playlist on the Grafana Play site in Kiosk mode will look like this:
|
||||||
|
|
||||||
[https://play.grafana.org/playlists/play/1?kiosk](https://play.grafana.org/playlists/play/1?kiosk).
|
[https://play.grafana.org/playlists/play/1?kiosk](https://play.grafana.org/playlists/play/1?kiosk).
|
||||||
|
|
||||||
1. Paste the URL to your destination.
|
1. Paste the URL to your destination.
|
||||||
|
|||||||
@@ -48,14 +48,16 @@ Folders help you organize and group dashboards, which is useful when you have ma
|
|||||||
|
|
||||||
**To create a dashboard folder:**
|
**To create a dashboard folder:**
|
||||||
|
|
||||||
1. Sign in to Grafana and on the side menu, click **Dashboards > New folder**.
|
1. Sign in to Grafana.
|
||||||
|
1. Click **Dashboards** in the left-side menu.
|
||||||
|
1. On the Dashboards page, click **New** and select **New folder** in the dropdown.
|
||||||
1. Enter a unique name and click **Create**.
|
1. Enter a unique name and click **Create**.
|
||||||
|
|
||||||
When you save a dashboard, you can either select a folder for the dashboard to be saved in or create a new folder.
|
When you save a dashboard, you can either select a folder for the dashboard to be saved in or create a new folder.
|
||||||
|
|
||||||
## Manage dashboards
|
## Manage dashboards
|
||||||
|
|
||||||
On the **Manage dashboards and folders** page, you can:
|
On the Dashboards page, you can:
|
||||||
|
|
||||||
- create a folder
|
- create a folder
|
||||||
- create a dashboard
|
- create a dashboard
|
||||||
@@ -65,17 +67,17 @@ On the **Manage dashboards and folders** page, you can:
|
|||||||
|
|
||||||
### Dashboard folder page
|
### Dashboard folder page
|
||||||
|
|
||||||
You can complete the following tasks on the **Dashboard Folder** page:
|
You can complete the following tasks on a dashboard folder page:
|
||||||
|
|
||||||
- Move or delete dashboards in a folder
|
- Move or delete dashboards in a folder
|
||||||
- Rename a folder (available under the **Settings** tab)
|
- Rename a folder (available on the Settings tab)
|
||||||
- Assign permissions to folders (which are inherited by the dashboards in the folder)
|
- Assign permissions to folders (which are inherited by the dashboards in the folder)
|
||||||
|
|
||||||
To navigate to the dashboard folder page, click the cog appears when you hover over a folder in the dashboard search result list or the **Manage dashboards and folders** page.
|
To navigate to the dashboard folder page, hover over the name of the folder and click **Go to folder** in the dashboard search result list or on the Dashboards page.
|
||||||
|
|
||||||
### Dashboard permissions
|
### Dashboard permissions
|
||||||
|
|
||||||
You can assign permissions to a folder. Any permissions you assign are inherited by the dashboards in the folder. An Access Control List (ACL) is used where **Organization Role**, **Team** and a **User** can be assigned permissions.
|
You can assign permissions to a folder. Any permissions you assign are inherited by the dashboards in the folder. An Access Control List (ACL) is used where **Organization Role**, **Team**, and a **User** can be assigned permissions.
|
||||||
|
|
||||||
For more information about dashboard permissions, refer to [Dashboard permissions]({{< relref "../../administration/roles-and-permissions/#dashboard-permissions" >}}).
|
For more information about dashboard permissions, refer to [Dashboard permissions]({{< relref "../../administration/roles-and-permissions/#dashboard-permissions" >}}).
|
||||||
|
|
||||||
@@ -87,10 +89,11 @@ You can use the Grafana UI or the [HTTP API]({{< relref "../../developers/http_a
|
|||||||
|
|
||||||
The dashboard export action creates a Grafana JSON file that contains everything you need, including layout, variables, styles, data sources, queries, and so on, so that you can later import the dashboard.
|
The dashboard export action creates a Grafana JSON file that contains everything you need, including layout, variables, styles, data sources, queries, and so on, so that you can later import the dashboard.
|
||||||
|
|
||||||
|
1. Click **Dashboards** in the left-side menu.
|
||||||
1. Open the dashboard you want to export.
|
1. Open the dashboard you want to export.
|
||||||
2. Click the **Share** icon.
|
1. Click the **Share** icon.
|
||||||
3. Click **Export**.
|
1. Click **Export**.
|
||||||
4. Click **Save to file**.
|
1. Click **Save to file**.
|
||||||
|
|
||||||
Grafana downloads a JSON file to your local machine.
|
Grafana downloads a JSON file to your local machine.
|
||||||
|
|
||||||
@@ -102,7 +105,8 @@ A template variable of the type `Constant` will automatically be hidden in the d
|
|||||||
|
|
||||||
### Import a dashboard
|
### Import a dashboard
|
||||||
|
|
||||||
1. Click **Dashboards > Import** in the side menu.
|
1. Click **Dashboards** in the left-side menu.
|
||||||
|
1. Click **New** and select **Import** in the dropdown menu.
|
||||||
1. Perform one of the following steps:
|
1. Perform one of the following steps:
|
||||||
|
|
||||||
- Upload a dashboard JSON file
|
- Upload a dashboard JSON file
|
||||||
@@ -118,7 +122,7 @@ The import process enables you to change the name of the dashboard, pick the dat
|
|||||||
|
|
||||||
Find dashboards for common server applications at [Grafana.com/dashboards](https://grafana.com/dashboards).
|
Find dashboards for common server applications at [Grafana.com/dashboards](https://grafana.com/dashboards).
|
||||||
|
|
||||||
{{< figure src="/static/img/docs/v50/gcom_dashboard_list.png" max-width="700px" >}}
|
{{< figure src="/media/docs/grafana/dashboards/screenshot-gcom-dashboards.png" >}}
|
||||||
|
|
||||||
## Troubleshoot dashboards
|
## Troubleshoot dashboards
|
||||||
|
|
||||||
|
|||||||
@@ -52,10 +52,11 @@ You can share a dashboard as a direct link or as a snapshot. You can also export
|
|||||||
|
|
||||||
> **Note:** If you change a dashboard, ensure that you save the changes before sharing.
|
> **Note:** If you change a dashboard, ensure that you save the changes before sharing.
|
||||||
|
|
||||||
1. Navigate to the home page of your Grafana instance.
|
1. Click **Dashboards** in the left-side menu.
|
||||||
1. Click on the share icon in the top navigation.
|
1. Click the dashboard you want to share.
|
||||||
|
1. Click the share icon at the top of the screen.
|
||||||
|
|
||||||
The share dialog opens and shows the **Link** tab.
|
The share dialog opens and shows the Link tab.
|
||||||
|
|
||||||
### Share a direct link
|
### Share a direct link
|
||||||
|
|
||||||
@@ -73,7 +74,8 @@ A dashboard snapshot shares an interactive dashboard publicly. Grafana strips se
|
|||||||
|
|
||||||
You can publish snapshots to your local instance or to [snapshots.raintank.io](http://snapshots.raintank.io). The latter is a free service provided by Grafana Labs that enables you to publish dashboard snapshots to an external Grafana instance. Anyone with the link can view it. You can set an expiration time if you want the snapshot removed after a certain time period.
|
You can publish snapshots to your local instance or to [snapshots.raintank.io](http://snapshots.raintank.io). The latter is a free service provided by Grafana Labs that enables you to publish dashboard snapshots to an external Grafana instance. Anyone with the link can view it. You can set an expiration time if you want the snapshot removed after a certain time period.
|
||||||
|
|
||||||
1. Click **Local Snapshot** or **Publish to snapshots.raintank.io**.
|
1. Click the **Snapshot** tab.
|
||||||
|
1. Click **Publish to snapshots.raintank.io** or **Local Snapshot**.
|
||||||
|
|
||||||
Grafana generates a link of the snapshot.
|
Grafana generates a link of the snapshot.
|
||||||
|
|
||||||
@@ -91,7 +93,9 @@ You can generate and save PDF files of any dashboard.
|
|||||||
|
|
||||||
> **Note:** Available in [Grafana Enterprise]({{< relref "../../introduction/grafana-enterprise/" >}}).
|
> **Note:** Available in [Grafana Enterprise]({{< relref "../../introduction/grafana-enterprise/" >}}).
|
||||||
|
|
||||||
1. In the upper-right corner of the dashboard that you want to export as PDF, click the **Share dashboard** icon.
|
1. Click **Dashboards** in the left-side menu.
|
||||||
|
1. Click the dashboard you want to share.
|
||||||
|
1. Click the share icon at the top of the screen.
|
||||||
1. On the PDF tab, select a layout option for the exported dashboard: **Portrait** or **Landscape**.
|
1. On the PDF tab, select a layout option for the exported dashboard: **Portrait** or **Landscape**.
|
||||||
1. Click **Save as PDF** to render the dashboard as a PDF file.
|
1. Click **Save as PDF** to render the dashboard as a PDF file.
|
||||||
|
|
||||||
@@ -101,8 +105,8 @@ You can generate and save PDF files of any dashboard.
|
|||||||
|
|
||||||
You can share a panel as a direct link, as a snapshot, or as an embedded link. You can also create library panels using the **Share** option on any panel.
|
You can share a panel as a direct link, as a snapshot, or as an embedded link. You can also create library panels using the **Share** option on any panel.
|
||||||
|
|
||||||
1. Click a panel title to open the panel menu.
|
1. Hover over any part of the panel to display the actions menu on the top right corner.
|
||||||
1. Click **Share**.
|
1. Click the menu and select **Share**.
|
||||||
|
|
||||||
The share dialog opens and shows the **Link** tab.
|
The share dialog opens and shows the **Link** tab.
|
||||||
|
|
||||||
@@ -139,8 +143,8 @@ A panel snapshot shares an interactive panel publicly. Grafana strips sensitive
|
|||||||
|
|
||||||
You can publish snapshots to your local instance or to [snapshots.raintank.io](http://snapshots.raintank.io). The latter is a free service provided by [Grafana Labs](https://grafana.com), that enables you to publish dashboard snapshots to an external Grafana instance. You can optionally set an expiration time if you want the snapshot to be removed after a certain time period.
|
You can publish snapshots to your local instance or to [snapshots.raintank.io](http://snapshots.raintank.io). The latter is a free service provided by [Grafana Labs](https://grafana.com), that enables you to publish dashboard snapshots to an external Grafana instance. You can optionally set an expiration time if you want the snapshot to be removed after a certain time period.
|
||||||
|
|
||||||
1. In the **Share Panel** dialog, click **Snapshot** to open the tab.
|
1. In the **Share Panel** dialog, click **Snapshot** to go to the tab.
|
||||||
1. Click **Local Snapshot** or **Publish to snapshots.raintank.io**.
|
1. Click **Publish to snapshots.raintank.io** or **Local Snapshot**.
|
||||||
|
|
||||||
Grafana generates the link of the snapshot.
|
Grafana generates the link of the snapshot.
|
||||||
|
|
||||||
|
|||||||
@@ -27,27 +27,28 @@ The dashboard user interface provides a number of features that you can use to c
|
|||||||
|
|
||||||
The following image and descriptions highlights all dashboards features.
|
The following image and descriptions highlights all dashboards features.
|
||||||
|
|
||||||
{{< figure src="/static/img/docs/v91/dashboard-features/dashboard-features.png" width="700px" >}}
|
{{< figure src="/media/docs/grafana/dashboards/screenshot-dashboard-annotated-9-5-0.png" width="700px" >}}
|
||||||
|
|
||||||
- **Grafana home** (1): Click the Grafana home icon to be redirected to the home page configured in the Grafana instance.
|
- **Grafana home** (1): Click **Home** in the breadcrumb to be redirected to the home page configured in the Grafana instance.
|
||||||
- **Dashboard title** (2): When you click the dashboard title you can search for dashboard contained in the current folder.
|
- **Dashboard title** (2): When you click the dashboard title you can search for dashboard contained in the current folder.
|
||||||
- **Share dashboard** (3): Use this option to share the current dashboard by link or snapshot. You can also export the dashboard definition from the share modal.
|
- **Share dashboard or panel** (3): Use this option to share the current dashboard or panel by link or snapshot. You can also export the dashboard definition from the share modal.
|
||||||
- **Add a new panel** (4): Use this option to add a panel, dashboard row, or library panel to the current dashboard.
|
- **Add** (4): Use this option to add a panel, dashboard row, or library panel to the current dashboard.
|
||||||
- **Dashboard settings** (5): Use this option to change dashboard name, folder, and tags and manage variables and annotation queries. For more information about dashboard settings, refer to [Modify dashboard settings]({{< relref "../build-dashboards/modify-dashboard-settings/" >}}).
|
- **Save dashboard** (5): Click to save changes to your dashboard.
|
||||||
- **Time picker dropdown** (6): Click to select relative time range options and set custom absolute time ranges.
|
- **Dashboard insights** (6): Click to view analytics about your dashboard including information about users, activity, query counts.
|
||||||
|
- **Dashboard settings** (7): Use this option to change dashboard name, folder, and tags and manage variables and annotation queries. For more information about dashboard settings, refer to [Modify dashboard settings]({{< relref "../build-dashboards/modify-dashboard-settings/" >}}).
|
||||||
|
- **Time picker dropdown** (8): Click to select relative time range options and set custom absolute time ranges.
|
||||||
- You can change the **Timezone** and **fiscal year** settings from the time range controls by clicking the **Change time settings** button.
|
- You can change the **Timezone** and **fiscal year** settings from the time range controls by clicking the **Change time settings** button.
|
||||||
- Time settings are saved on a per-dashboard basis.
|
- Time settings are saved on a per-dashboard basis.
|
||||||
- **Zoom out time range** (7): Click to zoom out the time range. For more information about how to use time range controls, refer to [Common time range controls]({{< relref "#common-time-range-controls" >}}).
|
- **Zoom out time range** (9): Click to zoom out the time range. For more information about how to use time range controls, refer to [Common time range controls]({{< relref "#common-time-range-controls" >}}).
|
||||||
- **Refresh dashboard** (8): Click to immediately trigger queries and refresh dashboard data.
|
- **Refresh dashboard** (10): Click to immediately trigger queries and refresh dashboard data.
|
||||||
- **Refresh dashboard time interval** (9): Click to select a dashboard auto refresh time interval.
|
- **Refresh dashboard time interval** (11): Click to select a dashboard auto refresh time interval.
|
||||||
- **View mode** (10): Click to display the dashboard on a large screen such as a TV or a kiosk. View mode hides irrelevant information such as navigation menus. For more information about view mode, refer to [How to Create Kiosks to Display Dashboards on a TV](https://grafana.com/blog/2019/05/02/grafana-tutorial-how-to-create-kiosks-to-display-dashboards-on-a-tv/).
|
- **View mode** (12): Click to display the dashboard on a large screen such as a TV or a kiosk. View mode hides irrelevant information such as navigation menus. For more information about view mode, refer to [How to Create Kiosks to Display Dashboards on a TV](https://grafana.com/blog/2019/05/02/grafana-tutorial-how-to-create-kiosks-to-display-dashboards-on-a-tv/).
|
||||||
- **Dashboard panel** (11): The primary building block of a dashboard is the panel. To add a new panel, dashboard row, or library panel, click **Add panel**.
|
- **Dashboard panel** (13): The primary building block of a dashboard is the panel. To add a new panel, dashboard row, or library panel, click **Add panel**.
|
||||||
- Library panels can be shared among many dashboards.
|
- Library panels can be shared among many dashboards.
|
||||||
- To move a panel, drag the panel header to another location.
|
- To move a panel, drag the panel header to another location.
|
||||||
- To resize a panel, click and drag the lower right corner of the panel.
|
- To resize a panel, click and drag the lower right corner of the panel.
|
||||||
- **Graph legend** (12): Change series colors, y-axis and series visibility directly from the legend.
|
- **Graph legend** (14): Change series colors, y-axis and series visibility directly from the legend.
|
||||||
- **Search** (13): Click **Search** to search for dashboards by name or panel title.
|
- **Dashboard row** (15): A dashboard row is a logical divider within a dashboard that groups panels together.
|
||||||
- **Dashboard row** (14): A dashboard row is a logical divider within a dashboard that groups panels together.
|
|
||||||
- Rows can be collapsed or expanded allowing you to hide parts of the dashboard.
|
- Rows can be collapsed or expanded allowing you to hide parts of the dashboard.
|
||||||
- Panels inside a collapsed row do not issue queries.
|
- Panels inside a collapsed row do not issue queries.
|
||||||
- Use [repeating rows]({{< relref "../build-dashboards/create-dashboard/#configure-repeating-rows" >}}) to dynamically create rows based on a template variable.
|
- Use [repeating rows]({{< relref "../build-dashboards/create-dashboard/#configure-repeating-rows" >}}) to dynamically create rows based on a template variable.
|
||||||
@@ -129,7 +130,7 @@ Hover your cursor over the field to see the exact time stamps in the range and t
|
|||||||
|
|
||||||
Click the current time range to change it. You can change the current time using a _relative time range_, such as the last 15 minutes, or an _absolute time range_, such as `2020-05-14 00:00:00 to 2020-05-15 23:59:59`.
|
Click the current time range to change it. You can change the current time using a _relative time range_, such as the last 15 minutes, or an _absolute time range_, such as `2020-05-14 00:00:00 to 2020-05-15 23:59:59`.
|
||||||
|
|
||||||
<img class="no-shadow" src="/static/img/docs/time-range-controls/change-current-time-range-7-0.png" max-width="900px">
|
<img class="no-shadow" src="/media/docs/grafana/dashboards/screenshot-change-current-time-range.png" max-width="900px">
|
||||||
|
|
||||||
#### Relative time range
|
#### Relative time range
|
||||||
|
|
||||||
|
|||||||
@@ -44,17 +44,17 @@ weight: 100
|
|||||||
|
|
||||||
The following table lists the types of variables shipped with Grafana.
|
The following table lists the types of variables shipped with Grafana.
|
||||||
|
|
||||||
| Variable type | Description |
|
| Variable type | Description |
|
||||||
| :---------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| :---------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| Query | Query-generated list of values such as metric names, server names, sensor IDs, data centers, and so on. [Add a query variable]({{< relref "#add-a-query-variable" >}}). |
|
| Query | Query-generated list of values such as metric names, server names, sensor IDs, data centers, and so on. [Add a query variable]({{< relref "#add-a-query-variable" >}}). |
|
||||||
| Custom | Define the variable options manually using a comma-separated list. [Add a custom variable]({{< relref "#add-a-custom-variable" >}}). |
|
| Custom | Define the variable options manually using a comma-separated list. [Add a custom variable]({{< relref "#add-a-custom-variable" >}}). |
|
||||||
| Text box | Display a free text input field with an optional default value. [Add a text box variable]({{< relref "#add-a-text-box-variable" >}}). |
|
| Text box | Display a free text input field with an optional default value. [Add a text box variable]({{< relref "#add-a-text-box-variable" >}}). |
|
||||||
| Constant | Define a hidden constant. [Add a constant variable]({{< relref "#add-a-constant-variable" >}}). |
|
| Constant | Define a hidden constant. [Add a constant variable]({{< relref "#add-a-constant-variable" >}}). |
|
||||||
| Data source | Quickly change the data source for an entire dashboard. [Add a data source variable]({{< relref "#add-a-data-source-variable" >}}). |
|
| Data source | Quickly change the data source for an entire dashboard. [Add a data source variable]({{< relref "#add-a-data-source-variable" >}}). |
|
||||||
| Interval | Interval variables represent time spans. [Add an interval variable]({{< relref "#add-an-interval-variable" >}}). |
|
| Interval | Interval variables represent time spans. [Add an interval variable]({{< relref "#add-an-interval-variable" >}}). |
|
||||||
| Ad hoc filters | Key/value filters that are automatically added to all metric queries for a data source (InfluxDB, Prometheus, and Elasticsearch only). [Add ad hoc filters]({{< relref "#add-ad-hoc-filters" >}}). |
|
| Ad hoc filters | Key/value filters that are automatically added to all metric queries for a data source (Prometheus, Loki, InfluxDB, and Elasticsearch only). [Add ad hoc filters]({{< relref "#add-ad-hoc-filters" >}}). |
|
||||||
| Global variables | Built-in variables that can be used in expressions in the query editor. Refer to [Global variables]({{< relref "#global-variables" >}}). |
|
| Global variables | Built-in variables that can be used in expressions in the query editor. Refer to [Global variables]({{< relref "#global-variables" >}}). |
|
||||||
| Chained variables | Variable queries can contain other variables. Refer to [Chained variables]({{< relref "#chained-variables" >}}). |
|
| Chained variables | Variable queries can contain other variables. Refer to [Chained variables]({{< relref "#chained-variables" >}}). |
|
||||||
|
|
||||||
## Enter General options
|
## Enter General options
|
||||||
|
|
||||||
@@ -194,7 +194,7 @@ Ad hoc filters are one of the most complex and flexible variable options availab
|
|||||||
|
|
||||||
Interpolating a variable with multiple values selected is tricky as it is not straight forward how to format the multiple values into a string that is valid in the given context where the variable is used. Grafana tries to solve this by allowing each data source plugin to inform the templating interpolation engine what format to use for multiple values.
|
Interpolating a variable with multiple values selected is tricky as it is not straight forward how to format the multiple values into a string that is valid in the given context where the variable is used. Grafana tries to solve this by allowing each data source plugin to inform the templating interpolation engine what format to use for multiple values.
|
||||||
|
|
||||||
> **Note:** The **Custom all value** option on the variable must be blank for Grafana to format all values into a single string. If leave it blank, then the Grafana concatenates (adds together) all the values in the query. Something like `value1,value2,value3`. If a custom `all` value is used, then instead the value will be something like `*` or `all`.
|
> **Note:** The **Custom all value** option on the variable must be blank for Grafana to format all values into a single string. If it is left blank, then Grafana concatenates (adds together) all the values in the query. Something like `value1,value2,value3`. If a custom `all` value is used, then instead the value will be something like `*` or `all`.
|
||||||
|
|
||||||
#### Multi-value variables with a Graphite data source
|
#### Multi-value variables with a Graphite data source
|
||||||
|
|
||||||
@@ -281,6 +281,8 @@ This variable is the `$__interval` variable in milliseconds, not a time interval
|
|||||||
|
|
||||||
This variable is only available in the Singlestat panel and can be used in the prefix or suffix fields on the Options tab. The variable will be replaced with the series name or alias.
|
This variable is only available in the Singlestat panel and can be used in the prefix or suffix fields on the Options tab. The variable will be replaced with the series name or alias.
|
||||||
|
|
||||||
|
> **Note:** The Singlestat panel is no longer available from Grafana 8.0.
|
||||||
|
|
||||||
### $\_\_org
|
### $\_\_org
|
||||||
|
|
||||||
This variable is the ID of the current organization.
|
This variable is the ID of the current organization.
|
||||||
@@ -398,7 +400,7 @@ apps.fakesite.web_server_01.cpu.*
|
|||||||
|
|
||||||
#### InfluxDB example
|
#### InfluxDB example
|
||||||
|
|
||||||
In this example, you have several data centers. Each data center has a different subset of hosts. It is based on the [InfluxDB Templated](https://play.grafana.org/d/000000002/influxdb-templated?orgId=1).
|
In this example, you have several data centers. Each data center has a different subset of hosts. It is based on the [InfluxDB Templated](https://play.grafana.org/d/000000002/influxdb-templated?orgId=1) dashboard.
|
||||||
|
|
||||||
In this example, when the user changes the value of the `datacenter` variable, it changes the dropdown options returned by the `host` variable. The `host` variable uses the **Multi-value** option and **Include all option**, allowing users to select some or all options presented at any time. The `datacenter` does not use either option, so you can only select one data center at a time.
|
In this example, when the user changes the value of the `datacenter` variable, it changes the dropdown options returned by the `host` variable. The `host` variable uses the **Multi-value** option and **Include all option**, allowing users to select some or all options presented at any time. The `datacenter` does not use either option, so you can only select one data center at a time.
|
||||||
|
|
||||||
@@ -407,7 +409,7 @@ In this example, when the user changes the value of the `datacenter` variable, i
|
|||||||
The query for this variable basically says, "Give me all the data centers that exist."
|
The query for this variable basically says, "Give me all the data centers that exist."
|
||||||
|
|
||||||
```
|
```
|
||||||
SHOW TAG VALUES WITH KEY = "datacenter"
|
SHOW TAG VALUES WITH KEY = "datacenter"
|
||||||
```
|
```
|
||||||
|
|
||||||
The values returned are `America`, `Africa`, `Asia`, and `Europe`.
|
The values returned are `America`, `Africa`, `Asia`, and `Europe`.
|
||||||
|
|||||||
@@ -28,24 +28,25 @@ When using Prometheus, contact points and notification policies are read-only in
|
|||||||
|
|
||||||
## Configure the data source
|
## Configure the data source
|
||||||
|
|
||||||
**To access the data source configuration page:**
|
To configure basic settings for the data source, complete the following steps:
|
||||||
|
|
||||||
1. Select the **Data sources** section from the **Administration** menu
|
1. Click **Connections** in the left-side menu.
|
||||||
2. Select the **Alertmanager** data source
|
1. Under Your connections, click **Data sources**.
|
||||||
|
1. Enter `Alertmanager` in the search bar.
|
||||||
|
1. Click **Alertmanager**.
|
||||||
|
|
||||||
Set the data source's basic configuration options carefully:
|
The **Settings** tab of the data source is displayed.
|
||||||
|
|
||||||
| Name | Description |
|
1. Set the data source's basic configuration options:
|
||||||
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
||||||
| **Name** | Sets the name you use to refer to the data source |
|
| Name | Description |
|
||||||
| **Default** | Sets whether the data source is pre-selected for new panels and queries |
|
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| **Alertmanager** | |
|
| **Name** | Sets the name you use to refer to the data source |
|
||||||
| **Implementation** | Alertmanager implementation. **Mimir**, **Cortex,** and **Prometheus** are supported |
|
| **Default** | Sets whether the data source is pre-selected for new panels and queries |
|
||||||
| **Receive Grafana Alerts** | When enabled the Alertmanager receives alert instances from Grafana-managed alert rules. **Important:** It works only if Grafana alerting is configured to send its alert instances to external Alertmanagers |
|
| **Alertmanager Implementation** | Alertmanager implementation. **Mimir**, **Cortex,** and **Prometheus** are supported |
|
||||||
| **HTTP** | |
|
| **Receive Grafana Alerts** | When enabled the Alertmanager receives alert instances from Grafana-managed alert rules. **Important:** It works only if Grafana alerting is configured to send its alert instances to external Alertmanagers |
|
||||||
| **URL** | Sets the HTTP protocol, IP, and port of your Alertmanager instance, such as `https://alertmanager.example.org:9093` |
|
| **HTTP URL** | Sets the HTTP protocol, IP, and port of your Alertmanager instance, such as `https://alertmanager.example.org:9093` |
|
||||||
| **Access** | Only **Server** access mode is functional |
|
| **Access** | Only **Server** access mode is functional |
|
||||||
| | |
|
|
||||||
|
|
||||||
## Provision the Alertmanager data source
|
## Provision the Alertmanager data source
|
||||||
|
|
||||||
|
|||||||
@@ -31,11 +31,12 @@ Once you've added the data source, you can [configure it]({{< relref "#configure
|
|||||||
|
|
||||||
## Configure the data source
|
## Configure the data source
|
||||||
|
|
||||||
**To access the data source configuration page:**
|
1. Click **Connections** in the left-side menu.
|
||||||
|
1. Under Your connections, click **Data sources**.
|
||||||
|
1. Enter `CloudWatch` in the search bar.
|
||||||
|
1. Click **CloudWatch**.
|
||||||
|
|
||||||
1. Hover the cursor over the **Configuration** (gear) icon.
|
The **Settings** tab of the data source is displayed.
|
||||||
1. Select **Data Sources**.
|
|
||||||
1. Select the CloudWatch data source.
|
|
||||||
|
|
||||||
### Configure AWS authentication
|
### Configure AWS authentication
|
||||||
|
|
||||||
@@ -49,7 +50,7 @@ For authentication options and configuration details, refer to [AWS authenticati
|
|||||||
To read CloudWatch metrics and EC2 tags, instances, regions, and alarms, you must grant Grafana permissions via IAM.
|
To read CloudWatch metrics and EC2 tags, instances, regions, and alarms, you must grant Grafana permissions via IAM.
|
||||||
You can attach these permissions to the IAM role or IAM user you configured in [AWS authentication]({{< relref "./aws-authentication/" >}}).
|
You can attach these permissions to the IAM role or IAM user you configured in [AWS authentication]({{< relref "./aws-authentication/" >}}).
|
||||||
|
|
||||||
**Metrics-only:**
|
##### Metrics-only permissions
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
@@ -84,7 +85,7 @@ You can attach these permissions to the IAM role or IAM user you configured in [
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Logs-only:**
|
##### Logs-only permissions
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
@@ -119,7 +120,7 @@ You can attach these permissions to the IAM role or IAM user you configured in [
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Metrics and Logs:**
|
##### Metrics and logs permissions
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
@@ -167,7 +168,7 @@ You can attach these permissions to the IAM role or IAM user you configured in [
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Cross-account observability: (see below) **
|
##### Cross-account observability permissions
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
@@ -234,7 +235,7 @@ For more information about provisioning, and for available configuration options
|
|||||||
|
|
||||||
#### Provisioning examples
|
#### Provisioning examples
|
||||||
|
|
||||||
**Using AWS SDK (default):**
|
##### Using AWS SDK (default)
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
apiVersion: 1
|
apiVersion: 1
|
||||||
@@ -246,7 +247,7 @@ datasources:
|
|||||||
defaultRegion: eu-west-2
|
defaultRegion: eu-west-2
|
||||||
```
|
```
|
||||||
|
|
||||||
**Using credentials' profile name (non-default):**
|
##### Using credentials' profile name (non-default)
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
apiVersion: 1
|
apiVersion: 1
|
||||||
@@ -261,7 +262,7 @@ datasources:
|
|||||||
profile: secondary
|
profile: secondary
|
||||||
```
|
```
|
||||||
|
|
||||||
**Using accessKey and secretKey:**
|
##### Using accessKey and secretKey
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
apiVersion: 1
|
apiVersion: 1
|
||||||
@@ -277,7 +278,7 @@ datasources:
|
|||||||
secretKey: '<your secret key>'
|
secretKey: '<your secret key>'
|
||||||
```
|
```
|
||||||
|
|
||||||
**Using AWS SDK Default and ARN of IAM Role to Assume:**
|
##### Using AWS SDK Default and ARN of IAM Role to Assume
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
apiVersion: 1
|
apiVersion: 1
|
||||||
@@ -375,3 +376,7 @@ For more information, refer to the AWS documentation for [Service Quotas](https:
|
|||||||
The CloudWatch plugin enables you to monitor and troubleshoot applications across multiple regional accounts. Using cross-account observability, you can seamlessly search, visualize and analyze metrics and logs without worrying about account boundaries.
|
The CloudWatch plugin enables you to monitor and troubleshoot applications across multiple regional accounts. Using cross-account observability, you can seamlessly search, visualize and analyze metrics and logs without worrying about account boundaries.
|
||||||
|
|
||||||
To use this feature, configure in the [AWS console under Cloudwatch Settings](https://aws.amazon.com/blogs/aws/new-amazon-cloudwatch-cross-account-observability/), a monitoring and source account, and then add the necessary IAM permissions as described above.
|
To use this feature, configure in the [AWS console under Cloudwatch Settings](https://aws.amazon.com/blogs/aws/new-amazon-cloudwatch-cross-account-observability/), a monitoring and source account, and then add the necessary IAM permissions as described above.
|
||||||
|
|
||||||
|
## CloudWatch Logs data protection
|
||||||
|
|
||||||
|
CloudWatch Logs can safeguard data by using log group data protection policies. If you have data protection enabled for a log group, then any sensitive data that matches the data identifiers you've selected will be masked. In order to view masked data you will need to have the `logs:Unmask` IAM permission enabled. See the AWS documentation on how to [help protect sensitive log data with masking](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/mask-sensitive-log-data.html) to learn more about this.
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ For example, to apply arithmetic operations to a metric, apply a unique string i
|
|||||||
|
|
||||||
> **Note:** If you use the expression field to reference another query, like `queryA * 2`, you can't create an alert rule based on that query.
|
> **Note:** If you use the expression field to reference another query, like `queryA * 2`, you can't create an alert rule based on that query.
|
||||||
|
|
||||||
##### Period macro
|
#### Period macro
|
||||||
|
|
||||||
If you're using a CloudWatch [`SEARCH`](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/search-expression-syntax.html) expression, you may want to use the `$__period_auto` macro rather than specifying a period explicitly. The `$__period_auto` macro will resolve to a [CloudWatch period](https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_GetMetricData.html) that is suitable for the chosen time range.
|
If you're using a CloudWatch [`SEARCH`](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/search-expression-syntax.html) expression, you may want to use the `$__period_auto` macro rather than specifying a period explicitly. The `$__period_auto` macro will resolve to a [CloudWatch period](https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_GetMetricData.html) that is suitable for the chosen time range.
|
||||||
|
|
||||||
@@ -218,9 +218,17 @@ When making `stats` queries in [Explore]({{< relref "../../../explore/" >}}), ma
|
|||||||
|
|
||||||
{{< figure src="/static/img/docs/v70/explore-mode-switcher.png" max-width="500px" class="docs-image--right" caption="Explore mode switcher" >}}
|
{{< figure src="/static/img/docs/v70/explore-mode-switcher.png" max-width="500px" class="docs-image--right" caption="Explore mode switcher" >}}
|
||||||
|
|
||||||
### Getting started
|
## Cross-account observability
|
||||||
|
|
||||||
To enable cross-account observability, first enable it in CloudWatch using the official [CloudWatch docs](http://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-Unified-Cross-Account.html), then add [two new API actions]({{< relref "../#cross-account-observability" >}}) to the IAM policy attached to the role/user running the plugin.
|
The CloudWatch plugin allows monitoring and troubleshooting applications that span multiple accounts within a region. Using cross-account observability, you can seamlessly search, visualize, and analyze metrics and logs without worrying about account boundaries.
|
||||||
|
|
||||||
|
### Get started
|
||||||
|
|
||||||
|
To enable cross-account observability, complete the following steps:
|
||||||
|
|
||||||
|
1. Go to the [Amazon CloudWatch docs](http://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-Unified-Cross-Account.html) and follow the instructions on enabling cross-account observability.
|
||||||
|
|
||||||
|
1. Add [two API actions](/docs/grafana/latest/datasources/aws-cloudwatch/#cross-account-observability-permissions) to the IAM policy attached to the role/user running the plugin.
|
||||||
|
|
||||||
Cross-account querying is available in the plugin through the `Logs` mode and the `Metric search` mode. Once you have it configured correctly, you'll see a "Monitoring account" badge displayed in the query editor header.
|
Cross-account querying is available in the plugin through the `Logs` mode and the `Metric search` mode. Once you have it configured correctly, you'll see a "Monitoring account" badge displayed in the query editor header.
|
||||||
|
|
||||||
|
|||||||
@@ -24,26 +24,29 @@ Once you've added the Graphite data source, you can [configure it]({{< relref "#
|
|||||||
|
|
||||||
## Configure the data source
|
## Configure the data source
|
||||||
|
|
||||||
**To access the data source configuration page:**
|
To configure basic settings for the data source, complete the following steps:
|
||||||
|
|
||||||
1. Hover the cursor over the **Configuration** (gear) icon.
|
1. Click **Connections** in the left-side menu.
|
||||||
1. Select **Data Sources**.
|
1. Under Your connections, click **Data sources**.
|
||||||
1. Select the Graphite data source.
|
1. Enter `Graphite` in the search bar.
|
||||||
|
1. Click **Graphite**.
|
||||||
|
|
||||||
Set the data source's basic configuration options carefully:
|
The **Settings** tab of the data source is displayed.
|
||||||
|
|
||||||
| Name | Description |
|
1. Set the data source's basic configuration options:
|
||||||
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
|
|
||||||
| **Name** | Sets the name you use to refer to the data source in panels and queries. |
|
| Name | Description |
|
||||||
| **Default** | Sets whether the data source is pre-selected for new panels. You can set only one default data source per organization. |
|
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
|
||||||
| **URL** | Sets the HTTP protocol, IP, and port of your graphite-web or graphite-api installation. |
|
| **Name** | Sets the name you use to refer to the data source in panels and queries. |
|
||||||
| **Auth** | For details, refer to [Configure Authentication]({{< relref "../../setup-grafana/configure-security/configure-authentication/" >}}). |
|
| **Default** | Sets whether the data source is pre-selected for new panels. You can set only one default data source per organization. |
|
||||||
| **Basic Auth** | Enables basic authentication to the data source. |
|
| **URL** | Sets the HTTP protocol, IP, and port of your graphite-web or graphite-api installation. |
|
||||||
| **User** | Sets the user name for basic authentication. |
|
| **Auth** | For details, refer to [Configure Authentication]({{< relref "../../setup-grafana/configure-security/configure-authentication/" >}}). |
|
||||||
| **Password** | Sets the password for basic authentication. |
|
| **Basic Auth** | Enables basic authentication to the data source. |
|
||||||
| **Custom HTTP Headers** | Click **Add header** to add a custom HTTP header. |
|
| **User** | Sets the user name for basic authentication. |
|
||||||
| **Header** | Defines the custom header name. |
|
| **Password** | Sets the password for basic authentication. |
|
||||||
| **Value** | Defines the custom header value. |
|
| **Custom HTTP Headers** | Click **Add header** to add a custom HTTP header. |
|
||||||
|
| **Header** | Defines the custom header name. |
|
||||||
|
| **Value** | Defines the custom header value. |
|
||||||
|
|
||||||
You can also configure settings specific to the Graphite data source:
|
You can also configure settings specific to the Graphite data source:
|
||||||
|
|
||||||
|
|||||||
@@ -41,14 +41,13 @@ To configure basic settings for the data source, complete the following steps:
|
|||||||
|
|
||||||
1. Set the data source's basic configuration options carefully:
|
1. Set the data source's basic configuration options carefully:
|
||||||
|
|
||||||
| Name | Description |
|
| Name | Description |
|
||||||
|
|
||||||
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||||
| **Name** | Sets the name you use to refer to the data source in panels and queries. We recommend something like `InfluxDB-InfluxQL`. |
|
| **Name** | Sets the name you use to refer to the data source in panels and queries. We recommend something like `InfluxDB-InfluxQL`. |
|
||||||
| **Default** | Sets whether the data source is pre-selected for new panels. |
|
| **Default** | Sets whether the data source is pre-selected for new panels. |
|
||||||
| **URL** | The HTTP protocol, IP address, and port of your InfluxDB API. InfluxDB's default API port is 8086. |
|
| **URL** | The HTTP protocol, IP address, and port of your InfluxDB API. InfluxDB's default API port is 8086. |
|
||||||
| **Min time interval** | _(Optional)_ Refer to [Min time interval]({{< relref "#configure-min-time-interval" >}}). |
|
| **Min time interval** | _(Optional)_ Refer to [Min time interval]({{< relref "#configure-min-time-interval" >}}). |
|
||||||
| **Max series** | _(Optional)_ Limits the number of series and tables that Grafana processes. Lower this number to prevent abuse, and increase it if you have many small time series and not all are shown. Defaults to 1,000. |
|
| **Max series** | _(Optional)_ Limits the number of series and tables that Grafana processes. Lower this number to prevent abuse, and increase it if you have many small time series and not all are shown. Defaults to 1,000. |
|
||||||
|
|
||||||
You can also configure settings specific to the InfluxDB data source. These options are described in the sections below.
|
You can also configure settings specific to the InfluxDB data source. These options are described in the sections below.
|
||||||
|
|
||||||
|
|||||||
@@ -54,45 +54,10 @@ Code mode's autocompletion feature works automatically while typing.
|
|||||||
The query editor can autocomplete static functions, aggregations, and keywords, and also dynamic items like labels.
|
The query editor can autocomplete static functions, aggregations, and keywords, and also dynamic items like labels.
|
||||||
The autocompletion dropdown includes documentation for the suggested items where available.
|
The autocompletion dropdown includes documentation for the suggested items where available.
|
||||||
|
|
||||||
### Label browser
|
|
||||||
|
|
||||||
You can use the Loki label browser to navigate through your labels and values, and build queries.
|
|
||||||
|
|
||||||
**To navigate Loki and build a query:**
|
|
||||||
|
|
||||||
1. Choose labels to locate.
|
|
||||||
1. Search for the values of your selected labels.
|
|
||||||
|
|
||||||
The search field supports fuzzy search, and the label browser also supports faceting to list only possible label combinations.
|
|
||||||
|
|
||||||
1. Choose a query type between [**logs query**]({{< relref "#create-a-log-query" >}}) and [**rate metrics query**]({{< relref "#create-a-metric-query" >}}).
|
|
||||||
You can also validate the selector.
|
|
||||||
|
|
||||||
{{< figure src="/static/img/docs/v75/loki_label_browser.png" class="docs-image--no-shadow" max-width="800px" caption="The Loki label browser" >}}
|
|
||||||
|
|
||||||
### Configure query settings
|
|
||||||
|
|
||||||
| Name | Description |
|
|
||||||
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
||||||
| **Type** | Selects the query type to run. The `instant` type queries against a single point in time. We use the "To" time from the time range. The `range` type queries over the selected range of time. |
|
|
||||||
| **Line limit** | Defines the upper limit for the number of log lines returned by a query. The default is Loki's configured maximum lines limit. |
|
|
||||||
| **Legend** | _(Available only in a dashboard)_ Controls the time series name, using a name or pattern. For example, `{{hostname}}` is replaced with the label value for the label `hostname`. |
|
|
||||||
| **Resolution** | 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. |
|
|
||||||
|
|
||||||
## Builder mode
|
## Builder mode
|
||||||
|
|
||||||
Use Builder mode to visually construct queries, without needing to manually enter LogQL.
|
Use Builder mode to visually construct queries, without needing to manually enter LogQL.
|
||||||
|
|
||||||
### Review toolbar features
|
|
||||||
|
|
||||||
In addition to the **Run query** button and mode switcher, Builder mode provides additional elements:
|
|
||||||
|
|
||||||
| Name | Description |
|
|
||||||
| ------------------------- | ----------------------------------------------------------------------------------------- |
|
|
||||||
| **Kick start your query** | A list of useful operation patterns you can use to add multiple operations to your query. |
|
|
||||||
| **Label browser** | Used to navigate through your labels and values, and also build queries. |
|
|
||||||
| **Explain query** | Displays a step-by-step explanation of all query components and operations. |
|
|
||||||
|
|
||||||
### Use the Labels selector
|
### Use the Labels selector
|
||||||
|
|
||||||
Select labels and their values from the dropdown list.
|
Select labels and their values from the dropdown list.
|
||||||
@@ -108,11 +73,11 @@ The query editor groups operations into related sections, and you can type while
|
|||||||
The query editor displays a query's operations as boxes in the operations section.
|
The query editor displays a query's operations as boxes in the operations section.
|
||||||
Each operation's header displays its name, and additional action buttons appear when you hover your cursor over the header:
|
Each operation's header displays its name, and additional action buttons appear when you hover your cursor over the header:
|
||||||
|
|
||||||
| Button | Action |
|
| Button | Action |
|
||||||
| ------ | ----------------------------------------------------------------- |
|
| ----------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- |
|
||||||
| `v` | Replaces the operation with different operation of the same type. |
|
| {{< figure src="/static/img/docs/v95/loki_operation_replace.png" class="docs-image--no-shadow" max-width="30px" >}} | Replaces the operation with different operation of the same type. |
|
||||||
| `info` | Opens the operation's description tooltip. |
|
| {{< figure src="/static/img/docs/v95/loki_operation_description.png" class="docs-image--no-shadow" max-width="30px" >}} | Opens the operation's description tooltip. |
|
||||||
| `x` | Removes the operation. |
|
| {{< figure src="/static/img/docs/v95/loki_operation_remove.png" class="docs-image--no-shadow" max-width="30px" >}} | Removes the operation. |
|
||||||
|
|
||||||
Some operations have additional parameters under the operation header.
|
Some operations have additional parameters under the operation header.
|
||||||
For details about each operation, use the `info` button to view the operation's description, or refer to the [Loki documentation](/docs/loki/latest/operations/).
|
For details about each operation, use the `info` button to view the operation's description, or refer to the [Loki documentation](/docs/loki/latest/operations/).
|
||||||
@@ -125,10 +90,6 @@ To re-order operations manually, drag the operation box by its name and drop it
|
|||||||
|
|
||||||
In same cases the query editor can detect which operations would be most appropriate for a selected log stream. In such cases it will show a hint next to the `+ Operations` button. Click on the hint to add the operations to your query.
|
In same cases the query editor can detect which operations would be most appropriate for a selected log stream. In such cases it will show a hint next to the `+ Operations` button. Click on the hint to add the operations to your query.
|
||||||
|
|
||||||
### Explain query
|
|
||||||
|
|
||||||
This section is only shown if the `Explain query` switch from the query editor top toolbar is set to `on`. It shows a step by step explanation of all query parts and the operations.
|
|
||||||
|
|
||||||
## Create a log query
|
## Create a log query
|
||||||
|
|
||||||
Loki log queries return the contents of the log lines.
|
Loki log queries return the contents of the log lines.
|
||||||
@@ -205,6 +166,45 @@ You can use LogQL to wrap a log query with functions that create metrics from yo
|
|||||||
|
|
||||||
For more information about metric queries, refer to the [Loki metric queries documentation](/docs/loki/latest/logql/metric_queries/).
|
For more information about metric queries, refer to the [Loki metric queries documentation](/docs/loki/latest/logql/metric_queries/).
|
||||||
|
|
||||||
|
## Review toolbar features
|
||||||
|
|
||||||
|
In addition to the **Run query** button and mode switcher, Builder mode provides additional elements:
|
||||||
|
|
||||||
|
| Name | Description |
|
||||||
|
| ------------------------- | ----------------------------------------------------------------------------------------- |
|
||||||
|
| **Kick start your query** | A list of useful operation patterns you can use to add multiple operations to your query. |
|
||||||
|
| **Label browser** | Used to navigate through your labels and values, and also build queries. |
|
||||||
|
| **Explain query** | Displays a step-by-step explanation of all query components and operations. |
|
||||||
|
|
||||||
|
### Label browser
|
||||||
|
|
||||||
|
You can use the Loki label browser to navigate through your labels and values, and build queries.
|
||||||
|
|
||||||
|
**To navigate Loki and build a query:**
|
||||||
|
|
||||||
|
1. Choose labels to locate.
|
||||||
|
1. Search for the values of your selected labels.
|
||||||
|
|
||||||
|
The search field supports fuzzy search, and the label browser also supports faceting to list only possible label combinations.
|
||||||
|
|
||||||
|
1. Choose a query type between [**logs query**]({{< relref "#create-a-log-query" >}}) and [**rate metrics query**]({{< relref "#create-a-metric-query" >}}).
|
||||||
|
You can also validate the selector.
|
||||||
|
|
||||||
|
{{< figure src="/static/img/docs/v75/loki_label_browser.png" class="docs-image--no-shadow" max-width="800px" caption="The Loki label browser" >}}
|
||||||
|
|
||||||
|
### Explain query
|
||||||
|
|
||||||
|
This section is only shown if the `Explain query` switch from the query editor top toolbar is set to `on`. It shows a step by step explanation of all query parts and the operations.
|
||||||
|
|
||||||
|
## Configure query settings
|
||||||
|
|
||||||
|
| Name | Description |
|
||||||
|
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||||
|
| **Type** | Selects the query type to run. The `instant` type queries against a single point in time. We use the "To" time from the time range. The `range` type queries over the selected range of time. |
|
||||||
|
| **Line limit** | Defines the upper limit for the number of log lines returned by a query. The default is Loki's configured maximum lines limit. |
|
||||||
|
| **Legend** | _(Available only in a dashboard)_ Controls the time series name, using a name or pattern. For example, `{{hostname}}` is replaced with the label value for the label `hostname`. |
|
||||||
|
| **Resolution** | 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. |
|
||||||
|
|
||||||
## Apply annotations
|
## Apply annotations
|
||||||
|
|
||||||
[Annotations]({{< relref "../../../dashboards/build-dashboards/annotate-visualizations" >}}) overlay rich event information on top of graphs.
|
[Annotations]({{< relref "../../../dashboards/build-dashboards/annotate-visualizations" >}}) overlay rich event information on top of graphs.
|
||||||
|
|||||||
@@ -18,16 +18,25 @@ Grafana ships with built-in support for Parca, a continuous profiling OSS databa
|
|||||||
|
|
||||||
## Configure the Parca data source
|
## Configure the Parca data source
|
||||||
|
|
||||||
To access Parca settings, click the **Configuration** (gear) icon, then click **Data Sources** > **Parca**.
|
To configure basic settings for the data source, complete the following steps:
|
||||||
|
|
||||||
| Name | Description |
|
1. Click **Connections** in the left-side menu.
|
||||||
| ------------ | ------------------------------------------------------------------ |
|
1. Under Your connections, click **Data sources**.
|
||||||
| `Name` | A name to specify the data source in panels, queries, and Explore. |
|
1. Enter `Parca` in the search bar.
|
||||||
| `Default` | The default data source will be pre-selected for new panels. |
|
1. Click **Parca**.
|
||||||
| `URL` | The URL of the Parca instance, e.g., `http://localhost:4100` |
|
|
||||||
| `Basic Auth` | Enable basic authentication to the Parca data source. |
|
The **Settings** tab of the data source is displayed.
|
||||||
| `User` | User name for basic authentication. |
|
|
||||||
| `Password` | Password for basic authentication. |
|
1. Set the data source's basic configuration options:
|
||||||
|
|
||||||
|
| Name | Description |
|
||||||
|
| ------------ | ------------------------------------------------------------------ |
|
||||||
|
| `Name` | A name to specify the data source in panels, queries, and Explore. |
|
||||||
|
| `Default` | The default data source will be pre-selected for new panels. |
|
||||||
|
| `URL` | The URL of the Parca instance, e.g., `http://localhost:4100` |
|
||||||
|
| `Basic Auth` | Enable basic authentication to the Parca data source. |
|
||||||
|
| `User` | User name for basic authentication. |
|
||||||
|
| `Password` | Password for basic authentication. |
|
||||||
|
|
||||||
## Querying
|
## Querying
|
||||||
|
|
||||||
|
|||||||
@@ -18,17 +18,26 @@ Grafana ships with built-in support for Phlare, a horizontally scalable, highly-
|
|||||||
|
|
||||||
## Configure the Phlare data source
|
## Configure the Phlare data source
|
||||||
|
|
||||||
To access Phlare settings, click the **Configuration** (gear) icon, then click **Data Sources** > **Phlare**.
|
To configure basic settings for the data source, complete the following steps:
|
||||||
|
|
||||||
| Name | Description |
|
1. Click **Connections** in the left-side menu.
|
||||||
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
1. Under Your connections, click **Data sources**.
|
||||||
| `Name` | A name to specify the data source in panels, queries, and Explore. |
|
1. Enter `Phlare` in the search bar.
|
||||||
| `Default` | The default data source will be pre-selected for new panels. |
|
1. Click **Phlare**.
|
||||||
| `URL` | The URL of the Phlare instance, e.g., `http://localhost:4100` |
|
|
||||||
| `Basic Auth` | Enable basic authentication to the Phlare data source. |
|
The **Settings** tab of the data source is displayed.
|
||||||
| `User` | User name for basic authentication. |
|
|
||||||
| `Password` | Password for basic authentication. |
|
1. Set the data source's basic configuration options:
|
||||||
| `Minimal step` | Similar to Prometheus, Phlare scrapes profiles at certain intervals. To prevent querying at smaller interval use Minimal step same or higher than your Phlare scrape interval. |
|
|
||||||
|
| Name | Description |
|
||||||
|
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||||
|
| `Name` | A name to specify the data source in panels, queries, and Explore. |
|
||||||
|
| `Default` | The default data source will be pre-selected for new panels. |
|
||||||
|
| `URL` | The URL of the Phlare instance, e.g., `http://localhost:4100` |
|
||||||
|
| `Basic Auth` | Enable basic authentication to the Phlare data source. |
|
||||||
|
| `User` | User name for basic authentication. |
|
||||||
|
| `Password` | Password for basic authentication. |
|
||||||
|
| `Minimal step` | Similar to Prometheus, Phlare scrapes profiles at certain intervals. To prevent querying at smaller interval use Minimal step same or higher than your Phlare scrape interval. |
|
||||||
|
|
||||||
## Querying
|
## Querying
|
||||||
|
|
||||||
|
|||||||
@@ -45,40 +45,38 @@ To configure basic settings for the data source, complete the following steps:
|
|||||||
|
|
||||||
1. Set the data source's basic configuration options:
|
1. Set the data source's basic configuration options:
|
||||||
|
|
||||||
| Name | Description |
|
| Name | Description |
|
||||||
|
|
||||||
| ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| `Name` | The data source name. This is how you refer to the data source in panels and queries. |
|
| `Name` | The data source name. This is how you refer to the data source in panels and queries. |
|
||||||
| `Default` | Default data source that is pre-selected for new panels. |
|
| `Default` | Default data source that is pre-selected for new panels. |
|
||||||
| `URL` | The URL of your Prometheus server, for example, `http://prometheus.example.org:9090`. |
|
| `URL` | The URL of your Prometheus server, for example, `http://prometheus.example.org:9090`. |
|
||||||
| `Access` | Only Server access mode is functional. If Server mode is already selected this option is hidden. Otherwise change to Server mode to prevent errors. |
|
| `Access` | Only Server access mode is functional. If Server mode is already selected this option is hidden. Otherwise change to Server mode to prevent errors. |
|
||||||
| `Basic Auth` | Enable basic authentication to the Prometheus data source. |
|
| `Basic Auth` | Enable basic authentication to the Prometheus data source. |
|
||||||
| `User` | User name for basic authentication. |
|
| `User` | User name for basic authentication. |
|
||||||
| `Password` | Password for basic authentication. |
|
| `Password` | Password for basic authentication. |
|
||||||
| `Manage alerts via Alerting UI` | Toggle whether to enable Alertmanager integration for this data source. |
|
| `Manage alerts via Alerting UI` | Toggle whether to enable Alertmanager integration for this data source. |
|
||||||
| `Scrape interval` | Set this to the typical scrape and evaluation interval configured in Prometheus. Defaults to 15s. |
|
| `Scrape interval` | Set this to the typical scrape and evaluation interval configured in Prometheus. Defaults to 15s. |
|
||||||
| `HTTP method` | Use either POST or GET HTTP method to query your data source. POST is the recommended and pre-selected method as it allows bigger queries. Change this to GET if you have a Prometheus version older than 2.1 or if POST requests are restricted in your network. |
|
| `HTTP method` | Use either POST or GET HTTP method to query your data source. POST is the recommended and pre-selected method as it allows bigger queries. Change this to GET if you have a Prometheus version older than 2.1 or if POST requests are restricted in your network. |
|
||||||
| `Type` | The type of your Prometheus server; `Prometheus`, `Cortex`, `Thanos`, `Mimir`. When selected, the **Version** field attempts to populate automatically using the Prometheus [buildinfo](https://semver.org/) API. Some Prometheus types, such as Cortex, don't support this API and must be manually populated. |
|
| `Type` | The type of your Prometheus server; `Prometheus`, `Cortex`, `Thanos`, `Mimir`. When selected, the **Version** field attempts to populate automatically using the Prometheus [buildinfo](https://semver.org/) API. Some Prometheus types, such as Cortex, don't support this API and must be manually populated. |
|
||||||
| `Version` | The version of your Prometheus server, note that this field is not visible until the Prometheus type is selected. |
|
| `Version` | The version of your Prometheus server, note that this field is not visible until the Prometheus type is selected. |
|
||||||
| `Disable metrics lookup` | Checking this option will disable the metrics chooser and metric/label support in the query field's autocomplete. This helps if you have performance issues with bigger Prometheus instances. |
|
| `Disable metrics lookup` | Checking this option will disable the metrics chooser and metric/label support in the query field's autocomplete. This helps if you have performance issues with bigger Prometheus instances. |
|
||||||
| `Custom query parameters` | Add custom parameters to the Prometheus query URL. For example `timeout`, `partial_response`, `dedup`, or `max_source_resolution`. Multiple parameters should be concatenated together with an '&'. |
|
| `Custom query parameters` | Add custom parameters to the Prometheus query URL. For example `timeout`, `partial_response`, `dedup`, or `max_source_resolution`. Multiple parameters should be concatenated together with an '&'. |
|
||||||
| **Exemplars configuration** | |
|
| **Exemplars configuration** | |
|
||||||
| `Internal link` | Enable this option is you have an internal link. When you enable this option, you will see a data source selector. Select the backend tracing data store for your exemplar data. |
|
| `Internal link` | Enable this option is you have an internal link. When you enable this option, you will see a data source selector. Select the backend tracing data store for your exemplar data. |
|
||||||
| `Data source` | You will see this option only if you enable `Internal link` option. Select the backend tracing data store for your exemplar data. |
|
| `Data source` | You will see this option only if you enable `Internal link` option. Select the backend tracing data store for your exemplar data. |
|
||||||
| `URL` | You will see this option only if the `Internal link` option is disabled. Enter the full URL of the external link. You can interpolate the value from the field with `${__value.raw }` macro. |
|
| `URL` | You will see this option only if the `Internal link` option is disabled. Enter the full URL of the external link. You can interpolate the value from the field with `${__value.raw }` macro. |
|
||||||
| `URL Label` | (Optional) add a custom display label to override the value of the `Label name` field. |
|
| `URL Label` | (Optional) add a custom display label to override the value of the `Label name` field. |
|
||||||
| `Label name` | Add a name for the exemplar traceID property. |
|
| `Label name` | Add a name for the exemplar traceID property. |
|
||||||
|
|
||||||
**Exemplars configuration:**
|
**Exemplars configuration:**
|
||||||
|
|
||||||
| Name | Description |
|
| Name | Description |
|
||||||
|
|
||||||
| ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| **Internal link** | Enable this option if you have an internal link. When enabled, this reveals the data source selector. Select the backend tracing data store for your exemplar data. |
|
| **Internal link** | Enable this option if you have an internal link. When enabled, this reveals the data source selector. Select the backend tracing data store for your exemplar data. |
|
||||||
| **Data source** | _(Visible only if you enable `Internal link`)_ Selects the backend tracing data store for your exemplar data. |
|
| **Data source** | _(Visible only if you enable `Internal link`)_ Selects the backend tracing data store for your exemplar data. |
|
||||||
| **URL** | _(Visible only if you disable `Internal link`)_ Defines the external link's full URL. You can interpolate the value from the field by using the [`${__value.raw}` macro]({{< relref "../..//panels-visualizations/configure-data-links/#value-variables" >}}). |
|
| **URL** | _(Visible only if you disable `Internal link`)_ Defines the external link's full URL. You can interpolate the value from the field by using the [`${__value.raw}` macro]({{< relref "../..//panels-visualizations/configure-data-links/#value-variables" >}}). |
|
||||||
| **URL label** | _(Optional)_ Adds a custom display label to override the value of the `Label name` field. |
|
| **URL label** | _(Optional)_ Adds a custom display label to override the value of the `Label name` field. |
|
||||||
| **Label name** | Adds a name for the exemplar traceID property. |
|
| **Label name** | Adds a name for the exemplar traceID property. |
|
||||||
|
|
||||||
### Provision the data source
|
### Provision the data source
|
||||||
|
|
||||||
|
|||||||
@@ -38,15 +38,14 @@ To configure basic settings for the data source, complete the following steps:
|
|||||||
|
|
||||||
1. Set the data source's basic configuration options:
|
1. Set the data source's basic configuration options:
|
||||||
|
|
||||||
| Name | Description |
|
| Name | Description |
|
||||||
|
|
||||||
| -------------- | ------------------------------------------------------------------------ |
|
| -------------- | ------------------------------------------------------------------------ |
|
||||||
| **Name** | Sets the name you use to refer to the data source in panels and queries. |
|
| **Name** | Sets the name you use to refer to the data source in panels and queries. |
|
||||||
| **Default** | Sets the data source that's pre-selected for new panels. |
|
| **Default** | Sets the data source that's pre-selected for new panels. |
|
||||||
| **URL** | Sets the URL of the Tempo instance, such as `http://tempo`. |
|
| **URL** | Sets the URL of the Tempo instance, such as `http://tempo`. |
|
||||||
| **Basic Auth** | Enables basic authentication to the Tempo data source. |
|
| **Basic Auth** | Enables basic authentication to the Tempo data source. |
|
||||||
| **User** | Sets the user name for basic authentication. |
|
| **User** | Sets the user name for basic authentication. |
|
||||||
| **Password** | Sets the password for basic authentication. |
|
| **Password** | Sets the password for basic authentication. |
|
||||||
|
|
||||||
You can also configure settings specific to the Tempo data source. These options are described in the sections below.
|
You can also configure settings specific to the Tempo data source. These options are described in the sections below.
|
||||||
|
|
||||||
@@ -232,6 +231,10 @@ datasources:
|
|||||||
spanBar:
|
spanBar:
|
||||||
type: 'Tag'
|
type: 'Tag'
|
||||||
tag: 'http.path'
|
tag: 'http.path'
|
||||||
|
traceQuery:
|
||||||
|
timeShiftEnabled: true
|
||||||
|
spanStartTimeShift: 15m
|
||||||
|
spanEndTimeShift: 20m
|
||||||
```
|
```
|
||||||
|
|
||||||
## Query the data source
|
## Query the data source
|
||||||
|
|||||||
+3
-4
@@ -33,11 +33,10 @@ To configure basic settings for the data source, complete the following steps:
|
|||||||
|
|
||||||
The **Settings** tab of the data source is displayed. The data source doesn't provide any settings beyond the most basic options common to all data sources:
|
The **Settings** tab of the data source is displayed. The data source doesn't provide any settings beyond the most basic options common to all data sources:
|
||||||
|
|
||||||
| Name | Description |
|
| Name | Description |
|
||||||
|
|
||||||
| ----------- | ------------------------------------------------------------------------ |
|
| ----------- | ------------------------------------------------------------------------ |
|
||||||
| **Name** | Sets the name you use to refer to the data source in panels and queries. |
|
| **Name** | Sets the name you use to refer to the data source in panels and queries. |
|
||||||
| **Default** | Defines whether this data source is pre-selected for new panels. |
|
| **Default** | Defines whether this data source is pre-selected for new panels. |
|
||||||
|
|
||||||
## Create mock data
|
## Create mock data
|
||||||
|
|
||||||
|
|||||||
@@ -38,15 +38,14 @@ To configure basic settings for the data source, complete the following steps:
|
|||||||
|
|
||||||
1. Set the data source's basic configuration options:
|
1. Set the data source's basic configuration options:
|
||||||
|
|
||||||
| Name | Description |
|
| Name | Description |
|
||||||
|
|
||||||
| -------------- | ------------------------------------------------------------------------ |
|
| -------------- | ------------------------------------------------------------------------ |
|
||||||
| **Name** | Sets the name you use to refer to the data source in panels and queries. |
|
| **Name** | Sets the name you use to refer to the data source in panels and queries. |
|
||||||
| **Default** | Defines whether this data source is pre-selected for new panels. |
|
| **Default** | Defines whether this data source is pre-selected for new panels. |
|
||||||
| **URL** | Sets the URL of the Zipkin instance, such as `http://localhost:9411`. |
|
| **URL** | Sets the URL of the Zipkin instance, such as `http://localhost:9411`. |
|
||||||
| **Basic Auth** | Enables basic authentication for the Zipkin data source. |
|
| **Basic Auth** | Enables basic authentication for the Zipkin data source. |
|
||||||
| **User** | Defines the user name for basic authentication. |
|
| **User** | Defines the user name for basic authentication. |
|
||||||
| **Password** | Defines the password for basic authentication. |
|
| **Password** | Defines the password for basic authentication. |
|
||||||
|
|
||||||
### Trace to logs
|
### Trace to logs
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ weight: 5
|
|||||||
|
|
||||||
# Grafana OSS
|
# Grafana OSS
|
||||||
|
|
||||||
[Grafana open source software](https://grafana.com/oss/) enables you to query, visualize, alert on, and explore your metrics, logs, and traces wherever they are stored. Grafana OSS provides you with tools to turn your time-series database (TSDB) data into insightful graphs and visualizations.
|
[Grafana open source software](https://grafana.com/oss/) enables you to query, visualize, alert on, and explore your metrics, logs, and traces wherever they are stored. Grafana OSS provides you with tools to turn your time-series database (TSDB) data into insightful graphs and visualizations. The Grafana OSS plugin framework also enables you to connect other data sources like NoSQL/SQL databases, ticketing tools like Jira or ServiceNow, and CI/CD tooling like GitLab.
|
||||||
|
|
||||||
After you have [installed Grafana]({{< relref "../setup-grafana/installation/" >}}) and set up your first dashboard using instructions in [Getting started with Grafana]({{< relref "../getting-started/build-first-dashboard.md" >}}), you will have many options to choose from depending on your requirements. For example, if you want to view weather data and statistics about your smart home, then you can create a [playlist]({{< relref "../dashboards/create-manage-playlists/" >}}). If you are the administrator for an enterprise and are managing Grafana for multiple teams, then you can set up [provisioning]({{< relref "../administration/provisioning/" >}}) and [authentication]({{< relref "../setup-grafana/configure-security/configure-authentication/" >}}).
|
After you have [installed Grafana]({{< relref "../setup-grafana/installation/" >}}) and set up your first dashboard using instructions in [Getting started with Grafana]({{< relref "../getting-started/build-first-dashboard.md" >}}), you will have many options to choose from depending on your requirements. For example, if you want to view weather data and statistics about your smart home, then you can create a [playlist]({{< relref "../dashboards/create-manage-playlists/" >}}). If you are the administrator for an enterprise and are managing Grafana for multiple teams, then you can set up [provisioning]({{< relref "../administration/provisioning/" >}}) and [authentication]({{< relref "../setup-grafana/configure-security/configure-authentication/" >}}).
|
||||||
|
|
||||||
@@ -71,3 +71,5 @@ In addition to Grafana, Grafana Labs also provides the following open source pro
|
|||||||
**Grafana Tempo:** Grafana Tempo is an open source, easy-to-use and high-volume distributed tracing backend. For more information, refer to [Grafana Tempo documentation](https://grafana.com/docs/tempo/latest/?pg=oss-tempo&plcmt=hero-txt/).
|
**Grafana Tempo:** Grafana Tempo is an open source, easy-to-use and high-volume distributed tracing backend. For more information, refer to [Grafana Tempo documentation](https://grafana.com/docs/tempo/latest/?pg=oss-tempo&plcmt=hero-txt/).
|
||||||
|
|
||||||
**Grafana Mimir:** Grafana Mimir is an open source software project that provides a scalable long-term storage for Prometheus. For more information about Grafana Mimir, refer to [Grafana Mimir documentation](https://grafana.com/docs/mimir/latest/).
|
**Grafana Mimir:** Grafana Mimir is an open source software project that provides a scalable long-term storage for Prometheus. For more information about Grafana Mimir, refer to [Grafana Mimir documentation](https://grafana.com/docs/mimir/latest/).
|
||||||
|
|
||||||
|
**Grafana Phlare:** Grafana Phlare is an open-source software project for aggregating continuous profiling data. Continuous profiling is an observability signal that enables you to understand your workload's resource (CPU, memory, etc.) usage to the exact line number. For more information about using Grafana Phlare, refer to [Grafana Phlare documentation](https://grafana.com/docs/phlare/latest/).
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ On each dashboard load, this panel queries the dashboard list, always providing
|
|||||||
|
|
||||||
Use these options to refine your visualization.
|
Use these options to refine your visualization.
|
||||||
|
|
||||||
|
- **Include current time range -** Select this option to propagate the time range of the current dashboard to the dashboard links. When the user clicks a link, the linked dashboard opens with the indicated time range already set.
|
||||||
|
- **Include current template variable values -** Select this option to include template variables currently used as query parameters in a link. When the user clicks the link, any matching templates in the linked dashboard are set to the values from the link. Learn more about [Dashboard URL variables]({{< relref "../../../dashboards/build-dashboards/create-dashboard-url-variables/" >}}).
|
||||||
- **Starred -** Display starred dashboards in alphabetical order.
|
- **Starred -** Display starred dashboards in alphabetical order.
|
||||||
- **Recently viewed -** Display recently viewed dashboards in alphabetical order.
|
- **Recently viewed -** Display recently viewed dashboards in alphabetical order.
|
||||||
- **Search -** Display dashboards by search query or tags. You must enter at least one value in **Query** or **Tags**. For the **Query** and **Tags** fields. Variable interpolation is supported, for example,`$my_var` or `${my_var}`.
|
- **Search -** Display dashboards by search query or tags. You must enter at least one value in **Query** or **Tags**. For the **Query** and **Tags** fields. Variable interpolation is supported, for example,`$my_var` or `${my_var}`.
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ Some stable features are enabled by default. You can disable a stable feature by
|
|||||||
| `validateDashboardsOnSave` | Validate dashboard JSON POSTed to api/dashboards/db |
|
| `validateDashboardsOnSave` | Validate dashboard JSON POSTed to api/dashboards/db |
|
||||||
| `autoMigrateOldPanels` | Migrate old angular panels to supported versions (graph, table-old, worldmap, etc) |
|
| `autoMigrateOldPanels` | Migrate old angular panels to supported versions (graph, table-old, worldmap, etc) |
|
||||||
| `disableAngular` | Dynamic flag to disable angular at runtime. The preferred method is to set `angular_support_enabled` to `false` in the [security] settings, which allows you to change the state at runtime. |
|
| `disableAngular` | Dynamic flag to disable angular at runtime. The preferred method is to set `angular_support_enabled` to `false` in the [security] settings, which allows you to change the state at runtime. |
|
||||||
|
| `grpcServer` | Run the GRPC server |
|
||||||
| `accessControlOnCall` | Access control primitives for OnCall |
|
| `accessControlOnCall` | Access control primitives for OnCall |
|
||||||
| `alertingNoNormalState` | Stop maintaining state of alerts that are not firing |
|
| `alertingNoNormalState` | Stop maintaining state of alerts that are not firing |
|
||||||
| `disableElasticsearchBackendExploreQuery` | Disable executing of Elasticsearch Explore queries trough backend |
|
| `disableElasticsearchBackendExploreQuery` | Disable executing of Elasticsearch Explore queries trough backend |
|
||||||
@@ -59,7 +60,6 @@ Alpha features might be changed or removed without prior notice.
|
|||||||
|
|
||||||
| Feature toggle name | Description |
|
| Feature toggle name | Description |
|
||||||
| ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| `alertingBigTransactions` | Use big transactions for alerting database writes |
|
|
||||||
| `dashboardPreviews` | Create and show thumbnails for dashboard search results |
|
| `dashboardPreviews` | Create and show thumbnails for dashboard search results |
|
||||||
| `live-service-web-worker` | This will use a webworker thread to processes events rather than the main thread |
|
| `live-service-web-worker` | This will use a webworker thread to processes events rather than the main thread |
|
||||||
| `queryOverLive` | Use Grafana Live WebSocket to execute backend queries |
|
| `queryOverLive` | Use Grafana Live WebSocket to execute backend queries |
|
||||||
@@ -83,6 +83,7 @@ Alpha features might be changed or removed without prior notice.
|
|||||||
| `showDashboardValidationWarnings` | Show warnings when dashboards do not validate against the schema |
|
| `showDashboardValidationWarnings` | Show warnings when dashboards do not validate against the schema |
|
||||||
| `mysqlAnsiQuotes` | Use double quotes to escape keyword in a MySQL query |
|
| `mysqlAnsiQuotes` | Use double quotes to escape keyword in a MySQL query |
|
||||||
| `elasticsearchBackendMigration` | Use Elasticsearch as backend data source |
|
| `elasticsearchBackendMigration` | Use Elasticsearch as backend data source |
|
||||||
|
| `showTraceId` | Show trace ids for requests |
|
||||||
| `datasourceOnboarding` | Enable data source onboarding page |
|
| `datasourceOnboarding` | Enable data source onboarding page |
|
||||||
| `secureSocksDatasourceProxy` | Enable secure socks tunneling for supported core datasources |
|
| `secureSocksDatasourceProxy` | Enable secure socks tunneling for supported core datasources |
|
||||||
| `authnService` | Use new auth service to perform authentication |
|
| `authnService` | Use new auth service to perform authentication |
|
||||||
@@ -105,6 +106,7 @@ Alpha features might be changed or removed without prior notice.
|
|||||||
| `alertStateHistoryLokiPrimary` | Enable a remote Loki instance as the primary source for state history reads. |
|
| `alertStateHistoryLokiPrimary` | Enable a remote Loki instance as the primary source for state history reads. |
|
||||||
| `alertStateHistoryLokiOnly` | Disable Grafana alerts from emitting annotations when a remote Loki instance is available. |
|
| `alertStateHistoryLokiOnly` | Disable Grafana alerts from emitting annotations when a remote Loki instance is available. |
|
||||||
| `unifiedRequestLog` | Writes error logs to the request logger |
|
| `unifiedRequestLog` | Writes error logs to the request logger |
|
||||||
|
| `pyroscopeFlameGraph` | Changes flame graph to pyroscope one |
|
||||||
|
|
||||||
## Development feature toggles
|
## Development feature toggles
|
||||||
|
|
||||||
@@ -113,6 +115,5 @@ The following toggles require explicitly setting Grafana's [app mode]({{< relref
|
|||||||
| Feature toggle name | Description |
|
| Feature toggle name | Description |
|
||||||
| ------------------- | --------------------------------------------------- |
|
| ------------------- | --------------------------------------------------- |
|
||||||
| `k8s` | Explore native k8s integrations |
|
| `k8s` | Explore native k8s integrations |
|
||||||
| `grpcServer` | Run GRPC server |
|
|
||||||
| `entityStore` | SQL-based entity store (requires storage flag also) |
|
| `entityStore` | SQL-based entity store (requires storage flag also) |
|
||||||
| `nestedFolders` | Enable folder nesting |
|
| `nestedFolders` | Enable folder nesting |
|
||||||
|
|||||||
+1
@@ -19,6 +19,7 @@ weight: 900
|
|||||||
The enhanced LDAP integration adds additional functionality on top of the [LDAP integration]({{< relref "ldap/" >}}) available in the open source edition of Grafana.
|
The enhanced LDAP integration adds additional functionality on top of the [LDAP integration]({{< relref "ldap/" >}}) available in the open source edition of Grafana.
|
||||||
|
|
||||||
> **Note:** Available in [Grafana Enterprise]({{< relref "../../../../introduction/grafana-enterprise/" >}}) and [Grafana Cloud Advanced](/docs/grafana-cloud).
|
> **Note:** Available in [Grafana Enterprise]({{< relref "../../../../introduction/grafana-enterprise/" >}}) and [Grafana Cloud Advanced](/docs/grafana-cloud).
|
||||||
|
> If you are a Grafana Cloud customer, please [open a support ticket in the Cloud Portal](/profile/org#support) to request this feature.
|
||||||
|
|
||||||
> To control user access with role-based permissions, refer to [role-based access control]({{< relref "../../../../administration/roles-and-permissions/access-control/" >}}).
|
> To control user access with role-based permissions, refer to [role-based access control]({{< relref "../../../../administration/roles-and-permissions/access-control/" >}}).
|
||||||
|
|
||||||
|
|||||||
@@ -296,6 +296,10 @@ We've added support for JWT authentication.
|
|||||||
|
|
||||||
We've added support for custom session parameters.
|
We've added support for custom session parameters.
|
||||||
|
|
||||||
|
## Postgres, MySQL, and MSSQL data sources
|
||||||
|
|
||||||
|
The `database` property is now under the `jsonData` key in the data source configuration. This change is backward compatible, and existing configurations will continue to work.
|
||||||
|
|
||||||
## Before you upgrade
|
## Before you upgrade
|
||||||
|
|
||||||
There are no known breaking changes associated with this version of Grafana.
|
There are no known breaking changes associated with this version of Grafana.
|
||||||
|
|||||||
@@ -8,7 +8,11 @@ e2e.scenario({
|
|||||||
skipScenario: false,
|
skipScenario: false,
|
||||||
scenario: () => {
|
scenario: () => {
|
||||||
// Opening a dashboard without template variables
|
// Opening a dashboard without template variables
|
||||||
e2e().intercept('POST', '/api/ds/query').as('query');
|
e2e()
|
||||||
|
.intercept({
|
||||||
|
pathname: '/api/ds/query',
|
||||||
|
})
|
||||||
|
.as('query');
|
||||||
e2e.flows.openDashboard({ uid: 'ZqZnVvFZz' });
|
e2e.flows.openDashboard({ uid: 'ZqZnVvFZz' });
|
||||||
e2e().wait('@query');
|
e2e().wait('@query');
|
||||||
|
|
||||||
@@ -65,7 +69,12 @@ e2e.scenario({
|
|||||||
skipScenario: false,
|
skipScenario: false,
|
||||||
scenario: () => {
|
scenario: () => {
|
||||||
// Opening a dashboard without template variables
|
// Opening a dashboard without template variables
|
||||||
e2e().intercept('POST', '/api/ds/query').as('query');
|
e2e()
|
||||||
|
.intercept({
|
||||||
|
method: 'POST',
|
||||||
|
pathname: '/api/ds/query',
|
||||||
|
})
|
||||||
|
.as('query');
|
||||||
e2e.flows.openDashboard({ uid: 'ZqZnVvFZz' });
|
e2e.flows.openDashboard({ uid: 'ZqZnVvFZz' });
|
||||||
e2e().wait('@query');
|
e2e().wait('@query');
|
||||||
|
|
||||||
@@ -109,7 +118,12 @@ e2e.scenario({
|
|||||||
skipScenario: false,
|
skipScenario: false,
|
||||||
scenario: () => {
|
scenario: () => {
|
||||||
// Opening a dashboard without template variables
|
// Opening a dashboard without template variables
|
||||||
e2e().intercept('/api/ds/query').as('query');
|
e2e()
|
||||||
|
.intercept({
|
||||||
|
method: 'POST',
|
||||||
|
pathname: '/api/ds/query',
|
||||||
|
})
|
||||||
|
.as('query');
|
||||||
e2e.flows.openDashboard({ uid: 'ZqZnVvFZz' });
|
e2e.flows.openDashboard({ uid: 'ZqZnVvFZz' });
|
||||||
e2e().wait('@query');
|
e2e().wait('@query');
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ describe('Variables - Load options from Url', () => {
|
|||||||
e2e()
|
e2e()
|
||||||
.intercept({
|
.intercept({
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
url: '/api/ds/query',
|
pathname: '/api/ds/query*',
|
||||||
})
|
})
|
||||||
.as('query');
|
.as('query');
|
||||||
|
|
||||||
@@ -61,7 +61,7 @@ describe('Variables - Load options from Url', () => {
|
|||||||
e2e()
|
e2e()
|
||||||
.intercept({
|
.intercept({
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
url: '/api/ds/query',
|
pathname: '/api/ds/query',
|
||||||
})
|
})
|
||||||
.as('query');
|
.as('query');
|
||||||
|
|
||||||
@@ -124,7 +124,7 @@ describe('Variables - Load options from Url', () => {
|
|||||||
e2e()
|
e2e()
|
||||||
.intercept({
|
.intercept({
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
url: '/api/ds/query',
|
pathname: '/api/ds/query',
|
||||||
})
|
})
|
||||||
.as('query');
|
.as('query');
|
||||||
|
|
||||||
|
|||||||
@@ -61,7 +61,11 @@ describe('Variables - Set options from ui', () => {
|
|||||||
it('adding a value that is not part of dependents options should add the new values dependant options', () => {
|
it('adding a value that is not part of dependents options should add the new values dependant options', () => {
|
||||||
e2e.flows.login('admin', 'admin');
|
e2e.flows.login('admin', 'admin');
|
||||||
e2e.flows.openDashboard({ uid: `${PAGE_UNDER_TEST}?orgId=1&var-datacenter=A&var-server=AA&var-pod=AAA` });
|
e2e.flows.openDashboard({ uid: `${PAGE_UNDER_TEST}?orgId=1&var-datacenter=A&var-server=AA&var-pod=AAA` });
|
||||||
e2e().intercept('/api/ds/query').as('query');
|
e2e()
|
||||||
|
.intercept({
|
||||||
|
pathname: '/api/ds/query',
|
||||||
|
})
|
||||||
|
.as('query');
|
||||||
|
|
||||||
e2e().wait('@query');
|
e2e().wait('@query');
|
||||||
|
|
||||||
@@ -119,7 +123,7 @@ describe('Variables - Set options from ui', () => {
|
|||||||
e2e.flows.openDashboard({
|
e2e.flows.openDashboard({
|
||||||
uid: `${PAGE_UNDER_TEST}?orgId=1&var-datacenter=A&var-datacenter=B&var-server=AA&var-server=BB&var-pod=AAA&var-pod=BBB`,
|
uid: `${PAGE_UNDER_TEST}?orgId=1&var-datacenter=A&var-datacenter=B&var-server=AA&var-server=BB&var-pod=AAA&var-pod=BBB`,
|
||||||
});
|
});
|
||||||
e2e().intercept('/api/ds/query').as('query');
|
e2e().intercept({ pathname: '/api/ds/query' }).as('query');
|
||||||
|
|
||||||
e2e().wait('@query');
|
e2e().wait('@query');
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,11 @@ e2e.scenario({
|
|||||||
addScenarioDashBoard: false,
|
addScenarioDashBoard: false,
|
||||||
skipScenario: false,
|
skipScenario: false,
|
||||||
scenario: () => {
|
scenario: () => {
|
||||||
e2e().intercept('/api/ds/query').as('query');
|
e2e()
|
||||||
|
.intercept({
|
||||||
|
pathname: '/api/ds/query',
|
||||||
|
})
|
||||||
|
.as('query');
|
||||||
e2e.flows.openDashboard({ uid: 'TkZXxlNG3' });
|
e2e.flows.openDashboard({ uid: 'TkZXxlNG3' });
|
||||||
e2e().wait('@query');
|
e2e().wait('@query');
|
||||||
|
|
||||||
@@ -79,6 +83,7 @@ e2e.scenario({
|
|||||||
e2e.components.PluginVisualization.current().should((e) => expect(e).to.contain('Time series'));
|
e2e.components.PluginVisualization.current().should((e) => expect(e).to.contain('Time series'));
|
||||||
|
|
||||||
// Check that table view works
|
// Check that table view works
|
||||||
|
e2e.components.Panels.Panel.loadingBar().should('not.exist');
|
||||||
e2e.components.PanelEditor.toggleTableView().click({ force: true });
|
e2e.components.PanelEditor.toggleTableView().click({ force: true });
|
||||||
e2e.components.Panels.Visualization.Table.header()
|
e2e.components.Panels.Visualization.Table.header()
|
||||||
.should('be.visible')
|
.should('be.visible')
|
||||||
|
|||||||
+23
-17
@@ -11,24 +11,30 @@ describe('MySQL datasource', () => {
|
|||||||
it('code editor autocomplete should handle table name escaping/quoting', () => {
|
it('code editor autocomplete should handle table name escaping/quoting', () => {
|
||||||
e2e.flows.login('admin', 'admin');
|
e2e.flows.login('admin', 'admin');
|
||||||
|
|
||||||
e2e().intercept('POST', '**/api/ds/query', (req) => {
|
e2e().intercept(
|
||||||
if (req.body.queries[0].refId === 'datasets') {
|
'POST',
|
||||||
req.alias = 'datasets';
|
{
|
||||||
req.reply({
|
pathname: '/api/ds/query',
|
||||||
body: datasetResponse,
|
},
|
||||||
});
|
(req) => {
|
||||||
} else if (req.body.queries[0].refId === 'tables') {
|
if (req.body.queries[0].refId === 'datasets') {
|
||||||
req.alias = 'tables';
|
req.alias = 'datasets';
|
||||||
req.reply({
|
req.reply({
|
||||||
body: tablesResponse,
|
body: datasetResponse,
|
||||||
});
|
});
|
||||||
} else if (req.body.queries[0].refId === 'fields') {
|
} else if (req.body.queries[0].refId === 'tables') {
|
||||||
req.alias = 'fields';
|
req.alias = 'tables';
|
||||||
req.reply({
|
req.reply({
|
||||||
body: fieldsResponse,
|
body: tablesResponse,
|
||||||
});
|
});
|
||||||
|
} else if (req.body.queries[0].refId === 'fields') {
|
||||||
|
req.alias = 'fields';
|
||||||
|
req.reply({
|
||||||
|
body: fieldsResponse,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
);
|
||||||
|
|
||||||
e2e.pages.Explore.visit();
|
e2e.pages.Explore.visit();
|
||||||
|
|
||||||
|
|||||||
@@ -32,16 +32,21 @@ describe('Exemplars', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to navigate to configured data source', () => {
|
it('should be able to navigate to configured data source', () => {
|
||||||
let intercept = 'prometheus';
|
e2e().intercept(
|
||||||
e2e().intercept('/api/ds/query', (req) => {
|
{
|
||||||
if (intercept === 'prometheus') {
|
pathname: '/api/ds/query',
|
||||||
// For second intercept, we want to send tempo response
|
},
|
||||||
intercept = 'tempo';
|
(req) => {
|
||||||
req.reply({ fixture: 'exemplars-query-response.json' });
|
const datasourceType = req.body.queries[0].datasource.type;
|
||||||
} else {
|
if (datasourceType === 'prometheus') {
|
||||||
req.reply({ fixture: 'tempo-response.json' });
|
req.reply({ fixture: 'exemplars-query-response.json' });
|
||||||
|
} else if (datasourceType === 'tempo') {
|
||||||
|
req.reply({ fixture: 'tempo-response.json' });
|
||||||
|
} else {
|
||||||
|
req.reply({});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
);
|
||||||
|
|
||||||
e2e.pages.Explore.visit();
|
e2e.pages.Explore.visit();
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,15 @@ e2e.scenario({
|
|||||||
e2e.pages.Explore.General.container().should('have.length', 1);
|
e2e.pages.Explore.General.container().should('have.length', 1);
|
||||||
e2e.components.RefreshPicker.runButtonV2().should('have.length', 1);
|
e2e.components.RefreshPicker.runButtonV2().should('have.length', 1);
|
||||||
|
|
||||||
|
// delete query history queries that would be unrelated
|
||||||
|
e2e.components.QueryTab.queryHistoryButton().should('be.visible').click();
|
||||||
|
cy.get('button[title="Delete query"]').each((button) => {
|
||||||
|
button.trigger('click');
|
||||||
|
});
|
||||||
|
e2e.components.QueryTab.queryHistoryButton().should('be.visible').click();
|
||||||
|
|
||||||
e2e.components.DataSource.TestData.QueryTab.scenarioSelectContainer()
|
e2e.components.DataSource.TestData.QueryTab.scenarioSelectContainer()
|
||||||
|
.scrollIntoView()
|
||||||
.should('be.visible')
|
.should('be.visible')
|
||||||
.within(() => {
|
.within(() => {
|
||||||
e2e().get('input[id*="test-data-scenario-select-"]').should('be.visible').click();
|
e2e().get('input[id*="test-data-scenario-select-"]').should('be.visible').click();
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ require (
|
|||||||
github.com/grafana/cuetsy v0.1.6
|
github.com/grafana/cuetsy v0.1.6
|
||||||
github.com/grafana/grafana-aws-sdk v0.12.0
|
github.com/grafana/grafana-aws-sdk v0.12.0
|
||||||
github.com/grafana/grafana-azure-sdk-go v1.6.0
|
github.com/grafana/grafana-azure-sdk-go v1.6.0
|
||||||
github.com/grafana/grafana-plugin-sdk-go v0.157.0
|
github.com/grafana/grafana-plugin-sdk-go v0.158.0
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0
|
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0
|
||||||
github.com/hashicorp/go-hclog v1.2.0
|
github.com/hashicorp/go-hclog v1.2.0
|
||||||
github.com/hashicorp/go-plugin v1.4.3
|
github.com/hashicorp/go-plugin v1.4.3
|
||||||
|
|||||||
@@ -1297,6 +1297,8 @@ github.com/grafana/grafana-plugin-sdk-go v0.94.0/go.mod h1:3VXz4nCv6wH5SfgB3mlW3
|
|||||||
github.com/grafana/grafana-plugin-sdk-go v0.114.0/go.mod h1:D7x3ah+1d4phNXpbnOaxa/osSaZlwh9/ZUnGGzegRbk=
|
github.com/grafana/grafana-plugin-sdk-go v0.114.0/go.mod h1:D7x3ah+1d4phNXpbnOaxa/osSaZlwh9/ZUnGGzegRbk=
|
||||||
github.com/grafana/grafana-plugin-sdk-go v0.157.0 h1:Qm0r5A4TsG+Tmy8Vagffqv21t3R/tzFUdYZZpd9COYE=
|
github.com/grafana/grafana-plugin-sdk-go v0.157.0 h1:Qm0r5A4TsG+Tmy8Vagffqv21t3R/tzFUdYZZpd9COYE=
|
||||||
github.com/grafana/grafana-plugin-sdk-go v0.157.0/go.mod h1:FwinU1fti54nWWsacIdL8D2WfYcKOWB2VRMtxnBbY+o=
|
github.com/grafana/grafana-plugin-sdk-go v0.157.0/go.mod h1:FwinU1fti54nWWsacIdL8D2WfYcKOWB2VRMtxnBbY+o=
|
||||||
|
github.com/grafana/grafana-plugin-sdk-go v0.158.0 h1:kucTwr4LEa6hoSunnRqkuEeJOgbBTFrhdGNkJrMV4Zg=
|
||||||
|
github.com/grafana/grafana-plugin-sdk-go v0.158.0/go.mod h1:7/F3lL/w3MGuZTwu0jam5oL/4zNOQmhs2k8WZ9VlzhI=
|
||||||
github.com/grafana/kindsys v0.0.0-20230309200316-812b9884a375 h1:iWFjqAU5GjIV/HetIE/Me6VF3SRw29u5QviMVbJUVQo=
|
github.com/grafana/kindsys v0.0.0-20230309200316-812b9884a375 h1:iWFjqAU5GjIV/HetIE/Me6VF3SRw29u5QviMVbJUVQo=
|
||||||
github.com/grafana/kindsys v0.0.0-20230309200316-812b9884a375/go.mod h1:213a3clTiegHfheYcLPLeEyHv/azK/fAF67OEbzuLzw=
|
github.com/grafana/kindsys v0.0.0-20230309200316-812b9884a375/go.mod h1:213a3clTiegHfheYcLPLeEyHv/azK/fAF67OEbzuLzw=
|
||||||
github.com/grafana/mysql v1.6.8 h1:kyo38C4NgghJMqaPrkWPy4rifAcipQVF+dKttfpgTCs=
|
github.com/grafana/mysql v1.6.8 h1:kyo38C4NgghJMqaPrkWPy4rifAcipQVF+dKttfpgTCs=
|
||||||
|
|||||||
+4
-2
@@ -1,6 +1,8 @@
|
|||||||
{
|
{
|
||||||
"npmClient": "yarn",
|
"npmClient": "yarn",
|
||||||
"useWorkspaces": true,
|
"useWorkspaces": true,
|
||||||
"packages": ["packages/*"],
|
"packages": [
|
||||||
"version": "9.5.0-pre"
|
"packages/*"
|
||||||
|
],
|
||||||
|
"version": "10.0.0-pre"
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-2
@@ -3,7 +3,7 @@
|
|||||||
"license": "AGPL-3.0-only",
|
"license": "AGPL-3.0-only",
|
||||||
"private": true,
|
"private": true,
|
||||||
"name": "grafana",
|
"name": "grafana",
|
||||||
"version": "9.5.0-pre",
|
"version": "10.0.0-pre",
|
||||||
"repository": "github:grafana/grafana",
|
"repository": "github:grafana/grafana",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "yarn i18n:compile && NODE_ENV=production webpack --progress --config scripts/webpack/webpack.prod.js",
|
"build": "yarn i18n:compile && NODE_ENV=production webpack --progress --config scripts/webpack/webpack.prod.js",
|
||||||
@@ -266,7 +266,7 @@
|
|||||||
"@grafana/lezer-logql": "0.1.2",
|
"@grafana/lezer-logql": "0.1.2",
|
||||||
"@grafana/monaco-logql": "^0.0.7",
|
"@grafana/monaco-logql": "^0.0.7",
|
||||||
"@grafana/runtime": "workspace:*",
|
"@grafana/runtime": "workspace:*",
|
||||||
"@grafana/scenes": "^0.2.0",
|
"@grafana/scenes": "^0.3.0",
|
||||||
"@grafana/schema": "workspace:*",
|
"@grafana/schema": "workspace:*",
|
||||||
"@grafana/ui": "workspace:*",
|
"@grafana/ui": "workspace:*",
|
||||||
"@kusto/monaco-kusto": "5.3.6",
|
"@kusto/monaco-kusto": "5.3.6",
|
||||||
@@ -279,6 +279,7 @@
|
|||||||
"@opentelemetry/semantic-conventions": "1.9.1",
|
"@opentelemetry/semantic-conventions": "1.9.1",
|
||||||
"@popperjs/core": "2.11.6",
|
"@popperjs/core": "2.11.6",
|
||||||
"@prometheus-io/lezer-promql": "^0.37.0-rc.1",
|
"@prometheus-io/lezer-promql": "^0.37.0-rc.1",
|
||||||
|
"@pyroscope/flamegraph": "^0.35.5",
|
||||||
"@react-aria/button": "3.6.1",
|
"@react-aria/button": "3.6.1",
|
||||||
"@react-aria/dialog": "3.3.1",
|
"@react-aria/dialog": "3.3.1",
|
||||||
"@react-aria/focus": "3.8.0",
|
"@react-aria/focus": "3.8.0",
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"author": "Grafana Labs",
|
"author": "Grafana Labs",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"name": "@grafana/data",
|
"name": "@grafana/data",
|
||||||
"version": "9.5.0-pre",
|
"version": "10.0.0-pre",
|
||||||
"description": "Grafana Data Library",
|
"description": "Grafana Data Library",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"typescript"
|
"typescript"
|
||||||
@@ -36,7 +36,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@braintree/sanitize-url": "6.0.2",
|
"@braintree/sanitize-url": "6.0.2",
|
||||||
"@grafana/schema": "9.5.0-pre",
|
"@grafana/schema": "10.0.0-pre",
|
||||||
"@types/d3-interpolate": "^3.0.0",
|
"@types/d3-interpolate": "^3.0.0",
|
||||||
"d3-interpolate": "3.0.1",
|
"d3-interpolate": "3.0.1",
|
||||||
"date-fns": "2.29.3",
|
"date-fns": "2.29.3",
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { FieldType } from '../types/dataFrame';
|
import { ArrayVector } from '..';
|
||||||
|
import { DataFrame, FieldType } from '../types/dataFrame';
|
||||||
|
|
||||||
import { DataFrameJSON, dataFrameFromJSON } from './DataFrameJSON';
|
import { DataFrameJSON, dataFrameFromJSON, dataFrameToJSON } from './DataFrameJSON';
|
||||||
|
|
||||||
describe('DataFrame JSON', () => {
|
describe('DataFrame JSON', () => {
|
||||||
describe('when called with a DataFrame', () => {
|
describe('when called with a DataFrame', () => {
|
||||||
@@ -137,5 +138,104 @@ describe('DataFrame JSON', () => {
|
|||||||
}
|
}
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should decode fields with nanos', () => {
|
||||||
|
const json: DataFrameJSON = {
|
||||||
|
schema: {
|
||||||
|
fields: [
|
||||||
|
{ name: 'time1', type: FieldType.time },
|
||||||
|
{ name: 'time2', type: FieldType.time },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
values: [
|
||||||
|
[1, 2, 3],
|
||||||
|
[4, 5, 6],
|
||||||
|
],
|
||||||
|
nanos: [null, [7, 8, 9]],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const frame = dataFrameFromJSON(json);
|
||||||
|
expect(frame).toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"config": {},
|
||||||
|
"entities": {},
|
||||||
|
"name": "time1",
|
||||||
|
"type": "time",
|
||||||
|
"values": [
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"config": {},
|
||||||
|
"entities": {},
|
||||||
|
"name": "time2",
|
||||||
|
"nanos": [
|
||||||
|
7,
|
||||||
|
8,
|
||||||
|
9,
|
||||||
|
],
|
||||||
|
"type": "time",
|
||||||
|
"values": [
|
||||||
|
4,
|
||||||
|
5,
|
||||||
|
6,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"length": 3,
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should encode fields with nanos', () => {
|
||||||
|
const inputFrame: DataFrame = {
|
||||||
|
refId: 'A',
|
||||||
|
meta: {},
|
||||||
|
name: 'f1',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'time1',
|
||||||
|
type: FieldType.time,
|
||||||
|
config: {},
|
||||||
|
values: new ArrayVector([11, 12, 13]),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'time2',
|
||||||
|
type: FieldType.time,
|
||||||
|
config: {},
|
||||||
|
values: new ArrayVector([14, 15, 16]),
|
||||||
|
nanos: [17, 18, 19],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
length: 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
const expectedJSON: DataFrameJSON = {
|
||||||
|
schema: {
|
||||||
|
fields: [
|
||||||
|
{ name: 'time1', type: FieldType.time, config: {} },
|
||||||
|
{ name: 'time2', type: FieldType.time, config: {} },
|
||||||
|
],
|
||||||
|
meta: {},
|
||||||
|
name: 'f1',
|
||||||
|
refId: 'A',
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
nanos: [null, [17, 18, 19]],
|
||||||
|
values: [
|
||||||
|
[11, 12, 13],
|
||||||
|
[14, 15, 16],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(dataFrameToJSON(inputFrame)).toStrictEqual(expectedJSON);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { DataFrame, FieldType, FieldConfig, Labels, QueryResultMeta } from '../types';
|
import { DataFrame, FieldType, FieldConfig, Labels, QueryResultMeta, Field } from '../types';
|
||||||
import { ArrayVector } from '../vector';
|
import { ArrayVector } from '../vector';
|
||||||
|
|
||||||
import { guessFieldTypeFromNameAndValue } from './processDataFrame';
|
import { guessFieldTypeFromNameAndValue } from './processDataFrame';
|
||||||
@@ -56,6 +56,13 @@ export interface DataFrameData {
|
|||||||
* NOTE: currently only decoding is implemented
|
* NOTE: currently only decoding is implemented
|
||||||
*/
|
*/
|
||||||
enums?: Array<string[] | null>;
|
enums?: Array<string[] | null>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds integers between 0 and 999999, used by time-fields
|
||||||
|
* to store the nanosecond-precision that cannot be represented
|
||||||
|
* by the millisecond-based base value.
|
||||||
|
*/
|
||||||
|
nanos?: Array<number[] | null>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -188,9 +195,11 @@ export function dataFrameFromJSON(dto: DataFrameJSON): DataFrame {
|
|||||||
type = FieldType.string;
|
type = FieldType.string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const nanos = data?.nanos?.[index];
|
||||||
|
|
||||||
// TODO: expand arrays further using bases,factors
|
// TODO: expand arrays further using bases,factors
|
||||||
|
|
||||||
return {
|
const dataFrameField: Field & { entities: FieldValueEntityLookup } = {
|
||||||
...f,
|
...f,
|
||||||
type: type ?? guessFieldType(f.name, buffer),
|
type: type ?? guessFieldType(f.name, buffer),
|
||||||
config: f.config ?? {},
|
config: f.config ?? {},
|
||||||
@@ -198,6 +207,12 @@ export function dataFrameFromJSON(dto: DataFrameJSON): DataFrame {
|
|||||||
// the presence of this prop is an optimization signal & lookup for consumers
|
// the presence of this prop is an optimization signal & lookup for consumers
|
||||||
entities: entities ?? {},
|
entities: entities ?? {},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (nanos != null) {
|
||||||
|
dataFrameField.nanos = nanos;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dataFrameField;
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -216,18 +231,34 @@ export function dataFrameToJSON(frame: DataFrame): DataFrameJSON {
|
|||||||
const data: DataFrameData = {
|
const data: DataFrameData = {
|
||||||
values: [],
|
values: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const allNanos: Array<number[] | null> = [];
|
||||||
|
let hasNanos = false;
|
||||||
|
|
||||||
const schema: DataFrameSchema = {
|
const schema: DataFrameSchema = {
|
||||||
refId: frame.refId,
|
refId: frame.refId,
|
||||||
meta: frame.meta,
|
meta: frame.meta,
|
||||||
name: frame.name,
|
name: frame.name,
|
||||||
fields: frame.fields.map((f) => {
|
fields: frame.fields.map((f) => {
|
||||||
const { values, state, display, ...sfield } = f;
|
const { values, nanos, state, display, ...sfield } = f;
|
||||||
delete (sfield as any).entities;
|
delete (sfield as any).entities;
|
||||||
data.values.push(values.toArray());
|
data.values.push(values.toArray());
|
||||||
|
|
||||||
|
if (nanos != null) {
|
||||||
|
allNanos.push(nanos);
|
||||||
|
hasNanos = true;
|
||||||
|
} else {
|
||||||
|
allNanos.push(null);
|
||||||
|
}
|
||||||
|
|
||||||
return sfield;
|
return sfield;
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (hasNanos) {
|
||||||
|
data.nanos = allNanos;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
schema,
|
schema,
|
||||||
data,
|
data,
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { ReducerID } from '../transformations/fieldReducer';
|
|||||||
import { FieldConfigPropertyItem, MappingType, SpecialValueMatch, ValueMapping } from '../types';
|
import { FieldConfigPropertyItem, MappingType, SpecialValueMatch, ValueMapping } from '../types';
|
||||||
|
|
||||||
import { getDisplayProcessor } from './displayProcessor';
|
import { getDisplayProcessor } from './displayProcessor';
|
||||||
import { getFieldDisplayValues, GetFieldDisplayValuesOptions } from './fieldDisplay';
|
import { fixCellTemplateExpressions, getFieldDisplayValues, GetFieldDisplayValuesOptions } from './fieldDisplay';
|
||||||
import { standardFieldConfigEditorRegistry } from './standardFieldConfigEditorRegistry';
|
import { standardFieldConfigEditorRegistry } from './standardFieldConfigEditorRegistry';
|
||||||
|
|
||||||
describe('FieldDisplay', () => {
|
describe('FieldDisplay', () => {
|
||||||
@@ -534,3 +534,11 @@ function createDisplayOptions(extend: Partial<GetFieldDisplayValuesOptions> = {}
|
|||||||
|
|
||||||
return merge(options, extend);
|
return merge(options, extend);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
describe('fixCellTemplateExpressions', () => {
|
||||||
|
it('Should replace __cell_x correctly', () => {
|
||||||
|
expect(fixCellTemplateExpressions('$__cell_10 asd ${__cell_15} asd [[__cell_20]]')).toEqual(
|
||||||
|
'${__data.fields[10]} asd ${__data.fields[15]} asd ${__data.fields[20]}'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { toString, isEmpty } from 'lodash';
|
import { isEmpty } from 'lodash';
|
||||||
|
|
||||||
import { DataFrameView } from '../dataframe/DataFrameView';
|
import { DataFrameView } from '../dataframe/DataFrameView';
|
||||||
import { getTimeField } from '../dataframe/processDataFrame';
|
import { getTimeField } from '../dataframe/processDataFrame';
|
||||||
@@ -96,7 +96,6 @@ export const getFieldDisplayValues = (options: GetFieldDisplayValuesOptions): Fi
|
|||||||
|
|
||||||
const data = options.data ?? [];
|
const data = options.data ?? [];
|
||||||
const limit = reduceOptions.limit ? reduceOptions.limit : DEFAULT_FIELD_DISPLAY_VALUES_LIMIT;
|
const limit = reduceOptions.limit ? reduceOptions.limit : DEFAULT_FIELD_DISPLAY_VALUES_LIMIT;
|
||||||
const scopedVars: ScopedVars = {};
|
|
||||||
|
|
||||||
let hitLimit = false;
|
let hitLimit = false;
|
||||||
|
|
||||||
@@ -125,7 +124,7 @@ export const getFieldDisplayValues = (options: GetFieldDisplayValuesOptions): Fi
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const displayName = field.config.displayName ?? '';
|
let displayName = field.config.displayName ?? '';
|
||||||
|
|
||||||
const display =
|
const display =
|
||||||
field.display ??
|
field.display ??
|
||||||
@@ -137,23 +136,10 @@ export const getFieldDisplayValues = (options: GetFieldDisplayValuesOptions): Fi
|
|||||||
|
|
||||||
// Show all rows
|
// Show all rows
|
||||||
if (reduceOptions.values) {
|
if (reduceOptions.values) {
|
||||||
const usesCellValues = displayName.indexOf(VAR_CELL_PREFIX) >= 0;
|
|
||||||
|
|
||||||
for (let j = 0; j < field.values.length; j++) {
|
for (let j = 0; j < field.values.length; j++) {
|
||||||
// Add all the row variables
|
|
||||||
if (usesCellValues) {
|
|
||||||
for (let k = 0; k < dataFrame.fields.length; k++) {
|
|
||||||
const f = dataFrame.fields[k];
|
|
||||||
const v = f.values.get(j);
|
|
||||||
scopedVars[VAR_CELL_PREFIX + k] = {
|
|
||||||
value: v,
|
|
||||||
text: toString(v),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
field.state = setIndexForPaletteColor(field, values.length);
|
field.state = setIndexForPaletteColor(field, values.length);
|
||||||
|
|
||||||
|
const scopedVars = getFieldScopedVarsWithDataContexAndRowIndex(field, j);
|
||||||
const displayValue = display(field.values.get(j));
|
const displayValue = display(field.values.get(j));
|
||||||
const rowName = getSmartDisplayNameForRow(dataFrame, field, j, replaceVariables, scopedVars);
|
const rowName = getSmartDisplayNameForRow(dataFrame, field, j, replaceVariables, scopedVars);
|
||||||
const overrideColor = lookupRowColorFromOverride(rowName, options.fieldConfig, theme);
|
const overrideColor = lookupRowColorFromOverride(rowName, options.fieldConfig, theme);
|
||||||
@@ -190,14 +176,13 @@ export const getFieldDisplayValues = (options: GetFieldDisplayValuesOptions): Fi
|
|||||||
});
|
});
|
||||||
|
|
||||||
for (const calc of calcs) {
|
for (const calc of calcs) {
|
||||||
|
const scopedVars = field.state?.scopedVars ?? {};
|
||||||
scopedVars[VAR_CALC] = { value: calc, text: calc };
|
scopedVars[VAR_CALC] = { value: calc, text: calc };
|
||||||
|
|
||||||
const displayValue = display(results[calc]);
|
const displayValue = display(results[calc]);
|
||||||
|
|
||||||
if (displayName !== '') {
|
if (displayName !== '') {
|
||||||
displayValue.title = replaceVariables(displayName, {
|
displayValue.title = replaceVariables(displayName, scopedVars);
|
||||||
...field.state?.scopedVars, // series and field scoped vars
|
|
||||||
...scopedVars,
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
displayValue.title = getFieldDisplayName(field, dataFrame, data);
|
displayValue.title = getFieldDisplayName(field, dataFrame, data);
|
||||||
}
|
}
|
||||||
@@ -247,18 +232,22 @@ function getSmartDisplayNameForRow(
|
|||||||
field: Field,
|
field: Field,
|
||||||
rowIndex: number,
|
rowIndex: number,
|
||||||
replaceVariables: InterpolateFunction,
|
replaceVariables: InterpolateFunction,
|
||||||
scopedVars: ScopedVars
|
scopedVars: ScopedVars | undefined
|
||||||
): string {
|
): string {
|
||||||
|
const displayName = field.config.displayName;
|
||||||
|
|
||||||
|
if (displayName) {
|
||||||
|
// Handle old __cell_n syntax
|
||||||
|
if (displayName.indexOf(VAR_CELL_PREFIX)) {
|
||||||
|
return replaceVariables(fixCellTemplateExpressions(displayName), scopedVars);
|
||||||
|
}
|
||||||
|
|
||||||
|
return replaceVariables(displayName, scopedVars);
|
||||||
|
}
|
||||||
|
|
||||||
let parts: string[] = [];
|
let parts: string[] = [];
|
||||||
let otherNumericFields = 0;
|
let otherNumericFields = 0;
|
||||||
|
|
||||||
if (field.config.displayName) {
|
|
||||||
return replaceVariables(field.config.displayName, {
|
|
||||||
...field.state?.scopedVars, // series and field scoped vars
|
|
||||||
...scopedVars,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const otherField of frame.fields) {
|
for (const otherField of frame.fields) {
|
||||||
if (otherField === field) {
|
if (otherField === field) {
|
||||||
continue;
|
continue;
|
||||||
@@ -382,3 +371,28 @@ function getDisplayText(display: DisplayValue, fallback: string): string {
|
|||||||
}
|
}
|
||||||
return display.text;
|
return display.text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function fixCellTemplateExpressions(str: string) {
|
||||||
|
return str.replace(/\${__cell_(\d+)}|\[\[__cell_(\d+)\]\]|\$__cell_(\d+)/g, (match, fmt1, fmt2, fmt3) => {
|
||||||
|
return `\${__data.fields[${fmt1 ?? fmt2 ?? fmt3}]}`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clones the existing dataContext and adds rowIndex to it
|
||||||
|
*/
|
||||||
|
function getFieldScopedVarsWithDataContexAndRowIndex(field: Field, rowIndex: number): ScopedVars | undefined {
|
||||||
|
if (field.state?.scopedVars?.__dataContext) {
|
||||||
|
return {
|
||||||
|
...field.state?.scopedVars,
|
||||||
|
__dataContext: {
|
||||||
|
value: {
|
||||||
|
...field.state?.scopedVars?.__dataContext.value,
|
||||||
|
rowIndex,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return field.state?.scopedVars;
|
||||||
|
}
|
||||||
|
|||||||
@@ -199,35 +199,9 @@ describe('applyFieldOverrides', () => {
|
|||||||
fieldConfigRegistry: new FieldConfigOptionsRegistry(),
|
fieldConfigRegistry: new FieldConfigOptionsRegistry(),
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(withOverrides[0].fields[0].state!.scopedVars).toMatchInlineSnapshot(`
|
expect(withOverrides[0].fields[0].state!.scopedVars?.__dataContext?.value.frame).toBe(withOverrides[0]);
|
||||||
{
|
expect(withOverrides[0].fields[0].state!.scopedVars?.__dataContext?.value.frameIndex).toBe(0);
|
||||||
"__field": {
|
expect(withOverrides[0].fields[0].state!.scopedVars?.__dataContext?.value.field).toBe(withOverrides[0].fields[0]);
|
||||||
"text": "Field",
|
|
||||||
"value": {},
|
|
||||||
},
|
|
||||||
"__series": {
|
|
||||||
"text": "Series",
|
|
||||||
"value": {
|
|
||||||
"name": "A",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
`);
|
|
||||||
|
|
||||||
expect(withOverrides[1].fields[0].state!.scopedVars).toMatchInlineSnapshot(`
|
|
||||||
{
|
|
||||||
"__field": {
|
|
||||||
"text": "Field",
|
|
||||||
"value": {},
|
|
||||||
},
|
|
||||||
"__series": {
|
|
||||||
"text": "Series",
|
|
||||||
"value": {
|
|
||||||
"name": "B",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
`);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -441,6 +415,124 @@ describe('setFieldConfigDefaults', () => {
|
|||||||
}
|
}
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('applies field config defaults correctly when links property exist in field config and no links are defined in panel', () => {
|
||||||
|
const dsFieldConfig: FieldConfig = {
|
||||||
|
links: [
|
||||||
|
{
|
||||||
|
title: 'Google link',
|
||||||
|
url: 'https://google.com',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const panelFieldConfig: FieldConfig = {};
|
||||||
|
|
||||||
|
const context: FieldOverrideEnv = {
|
||||||
|
data: [],
|
||||||
|
field: { type: FieldType.number } as Field,
|
||||||
|
dataFrameIndex: 0,
|
||||||
|
fieldConfigRegistry: customFieldRegistry,
|
||||||
|
};
|
||||||
|
|
||||||
|
// we mutate dsFieldConfig
|
||||||
|
// @ts-ignore
|
||||||
|
setFieldConfigDefaults(dsFieldConfig, panelFieldConfig, context);
|
||||||
|
|
||||||
|
expect(dsFieldConfig).toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"custom": {},
|
||||||
|
"links": [
|
||||||
|
{
|
||||||
|
"title": "Google link",
|
||||||
|
"url": "https://google.com",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('applies field config defaults correctly when links property exist in panel config and no links are defined in ds field config', () => {
|
||||||
|
const dsFieldConfig: FieldConfig = {};
|
||||||
|
|
||||||
|
const panelFieldConfig: FieldConfig = {
|
||||||
|
links: [
|
||||||
|
{
|
||||||
|
title: 'Google link',
|
||||||
|
url: 'https://google.com',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const context: FieldOverrideEnv = {
|
||||||
|
data: [],
|
||||||
|
field: { type: FieldType.number } as Field,
|
||||||
|
dataFrameIndex: 0,
|
||||||
|
fieldConfigRegistry: customFieldRegistry,
|
||||||
|
};
|
||||||
|
|
||||||
|
// we mutate dsFieldConfig
|
||||||
|
// @ts-ignore
|
||||||
|
setFieldConfigDefaults(dsFieldConfig, panelFieldConfig, context);
|
||||||
|
|
||||||
|
expect(dsFieldConfig).toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"custom": {},
|
||||||
|
"links": [
|
||||||
|
{
|
||||||
|
"title": "Google link",
|
||||||
|
"url": "https://google.com",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('applies a merge strategy for links when they exist in ds config and panel', () => {
|
||||||
|
const dsFieldConfig: FieldConfig = {
|
||||||
|
links: [
|
||||||
|
{
|
||||||
|
title: 'Google link',
|
||||||
|
url: 'https://google.com',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const panelFieldConfig: FieldConfig = {
|
||||||
|
links: [
|
||||||
|
{
|
||||||
|
title: 'Grafana',
|
||||||
|
url: 'https://grafana.com',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const context: FieldOverrideEnv = {
|
||||||
|
data: [],
|
||||||
|
field: { type: FieldType.number } as Field,
|
||||||
|
dataFrameIndex: 0,
|
||||||
|
fieldConfigRegistry: customFieldRegistry,
|
||||||
|
};
|
||||||
|
|
||||||
|
// we mutate dsFieldConfig
|
||||||
|
setFieldConfigDefaults(dsFieldConfig, panelFieldConfig, context);
|
||||||
|
|
||||||
|
expect(dsFieldConfig).toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"custom": {},
|
||||||
|
"links": [
|
||||||
|
{
|
||||||
|
"title": "Google link",
|
||||||
|
"url": "https://google.com",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Grafana",
|
||||||
|
"url": "https://grafana.com",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('setDynamicConfigValue', () => {
|
describe('setDynamicConfigValue', () => {
|
||||||
|
|||||||
@@ -39,10 +39,7 @@ import { mapInternalLinkToExplore } from '../utils/dataLinks';
|
|||||||
|
|
||||||
import { FieldConfigOptionsRegistry } from './FieldConfigOptionsRegistry';
|
import { FieldConfigOptionsRegistry } from './FieldConfigOptionsRegistry';
|
||||||
import { getDisplayProcessor, getRawDisplayProcessor } from './displayProcessor';
|
import { getDisplayProcessor, getRawDisplayProcessor } from './displayProcessor';
|
||||||
import { getFrameDisplayName } from './fieldState';
|
|
||||||
import { getFieldDisplayValuesProxy } from './getFieldDisplayValuesProxy';
|
|
||||||
import { standardFieldConfigEditorRegistry } from './standardFieldConfigEditorRegistry';
|
import { standardFieldConfigEditorRegistry } from './standardFieldConfigEditorRegistry';
|
||||||
import { getTemplateProxyForField } from './templateProxies';
|
|
||||||
|
|
||||||
interface OverrideProps {
|
interface OverrideProps {
|
||||||
match: FieldMatcher;
|
match: FieldMatcher;
|
||||||
@@ -122,18 +119,17 @@ export function applyFieldOverrides(options: ApplyFieldOverrideOptions): DataFra
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
const scopedVars: ScopedVars = {
|
|
||||||
__series: { text: 'Series', value: { name: getFrameDisplayName(newFrame, index) } }, // might be missing
|
|
||||||
};
|
|
||||||
|
|
||||||
for (const field of newFrame.fields) {
|
for (const field of newFrame.fields) {
|
||||||
const config = field.config;
|
const config = field.config;
|
||||||
|
|
||||||
field.state!.scopedVars = {
|
field.state!.scopedVars = {
|
||||||
...scopedVars,
|
__dataContext: {
|
||||||
__field: {
|
value: {
|
||||||
text: 'Field',
|
data: options.data!,
|
||||||
value: getTemplateProxyForField(field, newFrame, options.data),
|
frame: newFrame,
|
||||||
|
frameIndex: index,
|
||||||
|
field: field,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -293,6 +289,11 @@ export function setDynamicConfigValue(config: FieldConfig, value: DynamicConfigV
|
|||||||
// config -> from DS
|
// config -> from DS
|
||||||
// defaults -> from Panel config
|
// defaults -> from Panel config
|
||||||
export function setFieldConfigDefaults(config: FieldConfig, defaults: FieldConfig, context: FieldOverrideEnv) {
|
export function setFieldConfigDefaults(config: FieldConfig, defaults: FieldConfig, context: FieldOverrideEnv) {
|
||||||
|
// For cases where we have links on the datasource config and the panel config, we need to merge them
|
||||||
|
if (config.links && defaults.links) {
|
||||||
|
// Combine the data source links and the panel default config links
|
||||||
|
config.links = [...config.links, ...defaults.links];
|
||||||
|
}
|
||||||
for (const fieldConfigProperty of context.fieldConfigRegistry.list()) {
|
for (const fieldConfigProperty of context.fieldConfigRegistry.list()) {
|
||||||
if (fieldConfigProperty.isCustom && !config.custom) {
|
if (fieldConfigProperty.isCustom && !config.custom) {
|
||||||
config.custom = {};
|
config.custom = {};
|
||||||
@@ -371,49 +372,29 @@ export const getLinksSupplier =
|
|||||||
}
|
}
|
||||||
|
|
||||||
return field.config.links.map((link: DataLink) => {
|
return field.config.links.map((link: DataLink) => {
|
||||||
let dataFrameVars = {};
|
const dataContext: DataContextScopedVar = getFieldDataContextClone(frame, field, fieldScopedVars);
|
||||||
let dataContext: DataContextScopedVar = { value: { frame, field } };
|
const dataLinkScopedVars = {
|
||||||
|
...fieldScopedVars,
|
||||||
|
__dataContext: dataContext,
|
||||||
|
};
|
||||||
|
|
||||||
// We are not displaying reduction result
|
// We are not displaying reduction result
|
||||||
if (config.valueRowIndex !== undefined && !isNaN(config.valueRowIndex)) {
|
if (config.valueRowIndex !== undefined && !isNaN(config.valueRowIndex)) {
|
||||||
dataContext.value.rowIndex = config.valueRowIndex;
|
dataContext.value.rowIndex = config.valueRowIndex;
|
||||||
|
|
||||||
const fieldsProxy = getFieldDisplayValuesProxy({
|
|
||||||
frame,
|
|
||||||
rowIndex: config.valueRowIndex,
|
|
||||||
timeZone: timeZone,
|
|
||||||
});
|
|
||||||
|
|
||||||
dataFrameVars = {
|
|
||||||
__data: {
|
|
||||||
value: {
|
|
||||||
name: frame.name,
|
|
||||||
refId: frame.refId,
|
|
||||||
fields: fieldsProxy,
|
|
||||||
},
|
|
||||||
text: 'Data',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
} else {
|
} else {
|
||||||
dataContext.value.calculatedValue = config.calculatedValue;
|
dataContext.value.calculatedValue = config.calculatedValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const variables: ScopedVars = {
|
|
||||||
...fieldScopedVars,
|
|
||||||
...dataFrameVars,
|
|
||||||
__dataContext: dataContext,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (link.onClick) {
|
if (link.onClick) {
|
||||||
return {
|
return {
|
||||||
href: link.url,
|
href: link.url,
|
||||||
title: replaceVariables(link.title || '', variables),
|
title: replaceVariables(link.title || '', dataLinkScopedVars),
|
||||||
target: link.targetBlank ? '_blank' : undefined,
|
target: link.targetBlank ? '_blank' : undefined,
|
||||||
onClick: (evt, origin) => {
|
onClick: (evt, origin) => {
|
||||||
link.onClick!({
|
link.onClick!({
|
||||||
origin: origin ?? field,
|
origin: origin ?? field,
|
||||||
e: evt,
|
e: evt,
|
||||||
replaceVariables: (v) => replaceVariables(v, variables),
|
replaceVariables: (v) => replaceVariables(v, dataLinkScopedVars),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
origin: field,
|
origin: field,
|
||||||
@@ -425,7 +406,7 @@ export const getLinksSupplier =
|
|||||||
return mapInternalLinkToExplore({
|
return mapInternalLinkToExplore({
|
||||||
link,
|
link,
|
||||||
internalLink: link.internal,
|
internalLink: link.internal,
|
||||||
scopedVars: variables,
|
scopedVars: dataLinkScopedVars,
|
||||||
field,
|
field,
|
||||||
range: link.internal.range ?? ({} as any),
|
range: link.internal.range ?? ({} as any),
|
||||||
replaceVariables,
|
replaceVariables,
|
||||||
@@ -440,13 +421,13 @@ export const getLinksSupplier =
|
|||||||
|
|
||||||
if (href) {
|
if (href) {
|
||||||
href = locationUtil.assureBaseUrl(href.replace(/\n/g, ''));
|
href = locationUtil.assureBaseUrl(href.replace(/\n/g, ''));
|
||||||
href = replaceVariables(href, variables, VariableFormatID.PercentEncode);
|
href = replaceVariables(href, dataLinkScopedVars, VariableFormatID.PercentEncode);
|
||||||
href = locationUtil.processUrl(href);
|
href = locationUtil.processUrl(href);
|
||||||
}
|
}
|
||||||
|
|
||||||
const info: LinkModel<Field> = {
|
const info: LinkModel<Field> = {
|
||||||
href,
|
href,
|
||||||
title: replaceVariables(link.title || '', variables),
|
title: replaceVariables(link.title || '', dataLinkScopedVars),
|
||||||
target: link.targetBlank ? '_blank' : undefined,
|
target: link.targetBlank ? '_blank' : undefined,
|
||||||
origin: field,
|
origin: field,
|
||||||
};
|
};
|
||||||
@@ -530,3 +511,18 @@ export function useFieldOverrides(
|
|||||||
};
|
};
|
||||||
}, [fieldConfigRegistry, fieldConfig, data, prevSeries, timeZone, theme, replace]);
|
}, [fieldConfigRegistry, fieldConfig, data, prevSeries, timeZone, theme, replace]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clones the existing dataContext or creates a new one
|
||||||
|
*/
|
||||||
|
function getFieldDataContextClone(frame: DataFrame, field: Field, fieldScopedVars: ScopedVars) {
|
||||||
|
if (fieldScopedVars?.__dataContext) {
|
||||||
|
return {
|
||||||
|
value: {
|
||||||
|
...fieldScopedVars.__dataContext.value,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return { value: { frame, field, data: [frame] } };
|
||||||
|
}
|
||||||
|
|||||||
@@ -16,9 +16,11 @@ export interface ScopedVars {
|
|||||||
*/
|
*/
|
||||||
export interface DataContextScopedVar {
|
export interface DataContextScopedVar {
|
||||||
value: {
|
value: {
|
||||||
|
data: DataFrame[];
|
||||||
frame: DataFrame;
|
frame: DataFrame;
|
||||||
field: Field;
|
field: Field;
|
||||||
rowIndex?: number;
|
rowIndex?: number;
|
||||||
|
frameIndex?: number;
|
||||||
calculatedValue?: DisplayValue;
|
calculatedValue?: DisplayValue;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ export class AppPlugin<T extends KeyValue = KeyValue> extends GrafanaPlugin<AppP
|
|||||||
return this._extensionConfigs;
|
return this._extensionConfigs;
|
||||||
}
|
}
|
||||||
|
|
||||||
configureExtensionLink<Context extends object>(extension: Exclude<PluginExtensionLinkConfig<Context>, 'type'>) {
|
configureExtensionLink<Context extends object>(extension: Omit<PluginExtensionLinkConfig<Context>, 'type'>) {
|
||||||
this._extensionConfigs.push({
|
this._extensionConfigs.push({
|
||||||
...extension,
|
...extension,
|
||||||
type: PluginExtensionTypes.link,
|
type: PluginExtensionTypes.link,
|
||||||
|
|||||||
@@ -137,6 +137,14 @@ export interface Field<T = any, V = Vector<T>> {
|
|||||||
*/
|
*/
|
||||||
config: FieldConfig;
|
config: FieldConfig;
|
||||||
values: V; // The raw field values
|
values: V; // The raw field values
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When type === FieldType.Time, this can optionally store
|
||||||
|
* the nanosecond-precison fractions as integers between
|
||||||
|
* 0 and 999999.
|
||||||
|
*/
|
||||||
|
nanos?: number[];
|
||||||
|
|
||||||
labels?: Labels;
|
labels?: Labels;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -465,6 +465,11 @@ export interface DataQueryResponse {
|
|||||||
* Defaults to LoadingState.Done if state is not defined
|
* Defaults to LoadingState.Done if state is not defined
|
||||||
*/
|
*/
|
||||||
state?: LoadingState;
|
state?: LoadingState;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* traceIds related to the response, if available
|
||||||
|
*/
|
||||||
|
traceIds?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum DataQueryErrorType {
|
export enum DataQueryErrorType {
|
||||||
@@ -488,6 +493,7 @@ export interface DataQueryError {
|
|||||||
status?: number;
|
status?: number;
|
||||||
statusText?: string;
|
statusText?: string;
|
||||||
refId?: string;
|
refId?: string;
|
||||||
|
traceId?: string;
|
||||||
type?: DataQueryErrorType;
|
type?: DataQueryErrorType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,6 @@
|
|||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
export interface FeatureToggles {
|
export interface FeatureToggles {
|
||||||
alertingBigTransactions?: boolean;
|
|
||||||
trimDefaults?: boolean;
|
trimDefaults?: boolean;
|
||||||
disableEnvelopeEncryption?: boolean;
|
disableEnvelopeEncryption?: boolean;
|
||||||
database_metrics?: boolean;
|
database_metrics?: boolean;
|
||||||
@@ -65,6 +64,7 @@ export interface FeatureToggles {
|
|||||||
nestedFolders?: boolean;
|
nestedFolders?: boolean;
|
||||||
accessTokenExpirationCheck?: boolean;
|
accessTokenExpirationCheck?: boolean;
|
||||||
elasticsearchBackendMigration?: boolean;
|
elasticsearchBackendMigration?: boolean;
|
||||||
|
showTraceId?: boolean;
|
||||||
datasourceOnboarding?: boolean;
|
datasourceOnboarding?: boolean;
|
||||||
emptyDashboardPage?: boolean;
|
emptyDashboardPage?: boolean;
|
||||||
secureSocksDatasourceProxy?: boolean;
|
secureSocksDatasourceProxy?: boolean;
|
||||||
@@ -93,4 +93,5 @@ export interface FeatureToggles {
|
|||||||
alertStateHistoryLokiOnly?: boolean;
|
alertStateHistoryLokiOnly?: boolean;
|
||||||
unifiedRequestLog?: boolean;
|
unifiedRequestLog?: boolean;
|
||||||
renderAuthJWT?: boolean;
|
renderAuthJWT?: boolean;
|
||||||
|
pyroscopeFlameGraph?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,6 +66,9 @@ export interface PanelData {
|
|||||||
|
|
||||||
/** Contains the range from the request or a shifted time range if a request uses relative time */
|
/** Contains the range from the request or a shifted time range if a request uses relative time */
|
||||||
timeRange: TimeRange;
|
timeRange: TimeRange;
|
||||||
|
|
||||||
|
/** traceIds collected during the processing of the requests */
|
||||||
|
traceIds?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PanelProps<T = any> {
|
export interface PanelProps<T = any> {
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { DataQuery } from '@grafana/schema';
|
||||||
|
|
||||||
import { RawTimeRange, TimeZone } from './time';
|
import { RawTimeRange, TimeZone } from './time';
|
||||||
|
|
||||||
// Plugin Extensions types
|
// Plugin Extensions types
|
||||||
@@ -18,7 +20,7 @@ export type PluginExtension = {
|
|||||||
export type PluginExtensionLink = PluginExtension & {
|
export type PluginExtensionLink = PluginExtension & {
|
||||||
type: PluginExtensionTypes.link;
|
type: PluginExtensionTypes.link;
|
||||||
path?: string;
|
path?: string;
|
||||||
onClick?: (event: React.MouseEvent) => void;
|
onClick?: (event?: React.MouseEvent) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Objects used for registering extensions (in app plugins)
|
// Objects used for registering extensions (in app plugins)
|
||||||
@@ -43,7 +45,7 @@ export type PluginExtensionLinkConfig<Context extends object = object> = PluginE
|
|||||||
Context,
|
Context,
|
||||||
Pick<PluginExtensionLink, 'path'> & {
|
Pick<PluginExtensionLink, 'path'> & {
|
||||||
type: PluginExtensionTypes.link;
|
type: PluginExtensionTypes.link;
|
||||||
onClick?: (event: React.MouseEvent, helpers: PluginExtensionEventHelpers<Context>) => void;
|
onClick?: (event: React.MouseEvent | undefined, helpers: PluginExtensionEventHelpers<Context>) => void;
|
||||||
}
|
}
|
||||||
>;
|
>;
|
||||||
|
|
||||||
@@ -73,7 +75,7 @@ export type PluginExtensionPanelContext = {
|
|||||||
timeRange: RawTimeRange;
|
timeRange: RawTimeRange;
|
||||||
timeZone: TimeZone;
|
timeZone: TimeZone;
|
||||||
dashboard: Dashboard;
|
dashboard: Dashboard;
|
||||||
targets: Target[];
|
targets: DataQuery[];
|
||||||
};
|
};
|
||||||
|
|
||||||
type Dashboard = {
|
type Dashboard = {
|
||||||
@@ -81,8 +83,3 @@ type Dashboard = {
|
|||||||
title: string;
|
title: string;
|
||||||
tags: string[];
|
tags: string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
type Target = {
|
|
||||||
pluginId: string;
|
|
||||||
refId: string;
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"author": "Grafana Labs",
|
"author": "Grafana Labs",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"name": "@grafana/e2e-selectors",
|
"name": "@grafana/e2e-selectors",
|
||||||
"version": "9.5.0-pre",
|
"version": "10.0.0-pre",
|
||||||
"description": "Grafana End-to-End Test Selectors Library",
|
"description": "Grafana End-to-End Test Selectors Library",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"cli",
|
"cli",
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ export const Components = {
|
|||||||
menu: (title: string) => `data-testid Panel menu ${title}`,
|
menu: (title: string) => `data-testid Panel menu ${title}`,
|
||||||
containerByTitle: (title: string) => `${title} panel`,
|
containerByTitle: (title: string) => `${title} panel`,
|
||||||
headerCornerInfo: (mode: string) => `Panel header ${mode}`,
|
headerCornerInfo: (mode: string) => `Panel header ${mode}`,
|
||||||
|
loadingBar: () => `Panel loading bar`,
|
||||||
},
|
},
|
||||||
Visualization: {
|
Visualization: {
|
||||||
Graph: {
|
Graph: {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"author": "Grafana Labs",
|
"author": "Grafana Labs",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"name": "@grafana/e2e",
|
"name": "@grafana/e2e",
|
||||||
"version": "9.5.0-pre",
|
"version": "10.0.0-pre",
|
||||||
"description": "Grafana End-to-End Test Library",
|
"description": "Grafana End-to-End Test Library",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"cli",
|
"cli",
|
||||||
@@ -63,7 +63,7 @@
|
|||||||
"@babel/core": "7.20.5",
|
"@babel/core": "7.20.5",
|
||||||
"@babel/preset-env": "7.20.2",
|
"@babel/preset-env": "7.20.2",
|
||||||
"@cypress/webpack-preprocessor": "5.17.0",
|
"@cypress/webpack-preprocessor": "5.17.0",
|
||||||
"@grafana/e2e-selectors": "9.5.0-pre",
|
"@grafana/e2e-selectors": "10.0.0-pre",
|
||||||
"@grafana/tsconfig": "^1.2.0-rc1",
|
"@grafana/tsconfig": "^1.2.0-rc1",
|
||||||
"@mochajs/json-file-reporter": "^1.2.0",
|
"@mochajs/json-file-reporter": "^1.2.0",
|
||||||
"babel-loader": "9.1.2",
|
"babel-loader": "9.1.2",
|
||||||
|
|||||||
@@ -91,15 +91,15 @@ export const configurePanel = (config: PartialAddPanelConfig | PartialEditPanelC
|
|||||||
e2e.components.Panels.Panel.headerItems('Edit').click();
|
e2e.components.Panels.Panel.headerItems('Edit').click();
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
e2e.components.PageToolbar.item('Add panel').should('be.visible');
|
e2e.components.PageToolbar.itemButton('Add panel button').should('be.visible');
|
||||||
e2e.components.PageToolbar.item('Add panel').click();
|
e2e.components.PageToolbar.itemButton('Add panel button').click();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Depending on the screen size, the "Add panel" button might be hidden
|
// Depending on the screen size, the "Add panel" button might be hidden
|
||||||
e2e.components.PageToolbar.item('Show more items').click();
|
e2e.components.PageToolbar.item('Show more items').click();
|
||||||
e2e.components.PageToolbar.item('Add panel').last().click();
|
e2e.components.PageToolbar.item('Add panel button').last().click();
|
||||||
}
|
}
|
||||||
e2e.pages.AddDashboard.addNewPanel().should('be.visible');
|
e2e.pages.AddDashboard.itemButton('Add new visualization menu item').should('be.visible');
|
||||||
e2e.pages.AddDashboard.addNewPanel().click();
|
e2e.pages.AddDashboard.itemButton('Add new visualization menu item').click();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (timeRange) {
|
if (timeRange) {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@grafana/eslint-plugin",
|
"name": "@grafana/eslint-plugin",
|
||||||
"description": "ESLint rules for use within the Grafana repo. Not suitable (or supported) for external use.",
|
"description": "ESLint rules for use within the Grafana repo. Not suitable (or supported) for external use.",
|
||||||
"version": "9.5.0-pre",
|
"version": "10.0.0-pre",
|
||||||
"main": "./index.cjs",
|
"main": "./index.cjs",
|
||||||
"author": "Grafana Labs",
|
"author": "Grafana Labs",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"author": "Grafana Labs",
|
"author": "Grafana Labs",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"name": "@grafana/runtime",
|
"name": "@grafana/runtime",
|
||||||
"version": "9.5.0-pre",
|
"version": "10.0.0-pre",
|
||||||
"description": "Grafana Runtime Library",
|
"description": "Grafana Runtime Library",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"grafana",
|
"grafana",
|
||||||
@@ -37,10 +37,10 @@
|
|||||||
"postpack": "mv package.json.bak package.json"
|
"postpack": "mv package.json.bak package.json"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@grafana/data": "9.5.0-pre",
|
"@grafana/data": "10.0.0-pre",
|
||||||
"@grafana/e2e-selectors": "9.5.0-pre",
|
"@grafana/e2e-selectors": "10.0.0-pre",
|
||||||
"@grafana/faro-web-sdk": "1.0.2",
|
"@grafana/faro-web-sdk": "1.0.2",
|
||||||
"@grafana/ui": "9.5.0-pre",
|
"@grafana/ui": "10.0.0-pre",
|
||||||
"@sentry/browser": "6.19.7",
|
"@sentry/browser": "6.19.7",
|
||||||
"history": "4.10.1",
|
"history": "4.10.1",
|
||||||
"lodash": "4.17.21",
|
"lodash": "4.17.21",
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ export interface FetchResponse<T = any> {
|
|||||||
readonly type: ResponseType;
|
readonly type: ResponseType;
|
||||||
readonly url: string;
|
readonly url: string;
|
||||||
readonly config: BackendSrvRequest;
|
readonly config: BackendSrvRequest;
|
||||||
|
readonly traceId?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -122,6 +123,7 @@ export interface FetchError<T = any> {
|
|||||||
cancelled?: boolean;
|
cancelled?: boolean;
|
||||||
isHandled?: boolean;
|
isHandled?: boolean;
|
||||||
config: BackendSrvRequest;
|
config: BackendSrvRequest;
|
||||||
|
traceId?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isFetchError(e: unknown): e is FetchError {
|
export function isFetchError(e: unknown): e is FetchError {
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ describe('DataSourceWithBackend', () => {
|
|||||||
"hideFromInspector": false,
|
"hideFromInspector": false,
|
||||||
"method": "POST",
|
"method": "POST",
|
||||||
"requestId": undefined,
|
"requestId": undefined,
|
||||||
"url": "/api/ds/query",
|
"url": "/api/ds/query?ds_type=dummy",
|
||||||
}
|
}
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
@@ -153,7 +153,7 @@ describe('DataSourceWithBackend', () => {
|
|||||||
"hideFromInspector": false,
|
"hideFromInspector": false,
|
||||||
"method": "POST",
|
"method": "POST",
|
||||||
"requestId": undefined,
|
"requestId": undefined,
|
||||||
"url": "/api/ds/query?expression=true",
|
"url": "/api/ds/query?ds_type=dummy&expression=true",
|
||||||
}
|
}
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
@@ -222,7 +222,7 @@ describe('DataSourceWithBackend', () => {
|
|||||||
"hideFromInspector": true,
|
"hideFromInspector": true,
|
||||||
"method": "POST",
|
"method": "POST",
|
||||||
"requestId": undefined,
|
"requestId": undefined,
|
||||||
"url": "/api/ds/query",
|
"url": "/api/ds/query?ds_type=dummy",
|
||||||
}
|
}
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -202,10 +202,16 @@ class DataSourceWithBackend<
|
|||||||
headers[PluginRequestHeaders.PluginID] = Array.from(pluginIDs).join(', ');
|
headers[PluginRequestHeaders.PluginID] = Array.from(pluginIDs).join(', ');
|
||||||
headers[PluginRequestHeaders.DatasourceUID] = Array.from(dsUIDs).join(', ');
|
headers[PluginRequestHeaders.DatasourceUID] = Array.from(dsUIDs).join(', ');
|
||||||
|
|
||||||
let url = '/api/ds/query';
|
let url = '/api/ds/query?ds_type=' + this.type;
|
||||||
|
|
||||||
if (hasExpr) {
|
if (hasExpr) {
|
||||||
headers[PluginRequestHeaders.FromExpression] = 'true';
|
headers[PluginRequestHeaders.FromExpression] = 'true';
|
||||||
url += '?expression=true';
|
url += '&expression=true';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Appending request ID to url to facilitate client-side performance metrics. See #65244 for more context.
|
||||||
|
if (requestId) {
|
||||||
|
url += `&requestId=${requestId}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.dashboardUID) {
|
if (request.dashboardUID) {
|
||||||
|
|||||||
@@ -280,6 +280,82 @@ describe('Query Response parser', () => {
|
|||||||
expect(ids).toEqual(['A', 'B']);
|
expect(ids).toEqual(['A', 'B']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should handle a success-response without traceIds', () => {
|
||||||
|
const input = {
|
||||||
|
data: {
|
||||||
|
results: {
|
||||||
|
A: {
|
||||||
|
frames: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as unknown as FetchResponse<BackendDataSourceResponse>;
|
||||||
|
const res = toDataQueryResponse(input);
|
||||||
|
expect(res.traceIds).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should handle a success-response with traceIds', () => {
|
||||||
|
const input = {
|
||||||
|
data: {
|
||||||
|
results: {
|
||||||
|
A: {
|
||||||
|
frames: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
traceId: 'traceId1',
|
||||||
|
} as unknown as FetchResponse<BackendDataSourceResponse>;
|
||||||
|
const res = toDataQueryResponse(input);
|
||||||
|
expect(res.traceIds).toStrictEqual(['traceId1']);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should handle an error-response without traceIds', () => {
|
||||||
|
const input = {
|
||||||
|
data: {
|
||||||
|
results: {
|
||||||
|
A: {
|
||||||
|
error: 'error from A',
|
||||||
|
status: 400,
|
||||||
|
},
|
||||||
|
B: {
|
||||||
|
error: 'error from B',
|
||||||
|
status: 400,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as unknown as FetchResponse<BackendDataSourceResponse>;
|
||||||
|
const res = toDataQueryResponse(input);
|
||||||
|
expect(res.traceIds).toBeUndefined();
|
||||||
|
expect(res.error?.traceId).toBeUndefined();
|
||||||
|
expect(res.errors).toHaveLength(2);
|
||||||
|
expect(res.errors?.[0].traceId).toBeUndefined();
|
||||||
|
expect(res.errors?.[1].traceId).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should handle an error-response with traceIds', () => {
|
||||||
|
const input = {
|
||||||
|
data: {
|
||||||
|
results: {
|
||||||
|
A: {
|
||||||
|
error: 'error from A',
|
||||||
|
status: 400,
|
||||||
|
},
|
||||||
|
B: {
|
||||||
|
error: 'error from B',
|
||||||
|
status: 400,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
traceId: 'traceId1',
|
||||||
|
} as unknown as FetchResponse<BackendDataSourceResponse>;
|
||||||
|
const res = toDataQueryResponse(input);
|
||||||
|
expect(res.traceIds).toStrictEqual(['traceId1']);
|
||||||
|
expect(res.error?.traceId).toBe('traceId1');
|
||||||
|
expect(res.errors).toHaveLength(2);
|
||||||
|
expect(res.errors?.[0].traceId).toBe('traceId1');
|
||||||
|
expect(res.errors?.[1].traceId).toBe('traceId1');
|
||||||
|
});
|
||||||
|
|
||||||
describe('Cache notice', () => {
|
describe('Cache notice', () => {
|
||||||
let resp: FetchResponse<BackendDataSourceResponse>;
|
let resp: FetchResponse<BackendDataSourceResponse>;
|
||||||
|
|
||||||
|
|||||||
@@ -65,6 +65,13 @@ export function toDataQueryResponse(
|
|||||||
queries?: DataQuery[]
|
queries?: DataQuery[]
|
||||||
): DataQueryResponse {
|
): DataQueryResponse {
|
||||||
const rsp: DataQueryResponse = { data: [], state: LoadingState.Done };
|
const rsp: DataQueryResponse = { data: [], state: LoadingState.Done };
|
||||||
|
|
||||||
|
const traceId = 'traceId' in res ? res.traceId : undefined;
|
||||||
|
|
||||||
|
if (traceId != null) {
|
||||||
|
rsp.traceIds = [traceId];
|
||||||
|
}
|
||||||
|
|
||||||
// If the response isn't in a correct shape we just ignore the data and pass empty DataQueryResponse.
|
// If the response isn't in a correct shape we just ignore the data and pass empty DataQueryResponse.
|
||||||
if ((res as FetchResponse).data?.results) {
|
if ((res as FetchResponse).data?.results) {
|
||||||
const results = (res as FetchResponse).data.results;
|
const results = (res as FetchResponse).data.results;
|
||||||
@@ -83,17 +90,21 @@ export function toDataQueryResponse(
|
|||||||
|
|
||||||
for (const dr of data) {
|
for (const dr of data) {
|
||||||
if (dr.error) {
|
if (dr.error) {
|
||||||
|
const errorObj: DataQueryError = {
|
||||||
|
refId: dr.refId,
|
||||||
|
message: dr.error,
|
||||||
|
status: dr.status,
|
||||||
|
};
|
||||||
|
if (traceId != null) {
|
||||||
|
errorObj.traceId = traceId;
|
||||||
|
}
|
||||||
if (!rsp.error) {
|
if (!rsp.error) {
|
||||||
rsp.error = {
|
rsp.error = { ...errorObj };
|
||||||
refId: dr.refId,
|
|
||||||
message: dr.error,
|
|
||||||
status: dr.status,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
if (rsp.errors) {
|
if (rsp.errors) {
|
||||||
rsp.errors.push({ refId: dr.refId, message: dr.error, status: dr.status });
|
rsp.errors.push({ ...errorObj });
|
||||||
} else {
|
} else {
|
||||||
rsp.errors = [{ refId: dr.refId, message: dr.error, status: dr.status }];
|
rsp.errors = [{ ...errorObj }];
|
||||||
}
|
}
|
||||||
rsp.state = LoadingState.Error;
|
rsp.state = LoadingState.Error;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"author": "Grafana Labs",
|
"author": "Grafana Labs",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"name": "@grafana/schema",
|
"name": "@grafana/schema",
|
||||||
"version": "9.5.0-pre",
|
"version": "10.0.0-pre",
|
||||||
"description": "Grafana Schema Library",
|
"description": "Grafana Schema Library",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"typescript"
|
"typescript"
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"author": "Grafana Labs",
|
"author": "Grafana Labs",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"name": "@grafana/toolkit",
|
"name": "@grafana/toolkit",
|
||||||
"version": "9.5.0-pre",
|
"version": "10.0.0-pre",
|
||||||
"description": "Grafana Toolkit",
|
"description": "Grafana Toolkit",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"grafana",
|
"grafana",
|
||||||
@@ -51,10 +51,10 @@
|
|||||||
"@babel/preset-env": "7.18.9",
|
"@babel/preset-env": "7.18.9",
|
||||||
"@babel/preset-react": "7.18.6",
|
"@babel/preset-react": "7.18.6",
|
||||||
"@babel/preset-typescript": "7.18.6",
|
"@babel/preset-typescript": "7.18.6",
|
||||||
"@grafana/data": "9.5.0-pre",
|
"@grafana/data": "10.0.0-pre",
|
||||||
"@grafana/eslint-config": "5.1.0",
|
"@grafana/eslint-config": "5.1.0",
|
||||||
"@grafana/tsconfig": "^1.2.0-rc1",
|
"@grafana/tsconfig": "^1.2.0-rc1",
|
||||||
"@grafana/ui": "9.5.0-pre",
|
"@grafana/ui": "10.0.0-pre",
|
||||||
"@jest/core": "27.5.1",
|
"@jest/core": "27.5.1",
|
||||||
"@types/command-exists": "^1.2.0",
|
"@types/command-exists": "^1.2.0",
|
||||||
"@types/eslint": "8.4.1",
|
"@types/eslint": "8.4.1",
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"author": "Grafana Labs",
|
"author": "Grafana Labs",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"name": "@grafana/ui",
|
"name": "@grafana/ui",
|
||||||
"version": "9.5.0-pre",
|
"version": "10.0.0-pre",
|
||||||
"description": "Grafana Components Library",
|
"description": "Grafana Components Library",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"grafana",
|
"grafana",
|
||||||
@@ -49,10 +49,10 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emotion/css": "11.10.6",
|
"@emotion/css": "11.10.6",
|
||||||
"@emotion/react": "11.10.6",
|
"@emotion/react": "11.10.6",
|
||||||
"@grafana/data": "9.5.0-pre",
|
"@grafana/data": "10.0.0-pre",
|
||||||
"@grafana/e2e-selectors": "9.5.0-pre",
|
"@grafana/e2e-selectors": "10.0.0-pre",
|
||||||
"@grafana/faro-web-sdk": "1.0.2",
|
"@grafana/faro-web-sdk": "1.0.2",
|
||||||
"@grafana/schema": "9.5.0-pre",
|
"@grafana/schema": "10.0.0-pre",
|
||||||
"@leeoniya/ufuzzy": "1.0.6",
|
"@leeoniya/ufuzzy": "1.0.6",
|
||||||
"@monaco-editor/react": "4.4.6",
|
"@monaco-editor/react": "4.4.6",
|
||||||
"@popperjs/core": "2.11.6",
|
"@popperjs/core": "2.11.6",
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import { GrafanaTheme2 } from '@grafana/data';
|
|||||||
import { useStyles2 } from '../../themes/ThemeContext';
|
import { useStyles2 } from '../../themes/ThemeContext';
|
||||||
import { IconName } from '../../types';
|
import { IconName } from '../../types';
|
||||||
import { Icon } from '../Icon/Icon';
|
import { Icon } from '../Icon/Icon';
|
||||||
import { HorizontalGroup } from '../Layout/Layout';
|
|
||||||
import { Tooltip } from '../Tooltip/Tooltip';
|
import { Tooltip } from '../Tooltip/Tooltip';
|
||||||
|
|
||||||
export type BadgeColor = 'blue' | 'red' | 'green' | 'orange' | 'purple';
|
export type BadgeColor = 'blue' | 'red' | 'green' | 'orange' | 'purple';
|
||||||
@@ -23,10 +22,8 @@ export const Badge = React.memo<BadgeProps>(({ icon, color, text, tooltip, class
|
|||||||
const styles = useStyles2(useCallback((theme) => getStyles(theme, color), [color]));
|
const styles = useStyles2(useCallback((theme) => getStyles(theme, color), [color]));
|
||||||
const badge = (
|
const badge = (
|
||||||
<div className={cx(styles.wrapper, className)} {...otherProps}>
|
<div className={cx(styles.wrapper, className)} {...otherProps}>
|
||||||
<HorizontalGroup align="center" spacing="xs">
|
{icon && <Icon name={icon} size="sm" />}
|
||||||
{icon && <Icon name={icon} size="sm" />}
|
{text}
|
||||||
<span>{text}</span>
|
|
||||||
</HorizontalGroup>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -59,7 +56,6 @@ const getStyles = (theme: GrafanaTheme2, color: BadgeColor) => {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
wrapper: css`
|
wrapper: css`
|
||||||
font-size: ${theme.typography.size.sm};
|
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
padding: 1px 4px;
|
padding: 1px 4px;
|
||||||
border-radius: ${theme.shape.radius.default};
|
border-radius: ${theme.shape.radius.default};
|
||||||
@@ -67,12 +63,10 @@ const getStyles = (theme: GrafanaTheme2, color: BadgeColor) => {
|
|||||||
border: 1px solid ${borderColor};
|
border: 1px solid ${borderColor};
|
||||||
color: ${textColor};
|
color: ${textColor};
|
||||||
font-weight: ${theme.typography.fontWeightRegular};
|
font-weight: ${theme.typography.fontWeightRegular};
|
||||||
|
gap: 2px;
|
||||||
> span {
|
font-size: ${theme.typography.bodySmall.fontSize};
|
||||||
position: relative;
|
line-height: ${theme.typography.bodySmall.lineHeight};
|
||||||
top: 1px;
|
align-items: center;
|
||||||
margin-left: 2px;
|
|
||||||
}
|
|
||||||
`,
|
`,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { TooltipPlacement } from '../Tooltip/types';
|
|||||||
export interface Props {
|
export interface Props {
|
||||||
overlay: React.ReactElement | (() => React.ReactElement);
|
overlay: React.ReactElement | (() => React.ReactElement);
|
||||||
placement?: TooltipPlacement;
|
placement?: TooltipPlacement;
|
||||||
children: React.ReactElement | ((isOpen: boolean) => React.ReactElement);
|
children: React.ReactElement;
|
||||||
/** Amount in pixels to nudge the dropdown vertically and horizontally, respectively. */
|
/** Amount in pixels to nudge the dropdown vertically and horizontally, respectively. */
|
||||||
offset?: [number, number];
|
offset?: [number, number];
|
||||||
onVisibleChange?: (state: boolean) => void;
|
onVisibleChange?: (state: boolean) => void;
|
||||||
@@ -51,7 +51,7 @@ export const Dropdown = React.memo(({ children, overlay, placement, offset, onVi
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{React.cloneElement(typeof children === 'function' ? children(visible) : children, {
|
{React.cloneElement(children, {
|
||||||
ref: setTriggerRef,
|
ref: setTriggerRef,
|
||||||
})}
|
})}
|
||||||
{visible && (
|
{visible && (
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { getSegmentStyles } from './styles';
|
|||||||
|
|
||||||
import { SegmentSelect, useExpandableLabel, SegmentProps } from './';
|
import { SegmentSelect, useExpandableLabel, SegmentProps } from './';
|
||||||
|
|
||||||
export interface SegmentSyncProps<T> extends SegmentProps<T>, Omit<HTMLProps<HTMLDivElement>, 'value' | 'onChange'> {
|
export interface SegmentSyncProps<T> extends SegmentProps, Omit<HTMLProps<HTMLDivElement>, 'value' | 'onChange'> {
|
||||||
value?: T | SelectableValue<T>;
|
value?: T | SelectableValue<T>;
|
||||||
onChange: (item: SelectableValue<T>) => void;
|
onChange: (item: SelectableValue<T>) => void;
|
||||||
options: Array<SelectableValue<T>>;
|
options: Array<SelectableValue<T>>;
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import { getSegmentStyles } from './styles';
|
|||||||
|
|
||||||
import { useExpandableLabel, SegmentProps } from '.';
|
import { useExpandableLabel, SegmentProps } from '.';
|
||||||
|
|
||||||
export interface SegmentAsyncProps<T> extends SegmentProps<T>, Omit<HTMLProps<HTMLDivElement>, 'value' | 'onChange'> {
|
export interface SegmentAsyncProps<T> extends SegmentProps, Omit<HTMLProps<HTMLDivElement>, 'value' | 'onChange'> {
|
||||||
value?: T | SelectableValue<T>;
|
value?: T | SelectableValue<T>;
|
||||||
loadOptions: (query?: string) => Promise<Array<SelectableValue<T>>>;
|
loadOptions: (query?: string) => Promise<Array<SelectableValue<T>>>;
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -100,12 +100,10 @@ export const InputWithAutoFocus = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Basic: ComponentStory<React.ComponentType<SegmentInputProps<string | number>>> = (
|
export const Basic: ComponentStory<React.ComponentType<SegmentInputProps>> = (args: SegmentInputProps) => {
|
||||||
args: SegmentInputProps<string | number>
|
|
||||||
) => {
|
|
||||||
const [value, setValue] = useState(args.value);
|
const [value, setValue] = useState(args.value);
|
||||||
|
|
||||||
const props: SegmentInputProps<string | number> = {
|
const props: SegmentInputProps = {
|
||||||
...args,
|
...args,
|
||||||
value,
|
value,
|
||||||
onChange: (value) => {
|
onChange: (value) => {
|
||||||
@@ -117,7 +115,7 @@ export const Basic: ComponentStory<React.ComponentType<SegmentInputProps<string
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<SegmentSection label="Segment:">
|
<SegmentSection label="Segment:">
|
||||||
<SegmentInput<string | number> {...props} />
|
<SegmentInput {...props} />
|
||||||
</SegmentSection>
|
</SegmentSection>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import { getSegmentStyles } from './styles';
|
|||||||
|
|
||||||
import { useExpandableLabel, SegmentProps } from '.';
|
import { useExpandableLabel, SegmentProps } from '.';
|
||||||
|
|
||||||
export interface SegmentInputProps<T>
|
export interface SegmentInputProps
|
||||||
extends Omit<SegmentProps<T>, 'allowCustomValue' | 'allowEmptyValue'>,
|
extends Omit<SegmentProps, 'allowCustomValue' | 'allowEmptyValue'>,
|
||||||
Omit<HTMLProps<HTMLInputElement>, 'value' | 'onChange'> {
|
Omit<HTMLProps<HTMLInputElement>, 'value' | 'onChange'> {
|
||||||
value: string | number;
|
value: string | number;
|
||||||
onChange: (text: string | number) => void;
|
onChange: (text: string | number) => void;
|
||||||
@@ -19,7 +19,7 @@ export interface SegmentInputProps<T>
|
|||||||
|
|
||||||
const FONT_SIZE = 14;
|
const FONT_SIZE = 14;
|
||||||
|
|
||||||
export function SegmentInput<T>({
|
export function SegmentInput({
|
||||||
value: initialValue,
|
value: initialValue,
|
||||||
onChange,
|
onChange,
|
||||||
Component,
|
Component,
|
||||||
@@ -30,7 +30,7 @@ export function SegmentInput<T>({
|
|||||||
autofocus = false,
|
autofocus = false,
|
||||||
onExpandedChange,
|
onExpandedChange,
|
||||||
...rest
|
...rest
|
||||||
}: React.PropsWithChildren<SegmentInputProps<T>>) {
|
}: React.PropsWithChildren<SegmentInputProps>) {
|
||||||
const ref = useRef<HTMLInputElement>(null);
|
const ref = useRef<HTMLInputElement>(null);
|
||||||
const [value, setValue] = useState<number | string>(initialValue);
|
const [value, setValue] = useState<number | string>(initialValue);
|
||||||
const [inputWidth, setInputWidth] = useState<number>(measureText((initialValue || '').toString(), FONT_SIZE).width);
|
const [inputWidth, setInputWidth] = useState<number>(measureText((initialValue || '').toString(), FONT_SIZE).width);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { ReactElement } from 'react';
|
import { ReactElement } from 'react';
|
||||||
|
|
||||||
export interface SegmentProps<T> {
|
export interface SegmentProps {
|
||||||
Component?: ReactElement;
|
Component?: ReactElement;
|
||||||
className?: string;
|
className?: string;
|
||||||
allowCustomValue?: boolean;
|
allowCustomValue?: boolean;
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ export const SeriesIcon = React.memo(
|
|||||||
background: cssColor,
|
background: cssColor,
|
||||||
width: '14px',
|
width: '14px',
|
||||||
height: '4px',
|
height: '4px',
|
||||||
borderRadius: theme.shape.radius.default,
|
borderRadius: theme.shape.radius.pill,
|
||||||
display: 'inline-block',
|
display: 'inline-block',
|
||||||
marginRight: '8px',
|
marginRight: '8px',
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -156,6 +156,11 @@ export class UPlotScaleBuilder extends PlotConfigBuilder<ScaleProps, Scale> {
|
|||||||
|
|
||||||
let minMax: uPlot.Range.MinMax = [dataMin, dataMax];
|
let minMax: uPlot.Range.MinMax = [dataMin, dataMax];
|
||||||
|
|
||||||
|
// don't pad numeric x scales
|
||||||
|
if (scaleKey === 'x' && !isTime) {
|
||||||
|
return minMax;
|
||||||
|
}
|
||||||
|
|
||||||
// happens when all series on a scale are `show: false`, re-returning nulls will auto-disable axis
|
// happens when all series on a scale are `show: false`, re-returning nulls will auto-disable axis
|
||||||
if (!hasFixedRange && dataMin == null && dataMax == null) {
|
if (!hasFixedRange && dataMin == null && dataMax == null) {
|
||||||
return minMax;
|
return minMax;
|
||||||
|
|||||||
@@ -5,6 +5,14 @@
|
|||||||
"@grafana/ui": ["."]
|
"@grafana/ui": ["."]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"exclude": ["**/*.story.tsx", "**/*.test.ts*", "**/*.tmpl.ts", "dist", "node_modules", "src/utils/storybook"],
|
"exclude": [
|
||||||
|
"**/*.story.tsx",
|
||||||
|
"**/*.story.internal.tsx",
|
||||||
|
"**/*.test.ts*",
|
||||||
|
"**/*.tmpl.ts",
|
||||||
|
"dist",
|
||||||
|
"node_modules",
|
||||||
|
"src/utils/storybook"
|
||||||
|
],
|
||||||
"extends": "./tsconfig.json"
|
"extends": "./tsconfig.json"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||||
"github.com/grafana/grafana/pkg/plugins/backendplugin/coreplugin"
|
"github.com/grafana/grafana/pkg/plugins/backendplugin/coreplugin"
|
||||||
"github.com/grafana/grafana/pkg/plugins/backendplugin/provider"
|
"github.com/grafana/grafana/pkg/plugins/backendplugin/provider"
|
||||||
"github.com/grafana/grafana/pkg/plugins/config"
|
|
||||||
pluginClient "github.com/grafana/grafana/pkg/plugins/manager/client"
|
pluginClient "github.com/grafana/grafana/pkg/plugins/manager/client"
|
||||||
"github.com/grafana/grafana/pkg/plugins/manager/fakes"
|
"github.com/grafana/grafana/pkg/plugins/manager/fakes"
|
||||||
"github.com/grafana/grafana/pkg/plugins/manager/loader"
|
"github.com/grafana/grafana/pkg/plugins/manager/loader"
|
||||||
@@ -34,6 +33,7 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||||
"github.com/grafana/grafana/pkg/services/oauthtoken/oauthtokentest"
|
"github.com/grafana/grafana/pkg/services/oauthtoken/oauthtokentest"
|
||||||
"github.com/grafana/grafana/pkg/services/pluginsintegration"
|
"github.com/grafana/grafana/pkg/services/pluginsintegration"
|
||||||
|
"github.com/grafana/grafana/pkg/services/pluginsintegration/config"
|
||||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginaccesscontrol"
|
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginaccesscontrol"
|
||||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext"
|
"github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext"
|
||||||
pluginSettings "github.com/grafana/grafana/pkg/services/pluginsintegration/pluginsettings/service"
|
pluginSettings "github.com/grafana/grafana/pkg/services/pluginsintegration/pluginsettings/service"
|
||||||
@@ -59,13 +59,12 @@ func TestCallResource(t *testing.T) {
|
|||||||
|
|
||||||
coreRegistry := coreplugin.ProvideCoreRegistry(nil, &cloudwatch.CloudWatchService{}, nil, nil, nil, nil,
|
coreRegistry := coreplugin.ProvideCoreRegistry(nil, &cloudwatch.CloudWatchService{}, nil, nil, nil, nil,
|
||||||
nil, nil, nil, nil, testdatasource.ProvideService(cfg, featuremgmt.WithFeatures()), nil, nil, nil, nil, nil, nil)
|
nil, nil, nil, nil, testdatasource.ProvideService(cfg, featuremgmt.WithFeatures()), nil, nil, nil, nil, nil, nil)
|
||||||
var pCfg *config.Cfg
|
pCfg, err := config.ProvideConfig(setting.ProvideProvider(cfg), cfg)
|
||||||
pCfg, err = config.ProvideConfig(setting.ProvideProvider(cfg), cfg)
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
reg := registry.ProvideService()
|
reg := registry.ProvideService()
|
||||||
cdn := pluginscdn.ProvideService(pCfg)
|
|
||||||
l := loader.ProvideService(pCfg, fakes.NewFakeLicensingService(), signature.NewUnsignedAuthorizer(pCfg),
|
l := loader.ProvideService(pCfg, fakes.NewFakeLicensingService(), signature.NewUnsignedAuthorizer(pCfg),
|
||||||
reg, provider.ProvideService(coreRegistry), finder.NewLocalFinder(), fakes.NewFakeRoleRegistry(), cdn, assetpath.ProvideService(cdn))
|
reg, provider.ProvideService(coreRegistry), finder.NewLocalFinder(), fakes.NewFakeRoleRegistry(),
|
||||||
|
assetpath.ProvideService(pluginscdn.ProvideService(pCfg)))
|
||||||
srcs := sources.ProvideService(cfg, pCfg)
|
srcs := sources.ProvideService(cfg, pCfg)
|
||||||
ps, err := store.ProvideService(reg, srcs, l)
|
ps, err := store.ProvideService(reg, srcs, l)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|||||||
@@ -771,8 +771,7 @@ func realPackageVariant(ctx context.Context, v config.Variant, edition config.Ed
|
|||||||
defaultFileSrc: filepath.Join(grafanaDir, "packaging", "rpm", "sysconfig", "grafana-server"),
|
defaultFileSrc: filepath.Join(grafanaDir, "packaging", "rpm", "sysconfig", "grafana-server"),
|
||||||
systemdFileSrc: filepath.Join(grafanaDir, "packaging", "rpm", "systemd", "grafana-server.service"),
|
systemdFileSrc: filepath.Join(grafanaDir, "packaging", "rpm", "systemd", "grafana-server.service"),
|
||||||
wrapperFilePath: filepath.Join(grafanaDir, "packaging", "wrappers"),
|
wrapperFilePath: filepath.Join(grafanaDir, "packaging", "wrappers"),
|
||||||
// chkconfig is depended on since our systemd service wraps a SysV init script, and that requires chkconfig
|
depends: []string{"/sbin/service", "fontconfig", "freetype", "urw-fonts"},
|
||||||
depends: []string{"/sbin/service", "chkconfig", "fontconfig", "freetype", "urw-fonts"},
|
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,20 +5,26 @@ import (
|
|||||||
|
|
||||||
ac "github.com/grafana/grafana/pkg/services/accesscontrol"
|
ac "github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||||
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
|
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore/permissions"
|
"github.com/grafana/grafana/pkg/services/sqlstore/permissions"
|
||||||
"github.com/grafana/grafana/pkg/services/user"
|
"github.com/grafana/grafana/pkg/services/user"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewSqlBuilder(cfg *setting.Cfg, dialect migrator.Dialect) SQLBuilder {
|
func NewSqlBuilder(cfg *setting.Cfg, features featuremgmt.FeatureToggles, dialect migrator.Dialect, recursiveQueriesAreSupported bool) SQLBuilder {
|
||||||
return SQLBuilder{cfg: cfg, dialect: dialect}
|
return SQLBuilder{cfg: cfg, features: features, dialect: dialect, recursiveQueriesAreSupported: recursiveQueriesAreSupported}
|
||||||
}
|
}
|
||||||
|
|
||||||
type SQLBuilder struct {
|
type SQLBuilder struct {
|
||||||
cfg *setting.Cfg
|
cfg *setting.Cfg
|
||||||
sql bytes.Buffer
|
features featuremgmt.FeatureToggles
|
||||||
params []interface{}
|
sql bytes.Buffer
|
||||||
|
params []interface{}
|
||||||
|
recQry string
|
||||||
|
recQryParams []interface{}
|
||||||
|
recursiveQueriesAreSupported bool
|
||||||
|
|
||||||
dialect migrator.Dialect
|
dialect migrator.Dialect
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,10 +37,22 @@ func (sb *SQLBuilder) Write(sql string, params ...interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (sb *SQLBuilder) GetSQLString() string {
|
func (sb *SQLBuilder) GetSQLString() string {
|
||||||
return sb.sql.String()
|
if sb.recQry == "" {
|
||||||
|
return sb.sql.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
var bf bytes.Buffer
|
||||||
|
bf.WriteString(sb.recQry)
|
||||||
|
bf.WriteString(sb.sql.String())
|
||||||
|
return bf.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sb *SQLBuilder) GetParams() []interface{} {
|
func (sb *SQLBuilder) GetParams() []interface{} {
|
||||||
|
if len(sb.recQryParams) == 0 {
|
||||||
|
return sb.params
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.params = append(sb.recQryParams, sb.params...)
|
||||||
return sb.params
|
return sb.params
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,11 +62,15 @@ func (sb *SQLBuilder) AddParams(params ...interface{}) {
|
|||||||
|
|
||||||
func (sb *SQLBuilder) WriteDashboardPermissionFilter(user *user.SignedInUser, permission dashboards.PermissionType) {
|
func (sb *SQLBuilder) WriteDashboardPermissionFilter(user *user.SignedInUser, permission dashboards.PermissionType) {
|
||||||
var (
|
var (
|
||||||
sql string
|
sql string
|
||||||
params []interface{}
|
params []interface{}
|
||||||
|
recQry string
|
||||||
|
recQryParams []interface{}
|
||||||
)
|
)
|
||||||
if !ac.IsDisabled(sb.cfg) {
|
if !ac.IsDisabled(sb.cfg) {
|
||||||
sql, params = permissions.NewAccessControlDashboardPermissionFilter(user, permission, "").Where()
|
filterRBAC := permissions.NewAccessControlDashboardPermissionFilter(user, permission, "", sb.features, sb.recursiveQueriesAreSupported)
|
||||||
|
sql, params = filterRBAC.Where()
|
||||||
|
recQry, recQryParams = filterRBAC.With()
|
||||||
} else {
|
} else {
|
||||||
sql, params = permissions.DashboardPermissionFilter{
|
sql, params = permissions.DashboardPermissionFilter{
|
||||||
OrgRole: user.OrgRole,
|
OrgRole: user.OrgRole,
|
||||||
@@ -61,4 +83,6 @@ func (sb *SQLBuilder) WriteDashboardPermissionFilter(user *user.SignedInUser, pe
|
|||||||
|
|
||||||
sb.sql.WriteString(" AND " + sql)
|
sb.sql.WriteString(" AND " + sql)
|
||||||
sb.params = append(sb.params, params...)
|
sb.params = append(sb.params, params...)
|
||||||
|
sb.recQry = recQry
|
||||||
|
sb.recQryParams = recQryParams
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||||
dashver "github.com/grafana/grafana/pkg/services/dashboardversion"
|
dashver "github.com/grafana/grafana/pkg/services/dashboardversion"
|
||||||
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||||
"github.com/grafana/grafana/pkg/services/org"
|
"github.com/grafana/grafana/pkg/services/org"
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||||
"github.com/grafana/grafana/pkg/services/user"
|
"github.com/grafana/grafana/pkg/services/user"
|
||||||
@@ -24,6 +25,7 @@ func TestIntegrationSQLBuilder(t *testing.T) {
|
|||||||
if testing.Short() {
|
if testing.Short() {
|
||||||
t.Skip("skipping integration test")
|
t.Skip("skipping integration test")
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Run("WriteDashboardPermissionFilter", func(t *testing.T) {
|
t.Run("WriteDashboardPermissionFilter", func(t *testing.T) {
|
||||||
t.Run("user ACL", func(t *testing.T) {
|
t.Run("user ACL", func(t *testing.T) {
|
||||||
test(t,
|
test(t,
|
||||||
@@ -31,6 +33,7 @@ func TestIntegrationSQLBuilder(t *testing.T) {
|
|||||||
&DashboardPermission{User: true, Permission: dashboards.PERMISSION_VIEW},
|
&DashboardPermission{User: true, Permission: dashboards.PERMISSION_VIEW},
|
||||||
Search{UserFromACL: true, RequiredPermission: dashboards.PERMISSION_VIEW},
|
Search{UserFromACL: true, RequiredPermission: dashboards.PERMISSION_VIEW},
|
||||||
shouldFind,
|
shouldFind,
|
||||||
|
featuremgmt.WithFeatures(),
|
||||||
)
|
)
|
||||||
|
|
||||||
test(t,
|
test(t,
|
||||||
@@ -38,6 +41,7 @@ func TestIntegrationSQLBuilder(t *testing.T) {
|
|||||||
&DashboardPermission{User: true, Permission: dashboards.PERMISSION_VIEW},
|
&DashboardPermission{User: true, Permission: dashboards.PERMISSION_VIEW},
|
||||||
Search{UserFromACL: true, RequiredPermission: dashboards.PERMISSION_EDIT},
|
Search{UserFromACL: true, RequiredPermission: dashboards.PERMISSION_EDIT},
|
||||||
shouldNotFind,
|
shouldNotFind,
|
||||||
|
featuremgmt.WithFeatures(),
|
||||||
)
|
)
|
||||||
|
|
||||||
test(t,
|
test(t,
|
||||||
@@ -45,6 +49,7 @@ func TestIntegrationSQLBuilder(t *testing.T) {
|
|||||||
&DashboardPermission{User: true, Permission: dashboards.PERMISSION_EDIT},
|
&DashboardPermission{User: true, Permission: dashboards.PERMISSION_EDIT},
|
||||||
Search{UserFromACL: true, RequiredPermission: dashboards.PERMISSION_EDIT},
|
Search{UserFromACL: true, RequiredPermission: dashboards.PERMISSION_EDIT},
|
||||||
shouldFind,
|
shouldFind,
|
||||||
|
featuremgmt.WithFeatures(),
|
||||||
)
|
)
|
||||||
|
|
||||||
test(t,
|
test(t,
|
||||||
@@ -52,6 +57,41 @@ func TestIntegrationSQLBuilder(t *testing.T) {
|
|||||||
&DashboardPermission{User: true, Permission: dashboards.PERMISSION_VIEW},
|
&DashboardPermission{User: true, Permission: dashboards.PERMISSION_VIEW},
|
||||||
Search{RequiredPermission: dashboards.PERMISSION_VIEW},
|
Search{RequiredPermission: dashboards.PERMISSION_VIEW},
|
||||||
shouldNotFind,
|
shouldNotFind,
|
||||||
|
featuremgmt.WithFeatures(),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("user ACL with nested folders", func(t *testing.T) {
|
||||||
|
test(t,
|
||||||
|
DashboardProps{},
|
||||||
|
&DashboardPermission{User: true, Permission: dashboards.PERMISSION_VIEW},
|
||||||
|
Search{UserFromACL: true, RequiredPermission: dashboards.PERMISSION_VIEW},
|
||||||
|
shouldFind,
|
||||||
|
featuremgmt.WithFeatures(featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)),
|
||||||
|
)
|
||||||
|
|
||||||
|
test(t,
|
||||||
|
DashboardProps{},
|
||||||
|
&DashboardPermission{User: true, Permission: dashboards.PERMISSION_VIEW},
|
||||||
|
Search{UserFromACL: true, RequiredPermission: dashboards.PERMISSION_EDIT},
|
||||||
|
shouldNotFind,
|
||||||
|
featuremgmt.WithFeatures(featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)),
|
||||||
|
)
|
||||||
|
|
||||||
|
test(t,
|
||||||
|
DashboardProps{},
|
||||||
|
&DashboardPermission{User: true, Permission: dashboards.PERMISSION_EDIT},
|
||||||
|
Search{UserFromACL: true, RequiredPermission: dashboards.PERMISSION_EDIT},
|
||||||
|
shouldFind,
|
||||||
|
featuremgmt.WithFeatures(featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)),
|
||||||
|
)
|
||||||
|
|
||||||
|
test(t,
|
||||||
|
DashboardProps{},
|
||||||
|
&DashboardPermission{User: true, Permission: dashboards.PERMISSION_VIEW},
|
||||||
|
Search{RequiredPermission: dashboards.PERMISSION_VIEW},
|
||||||
|
shouldNotFind,
|
||||||
|
featuremgmt.WithFeatures(featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -61,6 +101,7 @@ func TestIntegrationSQLBuilder(t *testing.T) {
|
|||||||
&DashboardPermission{Role: org.RoleViewer, Permission: dashboards.PERMISSION_VIEW},
|
&DashboardPermission{Role: org.RoleViewer, Permission: dashboards.PERMISSION_VIEW},
|
||||||
Search{UsersOrgRole: org.RoleViewer, RequiredPermission: dashboards.PERMISSION_VIEW},
|
Search{UsersOrgRole: org.RoleViewer, RequiredPermission: dashboards.PERMISSION_VIEW},
|
||||||
shouldFind,
|
shouldFind,
|
||||||
|
featuremgmt.WithFeatures(),
|
||||||
)
|
)
|
||||||
|
|
||||||
test(t,
|
test(t,
|
||||||
@@ -68,6 +109,7 @@ func TestIntegrationSQLBuilder(t *testing.T) {
|
|||||||
&DashboardPermission{Role: org.RoleViewer, Permission: dashboards.PERMISSION_VIEW},
|
&DashboardPermission{Role: org.RoleViewer, Permission: dashboards.PERMISSION_VIEW},
|
||||||
Search{UsersOrgRole: org.RoleViewer, RequiredPermission: dashboards.PERMISSION_EDIT},
|
Search{UsersOrgRole: org.RoleViewer, RequiredPermission: dashboards.PERMISSION_EDIT},
|
||||||
shouldNotFind,
|
shouldNotFind,
|
||||||
|
featuremgmt.WithFeatures(),
|
||||||
)
|
)
|
||||||
|
|
||||||
test(t,
|
test(t,
|
||||||
@@ -75,6 +117,7 @@ func TestIntegrationSQLBuilder(t *testing.T) {
|
|||||||
&DashboardPermission{Role: org.RoleEditor, Permission: dashboards.PERMISSION_VIEW},
|
&DashboardPermission{Role: org.RoleEditor, Permission: dashboards.PERMISSION_VIEW},
|
||||||
Search{UsersOrgRole: org.RoleViewer, RequiredPermission: dashboards.PERMISSION_VIEW},
|
Search{UsersOrgRole: org.RoleViewer, RequiredPermission: dashboards.PERMISSION_VIEW},
|
||||||
shouldNotFind,
|
shouldNotFind,
|
||||||
|
featuremgmt.WithFeatures(),
|
||||||
)
|
)
|
||||||
|
|
||||||
test(t,
|
test(t,
|
||||||
@@ -82,6 +125,41 @@ func TestIntegrationSQLBuilder(t *testing.T) {
|
|||||||
&DashboardPermission{Role: org.RoleEditor, Permission: dashboards.PERMISSION_VIEW},
|
&DashboardPermission{Role: org.RoleEditor, Permission: dashboards.PERMISSION_VIEW},
|
||||||
Search{UsersOrgRole: org.RoleViewer, RequiredPermission: dashboards.PERMISSION_VIEW},
|
Search{UsersOrgRole: org.RoleViewer, RequiredPermission: dashboards.PERMISSION_VIEW},
|
||||||
shouldNotFind,
|
shouldNotFind,
|
||||||
|
featuremgmt.WithFeatures(),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("role ACL with nested folders", func(t *testing.T) {
|
||||||
|
test(t,
|
||||||
|
DashboardProps{},
|
||||||
|
&DashboardPermission{Role: org.RoleViewer, Permission: dashboards.PERMISSION_VIEW},
|
||||||
|
Search{UsersOrgRole: org.RoleViewer, RequiredPermission: dashboards.PERMISSION_VIEW},
|
||||||
|
shouldFind,
|
||||||
|
featuremgmt.WithFeatures(featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)),
|
||||||
|
)
|
||||||
|
|
||||||
|
test(t,
|
||||||
|
DashboardProps{},
|
||||||
|
&DashboardPermission{Role: org.RoleViewer, Permission: dashboards.PERMISSION_VIEW},
|
||||||
|
Search{UsersOrgRole: org.RoleViewer, RequiredPermission: dashboards.PERMISSION_EDIT},
|
||||||
|
shouldNotFind,
|
||||||
|
featuremgmt.WithFeatures(featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)),
|
||||||
|
)
|
||||||
|
|
||||||
|
test(t,
|
||||||
|
DashboardProps{},
|
||||||
|
&DashboardPermission{Role: org.RoleEditor, Permission: dashboards.PERMISSION_VIEW},
|
||||||
|
Search{UsersOrgRole: org.RoleViewer, RequiredPermission: dashboards.PERMISSION_VIEW},
|
||||||
|
shouldNotFind,
|
||||||
|
featuremgmt.WithFeatures(featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)),
|
||||||
|
)
|
||||||
|
|
||||||
|
test(t,
|
||||||
|
DashboardProps{},
|
||||||
|
&DashboardPermission{Role: org.RoleEditor, Permission: dashboards.PERMISSION_VIEW},
|
||||||
|
Search{UsersOrgRole: org.RoleViewer, RequiredPermission: dashboards.PERMISSION_VIEW},
|
||||||
|
shouldNotFind,
|
||||||
|
featuremgmt.WithFeatures(featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -91,6 +169,7 @@ func TestIntegrationSQLBuilder(t *testing.T) {
|
|||||||
&DashboardPermission{Team: true, Permission: dashboards.PERMISSION_VIEW},
|
&DashboardPermission{Team: true, Permission: dashboards.PERMISSION_VIEW},
|
||||||
Search{UserFromACL: true, RequiredPermission: dashboards.PERMISSION_VIEW},
|
Search{UserFromACL: true, RequiredPermission: dashboards.PERMISSION_VIEW},
|
||||||
shouldFind,
|
shouldFind,
|
||||||
|
featuremgmt.WithFeatures(),
|
||||||
)
|
)
|
||||||
|
|
||||||
test(t,
|
test(t,
|
||||||
@@ -98,6 +177,7 @@ func TestIntegrationSQLBuilder(t *testing.T) {
|
|||||||
&DashboardPermission{Team: true, Permission: dashboards.PERMISSION_VIEW},
|
&DashboardPermission{Team: true, Permission: dashboards.PERMISSION_VIEW},
|
||||||
Search{UserFromACL: true, RequiredPermission: dashboards.PERMISSION_EDIT},
|
Search{UserFromACL: true, RequiredPermission: dashboards.PERMISSION_EDIT},
|
||||||
shouldNotFind,
|
shouldNotFind,
|
||||||
|
featuremgmt.WithFeatures(),
|
||||||
)
|
)
|
||||||
|
|
||||||
test(t,
|
test(t,
|
||||||
@@ -105,6 +185,7 @@ func TestIntegrationSQLBuilder(t *testing.T) {
|
|||||||
&DashboardPermission{Team: true, Permission: dashboards.PERMISSION_EDIT},
|
&DashboardPermission{Team: true, Permission: dashboards.PERMISSION_EDIT},
|
||||||
Search{UserFromACL: true, RequiredPermission: dashboards.PERMISSION_EDIT},
|
Search{UserFromACL: true, RequiredPermission: dashboards.PERMISSION_EDIT},
|
||||||
shouldFind,
|
shouldFind,
|
||||||
|
featuremgmt.WithFeatures(),
|
||||||
)
|
)
|
||||||
|
|
||||||
test(t,
|
test(t,
|
||||||
@@ -112,6 +193,41 @@ func TestIntegrationSQLBuilder(t *testing.T) {
|
|||||||
&DashboardPermission{Team: true, Permission: dashboards.PERMISSION_EDIT},
|
&DashboardPermission{Team: true, Permission: dashboards.PERMISSION_EDIT},
|
||||||
Search{UserFromACL: false, RequiredPermission: dashboards.PERMISSION_EDIT},
|
Search{UserFromACL: false, RequiredPermission: dashboards.PERMISSION_EDIT},
|
||||||
shouldNotFind,
|
shouldNotFind,
|
||||||
|
featuremgmt.WithFeatures(),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("team ACL with nested folders", func(t *testing.T) {
|
||||||
|
test(t,
|
||||||
|
DashboardProps{},
|
||||||
|
&DashboardPermission{Team: true, Permission: dashboards.PERMISSION_VIEW},
|
||||||
|
Search{UserFromACL: true, RequiredPermission: dashboards.PERMISSION_VIEW},
|
||||||
|
shouldFind,
|
||||||
|
featuremgmt.WithFeatures(featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)),
|
||||||
|
)
|
||||||
|
|
||||||
|
test(t,
|
||||||
|
DashboardProps{},
|
||||||
|
&DashboardPermission{Team: true, Permission: dashboards.PERMISSION_VIEW},
|
||||||
|
Search{UserFromACL: true, RequiredPermission: dashboards.PERMISSION_EDIT},
|
||||||
|
shouldNotFind,
|
||||||
|
featuremgmt.WithFeatures(featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)),
|
||||||
|
)
|
||||||
|
|
||||||
|
test(t,
|
||||||
|
DashboardProps{},
|
||||||
|
&DashboardPermission{Team: true, Permission: dashboards.PERMISSION_EDIT},
|
||||||
|
Search{UserFromACL: true, RequiredPermission: dashboards.PERMISSION_EDIT},
|
||||||
|
shouldFind,
|
||||||
|
featuremgmt.WithFeatures(featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)),
|
||||||
|
)
|
||||||
|
|
||||||
|
test(t,
|
||||||
|
DashboardProps{},
|
||||||
|
&DashboardPermission{Team: true, Permission: dashboards.PERMISSION_EDIT},
|
||||||
|
Search{UserFromACL: false, RequiredPermission: dashboards.PERMISSION_EDIT},
|
||||||
|
shouldNotFind,
|
||||||
|
featuremgmt.WithFeatures(featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -121,6 +237,7 @@ func TestIntegrationSQLBuilder(t *testing.T) {
|
|||||||
nil,
|
nil,
|
||||||
Search{OrgId: -1, UsersOrgRole: org.RoleViewer, RequiredPermission: dashboards.PERMISSION_VIEW},
|
Search{OrgId: -1, UsersOrgRole: org.RoleViewer, RequiredPermission: dashboards.PERMISSION_VIEW},
|
||||||
shouldNotFind,
|
shouldNotFind,
|
||||||
|
featuremgmt.WithFeatures(),
|
||||||
)
|
)
|
||||||
|
|
||||||
test(t,
|
test(t,
|
||||||
@@ -128,6 +245,7 @@ func TestIntegrationSQLBuilder(t *testing.T) {
|
|||||||
nil,
|
nil,
|
||||||
Search{OrgId: -1, UsersOrgRole: org.RoleViewer, RequiredPermission: dashboards.PERMISSION_VIEW},
|
Search{OrgId: -1, UsersOrgRole: org.RoleViewer, RequiredPermission: dashboards.PERMISSION_VIEW},
|
||||||
shouldFind,
|
shouldFind,
|
||||||
|
featuremgmt.WithFeatures(),
|
||||||
)
|
)
|
||||||
|
|
||||||
test(t,
|
test(t,
|
||||||
@@ -135,6 +253,7 @@ func TestIntegrationSQLBuilder(t *testing.T) {
|
|||||||
nil,
|
nil,
|
||||||
Search{OrgId: -1, UsersOrgRole: org.RoleEditor, RequiredPermission: dashboards.PERMISSION_EDIT},
|
Search{OrgId: -1, UsersOrgRole: org.RoleEditor, RequiredPermission: dashboards.PERMISSION_EDIT},
|
||||||
shouldFind,
|
shouldFind,
|
||||||
|
featuremgmt.WithFeatures(),
|
||||||
)
|
)
|
||||||
|
|
||||||
test(t,
|
test(t,
|
||||||
@@ -142,6 +261,41 @@ func TestIntegrationSQLBuilder(t *testing.T) {
|
|||||||
nil,
|
nil,
|
||||||
Search{OrgId: -1, UsersOrgRole: org.RoleViewer, RequiredPermission: dashboards.PERMISSION_EDIT},
|
Search{OrgId: -1, UsersOrgRole: org.RoleViewer, RequiredPermission: dashboards.PERMISSION_EDIT},
|
||||||
shouldNotFind,
|
shouldNotFind,
|
||||||
|
featuremgmt.WithFeatures(),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("defaults for user ACL with nested folders", func(t *testing.T) {
|
||||||
|
test(t,
|
||||||
|
DashboardProps{},
|
||||||
|
nil,
|
||||||
|
Search{OrgId: -1, UsersOrgRole: org.RoleViewer, RequiredPermission: dashboards.PERMISSION_VIEW},
|
||||||
|
shouldNotFind,
|
||||||
|
featuremgmt.WithFeatures(featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)),
|
||||||
|
)
|
||||||
|
|
||||||
|
test(t,
|
||||||
|
DashboardProps{OrgId: -1},
|
||||||
|
nil,
|
||||||
|
Search{OrgId: -1, UsersOrgRole: org.RoleViewer, RequiredPermission: dashboards.PERMISSION_VIEW},
|
||||||
|
shouldFind,
|
||||||
|
featuremgmt.WithFeatures(featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)),
|
||||||
|
)
|
||||||
|
|
||||||
|
test(t,
|
||||||
|
DashboardProps{OrgId: -1},
|
||||||
|
nil,
|
||||||
|
Search{OrgId: -1, UsersOrgRole: org.RoleEditor, RequiredPermission: dashboards.PERMISSION_EDIT},
|
||||||
|
shouldFind,
|
||||||
|
featuremgmt.WithFeatures(featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)),
|
||||||
|
)
|
||||||
|
|
||||||
|
test(t,
|
||||||
|
DashboardProps{OrgId: -1},
|
||||||
|
nil,
|
||||||
|
Search{OrgId: -1, UsersOrgRole: org.RoleViewer, RequiredPermission: dashboards.PERMISSION_EDIT},
|
||||||
|
shouldNotFind,
|
||||||
|
featuremgmt.WithFeatures(featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -172,7 +326,7 @@ type dashboardResponse struct {
|
|||||||
Id int64
|
Id int64
|
||||||
}
|
}
|
||||||
|
|
||||||
func test(t *testing.T, dashboardProps DashboardProps, dashboardPermission *DashboardPermission, search Search, shouldFind bool) {
|
func test(t *testing.T, dashboardProps DashboardProps, dashboardPermission *DashboardPermission, search Search, shouldFind bool, features featuremgmt.FeatureToggles) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
t.Run("", func(t *testing.T) {
|
t.Run("", func(t *testing.T) {
|
||||||
@@ -186,7 +340,7 @@ func test(t *testing.T, dashboardProps DashboardProps, dashboardPermission *Dash
|
|||||||
aclUserID = createDummyACL(t, sqlStore, dashboardPermission, search, dashboard.ID)
|
aclUserID = createDummyACL(t, sqlStore, dashboardPermission, search, dashboard.ID)
|
||||||
t.Logf("Created ACL with user ID %d\n", aclUserID)
|
t.Logf("Created ACL with user ID %d\n", aclUserID)
|
||||||
}
|
}
|
||||||
dashboards := getDashboards(t, sqlStore, search, aclUserID)
|
dashboards := getDashboards(t, sqlStore, search, aclUserID, features)
|
||||||
|
|
||||||
if shouldFind {
|
if shouldFind {
|
||||||
require.Len(t, dashboards, 1, "Should return one dashboard")
|
require.Len(t, dashboards, 1, "Should return one dashboard")
|
||||||
@@ -292,7 +446,7 @@ func createDummyACL(t *testing.T, sqlStore *sqlstore.SQLStore, dashboardPermissi
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func getDashboards(t *testing.T, sqlStore *sqlstore.SQLStore, search Search, aclUserID int64) []*dashboardResponse {
|
func getDashboards(t *testing.T, sqlStore *sqlstore.SQLStore, search Search, aclUserID int64, features featuremgmt.FeatureToggles) []*dashboardResponse {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
old := sqlStore.Cfg.RBACEnabled
|
old := sqlStore.Cfg.RBACEnabled
|
||||||
@@ -301,7 +455,10 @@ func getDashboards(t *testing.T, sqlStore *sqlstore.SQLStore, search Search, acl
|
|||||||
sqlStore.Cfg.RBACEnabled = old
|
sqlStore.Cfg.RBACEnabled = old
|
||||||
}()
|
}()
|
||||||
|
|
||||||
builder := NewSqlBuilder(sqlStore.Cfg, sqlStore.GetDialect())
|
recursiveQueriesAreSupported, err := sqlStore.RecursiveQueriesAreSupported()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
builder := NewSqlBuilder(sqlStore.Cfg, features, sqlStore.GetDialect(), recursiveQueriesAreSupported)
|
||||||
signedInUser := &user.SignedInUser{
|
signedInUser := &user.SignedInUser{
|
||||||
UserID: 9999999999,
|
UserID: 9999999999,
|
||||||
}
|
}
|
||||||
@@ -325,7 +482,7 @@ func getDashboards(t *testing.T, sqlStore *sqlstore.SQLStore, search Search, acl
|
|||||||
builder.Write("SELECT * FROM dashboard WHERE true")
|
builder.Write("SELECT * FROM dashboard WHERE true")
|
||||||
builder.WriteDashboardPermissionFilter(signedInUser, search.RequiredPermission)
|
builder.WriteDashboardPermissionFilter(signedInUser, search.RequiredPermission)
|
||||||
t.Logf("Searching for dashboards, SQL: %q\n", builder.GetSQLString())
|
t.Logf("Searching for dashboards, SQL: %q\n", builder.GetSQLString())
|
||||||
err := sqlStore.GetEngine().SQL(builder.GetSQLString(), builder.params...).Find(&res)
|
err = sqlStore.GetEngine().SQL(builder.GetSQLString(), builder.params...).Find(&res)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,23 @@
|
|||||||
//go:build memcached
|
|
||||||
// +build memcached
|
|
||||||
|
|
||||||
package remotecache
|
package remotecache
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMemcachedCacheStorage(t *testing.T) {
|
func TestIntegrationMemcachedCacheStorage(t *testing.T) {
|
||||||
opts := &setting.RemoteCacheOptions{Name: memcachedCacheType, ConnStr: "localhost:11211"}
|
if testing.Short() {
|
||||||
|
t.Skip("skipping integration test")
|
||||||
|
}
|
||||||
|
|
||||||
|
u, ok := os.LookupEnv("MEMCACHED_HOSTS")
|
||||||
|
if !ok || u == "" {
|
||||||
|
t.Skip("No Memcached hosts provided")
|
||||||
|
}
|
||||||
|
|
||||||
|
opts := &setting.RemoteCacheOptions{Name: memcachedCacheType, ConnStr: u}
|
||||||
client := createTestClient(t, opts, nil)
|
client := createTestClient(t, opts, nil)
|
||||||
runTestsForClient(t, client)
|
runTestsForClient(t, client)
|
||||||
runCountTestsForClient(t, opts, nil)
|
runCountTestsForClient(t, opts, nil)
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user