Compare commits
71 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6ff9d522bc | |||
| 9eb5be78f9 | |||
| 667be498d5 | |||
| ee196f42d3 | |||
| 7dd079b72e | |||
| b5655a0c20 | |||
| 9deb30d88f | |||
| 4e6892bac8 | |||
| 05fd304dbd | |||
| 1850163346 | |||
| 26ce2c09d7 | |||
| 051cdaad0d | |||
| 1862e5dac5 | |||
| b123e24d86 | |||
| 19f6dbe1bb | |||
| facb25a09c | |||
| d0792ebe97 | |||
| 98aa6c50dc | |||
| a65aa9d18f | |||
| 58a026b6a5 | |||
| 7e5eb46bea | |||
| 4bcd31b17a | |||
| c7af2be682 | |||
| 2c9b7ca135 | |||
| 5a1ae834e0 | |||
| 36bc5535f4 | |||
| 46510e72f3 | |||
| 7d2475454c | |||
| 50fa37af53 | |||
| 2d72990c17 | |||
| 9c1df45589 | |||
| b815680a6b | |||
| 32a63c0cf0 | |||
| c4455f71da | |||
| 81bff1a39e | |||
| 9635f8ba4e | |||
| 206bc6c4d9 | |||
| dfc5a07259 | |||
| a8ff242a3f | |||
| 6042dfef89 | |||
| 0b89c821ad | |||
| 942ed4b4e8 | |||
| a8325b1e87 | |||
| ca1a431cc8 | |||
| ed59edd88e | |||
| e21ca340be | |||
| bf40fbe064 | |||
| e3bced33a7 | |||
| 77138f640a | |||
| b300bd8b85 | |||
| 59ec3cc8a9 | |||
| 23e6c3301b | |||
| 87521b0348 | |||
| 0281ef1fed | |||
| f389a1aee2 | |||
| bbb770a325 | |||
| d52aea6d32 | |||
| 3f1a2833a8 | |||
| aa87720f4a | |||
| 0428d4d745 | |||
| c9387d0f44 | |||
| 1967134c45 | |||
| 1424016863 | |||
| 5b229a80d3 | |||
| a5a9294784 | |||
| 31e3a97ef2 | |||
| 599b624fe9 | |||
| 76729fa866 | |||
| 1e0456da13 | |||
| adeb6e42b7 | |||
| 33a27eaa4d |
+3
-9
@@ -300,15 +300,9 @@
|
||||
"y": 0
|
||||
},
|
||||
"id": 6,
|
||||
"options": {
|
||||
"code": {
|
||||
"language": "plaintext",
|
||||
"showLineNumbers": false,
|
||||
"showMiniMap": false
|
||||
},
|
||||
"content": "# Graph panel \u003e\u003e Timeseries panel\n\nKnown issues:\n* hiding null/empty series\n* time regions",
|
||||
"mode": "markdown"
|
||||
},
|
||||
"options": {},
|
||||
"content": "# Graph panel \u003e\u003e Timeseries panel\n\nKnown issues:\n* hiding null/empty series\n* time regions",
|
||||
"mode": "markdown",
|
||||
"pluginVersion": "11.0.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
|
||||
+31
-140
@@ -71,12 +71,11 @@
|
||||
"id": 1,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidthFactor": 0.4,
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"rounded": true,
|
||||
"spotlight": false,
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
@@ -150,12 +149,11 @@
|
||||
"id": 4,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidthFactor": 0.4,
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": true,
|
||||
"rounded": true,
|
||||
"spotlight": false,
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
@@ -229,12 +227,11 @@
|
||||
"id": 3,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidthFactor": 0.4,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"rounded": true,
|
||||
"spotlight": false,
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
@@ -271,85 +268,6 @@
|
||||
"title": "Center and bar glow",
|
||||
"type": "radialbar"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "grafana-testdata-datasource"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "thresholds"
|
||||
},
|
||||
"mappings": [],
|
||||
"max": 100,
|
||||
"min": 0,
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 6,
|
||||
"w": 4,
|
||||
"x": 12,
|
||||
"y": 1
|
||||
},
|
||||
"id": 5,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barWidthFactor": 0.4,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"rounded": true,
|
||||
"spotlight": true,
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"lastNotNull"
|
||||
],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"segmentCount": 1,
|
||||
"segmentSpacing": 0.3,
|
||||
"shape": "circle",
|
||||
"showThresholdLabels": false,
|
||||
"showThresholdMarkers": false,
|
||||
"sparkline": false
|
||||
},
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"alias": "1",
|
||||
"datasource": {
|
||||
"type": "grafana-testdata-datasource"
|
||||
},
|
||||
"max": 100,
|
||||
"min": 1,
|
||||
"noise": 22,
|
||||
"refId": "A",
|
||||
"scenarioId": "random_walk",
|
||||
"spread": 22,
|
||||
"startValue": 1
|
||||
}
|
||||
],
|
||||
"title": "Spotlight",
|
||||
"type": "radialbar"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "grafana-testdata-datasource"
|
||||
@@ -391,10 +309,9 @@
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"rounded": true,
|
||||
"spotlight": true,
|
||||
"gradient": false
|
||||
},
|
||||
"barShape": "rounded",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -470,10 +387,9 @@
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"rounded": false,
|
||||
"spotlight": true,
|
||||
"gradient": false
|
||||
},
|
||||
"barShape": "flat",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -549,10 +465,9 @@
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"rounded": false,
|
||||
"spotlight": true,
|
||||
"gradient": false
|
||||
},
|
||||
"barShape": "flat",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -641,10 +556,9 @@
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"rounded": true,
|
||||
"spotlight": true,
|
||||
"gradient": false
|
||||
},
|
||||
"barShape": "rounded",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -720,10 +634,9 @@
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"rounded": true,
|
||||
"spotlight": true,
|
||||
"gradient": false
|
||||
},
|
||||
"barShape": "rounded",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -799,10 +712,9 @@
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"rounded": true,
|
||||
"spotlight": true,
|
||||
"gradient": false
|
||||
},
|
||||
"barShape": "rounded",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -878,10 +790,9 @@
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"rounded": true,
|
||||
"spotlight": true,
|
||||
"gradient": false
|
||||
},
|
||||
"barShape": "rounded",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -974,10 +885,9 @@
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"rounded": false,
|
||||
"spotlight": false,
|
||||
"gradient": false
|
||||
},
|
||||
"barShape": "flat",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -1053,10 +963,9 @@
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"rounded": false,
|
||||
"spotlight": false,
|
||||
"gradient": false
|
||||
},
|
||||
"barShape": "flat",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -1132,10 +1041,9 @@
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"rounded": false,
|
||||
"spotlight": false,
|
||||
"gradient": true
|
||||
},
|
||||
"barShape": "flat",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -1211,10 +1119,9 @@
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"rounded": false,
|
||||
"spotlight": false,
|
||||
"gradient": false
|
||||
},
|
||||
"barShape": "flat",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -1290,10 +1197,9 @@
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"rounded": false,
|
||||
"spotlight": false,
|
||||
"gradient": false
|
||||
},
|
||||
"barShape": "flat",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -1386,10 +1292,9 @@
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"rounded": false,
|
||||
"spotlight": false,
|
||||
"gradient": true
|
||||
},
|
||||
"barShape": "flat",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -1469,10 +1374,9 @@
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"rounded": false,
|
||||
"spotlight": false,
|
||||
"gradient": true
|
||||
},
|
||||
"barShape": "flat",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -1552,10 +1456,9 @@
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"rounded": false,
|
||||
"spotlight": false,
|
||||
"gradient": true
|
||||
},
|
||||
"barShape": "flat",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -1641,13 +1544,13 @@
|
||||
"options": {
|
||||
"barWidth": 12,
|
||||
"barWidthFactor": 0.4,
|
||||
"barShape": "rounded",
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"rounded": true,
|
||||
"spotlight": true,
|
||||
"gradient": true
|
||||
},
|
||||
"endpointMarker": "glow",
|
||||
"glow": "both",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -1662,8 +1565,7 @@
|
||||
"shape": "circle",
|
||||
"showThresholdLabels": false,
|
||||
"showThresholdMarkers": false,
|
||||
"sparkline": false,
|
||||
"spotlight": true
|
||||
"sparkline": false
|
||||
},
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"targets": [
|
||||
@@ -1730,10 +1632,9 @@
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"rounded": true,
|
||||
"spotlight": true,
|
||||
"gradient": true
|
||||
},
|
||||
"barShape": "rounded",
|
||||
"glow": "both",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -1748,8 +1649,7 @@
|
||||
"shape": "gauge",
|
||||
"showThresholdLabels": false,
|
||||
"showThresholdMarkers": false,
|
||||
"sparkline": true,
|
||||
"spotlight": true
|
||||
"sparkline": true
|
||||
},
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"targets": [
|
||||
@@ -1830,10 +1730,9 @@
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"rounded": true,
|
||||
"spotlight": true,
|
||||
"gradient": true
|
||||
},
|
||||
"barShape": "rounded",
|
||||
"glow": "both",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -1848,8 +1747,7 @@
|
||||
"shape": "circle",
|
||||
"showThresholdLabels": false,
|
||||
"showThresholdMarkers": false,
|
||||
"sparkline": false,
|
||||
"spotlight": true
|
||||
"sparkline": false
|
||||
},
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"targets": [
|
||||
@@ -1917,9 +1815,6 @@
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"rounded": true,
|
||||
"sparkline": false,
|
||||
"spotlight": true,
|
||||
"gradient": true
|
||||
},
|
||||
"glow": "both",
|
||||
@@ -1934,10 +1829,10 @@
|
||||
"segmentCount": 12,
|
||||
"segmentSpacing": 0.3,
|
||||
"shape": "circle",
|
||||
"barShape": "rounded",
|
||||
"showThresholdLabels": false,
|
||||
"showThresholdMarkers": false,
|
||||
"sparkline": false,
|
||||
"spotlight": true
|
||||
"sparkline": false
|
||||
},
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"targets": [
|
||||
@@ -2004,10 +1899,9 @@
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"rounded": true,
|
||||
"spotlight": true,
|
||||
"gradient": true
|
||||
},
|
||||
"barShape": "rounded",
|
||||
"glow": "both",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -2022,8 +1916,7 @@
|
||||
"shape": "circle",
|
||||
"showThresholdLabels": false,
|
||||
"showThresholdMarkers": false,
|
||||
"sparkline": false,
|
||||
"spotlight": true
|
||||
"sparkline": false
|
||||
},
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"targets": [
|
||||
@@ -2090,10 +1983,9 @@
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"rounded": true,
|
||||
"spotlight": true,
|
||||
"gradient": true
|
||||
},
|
||||
"barShape": "rounded",
|
||||
"glow": "both",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -2108,8 +2000,7 @@
|
||||
"shape": "circle",
|
||||
"showThresholdLabels": false,
|
||||
"showThresholdMarkers": false,
|
||||
"sparkline": false,
|
||||
"spotlight": true
|
||||
"sparkline": false
|
||||
},
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"targets": [
|
||||
|
||||
-2
@@ -955,8 +955,6 @@
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"rounded": false,
|
||||
"spotlight": false,
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
|
||||
+8
-1
@@ -115,7 +115,14 @@
|
||||
"kind": "logs",
|
||||
"spec": {
|
||||
"pluginVersion": "",
|
||||
"options": {},
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "logs",
|
||||
"originalOptions": {
|
||||
"height": 100
|
||||
}
|
||||
}
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
|
||||
+8
-1
@@ -120,7 +120,14 @@
|
||||
"group": "logs",
|
||||
"version": "",
|
||||
"spec": {
|
||||
"options": {},
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "logs",
|
||||
"originalOptions": {
|
||||
"height": 100
|
||||
}
|
||||
}
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
|
||||
+14
-1
@@ -182,7 +182,20 @@
|
||||
"kind": "table",
|
||||
"spec": {
|
||||
"pluginVersion": "",
|
||||
"options": {},
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "table",
|
||||
"originalOptions": {
|
||||
"grid": {
|
||||
"max": 100,
|
||||
"min": 0
|
||||
},
|
||||
"legend": true,
|
||||
"y2_format": "bytes",
|
||||
"y_format": "short"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
|
||||
+14
-1
@@ -189,7 +189,20 @@
|
||||
"group": "table",
|
||||
"version": "",
|
||||
"spec": {
|
||||
"options": {},
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "table",
|
||||
"originalOptions": {
|
||||
"grid": {
|
||||
"max": 100,
|
||||
"min": 0
|
||||
},
|
||||
"legend": true,
|
||||
"y2_format": "bytes",
|
||||
"y_format": "short"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
|
||||
+23
-1
@@ -435,7 +435,29 @@
|
||||
"kind": "table",
|
||||
"spec": {
|
||||
"pluginVersion": "",
|
||||
"options": {},
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "table",
|
||||
"originalOptions": {
|
||||
"styles": [
|
||||
{
|
||||
"colors": [
|
||||
"red",
|
||||
"yellow",
|
||||
"green"
|
||||
],
|
||||
"pattern": "/.*/",
|
||||
"thresholds": [
|
||||
"10",
|
||||
"20"
|
||||
],
|
||||
"unit": "short"
|
||||
}
|
||||
],
|
||||
"table": "table2"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
|
||||
+23
-1
@@ -449,7 +449,29 @@
|
||||
"group": "table",
|
||||
"version": "",
|
||||
"spec": {
|
||||
"options": {},
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "table",
|
||||
"originalOptions": {
|
||||
"styles": [
|
||||
{
|
||||
"colors": [
|
||||
"red",
|
||||
"yellow",
|
||||
"green"
|
||||
],
|
||||
"pattern": "/.*/",
|
||||
"thresholds": [
|
||||
"10",
|
||||
"20"
|
||||
],
|
||||
"unit": "short"
|
||||
}
|
||||
],
|
||||
"table": "table2"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
|
||||
+9
-1
@@ -110,7 +110,15 @@
|
||||
"kind": "text",
|
||||
"spec": {
|
||||
"pluginVersion": "",
|
||||
"options": {},
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "text",
|
||||
"originalOptions": {
|
||||
"content": "# Angular Text Panel\n# $constant\n\nFor markdown syntax help: [commonmark.org/help](https://commonmark.org/help/)\n\n## $text\n\n",
|
||||
"mode": "markdown"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
|
||||
+9
-1
@@ -115,7 +115,15 @@
|
||||
"group": "text",
|
||||
"version": "",
|
||||
"spec": {
|
||||
"options": {},
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "text",
|
||||
"originalOptions": {
|
||||
"content": "# Angular Text Panel\n# $constant\n\nFor markdown syntax help: [commonmark.org/help](https://commonmark.org/help/)\n\n## $text\n\n",
|
||||
"mode": "markdown"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
|
||||
+9
-1
@@ -361,7 +361,15 @@
|
||||
"kind": "text",
|
||||
"spec": {
|
||||
"pluginVersion": "",
|
||||
"options": {},
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "text",
|
||||
"originalOptions": {
|
||||
"content": "## Data link variables overview\n\nThis dashboard presents variables that one can use when creating *data links*. All links redirect to this dashboard and this panel represents the values that were interpolated in the link that was clicked.\n\n\n#### Series variables\n1. **Name:** \u003cspan style=\"color: orange;\"\u003e$seriesName\u003c/span\u003e\n2. **label.datacenter:** \u003cspan style=\"color: orange;\"\u003e$labelDatacenter\u003c/span\u003e\n3. **label.datacenter.region:** \u003cspan style=\"color: orange;\"\u003e$labelDatacenterRegion\u003c/span\u003e\n\n#### Field variables\n1. **Name:** \u003cspan style=\"color: orange;\"\u003e$fieldName\u003c/span\u003e\n\n#### Value variables\n1. **Time:** \u003cspan style=\"color: orange;\"\u003e$valueTime\u003c/span\u003e\n2. **Numeric:** \u003cspan style=\"color: orange;\"\u003e$valueNumeric\u003c/span\u003e\n3. **Text:** \u003cspan style=\"color: orange;\"\u003e$valueText\u003c/span\u003e\n4. **Calc:** \u003cspan style=\"color: orange;\"\u003e$valueCalc\u003c/span\u003e\n\n",
|
||||
"mode": "markdown"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
|
||||
+9
-1
@@ -372,7 +372,15 @@
|
||||
"group": "text",
|
||||
"version": "",
|
||||
"spec": {
|
||||
"options": {},
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "text",
|
||||
"originalOptions": {
|
||||
"content": "## Data link variables overview\n\nThis dashboard presents variables that one can use when creating *data links*. All links redirect to this dashboard and this panel represents the values that were interpolated in the link that was clicked.\n\n\n#### Series variables\n1. **Name:** \u003cspan style=\"color: orange;\"\u003e$seriesName\u003c/span\u003e\n2. **label.datacenter:** \u003cspan style=\"color: orange;\"\u003e$labelDatacenter\u003c/span\u003e\n3. **label.datacenter.region:** \u003cspan style=\"color: orange;\"\u003e$labelDatacenterRegion\u003c/span\u003e\n\n#### Field variables\n1. **Name:** \u003cspan style=\"color: orange;\"\u003e$fieldName\u003c/span\u003e\n\n#### Value variables\n1. **Time:** \u003cspan style=\"color: orange;\"\u003e$valueTime\u003c/span\u003e\n2. **Numeric:** \u003cspan style=\"color: orange;\"\u003e$valueNumeric\u003c/span\u003e\n3. **Text:** \u003cspan style=\"color: orange;\"\u003e$valueText\u003c/span\u003e\n4. **Calc:** \u003cspan style=\"color: orange;\"\u003e$valueCalc\u003c/span\u003e\n\n",
|
||||
"mode": "markdown"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
|
||||
+9
-1
@@ -167,7 +167,15 @@
|
||||
"kind": "text",
|
||||
"spec": {
|
||||
"pluginVersion": "",
|
||||
"options": {},
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "text",
|
||||
"originalOptions": {
|
||||
"content": "## Data center = $datacenter\n\n### server = $server\n\n#### pod = $pod",
|
||||
"mode": "markdown"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
|
||||
+9
-1
@@ -174,7 +174,15 @@
|
||||
"group": "text",
|
||||
"version": "",
|
||||
"spec": {
|
||||
"options": {},
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "text",
|
||||
"originalOptions": {
|
||||
"content": "## Data center = $datacenter\n\n### server = $server\n\n#### pod = $pod",
|
||||
"mode": "markdown"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
|
||||
+9
-1
@@ -273,7 +273,15 @@
|
||||
"kind": "text",
|
||||
"spec": {
|
||||
"pluginVersion": "",
|
||||
"options": {},
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "text",
|
||||
"originalOptions": {
|
||||
"content": "## Data center = $datacenter\n\n### server = $server\n\n#### pod = $pod",
|
||||
"mode": "markdown"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
|
||||
+9
-1
@@ -282,7 +282,15 @@
|
||||
"group": "text",
|
||||
"version": "",
|
||||
"spec": {
|
||||
"options": {},
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "text",
|
||||
"originalOptions": {
|
||||
"content": "## Data center = $datacenter\n\n### server = $server\n\n#### pod = $pod",
|
||||
"mode": "markdown"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
|
||||
+2
-9
@@ -296,6 +296,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"content": "# Graph panel \u003e\u003e Timeseries panel\n\nKnown issues:\n* hiding null/empty series\n* time regions",
|
||||
"datasource": {
|
||||
"type": "grafana-testdata-datasource"
|
||||
},
|
||||
@@ -306,15 +307,7 @@
|
||||
"y": 0
|
||||
},
|
||||
"id": 6,
|
||||
"options": {
|
||||
"code": {
|
||||
"language": "plaintext",
|
||||
"showLineNumbers": false,
|
||||
"showMiniMap": false
|
||||
},
|
||||
"content": "# Graph panel \u003e\u003e Timeseries panel\n\nKnown issues:\n* hiding null/empty series\n* time regions",
|
||||
"mode": "markdown"
|
||||
},
|
||||
"mode": "markdown",
|
||||
"pluginVersion": "11.0.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
|
||||
+7
-7
@@ -1256,13 +1256,13 @@
|
||||
"spec": {
|
||||
"pluginVersion": "11.0.0-pre",
|
||||
"options": {
|
||||
"code": {
|
||||
"language": "plaintext",
|
||||
"showLineNumbers": false,
|
||||
"showMiniMap": false
|
||||
},
|
||||
"content": "# Graph panel \u003e\u003e Timeseries panel\n\nKnown issues:\n* hiding null/empty series\n* time regions",
|
||||
"mode": "markdown"
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "text",
|
||||
"originalOptions": {
|
||||
"content": "# Graph panel \u003e\u003e Timeseries panel\n\nKnown issues:\n* hiding null/empty series\n* time regions",
|
||||
"mode": "markdown"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
|
||||
+7
-7
@@ -1301,13 +1301,13 @@
|
||||
"version": "11.0.0-pre",
|
||||
"spec": {
|
||||
"options": {
|
||||
"code": {
|
||||
"language": "plaintext",
|
||||
"showLineNumbers": false,
|
||||
"showMiniMap": false
|
||||
},
|
||||
"content": "# Graph panel \u003e\u003e Timeseries panel\n\nKnown issues:\n* hiding null/empty series\n* time regions",
|
||||
"mode": "markdown"
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "text",
|
||||
"originalOptions": {
|
||||
"content": "# Graph panel \u003e\u003e Timeseries panel\n\nKnown issues:\n* hiding null/empty series\n* time regions",
|
||||
"mode": "markdown"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
|
||||
+72
@@ -62,6 +62,12 @@
|
||||
"spec": {
|
||||
"pluginVersion": "7.4.0-pre",
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "gauge",
|
||||
"originalOptions": {
|
||||
"nullPointMode": "null"
|
||||
}
|
||||
},
|
||||
"baseColor": "#299c46",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -151,6 +157,12 @@
|
||||
"spec": {
|
||||
"pluginVersion": "7.4.0-pre",
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "gauge",
|
||||
"originalOptions": {
|
||||
"nullPointMode": "null"
|
||||
}
|
||||
},
|
||||
"baseColor": "#299c46",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -241,6 +253,12 @@
|
||||
"spec": {
|
||||
"pluginVersion": "7.4.0-pre",
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "gauge",
|
||||
"originalOptions": {
|
||||
"nullPointMode": "null"
|
||||
}
|
||||
},
|
||||
"baseColor": "#299c46",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -320,6 +338,12 @@
|
||||
"spec": {
|
||||
"pluginVersion": "7.4.0-pre",
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "gauge",
|
||||
"originalOptions": {
|
||||
"nullPointMode": "null"
|
||||
}
|
||||
},
|
||||
"baseColor": "#299c46",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -401,6 +425,12 @@
|
||||
"spec": {
|
||||
"pluginVersion": "7.4.0-pre",
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "gauge",
|
||||
"originalOptions": {
|
||||
"nullPointMode": "null"
|
||||
}
|
||||
},
|
||||
"baseColor": "#299c46",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -480,6 +510,12 @@
|
||||
"spec": {
|
||||
"pluginVersion": "7.4.0-pre",
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "gauge",
|
||||
"originalOptions": {
|
||||
"nullPointMode": "null"
|
||||
}
|
||||
},
|
||||
"baseColor": "#299c46",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -559,6 +595,12 @@
|
||||
"spec": {
|
||||
"pluginVersion": "7.4.0-pre",
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "gauge",
|
||||
"originalOptions": {
|
||||
"nullPointMode": "null"
|
||||
}
|
||||
},
|
||||
"baseColor": "#299c46",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -639,6 +681,12 @@
|
||||
"spec": {
|
||||
"pluginVersion": "7.4.0-pre",
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "gauge",
|
||||
"originalOptions": {
|
||||
"nullPointMode": "null"
|
||||
}
|
||||
},
|
||||
"baseColor": "#299c46",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -730,6 +778,12 @@
|
||||
"spec": {
|
||||
"pluginVersion": "7.4.0-pre",
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "gauge",
|
||||
"originalOptions": {
|
||||
"nullPointMode": "null"
|
||||
}
|
||||
},
|
||||
"baseColor": "#299c46",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -927,6 +981,12 @@
|
||||
"spec": {
|
||||
"pluginVersion": "7.4.0-pre",
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "gauge",
|
||||
"originalOptions": {
|
||||
"nullPointMode": "null"
|
||||
}
|
||||
},
|
||||
"baseColor": "#299c46",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -1006,6 +1066,12 @@
|
||||
"spec": {
|
||||
"pluginVersion": "7.4.0-pre",
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "gauge",
|
||||
"originalOptions": {
|
||||
"nullPointMode": "null"
|
||||
}
|
||||
},
|
||||
"baseColor": "#299c46",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -1085,6 +1151,12 @@
|
||||
"spec": {
|
||||
"pluginVersion": "7.4.0-pre",
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "gauge",
|
||||
"originalOptions": {
|
||||
"nullPointMode": "null"
|
||||
}
|
||||
},
|
||||
"baseColor": "#299c46",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
|
||||
+72
@@ -67,6 +67,12 @@
|
||||
"version": "7.4.0-pre",
|
||||
"spec": {
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "gauge",
|
||||
"originalOptions": {
|
||||
"nullPointMode": "null"
|
||||
}
|
||||
},
|
||||
"baseColor": "#299c46",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -159,6 +165,12 @@
|
||||
"version": "7.4.0-pre",
|
||||
"spec": {
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "gauge",
|
||||
"originalOptions": {
|
||||
"nullPointMode": "null"
|
||||
}
|
||||
},
|
||||
"baseColor": "#299c46",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -252,6 +264,12 @@
|
||||
"version": "7.4.0-pre",
|
||||
"spec": {
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "gauge",
|
||||
"originalOptions": {
|
||||
"nullPointMode": "null"
|
||||
}
|
||||
},
|
||||
"baseColor": "#299c46",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -334,6 +352,12 @@
|
||||
"version": "7.4.0-pre",
|
||||
"spec": {
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "gauge",
|
||||
"originalOptions": {
|
||||
"nullPointMode": "null"
|
||||
}
|
||||
},
|
||||
"baseColor": "#299c46",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -418,6 +442,12 @@
|
||||
"version": "7.4.0-pre",
|
||||
"spec": {
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "gauge",
|
||||
"originalOptions": {
|
||||
"nullPointMode": "null"
|
||||
}
|
||||
},
|
||||
"baseColor": "#299c46",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -500,6 +530,12 @@
|
||||
"version": "7.4.0-pre",
|
||||
"spec": {
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "gauge",
|
||||
"originalOptions": {
|
||||
"nullPointMode": "null"
|
||||
}
|
||||
},
|
||||
"baseColor": "#299c46",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -582,6 +618,12 @@
|
||||
"version": "7.4.0-pre",
|
||||
"spec": {
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "gauge",
|
||||
"originalOptions": {
|
||||
"nullPointMode": "null"
|
||||
}
|
||||
},
|
||||
"baseColor": "#299c46",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -665,6 +707,12 @@
|
||||
"version": "7.4.0-pre",
|
||||
"spec": {
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "gauge",
|
||||
"originalOptions": {
|
||||
"nullPointMode": "null"
|
||||
}
|
||||
},
|
||||
"baseColor": "#299c46",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -759,6 +807,12 @@
|
||||
"version": "7.4.0-pre",
|
||||
"spec": {
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "gauge",
|
||||
"originalOptions": {
|
||||
"nullPointMode": "null"
|
||||
}
|
||||
},
|
||||
"baseColor": "#299c46",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -961,6 +1015,12 @@
|
||||
"version": "7.4.0-pre",
|
||||
"spec": {
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "gauge",
|
||||
"originalOptions": {
|
||||
"nullPointMode": "null"
|
||||
}
|
||||
},
|
||||
"baseColor": "#299c46",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -1043,6 +1103,12 @@
|
||||
"version": "7.4.0-pre",
|
||||
"spec": {
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "gauge",
|
||||
"originalOptions": {
|
||||
"nullPointMode": "null"
|
||||
}
|
||||
},
|
||||
"baseColor": "#299c46",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -1125,6 +1191,12 @@
|
||||
"version": "7.4.0-pre",
|
||||
"spec": {
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "gauge",
|
||||
"originalOptions": {
|
||||
"nullPointMode": "null"
|
||||
}
|
||||
},
|
||||
"baseColor": "#299c46",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
|
||||
+56
-165
@@ -77,13 +77,12 @@
|
||||
"id": 1,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidthFactor": 0.4,
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": false,
|
||||
"rounded": true,
|
||||
"spotlight": false
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -156,13 +155,12 @@
|
||||
"id": 4,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidthFactor": 0.4,
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": true,
|
||||
"gradient": false,
|
||||
"rounded": true,
|
||||
"spotlight": false
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -235,13 +233,12 @@
|
||||
"id": 3,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidthFactor": 0.4,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": false,
|
||||
"rounded": true,
|
||||
"spotlight": false
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -277,85 +274,6 @@
|
||||
"title": "Center and bar glow",
|
||||
"type": "radialbar"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "grafana-testdata-datasource"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "thresholds"
|
||||
},
|
||||
"mappings": [],
|
||||
"max": 100,
|
||||
"min": 0,
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 6,
|
||||
"w": 4,
|
||||
"x": 12,
|
||||
"y": 1
|
||||
},
|
||||
"id": 5,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barWidthFactor": 0.4,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": false,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"lastNotNull"
|
||||
],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"segmentCount": 1,
|
||||
"segmentSpacing": 0.3,
|
||||
"shape": "circle",
|
||||
"showThresholdLabels": false,
|
||||
"showThresholdMarkers": false,
|
||||
"sparkline": false
|
||||
},
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"alias": "1",
|
||||
"datasource": {
|
||||
"type": "grafana-testdata-datasource"
|
||||
},
|
||||
"max": 100,
|
||||
"min": 1,
|
||||
"noise": 22,
|
||||
"refId": "A",
|
||||
"scenarioId": "random_walk",
|
||||
"spread": 22,
|
||||
"startValue": 1
|
||||
}
|
||||
],
|
||||
"title": "Spotlight",
|
||||
"type": "radialbar"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "grafana-testdata-datasource"
|
||||
@@ -393,13 +311,12 @@
|
||||
"id": 8,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidthFactor": 0.4,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": false,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -472,13 +389,12 @@
|
||||
"id": 22,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "flat",
|
||||
"barWidthFactor": 0.72,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": false,
|
||||
"rounded": false,
|
||||
"spotlight": true
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -551,13 +467,12 @@
|
||||
"id": 23,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "flat",
|
||||
"barWidthFactor": 0.72,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": false,
|
||||
"rounded": false,
|
||||
"spotlight": true
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -643,13 +558,12 @@
|
||||
"id": 18,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidthFactor": 0.1,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": false,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -722,13 +636,12 @@
|
||||
"id": 19,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidthFactor": 0.32,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": false,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -801,13 +714,12 @@
|
||||
"id": 20,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidthFactor": 0.57,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": false,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -880,13 +792,12 @@
|
||||
"id": 21,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidthFactor": 0.8,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": false,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -976,13 +887,12 @@
|
||||
"id": 25,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "flat",
|
||||
"barWidthFactor": 0.9,
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": false,
|
||||
"rounded": false,
|
||||
"spotlight": false
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -1055,13 +965,12 @@
|
||||
"id": 26,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "flat",
|
||||
"barWidthFactor": 0.72,
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": false,
|
||||
"rounded": false,
|
||||
"spotlight": false
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -1134,13 +1043,12 @@
|
||||
"id": 29,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "flat",
|
||||
"barWidthFactor": 0.72,
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": true,
|
||||
"rounded": false,
|
||||
"spotlight": false
|
||||
"gradient": true
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -1213,13 +1121,12 @@
|
||||
"id": 30,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "flat",
|
||||
"barWidthFactor": 0.9,
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": false,
|
||||
"rounded": false,
|
||||
"spotlight": false
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -1292,13 +1199,12 @@
|
||||
"id": 28,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "flat",
|
||||
"barWidthFactor": 0.72,
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": false,
|
||||
"rounded": false,
|
||||
"spotlight": false
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -1388,13 +1294,12 @@
|
||||
"id": 32,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "flat",
|
||||
"barWidthFactor": 0.9,
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": true,
|
||||
"rounded": false,
|
||||
"spotlight": false
|
||||
"gradient": true
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -1471,13 +1376,12 @@
|
||||
"id": 34,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "flat",
|
||||
"barWidthFactor": 0.9,
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": true,
|
||||
"rounded": false,
|
||||
"spotlight": false
|
||||
"gradient": true
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -1554,13 +1458,12 @@
|
||||
"id": 33,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "flat",
|
||||
"barWidthFactor": 0.9,
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": true,
|
||||
"rounded": false,
|
||||
"spotlight": false
|
||||
"gradient": true
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -1645,15 +1548,15 @@
|
||||
"id": 9,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidth": 12,
|
||||
"barWidthFactor": 0.4,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": true,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": true
|
||||
},
|
||||
"endpointMarker": "glow",
|
||||
"glow": "both",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -1668,8 +1571,7 @@
|
||||
"shape": "circle",
|
||||
"showThresholdLabels": false,
|
||||
"showThresholdMarkers": false,
|
||||
"sparkline": false,
|
||||
"spotlight": true
|
||||
"sparkline": false
|
||||
},
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"targets": [
|
||||
@@ -1731,14 +1633,13 @@
|
||||
"id": 11,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidth": 12,
|
||||
"barWidthFactor": 0.4,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": true,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": true
|
||||
},
|
||||
"glow": "both",
|
||||
"orientation": "auto",
|
||||
@@ -1754,8 +1655,7 @@
|
||||
"shape": "gauge",
|
||||
"showThresholdLabels": false,
|
||||
"showThresholdMarkers": false,
|
||||
"sparkline": true,
|
||||
"spotlight": true
|
||||
"sparkline": true
|
||||
},
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"targets": [
|
||||
@@ -1831,14 +1731,13 @@
|
||||
"id": 13,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidth": 12,
|
||||
"barWidthFactor": 0.49,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": true,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": true
|
||||
},
|
||||
"glow": "both",
|
||||
"orientation": "auto",
|
||||
@@ -1854,8 +1753,7 @@
|
||||
"shape": "circle",
|
||||
"showThresholdLabels": false,
|
||||
"showThresholdMarkers": false,
|
||||
"sparkline": false,
|
||||
"spotlight": true
|
||||
"sparkline": false
|
||||
},
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"targets": [
|
||||
@@ -1918,15 +1816,13 @@
|
||||
"id": 14,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidth": 12,
|
||||
"barWidthFactor": 0.49,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": true,
|
||||
"rounded": true,
|
||||
"sparkline": false,
|
||||
"spotlight": true
|
||||
"gradient": true
|
||||
},
|
||||
"glow": "both",
|
||||
"orientation": "auto",
|
||||
@@ -1942,8 +1838,7 @@
|
||||
"shape": "circle",
|
||||
"showThresholdLabels": false,
|
||||
"showThresholdMarkers": false,
|
||||
"sparkline": false,
|
||||
"spotlight": true
|
||||
"sparkline": false
|
||||
},
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"targets": [
|
||||
@@ -2005,14 +1900,13 @@
|
||||
"id": 15,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidth": 12,
|
||||
"barWidthFactor": 0.84,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": true,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": true
|
||||
},
|
||||
"glow": "both",
|
||||
"orientation": "auto",
|
||||
@@ -2028,8 +1922,7 @@
|
||||
"shape": "circle",
|
||||
"showThresholdLabels": false,
|
||||
"showThresholdMarkers": false,
|
||||
"sparkline": false,
|
||||
"spotlight": true
|
||||
"sparkline": false
|
||||
},
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"targets": [
|
||||
@@ -2091,14 +1984,13 @@
|
||||
"id": 16,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidth": 12,
|
||||
"barWidthFactor": 0.66,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": true,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": true
|
||||
},
|
||||
"glow": "both",
|
||||
"orientation": "auto",
|
||||
@@ -2114,8 +2006,7 @@
|
||||
"shape": "circle",
|
||||
"showThresholdLabels": false,
|
||||
"showThresholdMarkers": false,
|
||||
"sparkline": false,
|
||||
"spotlight": true
|
||||
"sparkline": false
|
||||
},
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"targets": [
|
||||
@@ -2160,4 +2051,4 @@
|
||||
"storedVersion": "v0alpha1"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+56
-191
@@ -73,13 +73,12 @@
|
||||
"spec": {
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidthFactor": 0.4,
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": false,
|
||||
"rounded": true,
|
||||
"spotlight": false
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -165,14 +164,13 @@
|
||||
"spec": {
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidth": 12,
|
||||
"barWidthFactor": 0.4,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": true,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": true
|
||||
},
|
||||
"glow": "both",
|
||||
"orientation": "auto",
|
||||
@@ -188,8 +186,7 @@
|
||||
"shape": "gauge",
|
||||
"showThresholdLabels": false,
|
||||
"showThresholdMarkers": false,
|
||||
"sparkline": true,
|
||||
"spotlight": true
|
||||
"sparkline": true
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
@@ -262,14 +259,13 @@
|
||||
"spec": {
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidth": 12,
|
||||
"barWidthFactor": 0.49,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": true,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": true
|
||||
},
|
||||
"glow": "both",
|
||||
"orientation": "auto",
|
||||
@@ -285,8 +281,7 @@
|
||||
"shape": "circle",
|
||||
"showThresholdLabels": false,
|
||||
"showThresholdMarkers": false,
|
||||
"sparkline": false,
|
||||
"spotlight": true
|
||||
"sparkline": false
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
@@ -360,15 +355,13 @@
|
||||
"spec": {
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidth": 12,
|
||||
"barWidthFactor": 0.49,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": true,
|
||||
"rounded": true,
|
||||
"sparkline": false,
|
||||
"spotlight": true
|
||||
"gradient": true
|
||||
},
|
||||
"glow": "both",
|
||||
"orientation": "auto",
|
||||
@@ -384,8 +377,7 @@
|
||||
"shape": "circle",
|
||||
"showThresholdLabels": false,
|
||||
"showThresholdMarkers": false,
|
||||
"sparkline": false,
|
||||
"spotlight": true
|
||||
"sparkline": false
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
@@ -459,14 +451,13 @@
|
||||
"spec": {
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidth": 12,
|
||||
"barWidthFactor": 0.84,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": true,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": true
|
||||
},
|
||||
"glow": "both",
|
||||
"orientation": "auto",
|
||||
@@ -482,8 +473,7 @@
|
||||
"shape": "circle",
|
||||
"showThresholdLabels": false,
|
||||
"showThresholdMarkers": false,
|
||||
"sparkline": false,
|
||||
"spotlight": true
|
||||
"sparkline": false
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
@@ -556,14 +546,13 @@
|
||||
"spec": {
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidth": 12,
|
||||
"barWidthFactor": 0.66,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": true,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": true
|
||||
},
|
||||
"glow": "both",
|
||||
"orientation": "auto",
|
||||
@@ -579,8 +568,7 @@
|
||||
"shape": "circle",
|
||||
"showThresholdLabels": false,
|
||||
"showThresholdMarkers": false,
|
||||
"sparkline": false,
|
||||
"spotlight": true
|
||||
"sparkline": false
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
@@ -653,13 +641,12 @@
|
||||
"spec": {
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidthFactor": 0.1,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": false,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -745,13 +732,12 @@
|
||||
"spec": {
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidthFactor": 0.32,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": false,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -837,13 +823,12 @@
|
||||
"spec": {
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidthFactor": 0.57,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": false,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -929,13 +914,12 @@
|
||||
"spec": {
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidthFactor": 0.8,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": false,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -1021,13 +1005,12 @@
|
||||
"spec": {
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"options": {
|
||||
"barShape": "flat",
|
||||
"barWidthFactor": 0.72,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": false,
|
||||
"rounded": false,
|
||||
"spotlight": true
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -1113,13 +1096,12 @@
|
||||
"spec": {
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"options": {
|
||||
"barShape": "flat",
|
||||
"barWidthFactor": 0.72,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": false,
|
||||
"rounded": false,
|
||||
"spotlight": true
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -1201,13 +1183,12 @@
|
||||
"spec": {
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"options": {
|
||||
"barShape": "flat",
|
||||
"barWidthFactor": 0.9,
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": false,
|
||||
"rounded": false,
|
||||
"spotlight": false
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -1293,13 +1274,12 @@
|
||||
"spec": {
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"options": {
|
||||
"barShape": "flat",
|
||||
"barWidthFactor": 0.72,
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": false,
|
||||
"rounded": false,
|
||||
"spotlight": false
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -1385,13 +1365,12 @@
|
||||
"spec": {
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"options": {
|
||||
"barShape": "flat",
|
||||
"barWidthFactor": 0.72,
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": false,
|
||||
"rounded": false,
|
||||
"spotlight": false
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -1477,13 +1456,12 @@
|
||||
"spec": {
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"options": {
|
||||
"barShape": "flat",
|
||||
"barWidthFactor": 0.72,
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": true,
|
||||
"rounded": false,
|
||||
"spotlight": false
|
||||
"gradient": true
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -1573,13 +1551,12 @@
|
||||
"spec": {
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidthFactor": 0.4,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": false,
|
||||
"rounded": true,
|
||||
"spotlight": false
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -1661,13 +1638,12 @@
|
||||
"spec": {
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"options": {
|
||||
"barShape": "flat",
|
||||
"barWidthFactor": 0.9,
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": false,
|
||||
"rounded": false,
|
||||
"spotlight": false
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -1753,13 +1729,12 @@
|
||||
"spec": {
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"options": {
|
||||
"barShape": "flat",
|
||||
"barWidthFactor": 0.9,
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": true,
|
||||
"rounded": false,
|
||||
"spotlight": false
|
||||
"gradient": true
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -1849,13 +1824,12 @@
|
||||
"spec": {
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"options": {
|
||||
"barShape": "flat",
|
||||
"barWidthFactor": 0.9,
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": true,
|
||||
"rounded": false,
|
||||
"spotlight": false
|
||||
"gradient": true
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -1945,13 +1919,12 @@
|
||||
"spec": {
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"options": {
|
||||
"barShape": "flat",
|
||||
"barWidthFactor": 0.9,
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": true,
|
||||
"rounded": false,
|
||||
"spotlight": false
|
||||
"gradient": true
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -2045,105 +2018,12 @@
|
||||
"spec": {
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidthFactor": 0.4,
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": true,
|
||||
"gradient": false,
|
||||
"rounded": true,
|
||||
"spotlight": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"lastNotNull"
|
||||
],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"segmentCount": 1,
|
||||
"segmentSpacing": 0.3,
|
||||
"shape": "circle",
|
||||
"showThresholdLabels": false,
|
||||
"showThresholdMarkers": false,
|
||||
"sparkline": false
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"min": 0,
|
||||
"max": 100,
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"value": 0,
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"value": 80,
|
||||
"color": "red"
|
||||
}
|
||||
]
|
||||
},
|
||||
"color": {
|
||||
"mode": "thresholds"
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"panel-5": {
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"id": 5,
|
||||
"title": "Spotlight",
|
||||
"description": "",
|
||||
"links": [],
|
||||
"data": {
|
||||
"kind": "QueryGroup",
|
||||
"spec": {
|
||||
"queries": [
|
||||
{
|
||||
"kind": "PanelQuery",
|
||||
"spec": {
|
||||
"query": {
|
||||
"kind": "grafana-testdata-datasource",
|
||||
"spec": {
|
||||
"alias": "1",
|
||||
"max": 100,
|
||||
"min": 1,
|
||||
"noise": 22,
|
||||
"scenarioId": "random_walk",
|
||||
"spread": 22,
|
||||
"startValue": 1
|
||||
}
|
||||
},
|
||||
"refId": "A",
|
||||
"hidden": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"transformations": [],
|
||||
"queryOptions": {
|
||||
"maxDataPoints": 20
|
||||
}
|
||||
}
|
||||
},
|
||||
"vizConfig": {
|
||||
"kind": "radialbar",
|
||||
"spec": {
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"options": {
|
||||
"barWidthFactor": 0.4,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": false,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -2229,13 +2109,12 @@
|
||||
"spec": {
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidthFactor": 0.4,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": false,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -2321,15 +2200,15 @@
|
||||
"spec": {
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidth": 12,
|
||||
"barWidthFactor": 0.4,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": true,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": true
|
||||
},
|
||||
"endpointMarker": "glow",
|
||||
"glow": "both",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -2344,8 +2223,7 @@
|
||||
"shape": "circle",
|
||||
"showThresholdLabels": false,
|
||||
"showThresholdMarkers": false,
|
||||
"sparkline": false,
|
||||
"spotlight": true
|
||||
"sparkline": false
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
@@ -2429,19 +2307,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "GridLayoutItem",
|
||||
"spec": {
|
||||
"x": 12,
|
||||
"y": 0,
|
||||
"width": 4,
|
||||
"height": 6,
|
||||
"element": {
|
||||
"kind": "ElementReference",
|
||||
"name": "panel-5"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "GridLayoutItem",
|
||||
"spec": {
|
||||
@@ -2826,4 +2691,4 @@
|
||||
"storedVersion": "v0alpha1"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+56
-194
@@ -77,13 +77,12 @@
|
||||
"version": "13.0.0-pre",
|
||||
"spec": {
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidthFactor": 0.4,
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": false,
|
||||
"rounded": true,
|
||||
"spotlight": false
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -172,14 +171,13 @@
|
||||
"version": "13.0.0-pre",
|
||||
"spec": {
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidth": 12,
|
||||
"barWidthFactor": 0.4,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": true,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": true
|
||||
},
|
||||
"glow": "both",
|
||||
"orientation": "auto",
|
||||
@@ -195,8 +193,7 @@
|
||||
"shape": "gauge",
|
||||
"showThresholdLabels": false,
|
||||
"showThresholdMarkers": false,
|
||||
"sparkline": true,
|
||||
"spotlight": true
|
||||
"sparkline": true
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
@@ -272,14 +269,13 @@
|
||||
"version": "13.0.0-pre",
|
||||
"spec": {
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidth": 12,
|
||||
"barWidthFactor": 0.49,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": true,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": true
|
||||
},
|
||||
"glow": "both",
|
||||
"orientation": "auto",
|
||||
@@ -295,8 +291,7 @@
|
||||
"shape": "circle",
|
||||
"showThresholdLabels": false,
|
||||
"showThresholdMarkers": false,
|
||||
"sparkline": false,
|
||||
"spotlight": true
|
||||
"sparkline": false
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
@@ -373,15 +368,13 @@
|
||||
"version": "13.0.0-pre",
|
||||
"spec": {
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidth": 12,
|
||||
"barWidthFactor": 0.49,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": true,
|
||||
"rounded": true,
|
||||
"sparkline": false,
|
||||
"spotlight": true
|
||||
"gradient": true
|
||||
},
|
||||
"glow": "both",
|
||||
"orientation": "auto",
|
||||
@@ -397,8 +390,7 @@
|
||||
"shape": "circle",
|
||||
"showThresholdLabels": false,
|
||||
"showThresholdMarkers": false,
|
||||
"sparkline": false,
|
||||
"spotlight": true
|
||||
"sparkline": false
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
@@ -475,14 +467,13 @@
|
||||
"version": "13.0.0-pre",
|
||||
"spec": {
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidth": 12,
|
||||
"barWidthFactor": 0.84,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": true,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": true
|
||||
},
|
||||
"glow": "both",
|
||||
"orientation": "auto",
|
||||
@@ -498,8 +489,7 @@
|
||||
"shape": "circle",
|
||||
"showThresholdLabels": false,
|
||||
"showThresholdMarkers": false,
|
||||
"sparkline": false,
|
||||
"spotlight": true
|
||||
"sparkline": false
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
@@ -575,14 +565,13 @@
|
||||
"version": "13.0.0-pre",
|
||||
"spec": {
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidth": 12,
|
||||
"barWidthFactor": 0.66,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": true,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": true
|
||||
},
|
||||
"glow": "both",
|
||||
"orientation": "auto",
|
||||
@@ -598,8 +587,7 @@
|
||||
"shape": "circle",
|
||||
"showThresholdLabels": false,
|
||||
"showThresholdMarkers": false,
|
||||
"sparkline": false,
|
||||
"spotlight": true
|
||||
"sparkline": false
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
@@ -675,13 +663,12 @@
|
||||
"version": "13.0.0-pre",
|
||||
"spec": {
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidthFactor": 0.1,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": false,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -770,13 +757,12 @@
|
||||
"version": "13.0.0-pre",
|
||||
"spec": {
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidthFactor": 0.32,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": false,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -865,13 +851,12 @@
|
||||
"version": "13.0.0-pre",
|
||||
"spec": {
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidthFactor": 0.57,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": false,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -960,13 +945,12 @@
|
||||
"version": "13.0.0-pre",
|
||||
"spec": {
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidthFactor": 0.8,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": false,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -1055,13 +1039,12 @@
|
||||
"version": "13.0.0-pre",
|
||||
"spec": {
|
||||
"options": {
|
||||
"barShape": "flat",
|
||||
"barWidthFactor": 0.72,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": false,
|
||||
"rounded": false,
|
||||
"spotlight": true
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -1150,13 +1133,12 @@
|
||||
"version": "13.0.0-pre",
|
||||
"spec": {
|
||||
"options": {
|
||||
"barShape": "flat",
|
||||
"barWidthFactor": 0.72,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": false,
|
||||
"rounded": false,
|
||||
"spotlight": true
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -1241,13 +1223,12 @@
|
||||
"version": "13.0.0-pre",
|
||||
"spec": {
|
||||
"options": {
|
||||
"barShape": "flat",
|
||||
"barWidthFactor": 0.9,
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": false,
|
||||
"rounded": false,
|
||||
"spotlight": false
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -1336,13 +1317,12 @@
|
||||
"version": "13.0.0-pre",
|
||||
"spec": {
|
||||
"options": {
|
||||
"barShape": "flat",
|
||||
"barWidthFactor": 0.72,
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": false,
|
||||
"rounded": false,
|
||||
"spotlight": false
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -1431,13 +1411,12 @@
|
||||
"version": "13.0.0-pre",
|
||||
"spec": {
|
||||
"options": {
|
||||
"barShape": "flat",
|
||||
"barWidthFactor": 0.72,
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": false,
|
||||
"rounded": false,
|
||||
"spotlight": false
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -1526,13 +1505,12 @@
|
||||
"version": "13.0.0-pre",
|
||||
"spec": {
|
||||
"options": {
|
||||
"barShape": "flat",
|
||||
"barWidthFactor": 0.72,
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": true,
|
||||
"rounded": false,
|
||||
"spotlight": false
|
||||
"gradient": true
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -1625,13 +1603,12 @@
|
||||
"version": "13.0.0-pre",
|
||||
"spec": {
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidthFactor": 0.4,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": false,
|
||||
"rounded": true,
|
||||
"spotlight": false
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -1716,13 +1693,12 @@
|
||||
"version": "13.0.0-pre",
|
||||
"spec": {
|
||||
"options": {
|
||||
"barShape": "flat",
|
||||
"barWidthFactor": 0.9,
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": false,
|
||||
"rounded": false,
|
||||
"spotlight": false
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -1811,13 +1787,12 @@
|
||||
"version": "13.0.0-pre",
|
||||
"spec": {
|
||||
"options": {
|
||||
"barShape": "flat",
|
||||
"barWidthFactor": 0.9,
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": true,
|
||||
"rounded": false,
|
||||
"spotlight": false
|
||||
"gradient": true
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -1910,13 +1885,12 @@
|
||||
"version": "13.0.0-pre",
|
||||
"spec": {
|
||||
"options": {
|
||||
"barShape": "flat",
|
||||
"barWidthFactor": 0.9,
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": true,
|
||||
"rounded": false,
|
||||
"spotlight": false
|
||||
"gradient": true
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -2009,13 +1983,12 @@
|
||||
"version": "13.0.0-pre",
|
||||
"spec": {
|
||||
"options": {
|
||||
"barShape": "flat",
|
||||
"barWidthFactor": 0.9,
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": true,
|
||||
"rounded": false,
|
||||
"spotlight": false
|
||||
"gradient": true
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -2112,108 +2085,12 @@
|
||||
"version": "13.0.0-pre",
|
||||
"spec": {
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidthFactor": 0.4,
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": true,
|
||||
"gradient": false,
|
||||
"rounded": true,
|
||||
"spotlight": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"lastNotNull"
|
||||
],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"segmentCount": 1,
|
||||
"segmentSpacing": 0.3,
|
||||
"shape": "circle",
|
||||
"showThresholdLabels": false,
|
||||
"showThresholdMarkers": false,
|
||||
"sparkline": false
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"min": 0,
|
||||
"max": 100,
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"value": 0,
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"value": 80,
|
||||
"color": "red"
|
||||
}
|
||||
]
|
||||
},
|
||||
"color": {
|
||||
"mode": "thresholds"
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"panel-5": {
|
||||
"kind": "Panel",
|
||||
"spec": {
|
||||
"id": 5,
|
||||
"title": "Spotlight",
|
||||
"description": "",
|
||||
"links": [],
|
||||
"data": {
|
||||
"kind": "QueryGroup",
|
||||
"spec": {
|
||||
"queries": [
|
||||
{
|
||||
"kind": "PanelQuery",
|
||||
"spec": {
|
||||
"query": {
|
||||
"kind": "DataQuery",
|
||||
"group": "grafana-testdata-datasource",
|
||||
"version": "v0",
|
||||
"spec": {
|
||||
"alias": "1",
|
||||
"max": 100,
|
||||
"min": 1,
|
||||
"noise": 22,
|
||||
"scenarioId": "random_walk",
|
||||
"spread": 22,
|
||||
"startValue": 1
|
||||
}
|
||||
},
|
||||
"refId": "A",
|
||||
"hidden": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"transformations": [],
|
||||
"queryOptions": {
|
||||
"maxDataPoints": 20
|
||||
}
|
||||
}
|
||||
},
|
||||
"vizConfig": {
|
||||
"kind": "VizConfig",
|
||||
"group": "radialbar",
|
||||
"version": "13.0.0-pre",
|
||||
"spec": {
|
||||
"options": {
|
||||
"barWidthFactor": 0.4,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": false,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -2302,13 +2179,12 @@
|
||||
"version": "13.0.0-pre",
|
||||
"spec": {
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidthFactor": 0.4,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": false,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -2397,15 +2273,15 @@
|
||||
"version": "13.0.0-pre",
|
||||
"spec": {
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidth": 12,
|
||||
"barWidthFactor": 0.4,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": true,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": true
|
||||
},
|
||||
"endpointMarker": "glow",
|
||||
"glow": "both",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -2420,8 +2296,7 @@
|
||||
"shape": "circle",
|
||||
"showThresholdLabels": false,
|
||||
"showThresholdMarkers": false,
|
||||
"sparkline": false,
|
||||
"spotlight": true
|
||||
"sparkline": false
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
@@ -2505,19 +2380,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "GridLayoutItem",
|
||||
"spec": {
|
||||
"x": 12,
|
||||
"y": 0,
|
||||
"width": 4,
|
||||
"height": 6,
|
||||
"element": {
|
||||
"kind": "ElementReference",
|
||||
"name": "panel-5"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "GridLayoutItem",
|
||||
"spec": {
|
||||
@@ -2902,4 +2764,4 @@
|
||||
"storedVersion": "v0alpha1"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-4
@@ -961,9 +961,7 @@
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": false,
|
||||
"rounded": false,
|
||||
"spotlight": false
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -1175,4 +1173,4 @@
|
||||
"storedVersion": "v0alpha1"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-4
@@ -864,9 +864,7 @@
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": false,
|
||||
"rounded": false,
|
||||
"spotlight": false
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -1620,4 +1618,4 @@
|
||||
"storedVersion": "v0alpha1"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-4
@@ -901,9 +901,7 @@
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": false,
|
||||
"rounded": false,
|
||||
"spotlight": false
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -1672,4 +1670,4 @@
|
||||
"storedVersion": "v0alpha1"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+66
-6
@@ -412,7 +412,17 @@
|
||||
"kind": "text",
|
||||
"spec": {
|
||||
"pluginVersion": "",
|
||||
"options": {},
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "text",
|
||||
"originalOptions": {
|
||||
"content": "Should be a long line connecting the null region in the `connected` mode, and in zero it should just be a line with zero value at the null points. ",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"mode": "markdown"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
@@ -456,7 +466,17 @@
|
||||
"kind": "text",
|
||||
"spec": {
|
||||
"pluginVersion": "",
|
||||
"options": {},
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "text",
|
||||
"originalOptions": {
|
||||
"content": "Stacking values on top of nulls, should treat the null values as zero. ",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"mode": "markdown"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
@@ -500,7 +520,17 @@
|
||||
"kind": "text",
|
||||
"spec": {
|
||||
"pluginVersion": "",
|
||||
"options": {},
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "text",
|
||||
"originalOptions": {
|
||||
"content": "Stacking when all values are null should leave a gap in the graph",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"mode": "markdown"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
@@ -1681,7 +1711,17 @@
|
||||
"kind": "text",
|
||||
"spec": {
|
||||
"pluginVersion": "",
|
||||
"options": {},
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "text",
|
||||
"originalOptions": {
|
||||
"content": "Left is showing null between values for a normal line graph and staircase graph. Orphaned data points should be rendered as points",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"mode": "markdown"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
@@ -2061,7 +2101,17 @@
|
||||
"kind": "text",
|
||||
"spec": {
|
||||
"pluginVersion": "",
|
||||
"options": {},
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "text",
|
||||
"originalOptions": {
|
||||
"content": "Just verify that the tooltip time has millisecond resolution ",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"mode": "markdown"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
@@ -2105,7 +2155,17 @@
|
||||
"kind": "text",
|
||||
"spec": {
|
||||
"pluginVersion": "",
|
||||
"options": {},
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "text",
|
||||
"originalOptions": {
|
||||
"content": "Verify that axis labels look ok",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"mode": "markdown"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
|
||||
+66
-6
@@ -429,7 +429,17 @@
|
||||
"group": "text",
|
||||
"version": "",
|
||||
"spec": {
|
||||
"options": {},
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "text",
|
||||
"originalOptions": {
|
||||
"content": "Should be a long line connecting the null region in the `connected` mode, and in zero it should just be a line with zero value at the null points. ",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"mode": "markdown"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
@@ -475,7 +485,17 @@
|
||||
"group": "text",
|
||||
"version": "",
|
||||
"spec": {
|
||||
"options": {},
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "text",
|
||||
"originalOptions": {
|
||||
"content": "Stacking values on top of nulls, should treat the null values as zero. ",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"mode": "markdown"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
@@ -521,7 +541,17 @@
|
||||
"group": "text",
|
||||
"version": "",
|
||||
"spec": {
|
||||
"options": {},
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "text",
|
||||
"originalOptions": {
|
||||
"content": "Stacking when all values are null should leave a gap in the graph",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"mode": "markdown"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
@@ -1779,7 +1809,17 @@
|
||||
"group": "text",
|
||||
"version": "",
|
||||
"spec": {
|
||||
"options": {},
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "text",
|
||||
"originalOptions": {
|
||||
"content": "Left is showing null between values for a normal line graph and staircase graph. Orphaned data points should be rendered as points",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"mode": "markdown"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
@@ -2172,7 +2212,17 @@
|
||||
"group": "text",
|
||||
"version": "",
|
||||
"spec": {
|
||||
"options": {},
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "text",
|
||||
"originalOptions": {
|
||||
"content": "Just verify that the tooltip time has millisecond resolution ",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"mode": "markdown"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
@@ -2218,7 +2268,17 @@
|
||||
"group": "text",
|
||||
"version": "",
|
||||
"spec": {
|
||||
"options": {},
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "text",
|
||||
"originalOptions": {
|
||||
"content": "Verify that axis labels look ok",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"mode": "markdown"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
|
||||
+232
-6
@@ -74,7 +74,44 @@
|
||||
"kind": "heatmap",
|
||||
"spec": {
|
||||
"pluginVersion": "",
|
||||
"options": {},
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "heatmap",
|
||||
"originalOptions": {
|
||||
"cards": {},
|
||||
"color": {
|
||||
"cardColor": "#b4ff00",
|
||||
"colorScale": "sqrt",
|
||||
"colorScheme": "interpolateViridis",
|
||||
"exponent": 0.5,
|
||||
"mode": "spectrum"
|
||||
},
|
||||
"dataFormat": "timeseries",
|
||||
"heatmap": {},
|
||||
"hideZeroBuckets": false,
|
||||
"highlightCards": true,
|
||||
"legend": {
|
||||
"show": true
|
||||
},
|
||||
"reverseYBuckets": false,
|
||||
"tooltip": {
|
||||
"show": true,
|
||||
"showHistogram": true
|
||||
},
|
||||
"tooltipDecimals": 4,
|
||||
"xAxis": {
|
||||
"show": true
|
||||
},
|
||||
"yAxis": {
|
||||
"decimals": 2,
|
||||
"format": "areaM2",
|
||||
"logBase": 1,
|
||||
"show": true
|
||||
},
|
||||
"yBucketBound": "auto"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
@@ -116,7 +153,46 @@
|
||||
"kind": "heatmap",
|
||||
"spec": {
|
||||
"pluginVersion": "",
|
||||
"options": {},
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "heatmap",
|
||||
"originalOptions": {
|
||||
"cards": {
|
||||
"cardRound": 50
|
||||
},
|
||||
"color": {
|
||||
"cardColor": "#1F60C4",
|
||||
"colorScale": "sqrt",
|
||||
"colorScheme": "interpolateOranges",
|
||||
"exponent": 0.5,
|
||||
"mode": "opacity"
|
||||
},
|
||||
"dataFormat": "tsbuckets",
|
||||
"heatmap": {},
|
||||
"hideZeroBuckets": false,
|
||||
"highlightCards": true,
|
||||
"legend": {
|
||||
"show": true
|
||||
},
|
||||
"reverseYBuckets": false,
|
||||
"tooltip": {
|
||||
"show": true,
|
||||
"showHistogram": false
|
||||
},
|
||||
"xAxis": {
|
||||
"show": true
|
||||
},
|
||||
"yAxis": {
|
||||
"decimals": 1,
|
||||
"format": "kwatt",
|
||||
"logBase": 1,
|
||||
"show": true,
|
||||
"width": "100"
|
||||
},
|
||||
"yBucketBound": "auto"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
@@ -158,7 +234,44 @@
|
||||
"kind": "heatmap",
|
||||
"spec": {
|
||||
"pluginVersion": "",
|
||||
"options": {},
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "heatmap",
|
||||
"originalOptions": {
|
||||
"cards": {},
|
||||
"color": {
|
||||
"cardColor": "#1F60C4",
|
||||
"colorScale": "sqrt",
|
||||
"colorScheme": "interpolateOranges",
|
||||
"exponent": 0.5,
|
||||
"mode": "opacity"
|
||||
},
|
||||
"dataFormat": "tsbuckets",
|
||||
"heatmap": {},
|
||||
"hideZeroBuckets": false,
|
||||
"highlightCards": true,
|
||||
"legend": {
|
||||
"show": true
|
||||
},
|
||||
"reverseYBuckets": true,
|
||||
"tooltip": {
|
||||
"show": true,
|
||||
"showHistogram": false
|
||||
},
|
||||
"xAxis": {
|
||||
"show": true
|
||||
},
|
||||
"yAxis": {
|
||||
"decimals": 1,
|
||||
"format": "kwatt",
|
||||
"logBase": 1,
|
||||
"show": true,
|
||||
"width": "100"
|
||||
},
|
||||
"yBucketBound": "auto"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
@@ -204,7 +317,46 @@
|
||||
"kind": "heatmap",
|
||||
"spec": {
|
||||
"pluginVersion": "",
|
||||
"options": {},
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "heatmap",
|
||||
"originalOptions": {
|
||||
"cards": {},
|
||||
"color": {
|
||||
"cardColor": "#b4ff00",
|
||||
"colorScale": "sqrt",
|
||||
"colorScheme": "interpolateViridis",
|
||||
"exponent": 0.5,
|
||||
"mode": "spectrum"
|
||||
},
|
||||
"dataFormat": "timeseries",
|
||||
"heatmap": {},
|
||||
"hideZeroBuckets": false,
|
||||
"highlightCards": true,
|
||||
"legend": {
|
||||
"show": true
|
||||
},
|
||||
"reverseYBuckets": false,
|
||||
"tooltip": {
|
||||
"show": true,
|
||||
"showHistogram": true
|
||||
},
|
||||
"tooltipDecimals": 4,
|
||||
"xAxis": {
|
||||
"show": true
|
||||
},
|
||||
"yAxis": {
|
||||
"decimals": 2,
|
||||
"format": "areaM2",
|
||||
"logBase": 1,
|
||||
"max": "50",
|
||||
"min": "20",
|
||||
"show": true
|
||||
},
|
||||
"yBucketBound": "auto"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
@@ -246,7 +398,44 @@
|
||||
"kind": "heatmap",
|
||||
"spec": {
|
||||
"pluginVersion": "",
|
||||
"options": {},
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "heatmap",
|
||||
"originalOptions": {
|
||||
"cards": {},
|
||||
"color": {
|
||||
"cardColor": "#b4ff00",
|
||||
"colorScale": "sqrt",
|
||||
"colorScheme": "interpolateBuGn",
|
||||
"exponent": 0.5,
|
||||
"mode": "spectrum"
|
||||
},
|
||||
"dataFormat": "timeseries",
|
||||
"heatmap": {},
|
||||
"hideZeroBuckets": true,
|
||||
"highlightCards": true,
|
||||
"legend": {
|
||||
"show": true
|
||||
},
|
||||
"reverseYBuckets": false,
|
||||
"tooltip": {
|
||||
"show": true,
|
||||
"showHistogram": true
|
||||
},
|
||||
"xAxis": {
|
||||
"show": true
|
||||
},
|
||||
"xBucketNumber": 10,
|
||||
"yAxis": {
|
||||
"format": "short",
|
||||
"logBase": 2,
|
||||
"show": true,
|
||||
"splitFactor": 2
|
||||
},
|
||||
"yBucketBound": "auto"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
@@ -288,7 +477,44 @@
|
||||
"kind": "heatmap",
|
||||
"spec": {
|
||||
"pluginVersion": "",
|
||||
"options": {},
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "heatmap",
|
||||
"originalOptions": {
|
||||
"cards": {},
|
||||
"color": {
|
||||
"cardColor": "#b4ff00",
|
||||
"colorScale": "sqrt",
|
||||
"colorScheme": "interpolateBuGn",
|
||||
"exponent": 0.5,
|
||||
"mode": "spectrum"
|
||||
},
|
||||
"dataFormat": "timeseries",
|
||||
"heatmap": {},
|
||||
"hideZeroBuckets": true,
|
||||
"highlightCards": true,
|
||||
"legend": {
|
||||
"show": true
|
||||
},
|
||||
"reverseYBuckets": false,
|
||||
"tooltip": {
|
||||
"show": true,
|
||||
"showHistogram": true
|
||||
},
|
||||
"xAxis": {
|
||||
"show": true
|
||||
},
|
||||
"xBucketNumber": 10,
|
||||
"yAxis": {
|
||||
"format": "short",
|
||||
"logBase": 10,
|
||||
"show": true,
|
||||
"splitFactor": 5
|
||||
},
|
||||
"yBucketBound": "auto"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
|
||||
+232
-6
@@ -78,7 +78,44 @@
|
||||
"group": "heatmap",
|
||||
"version": "",
|
||||
"spec": {
|
||||
"options": {},
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "heatmap",
|
||||
"originalOptions": {
|
||||
"cards": {},
|
||||
"color": {
|
||||
"cardColor": "#b4ff00",
|
||||
"colorScale": "sqrt",
|
||||
"colorScheme": "interpolateViridis",
|
||||
"exponent": 0.5,
|
||||
"mode": "spectrum"
|
||||
},
|
||||
"dataFormat": "timeseries",
|
||||
"heatmap": {},
|
||||
"hideZeroBuckets": false,
|
||||
"highlightCards": true,
|
||||
"legend": {
|
||||
"show": true
|
||||
},
|
||||
"reverseYBuckets": false,
|
||||
"tooltip": {
|
||||
"show": true,
|
||||
"showHistogram": true
|
||||
},
|
||||
"tooltipDecimals": 4,
|
||||
"xAxis": {
|
||||
"show": true
|
||||
},
|
||||
"yAxis": {
|
||||
"decimals": 2,
|
||||
"format": "areaM2",
|
||||
"logBase": 1,
|
||||
"show": true
|
||||
},
|
||||
"yBucketBound": "auto"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
@@ -123,7 +160,46 @@
|
||||
"group": "heatmap",
|
||||
"version": "",
|
||||
"spec": {
|
||||
"options": {},
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "heatmap",
|
||||
"originalOptions": {
|
||||
"cards": {
|
||||
"cardRound": 50
|
||||
},
|
||||
"color": {
|
||||
"cardColor": "#1F60C4",
|
||||
"colorScale": "sqrt",
|
||||
"colorScheme": "interpolateOranges",
|
||||
"exponent": 0.5,
|
||||
"mode": "opacity"
|
||||
},
|
||||
"dataFormat": "tsbuckets",
|
||||
"heatmap": {},
|
||||
"hideZeroBuckets": false,
|
||||
"highlightCards": true,
|
||||
"legend": {
|
||||
"show": true
|
||||
},
|
||||
"reverseYBuckets": false,
|
||||
"tooltip": {
|
||||
"show": true,
|
||||
"showHistogram": false
|
||||
},
|
||||
"xAxis": {
|
||||
"show": true
|
||||
},
|
||||
"yAxis": {
|
||||
"decimals": 1,
|
||||
"format": "kwatt",
|
||||
"logBase": 1,
|
||||
"show": true,
|
||||
"width": "100"
|
||||
},
|
||||
"yBucketBound": "auto"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
@@ -168,7 +244,44 @@
|
||||
"group": "heatmap",
|
||||
"version": "",
|
||||
"spec": {
|
||||
"options": {},
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "heatmap",
|
||||
"originalOptions": {
|
||||
"cards": {},
|
||||
"color": {
|
||||
"cardColor": "#1F60C4",
|
||||
"colorScale": "sqrt",
|
||||
"colorScheme": "interpolateOranges",
|
||||
"exponent": 0.5,
|
||||
"mode": "opacity"
|
||||
},
|
||||
"dataFormat": "tsbuckets",
|
||||
"heatmap": {},
|
||||
"hideZeroBuckets": false,
|
||||
"highlightCards": true,
|
||||
"legend": {
|
||||
"show": true
|
||||
},
|
||||
"reverseYBuckets": true,
|
||||
"tooltip": {
|
||||
"show": true,
|
||||
"showHistogram": false
|
||||
},
|
||||
"xAxis": {
|
||||
"show": true
|
||||
},
|
||||
"yAxis": {
|
||||
"decimals": 1,
|
||||
"format": "kwatt",
|
||||
"logBase": 1,
|
||||
"show": true,
|
||||
"width": "100"
|
||||
},
|
||||
"yBucketBound": "auto"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
@@ -216,7 +329,46 @@
|
||||
"group": "heatmap",
|
||||
"version": "",
|
||||
"spec": {
|
||||
"options": {},
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "heatmap",
|
||||
"originalOptions": {
|
||||
"cards": {},
|
||||
"color": {
|
||||
"cardColor": "#b4ff00",
|
||||
"colorScale": "sqrt",
|
||||
"colorScheme": "interpolateViridis",
|
||||
"exponent": 0.5,
|
||||
"mode": "spectrum"
|
||||
},
|
||||
"dataFormat": "timeseries",
|
||||
"heatmap": {},
|
||||
"hideZeroBuckets": false,
|
||||
"highlightCards": true,
|
||||
"legend": {
|
||||
"show": true
|
||||
},
|
||||
"reverseYBuckets": false,
|
||||
"tooltip": {
|
||||
"show": true,
|
||||
"showHistogram": true
|
||||
},
|
||||
"tooltipDecimals": 4,
|
||||
"xAxis": {
|
||||
"show": true
|
||||
},
|
||||
"yAxis": {
|
||||
"decimals": 2,
|
||||
"format": "areaM2",
|
||||
"logBase": 1,
|
||||
"max": "50",
|
||||
"min": "20",
|
||||
"show": true
|
||||
},
|
||||
"yBucketBound": "auto"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
@@ -261,7 +413,44 @@
|
||||
"group": "heatmap",
|
||||
"version": "",
|
||||
"spec": {
|
||||
"options": {},
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "heatmap",
|
||||
"originalOptions": {
|
||||
"cards": {},
|
||||
"color": {
|
||||
"cardColor": "#b4ff00",
|
||||
"colorScale": "sqrt",
|
||||
"colorScheme": "interpolateBuGn",
|
||||
"exponent": 0.5,
|
||||
"mode": "spectrum"
|
||||
},
|
||||
"dataFormat": "timeseries",
|
||||
"heatmap": {},
|
||||
"hideZeroBuckets": true,
|
||||
"highlightCards": true,
|
||||
"legend": {
|
||||
"show": true
|
||||
},
|
||||
"reverseYBuckets": false,
|
||||
"tooltip": {
|
||||
"show": true,
|
||||
"showHistogram": true
|
||||
},
|
||||
"xAxis": {
|
||||
"show": true
|
||||
},
|
||||
"xBucketNumber": 10,
|
||||
"yAxis": {
|
||||
"format": "short",
|
||||
"logBase": 2,
|
||||
"show": true,
|
||||
"splitFactor": 2
|
||||
},
|
||||
"yBucketBound": "auto"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
@@ -306,7 +495,44 @@
|
||||
"group": "heatmap",
|
||||
"version": "",
|
||||
"spec": {
|
||||
"options": {},
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "heatmap",
|
||||
"originalOptions": {
|
||||
"cards": {},
|
||||
"color": {
|
||||
"cardColor": "#b4ff00",
|
||||
"colorScale": "sqrt",
|
||||
"colorScheme": "interpolateBuGn",
|
||||
"exponent": 0.5,
|
||||
"mode": "spectrum"
|
||||
},
|
||||
"dataFormat": "timeseries",
|
||||
"heatmap": {},
|
||||
"hideZeroBuckets": true,
|
||||
"highlightCards": true,
|
||||
"legend": {
|
||||
"show": true
|
||||
},
|
||||
"reverseYBuckets": false,
|
||||
"tooltip": {
|
||||
"show": true,
|
||||
"showHistogram": true
|
||||
},
|
||||
"xAxis": {
|
||||
"show": true
|
||||
},
|
||||
"xBucketNumber": 10,
|
||||
"yAxis": {
|
||||
"format": "short",
|
||||
"logBase": 10,
|
||||
"show": true,
|
||||
"splitFactor": 5
|
||||
},
|
||||
"yBucketBound": "auto"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
|
||||
+3274
-3
File diff suppressed because it is too large
Load Diff
+3274
-3
File diff suppressed because it is too large
Load Diff
+36
-1
@@ -665,7 +665,42 @@
|
||||
"kind": "heatmap",
|
||||
"spec": {
|
||||
"pluginVersion": "",
|
||||
"options": {},
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "heatmap",
|
||||
"originalOptions": {
|
||||
"cards": {},
|
||||
"color": {
|
||||
"cardColor": "#b4ff00",
|
||||
"colorScale": "sqrt",
|
||||
"colorScheme": "interpolateOranges",
|
||||
"exponent": 0.5,
|
||||
"mode": "spectrum"
|
||||
},
|
||||
"dataFormat": "timeseries",
|
||||
"heatmap": {},
|
||||
"hideZeroBuckets": false,
|
||||
"highlightCards": true,
|
||||
"legend": {
|
||||
"show": false
|
||||
},
|
||||
"reverseYBuckets": false,
|
||||
"tooltip": {
|
||||
"show": true,
|
||||
"showHistogram": false
|
||||
},
|
||||
"xAxis": {
|
||||
"show": true
|
||||
},
|
||||
"yAxis": {
|
||||
"format": "short",
|
||||
"logBase": 1,
|
||||
"show": true
|
||||
},
|
||||
"yBucketBound": "auto"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
|
||||
+36
-1
@@ -691,7 +691,42 @@
|
||||
"group": "heatmap",
|
||||
"version": "",
|
||||
"spec": {
|
||||
"options": {},
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "heatmap",
|
||||
"originalOptions": {
|
||||
"cards": {},
|
||||
"color": {
|
||||
"cardColor": "#b4ff00",
|
||||
"colorScale": "sqrt",
|
||||
"colorScheme": "interpolateOranges",
|
||||
"exponent": 0.5,
|
||||
"mode": "spectrum"
|
||||
},
|
||||
"dataFormat": "timeseries",
|
||||
"heatmap": {},
|
||||
"hideZeroBuckets": false,
|
||||
"highlightCards": true,
|
||||
"legend": {
|
||||
"show": false
|
||||
},
|
||||
"reverseYBuckets": false,
|
||||
"tooltip": {
|
||||
"show": true,
|
||||
"showHistogram": false
|
||||
},
|
||||
"xAxis": {
|
||||
"show": true
|
||||
},
|
||||
"yAxis": {
|
||||
"format": "short",
|
||||
"logBase": 1,
|
||||
"show": true
|
||||
},
|
||||
"yBucketBound": "auto"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
|
||||
+50
@@ -56,6 +56,14 @@
|
||||
"spec": {
|
||||
"pluginVersion": "9.0.0-pre",
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "dashlist",
|
||||
"originalOptions": {
|
||||
"tags": [
|
||||
"panel-tests"
|
||||
]
|
||||
}
|
||||
},
|
||||
"maxItems": 1000,
|
||||
"query": "",
|
||||
"showHeadings": false,
|
||||
@@ -94,6 +102,15 @@
|
||||
"spec": {
|
||||
"pluginVersion": "9.0.0-pre",
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "dashlist",
|
||||
"originalOptions": {
|
||||
"tags": [
|
||||
"gdev",
|
||||
"demo"
|
||||
]
|
||||
}
|
||||
},
|
||||
"maxItems": 1000,
|
||||
"query": "",
|
||||
"showHeadings": false,
|
||||
@@ -133,6 +150,15 @@
|
||||
"spec": {
|
||||
"pluginVersion": "9.0.0-pre",
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "dashlist",
|
||||
"originalOptions": {
|
||||
"tags": [
|
||||
"templating",
|
||||
"gdev"
|
||||
]
|
||||
}
|
||||
},
|
||||
"maxItems": 1000,
|
||||
"query": "",
|
||||
"showHeadings": false,
|
||||
@@ -172,6 +198,15 @@
|
||||
"spec": {
|
||||
"pluginVersion": "9.0.0-pre",
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "dashlist",
|
||||
"originalOptions": {
|
||||
"tags": [
|
||||
"gdev",
|
||||
"datasource-test"
|
||||
]
|
||||
}
|
||||
},
|
||||
"maxItems": 1000,
|
||||
"query": "",
|
||||
"showHeadings": false,
|
||||
@@ -211,6 +246,12 @@
|
||||
"spec": {
|
||||
"pluginVersion": "9.0.0-pre",
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "dashlist",
|
||||
"originalOptions": {
|
||||
"tags": []
|
||||
}
|
||||
},
|
||||
"maxItems": 100,
|
||||
"query": "",
|
||||
"showHeadings": true,
|
||||
@@ -247,6 +288,15 @@
|
||||
"spec": {
|
||||
"pluginVersion": "9.0.0-pre",
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "dashlist",
|
||||
"originalOptions": {
|
||||
"tags": [
|
||||
"gdev",
|
||||
"demo"
|
||||
]
|
||||
}
|
||||
},
|
||||
"maxItems": 1000,
|
||||
"query": "",
|
||||
"showHeadings": false,
|
||||
|
||||
+50
@@ -58,6 +58,14 @@
|
||||
"version": "9.0.0-pre",
|
||||
"spec": {
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "dashlist",
|
||||
"originalOptions": {
|
||||
"tags": [
|
||||
"panel-tests"
|
||||
]
|
||||
}
|
||||
},
|
||||
"maxItems": 1000,
|
||||
"query": "",
|
||||
"showHeadings": false,
|
||||
@@ -97,6 +105,15 @@
|
||||
"version": "9.0.0-pre",
|
||||
"spec": {
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "dashlist",
|
||||
"originalOptions": {
|
||||
"tags": [
|
||||
"gdev",
|
||||
"demo"
|
||||
]
|
||||
}
|
||||
},
|
||||
"maxItems": 1000,
|
||||
"query": "",
|
||||
"showHeadings": false,
|
||||
@@ -137,6 +154,15 @@
|
||||
"version": "9.0.0-pre",
|
||||
"spec": {
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "dashlist",
|
||||
"originalOptions": {
|
||||
"tags": [
|
||||
"templating",
|
||||
"gdev"
|
||||
]
|
||||
}
|
||||
},
|
||||
"maxItems": 1000,
|
||||
"query": "",
|
||||
"showHeadings": false,
|
||||
@@ -177,6 +203,15 @@
|
||||
"version": "9.0.0-pre",
|
||||
"spec": {
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "dashlist",
|
||||
"originalOptions": {
|
||||
"tags": [
|
||||
"gdev",
|
||||
"datasource-test"
|
||||
]
|
||||
}
|
||||
},
|
||||
"maxItems": 1000,
|
||||
"query": "",
|
||||
"showHeadings": false,
|
||||
@@ -217,6 +252,12 @@
|
||||
"version": "9.0.0-pre",
|
||||
"spec": {
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "dashlist",
|
||||
"originalOptions": {
|
||||
"tags": []
|
||||
}
|
||||
},
|
||||
"maxItems": 100,
|
||||
"query": "",
|
||||
"showHeadings": true,
|
||||
@@ -254,6 +295,15 @@
|
||||
"version": "9.0.0-pre",
|
||||
"spec": {
|
||||
"options": {
|
||||
"__angularMigration": {
|
||||
"autoMigrateFrom": "dashlist",
|
||||
"originalOptions": {
|
||||
"tags": [
|
||||
"gdev",
|
||||
"demo"
|
||||
]
|
||||
}
|
||||
},
|
||||
"maxItems": 1000,
|
||||
"query": "",
|
||||
"showHeadings": false,
|
||||
|
||||
@@ -2296,20 +2296,24 @@ func buildVizConfig(panelMap map[string]interface{}) dashv2alpha1.DashboardVizCo
|
||||
// We check two cases:
|
||||
// 1. Panel already has autoMigrateFrom set (from v0→v1 migration) - panel type already converted
|
||||
// 2. Panel type is a known Angular panel - need to convert type AND set autoMigrateFrom
|
||||
// 3. Panel has original options - need to set autoMigrateFrom and originalOptions
|
||||
autoMigrateFrom, hasAutoMigrateFrom := panelMap["autoMigrateFrom"].(string)
|
||||
originalOptions := extractAngularOptions(panelMap)
|
||||
|
||||
if !hasAutoMigrateFrom || autoMigrateFrom == "" {
|
||||
// Check if panel type is an Angular type that needs migration
|
||||
if newType := getAngularPanelMigration(panelType, panelMap); newType != "" {
|
||||
autoMigrateFrom = panelType // Original Angular type
|
||||
panelType = newType // New modern type
|
||||
} else if len(originalOptions) > 0 {
|
||||
autoMigrateFrom = panelType
|
||||
}
|
||||
}
|
||||
|
||||
if autoMigrateFrom != "" {
|
||||
options["__angularMigration"] = map[string]interface{}{
|
||||
"autoMigrateFrom": autoMigrateFrom,
|
||||
"originalOptions": extractAngularOptions(panelMap),
|
||||
"originalOptions": originalOptions,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-9
@@ -290,6 +290,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"content": "# Graph panel \u003e\u003e Timeseries panel\n\nKnown issues:\n* hiding null/empty series\n* time regions",
|
||||
"datasource": {
|
||||
"type": "grafana-testdata-datasource"
|
||||
},
|
||||
@@ -300,15 +301,7 @@
|
||||
"y": 0
|
||||
},
|
||||
"id": 6,
|
||||
"options": {
|
||||
"code": {
|
||||
"language": "plaintext",
|
||||
"showLineNumbers": false,
|
||||
"showMiniMap": false
|
||||
},
|
||||
"content": "# Graph panel \u003e\u003e Timeseries panel\n\nKnown issues:\n* hiding null/empty series\n* time regions",
|
||||
"mode": "markdown"
|
||||
},
|
||||
"mode": "markdown",
|
||||
"pluginVersion": "11.0.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
|
||||
Vendored
+145
-223
@@ -75,10 +75,9 @@
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": false,
|
||||
"rounded": true,
|
||||
"spotlight": false
|
||||
"gradient": false
|
||||
},
|
||||
"barShape": "rounded",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -154,10 +153,9 @@
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": true,
|
||||
"gradient": false,
|
||||
"rounded": true,
|
||||
"spotlight": false
|
||||
"gradient": false
|
||||
},
|
||||
"barShape": "rounded",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -233,10 +231,9 @@
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": false,
|
||||
"rounded": true,
|
||||
"spotlight": false
|
||||
"gradient": false
|
||||
},
|
||||
"barShape": "rounded",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -305,85 +302,6 @@
|
||||
"x": 12,
|
||||
"y": 1
|
||||
},
|
||||
"id": 5,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barWidthFactor": 0.4,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": false,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"lastNotNull"
|
||||
],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"segmentCount": 1,
|
||||
"segmentSpacing": 0.3,
|
||||
"shape": "circle",
|
||||
"showThresholdLabels": false,
|
||||
"showThresholdMarkers": false,
|
||||
"sparkline": false
|
||||
},
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"alias": "1",
|
||||
"datasource": {
|
||||
"type": "grafana-testdata-datasource"
|
||||
},
|
||||
"max": 100,
|
||||
"min": 1,
|
||||
"noise": 22,
|
||||
"refId": "A",
|
||||
"scenarioId": "random_walk",
|
||||
"spread": 22,
|
||||
"startValue": 1
|
||||
}
|
||||
],
|
||||
"title": "Spotlight",
|
||||
"type": "radialbar"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "grafana-testdata-datasource"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "thresholds"
|
||||
},
|
||||
"mappings": [],
|
||||
"max": 100,
|
||||
"min": 0,
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 6,
|
||||
"w": 4,
|
||||
"x": 16,
|
||||
"y": 1
|
||||
},
|
||||
"id": 8,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
@@ -391,10 +309,9 @@
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": false,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": false
|
||||
},
|
||||
"barShape": "rounded",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -460,8 +377,8 @@
|
||||
"gridPos": {
|
||||
"h": 6,
|
||||
"w": 4,
|
||||
"x": 0,
|
||||
"y": 7
|
||||
"x": 16,
|
||||
"y": 1
|
||||
},
|
||||
"id": 22,
|
||||
"maxDataPoints": 20,
|
||||
@@ -470,10 +387,9 @@
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": false,
|
||||
"rounded": false,
|
||||
"spotlight": true
|
||||
"gradient": false
|
||||
},
|
||||
"barShape": "flat",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -539,8 +455,8 @@
|
||||
"gridPos": {
|
||||
"h": 6,
|
||||
"w": 4,
|
||||
"x": 4,
|
||||
"y": 7
|
||||
"x": 20,
|
||||
"y": 1
|
||||
},
|
||||
"id": 23,
|
||||
"maxDataPoints": 20,
|
||||
@@ -549,10 +465,9 @@
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": false,
|
||||
"rounded": false,
|
||||
"spotlight": true
|
||||
"gradient": false
|
||||
},
|
||||
"barShape": "flat",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -593,7 +508,7 @@
|
||||
"h": 1,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 13
|
||||
"y": 7
|
||||
},
|
||||
"id": 17,
|
||||
"panels": [],
|
||||
@@ -630,9 +545,9 @@
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 6,
|
||||
"w": 5,
|
||||
"w": 4,
|
||||
"x": 0,
|
||||
"y": 14
|
||||
"y": 8
|
||||
},
|
||||
"id": 18,
|
||||
"maxDataPoints": 20,
|
||||
@@ -641,10 +556,9 @@
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": false,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": false
|
||||
},
|
||||
"barShape": "rounded",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -709,9 +623,9 @@
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 6,
|
||||
"w": 5,
|
||||
"x": 5,
|
||||
"y": 14
|
||||
"w": 4,
|
||||
"x": 4,
|
||||
"y": 8
|
||||
},
|
||||
"id": 19,
|
||||
"maxDataPoints": 20,
|
||||
@@ -720,10 +634,9 @@
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": false,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": false
|
||||
},
|
||||
"barShape": "rounded",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -788,9 +701,9 @@
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 6,
|
||||
"w": 5,
|
||||
"x": 10,
|
||||
"y": 14
|
||||
"w": 4,
|
||||
"x": 8,
|
||||
"y": 8
|
||||
},
|
||||
"id": 20,
|
||||
"maxDataPoints": 20,
|
||||
@@ -799,10 +712,9 @@
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": false,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": false
|
||||
},
|
||||
"barShape": "rounded",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -867,9 +779,9 @@
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 6,
|
||||
"w": 5,
|
||||
"x": 15,
|
||||
"y": 14
|
||||
"w": 4,
|
||||
"x": 12,
|
||||
"y": 8
|
||||
},
|
||||
"id": 21,
|
||||
"maxDataPoints": 20,
|
||||
@@ -878,10 +790,9 @@
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": false,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": false
|
||||
},
|
||||
"barShape": "rounded",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -922,7 +833,7 @@
|
||||
"h": 1,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 20
|
||||
"y": 14
|
||||
},
|
||||
"id": 24,
|
||||
"panels": [],
|
||||
@@ -963,9 +874,9 @@
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 6,
|
||||
"w": 6,
|
||||
"w": 4,
|
||||
"x": 0,
|
||||
"y": 21
|
||||
"y": 15
|
||||
},
|
||||
"id": 25,
|
||||
"maxDataPoints": 20,
|
||||
@@ -974,10 +885,9 @@
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": false,
|
||||
"rounded": false,
|
||||
"spotlight": false
|
||||
"gradient": false
|
||||
},
|
||||
"barShape": "flat",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -1042,9 +952,9 @@
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 6,
|
||||
"w": 6,
|
||||
"x": 6,
|
||||
"y": 21
|
||||
"w": 4,
|
||||
"x": 4,
|
||||
"y": 15
|
||||
},
|
||||
"id": 26,
|
||||
"maxDataPoints": 20,
|
||||
@@ -1053,10 +963,9 @@
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": false,
|
||||
"rounded": false,
|
||||
"spotlight": false
|
||||
"gradient": false
|
||||
},
|
||||
"barShape": "flat",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -1121,9 +1030,9 @@
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 6,
|
||||
"w": 5,
|
||||
"x": 12,
|
||||
"y": 21
|
||||
"w": 4,
|
||||
"x": 8,
|
||||
"y": 15
|
||||
},
|
||||
"id": 29,
|
||||
"maxDataPoints": 20,
|
||||
@@ -1132,10 +1041,9 @@
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": true,
|
||||
"rounded": false,
|
||||
"spotlight": false
|
||||
"gradient": true
|
||||
},
|
||||
"barShape": "flat",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -1199,10 +1107,10 @@
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 6,
|
||||
"x": 0,
|
||||
"y": 27
|
||||
"h": 6,
|
||||
"w": 4,
|
||||
"x": 12,
|
||||
"y": 15
|
||||
},
|
||||
"id": 30,
|
||||
"maxDataPoints": 20,
|
||||
@@ -1211,10 +1119,9 @@
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": false,
|
||||
"rounded": false,
|
||||
"spotlight": false
|
||||
"gradient": false
|
||||
},
|
||||
"barShape": "flat",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -1278,10 +1185,10 @@
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 6,
|
||||
"x": 6,
|
||||
"y": 27
|
||||
"h": 6,
|
||||
"w": 4,
|
||||
"x": 16,
|
||||
"y": 15
|
||||
},
|
||||
"id": 28,
|
||||
"maxDataPoints": 20,
|
||||
@@ -1290,10 +1197,9 @@
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": false,
|
||||
"rounded": false,
|
||||
"spotlight": false
|
||||
"gradient": false
|
||||
},
|
||||
"barShape": "flat",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -1330,7 +1236,7 @@
|
||||
"h": 1,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 34
|
||||
"y": 21
|
||||
},
|
||||
"id": 31,
|
||||
"panels": [],
|
||||
@@ -1377,7 +1283,7 @@
|
||||
"h": 10,
|
||||
"w": 7,
|
||||
"x": 0,
|
||||
"y": 35
|
||||
"y": 22
|
||||
},
|
||||
"id": 32,
|
||||
"maxDataPoints": 20,
|
||||
@@ -1386,10 +1292,9 @@
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": true,
|
||||
"rounded": false,
|
||||
"spotlight": false
|
||||
"gradient": true
|
||||
},
|
||||
"barShape": "flat",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -1460,7 +1365,7 @@
|
||||
"h": 10,
|
||||
"w": 7,
|
||||
"x": 7,
|
||||
"y": 35
|
||||
"y": 22
|
||||
},
|
||||
"id": 34,
|
||||
"maxDataPoints": 20,
|
||||
@@ -1469,10 +1374,9 @@
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": true,
|
||||
"rounded": false,
|
||||
"spotlight": false
|
||||
"gradient": true
|
||||
},
|
||||
"barShape": "flat",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -1543,7 +1447,7 @@
|
||||
"h": 10,
|
||||
"w": 6,
|
||||
"x": 14,
|
||||
"y": 35
|
||||
"y": 22
|
||||
},
|
||||
"id": 33,
|
||||
"maxDataPoints": 20,
|
||||
@@ -1552,10 +1456,9 @@
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": true,
|
||||
"rounded": false,
|
||||
"spotlight": false
|
||||
"gradient": true
|
||||
},
|
||||
"barShape": "flat",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -1592,7 +1495,7 @@
|
||||
"h": 1,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 45
|
||||
"y": 32
|
||||
},
|
||||
"id": 6,
|
||||
"panels": [],
|
||||
@@ -1633,20 +1536,20 @@
|
||||
"h": 6,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 46
|
||||
"y": 33
|
||||
},
|
||||
"id": 9,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barWidth": 12,
|
||||
"barWidthFactor": 0.4,
|
||||
"barShape": "rounded",
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": true,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": true
|
||||
},
|
||||
"endpointMarker": "glow",
|
||||
"glow": "both",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -1661,8 +1564,7 @@
|
||||
"shape": "circle",
|
||||
"showThresholdLabels": false,
|
||||
"showThresholdMarkers": false,
|
||||
"sparkline": false,
|
||||
"spotlight": true
|
||||
"sparkline": false
|
||||
},
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"targets": [
|
||||
@@ -1717,7 +1619,7 @@
|
||||
"h": 6,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 52
|
||||
"y": 39
|
||||
},
|
||||
"id": 11,
|
||||
"maxDataPoints": 20,
|
||||
@@ -1727,10 +1629,9 @@
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": true,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": true
|
||||
},
|
||||
"barShape": "rounded",
|
||||
"glow": "both",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -1745,8 +1646,7 @@
|
||||
"shape": "gauge",
|
||||
"showThresholdLabels": false,
|
||||
"showThresholdMarkers": false,
|
||||
"sparkline": true,
|
||||
"spotlight": true
|
||||
"sparkline": true
|
||||
},
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"targets": [
|
||||
@@ -1773,7 +1673,7 @@
|
||||
"h": 1,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 58
|
||||
"y": 45
|
||||
},
|
||||
"id": 12,
|
||||
"panels": [],
|
||||
@@ -1815,7 +1715,7 @@
|
||||
"h": 7,
|
||||
"w": 4,
|
||||
"x": 0,
|
||||
"y": 59
|
||||
"y": 46
|
||||
},
|
||||
"id": 13,
|
||||
"maxDataPoints": 20,
|
||||
@@ -1825,10 +1725,9 @@
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": true,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": true
|
||||
},
|
||||
"barShape": "rounded",
|
||||
"glow": "both",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -1843,8 +1742,7 @@
|
||||
"shape": "circle",
|
||||
"showThresholdLabels": false,
|
||||
"showThresholdMarkers": false,
|
||||
"sparkline": false,
|
||||
"spotlight": true
|
||||
"sparkline": false
|
||||
},
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"targets": [
|
||||
@@ -1862,6 +1760,22 @@
|
||||
"startValue": 0
|
||||
}
|
||||
],
|
||||
"transformations": [
|
||||
{
|
||||
"id": "calculateField",
|
||||
"options": {
|
||||
"mode": "unary",
|
||||
"reduce": {
|
||||
"reducer": "sum"
|
||||
},
|
||||
"replaceFields": true,
|
||||
"unary": {
|
||||
"operator": "round",
|
||||
"fieldName": "A-series"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"title": "Active gateways",
|
||||
"type": "radialbar"
|
||||
},
|
||||
@@ -1900,7 +1814,7 @@
|
||||
"h": 7,
|
||||
"w": 5,
|
||||
"x": 4,
|
||||
"y": 59
|
||||
"y": 46
|
||||
},
|
||||
"id": 14,
|
||||
"maxDataPoints": 20,
|
||||
@@ -1910,10 +1824,9 @@
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": true,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": true
|
||||
},
|
||||
"barShape": "rounded",
|
||||
"glow": "both",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -1928,8 +1841,7 @@
|
||||
"shape": "circle",
|
||||
"showThresholdLabels": false,
|
||||
"showThresholdMarkers": false,
|
||||
"sparkline": false,
|
||||
"spotlight": true
|
||||
"sparkline": false
|
||||
},
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"targets": [
|
||||
@@ -1947,6 +1859,22 @@
|
||||
"startValue": 0
|
||||
}
|
||||
],
|
||||
"transformations": [
|
||||
{
|
||||
"id": "calculateField",
|
||||
"options": {
|
||||
"mode": "unary",
|
||||
"reduce": {
|
||||
"reducer": "sum"
|
||||
},
|
||||
"replaceFields": true,
|
||||
"unary": {
|
||||
"operator": "round",
|
||||
"fieldName": "A-series"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"title": "Active pods",
|
||||
"type": "radialbar"
|
||||
},
|
||||
@@ -1984,7 +1912,7 @@
|
||||
"h": 7,
|
||||
"w": 5,
|
||||
"x": 9,
|
||||
"y": 59
|
||||
"y": 46
|
||||
},
|
||||
"id": 15,
|
||||
"maxDataPoints": 20,
|
||||
@@ -1994,10 +1922,9 @@
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": true,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": true
|
||||
},
|
||||
"barShape": "rounded",
|
||||
"glow": "both",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -2012,8 +1939,7 @@
|
||||
"shape": "circle",
|
||||
"showThresholdLabels": false,
|
||||
"showThresholdMarkers": false,
|
||||
"sparkline": false,
|
||||
"spotlight": true
|
||||
"sparkline": false
|
||||
},
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"targets": [
|
||||
@@ -2068,7 +1994,7 @@
|
||||
"h": 7,
|
||||
"w": 6,
|
||||
"x": 14,
|
||||
"y": 59
|
||||
"y": 46
|
||||
},
|
||||
"id": 16,
|
||||
"maxDataPoints": 20,
|
||||
@@ -2078,10 +2004,9 @@
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": true,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": true
|
||||
},
|
||||
"barShape": "rounded",
|
||||
"glow": "both",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -2096,8 +2021,7 @@
|
||||
"shape": "circle",
|
||||
"showThresholdLabels": false,
|
||||
"showThresholdMarkers": false,
|
||||
"sparkline": false,
|
||||
"spotlight": true
|
||||
"sparkline": false
|
||||
},
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"targets": [
|
||||
@@ -2124,7 +2048,7 @@
|
||||
"h": 1,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 66
|
||||
"y": 53
|
||||
},
|
||||
"id": 35,
|
||||
"panels": [],
|
||||
@@ -2155,10 +2079,10 @@
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 6,
|
||||
"h": 5,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 67
|
||||
"y": 54
|
||||
},
|
||||
"id": 36,
|
||||
"options": {
|
||||
@@ -2166,10 +2090,9 @@
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": true,
|
||||
"rounded": false,
|
||||
"spotlight": false
|
||||
"gradient": true
|
||||
},
|
||||
"barShape": "flat",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -2223,10 +2146,10 @@
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 6,
|
||||
"x": 6,
|
||||
"y": 67
|
||||
"h": 5,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 54
|
||||
},
|
||||
"id": 37,
|
||||
"options": {
|
||||
@@ -2234,10 +2157,9 @@
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": true,
|
||||
"rounded": false,
|
||||
"spotlight": false
|
||||
"gradient": true
|
||||
},
|
||||
"barShape": "flat",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
@@ -2279,4 +2201,4 @@
|
||||
"title": "Panel tests - Gauge (new)",
|
||||
"uid": "panel-tests-gauge-new",
|
||||
"weekStart": ""
|
||||
}
|
||||
}
|
||||
|
||||
+2
-4
@@ -955,9 +955,7 @@
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": false,
|
||||
"rounded": false,
|
||||
"spotlight": false
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -1162,4 +1160,4 @@
|
||||
"title": "Panel tests - Old gauge to new",
|
||||
"uid": "panel-tests-old-gauge-to-new",
|
||||
"weekStart": ""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -335,6 +335,9 @@ rudderstack_data_plane_url =
|
||||
# Rudderstack SDK url, optional, only valid if rudderstack_write_key and rudderstack_data_plane_url is also set
|
||||
rudderstack_sdk_url =
|
||||
|
||||
# Rudderstack v3 SDK, optional, defaults to false. If set, Rudderstack v3 SDK will be used instead of v1
|
||||
rudderstack_v3_sdk_url =
|
||||
|
||||
# Rudderstack Config url, optional, used by Rudderstack SDK to fetch source config
|
||||
rudderstack_config_url =
|
||||
|
||||
|
||||
@@ -322,6 +322,9 @@
|
||||
# Rudderstack SDK url, optional, only valid if rudderstack_write_key and rudderstack_data_plane_url is also set
|
||||
;rudderstack_sdk_url =
|
||||
|
||||
# Rudderstack v3 SDK, optional, defaults to false. If set, Rudderstack v3 SDK will be used instead of v1
|
||||
;rudderstack_v3_sdk_url =
|
||||
|
||||
# Rudderstack Config url, optional, used by Rudderstack SDK to fetch source config
|
||||
;rudderstack_config_url =
|
||||
|
||||
|
||||
@@ -299,15 +299,9 @@
|
||||
"y": 0
|
||||
},
|
||||
"id": 6,
|
||||
"options": {
|
||||
"code": {
|
||||
"language": "plaintext",
|
||||
"showLineNumbers": false,
|
||||
"showMiniMap": false
|
||||
},
|
||||
"content": "# Graph panel >> Timeseries panel\n\nKnown issues:\n* hiding null/empty series\n* time regions",
|
||||
"mode": "markdown"
|
||||
},
|
||||
"options": {},
|
||||
"content": "# Graph panel >> Timeseries panel\n\nKnown issues:\n* hiding null/empty series\n* time regions",
|
||||
"mode": "markdown",
|
||||
"pluginVersion": "11.0.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
|
||||
@@ -71,13 +71,12 @@
|
||||
"id": 1,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidthFactor": 0.4,
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": false,
|
||||
"rounded": true,
|
||||
"spotlight": false
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -148,13 +147,12 @@
|
||||
"id": 4,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidthFactor": 0.4,
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": true,
|
||||
"gradient": false,
|
||||
"rounded": true,
|
||||
"spotlight": false
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -225,13 +223,12 @@
|
||||
"id": 3,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidthFactor": 0.4,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": false,
|
||||
"rounded": true,
|
||||
"spotlight": false
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -299,93 +296,15 @@
|
||||
"x": 12,
|
||||
"y": 1
|
||||
},
|
||||
"id": 5,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barWidthFactor": 0.4,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": false,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": ["lastNotNull"],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"segmentCount": 1,
|
||||
"segmentSpacing": 0.3,
|
||||
"shape": "circle",
|
||||
"showThresholdLabels": false,
|
||||
"showThresholdMarkers": false,
|
||||
"sparkline": false
|
||||
},
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"alias": "1",
|
||||
"datasource": {
|
||||
"type": "grafana-testdata-datasource"
|
||||
},
|
||||
"max": 100,
|
||||
"min": 1,
|
||||
"noise": 22,
|
||||
"refId": "A",
|
||||
"scenarioId": "random_walk",
|
||||
"spread": 22,
|
||||
"startValue": 1
|
||||
}
|
||||
],
|
||||
"title": "Spotlight",
|
||||
"type": "radialbar"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "grafana-testdata-datasource"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "thresholds"
|
||||
},
|
||||
"mappings": [],
|
||||
"max": 100,
|
||||
"min": 0,
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 6,
|
||||
"w": 4,
|
||||
"x": 16,
|
||||
"y": 1
|
||||
},
|
||||
"id": 8,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidthFactor": 0.4,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": false,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -450,19 +369,18 @@
|
||||
"gridPos": {
|
||||
"h": 6,
|
||||
"w": 4,
|
||||
"x": 0,
|
||||
"y": 7
|
||||
"x": 16,
|
||||
"y": 1
|
||||
},
|
||||
"id": 22,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "flat",
|
||||
"barWidthFactor": 0.72,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": false,
|
||||
"rounded": false,
|
||||
"spotlight": true
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -527,19 +445,18 @@
|
||||
"gridPos": {
|
||||
"h": 6,
|
||||
"w": 4,
|
||||
"x": 4,
|
||||
"y": 7
|
||||
"x": 20,
|
||||
"y": 1
|
||||
},
|
||||
"id": 23,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "flat",
|
||||
"barWidthFactor": 0.72,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": false,
|
||||
"rounded": false,
|
||||
"spotlight": true
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -579,7 +496,7 @@
|
||||
"h": 1,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 13
|
||||
"y": 7
|
||||
},
|
||||
"id": 17,
|
||||
"panels": [],
|
||||
@@ -616,20 +533,19 @@
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 6,
|
||||
"w": 5,
|
||||
"w": 4,
|
||||
"x": 0,
|
||||
"y": 14
|
||||
"y": 8
|
||||
},
|
||||
"id": 18,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidthFactor": 0.1,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": false,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -693,20 +609,19 @@
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 6,
|
||||
"w": 5,
|
||||
"x": 5,
|
||||
"y": 14
|
||||
"w": 4,
|
||||
"x": 4,
|
||||
"y": 8
|
||||
},
|
||||
"id": 19,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidthFactor": 0.32,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": false,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -770,20 +685,19 @@
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 6,
|
||||
"w": 5,
|
||||
"x": 10,
|
||||
"y": 14
|
||||
"w": 4,
|
||||
"x": 8,
|
||||
"y": 8
|
||||
},
|
||||
"id": 20,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidthFactor": 0.57,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": false,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -847,20 +761,19 @@
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 6,
|
||||
"w": 5,
|
||||
"x": 15,
|
||||
"y": 14
|
||||
"w": 4,
|
||||
"x": 12,
|
||||
"y": 8
|
||||
},
|
||||
"id": 21,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidthFactor": 0.8,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": false,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -900,7 +813,7 @@
|
||||
"h": 1,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 20
|
||||
"y": 14
|
||||
},
|
||||
"id": 24,
|
||||
"panels": [],
|
||||
@@ -941,20 +854,19 @@
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 6,
|
||||
"w": 6,
|
||||
"w": 4,
|
||||
"x": 0,
|
||||
"y": 21
|
||||
"y": 15
|
||||
},
|
||||
"id": 25,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "flat",
|
||||
"barWidthFactor": 0.9,
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": false,
|
||||
"rounded": false,
|
||||
"spotlight": false
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -1018,20 +930,19 @@
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 6,
|
||||
"w": 6,
|
||||
"x": 6,
|
||||
"y": 21
|
||||
"w": 4,
|
||||
"x": 4,
|
||||
"y": 15
|
||||
},
|
||||
"id": 26,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "flat",
|
||||
"barWidthFactor": 0.72,
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": false,
|
||||
"rounded": false,
|
||||
"spotlight": false
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -1095,20 +1006,19 @@
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 6,
|
||||
"w": 5,
|
||||
"x": 12,
|
||||
"y": 21
|
||||
"w": 4,
|
||||
"x": 8,
|
||||
"y": 15
|
||||
},
|
||||
"id": 29,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "flat",
|
||||
"barWidthFactor": 0.72,
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": true,
|
||||
"rounded": false,
|
||||
"spotlight": false
|
||||
"gradient": true
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -1171,21 +1081,20 @@
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 6,
|
||||
"x": 0,
|
||||
"y": 27
|
||||
"h": 6,
|
||||
"w": 4,
|
||||
"x": 12,
|
||||
"y": 15
|
||||
},
|
||||
"id": 30,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "flat",
|
||||
"barWidthFactor": 0.9,
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": false,
|
||||
"rounded": false,
|
||||
"spotlight": false
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -1248,21 +1157,20 @@
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 6,
|
||||
"x": 6,
|
||||
"y": 27
|
||||
"h": 6,
|
||||
"w": 4,
|
||||
"x": 16,
|
||||
"y": 15
|
||||
},
|
||||
"id": 28,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "flat",
|
||||
"barWidthFactor": 0.72,
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": false,
|
||||
"rounded": false,
|
||||
"spotlight": false
|
||||
"gradient": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -1298,7 +1206,7 @@
|
||||
"h": 1,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 34
|
||||
"y": 21
|
||||
},
|
||||
"id": 31,
|
||||
"panels": [],
|
||||
@@ -1345,18 +1253,17 @@
|
||||
"h": 10,
|
||||
"w": 7,
|
||||
"x": 0,
|
||||
"y": 35
|
||||
"y": 22
|
||||
},
|
||||
"id": 32,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "flat",
|
||||
"barWidthFactor": 0.9,
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": true,
|
||||
"rounded": false,
|
||||
"spotlight": false
|
||||
"gradient": true
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -1426,18 +1333,17 @@
|
||||
"h": 10,
|
||||
"w": 7,
|
||||
"x": 7,
|
||||
"y": 35
|
||||
"y": 22
|
||||
},
|
||||
"id": 34,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "flat",
|
||||
"barWidthFactor": 0.9,
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": true,
|
||||
"rounded": false,
|
||||
"spotlight": false
|
||||
"gradient": true
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -1507,18 +1413,17 @@
|
||||
"h": 10,
|
||||
"w": 6,
|
||||
"x": 14,
|
||||
"y": 35
|
||||
"y": 22
|
||||
},
|
||||
"id": 33,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "flat",
|
||||
"barWidthFactor": 0.9,
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": true,
|
||||
"rounded": false,
|
||||
"spotlight": false
|
||||
"gradient": true
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -1554,7 +1459,7 @@
|
||||
"h": 1,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 45
|
||||
"y": 32
|
||||
},
|
||||
"id": 6,
|
||||
"panels": [],
|
||||
@@ -1595,20 +1500,20 @@
|
||||
"h": 6,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 46
|
||||
"y": 33
|
||||
},
|
||||
"id": 9,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidth": 12,
|
||||
"barWidthFactor": 0.4,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": true,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": true
|
||||
},
|
||||
"endpointMarker": "glow",
|
||||
"glow": "both",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -1621,8 +1526,7 @@
|
||||
"shape": "circle",
|
||||
"showThresholdLabels": false,
|
||||
"showThresholdMarkers": false,
|
||||
"sparkline": false,
|
||||
"spotlight": true
|
||||
"sparkline": false
|
||||
},
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"targets": [
|
||||
@@ -1677,19 +1581,18 @@
|
||||
"h": 6,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 52
|
||||
"y": 39
|
||||
},
|
||||
"id": 11,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidth": 12,
|
||||
"barWidthFactor": 0.4,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": true,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": true
|
||||
},
|
||||
"glow": "both",
|
||||
"orientation": "auto",
|
||||
@@ -1703,8 +1606,7 @@
|
||||
"shape": "gauge",
|
||||
"showThresholdLabels": false,
|
||||
"showThresholdMarkers": false,
|
||||
"sparkline": true,
|
||||
"spotlight": true
|
||||
"sparkline": true
|
||||
},
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"targets": [
|
||||
@@ -1731,7 +1633,7 @@
|
||||
"h": 1,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 58
|
||||
"y": 45
|
||||
},
|
||||
"id": 12,
|
||||
"panels": [],
|
||||
@@ -1773,19 +1675,18 @@
|
||||
"h": 7,
|
||||
"w": 4,
|
||||
"x": 0,
|
||||
"y": 59
|
||||
"y": 46
|
||||
},
|
||||
"id": 13,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidth": 12,
|
||||
"barWidthFactor": 0.49,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": true,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": true
|
||||
},
|
||||
"glow": "both",
|
||||
"orientation": "auto",
|
||||
@@ -1799,8 +1700,7 @@
|
||||
"shape": "circle",
|
||||
"showThresholdLabels": false,
|
||||
"showThresholdMarkers": false,
|
||||
"sparkline": false,
|
||||
"spotlight": true
|
||||
"sparkline": false
|
||||
},
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"targets": [
|
||||
@@ -1818,6 +1718,22 @@
|
||||
"startValue": 0
|
||||
}
|
||||
],
|
||||
"transformations": [
|
||||
{
|
||||
"id": "calculateField",
|
||||
"options": {
|
||||
"mode": "unary",
|
||||
"reduce": {
|
||||
"reducer": "sum"
|
||||
},
|
||||
"replaceFields": true,
|
||||
"unary": {
|
||||
"operator": "round",
|
||||
"fieldName": "A-series"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"title": "Active gateways",
|
||||
"type": "radialbar"
|
||||
},
|
||||
@@ -1856,19 +1772,18 @@
|
||||
"h": 7,
|
||||
"w": 5,
|
||||
"x": 4,
|
||||
"y": 59
|
||||
"y": 46
|
||||
},
|
||||
"id": 14,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidth": 12,
|
||||
"barWidthFactor": 0.49,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": true,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": true
|
||||
},
|
||||
"glow": "both",
|
||||
"orientation": "auto",
|
||||
@@ -1882,8 +1797,7 @@
|
||||
"shape": "circle",
|
||||
"showThresholdLabels": false,
|
||||
"showThresholdMarkers": false,
|
||||
"sparkline": false,
|
||||
"spotlight": true
|
||||
"sparkline": false
|
||||
},
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"targets": [
|
||||
@@ -1901,6 +1815,22 @@
|
||||
"startValue": 0
|
||||
}
|
||||
],
|
||||
"transformations": [
|
||||
{
|
||||
"id": "calculateField",
|
||||
"options": {
|
||||
"mode": "unary",
|
||||
"reduce": {
|
||||
"reducer": "sum"
|
||||
},
|
||||
"replaceFields": true,
|
||||
"unary": {
|
||||
"operator": "round",
|
||||
"fieldName": "A-series"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"title": "Active pods",
|
||||
"type": "radialbar"
|
||||
},
|
||||
@@ -1938,19 +1868,18 @@
|
||||
"h": 7,
|
||||
"w": 5,
|
||||
"x": 9,
|
||||
"y": 59
|
||||
"y": 46
|
||||
},
|
||||
"id": 15,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidth": 12,
|
||||
"barWidthFactor": 0.84,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": true,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": true
|
||||
},
|
||||
"glow": "both",
|
||||
"orientation": "auto",
|
||||
@@ -1964,8 +1893,7 @@
|
||||
"shape": "circle",
|
||||
"showThresholdLabels": false,
|
||||
"showThresholdMarkers": false,
|
||||
"sparkline": false,
|
||||
"spotlight": true
|
||||
"sparkline": false
|
||||
},
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"targets": [
|
||||
@@ -2020,19 +1948,18 @@
|
||||
"h": 7,
|
||||
"w": 6,
|
||||
"x": 14,
|
||||
"y": 59
|
||||
"y": 46
|
||||
},
|
||||
"id": 16,
|
||||
"maxDataPoints": 20,
|
||||
"options": {
|
||||
"barShape": "rounded",
|
||||
"barWidth": 12,
|
||||
"barWidthFactor": 0.66,
|
||||
"effects": {
|
||||
"barGlow": true,
|
||||
"centerGlow": true,
|
||||
"gradient": true,
|
||||
"rounded": true,
|
||||
"spotlight": true
|
||||
"gradient": true
|
||||
},
|
||||
"glow": "both",
|
||||
"orientation": "auto",
|
||||
@@ -2046,8 +1973,7 @@
|
||||
"shape": "circle",
|
||||
"showThresholdLabels": false,
|
||||
"showThresholdMarkers": false,
|
||||
"sparkline": false,
|
||||
"spotlight": true
|
||||
"sparkline": false
|
||||
},
|
||||
"pluginVersion": "13.0.0-pre",
|
||||
"targets": [
|
||||
@@ -2074,7 +2000,7 @@
|
||||
"h": 1,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 66
|
||||
"y": 53
|
||||
},
|
||||
"id": 35,
|
||||
"panels": [],
|
||||
@@ -2105,20 +2031,19 @@
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 6,
|
||||
"h": 5,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 67
|
||||
"y": 54
|
||||
},
|
||||
"id": 36,
|
||||
"options": {
|
||||
"barShape": "flat",
|
||||
"barWidthFactor": 0.5,
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": true,
|
||||
"rounded": false,
|
||||
"spotlight": false
|
||||
"gradient": true
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -2171,20 +2096,19 @@
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 6,
|
||||
"x": 6,
|
||||
"y": 67
|
||||
"h": 5,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 54
|
||||
},
|
||||
"id": 37,
|
||||
"options": {
|
||||
"barShape": "flat",
|
||||
"barWidthFactor": 0.5,
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"gradient": true,
|
||||
"rounded": false,
|
||||
"spotlight": false
|
||||
"gradient": true
|
||||
},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
@@ -2224,5 +2148,6 @@
|
||||
"timezone": "browser",
|
||||
"title": "Panel tests - Gauge (new)",
|
||||
"uid": "panel-tests-gauge-new",
|
||||
"version": 9
|
||||
"version": 22,
|
||||
"weekStart": ""
|
||||
}
|
||||
|
||||
@@ -956,8 +956,6 @@
|
||||
"effects": {
|
||||
"barGlow": false,
|
||||
"centerGlow": false,
|
||||
"rounded": false,
|
||||
"spotlight": false,
|
||||
"gradient": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,18 +54,6 @@ SCIM offers several advantages for managing users and teams in Grafana:
|
||||
|
||||
## Authentication and access requirements
|
||||
|
||||
{{< admonition type="warning" title="Critical: Aligning SAML Identifier with SCIM externalId" >}}
|
||||
When using SAML for authentication alongside SCIM provisioning, a critical security measure is to ensure proper alignment between the the SCIM user's `externalId` and the SAML user identifier. The unique identifier used for SCIM provisioning (which becomes the `externalId` in Grafana, often sourced from a stable IdP attribute like Entra ID's `user.objectid`) **must also be sent as a claim in the SAML assertion from your Identity Provider.**
|
||||
Furthermore, the Grafana SAML configuration must be correctly set up to identify and use this specific claim for linking the authenticated SAML user to their SCIM-provisioned user. This can be achieved by either ensuring the primary SAML login identifier by using the `assertion_attribute_external_uid` setting in Grafana to explicitly set the name of the SAML claim that contains the stable unique identifier attribute.
|
||||
|
||||
**Why is this important?**
|
||||
A mismatch or inconsistent mapping between this SAML login identifier and the SCIM `externalId` creates a critical security vulnerability. If these two identifiers are not reliably and uniquely aligned for each individual user, Grafana may fail to correctly link an authenticated SAML session to the intended SCIM-provisioned user profile and its associated permissions. This can enable a malicious actor to impersonate another user—for instance, by crafting a SAML assertion that, due to the identifier misalignment, incorrectly grants them the access rights of the targeted user.
|
||||
|
||||
Grafana relies on this linkage to correctly associate the authenticated user from SAML with the provisioned user from SCIM. Failure to ensure a consistent and unique identifier across both systems can break this linkage, leading to incorrect user mapping and potential unauthorized access.
|
||||
|
||||
Always verify that your SAML identity provider is configured to send a stable, unique user identifier that your SCIM configuration maps to `externalId`. Refer to your identity provider's documentation and the specific Grafana SCIM integration guides (e.g., for [Entra ID](configure-scim-with-azuread/) or [Okta](configure-scim-with-okta/)) for detailed instructions on configuring these attributes correctly.
|
||||
{{< /admonition >}}
|
||||
|
||||
When you enable SCIM in Grafana, the following requirements and restrictions apply:
|
||||
|
||||
1. **Use the same identity provider for user provisioning and for authentication flow**: You must use the same identity provider for both authentication and user provisioning.
|
||||
@@ -74,6 +62,12 @@ When you enable SCIM in Grafana, the following requirements and restrictions app
|
||||
- Configure `userUID` SAML assertion in [Entra ID](/docs/grafana/<GRAFANA_VERSION>/setup-grafana/configure-access/configure-authentication/saml/configure-saml-with-azuread/#configure-saml-assertions-when-using-scim-provisioning)
|
||||
- Configure `userUID` SAML assertion in [Okta](/docs/grafana/<GRAFANA_VERSION>/setup-grafana/configure-access/configure-authentication/saml/configure-saml-with-okta/#configure-saml-assertions-when-using-scim-provisioning)
|
||||
|
||||
### Align SAML identifier with SCIM `externalId`
|
||||
|
||||
When you use SAML with SCIM provisioning, align the SCIM `externalId` with the SAML user identifier. Use a stable IdP attribute (for example, Entra ID `user.objectid`) as the SCIM `externalId`, and send that same value as a SAML claim. Configure Grafana to read this claim with the `assertion_attribute_external_uid` setting so SAML authentication links to the SCIM-provisioned user and its permissions.
|
||||
|
||||
If the SAML identifier and SCIM `externalId` differ, Grafana may not link the authenticated user to the intended SCIM profile, which can result in incorrect access. Verify your IdP sends a stable, unique identifier and that it matches the SCIM `externalId`. Refer to your IdP docs and the Grafana SCIM integration guides for [Entra ID](configure-scim-with-azuread/) and [Okta](configure-scim-with-okta/) for attribute configuration details.
|
||||
|
||||
## Configure SCIM using the Grafana user interface
|
||||
|
||||
You can configure SCIM in Grafana using the Grafana user interface. To do this, navigate to **Administration > Authentication > SCIM**.
|
||||
|
||||
@@ -642,6 +642,12 @@ You must also provide the `rudderstack_write_key` to enable this feature.
|
||||
Optional.
|
||||
If tracking with RudderStack is enabled, you can provide a custom URL to load the RudderStack SDK.
|
||||
|
||||
#### `rudderstack_v3_sdk_url`
|
||||
|
||||
Optional.
|
||||
This is mirroring the old configuration option, which will be deprecated.
|
||||
If `rudderstack_sdk_url` and `rudderstack_v3_sdk_url` are both set, the feature toggle `rudderstackUpgrade` will control which one is loaded.
|
||||
|
||||
#### `rudderstack_config_url`
|
||||
|
||||
Optional.
|
||||
|
||||
@@ -1888,11 +1888,6 @@
|
||||
"count": 1
|
||||
}
|
||||
},
|
||||
"public/app/features/dashboard-scene/serialization/angularMigration.test.ts": {
|
||||
"@typescript-eslint/no-explicit-any": {
|
||||
"count": 1
|
||||
}
|
||||
},
|
||||
"public/app/features/dashboard-scene/serialization/buildNewDashboardSaveModel.ts": {
|
||||
"@typescript-eslint/consistent-type-assertions": {
|
||||
"count": 1
|
||||
@@ -2873,6 +2868,11 @@
|
||||
"count": 1
|
||||
}
|
||||
},
|
||||
"public/app/features/plugins/admin/components/PluginDetailsPage.tsx": {
|
||||
"@typescript-eslint/consistent-type-assertions": {
|
||||
"count": 1
|
||||
}
|
||||
},
|
||||
"public/app/features/plugins/admin/helpers.ts": {
|
||||
"no-restricted-syntax": {
|
||||
"count": 2
|
||||
|
||||
+2
-2
@@ -295,8 +295,8 @@
|
||||
"@grafana/plugin-ui": "^0.11.1",
|
||||
"@grafana/prometheus": "workspace:*",
|
||||
"@grafana/runtime": "workspace:*",
|
||||
"@grafana/scenes": "^6.51.0",
|
||||
"@grafana/scenes-react": "^6.51.0",
|
||||
"@grafana/scenes": "6.52.0",
|
||||
"@grafana/scenes-react": "6.52.0",
|
||||
"@grafana/schema": "workspace:*",
|
||||
"@grafana/sql": "workspace:*",
|
||||
"@grafana/ui": "workspace:*",
|
||||
|
||||
@@ -3,7 +3,7 @@ import { isEmpty } from 'lodash';
|
||||
import { DataFrameView } from '../dataframe/DataFrameView';
|
||||
import { getTimeField } from '../dataframe/processDataFrame';
|
||||
import { GrafanaTheme2 } from '../themes/types';
|
||||
import { reduceField, ReducerID } from '../transformations/fieldReducer';
|
||||
import { isReducerID, reduceField, ReducerID } from '../transformations/fieldReducer';
|
||||
import { getFieldMatcher } from '../transformations/matchers';
|
||||
import { FieldMatcherID } from '../transformations/matchers/ids';
|
||||
import { ScopedVars } from '../types/ScopedVars';
|
||||
@@ -43,6 +43,7 @@ export interface FieldSparkline {
|
||||
x?: Field; // if this does not exist, use the index
|
||||
timeRange?: TimeRange; // Optionally force an absolute time
|
||||
highlightIndex?: number;
|
||||
highlightLine?: number;
|
||||
}
|
||||
|
||||
export interface FieldDisplay {
|
||||
@@ -72,6 +73,76 @@ export interface GetFieldDisplayValuesOptions {
|
||||
|
||||
export const DEFAULT_FIELD_DISPLAY_VALUES_LIMIT = 25;
|
||||
|
||||
interface SparklineHighlightPoint {
|
||||
type: 'point';
|
||||
xIdx: number;
|
||||
}
|
||||
|
||||
interface SparklineHighlightLine {
|
||||
type: 'line';
|
||||
y: number;
|
||||
}
|
||||
|
||||
export function getSparklineHighlight(
|
||||
sparkline: FieldSparkline,
|
||||
calc: ReducerID
|
||||
): SparklineHighlightPoint | SparklineHighlightLine | void {
|
||||
switch (calc) {
|
||||
case ReducerID.last:
|
||||
return { type: 'point', xIdx: sparkline.y.values.length - 1 };
|
||||
case ReducerID.first:
|
||||
return { type: 'point', xIdx: 0 };
|
||||
case ReducerID.lastNotNull: {
|
||||
for (let k = sparkline.y.values.length - 1; k >= 0; k--) {
|
||||
const v = sparkline.y.values[k];
|
||||
if (v !== null && v !== undefined && !Number.isNaN(v)) {
|
||||
return { type: 'point', xIdx: k };
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
case ReducerID.firstNotNull: {
|
||||
for (let k = 0; k < sparkline.y.values.length; k++) {
|
||||
const v = sparkline.y.values[k];
|
||||
if (v !== null && v !== undefined && !Number.isNaN(v)) {
|
||||
return { type: 'point', xIdx: k };
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
case ReducerID.min: {
|
||||
let minIdx = -1;
|
||||
let prevMin = Infinity;
|
||||
for (let k = 0; k < sparkline.y.values.length; k++) {
|
||||
const v = sparkline.y.values[k];
|
||||
if (v !== null && v !== undefined && !Number.isNaN(v) && v < prevMin) {
|
||||
prevMin = v;
|
||||
minIdx = k;
|
||||
}
|
||||
}
|
||||
return minIdx >= 0 ? { type: 'point', xIdx: minIdx } : undefined;
|
||||
}
|
||||
case ReducerID.max: {
|
||||
let maxIdx = -1;
|
||||
let prevMax = -Infinity;
|
||||
for (let k = 0; k < sparkline.y.values.length; k++) {
|
||||
const v = sparkline.y.values[k];
|
||||
if (v !== null && v !== undefined && !Number.isNaN(v) && v > prevMax) {
|
||||
prevMax = v;
|
||||
maxIdx = k;
|
||||
}
|
||||
}
|
||||
return maxIdx >= 0 ? { type: 'point', xIdx: maxIdx } : undefined;
|
||||
}
|
||||
case ReducerID.mean:
|
||||
return { type: 'line', y: reduceField({ field: sparkline.y, reducers: [ReducerID.mean] }).mean };
|
||||
case ReducerID.median:
|
||||
return { type: 'line', y: reduceField({ field: sparkline.y, reducers: [ReducerID.median] }).median };
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
export const getFieldDisplayValues = (options: GetFieldDisplayValuesOptions): FieldDisplay[] => {
|
||||
const { replaceVariables, reduceOptions, timeZone, theme } = options;
|
||||
const calcs = reduceOptions.calcs.length ? reduceOptions.calcs : [ReducerID.last];
|
||||
@@ -190,62 +261,16 @@ export const getFieldDisplayValues = (options: GetFieldDisplayValuesOptions): Fi
|
||||
y: dataFrame.fields[i],
|
||||
x: timeField,
|
||||
};
|
||||
let highlightIdx: number | undefined = (() => {
|
||||
switch (calc) {
|
||||
case ReducerID.last:
|
||||
return sparkline.y.values.length - 1;
|
||||
case ReducerID.first:
|
||||
return 0;
|
||||
// TODO: #112977 enable more reducers for highlight index
|
||||
// case ReducerID.lastNotNull: {
|
||||
// for (let k = sparkline.y.values.length - 1; k >= 0; k--) {
|
||||
// const v = sparkline.y.values[k];
|
||||
// if (v !== null && v !== undefined && !Number.isNaN(v)) {
|
||||
// return k;
|
||||
// }
|
||||
// }
|
||||
// return;
|
||||
// }
|
||||
// case ReducerID.firstNotNull: {
|
||||
// for (let k = 0; k < sparkline.y.values.length; k++) {
|
||||
// const v = sparkline.y.values[k];
|
||||
// if (v !== null && v !== undefined && !Number.isNaN(v)) {
|
||||
// return k;
|
||||
// }
|
||||
// }
|
||||
// return;
|
||||
// }
|
||||
// case ReducerID.min: {
|
||||
// let minIdx = -1;
|
||||
// let prevMin = Infinity;
|
||||
// for (let k = 0; k < sparkline.y.values.length; k++) {
|
||||
// const v = sparkline.y.values[k];
|
||||
// if (v !== null && v !== undefined && !Number.isNaN(v) && v < prevMin) {
|
||||
// prevMin = v;
|
||||
// minIdx = k;
|
||||
// }
|
||||
// }
|
||||
// return minIdx >= 0 ? minIdx : undefined;
|
||||
// }
|
||||
// case ReducerID.max: {
|
||||
// let maxIdx = -1;
|
||||
// let prevMax = -Infinity;
|
||||
// for (let k = 0; k < sparkline.y.values.length; k++) {
|
||||
// const v = sparkline.y.values[k];
|
||||
// if (v !== null && v !== undefined && !Number.isNaN(v) && v > prevMax) {
|
||||
// prevMax = v;
|
||||
// maxIdx = k;
|
||||
// }
|
||||
// }
|
||||
// return maxIdx >= 0 ? maxIdx : undefined;
|
||||
// }
|
||||
default:
|
||||
return;
|
||||
if (isReducerID(calc)) {
|
||||
const sparklineHighlight = getSparklineHighlight(sparkline, calc);
|
||||
switch (sparklineHighlight?.type) {
|
||||
case 'point':
|
||||
sparkline.highlightIndex = sparklineHighlight.xIdx;
|
||||
break;
|
||||
case 'line':
|
||||
sparkline.highlightLine = sparklineHighlight.y;
|
||||
break;
|
||||
}
|
||||
})();
|
||||
|
||||
if (typeof highlightIdx === 'number') {
|
||||
sparkline.highlightIndex = highlightIdx;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -289,6 +289,7 @@ export interface GrafanaConfig {
|
||||
rudderstackWriteKey: string;
|
||||
rudderstackDataPlaneUrl: string;
|
||||
rudderstackSdkUrl: string;
|
||||
rudderstackV3SdkUrl: string;
|
||||
rudderstackConfigUrl: string;
|
||||
rudderstackIntegrationsUrl: string;
|
||||
applicationInsightsConnectionString: string;
|
||||
|
||||
+4
-5
@@ -499,6 +499,10 @@ export interface FeatureToggles {
|
||||
*/
|
||||
newDashboardWithFiltersAndGroupBy?: boolean;
|
||||
/**
|
||||
* Wraps the ad hoc and group by variables in a single wrapper, with all other variables below it
|
||||
*/
|
||||
dashboardAdHocAndGroupByWrapper?: boolean;
|
||||
/**
|
||||
* Updates CloudWatch label parsing to be more accurate
|
||||
* @default true
|
||||
*/
|
||||
@@ -1189,11 +1193,6 @@ export interface FeatureToggles {
|
||||
*/
|
||||
onlyStoreActionSets?: boolean;
|
||||
/**
|
||||
* Show insights for plugins in the plugin details page
|
||||
* @default false
|
||||
*/
|
||||
pluginInsights?: boolean;
|
||||
/**
|
||||
* Enables a new panel time settings drawer
|
||||
*/
|
||||
panelTimeSettings?: boolean;
|
||||
|
||||
@@ -224,6 +224,7 @@ export class GrafanaBootConfig {
|
||||
rudderstackWriteKey?: string;
|
||||
rudderstackDataPlaneUrl?: string;
|
||||
rudderstackSdkUrl?: string;
|
||||
rudderstackV3SdkUrl?: string;
|
||||
rudderstackConfigUrl?: string;
|
||||
rudderstackIntegrationsUrl?: string;
|
||||
analyticsConsoleReporting = false;
|
||||
|
||||
Generated
+4
-4
@@ -16,21 +16,19 @@ export interface GaugePanelEffects {
|
||||
barGlow?: boolean;
|
||||
centerGlow?: boolean;
|
||||
gradient?: boolean;
|
||||
rounded?: boolean;
|
||||
spotlight?: boolean;
|
||||
}
|
||||
|
||||
export const defaultGaugePanelEffects: Partial<GaugePanelEffects> = {
|
||||
barGlow: false,
|
||||
centerGlow: false,
|
||||
gradient: true,
|
||||
rounded: false,
|
||||
spotlight: false,
|
||||
};
|
||||
|
||||
export interface Options extends common.SingleStatBaseOptions {
|
||||
barShape: ('flat' | 'rounded');
|
||||
barWidthFactor: number;
|
||||
effects: GaugePanelEffects;
|
||||
endpointMarker?: ('point' | 'glow' | 'none');
|
||||
segmentCount: number;
|
||||
segmentSpacing: number;
|
||||
shape: ('circle' | 'gauge');
|
||||
@@ -40,8 +38,10 @@ export interface Options extends common.SingleStatBaseOptions {
|
||||
}
|
||||
|
||||
export const defaultOptions: Partial<Options> = {
|
||||
barShape: 'flat',
|
||||
barWidthFactor: 0.5,
|
||||
effects: {},
|
||||
endpointMarker: 'point',
|
||||
segmentCount: 1,
|
||||
segmentSpacing: 0.3,
|
||||
shape: 'gauge',
|
||||
|
||||
@@ -1,52 +1,149 @@
|
||||
import { GaugeDimensions, toRad } from './utils';
|
||||
import { useId, memo, HTMLAttributes, ReactNode } from 'react';
|
||||
|
||||
export interface RadialArcPathProps {
|
||||
startAngle: number;
|
||||
dimensions: GaugeDimensions;
|
||||
color: string;
|
||||
glowFilter?: string;
|
||||
import { FieldDisplay } from '@grafana/data';
|
||||
|
||||
import { getBarEndcapColors, getGradientCss, getEndpointMarkerColors } from './colors';
|
||||
import { RadialShape, RadialGaugeDimensions, GradientStop } from './types';
|
||||
import { drawRadialArcPath, toRad } from './utils';
|
||||
|
||||
export interface RadialArcPathPropsBase {
|
||||
arcLengthDeg: number;
|
||||
barEndcaps?: boolean;
|
||||
dimensions: RadialGaugeDimensions;
|
||||
fieldDisplay: FieldDisplay;
|
||||
roundedBars?: boolean;
|
||||
shape: RadialShape;
|
||||
endpointMarker?: 'point' | 'glow';
|
||||
startAngle: number;
|
||||
glowFilter?: string;
|
||||
endpointMarkerGlowFilter?: string;
|
||||
}
|
||||
|
||||
export function RadialArcPath({
|
||||
startAngle: angle,
|
||||
dimensions,
|
||||
color,
|
||||
glowFilter,
|
||||
arcLengthDeg,
|
||||
roundedBars,
|
||||
}: RadialArcPathProps) {
|
||||
const { radius, centerX, centerY, barWidth } = dimensions;
|
||||
interface RadialArcPathPropsWithColor extends RadialArcPathPropsBase {
|
||||
color: string;
|
||||
}
|
||||
|
||||
if (arcLengthDeg === 360) {
|
||||
// For some reason a 100% full arc cannot be rendered
|
||||
arcLengthDeg = 359.99;
|
||||
interface RadialArcPathPropsWithGradient extends RadialArcPathPropsBase {
|
||||
gradient: GradientStop[];
|
||||
}
|
||||
|
||||
type RadialArcPathProps = RadialArcPathPropsWithColor | RadialArcPathPropsWithGradient;
|
||||
|
||||
const ENDPOINT_MARKER_MIN_ANGLE = 10;
|
||||
const DOT_OPACITY = 0.5;
|
||||
const DOT_RADIUS_FACTOR = 0.4;
|
||||
const MAX_DOT_RADIUS = 8;
|
||||
|
||||
export const RadialArcPath = memo(
|
||||
({
|
||||
arcLengthDeg,
|
||||
dimensions,
|
||||
fieldDisplay,
|
||||
roundedBars,
|
||||
shape,
|
||||
endpointMarker,
|
||||
barEndcaps,
|
||||
startAngle: angle,
|
||||
glowFilter,
|
||||
endpointMarkerGlowFilter,
|
||||
...rest
|
||||
}: RadialArcPathProps) => {
|
||||
const id = useId();
|
||||
|
||||
const bgDivStyle: HTMLAttributes<HTMLDivElement>['style'] = { width: '100%', height: '100%' };
|
||||
if ('color' in rest) {
|
||||
bgDivStyle.backgroundColor = rest.color;
|
||||
} else {
|
||||
bgDivStyle.backgroundImage = getGradientCss(rest.gradient, shape);
|
||||
}
|
||||
|
||||
const { radius, centerX, centerY, barWidth } = dimensions;
|
||||
|
||||
const path = drawRadialArcPath(angle, arcLengthDeg, dimensions, roundedBars);
|
||||
|
||||
const startRadians = toRad(angle);
|
||||
const endRadians = toRad(angle + arcLengthDeg);
|
||||
|
||||
const xStart = centerX + radius * Math.cos(startRadians);
|
||||
const yStart = centerY + radius * Math.sin(startRadians);
|
||||
const xEnd = centerX + radius * Math.cos(endRadians);
|
||||
const yEnd = centerY + radius * Math.sin(endRadians);
|
||||
|
||||
const dotRadius =
|
||||
endpointMarker === 'point' ? Math.min((barWidth / 2) * DOT_RADIUS_FACTOR, MAX_DOT_RADIUS) : barWidth / 2;
|
||||
|
||||
let barEndcapColors: [string, string] | undefined;
|
||||
let endpointMarks: ReactNode = null;
|
||||
if ('gradient' in rest) {
|
||||
if (endpointMarker && (rest.gradient?.length ?? 0) > 0) {
|
||||
switch (endpointMarker) {
|
||||
case 'point':
|
||||
const [pointColorStart, pointColorEnd] = getEndpointMarkerColors(
|
||||
rest.gradient!,
|
||||
fieldDisplay.display.percent
|
||||
);
|
||||
endpointMarks = (
|
||||
<>
|
||||
{arcLengthDeg > ENDPOINT_MARKER_MIN_ANGLE && (
|
||||
<circle cx={xStart} cy={yStart} r={dotRadius} fill={pointColorStart} opacity={DOT_OPACITY} />
|
||||
)}
|
||||
<circle cx={xEnd} cy={yEnd} r={dotRadius} fill={pointColorEnd} opacity={DOT_OPACITY} />
|
||||
</>
|
||||
);
|
||||
break;
|
||||
case 'glow':
|
||||
const offsetAngle = toRad(ENDPOINT_MARKER_MIN_ANGLE);
|
||||
const xStartMark = centerX + radius * Math.cos(endRadians + offsetAngle);
|
||||
const yStartMark = centerY + radius * Math.sin(endRadians + offsetAngle);
|
||||
endpointMarks =
|
||||
arcLengthDeg > ENDPOINT_MARKER_MIN_ANGLE ? (
|
||||
<path
|
||||
d={['M', xStartMark, yStartMark, 'A', radius, radius, 0, 0, 1, xEnd, yEnd].join(' ')}
|
||||
fill="none"
|
||||
strokeWidth={barWidth}
|
||||
stroke={endpointMarkerGlowFilter}
|
||||
strokeLinecap={roundedBars ? 'round' : 'butt'}
|
||||
filter={glowFilter}
|
||||
/>
|
||||
) : null;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (barEndcaps) {
|
||||
barEndcapColors = getBarEndcapColors(rest.gradient, fieldDisplay.display.percent);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* FIXME: optimize this by only using clippath + foreign obj for gradients */}
|
||||
<clipPath id={id}>
|
||||
<path d={path} />
|
||||
</clipPath>
|
||||
|
||||
<g filter={glowFilter}>
|
||||
<foreignObject
|
||||
x={centerX - radius - barWidth}
|
||||
y={centerY - radius - barWidth}
|
||||
width={(radius + barWidth) * 2}
|
||||
height={(radius + barWidth) * 2}
|
||||
clipPath={`url(#${id})`}
|
||||
>
|
||||
<div style={bgDivStyle} />
|
||||
</foreignObject>
|
||||
{barEndcapColors?.[0] && <circle cx={xStart} cy={yStart} r={barWidth / 2} fill={barEndcapColors[0]} />}
|
||||
{barEndcapColors?.[1] && (
|
||||
<circle cx={xEnd} cy={yEnd} r={barWidth / 2} fill={barEndcapColors[1]} opacity={0.5} />
|
||||
)}
|
||||
</g>
|
||||
|
||||
{endpointMarks}
|
||||
</>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
const startRadians = toRad(angle);
|
||||
const endRadians = toRad(angle + arcLengthDeg);
|
||||
|
||||
let x1 = centerX + radius * Math.cos(startRadians);
|
||||
let y1 = centerY + radius * Math.sin(startRadians);
|
||||
let x2 = centerX + radius * Math.cos(endRadians);
|
||||
let y2 = centerY + radius * Math.sin(endRadians);
|
||||
|
||||
const largeArc = arcLengthDeg > 180 ? 1 : 0;
|
||||
|
||||
const path = ['M', x1, y1, 'A', radius, radius, 0, largeArc, 1, x2, y2].join(' ');
|
||||
|
||||
return (
|
||||
<path
|
||||
d={path}
|
||||
fill="none"
|
||||
fillOpacity="1"
|
||||
stroke={color}
|
||||
strokeOpacity="1"
|
||||
strokeWidth={barWidth}
|
||||
filter={glowFilter}
|
||||
strokeLinecap={roundedBars ? 'round' : 'butt'}
|
||||
className="radial-arc-path"
|
||||
/>
|
||||
);
|
||||
}
|
||||
RadialArcPath.displayName = 'RadialArcPath';
|
||||
|
||||
@@ -1,97 +1,64 @@
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { FALLBACK_COLOR, FieldDisplay } from '@grafana/data';
|
||||
|
||||
import { useTheme2 } from '../../themes/ThemeContext';
|
||||
|
||||
import { RadialArcPath } from './RadialArcPath';
|
||||
import { RadialColorDefs } from './RadialColorDefs';
|
||||
import { GaugeDimensions, toRad } from './utils';
|
||||
import { RadialShape, RadialGaugeDimensions, GradientStop } from './types';
|
||||
|
||||
export interface RadialBarProps {
|
||||
dimensions: GaugeDimensions;
|
||||
colorDefs: RadialColorDefs;
|
||||
angleRange: number;
|
||||
angle: number;
|
||||
startAngle: number;
|
||||
angleRange: number;
|
||||
dimensions: RadialGaugeDimensions;
|
||||
fieldDisplay: FieldDisplay;
|
||||
gradient?: GradientStop[];
|
||||
roundedBars?: boolean;
|
||||
spotlightStroke: string;
|
||||
endpointMarker?: 'point' | 'glow';
|
||||
shape: RadialShape;
|
||||
startAngle: number;
|
||||
glowFilter?: string;
|
||||
endpointMarkerGlowFilter?: string;
|
||||
}
|
||||
export function RadialBar({
|
||||
dimensions,
|
||||
colorDefs,
|
||||
angleRange,
|
||||
angle,
|
||||
startAngle,
|
||||
angleRange,
|
||||
dimensions,
|
||||
fieldDisplay,
|
||||
gradient,
|
||||
roundedBars,
|
||||
spotlightStroke,
|
||||
endpointMarker,
|
||||
shape,
|
||||
startAngle,
|
||||
glowFilter,
|
||||
endpointMarkerGlowFilter,
|
||||
}: RadialBarProps) {
|
||||
const theme = useTheme2();
|
||||
|
||||
const colorProps = gradient ? { gradient } : { color: fieldDisplay.display.color ?? FALLBACK_COLOR };
|
||||
return (
|
||||
<>
|
||||
<g>
|
||||
{/** Track */}
|
||||
<RadialArcPath
|
||||
startAngle={startAngle + angle}
|
||||
dimensions={dimensions}
|
||||
arcLengthDeg={angleRange - angle}
|
||||
color={theme.colors.action.hover}
|
||||
roundedBars={roundedBars}
|
||||
/>
|
||||
{/** The colored bar */}
|
||||
<RadialArcPath
|
||||
dimensions={dimensions}
|
||||
startAngle={startAngle}
|
||||
arcLengthDeg={angle}
|
||||
color={colorDefs.getMainBarColor()}
|
||||
roundedBars={roundedBars}
|
||||
glowFilter={glowFilter}
|
||||
/>
|
||||
{spotlightStroke && angle > 8 && (
|
||||
<SpotlightSquareEffect
|
||||
dimensions={dimensions}
|
||||
angle={startAngle + angle}
|
||||
glowFilter={glowFilter}
|
||||
spotlightStroke={spotlightStroke}
|
||||
theme={theme}
|
||||
roundedBars={roundedBars}
|
||||
/>
|
||||
)}
|
||||
</g>
|
||||
<defs>{colorDefs.getDefs()}</defs>
|
||||
{/** Track */}
|
||||
<RadialArcPath
|
||||
arcLengthDeg={angleRange - angle}
|
||||
fieldDisplay={fieldDisplay}
|
||||
color={theme.colors.action.hover}
|
||||
dimensions={dimensions}
|
||||
roundedBars={roundedBars}
|
||||
shape={shape}
|
||||
startAngle={startAngle + angle}
|
||||
/>
|
||||
{/** The colored bar */}
|
||||
<RadialArcPath
|
||||
arcLengthDeg={angle}
|
||||
barEndcaps={shape === 'circle' && roundedBars}
|
||||
dimensions={dimensions}
|
||||
endpointMarker={roundedBars ? endpointMarker : undefined}
|
||||
endpointMarkerGlowFilter={endpointMarkerGlowFilter}
|
||||
fieldDisplay={fieldDisplay}
|
||||
glowFilter={glowFilter}
|
||||
roundedBars={roundedBars}
|
||||
shape={shape}
|
||||
startAngle={startAngle}
|
||||
{...colorProps}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
interface SpotlightEffectProps {
|
||||
dimensions: GaugeDimensions;
|
||||
angle: number;
|
||||
glowFilter?: string;
|
||||
spotlightStroke: string;
|
||||
theme: GrafanaTheme2;
|
||||
roundedBars?: boolean;
|
||||
}
|
||||
|
||||
function SpotlightSquareEffect({ dimensions, angle, glowFilter, spotlightStroke, roundedBars }: SpotlightEffectProps) {
|
||||
const { radius, centerX, centerY, barWidth } = dimensions;
|
||||
|
||||
const angleRadian = toRad(angle);
|
||||
const x1 = centerX + radius * Math.cos(angleRadian - 0.2);
|
||||
const y1 = centerY + radius * Math.sin(angleRadian - 0.2);
|
||||
const x2 = centerX + radius * Math.cos(angleRadian);
|
||||
const y2 = centerY + radius * Math.sin(angleRadian);
|
||||
|
||||
const path = ['M', x1, y1, 'A', radius, radius, 0, 0, 1, x2, y2].join(' ');
|
||||
|
||||
return (
|
||||
<path
|
||||
d={path}
|
||||
fill="none"
|
||||
strokeWidth={barWidth}
|
||||
stroke={spotlightStroke}
|
||||
strokeLinecap={roundedBars ? 'round' : 'butt'}
|
||||
filter={glowFilter}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,126 +1,74 @@
|
||||
import { FieldDisplay } from '@grafana/data';
|
||||
import { memo } from 'react';
|
||||
|
||||
import { FALLBACK_COLOR, FieldDisplay } from '@grafana/data';
|
||||
|
||||
import { useTheme2 } from '../../themes/ThemeContext';
|
||||
|
||||
import { RadialArcPath } from './RadialArcPath';
|
||||
import { RadialColorDefs } from './RadialColorDefs';
|
||||
import { GaugeDimensions } from './utils';
|
||||
import { RadialShape, RadialGaugeDimensions, GradientStop } from './types';
|
||||
import {
|
||||
getAngleBetweenSegments,
|
||||
getFieldConfigMinMax,
|
||||
getFieldDisplayProcessor,
|
||||
getOptimalSegmentCount,
|
||||
} from './utils';
|
||||
|
||||
export interface RadialBarSegmentedProps {
|
||||
fieldDisplay: FieldDisplay;
|
||||
dimensions: GaugeDimensions;
|
||||
colorDefs: RadialColorDefs;
|
||||
dimensions: RadialGaugeDimensions;
|
||||
angleRange: number;
|
||||
startAngle: number;
|
||||
glowFilter?: string;
|
||||
segmentCount: number;
|
||||
segmentSpacing: number;
|
||||
shape: RadialShape;
|
||||
gradient?: GradientStop[];
|
||||
}
|
||||
export function RadialBarSegmented({
|
||||
fieldDisplay,
|
||||
dimensions,
|
||||
startAngle,
|
||||
angleRange,
|
||||
glowFilter,
|
||||
segmentCount,
|
||||
segmentSpacing,
|
||||
colorDefs,
|
||||
}: RadialBarSegmentedProps) {
|
||||
const segments: React.ReactNode[] = [];
|
||||
const theme = useTheme2();
|
||||
|
||||
const segmentCountAdjusted = getOptimalSegmentCount(dimensions, segmentSpacing, segmentCount, angleRange);
|
||||
const min = fieldDisplay.field.min ?? 0;
|
||||
const max = fieldDisplay.field.max ?? 100;
|
||||
const value = fieldDisplay.display.numeric;
|
||||
const angleBetweenSegments = getAngleBetweenSegments(segmentSpacing, segmentCount, angleRange);
|
||||
const segmentArcLengthDeg = angleRange / segmentCountAdjusted - angleBetweenSegments;
|
||||
export const RadialBarSegmented = memo(
|
||||
({
|
||||
fieldDisplay,
|
||||
dimensions,
|
||||
startAngle,
|
||||
angleRange,
|
||||
glowFilter,
|
||||
gradient,
|
||||
segmentCount,
|
||||
segmentSpacing,
|
||||
shape,
|
||||
}: RadialBarSegmentedProps) => {
|
||||
const theme = useTheme2();
|
||||
const segments: React.ReactNode[] = [];
|
||||
const segmentCountAdjusted = getOptimalSegmentCount(dimensions, segmentSpacing, segmentCount, angleRange);
|
||||
const [min, max] = getFieldConfigMinMax(fieldDisplay);
|
||||
const value = fieldDisplay.display.numeric;
|
||||
const angleBetweenSegments = getAngleBetweenSegments(segmentSpacing, segmentCount, angleRange);
|
||||
const segmentArcLengthDeg = angleRange / segmentCountAdjusted - angleBetweenSegments;
|
||||
const displayProcessor = getFieldDisplayProcessor(fieldDisplay);
|
||||
|
||||
for (let i = 0; i < segmentCountAdjusted; i++) {
|
||||
const angleValue = min + ((max - min) / segmentCountAdjusted) * i;
|
||||
const angleColor = colorDefs.getSegmentColor(angleValue);
|
||||
const segmentAngle = startAngle + (angleRange / segmentCountAdjusted) * i + 0.01;
|
||||
const segmentColor = angleValue >= value ? theme.colors.action.hover : angleColor;
|
||||
for (let i = 0; i < segmentCountAdjusted; i++) {
|
||||
const angleValue = min + ((max - min) / segmentCountAdjusted) * i;
|
||||
const segmentAngle = startAngle + (angleRange / segmentCountAdjusted) * i + 0.01;
|
||||
const segmentColor =
|
||||
angleValue >= value ? theme.colors.border.medium : (displayProcessor(angleValue).color ?? FALLBACK_COLOR);
|
||||
const colorProps = angleValue < value && gradient ? { gradient } : { color: segmentColor };
|
||||
|
||||
segments.push(
|
||||
<RadialArcPath
|
||||
key={i}
|
||||
startAngle={segmentAngle}
|
||||
dimensions={dimensions}
|
||||
color={segmentColor}
|
||||
glowFilter={glowFilter}
|
||||
arcLengthDeg={segmentArcLengthDeg}
|
||||
/>
|
||||
);
|
||||
segments.push(
|
||||
<RadialArcPath
|
||||
key={i}
|
||||
arcLengthDeg={segmentArcLengthDeg}
|
||||
dimensions={dimensions}
|
||||
fieldDisplay={fieldDisplay}
|
||||
glowFilter={glowFilter}
|
||||
shape={shape}
|
||||
startAngle={segmentAngle}
|
||||
{...colorProps}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return <g>{segments}</g>;
|
||||
}
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<g>{segments}</g>
|
||||
<defs>{colorDefs.getDefs()}</defs>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export function getAngleBetweenSegments(segmentSpacing: number, segmentCount: number, range: number) {
|
||||
// Max spacing is 8 degrees between segments
|
||||
// Changing this constant could be considered a breaking change
|
||||
const maxAngleBetweenSegments = Math.max(range / 1.5 / segmentCount, 2);
|
||||
return segmentSpacing * maxAngleBetweenSegments;
|
||||
}
|
||||
|
||||
function getOptimalSegmentCount(
|
||||
dimensions: GaugeDimensions,
|
||||
segmentSpacing: number,
|
||||
segmentCount: number,
|
||||
range: number
|
||||
) {
|
||||
const angleBetweenSegments = getAngleBetweenSegments(segmentSpacing, segmentCount, range);
|
||||
|
||||
const innerRadius = dimensions.radius - dimensions.barWidth / 2;
|
||||
const circumference = Math.PI * innerRadius * 2 * (range / 360);
|
||||
const maxSegments = Math.floor(circumference / (angleBetweenSegments + 3));
|
||||
|
||||
return Math.min(maxSegments, segmentCount);
|
||||
}
|
||||
|
||||
// export function RadialSegmentLine({
|
||||
// gaugeId,
|
||||
// center,
|
||||
// angle,
|
||||
// size,
|
||||
// color,
|
||||
// barWidth,
|
||||
// roundedBars,
|
||||
// glow,
|
||||
// margin,
|
||||
// segmentWidth,
|
||||
// }: RadialSegmentProps) {
|
||||
// const arcSize = size - barWidth;
|
||||
// const radius = arcSize / 2 - margin;
|
||||
|
||||
// const angleRad = (Math.PI * (angle - 90)) / 180;
|
||||
// const lineLength = radius - barWidth;
|
||||
|
||||
// const x1 = center + radius * Math.cos(angleRad);
|
||||
// const y1 = center + radius * Math.sin(angleRad);
|
||||
// const x2 = center + lineLength * Math.cos(angleRad);
|
||||
// const y2 = center + lineLength * Math.sin(angleRad);
|
||||
|
||||
// return (
|
||||
// <line
|
||||
// x1={x1}
|
||||
// y1={y1}
|
||||
// x2={x2}
|
||||
// y2={y2}
|
||||
// fill="none"
|
||||
// fillOpacity="0.85"
|
||||
// stroke={color}
|
||||
// strokeOpacity="1"
|
||||
// strokeLinecap={roundedBars ? 'round' : 'butt'}
|
||||
// strokeWidth={segmentWidth}
|
||||
// strokeDasharray="0"
|
||||
// filter={glow ? `url(#glow-${gaugeId})` : undefined}
|
||||
// />
|
||||
// );
|
||||
// }
|
||||
RadialBarSegmented.displayName = 'RadialBarSegmented';
|
||||
|
||||
@@ -1,141 +0,0 @@
|
||||
import tinycolor from 'tinycolor2';
|
||||
|
||||
import { DisplayProcessor, FALLBACK_COLOR, FieldDisplay, getFieldColorMode, GrafanaTheme2 } from '@grafana/data';
|
||||
|
||||
import { RadialGradientMode, RadialShape } from './RadialGauge';
|
||||
import { GaugeDimensions } from './utils';
|
||||
|
||||
export interface RadialColorDefsOptions {
|
||||
gradient: RadialGradientMode;
|
||||
fieldDisplay: FieldDisplay;
|
||||
theme: GrafanaTheme2;
|
||||
dimensions: GaugeDimensions;
|
||||
shape: RadialShape;
|
||||
gaugeId: string;
|
||||
displayProcessor: DisplayProcessor;
|
||||
}
|
||||
|
||||
export class RadialColorDefs {
|
||||
private colorToIds: Record<string, string> = {};
|
||||
private defs: React.ReactNode[] = [];
|
||||
|
||||
constructor(private options: RadialColorDefsOptions) {}
|
||||
|
||||
getSegmentColor(forValue: number): string {
|
||||
const { displayProcessor } = this.options;
|
||||
const baseColor = displayProcessor(forValue).color ?? FALLBACK_COLOR;
|
||||
|
||||
return this.getColor(baseColor, true);
|
||||
}
|
||||
|
||||
getColor(baseColor: string, forSegment?: boolean): string {
|
||||
const { gradient, dimensions, gaugeId, fieldDisplay, shape, theme } = this.options;
|
||||
|
||||
const id = `value-color-${baseColor}-${gaugeId}`;
|
||||
|
||||
if (this.colorToIds[id]) {
|
||||
return this.colorToIds[id];
|
||||
}
|
||||
|
||||
// If no gradient, just return the base color
|
||||
if (gradient === 'none') {
|
||||
this.colorToIds[id] = baseColor;
|
||||
return baseColor;
|
||||
}
|
||||
|
||||
const returnColor = (this.colorToIds[id] = `url(#${id})`);
|
||||
const colorModeId = fieldDisplay.field.color?.mode;
|
||||
const colorMode = getFieldColorMode(colorModeId);
|
||||
const valuePercent = fieldDisplay.display.percent ?? 0;
|
||||
|
||||
// Handle continusous color modes first
|
||||
// If it's a segment color we don't want to do continuous gradients
|
||||
if (colorMode.isContinuous && colorMode.getColors && !forSegment) {
|
||||
const colors = colorMode.getColors(theme);
|
||||
const count = colors.length;
|
||||
|
||||
this.defs.push(
|
||||
<linearGradient x1="0" y1="0" x2={1 / valuePercent} y2="0" id={id}>
|
||||
{colors.map((stopColor, i) => (
|
||||
<stop key={i} offset={`${(i / (count - 1)).toFixed(2)}`} stopColor={stopColor} stopOpacity={1} />
|
||||
))}
|
||||
</linearGradient>
|
||||
);
|
||||
|
||||
return returnColor;
|
||||
}
|
||||
|
||||
// For value based colors we want to stay more true to the specific color
|
||||
// So a radial gradient that adds a bit of light and shade works best
|
||||
if (colorMode.isByValue) {
|
||||
const color1 = tinycolor(baseColor).darken(5);
|
||||
|
||||
this.defs.push(
|
||||
<radialGradient
|
||||
key={id}
|
||||
id={id}
|
||||
cx={dimensions.centerX}
|
||||
cy={dimensions.centerY}
|
||||
r={dimensions.radius + dimensions.barWidth / 2}
|
||||
fr={dimensions.radius - dimensions.barWidth / 2}
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop offset="0%" stopColor={tinycolor(baseColor).spin(20).lighten(10).toString()} stopOpacity={1} />
|
||||
<stop offset="60%" stopColor={color1.toString()} stopOpacity={1} />
|
||||
<stop offset="100%" stopColor={color1.toString()} stopOpacity={1} />
|
||||
</radialGradient>
|
||||
);
|
||||
|
||||
return returnColor;
|
||||
}
|
||||
|
||||
// For fixed / palette based color scales we can create a more fun
|
||||
// hue and light based linear gradient that we rotate/move with the value
|
||||
|
||||
const x2 = shape === 'circle' ? 0 : dimensions.centerX + dimensions.radius;
|
||||
const y2 = shape === 'circle' ? dimensions.centerY + dimensions.radius : 0;
|
||||
const color1 = tinycolor(baseColor).spin(-20).darken(5);
|
||||
const color2 = tinycolor(baseColor).saturate(20).spin(20).brighten(10);
|
||||
|
||||
// this makes it so the gradient is always brightest at the current value
|
||||
const transform =
|
||||
shape === 'circle'
|
||||
? `rotate(${360 * valuePercent - 180} ${dimensions.centerX} ${dimensions.centerY})`
|
||||
: `translate(-${dimensions.radius * 2 * (1 - valuePercent)}, 0)`;
|
||||
|
||||
this.defs.push(
|
||||
<linearGradient
|
||||
key={id}
|
||||
id={id}
|
||||
x1="0"
|
||||
y1="0"
|
||||
x2={x2}
|
||||
y2={y2}
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform={transform}
|
||||
>
|
||||
{theme.isDark ? (
|
||||
<>
|
||||
<stop offset="0%" stopColor={color1.darken(10).toString()} stopOpacity={1} />
|
||||
<stop offset="100%" stopColor={color2.lighten(10).toString()} stopOpacity={1} />
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<stop offset="0%" stopColor={color2.lighten(10).toString()} stopOpacity={1} />
|
||||
<stop offset="100%" stopColor={color1.toString()} stopOpacity={1} />
|
||||
</>
|
||||
)}
|
||||
</linearGradient>
|
||||
);
|
||||
|
||||
return returnColor;
|
||||
}
|
||||
|
||||
getMainBarColor(): string {
|
||||
return this.getColor(this.options.fieldDisplay.display.color ?? FALLBACK_COLOR);
|
||||
}
|
||||
|
||||
getDefs(): React.ReactNode[] {
|
||||
return this.defs;
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,8 @@ import { FieldColorModeId } from '@grafana/schema';
|
||||
import { useTheme2 } from '../../themes/ThemeContext';
|
||||
import { Stack } from '../Layout/Stack/Stack';
|
||||
|
||||
import { RadialGauge, RadialGaugeProps, RadialGradientMode, RadialShape, RadialTextMode } from './RadialGauge';
|
||||
import { RadialGauge, RadialGaugeProps } from './RadialGauge';
|
||||
import { RadialShape, RadialTextMode } from './types';
|
||||
|
||||
interface StoryProps extends RadialGaugeProps {
|
||||
value: number;
|
||||
@@ -31,10 +32,27 @@ const meta: Meta<StoryProps> = {
|
||||
controls: {
|
||||
exclude: ['theme', 'values', 'vizCount'],
|
||||
},
|
||||
a11y: {
|
||||
config: {
|
||||
rules: [
|
||||
{
|
||||
id: 'scrollable-region-focusable',
|
||||
selector: 'body',
|
||||
enabled: false,
|
||||
},
|
||||
// NOTE: this is necessary due to a false positive with the filered svg glow in one of the examples.
|
||||
// The color-contrast in this component should be accessible!
|
||||
{
|
||||
id: 'color-contrast',
|
||||
selector: 'text',
|
||||
enabled: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
args: {
|
||||
barWidthFactor: 0.2,
|
||||
spotlight: false,
|
||||
glowBar: false,
|
||||
glowCenter: false,
|
||||
sparkline: false,
|
||||
@@ -42,7 +60,7 @@ const meta: Meta<StoryProps> = {
|
||||
width: 200,
|
||||
height: 200,
|
||||
shape: 'circle',
|
||||
gradient: 'none',
|
||||
gradient: false,
|
||||
seriesCount: 1,
|
||||
segmentCount: 0,
|
||||
segmentSpacing: 0.2,
|
||||
@@ -56,14 +74,14 @@ const meta: Meta<StoryProps> = {
|
||||
width: { control: { type: 'range', min: 50, max: 600 } },
|
||||
height: { control: { type: 'range', min: 50, max: 600 } },
|
||||
value: { control: { type: 'range', min: 0, max: 110 } },
|
||||
spotlight: { control: 'boolean' },
|
||||
roundedBars: { control: 'boolean' },
|
||||
sparkline: { control: 'boolean' },
|
||||
thresholdsBar: { control: 'boolean' },
|
||||
gradient: { control: { type: 'radio' } },
|
||||
gradient: { control: { type: 'boolean' } },
|
||||
seriesCount: { control: { type: 'range', min: 1, max: 20 } },
|
||||
segmentCount: { control: { type: 'range', min: 0, max: 100 } },
|
||||
segmentSpacing: { control: { type: 'range', min: 0, max: 1, step: 0.01 } },
|
||||
endpointMarker: { control: { type: 'select' }, options: ['none', 'point', 'glow'] },
|
||||
colorScheme: {
|
||||
control: { type: 'select' },
|
||||
options: [
|
||||
@@ -102,57 +120,17 @@ export const Examples: StoryFn<StoryProps> = (args) => {
|
||||
<Stack direction={'column'} gap={3} wrap="wrap">
|
||||
<div>Bar width</div>
|
||||
<Stack direction="row" alignItems="center" gap={3} wrap="wrap">
|
||||
<RadialGaugeExample
|
||||
seriesName="0.1"
|
||||
value={args.value ?? 30}
|
||||
color="blue"
|
||||
gradient="auto"
|
||||
barWidthFactor={0.1}
|
||||
/>
|
||||
<RadialGaugeExample
|
||||
seriesName="0.4"
|
||||
value={args.value ?? 40}
|
||||
color="green"
|
||||
gradient="auto"
|
||||
barWidthFactor={0.4}
|
||||
/>
|
||||
<RadialGaugeExample
|
||||
seriesName="0.6"
|
||||
value={args.value ?? 60}
|
||||
color="red"
|
||||
gradient="auto"
|
||||
barWidthFactor={0.6}
|
||||
/>
|
||||
<RadialGaugeExample
|
||||
seriesName="0.8"
|
||||
value={args.value ?? 70}
|
||||
color="purple"
|
||||
gradient="auto"
|
||||
barWidthFactor={0.8}
|
||||
/>
|
||||
<RadialGaugeExample seriesName="0.1" value={args.value ?? 30} color="blue" gradient barWidthFactor={0.1} />
|
||||
<RadialGaugeExample seriesName="0.4" value={args.value ?? 40} color="green" gradient barWidthFactor={0.4} />
|
||||
<RadialGaugeExample seriesName="0.6" value={args.value ?? 60} color="red" gradient barWidthFactor={0.6} />
|
||||
<RadialGaugeExample seriesName="0.8" value={args.value ?? 70} color="purple" gradient barWidthFactor={0.8} />
|
||||
</Stack>
|
||||
<div>Effects</div>
|
||||
<Stack direction="row" alignItems="center" gap={3} wrap="wrap">
|
||||
<RadialGaugeExample value={args.value ?? 30} spotlight glowBar glowCenter color="blue" gradient="auto" />
|
||||
<RadialGaugeExample value={args.value ?? 40} spotlight glowBar glowCenter color="green" gradient="auto" />
|
||||
<RadialGaugeExample
|
||||
value={args.value ?? 60}
|
||||
spotlight
|
||||
glowBar
|
||||
glowCenter
|
||||
color="red"
|
||||
gradient="auto"
|
||||
roundedBars
|
||||
/>
|
||||
<RadialGaugeExample
|
||||
value={args.value ?? 70}
|
||||
spotlight
|
||||
glowBar
|
||||
glowCenter
|
||||
color="purple"
|
||||
gradient="auto"
|
||||
roundedBars
|
||||
/>
|
||||
<RadialGaugeExample value={args.value ?? 30} glowBar glowCenter color="blue" gradient />
|
||||
<RadialGaugeExample value={args.value ?? 40} glowBar glowCenter color="green" gradient />
|
||||
<RadialGaugeExample value={args.value ?? 60} glowBar glowCenter color="red" gradient roundedBars />
|
||||
<RadialGaugeExample value={args.value ?? 70} glowBar glowCenter color="purple" gradient roundedBars />
|
||||
</Stack>
|
||||
<div>Shape: Gauge & color scale</div>
|
||||
<Stack direction="row" alignItems="center" gap={3} wrap="wrap">
|
||||
@@ -160,14 +138,14 @@ export const Examples: StoryFn<StoryProps> = (args) => {
|
||||
value={40}
|
||||
shape="gauge"
|
||||
width={250}
|
||||
gradient="auto"
|
||||
gradient
|
||||
colorScheme={FieldColorModeId.ContinuousGrYlRd}
|
||||
glowCenter={true}
|
||||
barWidthFactor={0.6}
|
||||
/>
|
||||
<RadialGaugeExample
|
||||
colorScheme={FieldColorModeId.ContinuousGrYlRd}
|
||||
gradient="auto"
|
||||
gradient
|
||||
width={250}
|
||||
value={90}
|
||||
barWidthFactor={0.6}
|
||||
@@ -183,9 +161,8 @@ export const Examples: StoryFn<StoryProps> = (args) => {
|
||||
value={args.value ?? 70}
|
||||
color="blue"
|
||||
shape="gauge"
|
||||
gradient="auto"
|
||||
gradient
|
||||
sparkline={true}
|
||||
spotlight
|
||||
glowBar={true}
|
||||
glowCenter={true}
|
||||
barWidthFactor={0.2}
|
||||
@@ -194,9 +171,8 @@ export const Examples: StoryFn<StoryProps> = (args) => {
|
||||
value={args.value ?? 30}
|
||||
color="green"
|
||||
shape="gauge"
|
||||
gradient="auto"
|
||||
gradient
|
||||
sparkline={true}
|
||||
spotlight
|
||||
glowBar={true}
|
||||
glowCenter={true}
|
||||
barWidthFactor={0.8}
|
||||
@@ -206,9 +182,8 @@ export const Examples: StoryFn<StoryProps> = (args) => {
|
||||
color="red"
|
||||
shape="gauge"
|
||||
width={250}
|
||||
gradient="auto"
|
||||
gradient
|
||||
sparkline={true}
|
||||
spotlight
|
||||
glowBar={true}
|
||||
glowCenter={true}
|
||||
barWidthFactor={0.2}
|
||||
@@ -218,9 +193,8 @@ export const Examples: StoryFn<StoryProps> = (args) => {
|
||||
color="red"
|
||||
width={250}
|
||||
shape="gauge"
|
||||
gradient="auto"
|
||||
gradient
|
||||
sparkline={true}
|
||||
spotlight
|
||||
glowBar={true}
|
||||
glowCenter={true}
|
||||
barWidthFactor={0.8}
|
||||
@@ -231,7 +205,7 @@ export const Examples: StoryFn<StoryProps> = (args) => {
|
||||
<RadialGaugeExample
|
||||
value={args.value ?? 70}
|
||||
color="green"
|
||||
gradient="auto"
|
||||
gradient
|
||||
glowCenter={true}
|
||||
segmentCount={8}
|
||||
segmentSpacing={0.1}
|
||||
@@ -240,7 +214,7 @@ export const Examples: StoryFn<StoryProps> = (args) => {
|
||||
<RadialGaugeExample
|
||||
value={args.value ?? 30}
|
||||
color="purple"
|
||||
gradient="auto"
|
||||
gradient
|
||||
segmentCount={30}
|
||||
glowCenter={true}
|
||||
barWidthFactor={0.6}
|
||||
@@ -248,7 +222,7 @@ export const Examples: StoryFn<StoryProps> = (args) => {
|
||||
<RadialGaugeExample
|
||||
value={args.value ?? 50}
|
||||
color="red"
|
||||
gradient="auto"
|
||||
gradient
|
||||
segmentCount={40}
|
||||
glowCenter={true}
|
||||
barWidthFactor={1}
|
||||
@@ -260,7 +234,6 @@ export const Examples: StoryFn<StoryProps> = (args) => {
|
||||
<RadialGaugeExample
|
||||
value={args.value ?? 80}
|
||||
colorScheme={FieldColorModeId.ContinuousGrYlRd}
|
||||
spotlight
|
||||
glowBar={true}
|
||||
glowCenter={true}
|
||||
segmentCount={20}
|
||||
@@ -270,9 +243,8 @@ export const Examples: StoryFn<StoryProps> = (args) => {
|
||||
value={args.value ?? 80}
|
||||
width={250}
|
||||
colorScheme={FieldColorModeId.ContinuousGrYlRd}
|
||||
spotlight
|
||||
shape="gauge"
|
||||
gradient="auto"
|
||||
gradient
|
||||
glowBar={true}
|
||||
glowCenter={true}
|
||||
segmentCount={40}
|
||||
@@ -285,10 +257,9 @@ export const Examples: StoryFn<StoryProps> = (args) => {
|
||||
<RadialGaugeExample
|
||||
value={args.value ?? 70}
|
||||
colorScheme={FieldColorModeId.Thresholds}
|
||||
gradient="auto"
|
||||
gradient
|
||||
thresholdsBar={true}
|
||||
roundedBars={false}
|
||||
spotlight
|
||||
glowCenter={true}
|
||||
barWidthFactor={0.7}
|
||||
/>
|
||||
@@ -296,7 +267,7 @@ export const Examples: StoryFn<StoryProps> = (args) => {
|
||||
value={args.value ?? 70}
|
||||
width={250}
|
||||
colorScheme={FieldColorModeId.Thresholds}
|
||||
gradient="auto"
|
||||
gradient
|
||||
glowCenter={true}
|
||||
thresholdsBar={true}
|
||||
roundedBars={false}
|
||||
@@ -307,7 +278,7 @@ export const Examples: StoryFn<StoryProps> = (args) => {
|
||||
value={args.value ?? 70}
|
||||
width={250}
|
||||
colorScheme={FieldColorModeId.Thresholds}
|
||||
gradient="auto"
|
||||
gradient
|
||||
glowCenter={true}
|
||||
thresholdsBar={true}
|
||||
roundedBars={false}
|
||||
@@ -347,14 +318,12 @@ export const Temp: StoryFn<StoryProps> = (args) => {
|
||||
shape="gauge"
|
||||
roundedBars={false}
|
||||
barWidthFactor={0.8}
|
||||
spotlight
|
||||
/>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
interface ExampleProps {
|
||||
gradient?: RadialGradientMode;
|
||||
color?: string;
|
||||
seriesName?: string;
|
||||
value?: number;
|
||||
@@ -363,7 +332,7 @@ interface ExampleProps {
|
||||
max?: number;
|
||||
width?: number;
|
||||
height?: number;
|
||||
spotlight?: boolean;
|
||||
gradient?: boolean;
|
||||
glowBar?: boolean;
|
||||
glowCenter?: boolean;
|
||||
barWidthFactor?: number;
|
||||
@@ -376,12 +345,12 @@ interface ExampleProps {
|
||||
roundedBars?: boolean;
|
||||
thresholdsBar?: boolean;
|
||||
colorScheme?: FieldColorModeId;
|
||||
endpointMarker?: RadialGaugeProps['endpointMarker'];
|
||||
decimals?: number;
|
||||
showScaleLabels?: boolean;
|
||||
}
|
||||
|
||||
export function RadialGaugeExample({
|
||||
gradient = 'none',
|
||||
color,
|
||||
seriesName = 'Server A',
|
||||
value = 70,
|
||||
@@ -390,7 +359,7 @@ export function RadialGaugeExample({
|
||||
max = 100,
|
||||
width = 200,
|
||||
height = 200,
|
||||
spotlight = false,
|
||||
gradient = false,
|
||||
glowBar = false,
|
||||
glowCenter = false,
|
||||
barWidthFactor = 0.4,
|
||||
@@ -403,6 +372,7 @@ export function RadialGaugeExample({
|
||||
roundedBars = false,
|
||||
thresholdsBar = false,
|
||||
colorScheme = FieldColorModeId.Thresholds,
|
||||
endpointMarker = 'glow',
|
||||
decimals = 0,
|
||||
showScaleLabels,
|
||||
}: ExampleProps) {
|
||||
@@ -480,7 +450,6 @@ export function RadialGaugeExample({
|
||||
barWidthFactor={barWidthFactor}
|
||||
gradient={gradient}
|
||||
shape={shape}
|
||||
spotlight={spotlight}
|
||||
glowBar={glowBar}
|
||||
glowCenter={glowCenter}
|
||||
textMode={textMode}
|
||||
@@ -490,6 +459,7 @@ export function RadialGaugeExample({
|
||||
roundedBars={roundedBars}
|
||||
thresholdsBar={thresholdsBar}
|
||||
showScaleLabels={showScaleLabels}
|
||||
endpointMarker={endpointMarker}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,13 +1,28 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { ComponentProps } from 'react';
|
||||
|
||||
import { RadialGaugeExample } from './RadialGauge.story';
|
||||
|
||||
describe('RadialGauge', () => {
|
||||
it('should render', () => {
|
||||
render(<RadialGaugeExample />);
|
||||
|
||||
expect(screen.getByRole('img')).toBeInTheDocument();
|
||||
});
|
||||
it.each([
|
||||
{ description: 'default', props: {} },
|
||||
{ description: 'gauge shape', props: { shape: 'gauge' } },
|
||||
{ description: 'with gradient', props: { gradient: true } },
|
||||
{ description: 'with glow bar', props: { glowBar: true } },
|
||||
{ description: 'with glow center', props: { glowCenter: true } },
|
||||
{ description: 'with segments', props: { segmentCount: 5 } },
|
||||
{ description: 'with rounded bars', props: { roundedBars: true } },
|
||||
{ description: 'with endpoint marker glow', props: { roundedBars: true, endpointMarker: 'glow' } },
|
||||
{ description: 'with endpoint marker point', props: { roundedBars: true, endpointMarker: 'point' } },
|
||||
{ description: 'with thresholds bar', props: { thresholdsBar: true } },
|
||||
{ description: 'with sparkline', props: { sparkline: true } },
|
||||
] satisfies Array<{ description: string; props?: ComponentProps<typeof RadialGaugeExample> }>)(
|
||||
'should render $description without throwing',
|
||||
({ props }) => {
|
||||
render(<RadialGaugeExample {...props} />);
|
||||
expect(screen.getByRole('img')).toBeInTheDocument();
|
||||
}
|
||||
);
|
||||
|
||||
it('should render threshold labels', () => {
|
||||
render(<RadialGaugeExample showScaleLabels={true} />);
|
||||
|
||||
@@ -1,14 +1,7 @@
|
||||
import { css, cx } from '@emotion/css';
|
||||
import { isNumber } from 'lodash';
|
||||
import { useId } from 'react';
|
||||
|
||||
import {
|
||||
DisplayValueAlignmentFactors,
|
||||
FieldDisplay,
|
||||
getDisplayProcessor,
|
||||
GrafanaTheme2,
|
||||
TimeRange,
|
||||
} from '@grafana/data';
|
||||
import { DisplayValueAlignmentFactors, FALLBACK_COLOR, FieldDisplay, GrafanaTheme2, TimeRange } from '@grafana/data';
|
||||
import { t } from '@grafana/i18n';
|
||||
|
||||
import { useStyles2, useTheme2 } from '../../themes/ThemeContext';
|
||||
@@ -16,12 +9,13 @@ import { getFormattedThresholds } from '../Gauge/utils';
|
||||
|
||||
import { RadialBar } from './RadialBar';
|
||||
import { RadialBarSegmented } from './RadialBarSegmented';
|
||||
import { RadialColorDefs } from './RadialColorDefs';
|
||||
import { RadialScaleLabels } from './RadialScaleLabels';
|
||||
import { RadialSparkline } from './RadialSparkline';
|
||||
import { RadialText } from './RadialText';
|
||||
import { ThresholdsBar } from './ThresholdsBar';
|
||||
import { buildGradientColors } from './colors';
|
||||
import { GlowGradient, MiddleCircleGlow, SpotlightGradient } from './effects';
|
||||
import { RadialShape, RadialTextMode } from './types';
|
||||
import { calculateDimensions, getValueAngleForValue } from './utils';
|
||||
|
||||
export interface RadialGaugeProps {
|
||||
@@ -32,7 +26,7 @@ export interface RadialGaugeProps {
|
||||
* Circle or gauge (partial circle)
|
||||
*/
|
||||
shape?: RadialShape;
|
||||
gradient?: RadialGradientMode;
|
||||
gradient?: boolean;
|
||||
/**
|
||||
* Bar width is always relative to size of the gauge.
|
||||
* But this gives you control over the width relative to size.
|
||||
@@ -40,12 +34,14 @@ export interface RadialGaugeProps {
|
||||
* Defaults to 0.4
|
||||
**/
|
||||
barWidthFactor?: number;
|
||||
/** Adds a white spotlight for the end position */
|
||||
spotlight?: boolean;
|
||||
glowBar?: boolean;
|
||||
glowCenter?: boolean;
|
||||
roundedBars?: boolean;
|
||||
thresholdsBar?: boolean;
|
||||
/**
|
||||
* Specify if an endpoint marker should be shown at the end of the bar
|
||||
*/
|
||||
endpointMarker?: 'point' | 'glow';
|
||||
/**
|
||||
* Number of segments depends on size of gauge but this
|
||||
* factor 1-10 gives you relative control
|
||||
@@ -75,10 +71,6 @@ export interface RadialGaugeProps {
|
||||
timeRange?: TimeRange;
|
||||
}
|
||||
|
||||
export type RadialGradientMode = 'none' | 'auto';
|
||||
export type RadialTextMode = 'auto' | 'value_and_name' | 'value' | 'name' | 'none';
|
||||
export type RadialShape = 'circle' | 'gauge';
|
||||
|
||||
/**
|
||||
* https://developers.grafana.com/ui/latest/index.html?path=/docs/plugins-radialgauge--docs
|
||||
*/
|
||||
@@ -87,9 +79,8 @@ export function RadialGauge(props: RadialGaugeProps) {
|
||||
width = 256,
|
||||
height = 256,
|
||||
shape = 'circle',
|
||||
gradient = 'none',
|
||||
gradient = false,
|
||||
barWidthFactor = 0.4,
|
||||
spotlight = false,
|
||||
glowBar = false,
|
||||
glowCenter = false,
|
||||
textMode = 'auto',
|
||||
@@ -99,6 +90,7 @@ export function RadialGauge(props: RadialGaugeProps) {
|
||||
roundedBars = true,
|
||||
thresholdsBar = false,
|
||||
showScaleLabels = false,
|
||||
endpointMarker,
|
||||
onClick,
|
||||
values,
|
||||
} = props;
|
||||
@@ -121,7 +113,8 @@ export function RadialGauge(props: RadialGaugeProps) {
|
||||
for (let barIndex = 0; barIndex < values.length; barIndex++) {
|
||||
const displayValue = values[barIndex];
|
||||
const { angle, angleRange } = getValueAngleForValue(displayValue, startAngle, endAngle);
|
||||
const color = displayValue.display.color ?? 'gray';
|
||||
const gradientStops = buildGradientColors(gradient, theme, displayValue);
|
||||
const color = displayValue.display.color ?? FALLBACK_COLOR;
|
||||
const dimensions = calculateDimensions(
|
||||
width,
|
||||
height,
|
||||
@@ -134,20 +127,12 @@ export function RadialGauge(props: RadialGaugeProps) {
|
||||
showScaleLabels
|
||||
);
|
||||
|
||||
const displayProcessor = getFieldDisplayProcessor(displayValue);
|
||||
// FIXME: I want to move the ids for these filters into a context which the children
|
||||
// can reference via a hook, rather than passing them down as props
|
||||
const spotlightGradientId = `spotlight-${barIndex}-${gaugeId}`;
|
||||
const glowFilterId = `glow-${gaugeId}`;
|
||||
const colorDefs = new RadialColorDefs({
|
||||
gradient,
|
||||
fieldDisplay: displayValue,
|
||||
theme,
|
||||
dimensions,
|
||||
shape,
|
||||
gaugeId,
|
||||
displayProcessor,
|
||||
});
|
||||
|
||||
if (spotlight && theme.isDark) {
|
||||
if (endpointMarker === 'glow') {
|
||||
defs.push(
|
||||
<SpotlightGradient
|
||||
key={spotlightGradientId}
|
||||
@@ -171,7 +156,8 @@ export function RadialGauge(props: RadialGaugeProps) {
|
||||
glowFilter={`url(#${glowFilterId})`}
|
||||
segmentCount={segmentCount}
|
||||
segmentSpacing={segmentSpacing}
|
||||
colorDefs={colorDefs}
|
||||
shape={shape}
|
||||
gradient={gradientStops}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
@@ -179,13 +165,16 @@ export function RadialGauge(props: RadialGaugeProps) {
|
||||
<RadialBar
|
||||
key={`radial-bar-${barIndex}-${gaugeId}`}
|
||||
dimensions={dimensions}
|
||||
colorDefs={colorDefs}
|
||||
angle={angle}
|
||||
angleRange={angleRange}
|
||||
startAngle={startAngle}
|
||||
roundedBars={roundedBars}
|
||||
spotlightStroke={`url(#${spotlightGradientId})`}
|
||||
glowFilter={`url(#${glowFilterId})`}
|
||||
endpointMarkerGlowFilter={`url(#${spotlightGradientId})`}
|
||||
shape={shape}
|
||||
gradient={gradientStops}
|
||||
fieldDisplay={displayValue}
|
||||
endpointMarker={endpointMarker}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -245,7 +234,8 @@ export function RadialGauge(props: RadialGaugeProps) {
|
||||
angleRange={angleRange}
|
||||
roundedBars={roundedBars}
|
||||
glowFilter={`url(#${glowFilterId})`}
|
||||
colorDefs={colorDefs}
|
||||
shape={shape}
|
||||
gradient={gradientStops}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -291,17 +281,6 @@ export function RadialGauge(props: RadialGaugeProps) {
|
||||
);
|
||||
}
|
||||
|
||||
function getFieldDisplayProcessor(displayValue: FieldDisplay) {
|
||||
if (displayValue.view && isNumber(displayValue.colIndex)) {
|
||||
const dp = displayValue.view.getFieldDisplayProcessor(displayValue.colIndex);
|
||||
if (dp) {
|
||||
return dp;
|
||||
}
|
||||
}
|
||||
|
||||
return getDisplayProcessor();
|
||||
}
|
||||
|
||||
function getStyles(theme: GrafanaTheme2) {
|
||||
return {
|
||||
vizWrapper: css({
|
||||
|
||||
@@ -1,87 +1,84 @@
|
||||
import { memo } from 'react';
|
||||
|
||||
import { FieldDisplay, GrafanaTheme2, Threshold } from '@grafana/data';
|
||||
import { t } from '@grafana/i18n';
|
||||
|
||||
import { measureText } from '../../utils/measureText';
|
||||
|
||||
import { GaugeDimensions, toCartesian } from './utils';
|
||||
import { RadialGaugeDimensions } from './types';
|
||||
import { getFieldConfigMinMax, toCartesian } from './utils';
|
||||
|
||||
interface RadialScaleLabelsProps {
|
||||
fieldDisplay: FieldDisplay;
|
||||
theme: GrafanaTheme2;
|
||||
thresholds: Threshold[];
|
||||
dimensions: GaugeDimensions;
|
||||
dimensions: RadialGaugeDimensions;
|
||||
startAngle: number;
|
||||
endAngle: number;
|
||||
angleRange: number;
|
||||
}
|
||||
|
||||
export function RadialScaleLabels({
|
||||
fieldDisplay,
|
||||
thresholds,
|
||||
theme,
|
||||
dimensions,
|
||||
startAngle,
|
||||
endAngle,
|
||||
angleRange,
|
||||
}: RadialScaleLabelsProps) {
|
||||
const { centerX, centerY, scaleLabelsFontSize, scaleLabelsRadius } = dimensions;
|
||||
const LINE_HEIGHT_FACTOR = 1.2;
|
||||
|
||||
const fieldConfig = fieldDisplay.field;
|
||||
const min = fieldConfig.min ?? 0;
|
||||
const max = fieldConfig.max ?? 100;
|
||||
export const RadialScaleLabels = memo(
|
||||
({ fieldDisplay, thresholds, theme, dimensions, startAngle, endAngle, angleRange }: RadialScaleLabelsProps) => {
|
||||
const { centerX, centerY, scaleLabelsFontSize, scaleLabelsRadius } = dimensions;
|
||||
const [min, max] = getFieldConfigMinMax(fieldDisplay);
|
||||
|
||||
const fontSize = scaleLabelsFontSize;
|
||||
const textLineHeight = scaleLabelsFontSize * 1.2;
|
||||
const radius = scaleLabelsRadius - textLineHeight;
|
||||
const fontSize = scaleLabelsFontSize;
|
||||
const textLineHeight = scaleLabelsFontSize * LINE_HEIGHT_FACTOR;
|
||||
const radius = scaleLabelsRadius - textLineHeight;
|
||||
|
||||
function getTextPosition(text: string, value: number, index: number) {
|
||||
const isLast = index === thresholds.length - 1;
|
||||
const isFirst = index === 0;
|
||||
function getTextPosition(text: string, value: number, index: number) {
|
||||
const isLast = index === thresholds.length - 1;
|
||||
const isFirst = index === 0;
|
||||
|
||||
let valueDeg = ((value - min) / (max - min)) * angleRange;
|
||||
let finalAngle = startAngle + valueDeg;
|
||||
let valueDeg = ((value - min) / (max - min)) * angleRange;
|
||||
let finalAngle = startAngle + valueDeg;
|
||||
|
||||
// Now adjust the final angle based on the label text width and the labels position on the arc
|
||||
let measure = measureText(text, fontSize, theme.typography.fontWeightMedium);
|
||||
let textWidthAngle = (measure.width / (2 * Math.PI * radius)) * angleRange;
|
||||
// Now adjust the final angle based on the label text width and the labels position on the arc
|
||||
let measure = measureText(text, fontSize, theme.typography.fontWeightMedium);
|
||||
let textWidthAngle = (measure.width / (2 * Math.PI * radius)) * angleRange;
|
||||
|
||||
// the centering is different for gauge or circle shapes for some reason
|
||||
finalAngle -= endAngle < 180 ? textWidthAngle : textWidthAngle / 2;
|
||||
// the centering is different for gauge or circle shapes for some reason
|
||||
finalAngle -= endAngle < 180 ? textWidthAngle : textWidthAngle / 2;
|
||||
|
||||
// For circle gauges we need to shift the first label more
|
||||
if (isFirst) {
|
||||
finalAngle += textWidthAngle;
|
||||
// For circle gauges we need to shift the first label more
|
||||
if (isFirst) {
|
||||
finalAngle += textWidthAngle;
|
||||
}
|
||||
|
||||
// For circle gauges we need to shift the last label more
|
||||
if (isLast && endAngle === 360) {
|
||||
finalAngle -= textWidthAngle;
|
||||
}
|
||||
|
||||
const position = toCartesian(centerX, centerY, radius, finalAngle);
|
||||
|
||||
return { ...position, transform: `rotate(${finalAngle}, ${position.x}, ${position.y})` };
|
||||
}
|
||||
|
||||
// For circle gauges we need to shift the last label more
|
||||
if (isLast && endAngle === 360) {
|
||||
finalAngle -= textWidthAngle;
|
||||
}
|
||||
|
||||
const position = toCartesian(centerX, centerY, radius, finalAngle);
|
||||
|
||||
return { ...position, transform: `rotate(${finalAngle}, ${position.x}, ${position.y})` };
|
||||
return (
|
||||
<g>
|
||||
{thresholds.map((threshold, index) => {
|
||||
const labelPos = getTextPosition(String(threshold.value), threshold.value, index);
|
||||
return (
|
||||
<text
|
||||
key={index}
|
||||
x={labelPos.x}
|
||||
y={labelPos.y}
|
||||
fontSize={fontSize}
|
||||
fill={theme.colors.text.primary}
|
||||
transform={labelPos.transform}
|
||||
aria-label={t(`gauge.threshold`, 'Threshold {{value}}', { value: threshold.value })}
|
||||
>
|
||||
{threshold.value}
|
||||
</text>
|
||||
);
|
||||
})}
|
||||
</g>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
return (
|
||||
<g>
|
||||
{thresholds.map((threshold, index) => {
|
||||
const labelPos = getTextPosition(String(threshold.value), threshold.value, index);
|
||||
|
||||
return (
|
||||
<text
|
||||
key={index}
|
||||
x={labelPos.x}
|
||||
y={labelPos.y}
|
||||
fontSize={fontSize}
|
||||
fill={theme.colors.text.primary}
|
||||
transform={labelPos.transform}
|
||||
aria-label={t(`gauge.threshold`, 'Threshold {{value}}', { value: threshold.value })}
|
||||
>
|
||||
{threshold.value}
|
||||
</text>
|
||||
);
|
||||
})}
|
||||
</g>
|
||||
);
|
||||
}
|
||||
RadialScaleLabels.displayName = 'RadialScaleLabels';
|
||||
|
||||
@@ -1,49 +1,76 @@
|
||||
import { memo, useMemo } from 'react';
|
||||
|
||||
import { FieldDisplay, GrafanaTheme2, FieldConfig } from '@grafana/data';
|
||||
import { GraphFieldConfig, GraphGradientMode, LineInterpolation } from '@grafana/schema';
|
||||
|
||||
import { Sparkline } from '../Sparkline/Sparkline';
|
||||
|
||||
import { RadialShape, RadialTextMode } from './RadialGauge';
|
||||
import { GaugeDimensions } from './utils';
|
||||
import { RadialShape, RadialTextMode, RadialGaugeDimensions } from './types';
|
||||
|
||||
interface RadialSparklineProps {
|
||||
sparkline: FieldDisplay['sparkline'];
|
||||
dimensions: GaugeDimensions;
|
||||
theme: GrafanaTheme2;
|
||||
color?: string;
|
||||
shape?: RadialShape;
|
||||
dimensions: RadialGaugeDimensions;
|
||||
shape: RadialShape;
|
||||
sparkline: FieldDisplay['sparkline'];
|
||||
textMode: Exclude<RadialTextMode, 'auto'>;
|
||||
theme: GrafanaTheme2;
|
||||
}
|
||||
export function RadialSparkline({ sparkline, dimensions, theme, color, shape, textMode }: RadialSparklineProps) {
|
||||
const { radius, barWidth } = dimensions;
|
||||
|
||||
if (!sparkline) {
|
||||
return null;
|
||||
const SPARKLINE_HEIGHT_DIVISOR = 4;
|
||||
const SPARKLINE_HEIGHT_DIVISOR_NAME_AND_VALUE = 4;
|
||||
const SPARKLINE_WIDTH_FACTOR_ARC = 1.4;
|
||||
const SPARKLINE_WIDTH_FACTOR_CIRCLE = 1.6;
|
||||
const SPARKLINE_TOP_OFFSET_DIVISOR_CIRCLE = 4;
|
||||
const SPARKLINE_TOP_OFFSET_DIVISOR_CIRCLE_NAME_AND_VALUE = 3.3;
|
||||
const SPARKLINE_SPACING = 8;
|
||||
|
||||
export function getSparklineDimensions(
|
||||
radius: number,
|
||||
barWidth: number,
|
||||
showNameAndValue: boolean,
|
||||
shape: RadialShape
|
||||
): { width: number; height: number } {
|
||||
const height = radius / (showNameAndValue ? SPARKLINE_HEIGHT_DIVISOR_NAME_AND_VALUE : SPARKLINE_HEIGHT_DIVISOR);
|
||||
const width = radius * (shape === 'gauge' ? SPARKLINE_WIDTH_FACTOR_ARC : SPARKLINE_WIDTH_FACTOR_CIRCLE) - barWidth;
|
||||
return { width, height };
|
||||
}
|
||||
|
||||
export const RadialSparkline = memo(
|
||||
({ sparkline, dimensions, theme, color, shape, textMode }: RadialSparklineProps) => {
|
||||
const { radius, barWidth } = dimensions;
|
||||
|
||||
const showNameAndValue = textMode === 'value_and_name';
|
||||
const { width, height } = getSparklineDimensions(radius, barWidth, showNameAndValue, shape);
|
||||
const topPos =
|
||||
shape === 'gauge'
|
||||
? dimensions.gaugeBottomY - height - SPARKLINE_SPACING
|
||||
: `calc(50% + ${radius / (showNameAndValue ? SPARKLINE_TOP_OFFSET_DIVISOR_CIRCLE_NAME_AND_VALUE : SPARKLINE_TOP_OFFSET_DIVISOR_CIRCLE)}px)`;
|
||||
|
||||
const config: FieldConfig<GraphFieldConfig> = useMemo(
|
||||
() => ({
|
||||
color: {
|
||||
mode: 'fixed',
|
||||
fixedColor: color ?? 'blue',
|
||||
},
|
||||
custom: {
|
||||
gradientMode: GraphGradientMode.Opacity,
|
||||
fillOpacity: 40,
|
||||
lineInterpolation: LineInterpolation.Smooth,
|
||||
},
|
||||
}),
|
||||
[color]
|
||||
);
|
||||
|
||||
if (!sparkline) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{ position: 'absolute', top: topPos }}>
|
||||
<Sparkline height={height} width={width} sparkline={sparkline} theme={theme} config={config} showHighlights />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
const showNameAndValue = textMode === 'value_and_name';
|
||||
const height = radius / (showNameAndValue ? 4 : 3);
|
||||
const width = radius * (shape === 'gauge' ? 1.6 : 1.4) - barWidth;
|
||||
const topPos =
|
||||
shape === 'gauge'
|
||||
? `${dimensions.gaugeBottomY - height}px`
|
||||
: `calc(50% + ${radius / (showNameAndValue ? 3.3 : 4)}px)`;
|
||||
|
||||
const config: FieldConfig<GraphFieldConfig> = {
|
||||
color: {
|
||||
mode: 'fixed',
|
||||
fixedColor: color ?? 'blue',
|
||||
},
|
||||
custom: {
|
||||
gradientMode: GraphGradientMode.Opacity,
|
||||
fillOpacity: 40,
|
||||
lineInterpolation: LineInterpolation.Smooth,
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ position: 'absolute', top: topPos }}>
|
||||
<Sparkline height={height} width={width} sparkline={sparkline} theme={theme} config={config} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
RadialSparkline.displayName = 'RadialSparkline';
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { css } from '@emotion/css';
|
||||
import { memo } from 'react';
|
||||
|
||||
import {
|
||||
DisplayValue,
|
||||
@@ -11,13 +12,12 @@ import {
|
||||
import { useStyles2 } from '../../themes/ThemeContext';
|
||||
import { calculateFontSize } from '../../utils/measureText';
|
||||
|
||||
import { RadialShape, RadialTextMode } from './RadialGauge';
|
||||
import { GaugeDimensions } from './utils';
|
||||
import { RadialShape, RadialTextMode, RadialGaugeDimensions } from './types';
|
||||
|
||||
interface RadialTextProps {
|
||||
displayValue: DisplayValue;
|
||||
theme: GrafanaTheme2;
|
||||
dimensions: GaugeDimensions;
|
||||
dimensions: RadialGaugeDimensions;
|
||||
textMode: Exclude<RadialTextMode, 'auto'>;
|
||||
shape: RadialShape;
|
||||
sparkline?: FieldSparkline;
|
||||
@@ -26,123 +26,137 @@ interface RadialTextProps {
|
||||
nameManualFontSize?: number;
|
||||
}
|
||||
|
||||
export function RadialText({
|
||||
displayValue,
|
||||
theme,
|
||||
dimensions,
|
||||
textMode,
|
||||
shape,
|
||||
sparkline,
|
||||
alignmentFactors,
|
||||
valueManualFontSize,
|
||||
nameManualFontSize,
|
||||
}: RadialTextProps) {
|
||||
const styles = useStyles2(getStyles);
|
||||
const { centerX, centerY, radius, barWidth } = dimensions;
|
||||
const LINE_HEIGHT_FACTOR = 1.21;
|
||||
const VALUE_WIDTH_TO_RADIUS_FACTOR = 0.82;
|
||||
const NAME_TO_HEIGHT_FACTOR = 0.45;
|
||||
const LARGE_RADIUS_SCALING_DECAY = 0.86;
|
||||
const MAX_TEXT_WIDTH_DIVISOR = 7;
|
||||
const MAX_NAME_HEIGHT_DIVISOR = 4;
|
||||
const VALUE_SPACE_PERCENTAGE = 0.7;
|
||||
const SPARKLINE_SPACING = 8;
|
||||
const MIN_VALUE_FONT_SIZE = 1;
|
||||
const MIN_NAME_FONT_SIZE = 10;
|
||||
const MIN_UNIT_FONT_SIZE = 6;
|
||||
|
||||
if (textMode === 'none') {
|
||||
return null;
|
||||
}
|
||||
export const RadialText = memo(
|
||||
({
|
||||
displayValue,
|
||||
theme,
|
||||
dimensions,
|
||||
textMode,
|
||||
shape,
|
||||
sparkline,
|
||||
alignmentFactors,
|
||||
valueManualFontSize,
|
||||
nameManualFontSize,
|
||||
}: RadialTextProps) => {
|
||||
const styles = useStyles2(getStyles);
|
||||
const { centerX, centerY, radius, barWidth } = dimensions;
|
||||
|
||||
const nameToAlignTo = (alignmentFactors ? alignmentFactors.title : displayValue.title) ?? '';
|
||||
const valueToAlignTo = formattedValueToString(alignmentFactors ? alignmentFactors : displayValue);
|
||||
if (textMode === 'none') {
|
||||
return null;
|
||||
}
|
||||
|
||||
const showValue = textMode === 'value' || textMode === 'value_and_name';
|
||||
const showName = textMode === 'name' || textMode === 'value_and_name';
|
||||
const maxTextWidth = radius * 2 - barWidth - radius / 7;
|
||||
const nameToAlignTo = (alignmentFactors ? alignmentFactors.title : displayValue.title) ?? '';
|
||||
const valueToAlignTo = formattedValueToString(alignmentFactors ? alignmentFactors : displayValue);
|
||||
|
||||
// Not sure where this comes from but svg text is not using body line-height
|
||||
const lineHeight = 1.21;
|
||||
const valueWidthToRadiusFactor = 0.82;
|
||||
const nameToHeightFactor = 0.45;
|
||||
const largeRadiusScalingDecay = 0.86;
|
||||
const showValue = textMode === 'value' || textMode === 'value_and_name';
|
||||
const showName = textMode === 'name' || textMode === 'value_and_name';
|
||||
const maxTextWidth = radius * 2 - barWidth - radius / MAX_TEXT_WIDTH_DIVISOR;
|
||||
|
||||
// This pow 0.92 factor is to create a decay so the font size does not become rediculously large for very large panels
|
||||
let maxValueHeight = valueWidthToRadiusFactor * Math.pow(radius, largeRadiusScalingDecay);
|
||||
let maxNameHeight = radius / 4;
|
||||
// This pow 0.92 factor is to create a decay so the font size does not become rediculously large for very large panels
|
||||
let maxValueHeight = VALUE_WIDTH_TO_RADIUS_FACTOR * Math.pow(radius, LARGE_RADIUS_SCALING_DECAY);
|
||||
let maxNameHeight = radius / MAX_NAME_HEIGHT_DIVISOR;
|
||||
|
||||
if (showValue && showName) {
|
||||
maxValueHeight = valueWidthToRadiusFactor * Math.pow(radius, largeRadiusScalingDecay);
|
||||
maxNameHeight = nameToHeightFactor * Math.pow(radius, largeRadiusScalingDecay);
|
||||
}
|
||||
if (showValue && showName) {
|
||||
maxValueHeight = VALUE_WIDTH_TO_RADIUS_FACTOR * Math.pow(radius, LARGE_RADIUS_SCALING_DECAY);
|
||||
maxNameHeight = NAME_TO_HEIGHT_FACTOR * Math.pow(radius, LARGE_RADIUS_SCALING_DECAY);
|
||||
}
|
||||
|
||||
const valueFontSize =
|
||||
valueManualFontSize ??
|
||||
calculateFontSize(
|
||||
valueToAlignTo,
|
||||
maxTextWidth,
|
||||
maxValueHeight,
|
||||
lineHeight,
|
||||
undefined,
|
||||
theme.typography.body.fontWeight
|
||||
const valueFontSize = Math.max(
|
||||
valueManualFontSize ??
|
||||
calculateFontSize(
|
||||
valueToAlignTo,
|
||||
maxTextWidth,
|
||||
maxValueHeight,
|
||||
LINE_HEIGHT_FACTOR,
|
||||
undefined,
|
||||
theme.typography.body.fontWeight
|
||||
),
|
||||
MIN_VALUE_FONT_SIZE
|
||||
);
|
||||
|
||||
const nameFontSize =
|
||||
nameManualFontSize ??
|
||||
calculateFontSize(
|
||||
nameToAlignTo,
|
||||
maxTextWidth,
|
||||
maxNameHeight,
|
||||
lineHeight,
|
||||
undefined,
|
||||
theme.typography.body.fontWeight
|
||||
const nameFontSize = Math.max(
|
||||
nameManualFontSize ??
|
||||
calculateFontSize(
|
||||
nameToAlignTo,
|
||||
maxTextWidth,
|
||||
maxNameHeight,
|
||||
LINE_HEIGHT_FACTOR,
|
||||
undefined,
|
||||
theme.typography.body.fontWeight
|
||||
),
|
||||
MIN_NAME_FONT_SIZE
|
||||
);
|
||||
|
||||
const unitFontSize = Math.max(valueFontSize * 0.7, 5);
|
||||
const valueHeight = valueFontSize * lineHeight;
|
||||
const nameHeight = nameFontSize * lineHeight;
|
||||
const unitFontSize = Math.max(valueFontSize * VALUE_SPACE_PERCENTAGE, MIN_UNIT_FONT_SIZE);
|
||||
const valueHeight = valueFontSize * LINE_HEIGHT_FACTOR;
|
||||
const nameHeight = nameFontSize * LINE_HEIGHT_FACTOR;
|
||||
|
||||
const valueY = showName ? centerY - nameHeight * 0.3 : centerY;
|
||||
const nameY = showValue ? valueY + valueHeight * 0.7 : centerY;
|
||||
const nameColor = showValue ? theme.colors.text.secondary : theme.colors.text.primary;
|
||||
const suffixShift = (valueFontSize - unitFontSize * 1.2) / 2;
|
||||
const valueY = showName ? centerY - nameHeight * (1 - VALUE_SPACE_PERCENTAGE) : centerY;
|
||||
const nameY = showValue ? valueY + valueHeight * VALUE_SPACE_PERCENTAGE : centerY;
|
||||
const nameColor = showValue ? theme.colors.text.secondary : theme.colors.text.primary;
|
||||
const suffixShift = (valueFontSize - unitFontSize * LINE_HEIGHT_FACTOR) / 2;
|
||||
|
||||
// adjust the text up on gauges and when sparklines are present
|
||||
let yOffset = 0;
|
||||
if (shape === 'gauge') {
|
||||
// we render from the center of the gauge, so move up by half of half of the total height
|
||||
yOffset -= (valueHeight + nameHeight) / 4;
|
||||
}
|
||||
if (sparkline) {
|
||||
yOffset -= 8;
|
||||
// adjust the text up on gauges and when sparklines are present
|
||||
let yOffset = 0;
|
||||
if (shape === 'gauge') {
|
||||
// we render from the center of the gauge, so move up by half of half of the total height
|
||||
yOffset -= (valueHeight + nameHeight) / 4;
|
||||
}
|
||||
if (sparkline) {
|
||||
yOffset -= SPARKLINE_SPACING;
|
||||
}
|
||||
|
||||
return (
|
||||
<g transform={`translate(0, ${yOffset})`}>
|
||||
{showValue && (
|
||||
<text
|
||||
x={centerX}
|
||||
y={valueY}
|
||||
fontSize={valueFontSize}
|
||||
fill={theme.colors.text.primary}
|
||||
className={styles.text}
|
||||
textAnchor="middle"
|
||||
dominantBaseline="middle"
|
||||
>
|
||||
<tspan fontSize={unitFontSize}>{displayValue.prefix ?? ''}</tspan>
|
||||
<tspan>{displayValue.text}</tspan>
|
||||
<tspan className={styles.text} fontSize={unitFontSize} dy={suffixShift}>
|
||||
{displayValue.suffix ?? ''}
|
||||
</tspan>
|
||||
</text>
|
||||
)}
|
||||
{showName && (
|
||||
<text
|
||||
fontSize={nameFontSize}
|
||||
x={centerX}
|
||||
y={nameY}
|
||||
textAnchor="middle"
|
||||
dominantBaseline="middle"
|
||||
fill={nameColor}
|
||||
>
|
||||
{displayValue.title}
|
||||
</text>
|
||||
)}
|
||||
</g>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
return (
|
||||
<g transform={`translate(0, ${yOffset})`}>
|
||||
{showValue && (
|
||||
<text
|
||||
x={centerX}
|
||||
y={valueY}
|
||||
fontSize={valueFontSize}
|
||||
fill={theme.colors.text.primary}
|
||||
className={styles.text}
|
||||
textAnchor="middle"
|
||||
dominantBaseline="middle"
|
||||
>
|
||||
<tspan fontSize={unitFontSize}>{displayValue.prefix ?? ''}</tspan>
|
||||
<tspan>{displayValue.text}</tspan>
|
||||
<tspan className={styles.text} fontSize={unitFontSize} dy={suffixShift}>
|
||||
{displayValue.suffix ?? ''}
|
||||
</tspan>
|
||||
</text>
|
||||
)}
|
||||
{showName && (
|
||||
<text
|
||||
fontSize={nameFontSize}
|
||||
x={centerX}
|
||||
y={nameY}
|
||||
textAnchor="middle"
|
||||
dominantBaseline="middle"
|
||||
fill={nameColor}
|
||||
>
|
||||
{displayValue.title}
|
||||
</text>
|
||||
)}
|
||||
</g>
|
||||
);
|
||||
}
|
||||
RadialText.displayName = 'RadialText';
|
||||
|
||||
const getStyles = (theme: GrafanaTheme2) => ({
|
||||
const getStyles = (_theme: GrafanaTheme2) => ({
|
||||
text: css({
|
||||
verticalAlign: 'bottom',
|
||||
}),
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
import { FieldDisplay, Threshold } from '@grafana/data';
|
||||
|
||||
import { RadialArcPath } from './RadialArcPath';
|
||||
import { RadialColorDefs } from './RadialColorDefs';
|
||||
import { GaugeDimensions } from './utils';
|
||||
import { GradientStop, RadialGaugeDimensions, RadialShape } from './types';
|
||||
import { getFieldConfigMinMax } from './utils';
|
||||
|
||||
export interface Props {
|
||||
dimensions: GaugeDimensions;
|
||||
interface ThresholdsBarProps {
|
||||
dimensions: RadialGaugeDimensions;
|
||||
angleRange: number;
|
||||
startAngle: number;
|
||||
endAngle: number;
|
||||
shape: RadialShape;
|
||||
fieldDisplay: FieldDisplay;
|
||||
roundedBars?: boolean;
|
||||
glowFilter?: string;
|
||||
colorDefs: RadialColorDefs;
|
||||
thresholds: Threshold[];
|
||||
gradient?: GradientStop[];
|
||||
}
|
||||
|
||||
export function ThresholdsBar({
|
||||
dimensions,
|
||||
fieldDisplay,
|
||||
@@ -22,19 +24,18 @@ export function ThresholdsBar({
|
||||
angleRange,
|
||||
roundedBars,
|
||||
glowFilter,
|
||||
colorDefs,
|
||||
thresholds,
|
||||
}: Props) {
|
||||
const fieldConfig = fieldDisplay.field;
|
||||
const min = fieldConfig.min ?? 0;
|
||||
const max = fieldConfig.max ?? 100;
|
||||
|
||||
shape,
|
||||
gradient,
|
||||
}: ThresholdsBarProps) {
|
||||
const thresholdDimensions = {
|
||||
...dimensions,
|
||||
barWidth: dimensions.thresholdsBarWidth,
|
||||
radius: dimensions.thresholdsBarRadius,
|
||||
};
|
||||
|
||||
const [min, max] = getFieldConfigMinMax(fieldDisplay);
|
||||
|
||||
let currentStart = startAngle;
|
||||
let paths: React.ReactNode[] = [];
|
||||
|
||||
@@ -48,27 +49,26 @@ export function ThresholdsBar({
|
||||
valueDeg = 0;
|
||||
}
|
||||
|
||||
let lengthDeg = valueDeg - currentStart + startAngle;
|
||||
const lengthDeg = valueDeg - currentStart + startAngle;
|
||||
const colorProps = gradient ? { gradient } : { color: threshold.color };
|
||||
|
||||
paths.push(
|
||||
<RadialArcPath
|
||||
key={i}
|
||||
startAngle={currentStart}
|
||||
arcLengthDeg={lengthDeg}
|
||||
barEndcaps={shape === 'circle' && roundedBars}
|
||||
dimensions={thresholdDimensions}
|
||||
roundedBars={roundedBars}
|
||||
fieldDisplay={fieldDisplay}
|
||||
glowFilter={glowFilter}
|
||||
color={colorDefs.getColor(threshold.color, true)}
|
||||
roundedBars={roundedBars}
|
||||
shape={shape}
|
||||
startAngle={currentStart}
|
||||
{...colorProps}
|
||||
/>
|
||||
);
|
||||
|
||||
currentStart += lengthDeg;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<g>{paths}</g>
|
||||
<defs>{colorDefs.getDefs()}</defs>
|
||||
</>
|
||||
);
|
||||
return <g>{paths}</g>;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`RadialGauge color utils buildGradientColors should map threshold colors correctly (with baseColor if displayProcessor does not return colors) 1`] = `
|
||||
[
|
||||
{
|
||||
"color": "#444444",
|
||||
"percent": 0,
|
||||
},
|
||||
{
|
||||
"color": "#FADE2A",
|
||||
"percent": 0.5,
|
||||
},
|
||||
{
|
||||
"color": "#F2495C",
|
||||
"percent": 0.8,
|
||||
},
|
||||
{
|
||||
"color": "#444444",
|
||||
"percent": 1,
|
||||
},
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`RadialGauge color utils buildGradientColors should map threshold colors correctly (with baseColor if displayProcessor does not return colors) 2`] = `
|
||||
[
|
||||
{
|
||||
"color": "#FF0000",
|
||||
"percent": 0,
|
||||
},
|
||||
{
|
||||
"color": "#FADE2A",
|
||||
"percent": 0.5,
|
||||
},
|
||||
{
|
||||
"color": "#F2495C",
|
||||
"percent": 0.8,
|
||||
},
|
||||
{
|
||||
"color": "#FF0000",
|
||||
"percent": 1,
|
||||
},
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`RadialGauge color utils buildGradientColors should return gradient colors for by-value color mode in dark theme 1`] = `
|
||||
[
|
||||
{
|
||||
"color": "#181b1f",
|
||||
"percent": 0,
|
||||
},
|
||||
{
|
||||
"color": "#1F60C4",
|
||||
"percent": 1,
|
||||
},
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`RadialGauge color utils buildGradientColors should return gradient colors for by-value color mode in light theme 1`] = `
|
||||
[
|
||||
{
|
||||
"color": "#ffffff",
|
||||
"percent": 0,
|
||||
},
|
||||
{
|
||||
"color": "#1250B0",
|
||||
"percent": 1,
|
||||
},
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`RadialGauge color utils buildGradientColors should return gradient colors for continuous color modes 1`] = `
|
||||
[
|
||||
{
|
||||
"color": "rgb(0, 32, 81)",
|
||||
"percent": 0,
|
||||
},
|
||||
{
|
||||
"color": "rgb(17, 54, 108)",
|
||||
"percent": 0.125,
|
||||
},
|
||||
{
|
||||
"color": "rgb(60, 77, 110)",
|
||||
"percent": 0.25,
|
||||
},
|
||||
{
|
||||
"color": "rgb(98, 100, 111)",
|
||||
"percent": 0.375,
|
||||
},
|
||||
{
|
||||
"color": "rgb(127, 124, 117)",
|
||||
"percent": 0.5,
|
||||
},
|
||||
{
|
||||
"color": "rgb(154, 148, 120)",
|
||||
"percent": 0.625,
|
||||
},
|
||||
{
|
||||
"color": "rgb(187, 175, 113)",
|
||||
"percent": 0.75,
|
||||
},
|
||||
{
|
||||
"color": "rgb(226, 203, 92)",
|
||||
"percent": 0.875,
|
||||
},
|
||||
{
|
||||
"color": "rgb(253, 234, 69)",
|
||||
"percent": 1,
|
||||
},
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`RadialGauge color utils buildGradientColors should return gradient colors for fixed color mode in dark theme 1`] = `
|
||||
[
|
||||
{
|
||||
"color": "#37237a",
|
||||
"percent": 0,
|
||||
},
|
||||
{
|
||||
"color": "#a146da",
|
||||
"percent": 0.75,
|
||||
},
|
||||
{
|
||||
"color": "#a146da",
|
||||
"percent": 1,
|
||||
},
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`RadialGauge color utils buildGradientColors should return gradient colors for fixed color mode in light theme 1`] = `
|
||||
[
|
||||
{
|
||||
"color": "#a146da",
|
||||
"percent": 0,
|
||||
},
|
||||
{
|
||||
"color": "#3e2b9a",
|
||||
"percent": 0.75,
|
||||
},
|
||||
{
|
||||
"color": "#3e2b9a",
|
||||
"percent": 1,
|
||||
},
|
||||
]
|
||||
`;
|
||||
@@ -0,0 +1,17 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`RadialGauge utils drawRadialArcPath should draw correct path for center x and y 1`] = `"M 150 110 A 90 90 0 1 1 149.98429203681178 110.00000137077838 A 10 10 0 0 1 149.98778269529805 130.00000106616096 A 70 70 0 1 0 150 130 A 10 10 0 0 1 150 110 Z"`;
|
||||
|
||||
exports[`RadialGauge utils drawRadialArcPath should draw correct path for half arc 1`] = `"M 100 10 A 90 90 0 0 1 100 190 L 100 170 A 70 70 0 0 0 100 30 L 100 10 Z"`;
|
||||
|
||||
exports[`RadialGauge utils drawRadialArcPath should draw correct path for narrow bar width 1`] = `"M 100 17.5 A 82.5 82.5 0 0 1 100 182.5 L 100 177.5 A 77.5 77.5 0 0 0 100 22.5 L 100 17.5 Z"`;
|
||||
|
||||
exports[`RadialGauge utils drawRadialArcPath should draw correct path for narrow radius 1`] = `"M 100 40 A 60 60 0 0 1 100 160 L 100 140 A 40 40 0 0 0 100 60 L 100 40 Z"`;
|
||||
|
||||
exports[`RadialGauge utils drawRadialArcPath should draw correct path for quarter arc 1`] = `"M 100 10 A 90 90 0 0 1 190 100 L 170 100 A 70 70 0 0 0 100 30 L 100 10 Z"`;
|
||||
|
||||
exports[`RadialGauge utils drawRadialArcPath should draw correct path for rounded bars 1`] = `"M 100 10 A 90 90 0 1 1 10 100.00000000000001 A 10 10 0 0 1 30 100.00000000000001 A 70 70 0 1 0 100 30 A 10 10 0 0 1 100 10 Z"`;
|
||||
|
||||
exports[`RadialGauge utils drawRadialArcPath should draw correct path for three quarter arc 1`] = `"M 100 10 A 90 90 0 1 1 10 100.00000000000001 L 30 100.00000000000001 A 70 70 0 1 0 100 30 L 100 10 Z"`;
|
||||
|
||||
exports[`RadialGauge utils drawRadialArcPath should draw correct path for wide bar width 1`] = `"M 100 -5 A 105 105 0 0 1 100 205 L 100 155 A 55 55 0 0 0 100 45 L 100 -5 Z"`;
|
||||
@@ -0,0 +1,257 @@
|
||||
import { defaultsDeep } from 'lodash';
|
||||
|
||||
import { createTheme, FALLBACK_COLOR, Field, FieldDisplay, FieldType, ThresholdsMode } from '@grafana/data';
|
||||
import { FieldColorModeId } from '@grafana/schema';
|
||||
|
||||
import {
|
||||
buildGradientColors,
|
||||
colorAtGradientPercent,
|
||||
getBarEndcapColors,
|
||||
getEndpointMarkerColors,
|
||||
getGradientCss,
|
||||
} from './colors';
|
||||
|
||||
export type DeepPartial<T> = {
|
||||
[P in keyof T]?: DeepPartial<T[P]>;
|
||||
};
|
||||
|
||||
describe('RadialGauge color utils', () => {
|
||||
describe('buildGradientColors', () => {
|
||||
const createField = (colorMode: FieldColorModeId): Field =>
|
||||
({
|
||||
type: FieldType.number,
|
||||
name: 'Test Field',
|
||||
config: {
|
||||
color: {
|
||||
mode: colorMode,
|
||||
},
|
||||
thresholds: {
|
||||
mode: ThresholdsMode.Absolute,
|
||||
steps: [
|
||||
{ value: -Infinity, color: 'green' },
|
||||
{ value: 50, color: 'yellow' },
|
||||
{ value: 80, color: 'red' },
|
||||
],
|
||||
},
|
||||
},
|
||||
values: [70, 40, 30, 90, 55],
|
||||
}) satisfies Field;
|
||||
|
||||
const buildFieldDisplay = (field: Field, part = {}): FieldDisplay =>
|
||||
defaultsDeep(part, {
|
||||
field: field.config,
|
||||
colIndex: 0,
|
||||
view: {
|
||||
getFieldDisplayProcessor: jest.fn(() => jest.fn(() => ({ color: undefined }))),
|
||||
},
|
||||
display: {
|
||||
numeric: 75,
|
||||
},
|
||||
});
|
||||
|
||||
it('should return the baseColor if gradient is false-y', () => {
|
||||
expect(
|
||||
buildGradientColors(false, createTheme(), buildFieldDisplay(createField(FieldColorModeId.Fixed)), '#FF0000')
|
||||
).toEqual([
|
||||
{ color: '#FF0000', percent: 0 },
|
||||
{ color: '#FF0000', percent: 1 },
|
||||
]);
|
||||
|
||||
expect(
|
||||
buildGradientColors(undefined, createTheme(), buildFieldDisplay(createField(FieldColorModeId.Fixed)), '#FF0000')
|
||||
).toEqual([
|
||||
{ color: '#FF0000', percent: 0 },
|
||||
{ color: '#FF0000', percent: 1 },
|
||||
]);
|
||||
});
|
||||
|
||||
it('uses the fallback color if no baseColor is set', () => {
|
||||
expect(buildGradientColors(false, createTheme(), buildFieldDisplay(createField(FieldColorModeId.Fixed)))).toEqual(
|
||||
[
|
||||
{ color: FALLBACK_COLOR, percent: 0 },
|
||||
{ color: FALLBACK_COLOR, percent: 1 },
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
it('should map threshold colors correctly (with baseColor if displayProcessor does not return colors)', () => {
|
||||
expect(
|
||||
buildGradientColors(
|
||||
true,
|
||||
createTheme(),
|
||||
buildFieldDisplay(createField(FieldColorModeId.Thresholds), {
|
||||
view: { getFieldDisplayProcessor: jest.fn(() => jest.fn(() => ({ color: '#444444' }))) },
|
||||
})
|
||||
)
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should map threshold colors correctly (with baseColor if displayProcessor does not return colors)', () => {
|
||||
expect(
|
||||
buildGradientColors(true, createTheme(), buildFieldDisplay(createField(FieldColorModeId.Thresholds)), '#FF0000')
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should return gradient colors for continuous color modes', () => {
|
||||
expect(
|
||||
buildGradientColors(
|
||||
true,
|
||||
createTheme(),
|
||||
buildFieldDisplay(createField(FieldColorModeId.ContinuousCividis)),
|
||||
'#00FF00'
|
||||
)
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it.each(['dark', 'light'] as const)('should return gradient colors for by-value color mode in %s theme', (mode) => {
|
||||
expect(
|
||||
buildGradientColors(
|
||||
true,
|
||||
createTheme({ colors: { mode } }),
|
||||
buildFieldDisplay(createField(FieldColorModeId.ContinuousBlues))
|
||||
)
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it.each(['dark', 'light'] as const)('should return gradient colors for fixed color mode in %s theme', (mode) => {
|
||||
expect(
|
||||
buildGradientColors(
|
||||
true,
|
||||
createTheme({ colors: { mode } }),
|
||||
buildFieldDisplay(createField(FieldColorModeId.Fixed)),
|
||||
'#442299'
|
||||
)
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('colorAtGradientPercent', () => {
|
||||
it('should calculate the color at a given percent in a gradient of two colors', () => {
|
||||
const gradient = [
|
||||
{ color: '#ff0000', percent: 0 },
|
||||
{ color: '#0000ff', percent: 1 },
|
||||
];
|
||||
expect(colorAtGradientPercent(gradient, 0).toHexString()).toBe('#ff0000');
|
||||
expect(colorAtGradientPercent(gradient, 0.25).toHexString()).toBe('#bf0040');
|
||||
expect(colorAtGradientPercent(gradient, 0.5).toHexString()).toBe('#800080');
|
||||
expect(colorAtGradientPercent(gradient, 0.75).toHexString()).toBe('#4000bf');
|
||||
expect(colorAtGradientPercent(gradient, 1).toHexString()).toBe('#0000ff');
|
||||
});
|
||||
|
||||
it('should calculate the color at a given percent in a gradient of multiple colors', () => {
|
||||
const gradient = [
|
||||
{ color: '#ff0000', percent: 0 },
|
||||
{ color: '#00ff00', percent: 0.5 },
|
||||
{ color: '#0000ff', percent: 1 },
|
||||
];
|
||||
expect(colorAtGradientPercent(gradient, 0).toHexString()).toBe('#ff0000');
|
||||
expect(colorAtGradientPercent(gradient, 0.25).toHexString()).toBe('#808000');
|
||||
expect(colorAtGradientPercent(gradient, 0.5).toHexString()).toBe('#00ff00');
|
||||
expect(colorAtGradientPercent(gradient, 0.75).toHexString()).toBe('#008080');
|
||||
expect(colorAtGradientPercent(gradient, 1).toHexString()).toBe('#0000ff');
|
||||
});
|
||||
|
||||
it('will still work if unsorted', () => {
|
||||
const gradient = [
|
||||
{ color: '#0000ff', percent: 1 },
|
||||
{ color: '#00ff00', percent: 0.5 },
|
||||
{ color: '#ff0000', percent: 0 },
|
||||
];
|
||||
expect(colorAtGradientPercent(gradient, 0).toHexString()).toBe('#ff0000');
|
||||
expect(colorAtGradientPercent(gradient, 0.25).toHexString()).toBe('#808000');
|
||||
expect(colorAtGradientPercent(gradient, 0.5).toHexString()).toBe('#00ff00');
|
||||
expect(colorAtGradientPercent(gradient, 0.75).toHexString()).toBe('#008080');
|
||||
expect(colorAtGradientPercent(gradient, 1).toHexString()).toBe('#0000ff');
|
||||
});
|
||||
|
||||
it('should not throw an error when percent is outside 0-1 range', () => {
|
||||
const gradient = [
|
||||
{ color: '#ff0000', percent: 0 },
|
||||
{ color: '#0000ff', percent: 1 },
|
||||
];
|
||||
expect(colorAtGradientPercent(gradient, -0.5).toHexString()).toBe('#ff0000');
|
||||
expect(colorAtGradientPercent(gradient, 1.5).toHexString()).toBe('#0000ff');
|
||||
});
|
||||
|
||||
it('should throw an error when less than two stops are provided', () => {
|
||||
expect(() => {
|
||||
colorAtGradientPercent([], 0.5);
|
||||
}).toThrow('colorAtGradientPercent requires at least two color stops');
|
||||
expect(() => {
|
||||
colorAtGradientPercent([{ color: '#ff0000', percent: 0 }], 0.5);
|
||||
}).toThrow('colorAtGradientPercent requires at least two color stops');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getBarEndcapColors', () => {
|
||||
it('should return the first and last colors in the gradient', () => {
|
||||
const gradient = [
|
||||
{ color: '#ff0000', percent: 0 },
|
||||
{ color: '#00ff00', percent: 0.5 },
|
||||
{ color: '#0000ff', percent: 1 },
|
||||
];
|
||||
const [startColor, endColor] = getBarEndcapColors(gradient);
|
||||
expect(startColor).toBe('#ff0000');
|
||||
expect(endColor).toBe('#0000ff');
|
||||
});
|
||||
|
||||
it('should return the correct end color based on percent', () => {
|
||||
const gradient = [
|
||||
{ color: '#ff0000', percent: 0 },
|
||||
{ color: '#00ff00', percent: 0.5 },
|
||||
{ color: '#0000ff', percent: 1 },
|
||||
];
|
||||
const [startColor, endColor] = getBarEndcapColors(gradient, 0.25);
|
||||
expect(startColor).toBe('#ff0000');
|
||||
expect(endColor).toBe('#808000');
|
||||
});
|
||||
|
||||
it('should handle gradients with only one colors', () => {
|
||||
const gradient = [{ color: '#ff0000', percent: 0 }];
|
||||
const [startColor, endColor] = getBarEndcapColors(gradient);
|
||||
expect(startColor).toBe('#ff0000');
|
||||
expect(endColor).toBe('#ff0000');
|
||||
});
|
||||
|
||||
it('should throw an error when no colors are provided', () => {
|
||||
expect(() => {
|
||||
getBarEndcapColors([]);
|
||||
}).toThrow('getBarEndcapColors requires at least one color stop');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getGradientCss', () => {
|
||||
it('should return conic-gradient CSS for circle shape', () => {
|
||||
const gradient = [
|
||||
{ color: '#ff0000', percent: 0 },
|
||||
{ color: '#00ff00', percent: 0.5 },
|
||||
{ color: '#0000ff', percent: 1 },
|
||||
];
|
||||
const css = getGradientCss(gradient, 'circle');
|
||||
expect(css).toBe('conic-gradient(from 0deg, #ff0000 0.00%, #00ff00 50.00%, #0000ff 100.00%)');
|
||||
});
|
||||
|
||||
it('should return linear-gradient CSS for arc shape', () => {
|
||||
const gradient = [
|
||||
{ color: '#ff0000', percent: 0 },
|
||||
{ color: '#00ff00', percent: 0.5 },
|
||||
{ color: '#0000ff', percent: 1 },
|
||||
];
|
||||
const css = getGradientCss(gradient, 'gauge');
|
||||
expect(css).toBe('linear-gradient(90deg, #ff0000 0.00%, #00ff00 50.00%, #0000ff 100.00%)');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getEndpointMarkerColors', () => {
|
||||
it('should return contrasting guide dot colors based on the gradient endpoints and percent', () => {
|
||||
const gradient = [
|
||||
{ color: '#000000', percent: 0 },
|
||||
{ color: '#ffffff', percent: 0.5 },
|
||||
{ color: '#ffffff', percent: 1 },
|
||||
];
|
||||
const [startDotColor, endDotColor] = getEndpointMarkerColors(gradient, 0.35);
|
||||
expect(startDotColor).toBe('#fbfbfb');
|
||||
expect(endDotColor).toBe('#111217');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,179 @@
|
||||
import tinycolor from 'tinycolor2';
|
||||
|
||||
import { colorManipulator, FALLBACK_COLOR, FieldDisplay, getFieldColorMode, GrafanaTheme2 } from '@grafana/data';
|
||||
import { FieldColorModeId } from '@grafana/schema';
|
||||
|
||||
import { GradientStop, RadialShape } from './types';
|
||||
import { getFieldConfigMinMax, getFieldDisplayProcessor, getValuePercentageForValue } from './utils';
|
||||
|
||||
export function buildGradientColors(
|
||||
gradient = false,
|
||||
theme: GrafanaTheme2,
|
||||
fieldDisplay: FieldDisplay,
|
||||
baseColor = fieldDisplay.display.color ?? FALLBACK_COLOR
|
||||
): GradientStop[] {
|
||||
if (!gradient) {
|
||||
return [
|
||||
{ color: baseColor, percent: 0 },
|
||||
{ color: baseColor, percent: 1 },
|
||||
];
|
||||
}
|
||||
|
||||
const colorMode = getFieldColorMode(fieldDisplay.field.color?.mode);
|
||||
|
||||
// thresholds get special handling
|
||||
if (colorMode.id === FieldColorModeId.Thresholds) {
|
||||
const displayProcessor = getFieldDisplayProcessor(fieldDisplay);
|
||||
const [min, max] = getFieldConfigMinMax(fieldDisplay);
|
||||
const thresholds = fieldDisplay.field.thresholds?.steps ?? [];
|
||||
|
||||
const result: Array<{ color: string; percent: number }> = [
|
||||
{ color: displayProcessor(min).color ?? baseColor, percent: 0 },
|
||||
];
|
||||
|
||||
for (const threshold of thresholds) {
|
||||
if (threshold.value > min && threshold.value < max) {
|
||||
const percent = (threshold.value - min) / (max - min);
|
||||
result.push({ color: theme.visualization.getColorByName(threshold.color), percent });
|
||||
}
|
||||
}
|
||||
|
||||
result.push({ color: displayProcessor(max).color ?? baseColor, percent: 1 });
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Handle continuous color modes before other by-value modes
|
||||
if (colorMode.isContinuous && colorMode.getColors) {
|
||||
const colors = colorMode.getColors(theme);
|
||||
return colors.map((color, idx) => ({ color, percent: idx / (colors.length - 1) }));
|
||||
}
|
||||
|
||||
// For value-based colors, we want to stay more true to the specific color,
|
||||
// so a radial gradient that adds a bit of light and shade works best
|
||||
if (colorMode.isByValue) {
|
||||
const darkerColor = tinycolor(baseColor).darken(5);
|
||||
const lighterColor = tinycolor(baseColor).spin(20).lighten(10);
|
||||
|
||||
const color1 = theme.isDark ? lighterColor : darkerColor;
|
||||
const color2 = theme.isDark ? darkerColor : lighterColor;
|
||||
|
||||
return [
|
||||
{ color: color1.toString(), percent: 0 },
|
||||
{ color: color2.toString(), percent: 0.6 },
|
||||
{ color: color2.toString(), percent: 1 },
|
||||
];
|
||||
}
|
||||
|
||||
// For fixed / palette based color scales we can create a more hue and light
|
||||
// based linear gradient that we rotate with the value
|
||||
const darkerColor = tinycolor(baseColor)
|
||||
.spin(-20)
|
||||
.darken(theme.isDark ? 15 : 5);
|
||||
const lighterColor = tinycolor(baseColor).saturate(20).spin(20).brighten(10).lighten(10);
|
||||
|
||||
const underlyingGradient = [
|
||||
{ color: theme.isDark ? darkerColor.toString() : lighterColor.toString(), percent: 0 },
|
||||
{ color: theme.isDark ? lighterColor.toString() : darkerColor.toString(), percent: 1 },
|
||||
];
|
||||
|
||||
// rotate the gradient so that the highest contrasting point is the value, depending on theme.
|
||||
const valuePercent = getValuePercentageForValue(fieldDisplay);
|
||||
const startColor = theme.isDark
|
||||
? colorAtGradientPercent(underlyingGradient, 1 - valuePercent).toHexString()
|
||||
: underlyingGradient[0].color;
|
||||
const endColor = theme.isDark
|
||||
? underlyingGradient[1].color
|
||||
: colorAtGradientPercent(underlyingGradient, valuePercent).toHexString();
|
||||
return [
|
||||
{ color: startColor, percent: 0 },
|
||||
{ color: endColor, percent: valuePercent },
|
||||
{ color: endColor, percent: 1 },
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @alpha - perhaps this should go in colorManipulator.ts
|
||||
* Given color stops (each with a color and percentage 0..1) returns the color at a given percentage.
|
||||
* Uses tinycolor.mix for interpolation.
|
||||
* @params stops - array of color stops (percentages 0..1)
|
||||
* @params percent - percentage 0..1
|
||||
* @returns color at the given percentage
|
||||
*/
|
||||
export function colorAtGradientPercent(stops: GradientStop[], percent: number): tinycolor.Instance {
|
||||
if (!stops || stops.length < 2) {
|
||||
throw new Error('colorAtGradientPercent requires at least two color stops');
|
||||
}
|
||||
|
||||
// normalize and sort stops by percent. TODO: is this necessary? is gradientstops always sorted?
|
||||
const sorted = stops
|
||||
.map((s) => ({ color: s.color, percent: Math.min(Math.max(0, s.percent), 1) }))
|
||||
.sort((a, b) => a.percent - b.percent);
|
||||
|
||||
// percent outside range
|
||||
if (percent <= sorted[0].percent) {
|
||||
return tinycolor(sorted[0].color);
|
||||
}
|
||||
if (percent >= sorted[sorted.length - 1].percent) {
|
||||
return tinycolor(sorted[sorted.length - 1].color);
|
||||
}
|
||||
|
||||
// find surrounding stops using binary search
|
||||
let lo = 0;
|
||||
let hi = sorted.length - 1;
|
||||
while (lo + 1 < hi) {
|
||||
const mid = (lo + hi) >> 1;
|
||||
if (percent <= sorted[mid].percent) {
|
||||
hi = mid;
|
||||
} else {
|
||||
lo = mid;
|
||||
}
|
||||
}
|
||||
|
||||
const left = sorted[lo];
|
||||
const right = sorted[hi];
|
||||
|
||||
const range = right.percent - left.percent;
|
||||
const t = range === 0 ? 0 : (percent - left.percent) / range; // 0..1
|
||||
return tinycolor.mix(left.color, right.color, t * 100);
|
||||
}
|
||||
|
||||
export function getBarEndcapColors(gradientStops: GradientStop[], percent = 1): [string, string] {
|
||||
if (gradientStops.length === 0) {
|
||||
throw new Error('getBarEndcapColors requires at least one color stop');
|
||||
}
|
||||
|
||||
const startColor = gradientStops[0].color;
|
||||
let endColor = gradientStops[gradientStops.length - 1].color;
|
||||
|
||||
// if we have a percentageFilled, use it to get a the correct end color based on where the bar terminates
|
||||
if (gradientStops.length >= 2) {
|
||||
const endColorByPercentage = colorAtGradientPercent(gradientStops, percent);
|
||||
endColor =
|
||||
endColorByPercentage.getAlpha() === 1 ? endColorByPercentage.toHexString() : endColorByPercentage.toHex8String();
|
||||
}
|
||||
return [startColor, endColor];
|
||||
}
|
||||
|
||||
export function getGradientCss(gradientStops: GradientStop[], shape: RadialShape): string {
|
||||
const colorStrings = gradientStops.map((stop) => `${stop.color} ${(stop.percent * 100).toFixed(2)}%`);
|
||||
return shape === 'circle'
|
||||
? `conic-gradient(from 0deg, ${colorStrings.join(', ')})`
|
||||
: `linear-gradient(90deg, ${colorStrings.join(', ')})`;
|
||||
}
|
||||
|
||||
// the theme does not make the full palette available to us, and we
|
||||
// don't want transparent colors which our grays usually have.
|
||||
const GRAY_05 = '#111217';
|
||||
const GRAY_90 = '#fbfbfb';
|
||||
const CONTRAST_THRESHOLD_MAX = 4.5;
|
||||
const getGuideDotColor = (color: string): string => {
|
||||
const darkColor = GRAY_05;
|
||||
const lightColor = GRAY_90;
|
||||
return colorManipulator.getContrastRatio(darkColor, color) >= CONTRAST_THRESHOLD_MAX ? darkColor : lightColor;
|
||||
};
|
||||
|
||||
export function getEndpointMarkerColors(gradientStops: GradientStop[], percent = 1): [string, string] {
|
||||
const [startColor, endColor] = getBarEndcapColors(gradientStops, percent);
|
||||
return [getGuideDotColor(startColor), getGuideDotColor(endColor)];
|
||||
}
|
||||
@@ -1,15 +1,18 @@
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
|
||||
import { GaugeDimensions } from './utils';
|
||||
import { RadialGaugeDimensions } from './types';
|
||||
|
||||
export interface GlowGradientProps {
|
||||
id: string;
|
||||
barWidth: number;
|
||||
}
|
||||
|
||||
const MIN_GLOW_SIZE = 0.75;
|
||||
const GLOW_FACTOR = 0.08;
|
||||
|
||||
export function GlowGradient({ id, barWidth }: GlowGradientProps) {
|
||||
// 0.75 is the minimum glow size, and it scales with bar width
|
||||
const glowSize = 0.75 + barWidth * 0.08;
|
||||
const glowSize = MIN_GLOW_SIZE + barWidth * GLOW_FACTOR;
|
||||
|
||||
return (
|
||||
<filter id={id} filterUnits="userSpaceOnUse">
|
||||
@@ -22,56 +25,19 @@ export function GlowGradient({ id, barWidth }: GlowGradientProps) {
|
||||
);
|
||||
}
|
||||
|
||||
export function SpotlightGradient({
|
||||
id,
|
||||
dimensions,
|
||||
roundedBars,
|
||||
angle,
|
||||
theme,
|
||||
}: {
|
||||
id: string;
|
||||
dimensions: GaugeDimensions;
|
||||
angle: number;
|
||||
roundedBars: boolean;
|
||||
theme: GrafanaTheme2;
|
||||
}) {
|
||||
const angleRadian = ((angle - 90) * Math.PI) / 180;
|
||||
|
||||
let x1 = dimensions.centerX + dimensions.radius * Math.cos(angleRadian - 0.2);
|
||||
let y1 = dimensions.centerY + dimensions.radius * Math.sin(angleRadian - 0.2);
|
||||
let x2 = dimensions.centerX + dimensions.radius * Math.cos(angleRadian);
|
||||
let y2 = dimensions.centerY + dimensions.radius * Math.sin(angleRadian);
|
||||
|
||||
if (theme.isLight) {
|
||||
return (
|
||||
<linearGradient x1={x1} y1={y1} x2={x2} y2={y2} id={id} gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0%" stopColor={'black'} stopOpacity={0.0} />
|
||||
<stop offset="90%" stopColor={'black'} stopOpacity={0.0} />
|
||||
<stop offset="91%" stopColor={'black'} stopOpacity={1} />
|
||||
</linearGradient>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<linearGradient x1={x1} y1={y1} x2={x2} y2={y2} id={id} gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0%" stopColor={'white'} stopOpacity={0.0} />
|
||||
<stop offset="95%" stopColor={'white'} stopOpacity={0.5} />
|
||||
{roundedBars && <stop offset="100%" stopColor={'white'} stopOpacity={roundedBars ? 0.7 : 1} />}
|
||||
</linearGradient>
|
||||
);
|
||||
}
|
||||
const CENTER_GLOW_OPACITY = 0.15;
|
||||
|
||||
export function CenterGlowGradient({ gaugeId, color }: { gaugeId: string; color: string }) {
|
||||
return (
|
||||
<radialGradient id={`circle-glow-${gaugeId}`} r={'50%'} fr={'0%'}>
|
||||
<stop offset="0%" stopColor={color} stopOpacity={0.2} />
|
||||
<radialGradient id={`circle-glow-${gaugeId}`} r="50%" fr="0%">
|
||||
<stop offset="0%" stopColor={color} stopOpacity={CENTER_GLOW_OPACITY} />
|
||||
<stop offset="90%" stopColor={color} stopOpacity={0} />
|
||||
</radialGradient>
|
||||
);
|
||||
}
|
||||
|
||||
export interface CenterGlowProps {
|
||||
dimensions: GaugeDimensions;
|
||||
dimensions: RadialGaugeDimensions;
|
||||
gaugeId: string;
|
||||
color?: string;
|
||||
}
|
||||
@@ -82,8 +48,8 @@ export function MiddleCircleGlow({ dimensions, gaugeId, color }: CenterGlowProps
|
||||
return (
|
||||
<>
|
||||
<defs>
|
||||
<radialGradient id={gradientId} r={'50%'} fr={'0%'}>
|
||||
<stop offset="0%" stopColor={color} stopOpacity={0.15} />
|
||||
<radialGradient id={gradientId} r="50%" fr="0%">
|
||||
<stop offset="0%" stopColor={color} stopOpacity={CENTER_GLOW_OPACITY} />
|
||||
<stop offset="90%" stopColor={color} stopOpacity={0} />
|
||||
</radialGradient>
|
||||
</defs>
|
||||
@@ -93,3 +59,36 @@ export function MiddleCircleGlow({ dimensions, gaugeId, color }: CenterGlowProps
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export function SpotlightGradient({
|
||||
id,
|
||||
dimensions,
|
||||
roundedBars,
|
||||
angle,
|
||||
theme,
|
||||
}: {
|
||||
id: string;
|
||||
dimensions: RadialGaugeDimensions;
|
||||
angle: number;
|
||||
roundedBars: boolean;
|
||||
theme: GrafanaTheme2;
|
||||
}) {
|
||||
if (theme.isLight) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const angleRadian = ((angle - 90) * Math.PI) / 180;
|
||||
|
||||
let x1 = dimensions.centerX + dimensions.radius * Math.cos(angleRadian - 0.2);
|
||||
let y1 = dimensions.centerY + dimensions.radius * Math.sin(angleRadian - 0.2);
|
||||
let x2 = dimensions.centerX + dimensions.radius * Math.cos(angleRadian);
|
||||
let y2 = dimensions.centerY + dimensions.radius * Math.sin(angleRadian);
|
||||
|
||||
return (
|
||||
<linearGradient x1={x1} y1={y1} x2={x2} y2={y2} id={id} gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0%" stopColor={'white'} stopOpacity={0.0} />
|
||||
<stop offset="95%" stopColor={'white'} stopOpacity={0.5} />
|
||||
{roundedBars && <stop offset="100%" stopColor={'white'} stopOpacity={roundedBars ? 0.7 : 1} />}
|
||||
</linearGradient>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
export type RadialTextMode = 'auto' | 'value_and_name' | 'value' | 'name' | 'none';
|
||||
export type RadialShape = 'circle' | 'gauge';
|
||||
|
||||
export interface RadialGaugeDimensions {
|
||||
margin: number;
|
||||
radius: number;
|
||||
centerX: number;
|
||||
centerY: number;
|
||||
barWidth: number;
|
||||
endAngle?: number;
|
||||
barIndex: number;
|
||||
thresholdsBarRadius: number;
|
||||
thresholdsBarWidth: number;
|
||||
thresholdsBarSpacing: number;
|
||||
scaleLabelsFontSize: number;
|
||||
scaleLabelsSpacing: number;
|
||||
scaleLabelsRadius: number;
|
||||
gaugeBottomY: number;
|
||||
}
|
||||
|
||||
/** @alpha - perhaps this should go in @grafana/data */
|
||||
export interface GradientStop {
|
||||
color: string;
|
||||
percent: number;
|
||||
}
|
||||
@@ -1,24 +1,111 @@
|
||||
import { FieldDisplay } from '@grafana/data';
|
||||
import { DataFrameView, FieldDisplay } from '@grafana/data';
|
||||
|
||||
import type { RadialGaugeProps } from './RadialGauge';
|
||||
import { calculateDimensions, toRad, getValueAngleForValue } from './utils';
|
||||
import { RadialGaugeDimensions } from './types';
|
||||
import {
|
||||
calculateDimensions,
|
||||
toRad,
|
||||
getValueAngleForValue,
|
||||
drawRadialArcPath,
|
||||
getFieldConfigMinMax,
|
||||
getFieldDisplayProcessor,
|
||||
getAngleBetweenSegments,
|
||||
getOptimalSegmentCount,
|
||||
} from './utils';
|
||||
|
||||
describe('RadialGauge utils', () => {
|
||||
function calc(overrides: Partial<RadialGaugeProps & { barIndex: number }> = {}) {
|
||||
return calculateDimensions(
|
||||
overrides.width ?? 200,
|
||||
overrides.height ?? 200,
|
||||
overrides.shape === 'gauge' ? 110 : 360,
|
||||
overrides.glowBar ?? false,
|
||||
overrides.roundedBars ?? false,
|
||||
overrides.barWidthFactor ?? 0.4,
|
||||
overrides.barIndex ?? 0,
|
||||
overrides.thresholdsBar ?? false,
|
||||
overrides.showScaleLabels ?? false
|
||||
);
|
||||
}
|
||||
describe('getFieldDisplayProcessor', () => {
|
||||
it('should return display processor from view when available', () => {
|
||||
const mockProcessor = jest.fn();
|
||||
const mockView = {
|
||||
getFieldDisplayProcessor: jest.fn().mockReturnValue(mockProcessor),
|
||||
} as unknown as DataFrameView;
|
||||
|
||||
const fieldDisplay: FieldDisplay = {
|
||||
display: { numeric: 50, text: '50', color: 'blue' },
|
||||
field: {},
|
||||
view: mockView,
|
||||
colIndex: 0,
|
||||
rowIndex: 0,
|
||||
name: 'test',
|
||||
getLinks: () => [],
|
||||
hasLinks: false,
|
||||
};
|
||||
|
||||
const dp = getFieldDisplayProcessor(fieldDisplay);
|
||||
expect(dp).toBe(mockProcessor);
|
||||
expect(mockView.getFieldDisplayProcessor).toHaveBeenCalledWith(0);
|
||||
});
|
||||
|
||||
it('should return default display processor when view is not available', () => {
|
||||
const fieldDisplay: FieldDisplay = {
|
||||
display: { numeric: 50, text: '50', color: 'blue' },
|
||||
field: {},
|
||||
view: undefined,
|
||||
colIndex: 0,
|
||||
rowIndex: 0,
|
||||
name: 'test',
|
||||
getLinks: () => [],
|
||||
hasLinks: false,
|
||||
};
|
||||
|
||||
const dp = getFieldDisplayProcessor(fieldDisplay);
|
||||
expect(dp).toBeDefined();
|
||||
expect(typeof dp).toBe('function');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getFieldConfigMinMax', () => {
|
||||
it('should return min and max from field config when defined', () => {
|
||||
const fieldDisplay: FieldDisplay = {
|
||||
display: { numeric: 50, text: '50', color: 'blue' },
|
||||
field: { min: 10, max: 90 },
|
||||
view: undefined,
|
||||
colIndex: 0,
|
||||
rowIndex: 0,
|
||||
name: 'test',
|
||||
getLinks: () => [],
|
||||
hasLinks: false,
|
||||
};
|
||||
|
||||
const [min, max] = getFieldConfigMinMax(fieldDisplay);
|
||||
expect(min).toBe(10);
|
||||
expect(max).toBe(90);
|
||||
});
|
||||
|
||||
it('should return default min and max when not defined in field config', () => {
|
||||
const fieldDisplay: FieldDisplay = {
|
||||
display: { numeric: 50, text: '50', color: 'blue' },
|
||||
field: {},
|
||||
view: undefined,
|
||||
colIndex: 0,
|
||||
rowIndex: 0,
|
||||
name: 'test',
|
||||
getLinks: () => [],
|
||||
hasLinks: false,
|
||||
};
|
||||
|
||||
const [min, max] = getFieldConfigMinMax(fieldDisplay);
|
||||
expect(min).toBe(0);
|
||||
expect(max).toBe(100);
|
||||
});
|
||||
});
|
||||
|
||||
describe('calculateDimensions', () => {
|
||||
function calc(overrides: Partial<RadialGaugeProps & { barIndex: number }> = {}) {
|
||||
return calculateDimensions(
|
||||
overrides.width ?? 200,
|
||||
overrides.height ?? 200,
|
||||
overrides.shape === 'gauge' ? 110 : 360,
|
||||
overrides.glowBar ?? false,
|
||||
overrides.roundedBars ?? false,
|
||||
overrides.barWidthFactor ?? 0.4,
|
||||
overrides.barIndex ?? 0,
|
||||
overrides.thresholdsBar ?? false,
|
||||
overrides.showScaleLabels ?? false
|
||||
);
|
||||
}
|
||||
|
||||
it('should calculate basic dimensions for a square gauge', () => {
|
||||
const result = calc();
|
||||
|
||||
@@ -194,4 +281,84 @@ describe('RadialGauge utils', () => {
|
||||
expect(result.angle).toBe(240);
|
||||
});
|
||||
});
|
||||
|
||||
describe('drawRadialArcPath', () => {
|
||||
const defaultDims: RadialGaugeDimensions = Object.freeze({
|
||||
centerX: 100,
|
||||
centerY: 100,
|
||||
radius: 80,
|
||||
barWidth: 20,
|
||||
margin: 0,
|
||||
barIndex: 0,
|
||||
thresholdsBarWidth: 0,
|
||||
thresholdsBarSpacing: 0,
|
||||
thresholdsBarRadius: 0,
|
||||
scaleLabelsFontSize: 0,
|
||||
scaleLabelsSpacing: 0,
|
||||
scaleLabelsRadius: 0,
|
||||
gaugeBottomY: 0,
|
||||
});
|
||||
|
||||
it.each([
|
||||
{ description: 'quarter arc', startAngle: 0, endAngle: 90 },
|
||||
{ description: 'half arc', startAngle: 0, endAngle: 180 },
|
||||
{ description: 'three quarter arc', startAngle: 0, endAngle: 270 },
|
||||
{ description: 'rounded bars', startAngle: 0, endAngle: 270, roundedBars: true },
|
||||
{ description: 'wide bar width', startAngle: 0, endAngle: 180, dimensions: { barWidth: 50 } },
|
||||
{ description: 'narrow bar width', startAngle: 0, endAngle: 180, dimensions: { barWidth: 5 } },
|
||||
{ description: 'narrow radius', startAngle: 0, endAngle: 180, dimensions: { radius: 50 } },
|
||||
{
|
||||
description: 'center x and y',
|
||||
startAngle: 0,
|
||||
endAngle: 360,
|
||||
roundedBars: true,
|
||||
dimensions: { centerX: 150, centerY: 200 },
|
||||
},
|
||||
])(`should draw correct path for $description`, ({ startAngle, endAngle, dimensions, roundedBars }) => {
|
||||
const path = drawRadialArcPath(startAngle, endAngle, { ...defaultDims, ...dimensions }, roundedBars);
|
||||
expect(path).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe('edge cases', () => {
|
||||
it('should adjust 360deg or greater arcs to avoid SVG rendering issues', () => {
|
||||
expect(drawRadialArcPath(0, 360, defaultDims)).toEqual(drawRadialArcPath(0, 359.99, defaultDims));
|
||||
expect(drawRadialArcPath(0, 380, defaultDims)).toEqual(drawRadialArcPath(0, 380, defaultDims));
|
||||
});
|
||||
|
||||
it('should return empty string if inner radius collapses to zero or below', () => {
|
||||
const smallRadiusDims = { ...defaultDims, radius: 5, barWidth: 20 };
|
||||
expect(drawRadialArcPath(0, 180, smallRadiusDims)).toBe('');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getAngleBetweenSegments', () => {
|
||||
it('should calculate angle between segments based on spacing and count', () => {
|
||||
expect(getAngleBetweenSegments(2, 10, 360)).toBe(48);
|
||||
expect(getAngleBetweenSegments(5, 15, 180)).toBe(40);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getOptimalSegmentCount', () => {
|
||||
it('should adjust segment count based on dimensions and spacing', () => {
|
||||
const dimensions: RadialGaugeDimensions = {
|
||||
centerX: 100,
|
||||
centerY: 100,
|
||||
radius: 80,
|
||||
barWidth: 20,
|
||||
margin: 0,
|
||||
barIndex: 0,
|
||||
thresholdsBarWidth: 0,
|
||||
thresholdsBarSpacing: 0,
|
||||
thresholdsBarRadius: 0,
|
||||
scaleLabelsFontSize: 0,
|
||||
scaleLabelsSpacing: 0,
|
||||
scaleLabelsRadius: 0,
|
||||
gaugeBottomY: 0,
|
||||
};
|
||||
|
||||
expect(getOptimalSegmentCount(dimensions, 2, 10, 360)).toBe(8);
|
||||
expect(getOptimalSegmentCount(dimensions, 1, 5, 360)).toBe(5);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,11 +1,38 @@
|
||||
import { FieldDisplay } from '@grafana/data';
|
||||
import { FieldDisplay, getDisplayProcessor } from '@grafana/data';
|
||||
|
||||
export function getValueAngleForValue(fieldDisplay: FieldDisplay, startAngle: number, endAngle: number) {
|
||||
const angleRange = (360 % (startAngle === 0 ? 1 : startAngle)) + endAngle;
|
||||
import { RadialGaugeDimensions } from './types';
|
||||
|
||||
export function getFieldDisplayProcessor(displayValue: FieldDisplay) {
|
||||
if (displayValue.view && displayValue.colIndex != null) {
|
||||
const dp = displayValue.view.getFieldDisplayProcessor(displayValue.colIndex);
|
||||
if (dp) {
|
||||
return dp;
|
||||
}
|
||||
}
|
||||
|
||||
return getDisplayProcessor();
|
||||
}
|
||||
|
||||
export function getFieldConfigMinMax(fieldDisplay: FieldDisplay) {
|
||||
const min = fieldDisplay.field.min ?? 0;
|
||||
const max = fieldDisplay.field.max ?? 100;
|
||||
return [min, max];
|
||||
}
|
||||
|
||||
let angle = ((fieldDisplay.display.numeric - min) / (max - min)) * angleRange;
|
||||
export function getValuePercentageForValue(fieldDisplay: FieldDisplay, value = fieldDisplay.display.numeric) {
|
||||
const [min, max] = getFieldConfigMinMax(fieldDisplay);
|
||||
return (value - min) / (max - min);
|
||||
}
|
||||
|
||||
export function getValueAngleForValue(
|
||||
fieldDisplay: FieldDisplay,
|
||||
startAngle: number,
|
||||
endAngle: number,
|
||||
value = fieldDisplay.display.numeric
|
||||
) {
|
||||
const angleRange = (360 % (startAngle === 0 ? 1 : startAngle)) + endAngle;
|
||||
|
||||
let angle = getValuePercentageForValue(fieldDisplay, value) * angleRange;
|
||||
|
||||
if (angle > angleRange) {
|
||||
angle = angleRange;
|
||||
@@ -26,24 +53,19 @@ export function toRad(angle: number) {
|
||||
return ((angle - 90) * Math.PI) / 180;
|
||||
}
|
||||
|
||||
export interface GaugeDimensions {
|
||||
margin: number;
|
||||
radius: number;
|
||||
centerX: number;
|
||||
centerY: number;
|
||||
barWidth: number;
|
||||
endAngle?: number;
|
||||
barIndex: number;
|
||||
thresholdsBarRadius: number;
|
||||
thresholdsBarWidth: number;
|
||||
thresholdsBarSpacing: number;
|
||||
showScaleLabels?: boolean;
|
||||
scaleLabelsFontSize: number;
|
||||
scaleLabelsSpacing: number;
|
||||
scaleLabelsRadius: number;
|
||||
gaugeBottomY: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the calculated dimensions for the radial gauge
|
||||
* @param width
|
||||
* @param height
|
||||
* @param endAngle
|
||||
* @param glow
|
||||
* @param roundedBars
|
||||
* @param barWidthFactor
|
||||
* @param barIndex
|
||||
* @param thresholdBar
|
||||
* @param showScaleLabels
|
||||
* @returns {RadialGaugeDimensions}
|
||||
*/
|
||||
export function calculateDimensions(
|
||||
width: number,
|
||||
height: number,
|
||||
@@ -54,7 +76,7 @@ export function calculateDimensions(
|
||||
barIndex: number,
|
||||
thresholdBar?: boolean,
|
||||
showScaleLabels?: boolean
|
||||
): GaugeDimensions {
|
||||
): RadialGaugeDimensions {
|
||||
const yMaxAngle = endAngle > 180 ? 180 : endAngle;
|
||||
let margin = 0;
|
||||
|
||||
@@ -97,6 +119,7 @@ export function calculateDimensions(
|
||||
maxRadiusW -= labelsSize;
|
||||
maxRadiusH -= labelsSize;
|
||||
|
||||
// FIXME: needs coverage
|
||||
// For gauges the max label needs a bit more vertical space so that it does not get clipped
|
||||
if (maxRadiusIsLimitedByHeight && endAngle < 180) {
|
||||
const amount = outerRadius * 0.07;
|
||||
@@ -155,3 +178,105 @@ export function toCartesian(centerX: number, centerY: number, radius: number, an
|
||||
y: centerY + radius * Math.sin(radian),
|
||||
};
|
||||
}
|
||||
|
||||
export function drawRadialArcPath(
|
||||
startAngle: number,
|
||||
endAngle: number,
|
||||
dimensions: RadialGaugeDimensions,
|
||||
roundedBars?: boolean
|
||||
): string {
|
||||
const { radius, centerX, centerY, barWidth } = dimensions;
|
||||
|
||||
// For some reason a 100% full arc cannot be rendered
|
||||
if (endAngle >= 360) {
|
||||
endAngle = 359.99;
|
||||
}
|
||||
|
||||
const startRadians = toRad(startAngle);
|
||||
const endRadians = toRad(startAngle + endAngle);
|
||||
|
||||
const largeArc = endAngle > 180 ? 1 : 0;
|
||||
|
||||
const outerR = radius + barWidth / 2;
|
||||
const innerR = Math.max(0, radius - barWidth / 2);
|
||||
if (innerR <= 0) {
|
||||
return ''; // cannot draw arc with 0 inner radius
|
||||
}
|
||||
|
||||
// get points for both an inner and outer arc. we draw
|
||||
// the arc entirely with a path's fill instead of using stroke
|
||||
// so that it can be used as a clip-path.
|
||||
const ox1 = centerX + outerR * Math.cos(startRadians);
|
||||
const oy1 = centerY + outerR * Math.sin(startRadians);
|
||||
const ox2 = centerX + outerR * Math.cos(endRadians);
|
||||
const oy2 = centerY + outerR * Math.sin(endRadians);
|
||||
|
||||
const ix1 = centerX + innerR * Math.cos(startRadians);
|
||||
const iy1 = centerY + innerR * Math.sin(startRadians);
|
||||
const ix2 = centerX + innerR * Math.cos(endRadians);
|
||||
const iy2 = centerY + innerR * Math.sin(endRadians);
|
||||
|
||||
// calculate the cap width in case we're drawing rounded bars
|
||||
const capR = barWidth / 2;
|
||||
|
||||
const pathParts = [
|
||||
// start at outer start
|
||||
'M',
|
||||
ox1,
|
||||
oy1,
|
||||
// outer arc from start to end (clockwise)
|
||||
'A',
|
||||
outerR,
|
||||
outerR,
|
||||
0,
|
||||
largeArc,
|
||||
1,
|
||||
ox2,
|
||||
oy2,
|
||||
];
|
||||
|
||||
if (roundedBars) {
|
||||
// rounded end cap: small arc connecting outer end to inner end
|
||||
pathParts.push('A', capR, capR, 0, 0, 1, ix2, iy2);
|
||||
} else {
|
||||
// straight line to inner end (square butt)
|
||||
pathParts.push('L', ix2, iy2);
|
||||
}
|
||||
|
||||
// inner arc from end back to start (counter-clockwise)
|
||||
pathParts.push('A', innerR, innerR, 0, largeArc, 0, ix1, iy1);
|
||||
|
||||
if (roundedBars) {
|
||||
// rounded start cap: small arc connecting inner start back to outer start
|
||||
pathParts.push('A', capR, capR, 0, 0, 1, ox1, oy1);
|
||||
} else {
|
||||
// straight line back to outer start (square butt)
|
||||
pathParts.push('L', ox1, oy1);
|
||||
}
|
||||
|
||||
pathParts.push('Z');
|
||||
|
||||
return pathParts.join(' ');
|
||||
}
|
||||
|
||||
export function getAngleBetweenSegments(segmentSpacing: number, segmentCount: number, range: number) {
|
||||
// Max spacing is 8 degrees between segments
|
||||
// Changing this constant could be considered a breaking change
|
||||
const maxAngleBetweenSegments = Math.max(range / 1.5 / segmentCount, 2);
|
||||
return segmentSpacing * maxAngleBetweenSegments;
|
||||
}
|
||||
|
||||
export function getOptimalSegmentCount(
|
||||
dimensions: RadialGaugeDimensions,
|
||||
segmentSpacing: number,
|
||||
segmentCount: number,
|
||||
range: number
|
||||
) {
|
||||
const angleBetweenSegments = getAngleBetweenSegments(segmentSpacing, segmentCount, range);
|
||||
|
||||
const innerRadius = dimensions.radius - dimensions.barWidth / 2;
|
||||
const circumference = Math.PI * innerRadius * 2 * (range / 360);
|
||||
const maxSegments = Math.floor(circumference / (angleBetweenSegments + 3));
|
||||
|
||||
return Math.min(maxSegments, segmentCount);
|
||||
}
|
||||
|
||||
@@ -14,30 +14,20 @@ export interface SparklineProps extends Themeable2 {
|
||||
height: number;
|
||||
config?: FieldConfig<GraphFieldConfig>;
|
||||
sparkline: FieldSparkline;
|
||||
showHighlights?: boolean;
|
||||
}
|
||||
|
||||
const SparklineFn: React.FC<SparklineProps> = memo((props) => {
|
||||
const { sparkline, config: fieldConfig, theme, width, height } = props;
|
||||
|
||||
const { frame: alignedDataFrame, warning } = prepareSeries(sparkline, fieldConfig);
|
||||
export const Sparkline: React.FC<SparklineProps> = memo((props) => {
|
||||
const { sparkline, config: fieldConfig, theme, width, height, showHighlights } = props;
|
||||
const { frame: alignedDataFrame, warning } = prepareSeries(sparkline, theme, fieldConfig, showHighlights);
|
||||
if (warning) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const data = preparePlotData2(alignedDataFrame, getStackingGroups(alignedDataFrame));
|
||||
const configBuilder = prepareConfig(sparkline, alignedDataFrame, theme);
|
||||
const configBuilder = prepareConfig(sparkline, alignedDataFrame, theme, showHighlights);
|
||||
|
||||
return <UPlotChart data={data} config={configBuilder} width={width} height={height} />;
|
||||
});
|
||||
|
||||
SparklineFn.displayName = 'Sparkline';
|
||||
|
||||
// we converted to function component above, but some apps extend Sparkline, so we need
|
||||
// to keep exporting a class component until those apps are all rolled out.
|
||||
// see https://github.com/grafana/app-observability-plugin/pull/2079
|
||||
// eslint-disable-next-line react-prefer-function-component/react-prefer-function-component
|
||||
export class Sparkline extends React.PureComponent<SparklineProps> {
|
||||
render() {
|
||||
return <SparklineFn {...this.props} />;
|
||||
}
|
||||
}
|
||||
Sparkline.displayName = 'Sparkline';
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Range } from 'uplot';
|
||||
|
||||
import {
|
||||
applyNullInsertThreshold,
|
||||
// colorManipulator,
|
||||
DataFrame,
|
||||
FieldConfig,
|
||||
FieldSparkline,
|
||||
@@ -22,6 +23,7 @@ import {
|
||||
VisibilityMode,
|
||||
ScaleDirection,
|
||||
ScaleOrientation,
|
||||
// FieldColorModeId,
|
||||
} from '@grafana/schema';
|
||||
|
||||
import { UPlotConfigBuilder } from '../uPlot/config/UPlotConfigBuilder';
|
||||
@@ -112,8 +114,7 @@ export function getYRange(alignedFrame: DataFrame): Range.MinMax {
|
||||
return [roundedMin, roundedMax];
|
||||
}
|
||||
|
||||
// TODO: #112977 enable highlight index
|
||||
// const HIGHLIGHT_IDX_POINT_SIZE = 6;
|
||||
const HIGHLIGHT_IDX_POINT_SIZE = 6;
|
||||
|
||||
const defaultConfig: GraphFieldConfig = {
|
||||
drawStyle: GraphDrawStyle.Line,
|
||||
@@ -124,7 +125,9 @@ const defaultConfig: GraphFieldConfig = {
|
||||
|
||||
export const prepareSeries = (
|
||||
sparkline: FieldSparkline,
|
||||
fieldConfig?: FieldConfig<GraphFieldConfig>
|
||||
_theme: GrafanaTheme2,
|
||||
fieldConfig?: FieldConfig<GraphFieldConfig>,
|
||||
_showHighlights?: boolean
|
||||
): { frame: DataFrame; warning?: string } => {
|
||||
const frame = nullToValue(preparePlotFrame(sparkline, fieldConfig));
|
||||
if (frame.fields.some((f) => f.values.length <= 1)) {
|
||||
@@ -136,16 +139,41 @@ export const prepareSeries = (
|
||||
frame,
|
||||
};
|
||||
}
|
||||
// TODO:rgb(24, 24, 24) will address this.
|
||||
// if (showHighlights && typeof sparkline.highlightLine === 'number') {
|
||||
// const highlightY = sparkline.highlightLine;
|
||||
// const colorMode = getFieldColorModeForField(sparkline.y);
|
||||
// const seriesColor = colorMode.getCalculator(sparkline.y, theme)(highlightY, 0);
|
||||
// frame.fields.push({
|
||||
// name: 'highlightLine',
|
||||
// type: FieldType.number,
|
||||
// values: new Array(frame.length).fill(highlightY),
|
||||
// config: {
|
||||
// color: {
|
||||
// mode: FieldColorModeId.Fixed,
|
||||
// fixedColor: colorManipulator.lighten(seriesColor, 0.5),
|
||||
// },
|
||||
// custom: {
|
||||
// lineStyle: {
|
||||
// fill: 'dash',
|
||||
// dash: [5, 2],
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// state: {},
|
||||
// });
|
||||
// }
|
||||
return { frame };
|
||||
};
|
||||
|
||||
export const prepareConfig = (
|
||||
sparkline: FieldSparkline,
|
||||
dataFrame: DataFrame,
|
||||
theme: GrafanaTheme2
|
||||
theme: GrafanaTheme2,
|
||||
showHighlights?: boolean
|
||||
): UPlotConfigBuilder => {
|
||||
const builder = new UPlotConfigBuilder();
|
||||
// const rangePad = HIGHLIGHT_IDX_POINT_SIZE / 2;
|
||||
const rangePad = HIGHLIGHT_IDX_POINT_SIZE / 2;
|
||||
|
||||
builder.setCursor({
|
||||
show: false,
|
||||
@@ -206,13 +234,14 @@ export const prepareConfig = (
|
||||
|
||||
const colorMode = getFieldColorModeForField(field);
|
||||
const seriesColor = colorMode.getCalculator(field, theme)(0, 0);
|
||||
// TODO: #112977 enable highlight index and adjust padding accordingly
|
||||
// const hasHighlightIndex = typeof sparkline.highlightIndex === 'number';
|
||||
// if (hasHighlightIndex) {
|
||||
// builder.setPadding([rangePad, rangePad, rangePad, rangePad]);
|
||||
// }
|
||||
|
||||
const hasHighlightIndex = showHighlights && typeof sparkline.highlightIndex === 'number';
|
||||
if (hasHighlightIndex) {
|
||||
builder.setPadding([rangePad, rangePad, rangePad, rangePad]);
|
||||
}
|
||||
|
||||
const pointsMode =
|
||||
customConfig.drawStyle === GraphDrawStyle.Points // || hasHighlightIndex
|
||||
customConfig.drawStyle === GraphDrawStyle.Points || hasHighlightIndex
|
||||
? VisibilityMode.Always
|
||||
: customConfig.showPoints;
|
||||
|
||||
@@ -227,9 +256,8 @@ export const prepareConfig = (
|
||||
lineWidth: customConfig.lineWidth,
|
||||
lineInterpolation: customConfig.lineInterpolation,
|
||||
showPoints: pointsMode,
|
||||
// TODO: #112977 enable highlight index
|
||||
pointSize: /* hasHighlightIndex ? HIGHLIGHT_IDX_POINT_SIZE : */ customConfig.pointSize,
|
||||
// pointsFilter: hasHighlightIndex ? [sparkline.highlightIndex!] : undefined,
|
||||
pointSize: hasHighlightIndex ? HIGHLIGHT_IDX_POINT_SIZE : customConfig.pointSize,
|
||||
pointsFilter: hasHighlightIndex ? [sparkline.highlightIndex!] : undefined,
|
||||
fillOpacity: customConfig.fillOpacity,
|
||||
fillColor: customConfig.fillColor,
|
||||
lineStyle: customConfig.lineStyle,
|
||||
|
||||
@@ -200,6 +200,7 @@ type FrontendSettingsDTO struct {
|
||||
RudderstackWriteKey string `json:"rudderstackWriteKey"`
|
||||
RudderstackDataPlaneUrl string `json:"rudderstackDataPlaneUrl"`
|
||||
RudderstackSdkUrl string `json:"rudderstackSdkUrl"`
|
||||
RudderstackV3SdkUrl string `json:"rudderstackV3SdkUrl"`
|
||||
RudderstackConfigUrl string `json:"rudderstackConfigUrl"`
|
||||
RudderstackIntegrationsUrl string `json:"rudderstackIntegrationsUrl"`
|
||||
|
||||
|
||||
@@ -229,6 +229,7 @@ func (hs *HTTPServer) getFrontendSettings(c *contextmodel.ReqContext) (*dtos.Fro
|
||||
RudderstackWriteKey: hs.Cfg.RudderstackWriteKey,
|
||||
RudderstackDataPlaneUrl: hs.Cfg.RudderstackDataPlaneURL,
|
||||
RudderstackSdkUrl: hs.Cfg.RudderstackSDKURL,
|
||||
RudderstackV3SdkUrl: hs.Cfg.RudderstackV3SDKURL,
|
||||
RudderstackConfigUrl: hs.Cfg.RudderstackConfigURL,
|
||||
RudderstackIntegrationsUrl: hs.Cfg.RudderstackIntegrationsURL,
|
||||
AnalyticsConsoleReporting: hs.Cfg.FrontendAnalyticsConsoleReporting,
|
||||
|
||||
+23
-8
@@ -54,7 +54,8 @@ func init() {
|
||||
}
|
||||
logger := level.NewFilter(format(os.Stderr), level.AllowInfo())
|
||||
root = newManager(logger)
|
||||
initAppSDKLogger(logger)
|
||||
// Use default Info level during package initialization before config is loaded
|
||||
initAppSDKLogger(logger, slog.LevelInfo)
|
||||
|
||||
RegisterContextualLogProvider(func(ctx context.Context) ([]any, bool) {
|
||||
pFromCtx := ctx.Value(logParamsContextKey{})
|
||||
@@ -80,7 +81,7 @@ func newManager(logger gokitlog.Logger) *logManager {
|
||||
}
|
||||
}
|
||||
|
||||
func (lm *logManager) initialize(loggers []logWithFilters) {
|
||||
func (lm *logManager) initialize(loggers []logWithFilters, levelStr string) {
|
||||
lm.mutex.Lock()
|
||||
defer lm.mutex.Unlock()
|
||||
|
||||
@@ -113,7 +114,7 @@ func (lm *logManager) initialize(loggers []logWithFilters) {
|
||||
lm.loggersByName[name].Swap(&compositeLogger{loggers: ctxLoggers})
|
||||
}
|
||||
|
||||
initAppSDKLogger(lm.ConcreteLogger)
|
||||
initAppSDKLogger(lm.ConcreteLogger, stringToSlogLevel(levelStr))
|
||||
}
|
||||
|
||||
func (lm *logManager) New(ctx ...any) *ConcreteLogger {
|
||||
@@ -514,7 +515,7 @@ func ReadLoggingConfig(modes []string, logsPath string, cfg *ini.File) error {
|
||||
configLoggers = append(configLoggers, handler)
|
||||
}
|
||||
if len(configLoggers) > 0 {
|
||||
root.initialize(configLoggers)
|
||||
root.initialize(configLoggers, defaultLevelName)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -551,8 +552,22 @@ func SetupConsoleLogger(level string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func initAppSDKLogger(gkl gokitlog.Logger) {
|
||||
// We need to allow Debug logs here. go-kit/log does not support sharing the level we're using.
|
||||
// TODO: Refactor such that we can pass in a level in a more appropriate manner.
|
||||
logging.DefaultLogger = logging.NewSLogLogger(sloggokit.NewGoKitHandler(gkl, slog.LevelDebug))
|
||||
// stringToSlogLevel converts a log level string to slog.Level
|
||||
func stringToSlogLevel(levelStr string) slog.Level {
|
||||
switch strings.ToLower(levelStr) {
|
||||
case "trace", "debug":
|
||||
return slog.LevelDebug
|
||||
case "info":
|
||||
return slog.LevelInfo
|
||||
case "warn", "warning":
|
||||
return slog.LevelWarn
|
||||
case "error", "critical":
|
||||
return slog.LevelError
|
||||
default:
|
||||
return slog.LevelInfo
|
||||
}
|
||||
}
|
||||
|
||||
func initAppSDKLogger(gkl gokitlog.Logger, level slog.Level) {
|
||||
logging.DefaultLogger = logging.NewSLogLogger(sloggokit.NewGoKitHandler(gkl, level))
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ func TestNew(t *testing.T) {
|
||||
val: swapLogger,
|
||||
maxLevel: level.AllowAll(),
|
||||
},
|
||||
})
|
||||
}, "info")
|
||||
|
||||
err := log1.Log("msg", "hello 1")
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"log/slog"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
|
||||
@@ -102,7 +103,8 @@ func getColumns(fields []string) []*resourcepb.ResourceTableColumnDefinition {
|
||||
columns := getDefaultColumns()
|
||||
|
||||
for _, field := range fields {
|
||||
if col, ok := builders.TeamSearchTableColumnDefinitions[field]; ok {
|
||||
fieldName := strings.TrimPrefix(field, res.SEARCH_FIELD_PREFIX)
|
||||
if col, ok := builders.TeamSearchTableColumnDefinitions[fieldName]; ok {
|
||||
columns = append(columns, col)
|
||||
}
|
||||
}
|
||||
@@ -121,7 +123,8 @@ func getDefaultColumns() []*resourcepb.ResourceTableColumnDefinition {
|
||||
func createCells(t *team.TeamDTO, fields []string) [][]byte {
|
||||
cells := createDefaultCells(t)
|
||||
for _, field := range fields {
|
||||
switch field {
|
||||
fieldName := strings.TrimPrefix(field, res.SEARCH_FIELD_PREFIX)
|
||||
switch fieldName {
|
||||
case builders.TEAM_SEARCH_EMAIL:
|
||||
cells = append(cells, []byte(t.Email))
|
||||
case builders.TEAM_SEARCH_PROVISIONED:
|
||||
|
||||
@@ -2,6 +2,7 @@ package iam
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
@@ -12,6 +13,7 @@ import (
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
|
||||
iamv0alpha1 "github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/services/apiserver/builder"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
@@ -137,6 +139,12 @@ func (s *TeamSearchHandler) DoTeamSearch(w http.ResponseWriter, r *http.Request)
|
||||
return
|
||||
}
|
||||
|
||||
requester, err := identity.GetRequester(ctx)
|
||||
if err != nil {
|
||||
errhttp.Write(ctx, fmt.Errorf("no identity found for request: %w", err), w)
|
||||
return
|
||||
}
|
||||
|
||||
limit := 50
|
||||
offset := 0
|
||||
page := 1
|
||||
@@ -154,16 +162,23 @@ func (s *TeamSearchHandler) DoTeamSearch(w http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
|
||||
searchRequest := &resourcepb.ResourceSearchRequest{
|
||||
Options: &resourcepb.ListOptions{},
|
||||
Options: &resourcepb.ListOptions{
|
||||
Key: &resourcepb.ResourceKey{
|
||||
Group: iamv0alpha1.TeamResourceInfo.GroupResource().Group,
|
||||
Resource: iamv0alpha1.TeamResourceInfo.GroupResource().Resource,
|
||||
Namespace: requester.GetNamespace(),
|
||||
},
|
||||
},
|
||||
Query: queryParams.Get("query"),
|
||||
Limit: int64(limit),
|
||||
Offset: int64(offset),
|
||||
Page: int64(page),
|
||||
Explain: queryParams.Has("explain") && queryParams.Get("explain") != "false",
|
||||
Fields: []string{
|
||||
builders.TEAM_SEARCH_EMAIL,
|
||||
builders.TEAM_SEARCH_PROVISIONED,
|
||||
builders.TEAM_SEARCH_EXTERNAL_UID,
|
||||
resource.SEARCH_FIELD_TITLE,
|
||||
resource.SEARCH_FIELD_PREFIX + builders.TEAM_SEARCH_EMAIL,
|
||||
resource.SEARCH_FIELD_PREFIX + builders.TEAM_SEARCH_PROVISIONED,
|
||||
resource.SEARCH_FIELD_PREFIX + builders.TEAM_SEARCH_EXTERNAL_UID,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ func TestTeamSearchHandler(t *testing.T) {
|
||||
if mockClient.LastSearchRequest == nil {
|
||||
t.Fatalf("expected Search to be called, but it was not")
|
||||
}
|
||||
expectedFields := []string{"email", "provisioned", "externalUID"}
|
||||
expectedFields := []string{"title", "fields.email", "fields.provisioned", "fields.externalUID"}
|
||||
if fmt.Sprintf("%v", mockClient.LastSearchRequest.Fields) != fmt.Sprintf("%v", expectedFields) {
|
||||
t.Errorf("expected fields %v, got %v", expectedFields, mockClient.LastSearchRequest.Fields)
|
||||
}
|
||||
|
||||
@@ -9,10 +9,13 @@ import (
|
||||
"maps"
|
||||
"os"
|
||||
"slices"
|
||||
"time"
|
||||
|
||||
"github.com/fullstorydev/grpchan"
|
||||
grpc_retry "github.com/grpc-ecosystem/go-grpc-middleware/retry"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/credentials"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
"google.golang.org/grpc/metadata"
|
||||
@@ -72,6 +75,15 @@ func NewGRPCDecryptClientWithTLS(
|
||||
opts = append(opts, grpc.WithDisableServiceConfig())
|
||||
}
|
||||
|
||||
// Add retry interceptor to retry on transient connection issues.
|
||||
// Retries on ResourceExhausted (per-RPC limits reached) and Unavailable (system unavailable).
|
||||
retryInterceptor := grpc_retry.UnaryClientInterceptor(
|
||||
grpc_retry.WithMax(3),
|
||||
grpc_retry.WithBackoff(grpc_retry.BackoffExponentialWithJitter(time.Second, 0.5)),
|
||||
grpc_retry.WithCodes(codes.ResourceExhausted, codes.Unavailable),
|
||||
)
|
||||
opts = append(opts, grpc.WithUnaryInterceptor(retryInterceptor))
|
||||
|
||||
conn, err := grpc.NewClient(address, opts...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to connect to grpc decrypt server at %s: %w", address, err)
|
||||
|
||||
@@ -76,7 +76,7 @@ func ProvideAppInstallers(
|
||||
if features.IsEnabledGlobally(featuremgmt.FlagKubernetesLogsDrilldown) {
|
||||
installers = append(installers, logsdrilldownAppInstaller)
|
||||
}
|
||||
//nolint:staticcheck
|
||||
//nolint:staticcheck // not yet migrated to OpenFeature
|
||||
if features.IsEnabledGlobally(featuremgmt.FlagKubernetesAnnotations) {
|
||||
installers = append(installers, annotationAppInstaller)
|
||||
}
|
||||
|
||||
@@ -820,6 +820,13 @@ var (
|
||||
Owner: grafanaDashboardsSquad,
|
||||
HideFromDocs: true,
|
||||
},
|
||||
{
|
||||
Name: "dashboardAdHocAndGroupByWrapper",
|
||||
Description: "Wraps the ad hoc and group by variables in a single wrapper, with all other variables below it",
|
||||
Stage: FeatureStageExperimental,
|
||||
Owner: grafanaDashboardsSquad,
|
||||
HideFromDocs: true,
|
||||
},
|
||||
{
|
||||
Name: "cloudWatchNewLabelParsing",
|
||||
Description: "Updates CloudWatch label parsing to be more accurate",
|
||||
@@ -1960,14 +1967,6 @@ var (
|
||||
Owner: identityAccessTeam,
|
||||
Expression: "true",
|
||||
},
|
||||
{
|
||||
Name: "pluginInsights",
|
||||
Description: "Show insights for plugins in the plugin details page",
|
||||
Stage: FeatureStageExperimental,
|
||||
FrontendOnly: true,
|
||||
Owner: grafanaPluginsPlatformSquad,
|
||||
Expression: "false",
|
||||
},
|
||||
{
|
||||
Name: "panelTimeSettings",
|
||||
Description: "Enables a new panel time settings drawer",
|
||||
|
||||
Generated
+1
-1
@@ -113,6 +113,7 @@ scopeFilters,experimental,@grafana/dashboards-squad,false,false,false
|
||||
oauthRequireSubClaim,experimental,@grafana/identity-access-team,false,false,false
|
||||
refreshTokenRequired,experimental,@grafana/identity-access-team,false,false,false
|
||||
newDashboardWithFiltersAndGroupBy,experimental,@grafana/dashboards-squad,false,false,false
|
||||
dashboardAdHocAndGroupByWrapper,experimental,@grafana/dashboards-squad,false,false,false
|
||||
cloudWatchNewLabelParsing,GA,@grafana/aws-datasources,false,false,false
|
||||
disableNumericMetricsSortingInExpressions,experimental,@grafana/oss-big-tent,false,true,false
|
||||
grafanaManagedRecordingRules,experimental,@grafana/alerting-squad,false,false,false
|
||||
@@ -266,7 +267,6 @@ jaegerEnableGrpcEndpoint,experimental,@grafana/oss-big-tent,false,false,false
|
||||
pluginStoreServiceLoading,experimental,@grafana/plugins-platform-backend,false,false,false
|
||||
newPanelPadding,preview,@grafana/dashboards-squad,false,false,true
|
||||
onlyStoreActionSets,GA,@grafana/identity-access-team,false,false,false
|
||||
pluginInsights,experimental,@grafana/plugins-platform-backend,false,false,true
|
||||
panelTimeSettings,experimental,@grafana/dashboards-squad,false,false,false
|
||||
elasticsearchRawDSLQuery,experimental,@grafana/partner-datasources,false,false,false
|
||||
kubernetesAnnotations,experimental,@grafana/grafana-backend-services-squad,false,false,false
|
||||
|
||||
|
Generated
+4
@@ -339,6 +339,10 @@ const (
|
||||
// Enables filters and group by variables on all new dashboards. Variables are added only if default data source supports filtering.
|
||||
FlagNewDashboardWithFiltersAndGroupBy = "newDashboardWithFiltersAndGroupBy"
|
||||
|
||||
// FlagDashboardAdHocAndGroupByWrapper
|
||||
// Wraps the ad hoc and group by variables in a single wrapper, with all other variables below it
|
||||
FlagDashboardAdHocAndGroupByWrapper = "dashboardAdHocAndGroupByWrapper"
|
||||
|
||||
// FlagCloudWatchNewLabelParsing
|
||||
// Updates CloudWatch label parsing to be more accurate
|
||||
FlagCloudWatchNewLabelParsing = "cloudWatchNewLabelParsing"
|
||||
|
||||
+13
-14
@@ -922,6 +922,19 @@
|
||||
"frontend": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"name": "dashboardAdHocAndGroupByWrapper",
|
||||
"resourceVersion": "1765841806645",
|
||||
"creationTimestamp": "2025-12-15T23:36:46Z"
|
||||
},
|
||||
"spec": {
|
||||
"description": "Wraps the ad hoc and group by variables in a single wrapper, with all other variables below it",
|
||||
"stage": "experimental",
|
||||
"codeowner": "@grafana/dashboards-squad",
|
||||
"hideFromDocs": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"name": "dashboardDisableSchemaValidationV1",
|
||||
@@ -2693,20 +2706,6 @@
|
||||
"expression": "false"
|
||||
}
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"name": "pluginInsights",
|
||||
"resourceVersion": "1761300628147",
|
||||
"creationTimestamp": "2025-10-24T10:10:28Z"
|
||||
},
|
||||
"spec": {
|
||||
"description": "Show insights for plugins in the plugin details page",
|
||||
"stage": "experimental",
|
||||
"codeowner": "@grafana/plugins-platform-backend",
|
||||
"frontend": true,
|
||||
"expression": "false"
|
||||
}
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"name": "pluginInstallAPISync",
|
||||
|
||||
@@ -32,6 +32,7 @@ type FSFrontendSettings struct {
|
||||
RudderstackWriteKey string `json:"rudderstackWriteKey,omitempty"`
|
||||
RudderstackDataPlaneUrl string `json:"rudderstackDataPlaneUrl,omitempty"`
|
||||
RudderstackSdkUrl string `json:"rudderstackSdkUrl,omitempty"`
|
||||
RudderstackV3SdkUrl string `json:"rudderstackV3SdkUrl,omitempty"`
|
||||
RudderstackConfigUrl string `json:"rudderstackConfigUrl,omitempty"`
|
||||
RudderstackIntegrationsUrl string `json:"rudderstackIntegrationsUrl,omitempty"`
|
||||
|
||||
|
||||
@@ -94,6 +94,7 @@ func NewIndexProvider(cfg *setting.Cfg, assetsManifest dtos.EntryPointAssets, li
|
||||
RudderstackDataPlaneUrl: cfg.RudderstackDataPlaneURL,
|
||||
RudderstackIntegrationsUrl: cfg.RudderstackIntegrationsURL,
|
||||
RudderstackSdkUrl: cfg.RudderstackSDKURL,
|
||||
RudderstackV3SdkUrl: cfg.RudderstackV3SDKURL,
|
||||
RudderstackWriteKey: cfg.RudderstackWriteKey,
|
||||
TrustedTypesDefaultPolicyEnabled: (cfg.CSPEnabled && strings.Contains(cfg.CSPTemplate, "require-trusted-types-for")) || (cfg.CSPReportOnlyEnabled && strings.Contains(cfg.CSPReportOnlyTemplate, "require-trusted-types-for")),
|
||||
VerifyEmailEnabled: cfg.VerifyEmailEnabled,
|
||||
|
||||
@@ -414,6 +414,7 @@ type Cfg struct {
|
||||
RudderstackDataPlaneURL string
|
||||
RudderstackWriteKey string
|
||||
RudderstackSDKURL string
|
||||
RudderstackV3SDKURL string
|
||||
RudderstackConfigURL string
|
||||
RudderstackIntegrationsURL string
|
||||
IntercomSecret string
|
||||
@@ -510,6 +511,9 @@ type Cfg struct {
|
||||
// Query history
|
||||
QueryHistoryEnabled bool
|
||||
|
||||
// StartupSettings settings
|
||||
StartupSettings StartupSettings
|
||||
|
||||
// Open feature settings
|
||||
OpenFeature OpenFeatureSettings
|
||||
|
||||
@@ -1281,6 +1285,7 @@ func (cfg *Cfg) parseINIFile(iniFile *ini.File) error {
|
||||
cfg.RudderstackWriteKey = analytics.Key("rudderstack_write_key").String()
|
||||
cfg.RudderstackDataPlaneURL = analytics.Key("rudderstack_data_plane_url").String()
|
||||
cfg.RudderstackSDKURL = analytics.Key("rudderstack_sdk_url").String()
|
||||
cfg.RudderstackV3SDKURL = analytics.Key("rudderstack_v3_sdk_url").String()
|
||||
cfg.RudderstackConfigURL = analytics.Key("rudderstack_config_url").String()
|
||||
cfg.RudderstackIntegrationsURL = analytics.Key("rudderstack_integrations_url").String()
|
||||
cfg.IntercomSecret = analytics.Key("intercom_secret").String()
|
||||
@@ -1471,6 +1476,8 @@ func (cfg *Cfg) parseINIFile(iniFile *ini.File) error {
|
||||
// unified storage config
|
||||
cfg.setUnifiedStorageConfig()
|
||||
|
||||
// app platform config
|
||||
cfg.readStartupSettingsSection()
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package setting
|
||||
|
||||
type StartupSettings struct {
|
||||
KubernetesAnnotationsAppEnabled bool
|
||||
}
|
||||
|
||||
func (cfg *Cfg) readStartupSettingsSection() {
|
||||
settings := StartupSettings{}
|
||||
|
||||
startupSettingsSection := cfg.Raw.Section("startup_settings")
|
||||
settings.KubernetesAnnotationsAppEnabled = startupSettingsSection.Key("annotations_app_enabled").MustBool(false)
|
||||
|
||||
cfg.StartupSettings = settings
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
SELECT r.{{ .Ident "key_path" }}, r.{{ .Ident "value" }}
|
||||
FROM (
|
||||
{{ range $id, $key_path := .KeyPaths }}
|
||||
{{ if eq $id 0 }}
|
||||
SELECT {{ $.Arg $id }} AS idx, {{ $.Arg $key_path }} AS key_path
|
||||
{{ else }}
|
||||
UNION ALL SELECT {{ $.Arg $id }}, {{ $.Arg $key_path }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
) AS requested_keys
|
||||
INNER JOIN {{ .TableName }} r ON r.{{ .Ident "key_path" }} = requested_keys.{{ .Ident "key_path" }}
|
||||
ORDER BY requested_keys.{{ .Ident "idx" }};
|
||||
@@ -34,9 +34,10 @@ func mustTemplate(filename string) *template.Template {
|
||||
|
||||
// Templates.
|
||||
var (
|
||||
sqlKVGet = mustTemplate("sqlkv_get.sql")
|
||||
sqlKVDelete = mustTemplate("sqlkv_delete.sql")
|
||||
sqlKVKeys = mustTemplate("sqlkv_keys.sql")
|
||||
sqlKVKeys = mustTemplate("sqlkv_keys.sql")
|
||||
sqlKVGet = mustTemplate("sqlkv_get.sql")
|
||||
sqlKVBatchGet = mustTemplate("sqlkv_batch_get.sql")
|
||||
sqlKVDelete = mustTemplate("sqlkv_delete.sql")
|
||||
)
|
||||
|
||||
// sqlKVSection can be embedded in structs used when rendering query templates
|
||||
@@ -107,13 +108,23 @@ func (req sqlKVGetRequest) Results() ([]byte, error) {
|
||||
return req.Value, nil
|
||||
}
|
||||
|
||||
type sqlKVDeleteRequest struct {
|
||||
type sqlKVBatchGetRequest struct {
|
||||
sqltemplate.SQLTemplate
|
||||
sqlKVSectionKey
|
||||
sqlKVSection
|
||||
Keys []string
|
||||
}
|
||||
|
||||
func (req sqlKVDeleteRequest) Validate() error {
|
||||
return req.sqlKVSectionKey.Validate()
|
||||
func (req sqlKVBatchGetRequest) Validate() error {
|
||||
return req.sqlKVSection.Validate()
|
||||
}
|
||||
|
||||
func (req sqlKVBatchGetRequest) KeyPaths() []string {
|
||||
result := make([]string, 0, len(req.Keys))
|
||||
for _, key := range req.Keys {
|
||||
result = append(result, req.Section+"/"+key)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
type sqlKVKeysRequest struct {
|
||||
@@ -142,6 +153,15 @@ func (req sqlKVKeysRequest) SortAscending() bool {
|
||||
return req.Options.Sort != SortOrderDesc
|
||||
}
|
||||
|
||||
type sqlKVDeleteRequest struct {
|
||||
sqltemplate.SQLTemplate
|
||||
sqlKVSectionKey
|
||||
}
|
||||
|
||||
func (req sqlKVDeleteRequest) Validate() error {
|
||||
return req.sqlKVSectionKey.Validate()
|
||||
}
|
||||
|
||||
var _ KV = &sqlKV{}
|
||||
|
||||
type sqlKV struct {
|
||||
@@ -188,6 +208,7 @@ func (k *sqlKV) Keys(ctx context.Context, section string, opt ListOptions) iter.
|
||||
yield("", err)
|
||||
return
|
||||
}
|
||||
defer closeRows(rows, yield)
|
||||
|
||||
for rows.Next() {
|
||||
var key string
|
||||
@@ -225,7 +246,41 @@ func (k *sqlKV) Get(ctx context.Context, section string, key string) (io.ReadClo
|
||||
|
||||
func (k *sqlKV) BatchGet(ctx context.Context, section string, keys []string) iter.Seq2[KeyValue, error] {
|
||||
return func(yield func(KeyValue, error) bool) {
|
||||
panic("not implemented!")
|
||||
if len(keys) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
rows, err := dbutil.QueryRows(ctx, k.db, sqlKVBatchGet, sqlKVBatchGetRequest{
|
||||
SQLTemplate: sqltemplate.New(k.dialect),
|
||||
sqlKVSection: sqlKVSection{section},
|
||||
Keys: keys,
|
||||
})
|
||||
if err != nil {
|
||||
yield(KeyValue{}, err)
|
||||
return
|
||||
}
|
||||
defer closeRows(rows, yield)
|
||||
|
||||
for rows.Next() {
|
||||
var key string
|
||||
var value []byte
|
||||
if err := rows.Scan(&key, &value); err != nil {
|
||||
yield(KeyValue{}, fmt.Errorf("error reading row: %w", err))
|
||||
return
|
||||
}
|
||||
|
||||
kv := KeyValue{
|
||||
Key: strings.TrimPrefix(key, section+"/"),
|
||||
Value: io.NopCloser(bytes.NewReader(value)),
|
||||
}
|
||||
if !yield(kv, nil) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if err := rows.Err(); err != nil {
|
||||
yield(KeyValue{}, fmt.Errorf("failed to read rows: %w", err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -273,3 +328,10 @@ func (k *sqlKV) BatchDelete(ctx context.Context, section string, keys []string)
|
||||
func (k *sqlKV) UnixTimestamp(ctx context.Context) (int64, error) {
|
||||
panic("not implemented!")
|
||||
}
|
||||
|
||||
func closeRows[T any](rows db.Rows, yield func(T, error) bool) {
|
||||
if err := rows.Close(); err != nil {
|
||||
var zero T
|
||||
yield(zero, fmt.Errorf("error closing rows: %w", err))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,8 +46,8 @@ func GetTeamSearchBuilder() (resource.DocumentBuilderInfo, error) {
|
||||
|
||||
return resource.DocumentBuilderInfo{
|
||||
GroupResource: schema.GroupResource{
|
||||
Group: "iam.grafana.app",
|
||||
Resource: "searchTeams",
|
||||
Group: v0alpha1.TeamResourceInfo.GroupResource().Group,
|
||||
Resource: v0alpha1.TeamResourceInfo.GroupResource().Resource,
|
||||
},
|
||||
Fields: fields,
|
||||
Builder: new(teamSearchBuilder),
|
||||
|
||||
@@ -103,6 +103,7 @@ func namespacedKey(nsPrefix, key string) string {
|
||||
|
||||
func runTestKVGet(t *testing.T, kv resource.KV, nsPrefix string) {
|
||||
ctx := testutil.NewTestContext(t, time.Now().Add(30*time.Second))
|
||||
nsPrefix += "-get"
|
||||
|
||||
t.Run("get existing key", func(t *testing.T) {
|
||||
// First save a key
|
||||
@@ -221,6 +222,7 @@ func runTestKVSave(t *testing.T, kv resource.KV, nsPrefix string) {
|
||||
|
||||
func runTestKVDelete(t *testing.T, kv resource.KV, nsPrefix string) {
|
||||
ctx := testutil.NewTestContext(t, time.Now().Add(30*time.Second))
|
||||
nsPrefix += "-delete"
|
||||
|
||||
t.Run("delete existing key", func(t *testing.T) {
|
||||
// First create a key
|
||||
@@ -262,6 +264,7 @@ func runTestKVDelete(t *testing.T, kv resource.KV, nsPrefix string) {
|
||||
|
||||
func runTestKVKeys(t *testing.T, kv resource.KV, nsPrefix string) {
|
||||
ctx := testutil.NewTestContext(t, time.Now().Add(30*time.Second))
|
||||
nsPrefix += "-keys"
|
||||
|
||||
// Setup test data
|
||||
testKeys := namespacedKeys(nsPrefix, []string{"a1", "a2", "b1", "b2", "c1"})
|
||||
@@ -360,6 +363,7 @@ func runTestKVKeys(t *testing.T, kv resource.KV, nsPrefix string) {
|
||||
|
||||
func runTestKVKeysWithLimits(t *testing.T, kv resource.KV, nsPrefix string) {
|
||||
ctx := testutil.NewTestContext(t, time.Now().Add(30*time.Second))
|
||||
nsPrefix += "-keys-with-limits"
|
||||
|
||||
// Setup test data
|
||||
testKeys := namespacedKeys(nsPrefix, []string{"a1", "a2", "b1", "b2", "c1", "c2", "d1", "d2"})
|
||||
@@ -416,6 +420,7 @@ func runTestKVKeysWithLimits(t *testing.T, kv resource.KV, nsPrefix string) {
|
||||
|
||||
func runTestKVKeysWithSort(t *testing.T, kv resource.KV, nsPrefix string) {
|
||||
ctx := testutil.NewTestContext(t, time.Now().Add(30*time.Second))
|
||||
nsPrefix += "-keys-with-sort"
|
||||
|
||||
// Setup test data
|
||||
testKeys := namespacedKeys(nsPrefix, []string{"a1", "a2", "b1", "b2", "c1"})
|
||||
@@ -619,29 +624,29 @@ func runTestKVUnixTimestamp(t *testing.T, kv resource.KV, nsPrefix string) {
|
||||
|
||||
func runTestKVBatchGet(t *testing.T, kv resource.KV, nsPrefix string) {
|
||||
ctx := testutil.NewTestContext(t, time.Now().Add(30*time.Second))
|
||||
section := nsPrefix + "-batchget"
|
||||
nsPrefix += "-batchget"
|
||||
|
||||
t.Run("batch get existing keys", func(t *testing.T) {
|
||||
// Setup test data
|
||||
testData := map[string]string{
|
||||
"key1": "value1",
|
||||
"key2": "value2",
|
||||
"key3": "value3",
|
||||
namespacedKey(nsPrefix, "key1"): "value1",
|
||||
namespacedKey(nsPrefix, "key2"): "value2",
|
||||
namespacedKey(nsPrefix, "key3"): "value3",
|
||||
}
|
||||
|
||||
// Save test data
|
||||
for key, value := range testData {
|
||||
saveKVHelper(t, kv, ctx, section, key, strings.NewReader(value))
|
||||
saveKVHelper(t, kv, ctx, testSection, key, strings.NewReader(value))
|
||||
}
|
||||
|
||||
// Batch get all keys
|
||||
keys := []string{"key1", "key2", "key3"}
|
||||
keys := namespacedKeys(nsPrefix, []string{"key1", "key2", "key3"})
|
||||
type result struct {
|
||||
key string
|
||||
value string
|
||||
}
|
||||
var results []result
|
||||
for kv, err := range kv.BatchGet(ctx, section, keys) {
|
||||
for kv, err := range kv.BatchGet(ctx, testSection, keys) {
|
||||
require.NoError(t, err)
|
||||
value, err := io.ReadAll(kv.Value)
|
||||
require.NoError(t, err)
|
||||
@@ -651,10 +656,10 @@ func runTestKVBatchGet(t *testing.T, kv resource.KV, nsPrefix string) {
|
||||
}
|
||||
|
||||
// Verify results
|
||||
assert.Len(t, results, 3)
|
||||
require.Len(t, results, 3)
|
||||
|
||||
// Check that all keys are present and in order
|
||||
expectedKeys := []string{"key1", "key2", "key3"}
|
||||
expectedKeys := namespacedKeys(nsPrefix, []string{"key1", "key2", "key3"})
|
||||
actualKeys := make([]string, len(results))
|
||||
for i, r := range results {
|
||||
actualKeys[i] = r.key
|
||||
@@ -663,22 +668,40 @@ func runTestKVBatchGet(t *testing.T, kv resource.KV, nsPrefix string) {
|
||||
|
||||
// Verify values
|
||||
for _, r := range results {
|
||||
assert.Equal(t, testData[r.key], r.value)
|
||||
assert.Equal(t, testData[r.key], r.value, "key = %s", r.key)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("batch get with empty section", func(t *testing.T) {
|
||||
var kvs []resource.KeyValue
|
||||
var errs []error
|
||||
keys := namespacedKeys(nsPrefix, []string{"key1", "key2", "key3"})
|
||||
for kv, err := range kv.BatchGet(ctx, "", keys) {
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
continue
|
||||
}
|
||||
|
||||
kvs = append(kvs, kv)
|
||||
}
|
||||
|
||||
require.Len(t, errs, 1)
|
||||
assert.Contains(t, errs[0].Error(), "section is required")
|
||||
assert.Empty(t, kvs)
|
||||
})
|
||||
|
||||
t.Run("batch get with non-existent keys", func(t *testing.T) {
|
||||
// Setup some test data
|
||||
saveKVHelper(t, kv, ctx, section, "existing-key", strings.NewReader("existing-value"))
|
||||
saveKVHelper(t, kv, ctx, testSection, namespacedKey(nsPrefix, "existing-key"), strings.NewReader("existing-value"))
|
||||
|
||||
// Batch get with mix of existing and non-existent keys
|
||||
keys := []string{"existing-key", "non-existent-1", "non-existent-2"}
|
||||
keys := namespacedKeys(nsPrefix, []string{"existing-key", "non-existent-1", "non-existent-2"})
|
||||
type result struct {
|
||||
key string
|
||||
value string
|
||||
}
|
||||
var results []result
|
||||
for kv, err := range kv.BatchGet(ctx, section, keys) {
|
||||
for kv, err := range kv.BatchGet(ctx, testSection, keys) {
|
||||
require.NoError(t, err)
|
||||
value, err := io.ReadAll(kv.Value)
|
||||
require.NoError(t, err)
|
||||
@@ -688,15 +711,15 @@ func runTestKVBatchGet(t *testing.T, kv resource.KV, nsPrefix string) {
|
||||
}
|
||||
|
||||
// Should only return the existing key
|
||||
assert.Len(t, results, 1)
|
||||
assert.Equal(t, "existing-key", results[0].key)
|
||||
require.Len(t, results, 1)
|
||||
assert.Equal(t, namespacedKey(nsPrefix, "existing-key"), results[0].key)
|
||||
assert.Equal(t, "existing-value", results[0].value)
|
||||
})
|
||||
|
||||
t.Run("batch get with all non-existent keys", func(t *testing.T) {
|
||||
keys := []string{"non-existent-1", "non-existent-2", "non-existent-3"}
|
||||
keys := namespacedKeys(nsPrefix, []string{"non-existent-1", "non-existent-2", "non-existent-3"})
|
||||
var results []resource.KeyValue
|
||||
for kv, err := range kv.BatchGet(ctx, section, keys) {
|
||||
for kv, err := range kv.BatchGet(ctx, testSection, keys) {
|
||||
require.NoError(t, err)
|
||||
results = append(results, kv)
|
||||
}
|
||||
@@ -708,7 +731,7 @@ func runTestKVBatchGet(t *testing.T, kv resource.KV, nsPrefix string) {
|
||||
t.Run("batch get with empty keys list", func(t *testing.T) {
|
||||
keys := []string{}
|
||||
var results []resource.KeyValue
|
||||
for kv, err := range kv.BatchGet(ctx, section, keys) {
|
||||
for kv, err := range kv.BatchGet(ctx, testSection, keys) {
|
||||
require.NoError(t, err)
|
||||
results = append(results, kv)
|
||||
}
|
||||
@@ -718,16 +741,16 @@ func runTestKVBatchGet(t *testing.T, kv resource.KV, nsPrefix string) {
|
||||
})
|
||||
|
||||
t.Run("batch get with empty section", func(t *testing.T) {
|
||||
keys := []string{"some-key"}
|
||||
keys := namespacedKeys(nsPrefix, []string{"some-key"})
|
||||
var errors []error
|
||||
for kv, err := range kv.BatchGet(ctx, "", keys) {
|
||||
if err != nil {
|
||||
errors = append(errors, err)
|
||||
break
|
||||
continue
|
||||
}
|
||||
_ = kv // unused
|
||||
}
|
||||
assert.Len(t, errors, 1)
|
||||
require.Len(t, errors, 1)
|
||||
assert.Contains(t, errors[0].Error(), "section is required")
|
||||
})
|
||||
|
||||
@@ -741,13 +764,13 @@ func runTestKVBatchGet(t *testing.T, kv resource.KV, nsPrefix string) {
|
||||
|
||||
// Save test data
|
||||
for key, value := range testData {
|
||||
saveKVHelper(t, kv, ctx, section, key, strings.NewReader(value))
|
||||
saveKVHelper(t, kv, ctx, testSection, namespacedKey(nsPrefix, key), strings.NewReader(value))
|
||||
}
|
||||
|
||||
// Batch get in specific order
|
||||
keys := []string{"z-key", "a-key", "m-key"}
|
||||
keys := namespacedKeys(nsPrefix, []string{"z-key", "invalid-key1", "a-key", "invalid-key2", "m-key", "invalid-key3"})
|
||||
var results []string
|
||||
for kv, err := range kv.BatchGet(ctx, section, keys) {
|
||||
for kv, err := range kv.BatchGet(ctx, testSection, keys) {
|
||||
require.NoError(t, err)
|
||||
err = kv.Value.Close()
|
||||
require.NoError(t, err)
|
||||
@@ -755,8 +778,8 @@ func runTestKVBatchGet(t *testing.T, kv resource.KV, nsPrefix string) {
|
||||
}
|
||||
|
||||
// Verify order is preserved
|
||||
assert.Len(t, results, 3)
|
||||
expectedOrder := []string{"z-key", "a-key", "m-key"}
|
||||
require.Len(t, results, 3)
|
||||
expectedOrder := namespacedKeys(nsPrefix, []string{"z-key", "a-key", "m-key"})
|
||||
assert.Equal(t, expectedOrder, results)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -50,7 +50,6 @@ func TestSQLKV(t *testing.T) {
|
||||
TestKVSave: true,
|
||||
TestKVConcurrent: true,
|
||||
TestKVUnixTimestamp: true,
|
||||
TestKVBatchGet: true,
|
||||
TestKVBatchDelete: true,
|
||||
},
|
||||
})
|
||||
|
||||
@@ -21,8 +21,7 @@ import (
|
||||
func TestIntegrationTeamSearch(t *testing.T) {
|
||||
testutil.SkipIntegrationTestInShortMode(t)
|
||||
|
||||
// TODO: Add rest.Mode3 and rest.Mode4 when they're supported
|
||||
modes := []rest.DualWriterMode{rest.Mode0, rest.Mode1, rest.Mode2}
|
||||
modes := []rest.DualWriterMode{rest.Mode0, rest.Mode1, rest.Mode2, rest.Mode3, rest.Mode4, rest.Mode5}
|
||||
for _, mode := range modes {
|
||||
t.Run(fmt.Sprintf("Team search with dual writer mode %d", mode), func(t *testing.T) {
|
||||
helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{
|
||||
@@ -38,6 +37,7 @@ func TestIntegrationTeamSearch(t *testing.T) {
|
||||
featuremgmt.FlagGrafanaAPIServerWithExperimentalAPIs,
|
||||
featuremgmt.FlagKubernetesAuthnMutation,
|
||||
},
|
||||
UnifiedStorageEnableSearch: true,
|
||||
})
|
||||
doTeamSearchTests(t, helper)
|
||||
})
|
||||
@@ -59,7 +59,6 @@ func doTeamSearchTests(t *testing.T, helper *apis.K8sTestHelper) {
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, team1)
|
||||
|
||||
// Create a second team with a different name
|
||||
team2YAML := helper.LoadYAMLOrJSONFile("testdata/team-test-create-v0.yaml")
|
||||
team2YAML.Object["metadata"].(map[string]interface{})["name"] = "testteam2"
|
||||
team2YAML.Object["spec"].(map[string]interface{})["title"] = "Another Team"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user