mirror of
https://github.com/grafana/grafana.git
synced 2025-12-20 19:44:55 +08:00
Compare commits
37 Commits
plugin-dep
...
v6.2.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5d16da732f | ||
|
|
ee6703fedd | ||
|
|
ec8be5bf61 | ||
|
|
f3c2d03637 | ||
|
|
eb2b31007d | ||
|
|
98f9dbde95 | ||
|
|
7e090ea2a6 | ||
|
|
6a02faeeab | ||
|
|
a6a939cfd3 | ||
|
|
5a10298bd3 | ||
|
|
f52f7c101c | ||
|
|
7824f66cd3 | ||
|
|
71c1e8a731 | ||
|
|
74bc94bcec | ||
|
|
f566da0ff6 | ||
|
|
216aff96fd | ||
|
|
9de11c25a6 | ||
|
|
599e1030d8 | ||
|
|
d62da61d8a | ||
|
|
a2ca973925 | ||
|
|
98da29fd7b | ||
|
|
888ff61d30 | ||
|
|
c1be3adf3b | ||
|
|
ede9d9964d | ||
|
|
5cd69e8d39 | ||
|
|
ceb3672482 | ||
|
|
e519a9d2c4 | ||
|
|
2a3d6604c0 | ||
|
|
9cf0ea5395 | ||
|
|
db37e138bf | ||
|
|
a5a6d43f47 | ||
|
|
d9950aa4f1 | ||
|
|
6e9a395063 | ||
|
|
7374aafb90 | ||
|
|
b54e9880b4 | ||
|
|
09672a287f | ||
|
|
9d877d670e |
@@ -81,7 +81,7 @@ jobs:
|
||||
- run:
|
||||
# Important: all words have to be in lowercase, and separated by "\n".
|
||||
name: exclude known exceptions
|
||||
command: 'echo -e "unknwon" > words_to_ignore.txt'
|
||||
command: 'echo -e "unknwon\nreferer\nerrorstring" > words_to_ignore.txt'
|
||||
- run:
|
||||
name: check documentation spelling errors
|
||||
command: 'codespell -I ./words_to_ignore.txt docs/'
|
||||
@@ -566,6 +566,7 @@ jobs:
|
||||
root: .
|
||||
paths:
|
||||
- dist/grafana-*.msi
|
||||
- dist/grafana-*.msi.sha256
|
||||
|
||||
store-build-artifacts:
|
||||
docker:
|
||||
|
||||
@@ -66,8 +66,8 @@ RUN mkdir -p "$GF_PATHS_HOME/.aws" && \
|
||||
"$GF_PATHS_DATA" && \
|
||||
cp "$GF_PATHS_HOME/conf/sample.ini" "$GF_PATHS_CONFIG" && \
|
||||
cp "$GF_PATHS_HOME/conf/ldap.toml" /etc/grafana/ldap.toml && \
|
||||
chown -R grafana:grafana "$GF_PATHS_DATA" "$GF_PATHS_HOME/.aws" "$GF_PATHS_LOGS" "$GF_PATHS_PLUGINS" && \
|
||||
chmod 777 "$GF_PATHS_DATA" "$GF_PATHS_HOME/.aws" "$GF_PATHS_LOGS" "$GF_PATHS_PLUGINS"
|
||||
chown -R grafana:grafana "$GF_PATHS_DATA" "$GF_PATHS_HOME/.aws" "$GF_PATHS_LOGS" "$GF_PATHS_PLUGINS" "$GF_PATHS_PROVISIONING" && \
|
||||
chmod 777 -R "$GF_PATHS_DATA" "$GF_PATHS_HOME/.aws" "$GF_PATHS_LOGS" "$GF_PATHS_PLUGINS" "$GF_PATHS_PROVISIONING"
|
||||
|
||||
COPY --from=0 /go/src/github.com/grafana/grafana/bin/linux-amd64/grafana-server /go/src/github.com/grafana/grafana/bin/linux-amd64/grafana-cli ./bin/
|
||||
COPY --from=1 /usr/src/app/public ./public
|
||||
|
||||
1337
devenv/dev-dashboards/datasource-testdata/new_features_in_v62.json
Normal file
1337
devenv/dev-dashboards/datasource-testdata/new_features_in_v62.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -48,28 +48,6 @@
|
||||
"y": 0
|
||||
},
|
||||
"headings": false,
|
||||
"id": 8,
|
||||
"limit": 1000,
|
||||
"links": [],
|
||||
"query": "",
|
||||
"recent": false,
|
||||
"search": true,
|
||||
"starred": false,
|
||||
"tags": ["panel-demo"],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "tag: panel-demo",
|
||||
"type": "dashlist"
|
||||
},
|
||||
{
|
||||
"folderId": null,
|
||||
"gridPos": {
|
||||
"h": 13,
|
||||
"w": 6,
|
||||
"x": 12,
|
||||
"y": 0
|
||||
},
|
||||
"headings": false,
|
||||
"id": 2,
|
||||
"limit": 1000,
|
||||
"links": [],
|
||||
@@ -83,6 +61,28 @@
|
||||
"title": "tag: panel-tests",
|
||||
"type": "dashlist"
|
||||
},
|
||||
{
|
||||
"folderId": null,
|
||||
"gridPos": {
|
||||
"h": 26,
|
||||
"w": 6,
|
||||
"x": 12,
|
||||
"y": 0
|
||||
},
|
||||
"headings": false,
|
||||
"id": 3,
|
||||
"limit": 1000,
|
||||
"links": [],
|
||||
"query": "",
|
||||
"recent": false,
|
||||
"search": true,
|
||||
"starred": false,
|
||||
"tags": ["gdev", "demo"],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "tag: dashboard-demo",
|
||||
"type": "dashlist"
|
||||
},
|
||||
{
|
||||
"folderId": null,
|
||||
"gridPos": {
|
||||
@@ -114,28 +114,6 @@
|
||||
"y": 13
|
||||
},
|
||||
"headings": false,
|
||||
"id": 3,
|
||||
"limit": 1000,
|
||||
"links": [],
|
||||
"query": "",
|
||||
"recent": false,
|
||||
"search": true,
|
||||
"starred": false,
|
||||
"tags": ["gdev", "demo"],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "tag: dashboard-demo",
|
||||
"type": "dashlist"
|
||||
},
|
||||
{
|
||||
"folderId": null,
|
||||
"gridPos": {
|
||||
"h": 13,
|
||||
"w": 6,
|
||||
"x": 12,
|
||||
"y": 13
|
||||
},
|
||||
"headings": false,
|
||||
"id": 4,
|
||||
"limit": 1000,
|
||||
"links": [],
|
||||
@@ -146,7 +124,7 @@
|
||||
"tags": ["templating", "gdev"],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "tag: templating",
|
||||
"title": "tag: templating ",
|
||||
"type": "dashlist"
|
||||
}
|
||||
],
|
||||
@@ -167,5 +145,5 @@
|
||||
"timezone": "",
|
||||
"title": "Grafana Dev Overview & Home",
|
||||
"uid": "j6T00KRZz",
|
||||
"version": 1
|
||||
"version": 2
|
||||
}
|
||||
|
||||
@@ -15,26 +15,27 @@
|
||||
"editable": true,
|
||||
"gnetId": null,
|
||||
"graphTooltip": 0,
|
||||
"id": 7501,
|
||||
"links": [],
|
||||
"panels": [
|
||||
{
|
||||
"datasource": "gdev-testdata",
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 18,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"id": 7,
|
||||
"id": 2,
|
||||
"links": [],
|
||||
"options": {
|
||||
"displayMode": "gradient",
|
||||
"displayMode": "lcd",
|
||||
"fieldOptions": {
|
||||
"calcs": ["mean"],
|
||||
"defaults": {
|
||||
"decimals": null,
|
||||
"max": 100,
|
||||
"min": 0,
|
||||
"unit": "watt"
|
||||
"unit": "decgbytes"
|
||||
},
|
||||
"mappings": [],
|
||||
"override": {},
|
||||
@@ -47,7 +48,7 @@
|
||||
{
|
||||
"color": "orange",
|
||||
"index": 1,
|
||||
"value": 40
|
||||
"value": 60
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@@ -59,95 +60,188 @@
|
||||
},
|
||||
"orientation": "vertical"
|
||||
},
|
||||
"pluginVersion": "6.2.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"alias": "sda1",
|
||||
"refId": "A",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "sda2",
|
||||
"refId": "B",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "sda3",
|
||||
"refId": "C",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "sda4",
|
||||
"refId": "D",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "sda5",
|
||||
"refId": "E",
|
||||
"scenarioId": "csv_metric_values",
|
||||
"stringInput": "10003,33333"
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "sda6",
|
||||
"refId": "F",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "sda7",
|
||||
"refId": "G",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "sda8",
|
||||
"refId": "H",
|
||||
"scenarioId": "csv_metric_values",
|
||||
"stringInput": "100,100,100"
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "sda9",
|
||||
"refId": "I",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "sda10",
|
||||
"refId": "J",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "sda11",
|
||||
"refId": "K",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "sda12",
|
||||
"refId": "L",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "sda13",
|
||||
"refId": "M",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "sda14",
|
||||
"refId": "N",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "sda15",
|
||||
"refId": "O",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "sda16",
|
||||
"refId": "P",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "Q",
|
||||
"scenarioId": "random_walk"
|
||||
}
|
||||
],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Usage",
|
||||
"title": "",
|
||||
"transparent": true,
|
||||
"type": "bargauge"
|
||||
},
|
||||
{
|
||||
"datasource": "gdev-testdata",
|
||||
"gridPos": {
|
||||
"h": 22,
|
||||
"w": 6,
|
||||
"x": 18,
|
||||
"y": 0
|
||||
"h": 10,
|
||||
"w": 16,
|
||||
"x": 0,
|
||||
"y": 7
|
||||
},
|
||||
"id": 8,
|
||||
"id": 4,
|
||||
"links": [],
|
||||
"options": {
|
||||
"displayMode": "gradient",
|
||||
"fieldOptions": {
|
||||
"calcs": ["mean"],
|
||||
"defaults": {
|
||||
"decimals": null,
|
||||
"max": 100,
|
||||
"min": 0,
|
||||
"unit": "celsius"
|
||||
},
|
||||
"mappings": [],
|
||||
"override": {},
|
||||
"thresholds": [
|
||||
{
|
||||
"color": "blue",
|
||||
"index": 0,
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "green",
|
||||
"index": 1,
|
||||
"value": 20
|
||||
},
|
||||
{
|
||||
"color": "orange",
|
||||
"index": 2,
|
||||
"value": 40
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"index": 3,
|
||||
"value": 80
|
||||
}
|
||||
],
|
||||
"values": false
|
||||
},
|
||||
"orientation": "horizontal"
|
||||
},
|
||||
"pluginVersion": "6.2.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"alias": "Inside",
|
||||
"refId": "H",
|
||||
"scenarioId": "csv_metric_values",
|
||||
"stringInput": "100,100,100"
|
||||
},
|
||||
{
|
||||
"alias": "Outhouse",
|
||||
"refId": "A",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "Area B",
|
||||
"refId": "B",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "Basement",
|
||||
"refId": "C",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "Garage",
|
||||
"refId": "D",
|
||||
"scenarioId": "random_walk"
|
||||
}
|
||||
],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Gradient mode",
|
||||
"type": "bargauge"
|
||||
},
|
||||
{
|
||||
"datasource": "gdev-testdata",
|
||||
"gridPos": {
|
||||
"h": 10,
|
||||
"w": 6,
|
||||
"x": 16,
|
||||
"y": 7
|
||||
},
|
||||
"id": 6,
|
||||
"links": [],
|
||||
"options": {
|
||||
"displayMode": "basic",
|
||||
"fieldOptions": {
|
||||
"calcs": ["mean"],
|
||||
"defaults": {
|
||||
@@ -160,19 +254,24 @@
|
||||
"override": {},
|
||||
"thresholds": [
|
||||
{
|
||||
"color": "green",
|
||||
"color": "blue",
|
||||
"index": 0,
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "orange",
|
||||
"color": "green",
|
||||
"index": 1,
|
||||
"value": 55
|
||||
"value": 42.5
|
||||
},
|
||||
{
|
||||
"color": "orange",
|
||||
"index": 2,
|
||||
"value": 80
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"index": 2,
|
||||
"value": 95
|
||||
"index": 3,
|
||||
"value": 90
|
||||
}
|
||||
],
|
||||
"values": false
|
||||
@@ -181,10 +280,6 @@
|
||||
},
|
||||
"pluginVersion": "6.2.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"refId": "E",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "H",
|
||||
"scenarioId": "csv_metric_values",
|
||||
@@ -194,22 +289,6 @@
|
||||
"refId": "A",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "B",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "C",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "D",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "I",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "J",
|
||||
"scenarioId": "random_walk"
|
||||
@@ -241,47 +320,78 @@
|
||||
{
|
||||
"refId": "Q",
|
||||
"scenarioId": "random_walk"
|
||||
}
|
||||
],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Basic",
|
||||
"type": "bargauge"
|
||||
},
|
||||
{
|
||||
"datasource": "gdev-testdata",
|
||||
"gridPos": {
|
||||
"h": 22,
|
||||
"w": 2,
|
||||
"x": 22,
|
||||
"y": 7
|
||||
},
|
||||
"id": 8,
|
||||
"links": [],
|
||||
"options": {
|
||||
"displayMode": "lcd",
|
||||
"fieldOptions": {
|
||||
"calcs": ["mean"],
|
||||
"defaults": {
|
||||
"max": 100,
|
||||
"min": 0
|
||||
},
|
||||
"mappings": [],
|
||||
"override": {},
|
||||
"thresholds": [
|
||||
{
|
||||
"color": "red",
|
||||
"index": 0,
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"index": 1,
|
||||
"value": 90
|
||||
}
|
||||
],
|
||||
"values": false
|
||||
},
|
||||
"orientation": "vertical"
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"refId": "F",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "G",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "R",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "S",
|
||||
"refId": "A",
|
||||
"scenarioId": "random_walk"
|
||||
}
|
||||
],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Usage",
|
||||
"title": "Completion",
|
||||
"type": "bargauge"
|
||||
},
|
||||
{
|
||||
"datasource": "gdev-testdata",
|
||||
"gridPos": {
|
||||
"h": 15,
|
||||
"w": 11,
|
||||
"h": 12,
|
||||
"w": 22,
|
||||
"x": 0,
|
||||
"y": 7
|
||||
"y": 17
|
||||
},
|
||||
"id": 6,
|
||||
"id": 10,
|
||||
"links": [],
|
||||
"options": {
|
||||
"displayMode": "gradient",
|
||||
"fieldOptions": {
|
||||
"calcs": ["mean"],
|
||||
"defaults": {
|
||||
"decimals": null,
|
||||
"max": 100,
|
||||
"min": 0,
|
||||
"unit": "celsius"
|
||||
"unit": "decgbytes"
|
||||
},
|
||||
"mappings": [],
|
||||
"override": {},
|
||||
@@ -294,12 +404,12 @@
|
||||
{
|
||||
"color": "green",
|
||||
"index": 1,
|
||||
"value": 20
|
||||
"value": 30
|
||||
},
|
||||
{
|
||||
"color": "orange",
|
||||
"index": 2,
|
||||
"value": 40
|
||||
"value": 60
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@@ -309,69 +419,113 @@
|
||||
],
|
||||
"values": false
|
||||
},
|
||||
"orientation": "horizontal"
|
||||
"orientation": "vertical"
|
||||
},
|
||||
"pluginVersion": "6.2.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"alias": "Inside",
|
||||
"refId": "H",
|
||||
"scenarioId": "csv_metric_values",
|
||||
"stringInput": "100,100,100"
|
||||
},
|
||||
{
|
||||
"alias": "Outhouse",
|
||||
"alias": "sda1",
|
||||
"refId": "A",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "Area B",
|
||||
"alias": "sda2",
|
||||
"refId": "B",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "Basement",
|
||||
"alias": "sda3",
|
||||
"refId": "C",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "Garage",
|
||||
"alias": "sda4",
|
||||
"refId": "D",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "Attic",
|
||||
"alias": "sda5",
|
||||
"refId": "E",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "sda6",
|
||||
"refId": "F",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "sda7",
|
||||
"refId": "G",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "sda8",
|
||||
"refId": "H",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "sda9",
|
||||
"refId": "I",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "sda10",
|
||||
"refId": "J",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "sda11",
|
||||
"refId": "K",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "sda12",
|
||||
"refId": "L",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "sda13",
|
||||
"refId": "M",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "sda14",
|
||||
"refId": "N",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "sda15",
|
||||
"refId": "O",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "sda16",
|
||||
"refId": "P",
|
||||
"scenarioId": "random_walk"
|
||||
}
|
||||
],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Temperature",
|
||||
"title": "",
|
||||
"type": "bargauge"
|
||||
},
|
||||
{
|
||||
"datasource": "gdev-testdata",
|
||||
"gridPos": {
|
||||
"h": 15,
|
||||
"w": 7,
|
||||
"x": 11,
|
||||
"y": 7
|
||||
"h": 8,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 29
|
||||
},
|
||||
"id": 9,
|
||||
"id": 11,
|
||||
"links": [],
|
||||
"options": {
|
||||
"displayMode": "basic",
|
||||
"fieldOptions": {
|
||||
"calcs": ["mean"],
|
||||
"defaults": {
|
||||
"decimals": null,
|
||||
"max": 100,
|
||||
"min": 0,
|
||||
"unit": "celsius"
|
||||
"unit": "decgbytes"
|
||||
},
|
||||
"mappings": [],
|
||||
"override": {},
|
||||
@@ -384,12 +538,12 @@
|
||||
{
|
||||
"color": "green",
|
||||
"index": 1,
|
||||
"value": 20
|
||||
"value": 30
|
||||
},
|
||||
{
|
||||
"color": "orange",
|
||||
"index": 2,
|
||||
"value": 40
|
||||
"value": 60
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
@@ -399,89 +553,113 @@
|
||||
],
|
||||
"values": false
|
||||
},
|
||||
"orientation": "horizontal"
|
||||
"orientation": "vertical"
|
||||
},
|
||||
"pluginVersion": "6.2.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"alias": "Inside",
|
||||
"refId": "H",
|
||||
"scenarioId": "csv_metric_values",
|
||||
"stringInput": "100,100,100"
|
||||
},
|
||||
{
|
||||
"alias": "Outhouse",
|
||||
"alias": "sda1",
|
||||
"refId": "A",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "Area B",
|
||||
"alias": "sda2",
|
||||
"refId": "B",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "Basement",
|
||||
"alias": "sda3",
|
||||
"refId": "C",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "Garage",
|
||||
"alias": "sda4",
|
||||
"refId": "D",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "Attic",
|
||||
"alias": "sda5",
|
||||
"refId": "E",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "sda6",
|
||||
"refId": "F",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "sda7",
|
||||
"refId": "G",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "sda8",
|
||||
"refId": "H",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "sda9",
|
||||
"refId": "I",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "sda10",
|
||||
"refId": "J",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "sda11",
|
||||
"refId": "K",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "sda12",
|
||||
"refId": "L",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "sda13",
|
||||
"refId": "M",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "sda14",
|
||||
"refId": "N",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "sda15",
|
||||
"refId": "O",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "sda16",
|
||||
"refId": "P",
|
||||
"scenarioId": "random_walk"
|
||||
}
|
||||
],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Temperature",
|
||||
"title": "",
|
||||
"type": "bargauge"
|
||||
}
|
||||
],
|
||||
"refresh": false,
|
||||
"refresh": "10s",
|
||||
"schemaVersion": 18,
|
||||
"style": "dark",
|
||||
"tags": ["gdev", "bargauge", "panel-demo"],
|
||||
"tags": ["gdev", "demo"],
|
||||
"templating": {
|
||||
"list": []
|
||||
},
|
||||
"time": {
|
||||
"from": "now-30m",
|
||||
"from": "now-6h",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {
|
||||
"refresh_intervals": ["1s", "5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"],
|
||||
"refresh_intervals": ["2s", "5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"],
|
||||
"time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"]
|
||||
},
|
||||
"timezone": "",
|
||||
"title": "Bar Gauge Animated Demo",
|
||||
"uid": "k5IUwQeikaa",
|
||||
"version": 1
|
||||
"title": "Bar Gauge Demo",
|
||||
"uid": "vmie2cmWz",
|
||||
"version": 3
|
||||
}
|
||||
@@ -1,376 +0,0 @@
|
||||
{
|
||||
"annotations": {
|
||||
"list": [
|
||||
{
|
||||
"builtIn": 1,
|
||||
"datasource": "-- Grafana --",
|
||||
"enable": true,
|
||||
"hide": true,
|
||||
"iconColor": "rgba(0, 211, 255, 1)",
|
||||
"name": "Annotations & Alerts",
|
||||
"type": "dashboard"
|
||||
}
|
||||
]
|
||||
},
|
||||
"editable": true,
|
||||
"gnetId": null,
|
||||
"graphTooltip": 0,
|
||||
"links": [],
|
||||
"panels": [
|
||||
{
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 18,
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"id": 7,
|
||||
"links": [],
|
||||
"options": {
|
||||
"displayMode": "gradient",
|
||||
"fieldOptions": {
|
||||
"calcs": ["mean"],
|
||||
"defaults": {
|
||||
"decimals": null,
|
||||
"max": 100,
|
||||
"min": 0,
|
||||
"unit": "watt"
|
||||
},
|
||||
"mappings": [],
|
||||
"override": {},
|
||||
"thresholds": [
|
||||
{
|
||||
"color": "green",
|
||||
"index": 0,
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "orange",
|
||||
"index": 1,
|
||||
"value": 40
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"index": 2,
|
||||
"value": 80
|
||||
}
|
||||
],
|
||||
"values": false
|
||||
},
|
||||
"orientation": "vertical"
|
||||
},
|
||||
"pluginVersion": "6.2.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"refId": "A",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "B",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "C",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "D",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "E",
|
||||
"scenarioId": "csv_metric_values",
|
||||
"stringInput": "10003,33333"
|
||||
},
|
||||
{
|
||||
"refId": "F",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "G",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "H",
|
||||
"scenarioId": "csv_metric_values",
|
||||
"stringInput": "100,100,100"
|
||||
},
|
||||
{
|
||||
"refId": "I",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "J",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "K",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "L",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "M",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "N",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "O",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "P",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "Q",
|
||||
"scenarioId": "random_walk"
|
||||
}
|
||||
],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Usage",
|
||||
"type": "bargauge"
|
||||
},
|
||||
{
|
||||
"gridPos": {
|
||||
"h": 20,
|
||||
"w": 6,
|
||||
"x": 18,
|
||||
"y": 0
|
||||
},
|
||||
"id": 8,
|
||||
"links": [],
|
||||
"options": {
|
||||
"displayMode": "gradient",
|
||||
"fieldOptions": {
|
||||
"calcs": ["mean"],
|
||||
"defaults": {
|
||||
"decimals": null,
|
||||
"max": 100,
|
||||
"min": 0,
|
||||
"unit": "watt"
|
||||
},
|
||||
"mappings": [],
|
||||
"override": {},
|
||||
"thresholds": [
|
||||
{
|
||||
"color": "green",
|
||||
"index": 0,
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "orange",
|
||||
"index": 1,
|
||||
"value": 65
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"index": 2,
|
||||
"value": 95
|
||||
}
|
||||
],
|
||||
"values": false
|
||||
},
|
||||
"orientation": "horizontal"
|
||||
},
|
||||
"pluginVersion": "6.2.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"refId": "E",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "H",
|
||||
"scenarioId": "csv_metric_values",
|
||||
"stringInput": "100,100,100"
|
||||
},
|
||||
{
|
||||
"refId": "A",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "B",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "C",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "D",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "I",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "J",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "K",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "L",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "M",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "N",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "O",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "P",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "Q",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "F",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "G",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "R",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "S",
|
||||
"scenarioId": "random_walk"
|
||||
}
|
||||
],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Usage",
|
||||
"type": "bargauge"
|
||||
},
|
||||
{
|
||||
"gridPos": {
|
||||
"h": 13,
|
||||
"w": 18,
|
||||
"x": 0,
|
||||
"y": 7
|
||||
},
|
||||
"id": 6,
|
||||
"links": [],
|
||||
"options": {
|
||||
"displayMode": "gradient",
|
||||
"fieldOptions": {
|
||||
"calcs": ["mean"],
|
||||
"defaults": {
|
||||
"decimals": null,
|
||||
"max": 100,
|
||||
"min": 0,
|
||||
"unit": "celsius"
|
||||
},
|
||||
"mappings": [],
|
||||
"override": {},
|
||||
"thresholds": [
|
||||
{
|
||||
"color": "blue",
|
||||
"index": 0,
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "green",
|
||||
"index": 1,
|
||||
"value": 20
|
||||
},
|
||||
{
|
||||
"color": "orange",
|
||||
"index": 2,
|
||||
"value": 40
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"index": 3,
|
||||
"value": 80
|
||||
}
|
||||
],
|
||||
"values": false
|
||||
},
|
||||
"orientation": "horizontal"
|
||||
},
|
||||
"pluginVersion": "6.2.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"alias": "Inside",
|
||||
"refId": "H",
|
||||
"scenarioId": "csv_metric_values",
|
||||
"stringInput": "100,100,100"
|
||||
},
|
||||
{
|
||||
"alias": "Outhouse",
|
||||
"refId": "A",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "Area B",
|
||||
"refId": "B",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "Basement",
|
||||
"refId": "C",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "Garage",
|
||||
"refId": "D",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "Attic",
|
||||
"refId": "E",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "F",
|
||||
"scenarioId": "random_walk"
|
||||
}
|
||||
],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Temperature",
|
||||
"type": "bargauge"
|
||||
}
|
||||
],
|
||||
"schemaVersion": 18,
|
||||
"style": "dark",
|
||||
"tags": ["gdev", "bargauge", "panel-demo"],
|
||||
"templating": {
|
||||
"list": []
|
||||
},
|
||||
"time": {
|
||||
"from": "now-6h",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {
|
||||
"refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"],
|
||||
"time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"]
|
||||
},
|
||||
"timezone": "",
|
||||
"title": "Bar Gauge Gradient Demo",
|
||||
"uid": "RndRQw6mz",
|
||||
"version": 1
|
||||
}
|
||||
@@ -1,405 +0,0 @@
|
||||
{
|
||||
"annotations": {
|
||||
"list": [
|
||||
{
|
||||
"builtIn": 1,
|
||||
"datasource": "-- Grafana --",
|
||||
"enable": true,
|
||||
"hide": true,
|
||||
"iconColor": "rgba(0, 211, 255, 1)",
|
||||
"name": "Annotations & Alerts",
|
||||
"type": "dashboard"
|
||||
}
|
||||
]
|
||||
},
|
||||
"editable": true,
|
||||
"gnetId": null,
|
||||
"graphTooltip": 0,
|
||||
"links": [],
|
||||
"panels": [
|
||||
{
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 22,
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"id": 7,
|
||||
"links": [],
|
||||
"options": {
|
||||
"displayMode": "lcd",
|
||||
"fieldOptions": {
|
||||
"calcs": ["mean"],
|
||||
"defaults": {
|
||||
"decimals": null,
|
||||
"max": 100,
|
||||
"min": 0,
|
||||
"unit": "watt"
|
||||
},
|
||||
"mappings": [],
|
||||
"override": {},
|
||||
"thresholds": [
|
||||
{
|
||||
"color": "green",
|
||||
"index": 0,
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "orange",
|
||||
"index": 1,
|
||||
"value": 40
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"index": 2,
|
||||
"value": 80
|
||||
}
|
||||
],
|
||||
"values": false
|
||||
},
|
||||
"orientation": "vertical"
|
||||
},
|
||||
"pluginVersion": "6.2.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"refId": "A",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "B",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "C",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "D",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "E",
|
||||
"scenarioId": "csv_metric_values",
|
||||
"stringInput": "10003,33333"
|
||||
},
|
||||
{
|
||||
"refId": "F",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "G",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "H",
|
||||
"scenarioId": "csv_metric_values",
|
||||
"stringInput": "100,100,100"
|
||||
},
|
||||
{
|
||||
"refId": "I",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "J",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "K",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "L",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "M",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "N",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "O",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "P",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "Q",
|
||||
"scenarioId": "random_walk"
|
||||
}
|
||||
],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Usage",
|
||||
"type": "bargauge"
|
||||
},
|
||||
{
|
||||
"gridPos": {
|
||||
"h": 20,
|
||||
"w": 2,
|
||||
"x": 22,
|
||||
"y": 0
|
||||
},
|
||||
"id": 11,
|
||||
"links": [],
|
||||
"options": {
|
||||
"displayMode": "lcd",
|
||||
"fieldOptions": {
|
||||
"calcs": ["mean"],
|
||||
"defaults": {
|
||||
"decimals": null,
|
||||
"max": 100,
|
||||
"min": 0,
|
||||
"unit": "percent"
|
||||
},
|
||||
"mappings": [],
|
||||
"override": {},
|
||||
"thresholds": [
|
||||
{
|
||||
"color": "green",
|
||||
"index": 0,
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"index": 1,
|
||||
"value": 80
|
||||
}
|
||||
],
|
||||
"values": false
|
||||
},
|
||||
"orientation": "vertical"
|
||||
},
|
||||
"pluginVersion": "6.2.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"refId": "A",
|
||||
"scenarioId": "random_walk"
|
||||
}
|
||||
],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Progress",
|
||||
"type": "bargauge"
|
||||
},
|
||||
{
|
||||
"gridPos": {
|
||||
"h": 13,
|
||||
"w": 10,
|
||||
"x": 0,
|
||||
"y": 7
|
||||
},
|
||||
"id": 6,
|
||||
"links": [],
|
||||
"options": {
|
||||
"displayMode": "gradient",
|
||||
"fieldOptions": {
|
||||
"calcs": ["mean"],
|
||||
"defaults": {
|
||||
"decimals": null,
|
||||
"max": 100,
|
||||
"min": 0,
|
||||
"unit": "celsius"
|
||||
},
|
||||
"mappings": [],
|
||||
"override": {},
|
||||
"thresholds": [
|
||||
{
|
||||
"color": "blue",
|
||||
"index": 0,
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "green",
|
||||
"index": 1,
|
||||
"value": 20
|
||||
},
|
||||
{
|
||||
"color": "orange",
|
||||
"index": 2,
|
||||
"value": 40
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"index": 3,
|
||||
"value": 80
|
||||
}
|
||||
],
|
||||
"values": false
|
||||
},
|
||||
"orientation": "horizontal"
|
||||
},
|
||||
"pluginVersion": "6.2.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"alias": "Inside",
|
||||
"refId": "H",
|
||||
"scenarioId": "csv_metric_values",
|
||||
"stringInput": "100,100,100"
|
||||
},
|
||||
{
|
||||
"alias": "Outhouse",
|
||||
"refId": "A",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "Area B",
|
||||
"refId": "B",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "Basement",
|
||||
"refId": "C",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "Garage",
|
||||
"refId": "D",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "Attic",
|
||||
"refId": "E",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "F",
|
||||
"scenarioId": "random_walk"
|
||||
}
|
||||
],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Temperature",
|
||||
"type": "bargauge"
|
||||
},
|
||||
{
|
||||
"gridPos": {
|
||||
"h": 13,
|
||||
"w": 12,
|
||||
"x": 10,
|
||||
"y": 7
|
||||
},
|
||||
"id": 8,
|
||||
"links": [],
|
||||
"options": {
|
||||
"displayMode": "basic",
|
||||
"fieldOptions": {
|
||||
"calcs": ["mean"],
|
||||
"defaults": {
|
||||
"decimals": null,
|
||||
"max": 100,
|
||||
"min": 0,
|
||||
"unit": "watt"
|
||||
},
|
||||
"mappings": [],
|
||||
"override": {},
|
||||
"thresholds": [
|
||||
{
|
||||
"color": "green",
|
||||
"index": 0,
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "purple",
|
||||
"index": 1,
|
||||
"value": 50
|
||||
},
|
||||
{
|
||||
"color": "blue",
|
||||
"index": 2,
|
||||
"value": 70
|
||||
}
|
||||
],
|
||||
"values": false
|
||||
},
|
||||
"orientation": "horizontal"
|
||||
},
|
||||
"pluginVersion": "6.2.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"refId": "H",
|
||||
"scenarioId": "csv_metric_values",
|
||||
"stringInput": "100,100,100"
|
||||
},
|
||||
{
|
||||
"refId": "A",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "B",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "C",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "D",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "I",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "J",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "K",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "L",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "M",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "N",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "O",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "P",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "Q",
|
||||
"scenarioId": "random_walk"
|
||||
}
|
||||
],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Usage",
|
||||
"type": "bargauge"
|
||||
}
|
||||
],
|
||||
"schemaVersion": 18,
|
||||
"style": "dark",
|
||||
"tags": ["gdev", "bargauge", "panel-demo"],
|
||||
"templating": {
|
||||
"list": []
|
||||
},
|
||||
"time": {
|
||||
"from": "now-6h",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {
|
||||
"refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"],
|
||||
"time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"]
|
||||
},
|
||||
"timezone": "",
|
||||
"title": "Bar Gauge All Modes Demo",
|
||||
"uid": "zt2f6NgZzaa",
|
||||
"version": 1
|
||||
}
|
||||
829
devenv/dev-dashboards/panel-bargauge/panel_tests_bar_gauge.json
Normal file
829
devenv/dev-dashboards/panel-bargauge/panel_tests_bar_gauge.json
Normal file
@@ -0,0 +1,829 @@
|
||||
{
|
||||
"annotations": {
|
||||
"list": [
|
||||
{
|
||||
"builtIn": 1,
|
||||
"datasource": "-- Grafana --",
|
||||
"enable": true,
|
||||
"hide": true,
|
||||
"iconColor": "rgba(0, 211, 255, 1)",
|
||||
"name": "Annotations & Alerts",
|
||||
"type": "dashboard"
|
||||
}
|
||||
]
|
||||
},
|
||||
"editable": true,
|
||||
"gnetId": null,
|
||||
"graphTooltip": 0,
|
||||
"links": [],
|
||||
"panels": [
|
||||
{
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 6,
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"id": 6,
|
||||
"links": [],
|
||||
"options": {
|
||||
"displayMode": "gradient",
|
||||
"fieldOptions": {
|
||||
"calcs": ["mean"],
|
||||
"defaults": {
|
||||
"decimals": null,
|
||||
"max": 100,
|
||||
"min": 0,
|
||||
"unit": "celsius"
|
||||
},
|
||||
"mappings": [],
|
||||
"override": {},
|
||||
"thresholds": [
|
||||
{
|
||||
"color": "blue",
|
||||
"index": 0,
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "green",
|
||||
"index": 1,
|
||||
"value": 20
|
||||
},
|
||||
{
|
||||
"color": "orange",
|
||||
"index": 2,
|
||||
"value": 40
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"index": 3,
|
||||
"value": 80
|
||||
}
|
||||
],
|
||||
"values": false
|
||||
},
|
||||
"orientation": "horizontal"
|
||||
},
|
||||
"pluginVersion": "6.2.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"alias": "Inside",
|
||||
"refId": "H",
|
||||
"scenarioId": "csv_metric_values",
|
||||
"stringInput": "100,100,100"
|
||||
},
|
||||
{
|
||||
"alias": "Outhouse",
|
||||
"refId": "A",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "F",
|
||||
"scenarioId": "random_walk"
|
||||
}
|
||||
],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Title above bar",
|
||||
"type": "bargauge"
|
||||
},
|
||||
{
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 5,
|
||||
"x": 6,
|
||||
"y": 0
|
||||
},
|
||||
"id": 12,
|
||||
"links": [],
|
||||
"options": {
|
||||
"displayMode": "gradient",
|
||||
"fieldOptions": {
|
||||
"calcs": ["mean"],
|
||||
"defaults": {
|
||||
"decimals": null,
|
||||
"max": 100,
|
||||
"min": 0,
|
||||
"unit": "celsius"
|
||||
},
|
||||
"mappings": [],
|
||||
"override": {},
|
||||
"thresholds": [
|
||||
{
|
||||
"color": "blue",
|
||||
"index": 0,
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "green",
|
||||
"index": 1,
|
||||
"value": 20
|
||||
},
|
||||
{
|
||||
"color": "orange",
|
||||
"index": 2,
|
||||
"value": 40
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"index": 3,
|
||||
"value": 80
|
||||
}
|
||||
],
|
||||
"values": false
|
||||
},
|
||||
"orientation": "horizontal"
|
||||
},
|
||||
"pluginVersion": "6.2.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"alias": "Inside",
|
||||
"refId": "H",
|
||||
"scenarioId": "csv_metric_values",
|
||||
"stringInput": "100,100,100"
|
||||
},
|
||||
{
|
||||
"alias": "Outhouse",
|
||||
"refId": "A",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "F",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "B",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "C",
|
||||
"scenarioId": "random_walk"
|
||||
}
|
||||
],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Title to left of bar",
|
||||
"type": "bargauge"
|
||||
},
|
||||
{
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 7,
|
||||
"x": 11,
|
||||
"y": 0
|
||||
},
|
||||
"id": 13,
|
||||
"links": [],
|
||||
"options": {
|
||||
"displayMode": "basic",
|
||||
"fieldOptions": {
|
||||
"calcs": ["mean"],
|
||||
"defaults": {
|
||||
"decimals": null,
|
||||
"max": 100,
|
||||
"min": 0,
|
||||
"unit": "celsius"
|
||||
},
|
||||
"mappings": [],
|
||||
"override": {},
|
||||
"thresholds": [
|
||||
{
|
||||
"color": "blue",
|
||||
"index": 0,
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "green",
|
||||
"index": 1,
|
||||
"value": 20
|
||||
},
|
||||
{
|
||||
"color": "orange",
|
||||
"index": 2,
|
||||
"value": 40
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"index": 3,
|
||||
"value": 80
|
||||
}
|
||||
],
|
||||
"values": false
|
||||
},
|
||||
"orientation": "horizontal"
|
||||
},
|
||||
"pluginVersion": "6.2.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"alias": "Inside",
|
||||
"refId": "H",
|
||||
"scenarioId": "csv_metric_values",
|
||||
"stringInput": "100,100,100"
|
||||
},
|
||||
{
|
||||
"alias": "Outhouse",
|
||||
"refId": "A",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "F",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "B",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "C",
|
||||
"scenarioId": "random_walk"
|
||||
}
|
||||
],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Basic mode",
|
||||
"type": "bargauge"
|
||||
},
|
||||
{
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 6,
|
||||
"x": 18,
|
||||
"y": 0
|
||||
},
|
||||
"id": 14,
|
||||
"links": [],
|
||||
"options": {
|
||||
"displayMode": "lcd",
|
||||
"fieldOptions": {
|
||||
"calcs": ["mean"],
|
||||
"defaults": {
|
||||
"decimals": null,
|
||||
"max": 100,
|
||||
"min": 0,
|
||||
"unit": "celsius"
|
||||
},
|
||||
"mappings": [],
|
||||
"override": {},
|
||||
"thresholds": [
|
||||
{
|
||||
"color": "blue",
|
||||
"index": 0,
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "green",
|
||||
"index": 1,
|
||||
"value": 20
|
||||
},
|
||||
{
|
||||
"color": "orange",
|
||||
"index": 2,
|
||||
"value": 40
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"index": 3,
|
||||
"value": 80
|
||||
}
|
||||
],
|
||||
"values": false
|
||||
},
|
||||
"orientation": "horizontal"
|
||||
},
|
||||
"pluginVersion": "6.2.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"alias": "Inside",
|
||||
"refId": "H",
|
||||
"scenarioId": "csv_metric_values",
|
||||
"stringInput": "100,100,100"
|
||||
},
|
||||
{
|
||||
"alias": "Outhouse",
|
||||
"refId": "A",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "F",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "B",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "C",
|
||||
"scenarioId": "random_walk"
|
||||
}
|
||||
],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "LED",
|
||||
"type": "bargauge"
|
||||
},
|
||||
{
|
||||
"gridPos": {
|
||||
"h": 9,
|
||||
"w": 11,
|
||||
"x": 0,
|
||||
"y": 7
|
||||
},
|
||||
"id": 7,
|
||||
"links": [],
|
||||
"options": {
|
||||
"displayMode": "lcd",
|
||||
"fieldOptions": {
|
||||
"calcs": ["mean"],
|
||||
"defaults": {
|
||||
"decimals": null,
|
||||
"max": 100,
|
||||
"min": 0,
|
||||
"unit": "watt"
|
||||
},
|
||||
"mappings": [],
|
||||
"override": {},
|
||||
"thresholds": [
|
||||
{
|
||||
"color": "green",
|
||||
"index": 0,
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "orange",
|
||||
"index": 1,
|
||||
"value": 40
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"index": 2,
|
||||
"value": 80
|
||||
}
|
||||
],
|
||||
"values": false
|
||||
},
|
||||
"orientation": "vertical"
|
||||
},
|
||||
"pluginVersion": "6.2.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"refId": "E",
|
||||
"scenarioId": "csv_metric_values",
|
||||
"stringInput": "10003,33333"
|
||||
},
|
||||
{
|
||||
"refId": "F",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "G",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "H",
|
||||
"scenarioId": "csv_metric_values",
|
||||
"stringInput": "100,100,100"
|
||||
},
|
||||
{
|
||||
"refId": "I",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "J",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "K",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "L",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "M",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "N",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "O",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "P",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "Q",
|
||||
"scenarioId": "random_walk"
|
||||
}
|
||||
],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "LED Vertical",
|
||||
"type": "bargauge"
|
||||
},
|
||||
{
|
||||
"gridPos": {
|
||||
"h": 9,
|
||||
"w": 13,
|
||||
"x": 11,
|
||||
"y": 7
|
||||
},
|
||||
"id": 8,
|
||||
"links": [],
|
||||
"options": {
|
||||
"displayMode": "basic",
|
||||
"fieldOptions": {
|
||||
"calcs": ["mean"],
|
||||
"defaults": {
|
||||
"decimals": null,
|
||||
"max": 100,
|
||||
"min": 0,
|
||||
"unit": "watt"
|
||||
},
|
||||
"mappings": [],
|
||||
"override": {},
|
||||
"thresholds": [
|
||||
{
|
||||
"color": "green",
|
||||
"index": 0,
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "purple",
|
||||
"index": 1,
|
||||
"value": 50
|
||||
},
|
||||
{
|
||||
"color": "blue",
|
||||
"index": 2,
|
||||
"value": 70
|
||||
}
|
||||
],
|
||||
"values": false
|
||||
},
|
||||
"orientation": "vertical"
|
||||
},
|
||||
"pluginVersion": "6.2.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"refId": "H",
|
||||
"scenarioId": "csv_metric_values",
|
||||
"stringInput": "100,100,100"
|
||||
},
|
||||
{
|
||||
"refId": "A",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "B",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "C",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "D",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "I",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "J",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "K",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "L",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "M",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "N",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "O",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "P",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "Q",
|
||||
"scenarioId": "random_walk"
|
||||
}
|
||||
],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Basic vertical ",
|
||||
"type": "bargauge"
|
||||
},
|
||||
{
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 11,
|
||||
"x": 0,
|
||||
"y": 16
|
||||
},
|
||||
"id": 16,
|
||||
"links": [],
|
||||
"options": {
|
||||
"displayMode": "lcd",
|
||||
"fieldOptions": {
|
||||
"calcs": ["last"],
|
||||
"defaults": {
|
||||
"max": 100,
|
||||
"min": 0
|
||||
},
|
||||
"mappings": [],
|
||||
"override": {},
|
||||
"thresholds": [
|
||||
{
|
||||
"color": "green",
|
||||
"index": 0,
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "blue",
|
||||
"index": 1,
|
||||
"value": 40
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"index": 2,
|
||||
"value": 80
|
||||
}
|
||||
],
|
||||
"values": false
|
||||
},
|
||||
"orientation": "horizontal"
|
||||
},
|
||||
"pluginVersion": "6.3.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"refId": "A",
|
||||
"scenarioId": "csv_metric_values",
|
||||
"stringInput": "1,20,90,30,5,0,-100"
|
||||
}
|
||||
],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Negative value below min",
|
||||
"type": "bargauge"
|
||||
},
|
||||
{
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 3,
|
||||
"x": 11,
|
||||
"y": 16
|
||||
},
|
||||
"id": 17,
|
||||
"links": [],
|
||||
"options": {
|
||||
"displayMode": "lcd",
|
||||
"fieldOptions": {
|
||||
"calcs": ["last"],
|
||||
"defaults": {
|
||||
"max": 100,
|
||||
"min": 0
|
||||
},
|
||||
"mappings": [],
|
||||
"override": {},
|
||||
"thresholds": [
|
||||
{
|
||||
"color": "green",
|
||||
"index": 0,
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "blue",
|
||||
"index": 1,
|
||||
"value": 40
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"index": 2,
|
||||
"value": 80
|
||||
}
|
||||
],
|
||||
"values": false
|
||||
},
|
||||
"orientation": "vertical"
|
||||
},
|
||||
"pluginVersion": "6.3.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"refId": "A",
|
||||
"scenarioId": "csv_metric_values",
|
||||
"stringInput": "1,20,90,30,5,0,-100"
|
||||
}
|
||||
],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Negative value below min",
|
||||
"type": "bargauge"
|
||||
},
|
||||
{
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 3,
|
||||
"x": 14,
|
||||
"y": 16
|
||||
},
|
||||
"id": 18,
|
||||
"links": [],
|
||||
"options": {
|
||||
"displayMode": "lcd",
|
||||
"fieldOptions": {
|
||||
"calcs": ["last"],
|
||||
"defaults": {
|
||||
"max": 100,
|
||||
"min": -10
|
||||
},
|
||||
"mappings": [],
|
||||
"override": {},
|
||||
"thresholds": [
|
||||
{
|
||||
"color": "green",
|
||||
"index": 0,
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "blue",
|
||||
"index": 1,
|
||||
"value": 40
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"index": 2,
|
||||
"value": 80
|
||||
}
|
||||
],
|
||||
"values": false
|
||||
},
|
||||
"orientation": "vertical"
|
||||
},
|
||||
"pluginVersion": "6.3.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"refId": "A",
|
||||
"scenarioId": "csv_metric_values",
|
||||
"stringInput": "1,20,90,30,5,6"
|
||||
}
|
||||
],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Positive value above min",
|
||||
"type": "bargauge"
|
||||
},
|
||||
{
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 3,
|
||||
"x": 17,
|
||||
"y": 16
|
||||
},
|
||||
"id": 19,
|
||||
"links": [],
|
||||
"options": {
|
||||
"displayMode": "lcd",
|
||||
"fieldOptions": {
|
||||
"calcs": ["last"],
|
||||
"defaults": {
|
||||
"max": 35,
|
||||
"min": -20
|
||||
},
|
||||
"mappings": [],
|
||||
"override": {},
|
||||
"thresholds": [
|
||||
{
|
||||
"color": "blue",
|
||||
"index": 0,
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "green",
|
||||
"index": 1,
|
||||
"value": 5
|
||||
},
|
||||
{
|
||||
"color": "#EAB839",
|
||||
"index": 2,
|
||||
"value": 25
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"index": 3,
|
||||
"value": 30
|
||||
}
|
||||
],
|
||||
"values": false
|
||||
},
|
||||
"orientation": "vertical"
|
||||
},
|
||||
"pluginVersion": "6.3.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"refId": "A",
|
||||
"scenarioId": "csv_metric_values",
|
||||
"stringInput": "1,20,90,30,5,6"
|
||||
}
|
||||
],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Negative min ",
|
||||
"type": "bargauge"
|
||||
},
|
||||
{
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 4,
|
||||
"x": 20,
|
||||
"y": 16
|
||||
},
|
||||
"id": 20,
|
||||
"links": [],
|
||||
"options": {
|
||||
"displayMode": "gradient",
|
||||
"fieldOptions": {
|
||||
"calcs": ["last"],
|
||||
"defaults": {
|
||||
"max": 35,
|
||||
"min": -20
|
||||
},
|
||||
"mappings": [],
|
||||
"override": {},
|
||||
"thresholds": [
|
||||
{
|
||||
"color": "blue",
|
||||
"index": 0,
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "green",
|
||||
"index": 1,
|
||||
"value": 5
|
||||
},
|
||||
{
|
||||
"color": "#EAB839",
|
||||
"index": 2,
|
||||
"value": 25
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"index": 3,
|
||||
"value": 30
|
||||
}
|
||||
],
|
||||
"values": false
|
||||
},
|
||||
"orientation": "vertical"
|
||||
},
|
||||
"pluginVersion": "6.3.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"refId": "A",
|
||||
"scenarioId": "csv_metric_values",
|
||||
"stringInput": "30,30"
|
||||
}
|
||||
],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Negative min",
|
||||
"type": "bargauge"
|
||||
}
|
||||
],
|
||||
"schemaVersion": 18,
|
||||
"style": "dark",
|
||||
"tags": ["gdev", "panel-tests"],
|
||||
"templating": {
|
||||
"list": []
|
||||
},
|
||||
"time": {
|
||||
"from": "now-6h",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {
|
||||
"refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"],
|
||||
"time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"]
|
||||
},
|
||||
"timezone": "",
|
||||
"title": "Panel Tests - Bar Gauge",
|
||||
"uid": "O6f11TZWk",
|
||||
"version": 12
|
||||
}
|
||||
@@ -1,400 +0,0 @@
|
||||
{
|
||||
"annotations": {
|
||||
"list": [
|
||||
{
|
||||
"builtIn": 1,
|
||||
"datasource": "-- Grafana --",
|
||||
"enable": true,
|
||||
"hide": true,
|
||||
"iconColor": "rgba(0, 211, 255, 1)",
|
||||
"name": "Annotations & Alerts",
|
||||
"type": "dashboard"
|
||||
}
|
||||
]
|
||||
},
|
||||
"editable": true,
|
||||
"gnetId": null,
|
||||
"graphTooltip": 0,
|
||||
"links": [],
|
||||
"panels": [
|
||||
{
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 22,
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"id": 7,
|
||||
"links": [],
|
||||
"options": {
|
||||
"displayMode": "lcd",
|
||||
"fieldOptions": {
|
||||
"calcs": ["mean"],
|
||||
"defaults": {
|
||||
"decimals": null,
|
||||
"max": 100,
|
||||
"min": 0,
|
||||
"unit": "watt"
|
||||
},
|
||||
"mappings": [],
|
||||
"override": {},
|
||||
"thresholds": [
|
||||
{
|
||||
"color": "green",
|
||||
"index": 0,
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "orange",
|
||||
"index": 1,
|
||||
"value": 40
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"index": 2,
|
||||
"value": 80
|
||||
}
|
||||
],
|
||||
"values": false
|
||||
},
|
||||
"orientation": "vertical"
|
||||
},
|
||||
"pluginVersion": "6.2.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"refId": "A",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "B",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "C",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "D",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "E",
|
||||
"scenarioId": "csv_metric_values",
|
||||
"stringInput": "10003,33333"
|
||||
},
|
||||
{
|
||||
"refId": "F",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "G",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "H",
|
||||
"scenarioId": "csv_metric_values",
|
||||
"stringInput": "100,100,100"
|
||||
},
|
||||
{
|
||||
"refId": "I",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "J",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "K",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "L",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "M",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "N",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "O",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "P",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "Q",
|
||||
"scenarioId": "random_walk"
|
||||
}
|
||||
],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Usage",
|
||||
"type": "bargauge"
|
||||
},
|
||||
{
|
||||
"gridPos": {
|
||||
"h": 21,
|
||||
"w": 2,
|
||||
"x": 22,
|
||||
"y": 0
|
||||
},
|
||||
"id": 11,
|
||||
"links": [],
|
||||
"options": {
|
||||
"displayMode": "lcd",
|
||||
"fieldOptions": {
|
||||
"calcs": ["mean"],
|
||||
"defaults": {
|
||||
"decimals": null,
|
||||
"max": 100,
|
||||
"min": 0,
|
||||
"unit": "percent"
|
||||
},
|
||||
"mappings": [],
|
||||
"override": {},
|
||||
"thresholds": [
|
||||
{
|
||||
"color": "green",
|
||||
"index": 0,
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"index": 1,
|
||||
"value": 80
|
||||
}
|
||||
],
|
||||
"values": false
|
||||
},
|
||||
"orientation": "vertical"
|
||||
},
|
||||
"pluginVersion": "6.2.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"refId": "A",
|
||||
"scenarioId": "random_walk"
|
||||
}
|
||||
],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Progress",
|
||||
"type": "bargauge"
|
||||
},
|
||||
{
|
||||
"gridPos": {
|
||||
"h": 13,
|
||||
"w": 10,
|
||||
"x": 0,
|
||||
"y": 8
|
||||
},
|
||||
"id": 6,
|
||||
"links": [],
|
||||
"options": {
|
||||
"displayMode": "lcd",
|
||||
"fieldOptions": {
|
||||
"calcs": ["mean"],
|
||||
"defaults": {
|
||||
"decimals": null,
|
||||
"max": 100,
|
||||
"min": 0,
|
||||
"unit": "celsius"
|
||||
},
|
||||
"mappings": [],
|
||||
"override": {},
|
||||
"thresholds": [
|
||||
{
|
||||
"color": "green",
|
||||
"index": 0,
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "orange",
|
||||
"index": 1,
|
||||
"value": 40
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"index": 2,
|
||||
"value": 80
|
||||
}
|
||||
],
|
||||
"values": false
|
||||
},
|
||||
"orientation": "horizontal"
|
||||
},
|
||||
"pluginVersion": "6.2.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"alias": "Inside",
|
||||
"refId": "H",
|
||||
"scenarioId": "csv_metric_values",
|
||||
"stringInput": "100,100,100"
|
||||
},
|
||||
{
|
||||
"alias": "Outhouse",
|
||||
"refId": "A",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "Area B",
|
||||
"refId": "B",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "Basement",
|
||||
"refId": "C",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "Garage",
|
||||
"refId": "D",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"alias": "Attic",
|
||||
"refId": "E",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "F",
|
||||
"scenarioId": "random_walk"
|
||||
}
|
||||
],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Temperature",
|
||||
"type": "bargauge"
|
||||
},
|
||||
{
|
||||
"gridPos": {
|
||||
"h": 13,
|
||||
"w": 12,
|
||||
"x": 10,
|
||||
"y": 8
|
||||
},
|
||||
"id": 8,
|
||||
"links": [],
|
||||
"options": {
|
||||
"displayMode": "lcd",
|
||||
"fieldOptions": {
|
||||
"calcs": ["mean"],
|
||||
"defaults": {
|
||||
"decimals": null,
|
||||
"max": 100,
|
||||
"min": 0,
|
||||
"unit": "watt"
|
||||
},
|
||||
"mappings": [],
|
||||
"override": {},
|
||||
"thresholds": [
|
||||
{
|
||||
"color": "green",
|
||||
"index": 0,
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "orange",
|
||||
"index": 1,
|
||||
"value": 85
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"index": 2,
|
||||
"value": 95
|
||||
}
|
||||
],
|
||||
"values": false
|
||||
},
|
||||
"orientation": "horizontal"
|
||||
},
|
||||
"pluginVersion": "6.2.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"refId": "H",
|
||||
"scenarioId": "csv_metric_values",
|
||||
"stringInput": "100,100,100"
|
||||
},
|
||||
{
|
||||
"refId": "A",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "B",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "C",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "D",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "I",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "J",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "K",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "L",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "M",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "N",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "O",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "P",
|
||||
"scenarioId": "random_walk"
|
||||
},
|
||||
{
|
||||
"refId": "Q",
|
||||
"scenarioId": "random_walk"
|
||||
}
|
||||
],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Usage",
|
||||
"type": "bargauge"
|
||||
}
|
||||
],
|
||||
"schemaVersion": 18,
|
||||
"style": "dark",
|
||||
"tags": ["gdev", "bargauge", "panel-demo"],
|
||||
"templating": {
|
||||
"list": []
|
||||
},
|
||||
"time": {
|
||||
"from": "now-6h",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {
|
||||
"refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"],
|
||||
"time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"]
|
||||
},
|
||||
"timezone": "",
|
||||
"title": "Bar Gauge LED Demo",
|
||||
"uid": "0G3rbkqmkaa",
|
||||
"version": 1
|
||||
}
|
||||
@@ -51,6 +51,36 @@ then the Grafana proxy will transform it into "https://management.azure.com/foo/
|
||||
|
||||
The `method` parameter is optional. It can be set to any HTTP verb to provide more fine-grained control.
|
||||
|
||||
### Dynamic Routes
|
||||
|
||||
When using routes, you can also reference a variable stored in JsonData or SecureJsonData which will be interpolated when connecting to the datasource.
|
||||
|
||||
With JsonData:
|
||||
```json
|
||||
"routes": [
|
||||
{
|
||||
"path": "custom/api/v5/*",
|
||||
"method": "*",
|
||||
"url": "{{.JsonData.dynamicUrl}}",
|
||||
...
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
With SecureJsonData:
|
||||
```json
|
||||
"routes": [{
|
||||
"path": "custom/api/v5/*",
|
||||
"method": "*",
|
||||
"url": "{{.SecureJsonData.dynamicUrl}}",
|
||||
...
|
||||
}]
|
||||
```
|
||||
|
||||
In the above example, the app is able to set the value for `dynamicUrl` in JsonData or SecureJsonData and it will be replaced on-demand.
|
||||
|
||||
An app using this feature can be found [here](https://github.com/grafana/kentik-app).
|
||||
|
||||
## Encrypting Sensitive Data
|
||||
|
||||
When a user saves a password or secret with your datasource plugin's Config page, then you can save data to a column in the datasource table called `secureJsonData` that is an encrypted blob. Any data saved in the blob is encrypted by Grafana and can only be decrypted by the Grafana server on the backend. This means once a password is saved, no sensitive data is sent to the browser. If the password is saved in the `jsonData` blob or the `password` field then it is unencrypted and anyone with Admin access (with the help of Chrome Developer Tools) can read it.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"company": "Grafana Labs"
|
||||
},
|
||||
"name": "grafana",
|
||||
"version": "6.2.0-pre",
|
||||
"version": "6.2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "http://github.com/grafana/grafana.git"
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import { BarGauge, Props, getValueColor, getBasicAndGradientStyles, getBarGradient, getTitleStyles } from './BarGauge';
|
||||
import {
|
||||
BarGauge,
|
||||
Props,
|
||||
getValueColor,
|
||||
getBasicAndGradientStyles,
|
||||
getBarGradient,
|
||||
getTitleStyles,
|
||||
getValuePercent,
|
||||
} from './BarGauge';
|
||||
import { VizOrientation, DisplayValue } from '../../types';
|
||||
import { getTheme } from '../../themes';
|
||||
|
||||
@@ -63,6 +71,24 @@ describe('BarGauge', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Get value percent', () => {
|
||||
it('0 to 100 and value 40', () => {
|
||||
expect(getValuePercent(40, 0, 100)).toEqual(0.4);
|
||||
});
|
||||
|
||||
it('50 to 100 and value 75', () => {
|
||||
expect(getValuePercent(75, 50, 100)).toEqual(0.5);
|
||||
});
|
||||
|
||||
it('-30 to 30 and value 0', () => {
|
||||
expect(getValuePercent(0, -30, 30)).toEqual(0.5);
|
||||
});
|
||||
|
||||
it('-30 to 30 and value 30', () => {
|
||||
expect(getValuePercent(30, -30, 30)).toEqual(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Vertical bar without title', () => {
|
||||
it('should not include title height in height', () => {
|
||||
const props = getProps({
|
||||
|
||||
@@ -161,7 +161,7 @@ export class BarGauge extends PureComponent<Props> {
|
||||
const cells: JSX.Element[] = [];
|
||||
|
||||
for (let i = 0; i < cellCount; i++) {
|
||||
const currentValue = (valueRange / cellCount) * i;
|
||||
const currentValue = minValue + (valueRange / cellCount) * i;
|
||||
const cellColor = this.getCellColor(currentValue);
|
||||
const cellStyles: CSSProperties = {
|
||||
borderRadius: '2px',
|
||||
@@ -345,11 +345,6 @@ function calculateBarAndValueDimensions(props: Props): BarAndValueDimensions {
|
||||
}
|
||||
}
|
||||
|
||||
// console.log('titleDim', titleDim);
|
||||
// console.log('valueWidth', valueWidth);
|
||||
// console.log('width', width);
|
||||
// console.log('total', titleDim.width + maxBarWidth + valueWidth);
|
||||
|
||||
return {
|
||||
valueWidth,
|
||||
valueHeight,
|
||||
@@ -360,6 +355,10 @@ function calculateBarAndValueDimensions(props: Props): BarAndValueDimensions {
|
||||
};
|
||||
}
|
||||
|
||||
export function getValuePercent(value: number, minValue: number, maxValue: number): number {
|
||||
return Math.min((value - minValue) / (maxValue - minValue), 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Only exported to for unit test
|
||||
*/
|
||||
@@ -367,7 +366,7 @@ export function getBasicAndGradientStyles(props: Props): BasicAndGradientStyles
|
||||
const { displayMode, maxValue, minValue, value } = props;
|
||||
const { valueWidth, valueHeight, maxBarHeight, maxBarWidth } = calculateBarAndValueDimensions(props);
|
||||
|
||||
const valuePercent = Math.min(value.numeric / (maxValue - minValue), 1);
|
||||
const valuePercent = getValuePercent(value.numeric, minValue, maxValue);
|
||||
const valueColor = getValueColor(props);
|
||||
const valueStyles = getValueStyles(value.text, valueColor, valueWidth, valueHeight);
|
||||
const isBasic = displayMode === 'basic';
|
||||
@@ -450,7 +449,7 @@ export function getBarGradient(props: Props, maxSize: number): string {
|
||||
for (let i = 0; i < thresholds.length; i++) {
|
||||
const threshold = thresholds[i];
|
||||
const color = getColorFromHexRgbOrName(threshold.color);
|
||||
const valuePercent = Math.min(threshold.value / (maxValue - minValue), 1);
|
||||
const valuePercent = getValuePercent(threshold.value, minValue, maxValue);
|
||||
const pos = valuePercent * maxSize;
|
||||
const offset = Math.round(pos - (pos - lastpos) / 2);
|
||||
|
||||
@@ -499,30 +498,3 @@ function getValueStyles(value: string, color: string, width: number, height: num
|
||||
fontSize: fontSize.toFixed(2) + 'px',
|
||||
};
|
||||
}
|
||||
|
||||
// let canvasElement: HTMLCanvasElement | null = null;
|
||||
//
|
||||
// interface TextDimensions {
|
||||
// width: number;
|
||||
// height: number;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Uses canvas.measureText to compute and return the width of the given text of given font in pixels.
|
||||
// *
|
||||
// * @param {String} text The text to be rendered.
|
||||
// * @param {String} font The css font descriptor that text is to be rendered with (e.g. "bold 14px verdana").
|
||||
// *
|
||||
// * @see https://stackoverflow.com/questions/118241/calculate-text-width-with-javascript/21015393#21015393
|
||||
// */
|
||||
// function getTextWidth(text: string): number {
|
||||
// // re-use canvas object for better performance
|
||||
// canvasElement = canvasElement || document.createElement('canvas');
|
||||
// const context = canvasElement.getContext('2d');
|
||||
// if (context) {
|
||||
// context.font = 'normal 16px Roboto';
|
||||
// const metrics = context.measureText(text);
|
||||
// return metrics.width;
|
||||
// }
|
||||
// return 16;
|
||||
// }
|
||||
|
||||
@@ -42,9 +42,10 @@ export class CustomScrollbar extends Component<Props> {
|
||||
|
||||
updateScroll() {
|
||||
const ref = this.ref.current;
|
||||
const { scrollTop } = this.props;
|
||||
|
||||
if (ref && !isNil(this.props.scrollTop)) {
|
||||
ref.scrollTop(this.props.scrollTop);
|
||||
if (ref && !isNil(scrollTop)) {
|
||||
ref.scrollTop(scrollTop);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,6 +71,44 @@ export class CustomScrollbar extends Component<Props> {
|
||||
this.updateScroll();
|
||||
}
|
||||
|
||||
renderTrack = (track: 'track-vertical' | 'track-horizontal', hideTrack: boolean | undefined, passedProps: any) => {
|
||||
return (
|
||||
<div
|
||||
{...passedProps}
|
||||
className={cx(
|
||||
css`
|
||||
visibility: ${hideTrack ? 'none' : 'visible'};
|
||||
`,
|
||||
track
|
||||
)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
renderThumb = (thumb: 'thumb-horizontal' | 'thumb-vertical', passedProps: any) => {
|
||||
return <div {...passedProps} className={thumb} />;
|
||||
};
|
||||
|
||||
renderTrackHorizontal = (passedProps: any) => {
|
||||
return this.renderTrack('track-horizontal', this.props.hideHorizontalTrack, passedProps);
|
||||
};
|
||||
|
||||
renderTrackVertical = (passedProps: any) => {
|
||||
return this.renderTrack('track-vertical', this.props.hideVerticalTrack, passedProps);
|
||||
};
|
||||
|
||||
renderThumbHorizontal = (passedProps: any) => {
|
||||
return this.renderThumb('thumb-horizontal', passedProps);
|
||||
};
|
||||
|
||||
renderThumbVertical = (passedProps: any) => {
|
||||
return this.renderThumb('thumb-vertical', passedProps);
|
||||
};
|
||||
|
||||
renderView = (passedProps: any) => {
|
||||
return <div {...passedProps} className="view" />;
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
className,
|
||||
@@ -80,8 +119,6 @@ export class CustomScrollbar extends Component<Props> {
|
||||
autoHide,
|
||||
autoHideTimeout,
|
||||
hideTracksWhenNotNeeded,
|
||||
hideHorizontalTrack,
|
||||
hideVerticalTrack,
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
@@ -97,31 +134,11 @@ export class CustomScrollbar extends Component<Props> {
|
||||
// Before these where set to inhert but that caused problems with cut of legends in firefox
|
||||
autoHeightMax={autoHeightMax}
|
||||
autoHeightMin={autoHeightMin}
|
||||
renderTrackHorizontal={props => (
|
||||
<div
|
||||
{...props}
|
||||
className={cx(
|
||||
css`
|
||||
visibility: ${hideHorizontalTrack ? 'none' : 'visible'};
|
||||
`,
|
||||
'track-horizontal'
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
renderTrackVertical={props => (
|
||||
<div
|
||||
{...props}
|
||||
className={cx(
|
||||
css`
|
||||
visibility: ${hideVerticalTrack ? 'none' : 'visible'};
|
||||
`,
|
||||
'track-vertical'
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
renderThumbHorizontal={props => <div {...props} className="thumb-horizontal" />}
|
||||
renderThumbVertical={props => <div {...props} className="thumb-vertical" />}
|
||||
renderView={props => <div {...props} className="view" />}
|
||||
renderTrackHorizontal={this.renderTrackHorizontal}
|
||||
renderTrackVertical={this.renderTrackVertical}
|
||||
renderThumbHorizontal={this.renderThumbHorizontal}
|
||||
renderThumbVertical={this.renderThumbVertical}
|
||||
renderView={this.renderView}
|
||||
>
|
||||
{children}
|
||||
</Scrollbars>
|
||||
|
||||
@@ -37,7 +37,7 @@ exports[`CustomScrollbar renders correctly 1`] = `
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
className="css-17l4171 track-horizontal"
|
||||
className="css-52gpmd track-horizontal"
|
||||
style={
|
||||
Object {
|
||||
"display": "none",
|
||||
@@ -58,7 +58,7 @@ exports[`CustomScrollbar renders correctly 1`] = `
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="css-17l4171 track-vertical"
|
||||
className="css-52gpmd track-vertical"
|
||||
style={
|
||||
Object {
|
||||
"display": "none",
|
||||
|
||||
@@ -69,14 +69,14 @@ export class Gauge extends PureComponent<Props> {
|
||||
|
||||
const backgroundColor = selectThemeVariant(
|
||||
{
|
||||
dark: theme.colors.dark3,
|
||||
light: '#e6e6e6',
|
||||
dark: theme.colors.dark8,
|
||||
light: theme.colors.gray6,
|
||||
},
|
||||
theme.type
|
||||
);
|
||||
|
||||
const gaugeWidthReduceRatio = showThresholdLabels ? 1.5 : 1;
|
||||
const gaugeWidth = Math.min(dimension / 6, 40) / gaugeWidthReduceRatio;
|
||||
const gaugeWidth = Math.min(dimension / 5.5, 40) / gaugeWidthReduceRatio;
|
||||
const thresholdMarkersWidth = gaugeWidth / 5;
|
||||
const fontSize = Math.min(dimension / 5.5, 100) * (value.text !== null ? this.getFontScale(value.text.length) : 1);
|
||||
const thresholdLabelFontSize = fontSize / 2.5;
|
||||
@@ -181,7 +181,7 @@ function calculateGaugeAutoProps(width: number, height: number, title: string |
|
||||
const titleFontSize = Math.min((width * 0.15) / 1.5, 20); // 20% of height * line-height, max 40px
|
||||
const titleHeight = titleFontSize * 1.5;
|
||||
const availableHeight = showLabel ? height - titleHeight : height;
|
||||
const gaugeHeight = Math.min(availableHeight * 0.7, width);
|
||||
const gaugeHeight = Math.min(availableHeight, width);
|
||||
|
||||
return {
|
||||
showLabel,
|
||||
|
||||
@@ -4,7 +4,7 @@ import React, { FunctionComponent } from 'react';
|
||||
interface Props {
|
||||
title?: string;
|
||||
onClose?: () => void;
|
||||
children: JSX.Element | JSX.Element[] | boolean;
|
||||
children: React.ReactNode;
|
||||
onAdd?: () => void;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,116 +1,129 @@
|
||||
// Libraries
|
||||
import React, { PureComponent, ChangeEvent } from 'react';
|
||||
import React, { ChangeEvent, useState, useCallback } from 'react';
|
||||
|
||||
// Components
|
||||
import { PanelOptionsGroup } from '../PanelOptionsGroup/PanelOptionsGroup';
|
||||
import { FormField } from '../FormField/FormField';
|
||||
import { FormLabel } from '../FormLabel/FormLabel';
|
||||
import { UnitPicker } from '../UnitPicker/UnitPicker';
|
||||
|
||||
// Types
|
||||
import { Field } from '../../types/data';
|
||||
import { toNumberString, toIntegerOrUndefined } from '../../utils';
|
||||
import { toIntegerOrUndefined } from '../../utils';
|
||||
import { SelectOptionItem } from '../Select/Select';
|
||||
|
||||
import { VAR_SERIES_NAME, VAR_FIELD_NAME, VAR_CALC, VAR_CELL_PREFIX } from '../../utils/fieldDisplay';
|
||||
import { PanelOptionsGroup } from '../index';
|
||||
|
||||
const labelWidth = 6;
|
||||
|
||||
export interface Props {
|
||||
title: string;
|
||||
options: Partial<Field>;
|
||||
value: Partial<Field>;
|
||||
onChange: (fieldProperties: Partial<Field>) => void;
|
||||
showMinMax: boolean;
|
||||
}
|
||||
|
||||
export class FieldPropertiesEditor extends PureComponent<Props> {
|
||||
onTitleChange = (event: ChangeEvent<HTMLInputElement>) =>
|
||||
this.props.onChange({ ...this.props.options, title: event.target.value });
|
||||
export const FieldPropertiesEditor: React.FC<Props> = ({ value, onChange, showMinMax }) => {
|
||||
const { unit, title } = value;
|
||||
|
||||
// @ts-ignore
|
||||
onUnitChange = (unit: SelectOptionItem<string>) => this.props.onChange({ ...this.props.value, unit: unit.value });
|
||||
const [decimals, setDecimals] = useState(
|
||||
value.decimals !== undefined && value.decimals !== null ? value.decimals.toString() : ''
|
||||
);
|
||||
const [min, setMin] = useState(value.min !== undefined && value.min !== null ? value.min.toString() : '');
|
||||
const [max, setMax] = useState(value.max !== undefined && value.max !== null ? value.max.toString() : '');
|
||||
|
||||
onDecimalChange = (event: ChangeEvent<HTMLInputElement>) => {
|
||||
this.props.onChange({
|
||||
...this.props.options,
|
||||
decimals: toIntegerOrUndefined(event.target.value),
|
||||
});
|
||||
const onTitleChange = (event: ChangeEvent<HTMLInputElement>) => {
|
||||
onChange({ ...value, title: event.target.value });
|
||||
};
|
||||
|
||||
onMinChange = (event: ChangeEvent<HTMLInputElement>) => {
|
||||
this.props.onChange({
|
||||
...this.props.options,
|
||||
min: toIntegerOrUndefined(event.target.value),
|
||||
});
|
||||
const onDecimalChange = useCallback(
|
||||
(event: ChangeEvent<HTMLInputElement>) => {
|
||||
setDecimals(event.target.value);
|
||||
},
|
||||
[value.decimals, onChange]
|
||||
);
|
||||
|
||||
const onMinChange = useCallback(
|
||||
(event: ChangeEvent<HTMLInputElement>) => {
|
||||
setMin(event.target.value);
|
||||
},
|
||||
[value.min, onChange]
|
||||
);
|
||||
|
||||
const onMaxChange = useCallback(
|
||||
(event: ChangeEvent<HTMLInputElement>) => {
|
||||
setMax(event.target.value);
|
||||
},
|
||||
[value.max, onChange]
|
||||
);
|
||||
|
||||
const onUnitChange = (unit: SelectOptionItem<string>) => {
|
||||
onChange({ ...value, unit: unit.value });
|
||||
};
|
||||
|
||||
onMaxChange = (event: ChangeEvent<HTMLInputElement>) => {
|
||||
this.props.onChange({
|
||||
...this.props.options,
|
||||
max: toIntegerOrUndefined(event.target.value),
|
||||
const commitChanges = useCallback(() => {
|
||||
onChange({
|
||||
...value,
|
||||
decimals: toIntegerOrUndefined(decimals),
|
||||
min: toIntegerOrUndefined(min),
|
||||
max: toIntegerOrUndefined(max),
|
||||
});
|
||||
};
|
||||
}, [min, max, decimals]);
|
||||
|
||||
render() {
|
||||
const { showMinMax, title } = this.props;
|
||||
const { unit, decimals, min, max } = this.props.options;
|
||||
|
||||
const titleTooltip = (
|
||||
<div>
|
||||
Template Variables:
|
||||
<br />
|
||||
{'$' + VAR_SERIES_NAME}
|
||||
<br />
|
||||
{'$' + VAR_FIELD_NAME}
|
||||
<br />
|
||||
{'$' + VAR_CELL_PREFIX + '{N}'} / {'$' + VAR_CALC}
|
||||
const titleTooltip = (
|
||||
<div>
|
||||
Template Variables:
|
||||
<br />
|
||||
{'$' + VAR_SERIES_NAME}
|
||||
<br />
|
||||
{'$' + VAR_FIELD_NAME}
|
||||
<br />
|
||||
{'$' + VAR_CELL_PREFIX + '{N}'} / {'$' + VAR_CALC}
|
||||
</div>
|
||||
);
|
||||
return (
|
||||
<PanelOptionsGroup title="Field">
|
||||
<FormField
|
||||
label="Title"
|
||||
labelWidth={labelWidth}
|
||||
onChange={onTitleChange}
|
||||
value={title}
|
||||
tooltip={titleTooltip}
|
||||
placeholder="Auto"
|
||||
/>
|
||||
<div className="gf-form">
|
||||
<FormLabel width={labelWidth}>Unit</FormLabel>
|
||||
<UnitPicker defaultValue={unit} onChange={onUnitChange} />
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<PanelOptionsGroup title={title}>
|
||||
{showMinMax && (
|
||||
<>
|
||||
<FormField
|
||||
label="Title"
|
||||
label="Min"
|
||||
labelWidth={labelWidth}
|
||||
onChange={this.onTitleChange}
|
||||
value={this.props.options.title}
|
||||
tooltip={titleTooltip}
|
||||
placeholder="Auto"
|
||||
onChange={onMinChange}
|
||||
onBlur={commitChanges}
|
||||
value={min}
|
||||
type="number"
|
||||
/>
|
||||
|
||||
<div className="gf-form">
|
||||
<FormLabel width={labelWidth}>Unit</FormLabel>
|
||||
<UnitPicker defaultValue={unit} onChange={this.onUnitChange} />
|
||||
</div>
|
||||
{showMinMax && (
|
||||
<>
|
||||
<FormField
|
||||
label="Min"
|
||||
labelWidth={labelWidth}
|
||||
onChange={this.onMinChange}
|
||||
value={toNumberString(min)}
|
||||
type="number"
|
||||
/>
|
||||
<FormField
|
||||
label="Max"
|
||||
labelWidth={labelWidth}
|
||||
onChange={this.onMaxChange}
|
||||
value={toNumberString(max)}
|
||||
type="number"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<FormField
|
||||
label="Decimals"
|
||||
label="Max"
|
||||
labelWidth={labelWidth}
|
||||
placeholder="auto"
|
||||
onChange={this.onDecimalChange}
|
||||
value={toNumberString(decimals)}
|
||||
onChange={onMaxChange}
|
||||
onBlur={commitChanges}
|
||||
value={max}
|
||||
type="number"
|
||||
/>
|
||||
</>
|
||||
</PanelOptionsGroup>
|
||||
);
|
||||
}
|
||||
}
|
||||
)}
|
||||
<FormField
|
||||
label="Decimals"
|
||||
labelWidth={labelWidth}
|
||||
placeholder="auto"
|
||||
onChange={onDecimalChange}
|
||||
onBlur={commitChanges}
|
||||
value={decimals}
|
||||
type="number"
|
||||
/>
|
||||
</PanelOptionsGroup>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -80,6 +80,13 @@ export interface DataSourcePluginMeta extends PluginMeta {
|
||||
mixed?: boolean;
|
||||
hasQueryHelp?: boolean;
|
||||
queryOptions?: PluginMetaQueryOptions;
|
||||
sort?: number;
|
||||
/**
|
||||
* By default, hidden queries are not passed to the datasource
|
||||
* Set this to true in plugin.json to have hidden queries passed to the
|
||||
* DataSource query method
|
||||
*/
|
||||
hiddenQueries?: boolean;
|
||||
}
|
||||
|
||||
interface PluginMetaQueryOptions {
|
||||
|
||||
@@ -32,6 +32,7 @@ export interface PanelData {
|
||||
}
|
||||
|
||||
export interface PanelProps<T = any> {
|
||||
id: number; // ID within the current dashboard
|
||||
data: PanelData;
|
||||
// TODO: annotation?: PanelData;
|
||||
|
||||
|
||||
@@ -47,8 +47,8 @@ RUN mkdir -p "$GF_PATHS_HOME/.aws" && \
|
||||
"$GF_PATHS_DATA" && \
|
||||
cp "$GF_PATHS_HOME/conf/sample.ini" "$GF_PATHS_CONFIG" && \
|
||||
cp "$GF_PATHS_HOME/conf/ldap.toml" /etc/grafana/ldap.toml && \
|
||||
chown -R grafana:grafana "$GF_PATHS_DATA" "$GF_PATHS_HOME/.aws" "$GF_PATHS_LOGS" "$GF_PATHS_PLUGINS" && \
|
||||
chmod 777 "$GF_PATHS_DATA" "$GF_PATHS_HOME/.aws" "$GF_PATHS_LOGS" "$GF_PATHS_PLUGINS"
|
||||
chown -R grafana:grafana "$GF_PATHS_DATA" "$GF_PATHS_HOME/.aws" "$GF_PATHS_LOGS" "$GF_PATHS_PLUGINS" "$GF_PATHS_PROVISIONING" && \
|
||||
chmod -R 777 "$GF_PATHS_DATA" "$GF_PATHS_HOME/.aws" "$GF_PATHS_LOGS" "$GF_PATHS_PLUGINS" "$GF_PATHS_PROVISIONING"
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
|
||||
@@ -233,7 +233,7 @@ func (hs *HTTPServer) setIndexViewData(c *m.ReqContext) (*dtos.IndexViewData, er
|
||||
|
||||
if len(appLink.Children) > 0 && c.OrgRole == m.ROLE_ADMIN {
|
||||
appLink.Children = append(appLink.Children, &dtos.NavLink{Divider: true})
|
||||
appLink.Children = append(appLink.Children, &dtos.NavLink{Text: "Plugin Config", Icon: "gicon gicon-cog", Url: setting.AppSubUrl + "/plugins/" + plugin.Id + "/edit"})
|
||||
appLink.Children = append(appLink.Children, &dtos.NavLink{Text: "Plugin Config", Icon: "gicon gicon-cog", Url: setting.AppSubUrl + "/plugins/" + plugin.Id + "/"})
|
||||
}
|
||||
|
||||
if len(appLink.Children) > 0 {
|
||||
|
||||
@@ -67,14 +67,14 @@ func (provider *accessTokenProvider) getAccessToken(data templateData) (string,
|
||||
}
|
||||
}
|
||||
|
||||
urlInterpolated, err := interpolateString(provider.route.TokenAuth.Url, data)
|
||||
urlInterpolated, err := InterpolateString(provider.route.TokenAuth.Url, data)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
params := make(url.Values)
|
||||
for key, value := range provider.route.TokenAuth.Params {
|
||||
interpolatedParam, err := interpolateString(value, data)
|
||||
interpolatedParam, err := InterpolateString(value, data)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -119,7 +119,7 @@ func (provider *accessTokenProvider) getJwtAccessToken(ctx context.Context, data
|
||||
conf := &jwt.Config{}
|
||||
|
||||
if val, ok := provider.route.JwtTokenAuth.Params["client_email"]; ok {
|
||||
interpolatedVal, err := interpolateString(val, data)
|
||||
interpolatedVal, err := InterpolateString(val, data)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -127,7 +127,7 @@ func (provider *accessTokenProvider) getJwtAccessToken(ctx context.Context, data
|
||||
}
|
||||
|
||||
if val, ok := provider.route.JwtTokenAuth.Params["private_key"]; ok {
|
||||
interpolatedVal, err := interpolateString(val, data)
|
||||
interpolatedVal, err := InterpolateString(val, data)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -135,7 +135,7 @@ func (provider *accessTokenProvider) getJwtAccessToken(ctx context.Context, data
|
||||
}
|
||||
|
||||
if val, ok := provider.route.JwtTokenAuth.Params["token_uri"]; ok {
|
||||
interpolatedVal, err := interpolateString(val, data)
|
||||
interpolatedVal, err := InterpolateString(val, data)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
package pluginproxy
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
m "github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
@@ -24,7 +22,7 @@ func ApplyRoute(ctx context.Context, req *http.Request, proxyPath string, route
|
||||
SecureJsonData: ds.SecureJsonData.Decrypt(),
|
||||
}
|
||||
|
||||
interpolatedURL, err := interpolateString(route.Url, data)
|
||||
interpolatedURL, err := InterpolateString(route.Url, data)
|
||||
if err != nil {
|
||||
logger.Error("Error interpolating proxy url", "error", err)
|
||||
return
|
||||
@@ -81,24 +79,9 @@ func ApplyRoute(ctx context.Context, req *http.Request, proxyPath string, route
|
||||
logger.Info("Requesting", "url", req.URL.String())
|
||||
}
|
||||
|
||||
func interpolateString(text string, data templateData) (string, error) {
|
||||
t, err := template.New("content").Parse(text)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("could not parse template %s", text)
|
||||
}
|
||||
|
||||
var contentBuf bytes.Buffer
|
||||
err = t.Execute(&contentBuf, data)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to execute template %s", text)
|
||||
}
|
||||
|
||||
return contentBuf.String(), nil
|
||||
}
|
||||
|
||||
func addHeaders(reqHeaders *http.Header, route *plugins.AppPluginRoute, data templateData) error {
|
||||
for _, header := range route.Headers {
|
||||
interpolated, err := interpolateString(header.Content, data)
|
||||
interpolated, err := InterpolateString(header.Content, data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ func TestDsAuthProvider(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
interpolated, err := interpolateString("{{.SecureJsonData.Test}}", data)
|
||||
interpolated, err := InterpolateString("{{.SecureJsonData.Test}}", data)
|
||||
So(err, ShouldBeNil)
|
||||
So(interpolated, ShouldEqual, "0asd+asd")
|
||||
})
|
||||
|
||||
@@ -2,12 +2,13 @@ package pluginproxy
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/log"
|
||||
m "github.com/grafana/grafana/pkg/models"
|
||||
@@ -38,6 +39,24 @@ func getHeaders(route *plugins.AppPluginRoute, orgId int64, appID string) (http.
|
||||
return result, err
|
||||
}
|
||||
|
||||
func updateURL(route *plugins.AppPluginRoute, orgId int64, appID string) (string, error) {
|
||||
query := m.GetPluginSettingByIdQuery{OrgId: orgId, PluginId: appID}
|
||||
if err := bus.Dispatch(&query); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
data := templateData{
|
||||
JsonData: query.Result.JsonData,
|
||||
SecureJsonData: query.Result.SecureJsonData.Decrypt(),
|
||||
}
|
||||
interpolated, err := InterpolateString(route.Url, data)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return interpolated, err
|
||||
}
|
||||
|
||||
// NewApiPluginProxy create a plugin proxy
|
||||
func NewApiPluginProxy(ctx *m.ReqContext, proxyPath string, route *plugins.AppPluginRoute, appID string, cfg *setting.Cfg) *httputil.ReverseProxy {
|
||||
targetURL, _ := url.Parse(route.Url)
|
||||
|
||||
@@ -48,7 +67,6 @@ func NewApiPluginProxy(ctx *m.ReqContext, proxyPath string, route *plugins.AppPl
|
||||
req.Host = targetURL.Host
|
||||
|
||||
req.URL.Path = util.JoinURLFragments(targetURL.Path, proxyPath)
|
||||
|
||||
// clear cookie headers
|
||||
req.Header.Del("Cookie")
|
||||
req.Header.Del("Set-Cookie")
|
||||
@@ -72,13 +90,13 @@ func NewApiPluginProxy(ctx *m.ReqContext, proxyPath string, route *plugins.AppPl
|
||||
}
|
||||
|
||||
// Create a HTTP header with the context in it.
|
||||
ctxJson, err := json.Marshal(ctx.SignedInUser)
|
||||
ctxJSON, err := json.Marshal(ctx.SignedInUser)
|
||||
if err != nil {
|
||||
ctx.JsonApiErr(500, "failed to marshal context to json.", err)
|
||||
return
|
||||
}
|
||||
|
||||
req.Header.Add("X-Grafana-Context", string(ctxJson))
|
||||
req.Header.Add("X-Grafana-Context", string(ctxJSON))
|
||||
|
||||
if cfg.SendUserHeader && !ctx.SignedInUser.IsAnonymous {
|
||||
req.Header.Add("X-Grafana-User", ctx.SignedInUser.Login)
|
||||
@@ -97,6 +115,27 @@ func NewApiPluginProxy(ctx *m.ReqContext, proxyPath string, route *plugins.AppPl
|
||||
}
|
||||
}
|
||||
|
||||
if len(route.Url) > 0 {
|
||||
interpolatedURL, err := updateURL(route, ctx.OrgId, appID)
|
||||
if err != nil {
|
||||
ctx.JsonApiErr(500, "Could not interpolate plugin route url", err)
|
||||
}
|
||||
targetURL, err := url.Parse(interpolatedURL)
|
||||
if err != nil {
|
||||
ctx.JsonApiErr(500, "Could not parse custom url: %v", err)
|
||||
return
|
||||
}
|
||||
req.URL.Scheme = targetURL.Scheme
|
||||
req.URL.Host = targetURL.Host
|
||||
req.Host = targetURL.Host
|
||||
req.URL.Path = util.JoinURLFragments(targetURL.Path, proxyPath)
|
||||
|
||||
if err != nil {
|
||||
ctx.JsonApiErr(500, "Could not interpolate plugin route url", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// reqBytes, _ := httputil.DumpRequestOut(req, true);
|
||||
// log.Trace("Proxying plugin request: %s", string(reqBytes))
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@ func TestPluginProxy(t *testing.T) {
|
||||
},
|
||||
},
|
||||
&setting.Cfg{SendUserHeader: true},
|
||||
nil,
|
||||
)
|
||||
|
||||
Convey("Should add header with username", func() {
|
||||
@@ -69,6 +70,7 @@ func TestPluginProxy(t *testing.T) {
|
||||
},
|
||||
},
|
||||
&setting.Cfg{SendUserHeader: false},
|
||||
nil,
|
||||
)
|
||||
Convey("Should not add header with username", func() {
|
||||
// Get will return empty string even if header is not set
|
||||
@@ -82,6 +84,7 @@ func TestPluginProxy(t *testing.T) {
|
||||
SignedInUser: &m.SignedInUser{IsAnonymous: true},
|
||||
},
|
||||
&setting.Cfg{SendUserHeader: true},
|
||||
nil,
|
||||
)
|
||||
|
||||
Convey("Should not add header with username", func() {
|
||||
@@ -89,14 +92,59 @@ func TestPluginProxy(t *testing.T) {
|
||||
So(req.Header.Get("X-Grafana-User"), ShouldEqual, "")
|
||||
})
|
||||
})
|
||||
|
||||
Convey("When getting templated url", t, func() {
|
||||
route := &plugins.AppPluginRoute{
|
||||
Url: "{{.JsonData.dynamicUrl}}",
|
||||
Method: "GET",
|
||||
}
|
||||
|
||||
bus.AddHandler("test", func(query *m.GetPluginSettingByIdQuery) error {
|
||||
query.Result = &m.PluginSetting{
|
||||
JsonData: map[string]interface{}{
|
||||
"dynamicUrl": "https://dynamic.grafana.com",
|
||||
},
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
req := getPluginProxiedRequest(
|
||||
&m.ReqContext{
|
||||
SignedInUser: &m.SignedInUser{
|
||||
Login: "test_user",
|
||||
},
|
||||
},
|
||||
&setting.Cfg{SendUserHeader: true},
|
||||
route,
|
||||
)
|
||||
Convey("Headers should be updated", func() {
|
||||
header, err := getHeaders(route, 1, "my-app")
|
||||
So(err, ShouldBeNil)
|
||||
So(header.Get("X-Grafana-User"), ShouldEqual, "")
|
||||
})
|
||||
Convey("Should set req.URL to be interpolated value from jsonData", func() {
|
||||
So(req.URL.String(), ShouldEqual, "https://dynamic.grafana.com")
|
||||
})
|
||||
Convey("Route url should not be modified", func() {
|
||||
So(route.Url, ShouldEqual, "{{.JsonData.dynamicUrl}}")
|
||||
})
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
// getPluginProxiedRequest is a helper for easier setup of tests based on global config and ReqContext.
|
||||
func getPluginProxiedRequest(ctx *m.ReqContext, cfg *setting.Cfg) *http.Request {
|
||||
route := &plugins.AppPluginRoute{}
|
||||
func getPluginProxiedRequest(ctx *m.ReqContext, cfg *setting.Cfg, route *plugins.AppPluginRoute) *http.Request {
|
||||
// insert dummy route if none is specified
|
||||
if route == nil {
|
||||
route = &plugins.AppPluginRoute{
|
||||
Path: "api/v4/",
|
||||
Url: "https://www.google.com",
|
||||
ReqRole: m.ROLE_EDITOR,
|
||||
}
|
||||
}
|
||||
proxy := NewApiPluginProxy(ctx, "", route, "", cfg)
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, "http://grafana.com/sub", nil)
|
||||
req, err := http.NewRequest(http.MethodGet, route.Url, nil)
|
||||
So(err, ShouldBeNil)
|
||||
proxy.Director(req)
|
||||
return req
|
||||
|
||||
49
pkg/api/pluginproxy/utils.go
Normal file
49
pkg/api/pluginproxy/utils.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package pluginproxy
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"text/template"
|
||||
|
||||
m "github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
)
|
||||
|
||||
// InterpolateString accepts template data and return a string with substitutions
|
||||
func InterpolateString(text string, data templateData) (string, error) {
|
||||
t, err := template.New("content").Parse(text)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("could not parse template %s", text)
|
||||
}
|
||||
|
||||
var contentBuf bytes.Buffer
|
||||
err = t.Execute(&contentBuf, data)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to execute template %s", text)
|
||||
}
|
||||
|
||||
return contentBuf.String(), nil
|
||||
}
|
||||
|
||||
// InterpolateURL accepts template data and return a string with substitutions
|
||||
func InterpolateURL(anURL *url.URL, route *plugins.AppPluginRoute, orgID int64, appID string) (*url.URL, error) {
|
||||
query := m.GetPluginSettingByIdQuery{OrgId: orgID, PluginId: appID}
|
||||
result, err := url.Parse(anURL.String())
|
||||
if query.Result != nil {
|
||||
if len(query.Result.JsonData) > 0 {
|
||||
data := templateData{
|
||||
JsonData: query.Result.JsonData,
|
||||
}
|
||||
interpolatedResult, err := InterpolateString(anURL.String(), data)
|
||||
if err == nil {
|
||||
result, err = url.Parse(interpolatedResult)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error parsing plugin route url %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result, err
|
||||
}
|
||||
21
pkg/api/pluginproxy/utils_test.go
Normal file
21
pkg/api/pluginproxy/utils_test.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package pluginproxy
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
func TestInterpolateString(t *testing.T) {
|
||||
Convey("When interpolating string", t, func() {
|
||||
data := templateData{
|
||||
SecureJsonData: map[string]string{
|
||||
"Test": "0asd+asd",
|
||||
},
|
||||
}
|
||||
|
||||
interpolated, err := InterpolateString("{{.SecureJsonData.Test}}", data)
|
||||
So(err, ShouldBeNil)
|
||||
So(interpolated, ShouldEqual, "0asd+asd")
|
||||
})
|
||||
}
|
||||
@@ -39,10 +39,14 @@ func (dc *databaseCache) Run(ctx context.Context) error {
|
||||
}
|
||||
|
||||
func (dc *databaseCache) internalRunGC() {
|
||||
now := getTime().Unix()
|
||||
sql := `DELETE FROM cache_data WHERE (? - created_at) >= expires AND expires <> 0`
|
||||
err := dc.SQLStore.WithDbSession(context.Background(), func(session *sqlstore.DBSession) error {
|
||||
now := getTime().Unix()
|
||||
sql := `DELETE FROM cache_data WHERE (? - created_at) >= expires AND expires <> 0`
|
||||
|
||||
_, err := session.Exec(sql, now)
|
||||
return err
|
||||
})
|
||||
|
||||
_, err := dc.SQLStore.NewSession().Exec(sql, now)
|
||||
if err != nil {
|
||||
dc.log.Error("failed to run garbage collect", "error", err)
|
||||
}
|
||||
@@ -80,44 +84,48 @@ func (dc *databaseCache) Get(key string) (interface{}, error) {
|
||||
}
|
||||
|
||||
func (dc *databaseCache) Set(key string, value interface{}, expire time.Duration) error {
|
||||
item := &cachedItem{Val: value}
|
||||
data, err := encodeGob(item)
|
||||
if err != nil {
|
||||
return dc.SQLStore.WithTransactionalDbSession(context.Background(), func(session *sqlstore.DBSession) error {
|
||||
item := &cachedItem{Val: value}
|
||||
data, err := encodeGob(item)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var cacheHit CacheData
|
||||
has, err := session.Where("cache_key = ?", key).Get(&cacheHit)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var expiresInSeconds int64
|
||||
if expire != 0 {
|
||||
expiresInSeconds = int64(expire) / int64(time.Second)
|
||||
}
|
||||
|
||||
// insert or update depending on if item already exist
|
||||
if has {
|
||||
sql := `UPDATE cache_data SET data=?, created_at=?, expires=? WHERE cache_key=?`
|
||||
_, err = session.Exec(sql, data, getTime().Unix(), expiresInSeconds, key)
|
||||
} else {
|
||||
sql := `INSERT INTO cache_data (cache_key,data,created_at,expires) VALUES(?,?,?,?)`
|
||||
_, err = session.Exec(sql, key, data, getTime().Unix(), expiresInSeconds)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
session := dc.SQLStore.NewSession()
|
||||
|
||||
var cacheHit CacheData
|
||||
has, err := session.Where("cache_key = ?", key).Get(&cacheHit)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var expiresInSeconds int64
|
||||
if expire != 0 {
|
||||
expiresInSeconds = int64(expire) / int64(time.Second)
|
||||
}
|
||||
|
||||
// insert or update depending on if item already exist
|
||||
if has {
|
||||
sql := `UPDATE cache_data SET data=?, created_at=?, expires=? WHERE cache_key=?`
|
||||
_, err = session.Exec(sql, data, getTime().Unix(), expiresInSeconds, key)
|
||||
} else {
|
||||
sql := `INSERT INTO cache_data (cache_key,data,created_at,expires) VALUES(?,?,?,?)`
|
||||
_, err = session.Exec(sql, key, data, getTime().Unix(), expiresInSeconds)
|
||||
}
|
||||
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
func (dc *databaseCache) Delete(key string) error {
|
||||
sql := "DELETE FROM cache_data WHERE cache_key=?"
|
||||
_, err := dc.SQLStore.NewSession().Exec(sql, key)
|
||||
return dc.SQLStore.WithDbSession(context.Background(), func(session *sqlstore.DBSession) error {
|
||||
sql := "DELETE FROM cache_data WHERE cache_key=?"
|
||||
_, err := session.Exec(sql, key)
|
||||
|
||||
return err
|
||||
})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// CacheData is the struct representing the table in the database
|
||||
type CacheData struct {
|
||||
CacheKey string
|
||||
Data []byte
|
||||
|
||||
@@ -18,16 +18,17 @@ import (
|
||||
// DataSourcePlugin contains all metadata about a datasource plugin
|
||||
type DataSourcePlugin struct {
|
||||
FrontendPluginBase
|
||||
Annotations bool `json:"annotations"`
|
||||
Metrics bool `json:"metrics"`
|
||||
Alerting bool `json:"alerting"`
|
||||
Explore bool `json:"explore"`
|
||||
Table bool `json:"tables"`
|
||||
Logs bool `json:"logs"`
|
||||
QueryOptions map[string]bool `json:"queryOptions,omitempty"`
|
||||
BuiltIn bool `json:"builtIn,omitempty"`
|
||||
Mixed bool `json:"mixed,omitempty"`
|
||||
Routes []*AppPluginRoute `json:"routes"`
|
||||
Annotations bool `json:"annotations"`
|
||||
Metrics bool `json:"metrics"`
|
||||
Alerting bool `json:"alerting"`
|
||||
Explore bool `json:"explore"`
|
||||
Table bool `json:"tables"`
|
||||
HiddenQueries bool `json:"hiddenQueries"`
|
||||
Logs bool `json:"logs"`
|
||||
QueryOptions map[string]bool `json:"queryOptions,omitempty"`
|
||||
BuiltIn bool `json:"builtIn,omitempty"`
|
||||
Mixed bool `json:"mixed,omitempty"`
|
||||
Routes []*AppPluginRoute `json:"routes"`
|
||||
|
||||
Backend bool `json:"backend,omitempty"`
|
||||
Executable string `json:"executable,omitempty"`
|
||||
|
||||
@@ -85,14 +85,17 @@ func (e *AzureMonitorDatasource) buildQueries(queries []*tsdb.Query, timeRange *
|
||||
azlog.Debug("AzureMonitor", "target", azureMonitorTarget)
|
||||
|
||||
urlComponents := map[string]string{}
|
||||
urlComponents["subscription"] = fmt.Sprintf("%v", query.Model.Get("subscription").MustString())
|
||||
urlComponents["resourceGroup"] = fmt.Sprintf("%v", azureMonitorTarget["resourceGroup"])
|
||||
urlComponents["metricDefinition"] = fmt.Sprintf("%v", azureMonitorTarget["metricDefinition"])
|
||||
urlComponents["resourceName"] = fmt.Sprintf("%v", azureMonitorTarget["resourceName"])
|
||||
|
||||
ub := urlBuilder{
|
||||
ResourceGroup: urlComponents["resourceGroup"],
|
||||
MetricDefinition: urlComponents["metricDefinition"],
|
||||
ResourceName: urlComponents["resourceName"],
|
||||
DefaultSubscription: query.DataSource.JsonData.Get("subscriptionId").MustString(),
|
||||
Subscription: urlComponents["subscription"],
|
||||
ResourceGroup: urlComponents["resourceGroup"],
|
||||
MetricDefinition: urlComponents["metricDefinition"],
|
||||
ResourceName: urlComponents["resourceName"],
|
||||
}
|
||||
azureURL := ub.Build()
|
||||
|
||||
@@ -199,8 +202,7 @@ func (e *AzureMonitorDatasource) createRequest(ctx context.Context, dsInfo *mode
|
||||
}
|
||||
|
||||
cloudName := dsInfo.JsonData.Get("cloudName").MustString("azuremonitor")
|
||||
subscriptionID := dsInfo.JsonData.Get("subscriptionId").MustString()
|
||||
proxyPass := fmt.Sprintf("%s/subscriptions/%s", cloudName, subscriptionID)
|
||||
proxyPass := fmt.Sprintf("%s/subscriptions", cloudName)
|
||||
|
||||
u, _ := url.Parse(dsInfo.Url)
|
||||
u.Path = path.Join(u.Path, "render")
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/tsdb"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
@@ -27,7 +28,13 @@ func TestAzureMonitorDatasource(t *testing.T) {
|
||||
},
|
||||
Queries: []*tsdb.Query{
|
||||
{
|
||||
DataSource: &models.DataSource{
|
||||
JsonData: simplejson.NewFromAny(map[string]interface{}{
|
||||
"subscriptionId": "default-subscription",
|
||||
}),
|
||||
},
|
||||
Model: simplejson.NewFromAny(map[string]interface{}{
|
||||
"subscription": "12345678-aaaa-bbbb-cccc-123456789abc",
|
||||
"azureMonitor": map[string]interface{}{
|
||||
"timeGrain": "PT1M",
|
||||
"aggregation": "Average",
|
||||
@@ -49,7 +56,7 @@ func TestAzureMonitorDatasource(t *testing.T) {
|
||||
|
||||
So(len(queries), ShouldEqual, 1)
|
||||
So(queries[0].RefID, ShouldEqual, "A")
|
||||
So(queries[0].URL, ShouldEqual, "resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana/providers/microsoft.insights/metrics")
|
||||
So(queries[0].URL, ShouldEqual, "12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana/providers/microsoft.insights/metrics")
|
||||
So(queries[0].Target, ShouldEqual, "aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU×pan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z")
|
||||
So(len(queries[0].Params), ShouldEqual, 5)
|
||||
So(queries[0].Params["timespan"][0], ShouldEqual, "2018-03-15T13:00:00Z/2018-03-15T13:34:00Z")
|
||||
|
||||
@@ -7,22 +7,30 @@ import (
|
||||
|
||||
// urlBuilder builds the URL for calling the Azure Monitor API
|
||||
type urlBuilder struct {
|
||||
ResourceGroup string
|
||||
MetricDefinition string
|
||||
ResourceName string
|
||||
DefaultSubscription string
|
||||
Subscription string
|
||||
ResourceGroup string
|
||||
MetricDefinition string
|
||||
ResourceName string
|
||||
}
|
||||
|
||||
// Build checks the metric definition property to see which form of the url
|
||||
// should be returned
|
||||
func (ub *urlBuilder) Build() string {
|
||||
|
||||
subscription := ub.Subscription
|
||||
|
||||
if ub.Subscription == "" {
|
||||
subscription = ub.DefaultSubscription
|
||||
}
|
||||
|
||||
if strings.Count(ub.MetricDefinition, "/") > 1 {
|
||||
rn := strings.Split(ub.ResourceName, "/")
|
||||
lastIndex := strings.LastIndex(ub.MetricDefinition, "/")
|
||||
service := ub.MetricDefinition[lastIndex+1:]
|
||||
md := ub.MetricDefinition[0:lastIndex]
|
||||
return fmt.Sprintf("resourceGroups/%s/providers/%s/%s/%s/%s/providers/microsoft.insights/metrics", ub.ResourceGroup, md, rn[0], service, rn[1])
|
||||
return fmt.Sprintf("%s/resourceGroups/%s/providers/%s/%s/%s/%s/providers/microsoft.insights/metrics", subscription, ub.ResourceGroup, md, rn[0], service, rn[1])
|
||||
}
|
||||
|
||||
return fmt.Sprintf("resourceGroups/%s/providers/%s/%s/providers/microsoft.insights/metrics", ub.ResourceGroup, ub.MetricDefinition, ub.ResourceName)
|
||||
return fmt.Sprintf("%s/resourceGroups/%s/providers/%s/%s/providers/microsoft.insights/metrics", subscription, ub.ResourceGroup, ub.MetricDefinition, ub.ResourceName)
|
||||
}
|
||||
|
||||
@@ -11,35 +11,51 @@ func TestURLBuilder(t *testing.T) {
|
||||
|
||||
Convey("when metric definition is in the short form", func() {
|
||||
ub := &urlBuilder{
|
||||
ResourceGroup: "rg",
|
||||
MetricDefinition: "Microsoft.Compute/virtualMachines",
|
||||
ResourceName: "rn",
|
||||
DefaultSubscription: "default-sub",
|
||||
ResourceGroup: "rg",
|
||||
MetricDefinition: "Microsoft.Compute/virtualMachines",
|
||||
ResourceName: "rn",
|
||||
}
|
||||
|
||||
url := ub.Build()
|
||||
So(url, ShouldEqual, "resourceGroups/rg/providers/Microsoft.Compute/virtualMachines/rn/providers/microsoft.insights/metrics")
|
||||
So(url, ShouldEqual, "default-sub/resourceGroups/rg/providers/Microsoft.Compute/virtualMachines/rn/providers/microsoft.insights/metrics")
|
||||
})
|
||||
|
||||
Convey("when metric definition is in the short form and a subscription is defined", func() {
|
||||
ub := &urlBuilder{
|
||||
DefaultSubscription: "default-sub",
|
||||
Subscription: "specified-sub",
|
||||
ResourceGroup: "rg",
|
||||
MetricDefinition: "Microsoft.Compute/virtualMachines",
|
||||
ResourceName: "rn",
|
||||
}
|
||||
|
||||
url := ub.Build()
|
||||
So(url, ShouldEqual, "specified-sub/resourceGroups/rg/providers/Microsoft.Compute/virtualMachines/rn/providers/microsoft.insights/metrics")
|
||||
})
|
||||
|
||||
Convey("when metric definition is Microsoft.Storage/storageAccounts/blobServices", func() {
|
||||
ub := &urlBuilder{
|
||||
ResourceGroup: "rg",
|
||||
MetricDefinition: "Microsoft.Storage/storageAccounts/blobServices",
|
||||
ResourceName: "rn1/default",
|
||||
DefaultSubscription: "default-sub",
|
||||
ResourceGroup: "rg",
|
||||
MetricDefinition: "Microsoft.Storage/storageAccounts/blobServices",
|
||||
ResourceName: "rn1/default",
|
||||
}
|
||||
|
||||
url := ub.Build()
|
||||
So(url, ShouldEqual, "resourceGroups/rg/providers/Microsoft.Storage/storageAccounts/rn1/blobServices/default/providers/microsoft.insights/metrics")
|
||||
So(url, ShouldEqual, "default-sub/resourceGroups/rg/providers/Microsoft.Storage/storageAccounts/rn1/blobServices/default/providers/microsoft.insights/metrics")
|
||||
})
|
||||
|
||||
Convey("when metric definition is Microsoft.Storage/storageAccounts/fileServices", func() {
|
||||
ub := &urlBuilder{
|
||||
ResourceGroup: "rg",
|
||||
MetricDefinition: "Microsoft.Storage/storageAccounts/fileServices",
|
||||
ResourceName: "rn1/default",
|
||||
DefaultSubscription: "default-sub",
|
||||
ResourceGroup: "rg",
|
||||
MetricDefinition: "Microsoft.Storage/storageAccounts/fileServices",
|
||||
ResourceName: "rn1/default",
|
||||
}
|
||||
|
||||
url := ub.Build()
|
||||
So(url, ShouldEqual, "resourceGroups/rg/providers/Microsoft.Storage/storageAccounts/rn1/fileServices/default/providers/microsoft.insights/metrics")
|
||||
So(url, ShouldEqual, "default-sub/resourceGroups/rg/providers/Microsoft.Storage/storageAccounts/rn1/fileServices/default/providers/microsoft.insights/metrics")
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -13,8 +13,6 @@ export class HelpCtrl {
|
||||
{ keys: ['g', 'h'], description: 'Go to Home Dashboard' },
|
||||
{ keys: ['g', 'p'], description: 'Go to Profile' },
|
||||
{ keys: ['s', 'o'], description: 'Open search' },
|
||||
{ keys: ['s', 's'], description: 'Open search with starred filter' },
|
||||
{ keys: ['s', 't'], description: 'Open search in tags view' },
|
||||
{ keys: ['esc'], description: 'Exit edit/setting views' },
|
||||
],
|
||||
Dashboard: [
|
||||
|
||||
@@ -32,6 +32,10 @@ class SearchQueryParser {
|
||||
}
|
||||
}
|
||||
|
||||
interface OpenSearchParams {
|
||||
query?: string;
|
||||
}
|
||||
|
||||
export class SearchCtrl {
|
||||
isOpen: boolean;
|
||||
query: SearchQuery;
|
||||
@@ -88,7 +92,7 @@ export class SearchCtrl {
|
||||
appEvents.emit('search-query');
|
||||
}
|
||||
|
||||
openSearch(evt, payload) {
|
||||
openSearch(payload: OpenSearchParams = {}) {
|
||||
if (this.isOpen) {
|
||||
this.closeSearch();
|
||||
return;
|
||||
@@ -99,19 +103,16 @@ export class SearchCtrl {
|
||||
this.selectedIndex = -1;
|
||||
this.results = [];
|
||||
this.query = {
|
||||
query: evt ? `${evt.query} ` : '',
|
||||
parsedQuery: this.queryParser.parse(evt && evt.query),
|
||||
query: payload.query ? `${payload.query} ` : '',
|
||||
parsedQuery: this.queryParser.parse(payload.query),
|
||||
tags: [],
|
||||
starred: false,
|
||||
};
|
||||
|
||||
this.currentSearchId = 0;
|
||||
this.ignoreClose = true;
|
||||
this.isLoading = true;
|
||||
|
||||
if (payload && payload.starred) {
|
||||
this.query.starred = true;
|
||||
}
|
||||
|
||||
this.$timeout(() => {
|
||||
this.ignoreClose = false;
|
||||
this.giveSearchFocus = true;
|
||||
|
||||
@@ -356,7 +356,12 @@ export function seriesDataToLogsModel(seriesData: SeriesData[], intervalMs: numb
|
||||
return logsModel;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
return {
|
||||
hasUniqueLabels: false,
|
||||
rows: [],
|
||||
meta: [],
|
||||
series: [],
|
||||
};
|
||||
}
|
||||
|
||||
export function logSeriesToLogsModel(logSeries: SeriesData[]): LogsModel {
|
||||
|
||||
@@ -43,21 +43,11 @@ export class KeybindingSrv {
|
||||
this.bind('g h', this.goToHome);
|
||||
this.bind('g a', this.openAlerting);
|
||||
this.bind('g p', this.goToProfile);
|
||||
this.bind('s s', this.openSearchStarred);
|
||||
this.bind('s o', this.openSearch);
|
||||
this.bind('s t', this.openSearchTags);
|
||||
this.bind('f', this.openSearch);
|
||||
this.bindGlobal('esc', this.exit);
|
||||
}
|
||||
|
||||
openSearchStarred() {
|
||||
appEvents.emit('show-dash-search', { starred: true });
|
||||
}
|
||||
|
||||
openSearchTags() {
|
||||
appEvents.emit('show-dash-search', { tagsMode: true });
|
||||
}
|
||||
|
||||
openSearch() {
|
||||
appEvents.emit('show-dash-search');
|
||||
}
|
||||
|
||||
@@ -333,22 +333,29 @@ describe('LogsParsers', () => {
|
||||
});
|
||||
});
|
||||
|
||||
const emptyLogsModel = {
|
||||
hasUniqueLabels: false,
|
||||
rows: [],
|
||||
meta: [],
|
||||
series: [],
|
||||
};
|
||||
|
||||
describe('seriesDataToLogsModel', () => {
|
||||
it('given empty series should return undefined', () => {
|
||||
expect(seriesDataToLogsModel([] as SeriesData[], 0)).toBeUndefined();
|
||||
it('given empty series should return empty logs model', () => {
|
||||
expect(seriesDataToLogsModel([] as SeriesData[], 0)).toMatchObject(emptyLogsModel);
|
||||
});
|
||||
|
||||
it('given series without correct series name should not be processed', () => {
|
||||
it('given series without correct series name should return empty logs model', () => {
|
||||
const series: SeriesData[] = [
|
||||
{
|
||||
fields: [],
|
||||
rows: [],
|
||||
},
|
||||
];
|
||||
expect(seriesDataToLogsModel(series, 0)).toBeUndefined();
|
||||
expect(seriesDataToLogsModel(series, 0)).toMatchObject(emptyLogsModel);
|
||||
});
|
||||
|
||||
it('given series without a time field should not be processed', () => {
|
||||
it('given series without a time field should return empty logs model', () => {
|
||||
const series: SeriesData[] = [
|
||||
{
|
||||
fields: [
|
||||
@@ -360,10 +367,10 @@ describe('seriesDataToLogsModel', () => {
|
||||
rows: [],
|
||||
},
|
||||
];
|
||||
expect(seriesDataToLogsModel(series, 0)).toBeUndefined();
|
||||
expect(seriesDataToLogsModel(series, 0)).toMatchObject(emptyLogsModel);
|
||||
});
|
||||
|
||||
it('given series without a string field should not be processed', () => {
|
||||
it('given series without a string field should return empty logs model', () => {
|
||||
const series: SeriesData[] = [
|
||||
{
|
||||
fields: [
|
||||
@@ -375,7 +382,7 @@ describe('seriesDataToLogsModel', () => {
|
||||
rows: [],
|
||||
},
|
||||
];
|
||||
expect(seriesDataToLogsModel(series, 0)).toBeUndefined();
|
||||
expect(seriesDataToLogsModel(series, 0)).toMatchObject(emptyLogsModel);
|
||||
});
|
||||
|
||||
it('given one series should return expected logs model', () => {
|
||||
|
||||
@@ -212,7 +212,7 @@ exports[`ServerStats Should render table with stats 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="css-17l4171 track-horizontal"
|
||||
className="css-52gpmd track-horizontal"
|
||||
style={
|
||||
Object {
|
||||
"display": "none",
|
||||
@@ -233,7 +233,7 @@ exports[`ServerStats Should render table with stats 1`] = `
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="css-17l4171 track-vertical"
|
||||
className="css-52gpmd track-vertical"
|
||||
style={
|
||||
Object {
|
||||
"display": "none",
|
||||
|
||||
@@ -60,17 +60,14 @@ export class DashNav extends PureComponent<Props> {
|
||||
}
|
||||
}
|
||||
|
||||
onOpenSearch = () => {
|
||||
const { dashboard } = this.props;
|
||||
const haveFolder = dashboard.meta.folderId > 0;
|
||||
appEvents.emit(
|
||||
'show-dash-search',
|
||||
haveFolder
|
||||
? {
|
||||
query: 'folder:current',
|
||||
}
|
||||
: null
|
||||
);
|
||||
onDahboardNameClick = () => {
|
||||
appEvents.emit('show-dash-search');
|
||||
};
|
||||
|
||||
onFolderNameClick = () => {
|
||||
appEvents.emit('show-dash-search', {
|
||||
query: 'folder:current',
|
||||
});
|
||||
};
|
||||
|
||||
onClose = () => {
|
||||
@@ -148,11 +145,20 @@ export class DashNav extends PureComponent<Props> {
|
||||
return (
|
||||
<>
|
||||
<div>
|
||||
<a className="navbar-page-btn" onClick={this.onOpenSearch}>
|
||||
<div className="navbar-page-btn">
|
||||
{!this.isInFullscreenOrSettings && <i className="gicon gicon-dashboard" />}
|
||||
{haveFolder && <span className="navbar-page-btn--folder">{folderTitle} / </span>}
|
||||
{dashboard.title} <i className="fa fa-caret-down" />
|
||||
</a>
|
||||
{haveFolder && (
|
||||
<>
|
||||
<a className="navbar-page-btn__folder" onClick={this.onFolderNameClick}>
|
||||
{folderTitle}
|
||||
</a>
|
||||
<i className="fa fa-chevron-right navbar-page-btn__folder-icon" />
|
||||
</>
|
||||
)}
|
||||
<a onClick={this.onDahboardNameClick}>
|
||||
{dashboard.title} <i className="fa fa-caret-down navbar-page-btn__search" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{this.isSettings && <span className="navbar-settings-title"> / Settings</span>}
|
||||
<div className="navbar__spacer" />
|
||||
|
||||
@@ -61,6 +61,7 @@ export interface State {
|
||||
isFullscreen: boolean;
|
||||
fullscreenPanel: PanelModel | null;
|
||||
scrollTop: number;
|
||||
updateScrollTop: number;
|
||||
rememberScrollTop: number;
|
||||
showLoadingState: boolean;
|
||||
}
|
||||
@@ -73,6 +74,7 @@ export class DashboardPage extends PureComponent<Props, State> {
|
||||
showLoadingState: false,
|
||||
fullscreenPanel: null,
|
||||
scrollTop: 0,
|
||||
updateScrollTop: null,
|
||||
rememberScrollTop: 0,
|
||||
};
|
||||
|
||||
@@ -168,7 +170,7 @@ export class DashboardPage extends PureComponent<Props, State> {
|
||||
isEditing: false,
|
||||
isFullscreen: false,
|
||||
fullscreenPanel: null,
|
||||
scrollTop: this.state.rememberScrollTop,
|
||||
updateScrollTop: this.state.rememberScrollTop,
|
||||
},
|
||||
this.triggerPanelsRendering.bind(this)
|
||||
);
|
||||
@@ -204,7 +206,7 @@ export class DashboardPage extends PureComponent<Props, State> {
|
||||
|
||||
setScrollTop = (e: MouseEvent<HTMLElement>): void => {
|
||||
const target = e.target as HTMLElement;
|
||||
this.setState({ scrollTop: target.scrollTop });
|
||||
this.setState({ scrollTop: target.scrollTop, updateScrollTop: null });
|
||||
};
|
||||
|
||||
onAddPanel = () => {
|
||||
@@ -251,7 +253,7 @@ export class DashboardPage extends PureComponent<Props, State> {
|
||||
|
||||
render() {
|
||||
const { dashboard, editview, $injector, isInitSlow, initError } = this.props;
|
||||
const { isSettingsOpening, isEditing, isFullscreen, scrollTop } = this.state;
|
||||
const { isSettingsOpening, isEditing, isFullscreen, scrollTop, updateScrollTop } = this.state;
|
||||
|
||||
if (!dashboard) {
|
||||
if (isInitSlow) {
|
||||
@@ -285,9 +287,9 @@ export class DashboardPage extends PureComponent<Props, State> {
|
||||
/>
|
||||
<div className="scroll-canvas scroll-canvas--dashboard">
|
||||
<CustomScrollbar
|
||||
autoHeightMin={'100%'}
|
||||
autoHeightMin="100%"
|
||||
setScrollTop={this.setScrollTop}
|
||||
scrollTop={scrollTop}
|
||||
scrollTop={updateScrollTop}
|
||||
updateAfterMountMs={500}
|
||||
className="custom-scrollbar--page"
|
||||
>
|
||||
|
||||
@@ -111,7 +111,7 @@ exports[`DashboardPage Dashboard init completed Should render dashboard grid 1`
|
||||
autoHideTimeout={200}
|
||||
className="custom-scrollbar--page"
|
||||
hideTracksWhenNotNeeded={false}
|
||||
scrollTop={0}
|
||||
scrollTop={null}
|
||||
setScrollTop={[Function]}
|
||||
updateAfterMountMs={500}
|
||||
>
|
||||
@@ -349,7 +349,7 @@ exports[`DashboardPage When dashboard has editview url state should render setti
|
||||
autoHideTimeout={200}
|
||||
className="custom-scrollbar--page"
|
||||
hideTracksWhenNotNeeded={false}
|
||||
scrollTop={0}
|
||||
scrollTop={null}
|
||||
setScrollTop={[Function]}
|
||||
updateAfterMountMs={500}
|
||||
>
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
import React from 'react';
|
||||
import { shallow, ShallowWrapper } from 'enzyme';
|
||||
import { DashboardGrid, Props } from './DashboardGrid';
|
||||
import { DashboardModel } from '../state';
|
||||
|
||||
interface ScenarioContext {
|
||||
props: Props;
|
||||
wrapper?: ShallowWrapper<Props, any, DashboardGrid>;
|
||||
setup?: (fn: () => void) => void;
|
||||
setProps: (props: Partial<Props>) => void;
|
||||
}
|
||||
|
||||
function getTestDashboard(overrides?: any, metaOverrides?: any): DashboardModel {
|
||||
const data = Object.assign(
|
||||
{
|
||||
title: 'My dashboard',
|
||||
panels: [
|
||||
{
|
||||
id: 1,
|
||||
type: 'graph',
|
||||
title: 'My graph',
|
||||
gridPos: { x: 0, y: 0, w: 24, h: 10 },
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
type: 'graph2',
|
||||
title: 'My graph2',
|
||||
gridPos: { x: 0, y: 10, w: 25, h: 10 },
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
type: 'graph3',
|
||||
title: 'My graph3',
|
||||
gridPos: { x: 0, y: 20, w: 25, h: 100 },
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
type: 'graph4',
|
||||
title: 'My graph4',
|
||||
gridPos: { x: 0, y: 120, w: 25, h: 10 },
|
||||
},
|
||||
],
|
||||
},
|
||||
overrides
|
||||
);
|
||||
|
||||
const meta = Object.assign({ canSave: true, canEdit: true }, metaOverrides);
|
||||
return new DashboardModel(data, meta);
|
||||
}
|
||||
|
||||
function dashboardGridScenario(description, scenarioFn: (ctx: ScenarioContext) => void) {
|
||||
describe(description, () => {
|
||||
let setupFn: () => void;
|
||||
|
||||
const ctx: ScenarioContext = {
|
||||
setup: fn => {
|
||||
setupFn = fn;
|
||||
},
|
||||
props: {
|
||||
isEditing: false,
|
||||
isFullscreen: false,
|
||||
scrollTop: null,
|
||||
dashboard: getTestDashboard(),
|
||||
},
|
||||
setProps: (props: Partial<Props>) => {
|
||||
Object.assign(ctx.props, props);
|
||||
if (ctx.wrapper) {
|
||||
ctx.wrapper.setProps(ctx.props);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
setupFn();
|
||||
ctx.wrapper = shallow(<DashboardGrid {...ctx.props} />);
|
||||
});
|
||||
|
||||
scenarioFn(ctx);
|
||||
});
|
||||
}
|
||||
|
||||
describe('DashboardGrid', () => {
|
||||
dashboardGridScenario('Can render dashboard grid', ctx => {
|
||||
ctx.setup(() => {});
|
||||
|
||||
it('Should render', () => {
|
||||
expect(ctx.wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -205,7 +205,7 @@ export class DashboardGrid extends PureComponent<Props> {
|
||||
return false;
|
||||
}
|
||||
|
||||
const top = parseInt(elem.style.top.replace('px', ''), 10);
|
||||
const top = elem.offsetTop;
|
||||
const height = panel.gridPos.h * GRID_CELL_HEIGHT + 40;
|
||||
const bottom = top + height;
|
||||
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
import { react2AngularDirective } from 'app/core/utils/react2angular';
|
||||
import DashboardGrid from './DashboardGrid';
|
||||
|
||||
react2AngularDirective('dashboardGrid', DashboardGrid, [['dashboard', { watchDepth: 'reference' }]]);
|
||||
@@ -250,9 +250,10 @@ export class PanelChrome extends PureComponent<Props, State> {
|
||||
{loading === LoadingState.Loading && this.renderLoadingState()}
|
||||
<div className="panel-content">
|
||||
<PanelComponent
|
||||
id={panel.id}
|
||||
data={data}
|
||||
timeRange={data.request ? data.request.range : this.timeSrv.timeRange()}
|
||||
options={panel.getOptions(plugin.defaults)}
|
||||
options={panel.getOptions()}
|
||||
width={width - theme.panelPadding * 2}
|
||||
height={innerPanelHeight}
|
||||
renderCounter={renderCounter}
|
||||
|
||||
@@ -81,16 +81,21 @@ export class PanelHeader extends Component<Props, State> {
|
||||
|
||||
return (
|
||||
<>
|
||||
<PanelHeaderCorner
|
||||
panel={panel}
|
||||
title={panel.title}
|
||||
description={panel.description}
|
||||
scopedVars={panel.scopedVars}
|
||||
links={panel.links}
|
||||
error={error}
|
||||
/>
|
||||
<div className={panelHeaderClass}>
|
||||
<div className="panel-title-container" onClick={this.onMenuToggle} onMouseDown={this.onMouseDown}>
|
||||
<PanelHeaderCorner
|
||||
panel={panel}
|
||||
title={panel.title}
|
||||
description={panel.description}
|
||||
scopedVars={panel.scopedVars}
|
||||
links={panel.links}
|
||||
error={error}
|
||||
/>
|
||||
<div
|
||||
className="panel-title-container"
|
||||
onClick={this.onMenuToggle}
|
||||
onMouseDown={this.onMouseDown}
|
||||
aria-label="Panel Title"
|
||||
>
|
||||
<div className="panel-title">
|
||||
<span className="icon-gf panel-alert-icon" />
|
||||
<span className="panel-title-text">
|
||||
|
||||
@@ -0,0 +1,996 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
|
||||
<SizeMe(GridWrapper)
|
||||
className="layout"
|
||||
isDraggable={true}
|
||||
isFullscreen={false}
|
||||
isResizable={true}
|
||||
layout={
|
||||
Array [
|
||||
Object {
|
||||
"h": 10,
|
||||
"i": "1",
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
},
|
||||
Object {
|
||||
"h": 10,
|
||||
"i": "2",
|
||||
"w": 25,
|
||||
"x": 0,
|
||||
"y": 10,
|
||||
},
|
||||
Object {
|
||||
"h": 100,
|
||||
"i": "3",
|
||||
"w": 25,
|
||||
"x": 0,
|
||||
"y": 20,
|
||||
},
|
||||
Object {
|
||||
"h": 10,
|
||||
"i": "4",
|
||||
"w": 25,
|
||||
"x": 0,
|
||||
"y": 120,
|
||||
},
|
||||
]
|
||||
}
|
||||
onDragStop={[Function]}
|
||||
onLayoutChange={[Function]}
|
||||
onResize={[Function]}
|
||||
onResizeStop={[Function]}
|
||||
onWidthChange={[Function]}
|
||||
>
|
||||
<div
|
||||
className=""
|
||||
id="panel-1"
|
||||
key="1"
|
||||
>
|
||||
<DashboardPanel
|
||||
dashboard={
|
||||
DashboardModel {
|
||||
"annotations": Object {
|
||||
"list": Array [
|
||||
Object {
|
||||
"builtIn": 1,
|
||||
"datasource": "-- Grafana --",
|
||||
"enable": true,
|
||||
"hide": true,
|
||||
"iconColor": "rgba(0, 211, 255, 1)",
|
||||
"name": "Annotations & Alerts",
|
||||
"type": "dashboard",
|
||||
},
|
||||
],
|
||||
},
|
||||
"autoUpdate": undefined,
|
||||
"description": undefined,
|
||||
"editable": true,
|
||||
"events": Emitter {
|
||||
"emitter": EventEmitter {
|
||||
"_events": Object {
|
||||
"panel-added": EE {
|
||||
"context": [Circular],
|
||||
"fn": [Function],
|
||||
"once": false,
|
||||
},
|
||||
"panel-removed": EE {
|
||||
"context": [Circular],
|
||||
"fn": [Function],
|
||||
"once": false,
|
||||
},
|
||||
"repeats-processed": EE {
|
||||
"context": [Circular],
|
||||
"fn": [Function],
|
||||
"once": false,
|
||||
},
|
||||
"row-collapsed": EE {
|
||||
"context": [Circular],
|
||||
"fn": [Function],
|
||||
"once": false,
|
||||
},
|
||||
"row-expanded": EE {
|
||||
"context": [Circular],
|
||||
"fn": [Function],
|
||||
"once": false,
|
||||
},
|
||||
"view-mode-changed": EE {
|
||||
"context": [Circular],
|
||||
"fn": [Function],
|
||||
"once": false,
|
||||
},
|
||||
},
|
||||
"_eventsCount": 6,
|
||||
},
|
||||
},
|
||||
"gnetId": null,
|
||||
"graphTooltip": 0,
|
||||
"id": null,
|
||||
"links": Array [],
|
||||
"meta": Object {
|
||||
"canEdit": true,
|
||||
"canMakeEditable": false,
|
||||
"canSave": true,
|
||||
"canShare": true,
|
||||
"canStar": true,
|
||||
"fullscreen": false,
|
||||
"isEditing": false,
|
||||
"showSettings": true,
|
||||
},
|
||||
"originalTemplating": Array [],
|
||||
"originalTime": Object {
|
||||
"from": "now-6h",
|
||||
"to": "now",
|
||||
},
|
||||
"panels": Array [
|
||||
PanelModel {
|
||||
"cachedPluginOptions": Object {},
|
||||
"datasource": null,
|
||||
"events": Emitter {
|
||||
"emitter": EventEmitter {
|
||||
"_events": Object {},
|
||||
"_eventsCount": 0,
|
||||
},
|
||||
},
|
||||
"gridPos": Object {
|
||||
"h": 10,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
},
|
||||
"id": 1,
|
||||
"isInView": false,
|
||||
"targets": Array [
|
||||
Object {
|
||||
"refId": "A",
|
||||
},
|
||||
],
|
||||
"title": "My graph",
|
||||
"transparent": false,
|
||||
"type": "graph",
|
||||
},
|
||||
PanelModel {
|
||||
"cachedPluginOptions": Object {},
|
||||
"datasource": null,
|
||||
"events": Emitter {
|
||||
"emitter": EventEmitter {
|
||||
"_events": Object {},
|
||||
"_eventsCount": 0,
|
||||
},
|
||||
},
|
||||
"gridPos": Object {
|
||||
"h": 10,
|
||||
"w": 25,
|
||||
"x": 0,
|
||||
"y": 10,
|
||||
},
|
||||
"id": 2,
|
||||
"isInView": false,
|
||||
"targets": Array [
|
||||
Object {
|
||||
"refId": "A",
|
||||
},
|
||||
],
|
||||
"title": "My graph2",
|
||||
"transparent": false,
|
||||
"type": "graph2",
|
||||
},
|
||||
PanelModel {
|
||||
"cachedPluginOptions": Object {},
|
||||
"datasource": null,
|
||||
"events": Emitter {
|
||||
"emitter": EventEmitter {
|
||||
"_events": Object {},
|
||||
"_eventsCount": 0,
|
||||
},
|
||||
},
|
||||
"gridPos": Object {
|
||||
"h": 100,
|
||||
"w": 25,
|
||||
"x": 0,
|
||||
"y": 20,
|
||||
},
|
||||
"id": 3,
|
||||
"isInView": false,
|
||||
"targets": Array [
|
||||
Object {
|
||||
"refId": "A",
|
||||
},
|
||||
],
|
||||
"title": "My graph3",
|
||||
"transparent": false,
|
||||
"type": "graph3",
|
||||
},
|
||||
PanelModel {
|
||||
"cachedPluginOptions": Object {},
|
||||
"datasource": null,
|
||||
"events": Emitter {
|
||||
"emitter": EventEmitter {
|
||||
"_events": Object {},
|
||||
"_eventsCount": 0,
|
||||
},
|
||||
},
|
||||
"gridPos": Object {
|
||||
"h": 10,
|
||||
"w": 25,
|
||||
"x": 0,
|
||||
"y": 120,
|
||||
},
|
||||
"id": 4,
|
||||
"isInView": false,
|
||||
"targets": Array [
|
||||
Object {
|
||||
"refId": "A",
|
||||
},
|
||||
],
|
||||
"title": "My graph4",
|
||||
"transparent": false,
|
||||
"type": "graph4",
|
||||
},
|
||||
],
|
||||
"refresh": undefined,
|
||||
"revision": undefined,
|
||||
"schemaVersion": 18,
|
||||
"snapshot": undefined,
|
||||
"style": "dark",
|
||||
"tags": Array [],
|
||||
"templating": Object {
|
||||
"list": Array [],
|
||||
},
|
||||
"time": Object {
|
||||
"from": "now-6h",
|
||||
"to": "now",
|
||||
},
|
||||
"timepicker": Object {},
|
||||
"timezone": "",
|
||||
"title": "My dashboard",
|
||||
"uid": null,
|
||||
"version": 0,
|
||||
}
|
||||
}
|
||||
isInView={false}
|
||||
panel={
|
||||
PanelModel {
|
||||
"cachedPluginOptions": Object {},
|
||||
"datasource": null,
|
||||
"events": Emitter {
|
||||
"emitter": EventEmitter {
|
||||
"_events": Object {},
|
||||
"_eventsCount": 0,
|
||||
},
|
||||
},
|
||||
"gridPos": Object {
|
||||
"h": 10,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
},
|
||||
"id": 1,
|
||||
"isInView": false,
|
||||
"targets": Array [
|
||||
Object {
|
||||
"refId": "A",
|
||||
},
|
||||
],
|
||||
"title": "My graph",
|
||||
"transparent": false,
|
||||
"type": "graph",
|
||||
}
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className=""
|
||||
id="panel-2"
|
||||
key="2"
|
||||
>
|
||||
<DashboardPanel
|
||||
dashboard={
|
||||
DashboardModel {
|
||||
"annotations": Object {
|
||||
"list": Array [
|
||||
Object {
|
||||
"builtIn": 1,
|
||||
"datasource": "-- Grafana --",
|
||||
"enable": true,
|
||||
"hide": true,
|
||||
"iconColor": "rgba(0, 211, 255, 1)",
|
||||
"name": "Annotations & Alerts",
|
||||
"type": "dashboard",
|
||||
},
|
||||
],
|
||||
},
|
||||
"autoUpdate": undefined,
|
||||
"description": undefined,
|
||||
"editable": true,
|
||||
"events": Emitter {
|
||||
"emitter": EventEmitter {
|
||||
"_events": Object {
|
||||
"panel-added": EE {
|
||||
"context": [Circular],
|
||||
"fn": [Function],
|
||||
"once": false,
|
||||
},
|
||||
"panel-removed": EE {
|
||||
"context": [Circular],
|
||||
"fn": [Function],
|
||||
"once": false,
|
||||
},
|
||||
"repeats-processed": EE {
|
||||
"context": [Circular],
|
||||
"fn": [Function],
|
||||
"once": false,
|
||||
},
|
||||
"row-collapsed": EE {
|
||||
"context": [Circular],
|
||||
"fn": [Function],
|
||||
"once": false,
|
||||
},
|
||||
"row-expanded": EE {
|
||||
"context": [Circular],
|
||||
"fn": [Function],
|
||||
"once": false,
|
||||
},
|
||||
"view-mode-changed": EE {
|
||||
"context": [Circular],
|
||||
"fn": [Function],
|
||||
"once": false,
|
||||
},
|
||||
},
|
||||
"_eventsCount": 6,
|
||||
},
|
||||
},
|
||||
"gnetId": null,
|
||||
"graphTooltip": 0,
|
||||
"id": null,
|
||||
"links": Array [],
|
||||
"meta": Object {
|
||||
"canEdit": true,
|
||||
"canMakeEditable": false,
|
||||
"canSave": true,
|
||||
"canShare": true,
|
||||
"canStar": true,
|
||||
"fullscreen": false,
|
||||
"isEditing": false,
|
||||
"showSettings": true,
|
||||
},
|
||||
"originalTemplating": Array [],
|
||||
"originalTime": Object {
|
||||
"from": "now-6h",
|
||||
"to": "now",
|
||||
},
|
||||
"panels": Array [
|
||||
PanelModel {
|
||||
"cachedPluginOptions": Object {},
|
||||
"datasource": null,
|
||||
"events": Emitter {
|
||||
"emitter": EventEmitter {
|
||||
"_events": Object {},
|
||||
"_eventsCount": 0,
|
||||
},
|
||||
},
|
||||
"gridPos": Object {
|
||||
"h": 10,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
},
|
||||
"id": 1,
|
||||
"isInView": false,
|
||||
"targets": Array [
|
||||
Object {
|
||||
"refId": "A",
|
||||
},
|
||||
],
|
||||
"title": "My graph",
|
||||
"transparent": false,
|
||||
"type": "graph",
|
||||
},
|
||||
PanelModel {
|
||||
"cachedPluginOptions": Object {},
|
||||
"datasource": null,
|
||||
"events": Emitter {
|
||||
"emitter": EventEmitter {
|
||||
"_events": Object {},
|
||||
"_eventsCount": 0,
|
||||
},
|
||||
},
|
||||
"gridPos": Object {
|
||||
"h": 10,
|
||||
"w": 25,
|
||||
"x": 0,
|
||||
"y": 10,
|
||||
},
|
||||
"id": 2,
|
||||
"isInView": false,
|
||||
"targets": Array [
|
||||
Object {
|
||||
"refId": "A",
|
||||
},
|
||||
],
|
||||
"title": "My graph2",
|
||||
"transparent": false,
|
||||
"type": "graph2",
|
||||
},
|
||||
PanelModel {
|
||||
"cachedPluginOptions": Object {},
|
||||
"datasource": null,
|
||||
"events": Emitter {
|
||||
"emitter": EventEmitter {
|
||||
"_events": Object {},
|
||||
"_eventsCount": 0,
|
||||
},
|
||||
},
|
||||
"gridPos": Object {
|
||||
"h": 100,
|
||||
"w": 25,
|
||||
"x": 0,
|
||||
"y": 20,
|
||||
},
|
||||
"id": 3,
|
||||
"isInView": false,
|
||||
"targets": Array [
|
||||
Object {
|
||||
"refId": "A",
|
||||
},
|
||||
],
|
||||
"title": "My graph3",
|
||||
"transparent": false,
|
||||
"type": "graph3",
|
||||
},
|
||||
PanelModel {
|
||||
"cachedPluginOptions": Object {},
|
||||
"datasource": null,
|
||||
"events": Emitter {
|
||||
"emitter": EventEmitter {
|
||||
"_events": Object {},
|
||||
"_eventsCount": 0,
|
||||
},
|
||||
},
|
||||
"gridPos": Object {
|
||||
"h": 10,
|
||||
"w": 25,
|
||||
"x": 0,
|
||||
"y": 120,
|
||||
},
|
||||
"id": 4,
|
||||
"isInView": false,
|
||||
"targets": Array [
|
||||
Object {
|
||||
"refId": "A",
|
||||
},
|
||||
],
|
||||
"title": "My graph4",
|
||||
"transparent": false,
|
||||
"type": "graph4",
|
||||
},
|
||||
],
|
||||
"refresh": undefined,
|
||||
"revision": undefined,
|
||||
"schemaVersion": 18,
|
||||
"snapshot": undefined,
|
||||
"style": "dark",
|
||||
"tags": Array [],
|
||||
"templating": Object {
|
||||
"list": Array [],
|
||||
},
|
||||
"time": Object {
|
||||
"from": "now-6h",
|
||||
"to": "now",
|
||||
},
|
||||
"timepicker": Object {},
|
||||
"timezone": "",
|
||||
"title": "My dashboard",
|
||||
"uid": null,
|
||||
"version": 0,
|
||||
}
|
||||
}
|
||||
isInView={false}
|
||||
panel={
|
||||
PanelModel {
|
||||
"cachedPluginOptions": Object {},
|
||||
"datasource": null,
|
||||
"events": Emitter {
|
||||
"emitter": EventEmitter {
|
||||
"_events": Object {},
|
||||
"_eventsCount": 0,
|
||||
},
|
||||
},
|
||||
"gridPos": Object {
|
||||
"h": 10,
|
||||
"w": 25,
|
||||
"x": 0,
|
||||
"y": 10,
|
||||
},
|
||||
"id": 2,
|
||||
"isInView": false,
|
||||
"targets": Array [
|
||||
Object {
|
||||
"refId": "A",
|
||||
},
|
||||
],
|
||||
"title": "My graph2",
|
||||
"transparent": false,
|
||||
"type": "graph2",
|
||||
}
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className=""
|
||||
id="panel-3"
|
||||
key="3"
|
||||
>
|
||||
<DashboardPanel
|
||||
dashboard={
|
||||
DashboardModel {
|
||||
"annotations": Object {
|
||||
"list": Array [
|
||||
Object {
|
||||
"builtIn": 1,
|
||||
"datasource": "-- Grafana --",
|
||||
"enable": true,
|
||||
"hide": true,
|
||||
"iconColor": "rgba(0, 211, 255, 1)",
|
||||
"name": "Annotations & Alerts",
|
||||
"type": "dashboard",
|
||||
},
|
||||
],
|
||||
},
|
||||
"autoUpdate": undefined,
|
||||
"description": undefined,
|
||||
"editable": true,
|
||||
"events": Emitter {
|
||||
"emitter": EventEmitter {
|
||||
"_events": Object {
|
||||
"panel-added": EE {
|
||||
"context": [Circular],
|
||||
"fn": [Function],
|
||||
"once": false,
|
||||
},
|
||||
"panel-removed": EE {
|
||||
"context": [Circular],
|
||||
"fn": [Function],
|
||||
"once": false,
|
||||
},
|
||||
"repeats-processed": EE {
|
||||
"context": [Circular],
|
||||
"fn": [Function],
|
||||
"once": false,
|
||||
},
|
||||
"row-collapsed": EE {
|
||||
"context": [Circular],
|
||||
"fn": [Function],
|
||||
"once": false,
|
||||
},
|
||||
"row-expanded": EE {
|
||||
"context": [Circular],
|
||||
"fn": [Function],
|
||||
"once": false,
|
||||
},
|
||||
"view-mode-changed": EE {
|
||||
"context": [Circular],
|
||||
"fn": [Function],
|
||||
"once": false,
|
||||
},
|
||||
},
|
||||
"_eventsCount": 6,
|
||||
},
|
||||
},
|
||||
"gnetId": null,
|
||||
"graphTooltip": 0,
|
||||
"id": null,
|
||||
"links": Array [],
|
||||
"meta": Object {
|
||||
"canEdit": true,
|
||||
"canMakeEditable": false,
|
||||
"canSave": true,
|
||||
"canShare": true,
|
||||
"canStar": true,
|
||||
"fullscreen": false,
|
||||
"isEditing": false,
|
||||
"showSettings": true,
|
||||
},
|
||||
"originalTemplating": Array [],
|
||||
"originalTime": Object {
|
||||
"from": "now-6h",
|
||||
"to": "now",
|
||||
},
|
||||
"panels": Array [
|
||||
PanelModel {
|
||||
"cachedPluginOptions": Object {},
|
||||
"datasource": null,
|
||||
"events": Emitter {
|
||||
"emitter": EventEmitter {
|
||||
"_events": Object {},
|
||||
"_eventsCount": 0,
|
||||
},
|
||||
},
|
||||
"gridPos": Object {
|
||||
"h": 10,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
},
|
||||
"id": 1,
|
||||
"isInView": false,
|
||||
"targets": Array [
|
||||
Object {
|
||||
"refId": "A",
|
||||
},
|
||||
],
|
||||
"title": "My graph",
|
||||
"transparent": false,
|
||||
"type": "graph",
|
||||
},
|
||||
PanelModel {
|
||||
"cachedPluginOptions": Object {},
|
||||
"datasource": null,
|
||||
"events": Emitter {
|
||||
"emitter": EventEmitter {
|
||||
"_events": Object {},
|
||||
"_eventsCount": 0,
|
||||
},
|
||||
},
|
||||
"gridPos": Object {
|
||||
"h": 10,
|
||||
"w": 25,
|
||||
"x": 0,
|
||||
"y": 10,
|
||||
},
|
||||
"id": 2,
|
||||
"isInView": false,
|
||||
"targets": Array [
|
||||
Object {
|
||||
"refId": "A",
|
||||
},
|
||||
],
|
||||
"title": "My graph2",
|
||||
"transparent": false,
|
||||
"type": "graph2",
|
||||
},
|
||||
PanelModel {
|
||||
"cachedPluginOptions": Object {},
|
||||
"datasource": null,
|
||||
"events": Emitter {
|
||||
"emitter": EventEmitter {
|
||||
"_events": Object {},
|
||||
"_eventsCount": 0,
|
||||
},
|
||||
},
|
||||
"gridPos": Object {
|
||||
"h": 100,
|
||||
"w": 25,
|
||||
"x": 0,
|
||||
"y": 20,
|
||||
},
|
||||
"id": 3,
|
||||
"isInView": false,
|
||||
"targets": Array [
|
||||
Object {
|
||||
"refId": "A",
|
||||
},
|
||||
],
|
||||
"title": "My graph3",
|
||||
"transparent": false,
|
||||
"type": "graph3",
|
||||
},
|
||||
PanelModel {
|
||||
"cachedPluginOptions": Object {},
|
||||
"datasource": null,
|
||||
"events": Emitter {
|
||||
"emitter": EventEmitter {
|
||||
"_events": Object {},
|
||||
"_eventsCount": 0,
|
||||
},
|
||||
},
|
||||
"gridPos": Object {
|
||||
"h": 10,
|
||||
"w": 25,
|
||||
"x": 0,
|
||||
"y": 120,
|
||||
},
|
||||
"id": 4,
|
||||
"isInView": false,
|
||||
"targets": Array [
|
||||
Object {
|
||||
"refId": "A",
|
||||
},
|
||||
],
|
||||
"title": "My graph4",
|
||||
"transparent": false,
|
||||
"type": "graph4",
|
||||
},
|
||||
],
|
||||
"refresh": undefined,
|
||||
"revision": undefined,
|
||||
"schemaVersion": 18,
|
||||
"snapshot": undefined,
|
||||
"style": "dark",
|
||||
"tags": Array [],
|
||||
"templating": Object {
|
||||
"list": Array [],
|
||||
},
|
||||
"time": Object {
|
||||
"from": "now-6h",
|
||||
"to": "now",
|
||||
},
|
||||
"timepicker": Object {},
|
||||
"timezone": "",
|
||||
"title": "My dashboard",
|
||||
"uid": null,
|
||||
"version": 0,
|
||||
}
|
||||
}
|
||||
isInView={false}
|
||||
panel={
|
||||
PanelModel {
|
||||
"cachedPluginOptions": Object {},
|
||||
"datasource": null,
|
||||
"events": Emitter {
|
||||
"emitter": EventEmitter {
|
||||
"_events": Object {},
|
||||
"_eventsCount": 0,
|
||||
},
|
||||
},
|
||||
"gridPos": Object {
|
||||
"h": 100,
|
||||
"w": 25,
|
||||
"x": 0,
|
||||
"y": 20,
|
||||
},
|
||||
"id": 3,
|
||||
"isInView": false,
|
||||
"targets": Array [
|
||||
Object {
|
||||
"refId": "A",
|
||||
},
|
||||
],
|
||||
"title": "My graph3",
|
||||
"transparent": false,
|
||||
"type": "graph3",
|
||||
}
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className=""
|
||||
id="panel-4"
|
||||
key="4"
|
||||
>
|
||||
<DashboardPanel
|
||||
dashboard={
|
||||
DashboardModel {
|
||||
"annotations": Object {
|
||||
"list": Array [
|
||||
Object {
|
||||
"builtIn": 1,
|
||||
"datasource": "-- Grafana --",
|
||||
"enable": true,
|
||||
"hide": true,
|
||||
"iconColor": "rgba(0, 211, 255, 1)",
|
||||
"name": "Annotations & Alerts",
|
||||
"type": "dashboard",
|
||||
},
|
||||
],
|
||||
},
|
||||
"autoUpdate": undefined,
|
||||
"description": undefined,
|
||||
"editable": true,
|
||||
"events": Emitter {
|
||||
"emitter": EventEmitter {
|
||||
"_events": Object {
|
||||
"panel-added": EE {
|
||||
"context": [Circular],
|
||||
"fn": [Function],
|
||||
"once": false,
|
||||
},
|
||||
"panel-removed": EE {
|
||||
"context": [Circular],
|
||||
"fn": [Function],
|
||||
"once": false,
|
||||
},
|
||||
"repeats-processed": EE {
|
||||
"context": [Circular],
|
||||
"fn": [Function],
|
||||
"once": false,
|
||||
},
|
||||
"row-collapsed": EE {
|
||||
"context": [Circular],
|
||||
"fn": [Function],
|
||||
"once": false,
|
||||
},
|
||||
"row-expanded": EE {
|
||||
"context": [Circular],
|
||||
"fn": [Function],
|
||||
"once": false,
|
||||
},
|
||||
"view-mode-changed": EE {
|
||||
"context": [Circular],
|
||||
"fn": [Function],
|
||||
"once": false,
|
||||
},
|
||||
},
|
||||
"_eventsCount": 6,
|
||||
},
|
||||
},
|
||||
"gnetId": null,
|
||||
"graphTooltip": 0,
|
||||
"id": null,
|
||||
"links": Array [],
|
||||
"meta": Object {
|
||||
"canEdit": true,
|
||||
"canMakeEditable": false,
|
||||
"canSave": true,
|
||||
"canShare": true,
|
||||
"canStar": true,
|
||||
"fullscreen": false,
|
||||
"isEditing": false,
|
||||
"showSettings": true,
|
||||
},
|
||||
"originalTemplating": Array [],
|
||||
"originalTime": Object {
|
||||
"from": "now-6h",
|
||||
"to": "now",
|
||||
},
|
||||
"panels": Array [
|
||||
PanelModel {
|
||||
"cachedPluginOptions": Object {},
|
||||
"datasource": null,
|
||||
"events": Emitter {
|
||||
"emitter": EventEmitter {
|
||||
"_events": Object {},
|
||||
"_eventsCount": 0,
|
||||
},
|
||||
},
|
||||
"gridPos": Object {
|
||||
"h": 10,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
},
|
||||
"id": 1,
|
||||
"isInView": false,
|
||||
"targets": Array [
|
||||
Object {
|
||||
"refId": "A",
|
||||
},
|
||||
],
|
||||
"title": "My graph",
|
||||
"transparent": false,
|
||||
"type": "graph",
|
||||
},
|
||||
PanelModel {
|
||||
"cachedPluginOptions": Object {},
|
||||
"datasource": null,
|
||||
"events": Emitter {
|
||||
"emitter": EventEmitter {
|
||||
"_events": Object {},
|
||||
"_eventsCount": 0,
|
||||
},
|
||||
},
|
||||
"gridPos": Object {
|
||||
"h": 10,
|
||||
"w": 25,
|
||||
"x": 0,
|
||||
"y": 10,
|
||||
},
|
||||
"id": 2,
|
||||
"isInView": false,
|
||||
"targets": Array [
|
||||
Object {
|
||||
"refId": "A",
|
||||
},
|
||||
],
|
||||
"title": "My graph2",
|
||||
"transparent": false,
|
||||
"type": "graph2",
|
||||
},
|
||||
PanelModel {
|
||||
"cachedPluginOptions": Object {},
|
||||
"datasource": null,
|
||||
"events": Emitter {
|
||||
"emitter": EventEmitter {
|
||||
"_events": Object {},
|
||||
"_eventsCount": 0,
|
||||
},
|
||||
},
|
||||
"gridPos": Object {
|
||||
"h": 100,
|
||||
"w": 25,
|
||||
"x": 0,
|
||||
"y": 20,
|
||||
},
|
||||
"id": 3,
|
||||
"isInView": false,
|
||||
"targets": Array [
|
||||
Object {
|
||||
"refId": "A",
|
||||
},
|
||||
],
|
||||
"title": "My graph3",
|
||||
"transparent": false,
|
||||
"type": "graph3",
|
||||
},
|
||||
PanelModel {
|
||||
"cachedPluginOptions": Object {},
|
||||
"datasource": null,
|
||||
"events": Emitter {
|
||||
"emitter": EventEmitter {
|
||||
"_events": Object {},
|
||||
"_eventsCount": 0,
|
||||
},
|
||||
},
|
||||
"gridPos": Object {
|
||||
"h": 10,
|
||||
"w": 25,
|
||||
"x": 0,
|
||||
"y": 120,
|
||||
},
|
||||
"id": 4,
|
||||
"isInView": false,
|
||||
"targets": Array [
|
||||
Object {
|
||||
"refId": "A",
|
||||
},
|
||||
],
|
||||
"title": "My graph4",
|
||||
"transparent": false,
|
||||
"type": "graph4",
|
||||
},
|
||||
],
|
||||
"refresh": undefined,
|
||||
"revision": undefined,
|
||||
"schemaVersion": 18,
|
||||
"snapshot": undefined,
|
||||
"style": "dark",
|
||||
"tags": Array [],
|
||||
"templating": Object {
|
||||
"list": Array [],
|
||||
},
|
||||
"time": Object {
|
||||
"from": "now-6h",
|
||||
"to": "now",
|
||||
},
|
||||
"timepicker": Object {},
|
||||
"timezone": "",
|
||||
"title": "My dashboard",
|
||||
"uid": null,
|
||||
"version": 0,
|
||||
}
|
||||
}
|
||||
isInView={false}
|
||||
panel={
|
||||
PanelModel {
|
||||
"cachedPluginOptions": Object {},
|
||||
"datasource": null,
|
||||
"events": Emitter {
|
||||
"emitter": EventEmitter {
|
||||
"_events": Object {},
|
||||
"_eventsCount": 0,
|
||||
},
|
||||
},
|
||||
"gridPos": Object {
|
||||
"h": 10,
|
||||
"w": 25,
|
||||
"x": 0,
|
||||
"y": 120,
|
||||
},
|
||||
"id": 4,
|
||||
"isInView": false,
|
||||
"targets": Array [
|
||||
Object {
|
||||
"refId": "A",
|
||||
},
|
||||
],
|
||||
"title": "My graph4",
|
||||
"transparent": false,
|
||||
"type": "graph4",
|
||||
}
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</SizeMe(GridWrapper)>
|
||||
`;
|
||||
@@ -1,5 +1,3 @@
|
||||
import './dashgrid/DashboardGridDirective';
|
||||
|
||||
// Services
|
||||
import './services/UnsavedChangesSrv';
|
||||
import './services/DashboardLoaderSrv';
|
||||
|
||||
@@ -53,8 +53,8 @@ export class VisualizationTab extends PureComponent<Props, State> {
|
||||
}
|
||||
|
||||
getReactPanelOptions = () => {
|
||||
const { panel, plugin } = this.props;
|
||||
return panel.getOptions(plugin.defaults);
|
||||
const { panel } = this.props;
|
||||
return panel.getOptions();
|
||||
};
|
||||
|
||||
renderPanelOptions() {
|
||||
|
||||
@@ -7,45 +7,70 @@ describe('PanelModel', () => {
|
||||
describe('when creating new panel model', () => {
|
||||
let model;
|
||||
let modelJson;
|
||||
let persistedOptionsMock;
|
||||
const defaultOptionsMock = {
|
||||
fieldOptions: {
|
||||
thresholds: [
|
||||
{
|
||||
color: '#F2495C',
|
||||
index: 1,
|
||||
value: 50,
|
||||
},
|
||||
{
|
||||
color: '#73BF69',
|
||||
index: 0,
|
||||
value: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
showThresholds: true,
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
persistedOptionsMock = {
|
||||
fieldOptions: {
|
||||
thresholds: [
|
||||
{
|
||||
color: '#F2495C',
|
||||
index: 1,
|
||||
value: 50,
|
||||
},
|
||||
{
|
||||
color: '#73BF69',
|
||||
index: 0,
|
||||
value: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
modelJson = {
|
||||
type: 'table',
|
||||
showColumns: true,
|
||||
targets: [{ refId: 'A' }, { noRefId: true }],
|
||||
options: {
|
||||
fieldOptions: {
|
||||
thresholds: [
|
||||
{
|
||||
color: '#F2495C',
|
||||
index: 1,
|
||||
value: 50,
|
||||
},
|
||||
{
|
||||
color: '#73BF69',
|
||||
index: 0,
|
||||
value: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
options: persistedOptionsMock,
|
||||
};
|
||||
|
||||
model = new PanelModel(modelJson);
|
||||
model.pluginLoaded(
|
||||
getPanelPlugin(
|
||||
{
|
||||
id: 'table',
|
||||
},
|
||||
null, // react
|
||||
TablePanelCtrl // angular
|
||||
)
|
||||
const panelPlugin = getPanelPlugin(
|
||||
{
|
||||
id: 'table',
|
||||
},
|
||||
null, // react
|
||||
TablePanelCtrl // angular
|
||||
);
|
||||
panelPlugin.setDefaults(defaultOptionsMock);
|
||||
model.pluginLoaded(panelPlugin);
|
||||
});
|
||||
|
||||
it('should apply defaults', () => {
|
||||
expect(model.gridPos.h).toBe(3);
|
||||
});
|
||||
|
||||
it('should apply option defaults', () => {
|
||||
expect(model.getOptions().showThresholds).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should set model props on instance', () => {
|
||||
expect(model.showColumns).toBe(true);
|
||||
});
|
||||
@@ -89,11 +114,22 @@ describe('PanelModel', () => {
|
||||
});
|
||||
|
||||
describe('when changing panel type', () => {
|
||||
const newPanelPluginDefaults = {
|
||||
showThresholdLabels: false,
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
model.changePlugin(getPanelPlugin({ id: 'graph' }));
|
||||
const newPlugin = getPanelPlugin({ id: 'graph' });
|
||||
newPlugin.setDefaults(newPanelPluginDefaults);
|
||||
model.changePlugin(newPlugin);
|
||||
model.alert = { id: 2 };
|
||||
});
|
||||
|
||||
it('should apply next panel option defaults', () => {
|
||||
expect(model.getOptions().showThresholdLabels).toBeFalsy();
|
||||
expect(model.getOptions().showThresholds).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should remove table properties but keep core props', () => {
|
||||
expect(model.showColumns).toBe(undefined);
|
||||
});
|
||||
@@ -153,19 +189,5 @@ describe('PanelModel', () => {
|
||||
expect(panelQueryRunner).toBe(sameQueryRunner);
|
||||
});
|
||||
});
|
||||
|
||||
describe('get panel options', () => {
|
||||
it('should apply defaults', () => {
|
||||
model.options = { existingProp: 10 };
|
||||
const options = model.getOptions({
|
||||
defaultProp: true,
|
||||
existingProp: 0,
|
||||
});
|
||||
|
||||
expect(options.defaultProp).toBe(true);
|
||||
expect(options.existingProp).toBe(10);
|
||||
expect(model.options).toBe(options);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -157,8 +157,8 @@ export class PanelModel {
|
||||
}
|
||||
}
|
||||
|
||||
getOptions(panelDefaults: any) {
|
||||
return _.defaultsDeep(this.options || {}, panelDefaults);
|
||||
getOptions() {
|
||||
return this.options;
|
||||
}
|
||||
|
||||
updateOptions(options: object) {
|
||||
@@ -179,7 +179,6 @@ export class PanelModel {
|
||||
|
||||
model[property] = _.cloneDeep(this[property]);
|
||||
}
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
@@ -247,9 +246,18 @@ export class PanelModel {
|
||||
});
|
||||
}
|
||||
|
||||
private applyPluginOptionDefaults(plugin: PanelPlugin) {
|
||||
if (plugin.angularConfigCtrl) {
|
||||
return;
|
||||
}
|
||||
this.options = _.defaultsDeep({}, this.options || {}, plugin.defaults);
|
||||
}
|
||||
|
||||
pluginLoaded(plugin: PanelPlugin) {
|
||||
this.plugin = plugin;
|
||||
|
||||
this.applyPluginOptionDefaults(plugin);
|
||||
|
||||
if (plugin.panel && plugin.onPanelMigration) {
|
||||
const version = getPluginVersion(plugin);
|
||||
if (version !== this.pluginVersion) {
|
||||
@@ -284,7 +292,7 @@ export class PanelModel {
|
||||
// switch
|
||||
this.type = pluginId;
|
||||
this.plugin = newPlugin;
|
||||
|
||||
this.applyPluginOptionDefaults(newPlugin);
|
||||
// Let panel plugins inspect options from previous panel and keep any that it can use
|
||||
if (newPlugin.onPanelTypeChanged) {
|
||||
this.options = this.options || {};
|
||||
@@ -324,7 +332,7 @@ export class PanelModel {
|
||||
}
|
||||
|
||||
hasTitle() {
|
||||
return !!this.title.length;
|
||||
return this.title && this.title.length > 0;
|
||||
}
|
||||
|
||||
destroy() {
|
||||
|
||||
@@ -97,9 +97,6 @@ export class PanelQueryRunner {
|
||||
delayStateNotification,
|
||||
} = options;
|
||||
|
||||
// filter out hidden queries & deep clone them
|
||||
const clonedAndFilteredQueries = cloneDeep(queries.filter(q => !q.hide));
|
||||
|
||||
const request: DataQueryRequest = {
|
||||
requestId: getNextRequestId(),
|
||||
timezone,
|
||||
@@ -109,7 +106,7 @@ export class PanelQueryRunner {
|
||||
timeInfo,
|
||||
interval: '',
|
||||
intervalMs: 0,
|
||||
targets: clonedAndFilteredQueries,
|
||||
targets: cloneDeep(queries),
|
||||
maxDataPoints: maxDataPoints || widthPixels,
|
||||
scopedVars: scopedVars || {},
|
||||
cacheTimeout,
|
||||
@@ -124,6 +121,10 @@ export class PanelQueryRunner {
|
||||
try {
|
||||
const ds = await getDataSource(datasource, request.scopedVars);
|
||||
|
||||
if (ds.meta && !ds.meta.hiddenQueries) {
|
||||
request.targets = request.targets.filter(q => !q.hide);
|
||||
}
|
||||
|
||||
// Attach the datasource name to each query
|
||||
request.targets = request.targets.map(query => {
|
||||
if (!query.datasource) {
|
||||
|
||||
@@ -275,7 +275,6 @@ export class Explore extends React.PureComponent<ExploreProps> {
|
||||
<LogsContainer
|
||||
width={width}
|
||||
exploreId={exploreId}
|
||||
onChangeTime={this.onChangeTime}
|
||||
onClickLabel={this.onClickLabel}
|
||||
onStartScanning={this.onStartScanning}
|
||||
onStopScanning={this.onStopScanning}
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { hot } from 'react-hot-loader';
|
||||
import { connect } from 'react-redux';
|
||||
import moment from 'moment';
|
||||
import { RawTimeRange, TimeRange, LogLevel, TimeZone, AbsoluteTimeRange } from '@grafana/ui';
|
||||
|
||||
import { ExploreId, ExploreItemState } from 'app/types/explore';
|
||||
import { LogsModel, LogsDedupStrategy } from 'app/core/logs_model';
|
||||
import { StoreState } from 'app/types';
|
||||
|
||||
import { toggleLogs, changeDedupStrategy } from './state/actions';
|
||||
import { toggleLogs, changeDedupStrategy, changeTime } from './state/actions';
|
||||
import Logs from './Logs';
|
||||
import Panel from './Panel';
|
||||
import { toggleLogLevelAction } from 'app/features/explore/state/actionTypes';
|
||||
@@ -20,7 +21,6 @@ interface LogsContainerProps {
|
||||
logsHighlighterExpressions?: string[];
|
||||
logsResult?: LogsModel;
|
||||
dedupedResult?: LogsModel;
|
||||
onChangeTime: (range: AbsoluteTimeRange) => void;
|
||||
onClickLabel: (key: string, value: string) => void;
|
||||
onStartScanning: () => void;
|
||||
onStopScanning: () => void;
|
||||
@@ -35,9 +35,19 @@ interface LogsContainerProps {
|
||||
dedupStrategy: LogsDedupStrategy;
|
||||
hiddenLogLevels: Set<LogLevel>;
|
||||
width: number;
|
||||
changeTime: typeof changeTime;
|
||||
}
|
||||
|
||||
export class LogsContainer extends PureComponent<LogsContainerProps> {
|
||||
onChangeTime = (absRange: AbsoluteTimeRange) => {
|
||||
const { exploreId, timeZone, changeTime } = this.props;
|
||||
const range = {
|
||||
from: timeZone.isUtc ? moment.utc(absRange.from) : moment(absRange.from),
|
||||
to: timeZone.isUtc ? moment.utc(absRange.to) : moment(absRange.to),
|
||||
};
|
||||
|
||||
changeTime(exploreId, range);
|
||||
};
|
||||
onClickLogsButton = () => {
|
||||
this.props.toggleLogs(this.props.exploreId, this.props.showingLogs);
|
||||
};
|
||||
@@ -61,7 +71,6 @@ export class LogsContainer extends PureComponent<LogsContainerProps> {
|
||||
logsHighlighterExpressions,
|
||||
logsResult,
|
||||
dedupedResult,
|
||||
onChangeTime,
|
||||
onClickLabel,
|
||||
onStartScanning,
|
||||
onStopScanning,
|
||||
@@ -83,7 +92,7 @@ export class LogsContainer extends PureComponent<LogsContainerProps> {
|
||||
exploreId={exploreId}
|
||||
highlighterExpressions={logsHighlighterExpressions}
|
||||
loading={loading}
|
||||
onChangeTime={onChangeTime}
|
||||
onChangeTime={this.onChangeTime}
|
||||
onClickLabel={onClickLabel}
|
||||
onStartScanning={onStartScanning}
|
||||
onStopScanning={onStopScanning}
|
||||
@@ -130,6 +139,7 @@ const mapDispatchToProps = {
|
||||
toggleLogs,
|
||||
changeDedupStrategy,
|
||||
toggleLogLevelAction,
|
||||
changeTime,
|
||||
};
|
||||
|
||||
export default hot(module)(
|
||||
|
||||
@@ -1,18 +1,29 @@
|
||||
import React, { FC, useContext } from 'react';
|
||||
import { css } from 'emotion';
|
||||
import { PluginState, Tooltip, ThemeContext } from '@grafana/ui';
|
||||
import { PopperContent } from '@grafana/ui/src/components/Tooltip/PopperController';
|
||||
|
||||
interface Props {
|
||||
state?: PluginState;
|
||||
}
|
||||
|
||||
function getPluginStateInfoText(state?: PluginState): string | null {
|
||||
function getPluginStateInfoText(state?: PluginState): PopperContent<any> | null {
|
||||
switch (state) {
|
||||
case PluginState.alpha:
|
||||
return 'Plugin in alpha state. Means work in progress and updates may include breaking changes.';
|
||||
return (
|
||||
<div>
|
||||
<h5>Alpha Plugin</h5>
|
||||
<p>This plugin is a work in progress and updates may include breaking changes.</p>
|
||||
</div>
|
||||
);
|
||||
|
||||
case PluginState.beta:
|
||||
return 'Plugin in beta state. Means there could be bugs and minor breaking changes.';
|
||||
return (
|
||||
<div>
|
||||
<h5>Beta Plugin</h5>
|
||||
<p>There could be bugs and minor breaking changes to this plugin.</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -34,10 +45,11 @@ const PluginStateinfo: FC<Props> = props => {
|
||||
font-size: 13px;
|
||||
padding: 4px 8px;
|
||||
margin-left: 16px;
|
||||
cursor: help;
|
||||
`;
|
||||
|
||||
return (
|
||||
<Tooltip content={text}>
|
||||
<Tooltip content={text} theme={'info'} placement={'top'}>
|
||||
<div className={styles}>
|
||||
<i className="fa fa-warning" /> {props.state}
|
||||
</div>
|
||||
|
||||
@@ -105,7 +105,7 @@ exposeToPlugin('app/core/services/backend_srv', {
|
||||
});
|
||||
|
||||
exposeToPlugin('app/plugins/sdk', sdk);
|
||||
exposeToPlugin('@grafana/ui/src/utils/datemath', datemath);
|
||||
exposeToPlugin('app/core/utils/datemath', datemath);
|
||||
exposeToPlugin('app/core/utils/file_export', fileExport);
|
||||
exposeToPlugin('app/core/utils/flatten', flatten);
|
||||
exposeToPlugin('app/core/utils/kbn', kbn);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
"name": "CloudWatch",
|
||||
"id": "cloudwatch",
|
||||
|
||||
"hiddenQueries": true,
|
||||
"metrics": true,
|
||||
"alerting": true,
|
||||
"annotations": true,
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<div class="gf-form" ng-if="ctrl.target.queryType === 'Azure Monitor' || ctrl.target.queryType === 'Azure Log Analytics'">
|
||||
<label class="gf-form-label query-keyword width-9">Subscription</label>
|
||||
<gf-form-dropdown model="ctrl.target.subscription" allow-custom="true" lookup-text="true"
|
||||
get-options="ctrl.subscriptions" on-change="ctrl.onSubscriptionChange()" css-class="min-width-12">
|
||||
get-options="ctrl.getSubscriptions()" on-change="ctrl.onSubscriptionChange()" css-class="min-width-12">
|
||||
</gf-form-dropdown>
|
||||
</div>
|
||||
<div class="gf-form gf-form--grow">
|
||||
@@ -108,17 +108,18 @@
|
||||
<gf-form-dropdown model="ctrl.target.azureLogAnalytics.workspace" allow-custom="true" lookup-text="true"
|
||||
get-options="ctrl.workspaces" on-change="ctrl.refresh()" css-class="min-width-12">
|
||||
</gf-form-dropdown>
|
||||
<div class="gf-form">
|
||||
<div class="width-1"></div>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<button class="btn btn-primary width-10" ng-click="ctrl.refresh()">Run</button>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<label class="gf-form-label">(Run Query: Shift+Enter, Trigger Suggestion: Ctrl+Space)</label>
|
||||
</div>
|
||||
<div class="gf-form gf-form--grow">
|
||||
<div class="gf-form-label gf-form-label--grow"></div>
|
||||
<div class="gf-form">
|
||||
<div class="width-1"></div>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<button class="btn btn-primary width-10" ng-click="ctrl.refresh()">Run</button>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<label class="gf-form-label">(Run Query: Shift+Enter, Trigger Suggestion: Ctrl+Space)</label>
|
||||
</div>
|
||||
<div class="gf-form gf-form--grow">
|
||||
<div class="gf-form-label gf-form-label--grow"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -189,11 +189,19 @@ describe('AzureMonitorQueryCtrl', () => {
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
queryCtrl.target.subscription = 'sub1';
|
||||
queryCtrl.target.azureMonitor.resourceGroup = 'test';
|
||||
queryCtrl.target.azureMonitor.metricDefinition = 'Microsoft.Compute/virtualMachines';
|
||||
queryCtrl.target.azureMonitor.resourceName = 'test';
|
||||
queryCtrl.target.azureMonitor.metricName = 'Percentage CPU';
|
||||
queryCtrl.datasource.getMetricMetadata = function(resourceGroup, metricDefinition, resourceName, metricName) {
|
||||
queryCtrl.datasource.getMetricMetadata = function(
|
||||
subscription,
|
||||
resourceGroup,
|
||||
metricDefinition,
|
||||
resourceName,
|
||||
metricName
|
||||
) {
|
||||
expect(subscription).toBe('sub1');
|
||||
expect(resourceGroup).toBe('test');
|
||||
expect(metricDefinition).toBe('Microsoft.Compute/virtualMachines');
|
||||
expect(resourceName).toBe('test');
|
||||
|
||||
@@ -197,6 +197,8 @@ export class AzureMonitorQueryCtrl extends QueryCtrl {
|
||||
if (!this.target.subscription && this.subscriptions.length > 0) {
|
||||
this.target.subscription = this.subscriptions[0].value;
|
||||
}
|
||||
|
||||
return this.subscriptions;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -204,6 +206,18 @@ export class AzureMonitorQueryCtrl extends QueryCtrl {
|
||||
if (this.target.queryType === 'Azure Log Analytics') {
|
||||
return this.getWorkspaces();
|
||||
}
|
||||
|
||||
if (this.target.queryType === 'Azure Monitor') {
|
||||
this.target.azureMonitor.resourceGroup = this.defaultDropdownValue;
|
||||
this.target.azureMonitor.metricDefinition = this.defaultDropdownValue;
|
||||
this.target.azureMonitor.resourceName = this.defaultDropdownValue;
|
||||
this.target.azureMonitor.metricName = this.defaultDropdownValue;
|
||||
this.target.azureMonitor.aggregation = '';
|
||||
this.target.azureMonitor.timeGrains = [];
|
||||
this.target.azureMonitor.timeGrain = '';
|
||||
this.target.azureMonitor.dimensions = [];
|
||||
this.target.azureMonitor.dimension = '';
|
||||
}
|
||||
}
|
||||
|
||||
/* Azure Monitor Section */
|
||||
@@ -282,6 +296,9 @@ export class AzureMonitorQueryCtrl extends QueryCtrl {
|
||||
this.target.azureMonitor.metricDefinition = this.defaultDropdownValue;
|
||||
this.target.azureMonitor.resourceName = this.defaultDropdownValue;
|
||||
this.target.azureMonitor.metricName = this.defaultDropdownValue;
|
||||
this.target.azureMonitor.aggregation = '';
|
||||
this.target.azureMonitor.timeGrains = [];
|
||||
this.target.azureMonitor.timeGrain = '';
|
||||
this.target.azureMonitor.dimensions = [];
|
||||
this.target.azureMonitor.dimension = '';
|
||||
}
|
||||
@@ -289,12 +306,18 @@ export class AzureMonitorQueryCtrl extends QueryCtrl {
|
||||
onMetricDefinitionChange() {
|
||||
this.target.azureMonitor.resourceName = this.defaultDropdownValue;
|
||||
this.target.azureMonitor.metricName = this.defaultDropdownValue;
|
||||
this.target.azureMonitor.aggregation = '';
|
||||
this.target.azureMonitor.timeGrains = [];
|
||||
this.target.azureMonitor.timeGrain = '';
|
||||
this.target.azureMonitor.dimensions = [];
|
||||
this.target.azureMonitor.dimension = '';
|
||||
}
|
||||
|
||||
onResourceNameChange() {
|
||||
this.target.azureMonitor.metricName = this.defaultDropdownValue;
|
||||
this.target.azureMonitor.aggregation = '';
|
||||
this.target.azureMonitor.timeGrains = [];
|
||||
this.target.azureMonitor.timeGrain = '';
|
||||
this.target.azureMonitor.dimensions = [];
|
||||
this.target.azureMonitor.dimension = '';
|
||||
}
|
||||
@@ -306,6 +329,7 @@ export class AzureMonitorQueryCtrl extends QueryCtrl {
|
||||
|
||||
return this.datasource
|
||||
.getMetricMetadata(
|
||||
this.replace(this.target.subscription),
|
||||
this.replace(this.target.azureMonitor.resourceGroup),
|
||||
this.replace(this.target.azureMonitor.metricDefinition),
|
||||
this.replace(this.target.azureMonitor.resourceName),
|
||||
@@ -315,6 +339,7 @@ export class AzureMonitorQueryCtrl extends QueryCtrl {
|
||||
this.target.azureMonitor.aggOptions = metadata.supportedAggTypes || [metadata.primaryAggType];
|
||||
this.target.azureMonitor.aggregation = metadata.primaryAggType;
|
||||
this.target.azureMonitor.timeGrains = [{ text: 'auto', value: 'auto' }].concat(metadata.supportedTimeGrains);
|
||||
this.target.azureMonitor.timeGrain = 'auto';
|
||||
|
||||
this.target.azureMonitor.dimensions = metadata.dimensions;
|
||||
if (metadata.dimensions.length > 0) {
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
"includes": [{ "type": "dashboard", "name": "Graphite Carbon Metrics", "path": "dashboards/carbon_metrics.json" }],
|
||||
|
||||
"hiddenQueries": true,
|
||||
"metrics": true,
|
||||
"alerting": true,
|
||||
"annotations": true,
|
||||
|
||||
@@ -34,7 +34,7 @@ export default class InfluxDatasource {
|
||||
this.withCredentials = instanceSettings.withCredentials;
|
||||
this.interval = (instanceSettings.jsonData || {}).timeInterval;
|
||||
this.responseParser = new ResponseParser();
|
||||
this.httpMode = instanceSettings.jsonData.httpMode;
|
||||
this.httpMode = instanceSettings.jsonData.httpMode || 'GET';
|
||||
}
|
||||
|
||||
query(options) {
|
||||
|
||||
@@ -81,7 +81,7 @@ export class BarGaugePanelEditor extends PureComponent<PanelEditorProps<BarGauge
|
||||
title="Field"
|
||||
showMinMax={true}
|
||||
onChange={this.onDefaultsChange}
|
||||
options={fieldOptions.defaults}
|
||||
value={fieldOptions.defaults}
|
||||
/>
|
||||
|
||||
<ThresholdsEditor onChange={this.onThresholdsChanged} thresholds={fieldOptions.thresholds} />
|
||||
|
||||
@@ -5,7 +5,7 @@ import React, { PureComponent } from 'react';
|
||||
import { config } from 'app/core/config';
|
||||
|
||||
// Components
|
||||
import { Gauge, FieldDisplay, getFieldDisplayValues } from '@grafana/ui';
|
||||
import { Gauge, FieldDisplay, getFieldDisplayValues, VizOrientation } from '@grafana/ui';
|
||||
|
||||
// Types
|
||||
import { GaugeOptions } from './types';
|
||||
@@ -43,7 +43,7 @@ export class GaugePanel extends PureComponent<PanelProps<GaugeOptions>> {
|
||||
};
|
||||
|
||||
render() {
|
||||
const { height, width, options, data, renderCounter } = this.props;
|
||||
const { height, width, data, renderCounter } = this.props;
|
||||
return (
|
||||
<VizRepeater
|
||||
getValues={this.getValues}
|
||||
@@ -52,7 +52,7 @@ export class GaugePanel extends PureComponent<PanelProps<GaugeOptions>> {
|
||||
height={height}
|
||||
source={data}
|
||||
renderCounter={renderCounter}
|
||||
orientation={options.orientation}
|
||||
orientation={VizOrientation.Auto}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ export class GaugePanelEditor extends PureComponent<PanelEditorProps<GaugeOption
|
||||
title="Field"
|
||||
showMinMax={true}
|
||||
onChange={this.onDefaultsChange}
|
||||
options={fieldOptions.defaults}
|
||||
value={fieldOptions.defaults}
|
||||
/>
|
||||
|
||||
<ThresholdsEditor onChange={this.onThresholdsChanged} thresholds={fieldOptions.thresholds} />
|
||||
|
||||
174
public/app/plugins/panel/gettingstarted/GettingStarted.tsx
Normal file
174
public/app/plugins/panel/gettingstarted/GettingStarted.tsx
Normal file
@@ -0,0 +1,174 @@
|
||||
// Libraries
|
||||
import React, { PureComponent } from 'react';
|
||||
|
||||
import { PanelProps } from '@grafana/ui/src/types';
|
||||
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
|
||||
import { getBackendSrv } from 'app/core/services/backend_srv';
|
||||
import { contextSrv } from 'app/core/core';
|
||||
import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv';
|
||||
|
||||
interface Step {
|
||||
title: string;
|
||||
cta?: string;
|
||||
icon: string;
|
||||
href: string;
|
||||
target?: string;
|
||||
note?: string;
|
||||
check: () => Promise<boolean>;
|
||||
done?: boolean;
|
||||
}
|
||||
|
||||
interface State {
|
||||
checksDone: boolean;
|
||||
}
|
||||
|
||||
export class GettingStarted extends PureComponent<PanelProps, State> {
|
||||
stepIndex = 0;
|
||||
readonly steps: Step[];
|
||||
|
||||
constructor(props: PanelProps) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
checksDone: false,
|
||||
};
|
||||
|
||||
this.steps = [
|
||||
{
|
||||
title: 'Install Grafana',
|
||||
icon: 'icon-gf icon-gf-check',
|
||||
href: 'http://docs.grafana.org/',
|
||||
target: '_blank',
|
||||
note: 'Review the installation docs',
|
||||
check: () => Promise.resolve(true),
|
||||
},
|
||||
{
|
||||
title: 'Create your first data source',
|
||||
cta: 'Add data source',
|
||||
icon: 'gicon gicon-datasources',
|
||||
href: 'datasources/new?gettingstarted',
|
||||
check: () => {
|
||||
return new Promise(resolve => {
|
||||
resolve(
|
||||
getDatasourceSrv()
|
||||
.getMetricSources()
|
||||
.filter(item => {
|
||||
return item.meta.builtIn !== true;
|
||||
}).length > 0
|
||||
);
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'Create your first dashboard',
|
||||
cta: 'New dashboard',
|
||||
icon: 'gicon gicon-dashboard',
|
||||
href: 'dashboard/new?gettingstarted',
|
||||
check: () => {
|
||||
return getBackendSrv()
|
||||
.search({ limit: 1 })
|
||||
.then(result => {
|
||||
return result.length > 0;
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'Invite your team',
|
||||
cta: 'Add Users',
|
||||
icon: 'gicon gicon-team',
|
||||
href: 'org/users?gettingstarted',
|
||||
check: () => {
|
||||
return getBackendSrv()
|
||||
.get('/api/org/users')
|
||||
.then(res => {
|
||||
return res.length > 1;
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'Install apps & plugins',
|
||||
cta: 'Explore plugin repository',
|
||||
icon: 'gicon gicon-plugins',
|
||||
href: 'https://grafana.com/plugins?utm_source=grafana_getting_started',
|
||||
check: () => {
|
||||
return getBackendSrv()
|
||||
.get('/api/plugins', { embedded: 0, core: 0 })
|
||||
.then(plugins => {
|
||||
return plugins.length > 0;
|
||||
});
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.stepIndex = -1;
|
||||
return this.nextStep().then((res: any) => {
|
||||
this.setState({ checksDone: true });
|
||||
});
|
||||
}
|
||||
|
||||
nextStep() {
|
||||
if (this.stepIndex === this.steps.length - 1) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
this.stepIndex += 1;
|
||||
const currentStep = this.steps[this.stepIndex];
|
||||
return currentStep.check().then(passed => {
|
||||
if (passed) {
|
||||
currentStep.done = true;
|
||||
return this.nextStep();
|
||||
}
|
||||
return Promise.resolve();
|
||||
});
|
||||
}
|
||||
|
||||
dismiss = () => {
|
||||
const { id } = this.props;
|
||||
const dashboard = getDashboardSrv().getCurrent();
|
||||
const panel = dashboard.getPanelById(id);
|
||||
dashboard.removePanel(panel);
|
||||
getBackendSrv()
|
||||
.request({
|
||||
method: 'PUT',
|
||||
url: '/api/user/helpflags/1',
|
||||
showSuccessAlert: false,
|
||||
})
|
||||
.then((res: any) => {
|
||||
contextSrv.user.helpFlags1 = res.helpFlags1;
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { checksDone } = this.state;
|
||||
if (!checksDone) {
|
||||
return <div>checking...</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="progress-tracker-container">
|
||||
<button className="progress-tracker-close-btn" onClick={this.dismiss}>
|
||||
<i className="fa fa-remove" />
|
||||
</button>
|
||||
<div className="progress-tracker">
|
||||
{this.steps.map(step => {
|
||||
return (
|
||||
<div className={step.done ? 'progress-step completed' : 'progress-step active'}>
|
||||
<a className="progress-link" href={step.href} target={step.target} title={step.note}>
|
||||
<span className="progress-marker" ng-className="step.cssClass">
|
||||
<i className={step.icon} />
|
||||
</span>
|
||||
<span className="progress-text">{step.title}</span>
|
||||
</a>
|
||||
<a className="btn-small progress-step-cta" href={step.href} target={step.target}>
|
||||
{step.cta}
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
<div class="gf-form-group">
|
||||
<div class="gf-form-inline">
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-10">Mode</span>
|
||||
<div class="gf-form-select-wrapper max-width-10">
|
||||
<select class="gf-form-input" ng-model="ctrl.panel.mode" ng-options="f for f in ctrl.modes" ng-change="ctrl.refresh()"></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gf-form" ng-show="ctrl.panel.mode === 'recently viewed'">
|
||||
<span class="gf-form-label">
|
||||
<i class="grafana-tip fa fa-question-circle ng-scope" bs-tooltip="'WARNING: This list will be cleared when clearing browser cache'" data-original-title="" title=""></i>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gf-form-inline" ng-if="ctrl.panel.mode === 'search'">
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-10">Search options</span>
|
||||
<span class="gf-form-label">Query</span>
|
||||
|
||||
<input type="text" class="gf-form-input" placeholder="title query"
|
||||
ng-model="ctrl.panel.query" ng-change="ctrl.refresh()" ng-model-onblur>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label">Tags</span>
|
||||
|
||||
<bootstrap-tagsinput ng-model="ctrl.panel.tags" tagclass="label label-tag" placeholder="add tags" on-tags-updated="ctrl.refresh()">
|
||||
</bootstrap-tagsinput>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gf-form-inline">
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-10">Limit number to</span>
|
||||
<input class="gf-form-input" type="number" ng-model="ctrl.panel.limit" ng-model-onblur ng-change="ctrl.refresh()">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,16 +0,0 @@
|
||||
<div class="dashlist" ng-if="ctrl.checksDone">
|
||||
<div class="dashlist-section">
|
||||
<button class="dashlist-cta-close-btn" ng-click="ctrl.dismiss()">
|
||||
<i class="fa fa-remove"></i>
|
||||
</button>
|
||||
<ul class="progress-tracker">
|
||||
<li class="progress-step" ng-repeat="step in ctrl.steps" ng-class="step.cssClass">
|
||||
<a class="progress-link" ng-href="{{step.href}}" target="{{step.target}}" title="{{step.note}}">
|
||||
<span class="progress-marker" ng-class="step.cssClass"><i class="{{step.icon}}"></i></span>
|
||||
<span class="progress-text" ng-href="{{step.href}}" target="{{step.target}}">{{step.title}}</span>
|
||||
</a>
|
||||
<a class="btn-small progress-step-cta" ng-href="{{step.href}}" target="{{step.target}}">{{step.cta}}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,118 +1,5 @@
|
||||
import { PanelCtrl } from 'app/plugins/sdk';
|
||||
import { PanelPlugin } from '@grafana/ui';
|
||||
import { GettingStarted } from './GettingStarted';
|
||||
|
||||
import { contextSrv } from 'app/core/core';
|
||||
|
||||
class GettingStartedPanelCtrl extends PanelCtrl {
|
||||
static templateUrl = 'public/app/plugins/panel/gettingstarted/module.html';
|
||||
checksDone: boolean;
|
||||
stepIndex: number;
|
||||
steps: any;
|
||||
|
||||
/** @ngInject */
|
||||
constructor($scope, $injector, private backendSrv, datasourceSrv, private $q) {
|
||||
super($scope, $injector);
|
||||
|
||||
this.stepIndex = 0;
|
||||
this.steps = [];
|
||||
|
||||
this.steps.push({
|
||||
title: 'Install Grafana',
|
||||
icon: 'icon-gf icon-gf-check',
|
||||
href: 'http://docs.grafana.org/',
|
||||
target: '_blank',
|
||||
note: 'Review the installation docs',
|
||||
check: () => $q.when(true),
|
||||
});
|
||||
|
||||
this.steps.push({
|
||||
title: 'Create your first data source',
|
||||
cta: 'Add data source',
|
||||
icon: 'gicon gicon-datasources',
|
||||
href: 'datasources/new?gettingstarted',
|
||||
check: () => {
|
||||
return $q.when(
|
||||
datasourceSrv.getMetricSources().filter(item => {
|
||||
return item.meta.builtIn !== true;
|
||||
}).length > 0
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
this.steps.push({
|
||||
title: 'Create your first dashboard',
|
||||
cta: 'New dashboard',
|
||||
icon: 'gicon gicon-dashboard',
|
||||
href: 'dashboard/new?gettingstarted',
|
||||
check: () => {
|
||||
return this.backendSrv.search({ limit: 1 }).then(result => {
|
||||
return result.length > 0;
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
this.steps.push({
|
||||
title: 'Invite your team',
|
||||
cta: 'Add Users',
|
||||
icon: 'gicon gicon-team',
|
||||
href: 'org/users?gettingstarted',
|
||||
check: () => {
|
||||
return this.backendSrv.get('/api/org/users').then(res => {
|
||||
return res.length > 1;
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
this.steps.push({
|
||||
title: 'Install apps & plugins',
|
||||
cta: 'Explore plugin repository',
|
||||
icon: 'gicon gicon-plugins',
|
||||
href: 'https://grafana.com/plugins?utm_source=grafana_getting_started',
|
||||
check: () => {
|
||||
return this.backendSrv.get('/api/plugins', { embedded: 0, core: 0 }).then(plugins => {
|
||||
return plugins.length > 0;
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
$onInit() {
|
||||
this.stepIndex = -1;
|
||||
return this.nextStep().then(res => {
|
||||
this.checksDone = true;
|
||||
});
|
||||
}
|
||||
|
||||
nextStep() {
|
||||
if (this.stepIndex === this.steps.length - 1) {
|
||||
return this.$q.when();
|
||||
}
|
||||
|
||||
this.stepIndex += 1;
|
||||
const currentStep = this.steps[this.stepIndex];
|
||||
return currentStep.check().then(passed => {
|
||||
if (passed) {
|
||||
currentStep.cssClass = 'completed';
|
||||
return this.nextStep();
|
||||
}
|
||||
|
||||
currentStep.cssClass = 'active';
|
||||
return this.$q.when();
|
||||
});
|
||||
}
|
||||
|
||||
dismiss() {
|
||||
this.dashboard.removePanel(this.panel, false);
|
||||
|
||||
this.backendSrv
|
||||
.request({
|
||||
method: 'PUT',
|
||||
url: '/api/user/helpflags/1',
|
||||
showSuccessAlert: false,
|
||||
})
|
||||
.then(res => {
|
||||
contextSrv.user.helpFlags1 = res.helpFlags1;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export { GettingStartedPanelCtrl, GettingStartedPanelCtrl as PanelCtrl };
|
||||
// Simplest possible panel plugin
|
||||
export const plugin = new PanelPlugin(GettingStarted);
|
||||
|
||||
@@ -46,7 +46,7 @@ export class PieChartPanelEditor extends PureComponent<PanelEditorProps<PieChart
|
||||
title="Field (default)"
|
||||
showMinMax={true}
|
||||
onChange={this.onDefaultsChange}
|
||||
options={fieldOptions.defaults}
|
||||
value={fieldOptions.defaults}
|
||||
/>
|
||||
|
||||
<PieChartOptionsBox onOptionsChange={onOptionsChange} options={options} />
|
||||
|
||||
@@ -63,7 +63,7 @@ export class SingleStatEditor extends PureComponent<PanelEditorProps<SingleStatO
|
||||
title="Field (default)"
|
||||
showMinMax={true}
|
||||
onChange={this.onDefaultsChange}
|
||||
options={fieldOptions.defaults}
|
||||
value={fieldOptions.defaults}
|
||||
/>
|
||||
|
||||
<FontSizeEditor options={options} onChange={this.props.onOptionsChange} />
|
||||
|
||||
@@ -67,11 +67,6 @@
|
||||
min-height: $navbarHeight;
|
||||
line-height: $navbarHeight;
|
||||
|
||||
.fa-caret-down {
|
||||
font-size: 60%;
|
||||
padding-left: 6px;
|
||||
}
|
||||
|
||||
.gicon {
|
||||
top: -2px;
|
||||
position: relative;
|
||||
@@ -85,17 +80,32 @@
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&--folder {
|
||||
color: $text-color-weak;
|
||||
display: none;
|
||||
.navbar-page-btn__folder {
|
||||
color: $text-color-weak;
|
||||
display: none;
|
||||
|
||||
@include media-breakpoint-up(lg) {
|
||||
display: inline-block;
|
||||
}
|
||||
@include media-breakpoint-up(lg) {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
// element is needed here to override font-awesome specificity
|
||||
i.navbar-page-btn__folder-icon {
|
||||
font-size: $font-size-sm;
|
||||
color: $text-color-weak;
|
||||
padding: 0 $space-sm;
|
||||
position: relative;
|
||||
top: -1px;
|
||||
}
|
||||
|
||||
// element is needed here to override font-awesome specificity
|
||||
i.navbar-page-btn__search {
|
||||
font-size: $font-size-xs;
|
||||
padding: 0 $space-xs;
|
||||
}
|
||||
|
||||
.navbar-buttons {
|
||||
// height: $navbarHeight;
|
||||
display: flex;
|
||||
|
||||
@@ -13,18 +13,22 @@ $marker-size-half: ($marker-size / 2);
|
||||
$path-height: 2px !default;
|
||||
$path-position: $marker-size-half - ($path-height / 2);
|
||||
|
||||
.dashlist-cta-close-btn {
|
||||
.progress-tracker-container {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.progress-tracker-close-btn {
|
||||
color: $text-color-weak;
|
||||
float: right;
|
||||
padding: 0;
|
||||
margin: 0 2px 0 0;
|
||||
position: absolute;
|
||||
z-index: $panel-header-z-index;
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
font-size: $font-size-lg;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
|
||||
i {
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: $white;
|
||||
}
|
||||
@@ -33,9 +37,9 @@ $path-position: $marker-size-half - ($path-height / 2);
|
||||
// Container element
|
||||
.progress-tracker {
|
||||
display: flex;
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
// Step container that creates lines between steps
|
||||
@@ -46,6 +50,7 @@ $path-position: $marker-size-half - ($path-height / 2);
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
color: $text-color-weak;
|
||||
height: 84px;
|
||||
|
||||
// For a flexbox bug in firefox that wont allow the text overflow on the text
|
||||
min-width: $marker-size;
|
||||
@@ -54,7 +59,7 @@ $path-position: $marker-size-half - ($path-height / 2);
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
z-index: 0;
|
||||
top: $path-position;
|
||||
bottom: $path-position;
|
||||
right: -$marker-size-half;
|
||||
@@ -134,11 +139,10 @@ $path-position: $marker-size-half - ($path-height / 2);
|
||||
width: $marker-size;
|
||||
height: $marker-size;
|
||||
padding-bottom: 2px; // To align text within the marker
|
||||
z-index: 20;
|
||||
z-index: 1;
|
||||
background-color: $panel-bg;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-bottom: $spacer;
|
||||
color: $text-color-weak;
|
||||
font-size: 35px;
|
||||
vertical-align: sub;
|
||||
|
||||
@@ -126,6 +126,7 @@ $panel-header-no-title-zindex: 1;
|
||||
left: 0;
|
||||
width: $panel-header-height;
|
||||
height: $panel-header-height;
|
||||
z-index: $panel-header-no-title-zindex + 1;
|
||||
top: 0;
|
||||
|
||||
.fa {
|
||||
@@ -138,7 +139,8 @@ $panel-header-no-title-zindex: 1;
|
||||
|
||||
&--info {
|
||||
display: block;
|
||||
@include panel-corner-color(lighten($panel-corner, 4%));
|
||||
@include panel-corner-color(lighten($panel-corner, 6%));
|
||||
|
||||
.fa:before {
|
||||
content: '\f129';
|
||||
}
|
||||
@@ -146,7 +148,7 @@ $panel-header-no-title-zindex: 1;
|
||||
|
||||
&--links {
|
||||
display: block;
|
||||
@include panel-corner-color(lighten($panel-corner, 4%));
|
||||
@include panel-corner-color(lighten($panel-corner, 6%));
|
||||
.fa {
|
||||
left: 4px;
|
||||
}
|
||||
|
||||
@@ -6,16 +6,17 @@
|
||||
}
|
||||
|
||||
.singlestat-panel-value-container {
|
||||
line-height: 1;
|
||||
// line-height 0 is imporant here as the font-size is on this
|
||||
// level but overriden one level deeper and but the line-height: is still
|
||||
// based on the base font size on this level. Using line-height: 0 fixes that
|
||||
line-height: 0;
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
font-size: 3em;
|
||||
font-weight: $font-weight-semi-bold;
|
||||
// helps make the title feel more centered when there is a panel title
|
||||
padding-bottom: $panel-padding;
|
||||
font-size: 38px;
|
||||
}
|
||||
|
||||
// Helps
|
||||
|
||||
@@ -123,7 +123,7 @@
|
||||
}
|
||||
|
||||
.table-panel-table-header-inner {
|
||||
padding: 0.45em 0 0.45em 1.1em;
|
||||
padding: 0.3em 0 0.45em 1.1em;
|
||||
text-align: left;
|
||||
color: $blue;
|
||||
position: absolute;
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
height: 100%; // Chrome 74 needs this to make the element scrollable
|
||||
|
||||
.search-item--indent {
|
||||
margin-left: 14px;
|
||||
@@ -258,10 +259,6 @@
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.search-dropdown__col_1 {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.search-filter-box {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@@ -16,8 +16,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-button--zoom,
|
||||
.navbar-button--refresh {
|
||||
.navbar-button--zoom {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
.panel-alert-icon:before {
|
||||
content: '\e611';
|
||||
position: relative;
|
||||
top: 5px;
|
||||
top: 1px;
|
||||
left: -3px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,5 +24,11 @@ python3 generator/build.py "$@"
|
||||
chmod a+x /tmp/scratch/*.msi
|
||||
echo "MSI: Copy to $WORKING_DIRECTORY/dist"
|
||||
cp /tmp/scratch/*.msi $WORKING_DIRECTORY/dist
|
||||
echo "MSI: Generate SHA256"
|
||||
MSI_FILE=`ls $WORKING_DIRECTORY/dist/*.msi`
|
||||
SHA256SUM=`sha256sum $MSI_FILE | cut -f1 -d' '`
|
||||
echo $SHA256SUM > $MSI_FILE.sha256
|
||||
echo "MSI: SHA256 file content:"
|
||||
cat $MSI_FILE.sha256
|
||||
echo "MSI: contents of $WORKING_DIRECTORY/dist"
|
||||
ls -al $WORKING_DIRECTORY/dist
|
||||
|
||||
@@ -6,8 +6,8 @@ EXTRA_OPTS="$@"
|
||||
|
||||
# Right now we hack this in into the publish script.
|
||||
# Eventually we might want to keep a list of all previous releases somewhere.
|
||||
_releaseNoteUrl="https://community.grafana.com/t/release-notes-v6-0-x/14010"
|
||||
_whatsNewUrl="http://docs.grafana.org/guides/whats-new-in-v6-0/"
|
||||
_releaseNoteUrl="https://community.grafana.com/t/release-notes-v6-2-x/17037"
|
||||
_whatsNewUrl="https://grafana.com/docs/guides/whats-new-in-v6-2/"
|
||||
|
||||
./scripts/build/release_publisher/release_publisher \
|
||||
--wn ${_whatsNewUrl} \
|
||||
|
||||
@@ -174,6 +174,11 @@ var completeBuildArtifactConfigurations = []buildArtifact{
|
||||
arch: "amd64",
|
||||
urlPostfix: ".windows-amd64.zip",
|
||||
},
|
||||
{
|
||||
os: "win-installer",
|
||||
arch: "amd64",
|
||||
urlPostfix: ".windows-amd64.msi",
|
||||
},
|
||||
}
|
||||
|
||||
type artifactFilter struct {
|
||||
|
||||
@@ -74,6 +74,34 @@ func TestPreparingReleaseFromRemote(t *testing.T) {
|
||||
baseArchiveURL: "https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana",
|
||||
buildArtifacts: []buildArtifact{{"linux", "armv6", "_armhf.deb", "-rpi"}},
|
||||
},
|
||||
{
|
||||
version: "v5.4.0-pre1asdf",
|
||||
expectedVersion: "5.4.0-pre1asdf",
|
||||
whatsNewURL: "https://whatsnews.foo/",
|
||||
relNotesURL: "https://relnotes.foo/",
|
||||
nightly: true,
|
||||
expectedBeta: false,
|
||||
expectedStable: false,
|
||||
expectedArch: "amd64",
|
||||
expectedOs: "win-installer",
|
||||
expectedURL: "https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-5.4.0-pre1asdf.windows-amd64.msi",
|
||||
baseArchiveURL: "https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana",
|
||||
buildArtifacts: []buildArtifact{{"win-installer", "amd64", ".windows-amd64.msi", ""}},
|
||||
},
|
||||
{
|
||||
version: "v5.4.0-pre1asdf",
|
||||
expectedVersion: "5.4.0-pre1asdf",
|
||||
whatsNewURL: "https://whatsnews.foo/",
|
||||
relNotesURL: "https://relnotes.foo/",
|
||||
nightly: true,
|
||||
expectedBeta: false,
|
||||
expectedStable: false,
|
||||
expectedArch: "amd64",
|
||||
expectedOs: "win",
|
||||
expectedURL: "https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-5.4.0-pre1asdf.windows-amd64.zip",
|
||||
baseArchiveURL: "https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana",
|
||||
buildArtifacts: []buildArtifact{{"win", "amd64", ".windows-amd64.zip", ""}},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range cases {
|
||||
|
||||
0
scripts/build/release_publisher/testdata/grafana-enterprise-5.4.0-123pre1.windows-amd64.msi
vendored
Normal file
0
scripts/build/release_publisher/testdata/grafana-enterprise-5.4.0-123pre1.windows-amd64.msi
vendored
Normal file
@@ -0,0 +1 @@
|
||||
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
|
||||
@@ -16,22 +16,32 @@ const cherryPickRunner: TaskRunner<CherryPickOptions> = async () => {
|
||||
},
|
||||
});
|
||||
|
||||
// sort by closed date
|
||||
// sort by closed date ASC
|
||||
res.data.sort(function(a, b) {
|
||||
return new Date(b.closed_at).getTime() - new Date(a.closed_at).getTime();
|
||||
return new Date(a.closed_at).getTime() - new Date(b.closed_at).getTime();
|
||||
});
|
||||
|
||||
let commands = '';
|
||||
|
||||
console.log('--------------------------------------------------------------------');
|
||||
console.log('Printing PRs with cherry-pick-needed, in ASC merge date order');
|
||||
console.log('--------------------------------------------------------------------');
|
||||
|
||||
for (const item of res.data) {
|
||||
if (!item.milestone) {
|
||||
console.log(item.number + ' missing milestone!');
|
||||
continue;
|
||||
}
|
||||
|
||||
console.log(`${item.title} (${item.number}) closed_at ${item.closed_at}`);
|
||||
console.log(`\tURL: ${item.closed_at} ${item.html_url}`);
|
||||
const issueDetails = await client.get(item.pull_request.url);
|
||||
console.log(`\tMerge sha: ${issueDetails.data.merge_commit_sha}`);
|
||||
console.log(`* ${item.title}, (#${item.number}), merge-sha: ${issueDetails.data.merge_commit_sha}`);
|
||||
commands += `git cherry-pick -x ${issueDetails.data.merge_commit_sha}\n`;
|
||||
}
|
||||
|
||||
console.log('--------------------------------------------------------------------');
|
||||
console.log('Commands (in order of how they should be executed)');
|
||||
console.log('--------------------------------------------------------------------');
|
||||
console.log(commands);
|
||||
};
|
||||
|
||||
export const cherryPickTask = new Task<CherryPickOptions>();
|
||||
|
||||
Reference in New Issue
Block a user